6

私は配列を持っています:

$resolutions = array(
    '480x640',
    '480x800',
    '640x480',
    '640x960',
    '800x1280',
    '2048x1536'
);

最も近い縦横比(同じ向き)で最も近い大きな値を取得したい。

$needle = '768x1280'で、 ~の場合800x1280
そして、$needle = '320x240'~の場合640x480。ここで最も近いのは480x640一致するべきではありませんが、アスペクト比が大きく異なるためです。などなど。

目的:

で指定されている解像度の画像のセットがあります$resolutions。これらの画像は、スマートフォンの壁紙に使用される予定です。

screen.widthJavaScript を使用して、 とscreen.heightを決定するリクエストを送信してい$needleます。

サーバー側では、指定された解像度の最も大きな値を取得し、縦横比を維持しながら画面全体に収まるように縮小し、サイズが重なる場合は、画面に完全に収まるようにトリミングします。

問題:

スケーリングとトリミングではすべてが非常に単純ですが、参照画像をロードするために、最も近い大きな値を見つける方法は考えられません。

ヒント:

それが役立つ場合は、別の形式にすることができ$resolutionsます。$needlearray('width' => x, 'height' => y)

試行:

レーベンシュタイン距離を実験してみまし た: http://codepad.viper-7.com/e8JGOw という結果になりましたが、今回は合いません。
768x1280800x1280320x240480x640

4

7 に答える 7

10

これを試して

echo getClosestRes('500x960');
echo '<br /> try too large to match: '.getClosestRes('50000x960');

function getClosestRes($res){
    $screens = array(
        'landscape'=>array(
            '640x480',
            '1200x800'
        ),
        'portrait'=>array(
            '480x640',
            '480x800',
            '640x960',
            '800x1280',
            '1536x2048'
        )
    );

    list($x,$y)=explode('x',$res);
    $use=($x>$y?'landscape':'portrait');

    // if exact match exists return original
    if (array_search($res, $screens[$use])) return $res; 

    foreach ($screens[$use] as $screen){
        $s=explode('x',$screen);
        if ($s[0]>=$x && $s[1]>=$y) return $screen;
    }
    // just return largest if it gets this far.
    return $screen; // last one set to $screen is largest
}
于 2012-12-10T17:19:48.090 に答える
1

クイッククラスを作りました。指定した 2 つの数値の最小解像度を適切に見つける必要があります。指定した解像度でプリロードしましたが、$_resolutionsアレイは好きな標準に設定でき、オンザフライで変更することもできます。

class Resolution {

    /**
     * Standard resolutions
     *
     * Ordered by smallest to largest width, followed by height.
     *
     * @var array
     */
    private $_resolutions = array(
        array('480', '640'),
        array('480', '800'),
        array('640', '480'),
        array('640', '960'),
        array('800', '1280'),
        array('2048', '1536')
    );

    /**
     * Width
     *
     * @var int
     */
    private $_width;

    /**
     * Height
     *
     * @var int
     */
    private $_height;

    /**
     * Constructor
     *
     * @param  int $width
     * @param  int $height
     * @return void
     */
    public function __construct($width, $height) {
        $this->setSize($width, $height);
    }

    /**
     * Find the minimum matched standard resolution
     *
     * @param  bool $revertToLargest (OPTIONAL) If no large enough resolution is found, use the largest available.
     * @param  bool $matchAspectRatio (OPTIONAL) Attempt to get the closest resolution with the same aspect ratio. If no resolutions have the same aspect ratio, it will simply use the minimum available size.
     * @return array The matched resolution width/height as an array.  If no large enough resolution is found, FALSE is returned, unless $revertToLargest is set.
     */
    public function getMinimumMatch($revertToLargest = false, $matchAspectRatio = true) {
        if ($matchAspectRatio) {
            $aspect = $this->_width/$this->_height;
            foreach ($this->_resolutions as $res) {
                if ($res[0]/$res[1] == $aspect) {
                    if ($this->_width > $res[0] || $this->_height >     $res[1]) {
                        return ($revertToLargest ? $res : false);
                    }
                    return $res;
                }
            }
        }
        foreach ($this->_resolutions as $i => $res) {
            if ($this->_width <= $res[0]) {
                $total = count($this->_resolutions);
                for ($j = $i; $j < $total; $j++) {
                    if ($this->_height <= $this->_resolutions[$j][1]) {
                        return $this->_resolutions[$j];
                    }
                }
            }
        }
        return ($revertToLargest ? end($this->_resolutions) : false);
    }

    /**
     * Get the resolution
     *
     * @return array The resolution width/height as an array
     */
    public function getSize() {
        return array($this->_width, $this->_height);
    }

    /**
     * Set the resolution
     *
     * @param  int $width
     * @param  int $height
     * @return array The new resolution width/height as an array
     */
    public function setSize($width, $height) {
        $this->_width = abs(intval($width));
        $this->_height = abs(intval($height));
        return $this->getSize();
    }

    /**
     * Get the standard resolutions
     *
     * @return array
     */
    public function getStandardResolutions() {
        return $this->_resolutions;
    }

    /**
     * Set the standard resolution values
     *
     * @param  array An array of resolution width/heights as sub-arrays
     * @return array
     */
    public function setStandardResolutions(array $resolutions) {
        $this->_resolutions = $resolutions;
        return $this->_resolutions;
    }

}

使用例

$screen = new Resolution(320, 240);
$screen->getMinimumMatch();
// Returns 640 x 480 (aspect ratio matched)

$screen = new Resolution(1280, 960);
$screen->getMinimumMatch();
// Returns 640 x 480 (aspect ratio matched)

$screen = new Resolution(400, 960);
$screen->getMinimumMatch();
// Returns 640 x 960 (aspect ratio not matched, so uses closest fit)

$screen = new Resolution(5000, 5000);
$screen->getMinimumMatch();
// Returns FALSE (aspect ratio not matched and resolution too large)

$screen = new Resolution(5000, 5000);
$screen->getMinimumMatch(true);
// Returns 2048 x 1536 (aspect ratio not matched and resolution too large, so uses largest available)
于 2012-12-10T18:20:07.640 に答える
0

まず、最初に幅、次に高さを使用して干し草の山を保管します。

$resolutions = array(
    array('w' => 640, 'h' => 480),
    array('w' => 800, 'h' => 480),
    array('w' => 960, 'h' => 640),
    array('w' => 1280, 'h' => 800),
    array('w' => 2048, 'h' => 1536),
);

次に、針と各アイテムの寸法差を計算し、続いて面積サイズを計算します。

array_walk($resolutions, function(&$item) use ($needle) {
    $item['aspect'] = abs($item['w'] - $needle['w']) / abs($item['h'] - $needle['h']);
    $item['area'] = $item['w'] * item['h'];
});

usort($resolutions, function($a, $b) {
  if ($a['aspect'] != $b['aspect']) {
    return ($a['aspect'] < $b['aspect']) ? -1 : 1;
  }
 return 0;
});

次に、どの解像度が大きいかに基づいてリストをフィルタリングします。最初の一致は、針のアスペクト比に最も近いものです。

$needle_area = $needle['w'] * $needle['h'];
foreach ($resolutions as $item) {
    if ($needle_area < $item['area']) {
        return $item;
    }
}
return null;
于 2012-12-10T17:28:07.800 に答える
0

わかりました、私はそれを持っています。最低の適切な解像度を返し、非標準の解像度も考慮する関数を作成しました。

    <?php
    //some obscure resolution, for illustrative purposes
    $theirResolution = '530x700'; 
    $resolutions = array(
        '480x640',
        '480x800',
        '640x480',
        '640x960',
        '800x1280',
        '2048x1536'
    );

    function findSmallestResolution($theirResolution,$resolutions){
        $temp = explode('x',$theirResolution);
        //Isolate their display's X dimension
        $theirResolutionX = intval($temp[1]);
        foreach($resolutions as $key => $value){
            $temp = explode('x',$value);
            //if the current resolution is bigger than or equal to theirs in the X dimension, then it's a possibility.
            if($theirResolutionX <= intval($temp[1])){
                $possibleResolutionsX[] = $value;
            }
        }
        //Now we'll filter our $possibleResolutions in the Y dimension.
        $temp = explode('x',$theirResolution);
        //Isolate their display's Y dimension
        $theirResolutionY = intval($temp[0]);
        foreach($possibleResolutionsX as $key => $value){
            $temp = explode('x',$value);
            //if the current resolution is bigger than or equal to theirs in the X dimension, then it's a possibility.
            if($theirResolutionY <= intval($temp[0])){
                $possibleResolutionsXY[] = $value;
            }
        }
        //at this point, $possibleResolutionsXY has all of our entries that are big enough. Now to find the smallest among them.
        foreach($possibleResolutionsXY as $key => $value){
            $temp = explode('x', $value);
            //since we didn't specify how standard our app's possible resolutions are, I'll have to measure the smallest in terms of total dots and not simply X and Y.
            $dotCount[] = intval($temp[0]) * intval($temp[1]);
        }
        //find our resolution with the least dots from the ones that still fit the user's.
        foreach($dotCount as $key => $value){
            if($value == min($dotCount)){
                $minkey = $key;
            }
        }
        //use the key from dotCount to find its corresponding resolution from possibleResolutionsXY.
        return $possibleResolutionsXY[$minkey];
    }


    findSmallestResolution($theirResolution,$resolutions);
    // returns '640x960'.


    ?>
于 2012-12-10T17:26:14.297 に答える
0

うーん、予想以上に大きくなりましたが、基準は満たしていると思います。利用可能な解像度をその比率に分解することで機能します。次に、ターゲット比率と使用可能な比率の間のデルタで昇順に並べ替え、次にサイズ (ピクセル) で降順に並べ替えます。上位の一致を返します - これは、最も近く、最小の一致である必要があります。

class ResolutionMatcher
{
    private $resolutions;

    public function __construct(array $resolutions)
    {
        foreach ($resolutions as $resolution) {
            $this->resolutions[$resolution] = $this->examineResolution($resolution);
        }
    }

    public function findClosest($target)
    {
        $targetDetails = $this->examineResolution($target);
        $deltas = array();
        foreach ($this->resolutions as $resolution => $details) {
            if ($details['long'] < $targetDetails['long'] || $details['short'] < $targetDetails['short']) continue;
            $deltas[$resolution] = array(
                'resolution' => $resolution,
                'delta' => abs($details['ratio'] - $targetDetails['ratio']),
            );
        }
        $resolutions = $this->resolutions;
        uasort($deltas, function ($a, $b) use ($resolutions) {
            $deltaA = $a['delta'];
            $deltaB = $b['delta'];
            if ($deltaA === $deltaB) {
                $pixelsA = $resolutions[$a['resolution']]['pixels'];
                $pixelsB = $resolutions[$b['resolution']]['pixels'];
                if ($pixelsA === $pixelsB) {
                    return 0;
                }
                return $pixelsA > $pixelsB ? 1 : -1;
            }
            return $deltaA > $deltaB ? 1 : -1;
        });
        $resolutions = array_keys($deltas);
        return array_pop($resolutions);
    }

    private function examineResolution($resolution)
    {
        list($width, $height) = explode('x', $resolution);
        $long = ($width > $height) ? $width : $height;
        $short = ($width < $height) ? $width : $height;
        $ratio = $long / $short;
        $pixels = $long * $short;
        return array(
            'resolutions' => $resolution,
            'pixels' => $pixels,
            'long' => $long,
            'short' => $short,
            'ratio' => $ratio,
        );
    }
}

使用法:

$resolutions = array(
    '480x640',
    '480x800',
    '640x480',
    '640x960',
    '800x1280',
    '2048x1536'
);

$target = $_GET['target'];

$matcher = new ResolutionMatcher($resolutions);
$closest = $matcher->findClosest($target);
于 2012-12-10T18:19:10.810 に答える
0

最初に次のような配列を抽出できます。

$resolutions = array(
    '480x640',
    '480x800',
    '640x480',
    '640x960',
    '800x1280',
    '2048x1536'
);

foreach ($resolutions as $resolution):
    $width[]=(int)$resolution;
    $height[]=(int)substr(strrchr($resolution, 'x'), 1);
    echo $width,' x ',$height,'<br>';
endforeach;

次に、指定された針を次のように配列in_arrayと一致させることができます。array_search

$key = array_search('480', $items);
echo $key;  

キーを取得したら、最も近い大きな値に合わせてインクリメントします。私はあなたにそれを自分でやらせます。

于 2012-12-10T17:20:37.527 に答える
0

比較する数値が 1 つあれば、簡単に比較できますか?

これは比率なので、例えば: 640 / 480 = 1.33* とします。

次に、少なくとも送信している寸法と比較して、おそらく公差を考え出すための素晴らしく簡単なものがありますか?

ratio 配列が最低から最高の順に並べられていると仮定する簡単な例。これが問題になる場合は、領域 (x x y) で並べ替えた検索を作成します。

function getNearestRatio($myx, $myy)
{

    $ratios = array(
        array('x'=>480, 'y'=>640),
        array('x'=>480, 'y'=>800),
        array('x'=>640, 'y'=>480),
        array('x'=>640, 'y'=>960),
        array('x'=>800, 'y'=>1280),
        array('x'=>2048, 'y'=>1536)
    );
    $tolerance = 0.1;
    foreach ($ratios as $ratio) {
         $aspect = $ratio['x'] / $ratio['y'];
        $myaspect = $myx / $myy;

        if ( ! ($aspect - $tolerance < $myaspect && $myaspect < $aspect + $tolerance )) {
            continue;
        }

        if ($ratio['x'] < $myx || $ratio['y'] < $myy) {
            continue;
        }
        break;
    }

    return $ratio;
}

あなたの質問でほのめかしているように、「近くの」アスペクト比と一致するように、許容範囲を組み込んでいます。

この関数は、指定した両方のテスト ケースに合格する必要があります。

于 2012-12-10T17:14:46.597 に答える