Алгоритм изменения размера изображения и сохранения соотношения сторон для iPhone

#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);