Изменить размер / обрезать / дополнить изображение до фиксированного размера - PullRequest
8 голосов
/ 14 апреля 2009

Мне нужно изменить размер изображения до фиксированного размера. Но это должно держать факторы между шириной и высотой.

Скажите, что я хочу изменить размер изображения с 238 (w) X 182 (h) до 210 / 150

Что я делаю сейчас:

Original width / target width = 1.333333
Original Height / target Height = 1.213333

Теперь я возьму наименьший фактор.

Теперь у меня всегда правильная ширина, начиная с 238 / 1.333333 = 210. Но высота все еще 160.

Как мне уменьшить высоту до 160, не испортив картинку?

Нужно ли обрезать? Если так, то как?

Ответы [ 11 ]

25 голосов
/ 14 апреля 2009

Это решение, в основном, такое же, как у Can Berk Güder, но, потратив некоторое время на написание и комментирование, я захотел написать.

Эта функция создает миниатюру, которая в точности соответствует размеру, который вы ей даете. Размер изображения изменяется в соответствии с размером миниатюры. Если он не подходит точно в обоих направлениях, он центрируется в хвосте. Обширные комментарии объясняют, что происходит.

function thumbnail_box($img, $box_w, $box_h) {
    //create the image, of the required size
    $new = imagecreatetruecolor($box_w, $box_h);
    if($new === false) {
        //creation failed -- probably not enough memory
        return null;
    }


    //Fill the image with a light grey color
    //(this will be visible in the padding around the image,
    //if the aspect ratios of the image and the thumbnail do not match)
    //Replace this with any color you want, or comment it out for black.
    //I used grey for testing =)
    $fill = imagecolorallocate($new, 200, 200, 205);
    imagefill($new, 0, 0, $fill);

    //compute resize ratio
    $hratio = $box_h / imagesy($img);
    $wratio = $box_w / imagesx($img);
    $ratio = min($hratio, $wratio);

    //if the source is smaller than the thumbnail size, 
    //don't resize -- add a margin instead
    //(that is, dont magnify images)
    if($ratio > 1.0)
        $ratio = 1.0;

    //compute sizes
    $sy = floor(imagesy($img) * $ratio);
    $sx = floor(imagesx($img) * $ratio);

    //compute margins
    //Using these margins centers the image in the thumbnail.
    //If you always want the image to the top left, 
    //set both of these to 0
    $m_y = floor(($box_h - $sy) / 2);
    $m_x = floor(($box_w - $sx) / 2);

    //Copy the image data, and resample
    //
    //If you want a fast and ugly thumbnail,
    //replace imagecopyresampled with imagecopyresized
    if(!imagecopyresampled($new, $img,
        $m_x, $m_y, //dest x, y (margins)
        0, 0, //src x, y (0,0 means top left)
        $sx, $sy,//dest w, h (resample to this size (computed above)
        imagesx($img), imagesy($img)) //src w, h (the full size of the original)
    ) {
        //copy failed
        imagedestroy($new);
        return null;
    }
    //copy successful
    return $new;
}

Пример использования:

$i = imagecreatefromjpeg("img.jpg");
$thumb = thumbnail_box($i, 210, 150);
imagedestroy($i);

if(is_null($thumb)) {
    /* image creation or copying failed */
    header('HTTP/1.1 500 Internal Server Error');
    exit();
}
header('Content-Type: image/jpeg');
imagejpeg($thumb);
10 голосов
/ 14 апреля 2009

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

$w = 210;
$h = 150;

$orig_w = imagesx($original);
$orig_h = imagesy($original);

$w_ratio = $orig_w / $w;
$h_ratio = $orig_h / $h;

$ratio = $w_ratio > $h_ratio ? $w_ratio : $h_ratio;

$dst_w = $orig_w / $ratio;
$dst_h = $orig_h / $ratio;
$dst_x = ($w - $dst_w) / 2;
$dst_y = ($h - $dst_h) / 2;

$thumbnail = imagecreatetruecolor($w, $h);

imagecopyresampled($thumbnail, $original, $dst_x, $dst_y,
                   0, 0, $dst_w, $dst_h, $orig_w, $orig_h);
2 голосов
/ 14 апреля 2009

Просто совет для высококачественной быстрой генерации миниатюр из больших изображений: (* ​​1001 * с сайта php.net )

Если вы создаете миниатюру в двух этапах:

  1. От оригинала до промежуточного изображения с двойными окончательными размерами с использованием быстрого изменения размера
  2. От промежуточного изображения до конечного эскиза с использованием высококачественной повторной выборки

тогда это может быть намного быстрее; изменение размера на шаге 1 является относительно низким качеством для своего размера, но имеет достаточное дополнительное разрешение, чтобы на шаге 2 качество было приличным, а промежуточное изображение достаточно маленьким, чтобы высококачественная повторная выборка (которая хорошо работает при изменении размера 2: 1) продолжается очень быстро.

2 голосов
/ 14 апреля 2009

Может быть, посмотрите на PHPThumb (работает с GD и ImageMagick)

2 голосов
/ 14 апреля 2009

У вас есть Imagick ? Если это так, вы можете загрузить изображение с ним и сделать что-то вроде thumbnailimage()

Там вы можете пропустить любой из параметров (высоту или ширину), и он будет правильно изменять размер.

1 голос
/ 18 апреля 2009

Техника заключается в:

  1. изменить размер изображения так, чтобы одно измерение совпадало, а другое превысило желаемые размеры
  2. вынуть изображение нужного размера из центра изображения с измененным размером.

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

SourceWidth / SourceHeight = DestinationWidth / DestinationHeight

Если вам известны три параметра, вы можете легко вычислить четвертый.

Я написал статью об этом:
Обрезать изображение по ASP / PHP

1 голос
/ 14 апреля 2009

Я думаю, что есть небольшая путаница .. Если вы хотите только изменить его размер, сохранив исходное соотношение, правильная операция:

$ratio = $originalWidth / $originalHeight;
if(//you start from the width, and want to find the height){
 $newWidth = $x;
 $newHeight = $x / $ratio;
}else if(//you start from the height, and want to find the width){
 $newHeight = $x;
 $newWidth = $x * $ratio;
}

Иначе, если префиксы newWidth и newHeight не могут быть изменены, а коэффициент большого пальца отличается от исходного соотношения, единственный способ - обрезать или добавить границы для большого пальца.

Если вы идете по пути кройки, эта функция может вам помочь (я писал несколько лет назад за 5 минут, возможно, нужно что-то улучшить ... она работает только с jpg, например;):

    function thumb_cut($nomeimage, $source_path, $destination_path, $new_width, $new_height){
      list($width, $height, $type, $attr) = getimagesize($source_path.$nomeimage);
      if($type == 2){
        if($width > $new_width){
          $new_width = $width;
          $new_height = $height;
        }
        $compression = 100;
        $destimg = imagecreatetruecolor($new_width,$new_height) or die("Problems creating the image");
        $srcimg = ImageCreateFromJPEG($source_path.$nomeimage) or die("problem opening the image");
        $w = ImageSX($srcimg);
        $h = ImageSY($srcimg);
        $ro = $new_width/$new_height;
        $ri = $w/$h;
        if($ro<$ri){
          $par = "h";
        }else{
          $par = "w";
        }
        if($par == "h"){
          $ih = $h;
          $conv = $new_width/$new_height;
          $iw = $conv*$ih;
          $cw = ($w/2)-($iw/2);
          $ch = ($h/2)-($ih/2);
        }else if($par == "w"){
          $iw = $w;
          $conv = $new_height/$new_width;
          $ih = $conv*$iw;
          $cw = ($w/2)-($iw/2);
          $ch = ($h/2)-($ih/2);
        }
        ImageCopyResampled($destimg,$srcimg,0,0,$cw,$ch,$new_width,$new_height,$iw,$ih) or die("problems with resize");
        ImageJPEG($destimg,$destination_path.$nomeimage,$compression) or die("problems with storing new image");
      }
    }
1 голос
/ 14 апреля 2009

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

1 голос
/ 14 апреля 2009

Изменение размера изображений на веб-странице с использованием PHP может быть проблематичным. Большие изображения (около 2 МБ на диске) могут быть настолько большими, что для обработки им требуется более 32 МБ памяти.

По этой причине я склонен делать это либо из сценария на основе CLI, с доступной ему до 128 МБ памяти, либо из стандартной командной строки, которая также использует столько, сколько нужно.

# where to put the original file/image. It gets resized back 
# it was originally found (current directory)
SAFE=/home/website/PHOTOS/originals
# no more than 640x640 when finished, and always proportional
MAXSIZE=640
# the larger image is in /home/website/PHOTOS/, moved to .../originals
# and the resized image back to the parent dir.
cd $SAFE/.. && mv "$1" "$SAFE/$1" && \
   convert "$SAFE/$1" -resize $MAXSIZE\x$MAXSIZE\> "$1"

'convert' является частью инструментов командной строки ImageMagick.

1 голос
/ 14 апреля 2009

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

...