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

Дерево руководства
Глава 383 · После объектов, клонирования и исключений; совместимость с IM6
Imagick: устаревшая растровая clip-mask в IM6, защита записи и копии
Понять работающий старый обработчик: ограничить изменение прямоугольным окном, получить отдельную маску и проверить реальные пиксели и ошибки.
Увидеть защищённую область и настоящий локальный результат
В старом редакторе или обработчике изображений на ImageMagick 6 нужно изменить выбранное прямоугольное окно и защитить всё снаружи. Для этого можно встретить legacy clip-mask: отдельное растровое изображение того же размера управляет последующей записью пикселей. Начнём с настоящего результата на собственном рисунке.

Это прямоугольное окно, а не распознавание кружки. Цвет тела в пределах окна меняется, белый фон внутри становится чёрным, ручка за границей остаётся прежней. Маска имеет 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
Различать рабочее изображение, сохранённую маску и отдельные копии

| Сущность | Как она участвует |
|---|---|
| $base | Чистый исходник. Из него создаются независимые рабочие копии. |
| $mask | Подготовленная растровая маска. Setter копирует её, а не подписывается на будущие изменения этой переменной. |
| $image | Рабочее цветное изображение с прикреплённой маской. Его пиксели меняет следующая операция. |
| $read / $copy | Новый объект из getter. Его изменение не меняет уже прикреплённую маску. |
| $attached | Повторное чтение прикреплённой маски после изменения входа и getter-копии; в workflow она осталась прежней. |
Удобная модель — трафарет защиты записи. Для этого legacy механизма на нашем непрозрачном RGB-исходнике белое защищает старый пиксель, чёрное пропускает новую запись. Это не правило любой маски во всех библиотеках. Альфа-маска, которая отвечает за видимость слоя, может интерпретировать белый участок совсем иначе. Здесь маска не является цветной заливкой результата: она определяет, какие изменения сохранятся после обработки.
Серый не означает «изменить наполовину». В точном IM6 cache проверяется ненулевая интенсивность, после чего прежние компоненты восстанавливаются; величина серого не используется как коэффициент плавного смешивания. Реальный контроль gray50 ниже полностью защищает окно, как белый. Поэтому простое размытие этой clip-mask не обещает мягкую границу. Для такой задачи нужен отдельно объяснённый слой с альфа-каналом и композиция.
Clip-mask отличается и от встроенного 8BIM-контура: там путь сначала читается из метаданных, здесь передаётся уже готовый растр. Она также не равна crop и не ищет границы объекта по содержимому. Проверяем конкретный механизм на конкретной версии, не переносим автоматически результат IM6 на IM7.
Запустить короткий setter и отдельно прочитать существующую маску

Каждый архив самостоятельный. 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
Проверить независимость копий, ограничение серой маски и ошибки

В старом сервисе важно не испортить исходник и не принять случайное изменение вспомогательного объекта за изменение установленной маски. Сначала прикрепим её, изменим исходный объект $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. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.


