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

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

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

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

Глава 397 · После объектов и базовой работы с изображениями

Imagick: прочитать режим интерполяции и проверить результат обработки

Настройка текущего изображения, независимые клоны и кадры, явная операция пересчёта и два готовых PNG с рецептом повторного экспорта.

Проверить режим и увидеть, что настройка не перерисовывает изображение

Вы увеличиваете маленькую иконку и хотите понимать, почему одна версия остаётся пиксельной, а другая получает плавные края. Начните с проверки выбранной настройки. getImageInterpolateMethod отвечает, какой режим хранится у текущего изображения. Сам он не увеличивает картинку, а помогает проверить подготовку к обработке.

Собственная иконка 40×32 до и после изменения настройки. Обе панели увеличены 10× только для просмотра; исходные пиксели не менялись.
Собственная иконка 40×32 до и после изменения настройки. Обе панели увеличены 10× только для просмотра; исходные пиксели не менялись.

Для первого короткого фрагмента нужен файл icon.png рядом со скриптом. Он входит в каждый архив в виде base64; полный example.php автоматически восстановит обычный PNG. Можно взять и собственный файл. new Imagick читает его в объект $image; стрелка -> вызывает метод этого объекта. Пустые скобки getter означают, что аргументов ему не требуется.

$image = new Imagick(__DIR__ . "/icon.png");
$method = $image->getImageInterpolateMethod();
var_dump($method); // int(0) для нашего исходного PNG

Переменная $method получает целое число. Для нашего файла 0 соответствует INTERPOLATE_UNDEFINED: явный режим не выбран. Это нормальное состояние, а не ошибка. Следующие три строки назначат ближайший пиксель и прочитают настройку обратно. Символы :: обращаются к именованной константе класса; её имя объясняет смысл лучше случайного числа.

$image->setImageInterpolateMethod(Imagick::INTERPOLATE_NEAREST_PIXEL);
$method = $image->getImageInterpolateMethod();
var_dump($method === Imagick::INTERPOLATE_NEAREST_PIXEL); // bool(true)

В проверенной сборке это int(10), но код сравнивает имена констант. Размер пока остаётся 40×32, и домик не становится крупнее. Это удобно для диагностики: setter сообщает, что настройка принята, getter показывает, что хранится сейчас, а пересчёт выполняется отдельной операцией.

Прочитать настройку и убедиться, что сам рисунок не изменился

Getter вернул целое значение выбранного режима. В проверенной сборке исходный PNG имел UNDEFINED=0, после setter — NEAREST_PIXEL=10. Сам исходник остался 40×32 с прежними пикселями; две одинаковые картинки 400×320 — отдельное увеличение 10× для просмотра.

Прочитать настройку и убедиться, что сам рисунок не изменилсяПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__ . '/interpolate-fixture.php';
ipRestore();
$source = new Imagick(__DIR__ . '/icon.png');
$sourceBefore = ipState($source);
$sourceHash = hash_file('sha256', __DIR__ . '/icon.png');
$image = clone $source;
$before = ipState($image);
$setResult = $image->setImageInterpolateMethod(Imagick::INTERPOLATE_NEAREST_PIXEL);
$method = $image->getImageInterpolateMethod();
$after = ipState($image);
$left = ipPreview($source);
$right = ipPreview($image);
$images = ['before'=>ipImage($left,'first-before8.png'),'after'=>ipImage($right,'first-after8.png')];
$rects = ipCompare([$left,$right],'interpolate-first.png');
ipDiagnostic('interpolate-first',[
 'before'=>$before,'after'=>$after,'set_return'=>$setResult,'get_type'=>get_debug_type($method),'get_value'=>$method,'display'=>['source_geometry'=>[40,32],'preview_geometry'=>[400,320],'preview_method'=>'sampleImage','scale'=>10],
 'images'=>$images,'panel_keys'=>['before','after'],'panel_geometry'=>$rects,'source_before'=>$sourceBefore,'source_after'=>ipState($source),'source_sha256'=>$sourceHash,'source_unchanged'=>ipState($source)===$sourceBefore&&hash_file('sha256',__DIR__.'/icon.png')===$sourceHash,
 'checks'=>['default_undefined'=>$before['method']===Imagick::INTERPOLATE_UNDEFINED,'setter_true'=>$setResult===true,'getter_int'=>is_int($method),'getter_matches_setting'=>$method===Imagick::INTERPOLATE_NEAREST_PIXEL,'pixels_unchanged'=>$before['RGBA16_sha256']===$after['RGBA16_sha256'],'geometry_unchanged'=>$after['geometry']===[40,32],'display_equal'=>ipHash($left)===ipHash($right)]
]);
echo "interpolate-first.png\nfirst-before8.png\nfirst-after8.png\nmetrics.json\nbefore=UNDEFINED after=NEAREST_PIXEL getter=int pixels=unchanged size=40x32\n";

Getter вернул целое значение выбранного режима. В проверенной сборке исходный PNG имел UNDEFINED=0, после setter — NEAREST_PIXEL=10. Сам исходник остался 40×32 с прежними пикселями; две одинаковые картинки 400×320 — отдельное увеличение 10× для просмотра. В архиве example.php, icon.png.b64 и interpolate-fixture.php. Распакуйте файлы рядом и выполните php example.php: собственный icon.png восстановится автоматически. Вспомогательный PHP целиком приведён в конце главы. Проверенная среда: PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16, Windows. Полные примеры требуют interpolativeResizeImage и константу INTERPOLATE_NEAREST_PIXEL, проверяют их наличие перед обработкой.

Ожидаемый вывод после настоящего запуска
interpolate-first.png
first-before8.png
first-after8.png
metrics.json
before=UNDEFINED after=NEAREST_PIXEL getter=int pixels=unchanged size=40x32

Применить прочитанный режим и проверить отдельные кадры

Два одинаковых исходных кадра с разными настройками дали разные настоящие PNG 400×320 после явного применения getter.
Два одинаковых исходных кадра с разными настройками дали разные настоящие PNG 400×320 после явного применения getter.

Теперь передадим прочитанный режим операции, которая действительно использует интерполяцию. В нашей сборке interpolativeResizeImage получает ширину, высоту и метод. Здесь 400 и 320 — размеры результата в пикселях. В отличие от первых увеличенных панелей, это уже сами создаваемые изображения.

$method = $image->getImageInterpolateMethod();
$image->interpolativeResizeImage(400, 320, $method);
$image->setImageFormat("png");
$image->writeImage(__DIR__ . "/large-icon.png");

Для иконки из крупных цветных клеток NEAREST_PIXEL сохраняет отчётливую сетку. BILINEAR смешивает соседние значения, поэтому между цветами появляются переходы. Это два разных визуальных решения. Сглаживание не восстанавливает утраченные детали, а ближайший пиксель не является универсальным выбором для фотографий, тонких линий или уменьшения. Для фотографического превью отдельно выбирают операцию и фильтр, сравнивая результат в целевом размере.

Следующий полный пример нужен, когда обработчик работает с клонами или несколькими изображениями. Для наших одиночных изображений clone создаёт независимую копию: установка BILINEAR в $smooth не меняет NEAREST_PIXEL у $pixel. addImage добавляет обе копии в список. foreach выбирает текущий кадр, а getter внутри цикла читает именно его настройку. Перед обработкой getImage() выделяет текущий кадр в отдельный Imagick. Это существенно: clone объекта последовательности копирует весь список и в проверенном запуске возвращает выбор к первому кадру; такой clone нельзя использовать здесь как выделение текущего кадра. У нас два самостоятельных кадра в памяти, не сохранённая GIF-анимация.

Прочитать настройку клона и каждого кадра, затем применить её

Два кадра содержат одинаковый исходный рисунок, но разные настройки: NEAREST_PIXEL и BILINEAR. После явной передачи каждого getter в interpolativeResizeImage получены разные PNG 400×320: чёткие блоки пикселей и сглаженные переходы.

Прочитать настройку клона и каждого кадра, затем применить еёПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__ . '/interpolate-fixture.php';
ipRestore();
$source = new Imagick(__DIR__ . '/icon.png');
$sourceBefore = ipState($source);
$sourceHash = hash_file('sha256', __DIR__ . '/icon.png');
$pixel = clone $source;
$pixel->setImageInterpolateMethod(Imagick::INTERPOLATE_NEAREST_PIXEL);
$smooth = clone $pixel;
$smooth->setImageInterpolateMethod(Imagick::INTERPOLATE_BILINEAR);
$cloneStates = ['pixel'=>ipState($pixel),'smooth'=>ipState($smooth)];
$sequence = new Imagick();
$sequence->addImage($pixel);
$sequence->addImage($smooth);
$frameStates = [];
$outputs = [];
foreach ($sequence as $index => $frame) {
    $frameStates[] = ['index'=>$index,'state'=>ipState($frame)];
    $result = $frame->getImage();
    $selected = $result->getImageInterpolateMethod();
    $result->interpolativeResizeImage(400, 320, $selected);
    $outputs[] = $result;
}
$images = ['nearest'=>ipImage($outputs[0],'frames-nearest8.png'),'bilinear'=>ipImage($outputs[1],'frames-bilinear8.png')];
$rects = ipCompare($outputs,'interpolate-frames.png');
ipDiagnostic('interpolate-frames',[
 'clone_states'=>$cloneStates,'frame_states'=>$frameStates,'output_states'=>array_map('ipState',$outputs),'original_pixel_after'=>ipState($pixel),'sequence_frames'=>$sequence->getNumberImages(),
 'images'=>$images,'panel_keys'=>['nearest','bilinear'],'panel_geometry'=>$rects,'source_before'=>$sourceBefore,'source_after'=>ipState($source),'source_sha256'=>$sourceHash,'source_unchanged'=>ipState($source)===$sourceBefore&&hash_file('sha256',__DIR__.'/icon.png')===$sourceHash,
 'checks'=>['clone_independent'=>$pixel->getImageInterpolateMethod()===Imagick::INTERPOLATE_NEAREST_PIXEL&&$smooth->getImageInterpolateMethod()===Imagick::INTERPOLATE_BILINEAR,'clone_pixels_equal'=>ipHash($pixel)===ipHash($smooth),'two_frames'=>$sequence->getNumberImages()===2,'frame_methods'=>$frameStates[0]['state']['method']===Imagick::INTERPOLATE_NEAREST_PIXEL&&$frameStates[1]['state']['method']===Imagick::INTERPOLATE_BILINEAR,'outputs_differ'=>ipHash($outputs[0])!==ipHash($outputs[1]),'output_geometry'=>$outputs[0]->getImageGeometry()===['width'=>400,'height'=>320]&&$outputs[1]->getImageGeometry()===['width'=>400,'height'=>320]]
]);
echo "interpolate-frames.png\nframes-nearest8.png\nframes-bilinear8.png\nmetrics.json\nframe0=NEAREST_PIXEL frame1=BILINEAR outputs=400x320 different=yes\n";

Два кадра содержат одинаковый исходный рисунок, но разные настройки: NEAREST_PIXEL и BILINEAR. После явной передачи каждого getter в interpolativeResizeImage получены разные PNG 400×320: чёткие блоки пикселей и сглаженные переходы. В архиве example.php, icon.png.b64 и interpolate-fixture.php. Распакуйте файлы рядом и выполните php example.php: собственный icon.png восстановится автоматически. Вспомогательный PHP целиком приведён в конце главы. Проверенная среда: PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16, Windows. Полные примеры требуют interpolativeResizeImage и константу INTERPOLATE_NEAREST_PIXEL, проверяют их наличие перед обработкой.

Ожидаемый вывод после настоящего запуска
interpolate-frames.png
frames-nearest8.png
frames-bilinear8.png
metrics.json
frame0=NEAREST_PIXEL frame1=BILINEAR outputs=400x320 different=yes

Путь данных: исходные 40×32 → настройка конкретного кадра → getter → третий аргумент interpolativeResizeImage → новые 400×320 → PNG. Более подробная механика дробных координат уже разобрана в главе о выборке и интерполяции. Здесь важна привязка настройки к нужному изображению и её явная передача операции.

Не путать настройку, параметр операции и фильтр масштабирования

Две версии с FILTER_LANCZOS совпадают при разных настройках getter; отдельный явный BILINEAR выполняется независимо от сохранённого NEAREST_PIXEL.
Две версии с FILTER_LANCZOS совпадают при разных настройках getter; отдельный явный BILINEAR выполняется независимо от сохранённого NEAREST_PIXEL.

Частая ошибка — считать возвращённое значение историей всех преобразований. Пусть объект хранит NEAREST_PIXEL. Если передать в конкретный вызов interpolativeResizeImage явный BILINEAR, этот вызов рассчитает билинейный результат. В проверенной сборке getter после него всё ещё возвращает NEAREST_PIXEL: отдельный аргумент операции не переписал сохранённую настройку.

$image->setImageInterpolateMethod(Imagick::INTERPOLATE_NEAREST_PIXEL);
$image->interpolativeResizeImage(400, 320, Imagick::INTERPOLATE_BILINEAR);
var_dump($image->getImageInterpolateMethod() === Imagick::INTERPOLATE_NEAREST_PIXEL);
// bool(true); пиксели при этом рассчитаны явным BILINEAR.

У resizeImage другая связь параметров: ему передаётся фильтр из FILTER_*. Это не константа INTERPOLATE_*. В контроле ниже два клона получили разные настройки интерполяции, но одинаковый явный FILTER_LANCZOS; их пиксели оказались одинаковыми. Наблюдение относится к данной операции и параметрам, а не утверждает, что настройка вообще нигде не используется.

$image->resizeImage(400, 320, Imagick::FILTER_LANCZOS, 1.0);

1.0 — параметр размытия фильтра в этом вызове. Для точной диагностики сравнивайте результаты на одном этапе: здесь контроль явного BILINEAR сравнивает два состояния Q16 до записи. PNG с глубиной 8 бит может округлить промежуточные значения; нельзя объявить методы различными, сравнив несохранённый Q16 с прочитанным PNG8.

Отличить настройку от явного аргумента операции и фильтра resizeImage

Явный BILINEAR в interpolativeResizeImage дал билинейные пиксели, хотя getter объекта всё ещё показывает NEAREST_PIXEL. Два resizeImage с одним FILTER_LANCZOS дали одинаковые пиксели при разных настройках интерполяции. Три ошибочных вызова перехвачены.

Отличить настройку от явного аргумента операции и фильтра resizeImageПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__ . '/interpolate-fixture.php';
ipRestore();
$source = new Imagick(__DIR__ . '/icon.png');
$sourceBefore = ipState($source);
$sourceHash = hash_file('sha256', __DIR__ . '/icon.png');
$configured = clone $source;
$configured->setImageInterpolateMethod(Imagick::INTERPOLATE_NEAREST_PIXEL);
$override = clone $configured;
$override->interpolativeResizeImage(400, 320, Imagick::INTERPOLATE_BILINEAR);
$bilinearControl = clone $source;
$bilinearControl->setImageInterpolateMethod(Imagick::INTERPOLATE_BILINEAR);
$bilinearControl->interpolativeResizeImage(400, 320, $bilinearControl->getImageInterpolateMethod());
$overrideEqualsBilinear = ipHash($override) === ipHash($bilinearControl);
$lanczos = [];
foreach ([Imagick::INTERPOLATE_NEAREST_PIXEL, Imagick::INTERPOLATE_BILINEAR] as $method) {
    $result = clone $source;
    $result->setImageInterpolateMethod($method);
    $result->resizeImage(400, 320, Imagick::FILTER_LANCZOS, 1.0);
    $lanczos[] = $result;
}
$errors = ['empty_get'=>ipTry(fn()=>(new Imagick())->getImageInterpolateMethod()),'empty_set'=>ipTry(fn()=>(new Imagick())->setImageInterpolateMethod(Imagick::INTERPOLATE_BILINEAR)),'array_method'=>ipTry(fn()=>$configured->setImageInterpolateMethod([]))];
$images = ['lanczos_nearest'=>ipImage($lanczos[0],'controls-lanczos-nearest8.png'),'lanczos_bilinear'=>ipImage($lanczos[1],'controls-lanczos-bilinear8.png'),'override'=>ipImage($override,'controls-override8.png')];
$rects = ipCompare([$lanczos[0],$lanczos[1],$override],'interpolate-controls.png');
ipDiagnostic('interpolate-controls',[
 'override_state'=>ipState($override),'bilinear_control'=>ipState($bilinearControl),'override_argument'=>Imagick::INTERPOLATE_BILINEAR,'comparison_stage'=>'Both Q16 pixel states before any save; save helpers only mutate clones','lanczos_states'=>array_map('ipState',$lanczos),'filter'=>Imagick::FILTER_LANCZOS,'errors'=>$errors,
 'images'=>$images,'panel_keys'=>['lanczos_nearest','lanczos_bilinear','override'],'panel_geometry'=>$rects,'source_before'=>$sourceBefore,'source_after'=>ipState($source),'source_sha256'=>$sourceHash,'source_unchanged'=>ipState($source)===$sourceBefore&&hash_file('sha256',__DIR__.'/icon.png')===$sourceHash,
 'checks'=>['explicit_argument_wins'=>$overrideEqualsBilinear,'getter_is_not_history'=>$override->getImageInterpolateMethod()===Imagick::INTERPOLATE_NEAREST_PIXEL,'lanczos_pixels_equal'=>ipHash($lanczos[0])===ipHash($lanczos[1]),'lanczos_settings_differ'=>$lanczos[0]->getImageInterpolateMethod()!==$lanczos[1]->getImageInterpolateMethod(),'empty_get_caught'=>($errors['empty_get']['error']['class']??null)==='ImagickException','empty_set_caught'=>($errors['empty_set']['error']['class']??null)==='ImagickException','array_method_caught'=>($errors['array_method']['error']['class']??null)==='TypeError']
]);
echo "interpolate-controls.png\ncontrols-lanczos-nearest8.png\ncontrols-lanczos-bilinear8.png\ncontrols-override8.png\nmetrics.json\noverride=BILINEAR stored=NEAREST_PIXEL lanczos-equal=yes errors=3\n";

Явный BILINEAR в interpolativeResizeImage дал билинейные пиксели, хотя getter объекта всё ещё показывает NEAREST_PIXEL. Два resizeImage с одним FILTER_LANCZOS дали одинаковые пиксели при разных настройках интерполяции. Три ошибочных вызова перехвачены. В архиве example.php, icon.png.b64 и interpolate-fixture.php. Распакуйте файлы рядом и выполните php example.php: собственный icon.png восстановится автоматически. Вспомогательный PHP целиком приведён в конце главы. Проверенная среда: PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16, Windows. Полные примеры требуют interpolativeResizeImage и константу INTERPOLATE_NEAREST_PIXEL, проверяют их наличие перед обработкой.

Ожидаемый вывод после настоящего запуска
interpolate-controls.png
controls-lanczos-nearest8.png
controls-lanczos-bilinear8.png
controls-override8.png
metrics.json
override=BILINEAR stored=NEAREST_PIXEL lanczos-equal=yes errors=3

Пустой Imagick не содержит изображения, у которого можно прочитать настройку. Три перехваченные ошибки в программе показывают отдельно getter без картинки, setter без картинки и неверный тип аргумента setter. try/catch позволяет получить понятное сообщение и сохранить отчёт; это практическое дополнение к механизму исключений.

Сохранить два результата и рецепт следующего запуска

Две версии, реально прочитанные из pixel-icon.png и smooth-preview.png: обработанные пиксели сохранены, настройка getter после чтения снова UNDEFINED.
Две версии, реально прочитанные из pixel-icon.png и smooth-preview.png: обработанные пиксели сохранены, настройка getter после чтения снова UNDEFINED.

Для каталога собственных иконок нужен повторяемый экспорт: пиксельная версия для демонстрации сетки и мягкое превью для сравнения. Функция exportIcon ниже принимает исходный Imagick, режим и имя файла. Она клонирует исходник, читает назначенный режим, применяет его и возвращает сведения о результате. Сам исходный icon.png остаётся 40×32.

$pixel = exportIcon($source, Imagick::INTERPOLATE_NEAREST_PIXEL, "pixel-icon.png");
$smooth = exportIcon($source, Imagick::INTERPOLATE_BILINEAR, "smooth-preview.png");

Объявление exportIcon приведено в полном примере. В результате рядом появятся два PNG 400×320 и recipe.json. Откройте изображения: в первом видны клетки, во втором — плавные границы. JSON содержит имя и SHA исходника, имя операции, размеры и символические имена методов. Он нужен для повторного экспорта, а не для отображения PNG браузером.

Выдать две версии PNG и сохранить воспроизводимый рецепт

Получены pixel-icon.png и smooth-preview.png размером 400×320, а также recipe.json с двумя символическими режимами и SHA исходника. После нового чтения PNG getter вернул UNDEFINED=0, но разные рассчитанные пиксели остались. Повтор из исходных 40×32 по рецепту дал тот же результат до кодирования PNG.

Выдать две версии PNG и сохранить воспроизводимый рецептПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__ . '/interpolate-fixture.php';
ipRestore();
$source = new Imagick(__DIR__ . '/icon.png');
$sourceBefore = ipState($source);
$sourceHash = hash_file('sha256', __DIR__ . '/icon.png');
function exportIcon(Imagick $source, int $method, string $filename): array
{
    $result = clone $source;
    $result->setImageInterpolateMethod($method);
    $selected = $result->getImageInterpolateMethod();
    $result->interpolativeResizeImage(400, 320, $selected);
    $beforeSave = ipState($result);
    $saved = ipSave($result, $filename);
    return ['selected'=>$selected,'before_save'=>$beforeSave,'saved'=>$saved];
}
$exports = [
    'pixel'=>exportIcon($source, Imagick::INTERPOLATE_NEAREST_PIXEL, 'pixel-icon.png'),
    'smooth'=>exportIcon($source, Imagick::INTERPOLATE_BILINEAR, 'smooth-preview.png'),
];
$recipe = [
    'source'=>'icon.png',
    'source_sha256'=>$sourceHash,
    'operation'=>'interpolativeResizeImage',
    'width'=>400, 'height'=>320,
    'variants'=>[
        ['file'=>'pixel-icon.png','method'=>'NEAREST_PIXEL'],
        ['file'=>'smooth-preview.png','method'=>'BILINEAR'],
    ],
];
file_put_contents(__DIR__ . '/recipe.json', json_encode(
    $recipe, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR
) . "\n");
$readRecipe = json_decode((string)file_get_contents(__DIR__.'/recipe.json'),true,512,JSON_THROW_ON_ERROR);
$methodMap = ['NEAREST_PIXEL'=>Imagick::INTERPOLATE_NEAREST_PIXEL,'BILINEAR'=>Imagick::INTERPOLATE_BILINEAR];
$reads = [];
$replays = [];
foreach ($readRecipe['variants'] as $variant) {
    $read = new Imagick(__DIR__ . '/' . $variant['file']);
    $reads[] = $read;
    $replay = clone $source;
    $replay->setImageInterpolateMethod($methodMap[$variant['method']]);
    $selected = $replay->getImageInterpolateMethod();
    $replay->interpolativeResizeImage($readRecipe['width'], $readRecipe['height'], $selected);
    $expected = $variant['method']==='NEAREST_PIXEL' ? $exports['pixel'] : $exports['smooth'];
    $replays[] = ['method'=>$selected,'source_geometry'=>[40,32],'pre_save_equal'=>ipHash($replay)===$expected['before_save']['RGBA16_sha256']];
}
$images = ['pixel'=>ipImage($reads[0],'workflow-pixel8.png'),'smooth'=>ipImage($reads[1],'workflow-smooth8.png')];
$rects = ipCompare($reads,'interpolate-workflow.png');
ipDiagnostic('interpolate-workflow',[
 'exports'=>$exports,'readback'=>array_map('ipState',$reads),'recipe'=>$readRecipe,'recipe_sha256'=>hash_file('sha256',__DIR__.'/recipe.json'),'replays'=>$replays,
 'images'=>$images,'panel_keys'=>['pixel','smooth'],'panel_geometry'=>$rects,'source_before'=>$sourceBefore,'source_after'=>ipState($source),'source_sha256'=>$sourceHash,'source_unchanged'=>ipState($source)===$sourceBefore&&hash_file('sha256',__DIR__.'/icon.png')===$sourceHash,
 'checks'=>['selected_methods'=>$exports['pixel']['selected']===Imagick::INTERPOLATE_NEAREST_PIXEL&&$exports['smooth']['selected']===Imagick::INTERPOLATE_BILINEAR,'readback_setting_undefined'=>$reads[0]->getImageInterpolateMethod()===Imagick::INTERPOLATE_UNDEFINED&&$reads[1]->getImageInterpolateMethod()===Imagick::INTERPOLATE_UNDEFINED,'readback_pixels_differ'=>ipHash($reads[0])!==ipHash($reads[1]),'readback_geometry'=>$reads[0]->getImageGeometry()===['width'=>400,'height'=>320]&&$reads[1]->getImageGeometry()===['width'=>400,'height'=>320],'recipe_bound'=>$readRecipe['source_sha256']===$sourceHash,'replay_from_original_equal'=>$replays[0]['pre_save_equal']&&$replays[1]['pre_save_equal']]
]);
echo "interpolate-workflow.png\nworkflow-pixel8.png\nworkflow-smooth8.png\npixel-icon.png\nsmooth-preview.png\nrecipe.json\nmetrics.json\nexports=2 PNG-setting=UNDEFINED recipe=2-variants replay-from-original=equal\n";

Получены pixel-icon.png и smooth-preview.png размером 400×320, а также recipe.json с двумя символическими режимами и SHA исходника. После нового чтения PNG getter вернул UNDEFINED=0, но разные рассчитанные пиксели остались. Повтор из исходных 40×32 по рецепту дал тот же результат до кодирования PNG. В архиве example.php, icon.png.b64 и interpolate-fixture.php. Распакуйте файлы рядом и выполните php example.php: собственный icon.png восстановится автоматически. Вспомогательный PHP целиком приведён в конце главы. Проверенная среда: PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16, Windows. Полные примеры требуют interpolativeResizeImage и константу INTERPOLATE_NEAREST_PIXEL, проверяют их наличие перед обработкой.

Ожидаемый вывод после настоящего запуска
interpolate-workflow.png
workflow-pixel8.png
workflow-smooth8.png
pixel-icon.png
smooth-preview.png
recipe.json
metrics.json
exports=2 PNG-setting=UNDEFINED recipe=2-variants replay-from-original=equal

Новый Imagick из любого из этих PNG вернул UNDEFINED. Это не отменяет обработки: файл уже содержит её результат. Getter не определяет по внешнему виду, каким алгоритмом файл когда-то создан. Настройку для следующего преобразования назначают заново. Для воспроизводимого повтора программа читает recipe.json и начинает с исходных 40×32; повторное увеличение уже увеличенного файла было бы другой цепочкой операций.

В рецепте записаны NEAREST_PIXEL и BILINEAR, а не числа 10 и 5. Небольшой явный массив сопоставляет разрешённые имена с константами. Проверка SHA связывает рецепт с конкретным исходником, но не удостоверяет автора. В производственном обработчике дополнительно проверяют разрешённые пути и диапазоны размеров: здесь файлы и размеры собственные, фиксированные. Для разных версий ImageMagick сохраните версию среды и сравните итоговые файлы, если требуется повторяемость между машинами.

Если картинка кажется размытой только на странице, откройте PNG в его настоящем размере и проверьте CSS-размер: браузер может выполнить ещё одно масштабирование. Для пиксельной графики рассмотрите подходящий режим её отображения отдельно. Ни установка getter/setter, ни параметр качества JPEG сами по себе не создают недостающих деталей. Связанные темы: масштабирование и пропорции, запись и чтение файлов и структура JSON-документа.

Полный контракт getter, ошибки, ограничения и упражнения

Imagick::getImageInterpolateMethod: полный контракт

Imagick::getImageInterpolateMethod(): int

Метод читает настройку интерполяции текущего изображения в объекте Imagick. Обязательных и необязательных аргументов нет: скобки остаются пустыми. При успехе возвращается int — одна из констант Imagick::INTERPOLATE_*. Он не возвращает новое изображение и не запускает пересчёт пикселей. Официальная доступность: PECL imagick 2, PECL imagick 3. Отдельного changelog у официальной страницы нет.

Что читаемЧто означаетЧто из этого не следует
INTERPOLATE_UNDEFINEDВ изображении нет явно выбранного режима. В нашем PNG это int(0).Это не false и не ошибка; нельзя объявить одним этим числом алгоритм любой последующей операции.
INTERPOLATE_NEAREST_PIXELВыбран ближайший пиксель; это имя доступно в проверенной сборке ImageMagick 7.Оно не запускает увеличение и не выбирает фильтр resizeImage.
INTERPOLATE_BILINEARВыбрана билинейная интерполяция.Это не гарантия лучшего качества для каждого изображения и масштаба.
Другая константа INTERPOLATE_*Другой режим, поддерживаемый данной сборкой.Пример распознаёт только три состояния; остальные не следует молча переименовывать в BILINEAR.

Числа 0, 10 и 5 в этой главе — наблюдения нашей сборки, а не числа для подстановки в переносимый код. Сравнивайте с именованными константами. Историческое имя INTERPOLATE_NEARESTNEIGHBOR не определено в проверенной сборке ImageMagick 7; поэтому оно не используется в программах. Проверяйте defined для нужного имени и method_exists для операции, которую собираетесь выполнить. Условия её наличия зависят от версии и сборки расширения.

Официальный раздел ошибок указывает ImagickException. Реальный вызов getter на new Imagick() без изображения дал ImagickException: сначала прочитайте файл или создайте изображение. Setter на пустом объекте тоже дал ImagickException, массив вместо его int-аргумента — TypeError. Эти два последних условия относятся к setter, а не к безаргументному getter. Обработка ошибок не заменяет проверку доступности расширения и поддерживаемых методов.

$image = new Imagick(__DIR__ . "/icon.png");
$method = $image->getImageInterpolateMethod();
if ($method === Imagick::INTERPOLATE_UNDEFINED) {
    echo "Режим явно не выбран";
}

Getter смотрит на текущее изображение; при нескольких кадрах сначала выберите нужный кадр или перебирайте их. После клонирования изменение настройки клона не должно использоваться как проверка настройки исходника: читайте нужный объект. Getter также не является журналом обработки: операция могла получить собственный явный параметр, а после чтения сохранённого файла настройка может не восстановиться. В наших PNG повторное чтение вернуло UNDEFINED при сохранённых результатах обработки.

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

Запуск и проверка понимания

Каждый архив содержит example.php, icon.png.b64 и interpolate-fixture.php. Распакуйте всё рядом, затем выполните php example.php. Исходная иконка восстанавливается автоматически. Проверенная среда — PHP 8.5.11, Imagick 3.8.1, ImageMagick 7.1.1-46 Q16. Четыре программы действительно вызывают getter; вспомогательная операция interpolativeResizeImage подтверждена исходниками расширения и запуском. Её отдельная страница PHP.net в момент подготовки не была доступна, поэтому ссылка дана на исходный интерфейс расширения.

Упражнение: getter вернул 0 после чтения уже увеличенного PNG. Исчезло ли увеличение? Нет: проверьте размеры и сами пиксели; 0 относится к текущей настройке, а не к истории файла. Второе упражнение: getter показывает NEAREST_PIXEL, но явный третий аргумент операции — BILINEAR. Чем обработаны пиксели? В нашем контроле — BILINEAR. Третье упражнение: после назначения режима размер по-прежнему 40×32. Ошибка ли это? Нет, для изменения размера нужна отдельная операция. Четвёртое упражнение: обязательно ли NEAREST_PIXEL лучше для фотографии? Нет: он сохраняет дискретный вид, который может быть нежелателен для такой задачи.

Полный вспомогательный PHP из каждого архива
<?php
declare(strict_types=1);
function ipRestore(): void {
    $hashes = json_decode('{"icon.png":"60338b8053d2145687ce95bea04f4f53e1ec736cb5252c696695816705e44194"}', true, 512, JSON_THROW_ON_ERROR);
    foreach ($hashes as $name => $hash) {
        $raw = base64_decode((string) file_get_contents(__DIR__ . '/' . $name . '.b64'), true);
        if ($raw === false || hash('sha256', $raw) !== $hash || file_put_contents(__DIR__ . '/' . $name, $raw) === false) {
            throw new RuntimeException('Input missing or changed');
        }
    }
    if (!method_exists(Imagick::class, 'interpolativeResizeImage') || !defined('Imagick::INTERPOLATE_NEAREST_PIXEL')) {
        throw new RuntimeException('This example requires the demonstrated Imagick/ImageMagick 7 interpolation API');
    }
}
function ipHash(Imagick $image): string {
    return hash('sha256', json_encode($image->exportImagePixels(0, 0, $image->getImageWidth(), $image->getImageHeight(), 'RGBA', Imagick::PIXEL_SHORT), JSON_THROW_ON_ERROR));
}
function ipName(int $method): string {
    return match ($method) {
        Imagick::INTERPOLATE_UNDEFINED => 'UNDEFINED',
        Imagick::INTERPOLATE_NEAREST_PIXEL => 'NEAREST_PIXEL',
        Imagick::INTERPOLATE_BILINEAR => 'BILINEAR',
        default => 'OTHER(' . $method . ')',
    };
}
function ipState(Imagick $image): array {
    $method = $image->getImageInterpolateMethod();
    return ['geometry'=>[$image->getImageWidth(),$image->getImageHeight()], 'RGBA16_sha256'=>ipHash($image), 'method'=>$method, 'method_name'=>ipName($method)];
}
function ipSave(Imagick $image, string $name): array {
    $copy = clone $image;
    $copy->setImageFormat('png');
    $copy->setImageDepth(8);
    $copy->setOption('png:bit-depth', '8');
    $copy->setOption('png:color-type', '2');
    $copy->setOption('png:exclude-chunk', 'all');
    if (!$copy->writeImage(__DIR__ . '/' . $name)) throw new RuntimeException('Cannot save PNG');
    $read = new Imagick(__DIR__ . '/' . $name);
    return ['filename'=>$name,'sha256'=>hash_file('sha256',__DIR__.'/'.$name),'bytes'=>filesize(__DIR__.'/'.$name),'state'=>ipState($read)];
}
function ipImage(Imagick $image, string $name): array {
    $saved = ipSave($image, $name);
    return ['geometry'=>[$image->getImageWidth(),$image->getImageHeight()],'RGBA16_sha256'=>ipHash($image),'encoded_png'=>['filename'=>$name,'RGBA16_sha256'=>$saved['state']['RGBA16_sha256']],'display_basis'=>'Actual PHP raster; encoded PNG readback is distinct from pre-save Q16 state'];
}
function ipPreview(Imagick $image): Imagick {
    $copy = clone $image;
    $copy->sampleImage(400,320);
    return $copy;
}
function ipCompare(array $images, string $name): array {
    $canvas = new Imagick();
    $canvas->newImage(400*count($images),320,'white','png');
    $rects=[];
    foreach($images as $n=>$image) {
        $canvas->compositeImage($image,Imagick::COMPOSITE_COPY,400*$n,0);
        $rects[]=['x'=>400*$n,'y'=>0,'width'=>400,'height'=>320];
    }
    ipSave($canvas,$name);
    return $rects;
}
function ipTry(callable $fn): array {
    try { $value=$fn();return ['type'=>get_debug_type($value),'returned'=>$value]; }
    catch(Throwable $e) { return ['error'=>['class'=>get_class($e),'message'=>$e->getMessage()]]; }
}
function ipDiagnostic(string $id,array $data):void {
    $doc=['schema'=>'aen-interpolate-method-program-diagnostics-v1','example_id'=>$id,'runtime'=>['php'=>PHP_VERSION,'imagick'=>phpversion('imagick'),'imagemagick'=>Imagick::getVersion()],'constants'=>['UNDEFINED'=>Imagick::INTERPOLATE_UNDEFINED,'NEAREST_PIXEL'=>Imagick::INTERPOLATE_NEAREST_PIXEL,'BILINEAR'=>Imagick::INTERPOLATE_BILINEAR]]+$data;
    if(file_put_contents(__DIR__.'/metrics.json',json_encode($doc,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR)."\n")===false)throw new RuntimeException('Cannot save metrics');
}

ipRestore восстанавливает собственный вход и проверяет нужный API. ipState читает текущую настройку, размеры и пиксели для отчёта; ipPreview увеличивает маленький исходник исключительно для просмотра. ipSave сохраняет клон как PNG8 и читает его обратно, не меняя исследуемый объект. Это разделяет исходное Q16-состояние и действительно закодированные пиксели. metrics.json содержит фактические результаты, но для использования метода достаточно первых коротких фрагментов.

Практические вопросы и источники

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

ImageMagick resize without interpolation: Увеличение маленькой карты смешивает цвета вместо сохранения видимой сетки. Сравниваем два собственных результата и явно передаём режим операции; getter служит проверкой настройки.

Resize image programatically to get the same result as a browser: Файл превью выглядит иначе, чем большое изображение, уменьшенное браузером. Сравниваем фактические файлы одинакового размера и поясняем дополнительное масштабирование страницы.

Resize an image with 54x54 squares (540x540) to 54x54pixel lossless: Сетка цветных квадратов теряет чёткость при пересчёте размеров. Разделяем цель сохранения клеток и сглаживания; выбор режима зависит от содержимого и масштаба, а не от универсального числа качества.

preventing resized images from becoming blurred: После увеличения малого изображения автор получает размытый файл. Показываем исходные размеры и действительный результат; увеличение не восстанавливает неизвестные детали.

PHP Imagick: copy image object to another image object but with bigger resolution: Копирование и изменение resolution не дают ожидаемого нового растрового размера. Проверяем независимую настройку клона и отличаем сохранённое состояние от отдельного пересчёта пикселей.

PHP Imagick - Text and Lines not clear/smooth after resize: Тонкие линии и текст выглядят плохо после resize, crop и композиции. Отделяем параметры конкретной операции и проверяем её результат; getter не заменяет выбор фильтра и сравнение в целевом размере.

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

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

Imagick::getImageInterpolateMethodПрочитать настройку интерполяции и проверить реальную обработку

PECL imagick 2, PECL imagick 3 · imagick

Imagick::getImageInterpolateMethod(): int

Imagick::getImageInterpolateMethod: полный контракт

Imagick::getImageInterpolateMethod(): int

Метод читает настройку интерполяции текущего изображения в объекте Imagick. Обязательных и необязательных аргументов нет: скобки остаются пустыми. При успехе возвращается int — одна из констант Imagick::INTERPOLATE_*. Он не возвращает новое изображение и не запускает пересчёт пикселей. Официальная доступность: PECL imagick 2, PECL imagick 3. Отдельного changelog у официальной страницы нет.

Что читаемЧто означаетЧто из этого не следует
INTERPOLATE_UNDEFINEDВ изображении нет явно выбранного режима. В нашем PNG это int(0).Это не false и не ошибка; нельзя объявить одним этим числом алгоритм любой последующей операции.
INTERPOLATE_NEAREST_PIXELВыбран ближайший пиксель; это имя доступно в проверенной сборке ImageMagick 7.Оно не запускает увеличение и не выбирает фильтр resizeImage.
INTERPOLATE_BILINEARВыбрана билинейная интерполяция.Это не гарантия лучшего качества для каждого изображения и масштаба.
Другая константа INTERPOLATE_*Другой режим, поддерживаемый данной сборкой.Пример распознаёт только три состояния; остальные не следует молча переименовывать в BILINEAR.

Числа 0, 10 и 5 в этой главе — наблюдения нашей сборки, а не числа для подстановки в переносимый код. Сравнивайте с именованными константами. Историческое имя INTERPOLATE_NEARESTNEIGHBOR не определено в проверенной сборке ImageMagick 7; поэтому оно не используется в программах. Проверяйте defined для нужного имени и method_exists для операции, которую собираетесь выполнить. Условия её наличия зависят от версии и сборки расширения.

Официальный раздел ошибок указывает ImagickException. Реальный вызов getter на new Imagick() без изображения дал ImagickException: сначала прочитайте файл или создайте изображение. Setter на пустом объекте тоже дал ImagickException, массив вместо его int-аргумента — TypeError. Эти два последних условия относятся к setter, а не к безаргументному getter. Обработка ошибок не заменяет проверку доступности расширения и поддерживаемых методов.

$image = new Imagick(__DIR__ . "/icon.png");
$method = $image->getImageInterpolateMethod();
if ($method === Imagick::INTERPOLATE_UNDEFINED) {
    echo "Режим явно не выбран";
}

Getter смотрит на текущее изображение; при нескольких кадрах сначала выберите нужный кадр или перебирайте их. После клонирования изменение настройки клона не должно использоваться как проверка настройки исходника: читайте нужный объект. Getter также не является журналом обработки: операция могла получить собственный явный параметр, а после чтения сохранённого файла настройка может не восстановиться. В наших PNG повторное чтение вернуло UNDEFINED при сохранённых результатах обработки.

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

Прочитать настройку и убедиться, что сам рисунок не изменился

Getter вернул целое значение выбранного режима. В проверенной сборке исходный PNG имел UNDEFINED=0, после setter — NEAREST_PIXEL=10. Сам исходник остался 40×32 с прежними пикселями; две одинаковые картинки 400×320 — отдельное увеличение 10× для просмотра.

Прочитать настройку и убедиться, что сам рисунок не изменилсяПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__ . '/interpolate-fixture.php';
ipRestore();
$source = new Imagick(__DIR__ . '/icon.png');
$sourceBefore = ipState($source);
$sourceHash = hash_file('sha256', __DIR__ . '/icon.png');
$image = clone $source;
$before = ipState($image);
$setResult = $image->setImageInterpolateMethod(Imagick::INTERPOLATE_NEAREST_PIXEL);
$method = $image->getImageInterpolateMethod();
$after = ipState($image);
$left = ipPreview($source);
$right = ipPreview($image);
$images = ['before'=>ipImage($left,'first-before8.png'),'after'=>ipImage($right,'first-after8.png')];
$rects = ipCompare([$left,$right],'interpolate-first.png');
ipDiagnostic('interpolate-first',[
 'before'=>$before,'after'=>$after,'set_return'=>$setResult,'get_type'=>get_debug_type($method),'get_value'=>$method,'display'=>['source_geometry'=>[40,32],'preview_geometry'=>[400,320],'preview_method'=>'sampleImage','scale'=>10],
 'images'=>$images,'panel_keys'=>['before','after'],'panel_geometry'=>$rects,'source_before'=>$sourceBefore,'source_after'=>ipState($source),'source_sha256'=>$sourceHash,'source_unchanged'=>ipState($source)===$sourceBefore&&hash_file('sha256',__DIR__.'/icon.png')===$sourceHash,
 'checks'=>['default_undefined'=>$before['method']===Imagick::INTERPOLATE_UNDEFINED,'setter_true'=>$setResult===true,'getter_int'=>is_int($method),'getter_matches_setting'=>$method===Imagick::INTERPOLATE_NEAREST_PIXEL,'pixels_unchanged'=>$before['RGBA16_sha256']===$after['RGBA16_sha256'],'geometry_unchanged'=>$after['geometry']===[40,32],'display_equal'=>ipHash($left)===ipHash($right)]
]);
echo "interpolate-first.png\nfirst-before8.png\nfirst-after8.png\nmetrics.json\nbefore=UNDEFINED after=NEAREST_PIXEL getter=int pixels=unchanged size=40x32\n";

Getter вернул целое значение выбранного режима. В проверенной сборке исходный PNG имел UNDEFINED=0, после setter — NEAREST_PIXEL=10. Сам исходник остался 40×32 с прежними пикселями; две одинаковые картинки 400×320 — отдельное увеличение 10× для просмотра. В архиве example.php, icon.png.b64 и interpolate-fixture.php. Распакуйте файлы рядом и выполните php example.php: собственный icon.png восстановится автоматически. Вспомогательный PHP целиком приведён в конце главы. Проверенная среда: PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16, Windows. Полные примеры требуют interpolativeResizeImage и константу INTERPOLATE_NEAREST_PIXEL, проверяют их наличие перед обработкой.

Ожидаемый вывод после настоящего запуска
interpolate-first.png
first-before8.png
first-after8.png
metrics.json
before=UNDEFINED after=NEAREST_PIXEL getter=int pixels=unchanged size=40x32

Выдать две версии PNG и сохранить воспроизводимый рецепт

Получены pixel-icon.png и smooth-preview.png размером 400×320, а также recipe.json с двумя символическими режимами и SHA исходника. После нового чтения PNG getter вернул UNDEFINED=0, но разные рассчитанные пиксели остались. Повтор из исходных 40×32 по рецепту дал тот же результат до кодирования PNG.

Выдать две версии PNG и сохранить воспроизводимый рецептПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__ . '/interpolate-fixture.php';
ipRestore();
$source = new Imagick(__DIR__ . '/icon.png');
$sourceBefore = ipState($source);
$sourceHash = hash_file('sha256', __DIR__ . '/icon.png');
function exportIcon(Imagick $source, int $method, string $filename): array
{
    $result = clone $source;
    $result->setImageInterpolateMethod($method);
    $selected = $result->getImageInterpolateMethod();
    $result->interpolativeResizeImage(400, 320, $selected);
    $beforeSave = ipState($result);
    $saved = ipSave($result, $filename);
    return ['selected'=>$selected,'before_save'=>$beforeSave,'saved'=>$saved];
}
$exports = [
    'pixel'=>exportIcon($source, Imagick::INTERPOLATE_NEAREST_PIXEL, 'pixel-icon.png'),
    'smooth'=>exportIcon($source, Imagick::INTERPOLATE_BILINEAR, 'smooth-preview.png'),
];
$recipe = [
    'source'=>'icon.png',
    'source_sha256'=>$sourceHash,
    'operation'=>'interpolativeResizeImage',
    'width'=>400, 'height'=>320,
    'variants'=>[
        ['file'=>'pixel-icon.png','method'=>'NEAREST_PIXEL'],
        ['file'=>'smooth-preview.png','method'=>'BILINEAR'],
    ],
];
file_put_contents(__DIR__ . '/recipe.json', json_encode(
    $recipe, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR
) . "\n");
$readRecipe = json_decode((string)file_get_contents(__DIR__.'/recipe.json'),true,512,JSON_THROW_ON_ERROR);
$methodMap = ['NEAREST_PIXEL'=>Imagick::INTERPOLATE_NEAREST_PIXEL,'BILINEAR'=>Imagick::INTERPOLATE_BILINEAR];
$reads = [];
$replays = [];
foreach ($readRecipe['variants'] as $variant) {
    $read = new Imagick(__DIR__ . '/' . $variant['file']);
    $reads[] = $read;
    $replay = clone $source;
    $replay->setImageInterpolateMethod($methodMap[$variant['method']]);
    $selected = $replay->getImageInterpolateMethod();
    $replay->interpolativeResizeImage($readRecipe['width'], $readRecipe['height'], $selected);
    $expected = $variant['method']==='NEAREST_PIXEL' ? $exports['pixel'] : $exports['smooth'];
    $replays[] = ['method'=>$selected,'source_geometry'=>[40,32],'pre_save_equal'=>ipHash($replay)===$expected['before_save']['RGBA16_sha256']];
}
$images = ['pixel'=>ipImage($reads[0],'workflow-pixel8.png'),'smooth'=>ipImage($reads[1],'workflow-smooth8.png')];
$rects = ipCompare($reads,'interpolate-workflow.png');
ipDiagnostic('interpolate-workflow',[
 'exports'=>$exports,'readback'=>array_map('ipState',$reads),'recipe'=>$readRecipe,'recipe_sha256'=>hash_file('sha256',__DIR__.'/recipe.json'),'replays'=>$replays,
 'images'=>$images,'panel_keys'=>['pixel','smooth'],'panel_geometry'=>$rects,'source_before'=>$sourceBefore,'source_after'=>ipState($source),'source_sha256'=>$sourceHash,'source_unchanged'=>ipState($source)===$sourceBefore&&hash_file('sha256',__DIR__.'/icon.png')===$sourceHash,
 'checks'=>['selected_methods'=>$exports['pixel']['selected']===Imagick::INTERPOLATE_NEAREST_PIXEL&&$exports['smooth']['selected']===Imagick::INTERPOLATE_BILINEAR,'readback_setting_undefined'=>$reads[0]->getImageInterpolateMethod()===Imagick::INTERPOLATE_UNDEFINED&&$reads[1]->getImageInterpolateMethod()===Imagick::INTERPOLATE_UNDEFINED,'readback_pixels_differ'=>ipHash($reads[0])!==ipHash($reads[1]),'readback_geometry'=>$reads[0]->getImageGeometry()===['width'=>400,'height'=>320]&&$reads[1]->getImageGeometry()===['width'=>400,'height'=>320],'recipe_bound'=>$readRecipe['source_sha256']===$sourceHash,'replay_from_original_equal'=>$replays[0]['pre_save_equal']&&$replays[1]['pre_save_equal']]
]);
echo "interpolate-workflow.png\nworkflow-pixel8.png\nworkflow-smooth8.png\npixel-icon.png\nsmooth-preview.png\nrecipe.json\nmetrics.json\nexports=2 PNG-setting=UNDEFINED recipe=2-variants replay-from-original=equal\n";

Получены pixel-icon.png и smooth-preview.png размером 400×320, а также recipe.json с двумя символическими режимами и SHA исходника. После нового чтения PNG getter вернул UNDEFINED=0, но разные рассчитанные пиксели остались. Повтор из исходных 40×32 по рецепту дал тот же результат до кодирования PNG. В архиве example.php, icon.png.b64 и interpolate-fixture.php. Распакуйте файлы рядом и выполните php example.php: собственный icon.png восстановится автоматически. Вспомогательный PHP целиком приведён в конце главы. Проверенная среда: PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16, Windows. Полные примеры требуют interpolativeResizeImage и константу INTERPOLATE_NEAREST_PIXEL, проверяют их наличие перед обработкой.

Ожидаемый вывод после настоящего запуска
interpolate-workflow.png
workflow-pixel8.png
workflow-smooth8.png
pixel-icon.png
smooth-preview.png
recipe.json
metrics.json
exports=2 PNG-setting=UNDEFINED recipe=2-variants replay-from-original=equal
Источники и обсуждения

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

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

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

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