Изменение размера изображения без искажений с сохранением соотношения сторон, а затем обрезка при помощи WideImage - PullRequest
13 голосов
/ 15 июня 2011

На сайте, над которым я работаю, есть область, в которой будет отображаться изображение профиля пользователя, извлеченное из внешнего источника (поэтому нет контроля над его исходным размером).

Что я хочу сделать, так это взять изображение (в этом примере 1000px x 800px и изменить его размер до 200px x 150px. Очевидно, что при этом есть разница в соотношении сторон.

То, что я хочу сделать, это изменить исходное изображение без искажений, что в этом случае приведет к 200px x 160px изображению. Затем я хочу обрезать лишние края, чтобы получить правильный размер изображения. Таким образом, в этом случае обрежьте 5px сверху и снизу изображения, в результате чего получится 200px x 150px.

У меня есть библиотека WideImage , и я хотел бы использовать ее. Я видел несколько похожих вопросов по SO, но ничего, что я могу сказать, точно не соответствует тому, что я пытаюсь достичь.

Ответы [ 5 ]

27 голосов
/ 15 июня 2011

Вы можете попробовать:

$img->resize(200, 150, 'outside')->crop('center', 'middle', 200, 150);

Некоторые пользователи публикуют свои версии расчетов ... Вот и моя версия:

$sourceWidth = 1000;
$sourceHeight = 250;

$targetWidth = 200;
$targetHeight = 150;

$sourceRatio = $sourceWidth / $sourceHeight;
$targetRatio = $targetWidth / $targetHeight;

if ( $sourceRatio < $targetRatio ) {
    $scale = $sourceWidth / $targetWidth;
} else {
    $scale = $sourceHeight / $targetHeight;
}

$resizeWidth = (int)($sourceWidth / $scale);
$resizeHeight = (int)($sourceHeight / $scale);

$cropLeft = (int)(($resizeWidth - $targetWidth) / 2);
$cropTop = (int)(($resizeHeight - $targetHeight) / 2);

var_dump($resizeWidth, $resizeHeight, $cropLeft, $cropTop);
8 голосов
/ 19 мая 2012

Я испробовал все ваши решения и каждый раз придумывал странные цифры.Итак, это мой способ выполнения расчетов.

Основная пропорциональная формула: a / b = x / y -> ay = bx, затем найдите неизвестное значение.Итак, давайте поместим это в код.

Эта функция предполагает, что вы открыли изображение в переменную.Если вы пройдете путь, вам придется открыть изображение в функции, выполнить математику, убить его, вернуть значения и затем снова открыть изображение при изменении его размера, это неэффективно ...

function resize_values($image){
    #for the purpose of this example, we'll set this here
    #to make this function more powerful, i'd pass these 
    #to the function on the fly
    $maxWidth = 200; 
    $maxHeight = 200;

    #get the size of the image you're resizing.
    $origHeight = imagesy($image);
    $origWidth = imagesx($image);

    #check for longest side, we'll be seeing that to the max value above
    if($origHeight > $origWidth){ #if height is more than width
         $newWidth = ($maxHeight * $origWidth) / $origHeight;

         $retval = array(width => $newWidth, height => $maxHeight);
    }else{
         $newHeight= ($maxWidth * $origHeight) / $origWidth;

         $retval = array(width => $maxWidth, height => $newHeight);
    }
return $retval;
}

Выше функция возвращает массив, очевидно.Вы можете преобразовать формулу в любой скрипт, над которым вы работаете.Это оказалось правильной формулой для работы.Так что ... решать вам, используете ли вы его или нет.ПОЗЖЕ!

2 голосов
/ 23 марта 2012
//Following code for keeping aspect ratio

$srcWidth=1000;
$srcHeight=800;

$targetWidth=200;
$targetHeight=150;

$diff=0;
//get difference

if( $srcWidth > $srcHeight ) // 1000 > 800
{
    $diff = $srcWidth - $srcHeight; // 1000 - 800 = 200
    $diff = ($diff / $srcWidth) * 100; // ( 200 / 1000 ) * 100 = 20
}
else
{
    $diff = $srcHeight - $srcWidth;
    $diff = ($diff / $srcHeight)*100;
}

if( $targetWidth > $targetHeight)
{
    $targetHeight = (( $targetHeight * $diff ) / 100) - $targetWidth; // (( 200 * 20 ) /  100) - 200 = 160
}
else
{
    $targetWidth = (( $targetWidth * $diff ) / 100) - $targetHeight;
}
2 голосов
/ 15 июня 2011

Ответ № 1 (отредактировано)

После просмотра этого и этого вам, вероятно, нужно сделать что-то вроде этого:

$img->resize(200, 150, 'outside')->crop("center", "center", 200, 150);

При изменении размера оно изменит размер изображения так, чтобы оно либо точно вписывалось в рамку (box = 200x150), либо одно из размеров соответствовало, в то время как другое превышало поле. Во время обрезки часть изображения, которая кровоточит за пределами рамки, будет обрезана. Указание умной координаты center означает, что верхняя + нижняя или левая + правая часть будет удалена.

Ответ № 2

Если у вас возникли проблемы в вычислении что обрезать, попробуйте это:

<?php
$target_wide = 200;
$target_tall = 150;

$test_case = array(
    array(1000, 800),
    array(800, 1000),
    array(1000, 750), // perfect fit
    array(750, 1000)
);

foreach($test_case as $test) {
    list(
        $source_wide,
        $source_tall
    ) = $test;
    $source_aspect_ratio = $source_wide / $source_tall;
    $target_aspect_ratio = $target_wide / $target_tall;
    if ($source_aspect_ratio > $target_aspect_ratio)
    {
        $output_tall = $target_tall;
        $output_wide = (int) ($target_tall * $source_aspect_ratio);
    }
    else
    {
        $output_wide = $target_wide;
        $output_tall = (int) ($target_wide / $source_aspect_ratio);
    }
    $output_crop_hori = (int) (($output_wide - $target_wide) / 2);
    $output_crop_vert = (int) (($output_tall - $target_tall) / 2);
    var_dump($source_wide, $source_tall, $output_wide, $output_tall, $output_crop_hori, $output_crop_vert);
    echo PHP_EOL;
}

Выход:

int(1000)
int(800)
int(200)
int(160)
int(0)
int(5)

int(800)
int(1000)
int(200)
int(250)
int(0)
int(50)

int(1000)
int(750)
int(200)
int(150)
int(0)
int(0)

int(750)
int(1000)
int(200)
int(266)
int(0)
int(58)
1 голос
/ 15 июня 2011

Вот как можно рассчитать размер урожая:

$src_width = 1000;
$src_height = 500;
$src_ratio = $src_width/$src_height;

$width = 200;
$height = 150;
$ratio = $width/$height;

$crop_height = 0;
$crop_width = 0;

if ($src_height > $src_width)
{
    $new_height = $width/$src_ratio;
    $crop_height = $new_height-$height;
}
else
{
    $new_width = $height*$src_ratio;
    $crop_width = $new_width-$width;
}

print 'Crop height: '.$crop_height.PHP_EOL
      .'Crop width: '.$crop_width;
...