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

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

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

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

Глава 392 · После объектов и RGB; подготовка двух изображений

Imagick: собрать стереопару в красно-голубой анаглиф

Готовый PNG из двух видов, понятный путь RGB, фактический новый объект вместо bool, ошибки совмещения и настоящее сохранение/чтение.

Получить готовый анаглиф из двух подготовленных видов

Для учебной карточки стереопары нужен один красно-голубой PNG, который можно положить на сайт и скачать. У нас два готовых вида одной условной сцены: задний прямоугольник и передний круг на неподвижной сетке. Ниже виден настоящий результат PHP. Без очков заметны красные и голубые контуры; с подходящей стереопарой и красно-голубыми очками они разделяются между глазами. Код сам по себе не превращает одиночную фотографию в объёмную сцену.

Два собственных вида 400×320 и реально сформированный анаглиф; сетка общая, смещения объектов различны
Два собственных вида 400×320 и реально сформированный анаглиф; сетка общая, смещения объектов различны

Оба изображения приложены к ZIP в base64; полный example.php автоматически восстанавливает left.png и right.png перед обработкой. Короткие четыре строки ниже показывают основной вызов для уже подготовленных файлов. Это самостоятельно нарисованная модель двух плоских слоёв, а не фотографии откалиброванной камеры. Между видами прямоугольник смещён на 4 px, круг на 12 px, сетка — на 0 px. Так видно, зачем нужны два различающихся вида. Рисунок упрощает реальные перспективу и перекрытия; одинаковую фотографию нельзя просто объявить вторым независимым ракурсом.

$left = new Imagick(__DIR__ . "/left.png");
$right = new Imagick(__DIR__ . "/right.png");
$result = $left->stereoImage($right);
$result->writeImage(__DIR__ . "/anaglyph.png");

New Imagick открывает файл и создаёт объект. __DIR__ обозначает папку PHP-файла, точка склеивает её с именем. Стрелка -> вызывает метод объекта: слева берётся первый вид, в скобках передаётся второй. Знак = сохраняет новый результат в $result. Последняя строка записывает именно его. Это четыре основных действия; дальнейший полный запуск добавляет лишь восстановление входов, отдельные картинки и отчёт, чтобы результат было с чем сравнить. Основы объектов и аргументов и возвращаемых значений помогают разобрать запись.

Собрать красно-голубой превью-файл из двух готовых видов

Получаются левый вид, правый вид и красно-голубой анаглиф 400×320. Метод создал новый Imagick; оба входа не изменились. Проверены все 384000 значений RGB: R взят слева, G и B справа.

Собрать красно-голубой превью-файл из двух готовых видовПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__.'/stereo-fixture.php';
stRestore();
$left=new Imagick(__DIR__.'/left.png');
$right=new Imagick(__DIR__.'/right.png');
$beforeLeft=stState($left);$beforeRight=stState($right);
$result=$left->stereoImage($right);
$images=['left'=>stImage($left,'first-left8.png'),'right'=>stImage($right,'first-right8.png'),'result'=>stImage($result,'first-result8.png')];
$rects=stCompare([$left,$right,$result],'stereo-first.png');
$mismatches=stChannelMismatches($left,$right,$result);
stDiagnostic('stereo-first',['executed_api'=>'stereoImage','returned_type'=>get_debug_type($result),'distinct_object'=>$result!==$left&&$result!==$right,
    'before_left'=>$beforeLeft,'before_right'=>$beforeRight,'after_left'=>stState($left),'after_right'=>stState($right),'channel_mismatches'=>$mismatches,
    'images'=>$images,'panel_keys'=>['left','right','result'],'panel_geometry'=>$rects,'source_unchanged'=>stState($left)===$beforeLeft&&stState($right)===$beforeRight,
    'checks'=>['actual_Imagick'=>$result instanceof Imagick,'new_object'=>$result!==$left&&$result!==$right,'R_left_GB_right'=>$mismatches===0,
        'left_unchanged'=>stState($left)===$beforeLeft,'right_unchanged'=>stState($right)===$beforeRight,'size_preserved'=>$result->getImageGeometry()===$left->getImageGeometry()]]);
echo "stereo-first.png\nfirst-left8.png\nfirst-right8.png\nfirst-result8.png\nmetrics.json\nreturn=Imagick new-object=1 channels-exact=1 inputs-unchanged=1\n";

Получаются левый вид, правый вид и красно-голубой анаглиф 400×320. Метод создал новый Imagick; оба входа не изменились. Проверены все 384000 значений RGB: R взят слева, G и B справа. Каждый ZIP самодостаточен: example.php, два собственных PNG в base64 и stereo-fixture.php. Распакуйте рядом и выполните php example.php. stRestore проверяет хэши и восстанавливает left.png/right.png. stImage/stCompare сохраняют настоящие RGB8-копии и панели без масштабирования; stState читает размеры и RGB16; stDiagnostic пишет metrics.json. Изучаемые stereoImage-вызовы находятся в основном коде. Полный helper раскрыт в последнем разделе. Среда: PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16, Windows.

Ожидаемый вывод программы в проверенной среде
stereo-first.png
first-left8.png
first-right8.png
first-result8.png
metrics.json
return=Imagick new-object=1 channels-exact=1 inputs-unchanged=1

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

Путь данных R слева и G/B справа; одинаковые виды не добавляют ракурс, перестановка меняет каналы
Путь данных R слева и G/B справа; одинаковые виды не добавляют ракурс, перестановка меняет каналы

RGB — три числа, задающие красную, зелёную и синюю составляющие пикселя. Представьте три провода на выходе: красный подключён к левому виду, зелёный и синий — к правому. В точке с левым RGB(17,89,201) и правым RGB(231,57,102) получаем RGB(17,57,102). Это реальный контрольный вызов во втором примере. Числа 89,201 и 231 в этот выходной пиксель не попали. Аналогия описывает выбор каналов, а не физическую схему памяти PHP.

Мы используем серые исходники, где R=G=B: это позволяет показать содержимое обоих видов без подавления цветного объекта только потому, что у него слабый красный канал. Метод не переводит любое цветное фото в серое автоматически. Он не измеряет расстояние до круга и не вычисляет карту глубины. Фиксированная сетка остаётся совмещённой, а разные горизонтальные смещения фигур дают видимые цветные края. Перестановка $left и $right меняет назначение глаз; вертикальная ошибка остаётся ошибкой.

Сохранить новый объект и проверить RGB на простом примере

После вызова исходный левый объект остаётся прежним; готовое изображение находится в возвращённом объекте
После вызова исходный левый объект остаётся прежним; готовое изображение находится в возвращённом объекте

Не все методы Imagick меняют получателя. Здесь $left->stereoImage($right) возвращает отдельный Imagick. Если проигнорировать результат и вызвать $left->writeImage(...), сохранится левый вид без анаглифа. Поэтому полезно сначала освоить одну строку присваивания, а потом помещать её в обработчик. Официальное bool/true и Reflection в этой версии неточны; ниже рядом показаны объявленный тип и фактический объект, а также контрольный пиксель.

Присвоить результат вызова и проверить один цветной пиксель

Исходный левый вид остаётся серым, а новый объект содержит анаглиф. Контрольный RGB слева (17,89,201), справа (231,57,102) даёт (17,57,102). В проверенном binding Reflection сообщает bool, но действительный результат — Imagick.

Присвоить результат вызова и проверить один цветной пиксельПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__.'/stereo-fixture.php';
stRestore();
$left=new Imagick(__DIR__.'/left.png');
$right=new Imagick(__DIR__.'/right.png');
$beforeLeft=stState($left);$beforeRight=stState($right);
$result=$left->stereoImage($right);
$images=['before'=>stImage($left,'minimal-before8.png'),'result'=>stImage($result,'minimal-result8.png')];
$rects=stCompare([$left,$result],'stereo-minimal.png');
$leftPixel=new Imagick();$leftPixel->newImage(1,1,'rgb(17,89,201)','png');
$rightPixel=new Imagick();$rightPixel->newImage(1,1,'rgb(231,57,102)','png');
$pixelResult=$leftPixel->stereoImage($rightPixel);
$pixel=$pixelResult->getImagePixelColor(0,0)->getColor();
$declared=(string)(new ReflectionMethod(Imagick::class,'stereoImage'))->getReturnType();
stDiagnostic('stereo-minimal',['executed_api'=>'stereoImage','returned_type'=>get_debug_type($result),'declared_return'=>$declared,
    'calibration'=>['left'=>[17,89,201],'right'=>[231,57,102],'result'=>[$pixel['r'],$pixel['g'],$pixel['b']]],
    'before_left'=>$beforeLeft,'before_right'=>$beforeRight,'after_left'=>stState($left),'after_right'=>stState($right),
    'images'=>$images,'panel_keys'=>['before','result'],'panel_geometry'=>$rects,'source_unchanged'=>stState($left)===$beforeLeft&&stState($right)===$beforeRight,
    'checks'=>['actual_Imagick'=>$result instanceof Imagick,'declared_bool_is_not_actual'=>$declared==='bool','pixel_17_57_102'=>[$pixel['r'],$pixel['g'],$pixel['b']] === [17,57,102],
        'result_differs_from_receiver'=>stHash($result)!==stHash($left),'left_unchanged'=>stState($left)===$beforeLeft,'right_unchanged'=>stState($right)===$beforeRight]]);
echo "stereo-minimal.png\nminimal-before8.png\nminimal-result8.png\nmetrics.json\ndeclared=bool actual=Imagick pixel=17,57,102 original-unchanged=1\n";

Исходный левый вид остаётся серым, а новый объект содержит анаглиф. Контрольный RGB слева (17,89,201), справа (231,57,102) даёт (17,57,102). В проверенном binding Reflection сообщает bool, но действительный результат — Imagick. Каждый ZIP самодостаточен: example.php, два собственных PNG в base64 и stereo-fixture.php. Распакуйте рядом и выполните php example.php. stRestore проверяет хэши и восстанавливает left.png/right.png. stImage/stCompare сохраняют настоящие RGB8-копии и панели без масштабирования; stState читает размеры и RGB16; stDiagnostic пишет metrics.json. Изучаемые stereoImage-вызовы находятся в основном коде. Полный helper раскрыт в последнем разделе. Среда: PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16, Windows.

Ожидаемый вывод программы в проверенной среде
stereo-minimal.png
minimal-before8.png
minimal-result8.png
metrics.json
declared=bool actual=Imagick pixel=17,57,102 original-unchanged=1

В полном примере массив calibration хранит входные и выходные RGB. Reflection нужен только для демонстрации обнаруженного расхождения документации; чтобы создать анаглиф, он не требуется. Вторая картинка — результат метода, а не вручную добавленные цветные контуры. Исходные PNG на диске и оба прочитанных объекта не изменяются.

Разобрать ошибки пары, сохранить из функции и открыть результат

Вертикальная ошибка 8 px и готовый PNG до/после настоящего повторного открытия
Вертикальная ошибка 8 px и готовый PNG до/после настоящего повторного открытия

На практике пользователи путают соединение кадров с подготовкой стереопары. Сначала сравним три ошибочных ожидания: повтор одной картинки, перестановку глаз и сдвиг правого вида вниз на 8 px. Отдельно изменим page-offset — это метаданные виртуального холста, а не перемещение пикселей в этой операции.

Сравнить одинаковые виды, перепутанный порядок и вертикальную ошибку

Одинаковые входы не создают нового ракурса. При перестановке видов меняются красный и голубые контуры; вертикальный сдвиг 8 px создаёт ошибку совмещения. Изменение только page-offset на (20,8) не сдвигает пиксели при stereoImage.

Сравнить одинаковые виды, перепутанный порядок и вертикальную ошибкуПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__.'/stereo-fixture.php';
stRestore();
$left=new Imagick(__DIR__.'/left.png');
$right=new Imagick(__DIR__.'/right.png');
$beforeLeft=stState($left);$beforeRight=stState($right);
$normal=$left->stereoImage($right);
$same=$left->stereoImage($left);
$swapped=$right->stereoImage($left);
$shifted=new Imagick();$shifted->newImage(400,320,'#f0f0f0','png');
$shifted->compositeImage($right,Imagick::COMPOSITE_COPY,0,8);
$vertical=$left->stereoImage($shifted);
$pageOnly=clone $right;$pageOnly->setImagePage(400,320,20,8);
$pageResult=$left->stereoImage($pageOnly);
$images=['same'=>stImage($same,'controls-same8.png'),'swapped'=>stImage($swapped,'controls-swapped8.png'),'vertical'=>stImage($vertical,'controls-vertical8.png')];
$rects=stCompare([$same,$swapped,$vertical],'stereo-controls.png');
stDiagnostic('stereo-controls',['executed_api'=>'stereoImage','normal_hash'=>stHash($normal),'left_hash'=>stHash($left),'page_result_hash'=>stHash($pageResult),
    'same_hash'=>stHash($same),'swapped_hash'=>stHash($swapped),'vertical_hash'=>stHash($vertical),'vertical_shift_px'=>8,'page_only_offset'=>[20,8],
    'images'=>$images,'panel_keys'=>['same','swapped','vertical'],'panel_geometry'=>$rects,'source_unchanged'=>stState($left)===$beforeLeft&&stState($right)===$beforeRight,
    'checks'=>['same_pair_no_new_view'=>stHash($same)===stHash($left),'swapped_changes_channels'=>stHash($swapped)!==stHash($normal),
        'vertical_error_visible'=>stHash($vertical)!==stHash($normal),'page_offset_does_not_shift_pixels'=>stHash($pageResult)===stHash($normal),
        'left_unchanged'=>stState($left)===$beforeLeft,'right_unchanged'=>stState($right)===$beforeRight]]);
echo "stereo-controls.png\ncontrols-same8.png\ncontrols-swapped8.png\ncontrols-vertical8.png\nmetrics.json\nsame-pair=unchanged swapped=different vertical=different page-offset=ignored\n";

Одинаковые входы не создают нового ракурса. При перестановке видов меняются красный и голубые контуры; вертикальный сдвиг 8 px создаёт ошибку совмещения. Изменение только page-offset на (20,8) не сдвигает пиксели при stereoImage. Каждый ZIP самодостаточен: example.php, два собственных PNG в base64 и stereo-fixture.php. Распакуйте рядом и выполните php example.php. stRestore проверяет хэши и восстанавливает left.png/right.png. stImage/stCompare сохраняют настоящие RGB8-копии и панели без масштабирования; stState читает размеры и RGB16; stDiagnostic пишет metrics.json. Изучаемые stereoImage-вызовы находятся в основном коде. Полный helper раскрыт в последнем разделе. Среда: PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16, Windows.

Ожидаемый вывод программы в проверенной среде
stereo-controls.png
controls-same8.png
controls-swapped8.png
controls-vertical8.png
metrics.json
same-pair=unchanged swapped=different vertical=different page-offset=ignored

Одинаковые виды возвращают тот же RGB: новых данных о глубине не появилось. При перестановке меняется распределение каналов. При вертикальном сдвиге даже горизонтальные линии сетки расходятся по высоте. Только page-offset (20,8) в нашем опыте дал прежний результат: stereoImage вызывает StereoImage с нулевыми внутренними смещениями. Исправлять несовпадение нужно подготовкой реальных видов, а не произвольным подбором page-offset.

Теперь поместим рабочее действие в функцию makeStereoPreview. Её параметры — два пути и путь результата; return возвращает готовый объект для дальнейшего применения. Проверка stValidate требует один кадр и одинаковые размеры, затем выполняется тот же stereoImage. Записанный файл действительно открывается снова, поэтому отчёт подтверждает содержимое PNG, а не только объект до записи.

Сохранить превью из функции, перечитать PNG и обработать ошибки

Функция сохраняет готовый anaglyph-data.png. После настоящего открытия совпадают все RGB и размеры. Четыре вызова с ошибками сохранены по классу и сообщению; предварительная проверка разных размеров показана отдельно.

Сохранить превью из функции, перечитать PNG и обработать ошибкиПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__.'/stereo-fixture.php';
stRestore();
$left=new Imagick(__DIR__.'/left.png');
$right=new Imagick(__DIR__.'/right.png');
$beforeLeft=stState($left);$beforeRight=stState($right);
function makeStereoPreview(string $leftFile,string $rightFile,string $outputFile):Imagick {
    $a=new Imagick($leftFile);$b=new Imagick($rightFile);
    stValidate($a,$b);
    $preview=$a->stereoImage($b);
    $preview->setImageFormat('png');$preview->setImageDepth(8);
    $preview->setOption('png:color-type','2');$preview->setOption('png:bit-depth','8');
    if(!$preview->writeImage($outputFile)){throw new RuntimeException('Cannot write stereo preview');}
    return $preview;
}
$result=makeStereoPreview(__DIR__.'/left.png',__DIR__.'/right.png',__DIR__.'/anaglyph-data.png');
$reloaded=new Imagick(__DIR__.'/anaglyph-data.png');
$small=clone $right;$small->cropImage(399,320,0,0);
$errors['different_size']=stTry(fn()=>$left->stereoImage($small));
$errors['empty_receiver']=stTry(fn()=>(new Imagick())->stereoImage($right));
$errors['empty_argument']=stTry(fn()=>$left->stereoImage(new Imagick()));
$errors['wrong_type']=stTry(fn()=>$left->stereoImage('right.png'));
$policy=stTry(fn()=>stValidate($left,$small));
$images=['result'=>stImage($result,'workflow-result8.png'),'reloaded'=>stImage($reloaded,'workflow-reloaded8.png')];
$rects=stCompare([$result,$reloaded],'stereo-workflow.png');
$checks=['saved_RGB_exact'=>stHash($result)===stHash($reloaded),'saved_geometry'=>$reloaded->getImageGeometry()===['width'=>400,'height'=>320],
    'policy_rejected_different_size'=>($policy['error']['class']??null)==='InvalidArgumentException','inputs_unchanged'=>stState($left)===$beforeLeft&&stState($right)===$beforeRight];
foreach($errors as$name=>$entry){$checks['caught_'.$name]=isset($entry['error']);}
stDiagnostic('stereo-workflow',['executed_api'=>'stereoImage','saved'=>['filename'=>'anaglyph-data.png','sha256'=>hash_file('sha256',__DIR__.'/anaglyph-data.png'),'bytes'=>filesize(__DIR__.'/anaglyph-data.png'),'state'=>stState($reloaded)],
    'errors'=>$errors,'policy_error'=>$policy,'images'=>$images,'panel_keys'=>['result','reloaded'],'panel_geometry'=>$rects,'source_unchanged'=>stState($left)===$beforeLeft&&stState($right)===$beforeRight,'checks'=>$checks]);
echo "stereo-workflow.png\nworkflow-result8.png\nworkflow-reloaded8.png\nanaglyph-data.png\nmetrics.json\nsaved-RGB-exact=1 errors=4 policy-rejection=1 inputs-unchanged=1\n";

Функция сохраняет готовый anaglyph-data.png. После настоящего открытия совпадают все RGB и размеры. Четыре вызова с ошибками сохранены по классу и сообщению; предварительная проверка разных размеров показана отдельно. Каждый ZIP самодостаточен: example.php, два собственных PNG в base64 и stereo-fixture.php. Распакуйте рядом и выполните php example.php. stRestore проверяет хэши и восстанавливает left.png/right.png. stImage/stCompare сохраняют настоящие RGB8-копии и панели без масштабирования; stState читает размеры и RGB16; stDiagnostic пишет metrics.json. Изучаемые stereoImage-вызовы находятся в основном коде. Полный helper раскрыт в последнем разделе. Среда: PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16, Windows.

Ожидаемый вывод программы в проверенной среде
stereo-workflow.png
workflow-result8.png
workflow-reloaded8.png
anaglyph-data.png
metrics.json
saved-RGB-exact=1 errors=4 policy-rejection=1 inputs-unchanged=1
ПроблемаЧто получено и что делать
399×320 вместо 400×320Native даёт ImagickException. В рабочей функции это раньше отклоняет собственная проверка размеров; не растягивайте только один глаз наугад.
Пустой получатель или аргументДва реальных ImagickException. Сначала успешно прочитайте оба входа.
Строка right.png вместо объектаTypeError. Создайте new Imagick(...), затем передайте объект.
Сохранили левую картинкуПроверьте присваивание возвращённого Imagick и writeImage именно результата.
Файл изменил вид после конвертацииСогласуйте профили и непрозрачный фон заранее. Наш точный readback относится к PNG8 и подготовленной серой паре, а не ко всем кодерам/фотографиям.

Проверить полный контракт, запустить архив и применить результат

Полная официальная запись и уточнение фактического результата

Imagick::stereoImage(Imagick $offset_wand): bool

Официальная страница описывает объединение левого и правого изображений стереопары. Единственный обязательный параметр offset_wand имеет тип Imagick: это второй объект с изображением. В официальной таблице дополнительное описание параметра отсутствует; это не числовое смещение, не путь к файлу и не режим смешивания. В метод не передаются x/y: заранее подготовьте оба вида. Доступность: PECL imagick 2, PECL imagick 3. Запись не отмечена устаревшей в принятом инвентаре.

Важная неточность PHP.net и stub Imagick 3.8.1: они указывают bool и true при успехе. Реальный C-код создаёт возвращаемый объект Imagick; наш запуск PHP 8.5.11 / Imagick 3.8.1 / IM 7.1.1-46 подтвердил новый объект, отличный от обоих входов. Reflection в этой же сборке сообщает bool — этого описания недостаточно, чтобы понять поведение. Рабочий вызов: $result = $left->stereoImage($right); затем сохраняйте $result. Не проверяйте результат через === true и не записывайте левый вход в надежде, что он уже преобразован.

$result = $left->stereoImage($right); // фактически Imagick в проверенной сборке
$result->writeImage(__DIR__ . "/anaglyph.png");
Часть контрактаПрактический смысл
Получатель $leftТекущее изображение левого вида. Наш проект открывает по одному кадру в каждом объекте.
Аргумент $rightТекущее изображение правого вида с такими же размерами в пикселях.
RGB результатаR = R левого; G = G правого; B = B правого. Это не средняя яркость двух кадров.
ГеометрияРазмеры должны совпадать. API не калибрует камеры, не выравнивает виды и не восстанавливает глубину.
Изменение данныхВ нашей проверенной сборке создаётся новый объект, оба входа сохранены.
ОшибкиОфициально ImagickException. Разные размеры и два случая пустого объекта реально дали ImagickException; строка вместо Imagick — TypeError.

Исходники MagickCore отдельно обрабатывают alpha при определённых свойствах канала. Эти примеры используют непрозрачные sRGB-входы и не делают утверждений о произвольной прозрачности. Для фотографий сначала согласуйте цветовое пространство, экспозицию, масштаб, ориентацию и вертикальное положение; само объединение каналов этих задач не решает. Красный фильтр перед левым глазом и голубой перед правым разделяют каналы, но субъективный объём зависит от пары, очков и просмотра. Без подходящих очков видны цветные контуры.

Два различающихся применения: базовый превью-файл из готовой пары и функция сохранения с проверкой входов/настоящим readback. При ограничении обычным плоским превью используйте обычную композицию; для расположения двух видов рядом нужно соединение панелей, а не stereoImage. Контроль цветового пространства и ориентации выполняется до анаглифа.

Запуск, ограничения и следующее упражнение

Нужны PHP с Imagick и доступ на запись в распакованную папку. Все четыре ZIP содержат входы и helper; запустите php example.php. Во всех новых программах созданы настоящие PNG и metrics.json. Среда проверки закреплена: PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16, Windows. Исходные фигуры созданы специально для этого мануала; внешних фотографий и шрифтов в пакетах нет.

Упражнение: коллега записал $ok = $left->stereoImage($right), проверил $ok === true и затем сохранил $left. Почему готового анаглифа нет? Ответ: в проверенной сборке $ok — объект, поэтому строгая проверка на true ложна; левый вид не изменён. Назовите переменную $result, сохраните её, затем откройте PNG и сравните. Второе упражнение: поменяйте виды местами и объясните смену цветных краёв по трём каналам, не называя её автоматическим исправлением глубины.

Выход содержит число пикселей одного вида; хранение обоих входов, результата и диагностических массивов требует дополнительной памяти по их площади. В этом учебном примере полный RGB16 экспорт нужен для доказательства маршрута каналов; обычному обработчику не обязательно делать такой аудит на каждом запросе. Камеры, их синхронизация и калибровка находятся за границами данного метода. Для анимации нужно осмысленно сопоставлять кадры — один вызов не обрабатывает автоматически все пары последовательности.

Полный вспомогательный PHP из каждого архива
<?php
declare(strict_types=1);
function stRestore():void {
    $hashes=json_decode('{"left.png":"9021ff43b1b06d148cf7e35809a4a6e559f02111d22a3a71ff23da66b2cdb037","right.png":"02f25666567bfa529b0bc039ab506a044a38cc00464594b8a3f56ac1eed95ef4"}',true,512,JSON_THROW_ON_ERROR);
    foreach($hashes as $name=>$hash){$raw=base64_decode((string)file_get_contents(__DIR__.'/'.$name.'.b64'),true);
        if($raw===false||hash('sha256',$raw)!==$hash||file_put_contents(__DIR__.'/'.$name,$raw)===false){throw new RuntimeException('Stereo input missing or changed');}}
}
function stHash(Imagick $image):string {return hash('sha256',json_encode($image->exportImagePixels(0,0,$image->getImageWidth(),$image->getImageHeight(),'RGB',Imagick::PIXEL_SHORT),JSON_THROW_ON_ERROR));}
function stState(Imagick $image):array {return ['geometry'=>[$image->getImageWidth(),$image->getImageHeight()],'RGB16_sha256'=>stHash($image),'frames'=>$image->getNumberImages()];}
function stView(Imagick $image):Imagick {$c=clone $image;$c->stripImage();$c->setImageFormat('png');$c->setImageDepth(8);$c->setOption('png:bit-depth','8');$c->setOption('png:color-type','2');$c->setOption('png:exclude-chunk','all');return $c;}
function stImage(Imagick $image,string $filename):array {
    if(!stView($image)->writeImage(__DIR__.'/'.$filename)){throw new RuntimeException('Cannot save PNG');}$read=new Imagick(__DIR__.'/'.$filename);
    return stState($image)+['encoded_png'=>['filename'=>$filename,'RGB16_sha256'=>stHash($read)],'display_basis'=>'Native RGB8 clone, original size'];
}
function stCompare(array $images,string $filename):array {
    $board=new Imagick();$board->newImage(400*count($images),320,'white','png');$rects=[];
    foreach($images as$i=>$image){$board->compositeImage(stView($image),Imagick::COMPOSITE_COPY,400*$i,0);$rects[]=['x'=>400*$i,'y'=>0,'width'=>400,'height'=>320];}
    if(!stView($board)->writeImage(__DIR__.'/'.$filename)){throw new RuntimeException('Cannot save comparison');}return $rects;
}
function stChannelMismatches(Imagick $left,Imagick $right,Imagick $result):int {
    $w=$left->getImageWidth();$h=$left->getImageHeight();$a=$left->exportImagePixels(0,0,$w,$h,'RGB',Imagick::PIXEL_SHORT);$b=$right->exportImagePixels(0,0,$w,$h,'RGB',Imagick::PIXEL_SHORT);$c=$result->exportImagePixels(0,0,$w,$h,'RGB',Imagick::PIXEL_SHORT);$n=0;
    foreach($c as$k=>$v){if($v!==($k%3===0?$a[$k]:$b[$k]))$n++;}return $n;
}
function stTry(callable $operation):array {try{$r=$operation();return ['type'=>get_debug_type($r),'returned'=>$r instanceof Imagick?stState($r):$r];}catch(Throwable $e){return ['error'=>['class'=>get_class($e),'message'=>$e->getMessage()]];}}
function stValidate(Imagick $left,Imagick $right):void {
    if($left->getNumberImages()!==1||$right->getNumberImages()!==1){throw new InvalidArgumentException('Project expects one image per eye');}
    if($left->getImageGeometry()!==$right->getImageGeometry()){throw new InvalidArgumentException('Project expects equal pixel dimensions');}
}
function stDiagnostic(string $id,array $data):void {
    $doc=['schema'=>'aen-stereo-image-program-diagnostics-v1','example_id'=>$id,'runtime'=>['php'=>PHP_VERSION,'imagick'=>phpversion('imagick'),'imagemagick'=>Imagick::getVersion()]]+$data;
    if(file_put_contents(__DIR__.'/metrics.json',json_encode($doc,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR)."\n")===false){throw new RuntimeException('Cannot save measurements');}
}

StRestore восстанавливает ровно два известных входа по SHA. StState/stHash читают размеры и RGB16. StImage и stCompare записывают native-результаты без изменения масштаба; stChannelMismatches сверяет каждый R с левым, каждый G/B с правым. StTry сохраняет настоящие классы ошибок, stValidate — отдельное правило проекта. Ни одна из этих функций не скрывает вызов stereoImage: он показан в основном коде.

Реальные вопросы, которые помогают понять границы задачи

Обсуждения ниже служат источником практических задач; решения в этом разделе написаны самостоятельно, технические утверждения сверены с точными исходниками и запуском.

How to mix up a stereo image with EmguCV?: Два кадра камер пытаются смешать как обычные полупрозрачные изображения, не понимая выбора каналов. Показываем конкретный RGB-путь и отдельный контрольный пиксель; готовый анаглиф требует R слева и G/B справа, а не произвольного среднего.

Superimpose two web cam streams - Matlab: Разработчик хочет показать две камеры как стереовидео и смешивает задачу получения кадров с их объединением. Разделяем готовую синхронную пару и один вызов. Наш пример пишет одиночный PNG; realtime и синхронизация камер этим методом не реализованы.

Extract depth map from a 3D anaglyph image: Из анаглифа хотят получить карту глубины. Не обещаем вычисление расстояний: stereoImage лишь соединяет каналы. На собственной двухслойной модели объясняем смещения, не объявляя её полноценной реконструкцией.

Split image and name each half: Нужно получить и правильно назвать левый и правый виды из общего файла стереокамеры. Явно называем входы left.png/right.png и не смешиваем перестановку глаз со случайной нумерацией. Наш архив содержит готовую пару; извлечение из side-by-side выполняют до вызова.

Imagick compositeImage doesn't apply original width and height but smaller: После композиции воспринимаемый размер объекта не совпадает с ожиданием, и автор пытается подбирать множители масштаба. Проверяем одинаковые реальные размеры обоих видов и показываем настоящий отказ при399×320; не растягиваем один вид вслепую.

php imagick convert PNG to jpg: PNG после JPEG-конвертации даёт неожиданный чёрный фон, а не ожидаемый рисунок. Фиксируем непрозрачные RGB8-входы и PNG-выход, отдельно сохраняем/открываем результат. Не распространяем это наблюдение на произвольную прозрачность и кодеры.

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

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

Imagick::stereoImageСобрать красно-голубой PNG из двух подготовленных видов

PECL imagick 2, PECL imagick 3 · imagick

Imagick::stereoImage(Imagick $offset_wand): bool

Полная официальная запись и уточнение фактического результата

Imagick::stereoImage(Imagick $offset_wand): bool

Официальная страница описывает объединение левого и правого изображений стереопары. Единственный обязательный параметр offset_wand имеет тип Imagick: это второй объект с изображением. В официальной таблице дополнительное описание параметра отсутствует; это не числовое смещение, не путь к файлу и не режим смешивания. В метод не передаются x/y: заранее подготовьте оба вида. Доступность: PECL imagick 2, PECL imagick 3. Запись не отмечена устаревшей в принятом инвентаре.

Важная неточность PHP.net и stub Imagick 3.8.1: они указывают bool и true при успехе. Реальный C-код создаёт возвращаемый объект Imagick; наш запуск PHP 8.5.11 / Imagick 3.8.1 / IM 7.1.1-46 подтвердил новый объект, отличный от обоих входов. Reflection в этой же сборке сообщает bool — этого описания недостаточно, чтобы понять поведение. Рабочий вызов: $result = $left->stereoImage($right); затем сохраняйте $result. Не проверяйте результат через === true и не записывайте левый вход в надежде, что он уже преобразован.

$result = $left->stereoImage($right); // фактически Imagick в проверенной сборке
$result->writeImage(__DIR__ . "/anaglyph.png");
Часть контрактаПрактический смысл
Получатель $leftТекущее изображение левого вида. Наш проект открывает по одному кадру в каждом объекте.
Аргумент $rightТекущее изображение правого вида с такими же размерами в пикселях.
RGB результатаR = R левого; G = G правого; B = B правого. Это не средняя яркость двух кадров.
ГеометрияРазмеры должны совпадать. API не калибрует камеры, не выравнивает виды и не восстанавливает глубину.
Изменение данныхВ нашей проверенной сборке создаётся новый объект, оба входа сохранены.
ОшибкиОфициально ImagickException. Разные размеры и два случая пустого объекта реально дали ImagickException; строка вместо Imagick — TypeError.

Исходники MagickCore отдельно обрабатывают alpha при определённых свойствах канала. Эти примеры используют непрозрачные sRGB-входы и не делают утверждений о произвольной прозрачности. Для фотографий сначала согласуйте цветовое пространство, экспозицию, масштаб, ориентацию и вертикальное положение; само объединение каналов этих задач не решает. Красный фильтр перед левым глазом и голубой перед правым разделяют каналы, но субъективный объём зависит от пары, очков и просмотра. Без подходящих очков видны цветные контуры.

Два различающихся применения: базовый превью-файл из готовой пары и функция сохранения с проверкой входов/настоящим readback. При ограничении обычным плоским превью используйте обычную композицию; для расположения двух видов рядом нужно соединение панелей, а не stereoImage. Контроль цветового пространства и ориентации выполняется до анаглифа.

Присвоить результат вызова и проверить один цветной пиксель

Исходный левый вид остаётся серым, а новый объект содержит анаглиф. Контрольный RGB слева (17,89,201), справа (231,57,102) даёт (17,57,102). В проверенном binding Reflection сообщает bool, но действительный результат — Imagick.

Присвоить результат вызова и проверить один цветной пиксельПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__.'/stereo-fixture.php';
stRestore();
$left=new Imagick(__DIR__.'/left.png');
$right=new Imagick(__DIR__.'/right.png');
$beforeLeft=stState($left);$beforeRight=stState($right);
$result=$left->stereoImage($right);
$images=['before'=>stImage($left,'minimal-before8.png'),'result'=>stImage($result,'minimal-result8.png')];
$rects=stCompare([$left,$result],'stereo-minimal.png');
$leftPixel=new Imagick();$leftPixel->newImage(1,1,'rgb(17,89,201)','png');
$rightPixel=new Imagick();$rightPixel->newImage(1,1,'rgb(231,57,102)','png');
$pixelResult=$leftPixel->stereoImage($rightPixel);
$pixel=$pixelResult->getImagePixelColor(0,0)->getColor();
$declared=(string)(new ReflectionMethod(Imagick::class,'stereoImage'))->getReturnType();
stDiagnostic('stereo-minimal',['executed_api'=>'stereoImage','returned_type'=>get_debug_type($result),'declared_return'=>$declared,
    'calibration'=>['left'=>[17,89,201],'right'=>[231,57,102],'result'=>[$pixel['r'],$pixel['g'],$pixel['b']]],
    'before_left'=>$beforeLeft,'before_right'=>$beforeRight,'after_left'=>stState($left),'after_right'=>stState($right),
    'images'=>$images,'panel_keys'=>['before','result'],'panel_geometry'=>$rects,'source_unchanged'=>stState($left)===$beforeLeft&&stState($right)===$beforeRight,
    'checks'=>['actual_Imagick'=>$result instanceof Imagick,'declared_bool_is_not_actual'=>$declared==='bool','pixel_17_57_102'=>[$pixel['r'],$pixel['g'],$pixel['b']] === [17,57,102],
        'result_differs_from_receiver'=>stHash($result)!==stHash($left),'left_unchanged'=>stState($left)===$beforeLeft,'right_unchanged'=>stState($right)===$beforeRight]]);
echo "stereo-minimal.png\nminimal-before8.png\nminimal-result8.png\nmetrics.json\ndeclared=bool actual=Imagick pixel=17,57,102 original-unchanged=1\n";

Исходный левый вид остаётся серым, а новый объект содержит анаглиф. Контрольный RGB слева (17,89,201), справа (231,57,102) даёт (17,57,102). В проверенном binding Reflection сообщает bool, но действительный результат — Imagick. Каждый ZIP самодостаточен: example.php, два собственных PNG в base64 и stereo-fixture.php. Распакуйте рядом и выполните php example.php. stRestore проверяет хэши и восстанавливает left.png/right.png. stImage/stCompare сохраняют настоящие RGB8-копии и панели без масштабирования; stState читает размеры и RGB16; stDiagnostic пишет metrics.json. Изучаемые stereoImage-вызовы находятся в основном коде. Полный helper раскрыт в последнем разделе. Среда: PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16, Windows.

Ожидаемый вывод программы в проверенной среде
stereo-minimal.png
minimal-before8.png
minimal-result8.png
metrics.json
declared=bool actual=Imagick pixel=17,57,102 original-unchanged=1

Сохранить превью из функции, перечитать PNG и обработать ошибки

Функция сохраняет готовый anaglyph-data.png. После настоящего открытия совпадают все RGB и размеры. Четыре вызова с ошибками сохранены по классу и сообщению; предварительная проверка разных размеров показана отдельно.

Сохранить превью из функции, перечитать PNG и обработать ошибкиПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__.'/stereo-fixture.php';
stRestore();
$left=new Imagick(__DIR__.'/left.png');
$right=new Imagick(__DIR__.'/right.png');
$beforeLeft=stState($left);$beforeRight=stState($right);
function makeStereoPreview(string $leftFile,string $rightFile,string $outputFile):Imagick {
    $a=new Imagick($leftFile);$b=new Imagick($rightFile);
    stValidate($a,$b);
    $preview=$a->stereoImage($b);
    $preview->setImageFormat('png');$preview->setImageDepth(8);
    $preview->setOption('png:color-type','2');$preview->setOption('png:bit-depth','8');
    if(!$preview->writeImage($outputFile)){throw new RuntimeException('Cannot write stereo preview');}
    return $preview;
}
$result=makeStereoPreview(__DIR__.'/left.png',__DIR__.'/right.png',__DIR__.'/anaglyph-data.png');
$reloaded=new Imagick(__DIR__.'/anaglyph-data.png');
$small=clone $right;$small->cropImage(399,320,0,0);
$errors['different_size']=stTry(fn()=>$left->stereoImage($small));
$errors['empty_receiver']=stTry(fn()=>(new Imagick())->stereoImage($right));
$errors['empty_argument']=stTry(fn()=>$left->stereoImage(new Imagick()));
$errors['wrong_type']=stTry(fn()=>$left->stereoImage('right.png'));
$policy=stTry(fn()=>stValidate($left,$small));
$images=['result'=>stImage($result,'workflow-result8.png'),'reloaded'=>stImage($reloaded,'workflow-reloaded8.png')];
$rects=stCompare([$result,$reloaded],'stereo-workflow.png');
$checks=['saved_RGB_exact'=>stHash($result)===stHash($reloaded),'saved_geometry'=>$reloaded->getImageGeometry()===['width'=>400,'height'=>320],
    'policy_rejected_different_size'=>($policy['error']['class']??null)==='InvalidArgumentException','inputs_unchanged'=>stState($left)===$beforeLeft&&stState($right)===$beforeRight];
foreach($errors as$name=>$entry){$checks['caught_'.$name]=isset($entry['error']);}
stDiagnostic('stereo-workflow',['executed_api'=>'stereoImage','saved'=>['filename'=>'anaglyph-data.png','sha256'=>hash_file('sha256',__DIR__.'/anaglyph-data.png'),'bytes'=>filesize(__DIR__.'/anaglyph-data.png'),'state'=>stState($reloaded)],
    'errors'=>$errors,'policy_error'=>$policy,'images'=>$images,'panel_keys'=>['result','reloaded'],'panel_geometry'=>$rects,'source_unchanged'=>stState($left)===$beforeLeft&&stState($right)===$beforeRight,'checks'=>$checks]);
echo "stereo-workflow.png\nworkflow-result8.png\nworkflow-reloaded8.png\nanaglyph-data.png\nmetrics.json\nsaved-RGB-exact=1 errors=4 policy-rejection=1 inputs-unchanged=1\n";

Функция сохраняет готовый anaglyph-data.png. После настоящего открытия совпадают все RGB и размеры. Четыре вызова с ошибками сохранены по классу и сообщению; предварительная проверка разных размеров показана отдельно. Каждый ZIP самодостаточен: example.php, два собственных PNG в base64 и stereo-fixture.php. Распакуйте рядом и выполните php example.php. stRestore проверяет хэши и восстанавливает left.png/right.png. stImage/stCompare сохраняют настоящие RGB8-копии и панели без масштабирования; stState читает размеры и RGB16; stDiagnostic пишет metrics.json. Изучаемые stereoImage-вызовы находятся в основном коде. Полный helper раскрыт в последнем разделе. Среда: PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16, Windows.

Ожидаемый вывод программы в проверенной среде
stereo-workflow.png
workflow-result8.png
workflow-reloaded8.png
anaglyph-data.png
metrics.json
saved-RGB-exact=1 errors=4 policy-rejection=1 inputs-unchanged=1
Источники и обсуждения

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

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

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

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