PNG IDAT specification

2019-05-23 15:44发布

问题:

I'm going over the W3 PNG specification (creating a PNG library from scratch) and I've finally found how to create a green 1x1 image.

Now I'm trying to create a bigger image of mixed Red, Green and Blue pixels. Let's say a 4x4 image. Sadly I'm getting all the pixels mixed and some of them are Black or Pink.

Details:

  • Signature: OK
  • IHDR: OK
    • Width: 4
    • Heigh: 4
    • Bit depth: 8
    • Color: 2
    • Filter: 0
    • Compression: 0
    • Interlace: 0
  • IDATA: 4 chunks*
  • IEND: OK

*IDATA chunks:

  • 4 bytes length: Number of bytes of the DATA after Zlib deflate
  • 4*1 byte type: IDAT
  • X bytes data: 4*4bytes unsigned integers, Zlib deflated, one after the other, Network byte order
    • 255 for blue**
    • 65280 for green**
    • 16711680 for red**
  • 4 bytes crc: OK

**Bitwise results of:

alpha<<24 | red<<16 | green<<8 | blue

With alpha, blue, green and red taking values from 0 to 255

What's wrong with this?

回答1:

The PNG pixels are in RGBA order, not ARGB, so you'd need to write

alpha | red<<24 | green << 16 | blue <<8

But you are writing color type 2, so your pixels should be 3 bytes each instead of four; you can't really encode them in 4-byte integers as you've done. So either change the color type to 6 or switch to writing each sample as an individual byte.

Also you need a filter byte at the beginning of each row. Zero will work for you. So in your example 4x4 RGB image you will need to write 13 bytes per row

0 R G B R G B R G B R G B
0 R G B R G B R G B R G B
0 R G B R G B R G B R G B
0 R G B R G B R G B R G B

then concatenate all the row bytes into one byte stream and zlib-compress that. It can all go into one IDAT chunk. If you need to write smaller IDAT chunks, you have to zlib-compress the image first, then split the zlib output into pieces that you put in consecutive IDAT chunks.