Как стать автором
Обновить

Прописываем dpi в PNG с помощью PHP

Время на прочтение 2 мин
Количество просмотров 5.1K
Понадобилось мне тут вдруг для одной прикладной задачи генерировать 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<br>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.

Надеюсь кому-нибудь мой опыт окажется полезным.
Теги:
Хабы:
+49
Комментарии 121
Комментарии Комментарии 121

Публикации

Истории

Работа

PHP программист
175 вакансий

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн