1. Головна
  2. Колонка автора
  3. Клас для роботи із зображеннями PHP

Клас для роботи із зображеннями PHP

У цій статті опишемо простий клас для роботи із зображеннями. Вже багато років особисто його використовую, і він цілком себе виправдовує. Завдяки обробці зображення стають придатними для використання на веб-ресурсах.
Клас для роботи із зображеннями PHP

Властивості об'єкту класу Image


Як відомо, об'єкт - це сукупність даних (властивостей) та функцій (методів) для їх обробки. Властивості та методи називаються членами класу. Створимо клас ImageResize та оголосимо всередині наступні змінні:
private $image;
private $width;
private $height;
private $type;
Специфікатор Private (закритий) забороняє доступ до атрибутів та методів класу за його межами. Атрибут об'єкта Image містить ресурс цільового зображення. В атрибуті Widht міститься ширина, Height відповідно висота вихідного зображення. Змінна Type зберігатиме тип зображення.

Створюємо конструктор класу


Далі ми ініціалізуємо об'єкт, створюючи конструктор – спеціальний метод класу, який виконується під час створення об'єкта.
function __construct($file) {
$this->setType($file);
$this->openImage($file);
$this->setSize();
}
Перевірка існування та типу зображення має відбуватися ще до ініціалізації класу, тому при створенні конструктора ми повинні бути точно впевнені, що файл існує і являє собою зображення.

У конструкторі ми визначаємо тип файлу зображення:
$this->setType($file);
Створюємо нове зображення:
$this->openImage($file);
Остання операція є визначення висоти та ширини зображення:
$this->setSize();

Визначаємо тип вихідного зображення



Опишемо приватну функцію, яка записує в поле Type тип вихідного зображення:
private function setType($file) {
$pic = getimagesize($file);
switch($pic['mime']) {
case 'image/jpeg': $this->type = 'jpg'; break;
case 'image/png': $this->type = 'png'; break;
case 'image/gif': $this->type = 'gif'; break;
}
}

Функція створення нового зображення



Опишемо приватну функцію, яка створює нове зображення в залежності від типу зображення.
private function openImage($file) {
switch($this->type) {
case 'jpg': $this->image = @imagecreatefromJpeg($file); break;
case 'png': $this->image = @imagecreatefromPng($file); break;
case 'gif': $this->image = @imagecreatefromGif($file); break;
}
}
У параметрі $file ми як і в функції setType передаємо шлях до вихідного файлу.

Функція визначення розмірів вихідного зображення


Опишемо приватну функцію, яка записує розміри вихідного зображення:
private function setSize() {
$this->width = imageSX($this->image);
$this->height = imageSY($this->image);
}
Ця функція визначає розмір зображення залежно від створеного нового зображення функції OpenImage.

Функція зміни атрибутів зображення в залежності від параметрів


Створюємо функцію Resize, яка приймає параметри ширини та висоти зображення. Обидва параметри необов'язкові. Якщо в аргументах функції передані ширина і висота, зображення стиснеться в рамки. Якщо передано лише один параметр, зображення стискається по ширині. Якщо без параметра, зміна параметрів зображення не відбувається.
function resize($width = false, $height = false) {
if (is_numeric($width) && is_numeric($height) && $width > 0 && $height > 0) {
$newSize = $this->getSizeByFramework($width, $height);
} elseif (is_numeric($width) && $width > 0) {
$newSize = $this->getSizeByWidth($width);
} else {
$newSize = array($this->width, $this->height);
}
$newImage = imagecreatetruecolor($newSize[0], $newSize[1]);
if ($this->type == 'gif' || $this->type == 'png') {
$white = imagecolorallocate($newImage, 255, 255, 255);
imagefill($newImage, 0, 0, $white);
}
imagecopyresampled($newImage, $this->image, 0, 0, 0, 0, $newSize[0], $newSize[1], $this->width, $this->height);
$this->image = $newImage;
$this->setSize();
return $this;
}
Опишемо цю функцію докладніше. Спочатку йде перевірка на існування введеної ширини та висоти зображення:
if (is_numeric($width) && is_numeric($height) && $width > 0 && $height > 0) {
$newSize = $this->getSizeByFramework($width, $height);
}
Якщо виконання даної умови є істинним, тобто існує введене значення ширини і висоти, вони числові і більші за нуль, тоді передаємо управління функцією getSizeByFramework, яка визначає розміри нового зображення при вписуванні його в рамки.

Якщо вказана лише ширина зображення, тоді передаємо керування приватною функцією getSizeByWidth:
} elseif (is_numeric($width) && $width > 0) {
$newSize = $this->getSizeByWidth($width);
}
Якщо жодна з умов не спрацює, тоді повертаємо вихідну ширину та висоту:
} else {
$newSize = array($this->width, $this->height);
}
Далі в цій функції йде операція створення порожнього повнокольорового зображення з явно вказаною шириною та висотою за допомогою функції Imagecreatetruecolor:
$newImage = imagecreatetruecolor($newSize[0], $newSize[1]);
Далі створюємо білий фон для прозорих зображень:
if ($this->type == 'gif' || $this->type == 'png') {
$white = imagecolorallocate($newImage, 255, 255, 255);
imagefill($newImage, 0, 0, $white);
}
Далі відбувається копіювання та зміна розміру зображення з ресемплюванням за допомогою функції Imagecopyresampled:
imagecopyresampled($newImage, $this->image, 0, 0, 0, 0, $newSize[0], $newSize[1], $this->width, $this->height);
І останнє, що робить функція Resize - це повертає значення нового зображення, а також нові параметри висоти і ширини:
$this->image = $newImage;
$this->setSize();
return $this;
Далі розберемо окремо кожну функцію зміни розмірів зображення.

Функція визначення розмірів нового зображення та вписування його в рамки



Функції GetSizeByFramework визначає розміри нового зображення при вписуванні його в рамки:
private function getSizeByFramework($width, $height) {
if ($this->width <= $width && $this->height <= $height) {
return array($this->width, $this->height);
}
if ($this->width / $width > $this->height / $height) {
$newSize[0] = $width;
$newSize[1] = round($this->height * $width / $this->width);
} else {
$newSize[0] = round($this->width * $height / $this->height);
$newSize[1] = $height;
}
return $newSize;
}
У першій умові перевіряємо, якщо вихідна ширина менша або дорівнює введеній користувачем ширини, і відповідно така ситуація і з висотою, тоді просто повертаємо вихідну ширину та висоту:
if ($this->width <= $width && $this->height <= $height) {
return array($this->width, $this->height);
}
Далі йдуть такі умови:
if ($this->width / $width > $this->height / $height) {
$newSize[0] = $width;
$newSize[1] = round($this->height * $width / $this->width);
}
Якщо вихідна ширина розділена на ведену користувачем ширину більша відповідно до таких же умов висоти, значить ширина залишається незмінною, а висота дорівнюватиме округленому числу вихідної висоти помноженої на ширину, яка ділиться на вихідну ширину.

Якщо ж навпаки, тоді обчислюємо ширину, а висота залишається такою ж:
} else {
$newSize[0] = round($this->width * $height / $this->height);
$newSize[1] = $height;
}
Навіщо це все робиться запитаєте Ви? Я спочатку теж задумався над цим. А все дуже просто. Зміна розмірів завжди відбуватиметься з одного боку. Тобто, якщо висота, припустимо, 200 пікселів, а ширина 500, відповідно зображення ділиться по меншій стороні, у нашому випадку за висотою 200 пікселів. Зараз потрібно зрозуміти, що обрізка зображення завжди відбуватиметься з одного боку. Це робиться для збереження пропорції зображення.

Функція повертає масив, який містить розміри нового зображення.
return $newSize;

Також напишу, що якщо Вам, припустимо, на сайті потрібно обрізати фотографію в квадрат, це не обов'язково потрібно робити скриптом, можна скористатися каскадними таблицями стилів CSS.

Для того, щоб більше зрозуміти обчислення ширини та висоти, подивимося на картинку:
Клас для роботи із зображеннями PHP
Тут вихідне зображення має атрибути 300 пікселів ширини та 250 висоти. Друге зображення, яке буде як результат роботи даного скрипта, буде з атрибутами 200 пікселів ширина та 100 висота. Оскільки обрізання зображення відбуватиметься по меншій стороні, нам потрібно дізнатися про довжину другої сторони. Ще зі школи пам'ятаю, якщо X1 зіставляється значення Y1, а невідомому X2 - Y2, то невідомо X2 = X1 * Y2 / Y1.

Саме це завдання лежить на плечах функції GetSizeByFramework, визначення ширини і висоти зображення. Функція повертає масив, який містить розміри нового зображення.

Функція змін розміру зображення за шириною



Якщо вказано лише ширину зображення, тоді передаємо управління приватною функцією GetSizeByWidth. Опишемо цю функцію:
private function getSizeByWidth($width) {
if ($width >= $this->width) {
return array($this->width, $this->height);
}
$newSize[0] = $width;
$newSize[1] = round($this->height * $width / $this->width);
return $newSize;
}
Якщо Ви уважно читали про функцію GetSizeByFramework, тоді відразу зрозумієте роботу цієї функції. Спочатку перевіряємо, чи не перевищує розмір ширини введеної користувачем розмір вихідної ширини, якщо перевищує, повертаємо вихідну ширину. Далі просто обчислюємо висоту зображення.

Наступна функція виконує обрізку з координатами, шириною та висотою:
function crop($x0 = 0, $y0 = 0, $w = false, $h = false) {
if (!is_numeric($x0) || $x0 < 0 || $x0 >= $this->width) $x0 = 0;
if (!is_numeric($y0) || $y0 < 0 || $y0 >= $this->height) $y0 = 0;
if (!is_numeric($w) || $w <= 0 || $w > $this->width - $x0) $w = $this->width - $x0;
if (!is_numeric($h) || $h <= 0 || $h > $this->height - $y0) $h = $this->height - $y0;
return $this->cropSave($x0, $y0, $w, $h);
}

Функція додавання водяного знаку:


Далі слідує функція додавання водяного знака. Обов'язково має існувати саме зображення водяного знака, яке називатиметься watermark.png.
function watermark() {
$stamp = imagecreatefromPng('watermark.png');
$marge_right = 4;
$marge_bottom = 5;
$sx = imageSX($stamp);
$sy = imageSY($stamp);
imagealphablending($stamp, true);
imagealphablending($this->image, true);
imagecopy($this->image, $stamp, $this->width - $sx - $marge_right, $this->height - $sy - $marge_bottom, 0, 0, $sx, $sy);
return $this;
}

Функція зберігання обрізаного зображення:
private function cropSave($x0, $y0, $w, $h) {
$newImage = imagecreatetruecolor($w, $h);
imagecopyresampled($newImage, $this->image, 0, 0, $x0, $y0, $w, $h, $w, $h);
$this->image = $newImage;
$this->setSize();
return $this;
}

Іноді буває необхідно вивести зображення на екран, але не зберігаючи його. Для цього існує така функція:
function save_base64() {
ob_start();
imagejpeg($this->image);
$outputBuffer = ob_get_clean();
$base64 = 'data:image/'.$this->type.';base64,'.base64_encode($outputBuffer);
imagedestroy($this->image);
return $base64;
}

Функція збереження зображення


Далі слідує найважливіша функція, без якої все раніше описане просто не має сенсу. Це функція збереження результату:
function save($path, $fileName, $type = false, $quality = 100) {
if (trim($fileName) == '' || $this->image === false || !is_dir($path)) return false;
$type = strtolower($type);
switch($type) {
case false:
$savePath = $path.trim($fileName).'.'.$this->type;
switch($this->type) {
case 'jpg':
if (!is_numeric($quality) || $quality < 0 || $quality > 100) $quality = 100;
imagejpeg($this->image, $savePath, $quality);
return $savePath;
case 'png':
imagepng($this->image, $savePath);
return $savePath;
case 'gif':
imagegif($this->image, $savePath);
return $savePath;
default:
return false;
}
break;
case 'jpg':
$savePath = $path.trim($fileName).'.'.$type;
if (!is_numeric($quality) || $quality < 0 || $quality > 100) $quality = 100;
imagejpeg($this->image, $savePath, $quality);
return $savePath;
case 'png':
$savePath = $path.trim($fileName).'.'.$type;
imagepng($this->image, $savePath);
return $savePath;
case 'gif':
$savePath = $path.trim($fileName).".".$type;
imagegif($this->image, $savePath);
return $savePath;
default:
return false;
}
imagedestroy($this->image);
}
Опишемо аргументи цієї функції:

$Path - шлях до папки збереження;

$FileName – ім'я нового зображення;

$Type – тип зображення;

$Quality - якість зображення.

Якщо цей аргумент $Type має значення False, розширення зображення залишиться незмінним. Якщо цей аргумент явно вказаний (jpg, png, gif), тоді вихідне зображення зберігається саме у цьому форматі.

Сміливо можу вас запевнити, що 70 відсотків якості дуже хороший результат для веб-сторінок, як за якістю картинки, так і за розміром.

Приклади роботи класу ImageResize



Ну ось і добіг кінця клас для роботи з зображеннями.

Тепер залишилося навести найбільш уживані прийоми використання та управління класом.

Допустимо, ми маємо зображення Desert.jpg в корені сайту.

Щоб отримати зменшену копію зображення, необхідно скористатися таким виразом:
$img = new ImageResize($_SERVER['DOCUMENT_ROOT'].'/Desert.jpg');
$img->resize(200)->save($_SERVER['DOCUMENT_ROOT'].'/', 'images', false, 70);
Тепер у корені сайту буде створено зображення, з максимальною шириною 200 пікселів та якістю 70, назва якого Images. Розширення зображення буде JPG, оскільки атрибут типу вказаний False.

Трохи змінимо цей вираз:
$img->resize(200, 100)->save( $_SERVER['DOCUMENT_ROOT'].'/', 'images', 'PNG', 70);
Тепер створиться нове зображення у форматі PNG, з максимальною зі сторін 200 та 100 пікселів відповідно.

Щоб вивести зображення на екран, достатньо скористатися таким виразом:
$preview_thumbs = $img->resize(100)->crop(0, 0, 100, 100)->save_base64();
echo '<img src="'.$preview_thumbs.'" />';
Ось і все, тепер Ви зможете обрізати до потрібного розміру будь-які зображення. Скрипт написаний для роботи з веб-сайтами, а тут особливу увагу потрібно приділити оптимізації зображень. Добре, якщо їх кілька, а якщо сотні, а тисячі? Тоді потрібно дбати про розмір файлів. Завдяки цьому скрипту Ви можете бути впевнені у оптимізації Ваших зображень на сайті.
Редакція «КовельPost» може не поділяти думку блогерів або дописувачів. За зміст публікацій і їх достовірність відповідальність несуть автори.

Коментарі

Підписуйтесь на наш канал у Telegram! 🚀

@kovelpost