EncodeToPng() with custom ppi

Hey folks!

I’m trying to find a way to create a PNG file that will allow me to set the pixels per inch. Using EncodeToPNG() unfortunately doesn’t give that option.

I know there’s tools available in System.Drawing, however from what I’ve read, that will limit me to Windows machines.

If anyone knows of any way to do this, that’d be amazing!

Well, I’m not sure if Unity actually includes any “pHYs” chunk in the png data it generates, however i guess it doesn’t. So it’s possible to manually sneak in that chunk yourself. I haven’t really played around with the PNG format yet (only with GIF and BMP) but it seems to be straight forward.

What your PNG file would need is a “pHYs” chunk which contains the physical properties of the image. That includes the “pixels per unit” for each axis and a unit specifier. Though currently the only actual unit supported is “metre”. So if you want to specify “DPI” you need to convert it into DPM. 1 DPI is about 39.3701 DPM.

The only tricky part is that each chunk has a CRC at the end. So when creating / adding or modifying a chunk you need to calculate the CRC of that chunk. Though there’s a reference implementation in C which should make things easier. The pHYs chunk could be placed right after the IHDR chunk

Maybe if i find the time i try to implements such a “modifier” for a PNG file.

edit
I did it ^^. I quickly hacked those PNGTools together (also in my github repo). You can simply do

byte[] data = someImage.EncodeToPNG();
data = B83.Image.PNGTools.ChangePPI(data, 96, 96);

The actual functionality is rather small at the moment. Though i created the basic framework to work with PNG files and its chunktypes for future extension.

PNG uses BigEndian byte ordering everywhere. That makes the use of the BinaryReader / Writer a pain but i created some helpers (at the end) to read 32 and 64 bit integers in big endian format. It turns out i don’t really need much more for this.

I can’t really test this on systems which might already be big endian. If someone has found any issues, feel free to leave a comment (with details!! Posting “doesn’t work” it pointless). Windows 10 file details doesn’t really show any difference between an image with pHYs chunk and one without. However i opened the two image versions in Paint.NET (I’m not an artist, I don’t really use Photoshop ^^) and in the “change size” menu it shows the PPM i’ve setup.