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

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

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

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

Глава 320 · От одного кадра до проверенной анимации

Imagick: кадры, последовательности, слои и анимация

Полный официальный блок из 44 методов: курсор, время GIF, сборка кадров, coalesce/optimize, слои, montage, сравнение и граница X server.

Сначала задача: обработать несколько кадров и не перепутать их состояние

Один объект Imagick может содержать не одну картинку, а последовательность: кадры GIF, страницы TIFF/PDF или вручную добавленные изображения. Большинство методов работают с текущим кадром, поэтому сначала нужно понять положение курсора, page geometry и временные свойства.

Безопасный маршрут анимации
  1. ограничить формат, размеры и число кадров до тяжёлой обработки
  2. прочитать number/index/scene/delay/ticks/dispose и назвать единицы
  3. для delta-GIF получить полные кадры через coalesceImages
  4. изменить каждый полный кадр, вернуть курсор в начало и проверить порядок
  5. оптимизировать публикационную копию, записать во временный файл и открыть независимым viewer

Перед этой главой: установка, первый файл и resource policy, циклы, проверка и атомарная публикация файлов.

Наглядная модель: четыре полных кадра и один GIF-контейнер

Анимация из четырёх цветных кадров со стрелкой движения
Это проверенная иллюстрация структуры результата, созданная локальным ImageMagick CLI. Она не считается доказательством выполнения PHP Imagick; PHP-пример будет подтверждён отдельно, когда расширение доступно.
УровеньЧто хранитсяЧто проверять
Контейнерformat, число кадров, iterationsGIF/WebP/TIFF поддерживает нужную последовательность
Кадрpixels, page geometry, sceneразмеры, offset и порядок
Времяdelay и ticks per seconddelay / ticks_per_second в секундах
Переходdispose и delta-areaнет шлейфа, мерцания или случайно очищенного фона

Курсор и кадры: какой кадр сейчас выбран

Imagick с GIF, TIFF или PDF похож на стопку карточек. Курсор указывает на одну карточку; next/previous двигают курсор, getIteratorIndex читает позицию, а getNumberImages считает всю стопку.

Граница модели. Аналогия со стопкой не описывает pixel cache и page geometry: кадр может хранить только изменившуюся область, поэтому перед независимой обработкой GIF часто нужен coalesceImages().

Пройти все кадры без пропуска первогоПример для указанного окружения
<?php
declare(strict_types=1);

$sequence = new Imagick();
foreach (['#123b5d', '#1f8a70', '#f2b544'] as $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $sequence->addImage($frame);
    $frame->clear();
}
$sequence->setFirstIterator();
$seen = [];
do {
    $seen[] = $sequence->getIteratorIndex();
} while ($sequence->nextImage());
echo json_encode($seen, JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Проверяемая форма результата: [0,1,2]. Runtime в этой редакции не заявлен. Здесь выполнена только проверка синтаксиса; наличие Imagick и визуальный артефакт проверяются отдельным runtime-прогоном.

Официальные методы этого блока: current, getImage, getImageIndex, getIteratorIndex, getNumberImages, hasNextImage, hasPreviousImage, nextImage, previousImage, setFirstIterator, setImageIndex, setIteratorIndex, setLastIterator, valid. Ниже у каждого сохранены сигнатура, параметры, возврат, ошибки, версии и два отдельных сценария.

Время и повтор анимации: delay, ticks, dispose, iterations

delay измеряется в ticks, а ticks per second задаёт шкалу. В типичном GIF 20 ticks при 100 ticks/s означают 0,2 секунды. dispose говорит, что сделать с холстом перед следующим кадром.

Граница модели. Браузер или просмотрщик может округлять слишком короткие задержки. Проверяют не только числа metadata, но и реальное воспроизведение итогового GIF.

Задать 0,2 секунды, прочитать реальные значения и записать GIFПример для указанного окружения
<?php
declare(strict_types=1);

$sequence = new Imagick();
foreach (['#ef476f', '#06d6a0'] as $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'gif');
    if (!$frame->setImageTicksPerSecond(100) || !$frame->setImageDelay(20)) { throw new RuntimeException('Время кадра не задано'); }
    if (!$frame->setImageDispose(Imagick::DISPOSE_BACKGROUND)) { throw new RuntimeException('Dispose не задан'); }
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
if (!$sequence->setImageIterations(0)) { throw new RuntimeException('Iterations не заданы'); }
$iterations = $sequence->getImageIterations();
$timings = [];
foreach ($sequence as $frame) {
    $delay = $frame->getImageDelay(); $ticks = $frame->getImageTicksPerSecond();
    if ($delay !== 20 || $ticks !== 100) { throw new RuntimeException('Неверная длительность кадра'); }
    $timings[] = ['delay_ticks' => $delay, 'ticks_per_second' => $ticks, 'seconds' => $delay / $ticks];
}
if ($iterations !== 0) { throw new RuntimeException('Ожидался бесконечный повтор'); }
$out = __DIR__ . '/out/timed-status.gif';
if (!is_dir(dirname($out)) && !mkdir(dirname($out), 0775, true) && !is_dir(dirname($out))) { throw new RuntimeException('Нет каталога'); }
$sequence->setFirstIterator();
if (!$sequence->writeImages($out, true)) { throw new RuntimeException('GIF не записан'); }
echo json_encode(['timings' => $timings, 'iterations' => $iterations, 'file' => basename($out)], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

JSON показывает прочитанные значения каждого кадра и вычисленные 0,2 секунды, рядом создаётся timed-status.gif. Runtime PHP Imagick пока не подтверждён. Здесь выполнена только проверка синтаксиса; наличие Imagick и визуальный артефакт проверяются отдельным runtime-прогоном.

Официальные методы этого блока: getImageDelay, getImageDispose, getImageIterations, getImageScene, getImageTicksPerSecond, setImageDelay, setImageDispose, setImageIterations, setImageScene, setImageTicksPerSecond. Ниже у каждого сохранены сигнатура, параметры, возврат, ошибки, версии и два отдельных сценария.

Собрать и изменить последовательность

addImage добавляет кадр, setImage заменяет текущий, removeImage удаляет текущий. Возвращённый Imagick может быть новым объектом; его нельзя молча заменить исходным в рассуждении.

Граница модели. Размер, colorspace, alpha и page geometry кадров согласуют заранее. Иначе запись формально пройдёт, а визуальный результат будет сдвинут или обрезан.

Собрать три статусных кадра с одинаковой геометриейПример для указанного окружения
<?php
declare(strict_types=1);

$sequence = new Imagick();
foreach (['queued' => '#6c757d', 'processing' => '#0d6efd', 'done' => '#198754'] as $state => $color) {
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($color), 'png');
    $frame->setImageProperty('aen:state', $state);
    if (!$sequence->addImage($frame)) throw new RuntimeException('Кадр не добавлен');
    $frame->clear();
}
echo $sequence->getNumberImages(), " frames\n";
$sequence->clear();

Проверяемый результат — ровно три кадра и сохранённый порядок queued → processing → done. Здесь выполнена только проверка синтаксиса; наличие Imagick и визуальный артефакт проверяются отдельным runtime-прогоном.

Официальные методы этого блока: addImage, removeImage, setImage. Ниже у каждого сохранены сигнатура, параметры, возврат, ошибки, версии и два отдельных сценария.

Полный цикл GIF: coalesce → изменение → optimize

Оптимизированный GIF хранит различия между кадрами. coalesce строит полные кадры, после редактирования optimizeImageLayers снова ищет различия и уменьшает контейнер.

Граница модели. Coalesce резко увеличивает память: после него каждый кадр может занимать полный холст. До decode ограничивают ширину, высоту и число кадров.

Изменить полный GIF и снова оптимизироватьПример для указанного окружения
<?php
declare(strict_types=1);

$seed = new Imagick();
foreach (['#123b5d', '#1f8a70', '#f2b544'] as $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'gif');
    $frame->setImageDelay(12);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    $seed->addImage($frame);
    $frame->clear();
}
$seed->setImageIterations(0);
$seed->optimizeImageLayers();
$seed->setFormat('gif');
$source = new Imagick();
$source->readImageBlob($seed->getImagesBlob(), 'status.gif');
if ($source->getNumberImages() > 120) throw new RuntimeException('Слишком много кадров');
$work = $source->coalesceImages();
foreach ($work as $frame) {
    $frame->setImageFormat('gif');
    $frame->setImageDelay(12);
}
$work->setFirstIterator();
if (!$work->optimizeImageLayers()) throw new RuntimeException('Оптимизация не выполнена');
$out = __DIR__ . '/out/status-optimized.gif';
if (!is_dir(dirname($out)) && !mkdir(dirname($out), 0775, true)) throw new RuntimeException('Нет каталога');
if (!$work->writeImages($out, true)) throw new RuntimeException('GIF не записан');
echo json_encode(['file' => basename($out), 'frames' => $work->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$work->clear();
$source->clear();
$seed->clear();

После совместимого runtime должен появиться status-optimized.gif; исходная delta-последовательность создаётся внутри примера и не зависит от внешнего fixture. Здесь выполнена только проверка синтаксиса; наличие Imagick и визуальный артефакт проверяются отдельным runtime-прогоном.

Официальные методы этого блока: coalesceImages, deconstructImages, morphImages, optimizeImageLayers. Ниже у каждого сохранены сигнатура, параметры, возврат, ошибки, версии и два отдельных сценария.

Слои, ленты и montage: несколько изображений в один результат

appendImages и smushImages делают горизонтальную или вертикальную ленту; mergeImageLayers учитывает page geometry; montageImage строит сетку миниатюр.

Граница модели. flattenImages и mosaicImages устарели. Для нового кода выбирают явный mergeImageLayers и фиксируют порядок слоёв.

Собрать контактный лист из четырёх превьюПример для указанного окружения
<?php
declare(strict_types=1);

$images = new Imagick();
foreach (['#123b5d', '#1f8a70', '#f2b544', '#ef476f'] as $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $images->addImage($frame);
    $frame->clear();
}
$draw = new ImagickDraw();
$sheet = $images->montageImage($draw, '2x2+8+8', '160x90+0+0', Imagick::MONTAGEMODE_FRAME, '0');
$out = __DIR__ . '/out/contact-sheet.png';
if (!is_dir(dirname($out)) && !mkdir(dirname($out), 0775, true)) throw new RuntimeException('Нет каталога');
$sheet->setImageFormat('png');
if (!$sheet->writeImage($out)) throw new RuntimeException('Лист не записан');
echo basename($out), PHP_EOL;
$sheet->clear();
$images->clear();

После runtime ожидается одна PNG-сетка 2×2, а не четыре несвязанных файла. Здесь выполнена только проверка синтаксиса; наличие Imagick и визуальный артефакт проверяются отдельным runtime-прогоном.

Официальные методы этого блока: appendImages, combineImages, flattenImages, mergeImageLayers, montageImage, mosaicImages, smushImages. Ниже у каждого сохранены сигнатура, параметры, возврат, ошибки, версии и два отдельных сценария.

Сравнение кадров и слоёв: метрика плюс изображение различий

compareImages возвращает не только число, но и изображение различий. Метрика имеет смысл вместе с её названием, согласованными размерами и цветовым пространством.

Граница модели. Нельзя переносить один числовой порог между MAE, RMSE, PSNR и perceptual metric. Сначала калибруют порог на своей выборке.

Получить число и PNG-карту различийПример для указанного окружения
<?php
declare(strict_types=1);

$actual = new Imagick();
$actual->newImage(160, 90, new ImagickPixel('#123b5d'), 'png');
$expected = new Imagick();
$expected->newImage(160, 90, new ImagickPixel('#133b5d'), 'png');
[$diff, $metric] = $actual->compareImages($expected, Imagick::METRIC_ROOTMEANSQUAREDERROR);
$out = __DIR__ . '/out/diff.png';
if (!is_dir(dirname($out)) && !mkdir(dirname($out), 0775, true)) throw new RuntimeException('Нет каталога');
$diff->setImageFormat('png');
if (!$diff->writeImage($out)) throw new RuntimeException('Карта не записана');
echo json_encode(['metric' => $metric, 'file' => basename($out)], JSON_THROW_ON_ERROR), PHP_EOL;
$diff->clear();
$expected->clear();
$actual->clear();

Результат содержит metric и реальный diff.png; допустимый порог выбирают по тестовой выборке. Здесь выполнена только проверка синтаксиса; наличие Imagick и визуальный артефакт проверяются отдельным runtime-прогоном.

Официальные методы этого блока: compareImageChannels, compareImageLayers, compareImages. Ниже у каждого сохранены сигнатура, параметры, возврат, ошибки, версии и два отдельных сценария.

X server и интерактивный показ: отдельная эксплуатационная ветка

displayImage/displayImages/animateImages отправляют изображение X server, а не HTTP-клиенту. На обычном PHP-сайте посетитель ничего от этого вызова не увидит.

Граница модели. В web-worker сохраняют файл или возвращают bytes. X server не открывают из пользовательского ввода и не считают production-маршрутом выдачи изображения.

Не путать X server с выдачей изображения сайтомПример для указанного окружения
<?php
declare(strict_types=1);

$image = new Imagick();
$image->newImage(160, 90, new ImagickPixel('#123b5d'), 'png');
$display = getenv('DISPLAY') ?: '';
if ($display === '') {
    $out = __DIR__ . '/out/preview.png';
    if (!is_dir(dirname($out)) && !mkdir(dirname($out), 0775, true)) throw new RuntimeException('Нет каталога');
    $image->writeImage($out);
    echo "HTTP/download route: preview.png\n";
} else {
    $image->displayImage($display);
    echo "Shown on X server\n";
}
$image->clear();

На сервере без DISPLAY выбирается файл для HTTP/download, а не несуществующее окно. Здесь выполнена только проверка синтаксиса; наличие Imagick и визуальный артефакт проверяются отдельным runtime-прогоном.

Официальные методы этого блока: animateImages, displayImage, displayImages. Ниже у каждого сохранены сигнатура, параметры, возврат, ошибки, версии и два отдельных сценария.

Перед production: лимиты, очистка и доказательство результата

До decodeВо время обработкиПеред публикацией
allowlist форматов; width × height; frames; resource policytry/finally; clear временных объектов; не держать coalesced-мастер дольше нужноговременный файл; MIME по содержимому; число кадров; независимый decode
не принимать URL/glob от клиентане путать cursor index со scene; вернуть курсор в началопроиграть анимацию, проверить delay/dispose и атомарно переместить

Нативный runtime этой ветки пока недоступен. Поэтому lint подтверждает только синтаксис, CLI-превью — только визуальную модель, а expected остаётся null. После появления расширения каждый артефакт получит фактические размеры, число кадров и SHA-256.

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

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

Imagick::addImageДобавить созданный кадр в gif, tiff или pdf-последовательность.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::addImage(Imagick $source): bool

Зачем. Добавить созданный кадр в gif, tiff или pdf-последовательность.

Сигнатура. Imagick::addImage(Imagick $source): bool. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
$sourceImagickОтдельный объект Imagick, кадр которого добавляется в последовательность.
Формулировка PHP Manual

The source Imagick object

Возврат. bool. Returns true on success.

Что может пойти не так. Кадр другого размера или page geometry сдвинет композицию; source остаётся отдельным объектом. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Readimages для заранее известных файлов или явный цикл addimage для пофайловой диагностики.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: добавить созданный кадр в GIF, TIFF или PDF-последовательностьПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$extra = new Imagick();
$extra->newImage(160, 90, new ImagickPixel('#ef476f'), 'png');
$result = $sequence->addImage($extra);
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();
$extra->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$extra = new Imagick();
$extra->newImage(160, 90, new ImagickPixel('#ef476f'), 'png');
$result = $sequence->addImage($extra);
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();
$extra->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Adds new image to Imagick object image list

Description: Adds new image to Imagick object from the current position of the source object. After the operation iterator position is moved at the end of the list.

Return: Returns true on success.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::animateImagesПроиграть последовательность в доступном x server при локальной диагностике.

доступно: PECL imagick 2 >= 2.3.0, PECL imagick 3 · imagick

Imagick::animateImages(string $x_server): bool

Зачем. Проиграть последовательность в доступном x server при локальной диагностике.

Сигнатура. Imagick::animateImages(string $x_server): bool. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
$x_serverstringАдрес X server. На обычном web-сервере этот канал обычно отсутствует и не нужен.
Формулировка PHP Manual

X server address

Возврат. bool. Returns true on success.

Что может пойти не так. Без display/x server вызов бесполезен или завершится исключением; это не отправка в браузер. Официальная запись ошибок: не уточнена.

Когда выбрать другое. Writeimages в gif/webp и обычная http-выдача файла.

Версии. доступно: PECL imagick 2 >= 2.3.0, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: проиграть последовательность в доступном X server при локальной диагностикеПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$xServer = getenv('DISPLAY') ?: '';
if ($xServer === '') {
    echo "X server отсутствует; используйте запись файла\n";
    $sequence->clear();
    exit(0);
}
$result = $sequence->animateImages($xServer);
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$xServer = getenv('DISPLAY') ?: '';
if ($xServer === '') {
    echo "X server отсутствует; используйте запись файла\n";
    $sequence->clear();
    exit(0);
}
$result = $sequence->animateImages($xServer);
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Animates an image or images

Description: This method animates the image onto a local or remote X server. This method is not available on Windows. [imagick.method.available.0x636]

Return: Returns true on success.

Errors: —

Changelog: —

Связанные методы. Imagick::displayImage.

Imagick::appendImagesСклеить страницы или фотографии в одну вертикальную либо горизонтальную ленту.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::appendImages(bool $stack): Imagick

Зачем. Склеить страницы или фотографии в одну вертикальную либо горизонтальную ленту.

Сигнатура. Imagick::appendImages(bool $stack): Imagick. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
$stackbooltrue строит вертикальную ленту, false — горизонтальную.
Формулировка PHP Manual

Whether to stack the images vertically. By default (or if false is specified) images are stacked left-to-right. If stack is true, images are stacked top-to-bottom.

Возврат. Imagick. Returns Imagick instance on success.

Что может пойти не так. Полный результат может быть шире/выше допустимого и потребовать большой непрерывный буфер. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Smushimages для отступа или montageimage для сетки.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: склеить страницы или фотографии в одну вертикальную либо горизонтальную лентуПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->appendImages(true);
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/appendimages-minimal.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->appendImages(false);
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/appendimages-service.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Append a set of images

Description: Append a set of images into one larger image.

Return: Returns Imagick instance on success.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::coalesceImagesРазвернуть оптимизированный gif в полные кадры перед редактированием.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::coalesceImages(): Imagick

Зачем. Развернуть оптимизированный gif в полные кадры перед редактированием.

Сигнатура. Imagick::coalesceImages(): Imagick. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
—нет параметровМетод читает или меняет текущее состояние последовательности.

Возврат. Imagick. Returns a new Imagick object on success.

Что может пойти не так. Память растёт примерно до полного холста на каждый кадр. Официальная запись ошибок: [imagick.imagick.throws].

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

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: развернуть оптимизированный GIF в полные кадры перед редактированиемПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->coalesceImages();
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/coalesceimages-minimal.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->coalesceImages();
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/coalesceimages-service.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Composites a set of images

Description: Composites a set of images while respecting any page offsets and disposal methods. GIF, MIFF, and MNG animation sequences typically start with an image background and each subsequent image varies in size and offset. Returns a new Imagick object where each image in the sequence is the same size as the first and composited with the next image in the sequence.

Return: Returns a new Imagick object on success.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::combineImagesСобрать отдельные серые каналы в одно многоканальное изображение.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::combineImages(int $channelType): Imagick

Зачем. Собрать отдельные серые каналы в одно многоканальное изображение.

Сигнатура. Imagick::combineImages(int $channelType): Imagick. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
$channelTypeintКонстанта или маска CHANNEL_*; она определяет каналы операции.
Формулировка PHP Manual

Provide any channel constant that is valid for your channel mode. To apply to more than one channel, combine channeltype constants using bitwise operators. Refer to this list of channel constants .

Возврат. Imagick. Returns true on success.

Что может пойти не так. Неверный порядок и channeltype дают неправильные цвета. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Compositeimage для обычного наложения готовых цветных слоёв.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: собрать отдельные серые каналы в одно многоканальное изображениеПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$sequence->clear();
foreach ([0.15, 0.45, 0.8] as $intensity) {
    $channel = new Imagick();
    $channel->newImage(160, 90, new ImagickPixel(sprintf('gray(%g%%)', 100 * $intensity)), 'png');
    $channel->setImageColorspace(Imagick::COLORSPACE_GRAY);
    $sequence->addImage($channel);
    $channel->clear();
}
$sequence->setFirstIterator();
$result = $sequence->combineImages(Imagick::CHANNEL_RGB);
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/combineimages-minimal.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$sequence->clear();
foreach ([0.15, 0.45, 0.8] as $intensity) {
    $channel = new Imagick();
    $channel->newImage(160, 90, new ImagickPixel(sprintf('gray(%g%%)', 100 * $intensity)), 'png');
    $channel->setImageColorspace(Imagick::COLORSPACE_GRAY);
    $sequence->addImage($channel);
    $channel->clear();
}
$sequence->setFirstIterator();
$result = $sequence->combineImages(Imagick::CHANNEL_RGB);
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/combineimages-service.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Combines one or more images into a single image

Description: Combines one or more images into a single image. The grayscale value of the pixels of each image in the sequence is assigned in order to the specified channels of the combined image. The typical ordering would be image 1 =[gt] Red, 2 =[gt] Green, 3 =[gt] Blue, etc.

Return: Returns true on success.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::compareImageChannelsИзмерить различие только выбранных каналов.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::compareImageChannels(Imagick $image, int $channelType, int $metricType): array

Зачем. Измерить различие только выбранных каналов.

Сигнатура. Imagick::compareImageChannels(Imagick $image, int $channelType, int $metricType): array. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
$imageImagickЭталонный объект Imagick для сравнения.
Формулировка PHP Manual

Imagick object containing the image to compare.

$channelTypeintКонстанта или маска CHANNEL_*; она определяет каналы операции.
Формулировка PHP Manual

Provide any channel constant that is valid for your channel mode. To apply to more than one channel, combine channeltype constants using bitwise operators. Refer to this list of channel constants .

$metricTypeintЗначение по точной официальной сигнатуре этого метода.
Формулировка PHP Manual

One of the metric type constants .

Возврат. array. Array consisting of new_wand and distortion .

Что может пойти не так. Несогласованные размеры/colorspace и неверная маска каналов делают метрику бессмысленной. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Compareimages для всех каналов или getimagedistortion для одного числа.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: измерить различие только выбранных каналовПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$reference = new Imagick();
$reference->newImage(160, 90, new ImagickPixel('#123b5d'), 'png');
$reference->setImageColorspace(Imagick::COLORSPACE_SRGB);
$sequence->setImageColorspace(Imagick::COLORSPACE_SRGB);
$result = $sequence->compareImageChannels($reference, Imagick::CHANNEL_ALL, Imagick::METRIC_ROOTMEANSQUAREDERROR);
if (!is_array($result) || !isset($result[0], $result[1]) || !$result[0] instanceof Imagick) { throw new RuntimeException('Неожиданный ответ сравнения'); }
$diffPath = $outDir . '/compareimagechannels-diff-minimal.png';
$result[0]->setImageFormat('png');
if (!$result[0]->writeImage($diffPath)) { throw new RuntimeException('Карта различий не записана'); }
echo json_encode(['metric' => (float) $result[1], 'diff' => basename($diffPath)], JSON_THROW_ON_ERROR), PHP_EOL;
$result[0]->clear();
$sequence->clear();
$reference->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$reference = new Imagick();
$reference->newImage(240, 135, new ImagickPixel('#123b5d'), 'png');
$reference->setImageColorspace(Imagick::COLORSPACE_SRGB);
$sequence->setImageColorspace(Imagick::COLORSPACE_SRGB);
$result = $sequence->compareImageChannels($reference, Imagick::CHANNEL_ALL, Imagick::METRIC_ROOTMEANSQUAREDERROR);
if (!is_array($result) || !isset($result[0], $result[1]) || !$result[0] instanceof Imagick) { throw new RuntimeException('Неожиданный ответ сравнения'); }
$diffPath = $outDir . '/compareimagechannels-diff-service.png';
$result[0]->setImageFormat('png');
if (!$result[0]->writeImage($diffPath)) { throw new RuntimeException('Карта различий не записана'); }
echo json_encode(['metric' => (float) $result[1], 'diff' => basename($diffPath)], JSON_THROW_ON_ERROR), PHP_EOL;
$result[0]->clear();
$sequence->clear();
$reference->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Returns the difference in one or more images

Description: Compares one or more images and returns the difference image.

Return: Array consisting of new_wand and distortion .

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::compareImageLayersПолучить слои различий между соседними кадрами последовательности.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::compareImageLayers(int $method): Imagick

Зачем. Получить слои различий между соседними кадрами последовательности.

Сигнатура. Imagick::compareImageLayers(int $method): Imagick. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
$methodintИменованная константа LAYERMETHOD_* для сравнения слоёв.
Формулировка PHP Manual

One of the layer method constants .

Возврат. Imagick. Returns true on success.

Что может пойти не так. Метод ожидает осмысленную последовательность и корректную layer method. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Compareimages для пары явно выбранных кадров.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: получить слои различий между соседними кадрами последовательностиПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$sequence->setFirstIterator();
$layerIndex = 0;
foreach ($sequence as $layer) {
    $layer->setImagePage($layer->getImageWidth() + 24, $layer->getImageHeight() + 16, $layerIndex * 8, $layerIndex * 4);
    $layerIndex++;
}
$sequence->setFirstIterator();
$result = $sequence->compareImageLayers(Imagick::LAYERMETHOD_COMPAREANY);
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/compareimagelayers-minimal.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$sequence->setFirstIterator();
$layerIndex = 0;
foreach ($sequence as $layer) {
    $layer->setImagePage($layer->getImageWidth() + 24, $layer->getImageHeight() + 16, $layerIndex * 8, $layerIndex * 4);
    $layerIndex++;
}
$sequence->setFirstIterator();
$result = $sequence->compareImageLayers(Imagick::LAYERMETHOD_COMPARECLEAR);
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/compareimagelayers-service.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Returns the maximum bounding region between images

Description: Compares each image with the next in a sequence and returns the maximum bounding region of any pixel differences it discovers. [imagick.method.available.0x629]

Return: Returns true on success.

Errors: [imagick.imagick.throws]

Changelog: —

Связанные методы. Imagick::optimizeImageLayers, Imagick::writeImages, Imagick::writeImage.

Imagick::compareImagesСравнить результат рендера с эталоном и сохранить карту различий.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::compareImages(Imagick $compare, int $metric): array

Зачем. Сравнить результат рендера с эталоном и сохранить карту различий.

Сигнатура. Imagick::compareImages(Imagick $compare, int $metric): array. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
$compareImagickЭталонный объект Imagick, согласованный по размеру и colorspace.
Формулировка PHP Manual

An image to compare to.

$metricintИменованная константа METRIC_* и откалиброванный порог.
Формулировка PHP Manual

Provide a valid metric type constant. Refer to this list of metric constants .

Возврат. array. Returns an array containing a reconstructed image and the difference between images.

Что может пойти не так. Порог нельзя выбирать без названия metric и калибровочной выборки. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Getimagedistortion, если отдельная карта различий не нужна.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: сравнить результат рендера с эталоном и сохранить карту различийПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$reference = new Imagick();
$reference->newImage(160, 90, new ImagickPixel('#123b5d'), 'png');
$reference->setImageColorspace(Imagick::COLORSPACE_SRGB);
$sequence->setImageColorspace(Imagick::COLORSPACE_SRGB);
$result = $sequence->compareImages($reference, Imagick::METRIC_ROOTMEANSQUAREDERROR);
if (!is_array($result) || !isset($result[0], $result[1]) || !$result[0] instanceof Imagick) { throw new RuntimeException('Неожиданный ответ сравнения'); }
$diffPath = $outDir . '/compareimages-diff-minimal.png';
$result[0]->setImageFormat('png');
if (!$result[0]->writeImage($diffPath)) { throw new RuntimeException('Карта различий не записана'); }
echo json_encode(['metric' => (float) $result[1], 'diff' => basename($diffPath)], JSON_THROW_ON_ERROR), PHP_EOL;
$result[0]->clear();
$sequence->clear();
$reference->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$reference = new Imagick();
$reference->newImage(240, 135, new ImagickPixel('#123b5d'), 'png');
$reference->setImageColorspace(Imagick::COLORSPACE_SRGB);
$sequence->setImageColorspace(Imagick::COLORSPACE_SRGB);
$result = $sequence->compareImages($reference, Imagick::METRIC_ABSOLUTEERRORMETRIC);
if (!is_array($result) || !isset($result[0], $result[1]) || !$result[0] instanceof Imagick) { throw new RuntimeException('Неожиданный ответ сравнения'); }
$diffPath = $outDir . '/compareimages-diff-service.png';
$result[0]->setImageFormat('png');
if (!$result[0]->writeImage($diffPath)) { throw new RuntimeException('Карта различий не записана'); }
echo json_encode(['metric' => (float) $result[1], 'diff' => basename($diffPath)], JSON_THROW_ON_ERROR), PHP_EOL;
$result[0]->clear();
$sequence->clear();
$reference->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Compares an image to a reconstructed image

Description: Returns an array containing a reconstructed image and the difference between images.

Return: Returns an array containing a reconstructed image and the difference between images.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::currentПолучить объект текущего кадра во время обхода.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::current(): Imagick

Зачем. Получить объект текущего кадра во время обхода.

Сигнатура. Imagick::current(): Imagick. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
—нет параметровМетод читает или меняет текущее состояние последовательности.

Возврат. Imagick. Returns self on success.

Что может пойти не так. Курсор мог остаться после предыдущей операции, поэтому current не гарантирует первый кадр. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Setfirstiterator перед обходом и getimage для отдельной копии текущего кадра.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: получить объект текущего кадра во время обходаПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->current();
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/current-minimal.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->current();
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/current-service.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Returns a reference to the current Imagick object

Description: Returns reference to the current imagick object with image pointer at the correct sequence.

Return: Returns self on success.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::deconstructImagesНайти минимальные различия между полными кадрами после обработки.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::deconstructImages(): Imagick

Зачем. Найти минимальные различия между полными кадрами после обработки.

Сигнатура. Imagick::deconstructImages(): Imagick. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
—нет параметровМетод читает или меняет текущее состояние последовательности.

Возврат. Imagick. Returns a new Imagick object on success.

Что может пойти не так. На несогласованной геометрии оптимизация создаст неожиданные области. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Optimizeimagelayers как более прямой маршрут оптимизации gif.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: найти минимальные различия между полными кадрами после обработкиПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->deconstructImages();
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/deconstructimages-minimal.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->deconstructImages();
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/deconstructimages-service.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Returns certain pixel differences between images

Description: Compares each image with the next in a sequence and returns the maximum bounding region of any pixel differences it discovers.

Return: Returns a new Imagick object on success.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::displayImageПоказать текущий кадр на x server в локальном инструменте.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::displayImage(string $servername): bool

Зачем. Показать текущий кадр на x server в локальном инструменте.

Сигнатура. Imagick::displayImage(string $servername): bool. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
$servernamestringЗначение по точной официальной сигнатуре этого метода.
Формулировка PHP Manual

The X server name

Возврат. bool. Returns true on success.

Что может пойти не так. Сервер может быть недоступен, а web-клиент результата не увидит. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Writeimage или getimageblob.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: показать текущий кадр на X server в локальном инструментеПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$xServer = getenv('DISPLAY') ?: '';
if ($xServer === '') {
    echo "X server отсутствует; используйте запись файла\n";
    $sequence->clear();
    exit(0);
}
$result = $sequence->displayImage($xServer);
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$xServer = getenv('DISPLAY') ?: '';
if ($xServer === '') {
    echo "X server отсутствует; используйте запись файла\n";
    $sequence->clear();
    exit(0);
}
$result = $sequence->displayImage($xServer);
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Displays an image

Description: This method displays an image on a X server.

Return: Returns true on success.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::displayImagesПоказать все кадры на x server при ручной диагностике.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::displayImages(string $servername): bool

Зачем. Показать все кадры на x server при ручной диагностике.

Сигнатура. Imagick::displayImages(string $servername): bool. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
$servernamestringЗначение по точной официальной сигнатуре этого метода.
Формулировка PHP Manual

The X server name

Возврат. bool. Returns true on success.

Что может пойти не так. Удалённый x server и большая последовательность создают ненужный риск и задержку. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Writeimages и проверка обычным viewer.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: показать все кадры на X server при ручной диагностикеПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$xServer = getenv('DISPLAY') ?: '';
if ($xServer === '') {
    echo "X server отсутствует; используйте запись файла\n";
    $sequence->clear();
    exit(0);
}
$result = $sequence->displayImages($xServer);
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$xServer = getenv('DISPLAY') ?: '';
if ($xServer === '') {
    echo "X server отсутствует; используйте запись файла\n";
    $sequence->clear();
    exit(0);
}
$result = $sequence->displayImages($xServer);
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Displays an image or image sequence

Description: Displays an image or image sequence on a X server.

Return: Returns true on success.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::flattenImagesОбъединить слои старого проекта в один кадр.

доступно: PECL imagick 2, PECL imagick 3; deprecated: PECL imagick 3.4.4 · imagick

Imagick::flattenImages(): Imagick

Зачем. Объединить слои старого проекта в один кадр.

Сигнатура. Imagick::flattenImages(): Imagick. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
—нет параметровМетод читает или меняет текущее состояние последовательности.

Возврат. Imagick. Returns true on success.

Что может пойти не так. Метод deprecated с pecl imagick 3.4.4 и скрывает выбранный layer method. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Mergeimagelayers(imagick::layermethod_flatten).

Версии. доступно: PECL imagick 2, PECL imagick 3; deprecated: PECL imagick 3.4.4.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: объединить слои старого проекта в один кадрПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$sequence->setFirstIterator();
$layerIndex = 0;
foreach ($sequence as $layer) {
    $layer->setImagePage($layer->getImageWidth() + 24, $layer->getImageHeight() + 16, $layerIndex * 8, $layerIndex * 4);
    $layerIndex++;
}
$sequence->setFirstIterator();
$result = $sequence->flattenImages();
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/flattenimages-minimal.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$sequence->setFirstIterator();
$layerIndex = 0;
foreach ($sequence as $layer) {
    $layer->setImagePage($layer->getImageWidth() + 24, $layer->getImageHeight() + 16, $layerIndex * 8, $layerIndex * 4);
    $layerIndex++;
}
$sequence->setFirstIterator();
$result = $sequence->flattenImages();
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/flattenimages-service.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Merges a sequence of images

Description: Merges a sequence of images. This is useful for combining Photoshop layers into a single image.

Return: Returns true on success.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::getImageПолучить отдельный объект с текущим кадром для независимой записи.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::getImage(): Imagick

Зачем. Получить отдельный объект с текущим кадром для независимой записи.

Сигнатура. Imagick::getImage(): Imagick. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
—нет параметровМетод читает или меняет текущее состояние последовательности.

Возврат. Imagick. Returns a new Imagick object with the current image sequence.

Что может пойти не так. Если курсор выбран неверно, копируется не тот кадр; новый объект нужно clear. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Current для работы с текущим элементом итератора.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: получить отдельный объект с текущим кадром для независимой записиПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->getImage();
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/getimage-minimal.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->getImage();
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/getimage-service.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Returns a new Imagick object

Description: Returns a new Imagick object with the current image sequence.

Return: Returns a new Imagick object with the current image sequence.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::getImageDelayУзнать длительность показа текущего кадра.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::getImageDelay(): int

Зачем. Узнать длительность показа текущего кадра.

Сигнатура. Imagick::getImageDelay(): int. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
—нет параметровМетод читает или меняет текущее состояние последовательности.

Возврат. int. Returns the image delay.

Что может пойти не так. Число без ticks per second нельзя переводить в секунды. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Getimagetickspersecond вместе с delay.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: узнать длительность показа текущего кадраПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->getImageDelay();
echo json_encode(['value' => $result, 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->getImageDelay();
echo json_encode(['value' => $result, 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Gets the image delay

Description: Gets the image delay.

Return: Returns the image delay.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::getImageDisposeПонять, как холст очищается перед следующим gif-кадром.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::getImageDispose(): int

Зачем. Понять, как холст очищается перед следующим gif-кадром.

Сигнатура. Imagick::getImageDispose(): int. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
—нет параметровМетод читает или меняет текущее состояние последовательности.

Возврат. int. Returns the dispose method on success.

Что может пойти не так. Числовую константу легко неверно истолковать без dispose_*. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Coalesceimages для получения уже собранных полных кадров.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: понять, как холст очищается перед следующим GIF-кадромПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->getImageDispose();
echo json_encode(['value' => $result, 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->getImageDispose();
echo json_encode(['value' => $result, 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Gets the image disposal method

Description: Gets the image disposal method.

Return: Returns the dispose method on success.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::getImageIndexПрочитать позицию кадра в старом коде.

доступно: PECL imagick 2, PECL imagick 3; deprecated: PECL imagick 3.4.4 · imagick

Imagick::getImageIndex(): int

Зачем. Прочитать позицию кадра в старом коде.

Сигнатура. Imagick::getImageIndex(): int. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
—нет параметровМетод читает или меняет текущее состояние последовательности.

Возврат. int. Returns an integer containing the index of the image in the stack.

Что может пойти не так. Метод deprecated и не нужен для нового api. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Getiteratorindex.

Версии. доступно: PECL imagick 2, PECL imagick 3; deprecated: PECL imagick 3.4.4.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: прочитать позицию кадра в старом кодеПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->getImageIndex();
echo json_encode(['value' => $result, 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->getImageIndex();
echo json_encode(['value' => $result, 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Gets the index of the current active image

Description: Returns the index of the current active image within the Imagick object. This method has been deprecated. See Imagick::getIteratorIndex .

Return: Returns an integer containing the index of the image in the stack.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::getImageIterationsПрочитать число повторов анимации из текущего кадра.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::getImageIterations(): int

Зачем. Прочитать число повторов анимации из текущего кадра.

Сигнатура. Imagick::getImageIterations(): int. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
—нет параметровМетод читает или меняет текущее состояние последовательности.

Возврат. int. Returns the image iterations as an integer.

Что может пойти не так. 0 часто означает бесконечный цикл, а не отсутствие воспроизведения. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Зафиксировать product-policy и явно setimageiterations.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: прочитать число повторов анимации из текущего кадраПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->getImageIterations();
echo json_encode(['value' => $result, 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->getImageIterations();
echo json_encode(['value' => $result, 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Gets the image iterations

Description: Gets the image iterations.

Return: Returns the image iterations as an integer.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::getImageSceneПрочитать логический номер сцены текущего кадра.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::getImageScene(): int

Зачем. Прочитать логический номер сцены текущего кадра.

Сигнатура. Imagick::getImageScene(): int. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
—нет параметровМетод читает или меняет текущее состояние последовательности.

Возврат. int. Returns the image scene.

Что может пойти не так. Scene metadata не обязана совпадать с iterator index. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Getiteratorindex для фактической позиции в объекте.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: прочитать логический номер сцены текущего кадраПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->getImageScene();
echo json_encode(['value' => $result, 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->getImageScene();
echo json_encode(['value' => $result, 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Gets the image scene

Description: Gets the image scene.

Return: Returns the image scene.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::getImageTicksPerSecondПеревести delay текущего кадра во время.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::getImageTicksPerSecond(): int

Зачем. Перевести delay текущего кадра во время.

Сигнатура. Imagick::getImageTicksPerSecond(): int. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
—нет параметровМетод читает или меняет текущее состояние последовательности.

Возврат. int. Returns the image ticks-per-second.

Что может пойти не так. Нулевое или неожиданное значение требует защитной политики. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Для gif использовать проверенную шкалу 100 ticks/s только после чтения metadata.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: перевести delay текущего кадра во времяПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->getImageTicksPerSecond();
echo json_encode(['value' => $result, 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->getImageTicksPerSecond();
echo json_encode(['value' => $result, 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Gets the image ticks-per-second

Description: Gets the image ticks-per-second.

Return: Returns the image ticks-per-second.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::getIteratorIndexУзнать нулевую позицию курсора в последовательности.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::getIteratorIndex(): int

Зачем. Узнать нулевую позицию курсора в последовательности.

Сигнатура. Imagick::getIteratorIndex(): int. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
—нет параметровМетод читает или меняет текущее состояние последовательности.

Возврат. int. Returns an integer containing the index of the image in the stack.

Что может пойти не так. Индекс меняется после next/previous/set iterator и не является scene metadata. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Getimagescene для scene; хранить собственный счётчик при foreach.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: узнать нулевую позицию курсора в последовательностиПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->getIteratorIndex();
echo json_encode(['value' => $result, 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->getIteratorIndex();
echo json_encode(['value' => $result, 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Gets the index of the current active image

Description: Returns the index of the current active image within the Imagick object. [imagick.method.available.0x629]

Return: Returns an integer containing the index of the image in the stack.

Errors: [imagick.imagick.throws]

Changelog: —

Связанные методы. Imagick::setIteratorIndex, Imagick::getImageIndex, Imagick::setImageIndex.

Imagick::getNumberImagesОграничить число кадров до дорогой обработки.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::getNumberImages(): int

Зачем. Ограничить число кадров до дорогой обработки.

Сигнатура. Imagick::getNumberImages(): int. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
—нет параметровМетод читает или меняет текущее состояние последовательности.

Возврат. int. Returns the number of images associated with Imagick object.

Что может пойти не так. Сам getter не ограничивает уже выполненный decode и pixel cache. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Ping/идентификация контейнера до полной обработки плюс resource policy.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: ограничить число кадров до дорогой обработкиПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->getNumberImages();
echo json_encode(['value' => $result, 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->getNumberImages();
echo json_encode(['value' => $result, 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Returns the number of images in the object

Description: Returns the number of images associated with Imagick object.

Return: Returns the number of images associated with Imagick object.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::hasNextImageПроверить наличие следующего кадра, не двигая курсор.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::hasNextImage(): bool

Зачем. Проверить наличие следующего кадра, не двигая курсор.

Сигнатура. Imagick::hasNextImage(): bool. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
—нет параметровМетод читает или меняет текущее состояние последовательности.

Возврат. bool. Returns true if the object has more images when traversing the list in the forward direction, returns false if there are none.

Что может пойти не так. Проверка и переход — разные действия. Официальная запись ошибок: не уточнена.

Когда выбрать другое. Foreach для простого полного обхода.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: проверить наличие следующего кадра, не двигая курсорПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->hasNextImage();
echo json_encode(['predicate' => $result, 'index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->hasNextImage();
echo json_encode(['predicate' => $result, 'index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Checks if the object has more images

Description: Returns true if the object has more images when traversing the list in the forward direction.

Return: Returns true if the object has more images when traversing the list in the forward direction, returns false if there are none.

Errors: —

Changelog: —

Imagick::hasPreviousImageПроверить возможность шага назад.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::hasPreviousImage(): bool

Зачем. Проверить возможность шага назад.

Сигнатура. Imagick::hasPreviousImage(): bool. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
—нет параметровМетод читает или меняет текущее состояние последовательности.

Возврат. bool. Returns true if the object has more images when traversing the list in the reverse direction, returns false if there are none.

Что может пойти не так. False на первом кадре не означает пустую последовательность. Официальная запись ошибок: не уточнена.

Когда выбрать другое. Getiteratorindex и getnumberimages для явной границы.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: проверить возможность шага назадПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$sequence->setLastIterator();
$result = $sequence->hasPreviousImage();
echo json_encode(['predicate' => $result, 'index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$sequence->setLastIterator();
$result = $sequence->hasPreviousImage();
echo json_encode(['predicate' => $result, 'index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Checks if the object has a previous image

Description: Returns true if the object has more images when traversing the list in the reverse direction

Return: Returns true if the object has more images when traversing the list in the reverse direction, returns false if there are none.

Errors: —

Changelog: —

Imagick::mergeImageLayersСвести слои по выбранному layermethod_* с учётом page geometry.

доступно: PECL imagick 2 >= 2.1.0, PECL imagick 3 · imagick

Imagick::mergeImageLayers(int $layer_method): Imagick

Зачем. Свести слои по выбранному layermethod_* с учётом page geometry.

Сигнатура. Imagick::mergeImageLayers(int $layer_method): Imagick. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
$layer_methodintИменованная константа LAYERMETHOD_* для сведения слоёв.
Формулировка PHP Manual

One of the Imagick::LAYERMETHOD_ * constants

Возврат. Imagick. Returns an Imagick object containing the merged image.

Что может пойти не так. Неверный метод или смещения дают обрезанный холст. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Appendimages для простой ленты без наложения.

Версии. доступно: PECL imagick 2 >= 2.1.0, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: свести слои по выбранному LAYERMETHOD_* с учётом page geometryПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$sequence->setFirstIterator();
$layerIndex = 0;
foreach ($sequence as $layer) {
    $layer->setImagePage($layer->getImageWidth() + 24, $layer->getImageHeight() + 16, $layerIndex * 8, $layerIndex * 4);
    $layerIndex++;
}
$sequence->setFirstIterator();
$result = $sequence->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN);
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/mergeimagelayers-minimal.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$sequence->setFirstIterator();
$layerIndex = 0;
foreach ($sequence as $layer) {
    $layer->setImagePage($layer->getImageWidth() + 24, $layer->getImageHeight() + 16, $layerIndex * 8, $layerIndex * 4);
    $layerIndex++;
}
$sequence->setFirstIterator();
$result = $sequence->mergeImageLayers(Imagick::LAYERMETHOD_MERGE);
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/mergeimagelayers-service.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Merges image layers

Description: Merges image layers into one. This method is useful when working with image formats that use multiple layers such as PSD. The merging is controlled using the layer_method which defines how the layers are merged. [imagick.method.available.0x637]

Return: Returns an Imagick object containing the merged image.

Errors: [imagick.imagick.throws]

Changelog: —

Связанные методы. Imagick::flattenImages.

Imagick::montageImageСобрать контактный лист с несколькими превью.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::montageImage(ImagickDraw $draw, string $tile_geometry, string $thumbnail_geometry, int $mode, string $frame): Imagick

Зачем. Собрать контактный лист с несколькими превью.

Сигнатура. Imagick::montageImage(ImagickDraw $draw, string $tile_geometry, string $thumbnail_geometry, int $mode, string $frame): Imagick. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
$drawImagickDrawНастроенный ImagickDraw для рамки и текста montage.
Формулировка PHP Manual

The font name, size, and color are obtained from this object.

$tile_geometrystringСетка montage, например 2x2+8+8.
Формулировка PHP Manual

The number of tiles per row and page (e.g. 6x4+0+0).

$thumbnail_geometrystringРазмер ячейки/миниатюры с geometry-синтаксисом ImageMagick.
Формулировка PHP Manual

Preferred image size and border size of each thumbnail (e.g. 120x120+4+3).

$modeintКонстанта MONTAGEMODE_*.
Формулировка PHP Manual

Thumbnail framing mode, see Montage Mode constants .

$framestringGeometry рамки montage.
Формулировка PHP Manual

Surround the image with an ornamental border (e.g. 15x15+3+3). The frame color is that of the thumbnail's matte color.

Возврат. Imagick. Creates a composite image and returns it as a new Imagick object.

Что может пойти не так. Tile/thumbnail geometry и рамка могут создать огромный холст. Официальная запись ошибок: не уточнена.

Когда выбрать другое. Ручная сетка на заранее ограниченном холсте.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: собрать контактный лист с несколькими превьюПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$draw = new ImagickDraw();
$draw->setStrokeColor(new ImagickPixel('#d5e2ea'));
$draw->setFillColor(new ImagickPixel('#ffffff'));
$result = $sequence->montageImage($draw, '2x2+8+8', '160x90+0+0', Imagick::MONTAGEMODE_FRAME, '0');
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/montageimage-minimal.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$draw = new ImagickDraw();
$draw->setStrokeColor(new ImagickPixel('#d5e2ea'));
$draw->setFillColor(new ImagickPixel('#ffffff'));
$result = $sequence->montageImage($draw, '2x2+8+8', '160x90+0+0', Imagick::MONTAGEMODE_FRAME, '0');
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/montageimage-service.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Creates a composite image

Description: Creates a composite image by combining several separate images. The images are tiled on the composite image with the name of the image optionally appearing just below the individual tile.

Return: Creates a composite image and returns it as a new Imagick object.

Errors: —

Changelog: —

Imagick::morphImagesСгенерировать промежуточные кадры между ключевыми.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::morphImages(int $number_frames): Imagick

Зачем. Сгенерировать промежуточные кадры между ключевыми.

Сигнатура. Imagick::morphImages(int $number_frames): Imagick. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
$number_framesintЧисло промежуточных кадров между соседними исходными.
Формулировка PHP Manual

The number of in-between images to generate.

Возврат. Imagick. This method returns a new Imagick object on success. [imagick.imagickexception.throw]

Что может пойти не так. Число кадров быстро увеличивает память и размер результата. Официальная запись ошибок: не уточнена.

Когда выбрать другое. Css/video interpolation или меньше ключевых кадров.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: сгенерировать промежуточные кадры между ключевымиПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->morphImages(2);
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/morphimages-minimal.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->morphImages(3);
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/morphimages-service.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Method morphs a set of images

Description: Method morphs a set of images. Both the image pixels and size are linearly interpolated to give the appearance of a meta-morphosis from one image to the next.

Return: This method returns a new Imagick object on success. [imagick.imagickexception.throw]

Errors: —

Changelog: —

Imagick::mosaicImagesСвести слои старого проекта на общий холст.

доступно: PECL imagick 2, PECL imagick 3; deprecated: PECL imagick 3.4.4 · imagick

Imagick::mosaicImages(): Imagick

Зачем. Свести слои старого проекта на общий холст.

Сигнатура. Imagick::mosaicImages(): Imagick. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
—нет параметровМетод читает или меняет текущее состояние последовательности.

Возврат. Imagick. Returns true on success.

Что может пойти не так. Метод deprecated с pecl imagick 3.4.4 и не объясняет выбранную семантику. Официальная запись ошибок: не уточнена.

Когда выбрать другое. Mergeimagelayers(imagick::layermethod_merge).

Версии. доступно: PECL imagick 2, PECL imagick 3; deprecated: PECL imagick 3.4.4.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: свести слои старого проекта на общий холстПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$sequence->setFirstIterator();
$layerIndex = 0;
foreach ($sequence as $layer) {
    $layer->setImagePage($layer->getImageWidth() + 24, $layer->getImageHeight() + 16, $layerIndex * 8, $layerIndex * 4);
    $layerIndex++;
}
$sequence->setFirstIterator();
$result = $sequence->mosaicImages();
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/mosaicimages-minimal.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$sequence->setFirstIterator();
$layerIndex = 0;
foreach ($sequence as $layer) {
    $layer->setImagePage($layer->getImageWidth() + 24, $layer->getImageHeight() + 16, $layerIndex * 8, $layerIndex * 4);
    $layerIndex++;
}
$sequence->setFirstIterator();
$result = $sequence->mosaicImages();
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/mosaicimages-service.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Forms a mosaic from images

Description: Inlays an image sequence to form a single coherent picture. It returns a wand with each image in the sequence composited at the location defined by the page offset of the image.

Return: Returns true on success.

Errors: —

Changelog: —

Imagick::nextImageПерейти к следующему кадру в управляемом цикле.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::nextImage(): bool

Зачем. Перейти к следующему кадру в управляемом цикле.

Сигнатура. Imagick::nextImage(): bool. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
—нет параметровМетод читает или меняет текущее состояние последовательности.

Возврат. bool. Returns true on success.

Что может пойти не так. После последнего кадра возвращается false; бесконтрольный while может пропустить текущий кадр. Официальная запись ошибок: не уточнена.

Когда выбрать другое. Foreach или do/while после setfirstiterator.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: перейти к следующему кадру в управляемом циклеПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->nextImage();
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->nextImage();
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Moves to the next image

Description: Associates the next image in the image list with an Imagick object.

Return: Returns true on success.

Errors: —

Changelog: —

Imagick::optimizeImageLayersУменьшить gif после изменения полных coalesced-кадров.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::optimizeImageLayers(): bool

Зачем. Уменьшить gif после изменения полных coalesced-кадров.

Сигнатура. Imagick::optimizeImageLayers(): bool. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
—нет параметровМетод читает или меняет текущее состояние последовательности.

Возврат. bool. Returns true on success.

Что может пойти не так. Оптимизированные delta-кадры уже нельзя независимо редактировать как полные. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Хранить мастер с полными кадрами и оптимизировать только публикационную копию.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: уменьшить GIF после изменения полных coalesced-кадровПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$sequence->clear();
for ($position = 0; $position < 3; $position++) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel('#123b5d'), 'gif');
    $mark = new ImagickDraw();
    $mark->setFillColor('#f2b544');
    $mark->rectangle(10 + 24 * $position, 30, 27 + 24 * $position, 47);
    $frame->drawImage($mark);
    $frame->setImageDelay(15);
    $frame->setImageDispose(Imagick::DISPOSE_NONE);
    $sequence->addImage($frame);
    $mark->clear(); $frame->clear();
}
$sequence->setFirstIterator();
$beforeFrames = $sequence->coalesceImages();
$sequence->setFirstIterator();
$result = $sequence->optimizeImageLayers();
if ($result !== true) { throw new RuntimeException('Оптимизация отклонена'); }
$rendered = $sequence->coalesceImages();
if ($rendered->getNumberImages() !== $beforeFrames->getNumberImages()) { throw new RuntimeException('Потеряны кадры'); }
$maxError = 0.0;
foreach ($rendered as $index => $frame) {
    $beforeFrames->setIteratorIndex($index);
    $error = $frame->getImageChannelDistortion($beforeFrames, Imagick::CHANNEL_RGB, Imagick::METRIC_ROOTMEANSQUAREDERROR);
    $maxError = max($maxError, $error);
}
if ($maxError > 0.000001) { throw new RuntimeException('Изменилось изображение кадров'); }
$deltaPages = [];
foreach ($sequence as $frame) { $deltaPages[] = ['pixels' => $frame->getImageGeometry(), 'page' => $frame->getImagePage()]; }
$sequence->setFirstIterator();
$path = $outDir . '/moving-marker-optimized.gif';
if (!$sequence->writeImages($path, true)) { throw new RuntimeException('GIF не записан'); }
echo json_encode(['file' => basename($path), 'bytes' => filesize($path), 'delta_frames' => $deltaPages, 'rendered_rgb_max_error' => $maxError], JSON_THROW_ON_ERROR), PHP_EOL;
$rendered->clear(); $beforeFrames->clear();
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$sequence->clear();
for ($position = 0; $position < 4; $position++) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel('#123b5d'), 'gif');
    $mark = new ImagickDraw();
    $mark->setFillColor('#f2b544');
    $mark->rectangle(10 + 24 * $position, 30, 27 + 24 * $position, 47);
    $frame->drawImage($mark);
    $frame->setImageDelay(15);
    $frame->setImageDispose(Imagick::DISPOSE_NONE);
    $sequence->addImage($frame);
    $mark->clear(); $frame->clear();
}
$sequence->setFirstIterator();
$beforeFrames = $sequence->coalesceImages();
$sequence->setFirstIterator();
$result = $sequence->optimizeImageLayers();
if ($result !== true) { throw new RuntimeException('Оптимизация отклонена'); }
$rendered = $sequence->coalesceImages();
if ($rendered->getNumberImages() !== $beforeFrames->getNumberImages()) { throw new RuntimeException('Потеряны кадры'); }
$maxError = 0.0;
foreach ($rendered as $index => $frame) {
    $beforeFrames->setIteratorIndex($index);
    $error = $frame->getImageChannelDistortion($beforeFrames, Imagick::CHANNEL_RGB, Imagick::METRIC_ROOTMEANSQUAREDERROR);
    $maxError = max($maxError, $error);
}
if ($maxError > 0.000001) { throw new RuntimeException('Изменилось изображение кадров'); }
$deltaPages = [];
foreach ($sequence as $frame) { $deltaPages[] = ['pixels' => $frame->getImageGeometry(), 'page' => $frame->getImagePage()]; }
$sequence->setFirstIterator();
$path = $outDir . '/moving-marker-optimized.gif';
if (!$sequence->writeImages($path, true)) { throw new RuntimeException('GIF не записан'); }
echo json_encode(['file' => basename($path), 'bytes' => filesize($path), 'delta_frames' => $deltaPages, 'rendered_rgb_max_error' => $maxError], JSON_THROW_ON_ERROR), PHP_EOL;
$rendered->clear(); $beforeFrames->clear();
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Removes repeated portions of images to optimize

Description: Compares each image the GIF disposed forms of the previous image in the sequence. From this it attempts to select the smallest cropped image to replace each frame, while preserving the results of the animation. [imagick.method.available.0x629]

Return: Returns true on success.

Errors: [imagick.imagick.throws]

Changelog: —

Связанные методы. Imagick::compareImageLayers, Imagick::writeImages, Imagick::writeImage.

Imagick::previousImageВернуться к предыдущему кадру при пошаговом просмотре.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::previousImage(): bool

Зачем. Вернуться к предыдущему кадру при пошаговом просмотре.

Сигнатура. Imagick::previousImage(): bool. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
—нет параметровМетод читает или меняет текущее состояние последовательности.

Возврат. bool. Returns true on success.

Что может пойти не так. На первом кадре метод возвращает false. Официальная запись ошибок: не уточнена.

Когда выбрать другое. Setiteratorindex для прямого перехода.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: вернуться к предыдущему кадру при пошаговом просмотреПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$sequence->setLastIterator();
$result = $sequence->previousImage();
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$sequence->setLastIterator();
$result = $sequence->previousImage();
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Move to the previous image in the object

Description: Associates the previous image in an image list with the Imagick object.

Return: Returns true on success.

Errors: —

Changelog: —

Imagick::removeImageУдалить текущий неудачный кадр из импорта.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::removeImage(): bool

Зачем. Удалить текущий неудачный кадр из импорта.

Сигнатура. Imagick::removeImage(): bool. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
—нет параметровМетод читает или меняет текущее состояние последовательности.

Возврат. bool. Returns true on success.

Что может пойти не так. Курсор после удаления нужно проверять, а пустую последовательность нельзя записывать как успешную. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Собрать новую allowlist-последовательность через addimage.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: удалить текущий неудачный кадр из импортаПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->removeImage();
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->removeImage();
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Removes an image from the image list

Description: Removes an image from the image list.

Return: Returns true on success.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::setFirstIteratorСбросить курсор на первый кадр перед повторным обходом.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::setFirstIterator(): bool

Зачем. Сбросить курсор на первый кадр перед повторным обходом.

Сигнатура. Imagick::setFirstIterator(): bool. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
—нет параметровМетод читает или меняет текущее состояние последовательности.

Возврат. bool. Returns true on success.

Что может пойти не так. Сброс курсора не coalesce и не меняет сами кадры. Официальная запись ошибок: не уточнена.

Когда выбрать другое. Rewind через foreach допустим, но явный вызов лучше показывает намерение.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: сбросить курсор на первый кадр перед повторным обходомПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$sequence->setLastIterator();
$result = $sequence->setFirstIterator();
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$sequence->setLastIterator();
$result = $sequence->setFirstIterator();
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Sets the Imagick iterator to the first image

Description: Sets the Imagick iterator to the first image.

Return: Returns true on success.

Errors: —

Changelog: —

Imagick::setImageЗаменить текущий кадр исправленной версией.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::setImage(Imagick $replace): bool

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

Сигнатура. Imagick::setImage(Imagick $replace): bool. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
$replaceImagickОтдельный объект Imagick, который заменит текущий кадр.
Формулировка PHP Manual

The replace Imagick object

Возврат. bool. Returns true on success.

Что может пойти не так. Замена в неверной позиции меняет не тот кадр; geometry нового кадра должна совпадать. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Removeimage плюс addimage при явной пересборке порядка.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: заменить текущий кадр исправленной версиейПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$replacement = new Imagick();
$replacement->newImage(160, 90, new ImagickPixel('#06d6a0'), 'png');
$result = $sequence->setImage($replacement);
if ($result !== true) { throw new RuntimeException('Кадр не заменён'); }
$color = $sequence->getImagePixelColor(0, 0)->getColor(0);
if ([$color['r'], $color['g'], $color['b']] !== [6, 214, 160]) { throw new RuntimeException('Текущий кадр не содержит цвет замены'); }
$replaced = $sequence->getImage();
$replaced->setImageFormat('png');
$path = $outDir . '/replaced-current-frame.png';
if (!$replaced->writeImage($path)) { throw new RuntimeException('Кадр не записан'); }
echo json_encode(['current_frame_color' => $color, 'file' => basename($path), 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$replaced->clear();
$sequence->clear();
$replacement->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$replacement = new Imagick();
$replacement->newImage(240, 135, new ImagickPixel('#06d6a0'), 'png');
$result = $sequence->setImage($replacement);
if ($result !== true) { throw new RuntimeException('Кадр не заменён'); }
$color = $sequence->getImagePixelColor(0, 0)->getColor(0);
if ([$color['r'], $color['g'], $color['b']] !== [6, 214, 160]) { throw new RuntimeException('Текущий кадр не содержит цвет замены'); }
$replaced = $sequence->getImage();
$replaced->setImageFormat('png');
$path = $outDir . '/replaced-current-frame.png';
if (!$replaced->writeImage($path)) { throw new RuntimeException('Кадр не записан'); }
echo json_encode(['current_frame_color' => $color, 'file' => basename($path), 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$replaced->clear();
$sequence->clear();
$replacement->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Replaces image in the object

Description: Replaces the current image sequence with the image from replace object.

Return: Returns true on success.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::setImageDelayЗадать длительность показа одного кадра.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::setImageDelay(int $delay): bool

Зачем. Задать длительность показа одного кадра.

Сигнатура. Imagick::setImageDelay(int $delay): bool. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
$delayintДлительность в ticks; секунды получают как delay / ticks_per_second.
Формулировка PHP Manual

The amount of time expressed in 'ticks' that the image should be displayed for. For animated GIFs there are 100 ticks per second, so a value of 20 would be 20/100 of a second aka 1/5th of a second.

Возврат. bool. Returns true on success.

Что может пойти не так. Delay задаётся в ticks, а не миллисекундах; 20 при 100 ticks/s — 0,2 секунды. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Setimagetickspersecond вместе с вычисленным delay.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: задать длительность показа одного кадраПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->setImageDelay(20);
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['delay_ticks' => $sequence->getImageDelay(), 'ticks_per_second' => $sequence->getImageTicksPerSecond()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->setImageDelay(7);
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['delay_ticks' => $sequence->getImageDelay(), 'ticks_per_second' => $sequence->getImageTicksPerSecond()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Sets the image delay

Description: Sets the image delay. For an animated image this is the amount of time that this frame of the image should be displayed for, before displaying the next frame. The delay can be set individually for each frame in an image.

Return: Returns true on success.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::setImageDisposeУказать очистку/сохранение холста между gif-кадрами.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::setImageDispose(int $dispose): bool

Зачем. Указать очистку/сохранение холста между gif-кадрами.

Сигнатура. Imagick::setImageDispose(int $dispose): bool. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
$disposeintКонстанта DISPOSE_* — политика холста перед следующим кадром.

Возврат. bool. Returns true on success.

Что может пойти не так. Неверный dispose_* оставляет шлейф либо стирает нужный фон. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Coalesce и визуальная проверка на шахматном фоне.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: указать очистку/сохранение холста между GIF-кадрамиПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->setImageDispose(Imagick::DISPOSE_BACKGROUND);
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['dispose' => $sequence->getImageDispose()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->setImageDispose(Imagick::DISPOSE_PREVIOUS);
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['dispose' => $sequence->getImageDispose()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Sets the image disposal method

Description: Sets the image disposal method.

Return: Returns true on success.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::setImageIndexПерейти к кадру в совместимом старом коде.

доступно: PECL imagick 2, PECL imagick 3; deprecated: PECL imagick 3.4.4 · imagick

Imagick::setImageIndex(int $index): bool

Зачем. Перейти к кадру в совместимом старом коде.

Сигнатура. Imagick::setImageIndex(int $index): bool. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
$indexintНулевой индекс; сначала проверяют границы по getNumberImages().
Формулировка PHP Manual

The position to set the iterator to

Возврат. bool. Returns true on success.

Что может пойти не так. Метод deprecated с pecl imagick 3.4.4. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Setiteratorindex.

Версии. доступно: PECL imagick 2, PECL imagick 3; deprecated: PECL imagick 3.4.4.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: перейти к кадру в совместимом старом кодеПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->setImageIndex(1);
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->setImageIndex(2);
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Set the iterator position

Description: Set the iterator to the position in the image list specified with the index parameter. This method has been deprecated. See Imagick::setIteratorIndex .

Return: Returns true on success.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::setImageIterationsЗадать число повторов анимации.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::setImageIterations(int $iterations): bool

Зачем. Задать число повторов анимации.

Сигнатура. Imagick::setImageIterations(int $iterations): bool. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
$iterationsintЧисло повторов; 0 обычно означает бесконечный цикл.
Формулировка PHP Manual

The number of iterations the image should loop over. Set to '0' to loop continuously.

Возврат. bool. Returns true on success.

Что может пойти не так. 0 обычно означает бесконечное повторение; setter применяют к нужному кадру/контейнеру осознанно. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Product-policy: один проход, конечное число или бесконечный loop.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: задать число повторов анимацииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->setImageIterations(0);
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['iterations' => $sequence->getImageIterations()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->setImageIterations(3);
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['iterations' => $sequence->getImageIterations()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Sets the image iterations

Description: Sets the number of iterations an animated image is repeated.

Return: Returns true on success.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::setImageSceneСохранить логический номер сцены.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::setImageScene(int $scene): bool

Зачем. Сохранить логический номер сцены.

Сигнатура. Imagick::setImageScene(int $scene): bool. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
$sceneintЛогический номер scene metadata, а не физический iterator index.

Возврат. bool. Returns true on success.

Что может пойти не так. Scene не меняет физический порядок кадров. Официальная запись ошибок: [imagick.imagick.throws].

Когда выбрать другое. Setiteratorindex для выбора позиции.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: сохранить логический номер сценыПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->setImageScene(10);
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['scene' => $sequence->getImageScene(), 'iterator_index' => $sequence->getIteratorIndex()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->setImageScene(42);
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['scene' => $sequence->getImageScene(), 'iterator_index' => $sequence->getIteratorIndex()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Sets the image scene

Description: Sets the image scene.

Return: Returns true on success.

Errors: [imagick.imagick.throws]

Changelog: —

Imagick::setImageTicksPerSecondЗадать шкалу, в которой интерпретируется delay.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::setImageTicksPerSecond(int $ticks_per_second): bool

Зачем. Задать шкалу, в которой интерпретируется delay.

Сигнатура. Imagick::setImageTicksPerSecond(int $ticks_per_second): bool. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
$ticks_per_secondintСколько ticks составляют секунду; при смене шкалы пересчитывают delay.
Формулировка PHP Manual

The duration for which an image should be displayed expressed in ticks per second.

Возврат. bool. Returns true on success.

Что может пойти не так. Изменение шкалы без пересчёта delay меняет скорость. Официальная запись ошибок: не уточнена.

Когда выбрать другое. Оставить совместимую gif-шкалу и менять только delay.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: задать шкалу, в которой интерпретируется delayПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->setImageTicksPerSecond(100);
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['delay_ticks' => $sequence->getImageDelay(), 'ticks_per_second' => $sequence->getImageTicksPerSecond()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->setImageTicksPerSecond(50);
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['delay_ticks' => $sequence->getImageDelay(), 'ticks_per_second' => $sequence->getImageTicksPerSecond()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Sets the image ticks-per-second

Description: Adjust the amount of time that a frame of an animated image is displayed for. For animated GIFs, this function does not change the number of 'image ticks' per second, which is always defined as 100. Instead it adjusts the amount of time that the frame is displayed for to simulate the change in 'ticks per second'. For example, for an animated GIF where each frame is displayed for 20 ticks (1/5 of a second) when this method is called on each frame of that image with an argument of 50 the frames are adjusted to be displayed for 40 ticks (2/5 of a second) and the animation will play at half the original speed.

Return: Returns true on success.

Errors: —

Changelog: —

Imagick::setIteratorIndexПерейти к конкретному кадру по нулевому индексу.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::setIteratorIndex(int $index): bool

Зачем. Перейти к конкретному кадру по нулевому индексу.

Сигнатура. Imagick::setIteratorIndex(int $index): bool. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
$indexintНулевой индекс; сначала проверяют границы по getNumberImages().
Формулировка PHP Manual

The position to set the iterator to

Возврат. bool. Returns true on success.

Что может пойти не так. Индекс за границей возвращает false/ошибку и не должен приниматься напрямую от клиента. Официальная запись ошибок: не уточнена.

Когда выбрать другое. Проверить 0 <= index < getnumberimages.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: перейти к конкретному кадру по нулевому индексуПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->setIteratorIndex(1);
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->setIteratorIndex(2);
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Set the iterator position

Description: Set the iterator to the position in the image list specified with the index parameter. [imagick.method.available.0x629]

Return: Returns true on success.

Errors: —

Changelog: —

Связанные методы. Imagick::getIteratorIndex, Imagick::getImageIndex, Imagick::setImageIndex.

Imagick::setLastIteratorВыбрать последний кадр без ручного подсчёта.

доступно: PECL imagick 2 >= 2.0.1, PECL imagick 3 · imagick

Imagick::setLastIterator(): bool

Зачем. Выбрать последний кадр без ручного подсчёта.

Сигнатура. Imagick::setLastIterator(): bool. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
—нет параметровМетод читает или меняет текущее состояние последовательности.

Возврат. bool. Returns true on success.

Что может пойти не так. После вызова следующий nextimage вернёт false. Официальная запись ошибок: не уточнена.

Когда выбрать другое. Getnumberimages()-1 с setiteratorindex, если индекс нужен в отчёте.

Версии. доступно: PECL imagick 2 >= 2.0.1, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: выбрать последний кадр без ручного подсчётаПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->setLastIterator();
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->setLastIterator();
if ($result !== true) { throw new RuntimeException('Метод вернул false'); }
echo json_encode(['accepted' => true, 'effect' => ['index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()]], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Sets the Imagick iterator to the last image

Description: Sets the Imagick iterator to the last image.

Return: Returns true on success.

Errors: —

Changelog: —

Imagick::smushImagesСклеить изображения в ленту с управляемым отступом или перекрытием.

доступно: PECL imagick 3 >= 3.3.0 · imagick

Imagick::smushImages(bool $stack, int $offset): Imagick

Зачем. Склеить изображения в ленту с управляемым отступом или перекрытием.

Сигнатура. Imagick::smushImages(bool $stack, int $offset): Imagick. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
$stackbooltrue строит вертикальную ленту, false — горизонтальную.
$offsetintОтступ между изображениями; отрицательное значение создаёт перекрытие.

Возврат. Imagick. The new smushed image.

Что может пойти не так. Отрицательный offset перекрывает изображения; итоговый холст проверяют заранее. Официальная запись ошибок: не уточнена.

Когда выбрать другое. Appendimages при нулевом отступе.

Версии. доступно: PECL imagick 3 >= 3.3.0.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: склеить изображения в ленту с управляемым отступом или перекрытиемПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->smushImages(false, 12);
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/smushimages-minimal.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->smushImages(true, -8);
if (!$result instanceof Imagick) { throw new RuntimeException('Ожидался объект Imagick'); }
$frames = $result->getNumberImages();
$path = $outDir . '/smushimages-service.' . ($frames > 1 ? 'gif' : 'png');
$result->setFormat($frames > 1 ? 'gif' : 'png');
if (!$result->writeImages($path, true)) { throw new RuntimeException('Результат не записан'); }
echo json_encode(['file' => basename($path), 'frames' => $frames], JSON_THROW_ON_ERROR), PHP_EOL;
$result->clear();
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Takes all images from the current image pointer to the end of the image list and smushs them

Description: Takes all images from the current image pointer to the end of the image list and smushs them to each other top-to-bottom if the stack parameter is true, otherwise left-to-right.

Return: The new smushed image.

Errors: —

Changelog: —

Imagick::validПроверить, что текущая позиция итератора действительна.

доступно: PECL imagick 2, PECL imagick 3 · imagick

Imagick::valid(): bool

Зачем. Проверить, что текущая позиция итератора действительна.

Сигнатура. Imagick::valid(): bool. Метод работает с текущим кадром или всей последовательностью ровно в границах официального контракта ниже.

ПараметрТип/режимКак читать
—нет параметровМетод читает или меняет текущее состояние последовательности.

Возврат. bool. Returns true on success.

Что может пойти не так. True не проверяет декодирование каждого будущего кадра и не заменяет обработку исключений. Официальная запись ошибок: не уточнена.

Когда выбрать другое. Foreach с try/catch и лимитом кадров.

Версии. доступно: PECL imagick 2, PECL imagick 3.

Пошаговый маршрут. перейти к объяснению семейства.

Минимально: проверить, что текущая позиция итератора действительнаПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$colors = ['#123b5d', '#1f8a70', '#f2b544'];
foreach ($colors as $position => $color) {
    $frame = new Imagick();
    $frame->newImage(160, 90, new ImagickPixel($color), 'png');
    $frame->setImageDelay(12 + $position * 2);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр не добавлен'); }
    $frame->clear();
}
$sequence->setFirstIterator();
$result = $sequence->valid();
echo json_encode(['predicate' => $result, 'index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

Пример сам создаёт маленькую последовательность, вызывает метод и печатает наблюдаемую структуру либо записывает отдельный файл. Точный результат не заявлен без PHP Imagick runtime.

В сервисе: тот же контракт на другой длине и геометрииПример для указанного окружения
<?php
declare(strict_types=1);

$outDir = __DIR__ . '/out';
if (!is_dir($outDir) && !mkdir($outDir, 0775, true) && !is_dir($outDir)) {
    throw new RuntimeException('Не удалось создать каталог результата');
}
$sequence = new Imagick();
$manifest = [
    ['state' => 'queued', 'color' => '#4b2e83', 'durationMs' => 160],
    ['state' => 'processing', 'color' => '#9b5de5', 'durationMs' => 240],
    ['state' => 'checking', 'color' => '#f15bb5', 'durationMs' => 120],
    ['state' => 'done', 'color' => '#fee440', 'durationMs' => 500],
];
if (count($manifest) > 8) { throw new LengthException('Слишком много кадров'); }
foreach ($manifest as $position => $item) {
    if (!preg_match('/^#[0-9a-f]{6}$/i', $item['color'])) { throw new InvalidArgumentException('Некорректный цвет'); }
    $frame = new Imagick();
    $frame->newImage(240, 135, new ImagickPixel($item['color']), 'png');
    $frame->setImageProperty('aen:state', $item['state']);
    $frame->setImageTicksPerSecond(100);
    $frame->setImageDelay((int) max(1, round($item['durationMs'] / 10)));
    $frame->setImageScene($position);
    $frame->setImageDispose(Imagick::DISPOSE_BACKGROUND);
    if (!$sequence->addImage($frame)) { throw new RuntimeException('Кадр сервиса не добавлен'); }
    $frame->clear();
}
if ($sequence->getNumberImages() !== count($manifest)) { throw new RuntimeException('Последовательность собрана не полностью'); }
$sequence->setFirstIterator();
$result = $sequence->valid();
echo json_encode(['predicate' => $result, 'index' => $sequence->getIteratorIndex(), 'frames' => $sequence->getNumberImages()], JSON_THROW_ON_ERROR), PHP_EOL;
$sequence->clear();

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

Полный frozen-контракт PHP Manual

Purpose: Checks if the current item is valid

Description: Checks if the current item is valid.

Return: Returns true on success.

Errors: —

Changelog: —

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

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

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

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

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