我有一个数组:
$resolutions = array(
'480x640',
'480x800',
'640x480',
'640x960',
'800x1280',
'2048x1536'
);
我想用最近的宽高比(相同方向)检索最接近的较大值。
因此,如果是$needle = '768x1280'
- 800x1280
而且,如果是$needle = '320x240'
- 640x480
。虽然最接近的是480x640
但它不应该匹配,因为它的纵横比差别太大。
等等,等等。
我有一组图像,其分辨率在$resolutions
中指定。这些图像将用于智能手机壁纸。
使用JavaScript,我发送的请求包含screen.width
和screen.height
,以确定$needle
。
在服务器端,我将获取给定分辨率的最接近的较大值,将其缩小以适应整个屏幕,同时保留纵横比,如果某些内容与尺寸重叠,则将其裁剪为完全适合屏幕。
虽然缩放和裁剪一切都很简单,但我想不出找出最接近的较大值的方法,以加载参考图像。
如果有帮助,$resolutions
和$needle
可采用不同的格式,即:array('width' => x, 'height' => y)
。
我尝试用levenshtein距离进行实验:http://codepad.viper-7.com/e8JGOw
显然,它仅适用于768x1280
并且导致800x1280
。对于320x240
,它产生了480x640
,但这次不合适。
答案 0 :(得分:9)
试试这个
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
}
答案 1 :(得分:0)
如果你有一个数字要比较,会更容易吗?
这是一个比例,所以就这样做,例如:640/480 = 1.33 *
然后你至少要有一些好的和简单的东西可以与你发送的尺寸进行比较,并且可能会产生一个宽容?
一个简单的例子,它假设比率数组从最低到最高排序。如果这是一个问题,那么我们将创建一个按区域排序的搜索(x by 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;
}
我内置了一个容差,因此它会匹配“附近”的宽高比,正如您在问题中所提到的那样。
此函数应该通过您给出的两个测试用例。
答案 2 :(得分: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;
当您拥有密钥时,只需将其递增以获得最接近的较大值。我会让你自己做的。
答案 3 :(得分: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'.
?>
答案 4 :(得分: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;
答案 5 :(得分: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);
答案 6 :(得分:0)
快速上课。应该能够找到您指定的任何两个数字的最小分辨率。我已经使用您指定的分辨率预装了它,但$_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)