Перейти к содержимому
Поиск
Php Разработка

PHP: полный мануал с примерами, функциями и ООП

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

Александр НекрасовИзменено:
Практический мануал PHP: от переменных и функций к объектной модели интернет-магазина
PHP 8.5.11468 глав6256 карточек справочника
Дерево руководства

Глава 422 · После первых изображений Gmagick, массивов и объектов

Gmagick: пиксели, печатная плотность и чтение raw

Рассчитать физический размер, отличить метаданные от resample и декодировать собственный RGB16 с известной геометрией.

Разделить пиксели и плотность печати

Перед печатью сначала разделим три величины:320×200 пикселей,100 пикселей на единицу длины и физический размер.320÷100=3.2,200÷100=2. Если единица — дюйм, получаем 3.2×2 дюйма; если сантиметр —3.2×2 сантиметра. На экране обе картинки ниже выглядят одинаково: пиксели не пересчитывались.

320×200 пикселей при 100 px/in: расчётный отпечаток 3.2×2 дюйма
320×200 пикселей при 100 px/in: расчётный отпечаток 3.2×2 дюйма — 320 × 200 px.
Те же пиксели при 100 px/cm: расчётный отпечаток 3.2×2 сантиметра
Те же пиксели при 100 px/cm: расчётный отпечаток 3.2×2 сантиметра — 320 × 200 px.
<?php
$image = new Gmagick(__DIR__ . '/product.ppm');
$image->setImageUnits(Gmagick::RESOLUTION_PIXELSPERINCH);
$image->setImageResolution(100, 100);
$density = $image->getImageResolution();
echo $density['x'], ' px/in', "\n";

setImageUnits задаёт смысл чисел, setImageResolution — значения поX иY. Получается вывод «100 px/in». Для растра точнее говорить PPI, пиксели на дюйм; слово DPI часто используется интерфейсами, но точки принтера и пиксели файла не обязаны совпадать. Плотность — рекомендация для физического размещения, а не гарантия качества конкретного устройства. В полной программе проверяем также значение единиц.

Разделить пиксели и плотность печатиСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__ . '/gm-fixture.php';
gmRestore();
$source=new Gmagick(__DIR__.'/product.ppm');
$inch=clone $source;$inch->setImageUnits(Gmagick::RESOLUTION_PIXELSPERINCH);$inch->setImageResolution(100,100);
$cm=clone $source;$cm->setImageUnits(Gmagick::RESOLUTION_PIXELSPERCENTIMETER);$cm->setImageResolution(100,100);
$before=['inch'=>['units'=>$inch->getImageUnits(),'density'=>$inch->getImageResolution()],'cm'=>['units'=>$cm->getImageUnits(),'density'=>$cm->getImageResolution()]];
$inch->setImageDepth(8);
$inch->setImageFormat('PNG');
$inch->writeImage(__DIR__.'/gm99-density100-inch.png');
$cm->setImageDepth(8);
$cm->setImageFormat('PNG');
$cm->writeImage(__DIR__.'/gm99-density100-cm.png');
$a=new Gmagick(__DIR__.'/gm99-density100-inch.png');$b=new Gmagick(__DIR__.'/gm99-density100-cm.png');
$after=['inch'=>['units'=>$a->getImageUnits(),'density'=>$a->getImageResolution()],'cm'=>['units'=>$b->getImageUnits(),'density'=>$b->getImageResolution()]];

gmReport('gm99-density-label',["gmagick.construct", "gmagick.setimageunits", "gmagick.setimageresolution", "gmagick.getimageunits", "gmagick.getimageresolution", "gmagick.setimagedepth", "gmagick.setimageformat", "gmagick.writeimage"],["gm99-density100-inch.png", "gm99-density100-cm.png"],
    ['same_pixels'=>$a->getImageSignature()===$b->getImageSignature(),'units_before'=>$before['inch']['units']===Gmagick::RESOLUTION_PIXELSPERINCH&&$before['cm']['units']===Gmagick::RESOLUTION_PIXELSPERCENTIMETER,'png_units'=>$after['inch']['units']===Gmagick::RESOLUTION_PIXELSPERCENTIMETER&&abs($after['inch']['density']['x']-39.37)<0.001&&abs($after['cm']['density']['x']-100)<0.001,'size_gm99_density100_inch'=>gmInspect('gm99-density100-inch.png')['width']===320&&gmInspect('gm99-density100-inch.png')['height']===200,'size_gm99_density100_cm'=>gmInspect('gm99-density100-cm.png')['width']===320&&gmInspect('gm99-density100-cm.png')['height']===200],
    $errors ?? [], ['before_save'=>$before,'after_save'=>$after]);
echo "gm99-density100-inch.png 320x200 gm99-density100-cm.png 320x200\n";
Ожидаемый результат
gm99-density100-inch.png 320x200 gm99-density100-cm.png 320x200

Архив запускается командой php example.php с Gmagick. Проверенный отдельный runtime: PHP8.3.6 / Gmagick2.0.6RC1 / GraphicsMagick1.3.42 Q16. Собственные входы восстанавливаются из .b64; gm-fixture.php проверяет файлы и результат, изучаемые операции находятся в самой программе. PNG и metrics.json записываются рядом.

Вывод успешного запуска
gm99-density100-inch.png 320x200 gm99-density100-cm.png 320x200

После сохранения PNG100 px/in читаются здесь как 39.37 px/cm, с округлением: это почти то же физическое значение, потому что один дюйм равен 2.54 см. Не считайте такое чтение потерей плотности только из-за изменения числа. Второй файл действительно содержит 100 px/cm и означает другой размер. У PPM исходная плотность 0; придумывать 300 для неизвестного входа без правила приложения нельзя.

Визуальная модель: сетка 320×200 задаёт количество исходных точек. Линейка 100 px/in говорит, сколько точек разместить на дюйме. Смена линейки не добавляет ячеек сетки; resample меняет сетку. Это модель расчёта размера, а не модель работы всех сопел или лазерных точек принтера.

Изменить число отсчётов для той же физической ширины

Нужен тот же физический отпечаток, но с другим количеством отсчётов. Исходные 320×200 при 100 px/in занимают 3.2×2 дюйма. Для 200 px/in потребуются 640×400, для 50 —160×100. Ниже видны реальные изменённые растры; увеличение количества пикселей само по себе не создаёт новых деталей.

PPM содержит собственные размеры: подсказка 32×20 не превратила его в миниатюру
PPM содержит собственные размеры: подсказка 32×20 не превратила его в миниатюру — 320 × 200 px.
640×400 при явно записанных 200 px/in: прежние 3.2×2 дюйма
640×400 при явно записанных 200 px/in: прежние 3.2×2 дюйма — 640 × 400 px.
160×100 при явно записанных 50 px/in: те же 3.2×2 дюйма
160×100 при явно записанных 50 px/in: те же 3.2×2 дюйма — 160 × 100 px.
<?php
$image = new Gmagick(__DIR__ . '/product.ppm');
$image->setImageUnits(Gmagick::RESOLUTION_PIXELSPERINCH);
$image->setImageResolution(100, 100);
$image->resampleImage(200, 200, Gmagick::FILTER_LANCZOS, 1.0);
$image->setImageResolution(200, 200);
$image->setImageFormat('PNG');
$image->writeImage(__DIR__ . '/print-200.png');

Аргументы resampleImage — целевые плотности по осям, фильтр и blur.200 не является шириной будущего файла. FILTER_LANCZOS выбирает пересчёт,1.0 оставляет стандартный фактор. Важная особенность этого runtime: resampleImage изменяет геометрию, но getImageResolution сразу после него остаётся 100. Поэтому следующий явный setImageResolution(200,200) необходим для согласования физического размера.

Изменить число отсчётов для той же физической шириныСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__ . '/gm-fixture.php';
gmRestore();
$source=new Gmagick(__DIR__.'/product.ppm');$source->setImageUnits(Gmagick::RESOLUTION_PIXELSPERINCH);$source->setImageResolution(100,100);
$up=clone $source;$up->resampleImage(200,200,Gmagick::FILTER_LANCZOS,1.0);$upObserved=$up->getImageResolution();$up->setImageResolution(200,200);
$down=clone $source;$down->resampleImage(50,50,Gmagick::FILTER_LANCZOS,1.0);$downObserved=$down->getImageResolution();$down->setImageResolution(50,50);
$physical=[$source->getImageWidth()/100,$up->getImageWidth()/200,$down->getImageWidth()/50];
$errors=['empty'=>gmTry(fn()=>(new Gmagick())->resampleImage(100,100,Gmagick::FILTER_POINT,1.0))];
$up->setImageDepth(8);
$up->setImageFormat('PNG');
$up->writeImage(__DIR__.'/gm99-resample200.png');
$down->setImageDepth(8);
$down->setImageFormat('PNG');
$down->writeImage(__DIR__.'/gm99-resample50.png');

gmReport('gm99-print-resample',["gmagick.construct", "gmagick.setimageunits", "gmagick.setimageresolution", "gmagick.resampleimage", "gmagick.getimageresolution", "gmagick.getimagewidth", "gmagick.setimagedepth", "gmagick.setimageformat", "gmagick.writeimage"],["gm99-resample200.png", "gm99-resample50.png"],
    ['physical_width'=>abs($physical[0]-3.2)<1e-9&&$physical===[3.2,3.2,3.2],'observed_density_not_updated'=>$upObserved===['x'=>100.0,'y'=>100.0]&&$downObserved===$upObserved,'empty_rejected'=>$errors['empty']['class']==='GmagickException','size_gm99_resample200'=>gmInspect('gm99-resample200.png')['width']===640&&gmInspect('gm99-resample200.png')['height']===400,'size_gm99_resample50'=>gmInspect('gm99-resample50.png')['width']===160&&gmInspect('gm99-resample50.png')['height']===100],
    $errors ?? [], ['inches'=>$physical,'getter_after_resample_before_fix'=>[$upObserved,$downObserved]]);
echo "gm99-resample200.png 640x400 gm99-resample50.png 160x100\n";
Ожидаемый результат
gm99-resample200.png 640x400 gm99-resample50.png 160x100

Архив запускается командой php example.php с Gmagick. Проверенный отдельный runtime: PHP8.3.6 / Gmagick2.0.6RC1 / GraphicsMagick1.3.42 Q16. Собственные входы восстанавливаются из .b64; gm-fixture.php проверяет файлы и результат, изучаемые операции находятся в самой программе. PNG и metrics.json записываются рядом.

Вывод успешного запуска
gm99-resample200.png 640x400 gm99-resample50.png 160x100

Полная программа фиксирует оставшиеся 100, затем назначает целевые значения и проверяет 320/100=640/200=160/50=3.2. Для назначения плотности без изменения пикселей resample не нужен. Для заданной веб-ширины лучше resizeImage с пиксельными сторонами. Пустой объект даёт GmagickException; исходная плотность должна быть известна до расчёта отношения.

Собрать проверяемый маршрут печатной копии

Печатный сервис должен остановиться, если вход не сообщает единицы или плотность. Функция printCopy принимает известный исходник и целевую плотность, пересчитывает копию и явно обновляет метаданные. На выходе 160×100 при 50 px/in — прежняя ширина 3.2 дюйма.

PPM содержит собственные размеры: подсказка 32×20 не превратила его в миниатюру
PPM содержит собственные размеры: подсказка 32×20 не превратила его в миниатюру — 320 × 200 px.
Печатная копия 50 px/in; функция требует известную исходную плотность и единицы
Печатная копия 50 px/in; функция требует известную исходную плотность и единицы — 160 × 100 px.
<?php
$image = new Gmagick(__DIR__ . '/product.ppm');
$image->setImageUnits(Gmagick::RESOLUTION_PIXELSPERINCH);
$image->setImageResolution(100, 100);
$copy = clone $image;
$copy->resampleImage(50, 50, Gmagick::FILTER_LANCZOS, 1.0);
$copy->setImageResolution(50, 50);

Полная функция сначала читает getImageResolution и getImageUnits. Она принимает только известные px/in и положительные значения по обеим осям. Ограничение целевой плотности 600 — правило маленького учебного сервиса, помогающее ограничить рост, а не предел библиотеки. throw сообщает InvalidArgumentException, return передаёт готовую копию. Оригинал остаётся 320×200.

Собрать проверяемый маршрут печатной копииСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__ . '/gm-fixture.php';
gmRestore();
function printCopy(Gmagick $source,float $target):Gmagick {
    if($target<=0||$target>600)throw new InvalidArgumentException('Choose a positive target no greater than600');
    $density=$source->getImageResolution();$units=$source->getImageUnits();
    if($units!==Gmagick::RESOLUTION_PIXELSPERINCH||$density['x']<=0||$density['y']<=0)throw new InvalidArgumentException('Source needs known px/in density');
    $copy=clone $source;$copy->resampleImage($target,$target,Gmagick::FILTER_LANCZOS,1.0);$copy->setImageResolution($target,$target);return $copy;
}
$source=new Gmagick(__DIR__.'/product.ppm');$source->setImageUnits(Gmagick::RESOLUTION_PIXELSPERINCH);$source->setImageResolution(100,100);
$result=printCopy($source,50);$density=$result->getImageResolution();
$errors=['target'=>gmTry(fn()=>printCopy($source,0)),'unknown_density'=>gmTry(fn()=>printCopy(new Gmagick(__DIR__.'/product.ppm'),50))];
$result->setImageDepth(8);
$result->setImageFormat('PNG');
$result->writeImage(__DIR__.'/gm99-print-copy.png');

gmReport('gm99-print-function',["gmagick.construct", "gmagick.getimageresolution", "gmagick.getimageunits", "gmagick.resampleimage", "gmagick.setimageresolution", "gmagick.setimageunits", "gmagick.setimagedepth", "gmagick.setimageformat", "gmagick.writeimage"],["gm99-print-copy.png"],
    ['density50'=>$density===['x'=>50.0,'y'=>50.0],'original_size'=>$source->getImageWidth()===320&&$source->getImageHeight()===200,'target_rejected'=>$errors['target']['class']==='InvalidArgumentException','unknown_rejected'=>$errors['unknown_density']['class']==='InvalidArgumentException','size_gm99_print_copy'=>gmInspect('gm99-print-copy.png')['width']===160&&gmInspect('gm99-print-copy.png')['height']===100],
    $errors ?? [], ['target_density'=>$density,'physical_width_inches'=>3.2]);
echo "gm99-print-copy.png 160x100\n";
Ожидаемый результат
gm99-print-copy.png 160x100

Архив запускается командой php example.php с Gmagick. Проверенный отдельный runtime: PHP8.3.6 / Gmagick2.0.6RC1 / GraphicsMagick1.3.42 Q16. Собственные входы восстанавливаются из .b64; gm-fixture.php проверяет файлы и результат, изучаемые операции находятся в самой программе. PNG и metrics.json записываются рядом.

Вывод успешного запуска
gm99-print-copy.png 160x100

Две ошибочные ситуации различаются: нулевая цель и неизвестная плотность исходника. Числа из имени файла вроде «300dpi» не заменяют свойства изображения и не гарантируют пригодность к печати. Даже корректная плотность не говорит о резкости, цветовом профиле и разрешённом физическом размере — эти требования надо согласовать отдельно. Этот пример работает с одним локальным изображением, а не с PDF-рендерингом.

Прочитать поток RGB с известной геометрией

Поток датчика без заголовка не сообщает, где заканчивается строка и сколько в нём пикселей. Для собственного RGB16 файла заранее известны 32×20, три компонента и два байта на компонент:32×20×3×2=3840 байт. Маленький оригинал, двойной размер и увеличение×10 показаны отдельно.

Декодированный RGB16: 32×20 пикселей из 3840 байт без заголовка
Декодированный RGB16: 32×20 пикселей из 3840 байт без заголовка — 32 × 20 px.
magnifyImage увеличил каждую сторону вдвое
magnifyImage увеличил каждую сторону вдвое — 64 × 40 px.
Точечное увеличение ×10 исходника для рассмотрения пикселей
Точечное увеличение ×10 исходника для рассмотрения пикселей — 320 × 200 px.
<?php
$image = new Gmagick();
$image->setSize(32, 20);
$hint = $image->getSize();
$image->readImage('rgb:' . __DIR__ . '/sensor16.rgb');
$image->setImageFormat('PNG');
$image->writeImage(__DIR__ . '/sensor.png');

setSize должен стоять до чтения, getSize возвращает массив columns/rows. Префикс rgb: выбирает декодер потока, затем идёт путь. В нашем файле каждое исходное 8-битное значениеv расширено до 16 бит какv×257: оба байта одинаковы. Поэтому неоднозначность порядка этих двух байтов не влияет на данный специально созданный набор. Это не утверждение, что любой RGB16 файл устроен одинаково.

Прочитать поток RGB с известной геометриейСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__ . '/gm-fixture.php';
gmRestore();
$image=new Gmagick();$image->setSize(32,20);$hint=$image->getSize();
$image->readImage('rgb:'.__DIR__.'/sensor16.rgb');$effectiveDepth=$image->getImageDepth();
$sample=clone $image;$sample->cropImage(1,1,16,10);$center=$sample->getImageHistogram()[0]->getColor(true);
$double=clone $image;$double->magnifyImage();
$view=clone $image;$view->resizeImage(320,200,Gmagick::FILTER_POINT,1.0);
$image->setImageDepth(8);
$image->setImageFormat('PNG');
$image->writeImage(__DIR__.'/gm99-raw-native.png');
$double->setImageDepth(8);
$double->setImageFormat('PNG');
$double->writeImage(__DIR__.'/gm99-raw-double.png');
$view->setImageDepth(8);
$view->setImageFormat('PNG');
$view->writeImage(__DIR__.'/gm99-raw-view.png');

gmReport('gm99-raw-decode',["gmagick.construct", "gmagick.setsize", "gmagick.getsize", "gmagick.readimage", "gmagick.getimagedepth", "gmagick.cropimage", "gmagick.getimagehistogram", "gmagickpixel.getcolor", "gmagick.magnifyimage", "gmagick.resizeimage", "gmagick.setimagedepth", "gmagick.setimageformat", "gmagick.writeimage"],["gm99-raw-native.png", "gm99-raw-double.png", "gm99-raw-view.png"],
    ['hint'=>$hint===['columns'=>32,'rows'=>20],'byte_count'=>filesize(__DIR__."/sensor16.rgb")===3840,'effective_eight'=>$effectiveDepth===8,'known_center'=>$center===['r'=>131,'g'=>134,'b'=>132],'size_gm99_raw_native'=>gmInspect('gm99-raw-native.png')['width']===32&&gmInspect('gm99-raw-native.png')['height']===20,'size_gm99_raw_double'=>gmInspect('gm99-raw-double.png')['width']===64&&gmInspect('gm99-raw-double.png')['height']===40,'size_gm99_raw_view'=>gmInspect('gm99-raw-view.png')['width']===320&&gmInspect('gm99-raw-view.png')['height']===200],
    $errors ?? [], ['read_hint'=>$hint,'storage_bits_per_sample'=>16,'effective_depth'=>$effectiveDepth,'center'=>$center]);
echo "gm99-raw-native.png 32x20 gm99-raw-double.png 64x40 gm99-raw-view.png 320x200\n";
Ожидаемый результат
gm99-raw-native.png 32x20 gm99-raw-double.png 64x40 gm99-raw-view.png 320x200

Архив запускается командой php example.php с Gmagick. Проверенный отдельный runtime: PHP8.3.6 / Gmagick2.0.6RC1 / GraphicsMagick1.3.42 Q16. Собственные входы восстанавливаются из .b64; gm-fixture.php проверяет файлы и результат, изучаемые операции находятся в самой программе. PNG и metrics.json записываются рядом.

Вывод успешного запуска
gm99-raw-native.png 32x20 gm99-raw-double.png 64x40 gm99-raw-view.png 320x200

В фиксированной Q16-сборке поток RGB8 из 1920 байт дал Unexpected end-of-file; сохранённая попытка отдельно проверена, универсальный 8-битный декодер здесь не обещается. Работающий RGB16 содержит 3840 байт, однако getImageDepth показывает 8: все значения эффективно представимы 8 битами. Нельзя выводить размер raw-потока из этого getter. Полная программа проверяет центр RGB131,134,132 и увеличивает копию через magnifyImage; большое увеличение для чтения сделано точечным resizeImage.

Проверить, что подсказка чтения не является изменением размера

У PPM есть заголовок с реальными размерами. Поэтому настройка объекта 32×20 не обязана уменьшать прочитанный PPM320×200. Этот пример показывает исходную карточку и отдельно выполненное уменьшение, чтобы слово size не подменило нужную операцию.

PPM содержит собственные размеры: подсказка 32×20 не превратила его в миниатюру
PPM содержит собственные размеры: подсказка 32×20 не превратила его в миниатюру — 320 × 200 px.
Реальное уменьшение сделано отдельным minifyImage
Реальное уменьшение сделано отдельным minifyImage — 160 × 100 px.
<?php
$image = new Gmagick();
$image->setSize(32, 20);
$image->readImage(__DIR__ . '/product.ppm');
echo $image->getImageWidth(), 'x', $image->getImageHeight(), "\n";
$image->minifyImage();

До minifyImage код выводит «320x200». getSize по-прежнему описывает настройку columns32/rows20, а getImageWidth/getImageHeight — действительный растр. После minifyImage результат 160×100. Отсюда правило: подсказку декодеру не используем как универсальное изменение размера. Массив вместо целой ширины setSize отдельно даёт TypeError.

Проверить, что подсказка чтения не является изменением размераСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__ . '/gm-fixture.php';
gmRestore();
$image=new Gmagick();$image->setSize(32,20);$hint=$image->getSize();
$image->readImage(__DIR__.'/product.ppm');$actual=[$image->getImageWidth(),$image->getImageHeight()];
$small=clone $image;$small->minifyImage();
$errors=['size_type'=>gmTry(fn()=>(new Gmagick())->setSize([],20))];
$image->setImageDepth(8);
$image->setImageFormat('PNG');
$image->writeImage(__DIR__.'/gm99-size-hint-source.png');
$small->setImageDepth(8);
$small->setImageFormat('PNG');
$small->writeImage(__DIR__.'/gm99-size-hint-half.png');

gmReport('gm99-size-hint',["gmagick.construct", "gmagick.setsize", "gmagick.getsize", "gmagick.readimage", "gmagick.getimagewidth", "gmagick.getimageheight", "gmagick.minifyimage", "gmagick.setimagedepth", "gmagick.setimageformat", "gmagick.writeimage"],["gm99-size-hint-source.png", "gm99-size-hint-half.png"],
    ['hint_separate'=>$hint===['columns'=>32,'rows'=>20]&&$actual===[320,200],'type_rejected'=>$errors['size_type']['class']==='TypeError','size_gm99_size_hint_source'=>gmInspect('gm99-size-hint-source.png')['width']===320&&gmInspect('gm99-size-hint-source.png')['height']===200,'size_gm99_size_hint_half'=>gmInspect('gm99-size-hint-half.png')['width']===160&&gmInspect('gm99-size-hint-half.png')['height']===100],
    $errors ?? [], ['hint'=>$hint,'decoded_geometry'=>$actual]);
echo "gm99-size-hint-source.png 320x200 gm99-size-hint-half.png 160x100\n";
Ожидаемый результат
gm99-size-hint-source.png 320x200 gm99-size-hint-half.png 160x100

Архив запускается командой php example.php с Gmagick. Проверенный отдельный runtime: PHP8.3.6 / Gmagick2.0.6RC1 / GraphicsMagick1.3.42 Q16. Собственные входы восстанавливаются из .b64; gm-fixture.php проверяет файлы и результат, изучаемые операции находятся в самой программе. PNG и metrics.json записываются рядом.

Вывод успешного запуска
gm99-size-hint-source.png 320x200 gm99-size-hint-half.png 160x100

Для формата без размеров подсказка нужна; для формата с заголовком решение зависит от декодера. Пример не обещает, что setSize одинаково действует на все поддерживаемые форматы. Если сервис требует точную миниатюру, сначала прочитайте и проверьте действительную геометрию, затем вызовите соответствующий метод изменения размера.

Получить два масштаба превью из одного оригинала

Для страницы каталога нужны большая версия и маленькое превью. Оба результата создаются независимо из одного оригинала. Увеличение вдвое по каждой оси даёт 640×400, уменьшение —160×100; это разные растры с разной площадью и количеством данных.

PPM содержит собственные размеры: подсказка 32×20 не превратила его в миниатюру
PPM содержит собственные размеры: подсказка 32×20 не превратила его в миниатюру — 320 × 200 px.
magnifyImage: по две исходные стороны, площадь выросла в четыре раза
magnifyImage: по две исходные стороны, площадь выросла в четыре раза — 640 × 400 px.
minifyImage: половина каждой стороны, площадь составляет четверть
minifyImage: половина каждой стороны, площадь составляет четверть — 160 × 100 px.
<?php
$source = new Gmagick(__DIR__ . '/product.ppm');
$large = clone $source;
$large->magnifyImage();
$small = clone $source;
$small->minifyImage();

У обоих методов нет аргументов. Важно слово «каждая»:640×400 содержит вчетверо больше пикселей,160×100 — вчетверо меньше. Полная программа сохраняет оба файла и проверяет неизменность оригинала. Magnify возвращает тот же объект, хотя официальный тип результата обозначен mixed. clone нужен для независимости, а не для получения возвращаемого значения.

Получить два масштаба превью из одного оригиналаСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__ . '/gm-fixture.php';
gmRestore();
$source=new Gmagick(__DIR__.'/product.ppm');$sourceSignature=$source->getImageSignature();
$large=clone $source;$same=$large->magnifyImage()===$large;
$small=clone $source;$small->minifyImage();
$large->setImageDepth(8);
$large->setImageFormat('PNG');
$large->writeImage(__DIR__.'/gm99-magnified.png');
$small->setImageDepth(8);
$small->setImageFormat('PNG');
$small->writeImage(__DIR__.'/gm99-minified.png');

gmReport('gm99-preview-sizes',["gmagick.construct", "gmagick.getimagesignature", "gmagick.magnifyimage", "gmagick.minifyimage", "gmagick.setimagedepth", "gmagick.setimageformat", "gmagick.writeimage"],["gm99-magnified.png", "gm99-minified.png"],
    ['same_object'=>$same,'source_preserved'=>$source->getImageSignature()===$sourceSignature,'scaled_geometry'=>$large->getImageWidth()===640&&$small->getImageWidth()===160,'size_gm99_magnified'=>gmInspect('gm99-magnified.png')['width']===640&&gmInspect('gm99-magnified.png')['height']===400,'size_gm99_minified'=>gmInspect('gm99-minified.png')['width']===160&&gmInspect('gm99-minified.png')['height']===100],
    $errors ?? [], ['original'=>[320,200],'large'=>[640,400],'small'=>[160,100]]);
echo "gm99-magnified.png 640x400 gm99-minified.png 160x100\n";
Ожидаемый результат
gm99-magnified.png 640x400 gm99-minified.png 160x100

Архив запускается командой php example.php с Gmagick. Проверенный отдельный runtime: PHP8.3.6 / Gmagick2.0.6RC1 / GraphicsMagick1.3.42 Q16. Собственные входы восстанавливаются из .b64; gm-fixture.php проверяет файлы и результат, изучаемые операции находятся в самой программе. PNG и metrics.json записываются рядом.

Вывод успешного запуска
gm99-magnified.png 640x400 gm99-minified.png 160x100

Увеличение не восстанавливает мелкие детали, потерянные при уменьшении. Для заданной ширины вроде 240, выбора фильтра и запрета роста маленького входа используйте resizeImage или thumbnailImage из предыдущего маршрута. Эти результаты относятся к чётным 320×200; правило округления нечётных сторон здесь не заявляется. При обработке больших файлов учитывайте одновременно оригинал и обе копии в памяти.

Упражнение: ширина 600 px при 300 px/in — сколько дюймов? Ответ:2. Изменится ли ширина 600 px от одного setImageResolution(150,150)? Ответ:нет, изменится расчётный размер до 4 дюймов. Сколько байт в нашем 32×20 RGB16 без заголовка? Ответ:3840; эффективная глубина 8 не отменяет упаковку 16 бит. Для точных пиксельных размеров см. resizeImage и thumbnailImage, для выпуска файла — контракты экспорта. Геометрические эффекты разобраны в преобразованиях изображения.

Практический вопрос, из которого вырос сценарий

PHP Imagick::resampleImage resizes image instead of resampling: При запросе меньшей плотности автор получает меньшие пиксельные стороны, но прежнее число в метаданных, и смешивает плотность с размером веб-изображения. Сначала считаем физический размер как пиксели/плотность, затем отдельно показываем setters и resampleImage. На нашем Gmagick resample меняет стороны, но оставляет старую плотность; после измерения этого факта явно записываем целевое значение. PNG читается с учётом сантиметровых единиц и округления, а неизвестная исходная плотность отклоняется функцией.

Функции и методы этой темы

Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.

Gmagick::getimageresolutionПрочитать плотность отдельно по X и Y

PECL gmagick >= Unknown · gmagick

Gmagick::getimageresolution(): array

Без аргументов; результат array. Проверенная реализация возвращает ключи x и y с float. Это плотность, которую нужно интерпретировать вместе с getImageUnits, а не ширина и высота в пикселях. У PPM нашего входа обе величины 0: размер файла известен, печатная плотность — нет. После записи PNG значения могут вернуться в пикселях на сантиметр:100 px/in здесь читаются как 39.37 px/cm. Сравнивайте физический смысл с допуском, а не голое число 100 независимо от единиц.

Gmagick::getimageresolution(): array

Аргументов нет: пустые скобки обращаются к текущему изображению или настройке объекта, как пояснено выше.

Возврат по PHP.net: array — массив с указанными выше ключами.

Официальный отказ: GmagickException при ошибке операции. Неверный PHP-тип может быть отвергнут раньше как TypeError; проверка диапазона в наших функциях даёт отдельную InvalidArgumentException.

Требуется PECL Gmagick. Нижняя граница версии указана PHP.net как Unknown; её не заменяем датой страницы или номером PHP в новостном баннере. Результаты здесь проверяются на фиксированной Q16-сборке, другие версии могут отличаться.

Два применения: Разделить пиксели и плотность печати; Собрать проверяемый маршрут печатной копии.

Gmagick::getimageunitsПрочитать единицы плотности

PECL gmagick >= Unknown · gmagick

Gmagick::getimageunits(): int

Аргументов нет, результат int. Сравнивайте с Gmagick::RESOLUTION_UNDEFINED, RESOLUTION_PIXELSPERINCH либо RESOLUTION_PIXELSPERCENTIMETER. Без единиц число 100 нельзя честно объявить 100 dpi. PNG может хранить и возвращать другую единицу с эквивалентной величиной. У этой страницы PHP.net отдельный список исключений не приведён; C-обёртка проверяет наличие изображения. Функция печатной копии отвергает неизвестные единицы вместо молчаливого предположения.

Gmagick::getimageunits(): int

Аргументов нет: пустые скобки обращаются к текущему изображению или настройке объекта, как пояснено выше.

Возврат по PHP.net: int — целое число с указанным выше смыслом.

Отдельный раздел ошибок на этой странице PHP.net отсутствует; это не гарантия успеха на пустом или неверном входе.

Требуется PECL Gmagick. Нижняя граница версии указана PHP.net как Unknown; её не заменяем датой страницы или номером PHP в новостном баннере. Результаты здесь проверяются на фиксированной Q16-сборке, другие версии могут отличаться.

Два применения: Разделить пиксели и плотность печати; Собрать проверяемый маршрут печатной копии.

Gmagick::getsizeПрочитать настройку геометрии декодера

PECL gmagick >= Unknown · gmagick

Gmagick::getsize(): array

Без аргументов; array с ключами columns и rows. Это размер, связанный с объектом для чтения данных, а не универсальный аналог getImageWidth/getImageHeight. В новом объекте проверено 0/0; после setSize(32,20) —32/20. Raw-поток использует указанную геометрию. PPM с собственным заголовком остаётся 320×200 даже при настройке 32×20, что показано отдельным PNG. Измерять готовое изображение нужно методами ширины и высоты.

Gmagick::getsize(): array

Аргументов нет: пустые скобки обращаются к текущему изображению или настройке объекта, как пояснено выше.

Возврат по PHP.net: array — массив с указанными выше ключами.

Официальный отказ: GmagickException при ошибке операции. Неверный PHP-тип может быть отвергнут раньше как TypeError; проверка диапазона в наших функциях даёт отдельную InvalidArgumentException.

Требуется PECL Gmagick. Нижняя граница версии указана PHP.net как Unknown; её не заменяем датой страницы или номером PHP в новостном баннере. Результаты здесь проверяются на фиксированной Q16-сборке, другие версии могут отличаться.

Два применения: Прочитать поток RGB с известной геометрией; Проверить, что подсказка чтения не является изменением размера.

Gmagick::magnifyimageУвеличить обе стороны вдвое

PECL gmagick >= Unknown · gmagick

Gmagick::magnifyimage(): mixed

Аргументов нет. PHP.net обозначает возвращаемый тип mixed и описывает увеличенный объект Gmagick; в проверенной сборке возвращается тот же объект.32×20 становится 64×40,320×200 —640×400. Площадь и число пикселей растут вчетверо, поэтому память нельзя оценивать только множителем 2. Метод не добавляет новых реальных деталей исходника. Для заданного размера и выбора фильтра используйте resizeImage. Пример сохраняет оригинал через clone.

Gmagick::magnifyimage(): mixed

Аргументов нет: пустые скобки обращаются к текущему изображению или настройке объекта, как пояснено выше.

Возврат по PHP.net: mixed; описание обещает увеличенный Gmagick, что подтверждено на указанной сборке.

Официальный отказ: GmagickException при ошибке операции. Неверный PHP-тип может быть отвергнут раньше как TypeError; проверка диапазона в наших функциях даёт отдельную InvalidArgumentException.

Требуется PECL Gmagick. Нижняя граница версии указана PHP.net как Unknown; её не заменяем датой страницы или номером PHP в новостном баннере. Результаты здесь проверяются на фиксированной Q16-сборке, другие версии могут отличаться.

Два применения: Прочитать поток RGB с известной геометрией; Получить два масштаба превью из одного оригинала.

Gmagick::minifyimageУменьшить обе стороны вдвое

PECL gmagick >= Unknown · gmagick

Gmagick::minifyimage(): Gmagick

Без аргументов, результат Gmagick. На чётных размерах 320×200 получаем 160×100; площадь составляет четверть исходной. Это действие над пикселями, тогда как setSize задаёт настройку чтения. Способ пересчёта отличается от простого удаления каждого второго пикселя; видимый результат сохраняется для оценки. Для произвольных нечётных размеров не обещаем правило округления без отдельной проверки; для точных сторон и фильтра подходит resizeImage. Уменьшение и последующее увеличение не восстанавливают утраченную детализацию.

Gmagick::minifyimage(): Gmagick

Аргументов нет: пустые скобки обращаются к текущему изображению или настройке объекта, как пояснено выше.

Возврат по PHP.net: Gmagick — изменённый объект изображения.

Официальный отказ: GmagickException при ошибке операции. Неверный PHP-тип может быть отвергнут раньше как TypeError; проверка диапазона в наших функциях даёт отдельную InvalidArgumentException.

Требуется PECL Gmagick. Нижняя граница версии указана PHP.net как Unknown; её не заменяем датой страницы или номером PHP в новостном баннере. Результаты здесь проверяются на фиксированной Q16-сборке, другие версии могут отличаться.

Два применения: Проверить, что подсказка чтения не является изменением размера; Получить два масштаба превью из одного оригинала.

Gmagick::resampleimageПересчитать пиксели под целевую плотность

PECL gmagick >= Unknown · gmagick

Gmagick::resampleimage(float $xResolution, float $yResolution, int $filter, float $blur): Gmagick

xResolution и yResolution — целевые плотности float, не требуемые пиксельные стороны. filter — int из FILTER_*, blur — float: официально больше 1 размывает, меньше 1 заостряет; это не обещание восстановления деталей. Возвращается Gmagick. При известной исходной плотности 100 px/in запрос 200 даёт 320×200→640×400, запрос 50 —160×100. Но getter плотности в этом runtime остаётся 100: для сохранения физического размера явно записываем новую плотность после операции. X и Y можно задавать различно; это меняет соотношение отсчётов по осям. Неизвестную исходную плотность наша функция отклоняет. Пустой объект даёт GmagickException.

Gmagick::resampleimage(float $xResolution, float $yResolution, int $filter, float $blur): Gmagick
АргументТипСмысл
xResolutionfloat — обязательныйПлотность по горизонтальной оси в заданных единицах.
yResolutionfloat — обязательныйПлотность по вертикальной оси в заданных единицах.
filterint — обязательныйКонстанта FILTER_* алгоритма пересчёта.
blurfloat — обязательныйФактор размытия;1.0 в наших примерах.

Возврат по PHP.net: Gmagick — изменённый объект изображения.

Официальный отказ: GmagickException при ошибке операции. Неверный PHP-тип может быть отвергнут раньше как TypeError; проверка диапазона в наших функциях даёт отдельную InvalidArgumentException.

Требуется PECL Gmagick. Нижняя граница версии указана PHP.net как Unknown; её не заменяем датой страницы или номером PHP в новостном баннере. Результаты здесь проверяются на фиксированной Q16-сборке, другие версии могут отличаться.

Два применения: Изменить число отсчётов для той же физической ширины; Собрать проверяемый маршрут печатной копии.

Gmagick::setimageresolutionЗаписать печатную плотность изображения

PECL gmagick >= Unknown · gmagick

Gmagick::setimageresolution(float $xResolution, float $yResolution): Gmagick

xResolution и yResolution — float, плотности по осям в текущих единицах. Результат Gmagick. Метод не создаёт дополнительные пиксели:320×200 остаётся 320×200, меняется расчётный физический размер. Перед вызовом требуется существующее изображение; это не настройка декодирования ещё не прочитанного PDF. Для изменения количества отсчётов служит resampleImage. В этой сборке после resampleImage целевую плотность приходится записать явно; программа показывает отдельно наблюдение и исправление метаданных.

Gmagick::setimageresolution(float $xResolution, float $yResolution): Gmagick
АргументТипСмысл
xResolutionfloat — обязательныйПлотность по горизонтальной оси в заданных единицах.
yResolutionfloat — обязательныйПлотность по вертикальной оси в заданных единицах.

Возврат по PHP.net: Gmagick — изменённый объект изображения.

Официальный отказ: GmagickException при ошибке операции. Неверный PHP-тип может быть отвергнут раньше как TypeError; проверка диапазона в наших функциях даёт отдельную InvalidArgumentException.

Требуется PECL Gmagick. Нижняя граница версии указана PHP.net как Unknown; её не заменяем датой страницы или номером PHP в новостном баннере. Результаты здесь проверяются на фиксированной Q16-сборке, другие версии могут отличаться.

Два применения: Разделить пиксели и плотность печати; Изменить число отсчётов для той же физической ширины.

Gmagick::setimageunitsЗадать единицы для значения плотности

PECL gmagick >= Unknown · gmagick

Gmagick::setimageunits(int $resolution): Gmagick

resolution — int из констант RESOLUTION_*; название параметра не означает само число пикселей на дюйм. Метод возвращает Gmagick. Задаём единицы, затем обе числовые плотности через setImageResolution. Один и тот же 320×200 при 100 px/in означает 3.2×2 дюйма, а при 100 px/cm —3.2×2 сантиметра. Не заявляйте, что смена метки единиц сама гарантированно пересчитает числовую плотность: задавайте согласованные значения явно и проверяйте записанный файл.

Gmagick::setimageunits(int $resolution): Gmagick
АргументТипСмысл
resolutionint — обязательныйКонстанта RESOLUTION_*, обозначающая единицы.

Возврат по PHP.net: Gmagick — изменённый объект изображения.

Официальный отказ: GmagickException при ошибке операции. Неверный PHP-тип может быть отвергнут раньше как TypeError; проверка диапазона в наших функциях даёт отдельную InvalidArgumentException.

Требуется PECL Gmagick. Нижняя граница версии указана PHP.net как Unknown; её не заменяем датой страницы или номером PHP в новостном баннере. Результаты здесь проверяются на фиксированной Q16-сборке, другие версии могут отличаться.

Два применения: Разделить пиксели и плотность печати; Собрать проверяемый маршрут печатной копии.

Gmagick::setsizeПередать размеры до чтения потока без заголовка

PECL gmagick >= Unknown · gmagick

Gmagick::setsize(int $columns, int $rows): Gmagick

columns и rows — int, ширина и высота в пикселях; результат Gmagick. Официальное назначение — установить геометрию до чтения raw RGB/GRAY/CMYK. Упомянутые в тексте PHP.net COLORSPACE_* — цветовые модели, а не значения, которые надо подставлять вместо сторон; в реальном примере декодер выбирает префикс rgb: пути. Размеров недостаточно для произвольного raw: нужны модель, порядок компонентов, разрядность, байтовый порядок и размещение строк. Наш фиксированный Q16 runtime прочёл собственный interleaved RGB16 размером 32×20 из 3840 байт; RGB8 из 1920 байт дал Unexpected end-of-file. Это граница конкретной пары файла и декодера, не универсальная формула для всех raw-файлов.

Gmagick::setsize(int $columns, int $rows): Gmagick
АргументТипСмысл
columnsint — обязательныйШирина данных в пикселях перед чтением.
rowsint — обязательныйВысота данных в пикселях перед чтением.

Возврат по PHP.net: Gmagick — изменённый объект изображения.

Официальный отказ: GmagickException при ошибке операции. Неверный PHP-тип может быть отвергнут раньше как TypeError; проверка диапазона в наших функциях даёт отдельную InvalidArgumentException.

Требуется PECL Gmagick. Нижняя граница версии указана PHP.net как Unknown; её не заменяем датой страницы или номером PHP в новостном баннере. Результаты здесь проверяются на фиксированной Q16-сборке, другие версии могут отличаться.

Два применения: Прочитать поток RGB с известной геометрией; Проверить, что подсказка чтения не является изменением размера.

Источники и обсуждения

Код и руководство с собой

Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.

Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.

Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.