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

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

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

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

Глава 383 · После объектов, клонирования и исключений; совместимость с IM6

Imagick: устаревшая растровая clip-mask в IM6, защита записи и копии

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

Увидеть защищённую область и настоящий локальный результат

В старом редакторе или обработчике изображений на ImageMagick 6 нужно изменить выбранное прямоугольное окно и защитить всё снаружи. Для этого можно встретить legacy clip-mask: отдельное растровое изображение того же размера управляет последующей записью пикселей. Начнём с настоящего результата на собственном рисунке.

Исходник, извлечённая маска и negate в чёрном окне x=240..359, y=80..239; белая область защищает прежние пиксели
Исходник, извлечённая маска и negate в чёрном окне x=240..359, y=80..239; белая область защищает прежние пиксели

Это прямоугольное окно, а не распознавание кружки. Цвет тела в пределах окна меняется, белый фон внутри становится чёрным, ручка за границей остаётся прежней. Маска имеет 400 × 320, как исходник. Чёрный участок 120 × 160 разрешает изменения 19 200 пикселей, белое защищает остальные 108 800. Сам setter не обрезает холст и не удаляет фон.

$ok = $image->setImageClipMask($mask);
$image->negateImage(false);
$copy = $image->getImageClipMask();

$image — объект с цветным изображением, $mask — другой объект с чёрно-белой маской. Стрелка -> вызывает метод; запятые здесь не нужны, setter имеет единственный аргумент. $ok получает true, а $copy — отдельный Imagick. negateImage(false) — конкретная следующая операция; её false относится к самому negate, а не означает «обработать снаружи маски». Объекты, переменные и clone объясняются отдельно.

Методы устарели, поэтому в самостоятельных архивах вызов обёрнут в legacyMaskCall. Запись fn()=> $image->setImageClipMask($mask) создаёт короткую функцию без аргументов, которую helper сразу вызывает. Это позволяет ограничить обработчик E_DEPRECATED именно этой операцией; ссылка &$warnings в helper даёт сохранить точные сообщения в переданный массив. finally восстанавливает прежний обработчик даже при исключении. Полный код helper приведён в конце главы; глобальные настройки предупреждений не отключаются.

Изменить прямоугольное окно и сохранить всё снаружи

Видны исходник, настоящая возвращённая маска и результат negate внутри чёрного окна. Изменены 19 200 пикселей прямоугольника, 108 800 снаружи сохранены. Окно не следует контуру кружки: фон внутри тоже меняется, ручка за границей остаётся прежней.

Изменить прямоугольное окно и сохранить всё снаружиПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__.'/clip-mask-fixture.php';
legacyMaskRestore();
$base=legacyMaskBase(); $mask=legacyMaskPattern();
$before=legacyMaskHash($base); $warnings=[];
$image=clone $base;
$ok=legacyMaskCall(fn()=>$image->setImageClipMask($mask),$warnings);
$unchanged=legacyMaskHash($image)===$before;
$returned=legacyMaskCall(fn()=>$image->getImageClipMask(),$warnings);
$image->negateImage(false);
legacyMaskFirstProof('legacy-clip-mask-first',$base,$mask,$returned,$image,$ok,$unchanged,$warnings,$before);
echo "legacy-clip-mask-first.png\nsource-preview8.png\ninput-mask8.png\nreturned-mask8.png\ninside-result8.png\nmetrics.json\nset=true get=Imagick unchanged-after-set=1 local-effect=1 warnings=saved\n";

Видны исходник, настоящая возвращённая маска и результат negate внутри чёрного окна. Изменены 19 200 пикселей прямоугольника, 108 800 снаружи сохранены. Окно не следует контуру кружки: фон внутри тоже меняется, ручка за границей остаётся прежней. Архив содержит example.php, source.png.b64 и clip-mask-fixture.php. Сохраните рядом и выполните php example.php с IM6-совместимой Imagick и поддержкой PNG. Проверенная среда: PHP 8.3.6 / Imagick 3.7.0 / ImageMagick 6.9.12-98 Q16, Ubuntu 24.04. Это устаревшие IM6-only методы; выполнение на связанной с IM7 Windows-сборке здесь не заявлено. Helper восстанавливает собственный рисунок, создаёт явно показанную растровую маску, сохраняет PNG8 и измерения. Изучаемые set/get остаются видны в основной программе. legacyMaskCall перехватывает только предупреждения этих двух deprecated-методов в пределах вызова, сохраняет точные сообщения и восстанавливает прежний обработчик через finally.

Ожидаемый вывод в проверенной IM6-сборке
legacy-clip-mask-first.png
source-preview8.png
input-mask8.png
returned-mask8.png
inside-result8.png
metrics.json
set=true get=Imagick unchanged-after-set=1 local-effect=1 warnings=saved

Различать рабочее изображение, сохранённую маску и отдельные копии

Getter вернул отдельную копию: изменённый $read и повторно полученная прикреплённая маска $attached различаются
Getter вернул отдельную копию: изменённый $read и повторно полученная прикреплённая маска $attached различаются
СущностьКак она участвует
$baseЧистый исходник. Из него создаются независимые рабочие копии.
$maskПодготовленная растровая маска. Setter копирует её, а не подписывается на будущие изменения этой переменной.
$imageРабочее цветное изображение с прикреплённой маской. Его пиксели меняет следующая операция.
$read / $copyНовый объект из getter. Его изменение не меняет уже прикреплённую маску.
$attachedПовторное чтение прикреплённой маски после изменения входа и getter-копии; в workflow она осталась прежней.

Удобная модель — трафарет защиты записи. Для этого legacy механизма на нашем непрозрачном RGB-исходнике белое защищает старый пиксель, чёрное пропускает новую запись. Это не правило любой маски во всех библиотеках. Альфа-маска, которая отвечает за видимость слоя, может интерпретировать белый участок совсем иначе. Здесь маска не является цветной заливкой результата: она определяет, какие изменения сохранятся после обработки.

Серый не означает «изменить наполовину». В точном IM6 cache проверяется ненулевая интенсивность, после чего прежние компоненты восстанавливаются; величина серого не используется как коэффициент плавного смешивания. Реальный контроль gray50 ниже полностью защищает окно, как белый. Поэтому простое размытие этой clip-mask не обещает мягкую границу. Для такой задачи нужен отдельно объяснённый слой с альфа-каналом и композиция.

Clip-mask отличается и от встроенного 8BIM-контура: там путь сначала читается из метаданных, здесь передаётся уже готовый растр. Она также не равна crop и не ищет границы объекта по содержимому. Проверяем конкретный механизм на конкретной версии, не переносим автоматически результат IM6 на IM7.

Запустить короткий setter и отдельно прочитать существующую маску

Короткий setter даёт локальный результат; короткий getter возвращает саму маску
Короткий setter даёт локальный результат; короткий getter возвращает саму маску

Каждый архив самостоятельный. legacyMaskRestore проверяет SHA собственного PNG; legacyMaskBase накладывает его на белую основу и отключает альфа-сигнал через ALPHACHANNEL_DEACTIVATE. legacyMaskPattern создаёт белую маску 400 × 320 и рисует чёрный прямоугольник с включёнными границами x=240..359, y=80..239. Поэтому ширина 120, высота 160. Эти функции подготовки не прикрепляют маску к изображению. Следующий короткий пример показывает сам setter и одну последующую операцию.

Установить отдельную маску перед конкретной операцией

Setter вернул true и сам не изменил RGB. Следующий negate изменил только область, где непрозрачная маска чёрная. Это ограничение последующей записи, а не команда сделать фон прозрачным.

Установить отдельную маску перед конкретной операциейПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__.'/clip-mask-fixture.php';
legacyMaskRestore();
$base=legacyMaskBase(); $mask=legacyMaskPattern();
$before=legacyMaskHash($base); $warnings=[];
$image=clone $base;
$ok=legacyMaskCall(fn()=>$image->setImageClipMask($mask),$warnings);
$unchanged=legacyMaskHash($image)===$before;
$image->negateImage(false);
legacyMaskSetProof('legacy-clip-mask-set-minimal',$base,$mask,$image,$ok,$unchanged,$warnings,$before);
echo "legacy-clip-mask-set.png\nset-mask8.png\nmetrics.json\nset=true unchanged-after-set=1 effect=black-area warnings=saved\n";

Setter вернул true и сам не изменил RGB. Следующий negate изменил только область, где непрозрачная маска чёрная. Это ограничение последующей записи, а не команда сделать фон прозрачным. Архив содержит example.php, source.png.b64 и clip-mask-fixture.php. Сохраните рядом и выполните php example.php с IM6-совместимой Imagick и поддержкой PNG. Проверенная среда: PHP 8.3.6 / Imagick 3.7.0 / ImageMagick 6.9.12-98 Q16, Ubuntu 24.04. Это устаревшие IM6-only методы; выполнение на связанной с IM7 Windows-сборке здесь не заявлено. Helper восстанавливает собственный рисунок, создаёт явно показанную растровую маску, сохраняет PNG8 и измерения. Изучаемые set/get остаются видны в основной программе. legacyMaskCall перехватывает только предупреждения этих двух deprecated-методов в пределах вызова, сохраняет точные сообщения и восстанавливает прежний обработчик через finally.

Ожидаемый вывод в проверенной IM6-сборке
legacy-clip-mask-set.png
set-mask8.png
metrics.json
set=true unchanged-after-set=1 effect=black-area warnings=saved
$image->setImageClipMask($mask);
$copy = $image->getImageClipMask();

Чтобы получить маску, она должна уже быть прикреплена. В коротком getter-примере это условие видно непосредственно: сначала настоящий setter, затем настоящий getter. Метод без аргументов возвращает объект, который можно сохранить как PNG или исследовать. Он не возвращает имя файла и не меняет цветной исходник на чёрно-белое изображение.

Получить прикреплённую маску как отдельный объект

После явного предварительного setter вызов getter вернул настоящий Imagick 400 × 320 с той же маской. Getter не возвращает цветной результат negate и не превращает исходное изображение в маску.

Получить прикреплённую маску как отдельный объектПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__.'/clip-mask-fixture.php';
legacyMaskRestore();
$base=legacyMaskBase(); $mask=legacyMaskPattern();
$before=legacyMaskHash($base); $warnings=[];
$image=clone $base;
legacyMaskCall(fn()=>$image->setImageClipMask($mask),$warnings);
$copy=legacyMaskCall(fn()=>$image->getImageClipMask(),$warnings);
legacyMaskGetProof('legacy-clip-mask-get-minimal',$base,$mask,$copy,$warnings,$before);
echo "legacy-clip-mask-get.png\nget-source8.png\nmetrics.json\nget=Imagick size=400x320 matches-input=1 warnings=saved\n";

После явного предварительного setter вызов getter вернул настоящий Imagick 400 × 320 с той же маской. Getter не возвращает цветной результат negate и не превращает исходное изображение в маску. Архив содержит example.php, source.png.b64 и clip-mask-fixture.php. Сохраните рядом и выполните php example.php с IM6-совместимой Imagick и поддержкой PNG. Проверенная среда: PHP 8.3.6 / Imagick 3.7.0 / ImageMagick 6.9.12-98 Q16, Ubuntu 24.04. Это устаревшие IM6-only методы; выполнение на связанной с IM7 Windows-сборке здесь не заявлено. Helper восстанавливает собственный рисунок, создаёт явно показанную растровую маску, сохраняет PNG8 и измерения. Изучаемые set/get остаются видны в основной программе. legacyMaskCall перехватывает только предупреждения этих двух deprecated-методов в пределах вызова, сохраняет точные сообщения и восстанавливает прежний обработчик через finally.

Ожидаемый вывод в проверенной IM6-сборке
legacy-clip-mask-get.png
get-source8.png
metrics.json
get=Imagick size=400x320 matches-input=1 warnings=saved

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

Результаты чёрного, белого и серого окна: gray50 даёт полную защиту, а не промежуточное смешивание
Результаты чёрного, белого и серого окна: gray50 даёт полную защиту, а не промежуточное смешивание

В старом сервисе важно не испортить исходник и не принять случайное изменение вспомогательного объекта за изменение установленной маски. Сначала прикрепим её, изменим исходный объект $mask и проверим, что сохранённая копия прежняя. Затем изменим $read, полученный getter, и снова прочитаем маску. После этого сравним чёрное, белое и серое окно на одинаковом изображении.

Проверить копии, полярность, серую область и плохие входы

Сравнены чёрное окно, белое окно и gray50. Серый участок защищает полностью, как белый: это не мягкая альфа-маска. Изменение исходного объекта маски и полученной getter-копии не меняет уже прикреплённую маску. Шесть ошибок пойманы, оригинал сохранён.

Проверить копии, полярность, серую область и плохие входыПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__.'/clip-mask-fixture.php';
legacyMaskRestore();
$base=legacyMaskBase(); $mask=legacyMaskPattern();
$before=legacyMaskHash($base); $warnings=[];
$global=clone $base;$global->negateImage(false);$image=clone $base;
$ok=legacyMaskCall(fn()=>$image->setImageClipMask($mask),$warnings);
$setUnchanged=legacyMaskHash($image)===$before;
$read=legacyMaskCall(fn()=>$image->getImageClipMask(),$warnings);$maskBefore=legacyMaskHash($read);
$mask->negateImage(false);
$attached=legacyMaskCall(fn()=>$image->getImageClipMask(),$warnings);
$setterClones=legacyMaskHash($attached)===$maskBefore;
$read->negateImage(false);
$attached=legacyMaskCall(fn()=>$image->getImageClipMask(),$warnings);
$getterClones=legacyMaskHash($attached)===$maskBefore;
$image->negateImage(false);$insideCounts=legacyMaskCounts($base,$global,$image);
$outside=clone $base;$outsideMask=legacyMaskPattern('black','white');
legacyMaskCall(fn()=>$outside->setImageClipMask($outsideMask),$warnings);
$outside->negateImage(false);$outsideCounts=legacyMaskCounts($base,$global,$outside);
$gray=clone $base;$grayMask=legacyMaskPattern('black','gray50');
legacyMaskCall(fn()=>$gray->setImageClipMask($grayMask),$warnings);
$gray->negateImage(false);$grayCounts=legacyMaskCounts($base,$global,$gray);
$errors=[];
$attempts=[
    'get_absent'=>fn()=>(clone $base)->getImageClipMask(),
    'get_empty'=>fn()=>(new Imagick())->getImageClipMask(),
    'set_empty_base'=>fn()=>(new Imagick())->setImageClipMask($outsideMask),
    'set_empty_mask'=>fn()=>(clone $base)->setImageClipMask(new Imagick()),
    'set_size_mismatch'=>function()use($base){$small=new Imagick();$small->newImage(100,100,'black');return (clone $base)->setImageClipMask($small);},
    'set_null'=>fn()=>(clone $base)->setImageClipMask(null)
];
foreach($attempts as $name=>$attempt){
    try{legacyMaskCall($attempt,$warnings);$errors[$name]=['class'=>'not caught','message'=>''];}
    catch(Throwable $error){$errors[$name]=['class'=>get_class($error),'message'=>$error->getMessage()];}
}
legacyMaskView($image,'workflow-inside8.png');legacyMaskView($outside,'workflow-outside8.png');legacyMaskView($gray,'workflow-gray8.png');
legacyMaskView($attached,'workflow-returned8.png');legacyMaskView($read,'workflow-modified-copy8.png');
legacyMaskView($base,'workflow-source8.png');legacyMaskView($grayMask,'workflow-gray-mask8.png');
$rects=legacyMaskCompare([$image,$outside,$gray],'legacy-clip-mask-workflow.png');
$sourceKept=legacyMaskHash($base)===$before;
legacyMaskDiagnostic('legacy-clip-mask-workflow',['executed_apis'=>['setImageClipMask','getImageClipMask'],
    'setter_return'=>$ok,'RGB_unchanged_after_set'=>$setUnchanged,'setter_clones'=>$setterClones,'getter_clones'=>$getterClones,
    'inside_counts'=>$insideCounts,'outside_counts'=>$outsideCounts,'gray_counts'=>$grayCounts,'errors'=>$errors,
    'warnings'=>$warnings,'source_unchanged'=>$sourceKept,'panel_geometry'=>$rects,
    'checks'=>['setter_true'=>$ok===true,'set_keeps_RGB'=>$setUnchanged,'setter_copies_mask'=>$setterClones,'getter_returns_copy'=>$getterClones,
        'black_window_changes'=>legacyMaskInsideCorrect($insideCounts),'white_window_protects'=>legacyMaskOutsideCorrect($outsideCounts),
        'gray_is_full_protection'=>legacyMaskOutsideCorrect($grayCounts),'gray_matches_white_result'=>legacyMaskHash($gray)===legacyMaskHash($outside),
        'six_failures_caught'=>array_column($errors,'class')===['ImagickException','ImagickException','ImagickException','ImagickException','ImagickException','TypeError'],
        'original_preserved'=>$sourceKept,'deprecations_saved'=>legacyMaskWarningsValid($warnings)]]);
echo "legacy-clip-mask-workflow.png\nworkflow-inside8.png\nworkflow-outside8.png\nworkflow-gray8.png\nworkflow-returned8.png\nworkflow-modified-copy8.png\nworkflow-source8.png\nworkflow-gray-mask8.png\nmetrics.json\nsetter-copy=1 getter-copy=1 errors=6 source-unchanged=1 warnings=saved\n";

Сравнены чёрное окно, белое окно и gray50. Серый участок защищает полностью, как белый: это не мягкая альфа-маска. Изменение исходного объекта маски и полученной getter-копии не меняет уже прикреплённую маску. Шесть ошибок пойманы, оригинал сохранён. Архив содержит example.php, source.png.b64 и clip-mask-fixture.php. Сохраните рядом и выполните php example.php с IM6-совместимой Imagick и поддержкой PNG. Проверенная среда: PHP 8.3.6 / Imagick 3.7.0 / ImageMagick 6.9.12-98 Q16, Ubuntu 24.04. Это устаревшие IM6-only методы; выполнение на связанной с IM7 Windows-сборке здесь не заявлено. Helper восстанавливает собственный рисунок, создаёт явно показанную растровую маску, сохраняет PNG8 и измерения. Изучаемые set/get остаются видны в основной программе. legacyMaskCall перехватывает только предупреждения этих двух deprecated-методов в пределах вызова, сохраняет точные сообщения и восстанавливает прежний обработчик через finally.

Ожидаемый вывод в проверенной IM6-сборке
legacy-clip-mask-workflow.png
workflow-inside8.png
workflow-outside8.png
workflow-gray8.png
workflow-returned8.png
workflow-modified-copy8.png
workflow-source8.png
workflow-gray-mask8.png
metrics.json
setter-copy=1 getter-copy=1 errors=6 source-unchanged=1 warnings=saved

В чёрном окне изменены 19 200 пикселей, снаружи сохранены 108 800. У белого и gray50 внутри сохранены 19 200, снаружи изменены 108 800; их результаты совпали. В metrics.json хранится полный подсчёт всех 128 000 пикселей, независимость обеих копий, точные сообщения deprecated и ошибок. Подсчёт использует RGB через PIXEL_CHAR непосредственно до отдельного сохранения просмотров PNG8; он не выдаёт округление PNG-просмотра за новое измерение численного состояния. Это доказательство конкретного показанного результата, а не только return=true.

Неудачный входФактический результат
Getter на изображении без прикреплённой маскиImagickException: Unable to get image clip mask.
Getter на пустом объектеImagickException: Can not process empty Imagick object.
Setter на пустом текущем объекте или с пустой маскойImagickException: Can not process empty Imagick object.
Маска другого размераImagickException: Unable to set image clip mask.
null вместо объекта маскиTypeError; это нарушение PHP-типа аргумента, а не команда снять маску.

try/catch в программе намеренно перехватывает Throwable, потому что среди примеров есть и ошибка Imagick, и PHP TypeError. Это демонстрация границ API; в обычном обработчике проверяйте геометрию и понятные входные условия заранее, а реальные исключения превращайте в ясные сообщения. Чистый $base не получал маски и сохранился после всех шести неудач. Нейтральная чёрная маска могла бы быть заменой ограничения, но её прикрепление не является снятием маски; здесь для работы без маски сохраняется оригинал.

Сохранить официальный базис и учитывать устаревание и версию библиотеки

Полный официальный базис

Imagick::getImageClipMask(): Imagick

Оба имени объявлены устаревшими начиная с Imagick 3.4.4. Официальная базовая доступность связана с ImageMagick 6.3.6; полная исходная запись сохранена ниже. Точные bindings Imagick 3.7.0 и 3.8.1 включают эти методы только при ImageMagick < 7.0.0. Поэтому наличие PHP-кода из официального примера не означает, что этот метод существует в любой современной IM7-сборке.

getImageClipMask не принимает аргументов и возвращает новый объект Imagick с прикреплённой clip-mask. Это отдельная копия растровой маски, не исходное цветное изображение и не bool. Официальное описание ошибок указывает ImagickException. В проверенной реализации отсутствие прикреплённой маски тоже приводит к этому исключению; получить null или false как штатный результат этого старого getter нельзя.

В точном IM6 Core setter клонирует входную маску, а getter клонирует сохранённую. Изменение переданного объекта или полученной копии не переписывает прикреплённую маску. C-функция умеет снимать маску через NULL, но PHP-wrapper требует непустой Imagick: setImageClipMask(null) вызывает TypeError, пустой объект — ImagickException. Это не доступный из данного PHP-метода способ очистки. Для продолжения без ограничения сохраняйте чистый исходник и работайте с новой его копией.

Выполнение этих примеров относится к PHP 8.3.6 / Imagick 3.7.0 / ImageMagick 6.9.12-98 Q16. Точные deprecated-предупреждения записываются в metrics.json, а не скрываются оператором @. Новые IM7 getImageMask/setImageMask используют PixelMask-параметр и другой контракт: getter может вернуть null, setter имеет void. Их нельзя объявить автоматическим переименованием с идентичной полярностью и действием. Если нужна мягкая прозрачность слоя, это отдельная операция с альфа-каналом и композицией.

Полный официальный XML с доступностью, deprecated, параметрами, результатом, ошибками и примером
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<refentry xmlns="http://docbook.org/ns/docbook" xml:id="imagick.getimageclipmask">
 <refnamediv>
  <refname>Imagick::getImageClipMask</refname>
  <refpurpose>Gets image clip mask</refpurpose>
 </refnamediv>

 <refsynopsisdiv>
   &imagick.deprecated.function-3-4-4;
 </refsynopsisdiv>

 <refsect1 role="description">
  &reftitle.description;
  <methodsynopsis>
   <modifier>public</modifier> <type>Imagick</type><methodname>Imagick::getImageClipMask</methodname>
   <void />
  </methodsynopsis>

  <para>
   Returns the image clip mask. The clip mask is an Imagick object containing the clip mask.
   &imagick.method.available.0x636;
  </para>
 </refsect1>

 <refsect1 role="parameters">
  &reftitle.parameters;
  &no.function.parameters;
 </refsect1>

 <refsect1 role="returnvalues">
  &reftitle.returnvalues;
  <para>
   Returns an Imagick object containing the clip mask.
  </para>
 </refsect1>

 <refsect1 role="errors">
  &reftitle.errors;
  <para>
   &imagick.imagick.throws;
  </para>
 </refsect1>

</refentry>

<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->

Полный официальный базис

Imagick::setImageClipMask(Imagick $clip_mask): bool

Оба имени объявлены устаревшими начиная с Imagick 3.4.4. Официальная базовая доступность связана с ImageMagick 6.3.6; полная исходная запись сохранена ниже. Точные bindings Imagick 3.7.0 и 3.8.1 включают эти методы только при ImageMagick < 7.0.0. Поэтому наличие PHP-кода из официального примера не означает, что этот метод существует в любой современной IM7-сборке.

setImageClipMask принимает один обязательный объект Imagick, содержащий маску, и возвращает true при успехе. Изображение и маска должны быть непустыми и иметь одинаковые ширину и высоту. Setter прикрепляет копию маски к текущему изображению; RGB от самого прикрепления в примере не меняются. Конкретный видимый результат появляется после последующей операции, здесь negateImage(false). Официальный раздел ошибок сохранён: неуспех превращается в ImagickException.

Исходный официальный пример целиком сохранён ниже. Он читает файл, создаёт маску того же размера на прозрачной основе, рисует белый круг, вызывает setImageClipMask, затем negateImage(false), задаёт PNG через setFormat и выводит getImagesBlob с Content-Type. Прозрачная основа этого конкретного примера не делает clip-mask командой прозрачности: legacy cache читает интенсивность маски. Наши собственные простые варианты используют непрозрачные чёрное и белое, чтобы явно показать полярность.

В точном IM6 Core setter клонирует входную маску, а getter клонирует сохранённую. Изменение переданного объекта или полученной копии не переписывает прикреплённую маску. C-функция умеет снимать маску через NULL, но PHP-wrapper требует непустой Imagick: setImageClipMask(null) вызывает TypeError, пустой объект — ImagickException. Это не доступный из данного PHP-метода способ очистки. Для продолжения без ограничения сохраняйте чистый исходник и работайте с новой его копией.

Выполнение этих примеров относится к PHP 8.3.6 / Imagick 3.7.0 / ImageMagick 6.9.12-98 Q16. Точные deprecated-предупреждения записываются в metrics.json, а не скрываются оператором @. Новые IM7 getImageMask/setImageMask используют PixelMask-параметр и другой контракт: getter может вернуть null, setter имеет void. Их нельзя объявить автоматическим переименованием с идентичной полярностью и действием. Если нужна мягкая прозрачность слоя, это отдельная операция с альфа-каналом и композицией.

Полный официальный XML с доступностью, deprecated, параметрами, результатом, ошибками и примером
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<refentry xmlns="http://docbook.org/ns/docbook" xml:id="imagick.setimageclipmask">
 <refnamediv>
  <refname>Imagick::setImageClipMask</refname>
  <refpurpose>Sets image clip mask</refpurpose>
 </refnamediv>

 <refsynopsisdiv>
   &imagick.deprecated.function-3-4-4;
 </refsynopsisdiv>

 <refsect1 role="description">
  &reftitle.description;
  <methodsynopsis>
   <modifier>public</modifier> <type>bool</type><methodname>Imagick::setImageClipMask</methodname>
   <methodparam><type>Imagick</type><parameter>clip_mask</parameter></methodparam>
  </methodsynopsis>

  <para>
   Sets image clip mask from another Imagick object.
   &imagick.method.available.0x636;
  </para>
 </refsect1>

 <refsect1 role="parameters">
  &reftitle.parameters;
  <para>
   <variablelist>
    <varlistentry>
     <term><parameter>clip_mask</parameter></term>
     <listitem>
      <para>
      The Imagick object containing the clip mask
      </para>
     </listitem>
    </varlistentry>
   </variablelist>
  </para>
 </refsect1>

 <refsect1 role="returnvalues">
  &reftitle.returnvalues;
  <para>
   &imagick.return.success;
  </para>
 </refsect1>

 <refsect1 role="errors">
  &reftitle.errors;
  <para>
   &imagick.imagick.throws;
  </para>
 </refsect1>



 <refsect1 role="examples">
  &reftitle.examples;
  <para>
    <example>
      <title> <function>Imagick::setImageClipMask</function></title>
      <programlisting role="php">
      <![CDATA[
<?php
function setImageClipMask($imagePath) {
    $imagick = new \Imagick();
    $imagick->readImage(realpath($imagePath));

    $width = $imagick->getImageWidth();
    $height = $imagick->getImageHeight();

    $clipMask = new \Imagick();
    $clipMask->newPseudoImage(
        $width,
        $height,
        "canvas:transparent"
    );

    $draw = new \ImagickDraw();
    $draw->setFillColor('white');
    $draw->circle(
        $width / 2,
        $height / 2,
        ($width / 2) + ($width / 4),
        $height / 2
    );
    $clipMask->drawImage($draw);
    $imagick->setImageClipMask($clipMask);

    $imagick->negateImage(false);
    $imagick->setFormat("png");

    header("Content-Type: image/png");
    echo $imagick->getImagesBlob();
    
}

?>
]]>
      </programlisting>
    </example>
  </para>
 </refsect1>

</refentry>

<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->

Запуск проверенной ветки IM6

Для Ubuntu 24.04 использованы официальные пакеты PHP CLI и Imagick. После установки выполните php example.php в каталоге распакованного примера. Фактические версии проверки указаны выше; это не обещание, что любой пакет с именем Imagick связан с IM6.

sudo apt install php8.3-cli php8.3-imagick
php example.php

При переносе сначала уточните связанную версию ImageMagick и наличие обоих методов. На IM7 требуется пересмотреть задачу и другой API, а не убрать предупреждение или заменить имя метода без проверки результата. Если цель — мягкая прозрачность, выбирайте соответствующий альфа-композитинг; если цель — жёсткая защита записи в старом обработчике IM6, показанный растр и операция дают воспроизводимый результат.

Полный исполняемый fixture

<?php
declare(strict_types=1);
function legacyMaskRestore():void {
    $raw=base64_decode((string)file_get_contents(__DIR__.'/source.png.b64'),true);
    if($raw===false||hash('sha256',$raw)!=='f51e5780445e0f5130a7f23112b2a00618035afd5545b8e3042c7ccff09b617c'||file_put_contents(__DIR__.'/source.png',$raw)===false){throw new RuntimeException('Own exact PNG missing or changed');}
}
function legacyMaskBase():Imagick {
    $input=new Imagick(__DIR__.'/source.png');$base=new Imagick();$base->newImage(400,320,new ImagickPixel('white'),'png');
    $base->compositeImage($input,Imagick::COMPOSITE_OVER,0,0);$base->setImageAlphaChannel(Imagick::ALPHACHANNEL_DEACTIVATE);return $base;
}
function legacyMaskPattern(string $background='white',string $window='black'):Imagick {
    $mask=new Imagick();$mask->newImage(400,320,new ImagickPixel($background),'png');
    $draw=new ImagickDraw();$draw->setStrokeAntialias(false);$draw->setFillColor(new ImagickPixel($window));
    $draw->rectangle(240,80,359,239);$mask->drawImage($draw);return $mask;
}
function legacyMaskHash(Imagick $image):string {
    return hash('sha256',json_encode($image->exportImagePixels(0,0,$image->getImageWidth(),$image->getImageHeight(),'RGB',Imagick::PIXEL_DOUBLE),JSON_THROW_ON_ERROR));
}
function legacyMaskPixels(Imagick $image):array {return $image->exportImagePixels(0,0,400,320,'RGB',Imagick::PIXEL_CHAR);}
function legacyMaskCall(callable $operation,array &$warnings):mixed {
    set_error_handler(static function(int $level,string $message) use (&$warnings):bool {
        if($level===E_DEPRECATED&&(str_contains($message,'Imagick::setImageClipMask')||str_contains($message,'Imagick::getImageClipMask'))){
            $warnings[]=['level'=>$level,'message'=>$message];return true;
        }
        return false;
    });
    try{return $operation();}finally{restore_error_handler();}
}
function legacyMaskWarningsValid(array $warnings):bool {
    if(!$warnings){return false;}
    foreach($warnings as $warning){
        if($warning['level']!==E_DEPRECATED||!in_array($warning['message'],['Method Imagick::setImageClipMask() is deprecated','Method Imagick::getImageClipMask() is deprecated'],true)){return false;}
    }
    return true;
}
function legacyMaskView(Imagick $image,string $name):void {
    // A fresh display image has no attached clip mask of its own.
    $view=new Imagick();$view->newImage($image->getImageWidth(),$image->getImageHeight(),'white');
    $view->compositeImage($image,Imagick::COMPOSITE_OVER,0,0);$view->setImageType(Imagick::IMGTYPE_TRUECOLOR);
    $view->setImageFormat('png');$view->setImageDepth(8);$view->setOption('png:bit-depth','8');
    $view->setOption('png:color-type','2');$view->setOption('png:exclude-chunk','all');
    if(!$view->writeImage(__DIR__.'/'.$name)){throw new RuntimeException('PNG8 write failed');}
}
function legacyMaskCompare(array $images,string $name):array {
    $board=new Imagick();$board->newImage(400*count($images),320,'white');$rects=[];
    foreach($images as $i=>$image){
        if($image->getImageWidth()!==400||$image->getImageHeight()!==320){throw new RuntimeException('Expected a full 400x320 panel');}
        $board->compositeImage($image,Imagick::COMPOSITE_OVER,400*$i,0);$rects[]=['x'=>400*$i,'y'=>0,'width'=>400,'height'=>320];
    }
    legacyMaskView($board,$name);return $rects;
}
function legacyMaskCounts(Imagick $source,Imagick $global,Imagick $result):array {
    $a=legacyMaskPixels($source);$b=legacyMaskPixels($global);$c=legacyMaskPixels($result);
    $counts=['inside'=>['source'=>0,'global'=>0,'other'=>0],'outside'=>['source'=>0,'global'=>0,'other'=>0]];
    for($y=0;$y<320;$y++)for($x=0;$x<400;$x++){
        $i=($y*400+$x)*3;$region=($x>=240&&$x<=359&&$y>=80&&$y<=239)?'inside':'outside';
        $v=array_slice($c,$i,3);$key=$v===array_slice($a,$i,3)?'source':($v===array_slice($b,$i,3)?'global':'other');$counts[$region][$key]++;
    }
    return $counts;
}
function legacyMaskInsideCorrect(array $counts):bool {
    return $counts===['inside'=>['source'=>0,'global'=>19200,'other'=>0],'outside'=>['source'=>108800,'global'=>0,'other'=>0]];
}
function legacyMaskOutsideCorrect(array $counts):bool {
    return $counts===['inside'=>['source'=>19200,'global'=>0,'other'=>0],'outside'=>['source'=>0,'global'=>108800,'other'=>0]];
}
function legacyMaskDiagnostic(string $id,array $data):void {
    $doc=['schema'=>'aen-legacy-clip-mask-program-diagnostics-v1','example_id'=>$id]+$data;
    if(file_put_contents(__DIR__.'/metrics.json',json_encode($doc,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR)."\n")===false){throw new RuntimeException('Diagnostic write failed');}
}
function legacyMaskFirstProof(string $id,Imagick $base,Imagick $mask,Imagick $returned,Imagick $result,bool $ok,bool $unchanged,array $warnings,string $before):void {
    $global=clone $base;$global->negateImage(false);$counts=legacyMaskCounts($base,$global,$result);
    legacyMaskView($base,'source-preview8.png');legacyMaskView($mask,'input-mask8.png');legacyMaskView($returned,'returned-mask8.png');legacyMaskView($result,'inside-result8.png');
    $rects=legacyMaskCompare([$base,$returned,$result],'legacy-clip-mask-first.png');
    legacyMaskDiagnostic($id,['executed_apis'=>['setImageClipMask','getImageClipMask'],'setter_return'=>$ok,'RGB_unchanged_after_set'=>$unchanged,
        'getter_size'=>[$returned->getImageWidth(),$returned->getImageHeight()],'mask_matches_input'=>legacyMaskHash($returned)===legacyMaskHash($mask),
        'counts'=>$counts,'warnings'=>$warnings,'source_unchanged'=>legacyMaskHash($base)===$before,'panel_geometry'=>$rects,
        'checks'=>['setter_true'=>$ok===true,'set_keeps_RGB'=>$unchanged,'actual_mask_matches'=>legacyMaskHash($returned)===legacyMaskHash($mask),
            'black_window_changes'=>legacyMaskInsideCorrect($counts),'original_preserved'=>legacyMaskHash($base)===$before,'deprecations_saved'=>legacyMaskWarningsValid($warnings)]]);
}
function legacyMaskSetProof(string $id,Imagick $base,Imagick $mask,Imagick $result,bool $ok,bool $unchanged,array $warnings,string $before):void {
    $global=clone $base;$global->negateImage(false);$counts=legacyMaskCounts($base,$global,$result);
    legacyMaskView($mask,'set-mask8.png');legacyMaskView($result,'legacy-clip-mask-set.png');
    legacyMaskDiagnostic($id,['executed_api'=>'setImageClipMask','setter_return'=>$ok,'RGB_unchanged_after_set'=>$unchanged,
        'counts'=>$counts,'warnings'=>$warnings,'source_unchanged'=>legacyMaskHash($base)===$before,
        'checks'=>['setter_true'=>$ok===true,'set_keeps_RGB'=>$unchanged,'black_window_changes'=>legacyMaskInsideCorrect($counts),
            'original_preserved'=>legacyMaskHash($base)===$before,'deprecations_saved'=>legacyMaskWarningsValid($warnings)]]);
}
function legacyMaskGetProof(string $id,Imagick $base,Imagick $inputMask,Imagick $copy,array $warnings,string $before):void {
    legacyMaskView($base,'get-source8.png');legacyMaskView($copy,'legacy-clip-mask-get.png');$same=legacyMaskHash($copy)===legacyMaskHash($inputMask);
    legacyMaskDiagnostic($id,['executed_api'=>'getImageClipMask','getter_type'=>get_debug_type($copy),
        'getter_size'=>[$copy->getImageWidth(),$copy->getImageHeight()],'mask_matches_input'=>$same,'warnings'=>$warnings,
        'source_unchanged'=>legacyMaskHash($base)===$before,'checks'=>['real_mask_returned'=>$copy instanceof Imagick,
            'same_geometry'=>$copy->getImageWidth()===400&&$copy->getImageHeight()===320,'actual_mask_matches'=>$same,
            'original_preserved'=>legacyMaskHash($base)===$before,'deprecations_saved'=>legacyMaskWarningsValid($warnings)]]);
}

Helper готовит собственный вход и маску, сохраняет PNG8 через отдельный чистый просмотровый объект, считает пиксели и записывает JSON. Вызовы изучаемых get/set остаются в примерах. Обёртка legacyMaskCall сохраняет только относящиеся к ним E_DEPRECATED и возвращает прежний обработчик через finally; неожиданные предупреждения не выдаются за успех. Веб-ответ с PNG следует отправлять отдельно с Content-Type: image/png, без текстовой диагностики. Далее: исключения, функции и параметры, копии объектов и композиция.

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

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

Imagick::getImageClipMaskРастровая защита записи в IM6: чёрное окно, отдельная маска и независимые копии

PECL imagick 2 >= 2.3.0, PECL imagick 3 · imagick

Imagick::getImageClipMask(): Imagick

Полный официальный базис

Imagick::getImageClipMask(): Imagick

Оба имени объявлены устаревшими начиная с Imagick 3.4.4. Официальная базовая доступность связана с ImageMagick 6.3.6; полная исходная запись сохранена ниже. Точные bindings Imagick 3.7.0 и 3.8.1 включают эти методы только при ImageMagick < 7.0.0. Поэтому наличие PHP-кода из официального примера не означает, что этот метод существует в любой современной IM7-сборке.

getImageClipMask не принимает аргументов и возвращает новый объект Imagick с прикреплённой clip-mask. Это отдельная копия растровой маски, не исходное цветное изображение и не bool. Официальное описание ошибок указывает ImagickException. В проверенной реализации отсутствие прикреплённой маски тоже приводит к этому исключению; получить null или false как штатный результат этого старого getter нельзя.

В точном IM6 Core setter клонирует входную маску, а getter клонирует сохранённую. Изменение переданного объекта или полученной копии не переписывает прикреплённую маску. C-функция умеет снимать маску через NULL, но PHP-wrapper требует непустой Imagick: setImageClipMask(null) вызывает TypeError, пустой объект — ImagickException. Это не доступный из данного PHP-метода способ очистки. Для продолжения без ограничения сохраняйте чистый исходник и работайте с новой его копией.

Выполнение этих примеров относится к PHP 8.3.6 / Imagick 3.7.0 / ImageMagick 6.9.12-98 Q16. Точные deprecated-предупреждения записываются в metrics.json, а не скрываются оператором @. Новые IM7 getImageMask/setImageMask используют PixelMask-параметр и другой контракт: getter может вернуть null, setter имеет void. Их нельзя объявить автоматическим переименованием с идентичной полярностью и действием. Если нужна мягкая прозрачность слоя, это отдельная операция с альфа-каналом и композицией.

Полный официальный XML с доступностью, deprecated, параметрами, результатом, ошибками и примером
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<refentry xmlns="http://docbook.org/ns/docbook" xml:id="imagick.getimageclipmask">
 <refnamediv>
  <refname>Imagick::getImageClipMask</refname>
  <refpurpose>Gets image clip mask</refpurpose>
 </refnamediv>

 <refsynopsisdiv>
   &imagick.deprecated.function-3-4-4;
 </refsynopsisdiv>

 <refsect1 role="description">
  &reftitle.description;
  <methodsynopsis>
   <modifier>public</modifier> <type>Imagick</type><methodname>Imagick::getImageClipMask</methodname>
   <void />
  </methodsynopsis>

  <para>
   Returns the image clip mask. The clip mask is an Imagick object containing the clip mask.
   &imagick.method.available.0x636;
  </para>
 </refsect1>

 <refsect1 role="parameters">
  &reftitle.parameters;
  &no.function.parameters;
 </refsect1>

 <refsect1 role="returnvalues">
  &reftitle.returnvalues;
  <para>
   Returns an Imagick object containing the clip mask.
  </para>
 </refsect1>

 <refsect1 role="errors">
  &reftitle.errors;
  <para>
   &imagick.imagick.throws;
  </para>
 </refsect1>

</refentry>

<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->

Получить прикреплённую маску как отдельный объект

После явного предварительного setter вызов getter вернул настоящий Imagick 400 × 320 с той же маской. Getter не возвращает цветной результат negate и не превращает исходное изображение в маску.

Получить прикреплённую маску как отдельный объектПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__.'/clip-mask-fixture.php';
legacyMaskRestore();
$base=legacyMaskBase(); $mask=legacyMaskPattern();
$before=legacyMaskHash($base); $warnings=[];
$image=clone $base;
legacyMaskCall(fn()=>$image->setImageClipMask($mask),$warnings);
$copy=legacyMaskCall(fn()=>$image->getImageClipMask(),$warnings);
legacyMaskGetProof('legacy-clip-mask-get-minimal',$base,$mask,$copy,$warnings,$before);
echo "legacy-clip-mask-get.png\nget-source8.png\nmetrics.json\nget=Imagick size=400x320 matches-input=1 warnings=saved\n";

После явного предварительного setter вызов getter вернул настоящий Imagick 400 × 320 с той же маской. Getter не возвращает цветной результат negate и не превращает исходное изображение в маску. Архив содержит example.php, source.png.b64 и clip-mask-fixture.php. Сохраните рядом и выполните php example.php с IM6-совместимой Imagick и поддержкой PNG. Проверенная среда: PHP 8.3.6 / Imagick 3.7.0 / ImageMagick 6.9.12-98 Q16, Ubuntu 24.04. Это устаревшие IM6-only методы; выполнение на связанной с IM7 Windows-сборке здесь не заявлено. Helper восстанавливает собственный рисунок, создаёт явно показанную растровую маску, сохраняет PNG8 и измерения. Изучаемые set/get остаются видны в основной программе. legacyMaskCall перехватывает только предупреждения этих двух deprecated-методов в пределах вызова, сохраняет точные сообщения и восстанавливает прежний обработчик через finally.

Ожидаемый вывод в проверенной IM6-сборке
legacy-clip-mask-get.png
get-source8.png
metrics.json
get=Imagick size=400x320 matches-input=1 warnings=saved

Проверить копии, полярность, серую область и плохие входы

Сравнены чёрное окно, белое окно и gray50. Серый участок защищает полностью, как белый: это не мягкая альфа-маска. Изменение исходного объекта маски и полученной getter-копии не меняет уже прикреплённую маску. Шесть ошибок пойманы, оригинал сохранён.

Проверить копии, полярность, серую область и плохие входыПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__.'/clip-mask-fixture.php';
legacyMaskRestore();
$base=legacyMaskBase(); $mask=legacyMaskPattern();
$before=legacyMaskHash($base); $warnings=[];
$global=clone $base;$global->negateImage(false);$image=clone $base;
$ok=legacyMaskCall(fn()=>$image->setImageClipMask($mask),$warnings);
$setUnchanged=legacyMaskHash($image)===$before;
$read=legacyMaskCall(fn()=>$image->getImageClipMask(),$warnings);$maskBefore=legacyMaskHash($read);
$mask->negateImage(false);
$attached=legacyMaskCall(fn()=>$image->getImageClipMask(),$warnings);
$setterClones=legacyMaskHash($attached)===$maskBefore;
$read->negateImage(false);
$attached=legacyMaskCall(fn()=>$image->getImageClipMask(),$warnings);
$getterClones=legacyMaskHash($attached)===$maskBefore;
$image->negateImage(false);$insideCounts=legacyMaskCounts($base,$global,$image);
$outside=clone $base;$outsideMask=legacyMaskPattern('black','white');
legacyMaskCall(fn()=>$outside->setImageClipMask($outsideMask),$warnings);
$outside->negateImage(false);$outsideCounts=legacyMaskCounts($base,$global,$outside);
$gray=clone $base;$grayMask=legacyMaskPattern('black','gray50');
legacyMaskCall(fn()=>$gray->setImageClipMask($grayMask),$warnings);
$gray->negateImage(false);$grayCounts=legacyMaskCounts($base,$global,$gray);
$errors=[];
$attempts=[
    'get_absent'=>fn()=>(clone $base)->getImageClipMask(),
    'get_empty'=>fn()=>(new Imagick())->getImageClipMask(),
    'set_empty_base'=>fn()=>(new Imagick())->setImageClipMask($outsideMask),
    'set_empty_mask'=>fn()=>(clone $base)->setImageClipMask(new Imagick()),
    'set_size_mismatch'=>function()use($base){$small=new Imagick();$small->newImage(100,100,'black');return (clone $base)->setImageClipMask($small);},
    'set_null'=>fn()=>(clone $base)->setImageClipMask(null)
];
foreach($attempts as $name=>$attempt){
    try{legacyMaskCall($attempt,$warnings);$errors[$name]=['class'=>'not caught','message'=>''];}
    catch(Throwable $error){$errors[$name]=['class'=>get_class($error),'message'=>$error->getMessage()];}
}
legacyMaskView($image,'workflow-inside8.png');legacyMaskView($outside,'workflow-outside8.png');legacyMaskView($gray,'workflow-gray8.png');
legacyMaskView($attached,'workflow-returned8.png');legacyMaskView($read,'workflow-modified-copy8.png');
legacyMaskView($base,'workflow-source8.png');legacyMaskView($grayMask,'workflow-gray-mask8.png');
$rects=legacyMaskCompare([$image,$outside,$gray],'legacy-clip-mask-workflow.png');
$sourceKept=legacyMaskHash($base)===$before;
legacyMaskDiagnostic('legacy-clip-mask-workflow',['executed_apis'=>['setImageClipMask','getImageClipMask'],
    'setter_return'=>$ok,'RGB_unchanged_after_set'=>$setUnchanged,'setter_clones'=>$setterClones,'getter_clones'=>$getterClones,
    'inside_counts'=>$insideCounts,'outside_counts'=>$outsideCounts,'gray_counts'=>$grayCounts,'errors'=>$errors,
    'warnings'=>$warnings,'source_unchanged'=>$sourceKept,'panel_geometry'=>$rects,
    'checks'=>['setter_true'=>$ok===true,'set_keeps_RGB'=>$setUnchanged,'setter_copies_mask'=>$setterClones,'getter_returns_copy'=>$getterClones,
        'black_window_changes'=>legacyMaskInsideCorrect($insideCounts),'white_window_protects'=>legacyMaskOutsideCorrect($outsideCounts),
        'gray_is_full_protection'=>legacyMaskOutsideCorrect($grayCounts),'gray_matches_white_result'=>legacyMaskHash($gray)===legacyMaskHash($outside),
        'six_failures_caught'=>array_column($errors,'class')===['ImagickException','ImagickException','ImagickException','ImagickException','ImagickException','TypeError'],
        'original_preserved'=>$sourceKept,'deprecations_saved'=>legacyMaskWarningsValid($warnings)]]);
echo "legacy-clip-mask-workflow.png\nworkflow-inside8.png\nworkflow-outside8.png\nworkflow-gray8.png\nworkflow-returned8.png\nworkflow-modified-copy8.png\nworkflow-source8.png\nworkflow-gray-mask8.png\nmetrics.json\nsetter-copy=1 getter-copy=1 errors=6 source-unchanged=1 warnings=saved\n";

Сравнены чёрное окно, белое окно и gray50. Серый участок защищает полностью, как белый: это не мягкая альфа-маска. Изменение исходного объекта маски и полученной getter-копии не меняет уже прикреплённую маску. Шесть ошибок пойманы, оригинал сохранён. Архив содержит example.php, source.png.b64 и clip-mask-fixture.php. Сохраните рядом и выполните php example.php с IM6-совместимой Imagick и поддержкой PNG. Проверенная среда: PHP 8.3.6 / Imagick 3.7.0 / ImageMagick 6.9.12-98 Q16, Ubuntu 24.04. Это устаревшие IM6-only методы; выполнение на связанной с IM7 Windows-сборке здесь не заявлено. Helper восстанавливает собственный рисунок, создаёт явно показанную растровую маску, сохраняет PNG8 и измерения. Изучаемые set/get остаются видны в основной программе. legacyMaskCall перехватывает только предупреждения этих двух deprecated-методов в пределах вызова, сохраняет точные сообщения и восстанавливает прежний обработчик через finally.

Ожидаемый вывод в проверенной IM6-сборке
legacy-clip-mask-workflow.png
workflow-inside8.png
workflow-outside8.png
workflow-gray8.png
workflow-returned8.png
workflow-modified-copy8.png
workflow-source8.png
workflow-gray-mask8.png
metrics.json
setter-copy=1 getter-copy=1 errors=6 source-unchanged=1 warnings=saved
Imagick::setImageClipMaskРастровая защита записи в IM6: чёрное окно, отдельная маска и независимые копии

PECL imagick 2 >= 2.3.0, PECL imagick 3 · imagick

Imagick::setImageClipMask(Imagick $clip_mask): bool

Полный официальный базис

Imagick::setImageClipMask(Imagick $clip_mask): bool

Оба имени объявлены устаревшими начиная с Imagick 3.4.4. Официальная базовая доступность связана с ImageMagick 6.3.6; полная исходная запись сохранена ниже. Точные bindings Imagick 3.7.0 и 3.8.1 включают эти методы только при ImageMagick < 7.0.0. Поэтому наличие PHP-кода из официального примера не означает, что этот метод существует в любой современной IM7-сборке.

setImageClipMask принимает один обязательный объект Imagick, содержащий маску, и возвращает true при успехе. Изображение и маска должны быть непустыми и иметь одинаковые ширину и высоту. Setter прикрепляет копию маски к текущему изображению; RGB от самого прикрепления в примере не меняются. Конкретный видимый результат появляется после последующей операции, здесь negateImage(false). Официальный раздел ошибок сохранён: неуспех превращается в ImagickException.

Исходный официальный пример целиком сохранён ниже. Он читает файл, создаёт маску того же размера на прозрачной основе, рисует белый круг, вызывает setImageClipMask, затем negateImage(false), задаёт PNG через setFormat и выводит getImagesBlob с Content-Type. Прозрачная основа этого конкретного примера не делает clip-mask командой прозрачности: legacy cache читает интенсивность маски. Наши собственные простые варианты используют непрозрачные чёрное и белое, чтобы явно показать полярность.

В точном IM6 Core setter клонирует входную маску, а getter клонирует сохранённую. Изменение переданного объекта или полученной копии не переписывает прикреплённую маску. C-функция умеет снимать маску через NULL, но PHP-wrapper требует непустой Imagick: setImageClipMask(null) вызывает TypeError, пустой объект — ImagickException. Это не доступный из данного PHP-метода способ очистки. Для продолжения без ограничения сохраняйте чистый исходник и работайте с новой его копией.

Выполнение этих примеров относится к PHP 8.3.6 / Imagick 3.7.0 / ImageMagick 6.9.12-98 Q16. Точные deprecated-предупреждения записываются в metrics.json, а не скрываются оператором @. Новые IM7 getImageMask/setImageMask используют PixelMask-параметр и другой контракт: getter может вернуть null, setter имеет void. Их нельзя объявить автоматическим переименованием с идентичной полярностью и действием. Если нужна мягкая прозрачность слоя, это отдельная операция с альфа-каналом и композицией.

Полный официальный XML с доступностью, deprecated, параметрами, результатом, ошибками и примером
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<refentry xmlns="http://docbook.org/ns/docbook" xml:id="imagick.setimageclipmask">
 <refnamediv>
  <refname>Imagick::setImageClipMask</refname>
  <refpurpose>Sets image clip mask</refpurpose>
 </refnamediv>

 <refsynopsisdiv>
   &imagick.deprecated.function-3-4-4;
 </refsynopsisdiv>

 <refsect1 role="description">
  &reftitle.description;
  <methodsynopsis>
   <modifier>public</modifier> <type>bool</type><methodname>Imagick::setImageClipMask</methodname>
   <methodparam><type>Imagick</type><parameter>clip_mask</parameter></methodparam>
  </methodsynopsis>

  <para>
   Sets image clip mask from another Imagick object.
   &imagick.method.available.0x636;
  </para>
 </refsect1>

 <refsect1 role="parameters">
  &reftitle.parameters;
  <para>
   <variablelist>
    <varlistentry>
     <term><parameter>clip_mask</parameter></term>
     <listitem>
      <para>
      The Imagick object containing the clip mask
      </para>
     </listitem>
    </varlistentry>
   </variablelist>
  </para>
 </refsect1>

 <refsect1 role="returnvalues">
  &reftitle.returnvalues;
  <para>
   &imagick.return.success;
  </para>
 </refsect1>

 <refsect1 role="errors">
  &reftitle.errors;
  <para>
   &imagick.imagick.throws;
  </para>
 </refsect1>



 <refsect1 role="examples">
  &reftitle.examples;
  <para>
    <example>
      <title> <function>Imagick::setImageClipMask</function></title>
      <programlisting role="php">
      <![CDATA[
<?php
function setImageClipMask($imagePath) {
    $imagick = new \Imagick();
    $imagick->readImage(realpath($imagePath));

    $width = $imagick->getImageWidth();
    $height = $imagick->getImageHeight();

    $clipMask = new \Imagick();
    $clipMask->newPseudoImage(
        $width,
        $height,
        "canvas:transparent"
    );

    $draw = new \ImagickDraw();
    $draw->setFillColor('white');
    $draw->circle(
        $width / 2,
        $height / 2,
        ($width / 2) + ($width / 4),
        $height / 2
    );
    $clipMask->drawImage($draw);
    $imagick->setImageClipMask($clipMask);

    $imagick->negateImage(false);
    $imagick->setFormat("png");

    header("Content-Type: image/png");
    echo $imagick->getImagesBlob();
    
}

?>
]]>
      </programlisting>
    </example>
  </para>
 </refsect1>

</refentry>

<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->

Установить отдельную маску перед конкретной операцией

Setter вернул true и сам не изменил RGB. Следующий negate изменил только область, где непрозрачная маска чёрная. Это ограничение последующей записи, а не команда сделать фон прозрачным.

Установить отдельную маску перед конкретной операциейПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__.'/clip-mask-fixture.php';
legacyMaskRestore();
$base=legacyMaskBase(); $mask=legacyMaskPattern();
$before=legacyMaskHash($base); $warnings=[];
$image=clone $base;
$ok=legacyMaskCall(fn()=>$image->setImageClipMask($mask),$warnings);
$unchanged=legacyMaskHash($image)===$before;
$image->negateImage(false);
legacyMaskSetProof('legacy-clip-mask-set-minimal',$base,$mask,$image,$ok,$unchanged,$warnings,$before);
echo "legacy-clip-mask-set.png\nset-mask8.png\nmetrics.json\nset=true unchanged-after-set=1 effect=black-area warnings=saved\n";

Setter вернул true и сам не изменил RGB. Следующий negate изменил только область, где непрозрачная маска чёрная. Это ограничение последующей записи, а не команда сделать фон прозрачным. Архив содержит example.php, source.png.b64 и clip-mask-fixture.php. Сохраните рядом и выполните php example.php с IM6-совместимой Imagick и поддержкой PNG. Проверенная среда: PHP 8.3.6 / Imagick 3.7.0 / ImageMagick 6.9.12-98 Q16, Ubuntu 24.04. Это устаревшие IM6-only методы; выполнение на связанной с IM7 Windows-сборке здесь не заявлено. Helper восстанавливает собственный рисунок, создаёт явно показанную растровую маску, сохраняет PNG8 и измерения. Изучаемые set/get остаются видны в основной программе. legacyMaskCall перехватывает только предупреждения этих двух deprecated-методов в пределах вызова, сохраняет точные сообщения и восстанавливает прежний обработчик через finally.

Ожидаемый вывод в проверенной IM6-сборке
legacy-clip-mask-set.png
set-mask8.png
metrics.json
set=true unchanged-after-set=1 effect=black-area warnings=saved

Проверить копии, полярность, серую область и плохие входы

Сравнены чёрное окно, белое окно и gray50. Серый участок защищает полностью, как белый: это не мягкая альфа-маска. Изменение исходного объекта маски и полученной getter-копии не меняет уже прикреплённую маску. Шесть ошибок пойманы, оригинал сохранён.

Проверить копии, полярность, серую область и плохие входыПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__.'/clip-mask-fixture.php';
legacyMaskRestore();
$base=legacyMaskBase(); $mask=legacyMaskPattern();
$before=legacyMaskHash($base); $warnings=[];
$global=clone $base;$global->negateImage(false);$image=clone $base;
$ok=legacyMaskCall(fn()=>$image->setImageClipMask($mask),$warnings);
$setUnchanged=legacyMaskHash($image)===$before;
$read=legacyMaskCall(fn()=>$image->getImageClipMask(),$warnings);$maskBefore=legacyMaskHash($read);
$mask->negateImage(false);
$attached=legacyMaskCall(fn()=>$image->getImageClipMask(),$warnings);
$setterClones=legacyMaskHash($attached)===$maskBefore;
$read->negateImage(false);
$attached=legacyMaskCall(fn()=>$image->getImageClipMask(),$warnings);
$getterClones=legacyMaskHash($attached)===$maskBefore;
$image->negateImage(false);$insideCounts=legacyMaskCounts($base,$global,$image);
$outside=clone $base;$outsideMask=legacyMaskPattern('black','white');
legacyMaskCall(fn()=>$outside->setImageClipMask($outsideMask),$warnings);
$outside->negateImage(false);$outsideCounts=legacyMaskCounts($base,$global,$outside);
$gray=clone $base;$grayMask=legacyMaskPattern('black','gray50');
legacyMaskCall(fn()=>$gray->setImageClipMask($grayMask),$warnings);
$gray->negateImage(false);$grayCounts=legacyMaskCounts($base,$global,$gray);
$errors=[];
$attempts=[
    'get_absent'=>fn()=>(clone $base)->getImageClipMask(),
    'get_empty'=>fn()=>(new Imagick())->getImageClipMask(),
    'set_empty_base'=>fn()=>(new Imagick())->setImageClipMask($outsideMask),
    'set_empty_mask'=>fn()=>(clone $base)->setImageClipMask(new Imagick()),
    'set_size_mismatch'=>function()use($base){$small=new Imagick();$small->newImage(100,100,'black');return (clone $base)->setImageClipMask($small);},
    'set_null'=>fn()=>(clone $base)->setImageClipMask(null)
];
foreach($attempts as $name=>$attempt){
    try{legacyMaskCall($attempt,$warnings);$errors[$name]=['class'=>'not caught','message'=>''];}
    catch(Throwable $error){$errors[$name]=['class'=>get_class($error),'message'=>$error->getMessage()];}
}
legacyMaskView($image,'workflow-inside8.png');legacyMaskView($outside,'workflow-outside8.png');legacyMaskView($gray,'workflow-gray8.png');
legacyMaskView($attached,'workflow-returned8.png');legacyMaskView($read,'workflow-modified-copy8.png');
legacyMaskView($base,'workflow-source8.png');legacyMaskView($grayMask,'workflow-gray-mask8.png');
$rects=legacyMaskCompare([$image,$outside,$gray],'legacy-clip-mask-workflow.png');
$sourceKept=legacyMaskHash($base)===$before;
legacyMaskDiagnostic('legacy-clip-mask-workflow',['executed_apis'=>['setImageClipMask','getImageClipMask'],
    'setter_return'=>$ok,'RGB_unchanged_after_set'=>$setUnchanged,'setter_clones'=>$setterClones,'getter_clones'=>$getterClones,
    'inside_counts'=>$insideCounts,'outside_counts'=>$outsideCounts,'gray_counts'=>$grayCounts,'errors'=>$errors,
    'warnings'=>$warnings,'source_unchanged'=>$sourceKept,'panel_geometry'=>$rects,
    'checks'=>['setter_true'=>$ok===true,'set_keeps_RGB'=>$setUnchanged,'setter_copies_mask'=>$setterClones,'getter_returns_copy'=>$getterClones,
        'black_window_changes'=>legacyMaskInsideCorrect($insideCounts),'white_window_protects'=>legacyMaskOutsideCorrect($outsideCounts),
        'gray_is_full_protection'=>legacyMaskOutsideCorrect($grayCounts),'gray_matches_white_result'=>legacyMaskHash($gray)===legacyMaskHash($outside),
        'six_failures_caught'=>array_column($errors,'class')===['ImagickException','ImagickException','ImagickException','ImagickException','ImagickException','TypeError'],
        'original_preserved'=>$sourceKept,'deprecations_saved'=>legacyMaskWarningsValid($warnings)]]);
echo "legacy-clip-mask-workflow.png\nworkflow-inside8.png\nworkflow-outside8.png\nworkflow-gray8.png\nworkflow-returned8.png\nworkflow-modified-copy8.png\nworkflow-source8.png\nworkflow-gray-mask8.png\nmetrics.json\nsetter-copy=1 getter-copy=1 errors=6 source-unchanged=1 warnings=saved\n";

Сравнены чёрное окно, белое окно и gray50. Серый участок защищает полностью, как белый: это не мягкая альфа-маска. Изменение исходного объекта маски и полученной getter-копии не меняет уже прикреплённую маску. Шесть ошибок пойманы, оригинал сохранён. Архив содержит example.php, source.png.b64 и clip-mask-fixture.php. Сохраните рядом и выполните php example.php с IM6-совместимой Imagick и поддержкой PNG. Проверенная среда: PHP 8.3.6 / Imagick 3.7.0 / ImageMagick 6.9.12-98 Q16, Ubuntu 24.04. Это устаревшие IM6-only методы; выполнение на связанной с IM7 Windows-сборке здесь не заявлено. Helper восстанавливает собственный рисунок, создаёт явно показанную растровую маску, сохраняет PNG8 и измерения. Изучаемые set/get остаются видны в основной программе. legacyMaskCall перехватывает только предупреждения этих двух deprecated-методов в пределах вызова, сохраняет точные сообщения и восстанавливает прежний обработчик через finally.

Ожидаемый вывод в проверенной IM6-сборке
legacy-clip-mask-workflow.png
workflow-inside8.png
workflow-outside8.png
workflow-gray8.png
workflow-returned8.png
workflow-modified-copy8.png
workflow-source8.png
workflow-gray-mask8.png
metrics.json
setter-copy=1 getter-copy=1 errors=6 source-unchanged=1 warnings=saved
Источники и обсуждения

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

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

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

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