- Home /
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!
It would be nice to get some feedback. Have you seen my edit? Have you tried it? If my answer answers your problem you might want to accept the answer. If it doesn't you should provide some feedback.
Thanks.
Answer by Bunny83 · Nov 30, 2017 at 03:29 AM
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. 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.
Thanks for the answer!
Wish I actually came back and checked this earlier. I ended up writing my own after a long read through the PNG specs. Least I know how PNG files work now :p
Unity doesn't add a pHYs chunk, so it has to be added in manually. It'd be great if this was implemented natively.
@Bunny83 Thank you for sharing this! It was a real life saver.
@Bunny83 This is great. Thanks so much for sharing! Exactly what I was searching for.
Your answer
Follow this Question
Related Questions
ReadPixels generates corrupted textures on certain Android devices 0 Answers
Texture2D.EncodeToPNG not working on iOs on Unity 3.5.5f3 1 Answer
How do I prevent Texture2D.EncodeToPNG from creating artifacts on iOS? 1 Answer
Wrong colors from ReadPixels() 0 Answers
Bug - Texture "corrupted" after sending on server with MultipartformDataSection, only on iOS 1 Answer