int FilePNG::read_frame(VFrame *output, VFrame *input) { png_structp png_ptr; png_infop info_ptr; png_infop end_info = 0; int result = 0; int color_type; int color_depth; int colormodel; int size = input->get_compressed_size(); input->set_compressed_size(0); //printf("FilePNG::read_frame 1 %d %d\n", native_cmodel, output->get_color_model()); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); info_ptr = png_create_info_struct(png_ptr); png_set_read_fn(png_ptr, input, (png_rw_ptr)read_function); png_read_info(png_ptr, info_ptr); int png_color_type = png_get_color_type(png_ptr, info_ptr); if (png_color_type == PNG_COLOR_TYPE_GRAY || png_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); } colormodel = output->get_color_model(); color_type = png_get_color_type(png_ptr, info_ptr); color_depth = png_get_bit_depth(png_ptr,info_ptr); if (((native_cmodel == BC_RGBA16161616)||(native_cmodel == BC_RGB161616)) && ((colormodel == BC_RGBA8888)||(colormodel == BC_RGB888))) { png_set_strip_16(png_ptr); } /* If we're dropping the alpha channel, use the background color of the image otherwise, use black */ if (((native_cmodel == BC_RGBA16161616)||(native_cmodel == BC_RGBA8888)) && ((colormodel == BC_RGB161616)||(colormodel == BC_RGB888))) { png_color_16 my_background; png_color_16p image_background; memset(&my_background,0,sizeof(png_color_16)); if (png_get_bKGD(png_ptr, info_ptr, &image_background)) { png_set_background(png_ptr, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); } else { png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); } } /* Little endian */ if ((color_depth == 16) &&((colormodel == BC_RGBA16161616)||(colormodel == BC_RGB161616))) { png_set_swap(png_ptr); } if (!(color_type & PNG_COLOR_MASK_COLOR)) { png_set_gray_to_rgb(png_ptr); } if (color_type & PNG_COLOR_MASK_PALETTE) { png_set_palette_to_rgb(png_ptr); } if (color_depth <= 8) { png_set_expand(png_ptr); } /* read the image */ png_read_image(png_ptr, output->get_rows()); //printf("FilePNG::read_frame 3\n"); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); input->set_compressed_size(size); //printf("FilePNG::read_frame 4\n"); return result; }
int /* O - Read status */ _cupsImageReadPNG( cups_image_t *img, /* IO - cupsImage */ FILE *fp, /* I - cupsImage file */ cups_icspace_t primary, /* I - Primary choice for colorspace */ cups_icspace_t secondary, /* I - Secondary choice for colorspace */ int saturation, /* I - Color saturation (%) */ int hue, /* I - Color hue (degrees) */ const cups_ib_t *lut) /* I - Lookup table for gamma/brightness */ { int y; /* Looping var */ png_structp pp; /* PNG read pointer */ png_infop info; /* PNG info pointers */ png_uint_32 width, /* Width of image */ height; /* Height of image */ int bit_depth, /* Bit depth */ color_type, /* Color type */ interlace_type, /* Interlace type */ compression_type, /* Compression type */ filter_type; /* Filter type */ png_uint_32 xppm, /* X pixels per meter */ yppm; /* Y pixels per meter */ int bpp; /* Bytes per pixel */ int pass, /* Current pass */ passes; /* Number of passes required */ cups_ib_t *in, /* Input pixels */ *inptr, /* Pointer into pixels */ *out; /* Output pixels */ png_color_16 bg; /* Background color */ /* * Setup the PNG data structures... */ pp = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info = png_create_info_struct(pp); /* * Initialize the PNG read "engine"... */ png_init_io(pp, fp); /* * Get the image dimensions and load the output image... */ png_read_info(pp, info); png_get_IHDR(pp, info, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type); fprintf(stderr, "DEBUG: PNG image: %dx%dx%d, color_type=%x (%s%s%s)\n", (int)width, (int)height, bit_depth, color_type, (color_type & PNG_COLOR_MASK_COLOR) ? "RGB" : "GRAYSCALE", (color_type & PNG_COLOR_MASK_ALPHA) ? "+ALPHA" : "", (color_type & PNG_COLOR_MASK_PALETTE) ? "+PALETTE" : ""); if (color_type & PNG_COLOR_MASK_PALETTE) png_set_expand(pp); else if (bit_depth < 8) { png_set_packing(pp); png_set_expand(pp); } else if (bit_depth == 16) png_set_strip_16(pp); if (color_type & PNG_COLOR_MASK_COLOR) img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary; else img->colorspace = secondary; if (width == 0 || width > CUPS_IMAGE_MAX_WIDTH || height == 0 || height > CUPS_IMAGE_MAX_HEIGHT) { fprintf(stderr, "DEBUG: PNG image has invalid dimensions %ux%u!\n", (unsigned)width, (unsigned)height); fclose(fp); return (1); } img->xsize = width; img->ysize = height; if ((xppm = png_get_x_pixels_per_meter(pp, info)) != 0 && (yppm = png_get_y_pixels_per_meter(pp, info)) != 0) { img->xppi = (int)((float)xppm * 0.0254); img->yppi = (int)((float)yppm * 0.0254); if (img->xppi == 0 || img->yppi == 0) { fprintf(stderr, "DEBUG: PNG image has invalid resolution %dx%d PPI\n", img->xppi, img->yppi); img->xppi = img->yppi = 128; } } cupsImageSetMaxTiles(img, 0); passes = png_set_interlace_handling(pp); /* * Handle transparency... */ if (png_get_valid(pp, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(pp); bg.red = 65535; bg.green = 65535; bg.blue = 65535; png_set_background(pp, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); if (passes == 1) { /* * Load one row at a time... */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) in = malloc(img->xsize); else in = malloc(img->xsize * 3); } else { /* * Interlaced images must be loaded all at once... */ size_t bufsize; /* Size of buffer */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { bufsize = img->xsize * img->ysize; if ((bufsize / img->xsize) != img->ysize) { fprintf(stderr, "DEBUG: PNG image dimensions (%ux%u) too large!\n", (unsigned)width, (unsigned)height); fclose(fp); return (1); } } else { bufsize = img->xsize * img->ysize * 3; if ((bufsize / (img->xsize * 3)) != img->ysize) { fprintf(stderr, "DEBUG: PNG image dimensions (%ux%u) too large!\n", (unsigned)width, (unsigned)height); fclose(fp); return (1); } } in = malloc(bufsize); } bpp = cupsImageGetDepth(img); out = malloc(img->xsize * bpp); if (!in || !out) { fputs("DEBUG: Unable to allocate memory for PNG image!\n", stderr); if (in) free(in); if (out) free(out); fclose(fp); return (1); } /* * Read the image, interlacing as needed... */ for (pass = 1; pass <= passes; pass ++) for (inptr = in, y = 0; y < img->ysize; y ++) { png_read_row(pp, (png_bytep)inptr, NULL); if (pass == passes) { /* * Output this row... */ if (color_type & PNG_COLOR_MASK_COLOR) { if ((saturation != 100 || hue != 0) && bpp > 1) cupsImageRGBAdjust(inptr, img->xsize, saturation, hue); switch (img->colorspace) { case CUPS_IMAGE_WHITE : cupsImageRGBToWhite(inptr, out, img->xsize); break; case CUPS_IMAGE_RGB : case CUPS_IMAGE_RGB_CMYK : cupsImageRGBToRGB(inptr, out, img->xsize); break; case CUPS_IMAGE_BLACK : cupsImageRGBToBlack(inptr, out, img->xsize); break; case CUPS_IMAGE_CMY : cupsImageRGBToCMY(inptr, out, img->xsize); break; case CUPS_IMAGE_CMYK : cupsImageRGBToCMYK(inptr, out, img->xsize); break; } } else { switch (img->colorspace) { case CUPS_IMAGE_WHITE : memcpy(out, inptr, img->xsize); break; case CUPS_IMAGE_RGB : case CUPS_IMAGE_RGB_CMYK : cupsImageWhiteToRGB(inptr, out, img->xsize); break; case CUPS_IMAGE_BLACK : cupsImageWhiteToBlack(inptr, out, img->xsize); break; case CUPS_IMAGE_CMY : cupsImageWhiteToCMY(inptr, out, img->xsize); break; case CUPS_IMAGE_CMYK : cupsImageWhiteToCMYK(inptr, out, img->xsize); break; } } if (lut) cupsImageLut(out, img->xsize * bpp, lut); _cupsImagePutRow(img, 0, y, img->xsize, out); } if (passes > 1) { if (color_type & PNG_COLOR_MASK_COLOR) inptr += img->xsize * 3; else inptr += img->xsize; } } png_read_end(pp, info); png_destroy_read_struct(&pp, &info, NULL); fclose(fp); free(in); free(out); return (0); }
/* Read a PNG file. You may want to return an error code if the read * fails (depending upon the failure). There are two "prototypes" given * here - one where we are given the filename, and we need to open the * file, and the other where we are given an open file (possibly with * some or all of the magic bytes read - see comments above). */ #ifdef open_file /* prototype 1 */ void read_png(char *file_name) /* We need to open the file */ { png_structp png_ptr; png_infop info_ptr; unsigned int sig_read = 0; png_uint_32 width, height; int bit_depth, color_type, interlace_type; FILE *fp; if ((fp = fopen(file_name, "rb")) == NULL) return; #else no_open_file /* prototype 2 */ void read_png(FILE *fp, unsigned int sig_read) /* file is already open */ { png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int bit_depth, color_type, interlace_type; #endif no_open_file /* only use one prototype! */ /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also supply the * the compiler header file version, so that we know if the application * was compiled with a compatible version of the library. REQUIRED */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp user_error_ptr, user_error_fn, user_warning_fn); if (png_ptr == NULL) { fclose(fp); return; } /* Allocate/initialize the memory for image information. REQUIRED. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(fp); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return; } /* 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. */ #ifndef PNG_JMPBUF_SUPPORTED /* Old interface */ if (setjmp(png_ptr->jmpbuf)) #else /* New interface */ if (png_setjmp(png_ptr)) #endif { /* 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; } /* One of the following I/O initialization methods is REQUIRED */ #ifdef streams /* PNG file I/O method 1 */ /* Set up the input control if you are using standard C streams */ png_init_io(png_ptr, fp); #else no_streams /* PNG file I/O method 2 */ /* If you are using replacement read functions, instead of calling * png_init_io() here you would call: */ png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn); /* where user_io_ptr is a structure you want available to the callbacks */ #endif no_streams /* Use only one I/O method! */ /* If we have already read some of the signature */ png_set_sig_bytes(png_ptr, sig_read); #ifdef hilevel /* * If you have enough memory to read in the entire image at once, * and you need to specify only transforms that can be controlled * with one of the PNG_TRANSFORM_* bits (this presently excludes * dithering, filling, setting background, and doing gamma * adjustment), then you can read the entire image (including * pixels) into the info structure with this call: */ png_read_png(png_ptr, info_ptr, png_transforms, NULL); #else /* OK, you're doing it the hard way, with the lower-level functions */ /* The call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). REQUIRED */ png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); /**** Set up the data transformations you want. Note that these are all **** optional. Only call them if you want/need them. Many of the **** transformations only work on specific types of images, and many **** are mutually exclusive. ****/ /* tell libpng to strip 16 bit/color files down to 8 bits/color */ png_set_strip_16(png_ptr); /* Strip alpha bytes from the input data without combining with the * background (not recommended). */ png_set_strip_alpha(png_ptr); /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ png_set_packing(png_ptr); /* Change the order of packed pixels to least significant bit first * (not useful if you are using png_set_packing). */ png_set_packswap(png_ptr); /* Expand paletted colors into true RGB triplets */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(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(png_ptr); /* Expand paletted or RGB images with transparency to full alpha channels * so the data will be available as RGBA quartets. */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr); /* Set the background color to draw transparent and alpha images over. * It is possible to set the red, green, and blue components directly * for paletted images instead of supplying a palette index. Note that * even if the PNG file supplies a background, you are not required to * use it - you should use the (solid) application background if it has one. */ png_color_16 my_background, *image_background; if (png_get_bKGD(png_ptr, info_ptr, &image_background)) png_set_background(png_ptr, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); else png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); /* Some suggestions as to how to get a screen gamma value */ /* Note that screen gamma is the display_exponent, which includes * the CRT_exponent and any correction for viewing conditions */ if (/* We have a user-defined screen gamma value */) { screen_gamma = user-defined screen_gamma; } /* This is one way that applications share the same screen gamma value */ else if ((gamma_str = getenv("SCREEN_GAMMA")) != NULL)
unsigned char * ReadPNG(FILE *infile,int *width, int *height, XColor *colrs) { unsigned char *pixmap; unsigned char *p; png_byte *q; png_struct *png_ptr; png_info *info_ptr; double screen_gamma; png_byte *png_pixels=NULL, **row_pointers=NULL; int i, j; unsigned int packets; png_color std_color_cube[216]; /* first check to see if its a valid PNG file. If not, return. */ /* we assume that infile is a valid filepointer */ { int ret; png_byte buf[8]; ret = fread(buf, 1, 8, infile); if(ret != 8) return 0; ret = png_sig_cmp(buf, 0, 8); if(ret) return(0); } /* OK, it is a valid PNG file, so let's rewind it, and start decoding it */ rewind(infile); /* allocate the structures */ /*png_ptr = (png_struct *)malloc(sizeof(png_struct));*/ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png_ptr) return 0; /* initialize the structures */ info_ptr = png_create_info_struct(png_ptr); if(!info_ptr) { /*free(png_ptr);*/ return 0; } /* Establish the setjmp return context for png_error to use. */ if (setjmp(png_jmpbuf(png_ptr))) { #ifndef DISABLE_TRACE if (srcTrace) { fprintf(stderr, "\n!!!libpng read error!!!\n"); } #endif /*png_read_destroy(png_ptr, info_ptr, (png_info *)0); */ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); if(png_pixels != NULL) free((char *)png_pixels); if(row_pointers != NULL) free((png_byte **)row_pointers); /*free((char *)png_ptr);*/ free((char *)info_ptr); return 0; } #ifdef SAM_NO /* SWP -- Hopefully to fix cores on bad PNG files */ png_set_message_fn(png_ptr,png_get_msg_ptr(png_ptr),NULL,NULL); #endif /*png_read_init(png_ptr);*/ /* set up the input control */ png_init_io(png_ptr, infile); /* read the file information */ png_read_info(png_ptr, info_ptr); /* setup other stuff using the fields of png_info. */ *width = (int)png_ptr->width; *height = (int)png_ptr->height; #ifndef DISABLE_TRACE if (srcTrace) { fprintf(stderr,"\n\nBEFORE\nheight = %d\n", (int)png_ptr->width); fprintf(stderr,"width = %d\n", (int)png_ptr->height); fprintf(stderr,"bit depth = %d\n", info_ptr->bit_depth); fprintf(stderr,"color type = %d\n", info_ptr->color_type); fprintf(stderr,"compression type = %d\n", info_ptr->compression_type); fprintf(stderr,"filter type = %d\n", info_ptr->filter_type); fprintf(stderr,"interlace type = %d\n", info_ptr->interlace_type); fprintf(stderr,"num colors = %d\n",info_ptr->num_palette); fprintf(stderr,"rowbytes = %d\n", info_ptr->rowbytes); } #endif #if 0 /* This handles alpha and transparency by replacing it with a background value. */ /* its #if'ed out for now cause I don't have anything to test it with */ { png_color_16 my_background; if (info_ptr->valid & PNG_INFO_bKGD) png_set_background(png_ptr, &(info_ptr->background), PNG_GAMMA_FILE, 1, 1.0); else png_set_background(png_ptr, &my_background, PNG_GAMMA_SCREEN, 0, 1.0); } #endif /* strip pixels in 16-bit images down to 8 bits */ if (info_ptr->bit_depth == 16) png_set_strip_16(png_ptr); /* If it is a color image then check if it has a palette. If not then dither the image to 256 colors, and make up a palette */ if (info_ptr->color_type==PNG_COLOR_TYPE_RGB || info_ptr->color_type==PNG_COLOR_TYPE_RGB_ALPHA) { if(! (info_ptr->valid & PNG_INFO_PLTE)) { #ifndef DISABLE_TRACE if (srcTrace) { fprintf(stderr,"dithering (RGB->palette)...\n"); } #endif /* if there is is no valid palette, then we need to make one up */ for(i=0;i<216;i++) { /* 255.0/5 = 51 */ std_color_cube[i].red=(i%6)*51; std_color_cube[i].green=((i/6)%6)*51; std_color_cube[i].blue=(i/36)*51; } /* this should probably be dithering to Rdata.colors_per_inlined_image colors */ png_set_dither(png_ptr, std_color_cube, 216, 216, NULL, 1); } else { #ifndef DISABLE_TRACE if (srcTrace) { fprintf(stderr,"dithering (RGB->file supplied palette)...\n"); } #endif png_set_dither(png_ptr, info_ptr->palette, info_ptr->num_palette, get_pref_int(eCOLORS_PER_INLINED_IMAGE), info_ptr->hist, 1); } } /* PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as they can. This expands pixels to 1 pixel per byte, and if a transparency value is supplied, an alpha channel is built.*/ if (info_ptr->bit_depth < 8) png_set_packing(png_ptr); /* have libpng handle the gamma conversion */ if (get_pref_boolean(eUSE_SCREEN_GAMMA)) { /*SWP*/ if (info_ptr->bit_depth != 16) { /* temporary .. glennrp */ screen_gamma=(double)(get_pref_float(eSCREEN_GAMMA)); #ifndef DISABLE_TRACE if (srcTrace) { fprintf(stderr,"screen gamma=%f\n",screen_gamma); } #endif if (info_ptr->valid & PNG_INFO_gAMA) { #ifndef DISABLE_TRACE if (srcTrace) { printf("setting gamma=%f\n",info_ptr->gamma); } #endif png_set_gamma(png_ptr, screen_gamma, (double)info_ptr->gamma); } else { #ifndef DISABLE_TRACE if (srcTrace) { fprintf(stderr,"setting gamma=%f\n",0.45); } #endif png_set_gamma(png_ptr, screen_gamma, (double)0.45); } } } if (info_ptr->interlace_type) png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); #ifndef DISABLE_TRACE if (srcTrace) { fprintf(stderr,"\n\nAFTER\nheight = %d\n", (int)png_ptr->width); fprintf(stderr,"width = %d\n", (int)png_ptr->height); fprintf(stderr,"bit depth = %d\n", info_ptr->bit_depth); fprintf(stderr,"color type = %d\n", info_ptr->color_type); fprintf(stderr,"compression type = %d\n", info_ptr->compression_type); fprintf(stderr,"filter type = %d\n", info_ptr->filter_type); fprintf(stderr,"interlace type = %d\n", info_ptr->interlace_type); fprintf(stderr,"num colors = %d\n",info_ptr->num_palette); fprintf(stderr,"rowbytes = %d\n", info_ptr->rowbytes); } #endif /* allocate the pixel grid which we will need to send to png_read_image(). */ png_pixels = (png_byte *)malloc(info_ptr->rowbytes * (*height) * sizeof(png_byte)); row_pointers = (png_byte **) malloc((*height) * sizeof(png_byte *)); for (i=0; i < *height; i++) row_pointers[i]=png_pixels+(info_ptr->rowbytes*i); /* FINALLY - read the darn thing. */ png_read_image(png_ptr, row_pointers); /* now that we have the (transformed to 8-bit RGB) image, we have to copy the resulting palette to our colormap. */ if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) { if (info_ptr->valid & PNG_INFO_PLTE) { for (i=0; i < info_ptr->num_palette; i++) { colrs[i].red = info_ptr->palette[i].red << 8; colrs[i].green = info_ptr->palette[i].green << 8; colrs[i].blue = info_ptr->palette[i].blue << 8; colrs[i].pixel = i; colrs[i].flags = DoRed|DoGreen|DoBlue; } } else { for (i=0; i < 216; i++) { colrs[i].red = std_color_cube[i].red << 8; colrs[i].green = std_color_cube[i].green << 8; colrs[i].blue = std_color_cube[i].blue << 8; colrs[i].pixel = i; colrs[i].flags = DoRed|DoGreen|DoBlue; } } } else { /* grayscale image */ for(i=0; i < 256; i++ ) { colrs[i].red = i << 8; colrs[i].green = i << 8; colrs[i].blue = i << 8; colrs[i].pixel = i; colrs[i].flags = DoRed|DoGreen|DoBlue; } } /* Now copy the pixel data from png_pixels to pixmap */ pixmap = (png_byte *)malloc((*width) * (*height) * sizeof(png_byte)); p = pixmap; q = png_pixels; /* if there is an alpha channel, we have to get rid of it in the pixmap, since I don't do anything with it yet */ if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) { #ifndef DISABLE_TRACE if (srcTrace) { fprintf(stderr,"Getting rid of alpha channel\n"); } #endif for(i=0; i<*height; i++) { q = row_pointers[i]; for(j=0; j<*width; j++) { *p++ = *q++; /*palette index*/ q++; /* skip the alpha pixel */ } } free((char *)png_pixels); } else { #ifndef DISABLE_TRACE if (srcTrace) { fprintf(stderr,"No alpha channel\n"); } #endif for(i=0; i<*height; i++) { q = row_pointers[i]; for(j=0; j<*width; j++) { *p++ = *q++; /*palette index*/ } } free((char *)png_pixels); } free((png_byte **)row_pointers); /* clean up after the read, and free any memory allocated */ /*png_read_destroy(png_ptr, info_ptr, (png_info *)0);*/ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); /* free the structures */ /*free((char *)png_ptr);*/ free((char *)info_ptr); return pixmap; }
int fh_png_load(const char *name, unsigned char *buffer, int x, int y) { static const png_color_16 my_background = {0, 0, 0, 0, 0}; png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; unsigned int i; int bit_depth, color_type, interlace_type; int number_passes, pass; png_byte * 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); } if (setjmp(png_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); 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_palette_to_rgb(png_ptr); png_set_background(png_ptr, (png_color_16 *)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); /* other possibility for png_set_background: use png_get_bKGD */ } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); png_set_background(png_ptr, (png_color_16 *)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); } if (color_type & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); /* on Intel PC ?: if (bit_depth == 16) png_set_swap(png_ptr); */ number_passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); if (width * 3 != png_get_rowbytes(png_ptr, info_ptr)) { printf("[png.cpp]: Error processing %s - please report (including image).\n", name); return(FH_ERROR_FORMAT); } for(pass = 0; pass < number_passes; pass++) { fbptr = (png_byte *)buffer; for (i = 0; i < height; i++, fbptr += width * 3) { png_read_row(png_ptr, fbptr, NULL); } } 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 int check_transparency (png_structp png_ptr, png_infop info_ptr) { int trans_type; unsigned pdf_version; png_byte color_type; png_color_16p trans_values; png_bytep trans; int num_trans; pdf_version = pdf_get_version(); color_type = png_get_color_type(png_ptr, info_ptr); /* * First we set trans_type to appropriate value for PNG image. */ if (color_type == PNG_COLOR_TYPE_RGB_ALPHA || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { trans_type = PDF_TRANS_TYPE_ALPHA; } else if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) && png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values)) { /* Have valid tRNS chunk. */ switch (color_type) { case PNG_COLOR_TYPE_PALETTE: /* Use color-key mask if possible. */ trans_type = PDF_TRANS_TYPE_BINARY; while (num_trans-- > 0) { if (trans[num_trans] != 0x00 && trans[num_trans] != 0xff) { /* This seems not binary transparency */ trans_type = PDF_TRANS_TYPE_ALPHA; break; } } break; case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_RGB: /* RGB or GRAY, single color specified by trans_values is transparent. */ trans_type = PDF_TRANS_TYPE_BINARY; break; default: /* Else tRNS silently ignored. */ trans_type = PDF_TRANS_TYPE_NONE; } } else { /* no transparency */ trans_type = PDF_TRANS_TYPE_NONE; } /* * Now we check PDF version. * We can convert alpha cahnnels to explicit mask via user supplied alpha- * threshold value. But I will not do that. */ if (( pdf_version < 3 && trans_type != PDF_TRANS_TYPE_NONE ) || ( pdf_version < 4 && trans_type == PDF_TRANS_TYPE_ALPHA )) { /* * No transparency supported but PNG uses transparency, or Soft-Mask * required but no support for it is available in this version of PDF. * We must do pre-composition of image with the background image here. But, * we cannot do that in general since dvipdfmx is not a rasterizer. What we * can do here is to composite image with a rectangle filled with the * background color. However, images are stored as an Image XObject which * can be referenced anywhere in the PDF document content. Hence, we cannot * know the correct background color at this time. So we will choose white * as background color, which is most probable color in our cases. * We ignore bKGD chunk. */ png_color_16 bg; bg.red = 255; bg.green = 255; bg.blue = 255; bg.gray = 255; bg.index = 0; png_set_background(png_ptr, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); WARN("%s: Transparency will be ignored. (no support in PDF ver. < 1.3)", PNG_DEBUG_STR); if (pdf_version < 3) WARN("%s: Please use -V 3 option to enable binary transparency support.", PNG_DEBUG_STR); if (pdf_version < 4) WARN("%s: Please use -V 4 option to enable full alpha channel support.", PNG_DEBUG_STR); trans_type = PDF_TRANS_TYPE_NONE; } return trans_type; }
pointer PNG_READ_IMAGE(register context *ctx, int n, register pointer *argv) { char *file_name; pointer ret, image_ptr; ckarg(1); if (isstring(argv[0])) file_name = argv[0]->c.str.chars; else error(E_NOSTRING); FILE *fp = fopen(file_name, "rb"); if (!fp) { error(E_OPENFILE); return(NIL); } png_structp png_ptr; png_infop info_ptr; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); info_ptr = png_create_info_struct(png_ptr); if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fp); error(E_EOF); return(NIL); } png_init_io(png_ptr, fp); png_read_info(png_ptr, info_ptr); int width = png_get_image_width(png_ptr, info_ptr); int height = png_get_image_height(png_ptr, info_ptr); int bit_depth = png_get_bit_depth(png_ptr, info_ptr); int channels = png_get_channels(png_ptr, info_ptr); int color_type = png_get_color_type(png_ptr, info_ptr); //fprintf(stderr, "bit_depth = %d, channels %d, color_type =%d (pal:%d,gray:%d,rgb:%d,rgba:%d)\n", bit_depth, channels, color_type, PNG_COLOR_TYPE_PALETTE,PNG_COLOR_TYPE_GRAY,PNG_COLOR_TYPE_RGB,PNG_COLOR_TYPE_RGB_ALPHA); switch (color_type) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(png_ptr); break; case PNG_COLOR_TYPE_GRAY: #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED if ( bit_depth < 8) png_set_gray_to_rgb(png_ptr); #else if ( bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr); #endif break; case PNG_COLOR_TYPE_RGB: //png_set_bgr(png_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); // 16bit -> 8bit break; case PNG_COLOR_TYPE_RGB_ALPHA: if (bit_depth == 16) png_set_strip_16(png_ptr); // 16bit -> 8bit png_set_invert_alpha(png_ptr); //png_set_bgr(png_ptr); //png_set_strip_alpha(png_ptr); // RGBA -> rgb , GA -> g png_color_16 my_background = {0xff, 0xff, 0xff, 0xff, 0xff}; png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); break; } png_read_update_info(png_ptr, info_ptr); width = png_get_image_width(png_ptr, info_ptr); height = png_get_image_height(png_ptr, info_ptr);; bit_depth = png_get_bit_depth(png_ptr, info_ptr); channels = png_get_channels(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); png_bytep * row_pointers = (png_bytep *)malloc(height*sizeof(png_bytep)); int y, byte_per_scanline = png_get_rowbytes(png_ptr, info_ptr); image_ptr = makebuffer(height*byte_per_scanline); for(y=0;y<height;y++){ row_pointers[y] = image_ptr->c.str.chars+y*byte_per_scanline; } png_read_image(png_ptr, row_pointers); free(row_pointers); png_read_end(png_ptr,info_ptr); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fp); ret=cons(ctx,image_ptr,NIL); ret=cons(ctx,makeint(channels),ret); ret=cons(ctx,makeint(height),ret); ret=cons(ctx,makeint(width),ret); return (ret); }
int read_png(FILE *file, int filetype, F_pic *pic) { register int i, j; png_structp png_ptr; png_infop info_ptr; png_infop end_info; png_uint_32 w, h, rowsize; int bit_depth, color_type, interlace_type; int compression_type, filter_type; png_bytep *row_pointers; char *ptr; int num_palette; png_colorp palette; png_color_16 background; /* make scale factor smaller for metric */ float scale = (appres.INCHES ? (float)PIX_PER_INCH : 2.54*PIX_PER_CM)/(float)DISPLAY_PIX_PER_INCH; /* read the png file here */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL, NULL, NULL); if (!png_ptr) { close_picfile(file,filetype); return FileInvalid; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL); close_picfile(file,filetype); return FileInvalid; } end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); close_picfile(file,filetype); return FileInvalid; } /* set long jump recovery here */ if (setjmp(png_ptr->jmpbuf)) { /* if we get here there was a problem reading the file */ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); close_picfile(file,filetype); return FileInvalid; } /* set up the input code */ png_init_io(png_ptr, file); /* now read the file info */ png_read_info(png_ptr, info_ptr); /* get width, height etc */ png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type); if (info_ptr->valid & PNG_INFO_gAMA) png_set_gamma(png_ptr, 2.2, info_ptr->gamma); else png_set_gamma(png_ptr, 2.2, 0.45); if (info_ptr->valid & PNG_INFO_bKGD) /* set the background to the one supplied */ png_set_background(png_ptr, &info_ptr->background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); else { /* blend the canvas background using the alpha channel */ background.red = x_bg_color.red >> 8; background.green = x_bg_color.green >> 8; background.blue = x_bg_color.blue >> 8; background.gray = 0; png_set_background(png_ptr, &background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 2.2); } /* set order to BGR (default is RGB) */ if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) png_set_bgr(png_ptr); /* strip 16-bit RGB values down to 8-bit */ if (bit_depth == 16) png_set_strip_16(png_ptr); /* force to 8-bits per pixel if less than 8 */ if (bit_depth < 8) png_set_packing(png_ptr); /* dither rgb files down to 8 bit palette */ num_palette = 0; pic->pic_cache->transp = TRANSP_NONE; if (color_type & PNG_COLOR_MASK_COLOR) { png_uint_16p histogram; #ifdef USE_ALPHA /* we need to somehow give libpng a background color that it can combine with the alpha information in each pixel to make the image */ if (color_type & PNG_COLOR_MASK_ALPHA) pic->pic_cache->transp = TRANSP_BACKGROUND; #endif /* USE_ALPHA */ if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) { png_get_hIST(png_ptr, info_ptr, &histogram); png_set_dither(png_ptr, palette, num_palette, 256, histogram, 0); } } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { /* expand to full range */ png_set_expand(png_ptr); /* make a gray colormap */ num_palette = 256; for (i = 0; i < num_palette; i++) pic->pic_cache->cmap[i].red = pic->pic_cache->cmap[i].green = pic->pic_cache->cmap[i].blue = i; } else { /* transfer the palette to the object's colormap */ for (i=0; i<num_palette; i++) { pic->pic_cache->cmap[i].red = palette[i].red; pic->pic_cache->cmap[i].green = palette[i].green; pic->pic_cache->cmap[i].blue = palette[i].blue; } } rowsize = w; if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) rowsize = w*3; /* allocate the row pointers and rows */ row_pointers = (png_bytep *) malloc(h*sizeof(png_bytep)); for (i=0; i<h; i++) { if ((row_pointers[i] = malloc(rowsize)) == NULL) { for (j=0; j<i; j++) free(row_pointers[j]); close_picfile(file,filetype); return FileInvalid; } } /* finally, read the file */ png_read_image(png_ptr, row_pointers); /* allocate the bitmap */ if ((pic->pic_cache->bitmap=malloc(rowsize*h))==NULL) { close_picfile(file,filetype); return FileInvalid; } /* copy it to our bitmap */ ptr = pic->pic_cache->bitmap; for (i=0; i<h; i++) { bcopy(row_pointers[i], ptr, rowsize); ptr += rowsize; } /* put in width, height */ pic->pic_cache->bit_size.x = w; pic->pic_cache->bit_size.y = h; if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) { /* no palette, must use neural net to reduce to 256 colors with palette */ if (!map_to_palette(pic)) { close_picfile(file,filetype); return FileInvalid; /* out of memory or something */ } pic->pic_cache->numcols = 256; } else { pic->pic_cache->numcols = num_palette; } /* clean up */ png_read_end(png_ptr, end_info); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); for (i=0; i<h; i++) free(row_pointers[i]); pic->pic_cache->subtype = T_PIC_PNG; pic->pixmap = None; pic->hw_ratio = (float) pic->pic_cache->bit_size.y / pic->pic_cache->bit_size.x; pic->pic_cache->size_x = pic->pic_cache->bit_size.x * scale; pic->pic_cache->size_y = pic->pic_cache->bit_size.y * scale; /* if monochrome display map bitmap */ if (tool_cells <= 2 || appres.monochrome) map_to_mono(pic); close_picfile(file,filetype); return PicSuccess; }
int fh_png_load(const char *name,unsigned char **buffer,int* /*xp*/,int* /*yp*/) { static const png_color_16 my_background = {0, 0, 0, 0, 0}; png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; unsigned int i; int bit_depth, color_type, interlace_type; int number_passes,pass; png_byte * 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) { fclose(fh); 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); } if(setjmp(png_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); 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_palette_to_rgb(png_ptr); png_set_background(png_ptr, (png_color_16*)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); /* other possibility for png_set_background: use png_get_bKGD */ } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); png_set_background(png_ptr, (png_color_16*)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); } /* this test does not trigger for 8bit-paletted PNGs with newer libpng (1.2.36 at least), but the data delivered is with alpha channel anyway, so always strip alpha for now */ #if PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR <= 2 && PNG_LIBPNG_VER_RELEASE < 36 if (color_type & PNG_COLOR_MASK_ALPHA) #endif png_set_strip_alpha(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); /* on Intel PC ?: if (bit_depth == 16) png_set_swap(png_ptr); */ number_passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr,info_ptr); if (width * 3 != png_get_rowbytes(png_ptr, info_ptr)) { printf("[png.cpp]: Error processing %s - please report (including image).\n", name); printf(" width: %lu rowbytes: %lu\n", width, png_get_rowbytes(png_ptr, info_ptr)); fclose(fh); return(FH_ERROR_FORMAT); } for(pass = 0; pass < number_passes; pass++) { fbptr = (png_byte *)(*buffer); for (i = 0; i < height; i++, fbptr += width * 3) { png_read_row(png_ptr, fbptr, NULL); } } png_read_end(png_ptr, info_ptr); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fh); return(FH_ERROR_OK); }
pdf_obj *start_png_image (FILE *file, char *res_name) { pdf_obj *result = NULL, *dict = NULL; png_structp png_ptr; png_infop info_ptr; unsigned long width, height; unsigned bit_depth, color_type; rewind (file); if (!(png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) || !(info_ptr = png_create_info_struct (png_ptr))) { fprintf (stderr, "\n\nLibpng failed to initialize\n"); if (png_ptr) png_destroy_read_struct(&png_ptr, NULL, NULL); return NULL; } png_init_io (png_ptr, file); /* png_set_sig_bytes (png_ptr, 0); */ /* Read PNG header */ png_read_info (png_ptr, info_ptr); { png_color_16 default_background; png_color_16p file_background; default_background.red=255; default_background.green=255; default_background.blue=255; default_background.gray=0; default_background.index = 0; width = png_get_image_width(png_ptr, info_ptr); height = png_get_image_height(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); /* Convert paletted images to true color */ if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_expand(png_ptr); } /* Limit image component depth to 8 bits */ if (bit_depth == 16) { png_set_strip_16 (png_ptr); } if (png_get_bKGD(png_ptr, info_ptr, &file_background)) { png_set_background(png_ptr, file_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); } else { png_set_background(png_ptr, &default_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); } } { /* Read the image in raw RGB format */ int i, rowbytes, pdf_bit_depth; png_bytep *rows; png_read_update_info(png_ptr, info_ptr); rows = NEW (height, png_bytep); rowbytes = png_get_rowbytes(png_ptr, info_ptr); rows[0] = NEW (rowbytes*height, png_byte); for (i=1; i<height; i++) { rows[i] = rows[0] + rowbytes * i; } png_read_image(png_ptr, rows); result = pdf_new_stream(STREAM_COMPRESS); dict = pdf_stream_dict(result); pdf_add_dict (dict, pdf_new_name ("Width"), pdf_new_number(width)); pdf_add_dict (dict, pdf_new_name ("Height"), pdf_new_number(height)); if (color_type == PNG_COLOR_TYPE_GRAY) { pdf_bit_depth = bit_depth; } else { pdf_bit_depth = 8; } pdf_add_dict (dict, pdf_new_name ("BitsPerComponent"), pdf_new_number(pdf_bit_depth)); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { pdf_add_dict (dict, pdf_new_name ("ColorSpace"), pdf_new_name ("DeviceGray")); } else{ pdf_add_dict (dict, pdf_new_name ("ColorSpace"), pdf_new_name ("DeviceRGB")); } pdf_add_stream (result, (char *)rows[0], rowbytes*height); RELEASE (rows[0]); RELEASE (rows); } { /* Cleanup */ if (info_ptr) png_destroy_info_struct(png_ptr, &info_ptr); if (png_ptr) png_destroy_read_struct(&png_ptr, NULL, NULL); } return result; }
void LoadImage (const char *filename, unsigned char **pic, int *width, int *height) { png_byte** row_pointers; unsigned char *fbuffer = NULL; png_bytep p_fbuffer; int nLen = g_FileSystemTable.m_pfnLoadFile( (char *)filename, (void **)&fbuffer, 0 ); if (nLen == -1) return; p_fbuffer = fbuffer; // the reading glue // http://www.libpng.org/pub/png/libpng-manual.html png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, png_voidp_NULL, user_error_fn, user_warning_fn); if (!png_ptr) { g_FuncTable.m_pfnSysPrintf ("libpng error: png_create_read_struct\n"); return; } 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); g_FuncTable.m_pfnSysPrintf ("libpng error: png_create_info_struct (info_ptr)\n"); return; } png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); g_FuncTable.m_pfnSysPrintf ("libpng error: png_create_info_struct (end_info)\n"); return; } // configure the read function png_set_read_fn(png_ptr, (voidp)&p_fbuffer, (png_rw_ptr)&user_read_data); if (setjmp(png_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); if (*pic) { g_free(*pic); free(row_pointers); } return; } png_read_info(png_ptr, info_ptr); int bit_depth = png_get_bit_depth(png_ptr, info_ptr); int color_type = png_get_color_type(png_ptr, info_ptr); // we want to treat all images the same way // The following code transforms grayscale images of less than 8 to 8 bits, // changes paletted images to RGB, and adds a full alpha channel if there is // transparency information in a tRNS chunk. if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_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); if ( ! ( color_type & PNG_COLOR_MASK_ALPHA ) ) { // Set the background color to draw transparent and alpha images over. png_color_16 my_background, *image_background; if (png_get_bKGD(png_ptr, info_ptr, &image_background)) png_set_background(png_ptr, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); else png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); // Add alpha byte after each RGB triplet png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); } // read the sucker in one chunk png_read_update_info(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); *width = png_get_image_width(png_ptr, info_ptr); *height = png_get_image_height(png_ptr, info_ptr); // allocate the pixel buffer, and the row pointers int size = (*width)*(*height)*4; // still have to use that g_malloc heresy *pic = (unsigned char *)g_malloc(size); row_pointers = (png_byte**) malloc((*height) * sizeof(png_byte*)); int i; for(i = 0; i < (*height); i++) row_pointers[i] = (png_byte*)(*pic) + i * 4 * (*width); // actual read png_read_image(png_ptr, row_pointers); /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); /* free up the memory structure */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); free(row_pointers); g_FileSystemTable.m_pfnFreeFile (fbuffer); }
void ReadFilePNG(CByteImage& img, const char* filename) { // open the PNG input file FILE *stream = fopen(filename, "rb"); if (stream == 0) throw CError("ReadFilePNG: could not open %s", filename); // first check the eight byte PNG signature png_byte pbSig[8]; fread(pbSig, 1, 8, stream); if (!png_check_sig(pbSig, 8)) { fclose(stream); throw CError("ReadFilePNG: invalid PNG signature"); } // create the two png(-info) structures png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, (png_error_ptr)pngfile_error, (png_error_ptr)NULL); if (!png_ptr) { fclose(stream); throw CError("ReadFilePNG: error creating png structure"); } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); fclose(stream); throw CError("ReadFilePNG: error creating png structure"); } png_init_io(png_ptr, stream); png_set_sig_bytes(png_ptr, 8); // read all PNG info up to image data png_read_info(png_ptr, info_ptr); // get width, height, bit-depth and color-type int width, height, bits, colorType, nBands; png_uint_32 pwidth, pheight; png_get_IHDR(png_ptr, info_ptr, &pwidth, &pheight, //(png_uint_32 *)&width, (png_uint_32 *)&height, &bits, &colorType, NULL, NULL, NULL); width = pwidth; height = pheight; nBands = (int)png_get_channels(png_ptr, info_ptr); if (DEBUG_ImageIOpng) fprintf(stderr, " w=%d, h=%d, %2d bits, %s, nB=%d", width, height, bits, colorType == PNG_COLOR_TYPE_GRAY ? "gray" : colorType == PNG_COLOR_TYPE_PALETTE ? "plt " : colorType == PNG_COLOR_TYPE_RGB ? "rgb " : colorType == PNG_COLOR_TYPE_RGB_ALPHA ? "rgba" : colorType == PNG_COLOR_TYPE_GRAY_ALPHA ? "gr-a" : "??? ", nBands); // get rid of lower-order byte in 16-bit images // TODO: could allow this and read in IntImage in this case... if (bits == 16) png_set_strip_16(png_ptr); // change palette color into RGB if (colorType == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); // want at least 8 bits if (bits < 8) png_set_expand(png_ptr); // if there is a transparent palette entry, create alpha channel if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr); // make gray images with alpha channel into RGBA -- TODO: or just ignore alpha? if (colorType == PNG_COLOR_TYPE_GRAY_ALPHA) // colorType == PNG_COLOR_TYPE_GRAY // but leave gray images alone png_set_gray_to_rgb(png_ptr); // set the background color to draw transparent and alpha images over. // only needed for gray images with alpha if (colorType == PNG_COLOR_TYPE_GRAY_ALPHA || colorType == PNG_COLOR_TYPE_GRAY) { png_color_16 *pBackground; if (png_get_bKGD(png_ptr, info_ptr, &pBackground)) png_set_background(png_ptr, pBackground, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); } // if required set gamma conversion // this seems to cause problems, so let's just leave gamma alone. //double gamma; //if (png_get_gAMA(png_ptr, info_ptr, &gamma)) { // //fprintf(stderr, "\n reading gamma %lf\n", gamma); //png_set_gamma(png_ptr, 1.0, gamma); //} // we need colors in BGR order, not RGB png_set_bgr(png_ptr); // always convert 3-band to 4-band images (add alpha): if (colorType == PNG_COLOR_TYPE_RGB) png_set_add_alpha(png_ptr, 255, PNG_FILLER_AFTER); // after the transformations have been registered update info_ptr data png_read_update_info(png_ptr, info_ptr); // get again width, height and the new bit-depth and color-type png_get_IHDR(png_ptr, info_ptr, &pwidth, &pheight, //(png_uint_32 *)&width, (png_uint_32 *)&height, &bits, &colorType, NULL, NULL, NULL); width = pwidth; height = pheight; nBands = (int)png_get_channels(png_ptr, info_ptr); if (DEBUG_ImageIOpng) fprintf(stderr, " -> w=%d, h=%d, %2d bits, %s, nB=%d\n", width, height, bits, colorType == PNG_COLOR_TYPE_GRAY ? "gray" : colorType == PNG_COLOR_TYPE_PALETTE ? "plt " : colorType == PNG_COLOR_TYPE_RGB ? "rgb " : colorType == PNG_COLOR_TYPE_RGB_ALPHA ? "rgba" : colorType == PNG_COLOR_TYPE_GRAY_ALPHA ? "gr-a" : "??? ", nBands); if (! (nBands==1 || nBands==3 || nBands==4)) { fclose(stream); throw CError("ReadFilePNG: Can't handle nBands=%d", nBands); } // Set the image shape CShape sh(width, height, nBands); // Allocate the image if necessary img.ReAllocate(sh); // allocate a vector of row pointers std::vector<uchar *> rowPtrs; rowPtrs.resize(height); for (int y = 0; y<height; y++) rowPtrs[y] = &img.Pixel(0, y, 0); // read the whole image png_read_image(png_ptr, &rowPtrs[0]); // read the additional chunks in the PNG file (not really needed) png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(stream); }
int screen_write(struct screen *screen, char *file){ int y; png_bytep row; png_color_16 color; memset(&color, 0, sizeof(color)); /* Create PNG file. */ FILE *fp = fopen(file, "wb"); if ( ! fp ){ myrt_printf(ERROR, "Could not open file: %s\n", file); return -1; } /* Initialize stuff. */ screen->png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if ( ! screen->png_ptr ){ myrt_printf(ERROR, "Could not make PNG header.\n"); return -1; } screen->info_ptr = png_create_info_struct(screen->png_ptr); if ( ! screen->info_ptr ){ myrt_printf(ERROR, "Could not make PNG info struct.\n"); return -1; } if ( setjmp(png_jmpbuf(screen->png_ptr)) ){ myrt_printf(ERROR, "Failed to init png I/O."); return -1; } png_init_io(screen->png_ptr, fp); /* Write the header. */ if ( setjmp(png_jmpbuf(screen->png_ptr)) ){ myrt_printf(ERROR, "Failed to write PNG header.\n"); return -1; } png_set_IHDR(screen->png_ptr, screen->info_ptr, screen->width, screen->height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_set_background(screen->png_ptr, &color, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); png_write_info(screen->png_ptr, screen->info_ptr); /* Write some bytes. */ if ( setjmp(png_jmpbuf(screen->png_ptr)) ){ myrt_printf(ERROR, "Unable to write png data.\n"); return -1; } /* Write the PNG data. */ row = (png_bytep) screen->data; for ( y = 0; y < screen->height; y++ ){ png_write_row(screen->png_ptr, row); row += (screen->width * 4); } /* End write */ if ( setjmp(png_jmpbuf(screen->png_ptr)) ){ myrt_printf(ERROR, "Failed to finalize PNG.\n"); return -1; } png_write_end(screen->png_ptr, NULL); fclose(fp); return 0; }
/* pngReadImage: Reads an image from a memory buffer. Returns: non-zero if successful. */ int pngReadImage(int w, int h, int d, char* bits, char *data, int nBytes) { png_bytep *row_pointers = NULL; pngReadState rs; png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int bit_depth, color_type, interlace_type; DBG("pngReadImage: png_sig_cmp"); /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature. */ if(png_sig_cmp(data, (png_size_t)0, PNG_BYTES_TO_CHECK)) return 0; DBG("pngReadImage: png_create_read_struct"); /* Create the png_struct */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) return 0; DBG("pngReadImage: png_create_info_struct"); /* Allocate/initialize the image information data. REQUIRED */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); return 0; } /* Set error handling. REQUIRED if you aren't supplying your own * error handling functions in the png_create_read_struct() call. */ if (setjmp(png_jmpbuf(png_ptr))) { DBG("pngReadImage: triggered png_error"); /* If we get here, we had a problem reading the file */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); if(row_pointers) free(row_pointers); return 0; } rs.data = data; rs.position = 0; rs.length = nBytes; png_set_read_fn(png_ptr, (void *)&rs, readBytes); DBG("pngReadImage: png_read_info"); /* The call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). REQUIRED */ png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL); /* Set up the data transformations you want. Note that these are all * optional. Only call them if you want/need them. Many of the * transformations only work on specific types of images, and many * are mutually exclusive. */ /* tell libpng to strip 16 bit/color files down to 8 bits/color */ png_set_strip_16(png_ptr); /* flip the RGB pixels to BGR (or RGBA to BGRA) */ if (color_type & PNG_COLOR_MASK_COLOR) { DBG("pngReadImage: png_set_bgr"); png_set_bgr(png_ptr); } if(d == 32 && color_type == PNG_COLOR_TYPE_RGB) { /* Add filler (or alpha) byte (before/after each RGB triplet) */ DBG("pngReadImage: png_set_filler"); png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); } if(0) { /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ png_set_packing(png_ptr); /* Change the order of packed pixels to least significant bit first * (not useful if you are using png_set_packing). */ png_set_packswap(png_ptr); /* Expand paletted colors into true RGB triplets */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); } /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_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); if(0) { /* Set the background color to draw transparent and alpha images over. * It is possible to set the red, green, and blue components directly * for paletted images instead of supplying a palette index. Note that * even if the PNG file supplies a background, you are not required to * use it - you should use the (solid) application background if it has one */ png_color_16 my_background, *image_background; if (png_get_bKGD(png_ptr, info_ptr, &image_background)) png_set_background(png_ptr, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); else png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); } if(0) { /* Tell libpng to handle the gamma conversion for you. The final call * is a good guess for PC generated images, but it should be configurable * by the user at run time by the user. It is strongly suggested that * your application support gamma correction. */ int intent; double screen_gamma = 1.2; if (png_get_sRGB(png_ptr, info_ptr, &intent)) png_set_gamma(png_ptr, screen_gamma, 0.45455); else { double image_gamma; if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) png_set_gamma(png_ptr, screen_gamma, image_gamma); else png_set_gamma(png_ptr, screen_gamma, 0.45455); } } if(0) { /* If you want to shift the pixel values from the range [0,255] or * [0,65535] to the original [0,7] or [0,31], or whatever range the * colors were originally in: */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) { png_color_8p sig_bit; png_get_sBIT(png_ptr, info_ptr, &sig_bit); png_set_shift(png_ptr, sig_bit); } } if(0) { /* flip the RGB pixels to BGR (or RGBA to BGRA) */ if (color_type & PNG_COLOR_MASK_COLOR) png_set_bgr(png_ptr); /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ png_set_swap_alpha(png_ptr); /* swap bytes of 16 bit files to least significant byte first */ png_set_swap(png_ptr); } { /* initialize the png row pointers */ int row, ppw = 32 / d; int pitch = ((w + ppw - 1) / ppw) * 4; int rowbytes = png_get_rowbytes(png_ptr, info_ptr); if(0) { char info[100]; sprintf(info, "Form pitch: %d\nPNG rowbytes: %d",pitch, rowbytes); DBG(info); } /* XXXX: It seems that this test is pretty pointless; PNG appears to return the raw rowbytes value, not the padded one. A better test is probably to compare the w/h/d values of png with the form values to ensure correctness. */ if(pitch < rowbytes) { png_error(png_ptr, "Row bytes mismatch"); } row_pointers = (png_bytep*) calloc(h, sizeof(void*)); for (row = 0; row < h; row++) { row_pointers[row] = bits + (row*pitch); } } DBG("pngReadImage: png_read_image"); /* Read the entire image in one go */ png_read_image(png_ptr, row_pointers); DBG("pngReadImage: Cleaning up"); /* clean up after the read, and free any memory allocated - REQUIRED */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); if(row_pointers) free(row_pointers); return 1; }
void ZLEwlImageManager::convertImageDirectPng(const std::string &stringData, ZLImageData &data) const { struct s_my_png my_png; my_png.p = (char*)stringData.data(); my_png.size = stringData.length(); png_structp png_ptr = NULL; png_infop info_ptr = NULL; unsigned int *row = NULL; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)&my_png, mypng_error_func, mypng_warning_func); if ( !png_ptr ) return; if (setjmp( png_ptr->jmpbuf )) { data.init(0, 0); if (png_ptr) { png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); } if ( row ) delete row; return; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) mypng_error_func(png_ptr, "cannot create png info struct"); png_set_read_fn(png_ptr, (voidp)&my_png, mypng_read_func); png_read_info( png_ptr, info_ptr ); png_uint_32 width, height; int bit_depth, color_type, interlace_type; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); data.init(width, height); row = new unsigned int[ width ]; // SET TRANSFORMS if (color_type & PNG_COLOR_MASK_PALETTE) png_set_palette_to_rgb(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_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); if (bit_depth == 16) png_set_strip_16(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_invert_alpha(png_ptr); } else { png_color_16 bg = {0, 0xffff, 0xffff, 0xffff, 0xffff}; png_set_background(png_ptr, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 0.0); png_set_strip_alpha(png_ptr); } if (bit_depth < 8) png_set_packing(png_ptr); //if (color_type == PNG_COLOR_TYPE_RGB) //png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); //if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) // png_set_swap_alpha(png_ptr); if (! (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) png_set_rgb_to_gray(png_ptr, 1, -1, -1); int number_passes = png_set_interlace_handling(png_ptr); //if (color_type == PNG_COLOR_TYPE_RGB_ALPHA || // color_type == PNG_COLOR_TYPE_GRAY_ALPHA) //if (color_type == PNG_COLOR_TYPE_RGB || // color_type == PNG_COLOR_TYPE_RGB_ALPHA) png_set_bgr(png_ptr); ZLIntegerOption myDitherAlgo(ZLCategoryKey::LOOK_AND_FEEL, "Options", "DitherAlgo", 0); register int dalgo = myDitherAlgo.value(); char *c; for(int pass = 0; pass < number_passes; pass++) { for(unsigned int y = 0; y < height; y++) { png_read_rows(png_ptr, (unsigned char **)&row, png_bytepp_NULL, 1); c = ((ZLEwlImageData&)data).getImageData() + width * y; if ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) { unsigned char *s = (unsigned char*)row; if(dalgo == 1) for(unsigned int i = 0; i < width; i++) *c++ = Dither2BitColor(*(++s)++, i, y); else for(unsigned int i = 0; i < width; i++) *c++ = *(++s)++; } else if(dalgo == 1) { unsigned char *s = (unsigned char*)row; for(unsigned int i = 0; i < width; i++) *c++ = Dither2BitColor(*s++, i, y); } else memcpy(c, (char*)row, width); } } png_read_end(png_ptr, info_ptr); png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); }