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

Дерево руководства
Глава 426 · После первых изображений Gmagick, объектов, массивов и циклов
Gmagick: последовательности, ракурсы и навигация
Собрать ракурсы, выбрать обложку, пройти список в обе стороны и удалить ненужное изображение.
Собрать три ракурса и вставить недостающий средний
Продолжаем первые изображения и чтение файлов, байтов и потоков. Это расширение Gmagick для GraphicsMagick, не Imagick. Проверенная среда: PHP8.3.6 / Gmagick2.0.6RC1 / GraphicsMagick1.3.42 Q16. Для понимания переменных, объектов и циклов доступны переменные, объекты и циклы.
Карточке товара нужны несколько ракурсов в одном файле. Начнём с трёх собственных рисунков: коробка находится слева, посередине и справа. Отдельные PNG позволяют спокойно рассмотреть каждый кадр, а GIF показывает переходы. Изображение в переменной и список изображений — разные уровни работы.




<?php
$sequence = new Gmagick(__DIR__ . '/views.gif');
$sequence->setImageIndex(1);
$sequence->setImageFormat('PNG');
$sequence->writeImage(__DIR__ . '/middle.png', false);new создаёт объект; конструктор читает готовый собственный views.gif, включённый в ZIP. Стрелка -> вызывает метод объекта. Индекс1 — второй кадр, потому что отсчёт начинается с0. false во втором аргументе writeImage сохраняет только активный кадр. Полная программа ниже строит новый GIF: сначала читает два PPM одним потоком, затем addImage вставляет средний ракурс после индекса0, у которого уже есть следующий элемент. True в writeImage записывает весь список.
<?php
declare(strict_types=1);
require __DIR__ . '/gm-fixture.php';
gmRestore();
$sequence=new Gmagick();
$sequence->readImageBlob(file_get_contents(__DIR__.'/view0.ppm').file_get_contents(__DIR__.'/view2.ppm'));
$sequence->setImageIndex(0);
$same=$sequence->addImage(new Gmagick(__DIR__.'/view1.ppm'))===$sequence;
$count=$sequence->getNumberImages();
foreach([0,1,2] as $i){
$sequence->setImageIndex($i);$sequence->setImageDelay(30);
$sequence->setImageIterations(0);$sequence->setImageDispose(Gmagick::DISPOSE_NONE);
$sequence->setImageDepth(8);$sequence->setImageFormat('PNG');
$sequence->writeImage(__DIR__.'/gm100-view'.$i.'.png',false);
}
$sequence->setImageIndex(0);
do{$sequence->setImageFormat('GIF');}while($sequence->nextImage());
$sequence->setImageIndex(0);$sequence->writeImage(__DIR__.'/gm100-views.gif',true);
gmReport('gm100-seq-assemble',["gmagick.construct", "gmagick.readimageblob", "gmagick.setimageindex", "gmagick.addimage", "gmagick.getnumberimages", "gmagick.setimagedelay", "gmagick.setimageiterations", "gmagick.setimagedispose", "gmagick.setimagedepth", "gmagick.setimageformat", "gmagick.writeimage", "gmagick.nextimage"],["gm100-view0.png", "gm100-view1.png", "gm100-view2.png"],
['three_frames'=>$count===3,'chain_return'=>$same,'size_gm100_view0'=>gmInspect('gm100-view0.png')['width']===320&&gmInspect('gm100-view0.png')['height']===200,'size_gm100_view1'=>gmInspect('gm100-view1.png')['width']===320&&gmInspect('gm100-view1.png')['height']===200,'size_gm100_view2'=>gmInspect('gm100-view2.png')['width']===320&&gmInspect('gm100-view2.png')['height']===200],
$errors ?? [], ['count'=>$count,'insertion'=>'after index0 with an existing successor']);
echo "gm100-view0.png 320x200 gm100-view1.png 320x200 gm100-view2.png 320x200\n";
Ожидаемый результат
gm100-view0.png 320x200 gm100-view1.png 320x200 gm100-view2.png 320x200
Самостоятельный ZIP: php example.php с Gmagick. Окружение: PHP8.3.6 / Gmagick2.0.6RC1 / GraphicsMagick1.3.42 Q16. Собственные PPM и готовый views.gif восстанавливаются из .b64. gm-fixture.php проверяет файлы и записывает metrics.json; изучаемые операции видны в самой программе. PNG и GIF сохраняются рядом.
Вывод успешного запуска
gm100-view0.png 320x200 gm100-view1.png 320x200 gm100-view2.png 320x200
GIF — контейнер с последовательностью, а расширение .gif само по себе не заставляет записать все кадры. Если после преобразования получилась одна неподвижная картинка, сначала проверьте наличие нескольких кадров в объекте и all_frames=true в записи. Ошибку сборки списка нельзя исправить одним переименованием PNG в GIF.
Исходники собственные: шесть PPM320×200 содержат три положения коробки на ровном и градиентном фоне. views.ppm и ramp-views.ppm — три PPM подряд в одном многокадровом потоке. Готовый views.gif получен этой же библиотекой из этих кадров и включён для коротких фрагментов. gmRestore восстанавливает точные байты из .b64; никаких сетевых загрузок нет. file_get_contents читает байты файла, точка соединяет строки, readImageBlob декодирует один получившийся поток. Сами изучаемые операции не спрятаны в помощнике.
Граница этой сборки: addImage на пустом назначении и на обычной последней позиции возвращал self, но не добавлял кадр. Последовательные readImage увеличивали счётчик, но затем запись списка теряла его начало. Поэтому основной вход читается одним потоком. Для addImage показана настоящая вставка после элемента, у которого есть следующий. Дополнительно исследованный переход nextImage за конец позволяет дописывать к списку с несколькими кадрами, но не нужен начинающему маршруту. После вставки указатель здесь оказался на индексе2, поэтому дальнейшая позиция всегда выбирается явно. Источник addImage в этой библиотеке клонируется целым списком, даже если его указатель стоит посередине; в примерах источник содержит ровно одно изображение.
Перед writeImage(path,true) полная программа назначает GIF каждому кадру. Установка формата только текущему изображению не подготовила весь смешанный список в этой сборке. Малые фрагменты с готовым views.gif уже читают GIF-кадры; фрагменты с PPM явно выполняют цикл форматов. Не делайте вывод об успехе по одному возвращённому объекту — проверяйте сохранённый результат.
Выбрать обложку и понять ссылку current
Для каталога нужна отдельная обложка из второго ракурса. Выберем индекс1 и сохраним только его. Затем увидим важную особенность current: новая переменная указывает на тот же объект, поэтому изменение через неё действует на текущий кадр общего списка.



<?php
$sequence = new Gmagick(__DIR__ . '/views.gif');
$sequence->setImageIndex(1);
$active = $sequence->current();
$index = $active->getImageIndex();
$active->setImageFormat('PNG');
$active->writeImage(__DIR__ . '/cover.png', false);Готовый views.gif входит в каждый ZIP; короткий фрагмент не требует запуска другого примера. Полная программа дополнительно строит собственный список из PPM. $active — имя той же ссылки на объект; current() не извлекает отдельный файл. getImageIndex возвращает число, а запись false оставляет в PNG выбранное изображение.
<?php
declare(strict_types=1);
require __DIR__ . '/gm-fixture.php';
gmRestore();
$sequence=new Gmagick();
$sequence->readImageBlob(file_get_contents(__DIR__.'/views.ppm'));
$sequence->setImageIndex(0);
do{$sequence->setImageDelay(30);$sequence->setImageDispose(Gmagick::DISPOSE_NONE);$sequence->setImageIterations(0);}while($sequence->nextImage());
$sequence->setImageIndex(0);
$sequence->setImageIndex(1);$active=$sequence->current();
$same=$active===$sequence;$index=$active->getImageIndex();
$active->setImageDelay(45);$delay=$sequence->getImageDelay();
$active->setImageDepth(8);
$active->setImageFormat('PNG');
$active->writeImage(__DIR__.'/gm100-cover.png',false);
$sequence->setImageIndex(0);
do{$sequence->setImageFormat('GIF');}while($sequence->nextImage());
$sequence->setImageIndex(0);$sequence->writeImage(__DIR__.'/gm100-cover-selection.gif',true);
gmReport('gm100-seq-cover',["gmagick.construct", "gmagick.readimageblob", "gmagick.setimageindex", "gmagick.setimagedelay", "gmagick.setimagedispose", "gmagick.setimageiterations", "gmagick.nextimage", "gmagick.current", "gmagick.getimageindex", "gmagick.getimagedelay", "gmagick.setimagedepth", "gmagick.setimageformat", "gmagick.writeimage"],["gm100-cover.png"],
['same_reference'=>$same,'selected_middle'=>$index===1,'alias_changes_current'=>$delay===45,'size_gm100_cover'=>gmInspect('gm100-cover.png')['width']===320&&gmInspect('gm100-cover.png')['height']===200],
$errors ?? [], ['index'=>$index,'current_is_self'=>$same,'delay_via_alias'=>$delay]);
echo "gm100-cover.png 320x200\n";
Ожидаемый результат
gm100-cover.png 320x200
Самостоятельный ZIP: php example.php с Gmagick. Окружение: PHP8.3.6 / Gmagick2.0.6RC1 / GraphicsMagick1.3.42 Q16. Собственные PPM и готовый views.gif восстанавливаются из .b64. gm-fixture.php проверяет файлы и записывает metrics.json; изучаемые операции видны в самой программе. PNG и GIF сохраняются рядом.
Вывод успешного запуска
gm100-cover.png 320x200
Если нужна независимая обработка, продумайте отдельную копию и её указатель. Не храните результат current() в массиве в ожидании набора независимых кадров: ссылки будут относиться к одному перемещаемому объекту. Для фиксированных результатов здесь используются записанные PNG.
Экспортировать галерею последовательным обходом
Из трёх ракурсов подготовим три самостоятельные картинки для галереи. Указатель работает как закладка в списке: сначала обрабатываем текущую страницу, затем спрашиваем, существует ли следующая, и только после этого переходим.



<?php
$sequence = new Gmagick(__DIR__ . '/views.gif');
$sequence->setImageIndex(0);
do {
echo $sequence->getImageIndex(), "\n";
if (!$sequence->hasNextImage()) break;
} while ($sequence->nextImage());do выполняет тело хотя бы один раз, поэтому первый кадр не пропускается. hasNextImage только проверяет соседний элемент. ! означает «не», break заканчивает цикл, nextImage действительно двигает указатель и сообщает успех. Полная программа вместо одного echo пишет каждый активный ракурс в отдельный PNG.
<?php
declare(strict_types=1);
require __DIR__ . '/gm-fixture.php';
gmRestore();
$sequence=new Gmagick();
$sequence->readImageBlob(file_get_contents(__DIR__.'/views.ppm'));
$sequence->setImageIndex(0);
do{$sequence->setImageDelay(30);$sequence->setImageDispose(Gmagick::DISPOSE_NONE);$sequence->setImageIterations(0);}while($sequence->nextImage());
$sequence->setImageIndex(0);
$indices=[];
do{
$i=$sequence->getImageIndex();$indices[]=$i;
$sequence->setImageDepth(8);$sequence->setImageFormat('PNG');
$sequence->writeImage(__DIR__.'/gm100-forward'.$i.'.png',false);
if(!$sequence->hasNextImage())break;
}while($sequence->nextImage());
$atEnd=!$sequence->hasNextImage();
gmReport('gm100-seq-forward',["gmagick.construct", "gmagick.readimageblob", "gmagick.setimageindex", "gmagick.setimagedelay", "gmagick.setimagedispose", "gmagick.setimageiterations", "gmagick.nextimage", "gmagick.getimageindex", "gmagick.setimagedepth", "gmagick.setimageformat", "gmagick.writeimage", "gmagick.hasnextimage"],["gm100-forward0.png", "gm100-forward1.png", "gm100-forward2.png"],
['all_once'=>$indices===[0,1,2],'end_reached'=>$atEnd,'size_gm100_forward0'=>gmInspect('gm100-forward0.png')['width']===320&&gmInspect('gm100-forward0.png')['height']===200,'size_gm100_forward1'=>gmInspect('gm100-forward1.png')['width']===320&&gmInspect('gm100-forward1.png')['height']===200,'size_gm100_forward2'=>gmInspect('gm100-forward2.png')['width']===320&&gmInspect('gm100-forward2.png')['height']===200],
$errors ?? [], ['visited'=>$indices]);
echo "gm100-forward0.png 320x200 gm100-forward1.png 320x200 gm100-forward2.png 320x200\n";
Ожидаемый результат
gm100-forward0.png 320x200 gm100-forward1.png 320x200 gm100-forward2.png 320x200
Самостоятельный ZIP: php example.php с Gmagick. Окружение: PHP8.3.6 / Gmagick2.0.6RC1 / GraphicsMagick1.3.42 Q16. Собственные PPM и готовый views.gif восстанавливаются из .b64. gm-fixture.php проверяет файлы и записывает metrics.json; изучаемые операции видны в самой программе. PNG и GIF сохраняются рядом.
Вывод успешного запуска
gm100-forward0.png 320x200 gm100-forward1.png 320x200 gm100-forward2.png 320x200
Нельзя писать while(nextImage()) после выбора индекса0 и ожидать обработку первого кадра внутри цикла: переход произойдёт раньше тела. Для пустого списка требуется отдельная проверка; здесь список сначала создаётся из известных файлов.
Просмотреть список назад и собрать обратную анимацию
Посетитель листает ракурсы назад. Сохраним обратный порядок как отдельную анимацию: справа → центр → слева. Исходный список остаётся удобным источником; новый список содержит кадры в порядке добавления.






<?php
$sequence = new Gmagick(__DIR__ . '/views.gif');
$sequence->setImageIndex(2);
do {
echo $sequence->getImageIndex(), "\n";
if (!$sequence->hasPreviousImage()) break;
} while ($sequence->previousImage());Индекс2 — третий элемент списка из трёх. hasPreviousImage не двигает указатель; previousImage переводит его назад. В полном примере каждый посещённый ракурс сохраняется в PNG. Затем отдельный обратный список строится из крайних кадров с вставкой среднего через addImage. Обратный просмотр сам по себе не меняет порядок элементов исходного списка.
<?php
declare(strict_types=1);
require __DIR__ . '/gm-fixture.php';
gmRestore();
$sequence=new Gmagick();
$sequence->readImageBlob(file_get_contents(__DIR__.'/views.ppm'));
$sequence->setImageIndex(0);
do{$sequence->setImageDelay(30);$sequence->setImageDispose(Gmagick::DISPOSE_NONE);$sequence->setImageIterations(0);}while($sequence->nextImage());
$sequence->setImageIndex(0);
$sequence->setImageIndex(2);$indices=[];
do{
$i=$sequence->getImageIndex();$indices[]=$i;
$sequence->setImageDepth(8);$sequence->setImageFormat('PNG');
$sequence->writeImage(__DIR__.'/gm100-backward'.$i.'.png',false);
if(!$sequence->hasPreviousImage())break;
}while($sequence->previousImage());
$reverse=new Gmagick();$reverse->readImageBlob(file_get_contents(__DIR__.'/view2.ppm').file_get_contents(__DIR__.'/view0.ppm'));
$reverse->setImageIndex(0);$reverse->addImage(new Gmagick(__DIR__.'/view1.ppm'));
foreach([0,1,2] as $i){$reverse->setImageIndex($i);$reverse->setImageDelay(30);$reverse->setImageDispose(Gmagick::DISPOSE_NONE);$reverse->setImageIterations(0);}
$reverse->setImageIndex(0);
$reverse->setImageDepth(8);
$reverse->setImageFormat('PNG');
$reverse->writeImage(__DIR__.'/gm100-reverse-first.png',false);
$reverse->setImageIndex(0);
do{$reverse->setImageFormat('GIF');}while($reverse->nextImage());
$reverse->setImageIndex(0);$reverse->writeImage(__DIR__.'/gm100-reverse.gif',true);
gmReport('gm100-seq-backward',["gmagick.construct", "gmagick.readimageblob", "gmagick.setimageindex", "gmagick.setimagedelay", "gmagick.setimagedispose", "gmagick.setimageiterations", "gmagick.nextimage", "gmagick.getimageindex", "gmagick.setimagedepth", "gmagick.setimageformat", "gmagick.writeimage", "gmagick.haspreviousimage", "gmagick.previousimage", "gmagick.addimage"],["gm100-backward2.png", "gm100-backward1.png", "gm100-backward0.png", "gm100-reverse-first.png"],
['reverse_order'=>$indices===[2,1,0],'three_reverse_frames'=>$reverse->getNumberImages()===3,'at_start'=>!$sequence->hasPreviousImage(),'size_gm100_backward2'=>gmInspect('gm100-backward2.png')['width']===320&&gmInspect('gm100-backward2.png')['height']===200,'size_gm100_backward1'=>gmInspect('gm100-backward1.png')['width']===320&&gmInspect('gm100-backward1.png')['height']===200,'size_gm100_backward0'=>gmInspect('gm100-backward0.png')['width']===320&&gmInspect('gm100-backward0.png')['height']===200,'size_gm100_reverse_first'=>gmInspect('gm100-reverse-first.png')['width']===320&&gmInspect('gm100-reverse-first.png')['height']===200],
$errors ?? [], ['visited_backwards'=>$indices]);
echo "gm100-backward2.png 320x200 gm100-backward1.png 320x200 gm100-backward0.png 320x200 gm100-reverse-first.png 320x200\n";
Ожидаемый результат
gm100-backward2.png 320x200 gm100-backward1.png 320x200 gm100-backward0.png 320x200 gm100-reverse-first.png 320x200
Самостоятельный ZIP: php example.php с Gmagick. Окружение: PHP8.3.6 / Gmagick2.0.6RC1 / GraphicsMagick1.3.42 Q16. Собственные PPM и готовый views.gif восстанавливаются из .b64. gm-fixture.php проверяет файлы и записывает metrics.json; изучаемые операции видны в самой программе. PNG и GIF сохраняются рядом.
Вывод успешного запуска
gm100-backward2.png 320x200 gm100-backward1.png 320x200 gm100-backward0.png 320x200 gm100-reverse-first.png 320x200
Начальный индекс должен соответствовать размеру списка: число2 здесь относится именно к трём нашим кадрам. В прикладной функции размер узнают заранее или обходят список до конца. Не используйте номер scene в качестве индекса последнего элемента.
Удалить лишний средний ракурс
Средний ракурс оказался лишним. Удалим активный элемент, получим переход сразу от левого к правому и сравним анимации до и после. Это удаление кадра из памяти; три исходных PPM на диске сохраняются.





<?php
$sequence = new Gmagick(__DIR__ . '/views.gif');
$sequence->setImageIndex(1);
$sequence->removeImage();
$sequence->setImageIndex(0);
$sequence->setImageFormat('GIF');
$sequence->writeImage(__DIR__ . '/two-views.gif', true);Сначала setImageIndex выбирает удаляемый элемент. removeImage не принимает номер: он работает с активным изображением. После удаления явно возвращаемся к индексу0. У нового списка уже два элемента, поэтому старый индекс2 больше не обозначает третий ракурс.
<?php
declare(strict_types=1);
require __DIR__ . '/gm-fixture.php';
gmRestore();
$sequence=new Gmagick();
$sequence->readImageBlob(file_get_contents(__DIR__.'/views.ppm'));
$sequence->setImageIndex(0);
do{$sequence->setImageDelay(30);$sequence->setImageDispose(Gmagick::DISPOSE_NONE);$sequence->setImageIterations(0);}while($sequence->nextImage());
$sequence->setImageIndex(0);
$sequence->setImageIndex(0);
do{$sequence->setImageFormat('GIF');}while($sequence->nextImage());
$sequence->setImageIndex(0);$sequence->writeImage(__DIR__.'/gm100-before-removal.gif',true);
$sequence->setImageIndex(1);
$sequence->setImageDepth(8);
$sequence->setImageFormat('PNG');
$sequence->writeImage(__DIR__.'/gm100-removed-frame.png',false);
$same=$sequence->removeImage()===$sequence;$count=$sequence->getNumberImages();
$sequence->setImageIndex(0);
$sequence->setImageDepth(8);
$sequence->setImageFormat('PNG');
$sequence->writeImage(__DIR__.'/gm100-remove-first.png',false);
$sequence->setImageIndex(0);
do{$sequence->setImageFormat('GIF');}while($sequence->nextImage());
$sequence->setImageIndex(0);$sequence->writeImage(__DIR__.'/gm100-two-views.gif',true);
gmReport('gm100-seq-remove',["gmagick.construct", "gmagick.readimageblob", "gmagick.setimageindex", "gmagick.setimagedelay", "gmagick.setimagedispose", "gmagick.setimageiterations", "gmagick.nextimage", "gmagick.setimageformat", "gmagick.writeimage", "gmagick.setimagedepth", "gmagick.removeimage", "gmagick.getnumberimages"],["gm100-removed-frame.png", "gm100-remove-first.png"],
['two_remaining'=>$count===2,'same_object'=>$same,'size_gm100_removed_frame'=>gmInspect('gm100-removed-frame.png')['width']===320&&gmInspect('gm100-removed-frame.png')['height']===200,'size_gm100_remove_first'=>gmInspect('gm100-remove-first.png')['width']===320&&gmInspect('gm100-remove-first.png')['height']===200],
$errors ?? [], ['remaining'=>$count]);
echo "gm100-removed-frame.png 320x200 gm100-remove-first.png 320x200\n";
Ожидаемый результат
gm100-removed-frame.png 320x200 gm100-remove-first.png 320x200
Самостоятельный ZIP: php example.php с Gmagick. Окружение: PHP8.3.6 / Gmagick2.0.6RC1 / GraphicsMagick1.3.42 Q16. Собственные PPM и готовый views.gif восстанавливаются из .b64. gm-fixture.php проверяет файлы и записывает metrics.json; изучаемые операции видны в самой программе. PNG и GIF сохраняются рядом.
Вывод успешного запуска
gm100-removed-frame.png 320x200 gm100-remove-first.png 320x200
Перед удалением удобно сохранить самостоятельный PNG исключаемого кадра для проверки выбора. Не удаляйте элементы прямым циклом по возрастающим старым индексам без учёта сдвига: после каждой операции следующий элемент может получить уже обработанный номер.
Подготовить ракурсы без начальной заставки
Сервису нужна функция подготовки двух оставшихся ракурсов после удаления начальной заставки. Функция проверяет вход, удаляет выбранный элемент и экспортирует результат. Видимые PNG оставшихся кадров помогают обнаружить неверный индекс лучше одного сообщения «готово».



<?php
$sequence = new Gmagick(__DIR__ . '/views.gif');
$sequence->setImageIndex(0);
$sequence->removeImage();
$sequence->setImageIndex(1);
$hasPrevious = $sequence->hasPreviousImage();
$sequence->previousImage();
$index = $sequence->current()->getImageIndex();После удаления первого кадра остаются индексы0 и1. Чтение предыдущего элемента возвращает указатель на0. В полной функции отдельная проверка допустимого индекса даёт понятную InvalidArgumentException, а сама библиотека сообщает GmagickException при попытке выбрать несуществующий кадр.
<?php
declare(strict_types=1);
require __DIR__ . '/gm-fixture.php';
gmRestore();
$sequence=new Gmagick();
$sequence->readImageBlob(file_get_contents(__DIR__.'/views.ppm'));
$sequence->setImageIndex(0);
do{$sequence->setImageDelay(30);$sequence->setImageDispose(Gmagick::DISPOSE_NONE);$sequence->setImageIterations(0);}while($sequence->nextImage());
$sequence->setImageIndex(0);
function dropFrame(Gmagick $sequence,int $index):Gmagick{
if($index<0||$index>=$sequence->getNumberImages())throw new InvalidArgumentException('Frame index outside list');
$sequence->setImageIndex($index);$sequence->removeImage();
$sequence->setImageIndex(0);return $sequence;
}
$sequence=dropFrame($sequence,0);$first=$sequence->current();$same=$first===$sequence;
$canNext=$sequence->hasNextImage();$sequence->nextImage();$canPrevious=$sequence->hasPreviousImage();$sequence->previousImage();$index=$sequence->getImageIndex();
$sequence->setImageDepth(8);
$sequence->setImageFormat('PNG');
$sequence->writeImage(__DIR__.'/gm100-after-intro.png',false);
$sequence->setImageIndex(0);
do{$sequence->setImageFormat('GIF');}while($sequence->nextImage());
$sequence->setImageIndex(0);$sequence->writeImage(__DIR__.'/gm100-without-intro.gif',true);
$errors=['range'=>gmTry(fn()=>dropFrame($sequence,9)),'native_index'=>gmTry(fn()=>$sequence->setImageIndex(9))];
gmReport('gm100-seq-function',["gmagick.construct", "gmagick.readimageblob", "gmagick.setimageindex", "gmagick.setimagedelay", "gmagick.setimagedispose", "gmagick.setimageiterations", "gmagick.nextimage", "gmagick.getnumberimages", "gmagick.removeimage", "gmagick.current", "gmagick.hasnextimage", "gmagick.haspreviousimage", "gmagick.previousimage", "gmagick.getimageindex", "gmagick.setimagedepth", "gmagick.setimageformat", "gmagick.writeimage"],["gm100-after-intro.png"],
['two_remaining'=>$sequence->getNumberImages()===2,'navigation'=>$canNext&&$canPrevious&&$index===0,'current_identity'=>$same,'range_rejected'=>$errors['range']['class']==='InvalidArgumentException','native_rejected'=>$errors['native_index']['class']==='GmagickException','size_gm100_after_intro'=>gmInspect('gm100-after-intro.png')['width']===320&&gmInspect('gm100-after-intro.png')['height']===200],
$errors ?? [], ['remaining'=>2,'returned_index'=>$index]);
echo "gm100-after-intro.png 320x200\n";
Ожидаемый результат
gm100-after-intro.png 320x200
Самостоятельный ZIP: php example.php с Gmagick. Окружение: PHP8.3.6 / Gmagick2.0.6RC1 / GraphicsMagick1.3.42 Q16. Собственные PPM и готовый views.gif восстанавливаются из .b64. gm-fixture.php проверяет файлы и записывает metrics.json; изучаемые операции видны в самой программе. PNG и GIF сохраняются рядом.
Вывод успешного запуска
gm100-after-intro.png 320x200
Приложение должно различать правило своего интерфейса и отказ библиотеки. Текст исключения может меняться между версиями; проверяем класс и наличие сообщения, не выдаём конкретную английскую фразу за постоянный API.
Упражнение: у трёх кадров какие индексы? Ответ:0,1,2. Создаёт ли current независимый кадр? Ответ:нет, он возвращает self. Что произойдёт с прежним третьим кадром после удаления среднего? Ответ:он станет вторым, с индексом1. Дальше настроим время и повторы. Для проверки ошибок полезны исключения и функции.
Практический вопрос и наш ответ
Imagick making animated gifs not animated?: После обработки загруженного GIF автор получает одну неподвижную картинку и не понимает, потерялась ли анимация при resize или при записи. Наш самостоятельный маршрут различает список кадров, текущую позицию и all_frames. Для галереи экспортируются отдельные PNG, для движения явно записывается весь GIF. Это оригинальное объяснение на собственных кадрах Gmagick; код ответа Imagick не переносится как контракт другой библиотеки.
Функции и методы этой темы
Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.
Gmagick::addimageДобавляет изображения источника к списку назначения
PECL gmagick >= Unknown · gmagick
Gmagick::addimage(Gmagick $source): GmagickДобавляет изображения источника к списку назначения. Официальное описание говорит о текущей позиции источника и перемещении итератора в конец. Возвращает объект назначения. Отличайте сам список от выбранного в нём кадра; после операции проверяйте требуемую позицию явно.
Gmagick::addimage(Gmagick $source): Gmagick| Аргумент | Тип | Смысл |
|---|---|---|
source | Gmagick — обязательный | Объект Gmagick, из которого добавляются изображения относительно его текущей позиции. Проверяйте фактический состав списка: реализация установленной версии может расходиться с описанием. |
Возврат: Изменённый Gmagick; объект можно использовать для следующей операции.
PHP.net указывает GmagickException при ошибке. Неверный тип аргумента может быть отклонён PHP как TypeError до выполнения операции. Проверки диапазона в функциях примеров — отдельные правила приложения. Для nextImage/previousImage обычная граница обхода также выражается false.
Доступность: PECL Gmagick; нижняя граница на этих официальных страницах указана Unknown. Это не означает определённую версию PHP. Примеры привязаны к указанной Q16-сборке, ограничения которой разобраны в уроке.
Два применения: Собрать три ракурса и вставить недостающий средний; Просмотреть список назад и собрать обратную анимацию.
Gmagick::currentВозвращает self — тот же Gmagick с текущим указателем изображения
PECL gmagick >= Unknown · gmagick
Gmagick::current(): GmagickВозвращает self — тот же Gmagick с текущим указателем изображения. Это не выделение одного кадра и не независимая копия. Вызов метода через полученную переменную меняет тот же объект; одиночный PNG записывается writeImage(path,false).
Gmagick::current(): GmagickАргументов нет. Getter или навигация относятся к текущему изображению и списку, как описано выше.
Возврат: self: ссылка на тот же Gmagick, не самостоятельный кадр.
PHP.net указывает GmagickException при ошибке. Неверный тип аргумента может быть отклонён PHP как TypeError до выполнения операции. Проверки диапазона в функциях примеров — отдельные правила приложения. Для nextImage/previousImage обычная граница обхода также выражается false.
Доступность: PECL Gmagick; нижняя граница на этих официальных страницах указана Unknown. Это не означает определённую версию PHP. Примеры привязаны к указанной Q16-сборке, ограничения которой разобраны в уроке.
Два применения: Выбрать обложку и понять ссылку current; Подготовить ракурсы без начальной заставки.
Gmagick::getimageindexВозвращает текущую позицию активного изображения внутри списка
PECL gmagick >= Unknown · gmagick
Gmagick::getimageindex(): intВозвращает текущую позицию активного изображения внутри списка. У трёх кадров позиции0,1,2. Это положение указателя, а не общее количество изображений и не метка scene.
Gmagick::getimageindex(): intАргументов нет. Getter или навигация относятся к текущему изображению и списку, как описано выше.
Возврат: Целое число с указанным выше смыслом.
PHP.net указывает GmagickException при ошибке. Неверный тип аргумента может быть отклонён PHP как TypeError до выполнения операции. Проверки диапазона в функциях примеров — отдельные правила приложения. Для nextImage/previousImage обычная граница обхода также выражается false.
Доступность: PECL Gmagick; нижняя граница на этих официальных страницах указана Unknown. Это не означает определённую версию PHP. Примеры привязаны к указанной Q16-сборке, ограничения которой разобраны в уроке.
Два применения: Выбрать обложку и понять ссылку current; Экспортировать галерею последовательным обходом.
Gmagick::hasnextimageПроверяет наличие следующего изображения при движении вперёд, не перемещая указатель
PECL gmagick >= Unknown · gmagick
Gmagick::hasnextimage(): mixedПроверяет наличие следующего изображения при движении вперёд, не перемещая указатель. Сигнатура PHP.net содержит mixed, но описание обещает true при наличии и false при отсутствии следующего кадра.
Gmagick::hasnextimage(): mixedАргументов нет. Getter или навигация относятся к текущему изображению и списку, как описано выше.
Возврат: Сигнатура mixed, описание PHP.net обещает true/false по наличию соседнего изображения.
PHP.net указывает GmagickException при ошибке. Неверный тип аргумента может быть отклонён PHP как TypeError до выполнения операции. Проверки диапазона в функциях примеров — отдельные правила приложения. Для nextImage/previousImage обычная граница обхода также выражается false.
Доступность: PECL Gmagick; нижняя граница на этих официальных страницах указана Unknown. Это не означает определённую версию PHP. Примеры привязаны к указанной Q16-сборке, ограничения которой разобраны в уроке.
Два применения: Экспортировать галерею последовательным обходом; Подготовить ракурсы без начальной заставки.
Gmagick::haspreviousimageПроверяет наличие предыдущего изображения при движении назад, не перемещая указатель
PECL gmagick >= Unknown · gmagick
Gmagick::haspreviousimage(): mixedПроверяет наличие предыдущего изображения при движении назад, не перемещая указатель. Сигнатура PHP.net — mixed; фактический смысл возврата по описанию — булево условие наличия предыдущего кадра.
Gmagick::haspreviousimage(): mixedАргументов нет. Getter или навигация относятся к текущему изображению и списку, как описано выше.
Возврат: Сигнатура mixed, описание PHP.net обещает true/false по наличию соседнего изображения.
PHP.net указывает GmagickException при ошибке. Неверный тип аргумента может быть отклонён PHP как TypeError до выполнения операции. Проверки диапазона в функциях примеров — отдельные правила приложения. Для nextImage/previousImage обычная граница обхода также выражается false.
Доступность: PECL Gmagick; нижняя граница на этих официальных страницах указана Unknown. Это не означает определённую версию PHP. Примеры привязаны к указанной Q16-сборке, ограничения которой разобраны в уроке.
Два применения: Просмотреть список назад и собрать обратную анимацию; Подготовить ракурсы без начальной заставки.
Gmagick::nextimageСвязывает объект со следующим изображением списка и возвращает true при успешном переходе либо false при неудаче
PECL gmagick >= Unknown · gmagick
Gmagick::nextimage(): boolСвязывает объект со следующим изображением списка и возвращает true при успешном переходе либо false при неудаче. Обычная граница списка — повод закончить обход. В разделе ошибок PHP.net отдельно допускается GmagickException.
Gmagick::nextimage(): boolАргументов нет. Getter или навигация относятся к текущему изображению и списку, как описано выше.
Возврат: true при успешном переходе, false при неудаче.
PHP.net указывает GmagickException при ошибке. Неверный тип аргумента может быть отклонён PHP как TypeError до выполнения операции. Проверки диапазона в функциях примеров — отдельные правила приложения. Для nextImage/previousImage обычная граница обхода также выражается false.
Доступность: PECL Gmagick; нижняя граница на этих официальных страницах указана Unknown. Это не означает определённую версию PHP. Примеры привязаны к указанной Q16-сборке, ограничения которой разобраны в уроке.
Два применения: Экспортировать галерею последовательным обходом; Подготовить ракурсы без начальной заставки.
Gmagick::previousimageПереходит к предыдущему изображению
PECL gmagick >= Unknown · gmagick
Gmagick::previousimage(): boolПереходит к предыдущему изображению. Возвращает true при успехе и false при неудаче; официальный раздел ошибок также допускает GmagickException. Полезен для просмотра ракурсов в обратном порядке без переименования исходных файлов.
Gmagick::previousimage(): boolАргументов нет. Getter или навигация относятся к текущему изображению и списку, как описано выше.
Возврат: true при успешном переходе, false при неудаче.
PHP.net указывает GmagickException при ошибке. Неверный тип аргумента может быть отклонён PHP как TypeError до выполнения операции. Проверки диапазона в функциях примеров — отдельные правила приложения. Для nextImage/previousImage обычная граница обхода также выражается false.
Доступность: PECL Gmagick; нижняя граница на этих официальных страницах указана Unknown. Это не означает определённую версию PHP. Примеры привязаны к указанной Q16-сборке, ограничения которой разобраны в уроке.
Два применения: Просмотреть список назад и собрать обратную анимацию; Подготовить ракурсы без начальной заставки.
Gmagick::removeimageУдаляет активное изображение из списка и возвращает изменённый Gmagick
PECL gmagick >= Unknown · gmagick
Gmagick::removeimage(): GmagickУдаляет активное изображение из списка и возвращает изменённый Gmagick. После удаления индексы оставшихся кадров могут сдвинуться; перед следующей выборкой назначьте позицию явно. Исходные PPM-файлы эта операция не удаляет.
Gmagick::removeimage(): GmagickАргументов нет. Getter или навигация относятся к текущему изображению и списку, как описано выше.
Возврат: Изменённый Gmagick; объект можно использовать для следующей операции.
PHP.net указывает GmagickException при ошибке. Неверный тип аргумента может быть отклонён PHP как TypeError до выполнения операции. Проверки диапазона в функциях примеров — отдельные правила приложения. Для nextImage/previousImage обычная граница обхода также выражается false.
Доступность: PECL Gmagick; нижняя граница на этих официальных страницах указана Unknown. Это не означает определённую версию PHP. Примеры привязаны к указанной Q16-сборке, ограничения которой разобраны в уроке.
Два применения: Удалить лишний средний ракурс; Подготовить ракурсы без начальной заставки.
Gmagick::setimageindexУстанавливает итератор на указанную позицию списка
PECL gmagick >= Unknown · gmagick
Gmagick::setimageindex(int $index): GmagickУстанавливает итератор на указанную позицию списка. Нужен для выбора ракурса, правки задержки отдельного кадра и явного возврата в начало перед экспортом. Несуществующая позиция должна обрабатываться как ошибка.
Gmagick::setimageindex(int $index): Gmagick| Аргумент | Тип | Смысл |
|---|---|---|
index | int — обязательный | Позиция в списке, начиная с нуля. Это индекс итератора, а не метка scene; в кратком описании параметра PHP.net эти понятия неудачно смешаны. |
Возврат: Изменённый Gmagick; объект можно использовать для следующей операции.
PHP.net указывает GmagickException при ошибке. Неверный тип аргумента может быть отклонён PHP как TypeError до выполнения операции. Проверки диапазона в функциях примеров — отдельные правила приложения. Для nextImage/previousImage обычная граница обхода также выражается false.
Доступность: PECL Gmagick; нижняя граница на этих официальных страницах указана Unknown. Это не означает определённую версию PHP. Примеры привязаны к указанной Q16-сборке, ограничения которой разобраны в уроке.
Два применения: Выбрать обложку и понять ссылку current; Удалить лишний средний ракурс.
Источники и обсуждения
Код и руководство с собой
Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.
Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.
Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.


