#php #algorithm #image #resize #aspect-ratio
#php #алгоритм #изображение #изменение размера #соотношение сторон
Вопрос:
Я создаю веб-сервис для взаимодействия с приложением iPhone.
Когда мой клиент загружает изображения на сервер, я хочу, чтобы мой php-скрипт изменял размер изображения, сохраняя при этом соотношение сторон, чтобы оно помещалось на экран iPhone. (т. Е. Самая длинная сторона <= 960, а самая короткая <= 640
Я создал макет на JS просто потому, что мне легче сделать это быстро.
Я почти уверен, хотя я могу ошибаться, что это не самый эффективный способ сделать это. Может ли кто-нибудь исправить меня с помощью лучшей логики (особенно бит в начале) или более математического подхода к этому?
var w = 960, h = 960, new_w, new_h;
if (w >= h amp;amp; w > 960 || h >= w amp;amp; h > 960 || w >= h amp;amp; h > 640 || h >= w amp;amp; w > 640) {
if (w > h) {
if (w>960) {
new_w = 960;
new_h = h*(new_w/w);
}
if (h>640) {
new_h = 640;
new_w = w*(new_h/h);
}
}
else {
if (h>960) {
new_h = 960;
new_w = w*(new_h/h);
}
if (w>640) {
new_w = 640;
new_h = h*(new_w/w);
}
}
}
Комментарии:
1. Единственная проблема заключается в том, что вы действуете сразу после проверки w> 960 и предполагаете, что new_h = h * (new_w / w) <= 640, что может быть или не быть правдой. Сначала вы должны проверить границы для обоих.
Ответ №1:
Возможно, немного более короткая процедура будет:
// Calculate resize ratios for resizing
float ratioW = targetWidth / oldWidth;
float ratioH = targetHeight / oldHeight;
// smaller ratio will ensure that the image fits in the view
float ratio = ratioW < ratioH?ratioW:ratioH;
newWidth = oldWidth*ratio;
newHeight = oldHeight*ratio;
Очевидно, что если соотношение> 1, то оно увеличивается, если < 1, то оно уменьшается.
Комментарии:
1. Я просто хочу отметить, что переключение между подгонкой по размеру и заливкой по размеру действительно просто. Для заполнения аспекта просто вставьте знак:
float ratio = ratioW > ratioH ? ratioW : ratioH;
Ответ №2:
Я думаю, что следующее должно дать вам представление. Это не на каком-либо конкретном языке, а скорее псевдокод, подобный C.
shortSideMax = 640;
longSideMax = 960;
function Resize(image)
{
if (image.width >= image.height)
{
if (image.width <= longSideMax amp;amp; image.height <= shortSideMax)
return image; // no resizing required
wRatio = longSideMax / image.width;
hRatio = shortSideMax / image.height;
}
else
{
if (image.height <= longSideMax amp;amp; image.width <= shortSideMax)
return image; // no resizing required
wRatio = shortSideMax / image.width;
hRatio = longSideMax / image.height;
}
// hRatio and wRatio now have the scaling factors for height and width.
// You want the smallest of the two to ensure that the resulting image
// fits in the desired frame and maintains the aspect ratio.
resizeRatio = Min(wRatio, hRatio);
newHeight = image.Height * resizeRatio;
newWidth = image.Width * resizeRatio;
// Now call function to resize original image to [newWidth, newHeight]
// and return the result.
}
Эффективность этого кода или того, что у вас есть, не будет проблемой. Время, необходимое для фактического изменения размера изображения, затмит время, необходимое для выполнения пары сравнений, двух делений и двух умножений.
Является ли это «более математическим» способом сделать это? Я полагаю, в том смысле, что он разбивает ваши четыре случая на два. Но подход по сути тот же.
Комментарии:
1. У меня был почти точно такой же алгоритм, но было приятно увидеть чье-то другое решение этой проблемы — и хвала тому, что фактическое выполнение действия по изменению размера изображения сделает эффективность алгоритма спорной.
2. этот алгоритм не работает для меня, когда высота изображения равна 800, а ширина 600, в то время как shortsidemax равен 275 (по вертикали), а longsidemax равен 480 (по горизонтали).
3. @ManishJain: затем вы должны опубликовать вопрос, указав, что вы пробовали, и результаты, которые вы получаете. Обязательно свяжите этот ответ и объясните, что он не работает.
Ответ №3:
Ниже приведен самый простой способ, который я знаю, сохранить пропорции. Надеюсь, это поможет.
Javascript
function resize(width, height, maxWidth, maxHeight) {
var ratio = Math.min(maxWidth / width, maxHeight / height);
var newWidth = ratio * width;
var newHeight = ratio * height;
console.log(newWidth ' ' newHeight); // Test
// Process resizing...
}
resize(1280, 1024, 600, 300);
PHP
function resize($width, $height, $maxWidth, $maxHeight) {
$ratio = min(array($maxWidth / $width, $maxHeight / $height));
$newWidth = $ratio * $width;
$newHeight = $ratio * $height;
echo $newWidth . ' ' . $newHeight; // Test
// Process resizing...
}
resize(1600, 1280, 150, 150);
Комментарии:
1. Это проще, чем другие ответы. Используйте
Math.min()
для «подгонки» и используйтеMath.max()
для «заполнения».
Ответ №4:
Любой, кто заходит на эту страницу из Google, ищет ЗАЛИВКУ по АСПЕКТУ, а не ПОДГОНКУ по аспекту, это просто вопрос переключения кода выбора соотношения, т.е:
Ответ Джима:
resizeRatio = Min(wRatio, hRatio); //Aspect Fit
становится
resizeRatio = Max(wRatio, hRatio); //Aspect Fill
Ответ DevProd:
float ratio = ratioW < ratioH?ratioW:ratioH; //Aspect Fit
становится
float ratio = ratioW > ratioH?ratioW:ratioH; //Aspect Fill
Ответ №5:
Похоже на ответ DevProd, но я изо всех сил пытался следовать ему сам из-за соглашения об именах. Надеюсь, это немного понятнее:
Как мне наилучшим образом разместить некоторые носители (фотографию) внутри контейнера?
//Define media size and container size
int mediaWidth = 600;
int mediaHeight = 600;
int containerWidth = 1024;
int containerHeight= 768;
//Calculate best fit (whichever dimension has a smaller 'fit')
float wFits = containerWidth / mediaWidth;
float hFits = containerHeight / mediaHeight;
float minFits = wFits > hFits ? hFits : wFits;
//The new size of the media, best-fit'ing inside the container
int width = (int) (mediaWidth*minFits);
int height = (int) (mediaHeight*minFits);