PHP: уменьшение размера изображения и обрезка с помощью imagemagick

Я пытаюсь уменьшить размер изображения, загруженного пользователями во время загрузки.
Это не проблема, но сейчас я хочу уточнить размеры.

Мне нужен совет по алгоритму, который я изо всех сил пытаюсь создать, который будет принимать изображение любой формы - квадрат или прямоугольник любой ширины / высоты и уменьшать его.

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

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

Я действительно не прошу PHP-код более псевдо. Очевидно, что все в порядке.

Спасибо, пожалуйста.

Текущий код .. но я прошел так много итераций, что это может вообще не работать ..: P

$image = $image_orig->clone();
$wRatio = $imageprops['width'] / $dimensions[0];   // imageprops = original image dimens.
$hRatio = $imageprops['height'] / $dimensions[1];  // $dimensions[0] = new width
$maxRatio = max($wRatio,$hRatio);                  // $dimensions[1] = new height

var_dump('thumb');

$ratio = ($imageprops['width'] - $dimensions[0]) > ($imageprops['height'] - $dimensions[1]);
$shape = ($imageprops['width'] > $imageprops['height']);
$error = ($imageprops['width'] / $imageprops['height']);

if( $error < 0.95 || $error > 1.05 ) { // its NOT a square
    if($shape){  // longer width
        $scale = $imageprops['height'] / $dimensions[0];
        var_dump('1');

        $height = $imageprops['height'] / $scale;
        $image->scaleImage(0, $height);
    } else {
        $scale = $imageprops['width'] / $dimensions[1];
        var_dump('2');

        $width = $imageprops['width'] / $scale;
        $image->scaleImage($width, 0);


    }
} elseif($ratio) { // is square
    $scale = $imageprops['height'] / $dimensions[1];
    $newWidth = $imageprops['width'] / $scale;
    $extra = 0;

    $height = $dimensions[1]+$extra;
    $image->scaleImage(0, $height);
} else {
    $scale = $imageprops['width'] / $dimensions[0];
    $newHeight = $imageprops['height'] / $scale;
    $extra = 0;

    $width = $dimensions[0]+$extra;
    $image->scaleImage($width, 0);

}


$image_size = $image->getImageGeometry();

$image->cropImage($dimensions[0], $dimensions[1],($image_size['width']-$dimensions[0])/2,($image_size['height']-$dimensions[1])/2);

person mr12086    schedule 20.11.2012    source источник
comment
у вас, по-видимому, есть размеры блока, поэтому просто используйте их в вызове изменения размера? или вы хотите изменить размер пропорционально, чтобы изображение не искажалось?   -  person Marc B    schedule 20.11.2012
comment
Допустим, у меня 600x 457h, я хочу, чтобы он увеличился до 120x90 ... сохраняя пропорции оригинала. В этой ситуации, если я уменьшу 457 до 90 пропорционально, ширина станет 118 ... слишком мала. Теперь для некоторых изображений это работает, но для этого изображения мне пришлось бы использовать ширину в качестве начального размера для изменения размера. но мне нужен алгоритм, который работает для всех размеров изображения.   -  person mr12086    schedule 20.11.2012
comment
Меня действительно очень раздражает, что вы не включили эту информацию в свой исходный вопрос ... То, что вы только что опубликовали, полностью меняет исходное значение исходного сообщения, и я только что потратил последние 15 минут на написание твердого ответа, который не является т в малейшей степени то, что вам нужно.   -  person Layke    schedule 20.11.2012
comment
Мне очень жаль. Я устал - уже поздно. не стесняйтесь размещать это. Это все еще может быть полезно.   -  person mr12086    schedule 20.11.2012


Ответы (2)


Примечание: я написал этот ответ до того, как исходный автор отредактировал свой вопрос, включив в него элементы, проясняющие моменты, которые с тех пор изменили то, что, как я полагал, задавал исходный вопрос.


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

Поскольку вы всегда уменьшаете размер исходного изображения, вы, по сути, просто хотите «вырезать» часть изображения. Очень похоже на это:

введите описание изображения здесь

Однако проблема заключается в том, что вы часто хотите убедиться, что выбрали лучшую область изображения, чтобы не обрезать нерелевантный сегмент изображения. Это называется кадрированием изображений с учетом содержимого, и, просто выполнив поиск с помощью функции «Кадрирование изображений с учетом содержимого», можно найти массу информации.

В любом случае, двигаясь дальше, в зависимости от вашего конкретного варианта использования, вы можете обнаружить, что на самом деле вы не хотите вырезать что-либо из изображения, и вместо этого вы хотите «жидко масштабировать и обрезать» изображение, чтобы вы сделали «Content Осведомленность об изменении размера ". Разница с изменением размера с учетом содержимого заключается в том, что изменение размера игнорирует все соотношения сторон изображения и вместо этого смотрит на соседние края и цвета, чтобы изменить размер изображения плавным образом.

Итак, к счастью, Imagick имеет свою собственную [liquidRescaleImage][3] функцию.

Вы можете использовать это как

$im->liquidRescaleImage(480, 260, 3, 18);

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

Оригинал

Оригинал

Жидкое масштабирование с учетом содержимого (450x350)

Изменить масштаб

Однако если вы просто хотите масштабировать изображение и сохранить соотношение сторон, вы можете сделать то же самое, что и на таких сайтах, как Flickr, где они делают изображения longestLength равными значению. (Flickr, например, имеет около 6 различных размеров)

Мы изменяем размер ваших фотографий в соответствии с размерами, удобными для просмотра в Интернете. Каждое изображение имеет квадратную миниатюру 75x75 и 150x150 и версии с разрешением 100, 240, 320, 500, 640-800 *, 1024, 1600 * и 2048 * пикселей (это длина самой длинной стороны). , а также ваш исходный файл.

Базовый класс, который воспроизводит политики изменения размера Flickr ...

<?php    
class Scale {        
    public function getImageScale($x, $y, $longestLength, $allowDistort = false) {
        //Set the default NEW values to be the old, in case it doesn't even need scaling
        list($nx, $ny) = array($x, $y);            
            if ($x > $y) {                   
                if ($longestLength > $x && !$allowDistort) {
                    return array($x, $y);
                }
                $r = $x / $longestLength;
                return array($longestLength, $y / $r);
            } else {
                if ($longestLength > $x && !$allowDistort) {
                    return array($x, $y);
                }
                $r = $y / $longestLength;
                return array($x / $r, $longestLength);
            }
        return array($nx, $ny);
    }       
}

А затем, если вы передадите размеры изображения следующим образом:

$originalImageX = 480;
$originalImageY = 260;    
$scale = new Scale();
var_dump($scale->getImageScale($originalImageX,$originalImageY,120 ) );    

/* Outputs
   array(2) {
  [0]=>
  int(120)
  [1]=>
  int(65)
} */

Кроме того, в Git есть этот класс Content Aware Cropping, который я ранее адаптировал базовый класс / структуру для использования в моем собственном проекте, поэтому я знаю, что он отлично работает. Я не уверен в лицензировании этого класса, но вы, очевидно, можете взглянуть на него и выделить то, что работает для вас, как я делал ранее.

https://gist.github.com/2468935#file_content_aware_image.php

(И PS. В следующий раз предоставьте всю информацию прямо в ваших вопросах ...)

person Layke    schedule 20.11.2012
comment
Супер полезный пост. Спасибо! - person Josh Stuart; 26.02.2013

Не знаю, если это то, что вы хотите, из моей личной библиотеки сценариев xD: вам нужно только указать желаемый $ maxW $ maxH и то же самое для миниатюр, и это пропорционально уменьшит изображение.

Скрипт состоит из двух частей, которые почти одинаковы: одна для эскизов, а вторая - для самого изображения.

list($w, $h) = getimagesize($file);
$maxW = 1024;
$maxH = 786;
$thumbMaxW = 138;
$thumbMaxH = 92;

$newW = $w;
$newH = $h;

if($w > $thumbMaxW OR $h > $thumbMaxH){
    if($w>=$h){
        $thumbW = $thumbMaxW;
        $thumbRatio = $w/$thumbMaxW;
        $thumbH = (int)($h/$thumbRatio);
    } else {
        $thumbH = $thumbMaxH;
        $thumbRatio = $h/$thumbMaxH;
        $thumbW = (int)($w/$thumbRatio);
    }
} else {
    $thumbW = $w;
    $thumbH = $h;
}
--------------------------------------------

if($w > $maxW OR $h > $maxH){
    if($w >= $h){
        $newW = $maxW;
        $reduction = $w/$newW;
        $newH = (int)   ($h/$reduction);
    }

    if($h > $w){
        $newH = $maxH;
        $reduction = $h/$newH;
        $newW = (int)($w/$reduction);
    }
} else {
    $newW = $w;
    $newH = $h;
}
person aleation    schedule 20.11.2012
comment
И мне бы очень хотелось увидеть конструктивный комментарий от человека, проголосовавшего за меня, в основном для того, чтобы не допустить такой же ошибки в будущем. - person aleation; 20.11.2012