Exemplo n.º 1
0
    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 >( &params.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()
                      );
    }
Exemplo n.º 2
0
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);
}
Exemplo n.º 3
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;
}
Exemplo n.º 4
0
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);
}
Exemplo n.º 5
0
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;
}
Exemplo n.º 6
0
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;
}