PHP: полный мануал с примерами, функциями и ООП
Практический мануал PHP: от переменных и читаемого кода до безопасных форм, интеграций, базы данных и ООП на примере магазина. Учебный маршрут, поиск функций, подробные примеры, разбор ошибок и исходники для скачивания.

Дерево руководства
Глава 408 · После первых изображений Gmagick
Gmagick: вырезка, однотонные поля и исправление отражений
Выбрать область, убрать ровное поле, различить flip и flop; собрать проверяемое исправление скана.
Вырезать деталь товара по координатам
Продолжаем первые изображения Gmagick: используем собственный product.ppm размером 320×200. В коротких фрагментах этот файл уже лежит рядом с программой; архив полного примера сам восстанавливает его из .ppm.b64. PPM — простой формат пикселей, PNG — формат сохраняемых результатов. Чужие фотографии и сетевые загрузки здесь не нужны.
На странице товара нужна увеличенная деталь упаковки, а не весь снимок. Представьте окно, приложенное к фотографии: его левый верхний угол стоит в точке (80,40), ширина 160, высота 120. Снаружи остаются ненужные полосы. Модель окна объясняет выбор области, но сам результат — отдельный меньший растр, а не прозрачное окошко в старом изображении.


<?php
$image = new Gmagick(__DIR__ . '/product.ppm');
$image->cropImage(160, 120, 80, 40);
$image->setImageFormat('PNG');
$image->writeImage(__DIR__ . '/detail.png');$image — переменная с объектом изображения. new Gmagick(...) читает собственный файл; __DIR__ обозначает папку программы, точка соединяет строки пути. Стрелка -> вызывает метод этого объекта. В скобках cropImage сначала идут ширина и высота, затем x и y; запятые разделяют четыре числа. Точка с запятой завершает команду. PNG задаёт формат содержимого, writeImage сохраняет файл. Выход 160×120 состоит из прежних пикселей выбранной области: масштабирования здесь нет.
<?php
declare(strict_types=1);
require __DIR__ . '/gm-fixture.php';
gmRestore();
$image = new Gmagick(__DIR__.'/product.ppm');
$image->setImageFormat('PNG');
$image->setImageDepth(8);
$image->writeImage(__DIR__.'/gm97-source.png');
$result = $image->cropImage(160,120,80,40);
$image->setImageFormat('PNG');
$image->setImageDepth(8);
$image->writeImage(__DIR__.'/gm97-detail.png');
gmReport('gm97-crop-detail',["__construct", "setimageformat", "setimagedepth", "writeimage", "cropimage"],["gm97-source.png", "gm97-detail.png"],
['same_object'=>$result===$image,'geometry_source'=>gmInspect('gm97-source.png')['width']===320&&gmInspect('gm97-source.png')['height']===200,'geometry_detail'=>gmInspect('gm97-detail.png')['width']===160&&gmInspect('gm97-detail.png')['height']===120],
$errors ?? [], []);
echo "gm97-source.png 320x200 gm97-detail.png 160x120\n";
Ожидаемый результат
gm97-source.png 320x200 gm97-detail.png 160x120
Скачайте все файлы примера в одну папку. php example.php восстановит собственные PPM из .b64, сохранит PNG и metrics.json. Восстановление и проверки вынесены в неизменённый gm-fixture.php; преобразования видны непосредственно в example.php. Требуется расширение Gmagick. Проверенный стенд: PHP 8.3.6 / Gmagick 2.0.6RC1 / GraphicsMagick 1.3.42 Q16.
Вывод успешного запуска
gm97-source.png 320x200 gm97-detail.png 160x120
Полная программа сначала сохраняет исходник, затем вырезку. На входе 320×200 допустимые индексы идут от 0 до 319 и от 0 до 199. Для гарантии точного размера нужна проверка границ; ниже создадим её в функции. Если задача — вписать всю фотографию, используйте scaleImage или уже изученное превью; cropImage безвозвратно отбрасывает внешние пиксели в этой копии.
Основа синтаксиса: переменные, объекты и вызов метода, исключения. Эти программы требуют расширения Gmagick для GraphicsMagick; наличие Imagick не заменяет его. Установка и различие CLI/веб-окружения разобраны в первой главе маршрута.
Убрать ровное поле вокруг изображения
Поставщик прислал карточку с одинаковым белым полем. Координаты поля могут меняться от файла к файлу; вручную считать их для каждой карточки неудобно. Здесь программа сначала делает собственное белое поле известной толщины, чтобы результат автоматического удаления можно было проверить. Начинаем с точного совпадения цвета без допуска.


<?php
$image = new Gmagick(__DIR__ . '/product.ppm');
$image->borderImage('#ffffff', 12, 8);
$image->trimImage(0.0);
$image->setImageFormat('PNG');
$image->writeImage(__DIR__ . '/without-padding.png');borderImage — подготовка учебного входа: #ffffff означает белый, 12 добавляет по 12 пикселей слева и справа, 8 — сверху и снизу. Затем trimImage(0.0) удаляет внешнее однотонное поле; 0.0 — дробное число допуска, требующее точного совпадения. Вход с полем 344×216 возвращается к 320×200. При обработке полученного файла строка добавления учебной рамки не нужна: чтение → trim → сохранение.
<?php
declare(strict_types=1);
require __DIR__ . '/gm-fixture.php';
gmRestore();
$image = new Gmagick(__DIR__.'/product.ppm');
$image->borderImage('#ffffff',12,8);
$image->setImageFormat('PNG');
$image->setImageDepth(8);
$image->writeImage(__DIR__.'/gm97-padded.png');
$result = $image->trimImage(0.0);
$image->setImageFormat('PNG');
$image->setImageDepth(8);
$image->writeImage(__DIR__.'/gm97-trimmed.png');
gmReport('gm97-trim-padding',["__construct", "borderimage", "setimageformat", "setimagedepth", "writeimage", "trimimage"],["gm97-padded.png", "gm97-trimmed.png"],
['same_object'=>$result===$image,'geometry_padded'=>gmInspect('gm97-padded.png')['width']===344&&gmInspect('gm97-padded.png')['height']===216,'geometry_trimmed'=>gmInspect('gm97-trimmed.png')['width']===320&&gmInspect('gm97-trimmed.png')['height']===200],
$errors ?? [], []);
echo "gm97-padded.png 344x216 gm97-trimmed.png 320x200\n";
Ожидаемый результат
gm97-padded.png 344x216 gm97-trimmed.png 320x200
Скачайте все файлы примера в одну папку. php example.php восстановит собственные PPM из .b64, сохранит PNG и metrics.json. Восстановление и проверки вынесены в неизменённый gm-fixture.php; преобразования видны непосредственно в example.php. Требуется расширение Gmagick. Проверенный стенд: PHP 8.3.6 / Gmagick 2.0.6RC1 / GraphicsMagick 1.3.42 Q16.
Вывод успешного запуска
gm97-padded.png 344x216 gm97-trimmed.png 320x200
Тонкая JPEG-рябь может мешать точному сравнению, а слишком большой fuzz удалит полезные похожие оттенки. Это не процентный параметр: диапазон зависит от QuantumDepth библиотеки. Для фотографии на сложном фоне автоматическое удаление поля не равнозначно выделению предмета; разумнее сохранить исходник и выбрать явную область после просмотра.
Перевернуть верх и низ, сохранив левую сторону
Верх скана оказался внизу. Чтобы различие было видно, берём верхние 160 строк собственного рисунка: центральный блок больше не симметричен по вертикали. После исправления низ и верх меняются местами, красная полоса остаётся слева. Подписи и цветовые ориентиры позволяют проверить смысл действия, а не только размеры.


<?php
$image = new Gmagick(__DIR__ . '/product.ppm');
$image->cropImage(320, 160, 0, 0);
$image->flipImage();
$image->setImageFormat('PNG');
$image->writeImage(__DIR__ . '/flipped.png');Первые два нуля в конце cropImage задают начало в левом верхнем углу. flipImage() вызывается с пустыми скобками: параметров у него нет. Он отражает строки относительно горизонтальной середины. В частности, строка 0 переходит в 159, строка 159 в 0; ширина 320 и высота 160 сохраняются. Подготовительная обрезка нужна только для нашего наглядного несимметричного тестового входа.
<?php
declare(strict_types=1);
require __DIR__ . '/gm-fixture.php';
gmRestore();
$image = new Gmagick(__DIR__.'/product.ppm');
$image->cropImage(320,160,0,0);
$image->setImageFormat('PNG');
$image->setImageDepth(8);
$image->writeImage(__DIR__.'/gm97-flip-before.png');
$result = $image->flipImage();
$image->setImageFormat('PNG');
$image->setImageDepth(8);
$image->writeImage(__DIR__.'/gm97-flipped.png');
gmReport('gm97-flip-scan',["__construct", "cropimage", "setimageformat", "setimagedepth", "writeimage", "flipimage"],["gm97-flip-before.png", "gm97-flipped.png"],
['same_object'=>$result===$image,'geometry_flip_before'=>gmInspect('gm97-flip-before.png')['width']===320&&gmInspect('gm97-flip-before.png')['height']===160,'geometry_flipped'=>gmInspect('gm97-flipped.png')['width']===320&&gmInspect('gm97-flipped.png')['height']===160],
$errors ?? [], []);
echo "gm97-flip-before.png 320x160 gm97-flipped.png 320x160\n";
Ожидаемый результат
gm97-flip-before.png 320x160 gm97-flipped.png 320x160
Скачайте все файлы примера в одну папку. php example.php восстановит собственные PPM из .b64, сохранит PNG и metrics.json. Восстановление и проверки вынесены в неизменённый gm-fixture.php; преобразования видны непосредственно в example.php. Требуется расширение Gmagick. Проверенный стенд: PHP 8.3.6 / Gmagick 2.0.6RC1 / GraphicsMagick 1.3.42 Q16.
Вывод успешного запуска
gm97-flip-before.png 320x160 gm97-flipped.png 320x160
Не выбирайте flip только потому, что фотография «лежит неправильно»: поворот на 90°, отражение и метаданные ориентации — разные вещи. На вертикально симметричном рисунке вызов исполнится, но глазом перемену можно не увидеть. Для известного дефекта сканера правило допустимо автоматизировать; для случайных загрузок сначала определяют требуемое преобразование.
Исправить зеркальное отражение слева направо
Сканер или камера дал зеркальный вид товара. Нужно поменять местами левую и правую стороны. На нашем образце это легко заметить: зелёная полоса окажется слева, красная справа. В отличие от предыдущего урока, верх и низ остаются на месте.


<?php
$image = new Gmagick(__DIR__ . '/product.ppm');
$image->flopImage();
$image->setImageFormat('PNG');
$image->writeImage(__DIR__ . '/mirrored.png');flopImage() — горизонтальное отражение относительно вертикальной середины; у метода нет аргументов. При ширине 320 столбец 0 переносится в 319. Не путайте названия: flip меняет верх и низ, flop меняет левую и правую стороны. Оба возвращают объект Gmagick и изменяют его; присваивание результата другой переменной само по себе не создаст независимой копии.
<?php
declare(strict_types=1);
require __DIR__ . '/gm-fixture.php';
gmRestore();
$image = new Gmagick(__DIR__.'/product.ppm');
$result = $image->flopImage();
$image->setImageFormat('PNG');
$image->setImageDepth(8);
$image->writeImage(__DIR__.'/gm97-flopped.png');
gmReport('gm97-flop-display',["__construct", "flopimage", "setimageformat", "setimagedepth", "writeimage"],["gm97-flopped.png"],
['same_object'=>$result===$image,'geometry_flopped'=>gmInspect('gm97-flopped.png')['width']===320&&gmInspect('gm97-flopped.png')['height']===200],
$errors ?? [], []);
echo "gm97-flopped.png 320x200\n";
Ожидаемый результат
gm97-flopped.png 320x200
Скачайте все файлы примера в одну папку. php example.php восстановит собственные PPM из .b64, сохранит PNG и metrics.json. Восстановление и проверки вынесены в неизменённый gm-fixture.php; преобразования видны непосредственно в example.php. Требуется расширение Gmagick. Проверенный стенд: PHP 8.3.6 / Gmagick 2.0.6RC1 / GraphicsMagick 1.3.42 Q16.
Вывод успешного запуска
gm97-flopped.png 320x200
Для сравнения двух вариантов используйте clone перед отражением. Отражать фотографию с логотипом ради композиции рискованно: надпись тоже станет зеркальной. Здесь мы показываем само преобразование; решение о допустимости отражения зависит от содержания конкретного каталога.
Нормализовать перевёрнутый скан и проверить область
Теперь требование растёт: одинаковый сканер добавляет белое поле и отражает обе оси. Каталогу нужна исправленная деталь строго 200×120. Мы знаем происхождение дефекта, поэтому собираем понятную последовательность: удалить поле, исправить оси, проверить координаты, вырезать область в отдельной копии.


<?php
$image = new Gmagick(__DIR__ . '/product.ppm');
$detail = clone $image;
$detail->cropImage(200, 120, 60, 10);
$detail->setImageFormat('PNG');
$detail->writeImage(__DIR__ . '/catalog-detail.png');clone создаёт независимый объект: исходный $image можно использовать для другой карточки. В полной программе функция cropCatalogArea получает объект и четыре целых числа. Условие if проверяет положительные стороны, неотрицательный угол и обе границы; || означает «хотя бы одно условие». throw прекращает неверный маршрут с InvalidArgumentException. return передаёт готовую копию обратно в выражение вызова; результат получает $detail.
<?php
declare(strict_types=1);
require __DIR__ . '/gm-fixture.php';
gmRestore();
$image = new Gmagick(__DIR__.'/product.ppm');
// Собственный тестовый скан: неполная высота, две отражённые оси и белое поле.
$image->cropImage(320,160,0,0);
$image->flipImage();
$image->flopImage();
$image->borderImage('#ffffff',8,8);
$image->setImageFormat('PNG');
$image->setImageDepth(8);
$image->writeImage(__DIR__.'/gm97-scan-before.png');
function cropCatalogArea(Gmagick $image,int $w,int $h,int $x,int $y): Gmagick {
if ($w<=0 || $h<=0 || $x<0 || $y<0 || $x+$w>$image->getImageWidth() || $y+$h>$image->getImageHeight()) {
throw new InvalidArgumentException('The complete crop must fit inside the image');
}
$result = clone $image;
$result->cropImage($w,$h,$x,$y);
return $result;
}
$image->trimImage(0.0);
$image->flipImage();
$image->flopImage();
$detail = cropCatalogArea($image,200,120,60,10);
$errors = ['outside'=>gmTry(fn()=>cropCatalogArea($image,200,120,250,10)),
'empty'=>gmTry(fn()=>(new Gmagick())->cropImage(20,20,0,0))];
$detail->setImageFormat('PNG');
$detail->setImageDepth(8);
$detail->writeImage(__DIR__.'/gm97-scan-detail.png');
gmReport('gm97-scan-workflow',["__construct", "cropimage", "flipimage", "flopimage", "borderimage", "setimageformat", "setimagedepth", "writeimage", "getimagewidth", "getimageheight", "trimimage"],["gm97-scan-before.png", "gm97-scan-detail.png"],
['original_after_correction'=>$image->getImageWidth()===320&&$image->getImageHeight()===160,'outside_rejected'=>$errors['outside']['class']==='InvalidArgumentException','empty_rejected'=>$errors['empty']['class']==='GmagickException','geometry_scan_before'=>gmInspect('gm97-scan-before.png')['width']===336&&gmInspect('gm97-scan-before.png')['height']===176,'geometry_scan_detail'=>gmInspect('gm97-scan-detail.png')['width']===200&&gmInspect('gm97-scan-detail.png')['height']===120],
$errors ?? [], []);
echo "gm97-scan-before.png 336x176 gm97-scan-detail.png 200x120\n";
Ожидаемый результат
gm97-scan-before.png 336x176 gm97-scan-detail.png 200x120
Скачайте все файлы примера в одну папку. php example.php восстановит собственные PPM из .b64, сохранит PNG и metrics.json. Восстановление и проверки вынесены в неизменённый gm-fixture.php; преобразования видны непосредственно в example.php. Требуется расширение Gmagick. Проверенный стенд: PHP 8.3.6 / Gmagick 2.0.6RC1 / GraphicsMagick 1.3.42 Q16.
Вывод успешного запуска
gm97-scan-before.png 336x176 gm97-scan-detail.png 200x120
Порядок существенен: координаты (60,10) относятся уже к растру после удаления поля и отражений. После trim вход имеет 320×160, область заканчивается на x=259 и y=129 и помещается внутри. Вторая попытка с x=250 отвергается нашей функцией; пустой Gmagick отдельно показывает ошибку библиотеки. Нельзя объявлять любое исключение «неверными координатами»: причиной также бывает отсутствие изображения.
Упражнение: какая область 80×60 помещается в правый нижний угол исходного 320×200? Ответ: cropImage(80,60,240,140). Упражнение: чем отличаются flip и flop? Ответ: первый меняет строки, второй столбцы. При двух отражениях важна точка, относительно которой после этого задаётся вырезка. Разбор функций и return: функции PHP.
Практический вопрос, из которого вырос сценарий
Cropping a variable width frame with graphicsmagick: Автор хочет убрать внешнее поле переменной толщины без ручного вычисления координат вырезки. В собственном сценарии отделяем известную прямоугольную вырезку от автоматического удаления однотонного края. Создаём белое поле, удаляем его с точным fuzz=0 и проверяем размеры. Прозрачность примера из вопроса не приписываем нашим непрозрачным PNG; шумный фон и выделение предмета требуют дополнительной политики.
Функции и методы этой темы
Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.
Gmagick::cropimageВыделить прямоугольную область
PECL gmagick >= Unknown · gmagick
Gmagick::cropimage(int $width, int $height, int $x, int $y): GmagickВыделить прямоугольную область. Метод оставляет указанную область текущего изображения. width и height задают размеры вырезки, x и y — её левый верхний угол, а не правый нижний. Начало координат находится слева сверху; x растёт вправо, y вниз. cropImage(160,120,80,40) сохраняет столбцы 80…239 и строки 40…159. Выход за край не гарантирует отказ: отдельный probe с 100×80 в точке (280,170) дал лишь 40×30. Поэтому функция урока требует, чтобы весь прямоугольник помещался внутри; это правило приложения, а не сужение возможностей метода.
Gmagick::cropimage(int $width, int $height, int $x, int $y): Gmagick| Параметр | Тип и обязательность | Значение |
|---|---|---|
width | int; обязательный | Ширина сохраняемого прямоугольника в пикселях. |
height | int; обязательный | Высота сохраняемого прямоугольника в пикселях. |
x | int; обязательный | X левого верхнего угла области. |
y | int; обязательный | Y левого верхнего угла области. |
Результат: Gmagick с результатом операции. Проверенные преобразования меняют текущий объект и возвращают его же; для независимого варианта сначала создайте clone.
Ошибка по официальному контракту: GmagickException. Ошибочный PHP-тип может дать TypeError до обработки изображения; при разборе некорректного цвета возможен GmagickPixelException. Не печатайте успешный результат после перехвата ошибки, если файл не получен. Требуется PECL Gmagick; PHP.net помечает нижнюю границу версии как Unknown, поэтому конкретную минимальную версию здесь не придумываем.
Два разных применения: Вырезать деталь товара по координатам; Нормализовать перевёрнутый скан и проверить область.
Связанный метод: Gmagick::trimimage.
Gmagick::flipimageПоменять верх и низ местами
PECL gmagick >= Unknown · gmagick
Gmagick::flipimage(): GmagickПоменять верх и низ местами. Аргументов нет. Отражение происходит относительно центральной горизонтальной оси X: верхняя строка становится нижней. Левая и правая стороны сохраняют положение. На симметричном входе результат может выглядеть прежним, поэтому учебный вход специально содержит только верхние 160 строк. Для строки y при высоте H соответствующая новая строка H−1−y. Геометрия не меняется. Это действие над пикселями; чтение EXIF Orientation и выбор нужного исправления остаются отдельной задачей.
Gmagick::flipimage(): GmagickПараметров нет: пустые скобки означают вызов без аргументов.
Результат: Gmagick с результатом операции. Проверенные преобразования меняют текущий объект и возвращают его же; для независимого варианта сначала создайте clone.
Ошибка по официальному контракту: GmagickException. Ошибочный PHP-тип может дать TypeError до обработки изображения; при разборе некорректного цвета возможен GmagickPixelException. Не печатайте успешный результат после перехвата ошибки, если файл не получен. Требуется PECL Gmagick; PHP.net помечает нижнюю границу версии как Unknown, поэтому конкретную минимальную версию здесь не придумываем.
Два разных применения: Перевернуть верх и низ, сохранив левую сторону; Нормализовать перевёрнутый скан и проверить область.
Связанный метод: Gmagick::flopimage.
Gmagick::flopimageПоменять левую и правую стороны
PECL gmagick >= Unknown · gmagick
Gmagick::flopimage(): GmagickПоменять левую и правую стороны. Аргументов нет. Отражение относительно центральной вертикальной оси Y переносит левую сторону вправо. Для столбца x при ширине W новое положение W−1−x. На образце красная полоса перемещается направо, зелёная налево; верх и низ не меняются. Отражение может сделать надпись нечитаемой, поэтому его применяют для конкретного известного дефекта входа, а не ко всем загружаемым фотографиям.
Gmagick::flopimage(): GmagickПараметров нет: пустые скобки означают вызов без аргументов.
Результат: Gmagick с результатом операции. Проверенные преобразования меняют текущий объект и возвращают его же; для независимого варианта сначала создайте clone.
Ошибка по официальному контракту: GmagickException. Ошибочный PHP-тип может дать TypeError до обработки изображения; при разборе некорректного цвета возможен GmagickPixelException. Не печатайте успешный результат после перехвата ошибки, если файл не получен. Требуется PECL Gmagick; PHP.net помечает нижнюю границу версии как Unknown, поэтому конкретную минимальную версию здесь не придумываем.
Два разных применения: Исправить зеркальное отражение слева направо; Нормализовать перевёрнутый скан и проверить область.
Связанный метод: Gmagick::flipimage.
Gmagick::trimimageУдалить однотонные внешние поля
PECL gmagick >= Unknown · gmagick
Gmagick::trimimage(float $fuzz): GmagickУдалить однотонные внешние поля. Метод удаляет края, считающиеся фоновыми. В отличие от cropImage здесь не задаются координаты. fuzz — допустимое различие цветов в единицах quantum range; 0.0 требует точного совпадения. Число 1.0 не означает один процент. В Q16 полный диапазон равен 65535; условный 1% диапазона — 655.35, но подходящий допуск выбирают по конкретному входу. Слишком большой допуск способен захватить детали объекта. На собственном ровном белом поле 344×216 получено 320×200. Настройка background color не заменяет анализ пикселей края; метод не распознаёт предметы, лица или контур документа.
Gmagick::trimimage(float $fuzz): Gmagick| Параметр | Тип и обязательность | Значение |
|---|---|---|
fuzz | float; обязательный | Допустимое различие цветов относительно quantum range; 0.0 — точное совпадение. |
Результат: Gmagick с результатом операции. Проверенные преобразования меняют текущий объект и возвращают его же; для независимого варианта сначала создайте clone.
Ошибка по официальному контракту: GmagickException. Ошибочный PHP-тип может дать TypeError до обработки изображения; при разборе некорректного цвета возможен GmagickPixelException. Не печатайте успешный результат после перехвата ошибки, если файл не получен. Требуется PECL Gmagick; PHP.net помечает нижнюю границу версии как Unknown, поэтому конкретную минимальную версию здесь не придумываем.
Два разных применения: Убрать ровное поле вокруг изображения; Нормализовать перевёрнутый скан и проверить область.
Связанный метод: Gmagick::cropimage.
Код и руководство с собой
Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.
Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.
Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.


