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

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

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

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

Глава 434 · После первых изображений, файлов и методов

Gmagick: rendering intent, сравнение результатов и воспроизводимый экспорт

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

Выбрать правило преобразования, не меняя пиксели setter-ом

Сервису нужно явно выбрать правило цветового преобразования. Rendering intent отвечает за то, как преобразователь трактует различия между исходным и целевым цветовыми охватами и белой точкой. Это не сам профиль и не фильтр «сделать красивее». Первый опыт только задаёт правило: карточка остаётся с теми же P3-числами.

Тот же P3-исходник: выбран Relative; setter не пересчитал RGB
Тот же P3-исходник: выбран Relative; setter не пересчитал RGB

Это настоящие PNG данной программы. Цвет на экране зависит от монитора и поддержки профилей браузером; утверждения о равенстве RGB и ICC проверяются по сохранённым файлам, а не только на глаз.

$image = new Gmagick(__DIR__ . "/source-p3.png");
$image->setImageRenderingIntent(Gmagick::RENDERINGINTENT_RELATIVE);
$intent = $image->getImageRenderingIntent();
echo $intent;

Здесь выводится 4 — значение именованной константы Relative в проверенной сборке. В приложении используйте константу, а не запомненное число. Getter возвращает int, setter — тот же Gmagick. Профиль отвечает, что означают RGB; intent выбирает правило для последующего преобразования. Сам setter сохраняет параметры и не пересчитывает пиксели. Новый вход этой главы сообщает Undefined (0), то есть явно выбранного правила в объекте нет. После записи PNG с нашим ICC и повторного чтения getter снова сообщает 0, даже если перед записью было 4. Это не доказывает, что преобразования не было или что программа применяла другое правило: состояние рецепта не обязано сохраняться в этом файле. Для аудита сохраняем intent.json.

КонстантаЗначение в проверенной сборкеРоль
RENDERINGINTENT_UNDEFINED0Правило явно не задано; не синоним безопасного выбора.
RENDERINGINTENT_SATURATION1Приоритет насыщенности; результат зависит от профилей/CMS.
RENDERINGINTENT_PERCEPTUAL2Воспринимаемые отношения цветов и тонов.
RENDERINGINTENT_ABSOLUTE3Абсолютное сопоставление, в частности имитация носителя.
RENDERINGINTENT_RELATIVE4Сопоставление с учётом относительной белой точки.

Это числовые значения API Gmagick, а не нумерация поля intent внутри бинарного формата ICC или PNG. В коде используйте имена констант.

Выбрать правило преобразования, не меняя пиксели setter-омСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__ . '/gm103-profile-fixture.php';
gmRestore();

$image = new Gmagick(__DIR__ . '/source-p3.png');
$before = $image->getImageRenderingIntent();
$signature = $image->getImageSignature();
$returned = $image->setImageRenderingIntent(Gmagick::RENDERINGINTENT_RELATIVE);
$selected = $image->getImageRenderingIntent();
gmPng($image, 'gm103-intent-read-set-selected.png');
$saved = new Gmagick(__DIR__ . '/gm103-intent-read-set-selected.png');
$receipt = ['before' => $before, 'selected' => $selected,
    'after_png_read' => $saved->getImageRenderingIntent(), 'pixels_changed' => false];
file_put_contents(__DIR__ . '/gm103-intent-read-set-intent.json', json_encode($receipt, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));

$checks = [
    'getter_is_integer' => is_int($before) && is_int($selected),
    'selected_relative' => $selected === Gmagick::RENDERINGINTENT_RELATIVE,
    'setter_returns_same_object' => $returned === $image,
    'pixels_unchanged' => $signature === $image->getImageSignature(),
    'saved_png_not_recipe' => $saved->getImageRenderingIntent() === Gmagick::RENDERINGINTENT_UNDEFINED
];
gmReport('gm103-intent-read-set', ["gmagick.getimagerenderingintent", "gmagick.setimagerenderingintent"], ["gm103-intent-read-set-selected.png"], $checks, $errors ?? [], $receipt);
echo "intent-select: selected=relative(4); RGB unchanged; PNG readback=undefined(0)\n";
Ожидаемый результат
intent-select: selected=relative(4); RGB unchanged; PNG readback=undefined(0)

Распакуйте пример и выполните php example.php с установленным Gmagick и поддержкой PNG/ICC в GraphicsMagick. В комплекте известные входы в base64, их SHA256, лицензия ICC и gm103-profile-fixture.php. Helper восстанавливает входы, пишет PNG 8 бит/канал и metrics.json; gmSamePixels сравнивает реально сохранённые пиксели. Код операции показан коротко выше; полный пример создаёт перечисленные PNG и квитанции самостоятельно. Сырые бинарные ICC не выводятся на экран.

Упражнение: вызвать только setImageRenderingIntent и считать, что P3 уже превратился в sRGB. Не хватает profileImage с действительным целевым ICC. В следующем опыте обе операции соединены; отдельно проверяются заданное правило, результат по RGB и профиль записанного PNG.

Опорные понятия: объект и вызов метода, параметр и возвращаемое значение, исключения, clone. Связанные задачи: пропорциональные превью, цветовые координаты.

Сравнить четыре намерения на одном известном источнике

Как выбрать intent осмысленно? Сначала сопоставить реальные результаты одной задачи. Здесь один P3-оригинал преобразуется в один sRGB-профиль с четырьмя правилами. Все четыре PNG показываются открыто; comparison.json записывает, совпали ли их реальные RGB с Relative. Мы не рисуем искусственные различия ради иллюстрации.

P3 → sRGB: Perceptual; сравниваем реальные RGB, не ожидаем эффект фильтра
P3 → sRGB: Perceptual; сравниваем реальные RGB, не ожидаем эффект фильтра
P3 → sRGB: Relative; сравниваем реальные RGB, не ожидаем эффект фильтра
P3 → sRGB: Relative; сравниваем реальные RGB, не ожидаем эффект фильтра
P3 → sRGB: Saturation; сравниваем реальные RGB, не ожидаем эффект фильтра
P3 → sRGB: Saturation; сравниваем реальные RGB, не ожидаем эффект фильтра
P3 → sRGB: Absolute; сравниваем реальные RGB, не ожидаем эффект фильтра
P3 → sRGB: Absolute; сравниваем реальные RGB, не ожидаем эффект фильтра

Это настоящие PNG данной программы. Цвет на экране зависит от монитора и поддержки профилей браузером; утверждения о равенстве RGB и ICC проверяются по сохранённым файлам, а не только на глаз.

$image->setImageRenderingIntent(Gmagick::RENDERINGINTENT_PERCEPTUAL);
$image->profileImage("icm", $targetProfileBytes);
$image->writeImage("perceptual.png");

Perceptual предназначен для сохранения воспринимаемых отношений цветов при отображении охвата; Relative согласует белую точку и сохраняет соответствия внутри охвата; обработка неохватываемых цветов зависит от преобразователя; Absolute учитывает абсолютный цвет белого и применяется, в частности, в сценариях пробной печати; Saturation отдаёт приоритет насыщенности, например для диаграмм. Реальное поведение зависит от CMS, профилей и их таблиц. Это не четыре художественных пресета. Наши компактные RGB-профили матричные; у таких профилей разные intents могут дать одинаковые пиксели. Программа не делает вывод о выполнении вызова из видимого различия: getter подтверждает выбранное значение, а PNG проверяется отдельно. foreach перебирает словарь «понятное имя → константа»; clone каждый раз начинает с того же оригинала, поэтому одно преобразование не наслаивается на другое.

Сравнить четыре намерения на одном известном источникеСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__ . '/gm103-profile-fixture.php';
gmRestore();

$source = new Gmagick(__DIR__ . '/source-p3.png');
$target = file_get_contents(__DIR__ . '/target-srgb.icc');
$intents = ['perceptual' => Gmagick::RENDERINGINTENT_PERCEPTUAL,
    'relative' => Gmagick::RENDERINGINTENT_RELATIVE,
    'saturation' => Gmagick::RENDERINGINTENT_SATURATION,
    'absolute' => Gmagick::RENDERINGINTENT_ABSOLUTE];
$receipt = [];
foreach ($intents as $name => $intent) {
    $image = clone $source;
    $image->setImageRenderingIntent($intent);
    $image->profileImage('icm', $target);
    $filename = 'gm103-intent-compare-' . $name . '.png';
    gmPng($image, $filename);
    $receipt[$name] = ['requested' => $intent, 'selected' => $image->getImageRenderingIntent(),
        'profile_sha256' => hash('sha256', $image->getImageProfile('icm')),
        'same_RGB_as_relative' => null, 'file' => $filename];
}
foreach ($receipt as &$row) {
    $row['same_RGB_as_relative'] = gmSamePixels($row['file'], 'gm103-intent-compare-relative.png');
}
unset($row);
file_put_contents(__DIR__ . '/gm103-intent-compare-comparison.json', json_encode($receipt, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));

$checks = [
    'all_intents_selected' => count(array_filter($receipt, fn($row) => $row['requested'] !== $row['selected'])) === 0,
    'all_profiles_target' => count(array_filter($receipt, fn($row) => $row['profile_sha256'] !== GM_INPUT_HASHES['target-srgb.icc'])) === 0,
    'comparison_measured' => count(array_filter($receipt, fn($row) => !is_bool($row['same_RGB_as_relative']))) === 0,
    'source_profile_preserved' => hash('sha256', $source->getImageProfile('icm')) === GM_INPUT_HASHES['source-p3.icc']
];
gmReport('gm103-intent-compare', ["gmagick.getimagerenderingintent", "gmagick.setimagerenderingintent", "gmagick.profileimage", "gmagick.getimageprofile"], ["gm103-intent-compare-perceptual.png", "gm103-intent-compare-relative.png", "gm103-intent-compare-saturation.png", "gm103-intent-compare-absolute.png"], $checks, $errors ?? [], $receipt);
echo "intent-compare: four conversions saved; actual RGB comparisons in comparison.json\n";
Ожидаемый результат
intent-compare: four conversions saved; actual RGB comparisons in comparison.json

Распакуйте пример и выполните php example.php с установленным Gmagick и поддержкой PNG/ICC в GraphicsMagick. В комплекте известные входы в base64, их SHA256, лицензия ICC и gm103-profile-fixture.php. Helper восстанавливает входы, пишет PNG 8 бит/канал и metrics.json; gmSamePixels сравнивает реально сохранённые пиксели. Код операции показан коротко выше; полный пример создаёт перечисленные PNG и квитанции самостоятельно. Сырые бинарные ICC не выводятся на экран.

В выполненном запуске все четыре результата дали одинаковые декодированные RGB: same_RGB_as_relative равно true для каждого. Откройте comparison.json и сопоставьте эти числа с картинками. Такое совпадение допустимо; отсутствие заметной разницы на экране тоже не доказывает равенство чисел. Для выбора печатного сценария понадобятся реальные ICC и требования вывода. Нельзя по этой RGB-мишени обещать, что Absolute всегда выглядит тусклее или что Perceptual всегда лучше.

Опорные понятия: объект и вызов метода, параметр и возвращаемое значение, исключения, clone. Связанные задачи: пропорциональные превью, цветовые координаты.

Выпустить превью по явному рецепту и сохранить квитанцию

Каталог получил готовый PNG, а через месяц нужно понять, как его сделали. Размеров недостаточно: нужны исходник, целевой ICC и intent, применённый до конверсии. Программа выдаёт превью 200 × 160 и квитанцию с SHA256 входа и выхода. В ней отдельно записан выбор Relative и значение getter после повторного чтения PNG.

Архивный оригинал P3 400 × 320
Архивный оригинал P3 400 × 320
Публикуемое sRGB-превью 200 × 160; рецепт Relative сохранён в JSON
Публикуемое sRGB-превью 200 × 160; рецепт Relative сохранён в JSON

Это настоящие PNG данной программы. Цвет на экране зависит от монитора и поддержки профилей браузером; утверждения о равенстве RGB и ICC проверяются по сохранённым файлам, а не только на глаз.

$preview->setImageRenderingIntent(Gmagick::RENDERINGINTENT_RELATIVE);
$selected = $preview->getImageRenderingIntent();
$preview->profileImage("icm", $targetProfileBytes);
$convertedProfile = $preview->getImageProfile("icm");
$preview->thumbnailImage(200, 160, true);
$preview->setImageProfile("icm", $convertedProfile);

Выбор сохраняется до преобразования, чтобы не восстанавливать его по косвенным признакам. В нашей сборке thumbnailImage удаляет ICC, поэтому перед уменьшением сохраняем целевой профиль и после возвращаем его через setter. Цвет уже преобразован; второй profileImage здесь не нужен. Полная программа читает PNG ещё раз и проверяет профиль и размеры уже записанного файла. В нашем случае intent после чтения — Undefined (0); квитанция при этом сохраняет Relative (4). SHA256 результата связывает квитанцию с точными байтами данного файла. Это полезно при пересборке каталога, разборе жалобы на цвет или сравнении вариантов экспорта. Хеш не объясняет причину изменения и не измеряет визуальное качество: он только обнаруживает отличие. Оригинал не уменьшается и не перезаписывается. Профиль сохраняется в iCCP PNG; политика обработки цвета браузером и монитором остаётся отдельной частью воспроизведения.

Выпустить превью по явному рецепту и сохранить квитанциюСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__ . '/gm103-profile-fixture.php';
gmRestore();

$source = new Gmagick(__DIR__ . '/source-p3.png');
$preview = clone $source;
$preview->setImageRenderingIntent(Gmagick::RENDERINGINTENT_RELATIVE);
$selected = $preview->getImageRenderingIntent();
$preview->profileImage('icm', file_get_contents(__DIR__ . '/target-srgb.icc'));
$convertedProfile = $preview->getImageProfile('icm');
$preview->thumbnailImage(200, 160, true);
$preview->setImageProfile('icm', $convertedProfile);
gmPng($source, 'gm103-intent-web-recipe-source.png');
gmPng($preview, 'gm103-intent-web-recipe-preview.png');
$saved = new Gmagick(__DIR__ . '/gm103-intent-web-recipe-preview.png');
$receipt = ['input_sha256' => hash_file('sha256', __DIR__ . '/source-p3.png'),
    'target_profile_sha256' => hash('sha256', $saved->getImageProfile('icm')),
    'intent_name' => 'relative', 'intent_in_recipe' => $selected,
    'intent_after_png_read' => $saved->getImageRenderingIntent(),
    'file' => 'gm103-intent-web-recipe-preview.png', 'width' => $saved->getImageWidth(), 'height' => $saved->getImageHeight(),
    'output_sha256' => hash_file('sha256', __DIR__ . '/gm103-intent-web-recipe-preview.png')];
file_put_contents(__DIR__ . '/gm103-intent-web-recipe-receipt.json', json_encode($receipt, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));

$checks = [
    'recipe_selected_before_conversion' => $selected === Gmagick::RENDERINGINTENT_RELATIVE,
    'saved_target_profile' => hash('sha256', $saved->getImageProfile('icm')) === GM_INPUT_HASHES['target-srgb.icc'],
    'saved_dimensions' => $saved->getImageWidth() === 200 && $saved->getImageHeight() === 160,
    'intent_not_guessed_from_png' => $saved->getImageRenderingIntent() === Gmagick::RENDERINGINTENT_UNDEFINED
];
gmReport('gm103-intent-web-recipe', ["gmagick.getimagerenderingintent", "gmagick.setimagerenderingintent", "gmagick.profileimage", "gmagick.getimageprofile", "gmagick.thumbnailimage", "gmagick.setimageprofile"], ["gm103-intent-web-recipe-source.png", "gm103-intent-web-recipe-preview.png"], $checks, $errors ?? [], $receipt);
echo "intent-web: 200x160 sRGB; relative recipe and output SHA256 saved\n";
Ожидаемый результат
intent-web: 200x160 sRGB; relative recipe and output SHA256 saved

Распакуйте пример и выполните php example.php с установленным Gmagick и поддержкой PNG/ICC в GraphicsMagick. В комплекте известные входы в base64, их SHA256, лицензия ICC и gm103-profile-fixture.php. Helper восстанавливает входы, пишет PNG 8 бит/канал и metrics.json; gmSamePixels сравнивает реально сохранённые пиксели. Код операции показан коротко выше; полный пример создаёт перечисленные PNG и квитанции самостоятельно. Сырые бинарные ICC не выводятся на экран.

Представьте, что оптимизатор переписал PNG. Старый output_sha256 больше не совпадёт, хотя RGB могут быть прежними. Значит, нужно проверить новый файл и выпустить новую квитанцию. Не считайте простой getter готового PNG журналом истории преобразований.

Опорные понятия: объект и вызов метода, параметр и возвращаемое значение, исключения, clone. Связанные задачи: пропорциональные превью, цветовые координаты.

Принять понятный выбор пользователя и отклонить опечатку

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

Выбор catalog принят: Relative, реальный результат P3 → sRGB
Выбор catalog принят: Relative, реальный результат P3 → sRGB

Это настоящие PNG данной программы. Цвет на экране зависит от монитора и поддержки профилей браузером; утверждения о равенстве RGB и ICC проверяются по сохранённым файлам, а не только на глаз.

$allowed = ["catalog" => Gmagick::RENDERINGINTENT_RELATIVE];
if (!array_key_exists($choice, $allowed)) {
    throw new InvalidArgumentException("Unknown intent choice");
}
$image->setImageRenderingIntent($allowed[$choice]);

Это маленький вариант функции selectIntent ниже. $choice — уже полученная строка; пример не скрывает чтение $_POST внутри обработчика изображения. Ключи массива обозначают интерфейсные варианты, значения — разрешённые константы. Полная функция возвращает фактический getter и отклоняет catlog и "999" до вызова setter. Названия photo/catalog/diagram/proof — политика нашего приложения, не автоматическая экспертная рекомендация для любых файлов. В discovery setImageRenderingIntent(999) был принят и getter вернул 999, поэтому проверка допустимого набора нужна самому приложению. Отдельные демонстрации показывают TypeError при массиве вместо int и GmagickException при getter пустого объекта. Это разные ошибки: некорректный выбор пользователя, неверный PHP-тип и отсутствие изображения.

Принять понятный выбор пользователя и отклонить опечаткуСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__ . '/gm103-profile-fixture.php';
gmRestore();

function selectIntent(Gmagick $image, string $choice): int {
    $allowed = ['photo' => Gmagick::RENDERINGINTENT_PERCEPTUAL,
        'catalog' => Gmagick::RENDERINGINTENT_RELATIVE,
        'diagram' => Gmagick::RENDERINGINTENT_SATURATION,
        'proof' => Gmagick::RENDERINGINTENT_ABSOLUTE];
    if (!array_key_exists($choice, $allowed)) {
        throw new InvalidArgumentException('Unknown intent choice');
    }
    $image->setImageRenderingIntent($allowed[$choice]);
    return $image->getImageRenderingIntent();
}
$image = new Gmagick(__DIR__ . '/source-p3.png');
$selected = selectIntent($image, 'catalog');
$image->profileImage('icm', file_get_contents(__DIR__ . '/target-srgb.icc'));
gmPng($image, 'gm103-intent-input-accepted.png');
$errors['typo'] = gmTry(fn() => selectIntent($image, 'catlog'));
$errors['number_as_name'] = gmTry(fn() => selectIntent($image, '999'));
$errors['wrong_type'] = gmTry(fn() => $image->setImageRenderingIntent([]));
$errors['empty_object'] = gmTry(fn() => (new Gmagick())->getImageRenderingIntent());

$checks = [
    'known_choice_selected' => $selected === Gmagick::RENDERINGINTENT_RELATIVE,
    'rejections_are_explained' => $errors['typo']['class'] === 'InvalidArgumentException' && $errors['number_as_name']['class'] === 'InvalidArgumentException',
    'library_errors' => $errors['wrong_type']['class'] === 'TypeError' && $errors['empty_object']['class'] === 'GmagickException'
];
gmReport('gm103-intent-input', ["gmagick.getimagerenderingintent", "gmagick.setimagerenderingintent", "gmagick.profileimage"], ["gm103-intent-input-accepted.png"], $checks, $errors ?? [], []);
echo "intent-input: catalog accepted; typo, 999, array and empty object handled\n";
Ожидаемый результат
intent-input: catalog accepted; typo, 999, array and empty object handled

Распакуйте пример и выполните php example.php с установленным Gmagick и поддержкой PNG/ICC в GraphicsMagick. В комплекте известные входы в base64, их SHA256, лицензия ICC и gm103-profile-fixture.php. Helper восстанавливает входы, пишет PNG 8 бит/канал и metrics.json; gmSamePixels сравнивает реально сохранённые пиксели. Код операции показан коротко выше; полный пример создаёт перечисленные PNG и квитанции самостоятельно. Сырые бинарные ICC не выводятся на экран.

При подключении HTML-формы сначала убедитесь, что поле существует и содержит строку, затем передайте его функции. Не заменяйте ошибку молча значением 0. Дайте человеку понятный ответ и сохраните исходный файл, чтобы после исправления выбора можно было повторить обработку.

Опорные понятия: объект и вызов метода, параметр и возвращаемое значение, исключения, clone. Связанные задачи: пропорциональные превью, цветовые координаты.

Передача выбора из браузера: поле HTML-формы и $_POST.

Повторить экспорт по сохранённому рецепту, а не по getter готового PNG

После перезапуска очереди надо повторить экспорт. Сохранив только готовый PNG, мы не восстановим выбранный intent надёжно. Поэтому берём оригинал и небольшой recipe.json: SHA256 исходника, имя intent и целевой профиль. Два показанных результата получены отдельными вызовами из одного оригинала, а не многократным преобразованием уже готового sRGB.

Первый экспорт с явным Relative и целевым sRGB
Первый экспорт с явным Relative и целевым sRGB
Повторный экспорт из оригинала по recipe.json: те же RGB
Повторный экспорт из оригинала по recipe.json: те же RGB

Это настоящие PNG данной программы. Цвет на экране зависит от монитора и поддержки профилей браузером; утверждения о равенстве RGB и ICC проверяются по сохранённым файлам, а не только на глаз.

$recipe = json_decode(file_get_contents("recipe.json"), true, 512, JSON_THROW_ON_ERROR);
$image = new Gmagick("source-p3.png");
$image->setImageRenderingIntent(Gmagick::RENDERINGINTENT_RELATIVE);
$image->profileImage("icm", $targetProfileBytes);

true у json_decode даёт PHP-массив; JSON_THROW_ON_ERROR делает повреждённый JSON явной ошибкой. В полной exportByRecipe проверяется, что поддерживаемое правило и источник совпадают с рецептом. Результат повторного запуска должен иметь те же декодированные RGB и целевой ICC; служебные части файла не объявляются побайтно детерминированными. Намеренно подменённый источник получает DomainException до записи выхода. В более общей системе рецепту также нужны версии библиотеки и профилей, параметры изменения размера, ориентации и кодирования. Здесь зависимость от конкретного окружения фиксирует metrics.json каждого запуска, а краткий recipe иллюстрирует минимальный способ не потерять выбор.

Повторить экспорт по сохранённому рецепту, а не по getter готового PNGСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__ . '/gm103-profile-fixture.php';
gmRestore();

function exportByRecipe(array $recipe, string $filename): int {
    if ($recipe['intent'] !== 'relative' || $recipe['source_sha256'] !== GM_INPUT_HASHES['source-p3.png'] || $recipe['target_profile_sha256'] !== GM_INPUT_HASHES['target-srgb.icc']) {
        throw new DomainException('Unsupported or mismatched recipe');
    }
    $image = new Gmagick(__DIR__ . '/source-p3.png');
    $image->setImageRenderingIntent(Gmagick::RENDERINGINTENT_RELATIVE);
    $selected = $image->getImageRenderingIntent();
    $image->profileImage('icm', file_get_contents(__DIR__ . '/target-srgb.icc'));
    gmPng($image, $filename);
    return $selected;
}
$recipe = ['source_sha256' => GM_INPUT_HASHES['source-p3.png'], 'intent' => 'relative',
    'target_profile_sha256' => GM_INPUT_HASHES['target-srgb.icc']];
file_put_contents(__DIR__ . '/gm103-intent-restore-recipe.json', json_encode($recipe, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
$first = exportByRecipe($recipe, 'gm103-intent-restore-first.png');
$restoredRecipe = json_decode(file_get_contents(__DIR__ . '/gm103-intent-restore-recipe.json'), true, 512, JSON_THROW_ON_ERROR);
$second = exportByRecipe($restoredRecipe, 'gm103-intent-restore-second.png');
$readback = (new Gmagick(__DIR__ . '/gm103-intent-restore-second.png'))->getImageRenderingIntent();
$wrong = $restoredRecipe;
$wrong['source_sha256'] = 'not-our-source';
$errors['wrong_source'] = gmTry(fn() => exportByRecipe($wrong, 'gm103-intent-restore-never-written.png'));

$checks = [
    'recipe_restored' => $first === Gmagick::RENDERINGINTENT_RELATIVE && $second === $first,
    'same_saved_pixels' => gmSamePixels('gm103-intent-restore-first.png', 'gm103-intent-restore-second.png'),
    'png_not_used_as_recipe' => $readback === Gmagick::RENDERINGINTENT_UNDEFINED,
    'wrong_input_rejected' => $errors['wrong_source']['class'] === 'DomainException' && !file_exists(__DIR__ . '/gm103-intent-restore-never-written.png')
];
gmReport('gm103-intent-restore', ["gmagick.getimagerenderingintent", "gmagick.setimagerenderingintent", "gmagick.profileimage"], ["gm103-intent-restore-first.png", "gm103-intent-restore-second.png"], $checks, $errors ?? [], []);
echo "intent-restore: saved recipe repeated; RGB identical; wrong source rejected\n";
Ожидаемый результат
intent-restore: saved recipe repeated; RGB identical; wrong source rejected

Распакуйте пример и выполните php example.php с установленным Gmagick и поддержкой PNG/ICC в GraphicsMagick. В комплекте известные входы в base64, их SHA256, лицензия ICC и gm103-profile-fixture.php. Helper восстанавливает входы, пишет PNG 8 бит/канал и metrics.json; gmSamePixels сравнивает реально сохранённые пиксели. Код операции показан коротко выше; полный пример создаёт перечисленные PNG и квитанции самостоятельно. Сырые бинарные ICC не выводятся на экран.

Почему не превращать sRGB обратно в P3, а затем снова в sRGB? Переходы могут потерять информацию из-за охвата, округления и сжатия; повтор не обязан вернуть исходные числа. Для другого размера или профиля снова начинайте с сохранённого оригинала и явно выбранного рецепта.

Опорные понятия: объект и вызов метода, параметр и возвращаемое значение, исключения, clone. Связанные задачи: пропорциональные превью, цветовые координаты.

Как JSON становится PHP-массивом: вложенные данные и JSON.

Реальная задача разработчика

Keep colors when converting CMYK to sRGB to CMYK Imagick PHP. После CMYK → RGB → CMYK цвета и насыщенность отличаются от исходника; автор ожидает обратимость и результат как в Photoshop. Объясняем потери охвата и округления, отделяем рецепт от getter готовогоPNG. Повторяем экспорт из сохранённого оригинала с явным intent и профилями, вместо обещания обратимости цепочки.

Обработать очередь независимо и не потерять исходный профиль

В очереди два известных источника: наша P3-карточка и её исходная sRGB-версия. Нужны одинаковые размеры web-превью, но цветовой маршрут различается. Для P3 выполняется преобразование; известный sRGB только получает подтверждённое описание и уменьшается. Каждое задание создаёт отдельный объект и свою запись в manifest.json.

Первое задание: P3 преобразован в sRGB, превью 200 × 160
Первое задание: P3 преобразован в sRGB, превью 200 × 160
Второе задание: известный sRGB только уменьшен, без лишней конверсии
Второе задание: известный sRGB только уменьшен, без лишней конверсии

Это настоящие PNG данной программы. Цвет на экране зависит от монитора и поддержки профилей браузером; утверждения о равенстве RGB и ICC проверяются по сохранённым файлам, а не только на глаз.

foreach ($jobs as $job) {
    $image = new Gmagick($job["input"]);
    $image->setImageRenderingIntent(Gmagick::RENDERINGINTENT_RELATIVE);
    // Далее проверка известного профиля и нужное преобразование.
}

Короткий фрагмент показывает организацию очереди, а полный код ниже — условия и сохранение результатов. Для собственного source.png профиль известен из генератора, поэтому его можно назначить через setImageProfile. Для произвольной загрузки такая подстановка была бы догадкой и не допускается. Полные байты входного ICC сверяются с ожидаемыми. Если они уже совпадают с целевым профилем, ещё одну конверсию не выполняем. Это правило нашего набора проверенных входов; совпадения одного названия «sRGB» в произвольной строке недостаточно. После уменьшения возвращается сохранённый целевой ICC, поскольку thumbnailImage этой сборки удаляет профиль. Мы сохраняем профиль именно после нужной конверсии, чтобы не присвоить обратно P3 уже преобразованным sRGB-числам. Manifest фиксирует файл, intent, необходимость преобразования и SHA256 результата отдельно для каждого задания. Исходники остаются неизменными, а ошибки не маскируются чужим объектом, оставшимся от предыдущей итерации.

Обработать очередь независимо и не потерять исходный профильСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__ . '/gm103-profile-fixture.php';
gmRestore();

$jobs = [
    ['name' => 'p3', 'input' => 'source-p3.png', 'known_profile' => 'source-p3.icc'],
    ['name' => 'srgb', 'input' => 'source.png', 'known_profile' => 'target-srgb.icc'],
];
$target = file_get_contents(__DIR__ . '/target-srgb.icc');
$manifest = [];
foreach ($jobs as $job) {
    $image = new Gmagick(__DIR__ . '/' . $job['input']);
    // These are our own known fixtures; this is not a guess for arbitrary uploads.
    $known = file_get_contents(__DIR__ . '/' . $job['known_profile']);
    if ($job['input'] === 'source.png') {
        $image->setImageProfile('icm', $known);
    }
    if ($image->getImageProfile('icm') !== $known) {
        throw new DomainException('Unexpected source profile');
    }
    $image->setImageRenderingIntent(Gmagick::RENDERINGINTENT_RELATIVE);
    $intent = $image->getImageRenderingIntent();
    if ($known !== $target) {
        $image->profileImage('icm', $target);
    }
    $outputProfile = $image->getImageProfile('icm');
    $image->thumbnailImage(200, 160, true);
    $image->setImageProfile('icm', $outputProfile);
    $filename = 'gm103-intent-batch-' . $job['name'] . '.png';
    gmPng($image, $filename);
    $manifest[] = ['input' => $job['input'], 'output' => $filename, 'intent' => $intent,
        'profile_sha256' => hash('sha256', $image->getImageProfile('icm')),
        'converted' => $known !== $target, 'output_sha256' => hash_file('sha256', __DIR__ . '/' . $filename)];
}
file_put_contents(__DIR__ . '/gm103-intent-batch-manifest.json', json_encode($manifest, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));

$checks = [
    'two_independent_outputs' => count($manifest) === 2,
    'both_selected' => $manifest[0]['intent'] === Gmagick::RENDERINGINTENT_RELATIVE && $manifest[1]['intent'] === Gmagick::RENDERINGINTENT_RELATIVE,
    'both_target_profiles' => $manifest[0]['profile_sha256'] === GM_INPUT_HASHES['target-srgb.icc'] && $manifest[1]['profile_sha256'] === GM_INPUT_HASHES['target-srgb.icc'],
    'no_redundant_conversion' => $manifest[0]['converted'] === true && $manifest[1]['converted'] === false
];
gmReport('gm103-intent-batch', ["gmagick.getimagerenderingintent", "gmagick.setimagerenderingintent", "gmagick.getimageprofile", "gmagick.setimageprofile", "gmagick.profileimage", "gmagick.thumbnailimage"], ["gm103-intent-batch-p3.png", "gm103-intent-batch-srgb.png"], $checks, $errors ?? [], $manifest);
echo "intent-batch: 2 previews; P3 converted, known sRGB only resized; manifest saved\n";
Ожидаемый результат
intent-batch: 2 previews; P3 converted, known sRGB only resized; manifest saved

Распакуйте пример и выполните php example.php с установленным Gmagick и поддержкой PNG/ICC в GraphicsMagick. В комплекте известные входы в base64, их SHA256, лицензия ICC и gm103-profile-fixture.php. Helper восстанавливает входы, пишет PNG 8 бит/канал и metrics.json; gmSamePixels сравнивает реально сохранённые пиксели. Код операции показан коротко выше; полный пример создаёт перечисленные PNG и квитанции самостоятельно. Сырые бинарные ICC не выводятся на экран.

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

Опорные понятия: объект и вызов метода, параметр и возвращаемое значение, исключения, clone. Связанные задачи: пропорциональные превью, цветовые координаты.

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

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

Gmagick::getimagerenderingintentПрочитать выбранное правило цветопередачи текущего изображения

PECL gmagick >= Unknown · gmagick

Gmagick::getimagerenderingintent(): int

getImageRenderingIntent вызывается без параметров и возвращает int — текущее значение rendering intent. Сопоставляйте его с Gmagick::RENDERINGINTENT_*, а не с произвольной цифрой. Чтение не меняет RGB и не конвертирует профиль. На нашем исходном PNG возвращается Undefined (0); после явного выбора Relative в объекте — 4. PNG с iCCP после сохранения/перечитывания в данной сборке снова даёт 0, поэтому getter не является журналом выполненных преобразований. Рецепт хранится отдельно. На PHP.net абзац Return Values ошибочно описывает вырезание области и новый wand; фактическая сигнатура, реализация и выполненный пример возвращают int. Вызов на пустом объекте вызывает GmagickException.

Gmagick::getimagerenderingintent(): int

Параметров нет: () означает вызов без аргументов. Возвращаемое число можно сохранить в переменную и сравнить с именованной константой.

Официальная ошибка методов — GmagickException. TypeError и исключения прикладных функций названы отдельно в примерах; библиотечная ошибка не заменяет проверку происхождения профиля. PHP.net указывает PECL gmagick ≥ Unknown, поэтому точную минимальную версию не выдумываем. Наблюдаемые ограничения относятся к PHP 8.3.6, Gmagick 2.0.6RC1, GraphicsMagick 1.3.42 Q16; в другом окружении сверяйте реальные выходы.

Применения: Выбрать правило преобразования, не меняя пиксели setter-ом; Выпустить превью по явному рецепту и сохранить квитанцию; Повторить экспорт по сохранённому рецепту, а не по getter готового PNG.

Продолжение: ICC-профили и преобразования, цветовые координаты и белая точка, договор экспорта и метаданные.

Gmagick::setimagerenderingintentЗадать правило до ICC-преобразования

PECL gmagick >= Unknown · gmagick

Gmagick::setimagerenderingintent(int $rendering_intent): Gmagick

setImageRenderingIntent принимает обязательный int $rendering_intent и возвращает Gmagick; в проверенных вызовах возвращён тот же объект. Предусмотрены Gmagick::RENDERINGINTENT_UNDEFINED, SATURATION, PERCEPTUAL, ABSOLUTE, RELATIVE. Setter задаёт настройку изображения, а изменение пикселей выполняет последующее profileImage. Intent не подменяет исходный/целевой ICC или пространство цвета. Глава показывает четыре результата на одной паре профилей и измеряет, совпали ли RGB; различия не гарантируются. Библиотека в discovery приняла число 999, поэтому приложение должно проверять допустимые значения само. Массив вместо int даёт TypeError; пустой объект без изображения приводит к GmagickException. Сохранение выбранного значения в конкретном выходном формате не обещается: для воспроизводимости нужна квитанция.

Gmagick::setimagerenderingintent(int $rendering_intent): Gmagick
ПараметрТип и обязательностьДля чего
$rendering_intentint; обязательный; без defaultОдна из именованных констант Gmagick::RENDERINGINTENT_*. Проверка разрешённого набора — политика приложения.

Официальная ошибка методов — GmagickException. TypeError и исключения прикладных функций названы отдельно в примерах; библиотечная ошибка не заменяет проверку происхождения профиля. PHP.net указывает PECL gmagick ≥ Unknown, поэтому точную минимальную версию не выдумываем. Наблюдаемые ограничения относятся к PHP 8.3.6, Gmagick 2.0.6RC1, GraphicsMagick 1.3.42 Q16; в другом окружении сверяйте реальные выходы.

Применения: Выбрать правило преобразования, не меняя пиксели setter-ом; Принять понятный выбор пользователя и отклонить опечатку; Обработать очередь независимо и не потерять исходный профиль.

Продолжение: ICC-профили и преобразования, цветовые координаты и белая точка, договор экспорта и метаданные.

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

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

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

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

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