static size_t png2rgb(ss_t **rgb, struct RGB_Info *ri, const ss_t *png) { RETURN_IF(!png || !ss_size(png), 0); size_t out_size = 0; struct aux_png_rio pio = { 0, png }; png_structp s = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); png_infop pi = png_create_info_struct(s); png_set_read_fn(s, (png_voidp)&pio, aux_png_read); png_read_info(s, pi); if (!aux_png2rbi(pi, ri)) { png_destroy_info_struct(s, &pi); png_destroy_read_struct(&s, NULL, NULL); return 0; } if ((pi->color_type & PNG_COLOR_MASK_PALETTE) != 0) png_set_expand(s); /* pal: expand to RGB */ png_bytep *rows = (png_bytep *)alloca(sizeof(png_bytep) * pi->height); if (aux_png_read_set_rows(rows, pi, rgb)) { size_t i = png_set_interlace_handling(s); for (; i > 0; i--) png_read_rows(s, rows, NULL, pi->height); png_read_end(s, pi); out_size = ss_size(*rgb); } png_destroy_info_struct(s, &pi); png_destroy_read_struct(&s, NULL, NULL); return out_size; }
static HPDF_STATUS ReadPngData (HPDF_Dict image, png_structp png_ptr, png_infop info_ptr) { png_uint_32 len = png_get_rowbytes(png_ptr, info_ptr); png_uint_32 height = png_get_image_height(png_ptr, info_ptr); png_bytep buf_ptr = HPDF_GetMem (image->mmgr, len); if (buf_ptr) { HPDF_UINT i; for (i = 0; i < (HPDF_UINT)height; i++) { png_read_rows(png_ptr, (png_byte**)&buf_ptr, NULL, 1); if (image->error->error_no != HPDF_OK) break; if (HPDF_Stream_Write (image->stream, buf_ptr, len) != HPDF_OK) break; } HPDF_FreeMem (image->mmgr, buf_ptr); } return image->error->error_no; }
static unsigned char* _png_decode_row( wprint_image_info_t *image_info, int row ) { int i, rows; int start_row; int rows_cached; if ((row < 0) || (row >= image_info->sampled_height)) return(NULL); rows_cached = wprint_image_input_rows_cached(image_info); if ((image_info->swath_start == -1) || (row < image_info->swath_start) || (row >= (image_info->swath_start + rows_cached))) { start_row = ((image_info->swath_start < 0) ? 0 : (image_info->swath_start + rows_cached)); if (image_info->decoder_data.png_info.rowp == NULL) { rows_cached = wprint_image_compute_rows_to_cache(image_info); image_info->decoder_data.png_info.rowp = (png_bytep*)malloc(sizeof(png_bytep) * rows_cached); for(i = 0; i < rows_cached; i++) { image_info->decoder_data.png_info.rowp[i] = (png_bytep)malloc(png_get_rowbytes(image_info->decoder_data.png_info.png_ptr,image_info->decoder_data.png_info.info_ptr)); if (image_info->decoder_data.png_info.rowp[i] == NULL) break; } rows_cached = MIN(i, rows_cached); } else if ((image_info->swath_start != -1) && (row < image_info->swath_start)) { start_row = 0; png_destroy_read_struct(&image_info->decoder_data.png_info.png_ptr, &image_info->decoder_data.png_info.info_ptr, (png_infopp) NULL); if (_png_get_hdr(image_info) == ERROR) return(NULL); } if (rows_cached == 0) return(NULL); image_info->swath_start = ((row / rows_cached) * rows_cached); if (setjmp(png_jmpbuf(image_info->decoder_data.png_info.png_ptr))) { image_info->wprint_ifc->debug(DBG_ERROR, "ERROR: PNG read error or corrupt file"); return(NULL); } for(i = start_row; i <= image_info->swath_start; i += rows_cached) { rows = MIN(rows_cached, (image_info->height - i)); png_read_rows(image_info->decoder_data.png_info.png_ptr, NULL, image_info->decoder_data.png_info.rowp, rows); } } return(image_info->decoder_data.png_info.rowp[row - image_info->swath_start]); } /* _png_decode_row */
bool ImageCodecPng::decode(xs::Stream* input,ImageData& data,const void *p1,const void *p2) const { png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,png_error,png_warning); if(!png_ptr) { Error("Unable to initialize PNG decoder"); return false; } 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); Error("Unable to initialize PNG decoder"); return false; } png_infop end_info = png_create_info_struct(png_ptr); if(!end_info) { png_destroy_read_struct(&png_ptr,&info_ptr,(png_infopp)NULL); Error("Unable to initialize PNG decoder"); return false; } //now that the libpng structures are setup, change the error handlers and read routines //to use G3D functions so that BinaryInput can be used. png_set_read_fn(png_ptr,(png_voidp)input,png_read_data); //read in sequentially so that three copies of the file are not in memory at once png_read_info(png_ptr,info_ptr); uint png_width, png_height; int bit_depth, color_type, interlace_type; //this will validate the data it extracts from info_ptr png_get_IHDR(png_ptr,info_ptr,(png_uint_32*)&png_width,(png_uint_32*)&png_height,&bit_depth,&color_type, &interlace_type,int_p_NULL,int_p_NULL); if(color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_destroy_read_struct(&png_ptr,&info_ptr,&end_info); Error("Unsupported PNG color type - PNG_COLOR_TYPE_GRAY_ALPHA."); return false; } //swap bytes of 16 bit files to least significant uchar first png_set_swap(png_ptr); png_set_strip_16(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_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); } // Fix sub-8 bit_depth to 8bit if (bit_depth < 8) { png_set_packing(png_ptr); } data.width = png_width; data.height = png_height; data.depth = 1; data.num_mipmaps = 1; data.flags = 0; uint channels = 0; if (color_type == PNG_COLOR_TYPE_RGBA) { channels = 4; data.format = PF_R8G8B8A8; data.size = data.width * data.height * channels; data.pData = new uchar[data.size]; } else if((color_type == PNG_COLOR_TYPE_RGB) || (color_type == PNG_COLOR_TYPE_PALETTE)) { channels = 3; data.format = PF_R8G8B8; data.size = data.width * data.height * channels; data.pData = new uchar[data.size]; } else if(color_type == PNG_COLOR_TYPE_GRAY) { channels = 1; data.format = PF_A8; data.size = data.width * data.height * channels; data.pData = new uchar[data.size]; } else { Error("Unsupported PNG bit-depth or type"); return false; } //since we are reading row by row, required to handle interlacing uint number_passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr,info_ptr); for(uint pass = 0;pass < number_passes;++pass) for(uint y = 0;y < (uint)data.height;++y) { png_bytep rowPointer = &data.pData[data.width * channels * y]; png_read_rows(png_ptr,&rowPointer,png_bytepp_NULL,1); } //todo:if the code below is needed? //png_read_end(png_ptr,info_ptr); png_destroy_read_struct(&png_ptr,&info_ptr,&end_info); return true; }
int read_png(const std::string & file_name, image_t & image) { png_structp png; png_infop info; int color_type, bit_depth, interlaced; int has_alpha; int num_passes; int p; int ok = 0; png_uint_32 width, height, y; int stride; uint8_t* rgb = NULL; FILE * fp; #ifdef LINUX fp = fopen(file_name.c_str(), "rb"); #endif #ifdef WINDOWS fopen_s(&fp, file_name.c_str(), "rb"); #endif if (fp == NULL) throw webp::exception::FileOperationException(); png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (png == NULL) { goto End; } png_set_error_fn(png, 0, error_function, NULL); if (setjmp(png_jmpbuf(png))) { Error: png_destroy_read_struct(&png, NULL, NULL); free(rgb); goto End; } info = png_create_info_struct(png); if (info == NULL) goto Error; png_init_io(png, fp); png_read_info(png, info); if (!png_get_IHDR(png, info, &width, &height, &bit_depth, &color_type, &interlaced, NULL, NULL)) goto Error; png_set_strip_16(png); png_set_packing(png); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { if (bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(png); } png_set_gray_to_rgb(png); } if (png_get_valid(png, info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png); has_alpha = 1; } else { has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA); } num_passes = png_set_interlace_handling(png); png_read_update_info(png, info); stride = (has_alpha ? 4 : 3) * width * sizeof(*rgb); rgb = (uint8_t*)malloc(stride * height); if (rgb == NULL) goto Error; for (p = 0; p < num_passes; ++p) { for (y = 0; y < height; ++y) { png_bytep row = rgb + y * stride; png_read_rows(png, &row, NULL, 1); } } png_read_end(png, info); png_destroy_read_struct(&png, &info, NULL); image.width = width; image.height = height; image.image.realloc(height * width); for(size_t y = 0; y < height; y++) for(size_t x = 0; x < width; x++){ size_t i = y * width + x; if (has_alpha) { *webp::utils::ALPHA(image.image[i]) = rgb[stride * y + x * 4]; *webp::utils::RED(image.image[i]) = rgb[stride * y + x * 4 + 1]; *webp::utils::GREEN(image.image[i]) = rgb[stride * y + x * 4 + 2]; *webp::utils::BLUE(image.image[i]) = rgb[stride * y + x * 4 + 3]; } else{ *webp::utils::ALPHA(image.image[i]) = 0xFF; *webp::utils::RED(image.image[i]) = rgb[stride * y + x * 3]; *webp::utils::GREEN(image.image[i]) = rgb[stride * y + x * 3 + 1]; *webp::utils::BLUE(image.image[i]) = rgb[stride * y + x * 3 + 2]; } } free(rgb); End: fclose(fp); return ok; }
/* read a png file. You may want to return an error code if the read fails (depending upon the failure). */ void read_png(char *file_name) { FILE *fp; png_structp png_ptr; png_infop info_ptr; /* open the file */ fp = fopen(file_name, "rb"); if (!fp) return; /* 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 check that the header file is compatible with the library version. */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (void *)user_error_ptr, user_error_fn, user_warning_fn); if (!png_ptr) { fclose(fp); return; } info_ptr = png_create_info_struct(); if (!info_ptr) { fclose(fp); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return; } /* set error handling if you are using the setjmp/longjmp method */ if (setjmp(png_ptr->jmpbuf)) { /* 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; } /* set up the input control if you are using standard C streams */ png_init_io(png_ptr, fp); /* 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 */ /* read the file information */ png_read_info(png_ptr, info_ptr); /* set up the transformations you want. Note that these are all optional. Only call them if you want them */ /* expand paletted colors into true RGB triplets */ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); /* expand grayscale images to the full 8 bits */ if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY && info_ptr->bit_depth < 8) 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 (info_ptr->valid & PNG_INFO_tRNS) png_set_expand(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. */ png_color_16 my_background; if (info_ptr->valid & PNG_INFO_bKGD) png_set_background(png_ptr, &(info_ptr->background), PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); else png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); /* tell libpng to handle the gamma conversion for you */ if (info_ptr->valid & PNG_INFO_gAMA) png_set_gamma(png_ptr, screen_gamma, info_ptr->gamma); else png_set_gamma(png_ptr, screen_gamma, 0.45); /* tell libpng to strip 16 bit/color files down to 8 bits/color */ if (info_ptr->bit_depth == 16) png_set_strip_16(png_ptr); /* dither rgb files down to 8 bit palette & reduce palettes to the number of colors available on your screen */ if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) { if (info_ptr->valid & PNG_INFO_PLTE) png_set_dither(png_ptr, info_ptr->palette, info_ptr->num_palette, max_screen_colors, info_ptr->histogram); else { png_color std_color_cube[MAX_SCREEN_COLORS] = {/* ... colors ... */}; png_set_dither(png_ptr, std_color_cube, MAX_SCREEN_COLORS, MAX_SCREEN_COLORS, NULL); } } /* invert monocrome files to have 0 as white and 1 as black */ if (info_ptr->bit_depth == 1 && info_ptr->color_type == PNG_COLOR_GRAY) png_set_invert(png_ptr); /* shift the pixels down to their true bit depth */ if (info_ptr->valid & PNG_INFO_sBIT && info_ptr->bit_depth > info_ptr->sig_bit) png_set_shift(png_ptr, &(info_ptr->sig_bit)); /* pack multiple pixels with bit depths of 1, 2, and 4 into bytes (useful only for paletted and grayscale images) */ if (info_ptr->bit_depth < 8) png_set_packing(png_ptr); /* flip the rgb pixels to bgr */ if (info_ptr->color_type == PNG_COLOR_TYPE_RGB || info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) png_set_bgr(png_ptr); /* swap bytes of 16 bit files to least significant bit first */ if (info_ptr->bit_depth == 16) png_set_swap(png_ptr); /* add a filler byte to RGB files (before or after each RGB triplet) */ if (info_ptr->bit_depth == 8 && info_ptr->color_type == PNG_COLOR_TYPE_RGB) png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); /* turn on interlace handling if you are not using png_read_image() */ number_passes = png_set_interlace_handling(png_ptr); /* optional call to gamma correct and add the background to the palette and update info structure. */ png_read_update_info(png_ptr, info_ptr); /* allocate the memory to hold the image using the fields of png_info. */ /* the easiest way to read the image */ png_bytep row_pointers[height]; for (row = 0; row < height; row++) { row_pointers[row] = malloc(info_ptr->rowbytes); } png_read_image(png_ptr, row_pointers); /* the other way to read images - deal with interlacing */ for (pass = 0; pass < number_passes; pass++) { /* Read the image using the "sparkle" effect. */ png_read_rows(png_ptr, row_pointers, NULL, number_of_rows); /* If you are only reading on row at a time, this works */ for (y = 0; y < height; y++) { png_bytep row_pointers = row[y]; png_read_rows(png_ptr, &row_pointers, NULL, 1); } /* to get the rectangle effect, use the third parameter */ png_read_rows(png_ptr, NULL, row_pointers, number_of_rows); /* if you want to display the image after every pass, do so here */ } /* read the rest of the file, getting any additional chunks in info_ptr */ png_read_end(png_ptr, info_ptr); /* clean up after the read, and free any memory allocated */ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); /* close the file */ fclose(fp); /* that's it */ return; }
int fh_png_load(char *name,unsigned char *buffer, unsigned char ** alpha,int x,int y) { png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int i; int bit_depth, color_type, interlace_type; int number_passes,pass, trans = 0; char *rp; png_bytep rptr[2]; char *fbptr; FILE *fh; if(!(fh=fopen(name,"rb"))) return(FH_ERROR_FILE); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); if (png_ptr == NULL) return(FH_ERROR_FORMAT); info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); fclose(fh); return(FH_ERROR_FORMAT); } rp=0; if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); if(rp) free(rp); fclose(fh); return(FH_ERROR_FORMAT); } png_init_io(png_ptr,fh); png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,&interlace_type, NULL, NULL); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type== PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { trans = 1; png_set_tRNS_to_alpha(png_ptr); } if(bit_depth == 16) png_set_strip_16(png_ptr); number_passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr,info_ptr); if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_RGB_ALPHA || trans) { unsigned char * alpha_buffer = (unsigned char*) malloc(width * height); unsigned char * aptr; rp = (char*) malloc(width * 4); rptr[0] = (png_bytep) rp; *alpha = alpha_buffer; for (pass = 0; pass < number_passes; pass++) { fbptr = buffer; aptr = alpha_buffer; for(i=0; i<height; i++) { int n; unsigned char *trp = rp; png_read_rows(png_ptr, rptr, NULL, 1); for(n = 0; n < width; n++, fbptr += 3, trp += 4) { memcpy(fbptr, trp, 3); *(aptr++) = trp[3]; } } } free(rp); } else { for (pass = 0; pass < number_passes; pass++) { fbptr = buffer; for(i=0; i<height; i++, fbptr += width*3) { rptr[0] = (png_bytep) fbptr; png_read_rows(png_ptr, rptr, NULL, 1); } } } png_read_end(png_ptr, info_ptr); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fh); return(FH_ERROR_OK); }
static void skip_src_rows(png_structp png_ptr, uint8_t storage[], int count) { for (int i = 0; i < count; i++) { uint8_t* tmp = storage; png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); } }
static gint gegl_buffer_import_png (GeglBuffer *gegl_buffer, GInputStream *stream, gint dest_x, gint dest_y, gint *ret_width, gint *ret_height, const Babl *format, // can be NULL GError **err) { gint width; gint bit_depth; gint bpp; gint number_of_passes=1; png_uint_32 w; png_uint_32 h; png_structp load_png_ptr; png_infop load_info_ptr; guchar *pixels; /*png_bytep *rows;*/ unsigned int i; png_bytep *row_p = NULL; g_return_val_if_fail(stream, -1); if (!check_valid_png_header(stream, err)) { return -1; } load_png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, error_fn, NULL); if (!load_png_ptr) { return -1; } load_info_ptr = png_create_info_struct (load_png_ptr); if (!load_info_ptr) { png_destroy_read_struct (&load_png_ptr, &load_info_ptr, NULL); return -1; } if (setjmp (png_jmpbuf (load_png_ptr))) { png_destroy_read_struct (&load_png_ptr, &load_info_ptr, NULL); if (row_p) g_free (row_p); return -1; } png_set_read_fn(load_png_ptr, stream, read_fn); png_set_sig_bytes (load_png_ptr, 8); // we already read header png_read_info (load_png_ptr, load_info_ptr); { int color_type; int interlace_type; png_get_IHDR (load_png_ptr, load_info_ptr, &w, &h, &bit_depth, &color_type, &interlace_type, NULL, NULL); width = w; if (ret_width) *ret_width = w; if (ret_height) *ret_height = h; if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { png_set_expand (load_png_ptr); bit_depth = 8; } if (png_get_valid (load_png_ptr, load_info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha (load_png_ptr); color_type |= PNG_COLOR_MASK_ALPHA; } switch (color_type) { case PNG_COLOR_TYPE_GRAY: bpp = 1; break; case PNG_COLOR_TYPE_GRAY_ALPHA: bpp = 2; break; case PNG_COLOR_TYPE_RGB: bpp = 3; break; case PNG_COLOR_TYPE_RGB_ALPHA: bpp = 4; break; case (PNG_COLOR_TYPE_PALETTE | PNG_COLOR_MASK_ALPHA): bpp = 4; break; case PNG_COLOR_TYPE_PALETTE: bpp = 3; break; default: g_warning ("color type mismatch"); png_destroy_read_struct (&load_png_ptr, &load_info_ptr, NULL); return -1; } if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb (load_png_ptr); if (bit_depth == 16) bpp = bpp << 1; if (!format) format = get_babl_format(bit_depth, color_type); #if BYTE_ORDER == LITTLE_ENDIAN if (bit_depth == 16) png_set_swap (load_png_ptr); #endif if (interlace_type == PNG_INTERLACE_ADAM7) number_of_passes = png_set_interlace_handling (load_png_ptr); if (png_get_valid (load_png_ptr, load_info_ptr, PNG_INFO_gAMA)) { gdouble gamma; png_get_gAMA (load_png_ptr, load_info_ptr, &gamma); png_set_gamma (load_png_ptr, 2.2, gamma); } else { png_set_gamma (load_png_ptr, 2.2, 0.45455); } png_read_update_info (load_png_ptr, load_info_ptr); } pixels = g_malloc0 (width*bpp); { gint pass; GeglRectangle rect; for (pass=0; pass<number_of_passes; pass++) { for(i=0; i<h; i++) { gegl_rectangle_set (&rect, 0, i, width, 1); if (pass != 0) gegl_buffer_get (gegl_buffer, &rect, 1.0, format, pixels, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); png_read_rows (load_png_ptr, &pixels, NULL, 1); gegl_buffer_set (gegl_buffer, &rect, 0, format, pixels, GEGL_AUTO_ROWSTRIDE); } } } png_read_end (load_png_ptr, NULL); png_destroy_read_struct (&load_png_ptr, &load_info_ptr, NULL); g_free (pixels); return 0; }
bool GReadBitmapFromFile(const char path[], GBitmap* bitmap) { FILE* file = fopen(path, "rb"); if (NULL == file) { return always_false(); } GAutoFClose afc(file); uint8_t signature[SIGNATURE_BYTES]; if (SIGNATURE_BYTES != fread(signature, 1, SIGNATURE_BYTES, file)) { return always_false(); } if (png_sig_cmp(signature, 0, SIGNATURE_BYTES)) { return always_false(); } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (NULL == png_ptr) { return always_false(); } png_infop info_ptr = png_create_info_struct(png_ptr); if (NULL == info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); return always_false(); } GAutoPNGReader reader(png_ptr, info_ptr); if (setjmp(png_jmpbuf(png_ptr))) { return always_false(); } png_init_io(png_ptr, file); png_set_sig_bytes(png_ptr, SIGNATURE_BYTES); png_read_info(png_ptr, info_ptr); png_uint_32 width, height; int bitDepth, colorType; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bitDepth, &colorType, NULL, NULL, NULL); if (8 != bitDepth) { return always_false(); // TODO: handle other formats } if (png_set_interlace_handling(png_ptr) > 1) { return always_false(); // TODO: support interleave } swizzle_row_proc row_proc = NULL; switch (colorType) { case PNG_COLOR_TYPE_RGB: row_proc = swizzle_rgb_row; break; case PNG_COLOR_TYPE_RGB_ALPHA: row_proc = swizzle_rgba_row; break; default: return always_false(); } png_read_update_info(png_ptr, info_ptr); GAutoFree rowStorage(malloc(png_get_rowbytes(png_ptr, info_ptr))); png_bytep srcRow = (png_bytep)rowStorage.get(); if (!srcRow) { return always_false(); } GAutoFree pixelStorage(malloc(height * width * 4)); GPixel* dstRow = (GPixel*)pixelStorage.get(); if (NULL == dstRow) { return always_false(); } for (int y = 0; y < height; y++) { uint8_t* tmp = srcRow; png_read_rows(png_ptr, &tmp, NULL, 1); row_proc(dstRow, srcRow, width); dstRow += width; } bitmap->fWidth = width; bitmap->fHeight = height; bitmap->fRowBytes = width * 4; bitmap->fPixels = (GPixel*)pixelStorage.detach(); return true; }
/** Reads one PNG file. @param process Process the image data (0 for initial parameter determination) @returns -1 on failure, 1 on sucess */ int decode_png(const char *pngname, int process, parameters_t *param) { int num_pass = 1; int bit_depth, color_type; FILE *pngfile; //png_byte hdptr[8]; /* Now open this PNG file, and examine its header to retrieve the YUV4MPEG info that shall be written */ pngfile = fopen(pngname, "rb"); if (!pngfile) { perror("PNG file open failed:"); return -1; } //fread(hdptr, 1, 8, pngfile); #if 0 bool is_png = !png_sig_cmp(hdptr, 0, 8); if (!is_png) { mjpeg_error("%s is _no_ PNG file !\n"); return -1; } #endif png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) mjpeg_error_exit1("%s: Could not allocate PNG read struct !", pngname); png_init_io(png_ptr, pngfile); //png_set_sig_bytes(png_ptr, 8); info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); mjpeg_error_exit1("%s: Could not allocate PNG info struct !", pngname); } end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); mjpeg_error_exit1("%s: Could not allocate PNG end info struct !", pngname); } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); mjpeg_error("%s: Corrupted PNG file !", pngname); return -1; } if (process) png_set_read_user_transform_fn(png_ptr, png_separation); png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_STRIP_ALPHA, NULL); if (png_get_IHDR(png_ptr, info_ptr, ¶m->width, ¶m->height, &bit_depth, // &color_type, &interlace_type, &compression_type, &filter_type)) &color_type, NULL, NULL, NULL)) num_pass = png_set_interlace_handling(png_ptr); else mjpeg_error_exit1("PNG header reading failed !!\n"); #if 0 mjpeg_info("Reading info struct...\n"); png_read_info(png_ptr, info_ptr); mjpeg_info("Done...\n"); if (png_get_IHDR(png_ptr, info_ptr, ¶m->width, ¶m->height, &bit_depth, // &color_type, &interlace_type, &compression_type, &filter_type)) &color_type, NULL, NULL, NULL)) num_pass = png_set_interlace_handling(png_ptr); else mjpeg_error_exit1("PNG header reading failed !!\n"); if (process) { printf("%d passes needed\n\n", num_pass); if (bit_depth != 8 && bit_depth != 16) { mjpeg_error_exit1("Invalid bit_depth %d, only 8 and 16 bit allowed !!\n", bit_depth); } png_set_strip_16(png_ptr); // always has to strip the 16bit input, MPEG can't handle it png_set_strip_alpha(png_ptr); // Alpha can't be processed until Z/Alpha is integrated printf("\nAllocating row buffer..."); png_set_read_user_transform_fn(png_ptr, png_separation); png_bytep row_buf = (png_bytep)png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); for (int n=0; n < num_pass; n++) for (int y=0; y < sh_param->height; y++) { printf("Writing row data for pass %d\n", n); png_read_rows(png_ptr, (png_bytepp)&row_buf, NULL, 1); } png_free(png_ptr, row_buf); } png_read_end(png_ptr, info_ptr); #endif if (setjmp(png_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return 2; } fclose(pngfile); return 1; }
static int decode_png_pixels(struct gps_map *map, unsigned char *out, int x, int y, int width, int height, int bpp, int row_stride) { struct raster_map *raster_map = map->data; unsigned char *scan_line; png_structp png; png_infop info; int line, r; FILE *f; if (bpp != 24) return -1; f = fopen(raster_map->bitmap_filename, "rb"); if (f == NULL) { gps_error("%s: %s", raster_map->bitmap_filename, strerror(errno)); return -1; } info = NULL; r = -1; png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png == NULL) { gps_error("png_create_read_struct() failed"); goto fail1; } info = png_create_info_struct(png); if (info == NULL) goto fail2; png_init_io(png, f); png_read_info(png, info); png_set_palette_to_rgb(png); if (width == map->width) { unsigned char **row_ptrs; int i; row_ptrs = malloc(sizeof(*row_ptrs) * (y + height)); if (row_ptrs == NULL) goto fail2; for (i = 0; i < y + height; i++) if (i < y) row_ptrs[i] = NULL; else row_ptrs[i] = out + (i - y) * row_stride; png_read_rows(png, row_ptrs, NULL, y + height); free(row_ptrs); } else { scan_line = malloc(map->width * 3); for (line = 0; line < map->height; line++) { png_read_rows(png, &scan_line, png_bytepp_NULL, 1); if (line < y || line >= y + height) continue; memcpy(out, scan_line + x * 3, width * 3); out += row_stride; } free(scan_line); } r = 0; fail2: png_destroy_read_struct(&png, &info, png_infopp_NULL); fail1: fclose(f); return r; }
errCode genTextures(const char *rootDir, const sFileList *files, sTex ***dynarrTextures){ static const size_t BUFFLEN = 1024; int numTexs=0; int idxFile = files->num; sTex *refTex; if(idxFile <= 0 || rootDir == NULL || rootDir[0] == '\0' || dynarrTextures == NULL) return PROBLEM; size_t lenRootDir = strlen(rootDir); char filePath[BUFFLEN]; FILE *handFile; png_byte header[PNGHEAD_SIZE]; strncpy(filePath, rootDir, 1024); if(lenRootDir>0 && filePath[lenRootDir-1]!='/'){ filePath[lenRootDir] = '/'; lenRootDir += 1; } while(idxFile > 0){ --idxFile; strncpy(&filePath[lenRootDir], files->dynarrFiles[idxFile], 1024 - lenRootDir); handFile = fopen(filePath, "rb"); if(handFile == NULL){ WARN("Can't open file %s", filePath); continue; } if( fread(header, sizeof(png_byte), PNGHEAD_SIZE, handFile) == PNGHEAD_SIZE && png_sig_cmp(header, 0, PNGHEAD_SIZE) == 0 ){ XTRA_LOG("File %s opened as PNG", filePath); }else{ WARN("File %s isn't a PNG", filePath); fclose(handFile); continue; } ++numTexs; (*dynarrTextures) = (sTex**)realloc_chk((*dynarrTextures), (numTexs+1) * sizeof(sTex*)); (*dynarrTextures)[numTexs]=NULL; refTex = (*dynarrTextures)[numTexs-1] = (sTex*)malloc_chk(sizeof(sTex)); memset(refTex, 0, sizeof(sTex)); refTex->pngptrData = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, &myPNGWarnFoo ); if(refTex->pngptrData == NULL){ WARN("Unable to create png struct"); fclose(handFile); continue; } if(setjmp(png_jmpbuf(refTex->pngptrData)) != 0){ /** jumps here on errors. */ cleanupPNGImg( refTex->pngptrData, &refTex->dynarrRows ); png_destroy_read_struct( &(refTex->pngptrData), &(refTex->pngptrInfo), NULL ); refTex->h = refTex->w = 0; }else{ refTex->pngptrInfo = png_create_info_struct( refTex->pngptrData ); if(refTex->pngptrInfo == NULL){ WARN("Unable to create png info struct"); fclose(handFile); continue; } /** setup PNG decode */ png_init_io(refTex->pngptrData, handFile); png_set_sig_bytes(refTex->pngptrData, PNGHEAD_SIZE); png_read_info(refTex->pngptrData, refTex->pngptrInfo); png_byte colorCurrent = png_get_color_type( refTex->pngptrData, refTex->pngptrInfo ); png_set_filler(refTex->pngptrData, 0, PNG_FILLER_AFTER); png_set_packing(refTex->pngptrData); /** if < 8 bits */ { png_color_8p sig_bit; if (png_get_sBIT(refTex->pngptrData, refTex->pngptrInfo, &sig_bit)) png_set_shift(refTex->pngptrData, sig_bit); } switch(colorCurrent){ case PNG_COLOR_TYPE_RGB_ALPHA: /** already good */ break; case PNG_COLOR_TYPE_RGB: png_set_tRNS_to_alpha(refTex->pngptrData); break; case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb( refTex->pngptrData ); png_set_tRNS_to_alpha(refTex->pngptrData); break; case PNG_COLOR_TYPE_GRAY: png_set_expand_gray_1_2_4_to_8( refTex->pngptrData ); png_set_tRNS_to_alpha(refTex->pngptrData); break; default: WARN("unsupported colour"); break; } png_read_update_info(refTex->pngptrData, refTex->pngptrInfo); colorCurrent = png_get_color_type( refTex->pngptrData, refTex->pngptrInfo ); if(colorCurrent != PNG_COLOR_TYPE_RGB_ALPHA){ printf("<warning> %s didn't convert to the right colour type\n", files->dynarrFiles[idxFile]); png_destroy_read_struct(&refTex->pngptrData, &refTex->pngptrInfo, (png_infopp)NULL); fclose(handFile); continue; } refTex->colorType = colorCurrent; const int numPasses = png_set_interlace_handling( refTex->pngptrData ); /** setup other data */ copyString(&refTex->name, files->dynarrFiles[idxFile]); /** setup texture */ unsigned int row; const png_uint_32 sizeRow = png_get_rowbytes( refTex->pngptrData, refTex->pngptrInfo ); refTex->w = png_get_image_width( refTex->pngptrData, refTex->pngptrInfo ); refTex->h = png_get_image_height( refTex->pngptrData, refTex->pngptrInfo ); if(sizeRow/refTex->w != DEFAULT_BYTE_PP){ WARN("%s didn't convert to the right bit depth", refTex->name); png_destroy_read_struct(&refTex->pngptrData, &refTex->pngptrInfo, (png_infopp)NULL); fclose(handFile); continue; } refTex->dynarrRows = calloc_chk((refTex->h +1), sizeof(png_byte*)); refTex->dynarrRows[refTex->h] = NULL; for(row = 0; row < refTex->h; ++row) refTex->dynarrRows[row] = png_malloc(refTex->pngptrData, sizeRow); unsigned int pass; for(pass=0; pass < numPasses; ++pass){ for(row = 0; row < refTex->h; ++row){ png_read_rows( refTex->pngptrData, &refTex->dynarrRows[row], NULL, 1 ); } } png_read_end(refTex->pngptrData, refTex->pngptrInfo); } fclose(handFile); } return NOPROB; }
int ExtractBits(PNG_CONST TCHAR *inname, PNG_CONST TCHAR *outname) { static HANDLE fpin; static HANDLE fpout; /* "static" prevents setjmp corruption */ png_structp read_ptr; png_infop read_info_ptr, end_info_ptr; png_structp write_ptr = NULL; png_infop write_info_ptr = NULL; png_infop write_end_info_ptr = NULL; png_bytep row_buf; png_uint_32 y; png_uint_32 width, height; int num_pass, pass; int bit_depth, color_type; char inbuf[256], outbuf[256]; row_buf = NULL; if ((fpin = CreateFile(inname, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) { fprintf(STDERR, "Could not find input file %s\n", inname); return (1); } if ((fpout = CreateFile(outname, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL)) == INVALID_HANDLE_VALUE) { fprintf(STDERR, "Could not open output file %s\n", outname); FCLOSE(fpin); return (1); } png_debug(0, "Allocating read and write structures"); read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL, png_error_ptr_NULL, png_error_ptr_NULL); png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error, pngtest_warning); png_debug(0, "Allocating read_info, write_info and end_info structures"); read_info_ptr = png_create_info_struct(read_ptr); end_info_ptr = png_create_info_struct(read_ptr); png_debug(0, "Setting jmpbuf for read struct"); if (setjmp(png_jmpbuf(read_ptr))) { fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname); png_free(read_ptr, row_buf); row_buf = NULL; png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); FCLOSE(fpin); FCLOSE(fpout); return (1); } png_debug(0, "Initializing input and output streams"); png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data); if (status_dots_requested == 1) { png_set_read_status_fn(read_ptr, read_row_callback); } else { png_set_read_status_fn(read_ptr, png_read_status_ptr_NULL); } png_debug(0, "Reading info struct"); png_read_info(read_ptr, read_info_ptr); png_debug(0, "Transferring info struct"); { int interlace_type, compression_type, filter_type; if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type)) { png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, compression_type, filter_type); } } { int intent; if (png_get_sRGB(read_ptr, read_info_ptr, &intent)) png_set_sRGB(write_ptr, write_info_ptr, intent); } { png_colorp palette; int num_palette; if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette)) png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette); } { png_color_8p sig_bit; if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit)) png_set_sBIT(write_ptr, write_info_ptr, sig_bit); } { png_bytep trans; int num_trans; png_color_16p trans_values; if (png_get_tRNS(read_ptr, read_info_ptr, &trans, &num_trans, &trans_values)) { int sample_max = (1 << read_info_ptr->bit_depth); /* libpng doesn't reject a tRNS chunk with out-of-range samples */ if (!((read_info_ptr->color_type == PNG_COLOR_TYPE_GRAY && (int)trans_values->gray > sample_max) || (read_info_ptr->color_type == PNG_COLOR_TYPE_RGB && ((int)trans_values->red > sample_max || (int)trans_values->green > sample_max || (int)trans_values->blue > sample_max)))) png_set_tRNS(write_ptr, write_info_ptr, trans, num_trans, trans_values); } } png_debug(0, "Writing row data"); num_pass = png_set_interlace_handling(read_ptr); for(pass = 0; pass < num_pass; pass++) { png_debug1(0, "Writing row data for pass %d", pass); for(y = 0; y < height; y++) { png_debug2(0, "Allocating row buffer (pass %d, y = %ld)...", pass, y); row_buf = (png_bytep)png_malloc(read_ptr, png_get_rowbytes(read_ptr, read_info_ptr)); png_debug2(0, "0x%08lx (%ld bytes)", (unsigned long)row_buf, png_get_rowbytes(read_ptr, read_info_ptr)); png_read_rows(read_ptr, (png_bytepp)&row_buf, png_bytepp_NULL, 1); png_debug2(0, "Freeing row buffer (pass %d, y = %ld)", pass, y); png_free(read_ptr, row_buf); row_buf = NULL; } } png_debug(0, "Reading and writing end_info data"); png_read_end(read_ptr, end_info_ptr); { png_uint_32 iwidth, iheight; iwidth = png_get_image_width(write_ptr, write_info_ptr); iheight = png_get_image_height(write_ptr, write_info_ptr); fprintf(STDERR, "\n Image width = %lu, height = %lu\n", (unsigned long)iwidth, (unsigned long)iheight); } png_debug(0, "Destroying data structs"); png_debug(1, "destroying read_ptr, read_info_ptr, end_info_ptr"); png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); png_debug(0, "Destruction complete."); FCLOSE(fpin); FCLOSE(fpout); png_debug(0, "Opening files for comparison"); if ((fpin = CreateFile(inname, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) { fprintf(STDERR, "Could not find file %s\n", inname); return (1); } if ((fpout = CreateFile(outname, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) { fprintf(STDERR, "Could not find file %s\n", outname); FCLOSE(fpin); return (1); } for(;;) { DWORD num_in, num_out; READFILE(fpin, inbuf, 1, num_in); READFILE(fpout, outbuf, 1, num_out); if (num_in != num_out) { fprintf(STDERR, "\nFiles %s and %s are of a different size\n", inname, outname); if (wrote_question == 0) { fprintf(STDERR, " Was %s written with the same maximum IDAT chunk size (%d bytes),", inname, PNG_ZBUF_SIZE); fprintf(STDERR, "\n filtering heuristic (libpng default), compression"); fprintf(STDERR, " level (zlib default),\n and zlib version (%s)?\n\n", ZLIB_VERSION); wrote_question = 1; } FCLOSE(fpin); FCLOSE(fpout); return (0); } if (!num_in) break; if (png_memcmp(inbuf, outbuf, num_in)) { fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname); if (wrote_question == 0) { fprintf(STDERR, " Was %s written with the same maximum IDAT chunk size (%d bytes),", inname, PNG_ZBUF_SIZE); fprintf(STDERR, "\n filtering heuristic (libpng default), compression"); fprintf(STDERR, " level (zlib default),\n and zlib version (%s)?\n\n", ZLIB_VERSION); wrote_question = 1; } FCLOSE(fpin); FCLOSE(fpout); return (0); } } FCLOSE(fpin); FCLOSE(fpout); return (0); }
BitmapImage * PNGImageIO_loadPNGData(const void * data, size_t length, int pixelFormat, bool flipVertical) { png_byte headerBytes[PNG_HEADER_SIZE]; png_structp pngReadStruct; png_infop pngInfoStruct; struct memreadContext readContext; unsigned int width, height; png_int_32 bitDepth, colorType; png_bytep * rows = NULL; unsigned char * pixels = NULL; unsigned int rowIndex; enum BitmapPixelFormat chosenPixelFormat = BITMAP_PIXEL_FORMAT_RGBA_8888; BitmapImage * image; readContext = memreadContextInit(data, length); if (!memread(&readContext, PNG_HEADER_SIZE, headerBytes) || png_sig_cmp(headerBytes, 0, PNG_HEADER_SIZE)) { return NULL; } pngReadStruct = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); pngInfoStruct = png_create_info_struct(pngReadStruct); if (setjmp(png_jmpbuf(pngReadStruct))) { png_destroy_read_struct(&pngReadStruct, &pngInfoStruct, NULL); free(rows); free(pixels); return NULL; } png_set_read_fn(pngReadStruct, &readContext, pngReadFnMemread); png_set_sig_bytes(pngReadStruct, PNG_HEADER_SIZE); png_read_info(pngReadStruct, pngInfoStruct); width = png_get_image_width(pngReadStruct, pngInfoStruct); height = png_get_image_height(pngReadStruct, pngInfoStruct); bitDepth = png_get_bit_depth(pngReadStruct, pngInfoStruct); colorType = png_get_color_type(pngReadStruct, pngInfoStruct); if (colorType == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(pngReadStruct); colorType = PNG_COLOR_TYPE_RGB; } if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) { png_set_expand_gray_1_2_4_to_8(pngReadStruct); } if (png_get_valid(pngReadStruct, pngInfoStruct, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(pngReadStruct); } if (bitDepth == 16) { png_set_strip_16(pngReadStruct); } switch (pixelFormat) { case PNG_PIXEL_FORMAT_AUTOMATIC: switch (colorType) { case PNG_COLOR_TYPE_GRAY: chosenPixelFormat = BITMAP_PIXEL_FORMAT_GRAY_8; break; case PNG_COLOR_TYPE_GRAY_ALPHA: chosenPixelFormat = BITMAP_PIXEL_FORMAT_GRAYALPHA_88; break; case PNG_COLOR_TYPE_RGB: chosenPixelFormat = BITMAP_PIXEL_FORMAT_RGB_888; break; case PNG_COLOR_TYPE_RGB_ALPHA: chosenPixelFormat = BITMAP_PIXEL_FORMAT_RGBA_8888; break; } png_read_update_info(pngReadStruct, pngInfoStruct); break; case BITMAP_PIXEL_FORMAT_RGBA_8888: if (!(colorType & PNG_COLOR_MASK_ALPHA)) { png_set_add_alpha(pngReadStruct, 0xFF, PNG_FILLER_AFTER); } png_read_update_info(pngReadStruct, pngInfoStruct); if (!(colorType & PNG_COLOR_MASK_COLOR)) { png_set_gray_to_rgb(pngReadStruct); } chosenPixelFormat = BITMAP_PIXEL_FORMAT_RGBA_8888; break; case BITMAP_PIXEL_FORMAT_RGB_888: if (colorType & PNG_COLOR_MASK_ALPHA) { png_set_strip_alpha(pngReadStruct); } png_read_update_info(pngReadStruct, pngInfoStruct); if (!(colorType & PNG_COLOR_MASK_COLOR)) { png_set_gray_to_rgb(pngReadStruct); } chosenPixelFormat = BITMAP_PIXEL_FORMAT_RGB_888; break; case BITMAP_PIXEL_FORMAT_GRAYALPHA_88: if (!(colorType & PNG_COLOR_MASK_ALPHA)) { png_set_add_alpha(pngReadStruct, 0xFF, PNG_FILLER_AFTER); } png_read_update_info(pngReadStruct, pngInfoStruct); if (colorType & PNG_COLOR_MASK_COLOR) { png_set_rgb_to_gray(pngReadStruct, 1, (float) 0x55 / 0xFF, (float) 0x55 / 0xFF); } chosenPixelFormat = BITMAP_PIXEL_FORMAT_GRAYALPHA_88; break; case BITMAP_PIXEL_FORMAT_GRAY_8: if (colorType & PNG_COLOR_MASK_ALPHA) { png_set_strip_alpha(pngReadStruct); } png_read_update_info(pngReadStruct, pngInfoStruct); if (colorType & PNG_COLOR_MASK_COLOR) { png_set_rgb_to_gray(pngReadStruct, 1, (float) 0x55 / 0xFF, (float) 0x55 / 0xFF); } chosenPixelFormat = BITMAP_PIXEL_FORMAT_GRAY_8; break; } pixels = calloc(width * height, BitmapImage_pixelFormatBytes(chosenPixelFormat)); rows = malloc(sizeof(png_bytep) * height); for (rowIndex = 0; rowIndex < height; rowIndex++) { rows[rowIndex] = pixels + ((flipVertical ? height - rowIndex - 1 : rowIndex) * width * BitmapImage_pixelFormatBytes(chosenPixelFormat)); } png_read_rows(pngReadStruct, rows, NULL, height); png_read_end(pngReadStruct, NULL); png_destroy_read_struct(&pngReadStruct, &pngInfoStruct, NULL); free(rows); image = BitmapImage_createWithPixelsNoCopy(chosenPixelFormat, width, height, width * BitmapImage_pixelFormatBytes(chosenPixelFormat), pixels, true); return image; }
bool GR_Win32Image::_convertFromPNG(const UT_ByteBuf* pBB, UT_sint32 iDisplayWidth, UT_sint32 iDisplayHeight) { png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int bit_depth, color_type, interlace_type; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (void*) NULL, NULL, NULL); if (png_ptr == NULL) { return false; } /* Allocate/initialize the memory for image information. REQUIRED. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return false; } /* 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); /* If we get here, we had a problem reading the file */ return false; } struct _bb myBB; myBB.pBB = pBB; myBB.iCurPos = 0; png_set_read_fn(png_ptr, (void *)&myBB, _png_read); /* 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, NULL, NULL); /* 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); /* Expand paletted colors into true RGB triplets */ png_set_expand(png_ptr); /* If we've got images with 16 bits per channel, we don't need that much precision. We'll do fine with 8 bits per channel */ png_set_strip_16(png_ptr); /* For simplicity, treat grayscale as RGB */ png_set_gray_to_rgb(png_ptr); /* For simplicity, we'll ignore alpha */ png_set_strip_alpha(png_ptr); /* We want libpng to deinterlace the image for us */ UT_uint32 iInterlacePasses = png_set_interlace_handling(png_ptr); /* flip the RGB pixels to BGR (or RGBA to BGRA) */ png_set_bgr(png_ptr); UT_uint32 iBytesInRow = width * 3; if (iBytesInRow % 4) { iBytesInRow += (4 - (iBytesInRow % 4)); } m_pDIB = (BITMAPINFO*) g_try_malloc(sizeof(BITMAPINFOHEADER) + height * iBytesInRow); if (!m_pDIB) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return false; } /* Note that we do NOT create a DIB of iDisplayWidth,iDisplayHeight, since DIBs can be stretched automatically by the Win32 API. So we simply remember the display size for drawing later. */ setDisplaySize(iDisplayWidth, iDisplayHeight); m_pDIB->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); m_pDIB->bmiHeader.biWidth = width; m_pDIB->bmiHeader.biHeight = height; m_pDIB->bmiHeader.biPlanes = 1; m_pDIB->bmiHeader.biBitCount = 24; m_pDIB->bmiHeader.biCompression = BI_RGB; m_pDIB->bmiHeader.biSizeImage = 0; m_pDIB->bmiHeader.biXPelsPerMeter = 0; m_pDIB->bmiHeader.biYPelsPerMeter = 0; m_pDIB->bmiHeader.biClrUsed = 0; m_pDIB->bmiHeader.biClrImportant = 0; UT_Byte* pBits = ((unsigned char*) m_pDIB) + m_pDIB->bmiHeader.biSize; for (; iInterlacePasses; iInterlacePasses--) { for (UT_uint32 iRow = 0; iRow < height; iRow++) { UT_Byte* pRow = pBits + (height - iRow - 1) * iBytesInRow; png_read_rows(png_ptr, &pRow, NULL, 1); } } /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); /* clean up after the read, and g_free any memory allocated - REQUIRED */ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return true; }
bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap, SkBitmap::Config prefConfig, Mode mode) { // SkAutoTrace apr("SkPNGImageDecoder::onDecode"); /* 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. */ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, sk_error_fn, NULL); // png_voidp user_error_ptr, user_error_fn, user_warning_fn); if (png_ptr == NULL) { return false; } /* Allocate/initialize the memory for image information. */ png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); return false; } PNGAutoClean autoClean(png_ptr, info_ptr); /* 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))) { return false; } /* If you are using replacement read functions, instead of calling * png_init_io() here you would call: */ png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn); /* where user_io_ptr is a structure you want available to the callbacks */ /* If we have already read some of the signature */ // png_set_sig_bytes(png_ptr, 0 /* sig_read */ ); // hookup our peeker so we can see any user-chunks the caller may be interested in png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0); if (this->getPeeker()) { png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk); } /* 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(png_ptr, info_ptr); png_uint_32 origWidth, origHeight; int bit_depth, color_type, interlace_type; png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL); SkBitmap::Config config; bool hasAlpha = false; bool doDither = this->getDitherImage(); // check for sBIT chunk data, in case we should disable dithering because // our data is not truely 8bits per component if (doDither) { #if 0 SkDebugf("----- sBIT %d %d %d %d\n", info_ptr->sig_bit.red, info_ptr->sig_bit.green, info_ptr->sig_bit.blue, info_ptr->sig_bit.alpha); #endif // 0 seems to indicate no information available if (pos_le(info_ptr->sig_bit.red, SK_R16_BITS) && pos_le(info_ptr->sig_bit.green, SK_G16_BITS) && pos_le(info_ptr->sig_bit.blue, SK_B16_BITS)) { doDither = false; } } if (color_type == PNG_COLOR_TYPE_PALETTE) { config = SkBitmap::kIndex8_Config; // defer sniffing for hasAlpha } else { png_color_16p transColor; png_get_tRNS(png_ptr, info_ptr, NULL, NULL, &transColor); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) || PNG_COLOR_TYPE_RGB_ALPHA == color_type || PNG_COLOR_TYPE_GRAY_ALPHA == color_type) { hasAlpha = true; config = SkBitmap::kARGB_8888_Config; } else { // we get to choose the config config = prefConfig; if (config == SkBitmap::kNo_Config) { config = SkImageDecoder::GetDeviceConfig(); } if (config != SkBitmap::kRGB_565_Config && config != SkBitmap::kARGB_4444_Config) { config = SkBitmap::kARGB_8888_Config; } } } if (!this->chooseFromOneChoice(config, origWidth, origHeight)) { return false; } const int sampleSize = this->getSampleSize(); SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize); decodedBitmap->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight(), 0); if (SkImageDecoder::kDecodeBounds_Mode == mode) { return true; } // from here down we are concerned with colortables and pixels /* tell libpng to strip 16 bit/color files down to 8 bits/color */ if (bit_depth == 16) { png_set_strip_16(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). */ if (bit_depth < 8) { png_set_packing(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_gray_1_2_4_to_8(png_ptr); } /* Make a grayscale image into RGB. */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); } // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we // draw lots faster if we can flag the bitmap has being opaque bool reallyHasAlpha = false; SkColorTable* colorTable = NULL; if (color_type == PNG_COLOR_TYPE_PALETTE) { int num_palette; png_colorp palette; png_bytep trans; int num_trans; png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); /* BUGGY IMAGE WORKAROUND We hit some images (e.g. fruit_.png) who contain bytes that are == colortable_count which is a problem since we use the byte as an index. To work around this we grow the colortable by 1 (if its < 256) and duplicate the last color into that slot. */ int colorCount = num_palette + (num_palette < 256); colorTable = SkNEW_ARGS(SkColorTable, (colorCount)); SkPMColor* colorPtr = colorTable->lockColors(); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); hasAlpha = (num_trans > 0); } else { num_trans = 0; colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOpaque_Flag); } // check for bad images that might make us crash if (num_trans > num_palette) { num_trans = num_palette; } int index = 0; int transLessThanFF = 0; for (; index < num_trans; index++) { transLessThanFF |= (int)*trans - 0xFF; *colorPtr++ = SkPreMultiplyARGB(*trans++, palette->red, palette->green, palette->blue); palette++; } reallyHasAlpha |= (transLessThanFF < 0); for (; index < num_palette; index++) { *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue); palette++; } // see BUGGY IMAGE WORKAROUND comment above if (num_palette < 256) { *colorPtr = colorPtr[-1]; } colorTable->unlockColors(true); } SkAutoUnref aur(colorTable); if (!this->allocPixelRef(decodedBitmap, colorTable)) { delete colorTable; return false; } SkAutoLockPixels alp(*decodedBitmap); /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ // if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) // ; // 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) */ if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) { png_set_filler(png_ptr, 0xff, 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: */ const int number_passes = interlace_type != PNG_INTERLACE_NONE ? png_set_interlace_handling(png_ptr) : 1; /* 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); if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) { for (int i = 0; i < number_passes; i++) { for (png_uint_32 y = 0; y < origHeight; y++) { uint8_t* bmRow = decodedBitmap->getAddr8(0, y); png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); } } } else { SkScaledBitmapSampler::SrcConfig sc; int srcBytesPerPixel = 4; if (SkBitmap::kIndex8_Config == config) { sc = SkScaledBitmapSampler::kIndex; srcBytesPerPixel = 1; } else if (hasAlpha) { sc = SkScaledBitmapSampler::kRGBA; } else { sc = SkScaledBitmapSampler::kRGBX; } SkAutoMalloc storage(origWidth * srcBytesPerPixel); const int height = decodedBitmap->height(); for (int i = 0; i < number_passes; i++) { if (!sampler.begin(decodedBitmap, sc, doDither)) { return false; } uint8_t* srcRow = (uint8_t*)storage.get(); skip_src_rows(png_ptr, srcRow, sampler.srcY0()); for (int y = 0; y < height; y++) { uint8_t* tmp = srcRow; png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); reallyHasAlpha |= sampler.next(srcRow); if (y < height - 1) { skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1); } } // skip the rest of the rows (if any) png_uint_32 read = (height - 1) * sampler.srcDY() + sampler.srcY0() + 1; SkASSERT(read <= origHeight); skip_src_rows(png_ptr, srcRow, origHeight - read); } if (hasAlpha && !reallyHasAlpha) { SkDEBUGF(("Image doesn't really have alpha [%d %d]\n", origWidth, origHeight)); } } /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); decodedBitmap->setIsOpaque(!reallyHasAlpha); return true; }
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; }
static int ReadPNG(FILE* in_file, WebPPicture* const pic, int keep_alpha) { png_structp png; png_infop info; int color_type, bit_depth, interlaced; int has_alpha; int num_passes; int p; int ok = 0; png_uint_32 width, height, y; int stride; uint8_t* rgb = NULL; png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (png == NULL) { goto End; } png_set_error_fn(png, 0, error_function, NULL); if (setjmp(png_jmpbuf(png))) { Error: png_destroy_read_struct(&png, NULL, NULL); if (rgb) free(rgb); goto End; } info = png_create_info_struct(png); if (info == NULL) goto Error; png_init_io(png, in_file); png_read_info(png, info); if (!png_get_IHDR(png, info, &width, &height, &bit_depth, &color_type, &interlaced, NULL, NULL)) goto Error; png_set_strip_16(png); png_set_packing(png); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); if (color_type == PNG_COLOR_TYPE_GRAY) { if (bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(png); } png_set_gray_to_rgb(png); } if (png_get_valid(png, info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png); has_alpha = 1; } else { has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA); } if (!keep_alpha) { png_set_strip_alpha(png); has_alpha = 0; } #ifdef WEBP_EXPERIMENTAL_FEATURES if (has_alpha) { pic->colorspace |= WEBP_CSP_ALPHA_BIT; } #endif num_passes = png_set_interlace_handling(png); png_read_update_info(png, info); stride = (has_alpha ? 4 : 3) * width * sizeof(*rgb); rgb = (uint8_t*)malloc(stride * height); if (rgb == NULL) goto Error; for (p = 0; p < num_passes; ++p) { for (y = 0; y < height; ++y) { png_bytep row = rgb + y * stride; png_read_rows(png, &row, NULL, 1); } } png_read_end(png, info); png_destroy_read_struct(&png, &info, NULL); pic->width = width; pic->height = height; ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, stride) : WebPPictureImportRGB(pic, rgb, stride); free(rgb); End: return ok; }
/** The constructor loads the named PNG image from the given png filename. <P>The destructor free all memory and server resources that are used by the image. */ void LoadPNG(const char *png) // I - File to read { int i; // Looping var FILE *fp; // File pointer int channels; // Number of color channels png_structp pp; // PNG read pointer png_infop info; // PNG info pointers png_bytep *rows; // PNG row pointers // Open the PNG file... if ((fp = fopen(png, "rb")) == NULL) return; // Setup the PNG data structures... pp = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info = png_create_info_struct(pp); if (setjmp(pp->jmpbuf)) { int debug = 1; return; } // Initialize the PNG read "engine"... png_init_io(pp, fp); // Get the image dimensions and convert to grayscale or RGB... png_read_info(pp, info); if (info->color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(pp); if (info->color_type & PNG_COLOR_MASK_COLOR) channels = 3; else channels = 1; if ((info->color_type & PNG_COLOR_MASK_ALPHA) || info->num_trans) channels ++; int w = (int)(info->width); int h = (int)(info->height); int d = channels; pictureWidth = w; pictureHeight = h; if (info->bit_depth < 8) { png_set_packing(pp); png_set_expand(pp); } else if (info->bit_depth == 16) png_set_strip_16(pp); # if defined(HAVE_PNG_GET_VALID) && defined(HAVE_PNG_SET_TRNS_TO_ALPHA) // Handle transparency... if (png_get_valid(pp, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(pp); # endif // HAVE_PNG_GET_VALID && HAVE_PNG_SET_TRNS_TO_ALPHA unsigned char *array = (unsigned char *)pictureS; // Allocate pointers... rows = new png_bytep[h]; for (i = 0; i < h; i ++) rows[i] = (png_bytep)(array + i * w * d); // we flip it // Read the image, handling interlacing as needed... for (i = png_set_interlace_handling(pp); i > 0; i --) png_read_rows(pp, rows, NULL, h); #ifdef WIN32 // Some Windows graphics drivers don't honor transparency when RGB == white if (channels == 4) { // Convert RGB to 0 when alpha == 0... unsigned char *ptr = (unsigned char *)array; for (i = w * h; i > 0; i --, ptr += 4) if (!ptr[3]) ptr[0] = ptr[1] = ptr[2] = 0; } #endif // WIN32 if (channels == 3) { unsigned char *array2 = new unsigned char[pictureWidth * pictureHeight * 4]; for (int i = w * h - 1; i >= 0; --i) { array2[i*4+0] = array[i*3+0]; array2[i*4+1] = array[i*3+1]; array2[i*4+2] = array[i*3+2]; array2[i*4+3] = 255; } memcpy(array, array2, w * h * 4); delete[] array2; } // Free memory and return... delete[] rows; png_read_end(pp, info); png_destroy_read_struct(&pp, &info, NULL); fclose(fp); }
// PNG 8/24/32 bits my_image *loadPNG(boost::filesystem::path & aPath, int nbytes, bool for_bmp, bool inverse) { if ( nbytes != 0 && nbytes != 1 && nbytes != 3 && nbytes != 4 ) return NULL; FILE *fp; fopen_s(&fp, aPath.file_string().data(), "rb"); if (!fp) return NULL; // read header char header[8]; fread(header, 1, 8, fp); if (png_sig_cmp((png_bytep)header, 0, 8)) { // not a PNG file fclose(fp); return NULL; } // create and initialize the png_struct png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fclose(fp); return NULL; } // allocate the memory for image information 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); fclose(fp); return NULL; } 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); return NULL; } // set up the input control (use standard C streams) png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); // read information from the PNG file png_read_info(png_ptr, info_ptr); // bytes per pixel in stored image int samples; png_byte color_type = info_ptr->color_type; png_byte bit_depth = info_ptr->bit_depth; // interlacing temporary not supported if ( info_ptr->interlace_type != PNG_INTERLACE_NONE ) { png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); fclose(fp); return NULL; } //strip 16 bit/color files down to 8 bits/color if (bit_depth == 16) png_set_strip_16(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 colors into true RGB triplets if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); switch (color_type) { case PNG_COLOR_TYPE_GRAY: samples = 1; break; case PNG_COLOR_TYPE_PALETTE: color_type = PNG_COLOR_TYPE_RGB; samples = 3; break; case PNG_COLOR_TYPE_RGB: samples = 3; break; case PNG_COLOR_TYPE_RGBA: case PNG_COLOR_TYPE_GRAY_ALPHA: samples = 4; break; default: // unknown color type png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); fclose(fp); return NULL; break; } if (nbytes == 0) nbytes = samples; if (nbytes == 1) { // convert an RGB or RGBA image to grayscale or grayscale with alpha if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) png_set_rgb_to_gray_fixed(png_ptr, 1, 21268, 71514); // strip alpha bytes if (color_type & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(png_ptr); } if (nbytes == 3) { // convert a grayscale image to RGB if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); // strip alpha bytes if (color_type & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(png_ptr); } if (nbytes == 4) { // convert a grayscale image to RGB if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); // add alpha bytes if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) png_set_add_alpha(png_ptr, 255, PNG_FILLER_AFTER); } // call to update the users info_ptr structure png_read_update_info(png_ptr, info_ptr); // allocate memory for one row png_byte *row_pointer = (png_byte*) malloc(info_ptr->rowbytes); // create new image my_image *image = image_create(info_ptr->width, info_ptr->height, nbytes, for_bmp); // can't allocate memory if ( !image || !row_pointer ) { png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); fclose(fp); if (row_pointer) free(row_pointer); if (image) image_release(image); return NULL; } // length of row in new image int rowlen = image->width * image->nbytes; int height = image->height; int step = image->step; UCHAR *dst = image->data; if (inverse) { dst = image->data + (height - 1) * step; step = -step; } // TODO: add interlacing support // //turn on interlace handling //int number_of_passes = png_set_interlace_handling(png_ptr); // //for interlaced image (temporary, not so good !!! ) //for (int pass = 0; pass < number_of_passes - 1; pass++) // for (j = 0; j < height; j++) // png_read_rows(png_ptr, &row_pointer, png_bytepp_NULL, 1); for (int j = 0; j < height; j++) { png_read_rows(png_ptr, &row_pointer, png_bytepp_NULL, 1); memcpy(dst, (UCHAR*)row_pointer, rowlen); dst += step; } if (row_pointer) free(row_pointer); // read rest of file, and get additional chunks in info_ptr png_read_end(png_ptr, info_ptr); // clean up after the read, and free any memory allocated png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); fclose(fp); return image; }
bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap, Mode mode) { png_structp png_ptr; png_infop info_ptr; if (onDecodeInit(sk_stream, &png_ptr, &info_ptr) == false) { return false; } if (setjmp(png_jmpbuf(png_ptr))) { return false; } PNGAutoClean autoClean(png_ptr, info_ptr); png_uint_32 origWidth, origHeight; int bit_depth, color_type, interlace_type; png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL); SkBitmap::Config config; bool hasAlpha = false; bool doDither = this->getDitherImage(); SkPMColor theTranspColor = 0; // 0 tells us not to try to match if (getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha, &doDither, &theTranspColor) == false) { return false; } const int sampleSize = this->getSampleSize(); SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize); decodedBitmap->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight(), 0); if (SkImageDecoder::kDecodeBounds_Mode == mode) { return true; } // from here down we are concerned with colortables and pixels // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we // draw lots faster if we can flag the bitmap has being opaque bool reallyHasAlpha = false; SkColorTable* colorTable = NULL; if (color_type == PNG_COLOR_TYPE_PALETTE) { decodePalette(png_ptr, info_ptr, &hasAlpha, &reallyHasAlpha, &colorTable); } SkAutoUnref aur(colorTable); if (!this->allocPixelRef(decodedBitmap, SkBitmap::kIndex8_Config == config ? colorTable : NULL)) { return false; } SkAutoLockPixels alp(*decodedBitmap); /* Add filler (or alpha) byte (before/after each RGB triplet) */ if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) { png_set_filler(png_ptr, 0xff, 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: */ const int number_passes = interlace_type != PNG_INTERLACE_NONE ? png_set_interlace_handling(png_ptr) : 1; /* 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); if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) { for (int i = 0; i < number_passes; i++) { for (png_uint_32 y = 0; y < origHeight; y++) { uint8_t* bmRow = decodedBitmap->getAddr8(0, y); png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); } } } else { SkScaledBitmapSampler::SrcConfig sc; int srcBytesPerPixel = 4; if (colorTable != NULL) { sc = SkScaledBitmapSampler::kIndex; srcBytesPerPixel = 1; } else if (hasAlpha) { sc = SkScaledBitmapSampler::kRGBA; } else { sc = SkScaledBitmapSampler::kRGBX; } /* We have to pass the colortable explicitly, since we may have one even if our decodedBitmap doesn't, due to the request that we upscale png's palette to a direct model */ SkAutoLockColors ctLock(colorTable); if (!sampler.begin(decodedBitmap, sc, doDither, ctLock.colors())) { return false; } const int height = decodedBitmap->height(); if (number_passes > 1) { SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel); uint8_t* base = (uint8_t*)storage.get(); size_t rb = origWidth * srcBytesPerPixel; for (int i = 0; i < number_passes; i++) { uint8_t* row = base; for (png_uint_32 y = 0; y < origHeight; y++) { uint8_t* bmRow = row; png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); row += rb; } } // now sample it base += sampler.srcY0() * rb; for (int y = 0; y < height; y++) { reallyHasAlpha |= sampler.next(base); base += sampler.srcDY() * rb; } } else { SkAutoMalloc storage(origWidth * srcBytesPerPixel); uint8_t* srcRow = (uint8_t*)storage.get(); skip_src_rows(png_ptr, srcRow, sampler.srcY0()); for (int y = 0; y < height; y++) { uint8_t* tmp = srcRow; png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); reallyHasAlpha |= sampler.next(srcRow); if (y < height - 1) { skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1); } } // skip the rest of the rows (if any) png_uint_32 read = (height - 1) * sampler.srcDY() + sampler.srcY0() + 1; SkASSERT(read <= origHeight); skip_src_rows(png_ptr, srcRow, origHeight - read); } } /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); if (0 != theTranspColor) { reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor); } decodedBitmap->setIsOpaque(!reallyHasAlpha); return true; }
static unsigned char* _load_image_RGBA_png(const char *fileName, int *width, int *height) { // open the file FILE *fp = fopen(fileName, "rb"); if (!fp) return _load_img_error(width, height); // read the header const size_t HEADER_LENGTH = 8; png_byte header[HEADER_LENGTH]; size_t n = fread(header, 1, HEADER_LENGTH, fp); if (n != HEADER_LENGTH || png_sig_cmp(header, 0, HEADER_LENGTH)) return _load_img_error(width, height); // try to create the loading structures png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (!png_ptr) { fclose(fp); return _load_img_error(width, height); } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp) 0, (png_infopp) 0); fclose(fp); return _load_img_error(width, height); } png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)0); fclose(fp); return _load_img_error(width, height); } if (setjmp(png_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); return _load_img_error(width, height); } // start the io png_init_io(png_ptr, fp); // indicate that we have already read some of the hearder png_set_sig_bytes(png_ptr, HEADER_LENGTH); // read the image info, get some info png_read_info(png_ptr, info_ptr); *width = png_get_image_width(png_ptr, info_ptr); *height = png_get_image_height(png_ptr, info_ptr); int bit_depth = png_get_bit_depth(png_ptr, info_ptr); png_byte color_type = png_get_color_type(png_ptr, info_ptr); // force the image into RGBA, 8 bits per channel if (color_type != PNG_COLOR_TYPE_RGBA) png_set_expand(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); else if (bit_depth == 16) png_set_strip_16(png_ptr); if (color_type != PNG_COLOR_TYPE_RGBA) png_set_filler(png_ptr, 255, PNG_FILLER_AFTER); png_read_update_info(png_ptr, info_ptr); // make sure we're actually in rgba mode if ((int)png_get_rowbytes(png_ptr, info_ptr) != ((*width) * 4)) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); return _load_img_error(width, height); } // finally, read the file unsigned char *buffer = (unsigned char *) malloc((*width) * (*height) * 4); png_bytep *row_pointers = new png_bytep[*height]; for (int y = 0 ; y < (*height) ; y++) { row_pointers[y] = (png_byte *) (buffer + ((*height) - 1 - y) * (*width) * 4); } png_read_rows(png_ptr, row_pointers, 0, (long unsigned int) (*height)); // deallocate memory and return fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return buffer; }
int loadPNG(ePtr<gPixmap> &result, const char *filename) { __u8 header[8]; FILE *fp=fopen(filename, "rb"); if (!fp) { // eDebug("couldn't open %s", filename ); return 0; } if (!fread(header, 8, 1, fp)) { eDebug("couldn't read"); fclose(fp); return 0; } if (png_sig_cmp(header, 0, 8)) { fclose(fp); return 0; } png_structp png_ptr=png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (!png_ptr) { eDebug("no pngptr"); fclose(fp); return 0; } png_infop info_ptr=png_create_info_struct(png_ptr); if (!info_ptr) { eDebug("no info ptr"); png_destroy_read_struct(&png_ptr, (png_infopp)0, (png_infopp)0); fclose(fp); return 0; } png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { eDebug("no end"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fp); return 0; } if (setjmp(png_ptr->jmpbuf)) { eDebug("das war wohl nix"); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); result = 0; return 0; } png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); png_set_invert_alpha(png_ptr); png_read_info(png_ptr, info_ptr); png_uint_32 width, height; int bit_depth; int color_type; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); if (color_type == PNG_COLOR_TYPE_GRAY || color_type & PNG_COLOR_MASK_PALETTE) { result=new gPixmap(eSize(width, height), bit_depth); gSurface *surface = result->surface; png_bytep *rowptr=new png_bytep[height]; for (unsigned int i=0; i<height; i++) rowptr[i]=((png_byte*)(surface->data))+i*surface->stride; png_read_rows(png_ptr, rowptr, 0, height); delete [] rowptr; if (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) { png_color *palette; int num_palette; png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); if (num_palette) surface->clut.data=new gRGB[num_palette]; else surface->clut.data=0; surface->clut.colors=num_palette; for (int i=0; i<num_palette; i++) { surface->clut.data[i].a=0; surface->clut.data[i].r=palette[i].red; surface->clut.data[i].g=palette[i].green; surface->clut.data[i].b=palette[i].blue; } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_byte *trans; png_get_tRNS(png_ptr, info_ptr, &trans, &num_palette, 0); for (int i=0; i<num_palette; i++) surface->clut.data[i].a=255-trans[i]; } } else { surface->clut.data=0; surface->clut.colors=0; } surface->clut.start=0; png_read_end(png_ptr, end_info); #ifndef BUILD_VUPLUS } else { result=0; eDebug("%s: %dx%dx%d png, %d", filename, (int)width, (int)height, (int)bit_depth, color_type); } #else //csh Support for 32bit png file. }else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA && bit_depth == 8){
RADRT_API bool RADRT_CALL Decode(const void *buff, AddrSize buffLength, Image &out) { RAD_ASSERT(buff&&buffLength); RAD_ASSERT(buffLength <= std::numeric_limits<stream::SPos>::max()); out.Free(); stream::MemInputBuffer ib(buff, (stream::SPos)buffLength); stream::InputStream is(ib); { char sig[SigSize]; if (is.Read(sig, SigSize, 0) != SigSize) return false; // NOTE: png_sig_cmp() returns 0 if the sig matches the PNG sig. if (png_sig_cmp((png_bytep)sig, 0, SigSize)) return false; } png_structp png; png_infop info; png = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, 0, PNGErrorHandler, PNGWarningHandler, 0, PNGMalloc, PNGFree); if (!png) return false; info = png_create_info_struct(png); if (!info) { png_destroy_read_struct(&png, 0, 0); return false; } png_set_read_fn(png, &is, PNGRead); png_set_sig_bytes(png, SigSize); try { png_uint_32 w, h; int bd, color, interlace; png_read_info(png, info); png_get_IHDR(png, info, &w, &h, &bd, &color, &interlace, 0, 0); if (!out.AllocateFrames(1)||!out.AllocateMipmaps(0, 1)) { png_destroy_read_struct(&png, &info, 0); return false; } Mipmap &m = out.frames[0].mipmaps[0]; out.format = Format(png, info, bd, color); if (out.format == InvalidFormat) { out.Free(); png_destroy_read_struct(&png, &info, 0); return false; } out.bpp = FormatBPP(out.format); if (!out.AllocateMipmap(0, 0, w, h, w * out.bpp, w * h * out.bpp)) { out.Free(); png_destroy_read_struct(&png, &info, 0); return false; } png_set_strip_16(png); if (color == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png); } if (color == PNG_COLOR_TYPE_GRAY && bd < 8) { png_set_expand_gray_1_2_4_to_8(png); } if (png_get_valid(png, info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png); } png_set_swap(png); int passes = png_set_interlace_handling(png); png_bytep dstRow = 0; png_bytep imgRow = 0; png_uint_32 stride = (png_uint_32)png_get_rowbytes(png, info); RAD_ASSERT(stride >= m.stride); if (stride != m.stride) { dstRow = (png_bytep)safe_zone_malloc(ZImageCodec, stride, 0); } for (int pass = 0; pass < passes; ++pass) { if (stride == m.stride) { dstRow = (png_bytep)m.data; // reset. } imgRow = (png_bytep)m.data; for (png_uint_32 y = 0; y < h; ++y) { if (pass > 0 && stride != m.stride) { RAD_ASSERT(imgRow != dstRow); // interlaced image, copy the result of the last pass. memcpy(dstRow, imgRow, m.stride); } png_read_rows(png, &dstRow, 0, 1); if (stride != m.stride) { // imgRow/dstRow are correct, we are copying from dstRow to imgRow. memcpy(imgRow, dstRow, m.stride); } else { dstRow += m.stride; } imgRow += m.stride; } } if (stride != m.stride) { RAD_ASSERT(dstRow); zone_free(dstRow); } png_read_end(png, info); } catch (PNGException&) { out.Free(); png_destroy_read_struct(&png, &info, 0); return false; } png_destroy_read_struct(&png, &info, 0); return true; }
int ReadPNG(FILE* in_file, WebPPicture* const pic, int keep_alpha, Metadata* const metadata) { png_structp png; png_infop info = NULL; png_infop end_info = NULL; int color_type, bit_depth, interlaced; int has_alpha; int num_passes; int p; int ok = 0; png_uint_32 width, height, y; int stride; uint8_t* rgb = NULL; png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (png == NULL) { goto End; } png_set_error_fn(png, 0, error_function, NULL); if (setjmp(png_jmpbuf(png))) { Error: MetadataFree(metadata); png_destroy_read_struct(&png, &info, &end_info); goto End; } info = png_create_info_struct(png); if (info == NULL) goto Error; end_info = png_create_info_struct(png); if (end_info == NULL) goto Error; png_init_io(png, in_file); png_read_info(png, info); if (!png_get_IHDR(png, info, &width, &height, &bit_depth, &color_type, &interlaced, NULL, NULL)) goto Error; png_set_strip_16(png); png_set_packing(png); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { if (bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(png); } png_set_gray_to_rgb(png); } if (png_get_valid(png, info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png); has_alpha = 1; } else { has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA); } if (!keep_alpha) { png_set_strip_alpha(png); has_alpha = 0; } num_passes = png_set_interlace_handling(png); png_read_update_info(png, info); stride = (has_alpha ? 4 : 3) * width * sizeof(*rgb); rgb = (uint8_t*)malloc(stride * height); if (rgb == NULL) goto Error; for (p = 0; p < num_passes; ++p) { for (y = 0; y < height; ++y) { png_bytep row = rgb + y * stride; png_read_rows(png, &row, NULL, 1); } } png_read_end(png, end_info); if (metadata != NULL && !ExtractMetadataFromPNG(png, info, end_info, metadata)) { fprintf(stderr, "Error extracting PNG metadata!\n"); goto Error; } png_destroy_read_struct(&png, &info, &end_info); pic->width = width; pic->height = height; ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, stride) : WebPPictureImportRGB(pic, rgb, stride); if (!ok) { goto Error; } End: free(rgb); return ok; }
PyObject * load_png_fast_progressive (char *filename, PyObject *get_buffer_callback) { // Note: we are not using the method that libpng calls "Reading PNG // files progressively". That method would involve feeding the data // into libpng piece by piece, which is not necessary if we can give // libpng a simple FILE pointer. png_structp png_ptr = NULL; png_infop info_ptr = NULL; PyObject * result = NULL; FILE *fp = NULL; uint32_t width, height; uint32_t rows_left; png_byte color_type; png_byte bit_depth; bool have_alpha; char *cm_processing = NULL; // ICC profile-based colour conversion data. png_charp icc_profile_name = NULL; int icc_compression_type = 0; #if PNG_LIBPNG_VER < 10500 // 1.5.0beta36, according to libpng CHANGES png_charp icc_profile = NULL; #else png_bytep icc_profile = NULL; #endif png_uint_32 icc_proflen = 0; // The sRGB flag has an intent field, which we ignore - // the target gamut is sRGB already. int srgb_intent = 0; // Generic RGB space conversion params. // The assumptions we're making are those of sRGB, // but they'll be overridden by gammas or primaries in the file if used. bool generic_rgb_have_gAMA = false; bool generic_rgb_have_cHRM = false; double generic_rgb_file_gamma = 45455 / PNG_gAMA_scale; double generic_rgb_white_x = 31270 / PNG_cHRM_scale; double generic_rgb_white_y = 32900 / PNG_cHRM_scale; double generic_rgb_red_x = 64000 / PNG_cHRM_scale; double generic_rgb_red_y = 33000 / PNG_cHRM_scale; double generic_rgb_green_x = 30000 / PNG_cHRM_scale; double generic_rgb_green_y = 60000 / PNG_cHRM_scale; double generic_rgb_blue_x = 15000 / PNG_cHRM_scale; double generic_rgb_blue_y = 6000 / PNG_cHRM_scale; // Indicates the case where no CM information was present in the file and we // treated it as sRGB. bool possible_legacy_png = false; // LCMS stuff cmsHPROFILE input_buffer_profile = NULL; cmsHPROFILE nparray_data_profile = cmsCreate_sRGBProfile(); cmsHTRANSFORM input_buffer_to_nparray = NULL; cmsToneCurve *gamma_transfer_func = NULL; cmsUInt32Number input_buffer_format = 0; cmsSetLogErrorHandler(log_lcms2_error); fp = fopen(filename, "rb"); if (!fp) { PyErr_SetFromErrno(PyExc_IOError); //PyErr_Format(PyExc_IOError, "Could not open PNG file for writing: %s", // filename); goto cleanup; } png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, (png_voidp)NULL, png_read_error_callback, NULL); if (!png_ptr) { PyErr_SetString(PyExc_MemoryError, "png_create_write_struct() failed"); goto cleanup; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { PyErr_SetString(PyExc_MemoryError, "png_create_info_struct() failed"); goto cleanup; } if (setjmp(png_jmpbuf(png_ptr))) { goto cleanup; } png_init_io(png_ptr, fp); png_read_info(png_ptr, info_ptr); // If there's an embedded ICC profile, use it in preference to any other // colour management information present. if (png_get_iCCP (png_ptr, info_ptr, &icc_profile_name, &icc_compression_type, &icc_profile, &icc_proflen)) { input_buffer_profile = cmsOpenProfileFromMem(icc_profile, icc_proflen); if (! input_buffer_profile) { PyErr_SetString(PyExc_MemoryError, "cmsOpenProfileFromMem() failed"); goto cleanup; } cm_processing = "iCCP (use embedded colour profile)"; } // Shorthand for sRGB. else if (png_get_sRGB (png_ptr, info_ptr, &srgb_intent)) { input_buffer_profile = cmsCreate_sRGBProfile(); cm_processing = "sRGB (explicit sRGB chunk)"; } else { // We might have generic RGB transformation information in the form of // the chromaticities for R, G and B and a generic gamma curve. if (png_get_cHRM (png_ptr, info_ptr, &generic_rgb_white_x, &generic_rgb_white_y, &generic_rgb_red_x, &generic_rgb_red_y, &generic_rgb_green_x, &generic_rgb_green_y, &generic_rgb_blue_x, &generic_rgb_blue_y)) { generic_rgb_have_cHRM = true; } if (png_get_gAMA(png_ptr, info_ptr, &generic_rgb_file_gamma)) { generic_rgb_have_gAMA = true; } if (generic_rgb_have_gAMA || generic_rgb_have_cHRM) { cmsCIExyYTRIPLE primaries = {{generic_rgb_red_x, generic_rgb_red_y}, {generic_rgb_green_x, generic_rgb_green_y}, {generic_rgb_blue_x, generic_rgb_blue_y}}; cmsCIExyY white_point = {generic_rgb_white_x, generic_rgb_white_y}; gamma_transfer_func = cmsBuildGamma(NULL, 1.0/generic_rgb_file_gamma); cmsToneCurve *transfer_funcs[3] = {gamma_transfer_func, gamma_transfer_func, gamma_transfer_func }; input_buffer_profile = cmsCreateRGBProfile(&white_point, &primaries, transfer_funcs); cm_processing = "cHRM and/or gAMA (generic RGB space)"; } // Possible legacy PNG, or rather one which might have been written with an // old version of MyPaint. Treat as sRGB, but flag the strangeness because // it might be important for PNGs in old OpenRaster files. else { possible_legacy_png = true; input_buffer_profile = cmsCreate_sRGBProfile(); cm_processing = "sRGB (no CM chunks present)"; } } if (png_get_interlace_type (png_ptr, info_ptr) != PNG_INTERLACE_NONE) { PyErr_SetString(PyExc_RuntimeError, "Interlaced PNG files are not supported!"); goto cleanup; } color_type = png_get_color_type(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); have_alpha = color_type & PNG_COLOR_MASK_ALPHA; if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(png_ptr); } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); have_alpha = true; } if (bit_depth < 8) { png_set_packing(png_ptr); } if (!have_alpha) { png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER); } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); } png_read_update_info(png_ptr, info_ptr); // Verify what we have done bit_depth = png_get_bit_depth(png_ptr, info_ptr); if (! (bit_depth == 8 || bit_depth == 16)) { PyErr_SetString(PyExc_RuntimeError, "Failed to convince libpng to convert " "to 8 or 16 bits per channel"); goto cleanup; } if (png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_RGB_ALPHA) { PyErr_SetString(PyExc_RuntimeError, "Failed to convince libpng to convert " "to RGBA (wrong color_type)"); goto cleanup; } if (png_get_channels(png_ptr, info_ptr) != 4) { PyErr_SetString(PyExc_RuntimeError, "Failed to convince libpng to convert " "to RGBA (wrong number of channels)"); goto cleanup; } // PNGs use network byte order, i.e. big-endian in descending order // of bit significance. LittleCMS uses whatever's detected for the compiler. // ref: http://www.w3.org/TR/2003/REC-PNG-20031110/#7Integers-and-byte-order if (bit_depth == 16) { #ifdef CMS_USE_BIG_ENDIAN input_buffer_format = TYPE_RGBA_16; #else input_buffer_format = TYPE_RGBA_16_SE; #endif } else { input_buffer_format = TYPE_RGBA_8; } input_buffer_to_nparray = cmsCreateTransform (input_buffer_profile, input_buffer_format, nparray_data_profile, TYPE_RGBA_8, INTENT_PERCEPTUAL, 0); width = png_get_image_width(png_ptr, info_ptr); height = png_get_image_height(png_ptr, info_ptr); rows_left = height; while (rows_left) { PyObject *pyarr = NULL; uint32_t rows = 0; uint32_t row = 0; const uint8_t input_buf_bytes_per_pixel = (bit_depth==8) ? 4 : 8; const uint32_t input_buf_row_stride = sizeof(png_byte) * width * input_buf_bytes_per_pixel; png_byte *input_buffer = NULL; png_bytep *input_buf_row_pointers = NULL; pyarr = PyObject_CallFunction(get_buffer_callback, "ii", width, height); if (! pyarr) { PyErr_Format(PyExc_RuntimeError, "Get-buffer callback failed"); goto cleanup; } #ifdef HEAVY_DEBUG //assert(PyArray_ISCARRAY(arr)); assert(PyArray_NDIM(pyarr) == 3); assert(PyArray_DIM(pyarr, 1) == width); assert(PyArray_DIM(pyarr, 2) == 4); assert(PyArray_TYPE(pyarr) == NPY_UINT8); assert(PyArray_ISBEHAVED(pyarr)); assert(PyArray_STRIDE(pyarr, 1) == 4*sizeof(uint8_t)); assert(PyArray_STRIDE(pyarr, 2) == sizeof(uint8_t)); #endif rows = PyArray_DIM(pyarr, 0); if (rows > rows_left) { PyErr_Format(PyExc_RuntimeError, "Attempt to read %d rows from the PNG, " "but only %d are left", rows, rows_left); goto cleanup; } input_buffer = (png_byte *) malloc(rows * input_buf_row_stride); input_buf_row_pointers = (png_bytep *)malloc(rows * sizeof(png_bytep)); for (row=0; row<rows; row++) { input_buf_row_pointers[row] = input_buffer + (row * input_buf_row_stride); } png_read_rows(png_ptr, input_buf_row_pointers, NULL, rows); rows_left -= rows; for (row=0; row<rows; row++) { uint8_t *pyarr_row = (uint8_t *)PyArray_DATA(pyarr) + row*PyArray_STRIDE(pyarr, 0); uint8_t *input_row = input_buf_row_pointers[row]; // Really minimal fake colour management. Just remaps to sRGB. cmsDoTransform(input_buffer_to_nparray, input_row, pyarr_row, width); // lcms2 ignores alpha, so copy that verbatim // If it's 8bpc RGBA, use A. // If it's 16bpc RrGgBbAa, use A. for (uint32_t i=0; i<width; ++i) { const uint32_t pyarr_alpha_byte = (i*4) + 3; const uint32_t buf_alpha_byte = (i*input_buf_bytes_per_pixel) + ((bit_depth==8) ? 3 : 6); pyarr_row[pyarr_alpha_byte] = input_row[buf_alpha_byte]; } } free(input_buf_row_pointers); free(input_buffer); Py_DECREF(pyarr); } png_read_end(png_ptr, NULL); result = Py_BuildValue("{s:b,s:i,s:i,s:s}", "possible_legacy_png", possible_legacy_png, "width", width, "height", height, "cm_conversions_applied", cm_processing); cleanup: if (info_ptr) png_destroy_read_struct (&png_ptr, &info_ptr, NULL); // libpng's style is to free internally allocated stuff like the icc // tables in png_destroy_*(). I think. if (fp) fclose(fp); if (input_buffer_profile) cmsCloseProfile(input_buffer_profile); if (nparray_data_profile) cmsCloseProfile(nparray_data_profile); if (input_buffer_to_nparray) cmsDeleteTransform(input_buffer_to_nparray); if (gamma_transfer_func) cmsFreeToneCurve(gamma_transfer_func); return result; }
int ReadPNG(const uint8_t* const data, size_t data_size, struct WebPPicture* const pic, int keep_alpha, struct Metadata* const metadata) { volatile png_structp png = NULL; volatile png_infop info = NULL; volatile png_infop end_info = NULL; PNGReadContext context = { NULL, 0, 0 }; int color_type, bit_depth, interlaced; int has_alpha; int num_passes; int p; volatile int ok = 0; png_uint_32 width, height, y; int64_t stride; uint8_t* volatile rgb = NULL; if (data == NULL || data_size == 0 || pic == NULL) return 0; context.data = data; context.data_size = data_size; png = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL, NULL, MallocFunc, FreeFunc); if (png == NULL) goto End; png_set_error_fn(png, 0, error_function, NULL); if (setjmp(png_jmpbuf(png))) { Error: MetadataFree(metadata); goto End; } info = png_create_info_struct(png); if (info == NULL) goto Error; end_info = png_create_info_struct(png); if (end_info == NULL) goto Error; png_set_read_fn(png, &context, ReadFunc); png_read_info(png, info); if (!png_get_IHDR(png, info, &width, &height, &bit_depth, &color_type, &interlaced, NULL, NULL)) goto Error; png_set_strip_16(png); png_set_packing(png); if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png); } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { if (bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(png); } png_set_gray_to_rgb(png); } if (png_get_valid(png, info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png); has_alpha = 1; } else { has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA); } // Apply gamma correction if needed. { double image_gamma = 1 / 2.2, screen_gamma = 2.2; int srgb_intent; if (png_get_sRGB(png, info, &srgb_intent) || png_get_gAMA(png, info, &image_gamma)) { png_set_gamma(png, screen_gamma, image_gamma); } } if (!keep_alpha) { png_set_strip_alpha(png); has_alpha = 0; } num_passes = png_set_interlace_handling(png); png_read_update_info(png, info); stride = (int64_t)(has_alpha ? 4 : 3) * width * sizeof(*rgb); if (stride != (int)stride || !ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) { goto Error; } rgb = (uint8_t*)malloc((size_t)stride * height); if (rgb == NULL) goto Error; for (p = 0; p < num_passes; ++p) { png_bytep row = rgb; for (y = 0; y < height; ++y) { png_read_rows(png, &row, NULL, 1); row += stride; } } png_read_end(png, end_info); if (metadata != NULL && !ExtractMetadataFromPNG(png, info, end_info, metadata)) { fprintf(stderr, "Error extracting PNG metadata!\n"); goto Error; } pic->width = (int)width; pic->height = (int)height; ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, (int)stride) : WebPPictureImportRGB(pic, rgb, (int)stride); if (!ok) { goto Error; } End: if (png != NULL) { png_destroy_read_struct((png_structpp)&png, (png_infopp)&info, (png_infopp)&end_info); } free(rgb); return ok; }
bool PNG::Decode (Resource *resource, ImageBuffer *imageBuffer) { unsigned char png_sig[PNG_SIG_SIZE]; png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int bit_depth, color_type, interlace_type; FILE_HANDLE *file = NULL; if (resource->path) { file = lime::fopen (resource->path, "rb"); if (!file) return false; int read = lime::fread (png_sig, PNG_SIG_SIZE, 1, file); if (png_sig_cmp (png_sig, 0, PNG_SIG_SIZE)) { lime::fclose (file); return false; } } else { memcpy (png_sig, resource->data->Bytes (), PNG_SIG_SIZE); if (png_sig_cmp (png_sig, 0, PNG_SIG_SIZE)) { return false; } } if ((png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) == NULL) { if (file) lime::fclose (file); return false; } if ((info_ptr = png_create_info_struct (png_ptr)) == NULL) { png_destroy_read_struct (&png_ptr, (png_infopp)NULL, (png_infopp)NULL); if (file) lime::fclose (file); return false; } // sets the point which libpng will jump back to in the case of an error if (setjmp (png_jmpbuf (png_ptr))) { png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL); if (file) lime::fclose (file); return false; } if (file) { if (file->isFile ()) { png_init_io (png_ptr, file->getFile ()); png_set_sig_bytes (png_ptr, PNG_SIG_SIZE); } else { ByteArray data = ByteArray (resource->path); ReadBuffer buffer (data.Bytes (), data.Size ()); png_set_read_fn (png_ptr, &buffer, user_read_data_fn); } } else { ReadBuffer buffer (resource->data->Bytes (), resource->data->Size ()); png_set_read_fn (png_ptr, &buffer, user_read_data_fn); } png_read_info (png_ptr, info_ptr); png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); //bool has_alpha = (color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_RGB_ALPHA || png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)); png_set_expand (png_ptr); png_set_filler (png_ptr, 0xff, PNG_FILLER_AFTER); //png_set_gray_1_2_4_to_8 (png_ptr); png_set_palette_to_rgb (png_ptr); png_set_gray_to_rgb (png_ptr); if (bit_depth < 8) { png_set_packing (png_ptr); } else if (bit_depth == 16) { png_set_scale_16 (png_ptr); } //png_set_bgr (png_ptr); int bpp = 4; const unsigned int stride = width * bpp; imageBuffer->Resize (width, height, bpp); unsigned char *bytes = imageBuffer->data->Bytes (); int number_of_passes = png_set_interlace_handling (png_ptr); for (int pass = 0; pass < number_of_passes; pass++) { for (int i = 0; i < height; i++) { png_bytep anAddr = (png_bytep)(bytes + i * stride); png_read_rows (png_ptr, (png_bytepp) &anAddr, NULL, 1); } } png_read_end (png_ptr, NULL); png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL); if (file) lime::fclose (file); return true; }