📜 ⬆️ ⬇️

Writing dpi to PNG with PHP

It took me suddenly to generate PNG-shki for PHP for one application, so that they could then be inserted into documents and printed. But here’s the problem, with the help of GD in PHP, it’s impossible to set the resolution in dpi, but this is very important when printing. I didn’t want to contact ImageMagick, so I quickly jumped the PNG (Portable Network Graphics) Specification and wrote the following code:

// 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 )) ; //

I draw your attention to the fact that I proceeded from the fact that GD simply does not create pHYs chunk . Therefore, I simply insert my own before the first IDAT chunk. But if you want to work with an arbitrary png-shkoy, then you have to consider the case when the pHYs chunk already exists, find and replace it.

The composition of the chunk is written here: Chunk layout .

At the beginning there is a 4-byte unsigned integer containing the number of bytes allocated for the contents of the chunk (for our need 9 bytes). Then follow 4 ASCII bytes of the name of the chunk (we are interested in pHYs ). Next, the contents of the chunk, 4 bytes, is allocated for the width and 4 for the height, which are also unsigned integers. And then one byte must be set to one, otherwise we will set only relative proportions. After that, you need to calculate and write down 4 bytes of the CRC32 checksum from the name and contents of the chunk. Important! Note that all numeric variables (including crc) must be blunt-numbered (older to younger). Our height and width is given in points per meter. Therefore, to recalculate the point / inch should be divided by 0.0254.
')
I hope someone my experience will be useful.

Source: https://habr.com/ru/post/56588/


All Articles