Updated libpng to current version.

This commit is contained in:
nobody 2012-01-19 00:26:54 +00:00
parent bd2a951314
commit ca7007613d

View file

@ -15,361 +15,360 @@
// ============================================================================= // =============================================================================
static void user_read_fn (png_structp png_ptr, png_bytep data, png_size_t length) static void user_read_fn(png_structp png_ptr, png_bytep data, png_size_t length)
{ {
png_size_t check; png_size_t check;
// Read() returns 0 on error, so it is OK to store this in a png_size_t // Read() returns 0 on error, so it is OK to store this in a png_size_t
// instead of an int, which is what Read() actually returns. // instead of an int, which is what Read() actually returns.
check = (png_size_t)((File*)png_ptr->io_ptr)->Read (data, length); check = (png_size_t)((File*)png_get_io_ptr(png_ptr))->Read(data, length);
if (check != length) if (check != length)
png_error(png_ptr, "Read Error"); png_error(png_ptr, "Read Error");
} }
bool Image::LoadPNG (File& file) bool Image::LoadPNG(File& file)
{ {
unsigned char sig[8], red, green, blue; unsigned char sig[8], red, green, blue;
unsigned char *image_data = NULL; unsigned char *image_data = NULL;
unsigned char *src, *dest; unsigned char *src, *dest;
unsigned char r, g, b, a; unsigned char r, g, b, a;
unsigned long i, row; unsigned long i, row;
unsigned long image_rowbytes; unsigned long image_rowbytes;
png_color_16p pBackground; png_color_16p pBackground;
png_structp png_ptr = NULL; png_structp png_ptr = NULL;
png_infop info_ptr = NULL; png_infop info_ptr = NULL;
png_uint_32 width, height; png_uint_32 width, height;
png_bytepp row_pointers = NULL; png_bytepp row_pointers = NULL;
int bit_depth, color_type; int bit_depth, color_type;
int image_channels; int image_channels;
double gamma; double gamma;
FreeData (); FreeData();
file.Read (sig, 8); file.Read(sig, 8);
if (!png_check_sig(sig, 8)) if (!png_check_sig(sig, 8))
return false; // bad signature return false; // bad signature
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr) if (!png_ptr)
return false; // out of memory return false; // out of memory
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
png_destroy_read_struct(&png_ptr, NULL, NULL);
return false; // out of memory
}
if (setjmp(png_ptr->jmpbuf)) info_ptr = png_create_info_struct(png_ptr);
{ if (!info_ptr)
png_destroy_read_struct(&png_ptr, &info_ptr, NULL); {
return false; png_destroy_read_struct(&png_ptr, NULL, NULL);
} return false; // out of memory
}
png_set_read_fn(png_ptr, (void *)&file, user_read_fn); if (setjmp(png_jmpbuf(png_ptr)))
// png_init_io(png_ptr, f); {
png_set_sig_bytes(png_ptr, 8); // we already read the 8 signature bytes png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return false;
}
png_read_info(png_ptr, info_ptr); // read all PNG info up to image data png_set_read_fn(png_ptr, (void*)&file, user_read_fn);
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, // png_init_io(png_ptr, f);
NULL, NULL, NULL); png_set_sig_bytes(png_ptr, 8); // we already read the 8 signature bytes
if (setjmp(png_ptr->jmpbuf)) png_read_info(png_ptr, info_ptr); // read all PNG info up to image data
{ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return false;
}
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) if (setjmp(png_jmpbuf(png_ptr)))
{ {
png_get_bKGD(png_ptr, info_ptr, &pBackground); png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return false;
}
if (setjmp (png_ptr->jmpbuf)) if (png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD))
{ {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL); png_get_bKGD(png_ptr, info_ptr, &pBackground);
return false;
}
// however, it always returns the raw bKGD data, regardless of any if (setjmp(png_jmpbuf(png_ptr)))
// bit-depth transformations, so check depth and adjust if necessary {
if (bit_depth == 16) png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
{ return false;
red = pBackground->red >> 8; }
green = pBackground->green >> 8;
blue = pBackground->blue >> 8;
}
else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
{
if (bit_depth == 1)
red = green = blue = pBackground->gray? 255 : 0;
else if (bit_depth == 2)
red = green = blue = (255/3) * pBackground->gray;
else // bit_depth == 4
red = green = blue = (255/15) * pBackground->gray;
}
else
{
red = (unsigned char)pBackground->red;
green = (unsigned char)pBackground->green;
blue = (unsigned char)pBackground->blue;
}
}
else
{
if (setjmp (png_ptr->jmpbuf))
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return false;
}
red = green = blue = 0; // however, it always returns the raw bKGD data, regardless of any
} // bit-depth transformations, so check depth and adjust if necessary
if (bit_depth == 16)
{
red = pBackground->red >> 8;
green = pBackground->green >> 8;
blue = pBackground->blue >> 8;
}
else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
{
if (bit_depth == 1)
red = green = blue = pBackground->gray? 255 : 0;
else if (bit_depth == 2)
red = green = blue = (255/3) * pBackground->gray;
else // bit_depth == 4
red = green = blue = (255/15) * pBackground->gray;
}
else
{
red = (unsigned char)pBackground->red;
green = (unsigned char)pBackground->green;
blue = (unsigned char)pBackground->blue;
}
}
else
{
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return false;
}
// expand palette images to RGB, low-bit-depth grayscale images to 8 bits, red = green = blue = 0;
// transparency chunks to full alpha channel; strip 16-bit-per-sample }
// images to 8 bits per sample; and convert grayscale to RGB[A]
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_expand(png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
png_set_expand(png_ptr);
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_expand(png_ptr);
if (bit_depth == 16)
png_set_strip_16(png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png_ptr);
if (png_get_gAMA(png_ptr, info_ptr, &gamma)) // expand palette images to RGB, low-bit-depth grayscale images to 8 bits,
png_set_gamma(png_ptr, 2.2, gamma); // transparency chunks to full alpha channel; strip 16-bit-per-sample
// images to 8 bits per sample; and convert grayscale to RGB[A]
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_expand(png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
png_set_expand(png_ptr);
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_expand(png_ptr);
if (bit_depth == 16)
png_set_strip_16(png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png_ptr);
// all transformations have been registered; now update info_ptr data, if (png_get_gAMA(png_ptr, info_ptr, &gamma))
// get rowbytes and channels, and allocate image memory png_set_gamma(png_ptr, 2.2, gamma);
png_read_update_info(png_ptr, info_ptr);
image_rowbytes = png_get_rowbytes(png_ptr, info_ptr); // all transformations have been registered; now update info_ptr data,
image_channels = (int)png_get_channels(png_ptr, info_ptr); // get rowbytes and channels, and allocate image memory
png_read_update_info(png_ptr, info_ptr);
if ((image_data = (unsigned char*)malloc(image_rowbytes*height)) == NULL) image_rowbytes = png_get_rowbytes(png_ptr, info_ptr);
{ image_channels = (int)png_get_channels(png_ptr, info_ptr);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return false;
}
if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) if ((image_data = (unsigned char*)malloc(image_rowbytes*height)) == NULL)
{ {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
free(image_data); return false;
return false; }
}
// set the individual row_pointers to point at the correct offsets if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL)
for (i = 0; i < height; ++i) {
row_pointers[i] = image_data + i*image_rowbytes; png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
free(image_data);
return false;
}
// now we can go ahead and just read the whole image // set the individual row_pointers to point at the correct offsets
png_read_image(png_ptr, row_pointers); for (i = 0; i < height; ++i)
row_pointers[i] = image_data + i*image_rowbytes;
// and we're done! (png_read_end() can be omitted if no processing of // now we can go ahead and just read the whole image
// post-IDAT text/time/etc. is desired) png_read_image(png_ptr, row_pointers);
free(row_pointers);
row_pointers = NULL;
png_read_end(png_ptr, NULL); // and we're done! (png_read_end() can be omitted if no processing of
// post-IDAT text/time/etc. is desired)
free(row_pointers);
row_pointers = NULL;
// done with PNG file, so clean up to minimize memory usage png_read_end(png_ptr, NULL);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
if (!image_data) // done with PNG file, so clean up to minimize memory usage
return false; png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
// get our buffer set to hold data if (!image_data)
m_pData = (unsigned char*)malloc(width*height*image_channels); return false;
if (m_pData == NULL) // get our buffer set to hold data
{ m_pData = (unsigned char*)malloc(width*height*image_channels);
free (image_data);
return false;
}
m_nWidth = width; if (m_pData == NULL)
m_nHeight = height; {
if (image_channels == 3) free (image_data);
m_bAlpha = false; return false;
else }
m_bAlpha = true;
for (row = 0; row < height; row++) m_nWidth = width;
{ m_nHeight = height;
src = image_data + row*image_rowbytes; if (image_channels == 3)
dest = m_pData + row*image_channels*width; m_bAlpha = false;
else
m_bAlpha = true;
if (image_channels == 3) for (row = 0; row < height; row++)
{ {
for (i = width; i > 0; i--) src = image_data + row*image_rowbytes;
{ dest = m_pData + row*image_channels*width;
r = *src++;
g = *src++;
b = *src++;
*dest++ = r;
*dest++ = g;
*dest++ = b;
}
}
else // if (image_channels == 4)
{
for (i = width; i > 0; i--)
{
r = *src++;
g = *src++;
b = *src++;
a = *src++;
if (a == 255) if (image_channels == 3)
{ {
*dest++ = r; for (i = width; i > 0; i--)
*dest++ = g; {
*dest++ = b; r = *src++;
} g = *src++;
else if (a == 0) b = *src++;
{ *dest++ = r;
*dest++ = red; *dest++ = g;
*dest++ = green; *dest++ = b;
*dest++ = blue; }
} }
else else // if (image_channels == 4)
{ {
// this macro (copied from png.h) composites the for (i = width; i > 0; i--)
// foreground and background values and puts the {
// result into the first argument; there are no r = *src++;
// side effects with the first argument g = *src++;
alpha_composite(*dest++, r, a, red); b = *src++;
alpha_composite(*dest++, g, a, green); a = *src++;
alpha_composite(*dest++, b, a, blue);
}
*dest++ = a;
}
}
}
free(image_data); if (a == 255)
return true; {
*dest++ = r;
*dest++ = g;
*dest++ = b;
}
else if (a == 0)
{
*dest++ = red;
*dest++ = green;
*dest++ = blue;
}
else
{
// this macro (copied from png.h) composites the
// foreground and background values and puts the
// result into the first argument; there are no
// side effects with the first argument
alpha_composite(*dest++, r, a, red);
alpha_composite(*dest++, g, a, green);
alpha_composite(*dest++, b, a, blue);
}
*dest++ = a;
}
}
}
free(image_data);
return true;
} }
// ============================================================================= // =============================================================================
static void user_write_fn (png_structp png_ptr, png_bytep data, png_size_t length) static void user_write_fn(png_structp png_ptr, png_bytep data, png_size_t length)
{ {
png_uint_32 check; png_uint_32 check;
check = ((File*)png_ptr->io_ptr)->Write (data, length); check = ((File*)png_get_io_ptr(png_ptr))->Write(data, length);
if (check != length) if (check != length)
{ {
png_error(png_ptr, "Write Error"); png_error(png_ptr, "Write Error");
} }
} }
static void user_flush_fn (png_structp png_ptr) static void user_flush_fn(png_structp png_ptr)
{ {
((File*)png_ptr->io_ptr)->Flush (); ((File*)png_get_io_ptr(png_ptr))->Flush();
} }
bool Image::SavePNG (File& file, bool transparent, bool interlaced, unsigned char* background) const bool Image::SavePNG(File& file, bool transparent, bool interlaced, unsigned char* background) const
{ {
png_structp png_ptr; png_structp png_ptr;
png_infop info_ptr; png_infop info_ptr;
png_bytepp row_pointers = NULL; png_bytepp row_pointers = NULL;
png_color_8 sig_bit; png_color_8 sig_bit;
png_color_16 bg; png_color_16 bg;
int i; int i;
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr) if (!png_ptr)
return false; return false;
info_ptr = png_create_info_struct(png_ptr); info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) if (!info_ptr)
{ {
png_destroy_write_struct(&png_ptr, NULL); png_destroy_write_struct(&png_ptr, NULL);
return false; return false;
} }
if (setjmp(png_ptr->jmpbuf)) if (setjmp(png_jmpbuf(png_ptr)))
{ {
png_destroy_write_struct(&png_ptr, (png_infopp)NULL); png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
return false; return false;
} }
// png_init_io(png_ptr, fp); // png_init_io(png_ptr, fp);
png_set_write_fn (png_ptr, &file, user_write_fn, user_flush_fn); png_set_write_fn(png_ptr, &file, user_write_fn, user_flush_fn);
png_set_IHDR (png_ptr, info_ptr, m_nWidth, m_nHeight, 8, png_set_IHDR(png_ptr, info_ptr, m_nWidth, m_nHeight, 8,
transparent ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB, transparent ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB,
interlaced ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE, interlaced ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
bg.red = background[0]; bg.red = background[0];
bg.green = background[1]; bg.green = background[1];
bg.blue = background[2]; bg.blue = background[2];
png_set_bKGD(png_ptr, info_ptr, &bg); png_set_bKGD(png_ptr, info_ptr, &bg);
png_write_info(png_ptr, info_ptr); png_write_info(png_ptr, info_ptr);
// Set the true bit depth of the image data // Set the true bit depth of the image data
sig_bit.red = 8; sig_bit.red = 8;
sig_bit.green = 8; sig_bit.green = 8;
sig_bit.blue = 8; sig_bit.blue = 8;
sig_bit.alpha = 8; sig_bit.alpha = 8;
png_set_sBIT(png_ptr, info_ptr, &sig_bit); png_set_sBIT(png_ptr, info_ptr, &sig_bit);
if ((row_pointers = (png_bytepp)malloc(m_nHeight*sizeof(png_bytep))) == NULL) if ((row_pointers = (png_bytepp)malloc(m_nHeight*sizeof(png_bytep))) == NULL)
{ {
png_destroy_write_struct(&png_ptr, (png_infopp)NULL); png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
return false; return false;
} }
// set the individual row_pointers to point at the correct offsets // set the individual row_pointers to point at the correct offsets
if (transparent) if (transparent)
{ {
unsigned char *buf, *src, *dst, alpha; unsigned char *buf, *src, *dst, alpha;
dst = buf = (unsigned char*)malloc (m_nWidth*m_nHeight*4); dst = buf = (unsigned char*)malloc(m_nWidth*m_nHeight*4);
src = m_pData; src = m_pData;
for (i = 0; i < m_nWidth*m_nHeight; i++) for (i = 0; i < m_nWidth*m_nHeight; i++)
{ {
if ((src[0] == background[0]) && if ((src[0] == background[0]) &&
(src[1] == background[1]) && (src[1] == background[1]) &&
(src[2] == background[2])) (src[2] == background[2]))
alpha = 0; alpha = 0;
else else
alpha = 255; alpha = 255;
*dst++ = *src++; *dst++ = *src++;
*dst++ = *src++; *dst++ = *src++;
*dst++ = *src++; *dst++ = *src++;
*dst++ = alpha; *dst++ = alpha;
} }
for (i = 0; i < m_nHeight; i++) for (i = 0; i < m_nHeight; i++)
row_pointers[i] = buf + i*m_nWidth*4; row_pointers[i] = buf + i*m_nWidth*4;
png_write_image(png_ptr, row_pointers); png_write_image(png_ptr, row_pointers);
free(buf); free(buf);
} }
else else
{ {
for (i = 0; i < m_nHeight; i++) for (i = 0; i < m_nHeight; i++)
row_pointers[i] = m_pData + i*m_nWidth*3; row_pointers[i] = m_pData + i*m_nWidth*3;
png_write_image(png_ptr, row_pointers); png_write_image(png_ptr, row_pointers);
} }
free(row_pointers); free(row_pointers);
png_write_end(png_ptr, info_ptr); png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, &info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr);
return true; return true;
} }
#endif // LC_HAVE_PNGLIB #endif // LC_HAVE_PNGLIB