From: David B. <dba...@qu...> - 2005-04-03 03:46:46
|
> -----Original Message----- > From: Greg Roelofs > Sent: Friday, April 01, 2005 7:51 AM > Subject: Re: [png-mng-implement] Encoding from 16bpp source > > > Hi there, I've been using libpng with great success for some time with > 24bpp > > and 32bpp sources. However, I'm having trouble encoding at 24bpp image > from > > 16bpp sources (both 5551 and 565). Can anyone see what I'm doing wrong? > > libpng doesn't support 16bpp--you have to mask/shift the data yourself. > (All "16-bit" references in the API are 16 _bps_.) Ahh, after poking around in the implementation of "png_do_shift( )" I see my mistake: Yes, 'libpng' can transform the input data from an arbitrary bitdepth to the output bitdepth specified in "png_set_IHDR( )". But no, it cannot be given to 'libpng' in a "packed" form. Rather, the input data must be supplied to 'libpng' in the bitdepth specified in "png_set_IHDR( )", even if some of the bits aren't used. To clarify by example, I'm trying to convert from 16bpp RGB input into 8-bit PNG output. My input data is packed in 16-bit RGB565 format, meaning one pixel takes two bytes. However, I can't give it direct to 'libpng' in this format. Rather, I need to break apart my packed, 16-bit RGB565 pixel into three separate 8-bit channels. The first byte contains the five-bit R channel, the second the 6-bit G channel, and the third the five-bit B channel. So, the data I give to 'libpng' is neither in my original, packed 16-bit RGB565 format, nor in a packed 24-bit RGB888 format. Instead, it's in an intermediate "unpacked" 24-bit RGB565. Then, I can use "png_set_shift( )" to notify 'libpng' that the true bit depths of the R, G, and B channels are 5, 6, and 5, respectively. It'll scale up the data into a true 24-bit, packed RGB888 format, and then encode that. (Of course, if you're going to the trouble to unpack the data yourself, you might as well go the whole way do the scaling yourself and skip "png_set_shift( )" altogether.) The subtlety of this issue wasn't really apparent from my reading of the man page for "png_set_shift( )": If the data is stored in the row buffer in a bit depth other than one supported by PNG (e.g. 3 bit data in the range 0-7 for a 4-bit PNG), this will scale the values to appear to be the correct bit depth as is required by PNG. png_set_shift(png_ptr, &sig_bit); However, I'm at a loss for how to convey it more completely. My best attempt is: "This will scale each color channel in the row buffer from the true bit depth specified in 'sig_bit', to the PNG bit depth specified in 'png_set_IHDR( )'. However, this will not 'unpack' irregular encodings (such as RGB565), or unsupported bitdepths (such as RGB333). Rather, these must first be 'unpacked' into a valid row buffer (such as RGB888), and then scaled as necessary using 'png_set_shift( )'." However, this wording has flaws as well. Anyway, now that I've figured it out I thought I'd send it to this list for archiving, in the hopes anyone else suffering the same confusion might find this useful in the future. -david |