Форум АНТИЧАТ

Форум АНТИЧАТ (https://forum.antichat.xyz/index.php)
-   PHP, PERL, MySQL, JavaScript (https://forum.antichat.xyz/forumdisplay.php?f=37)
-   -   Прописываем dpi в PNG (PHP) (https://forum.antichat.xyz/showthread.php?t=115638)

_Spamer_ 12.04.2009 23:32

Прописываем dpi в PNG (PHP)
 
Понадобилось мне тут вдруг для одной прикладной задачи генерировать PNG-шки на PHP, чтобы затем их можно было вставлять в документы и распечатывать. Но вот проблема, никак с помощью GD в PHP при сохранении нельзя задать разрешение в dpi, а ведь это очень важно при печати. С ImageMagick мне связываться не хотелось, поэтому я быстренько нагуглил PNG (Portable Network Graphics) Specification и написал вот такой код:

Код:

//Я создал изображение с помощью GD, поэтому png-шку получаю таким способом:
    ob_start();
    imagepng($img);
    imagedestroy($img);
    $img = ob_get_contents();
    ob_end_clean();
   
    //Но вы можете загрузить готовую вот таким:
    $img = file_get_contents('path/fileName.png');
   
    $dpi = 600; //В пикселях на дюйм

    $incPos = strpos($img, 'IDAT') - 4; //Определяем позицию куда будем вставлять наш chunk
    $chunk = 'pHYs'.pack('NNc', round($dpi/0.0254), round($dpi/0.0254), 1); //Собираем chunk type + chunk data
    $incData = pack('N', 9).$chunk.pack('N', crc32($chunk)); //Добавляем в начало размер chunk-а, а в конец его crc
    file_put_contents('path/fileName.png', substr_replace($img, $incData, $incPos, 0 )); //Вставляем и сохраняем


Обращаю внимание, что я исходил из того, что GD просто не создает pHYs chunk-а. Поэтому я просто вставляю свой перед первым IDAT chunk-ом. Но если вы хотите работать с произвольной png-шкой, то вам придется предусмотреть случай, когда pHYs chunk уже существует, находить и заменять его.

О составе chunk-ов написано тут: Chunk layout.

В начале идет 4-х байтовое беззнаковое целочисленное содержащие количество байт отводимое на содержимое чанка (для нашего нужно 9 байт). Затем следуют 4 ASCII байта названия чанка (нас интересует pHYs). Далее содержимое чанка, 4 байта отводится под ширину и 4 под высоту, которые также представляют из себя беззнаковые целые. А затем один байт надо установить в единичку, иначе мы будем задавать лишь относительные пропорции. После этого нужно вычислить и записать 4 байта контрольной суммы CRC32 от названия и содержимого чанка. Важно! Обратите внимание, все числовые переменные (включая crc) должны быть с тупоконечным порядком (от старшего к младшему). Высота и ширина у нас задается в точках на метр. Поэтому для пересчета точки/дюйм надо делить на 0,0254.

Надеюсь кому-нибудь мой опыт окажется полезным.
C Bart


Время: 11:04