3 ноября 2012 г.

PHP. Добавляем комментарий в JPEG

Ниже приведен пример скрипта, в котором я получаю содержимое картинки, хранящейся на диске, и преобразовываю его в шестнадцатеричное представление. Далее я создаю строку комментария. Она состоит из
  • маркера COM (комментарий), который в шестнадцатеричном представлении выглядит так: 'fffe',
  • двух байтов, указывающих длину комментария + 2 этих байта ('0008' строка содержит 6 байт),
  • собственно, строки комментария.
Хотя комментарий в файле JPEG может появляться где угодно, для простоты примера, я дописываю комментарий в начало файла, сразу после маркера начала изображения (SOI - 'ffd8'). В конец файла комментарий дописывать нельзя, потому что маркер конца изображения (EOI - 'ffd9') должен следовать сразу после сжатых данных. Потом я вывожу картинку в браузер.
<?php
    $image = file_get_contents('head1.jpg');
    $imageHex = bin2hex($image);
    
    $hexString = '636f6d6d656e';
    $commentBlock = 'fffe0008'.$hexString;
    $imageHex = str_replace('ffd8', 'ffd8'.$commentBlock, $imageHex);
    
    $imageBin = pack('H*', $imageHex);
    header('Content-Type: image/jpeg');
    echo $imageBin;
?>

Вместо функции pack можно использовать hex2bin, добавленную в PHP 5.4.0.

PHP. Как получить содержимое сгенерированной картинки

Если необходимо получить доступ к содержимому картинки, созданной в PHP с помощью функций GD, то можно сохранить её на диск и получить содержимое с помощью функций file_get_contents или fread.

Но можно и не сохранять. Можно вывести содержимое во внутренний буфер и скопировать его в строковую переменную с помощью функции ob_get_contents().
<?php
    ob_start();
    imagejpeg($image, null, 100);    
    $imageStringData = ob_get_contents();
    ob_end_clean();
    imagedestroy($image);
?>

Далее можно преобразовать полученные данные в шестнадцатеричное представление с помощью bin2hex() и произвести поиск с помощью strpos(). Например, чтобы найти маркер конца файла, надо передать функции strpos()  в качестве искомой строки код маркера в шестнадцатеричном представлении (в нашем случае -  'ffd9').

С помощью регулярных выражений можно искать прямо в двоичных данных. Маркер конца файла можно найти так:
<?php
    preg_match_all('/\xFF\xD9/', $image, $matches, PREG_OFFSET_CAPTURE);
?>

После того как все необходимые манипуляции с содержимым произведены, изображение можно привести к двоичному представлению и, например, отдать браузеру:
<?php
    $imageBin = pack('H*', $imageHex);
    header('Content-Type: image/jpeg');
    echo $imageBin;
?>

Для версии PHP 5.4.0 и выше можно вместо функции pack использовать hex2bin.