void write_header( const View& view ) { using png_rw_info_t = detail::png_write_support < typename channel_type<typename get_pixel_type<View>::type>::type, typename color_space_type<View>::type >; // Set the image information here. Width and height are up to 2^31, // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, // or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED png_set_IHDR( get_struct() , get_info() , static_cast< png_image_width::type >( view.width() ) , static_cast< png_image_height::type >( view.height() ) , static_cast< png_bitdepth::type >( png_rw_info_t::_bit_depth ) , static_cast< png_color_type::type >( png_rw_info_t::_color_type ) , _info._interlace_method , _info._compression_type , _info._filter_method ); #ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED if( _info._valid_cie_colors ) { png_set_cHRM( get_struct() , get_info() , _info._white_x , _info._white_y , _info._red_x , _info._red_y , _info._green_x , _info._green_y , _info._blue_x , _info._blue_y ); } if( _info._valid_file_gamma ) { png_set_gAMA( get_struct() , get_info() , _info._file_gamma ); } #else if( _info._valid_cie_colors ) { png_set_cHRM_fixed( get_struct() , get_info() , _info._white_x , _info._white_y , _info._red_x , _info._red_y , _info._green_x , _info._green_y , _info._blue_x , _info._blue_y ); } if( _info._valid_file_gamma ) { png_set_gAMA_fixed( get_struct() , get_info() , _info._file_gamma ); } #endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED if( _info._valid_icc_profile ) { #if PNG_LIBPNG_VER_MINOR >= 5 png_set_iCCP( get_struct() , get_info() , const_cast< png_charp >( _info._icc_name.c_str() ) , _info._iccp_compression_type , reinterpret_cast< png_const_bytep >( & (_info._profile.front ()) ) , _info._profile_length ); #else png_set_iCCP( get_struct() , get_info() , const_cast< png_charp >( _info._icc_name.c_str() ) , _info._iccp_compression_type , const_cast< png_charp >( & (_info._profile.front()) ) , _info._profile_length ); #endif } if( _info._valid_intent ) { png_set_sRGB( get_struct() , get_info() , _info._intent ); } if( _info._valid_palette ) { png_set_PLTE( get_struct() , get_info() , const_cast< png_colorp >( &_info._palette.front() ) , _info._num_palette ); } if( _info._valid_background ) { png_set_bKGD( get_struct() , get_info() , const_cast< png_color_16p >( &_info._background ) ); } if( _info._valid_histogram ) { png_set_hIST( get_struct() , get_info() , const_cast< png_uint_16p >( &_info._histogram.front() ) ); } if( _info._valid_offset ) { png_set_oFFs( get_struct() , get_info() , _info._offset_x , _info._offset_y , _info._off_unit_type ); } if( _info._valid_pixel_calibration ) { std::vector< const char* > params( _info._num_params ); for( std::size_t i = 0; i < params.size(); ++i ) { params[i] = _info._params[ i ].c_str(); } png_set_pCAL( get_struct() , get_info() , const_cast< png_charp >( _info._purpose.c_str() ) , _info._X0 , _info._X1 , _info._cal_type , _info._num_params , const_cast< png_charp >( _info._units.c_str() ) , const_cast< png_charpp >( ¶ms.front() ) ); } if( _info._valid_resolution ) { png_set_pHYs( get_struct() , get_info() , _info._res_x , _info._res_y , _info._phy_unit_type ); } if( _info._valid_significant_bits ) { png_set_sBIT( get_struct() , get_info() , const_cast< png_color_8p >( &_info._sig_bits ) ); } #ifndef BOOST_GIL_IO_PNG_1_4_OR_LOWER #ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED if( _info._valid_scale_factors ) { png_set_sCAL( get_struct() , get_info() , this->_info._scale_unit , this->_info._scale_width , this->_info._scale_height ); } #else #ifdef BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED if( _info._valid_scale_factors ) { png_set_sCAL_fixed( get_struct() , get_info() , this->_info._scale_unit , this->_info._scale_width , this->_info._scale_height ); } #else if( _info._valid_scale_factors ) { png_set_sCAL_s( get_struct() , get_info() , this->_info._scale_unit , const_cast< png_charp >( this->_info._scale_width.c_str() ) , const_cast< png_charp >( this->_info._scale_height.c_str() ) ); } #endif // BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED #endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED #endif // BOOST_GIL_IO_PNG_1_4_OR_LOWER if( _info._valid_text ) { std::vector< png_text > texts( _info._num_text ); for( std::size_t i = 0; i < texts.size(); ++i ) { png_text pt; pt.compression = _info._text[i]._compression; pt.key = const_cast< png_charp >( this->_info._text[i]._key.c_str() ); pt.text = const_cast< png_charp >( this->_info._text[i]._text.c_str() ); pt.text_length = _info._text[i]._text.length(); texts[i] = pt; } png_set_text( get_struct() , get_info() , &texts.front() , _info._num_text ); } if( _info._valid_modification_time ) { png_set_tIME( get_struct() , get_info() , const_cast< png_timep >( &_info._mod_time ) ); } if( _info._valid_transparency_factors ) { int sample_max = ( 1u << _info._bit_depth ); /* libpng doesn't reject a tRNS chunk with out-of-range samples */ if( !( ( _info._color_type == PNG_COLOR_TYPE_GRAY && (int) _info._trans_values[0].gray > sample_max ) || ( _info._color_type == PNG_COLOR_TYPE_RGB &&( (int) _info._trans_values[0].red > sample_max || (int) _info._trans_values[0].green > sample_max || (int) _info._trans_values[0].blue > sample_max ) ) ) ) { //@todo Fix that once reading transparency values works /* png_set_tRNS( get_struct() , get_info() , trans , num_trans , trans_values ); */ } } // Compression Levels - valid values are [0,9] png_set_compression_level( get_struct() , _info._compression_level ); png_set_compression_mem_level( get_struct() , _info._compression_mem_level ); png_set_compression_strategy( get_struct() , _info._compression_strategy ); png_set_compression_window_bits( get_struct() , _info._compression_window_bits ); png_set_compression_method( get_struct() , _info._compression_method ); png_set_compression_buffer_size( get_struct() , _info._compression_buffer_size ); #ifdef BOOST_GIL_IO_PNG_DITHERING_SUPPORTED // Dithering if( _info._set_dithering ) { png_set_dither( get_struct() , &_info._dithering_palette.front() , _info._dithering_num_palette , _info._dithering_maximum_colors , &_info._dithering_histogram.front() , _info._full_dither ); } #endif // BOOST_GIL_IO_PNG_DITHERING_SUPPORTED // Filter if( _info._set_filter ) { png_set_filter( get_struct() , 0 , _info._filter ); } // Invert Mono if( _info._invert_mono ) { png_set_invert_mono( get_struct() ); } // True Bits if( _info._set_true_bits ) { png_set_sBIT( get_struct() , get_info() , &_info._true_bits.front() ); } // sRGB Intent if( _info._set_srgb_intent ) { png_set_sRGB( get_struct() , get_info() , _info._srgb_intent ); } // Strip Alpha if( _info._strip_alpha ) { png_set_strip_alpha( get_struct() ); } // Swap Alpha if( _info._swap_alpha ) { png_set_swap_alpha( get_struct() ); } png_write_info( get_struct() , get_info() ); }
int png_load(char *filename) { int i,j,k; FILE *fd; u_char header[NUMBER]; png_structp png_ptr; png_infop info_ptr,end_info; png_uint_32 width,height; int bit_depth,color_type,interlace_type; int compression_type,filter_type; int channels,rowbytes; double gamma; png_colorp palette; int num_palette; png_bytep *row_pointers; char c; int res=0; fd=fopen(filename,"rb"); if(fd==NULL) { VGLEnd(); perror("fopen"); exit(1); } fread(header,1,NUMBER,fd); if(!png_check_sig(header,NUMBER)) { fprintf(stderr,"Not a PNG file.\n"); return(-1); } png_ptr=png_create_read_struct(PNG_LIBPNG_VER_STRING,(void *)NULL, NULL,NULL); info_ptr=png_create_info_struct(png_ptr); end_info=png_create_info_struct(png_ptr); if(!png_ptr || !info_ptr || !end_info) { VGLEnd(); fprintf(stderr,"failed to allocate needed structs!\n"); png_destroy_read_struct(&png_ptr,&info_ptr,&end_info); return(-1); } png_set_sig_bytes(png_ptr,NUMBER); png_init_io(png_ptr,fd); png_read_info(png_ptr,info_ptr); png_get_IHDR(png_ptr,info_ptr,&width,&height,&bit_depth, &color_type,&interlace_type,&compression_type,&filter_type); png_get_PLTE(png_ptr,info_ptr,&palette,&num_palette); channels=png_get_channels(png_ptr,info_ptr); rowbytes=png_get_rowbytes(png_ptr,info_ptr); if(bit_depth==16) png_set_strip_16(png_ptr); if(color_type & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(png_ptr); if(png_get_gAMA(png_ptr,info_ptr,&gamma)) png_set_gamma(png_ptr,screen_gamma,gamma); else png_set_gamma(png_ptr,screen_gamma,0.45); if(res==0) { /* Dither */ if(color_type & PNG_COLOR_MASK_COLOR) { if(png_get_valid(png_ptr,info_ptr,PNG_INFO_PLTE)) { png_uint_16p histogram; png_get_hIST(png_ptr,info_ptr,&histogram); png_set_dither(png_ptr,palette,num_palette,max_screen_colors,histogram,0); } else { png_color std_color_cube[16]={ {0x00,0x00,0x00}, {0x02,0x02,0x02}, {0x04,0x04,0x04}, {0x06,0x06,0x06}, {0x08,0x08,0x08}, {0x0a,0x0a,0x0a}, {0x0c,0x0c,0x0c}, {0x0e,0x0e,0x0e}, {0x10,0x10,0x10}, {0x12,0x12,0x12}, {0x14,0x14,0x14}, {0x16,0x16,0x16}, {0x18,0x18,0x18}, {0x1a,0x1a,0x1a}, {0x1d,0x1d,0x1d}, {0xff,0xff,0xff}, }; png_set_dither(png_ptr,std_color_cube,max_screen_colors,max_screen_colors,NULL,0); } } } png_set_packing(png_ptr); 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); } png_read_update_info(png_ptr,info_ptr); png_get_IHDR(png_ptr,info_ptr,&width,&height,&bit_depth, &color_type,&interlace_type,&compression_type,&filter_type); png_get_PLTE(png_ptr,info_ptr,&palette,&num_palette); channels=png_get_channels(png_ptr,info_ptr); rowbytes=png_get_rowbytes(png_ptr,info_ptr); row_pointers=malloc(height*sizeof(png_bytep)); for(i=0;i<height;i++) { row_pointers[i]=malloc(rowbytes); } png_read_image(png_ptr,row_pointers); png_read_end(png_ptr,end_info); png_destroy_read_struct(&png_ptr,&info_ptr,&end_info); fclose(fd); /* Set palette */ if(res) k=2; else k=2; for(i=0;i<256;i++) { pal_red[i]=255; pal_green[i]=255; pal_blue[i]=255; } for(i=0;i<num_palette;i++) { pal_red[i]=(palette+i)->red>>k; pal_green[i]=(palette+i)->green>>k; pal_blue[i]=(palette+i)->blue>>k; } pal_colors=num_palette; if(pic.Bitmap!=NULL) free(pic.Bitmap); pic.Bitmap=(byte *)calloc(rowbytes*height,sizeof(byte)); pic.Type=MEMBUF; pic.Xsize=rowbytes; pic.Ysize=height; for(i=0;i<rowbytes;i++) { for(j=0;j<height;j++) { VGLSetXY(&pic, i,j,row_pointers[j][i]); } } a.zoom=1; a.Xshift=(VGLDisplay->Xsize-pic.Xsize)/2; a.Yshift=(VGLDisplay->Ysize-pic.Ysize)/2; a.rotate=0; return(0); }
/* 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; }
void input_png_file(struct Options opts, struct PNGImage *img) { FILE *f; int i, y, num_trans; bool has_palette = false; png_byte *trans_alpha; png_color_16 *trans_values; bool *full_alpha; png_color *palette; f = fopen(opts.infile, "rb"); if (!f) { err(1, "Opening input png file '%s' failed", opts.infile); } img->png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!img->png) { errx(1, "Creating png structure failed"); } img->info = png_create_info_struct(img->png); if (!img->info) { errx(1, "Creating png info structure failed"); } /* Better error handling here? */ if (setjmp(png_jmpbuf(img->png))) { exit(1); } png_init_io(img->png, f); png_read_info(img->png, img->info); img->width = png_get_image_width(img->png, img->info); img->height = png_get_image_height(img->png, img->info); img->depth = png_get_bit_depth(img->png, img->info); img->type = png_get_color_type(img->png, img->info); if (img->type & PNG_COLOR_MASK_ALPHA) { png_set_strip_alpha(img->png); } if (img->depth != depth) { if (opts.verbose) { warnx("Image bit depth is not %i (is %i).", depth, img->depth); } } if (img->type == PNG_COLOR_TYPE_GRAY) { if (img->depth < 8) { png_set_expand_gray_1_2_4_to_8(img->png); } png_set_gray_to_rgb(img->png); } else { if (img->depth < 8) { png_set_expand_gray_1_2_4_to_8(img->png); } has_palette = png_get_PLTE(img->png, img->info, &palette, &colors); } if (png_get_tRNS(img->png, img->info, &trans_alpha, &num_trans, &trans_values)) { if (img->type == PNG_COLOR_TYPE_PALETTE) { full_alpha = malloc(sizeof(bool) * num_trans); for (i = 0; i < num_trans; i++) { if (trans_alpha[i] > 0) { full_alpha[i] = false; } else { full_alpha[i] = true; } } for (i = 0; i < num_trans; i++) { if (full_alpha[i]) { palette[i].red = 0xFF; palette[i].green = 0x00; palette[i].blue = 0xFF; /* * Set to the lightest color in the * palette. */ } } free(full_alpha); } else { /* Set to the lightest color in the image. */ } png_free_data(img->png, img->info, PNG_FREE_TRNS, -1); } if (has_palette) { /* Make sure palette only has the amount of colors you want. */ } else { /* * Eventually when this copies colors from the image itself, * make sure order is lightest to darkest. */ palette = malloc(sizeof(png_color) * colors); if (strcmp(opts.infile, "rgb.png") == 0) { palette[0].red = 0xFF; palette[0].green = 0xEF; palette[0].blue = 0xFF; palette[1].red = 0xF7; palette[1].green = 0xF7; palette[1].blue = 0x8C; palette[2].red = 0x94; palette[2].green = 0x94; palette[2].blue = 0xC6; palette[3].red = 0x39; palette[3].green = 0x39; palette[3].blue = 0x84; } else { palette[0].red = 0xFF; palette[0].green = 0xFF; palette[0].blue = 0xFF; palette[1].red = 0xA9; palette[1].green = 0xA9; palette[1].blue = 0xA9; palette[2].red = 0x55; palette[2].green = 0x55; palette[2].blue = 0x55; palette[3].red = 0x00; palette[3].green = 0x00; palette[3].blue = 0x00; } } /* * Also unfortunately, this sets it at 8 bit, and I can't find any * option to reduce to 2 or 1 bit. */ #if PNG_LIBPNG_VER < 10402 png_set_dither(img->png, palette, colors, colors, NULL, 1); #else png_set_quantize(img->png, palette, colors, colors, NULL, 1); #endif if (!has_palette) { png_set_PLTE(img->png, img->info, palette, colors); free(palette); } /* * If other useless chunks exist (sRGB, bKGD, pHYs, gAMA, cHRM, iCCP, * etc.) offer to remove? */ png_read_update_info(img->png, img->info); img->data = malloc(sizeof(png_byte *) * img->height); for (y = 0; y < img->height; y++) { img->data[y] = malloc(png_get_rowbytes(img->png, img->info)); } png_read_image(img->png, img->data); png_read_end(img->png, img->info); fclose(f); }
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 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; }