void writeSetup2(png_structp png_ptr_write, png_infop info_ptr_write, png_structp png_ptr_read, png_infop info_ptr_read) { /* IHDR */ png_uint_32 width; png_uint_32 height; int bit_depth; int colour_type; int interlace_method; int compression_method; int filter_method; /* PLTE */ png_colorp palette = NULL; int palette_size = 0; /* gAMA */ double gamma; /* tRNS */ png_bytep trans; int num_trans; png_color_16p trans_values; /* bKGD */ png_color_16p background; png_get_IHDR(png_ptr_read, info_ptr_read, &width, &height, &bit_depth, &colour_type, &interlace_method, &compression_method, &filter_method); png_set_IHDR(png_ptr_write, info_ptr_write, width, height, bit_depth, colour_type, interlace_method, compression_method, filter_method); if(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_PLTE)) { png_get_PLTE(png_ptr_read, info_ptr_read, &palette, &palette_size); png_set_PLTE(png_ptr_write, info_ptr_write, palette, palette_size); } if(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_gAMA)) { png_get_gAMA(png_ptr_read, info_ptr_read, &gamma); png_set_gAMA(png_ptr_write, info_ptr_write, gamma); } if(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_tRNS)) { png_get_tRNS(png_ptr_read, info_ptr_read, &trans, &num_trans, &trans_values); png_set_tRNS(png_ptr_write, info_ptr_write, trans, num_trans, trans_values); } if(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_bKGD)) { png_get_bKGD(png_ptr_read, info_ptr_read, &background); png_set_bKGD(png_ptr_write, info_ptr_write, background); } }
static png_bytep * read_png(png_structp png_ptr, png_infop info_ptr, at_input_opts_type * opts) { int row; png_color_16p original_bg; png_color_16 my_bg; png_read_info(png_ptr, info_ptr); png_set_strip_16(png_ptr); png_set_packing(png_ptr); if ((png_get_bit_depth(png_ptr, info_ptr) < 8) || (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE) || (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))) png_set_expand(png_ptr); if (png_get_bKGD(png_ptr, info_ptr, &original_bg)) { /* Fill transparent region with ... */ my_bg.index = 0; if (opts && opts->background_color) { my_bg.red = 256 * opts->background_color->r; my_bg.green = 256 * opts->background_color->g; my_bg.blue = 256 * opts->background_color->b; my_bg.gray = 256* ((opts->background_color->r + opts->background_color->g + opts->background_color->b) / 3); } else /* else, use white */ my_bg.red = my_bg.green = my_bg.blue = my_bg.gray = 0xFFFF; png_set_background(png_ptr, &my_bg, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); } else png_set_strip_alpha(png_ptr); png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); // PGC to replace commented lines png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); png_read_end(png_ptr, info_ptr); return png_get_rows(png_ptr, info_ptr); // info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr, // info_ptr->height * sizeof(png_bytep)); //#ifdef PNG_FREE_ME_SUPPORTED // info_ptr->free_me |= PNG_FREE_ROWS; //#endif // for (row = 0; row < (int)info_ptr->height; row++) // info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr, // png_get_rowbytes(png_ptr, info_ptr)); // // png_read_image(png_ptr, info_ptr->row_pointers); // info_ptr->valid |= PNG_INFO_IDAT; // png_read_end(png_ptr, info_ptr); // return png_get_rows(png_ptr, info_ptr); }
// Do transformations to normalize the input to 8-bpp RGBA void LLPngWrapper::normalizeImage() { // 1. Expand any palettes // 2. Convert grayscales to RGB // 3. Create alpha layer from transparency // 4. Ensure 8-bpp for all images // 5. Apply background matte if any // 6. Set (or guess) gamma if (mColorType == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(mReadPngPtr); } if (mColorType == PNG_COLOR_TYPE_GRAY && mBitDepth < 8) { png_set_gray_1_2_4_to_8(mReadPngPtr); } if (mColorType == PNG_COLOR_TYPE_GRAY || mColorType == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(mReadPngPtr); } if (png_get_valid(mReadPngPtr, mReadInfoPtr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(mReadPngPtr); } if (mBitDepth < 8) { png_set_packing(mReadPngPtr); } else if (mBitDepth == 16) { png_set_strip_16(mReadPngPtr); } mHasBKGD = png_get_bKGD(mReadPngPtr, mReadInfoPtr, &mBackgroundColor); if (mHasBKGD) { png_set_background(mReadPngPtr, mBackgroundColor, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); } #if LL_DARWIN const F64 SCREEN_GAMMA = 1.8; #else const F64 SCREEN_GAMMA = 2.2; #endif if (png_get_gAMA(mReadPngPtr, mReadInfoPtr, &mGamma)) { png_set_gamma(mReadPngPtr, SCREEN_GAMMA, mGamma); } else { png_set_gamma(mReadPngPtr, SCREEN_GAMMA, 1/SCREEN_GAMMA); } }
// Read out the image meta-data void LLPngWrapper::updateMetaData() { png_read_update_info(mReadPngPtr, mReadInfoPtr); mWidth = png_get_image_width(mReadPngPtr, mReadInfoPtr); mHeight = png_get_image_height(mReadPngPtr, mReadInfoPtr); mBitDepth = png_get_bit_depth(mReadPngPtr, mReadInfoPtr); mColorType = png_get_color_type(mReadPngPtr, mReadInfoPtr); mChannels = png_get_channels(mReadPngPtr, mReadInfoPtr); mHasBKGD = png_get_bKGD(mReadPngPtr, mReadInfoPtr, &mBackgroundColor); }
/* * Analyze the usage of samples. * The output value usage_map[n] indicates whether the sample n * is used. The usage_map[] array must have 256 entries. * The function requires a valid bit depth between 1 and 8. */ static void opng_analyze_sample_usage(png_structp png_ptr, png_infop info_ptr, png_bytep usage_map) { png_bytep sample_ptr; int init_shift, init_mask, shift, mask; png_uint_32 i, j; png_uint_32 height = png_get_image_height(png_ptr, info_ptr); png_uint_32 width = png_get_image_width(png_ptr, info_ptr); int bit_depth = png_get_bit_depth(png_ptr, info_ptr); png_bytepp row_ptr = png_get_rows(png_ptr, info_ptr); /* Initialize the output entries with 0. */ memset(usage_map, 0, 256); /* Iterate through all sample values. */ if (bit_depth == 8) { for (i = 0; i < height; ++i, ++row_ptr) { for (j = 0, sample_ptr = *row_ptr; j < width; ++j, ++sample_ptr) usage_map[*sample_ptr] = 1; } } else { OPNG_ASSERT(bit_depth < 8); init_shift = 8 - bit_depth; init_mask = (1 << 8) - (1 << init_shift); for (i = 0; i < height; ++i, ++row_ptr) { for (j = 0, sample_ptr = *row_ptr; j < width; ++sample_ptr) { mask = init_mask; shift = init_shift; do { usage_map[(*sample_ptr & mask) >> shift] = 1; mask >>= bit_depth; shift -= bit_depth; ++j; } while (mask > 0 && j < width); } } } #ifdef PNG_bKGD_SUPPORTED png_color_16p background; /* bKGD also counts as a used sample. */ if (png_get_bKGD(png_ptr, info_ptr, &background)) usage_map[background->index] = 1; #endif }
/* * Analyze the redundancy of bits inside the image. * The parameter reductions indicates the intended reductions. * The function returns the possible reductions. */ static png_uint_32 opng_analyze_bits(png_structp png_ptr, png_infop info_ptr, png_uint_32 reductions) { png_uint_32 height, width; int bit_depth, color_type; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); if (bit_depth < 8 || !height || !width) return OPNG_REDUCE_NONE; /* not applicable */ if (color_type & PNG_COLOR_MASK_PALETTE) return OPNG_REDUCE_NONE; /* let opng_reduce_palette() handle it */ int byte_depth = bit_depth / 8; int channels = png_get_channels(png_ptr, info_ptr); int sample_size = channels * byte_depth; int offset_alpha = (channels - 1) * byte_depth; /* Select the applicable reductions. */ reductions &= (OPNG_REDUCE_16_TO_8 | OPNG_REDUCE_RGB_TO_GRAY | OPNG_REDUCE_STRIP_ALPHA); if (bit_depth <= 8) reductions &= ~OPNG_REDUCE_16_TO_8; if (!(color_type & PNG_COLOR_MASK_COLOR)) reductions &= ~OPNG_REDUCE_RGB_TO_GRAY; if (!(color_type & PNG_COLOR_MASK_ALPHA)) reductions &= ~OPNG_REDUCE_STRIP_ALPHA; /* Check if the ancillary information allows these reductions. */ #ifdef PNG_bKGD_SUPPORTED png_color_16p background; if (png_get_bKGD(png_ptr, info_ptr, &background)) { if (reductions & OPNG_REDUCE_16_TO_8) { if (background->red % 257 != 0 || background->green % 257 != 0 || background->blue % 257 != 0 || background->gray % 257 != 0) reductions &= ~OPNG_REDUCE_16_TO_8; } if (reductions & OPNG_REDUCE_RGB_TO_GRAY) { if (background->red != background->green || background->red != background->blue) reductions &= ~OPNG_REDUCE_RGB_TO_GRAY; } } #endif /* Check for each possible reduction, row by row. */ png_bytepp row_ptr = png_get_rows(png_ptr, info_ptr); for (png_uint_32 i = 0; i < height; ++i, ++row_ptr) { png_bytep component_ptr; png_uint_32 j; if (reductions == OPNG_REDUCE_NONE) return OPNG_REDUCE_NONE; /* no need to go any further */ /* Check if it is possible to reduce the bit depth to 8. */ if (reductions & OPNG_REDUCE_16_TO_8) { component_ptr = *row_ptr; for (j = 0; j < channels * width; ++j, component_ptr += 2) { if (component_ptr[0] != component_ptr[1]) { reductions &= ~OPNG_REDUCE_16_TO_8; break; } } } if (bit_depth == 8) { /* Check if it is possible to reduce rgb --> gray. */ if (reductions & OPNG_REDUCE_RGB_TO_GRAY) { component_ptr = *row_ptr; for (j = 0; j < width; ++j, component_ptr += sample_size) { if (component_ptr[0] != component_ptr[1] || component_ptr[0] != component_ptr[2]) { reductions &= ~OPNG_REDUCE_RGB_TO_GRAY; break; } } } /* Check if it is possible to strip the alpha channel. */ if (reductions & OPNG_REDUCE_STRIP_ALPHA) { component_ptr = *row_ptr + offset_alpha; for (j = 0; j < width; ++j, component_ptr += sample_size) { if (component_ptr[0] != 255) { reductions &= ~OPNG_REDUCE_STRIP_ALPHA; break; } } } } else /* bit_depth == 16 */ { /* Check if it is possible to reduce rgb --> gray. */ if (reductions & OPNG_REDUCE_RGB_TO_GRAY) { component_ptr = *row_ptr; for (j = 0; j < width; ++j, component_ptr += sample_size) { if (component_ptr[0] != component_ptr[2] || component_ptr[0] != component_ptr[4] || component_ptr[1] != component_ptr[3] || component_ptr[1] != component_ptr[5]) { reductions &= ~OPNG_REDUCE_RGB_TO_GRAY; break; } } } /* Check if it is possible to strip the alpha channel. */ if (reductions & OPNG_REDUCE_STRIP_ALPHA) { component_ptr = *row_ptr + offset_alpha; for (j = 0; j < width; ++j, component_ptr += sample_size) { if (component_ptr[0] != 255 || component_ptr[1] != 255) { reductions &= ~OPNG_REDUCE_STRIP_ALPHA; break; } } } } } return reductions; }
/* * Reduce the image type to a lower bit depth and color type, * by removing redundant bits. * Possible reductions: 16bpp to 8bpp; RGB to gray; strip alpha. * The parameter reductions indicates the intended reductions. * The function returns the successful reductions. * All reductions are performed in a single step. */ static png_uint_32 opng_reduce_bits(png_structp png_ptr, png_infop info_ptr, png_uint_32 reductions) { png_bytep src_ptr, dest_ptr; png_uint_32 width, height; int interlace_type, compression_type, filter_type, src_bit_depth, dest_bit_depth, src_color_type; /* See which reductions may be performed. */ reductions = opng_analyze_bits(png_ptr, info_ptr, reductions); if (reductions == OPNG_REDUCE_NONE) return OPNG_REDUCE_NONE; /* exit early */ png_get_IHDR(png_ptr, info_ptr, &width, &height, &src_bit_depth, &src_color_type, &interlace_type, &compression_type, &filter_type); if (!height || !width){ return OPNG_REDUCE_NONE; } /* Compute the new image parameters bit_depth, color_type, etc. */ OPNG_ASSERT(src_bit_depth >= 8); if (reductions & OPNG_REDUCE_16_TO_8) { OPNG_ASSERT(src_bit_depth == 16); dest_bit_depth = 8; } else dest_bit_depth = src_bit_depth; int src_byte_depth = src_bit_depth / 8; int dest_byte_depth = dest_bit_depth / 8; int dest_color_type = src_color_type; if (reductions & OPNG_REDUCE_RGB_TO_GRAY) { OPNG_ASSERT(src_color_type & PNG_COLOR_MASK_COLOR); dest_color_type &= ~PNG_COLOR_MASK_COLOR; } if (reductions & OPNG_REDUCE_STRIP_ALPHA) { OPNG_ASSERT(src_color_type & PNG_COLOR_MASK_ALPHA); dest_color_type &= ~PNG_COLOR_MASK_ALPHA; } int src_channels = png_get_channels(png_ptr, info_ptr); int dest_channels = ((dest_color_type & PNG_COLOR_MASK_COLOR) ? 3 : 1) + ((dest_color_type & PNG_COLOR_MASK_ALPHA) ? 1 : 0); int src_sample_size = src_channels * src_byte_depth; int dest_sample_size = dest_channels * dest_byte_depth; /* Pre-compute the intra-sample translation table. */ int k; int tran_tbl[8]; for (k = 0; k < 4 * dest_byte_depth; ++k) tran_tbl[k] = k * src_bit_depth / dest_bit_depth; /* If rgb --> gray, shift the alpha component two positions to the left. */ if ((reductions & OPNG_REDUCE_RGB_TO_GRAY) && (dest_color_type & PNG_COLOR_MASK_ALPHA)) { tran_tbl[dest_byte_depth] = tran_tbl[3 * dest_byte_depth]; if (dest_byte_depth == 2) tran_tbl[dest_byte_depth + 1] = tran_tbl[3 * dest_byte_depth + 1]; } /* Translate the samples to the new image type. */ OPNG_ASSERT(src_sample_size > dest_sample_size); png_bytepp row_ptr = png_get_rows(png_ptr, info_ptr); for (png_uint_32 i = 0; i < height; ++i, ++row_ptr) { src_ptr = dest_ptr = *row_ptr; for (png_uint_32 j = 0; j < width; ++j) { for (k = 0; k < dest_sample_size; ++k) dest_ptr[k] = src_ptr[tran_tbl[k]]; src_ptr += src_sample_size; dest_ptr += dest_sample_size; } } png_color_16p trans_color; /* Update the ancillary information. */ if (png_get_tRNS(png_ptr, info_ptr, 0, 0, &trans_color)) { if (reductions & OPNG_REDUCE_16_TO_8) { if (trans_color->red % 257 == 0 && trans_color->green % 257 == 0 && trans_color->blue % 257 == 0 && trans_color->gray % 257 == 0) { trans_color->red &= 255; trans_color->green &= 255; trans_color->blue &= 255; trans_color->gray &= 255; } else { /* 16-bit tRNS in 8-bit samples: all pixels are 100% opaque. */ png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, -1); png_set_invalid(png_ptr, info_ptr, PNG_INFO_tRNS); } } if (reductions & OPNG_REDUCE_RGB_TO_GRAY) { if (trans_color->red == trans_color->green || trans_color->red == trans_color->blue) trans_color->gray = trans_color->red; else { /* Non-gray tRNS in grayscale image: all pixels are 100% opaque. */ png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, -1); png_set_invalid(png_ptr, info_ptr, PNG_INFO_tRNS); } } } #ifdef PNG_bKGD_SUPPORTED png_color_16p background; if (png_get_bKGD(png_ptr, info_ptr, &background)) { if (reductions & OPNG_REDUCE_16_TO_8) { background->red &= 255; background->green &= 255; background->blue &= 255; background->gray &= 255; } if (reductions & OPNG_REDUCE_RGB_TO_GRAY) background->gray = background->red; } #endif #ifdef PNG_sBIT_SUPPORTED png_color_8p sig_bits; if (png_get_sBIT(png_ptr, info_ptr, &sig_bits)) { if (reductions & OPNG_REDUCE_16_TO_8) { if (sig_bits->red > 8) sig_bits->red = 8; if (sig_bits->green > 8) sig_bits->green = 8; if (sig_bits->blue > 8) sig_bits->blue = 8; if (sig_bits->gray > 8) sig_bits->gray = 8; if (sig_bits->alpha > 8) sig_bits->alpha = 8; } if (reductions & OPNG_REDUCE_RGB_TO_GRAY) { png_byte max_sig_bits = sig_bits->red; if (max_sig_bits < sig_bits->green) max_sig_bits = sig_bits->green; if (max_sig_bits < sig_bits->blue) max_sig_bits = sig_bits->blue; sig_bits->gray = max_sig_bits; } } #endif /* Update the image information. */ png_set_IHDR(png_ptr, info_ptr, width, height, dest_bit_depth, dest_color_type, interlace_type, compression_type, filter_type); return reductions; }
static void readpng2_info_callback(png_structp png_ptr, png_infop info_ptr) { mainprog_info *mainprog_ptr; int color_type, bit_depth; png_uint_32 width, height; #ifdef PNG_FLOATING_POINT_SUPPORTED double gamma; #else png_fixed_point gamma; #endif /* setjmp() doesn't make sense here, because we'd either have to exit(), * longjmp() ourselves, or return control to libpng, which doesn't want * to see us again. By not doing anything here, libpng will instead jump * to readpng2_decode_data(), which can return an error value to the main * program. */ /* retrieve the pointer to our special-purpose struct, using the png_ptr * that libpng passed back to us (i.e., not a global this time--there's * no real difference for a single image, but for a multithreaded browser * decoding several PNG images at the same time, one needs to avoid mixing * up different images' structs) */ mainprog_ptr = png_get_progressive_ptr(png_ptr); if (mainprog_ptr == NULL) { /* we be hosed */ fprintf(stderr, "readpng2 error: main struct not recoverable in info_callback.\n"); fflush(stderr); return; /* * Alternatively, we could call our error-handler just like libpng * does, which would effectively terminate the program. Since this * can only happen if png_ptr gets redirected somewhere odd or the * main PNG struct gets wiped, we're probably toast anyway. (If * png_ptr itself is NULL, we would not have been called.) */ } /* this is just like in the non-progressive case */ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); mainprog_ptr->width = (ulg)width; mainprog_ptr->height = (ulg)height; /* since we know we've read all of the PNG file's "header" (i.e., up * to IDAT), we can check for a background color here */ if (mainprog_ptr->need_bgcolor && png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) { png_color_16p pBackground; /* it is not obvious from the libpng documentation, but this function * takes a pointer to a pointer, and it always returns valid red, * green and blue values, regardless of color_type: */ png_get_bKGD(png_ptr, info_ptr, &pBackground); /* 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) { mainprog_ptr->bg_red = pBackground->red >> 8; mainprog_ptr->bg_green = pBackground->green >> 8; mainprog_ptr->bg_blue = pBackground->blue >> 8; } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
int main(int argc, char *argv[]) { setlocale(LC_ALL, ""); setvbuf(stdout, (char*)NULL, _IONBF, 0); if(argc != 4) { fprintf(stderr, MSG[I_HELP1], argv[0]); fputs(MSG[I_HELP2], stderr); return EXIT_FAILURE; } char *inname = argv[1], *outname = argv[2], *valarg = argv[3]; /* Quelldatei oeffnen und auf PNG-Signatur ueberpruefen **********************/ puts(MSG[I_OPEN]); FILE *f; f = fopen(inname, "rb"); if (f == NULL) { fputs(inname, stderr); fputs(MSG[E_OPEN], stderr); fputc('\n', stderr); return EXIT_FAILURE; } unsigned char sig[SIG_BYTES]; fread(sig, 1, SIG_BYTES, f); if (png_sig_cmp(sig, 0, SIG_BYTES)) { fputs(inname, stderr); fputs(MSG[E_CORRUPTED], stderr); fputc('\n', stderr); fclose(f); return EXIT_FAILURE; } /* PNG-Lesevorgang initialisieren *****************************************/ png_struct *png_ptr; png_info *info_ptr, *end_info; png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL ); if (png_ptr == NULL) { fputs(MSG[E_GENERIC], stderr); fputc('\n', stderr); fclose(f); return EXIT_FAILURE; } info_ptr = png_create_info_struct(png_ptr); end_info = png_create_info_struct(png_ptr); try_png_read( (info_ptr == NULL) || (end_info == NULL), &png_ptr, &info_ptr, &end_info, f, (char*)NULL ); try_png_read( setjmp(png_jmpbuf(png_ptr)), &png_ptr, &info_ptr, &end_info, f, MSG[E_READ] ); png_init_io(png_ptr, f); png_set_sig_bytes(png_ptr, SIG_BYTES); /* Bildinfo lesen: Bilddimensionen und ggf. Farbpalette. * Palette ggf. konvertieren. *********************************************/ long int width, height, pwidth, pheight; // png_uint_32 width, height, pwidth, pheight; comp_t *image, **row, *rwp; png_read_info(png_ptr, info_ptr); width = info_ptr->width; height = info_ptr->height; const long int original_width = info_ptr->width; const int bit_depth = info_ptr->bit_depth, color_type = info_ptr->color_type; const bool image_is_pal = (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE); const bool image_is_gray = ( (color_type == PNG_COLOR_TYPE_GRAY) || (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ); const bool alpha = ( (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) || (color_type == PNG_COLOR_TYPE_RGB_ALPHA) ); int num_palette = 0; png_color *png_pal_got = NULL; if (image_is_pal) try_png_read( !png_get_PLTE(png_ptr, info_ptr, &png_pal_got, &num_palette), &png_ptr, &info_ptr, &end_info, f, MSG[E_READPAL] ); png_color png_pal[num_palette]; comp_t comp_pal[num_palette]; if (image_is_pal) for (int i = 0; i < num_palette; i++) { png_pal[i] = png_pal_got[i]; comp_t c; c = png_pal[i].red; c <<= CHAR_BIT; c |= png_pal[i].green; c <<= CHAR_BIT; c |= png_pal[i].blue; comp_pal[i] = c; } png_color_16 *img_bkgd; png_color_16 background; if (png_get_bKGD(png_ptr, info_ptr, &img_bkgd)) background = *img_bkgd; /* Parameter fuer Groessenaenderung auswerten: * diff: (Seitenlaenge nachher) - (Seitenlaenge vorher), * vert: true <=> Aenderung der Bildhoehe (sonst -breite). ******************/ long int diff; bool vert; bool aspp = false, asp2 = false, enlg = false, sign = true; switch (tolower(*valarg++)) { case 'h': vert = false; break; case 'v': vert = true; break; case '%': aspp = true; break; case '@': asp2 = true; break; default : try_png_read(true, &png_ptr, &info_ptr, &end_info, f, MSG[E_DIM]); } switch (*valarg) { case '+': enlg = true; break; case '-': enlg = false; break; default: sign = false; break; } diff = atol(valarg); bool valargok = !!diff; if (aspp || asp2) { try_png_read(!sign, &png_ptr, &info_ptr, &end_info, f, MSG[E_SIGN]); const float fheight = (float)height, fwidth = (float)width, casp = fheight / fwidth; float nasp; if (asp2) { const char *aspsw = strtok(valarg, ":"), *aspsh = strtok((char*)NULL, ":"); valargok = ((aspsw != NULL) && (aspsh != NULL)); const float aspw = valargok? atol(aspsw): 0, asph = valargok? atol(aspsh): 0; nasp = valargok? fabs(asph / aspw): 0; } else nasp = ((float)labs(diff) / 100.0f); vert = ((nasp < casp) ^ enlg); diff = valargok? labs(vert? (height - (fwidth * nasp)): (width - (fheight / nasp)) ): 0; if (!enlg) diff = -diff; } if (!diff) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(f); if (valargok) { puts(MSG[I_NOTHINGTODO]); // const char copycmd[] = "copy /b /y"; const char copycmd[] = "cp"; char copycmdln[ strlen(copycmd) + strlen(argv[1]) + strlen(argv[2]) + 7 ]; sprintf( copycmdln, "%s \"%s\" \"%s\"", copycmd, argv[1], argv[2] ); return system(copycmdln); } try_png_read(!valargok, &png_ptr, &info_ptr, &end_info, f, MSG[E_PAR]); } if (!(aspp || asp2 || sign)) diff -= vert? height: width; try_png_read( labs(diff) > (vert? height: width), &png_ptr, &info_ptr, &end_info, f, MSG[E_SIZE] ); /* Bild- sowie Zeilenzeigerspeicher anfordern und Zeiger setzen. **********/ image = malloc(width * height * sizeof(comp_t)); try_png_read(image == NULL, &png_ptr, &info_ptr, &end_info, f, (char*)NULL); row = malloc(height * sizeof(comp_t*)); try_png_read(row == NULL, &png_ptr, &info_ptr, &end_info, f, (char*)NULL); rwp = image; for (int i = 0; i < height; i++) { row[i] = rwp; rwp += width; } /* Bild laden. * Falls Alphakanal vorhanden, Alpha invertieren: hoher Wert => hohe Deckung. * Falls Nicht-Palettenbild ohne Alphakanal (24 bpp) oder Graubild * (8 oder 16 bpp), mit "png_set_filler" die Bilddaten auf 32 bzw. 16 bpp * ausweiten. 32 Bit ist die * comp_t-Breite. ****************************/ puts(MSG[I_LOAD]); if (alpha) png_set_invert_alpha(png_ptr); else if (!image_is_pal) png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); png_read_image(png_ptr, (void*)row); /* Falls 8 oder 16 bpp, Bilddaten auf "Pixel = comp_t-Element" ausweiten. */ // trw: Temporaere Zeile. void *trw = malloc(image_is_gray? (width * 2): width); try_png_read(trw == NULL, &png_ptr, &info_ptr, &end_info, f, (char*)NULL); // Zunaechst Bildzeile nach Temporaerzeile kopieren, dann Elemente einzeln zurueck. if (image_is_pal) { for (int i = 0; i < height; i++) { uint8_t *trwp = trw; rwp = row[i]; memcpy(trw, row[i], width * sizeof *trwp); for (int j = 0; j < width; j++) *rwp++ = *trwp++; } } if (image_is_gray) { for (int i = 0; i < height; i++) { uint16_t *trwp = trw; rwp = row[i]; memcpy(trw, row[i], width * sizeof *trwp); for (int j = 0; j < width; j++) *rwp++ = *trwp++; } } /* Lesevorgang beenden und Quelldatei schliessen. ************************/ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(f); printf( "%s: %d*%d > %d*%d: %s %+d\n", MSG[I_MEASURES], width, height, vert? width: width + diff, vert? height + diff: height, vert? MSG[I_VERT]: MSG[I_HORI], diff ); /* Hier kommt Fugenschnitzer zum Einsatz. * diff: (Seitenlaenge nachher) - (Seitenlaenge vorher), * vert: true <=> Aenderung der Bildhoehe (sonst -breite). ****************/ sc_init(); sc_load(image, &width, &height, 0); const int prep = sc_prepare( vert, diff, // Bild ggf. erweitern false, alpha? MARK_ALPHA: MARK_KEEP, // Ggf. Alpha-Markierung (mark_t*)NULL, // keine Markierung sonst &width, &height, &pwidth, &pheight ); if (prep < 0) { fputs(MSG[E_GENERIC], stderr); fputc('\n', stderr); free(image); free(row); return EXIT_FAILURE; } if (prep & 2) puts(MSG[E_ALPHA]); // Bildspeicher erweitern, falls das Bild vergroessert wurde: if (prep & 1) { image = realloc(image, (size_t)width * (size_t)height * sizeof(comp_t)); if (image == NULL) { fputs(MSG[E_GENERIC], stderr); fputc('\n', stderr); return EXIT_FAILURE; } if (vert) { row = realloc(row, (size_t)height * sizeof(comp_t*)); if (row == NULL) { fputs(MSG[E_GENERIC], stderr); fputc('\n', stderr); free(image); return EXIT_FAILURE; } } } pthread_t seam_th; pthread_create(&seam_th, NULL, seam_progress, (void*)(&diff)); // sc_seam(diff); seam_paral(diff); pthread_join(seam_th, NULL); putchar('\n'); printf(MSG[I_RESIZING]); // sc_carve(diff, &width, &height, &pwidth, &pheight); carve_paral(diff, &width, &height, &pwidth, &pheight); sc_fix( false, // Nicht wiederherstellen &width, &height, &pwidth, &pheight ); sc_eject(image); sc_close(); /* Das war's mit Fugenschnitzer. -- Zeilenzeiger neu setzen. **************/ rwp = image; for (int i = 0; i < height; i++) { row[i] = rwp; rwp += width; } /* Zieldatei oeffnen und Schreibvorgang initialisieren. ********************/ putchar('\n'); printf(MSG[I_SAVE]); f = fopen(outname, "wb"); if (f == NULL) { fputs(outname, stderr); fputs(MSG[E_SAVE], stderr); fputc('\n', stderr); return EXIT_FAILURE; } png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL ); if (png_ptr == NULL) { fputs(MSG[E_GENERIC], stderr); fputc('\n', stderr); fclose(f); return EXIT_FAILURE; } info_ptr = png_create_info_struct(png_ptr); try_png_write(info_ptr == NULL, &png_ptr, &info_ptr, f, (char*)NULL); try_png_write( setjmp(png_jmpbuf(png_ptr)), &png_ptr, &info_ptr, f, MSG[E_WRITE] ); png_init_io(png_ptr, f); /* Bildparameter setzen. **************************************************/ png_set_IHDR( png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); if (image_is_pal) png_set_PLTE(png_ptr, info_ptr, png_pal, num_palette); if (alpha) png_set_bKGD(png_ptr, info_ptr, &background); png_write_info(png_ptr, info_ptr); /* Falls 8 oder 16 bpp, Bilddaten wieder zusammenschieben. ****************/ trw = realloc(trw, image_is_gray? (width * 2): width); try_png_write(trw == NULL, &png_ptr, &info_ptr, f, (char*)NULL); if (image_is_pal) { for (int i = 0; i < height; i++) { uint8_t *trwp = trw; rwp = row[i]; for (int j = 0; j < width; j++) *trwp++ = *rwp++; memcpy(row[i], trw, width * sizeof *trwp); } } if (image_is_gray) { for (int i = 0; i < height; i++) { uint16_t *trwp = trw; rwp = row[i]; for (int j = 0; j < width; j++) *trwp++ = *rwp++; memcpy(row[i], trw, width * sizeof *trwp); } } /* Bild speichern. Wieder Alpha invertieren (hoher Wert => hohe Transparenz) * sowie mit "png_set_filler" 32/16 bpp => 24/8 bpp setzen. ***************/ if (alpha) png_set_invert_alpha(png_ptr); else png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); png_write_image(png_ptr, (void*)row); png_write_end(png_ptr, (png_info*)NULL); puts(MSG[I_FINISHED]); /* Schreibvorgang beenden, Datei schliessen, Speicher freigeben, fertig. ***/ png_destroy_write_struct(&png_ptr, &info_ptr); fclose(f); free(trw); free(image); free(row); puts(MSG[I_COMPLETED]); return EXIT_SUCCESS; }
/* ReadPNG - Reads the contents of a PNG file and stores the contents into BMGImageStruct Inputs: filename - the name of the file to be opened Outputs: img - the BMGImageStruct containing the image data Returns: BMGError - if the file could not be read or a resource error occurred BMG_OK - if the file was read and the data was stored in img Limitations: None. Comments: 2-bit images are converted to 4-bit images. 16-bit images are converted to 8-bit images. gray scale images with alpha components are converted to 32-bit images */ BMGError ReadPNG( const char *filename, struct BMGImageStruct * volatile img ) { jmp_buf err_jmp; int error; FILE * volatile file = NULL; int BitDepth; int ColorType; int InterlaceType; unsigned char signature[8]; png_structp volatile png_ptr = NULL; png_infop volatile info_ptr = NULL; png_infop volatile end_info = NULL; png_color_16 *ImageBackground = NULL; png_bytep trns = NULL; int NumTrans = 0; int i, k; png_color_16p TransColors = NULL; png_uint_32 Width, Height; unsigned char *bits; unsigned char** volatile rows = NULL; BMGError tmp; /* error handler */ error = setjmp( err_jmp ); if (error != 0) { if (end_info != NULL) png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info); else if (info_ptr != NULL) png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, NULL); else if (png_ptr != NULL) png_destroy_read_struct((png_structp *) &png_ptr, NULL, NULL); if (rows) { if (rows[0]) free(rows[0]); free(rows); } if (img) FreeBMGImage(img); if (file) fclose(file); SetLastBMGError((BMGError) error); return (BMGError) error; } if ( img == NULL ) longjmp ( err_jmp, (int)errInvalidBMGImage ); file = fopen( filename, "rb" ); if ( !file || fread( signature, 1, 8, file ) != 8) longjmp ( err_jmp, (int)errFileOpen ); /* check the signature */ if ( png_sig_cmp( signature, 0, 8 ) != 0 ) longjmp( err_jmp, (int)errUnsupportedFileFormat ); /* create a pointer to the png read structure */ png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ); if ( !png_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* create a pointer to the png info structure */ info_ptr = png_create_info_struct( png_ptr ); if ( !info_ptr ) longjmp( err_jmp, (int)errMemoryAllocation ); /* create a pointer to the png end-info structure */ end_info = png_create_info_struct(png_ptr); if (!end_info) longjmp( err_jmp, (int)errMemoryAllocation ); /* bamboozle the PNG longjmp buffer */ /*generic PNG error handler*/ /* error will always == 1 which == errLib */ // error = png_setjmp(png_ptr); error = setjmp( png_jmpbuf( png_ptr ) ); if ( error > 0 ) longjmp( err_jmp, error ); /* set function pointers in the PNG library, for read callbacks */ png_set_read_fn(png_ptr, (png_voidp) file, user_read_data); /*let the read functions know that we have already read the 1st 8 bytes */ png_set_sig_bytes( png_ptr, 8 ); /* read all PNG data up to the image data */ png_read_info( png_ptr, info_ptr ); /* extract the data we need to form the HBITMAP from the PNG header */ png_get_IHDR( png_ptr, info_ptr, &Width, &Height, &BitDepth, &ColorType, &InterlaceType, NULL, NULL); img->width = (unsigned int) Width; img->height = (unsigned int) Height; img->bits_per_pixel = (unsigned char)32; img->scan_width = Width * 4; /* convert 16-bit images to 8-bit images */ if (BitDepth == 16) png_set_strip_16(png_ptr); /* These are not really required per Rice format spec, * but is done just in case someone uses them. */ /* convert palette color to rgb color */ if (ColorType == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); ColorType = PNG_COLOR_TYPE_RGB; } /* expand 1,2,4 bit gray scale to 8 bit gray scale */ if (ColorType == PNG_COLOR_TYPE_GRAY && BitDepth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); /* convert gray scale or gray scale + alpha to rgb color */ if (ColorType == PNG_COLOR_TYPE_GRAY || ColorType == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); ColorType = PNG_COLOR_TYPE_RGB; } /* add alpha channel if any */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); ColorType = PNG_COLOR_TYPE_RGB_ALPHA; } /* convert rgb to rgba */ if (ColorType == PNG_COLOR_TYPE_RGB) { png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); ColorType = PNG_COLOR_TYPE_RGB_ALPHA; } png_set_bgr(png_ptr); /* set the background color if one is found */ if ( png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD) ) png_get_bKGD(png_ptr, info_ptr, &ImageBackground); /* get the transparent color if one is there */ if ( png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ) ) png_get_tRNS( png_ptr, info_ptr, &trns, &NumTrans, &TransColors ); img->palette_size = (unsigned short)0; img->bytes_per_palette_entry = 4U; tmp = AllocateBMGImage( img ); if ( tmp != BMG_OK ) longjmp( err_jmp, (int)tmp ); png_read_update_info( png_ptr, info_ptr ); /* create buffer to read data to */ rows = (unsigned char **)malloc(Height*sizeof(unsigned char *)); if ( !rows ) longjmp( err_jmp, (int)errMemoryAllocation ); k = png_get_rowbytes( png_ptr, info_ptr ); rows[0] = (unsigned char *)malloc( Height*k*sizeof(char)); if ( !rows[0] ) longjmp( err_jmp, (int)errMemoryAllocation ); for ( i = 1; i < (int)Height; i++ ) rows[i] = rows[i-1] + k; /* read the entire image into rows */ png_read_image( png_ptr, rows ); bits = img->bits + (Height - 1) * img->scan_width; for ( i = 0; i < (int)Height; i++ ) { memcpy(bits, rows[i], 4*Width); bits -= img->scan_width; } free( rows[0] ); free( rows ); png_read_end( png_ptr, info_ptr ); png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info); fclose( file ); return BMG_OK; }
int PNGDIB_DECL pngdib_p2d_run(PNGDIB *qq) { struct p2d_struct *p2d; png_structp png_ptr; png_infop info_ptr; jmp_buf jbuf; struct errstruct errinfo; png_uint_32 width, height; int png_bit_depth, color_type, interlace_type; png_colorp png_palette; png_uint_32 res_x, res_y; int has_phys, has_gama; int res_unit_type; FILE *fp; int palette_entries; unsigned char **row_pointers; unsigned char *lpdib; unsigned char *dib_palette; unsigned char *dib_bits; unsigned char *tmprow; int dib_bpp, dib_bytesperrow; int i,j; int rv; png_color_16 bkgd; // used with png_set_background int has_trns, trns_color; int has_bkgd; // ==1 if there a bkgd chunk, and USE_BKGD flag png_color_16p temp_colorp; png_color_16p bg_colorp; // background color (if has_bkgd) png_bytep trns_trans; int manual_trns; int manual_gamma; struct PNGD_COLOR_struct bkgd_color; int is_grayscale,has_alpha_channel; double file_gamma; int dib_alpha32; int write_bitfields; p2d=(struct p2d_struct*)qq; dib_alpha32=0; write_bitfields=0; manual_trns=0; has_trns=has_bkgd=0; rv=PNGD_E_ERROR; png_ptr=NULL; info_ptr=NULL; fp=NULL; row_pointers=NULL; lpdib=NULL; StringCchCopy(p2d->common.errmsg,PNGDIB_ERRMSG_MAX,_T("")); if(p2d->use_custom_bg_flag) { bkgd_color.red= p2d->bgcolor.red; bkgd_color.green= p2d->bgcolor.green; bkgd_color.blue= p2d->bgcolor.blue; } else { bkgd_color.red= 255; // Should never get used. If the bkgd_color.green= 128; // background turns orange, it's a bug. bkgd_color.blue= 0; } // Set the user-defined pointer to point to our jmp_buf. This will // hopefully protect against potentially different sized jmp_buf's in // libpng, while still allowing this library to be threadsafe. errinfo.jbufp = &jbuf; errinfo.errmsg = p2d->common.errmsg; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,(void*)(&errinfo), my_png_error_fn, my_png_warning_fn); if(!png_ptr) { rv=PNGD_E_NOMEM; goto abort; } if(p2d->common.pngptrhook_function) { (*(p2d->common.pngptrhook_function))(p2d->common.userdata,(void*)png_ptr); } info_ptr = png_create_info_struct(png_ptr); if(!info_ptr) { //png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); rv=PNGD_E_NOMEM; goto abort; } if(setjmp(jbuf)) { // we'll get here if an error occurred in any of the following // png_ functions rv=PNGD_E_LIBPNG; goto abort; } if(p2d->input_method==PNGD_IO_METHOD_FILENAME) { // reading from a filename if(!p2d->input_filename) { StringCchPrintf(p2d->common.errmsg,PNGDIB_ERRMSG_MAX,_T("Input filename not set")); rv=PNGD_E_ERROR; goto abort; } if((fp = _tfopen(p2d->input_filename,_T("rb"))) == NULL) { rv=PNGD_E_READ; goto abort; } png_init_io(png_ptr, fp); } else if(p2d->input_method==PNGD_IO_METHOD_MEMBLK) { // reading from a memory block p2d->input_memblk_curpos=0; png_set_read_fn(png_ptr, (void*)p2d, my_png_read_fn); } else if(p2d->input_method==PNGD_IO_METHOD_CUSTOM) { png_set_read_fn(png_ptr, (void*)p2d, my_png_read_fn_custom); } else { goto abort; } png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &png_bit_depth, &color_type, &interlace_type, NULL, NULL); p2d->color_type=color_type; p2d->bits_per_sample=png_bit_depth; p2d->interlace=interlace_type; switch(color_type) { case PNG_COLOR_TYPE_RGB: p2d->bits_per_pixel=png_bit_depth*3; break; case PNG_COLOR_TYPE_RGB_ALPHA: p2d->bits_per_pixel=png_bit_depth*4; break; case PNG_COLOR_TYPE_GRAY_ALPHA: p2d->bits_per_pixel=png_bit_depth*2; break; default: p2d->bits_per_pixel=png_bit_depth; } is_grayscale = !(color_type&PNG_COLOR_MASK_COLOR); has_alpha_channel = (color_type&PNG_COLOR_MASK_ALPHA)?1:0; has_trns = png_get_valid(png_ptr,info_ptr,PNG_INFO_tRNS); if(p2d->common.dib_alpha32 && (has_trns || has_alpha_channel)) { // Fixme - if trns(for palette) has no transparent entries, // we could skip this. dib_alpha32=1; write_bitfields=1; if (!(color_type&PNG_COLOR_MASK_COLOR)) { png_set_gray_to_rgb(png_ptr); } else if(color_type==PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } if (has_trns) png_set_tRNS_to_alpha(png_ptr); goto notrans; } // look for bKGD chunk, and process if applicable if(p2d->use_file_bg_flag) { if(png_get_bKGD(png_ptr, info_ptr, &bg_colorp)) { // process the background, store 8-bit RGB in bkgd_color has_bkgd=1; if(is_grayscale && png_bit_depth<8) { bkgd_color.red = bkgd_color.green= bkgd_color.blue = (unsigned char) ( (bg_colorp->gray*255)/( (1<<png_bit_depth)-1 ) ); } else if(png_bit_depth<=8) { bkgd_color.red=(unsigned char)(bg_colorp->red); bkgd_color.green=(unsigned char)(bg_colorp->green); bkgd_color.blue =(unsigned char)(bg_colorp->blue); } else { bkgd_color.red=(unsigned char)(bg_colorp->red>>8); bkgd_color.green=(unsigned char)(bg_colorp->green>>8); bkgd_color.blue =(unsigned char)(bg_colorp->blue>>8); } } }
int png_read(struct image *img){ unsigned int y; png_bytepp row_pointers; struct png_t *p = (struct png_t *)img; if(setjmp(png_jmpbuf(p->png_ptr))){ png_destroy_read_struct(&p->png_ptr, &p->info_ptr, &p->end_info); return 1; } { int color_type = png_get_color_type(p->png_ptr, p->info_ptr); int bit_depth = png_get_bit_depth(p->png_ptr, p->info_ptr); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(p->png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(p->png_ptr); if (png_get_valid(p->png_ptr, p->info_ptr, PNG_INFO_tRNS)) png_set_expand(p->png_ptr); if (bit_depth == 16) png_set_strip_16(p->png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(p->png_ptr); //png_set_strip_alpha(p->png_ptr); png_color_16 my_background = {.red = 0xff, .green = 0xff, .blue = 0xff}; png_color_16p image_background; if(png_get_bKGD(p->png_ptr, p->info_ptr, &image_background)) png_set_background(p->png_ptr, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); else png_set_background(p->png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 2, 1.0); if(png_get_interlace_type(p->png_ptr, p->info_ptr) == PNG_INTERLACE_ADAM7) p->numpasses = png_set_interlace_handling(p->png_ptr); else p->numpasses = 1; png_read_update_info(p->png_ptr, p->info_ptr); } row_pointers = (png_bytepp)malloc(img->bufheight * sizeof(png_bytep)); for(y = 0; y < img->bufheight; y++) row_pointers[y] = img->buf + y * img->bufwidth * 3; png_read_image(p->png_ptr, row_pointers); free(row_pointers); img->state |= LOADED | SLOWLOADED; return 0; } void png_close(struct image *img){ struct png_t *p = (struct png_t *)img; png_destroy_read_struct(&p->png_ptr, &p->info_ptr, &p->end_info); fclose(p->f); } struct imageformat libpng = { png_open, NULL, png_read, png_close };
int read_PNG(char *file_name) { /* * Took this code from doc/fblib * and adjusted it to the likings * of this program. * ?i * It is really awesome that a NOOB * like me, Noisegate can actually * make useable software on an open * system like this Linux... * * openSOFtWARE rocKS */ png_structp png_ptr; png_infop info_ptr; unsigned int sig_read = 0; png_uint_32 _width, _height, row; int bit_depth, color_type, interlace_type; FILE *fp; float screen_gamma; if ((fp = fopen(file_name, "rb")) == NULL) return -1; /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also supply the * the compiler header file version, so that we know if the application * was compiled with a compatible version of the library. REQUIRED */ //png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp user_error_ptr, user_error_fn, user_warning_fn); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL); if (png_ptr == NULL){ fclose(fp); return -1; } /* Allocate/initialize the memory for image information. REQUIRED. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(fp); png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); return -1; } /* Set error handling if you are using the setjmp/longjmp method (this is * the normal method of doing things with libpng). REQUIRED unless you * set up your own error handlers in the png_create_read_struct() earlier. */ if (setjmp(png_jmpbuf(png_ptr))) { /* Free all of the memory associated with the png_ptr and info_ptr */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); fclose(fp); /* If we get here, we had a problem reading the file */ fprintf(stderr, "Error: Couldn't read the file."); return -1; } /* One of the following I/O initialization methods is REQUIRED */ /* Set up the input control if you are using standard C streams */ png_init_io(png_ptr, fp); /* If we have already read some of the signature */ png_set_sig_bytes(png_ptr, sig_read); /* OK, you're doing it the hard way, with the lower-level functions */ /* The call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). REQUIRED */ png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &_width, &_height, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL); /* Set up the data transformations you want. Note that these are all * optional. Only call them if you want/need them. Many of the * transformations only work on specific types of images, and many * are mutually exclusive. */ /* Tell libpng to strip 16 bit/color files down to 8 bits/color */ png_set_strip_16(png_ptr); /* Strip alpha bytes from the input data without combining with the * background (not recommended). */ //png_set_strip_alpha(png_ptr); /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ png_set_packing(png_ptr); /* Change the order of packed pixels to least significant bit first * (not useful if you are using png_set_packing). */ png_set_packswap(png_ptr); /* Expand paletted colors into true RGB triplets */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); /* Expand paletted or RGB images with transparency to full alpha channels * so the data will be available as RGBA quartets. */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); /* Set the background color to draw transparent and alpha images over. * It is possible to set the red, green, and blue components directly * for paletted images instead of supplying a palette index. Note that * even if the PNG file supplies a background, you are not required to * use it - you should use the (solid) application background if it has one. */ png_color_16 my_background, *image_background; if (png_get_bKGD(png_ptr, info_ptr, &image_background)) png_set_background(png_ptr, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); else png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); screen_gamma = 1.0; int intent; if (png_get_sRGB(png_ptr, info_ptr, &intent)) png_set_gamma(png_ptr, screen_gamma, 0.45455); else { double image_gamma; if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) png_set_gamma(png_ptr, screen_gamma, image_gamma); else png_set_gamma(png_ptr, screen_gamma, 0.45455); } /* Invert monochrome files to have 0 as white and 1 as black */ png_set_invert_mono(png_ptr); /* If you want to shift the pixel values from the range [0,255] or * [0,65535] to the original [0,7] or [0,31], or whatever range the * colors were originally in: */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) { png_color_8p sig_bit_p; png_get_sBIT(png_ptr, info_ptr, &sig_bit_p); png_set_shift(png_ptr, sig_bit_p); } /* Flip the RGB pixels to BGR (or RGBA to BGRA) */ if (color_type & PNG_COLOR_MASK_COLOR) png_set_bgr(png_ptr); /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ png_set_swap_alpha(png_ptr); /* Swap bytes of 16 bit files to least significant byte first */ png_set_swap(png_ptr); /* Add filler (or alpha) byte (before/after each RGB triplet) */ png_set_filler(png_ptr, 0x00, PNG_FILLER_AFTER); /* Turn on interlace handling. REQUIRED if you are not using * png_read_image(). To see how to handle interlacing passes, * see the png_read_row() method below: */ //number_passes = png_set_interlace_handling(png_ptr); /* Optional call to gamma correct and add the background to the palette * and update info structure. REQUIRED if you are expecting libpng to * update the palette for you (ie you selected such a transform above). */ png_read_update_info(png_ptr, info_ptr); /* Allocate the memory to hold the image using the fields of info_ptr. */ /* The easiest way to read the image: */ png_bytep row_pointers[_height]; /* Clear the pointer array */ for (row = 0; row < _height; row++) row_pointers[row] = NULL; for (row = 0; row < _height; row++) row_pointers[row] = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); /* Now it's time to read the image. One of these methods is REQUIRED */ png_read_image(png_ptr, row_pointers); /* Now mess this rowpointer thing into the tmp_buf * U dont know if width>_width and height>_height * so we trunc the guy */ int maxY = _height>height?height:_height; int maxX = _width>width?finfo.line_length:_width; int pix_offset=0; for (row=0; row<maxY;row++){ pix_offset = Ox*BPP + ((Oy+row)*finfo.line_length); memcpy(tmp_buf+pix_offset, row_pointers[row], maxX*BPP); } /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); /* At this point you have read the entire image */ /* Clean up after the read, and free any memory allocated - REQUIRED */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); /* Close the file */ fclose(fp); //printf("png W x H = %i x %i\n", _width, _height); /* That's it */ return 0; }
/* * Reduce the image type from grayscale(+alpha) or RGB(+alpha) to palette, * if possible. * The parameter reductions indicates the intended reductions. * The function returns the successful reductions. */ static png_uint_32 opng_reduce_to_palette(png_structp png_ptr, png_infop info_ptr, png_uint_32 reductions) { png_row_info row_info; png_bytep sample_ptr; png_uint_32 height, width; int color_type, interlace_type, compression_type, filter_type; int src_bit_depth; png_color palette[256]; png_byte trans_alpha[256]; int num_trans, index; unsigned gray, red, green, blue, alpha; unsigned prev_red, prev_green, prev_blue, prev_alpha; png_uint_32 j; png_get_IHDR(png_ptr, info_ptr, &width, &height, &src_bit_depth, &color_type, &interlace_type, &compression_type, &filter_type); if (src_bit_depth != 8 || !height || !width) return OPNG_REDUCE_NONE; /* nothing is done in this case */ OPNG_ASSERT(!(color_type & PNG_COLOR_MASK_PALETTE)); png_bytepp row_ptr = png_get_rows(png_ptr, info_ptr); int channels = png_get_channels(png_ptr, info_ptr); png_bytep alpha_row = (png_bytep)png_malloc(png_ptr, width); if (!alpha_row){ exit(1); } row_info.width = width; row_info.rowbytes = 0; /* not used */ row_info.color_type = (png_byte)color_type; row_info.bit_depth = (png_byte)src_bit_depth; row_info.channels = (png_byte)channels; row_info.pixel_depth = 0; /* not used */ /* Analyze the possibility of this reduction. */ int num_palette = num_trans = 0; png_color_16p trans_color = 0; png_get_tRNS(png_ptr, info_ptr, 0, 0, &trans_color); unsigned prev_gray = prev_red = prev_green = prev_blue = prev_alpha = 256; png_uint_32 i; for (i = 0; i < height; ++i, ++row_ptr) { sample_ptr = *row_ptr; opng_get_alpha_row(&row_info, trans_color, *row_ptr, alpha_row); if (color_type & PNG_COLOR_MASK_COLOR) { for (j = 0; j < width; ++j, sample_ptr += channels) { red = sample_ptr[0]; green = sample_ptr[1]; blue = sample_ptr[2]; alpha = alpha_row[j]; /* Check the cache first. */ if (red != prev_red || green != prev_green || blue != prev_blue || alpha != prev_alpha) { prev_red = red; prev_green = green; prev_blue = blue; prev_alpha = alpha; if (opng_insert_palette_entry(palette, &num_palette, trans_alpha, &num_trans, 256, red, green, blue, alpha, &index) < 0) /* overflow */ { OPNG_ASSERT(num_palette < 0); i = height; /* forced exit from outer loop */ break; } } } } else /* grayscale */ { for (j = 0; j < width; ++j, sample_ptr += channels) { gray = sample_ptr[0]; alpha = alpha_row[j]; /* Check the cache first. */ if (gray != prev_gray || alpha != prev_alpha) { prev_gray = gray; prev_alpha = alpha; if (opng_insert_palette_entry(palette, &num_palette, trans_alpha, &num_trans, 256, gray, gray, gray, alpha, &index) < 0) /* overflow */ { OPNG_ASSERT(num_palette < 0); i = height; /* forced exit from outer loop */ break; } } } } } #ifdef PNG_bKGD_SUPPORTED png_color_16p background; if ((num_palette >= 0) && png_get_bKGD(png_ptr, info_ptr, &background)) { /* bKGD has an alpha-agnostic palette entry. */ if (color_type & PNG_COLOR_MASK_COLOR) { red = background->red; green = background->green; blue = background->blue; } else red = green = blue = background->gray; opng_insert_palette_entry(palette, &num_palette, trans_alpha, &num_trans, 256, red, green, blue, 256, &index); if (index >= 0) background->index = (png_byte)index; } #endif /* Continue only if the uncompressed indexed image (pixels + PLTE + tRNS) * is smaller than the uncompressed RGB(A) image. * Casual overhead (headers, CRCs, etc.) is ignored. * * Compare: * num_pixels * (src_bit_depth * channels - dest_bit_depth) / 8 * vs. * sizeof(PLTE) + sizeof(tRNS) */ /* 5/3 times sizeof(PLTE) + sizeof(tRNS) as: 1. Palette is uncompressed additional IDAT data is 2. Headers */ if (num_palette >= 0) { int dest_bit_depth; OPNG_ASSERT(num_palette > 0 && num_palette <= 256); OPNG_ASSERT(num_trans >= 0 && num_trans <= num_palette); if (num_palette <= 2) dest_bit_depth = 1; else if (num_palette <= 4) dest_bit_depth = 2; else if (num_palette <= 16) dest_bit_depth = 4; else dest_bit_depth = 8; /* Do the comparison in a way that does not cause overflow. */ /*if (channels * 8 == dest_bit_depth || (3 * num_palette + num_trans) * 8 / (channels * 8 - dest_bit_depth) / width / height >= 1) */ if (channels * 8 == dest_bit_depth || (12 + (5 * num_palette + num_trans)) * 8 / (channels * 8 - dest_bit_depth) / width / height >= 1) {num_palette = -1;} if ((num_palette && width * height < 12u * num_palette) || width * height < 8000){ num_palette = -1; } } if (num_palette < 0) /* can't reduce */ { png_free(png_ptr, alpha_row); return OPNG_REDUCE_NONE; } /* Reduce. */ row_ptr = png_get_rows(png_ptr, info_ptr); index = -1; prev_red = prev_green = prev_blue = prev_alpha = (unsigned int)(-1); for (i = 0; i < height; ++i, ++row_ptr) { sample_ptr = *row_ptr; opng_get_alpha_row(&row_info, trans_color, *row_ptr, alpha_row); if (color_type & PNG_COLOR_MASK_COLOR) { for (j = 0; j < width; ++j, sample_ptr += channels) { red = sample_ptr[0]; green = sample_ptr[1]; blue = sample_ptr[2]; alpha = alpha_row[j]; /* Check the cache first. */ if (red != prev_red || green != prev_green || blue != prev_blue || alpha != prev_alpha) { prev_red = red; prev_green = green; prev_blue = blue; prev_alpha = alpha; if (opng_insert_palette_entry(palette, &num_palette, trans_alpha, &num_trans, 256, red, green, blue, alpha, &index) != 0) index = -1; /* this should not happen */ } OPNG_ASSERT(index >= 0); (*row_ptr)[j] = (png_byte)index; } } else /* grayscale */ { for (j = 0; j < width; ++j, sample_ptr += channels) { gray = sample_ptr[0]; alpha = alpha_row[j]; /* Check the cache first. */ if (gray != prev_gray || alpha != prev_alpha) { prev_gray = gray; prev_alpha = alpha; if (opng_insert_palette_entry(palette, &num_palette, trans_alpha, &num_trans, 256, gray, gray, gray, alpha, &index) != 0) index = -1; /* this should not happen */ } OPNG_ASSERT(index >= 0); (*row_ptr)[j] = (png_byte)index; } } } /* Update the image information. */ png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_PALETTE, interlace_type, compression_type, filter_type); png_set_PLTE(png_ptr, info_ptr, palette, num_palette); if (num_trans > 0) png_set_tRNS(png_ptr, info_ptr, trans_alpha, num_trans, 0); /* bKGD (if present) is automatically updated. */ png_free(png_ptr, alpha_row); png_uint_32 result = OPNG_REDUCE_RGB_TO_PALETTE; if (reductions & OPNG_REDUCE_8_TO_4_2_1) result |= opng_reduce_palette_bits(png_ptr, info_ptr, reductions); return result; }
static RGBAImagePtr LoadPNGBuff (unsigned char* fbuffer) { png_byte** row_pointers; png_bytep p_fbuffer; p_fbuffer = fbuffer; // the reading glue // http://www.libpng.org/pub/png/libpng-manual.html png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, user_error_fn, user_warning_fn); if (!png_ptr) { rError() << "libpng error: png_create_read_struct\n"; return RGBAImagePtr(); } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); rError() << "libpng error: png_create_info_struct (info_ptr)" << std::endl; return RGBAImagePtr(); } png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); rError() << "libpng error: png_create_info_struct (end_info)" << std::endl; return RGBAImagePtr(); } // configure the read function png_set_read_fn(png_ptr, (png_voidp)&p_fbuffer, (png_rw_ptr)&user_read_data); if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return RGBAImagePtr(); } png_read_info(png_ptr, info_ptr); int bit_depth = png_get_bit_depth(png_ptr, info_ptr); int color_type = png_get_color_type(png_ptr, info_ptr); // we want to treat all images the same way // The following code transforms grayscale images of less than 8 to 8 bits, // changes paletted images to RGB, and adds a full alpha channel if there is // transparency information in a tRNS chunk. if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { #if PNG_LIBPNG_VER < 10400 png_set_gray_1_2_4_to_8(png_ptr); #else png_set_expand_gray_1_2_4_to_8(png_ptr); #endif } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); } if (!(color_type & PNG_COLOR_MASK_ALPHA)) { // Set the background color to draw transparent and alpha images over. png_color_16 my_background, *image_background; if (png_get_bKGD(png_ptr, info_ptr, &image_background)) { png_set_background(png_ptr, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); } else { png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); } // Add alpha byte after each RGB triplet png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); } // read the sucker in one chunk png_read_update_info(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); int width = png_get_image_width(png_ptr, info_ptr); int height = png_get_image_height(png_ptr, info_ptr); // allocate the pixel buffer, and the row pointers RGBAImagePtr image(new RGBAImage(width, height)); row_pointers = (png_byte**) malloc((height) * sizeof(png_byte*)); for (int i = 0; i < height; i++) { row_pointers[i] = (png_byte*)(image->getMipMapPixels(0)) + i * 4 * (width); } // actual read png_read_image(png_ptr, row_pointers); /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); /* free up the memory structure */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); free(row_pointers); return image; }
static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_uint_32 width, height; int color_type; int bit_depth; int pixel_depth = 0; // pixel_depth = bit_depth * channels FIBITMAP *dib = NULL; png_bytepp row_pointers = NULL; fi_ioStructure fio; fio.s_handle = handle; fio.s_io = io; if (handle) { BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS; try { // check to see if the file is in fact a PNG file BYTE png_check[PNG_BYTES_TO_CHECK]; io->read_proc(png_check, PNG_BYTES_TO_CHECK, 1, handle); if (png_sig_cmp(png_check, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0) { return NULL; // Bad signature } // create the chunk manage structure png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, error_handler, warning_handler); if (!png_ptr) { return NULL; } // create the info structure info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return NULL; } // init the IO png_set_read_fn(png_ptr, &fio, _ReadProc); if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } // because we have already read the signature... png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); // read the IHDR chunk png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); // configure the decoder FREE_IMAGE_TYPE image_type = FIT_BITMAP; if(!ConfigureDecoder(png_ptr, info_ptr, flags, &image_type)) { throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; } // update image info color_type = png_get_color_type(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); pixel_depth = bit_depth * png_get_channels(png_ptr, info_ptr); // create a dib and write the bitmap header // set up the dib palette, if needed switch (color_type) { case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); break; case PNG_COLOR_TYPE_PALETTE: dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); if(dib) { png_colorp png_palette = NULL; int palette_entries = 0; png_get_PLTE(png_ptr,info_ptr, &png_palette, &palette_entries); palette_entries = MIN((unsigned)palette_entries, FreeImage_GetColorsUsed(dib)); // store the palette RGBQUAD *palette = FreeImage_GetPalette(dib); for(int i = 0; i < palette_entries; i++) { palette[i].rgbRed = png_palette[i].red; palette[i].rgbGreen = png_palette[i].green; palette[i].rgbBlue = png_palette[i].blue; } } break; case PNG_COLOR_TYPE_GRAY: dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); if(dib && (pixel_depth <= 8)) { RGBQUAD *palette = FreeImage_GetPalette(dib); const int palette_entries = 1 << pixel_depth; for(int i = 0; i < palette_entries; i++) { palette[i].rgbRed = palette[i].rgbGreen = palette[i].rgbBlue = (BYTE)((i * 255) / (palette_entries - 1)); } } break; default: throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; } if(!dib) { throw FI_MSG_ERROR_DIB_MEMORY; } // store the transparency table if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { // array of alpha (transparency) entries for palette png_bytep trans_alpha = NULL; // number of transparent entries int num_trans = 0; // graylevel or color sample values of the single transparent color for non-paletted images png_color_16p trans_color = NULL; png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color); if((color_type == PNG_COLOR_TYPE_GRAY) && trans_color) { // single transparent color if (trans_color->gray < 256) { BYTE table[256]; memset(table, 0xFF, 256); table[trans_color->gray] = 0; FreeImage_SetTransparencyTable(dib, table, 256); } // check for a full transparency table, too else if ((trans_alpha) && (pixel_depth <= 8)) { FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans); } } else if((color_type == PNG_COLOR_TYPE_PALETTE) && trans_alpha) { // transparency table FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans); } } // store the background color (only supported for FIT_BITMAP types) if ((image_type == FIT_BITMAP) && png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) { // Get the background color to draw transparent and alpha images over. // Note that even if the PNG file supplies a background, you are not required to // use it - you should use the (solid) application background if it has one. png_color_16p image_background = NULL; RGBQUAD rgbBkColor; if (png_get_bKGD(png_ptr, info_ptr, &image_background)) { rgbBkColor.rgbRed = (BYTE)image_background->red; rgbBkColor.rgbGreen = (BYTE)image_background->green; rgbBkColor.rgbBlue = (BYTE)image_background->blue; rgbBkColor.rgbReserved = 0; FreeImage_SetBackgroundColor(dib, &rgbBkColor); } } // get physical resolution if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) { png_uint_32 res_x, res_y; // we'll overload this var and use 0 to mean no phys data, // since if it's not in meters we can't use it anyway int res_unit_type = PNG_RESOLUTION_UNKNOWN; png_get_pHYs(png_ptr,info_ptr, &res_x, &res_y, &res_unit_type); if (res_unit_type == PNG_RESOLUTION_METER) { FreeImage_SetDotsPerMeterX(dib, res_x); FreeImage_SetDotsPerMeterY(dib, res_y); } } // get possible ICC profile if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) { png_charp profile_name = NULL; png_bytep profile_data = NULL; png_uint_32 profile_length = 0; int compression_type; png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &profile_length); // copy ICC profile data (must be done after FreeImage_AllocateHeader) FreeImage_CreateICCProfile(dib, profile_data, profile_length); } // --- header only mode => clean-up and return if (header_only) { // get possible metadata (it can be located both before and after the image data) ReadMetadata(png_ptr, info_ptr, dib); if (png_ptr) { // clean up after the read, and free any memory allocated - REQUIRED png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } return dib; } // set the individual row_pointers to point at the correct offsets row_pointers = (png_bytepp)malloc(height * sizeof(png_bytep)); if (!row_pointers) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); FreeImage_Unload(dib); return NULL; } // read in the bitmap bits via the pointer table // allow loading of PNG with minor errors (such as images with several IDAT chunks) for (png_uint_32 k = 0; k < height; k++) { row_pointers[height - 1 - k] = FreeImage_GetScanLine(dib, k); } png_set_benign_errors(png_ptr, 1); png_read_image(png_ptr, row_pointers); // check if the bitmap contains transparency, if so enable it in the header if (FreeImage_GetBPP(dib) == 32) { if (FreeImage_GetColorType(dib) == FIC_RGBALPHA) { FreeImage_SetTransparent(dib, TRUE); } else { FreeImage_SetTransparent(dib, FALSE); } } // cleanup if (row_pointers) { free(row_pointers); row_pointers = NULL; } // read the rest of the file, getting any additional chunks in info_ptr png_read_end(png_ptr, info_ptr); // get possible metadata (it can be located both before and after the image data) ReadMetadata(png_ptr, info_ptr, dib); if (png_ptr) { // clean up after the read, and free any memory allocated - REQUIRED png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } return dib; } catch (const char *text) { if (png_ptr) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } if (row_pointers) { free(row_pointers); } if (dib) { FreeImage_Unload(dib); } FreeImage_OutputMessageProc(s_format_id, text); return NULL; } } return NULL; }
int main( int argc, char *argv[] ) { int f, rowbytes; char buf[256]; static FILE *fpout; /* "static" prevents setjmp corruption */ png_structp write_ptr; png_infop write_info_ptr, end_info_ptr; png_bytep row_buf, here; png_uint_32 y; png_textp text_ptr, new_text_ptr; int num_text; int interlace_type, compression_type, filter_type, bit_depth, color_type; int it, ct, ft, bd, clrt; png_uint_32 width, height, w, h; int duration; if( argc < 4 ) { printf( "makeanim v0.2\nusage: makeanim <duration in milliseconds> <input files ...> <output file>\n" ); printf( "example: makeanim 1500 a00.png a01.png a02.png a03.png a04.png a.anim\n" ); return 1; } duration = atoi( argv[1] ); if( duration < 1 ) { printf( "duration is incorrect\n" ); return 1; } numfiles = argc - 3; input = (struct inputstruct *)malloc( sizeof( struct inputstruct ) * numfiles ); if( !input ) return 1; for( f = 0; f < numfiles; f++ ) { input[f].name = argv[f + 2]; printf( "opening file %d, \"%s\"\n", f, input[f].name ); /* open the file handle */ input[f].file = fopen( input[f].name, "rb" ); if( input[f].file == NULL ) { printf( "fopen() failed\n" ); return 1; } /* check if it's PNG */ if( fread( buf, 1, 8, input[f].file ) != 8 ) { printf( "fread() failed for file \"%s\"\n", input[f].name ); return 1; } if( png_sig_cmp( buf, (png_size_t)0, 8 ) ) { printf( "not a PNG file\n" ); return 1; } fseek( input[f].file, 0, SEEK_SET ); /* allocate read structure */ input[f].read_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL ); if( input[f].read_ptr == NULL ) { printf( "png_create_read_struct() failed\n" ); return 1; } /* allocate read info structure */ input[f].read_info_ptr = png_create_info_struct( input[f].read_ptr ); if( input[f].read_info_ptr == NULL ) { printf( "png_create_info_struct() failed\n" ); return 1; } /* set error handler code */ if( setjmp( input[f].read_ptr->jmpbuf ) ) { printf( "libpng read error\n" ); return 1; } /* initialize stream */ png_init_io( input[f].read_ptr, input[f].file ); png_set_read_status_fn( input[f].read_ptr, NULL ); /* read png info struct */ png_read_info( input[f].read_ptr, input[f].read_info_ptr ); /* get the info */ if( !png_get_IHDR( input[f].read_ptr, input[f].read_info_ptr, &w, &h, &bd, &clrt, &it, &ct, &ft ) ) { printf( "png_get_IHDR() failed\n" ); return 1; } /* save the info of the first frame */ if( f == 0 ) { width = w; height = h; bit_depth = bd; color_type = clrt; interlace_type = it; compression_type = ct; filter_type = ft; } /* compare all other frames to first frame */ else if( (w != width) || (h != height) || (bd != bit_depth) || (clrt != color_type) || (it != interlace_type) || (ct != compression_type) || (ft != filter_type) ) { if( w != width ) printf( "width is different\n" ); if( h != height ) printf( "height is different\n" ); if( bd != bit_depth ) printf( "bit depth is different\n" ); if( clrt != color_type ) printf( "color type is different\n" ); if( it != interlace_type ) printf( "interlace type is different\n" ); if( ct != compression_type ) printf( "compression type is different\n" ); if( ft != filter_type ) printf( "filter type is different\n" ); return 1; } } row_buf = (png_bytep)NULL; /* open output file */ printf( "opening file \"%s\"\n", argv[numfiles + 2] ); fpout = fopen( argv[numfiles + 2], "wb" ); if( fpout == NULL ) { printf( "fopen() failed\n" ); return 1; } /* allocate write structure */ write_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL ); /* allocate info structures */ write_info_ptr = png_create_info_struct( write_ptr ); end_info_ptr = png_create_info_struct( write_ptr ); /* error handling */ if( setjmp( write_ptr->jmpbuf ) ) { printf( "libpng write error\n" ); return 1; } /* initialize output stream */ png_init_io( write_ptr, fpout ); png_set_write_status_fn( write_ptr, NULL ); /* set info */ png_set_IHDR( write_ptr, write_info_ptr, width * numfiles, height, bit_depth, color_type, PNG_INTERLACE_NONE, compression_type, filter_type); /* image characteristics */ { png_color_16p background; double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y; double gamma; int intent; png_uint_16p hist; png_uint_32 offset_x, offset_y; int unit_type; png_charp purpose, units; png_charpp params; png_int_32 X0, X1; int type, nparams; png_uint_32 res_x, res_y; png_colorp palette; int num_palette; png_color_8p sig_bit; png_bytep trans; int num_trans; png_color_16p trans_values; /* background color */ if( png_get_bKGD( input[0].read_ptr, input[0].read_info_ptr, &background ) ) { png_set_bKGD( write_ptr, write_info_ptr, background ); } if( png_get_cHRM( input[0].read_ptr, input[0].read_info_ptr, &white_x, &white_y, &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y ) ) { png_set_cHRM( write_ptr, write_info_ptr, white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y ); } /* gamma */ if( png_get_gAMA( input[0].read_ptr, input[0].read_info_ptr, &gamma ) ) { png_set_gAMA( write_ptr, write_info_ptr, gamma ); } /* rendering intent */ if( png_get_sRGB( input[0].read_ptr, input[0].read_info_ptr, &intent ) ) { png_set_sRGB( write_ptr, write_info_ptr, intent ); } /* Histogram */ if( png_get_hIST( input[0].read_ptr, input[0].read_info_ptr, &hist ) ) { png_set_hIST( write_ptr, write_info_ptr, hist ); } /* offsets */ if( png_get_oFFs( input[0].read_ptr, input[0].read_info_ptr, &offset_x, &offset_y, &unit_type ) ) { png_set_oFFs( write_ptr, write_info_ptr, offset_x, offset_y, unit_type ); } if( png_get_pCAL( input[0].read_ptr, input[0].read_info_ptr, &purpose, &X0, &X1, &type, &nparams, &units, ¶ms ) ) { png_set_pCAL( write_ptr, write_info_ptr, purpose, X0, X1, type, nparams, units, params ); } /* pixel density */ if( png_get_pHYs( input[0].read_ptr, input[0].read_info_ptr, &res_x, &res_y, &unit_type ) ) { png_set_pHYs( write_ptr, write_info_ptr, res_x, res_y, unit_type ); } /* text chunks */ /* if( png_get_text( input[0].read_ptr, input[0].read_info_ptr, &text_ptr, &num_text ) > 0 ) { printf( "Handling %d tEXt/zTXt chunks\n", num_text ); png_set_text( write_ptr, write_info_ptr, text_ptr, num_text ); } */ /* palette */ if( png_get_PLTE( input[0].read_ptr, input[0].read_info_ptr, &palette, &num_palette ) ) { png_set_PLTE( write_ptr, write_info_ptr, palette, num_palette ); } /* significant bits */ if( png_get_sBIT( input[0].read_ptr, input[0].read_info_ptr, &sig_bit ) ) { png_set_sBIT( write_ptr, write_info_ptr, sig_bit ); } /* transparency */ if( png_get_tRNS( input[0].read_ptr, input[0].read_info_ptr, &trans, &num_trans, &trans_values ) ) { png_set_tRNS( write_ptr, write_info_ptr, trans, num_trans, trans_values ); } } /* text chunks */ num_text = 0; if( !png_get_text( input[0].read_ptr, input[0].read_info_ptr, &text_ptr, &num_text ) ) num_text = 0; new_text_ptr = (struct png_text_struct *)malloc( sizeof( struct png_text_struct ) * num_text + 1 ); if( !new_text_ptr ) { printf( "malloc() failed\n" ); return 1; } memcpy( new_text_ptr, text_ptr, sizeof( struct png_text_struct ) * num_text ); snprintf( buf, 255, "SDL_anim %d %d %d", duration, width, numfiles ); buf[255] = 0; new_text_ptr[num_text].compression = PNG_TEXT_COMPRESSION_NONE; new_text_ptr[num_text].key = "format"; new_text_ptr[num_text].text = buf; new_text_ptr[num_text].text_length = strlen( buf ); num_text++; png_set_text( write_ptr, write_info_ptr, new_text_ptr, num_text ); /* write info */ png_write_info( write_ptr, write_info_ptr ); /* allocate buffer */ rowbytes = png_get_rowbytes( input[0].read_ptr, input[0].read_info_ptr ); row_buf = (png_bytep)png_malloc( write_ptr, rowbytes * numfiles ); if( row_buf == NULL ) { printf( "png_malloc() failed\n" ); return 1; } /* copy raw data */ for( y = 0; y < height; y++ ) { /* grab a scanline from each file */ here = row_buf; for( f = 0; f < numfiles; f++ ) { png_read_rows( input[f].read_ptr, (png_bytepp)&here, (png_bytepp)NULL, 1 ); here += rowbytes; } /* write the long scanline */ png_write_rows( write_ptr, (png_bytepp)&row_buf, 1 ); } /* end io */ for( f = 0; f < numfiles; f++ ) png_read_end( input[f].read_ptr, end_info_ptr ); png_write_end( write_ptr, end_info_ptr ); /* cleanup */ png_free( write_ptr, row_buf ); for( f = 0; f < numfiles; f++ ) { png_destroy_read_struct( &input[f].read_ptr, &input[f].read_info_ptr, &end_info_ptr); fclose( input[f].file ); } png_destroy_write_struct( &write_ptr, &write_info_ptr ); fclose( fpout ); return 0; }
RImage *RLoadPNG(RContext *context, const char *file) { char *tmp; RImage *image = NULL; FILE *f; png_structp png; png_infop pinfo, einfo; png_color_16p bkcolor; int alpha; int x, y, i; double gamma, sgamma; png_uint_32 width, height; int depth, junk, color_type; png_bytep *png_rows; unsigned char *ptr; f = fopen(file, "rb"); if (!f) { RErrorCode = RERR_OPEN; return NULL; } png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, (png_error_ptr) NULL, (png_error_ptr) NULL); if (!png) { RErrorCode = RERR_NOMEMORY; fclose(f); return NULL; } pinfo = png_create_info_struct(png); if (!pinfo) { RErrorCode = RERR_NOMEMORY; fclose(f); png_destroy_read_struct(&png, NULL, NULL); return NULL; } einfo = png_create_info_struct(png); if (!einfo) { RErrorCode = RERR_NOMEMORY; fclose(f); png_destroy_read_struct(&png, &pinfo, NULL); return NULL; } RErrorCode = RERR_INTERNAL; #if PNG_LIBPNG_VER - 0 < 10400 if (setjmp(png->jmpbuf)) { #else if (setjmp(png_jmpbuf(png))) { #endif fclose(f); png_destroy_read_struct(&png, &pinfo, &einfo); if (image) RReleaseImage(image); return NULL; } png_init_io(png, f); png_read_info(png, pinfo); png_get_IHDR(png, pinfo, &width, &height, &depth, &color_type, &junk, &junk, &junk); /* sanity check */ if (width < 1 || height < 1) { fclose(f); png_destroy_read_struct(&png, &pinfo, &einfo); RErrorCode = RERR_BADIMAGEFILE; return NULL; } /* check for an alpha channel */ if (png_get_valid(png, pinfo, PNG_INFO_tRNS)) alpha = True; else alpha = (color_type & PNG_COLOR_MASK_ALPHA); /* allocate RImage */ image = RCreateImage(width, height, alpha); if (!image) { fclose(f); png_destroy_read_struct(&png, &pinfo, &einfo); return NULL; } /* normalize to 8bpp with alpha channel */ if (color_type == PNG_COLOR_TYPE_PALETTE && depth <= 8) png_set_expand(png); if (color_type == PNG_COLOR_TYPE_GRAY && depth <= 8) png_set_expand(png); if (png_get_valid(png, pinfo, PNG_INFO_tRNS)) png_set_expand(png); if (depth == 16) png_set_strip_16(png); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png); /* set gamma correction */ if ((context->attribs->flags & RC_GammaCorrection) && context->depth != 8) { sgamma = (context->attribs->rgamma + context->attribs->ggamma + context->attribs->bgamma) / 3; } else if ((tmp = getenv("DISPLAY_GAMMA")) != NULL) { sgamma = atof(tmp); if (sgamma < 1.0E-3) sgamma = 1; } else { /* blah */ sgamma = 2.2; } if (png_get_gAMA(png, pinfo, &gamma)) png_set_gamma(png, sgamma, gamma); else png_set_gamma(png, sgamma, 0.45); /* do the transforms */ png_read_update_info(png, pinfo); /* set background color */ if (png_get_bKGD(png, pinfo, &bkcolor)) { image->background.red = bkcolor->red >> 8; image->background.green = bkcolor->green >> 8; image->background.blue = bkcolor->blue >> 8; } png_rows = calloc(height, sizeof(char *)); if (!png_rows) { RErrorCode = RERR_NOMEMORY; fclose(f); RReleaseImage(image); png_destroy_read_struct(&png, &pinfo, &einfo); return NULL; } for (y = 0; y < height; y++) { png_rows[y] = malloc(png_get_rowbytes(png, pinfo)); if (!png_rows[y]) { RErrorCode = RERR_NOMEMORY; fclose(f); RReleaseImage(image); png_destroy_read_struct(&png, &pinfo, &einfo); while (y-- > 0) if (png_rows[y]) free(png_rows[y]); free(png_rows); return NULL; } } /* read data */ png_read_image(png, png_rows); png_read_end(png, einfo); png_destroy_read_struct(&png, &pinfo, &einfo); fclose(f); ptr = image->data; /* convert to RImage */ if (alpha) { for (y = 0; y < height; y++) { for (x = 0, i = width * 4; x < i; x++, ptr++) { *ptr = *(png_rows[y] + x); } } } else { for (y = 0; y < height; y++) { for (x = 0, i = width * 3; x < i; x++, ptr++) { *ptr = *(png_rows[y] + x); } } } for (y = 0; y < height; y++) if (png_rows[y]) free(png_rows[y]); free(png_rows); return image; }
void PLPNGDecoder::Open(PLDataSource *pDataSrc) { png_uint_32 width, height; m_png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, user_error_fn, user_warning_fn); PLASSERT(m_png_ptr); m_info_ptr = png_create_info_struct(m_png_ptr); PLASSERT(m_info_ptr); png_set_read_fn(m_png_ptr, (void*)pDataSrc, my_read_data); /* The call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). */ png_read_info(m_png_ptr, m_info_ptr); #ifdef DUMP_PNG_DATA debugLog("%s", toString(*m_png_ptr).cstr()); #endif png_get_IHDR(m_png_ptr, m_info_ptr, &width, &height, &m_bit_depth ,&m_color_type, NULL, NULL, NULL); if( (m_color_type != PNG_COLOR_TYPE_RGB_ALPHA) && (m_color_type != PNG_COLOR_TYPE_GRAY_ALPHA) && ((m_color_type != PNG_COLOR_TYPE_RGB) || (m_bit_depth < 16)) ) { #ifdef PNG_READ_16_TO_8_SUPPORTED if(m_bit_depth == 16) { #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED png_set_scale_16(png_ptr); #else png_set_strip_16(png_ptr); #endif } #endif if(m_color_type == PNG_COLOR_TYPE_PALETTE) { png_set_expand(m_png_ptr); } if(m_bit_depth < 8) { png_set_expand(m_png_ptr); } if(png_get_valid(m_png_ptr, m_info_ptr, PNG_INFO_tRNS)) { png_set_expand(m_png_ptr); } if((m_color_type == PNG_COLOR_TYPE_GRAY) || (m_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) { png_set_gray_to_rgb(m_png_ptr); } /* set the background color to draw transparent and alpha images over */ png_color_16 *pBackground; png_color bkgColor = {127, 127, 127}; if(png_get_bKGD(m_png_ptr, m_info_ptr, &pBackground)) { png_set_background(m_png_ptr, pBackground, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); bkgColor.red = (png_byte)pBackground->red; bkgColor.green = (png_byte)pBackground->green; bkgColor.blue = (png_byte)pBackground->blue; #ifdef DUMP_PNG_DATA debugLog(" Background : (%d,%d,%d)\n", bkgColor.red, bkgColor.green, bkgColor.blue); #endif } /* if required set gamma conversion */ double dGamma; if(png_get_gAMA(m_png_ptr, m_info_ptr, &dGamma)) { png_set_gamma(m_png_ptr, (double)2.2, dGamma); } /* after the transformations are registered, update info_ptr data */ png_read_update_info(m_png_ptr, m_info_ptr); png_get_IHDR(m_png_ptr, m_info_ptr, &width, &height, &m_bit_depth ,&m_color_type, NULL, NULL, NULL); } PLPixelFormat pf; switch(m_color_type) { case PNG_COLOR_TYPE_RGB: pf = PLPixelFormat::R8G8B8; break; case PNG_COLOR_TYPE_RGB_ALPHA: pf = PLPixelFormat::A8R8G8B8; break; case PNG_COLOR_TYPE_GRAY: pf = PLPixelFormat::L8; break; case PNG_COLOR_TYPE_GRAY_ALPHA: png_set_gray_to_rgb(m_png_ptr); png_set_expand(m_png_ptr); pf = PLPixelFormat::A8R8G8B8; break; case PNG_COLOR_TYPE_PALETTE: if(m_bit_depth != 16) { pf = PLPixelFormat::I8; } else { // 16-bit palette image png_set_expand(m_png_ptr); pf = PLPixelFormat::R8G8B8; } break; } if((pf.GetBitsPerPixel() == 32) || (pf.GetBitsPerPixel() == 24)) { png_set_bgr(m_png_ptr); } SetBmpInfo(PLPoint(width, height), PLPoint(0,0), pf); png_uint_32 XRes, YRes; int UnitType; png_get_pHYs(m_png_ptr, m_info_ptr, &XRes, &YRes, &UnitType); if(UnitType == PNG_RESOLUTION_METER) { m_Resolution = PLPoint(int (XRes/39.37f+0.5), int (YRes/39.37f+0.5)); } }
void __fastcall TPngDecoder::Init(){ pfFile=fopen(FFileName.c_str(),"rb"); if(!pfFile) throw Exception ( "Can't open file" ); // first check the eight byte PNG signature fread(pbSig, 1, 8, pfFile); if (!png_check_sig(pbSig, 8)) throw Exception ( "Bad file format" ); // create the two png(-info) structures png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) throw Exception( "Not enough memory" ); info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); throw Exception( "Not enough memory" ); } /*точка возврата после обработки ошибки или предупреждения*/ if (setjmp(png_jmpbuf(png_ptr))) { // awp_res=*((long*)png_ptr->error_ptr); if(row_pointers){ for (i = 0; i < FNumScanLines; i++){ if(row_pointers[i]) free(row_pointers[i]); } free(row_pointers); } png_destroy_read_struct(&png_ptr, &info_ptr,NULL); if(pfFile) fclose(pfFile); throw Exception( "" );; } // initialize the input png file png_init_io(png_ptr, pfFile); //8 байт сигнатуры уже прочитанно png_set_sig_bytes(png_ptr, 8); /* The call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). REQUIRED */ png_read_info(png_ptr, info_ptr); unsigned long width, hight; png_get_IHDR(png_ptr, info_ptr, &width, &hight, &iBitDepth, &iColorType, NULL, NULL, NULL); FWidth = width; FNumScanLines = hight; /**** Set up the data transformations you want. Note that these are all **** optional. Only call them if you want/need them. Many of the **** transformations only work on specific types of images, and many **** are mutually exclusive. ****/ /* tell libpng to strip 16 bit/color files down to 8 bits/color */ //может это не нужно? if (iBitDepth == 16) png_set_strip_16(png_ptr); if (iBitDepth < 8) png_set_expand(png_ptr); /* Expand paletted colors into true RGB triplets */ if (iColorType == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); /* Expand paletted or RGB images with transparency to full alpha channels * so the data will be available as RGBA quartets. */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr); /* tell libpng convert grayscale images to true rgd */ if (iColorType == PNG_COLOR_TYPE_GRAY|| iColorType == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); /*remove alpha channel instead combine with background*/ if (iColorType & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(png_ptr); /* Set the background color to draw transparent and alpha images over. * It is possible to set the red, green, and blue components directly * for paletted images instead of supplying a palette index. Note that * even if the PNG file supplies a background, you are not required to * use it - you should use the (solid) application background if it has one. */ // set the background color to draw transparent and alpha images over. if (png_get_bKGD(png_ptr, info_ptr, &pBackground)) png_set_background(png_ptr, pBackground, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); /* flip the RGB pixels to BGR (or RGBA to BGRA) */ if (iColorType & PNG_COLOR_MASK_COLOR) png_set_bgr(png_ptr); png_read_update_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &hight, &iBitDepth, &iColorType, NULL, NULL, NULL); FWidth = width; FNumScanLines = hight; FBufferSize = png_get_rowbytes(png_ptr, info_ptr); FScanBuffer = new char[FBufferSize]; if(width>0x7fff||hight>0x7fff) throw Exception( "Format not supported" ); }
/* Read a PNG file. You may want to return an error code if the read * fails (depending upon the failure). There are two "prototypes" given * here - one where we are given the filename, and we need to open the * file, and the other where we are given an open file (possibly with * some or all of the magic bytes read - see comments above). */ #ifdef open_file /* prototype 1 */ void read_png(char *file_name) /* We need to open the file */ { png_structp png_ptr; png_infop info_ptr; unsigned int sig_read = 0; png_uint_32 width, height; int bit_depth, color_type, interlace_type; FILE *fp; if ((fp = fopen(file_name, "rb")) == NULL) return (ERROR); #else no_open_file /* prototype 2 */ void read_png(FILE *fp, unsigned int sig_read) /* File is already open */ { png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int bit_depth, color_type, interlace_type; #endif no_open_file /* Only use one prototype! */ /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also supply the * the compiler header file version, so that we know if the application * was compiled with a compatible version of the library. REQUIRED */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp user_error_ptr, user_error_fn, user_warning_fn); if (png_ptr == NULL) { fclose(fp); return (ERROR); } /* Allocate/initialize the memory for image information. REQUIRED. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(fp); png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); return (ERROR); } /* Set error handling if you are using the setjmp/longjmp method (this is * the normal method of doing things with libpng). REQUIRED unless you * set up your own error handlers in the png_create_read_struct() earlier. */ if (setjmp(png_jmpbuf(png_ptr))) { /* Free all of the memory associated with the png_ptr and info_ptr */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); fclose(fp); /* If we get here, we had a problem reading the file */ return (ERROR); } /* One of the following I/O initialization methods is REQUIRED */ #ifdef streams /* PNG file I/O method 1 */ /* Set up the input control if you are using standard C streams */ png_init_io(png_ptr, fp); #else no_streams /* PNG file I/O method 2 */ /* If you are using replacement read functions, instead of calling * png_init_io() here you would call: */ png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn); /* where user_io_ptr is a structure you want available to the callbacks */ #endif no_streams /* Use only one I/O method! */ /* If we have already read some of the signature */ png_set_sig_bytes(png_ptr, sig_read); #ifdef hilevel /* * If you have enough memory to read in the entire image at once, * and you need to specify only transforms that can be controlled * with one of the PNG_TRANSFORM_* bits (this presently excludes * dithering, filling, setting background, and doing gamma * adjustment), then you can read the entire image (including * pixels) into the info structure with this call: */ png_read_png(png_ptr, info_ptr, png_transforms, png_voidp_NULL); #else /* OK, you're doing it the hard way, with the lower-level functions */ /* The call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). REQUIRED */ png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL); /* Set up the data transformations you want. Note that these are all * optional. Only call them if you want/need them. Many of the * transformations only work on specific types of images, and many * are mutually exclusive. */ /* Tell libpng to strip 16 bit/color files down to 8 bits/color */ png_set_strip_16(png_ptr); /* Strip alpha bytes from the input data without combining with the * background (not recommended). */ png_set_strip_alpha(png_ptr); /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ png_set_packing(png_ptr); /* Change the order of packed pixels to least significant bit first * (not useful if you are using png_set_packing). */ png_set_packswap(png_ptr); /* Expand paletted colors into true RGB triplets */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); /* Expand paletted or RGB images with transparency to full alpha channels * so the data will be available as RGBA quartets. */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); /* Set the background color to draw transparent and alpha images over. * It is possible to set the red, green, and blue components directly * for paletted images instead of supplying a palette index. Note that * even if the PNG file supplies a background, you are not required to * use it - you should use the (solid) application background if it has one. */ png_color_16 my_background, *image_background; if (png_get_bKGD(png_ptr, info_ptr, &image_background)) png_set_background(png_ptr, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); else png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); /* Some suggestions as to how to get a screen gamma value * * Note that screen gamma is the display_exponent, which includes * the CRT_exponent and any correction for viewing conditions */ if (/* We have a user-defined screen gamma value */) { screen_gamma = user-defined screen_gamma; } /* This is one way that applications share the same screen gamma value */ else if ((gamma_str = getenv("SCREEN_GAMMA")) != NULL)
static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { png_structp png_ptr = NULL; png_infop info_ptr; png_uint_32 width, height; png_colorp png_palette = NULL; int color_type, palette_entries = 0; int bit_depth, pixel_depth; // pixel_depth = bit_depth * channels FIBITMAP *dib = NULL; RGBQUAD *palette = NULL; // pointer to dib palette png_bytepp row_pointers = NULL; int i; fi_ioStructure fio; fio.s_handle = handle; fio.s_io = io; if (handle) { BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS; try { // check to see if the file is in fact a PNG file BYTE png_check[PNG_BYTES_TO_CHECK]; io->read_proc(png_check, PNG_BYTES_TO_CHECK, 1, handle); if (png_sig_cmp(png_check, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0) { return NULL; // Bad signature } // create the chunk manage structure png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, error_handler, warning_handler); if (!png_ptr) { return NULL; } // create the info structure info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return NULL; } // init the IO png_set_read_fn(png_ptr, &fio, _ReadProc); if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } // because we have already read the signature... png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); // read the IHDR chunk png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); pixel_depth = png_get_bit_depth(png_ptr, info_ptr) * png_get_channels(png_ptr, info_ptr); // get image data type (assume standard image type) FREE_IMAGE_TYPE image_type = FIT_BITMAP; if (bit_depth == 16) { if ((pixel_depth == 16) && (color_type == PNG_COLOR_TYPE_GRAY)) { image_type = FIT_UINT16; } else if ((pixel_depth == 48) && (color_type == PNG_COLOR_TYPE_RGB)) { image_type = FIT_RGB16; } else if ((pixel_depth == 64) && (color_type == PNG_COLOR_TYPE_RGB_ALPHA)) { image_type = FIT_RGBA16; } else { // tell libpng to strip 16 bit/color files down to 8 bits/color png_set_strip_16(png_ptr); bit_depth = 8; } } #ifndef FREEIMAGE_BIGENDIAN if((image_type == FIT_UINT16) || (image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) { // turn on 16 bit byte swapping png_set_swap(png_ptr); } #endif // set some additional flags switch(color_type) { case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR // flip the RGB pixels to BGR (or RGBA to BGRA) if(image_type == FIT_BITMAP) { png_set_bgr(png_ptr); } #endif break; case PNG_COLOR_TYPE_PALETTE: // expand palette images to the full 8 bits from 2 bits/pixel if (pixel_depth == 2) { png_set_packing(png_ptr); pixel_depth = 8; } break; case PNG_COLOR_TYPE_GRAY: // expand grayscale images to the full 8 bits from 2 bits/pixel // but *do not* expand fully transparent palette entries to a full alpha channel if (pixel_depth == 2) { png_set_expand_gray_1_2_4_to_8(png_ptr); pixel_depth = 8; } break; case PNG_COLOR_TYPE_GRAY_ALPHA: // expand 8-bit greyscale + 8-bit alpha to 32-bit png_set_gray_to_rgb(png_ptr); #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR // flip the RGBA pixels to BGRA png_set_bgr(png_ptr); #endif pixel_depth = 32; break; default: throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; } // unlike the example in the libpng documentation, we have *no* idea where // this file may have come from--so if it doesn't have a file gamma, don't // do any correction ("do no harm") if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) { double gamma = 0; double screen_gamma = 2.2; if (png_get_gAMA(png_ptr, info_ptr, &gamma) && ( flags & PNG_IGNOREGAMMA ) != PNG_IGNOREGAMMA) { png_set_gamma(png_ptr, screen_gamma, gamma); } } // all transformations have been registered; now update info_ptr data png_read_update_info(png_ptr, info_ptr); // color type may have changed, due to our transformations color_type = png_get_color_type(png_ptr,info_ptr); // create a DIB and write the bitmap header // set up the DIB palette, if needed switch (color_type) { case PNG_COLOR_TYPE_RGB: png_set_invert_alpha(png_ptr); if(image_type == FIT_BITMAP) { dib = FreeImage_AllocateHeader(header_only, width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); } else { dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth); } break; case PNG_COLOR_TYPE_RGB_ALPHA: if(image_type == FIT_BITMAP) { dib = FreeImage_AllocateHeader(header_only, width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); } else { dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth); } break; case PNG_COLOR_TYPE_PALETTE: dib = FreeImage_AllocateHeader(header_only, width, height, pixel_depth); png_get_PLTE(png_ptr,info_ptr, &png_palette, &palette_entries); palette_entries = MIN((unsigned)palette_entries, FreeImage_GetColorsUsed(dib)); palette = FreeImage_GetPalette(dib); // store the palette for (i = 0; i < palette_entries; i++) { palette[i].rgbRed = png_palette[i].red; palette[i].rgbGreen = png_palette[i].green; palette[i].rgbBlue = png_palette[i].blue; } break; case PNG_COLOR_TYPE_GRAY: dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth); if(pixel_depth <= 8) { palette = FreeImage_GetPalette(dib); palette_entries = 1 << pixel_depth; for (i = 0; i < palette_entries; i++) { palette[i].rgbRed = palette[i].rgbGreen = palette[i].rgbBlue = (BYTE)((i * 255) / (palette_entries - 1)); } } break; default: throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; } // store the transparency table if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { // array of alpha (transparency) entries for palette png_bytep trans_alpha = NULL; // number of transparent entries int num_trans = 0; // graylevel or color sample values of the single transparent color for non-paletted images png_color_16p trans_color = NULL; png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color); if((color_type == PNG_COLOR_TYPE_GRAY) && trans_color) { // single transparent color if (trans_color->gray < palette_entries) { BYTE table[256]; memset(table, 0xFF, palette_entries); table[trans_color->gray] = 0; FreeImage_SetTransparencyTable(dib, table, palette_entries); } } else if((color_type == PNG_COLOR_TYPE_PALETTE) && trans_alpha) { // transparency table FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans); } } // store the background color if (png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) { // Get the background color to draw transparent and alpha images over. // Note that even if the PNG file supplies a background, you are not required to // use it - you should use the (solid) application background if it has one. png_color_16p image_background = NULL; RGBQUAD rgbBkColor; if (png_get_bKGD(png_ptr, info_ptr, &image_background)) { rgbBkColor.rgbRed = (BYTE)image_background->red; rgbBkColor.rgbGreen = (BYTE)image_background->green; rgbBkColor.rgbBlue = (BYTE)image_background->blue; rgbBkColor.rgbReserved = 0; FreeImage_SetBackgroundColor(dib, &rgbBkColor); } } // get physical resolution if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) { png_uint_32 res_x, res_y; // we'll overload this var and use 0 to mean no phys data, // since if it's not in meters we can't use it anyway int res_unit_type = PNG_RESOLUTION_UNKNOWN; png_get_pHYs(png_ptr,info_ptr, &res_x, &res_y, &res_unit_type); if (res_unit_type == PNG_RESOLUTION_METER) { FreeImage_SetDotsPerMeterX(dib, res_x); FreeImage_SetDotsPerMeterY(dib, res_y); } } // get possible ICC profile if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) { png_charp profile_name = NULL; png_bytep profile_data = NULL; png_uint_32 profile_length = 0; int compression_type; png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &profile_length); // copy ICC profile data (must be done after FreeImage_AllocateHeader) FreeImage_CreateICCProfile(dib, profile_data, profile_length); } // --- header only mode => clean-up and return if (header_only) { // get possible metadata (it can be located both before and after the image data) ReadMetadata(png_ptr, info_ptr, dib); if (png_ptr) { // clean up after the read, and free any memory allocated - REQUIRED png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } return dib; } // set the individual row_pointers to point at the correct offsets row_pointers = (png_bytepp)malloc(height * sizeof(png_bytep)); if (!row_pointers) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); FreeImage_Unload(dib); return NULL; } // read in the bitmap bits via the pointer table // allow loading of PNG with minor errors (such as images with several IDAT chunks) for (png_uint_32 k = 0; k < height; k++) { row_pointers[height - 1 - k] = FreeImage_GetScanLine(dib, k); } png_set_benign_errors(png_ptr, 1); png_read_image(png_ptr, row_pointers); // check if the bitmap contains transparency, if so enable it in the header if (FreeImage_GetBPP(dib) == 32) { if (FreeImage_GetColorType(dib) == FIC_RGBALPHA) { FreeImage_SetTransparent(dib, TRUE); } else { FreeImage_SetTransparent(dib, FALSE); } } // cleanup if (row_pointers) { free(row_pointers); row_pointers = NULL; } // read the rest of the file, getting any additional chunks in info_ptr png_read_end(png_ptr, info_ptr); // get possible metadata (it can be located both before and after the image data) ReadMetadata(png_ptr, info_ptr, dib); if (png_ptr) { // clean up after the read, and free any memory allocated - REQUIRED png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } return dib; } catch (const char *text) { if (png_ptr) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } if (row_pointers) { free(row_pointers); } if (dib) { FreeImage_Unload(dib); } FreeImage_OutputMessageProc(s_format_id, text); return NULL; } } return NULL; }
AFRAMES OneFrameReader(png_structp png_ptr_read, png_infop info_ptr_read, png_structp png_ptr_write, png_infop info_ptr_write, png_uint_32 width, png_uint_32 height) { /* IHDR */ /* struct data need from background */ AFRAMES pframe; png_uint_32 garbage; int bit_depth; int colour_type; int interlace_method; int compression_method; int filter_method; /* PLTE */ png_colorp palette = NULL; int palette_size = 0; /* gAMA */ double gamma; /* tRNS */ png_bytep trans; int num_trans; png_color_16p trans_values; /* bKGD */ png_color_16p background; png_get_IHDR(png_ptr_read, info_ptr_read, &garbage, &garbage, &bit_depth, &colour_type, &interlace_method, &compression_method, &filter_method); png_set_IHDR(png_ptr_write, info_ptr_write, width, height, bit_depth, colour_type, interlace_method, compression_method, filter_method); int r = 0, g = 0, b = 0; int bpp = bit_depth; switch (colour_type) { case PNG_COLOR_TYPE_GRAY : break; case PNG_COLOR_TYPE_RGB : bpp *= 3; break; case PNG_COLOR_TYPE_PALETTE : break; case PNG_COLOR_TYPE_GRAY_ALPHA: bpp *= 2; break; case PNG_COLOR_TYPE_RGB_ALPHA : bpp *= 4; break; default: return pframe; } pframe.colortype = colour_type; pframe.bytedep = bpp; pframe.pngBG = trans_values; /////////qDebug() << "### color type " << colour_type << bpp << num_trans; if(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_PLTE)) { /////////qDebug() << "### PNG_INFO_PLTE"; png_get_PLTE(png_ptr_read, info_ptr_read, &palette, &palette_size); png_set_PLTE(png_ptr_write, info_ptr_write, palette, palette_size); } if(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_gAMA)) { /////////qDebug() << "### PNG_INFO_gAMA"; png_get_gAMA(png_ptr_read, info_ptr_read, &gamma); png_set_gAMA(png_ptr_write, info_ptr_write, gamma); } if(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_tRNS)) { //////////qDebug() << "### PNG_INFO_tRNS"; png_get_tRNS(png_ptr_read, info_ptr_read, &trans, &num_trans, &trans_values); png_set_tRNS(png_ptr_write, info_ptr_write, trans, num_trans, trans_values); } if(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_bKGD)) { ////////qDebug() << "### PNG_INFO_bKGD"; png_get_bKGD(png_ptr_read, info_ptr_read, &background); png_set_bKGD(png_ptr_write, info_ptr_write, background); png_color_16p bkgd = background; pframe.pngBG = background; int r = 0, g = 0, b = 0; if(colour_type == PNG_COLOR_TYPE_RGB || colour_type == PNG_COLOR_TYPE_RGB_ALPHA) { r = bkgd->red; g = bkgd->green; b = bkgd->blue; } if(colour_type == PNG_COLOR_TYPE_GRAY || colour_type == PNG_COLOR_TYPE_GRAY_ALPHA) { r = g = b = bkgd->gray; } if(colour_type == PNG_COLOR_TYPE_PALETTE) { r = palette[bkgd->index].red; g = palette[bkgd->index].green; b = palette[bkgd->index].blue; } // scale down to 8 bit color since QColor doesn't support 16 bit colors if(bit_depth > 8) { r >>= 8; g >>= 8; b >>= 8; } ////////qDebug() << "### color " << r << g << b; pframe.bg = QColor(r,g,b); pframe.foundcolor = true; } else {
ImageIO::errorType ImageIO::loadPNG(const char * filename) { #ifdef ENABLE_PNG FILE *file = fopen(filename, "rb"); if (!file) { printf("Error in loadPNG: Cannot open file %s.\n", filename); return IO_ERROR; } // read the header of the image file const unsigned int pngHeaderBytes = 8; png_byte pngHeader[pngHeaderBytes]; if (fread(pngHeader, 1, pngHeaderBytes, file) != pngHeaderBytes) { printf("Error in loadPNG: cannot read the header of the png file.\n"); fclose(file); return (INVALID_FILE_FORMAT); }; int pngFlag = !png_sig_cmp(pngHeader, 0, pngHeaderBytes); if (!pngFlag) { printf("Error in loadPNG: %s is not a png file.\n", filename); fclose(file); return (INVALID_FILE_FORMAT); } // initialize png_struct and png_info png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { printf("Error in loadPNG: Creating the internal structure failed.\n"); fclose(file); return (IO_ERROR); } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); printf("Error in loadPNG: Creating the information structure failed.\n"); fclose(file); return (IO_ERROR); } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(file); printf("Error in loadPNG: cannot setup the error handling.\n"); return (IO_ERROR); } png_init_io(png_ptr, file); png_set_sig_bytes(png_ptr, pngHeaderBytes); png_read_info(png_ptr, info_ptr); int color_type; int bit_depth; png_get_IHDR(png_ptr, info_ptr, (png_uint_32*)(&width), (png_uint_32*)(&height), &bit_depth, &color_type, NULL, NULL, NULL); // !!ATTETNION!! The following transformations are designed in the order that they should occur. // DO NOT change the sequence!! bool setBackgroundNeeded = false; switch (color_type) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(png_ptr); // change palette to RGB setBackgroundNeeded = true; break; case PNG_COLOR_TYPE_GRAY: if (bit_depth < BITS_PER_CHANNEL_8) // transforms grayscale images of less than 8 to 8 bits. { png_set_expand_gray_1_2_4_to_8(png_ptr); setBackgroundNeeded = true; } break; } // adds a full alpha channel if there is transparency information in a tRNS chunk if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); // The image has 16 bits per channel for every pixel. Strip the pixels down to 8 bits. if (bit_depth == BITS_PER_CHANNEL_16) png_set_strip_16(png_ptr); // PNG files pack pixels of bit depths 1,2, and 4 into bytes. // The following code expands to 1 pixel per byte without changing the value of the pixels if (bit_depth < BITS_PER_CHANNEL_8) png_set_packing(png_ptr); // convert a grayscale image to be represented as RGB if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); setBackgroundNeeded = true; } // set background color if needed if (setBackgroundNeeded) { png_color_16 myBackground = {0, 0, 0, 0, 0}; png_color_16 * imageBackground; if (png_get_bKGD(png_ptr, info_ptr, &imageBackground)) png_set_background(png_ptr, imageBackground, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); else png_set_background(png_ptr, &myBackground, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); } // PNG files store 16 bit pixels in net work byte order (big-endian) // The following code may be needed on PC as to change the storage to the little-endian. // if (bit_depth == 16) // png_set_swap(png_ptr); // After setting the transformations, update the png_info structure to reflect any transformations you have requested png_read_update_info(png_ptr, info_ptr); // get color type again. It may be changed if any transformation is applied ?? color_type = png_get_color_type(png_ptr, info_ptr); switch (color_type) { case PNG_COLOR_TYPE_RGB: bytesPerPixel = IMAGE_IO_RGB; break; case PNG_COLOR_TYPE_RGB_ALPHA: bytesPerPixel = IMAGE_IO_RGB_ALPHA; break; default: printf("Error in loadPNG: image transformation failed.\n"); fclose(file); exit(0); // comment this out after debugging, use return IO_ERROR //return (IO_ERROR); break; } // sanity check here if (png_get_rowbytes(png_ptr, info_ptr) != bytesPerPixel * width) { printf("Error in loadPNG: the number of bytes per row, which is %lu, does not match bytesPerPixel * width, which is %d.\n", png_get_rowbytes(png_ptr, info_ptr), bytesPerPixel * width); fclose(file); exit(0); // comment this out after debugging, use return IO_ERROR return (IO_ERROR); } unsigned int bytesPerRow = bytesPerPixel * width; pixels = (unsigned char *) malloc (sizeof(unsigned char) * bytesPerRow * height); png_bytep * row_pointers = (png_bytep*) malloc (sizeof(png_bytep) * height); for(unsigned int row = 0; row < height; row++) row_pointers[row] = (png_byte*)(&pixels[(height - row - 1) * bytesPerRow]); png_read_image(png_ptr, row_pointers); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); free(row_pointers); fclose(file); return OK; #else return INVALID_FILE_FORMAT; #endif }
// Get the chunk information of the PNG file. IDAT is marked as existing, only after decoding or reading the header. // Bits (if set indicates existence of the chunk): // 0 - gAMA // 1 - sBIT // 2 - cHRM // 3 - PLTE // 4 - tRNS // 5 - bKGD // 6 - hIST // 7 - pHYs // 8 - oFFs // 9 - tIME // 10 - pCAL // 11 - sRGB // 12 - iCCP // 13 - sPLT // 14 - sCAL // 15 - IDAT // 16:30 - reserved be_t<u32> pngDecGetChunkInformation(PStream stream, bool IDAT = false) { // The end result of the chunk information (bigger-endian) be_t<u32> chunk_information = 0; // Needed pointers for getting the chunk information f64 gamma; f64 red_x; f64 red_y; f64 green_x; f64 green_y; f64 blue_x; f64 blue_y; f64 white_x; f64 white_y; f64 width; f64 height; s32 intent; s32 num_trans; s32 num_palette; s32 unit_type; s32 type; s32 nparams; s32 compression_type; s32 unit; u16* hist; u32 proflen; png_bytep profile; png_bytep trans_alpha; png_charp units; png_charp name; png_charp purpose; png_charpp params; png_int_32 X0; png_int_32 X1; png_int_32 offset_x; png_int_32 offset_y; png_uint_32 res_x; png_uint_32 res_y; png_colorp palette; png_color_8p sig_bit; png_color_16p background; png_color_16p trans_color; png_sPLT_tp entries; png_timep mod_time; // Get chunk information and set the appropriate bits if (png_get_gAMA(stream->png_ptr, stream->info_ptr, &gamma)) { chunk_information |= 1 << 0; // gAMA } if (png_get_sBIT(stream->png_ptr, stream->info_ptr, &sig_bit)) { chunk_information |= 1 << 1; // sBIT } if (png_get_cHRM(stream->png_ptr, stream->info_ptr, &white_x, &white_y, &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y)) { chunk_information |= 1 << 2; // cHRM } if (png_get_PLTE(stream->png_ptr, stream->info_ptr, &palette, &num_palette)) { chunk_information |= 1 << 3; // PLTE } if (png_get_tRNS(stream->png_ptr, stream->info_ptr, &trans_alpha, &num_trans, &trans_color)) { chunk_information |= 1 << 4; // tRNS } if (png_get_bKGD(stream->png_ptr, stream->info_ptr, &background)) { chunk_information |= 1 << 5; // bKGD } if (png_get_hIST(stream->png_ptr, stream->info_ptr, &hist)) { chunk_information |= 1 << 6; // hIST } if (png_get_pHYs(stream->png_ptr, stream->info_ptr, &res_x, &res_y, &unit_type)) { chunk_information |= 1 << 7; // pHYs } if (png_get_oFFs(stream->png_ptr, stream->info_ptr, &offset_x, &offset_y, &unit_type)) { chunk_information |= 1 << 8; // oFFs } if (png_get_tIME(stream->png_ptr, stream->info_ptr, &mod_time)) { chunk_information |= 1 << 9; // tIME } if (png_get_pCAL(stream->png_ptr, stream->info_ptr, &purpose, &X0, &X1, &type, &nparams, &units, ¶ms)) { chunk_information |= 1 << 10; // pCAL } if (png_get_sRGB(stream->png_ptr, stream->info_ptr, &intent)) { chunk_information |= 1 << 11; // sRGB } if (png_get_iCCP(stream->png_ptr, stream->info_ptr, &name, &compression_type, &profile, &proflen)) { chunk_information |= 1 << 12; // iCCP } if (png_get_sPLT(stream->png_ptr, stream->info_ptr, &entries)) { chunk_information |= 1 << 13; // sPLT } if (png_get_sCAL(stream->png_ptr, stream->info_ptr, &unit, &width, &height)) { chunk_information |= 1 << 14; // sCAL } if (IDAT) { chunk_information |= 1 << 15; // IDAT } return chunk_information; }
static int pngu_info (IMGCTX ctx) { png_byte magic[8]; png_uint_32 width; png_uint_32 height; png_color_16p background; png_bytep trans; png_color_16p trans_values; int scale, i; // Check if there is a file selected and if it is a valid .png if (ctx->source == PNGU_SOURCE_BUFFER) memcpy (magic, ctx->buffer, 8); else if (ctx->source == PNGU_SOURCE_DEVICE) { // Open file if (!(ctx->fd = fopen (ctx->filename, "rb"))) return PNGU_CANT_OPEN_FILE; // Load first 8 bytes into magic buffer if (fread (magic, 1, 8, ctx->fd) != 8) { fclose (ctx->fd); return PNGU_CANT_READ_FILE; } } else return PNGU_NO_FILE_SELECTED;; if (png_sig_cmp(magic, 0, 8) != 0) { if (ctx->source == PNGU_SOURCE_DEVICE) fclose (ctx->fd); return PNGU_FILE_IS_NOT_PNG; } // Allocation of libpng structs ctx->png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!(ctx->png_ptr)) { if (ctx->source == PNGU_SOURCE_DEVICE) fclose (ctx->fd); return PNGU_LIB_ERROR; } ctx->info_ptr = png_create_info_struct (ctx->png_ptr); if (!(ctx->info_ptr)) { if (ctx->source == PNGU_SOURCE_DEVICE) fclose (ctx->fd); png_destroy_read_struct (&(ctx->png_ptr), (png_infopp)NULL, (png_infopp)NULL); return PNGU_LIB_ERROR; } if (ctx->source == PNGU_SOURCE_BUFFER) { // Installation of our custom data provider function ctx->cursor = 0; png_set_read_fn (ctx->png_ptr, ctx, pngu_read_data_from_buffer); } else if (ctx->source == PNGU_SOURCE_DEVICE) { // Default data provider uses function fread, so it needs to use our FILE* png_init_io (ctx->png_ptr, ctx->fd); png_set_sig_bytes (ctx->png_ptr, 8); // We have read 8 bytes already to check PNG authenticity } // Read png header png_read_info (ctx->png_ptr, ctx->info_ptr); // Query image properties if they have not been queried before if (!ctx->propRead) { int ctxNumTrans; png_get_IHDR(ctx->png_ptr, ctx->info_ptr, &width, &height, (int *) &(ctx->prop.imgBitDepth), (int *) &(ctx->prop.imgColorType), NULL, NULL, NULL); ctx->prop.imgWidth = width; ctx->prop.imgHeight = height; switch (ctx->prop.imgColorType) { case PNG_COLOR_TYPE_GRAY: ctx->prop.imgColorType = PNGU_COLOR_TYPE_GRAY; break; case PNG_COLOR_TYPE_GRAY_ALPHA: ctx->prop.imgColorType = PNGU_COLOR_TYPE_GRAY_ALPHA; break; case PNG_COLOR_TYPE_PALETTE: ctx->prop.imgColorType = PNGU_COLOR_TYPE_PALETTE; break; case PNG_COLOR_TYPE_RGB: ctx->prop.imgColorType = PNGU_COLOR_TYPE_RGB; break; case PNG_COLOR_TYPE_RGB_ALPHA: ctx->prop.imgColorType = PNGU_COLOR_TYPE_RGB_ALPHA; break; default: ctx->prop.imgColorType = PNGU_COLOR_TYPE_UNKNOWN; break; } // Constant used to scale 16 bit values to 8 bit values scale = 0; if (ctx->prop.imgBitDepth == 16) scale = 8; // Query background color, if any. ctx->prop.validBckgrnd = 0; switch(ctx->prop.imgColorType) { case PNGU_COLOR_TYPE_RGB: case PNGU_COLOR_TYPE_RGB_ALPHA: { if(png_get_bKGD (ctx->png_ptr, ctx->info_ptr, &background)){ ctx->prop.validBckgrnd = 1; ctx->prop.bckgrnd.r = background->red >> scale; ctx->prop.bckgrnd.g = background->green >> scale; ctx->prop.bckgrnd.b = background->blue >> scale; } // Query list of transparent colors, if any. ctx->prop.numTrans = 0; ctx->prop.trans = NULL; if(png_get_tRNS (ctx->png_ptr, ctx->info_ptr, &trans, (int *) &(ctx->prop.numTrans), &trans_values)){ ctxNumTrans = ctx->prop.numTrans; if(ctxNumTrans){ ctx->prop.trans = malloc (sizeof (PNGUCOLOR) * ctxNumTrans); if (ctx->prop.trans) for (i = 0; i < ctxNumTrans; i++) { ctx->prop.trans[i].r = trans_values[i].red >> scale; ctx->prop.trans[i].g = trans_values[i].green >> scale; ctx->prop.trans[i].b = trans_values[i].blue >> scale; } else ctx->prop.numTrans = 0; } }
int main(int argc, char **argv) { static char *usage="Usage:\n\t%s png__file\n"; int i; FILE *fp_in = NULL; png_structp png_p; png_infop info_p; char header[8]; int bit_depth; int color_type; png_color_16p input_backgrd; double gammaval; int file_width, file_height; png_int_32 xoff, yoff; png_uint_32 xres, yres; int unit_type; int rgb_intent; double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y; png_timep mod_time; png_textp text; int num_text; unsigned char *image; unsigned char **rows; if (argc != 2) { bu_log(usage, argv[0]); bu_exit(EXIT_FAILURE, "Incorrect number of arguments!!\n"); } else { if ((fp_in = fopen(argv[1], "rb")) == NULL) { perror(argv[1]); bu_log("png_onfo: cannot open \"%s\" for reading\n", argv[1]); bu_exit(EXIT_FAILURE, "Cannot open input file\n"); } } if (fread(header, 8, 1, fp_in) != 1) bu_exit(EXIT_FAILURE, "ERROR: Failed while reading file header!!!\n"); if (png_sig_cmp((png_bytep)header, 0, 8)) bu_exit(EXIT_FAILURE, "This is not a PNG file!!!\n"); png_p = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_p) bu_exit(EXIT_FAILURE, "png_create_read_struct() failed!!\n"); info_p = png_create_info_struct(png_p); if (!info_p) bu_exit(EXIT_FAILURE, "png_create_info_struct() failed!!\n"); png_init_io(png_p, fp_in); png_set_sig_bytes(png_p, 8); png_read_info(png_p, info_p); color_type = png_get_color_type(png_p, info_p); bit_depth = png_get_bit_depth(png_p, info_p); switch (color_type) { case PNG_COLOR_TYPE_GRAY: bu_log("color type: b/w (bit depth=%d)\n", bit_depth); break; case PNG_COLOR_TYPE_GRAY_ALPHA: bu_log("color type: b/w with alpha channel (bit depth=%d)\n", bit_depth); break; case PNG_COLOR_TYPE_PALETTE: bu_log("color type: color palette (bit depth=%d)\n", bit_depth); break; case PNG_COLOR_TYPE_RGB: bu_log("color type: RGB (bit depth=%d)\n", bit_depth); break; case PNG_COLOR_TYPE_RGB_ALPHA: bu_log("color type: RGB with alpha channel (bit depth=%d)\n", bit_depth); break; default: bu_log("Unrecognized color type (bit depth=%d)\n", bit_depth); break; } file_width = png_get_image_width(png_p, info_p); file_height = png_get_image_height(png_p, info_p); bu_log("Image size: %d X %d\n", file_width, file_height); /* allocate memory for image */ image = (unsigned char *)bu_calloc(1, file_width*file_height*3, "image"); /* create rows array */ rows = (unsigned char **)bu_calloc(file_height, sizeof(unsigned char *), "rows"); for (i=0; i<file_height; i++) rows[file_height-1-i] = image+(i*file_width*3); png_read_image(png_p, rows); if (png_get_oFFs(png_p, info_p, &xoff, &yoff, &unit_type)) { if (unit_type == PNG_OFFSET_PIXEL) bu_log("X Offset: %d pixels\nY Offset: %d pixels\n", (int)xoff, (int)yoff); else if (unit_type == PNG_OFFSET_MICROMETER) bu_log("X Offset: %d um\nY Offset: %d um\n", (int)xoff, (int)yoff); } if (png_get_pHYs(png_p, info_p, &xres, &yres, &unit_type)) { if (unit_type == PNG_RESOLUTION_UNKNOWN) bu_log("Aspect ratio: %g (width/height)\n", (double)xres/(double)yres); else if (unit_type == PNG_RESOLUTION_METER) bu_log("pixel density:\n\t%d pixels/m horizontal\n\t%d pixels/m vertical\n", (int)xres, (int)yres); } if (png_get_interlace_type(png_p, info_p) == PNG_INTERLACE_NONE) bu_log("not interlaced\n"); else bu_log("interlaced\n"); if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_RGB_ALPHA) if (png_get_bKGD(png_p, info_p, &input_backgrd)) bu_log("background color: %d %d %d\n", input_backgrd->red, input_backgrd->green, input_backgrd->blue); if (png_get_sRGB(png_p, info_p, &rgb_intent)) { bu_log("rendering intent: "); switch (rgb_intent) { case PNG_sRGB_INTENT_SATURATION: bu_log("saturation\n"); break; case PNG_sRGB_INTENT_PERCEPTUAL: bu_log("perceptual\n"); break; case PNG_sRGB_INTENT_ABSOLUTE: bu_log("absolute\n"); break; case PNG_sRGB_INTENT_RELATIVE: bu_log("relative\n"); break; } } if (png_get_gAMA(png_p, info_p, &gammaval)) bu_log("gamma: %g\n", gammaval); #if defined(PNG_READ_cHRM_SUPPORTED) if (png_get_cHRM(png_p, info_p, &white_x, &white_y, &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y)) { bu_log("Chromaticity:\n"); bu_log("\twhite point\t(%g %g)\n\tred\t(%g %g)\n\tgreen\t(%g %g)\n\tblue\t(%g %g)\n", white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y); } #endif if (png_get_text(png_p, info_p, &text, &num_text)) for (i=0; i<num_text; i++) bu_log("%s: %s\n", text[i].key, text[i].text); if (png_get_tIME(png_p, info_p, &mod_time)) bu_log("Last modified: %d/%d/%d %d:%d:%d\n", mod_time->month, mod_time->day, mod_time->year, mod_time->hour, mod_time->minute, mod_time->second); return 0; }
/* * Reduce the palette. (Only the fast method is implemented.) * The parameter reductions indicates the intended reductions. * The function returns the successful reductions. */ static png_uint_32 opng_reduce_palette(png_structp png_ptr, png_infop info_ptr, png_uint_32 reductions) { png_colorp palette; png_bytep trans_alpha; png_uint_32 width, height; int bit_depth, color_type, interlace_type, compression_type, filter_type; int num_palette, num_trans; int last_color_index, last_trans_index; png_byte crt_trans_value, last_trans_value; png_byte is_used[256]; png_color_16 gray_trans; png_uint_32 result = OPNG_REDUCE_NONE; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type); if (!height || !width){ return OPNG_REDUCE_NONE; } png_bytepp row_ptr = png_get_rows(png_ptr, info_ptr); if (!png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) { palette = 0; num_palette = 0; } if (!png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, 0)) { trans_alpha = 0; num_trans = 0; } else OPNG_ASSERT(trans_alpha && num_trans > 0); opng_analyze_sample_usage(png_ptr, info_ptr, is_used); /* Palette-to-gray does not work (yet) if the bit depth is below 8. */ int is_gray = (reductions & OPNG_REDUCE_PALETTE_TO_GRAY) && (bit_depth == 8); last_color_index = last_trans_index = -1; int k; for (k= 0; k < 256; ++k) { if (!is_used[k]) continue; last_color_index = k; if (k < num_trans && trans_alpha[k] < 255) last_trans_index = k; if (is_gray) if (palette[k].red != palette[k].green || palette[k].red != palette[k].blue) is_gray = 0; } OPNG_ASSERT(last_color_index >= 0); OPNG_ASSERT(last_color_index >= last_trans_index); /* Check the integrity of PLTE and tRNS. */ if (last_color_index >= num_palette) { png_warning(png_ptr, "Too few colors in PLTE"); /* Fix the palette by adding blank entries at the end. */ opng_realloc_PLTE(png_ptr, info_ptr, last_color_index + 1); png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); OPNG_ASSERT(num_palette == last_color_index + 1); result |= OPNG_REDUCE_REPAIR; } if (num_trans > num_palette) { png_warning(png_ptr, "Too many alpha values in tRNS"); /* Transparency will be fixed further below. */ result |= OPNG_REDUCE_REPAIR; } /* Check if tRNS can be reduced to grayscale. */ if (is_gray && last_trans_index >= 0) { gray_trans.gray = palette[last_trans_index].red; last_trans_value = trans_alpha[last_trans_index]; for (k = 0; k <= last_color_index; ++k) { if (!is_used[k]) continue; if (k <= last_trans_index) { crt_trans_value = trans_alpha[k]; /* Cannot reduce if different colors have transparency. */ if (crt_trans_value < 255 && palette[k].red != gray_trans.gray) { is_gray = 0; break; } } else crt_trans_value = 255; /* Cannot reduce if same color has multiple transparency levels. */ if (palette[k].red == gray_trans.gray && crt_trans_value != last_trans_value) { is_gray = 0; break; } } } /* Remove tRNS if it is entirely sterile. */ if (num_trans > 0 && last_trans_index < 0) { num_trans = 0; png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, -1); png_set_invalid(png_ptr, info_ptr, PNG_INFO_tRNS); result |= OPNG_REDUCE_PALETTE_FAST; } if (reductions & OPNG_REDUCE_PALETTE_FAST) { if (num_palette != last_color_index + 1) { /* Reduce PLTE. */ /* hIST is reduced automatically. */ opng_realloc_PLTE(png_ptr, info_ptr, last_color_index + 1); png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); OPNG_ASSERT(num_palette == last_color_index + 1); result |= OPNG_REDUCE_PALETTE_FAST; } if (num_trans > 0 && num_trans != last_trans_index + 1) { /* Reduce tRNS. */ opng_realloc_tRNS(png_ptr, info_ptr, last_trans_index + 1); png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, 0); OPNG_ASSERT(num_trans == last_trans_index + 1); result |= OPNG_REDUCE_PALETTE_FAST; } } if (reductions & OPNG_REDUCE_8_TO_4_2_1) { result |= opng_reduce_palette_bits(png_ptr, info_ptr, reductions); /* Refresh the image information. */ bit_depth = png_get_bit_depth(png_ptr, info_ptr); } if ((bit_depth < 8) || !is_gray) return result; /* Reduce palette --> grayscale. */ for (png_uint_32 i = 0; i < height; ++i) { for (png_uint_32 j = 0; j < width; ++j) row_ptr[i][j] = palette[row_ptr[i][j]].red; } /* Update the ancillary information. */ if (num_trans > 0) png_set_tRNS(png_ptr, info_ptr, 0, 0, &gray_trans); #ifdef PNG_bKGD_SUPPORTED png_color_16p background; if (png_get_bKGD(png_ptr, info_ptr, &background)) background->gray = palette[background->index].red; #endif #ifdef PNG_hIST_SUPPORTED png_uint_16p hist; if (png_get_hIST(png_ptr, info_ptr, &hist)) { png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, -1); png_set_invalid(png_ptr, info_ptr, PNG_INFO_hIST); } #endif #ifdef PNG_sBIT_SUPPORTED png_color_8p sig_bits; if (png_get_sBIT(png_ptr, info_ptr, &sig_bits)) { png_byte max_sig_bits = sig_bits->red; if (max_sig_bits < sig_bits->green) max_sig_bits = sig_bits->green; if (max_sig_bits < sig_bits->blue) max_sig_bits = sig_bits->blue; sig_bits->gray = max_sig_bits; } #endif /* Update the image information. */ png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_GRAY, interlace_type, compression_type, filter_type); png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, -1); png_set_invalid(png_ptr, info_ptr, PNG_INFO_PLTE); return OPNG_REDUCE_PALETTE_TO_GRAY; /* ignore the former result */ }
__error__ "PNG_FLAG_FILLER_AFTER" has an unexpected value #endif #endif /* * Check if it's safe to access libpng's internal structures directly. * Some fields might have their offsets shifted due to changes in * libpng's configuration. */ static void _opng_validate_internal(png_structp png_ptr, png_infop info_ptr) { #if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) png_color_16p background; #endif #if defined(PNG_hIST_SUPPORTED) png_uint_16p hist; #endif #if defined(PNG_sBIT_SUPPORTED) png_color_8p sig_bit; #endif png_bytep trans_alpha; int num_trans; png_color_16p trans_color; /* Check info_ptr. */ if (png_get_rows(png_ptr, info_ptr) != info_ptr->row_pointers) goto error; #if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) if (png_get_bKGD(png_ptr, info_ptr, &background)) if (background != &info_ptr->background) goto error; #endif #if defined(PNG_hIST_SUPPORTED) if (png_get_hIST(png_ptr, info_ptr, &hist)) if (hist != info_ptr->hist) goto error; #endif #if defined(PNG_sBIT_SUPPORTED) if (png_get_sBIT(png_ptr, info_ptr, &sig_bit)) if (sig_bit != &info_ptr->sig_bit) goto error; #endif if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color)) if ((trans_alpha != NULL && (trans_alpha != info_ptr->trans_alpha || num_trans != info_ptr->num_trans)) || (trans_color != NULL && trans_color != &info_ptr->trans_color)) goto error; /* Also check png_ptr. It's not much, we're doing what we can... */ if (png_get_compression_buffer_size(png_ptr) != png_ptr->zbuf_size) goto error; /* Everything looks okay. */ return; error: png_error(png_ptr, "[internal error] Inconsistent internal structures (incorrect libpng?)"); }
int readpng_get_bgcolor(uch *red, uch *green, uch *blue) { png_color_16p pBackground; /* setjmp() must be called in every function that calls a PNG-reading * libpng function */ if (setjmp(png_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return 2; } if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) return 1; /* it is not obvious from the libpng documentation, but this function * takes a pointer to a pointer, and it always returns valid red, green * and blue values, regardless of color_type: */ png_get_bKGD(png_ptr, info_ptr, &pBackground); /* 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) {