Added read support for (hopefully) every variety of PNG that libpng supports
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4070 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -533,7 +533,7 @@ translate_from_png(BPositionIO *inSource, BMessage *ioExtension,
|
|||||||
|
|
||||||
png_structp ppng = NULL;
|
png_structp ppng = NULL;
|
||||||
png_infop pinfo = NULL;
|
png_infop pinfo = NULL;
|
||||||
while (1) {
|
while (ppng == NULL) {
|
||||||
// create PNG read pointer with default error handling routines
|
// create PNG read pointer with default error handling routines
|
||||||
ppng = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
ppng = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
if (!ppng) {
|
if (!ppng) {
|
||||||
@@ -555,23 +555,54 @@ translate_from_png(BPositionIO *inSource, BMessage *ioExtension,
|
|||||||
// set read callback function
|
// set read callback function
|
||||||
png_set_read_fn(ppng, static_cast<void *>(inSource), pngcb_read_data);
|
png_set_read_fn(ppng, static_cast<void *>(inSource), pngcb_read_data);
|
||||||
|
|
||||||
// Read in the whole PNG all at once! (easy way?)
|
// Read in PNG image info
|
||||||
png_read_png(ppng, pinfo,
|
png_read_info(ppng, pinfo);
|
||||||
PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_BGR,
|
|
||||||
png_voidp_NULL);
|
|
||||||
|
|
||||||
png_uint_32 width, height;
|
png_uint_32 width, height;
|
||||||
int bit_depth, color_type, interlace_type;
|
int bit_depth, color_type, interlace_type;
|
||||||
png_get_IHDR(ppng, pinfo, &width, &height, &bit_depth, &color_type,
|
png_get_IHDR(ppng, pinfo, &width, &height, &bit_depth, &color_type,
|
||||||
&interlace_type, int_p_NULL, int_p_NULL);
|
&interlace_type, int_p_NULL, int_p_NULL);
|
||||||
|
|
||||||
if ((color_type != PNG_COLOR_TYPE_RGB || bit_depth != 8) &&
|
// Setup image transformations to make converting it easier
|
||||||
(color_type != PNG_COLOR_TYPE_RGB_ALPHA || bit_depth != 8)) {
|
bool balpha = false;
|
||||||
debugger("Unsupported colorspace!");
|
|
||||||
result = B_NO_TRANSLATOR;
|
if (bit_depth == 16)
|
||||||
break;
|
png_set_strip_16(ppng);
|
||||||
|
else if (bit_depth < 8)
|
||||||
|
png_set_packing(ppng);
|
||||||
|
|
||||||
|
if (color_type == PNG_COLOR_TYPE_PALETTE)
|
||||||
|
png_set_palette_to_rgb(ppng);
|
||||||
|
|
||||||
|
if (png_get_valid(ppng, pinfo, PNG_INFO_tRNS)) {
|
||||||
|
balpha = true;
|
||||||
|
png_set_tRNS_to_alpha(ppng);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// change RGB to BGR as it is in 'bits'
|
||||||
|
if (color_type & PNG_COLOR_MASK_COLOR)
|
||||||
|
png_set_bgr(ppng);
|
||||||
|
|
||||||
|
// have libpng convert gray to RGB for me
|
||||||
|
if (color_type == PNG_COLOR_TYPE_GRAY ||
|
||||||
|
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||||
|
png_set_gray_to_rgb(ppng);
|
||||||
|
|
||||||
|
if (color_type & PNG_COLOR_MASK_ALPHA)
|
||||||
|
balpha = true;
|
||||||
|
|
||||||
|
if (!balpha)
|
||||||
|
// add filler byte for images without alpha
|
||||||
|
// so that the pixels are 4 bytes each
|
||||||
|
png_set_filler(ppng, 0xff, PNG_FILLER_AFTER);
|
||||||
|
|
||||||
|
// Check that transformed PNG rowbytes matches
|
||||||
|
// what is expected
|
||||||
|
const int32 kbytes = 4;
|
||||||
|
png_uint_32 rowbytes = png_get_rowbytes(ppng, pinfo);
|
||||||
|
if (rowbytes < kbytes * width)
|
||||||
|
rowbytes = kbytes * width;
|
||||||
|
|
||||||
// Write out the data to outDestination
|
// Write out the data to outDestination
|
||||||
// Construct and write Be bitmap header
|
// Construct and write Be bitmap header
|
||||||
TranslatorBitmap bitsHeader;
|
TranslatorBitmap bitsHeader;
|
||||||
@@ -581,7 +612,7 @@ translate_from_png(BPositionIO *inSource, BMessage *ioExtension,
|
|||||||
bitsHeader.bounds.right = width - 1;
|
bitsHeader.bounds.right = width - 1;
|
||||||
bitsHeader.bounds.bottom = height - 1;
|
bitsHeader.bounds.bottom = height - 1;
|
||||||
bitsHeader.rowBytes = 4 * width;
|
bitsHeader.rowBytes = 4 * width;
|
||||||
if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
|
if (balpha)
|
||||||
bitsHeader.colors = B_RGBA32;
|
bitsHeader.colors = B_RGBA32;
|
||||||
else
|
else
|
||||||
bitsHeader.colors = B_RGB32;
|
bitsHeader.colors = B_RGB32;
|
||||||
@@ -593,29 +624,63 @@ translate_from_png(BPositionIO *inSource, BMessage *ioExtension,
|
|||||||
}
|
}
|
||||||
outDestination->Write(&bitsHeader, sizeof(TranslatorBitmap));
|
outDestination->Write(&bitsHeader, sizeof(TranslatorBitmap));
|
||||||
|
|
||||||
// write out bitmap data, one row at a time
|
if (interlace_type == PNG_INTERLACE_NONE) {
|
||||||
png_bytep *prows = png_get_rows(ppng, pinfo);
|
// allocate buffer for storing PNG row
|
||||||
|
png_bytep prow = new png_byte[rowbytes];
|
||||||
|
if (!prow) {
|
||||||
|
result = B_NO_MEMORY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (png_uint_32 i = 0; i < height; i++) {
|
||||||
|
png_read_row(ppng, prow, NULL);
|
||||||
|
outDestination->Write(prow, width * kbytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// finish reading, pass NULL for info because I
|
||||||
|
// don't need the extra data
|
||||||
|
png_read_end(ppng, NULL);
|
||||||
|
delete[] prow;
|
||||||
|
prow = NULL;
|
||||||
|
|
||||||
|
result = B_OK;
|
||||||
|
break;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// interlaced PNG image
|
||||||
|
png_bytep *prows = new png_bytep[height];
|
||||||
if (!prows) {
|
if (!prows) {
|
||||||
result = B_NO_MEMORY;
|
result = B_NO_MEMORY;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// allocate enough memory to store the whole image
|
||||||
|
png_uint_32 n;
|
||||||
|
for (n = 0; n < height; n++) {
|
||||||
|
prows[n] = new png_byte[rowbytes];
|
||||||
|
if (!prows[n])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
int ncopy;
|
if (n < height)
|
||||||
if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
|
result = B_NO_MEMORY;
|
||||||
ncopy = 4;
|
else {
|
||||||
else
|
png_read_image(ppng, prows);
|
||||||
ncopy = 3;
|
for (png_uint_32 i = 0; i < height; i++)
|
||||||
for (png_uint_32 i = 0; i < height; i++) {
|
outDestination->Write(prows[i], width * kbytes);
|
||||||
for (png_uint_32 k = 0; k < width; k++) {
|
|
||||||
uint8 pixel[4] = { 0xff };
|
|
||||||
memcpy(pixel, prows[i] + (k * ncopy), ncopy);
|
|
||||||
outDestination->Write(pixel, 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result = B_OK;
|
result = B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete row pointers and array of pointers to rows
|
||||||
|
while (n) {
|
||||||
|
n--;
|
||||||
|
delete[] prows[n];
|
||||||
|
}
|
||||||
|
delete[] prows;
|
||||||
|
prows = NULL;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ppng) {
|
if (ppng) {
|
||||||
if (!pinfo)
|
if (!pinfo)
|
||||||
|
|||||||
Reference in New Issue
Block a user