Статьи

Изменение размера и манипулирование изображениями в PHP (с примерами)

В моем предыдущем уроке мы обсуждали основные манипуляции с изображениями с использованием библиотеки PHP GD . В этом уроке я дал краткое введение в библиотеку и показал вам, как загружать изображения из файла или создавать их с нуля в PHP. После этого мы научились обрезать, вращать, масштабировать и переворачивать изображение с помощью GD. Я рассмотрел imagefilter() для применения различных фильтров к ресурсам изображений, загруженным в скрипт. Я также упомянул некоторые полезные функции в GD, такие как imagesx() и imagesy() чтобы получить ширину и высоту загруженного изображения.

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

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

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

Простой способ указать этот тип фильтра — с помощью так называемой «матрицы свертки». GD предоставляет imageconvolution( $image, $matrix, $div, $offset) для применения матрицы свертки 3×3 к ресурсу $image .

Параметр $matrix — это массив из трех массивов, каждый из которых содержит три значения с плавающей запятой, т. Е. Это матрица 3×3. Первый элемент первого массива умножается на значение цвета левого верхнего пикселя. Точно так же второй элемент первого массива умножается на значение цвета пикселя непосредственно поверх центрального пикселя. Окончательный цвет пикселя получается путем сложения результата всех этих умножений, а затем деления его на $div для нормализации. Обычно нормализация сохраняет окончательное значение цвета ниже 255.

Как мы уже видели, параметр $div используется в качестве делителя для результата свертки для нормализации его значения. Параметр $offset , с другой стороны, используется для указания значения смещения для всех цветов. Вы увидите, как это влияет на конечный результат в примерах ниже.

Вот список некоторых различных матриц свертки, которые мы применили к изображению чашки на столе.

1
2
$box_blur = array([1, 1, 1], [1, 1, 1], [1, 1, 1]);
imageconvolution($im_php, $box_blur, 9, 0);

Размытие рамки работает путем усреднения каждого пикселя с соседями. Мы устанавливаем значение делителя в 9, потому что сумма всех элементов в трех массивах равна 9.

1
2
$sharpen = array([0, -1, 0], [-1, 5, -1], [0, -1, 0]);
imageconvolution($im_php, $sharpen, 1, 0);

Резкость работает, преувеличивая различия между каждым пикселем и его соседями. Это делает края немного более четкими. В случае повышения резкости делитель по-прежнему равен 1, поскольку сумма всех элементов в трех массивах равна 1.

1
2
$emboss = array([-2, -1, 0], [-1, 1, 1], [0, 1, 2]);
imageconvolution($im_php, $emboss, 1, 0);

Матрица тиснения аналогична матрице резкости, за исключением того, что значения отрицательны в верхнем левом углу и положительны в нижнем правом — вот что создает эффект тиснения. Сумма всех элементов в случае матрицы рельефа тиснения равна 1, поэтому нам не нужно беспокоиться о нормализации или смещении цвета.

1
2
3
$edge_detect = array([-1, -1, -1], [-1, 8, -1], [-1, -1, -1]);
imageconvolution($im_php, $edge_detect, 1, 0);
imageconvolution($im_php, $edge_detect, 1, 255);

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

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

На следующем изображении показан результат всех этих матриц свертки.

Сверточная матрица

PHP GD имеет множество функций для копирования части изображения, а затем изменения его размера или объединения. При использовании этих функций важно помнить, что PHP считает верхний левый угол ресурса изображения своим источником. Положительное значение x приведет вас вправо к изображению, а положительное значение y приведет вас еще ниже.

Простейшей из этих функций является imagecopy( $dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h) . Это скопирует исходное изображение на конечное изображение. Параметры $dst_x и $dst_y определяют верхний левый угол, куда будет вставлено скопированное изображение. Параметры $src_x , $src_y , $src_w и $src_h определяют прямоугольную часть исходного изображения, которая будет скопирована в место назначения.

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

Одним из решений этой проблемы является использование функции imagecopyresized( $dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) . Он принимает все параметры imagecopy() и два дополнительных параметра для определения размера области назначения, куда будет скопировано исходное изображение.

Функция imagecopyresized() не идеальна, так как не очень хорошо масштабирует изображение вверх и вниз. Однако вы можете добиться лучшего качества изменения размера с помощью функции imagecopyresampled() , которая принимает все те же параметры.

Есть еще две функции, связанные с копированием изображений, которые вы найдете очень полезными: imagecopymerge() и imagecopymergegray() .

Функция imagecopymerge( $dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $pct) аналогична imagecopy() , где дополнительный параметр $pct определяет прозрачность скопированного образ. Значение 0 означает отсутствие прозрачности, а значение 100 означает полную прозрачность. Это будет очень полезно, если вы не хотите полностью скрывать содержание основного изображения за водяным знаком.

Функция imagecopymergegray() , с другой стороны, использует последний параметр для преобразования исходного изображения в градации серого. Если установлено значение 0, исходное изображение потеряет весь свой цвет. Если установлено значение 100, исходное изображение останется неизменным.

В следующем примере imagecopy() используется для превращения правой половины изображения в ее негатив. Мы уже обсуждали другие функции, такие как imagefilter() и imagescale() используемые в этом фрагменте кода в предыдущем уроке .

01
02
03
04
05
06
07
08
09
10
11
12
$im_php = imagecreatefromjpeg(‘fish-mosaic.jpg’);
$im_php = imagescale($im_php, 800);
$im_php_inv = imagescale($im_php, 800);
 
$im_width = imagesx($im_php);
$im_height = imagesy($im_php);
 
imagefilter($im_php_inv, IMG_FILTER_NEGATE);
imagecopy($im_php, $im_php_inv, $im_width/2, 0, $im_width/2, 0, $im_width/2, $im_height);
 
$new_name = ‘fish-mosaic-half-negate.jpg’;
imagejpeg($im_php, $new_name);

Здесь мы создаем две копии исходного изображения, каждое из которых было уменьшено до ширины 800 пикселей. После этого мы используем imagefilter() для создания негатива $img_php_inv изображения $img_php_inv . Правая половина этого негативного изображения затем копируется в исходное изображение с помощью функции imagecopy() .

Это было очень простое использование функции imagecopy() . Вы можете увидеть результаты ниже. Вы также можете разделить изображение на более мелкие участки или полосы, чтобы создать более интересные эффекты изображения. Мы будем использовать imagecopymergegray() в фрагменте кода ниже, чтобы создать намного больше полос в исходном изображении рыбы.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
$im_php = imagecreatefromjpeg(‘fish-mosaic.jpg’);
$im_php = imagescale($im_php, 800);
$im_php_bw = imagescale($im_php, 800);
 
$im_width = imagesx($im_php);
$im_height = imagesy($im_php);
 
$stripes = 200;
for($i = 0; $i < $stripes; $i++) {
    if($i%2 == 0) {
        imagecopymergegray($im_php, $im_php_bw, $i*$im_width/$stripes, 0, $i*$im_width/$stripes, 0, $im_width/$stripes, $im_height, 0);
    } else {
        imagecopymergegray($im_php, $im_php_bw, $i*$im_width/$stripes, 0, $i*$im_width/$stripes, 0, $im_width/$stripes, $im_height, 100);
    }
}
 
imagefilter($im_php, IMG_FILTER_CONTRAST, -255);
imagefilter($im_php, IMG_FILTER_COLORIZE, 250, 0, 0, 100);
 
$new_name = ‘fish-mosaic-stripes.jpg’;
imagejpeg($im_php, $new_name);

В приведенном выше примере кода используется стратегия, аналогичная предыдущему, но на этот раз мы разделили изображение на более мелкие полосы, которые превращаются в оттенки серого или остаются неизменными на основе значения переменной $i . После завершения всех операций слияния копий мы применяем два фильтра к изображению, чтобы выделить полосы.

На следующем рисунке показан конечный результат этих двух функций в сочетании с различными фильтрами изображений.

PHP GD Fish Mosaic

Некоторые организации добавляют водяные знаки на свои изображения, чтобы прояснить, что они владеют изображением. Это также помогает в узнаваемости бренда и не дает другим людям откровенно копировать изображения. Благодаря PHP GD создание водяных знаков для изображений является простой задачей.

01
02
03
04
05
06
07
08
09
10
11
12
13
$im_php = imagecreatefromjpeg(‘waterfall.jpg’);
$watermark = imagecreatefrompng(‘watermark.png’);
$im_width = imagesx($im_php);
$im_height = imagesy($im_php);
 
$watermark = imagescale($watermark, $im_width/5);
$wt_width = imagesx($watermark);
$wt_height = imagesy($watermark);
 
imagecopy($im_php, $watermark, 0.95*$im_width — $wt_width, 0.95*$im_height — $wt_height, 0, 0, $wt_width, $wt_height);
 
$new_name = ‘waterfall-watermark.jpg’;
imagejpeg($im_php, $new_name);

В приведенном выше фрагменте кода мы создали два разных ресурса изображения, используя imagecreatefromjpeg() для основного изображения и imagecreatefrompng() для водяного знака соответственно. Мы определяем ширину и высоту основного изображения с помощью imagesx() и imagesy() .

Не все изображения, которые вы хотите сделать водяным знаком, будут иметь одинаковые размеры. Если вы не измените размер водяного знака в зависимости от размеров основного изображения, это может выглядеть странно. Например, водяной знак размером 200 пикселей может хорошо выглядеть на изображении размером 1000 пикселей, но он будет слишком большим для изображения шириной 600 пикселей и может выглядеть слишком маленьким на изображении шириной 2400 пикселей.

Поэтому мы используем imagescale() чтобы всегда поддерживать водяной знак на одной пятой ширины исходного изображения. Затем мы используем imagecopy() чтобы разместить водяной знак в нужном месте. Вот окончательный результат приведенного выше фрагмента кода.

Добавить водяной знак к изображениям с помощью GD

Помимо водяных знаков, вы также можете добавить другую информацию, например, место, где была сделана фотография, или время, когда была сделана фотография.

Изучив основы работы с изображениями в нашем предыдущем уроке, мы узнали о нескольких других полезных функциях в библиотеке GD. В первой части урока обсуждалось, как мы можем манипулировать изображениями в PHP с использованием матрицы свертки. Я также показал несколько примеров работы матрицы свертки, чтобы помочь вам понять, как PHP достигает значений цвета разных пикселей.

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

Попробуйте использовать все эти функции для создания интересных эффектов изображения!