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

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

Это настоящие 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_UNDEFINED | 0 | Правило явно не задано; не синоним безопасного выбора. |
| RENDERINGINTENT_SATURATION | 1 | Приоритет насыщенности; результат зависит от профилей/CMS. |
| RENDERINGINTENT_PERCEPTUAL | 2 | Воспринимаемые отношения цветов и тонов. |
| RENDERINGINTENT_ABSOLUTE | 3 | Абсолютное сопоставление, в частности имитация носителя. |
| RENDERINGINTENT_RELATIVE | 4 | Сопоставление с учётом относительной белой точки. |
Это числовые значения API Gmagick, а не нумерация поля intent внутри бинарного формата ICC или PNG. В коде используйте имена констант.
<?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. Мы не рисуем искусственные различия ради иллюстрации.




Это настоящие 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.


Это настоящие 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: ошибочное значение может быть принято библиотекой и незаметно попасть в рецепт.

Это настоящие 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.


Это настоящие 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 иллюстрирует минимальный способ не потерять выбор.
<?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.


Это настоящие 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(): intgetImageRenderingIntent вызывается без параметров и возвращает 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): GmagicksetImageRenderingIntent принимает обязательный 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_intent | int; обязательный; без 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. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.


