Example #1
0
static pdf_obj *
create_soft_mask (png_structp png_ptr, png_infop info_ptr,
		  png_bytep image_data_ptr, png_uint_32 width, png_uint_32 height)
{
  pdf_obj    *smask, *dict;
  png_bytep   smask_data_ptr;
  png_bytep   trans;
  int         num_trans;
  png_uint_32 i;

  if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ||
      !png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL)) {
    WARN("%s: PNG does not have valid tRNS chunk but tRNS is requested.", PNG_DEBUG_STR);
    return NULL;
  }

  smask = pdf_new_stream(STREAM_COMPRESS);
  dict  = pdf_stream_dict(smask);
  smask_data_ptr = (png_bytep) NEW(width*height, png_byte);
  pdf_add_dict(dict, pdf_new_name("Type"),    pdf_new_name("XObject"));
  pdf_add_dict(dict, pdf_new_name("Subtype"), pdf_new_name("Image"));
  pdf_add_dict(dict, pdf_new_name("Width"),      pdf_new_number(width));
  pdf_add_dict(dict, pdf_new_name("Height"),     pdf_new_number(height));
  pdf_add_dict(dict, pdf_new_name("ColorSpace"), pdf_new_name("DeviceGray"));
  pdf_add_dict(dict, pdf_new_name("BitsPerComponent"), pdf_new_number(8));
  for (i = 0; i < width*height; i++) {
    png_byte idx = image_data_ptr[i];
    smask_data_ptr[i] = (idx < num_trans) ? trans[idx] : 0xff;
  }
  pdf_add_stream(smask, (char *)smask_data_ptr, width*height);
  RELEASE(smask_data_ptr);

  return smask;
}
Example #2
0
        void read()
        {
            assert(m_png);
            assert(m_info);

            png_read_info(m_png, m_info);
            png_get_IHDR(m_png,
                         m_info,
                         & m_width,
                         & m_height,
                         reinterpret_cast< int* >(& m_bit_depth),
                         reinterpret_cast< int* >(& m_color_type),
                         reinterpret_cast< int* >(& m_interlace_type),
                         reinterpret_cast< int* >(& m_compression_type),
                         reinterpret_cast< int* >(& m_filter_type));

            if (png_get_valid(m_png, m_info, chunk_PLTE) == chunk_PLTE)
            {
                png_color* colors = 0;
                int count = 0;
                png_get_PLTE(m_png, m_info, & colors, & count);
                m_palette.assign(colors, colors + count);
            }

#ifdef PNG_tRNS_SUPPORTED
            if (png_get_valid(m_png, m_info, chunk_tRNS) == chunk_tRNS)
            {
                if (m_color_type == color_type_palette)
                {
                    int count;
                    byte* values;
                    if (png_get_tRNS(m_png, m_info, & values, & count, NULL)
                        != PNG_INFO_tRNS)
                    {
                        throw error("png_get_tRNS() failed");
                    }
                    m_tRNS.assign(values, values + count);
                }
            }
#endif

#ifdef PNG_gAMA_SUPPORTED
            if (png_get_valid(m_png, m_info, chunk_gAMA) == chunk_gAMA)
            {
#ifdef PNG_FLOATING_POINT_SUPPORTED
                if (png_get_gAMA(m_png, m_info, &m_gamma) != PNG_INFO_gAMA)
                {
                    throw error("png_get_gAMA() failed");
                }
#else
                png_fixed_point gamma = 0;
                if (png_get_gAMA_fixed(m_png, m_info, &gamma) != PNG_INFO_gAMA)
                {
                    throw error("png_get_gAMA_fixed() failed");
                }
                m_gamma = gamma / 100000.0;
#endif
            }
#endif
        }
void writeSetup2(png_structp png_ptr_write, png_infop info_ptr_write,
                 png_structp png_ptr_read, png_infop info_ptr_read)
{
    /* IHDR */
    png_uint_32 width;
    png_uint_32 height;
    int bit_depth;
    int colour_type;
    int interlace_method;
    int compression_method;
    int filter_method;
    
    /* PLTE */
    png_colorp palette = NULL;
    int palette_size = 0;
    
    /* gAMA */
    double gamma;
    
    /* tRNS */
    png_bytep trans;
    int num_trans;
    png_color_16p trans_values;
    
    /* bKGD */
    png_color_16p background;
    
    png_get_IHDR(png_ptr_read, info_ptr_read, &width, &height,
                 &bit_depth, &colour_type, &interlace_method,
                 &compression_method, &filter_method);
    png_set_IHDR(png_ptr_write, info_ptr_write,  width, height,
                 bit_depth, colour_type, interlace_method,
                 compression_method, filter_method);
    
    if(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_PLTE))
    {
        png_get_PLTE(png_ptr_read, info_ptr_read, &palette, &palette_size);
        png_set_PLTE(png_ptr_write, info_ptr_write, palette, palette_size);
    }
    
    if(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_gAMA))
    {
        png_get_gAMA(png_ptr_read, info_ptr_read, &gamma);
        png_set_gAMA(png_ptr_write, info_ptr_write, gamma);
    }
    
    if(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_tRNS))
    {
        png_get_tRNS(png_ptr_read, info_ptr_read, &trans, &num_trans, &trans_values);
        png_set_tRNS(png_ptr_write, info_ptr_write, trans, num_trans, trans_values);
    }
    
    if(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_bKGD))
    {
        png_get_bKGD(png_ptr_read, info_ptr_read, &background);
        png_set_bKGD(png_ptr_write, info_ptr_write, background);
    }
}
bool SkPNGImageDecoder::getBitmapConfig(png_structp png_ptr, png_infop info_ptr,
        SkBitmap::Config *configp, bool *hasAlphap, bool *doDitherp,
        SkPMColor *theTranspColorp) {
    png_uint_32 origWidth, origHeight;
    int bit_depth, color_type, interlace_type;
    png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth,
            &color_type, &interlace_type, int_p_NULL, int_p_NULL);

    // check for sBIT chunk data, in case we should disable dithering because
    // our data is not truely 8bits per component
    if (*doDitherp) {
#if 0
        SkDebugf("----- sBIT %d %d %d %d\n", info_ptr->sig_bit.red,
                 info_ptr->sig_bit.green, info_ptr->sig_bit.blue,
                 info_ptr->sig_bit.alpha);
#endif
        // 0 seems to indicate no information available
        if (pos_le(info_ptr->sig_bit.red, SK_R16_BITS) &&
                pos_le(info_ptr->sig_bit.green, SK_G16_BITS) &&
                pos_le(info_ptr->sig_bit.blue, SK_B16_BITS)) {
            *doDitherp = false;
        }
    }

    if (color_type == PNG_COLOR_TYPE_PALETTE) {
        bool paletteHasAlpha = hasTransparencyInPalette(png_ptr, info_ptr);
        *configp = this->getPrefConfig(kIndex_SrcDepth, paletteHasAlpha);
        // now see if we can upscale to their requested config
        if (!canUpscalePaletteToConfig(*configp, paletteHasAlpha)) {
            *configp = SkBitmap::kIndex8_Config;
        }
    } else {
        png_color_16p   transpColor = NULL;
        int             numTransp = 0;

        png_get_tRNS(png_ptr, info_ptr, NULL, &numTransp, &transpColor);

        bool valid = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS);

        if (valid && numTransp == 1 && transpColor != NULL) {
            /*  Compute our transparent color, which we'll match against later.
                We don't really handle 16bit components properly here, since we
                do our compare *after* the values have been knocked down to 8bit
                which means we will find more matches than we should. The real
                fix seems to be to see the actual 16bit components, do the
                compare, and then knock it down to 8bits ourselves.
            */
            if (color_type & PNG_COLOR_MASK_COLOR) {
                if (16 == bit_depth) {
                    *theTranspColorp = SkPackARGB32(0xFF, transpColor->red >> 8,
                              transpColor->green >> 8, transpColor->blue >> 8);
                } else {
                    *theTranspColorp = SkPackARGB32(0xFF, transpColor->red,
                                      transpColor->green, transpColor->blue);
                }
            } else {    // gray
                if (16 == bit_depth) {
// call only if color_type is PALETTE. Returns true if the ctable has alpha
static bool hasTransparencyInPalette(png_structp png_ptr, png_infop info_ptr) {
    png_bytep trans;
    int num_trans;

    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
        png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
        return num_trans > 0;
    }
    return false;
}
/*
 * Change the size of the transparency buffer.
 * Changing info_ptr->num_trans directly, avoiding reallocation, should
 * have been sufficient, but can't be done using the current libpng API.
 */
static void opng_realloc_tRNS(png_structp png_ptr, png_infop info_ptr, int num_trans)
{
   png_byte buffer[PNG_MAX_PALETTE_LENGTH];
   png_bytep trans_alpha;
   int src_num_trans = 0;
   png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &src_num_trans, 0);
   if (num_trans == src_num_trans)
      return;
   memcpy(buffer, trans_alpha, (size_t)num_trans);
   if (num_trans > src_num_trans)
      memset(buffer + src_num_trans, 0, num_trans - src_num_trans);
   png_set_tRNS(png_ptr, info_ptr, buffer, num_trans, 0);
}
Example #7
0
static pdf_obj *
create_ckey_mask (png_structp png_ptr, png_infop info_ptr)
{
  pdf_obj  *colorkeys;
  png_byte  color_type;
  png_bytep trans;
  int       num_trans, i;
  png_color_16p colors;

  if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ||
      !png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &colors)) {
    WARN("%s: PNG does not have valid tRNS chunk!", PNG_DEBUG_STR);
    return NULL;
  }

  colorkeys  = pdf_new_array();
  color_type = png_get_color_type(png_ptr, info_ptr);

  switch (color_type) {
  case PNG_COLOR_TYPE_PALETTE:
    for (i = 0; i < num_trans; i++) {
      if (trans[i] == 0x00) {
        pdf_add_array(colorkeys, pdf_new_number(i));
        pdf_add_array(colorkeys, pdf_new_number(i));
      } else if (trans[i] != 0xff) {
        WARN("%s: You found a bug in pngimage.c.", PNG_DEBUG_STR);
      }
    }
    break;
  case PNG_COLOR_TYPE_RGB:
    pdf_add_array(colorkeys, pdf_new_number(colors->red));
    pdf_add_array(colorkeys, pdf_new_number(colors->red));
    pdf_add_array(colorkeys, pdf_new_number(colors->green));
    pdf_add_array(colorkeys, pdf_new_number(colors->green));
    pdf_add_array(colorkeys, pdf_new_number(colors->blue));
    pdf_add_array(colorkeys, pdf_new_number(colors->blue));
    break;
  case PNG_COLOR_TYPE_GRAY:
    pdf_add_array(colorkeys, pdf_new_number(colors->gray));
    pdf_add_array(colorkeys, pdf_new_number(colors->gray));
    break;
  default:
    WARN("%s: You found a bug in pngimage.c.", PNG_DEBUG_STR);
    pdf_release_obj(colorkeys);
    colorkeys = NULL;
  }

  return colorkeys;
}
Example #8
0
Error ImageLoaderPNG::_load_image(void *rf_up,png_rw_ptr p_func,Image *p_image) {



	png_structp png;
	png_infop info;

	//png = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);

	png = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,_png_error_function,_png_warn_function,(png_voidp)NULL,
				 _png_malloc_fn,_png_free_fn );

	ERR_FAIL_COND_V(!png, ERR_OUT_OF_MEMORY);

	info = png_create_info_struct(png);
	if (!info) {
		png_destroy_read_struct(&png,NULL,NULL);
		ERR_PRINT("Out of Memory");
		return ERR_OUT_OF_MEMORY;
	}

	if (setjmp(png_jmpbuf(png))) {

	      png_destroy_read_struct(&png,NULL,NULL);
	      ERR_PRINT("PNG Corrupted");
	      return ERR_FILE_CORRUPT;
	}

	png_set_read_fn(png,(void*)rf_up,p_func);

	png_uint_32 width, height;
	int depth, color;


	png_read_info(png, info);
	png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL);

	png_textp t;
	//https://svn.gov.pt/projects/ccidadao/repository/middleware-offline/trunk/_src/eidmw/FreeImagePTEiD/Source/FreeImage/PluginPNG.cpp
	//png_get_text(png,info,)
	/*
	printf("Image width:%i\n", width);
	printf("Image Height:%i\n", height);
	printf("Bit depth:%i\n", depth);
	printf("Color type:%i\n", color);
	*/

	if (depth<8) { //only bit dept 8 per channel is handled

		png_set_packing(png);
	};

	if (depth > 8) {
		png_set_strip_16(png);
		png_read_update_info(png, info);
	}

	int palette_colors = 0;
	int palette_components = 0;
	int components = 0;

	Image::Format fmt;
	switch(color) {


		case PNG_COLOR_TYPE_GRAY: {

			fmt=Image::FORMAT_GRAYSCALE;
			components=1;
		} break;
		case PNG_COLOR_TYPE_GRAY_ALPHA: {

			fmt=Image::FORMAT_GRAYSCALE_ALPHA;
			components=2;
		} break;
		case PNG_COLOR_TYPE_RGB: {

			fmt=Image::FORMAT_RGB;
			components=3;
		} break;
		case PNG_COLOR_TYPE_RGB_ALPHA: {

			fmt=Image::FORMAT_RGBA;
			components=4;
		} break;
		case PNG_COLOR_TYPE_PALETTE: {

			int ntrans = 0;
			png_get_tRNS(png, info, NULL, &ntrans, NULL);
			//printf("transparent colors %i\n", ntrans);

			fmt = ntrans > 0 ? Image::FORMAT_INDEXED_ALPHA : Image::FORMAT_INDEXED;
			palette_components = ntrans > 0 ? 4 : 3;
			components = 1;

			png_colorp colors;
			png_get_PLTE(png, info, &colors, &palette_colors);

		} break;
		default: {

			ERR_PRINT("INVALID PNG TYPE");
			png_destroy_read_struct(&png, &info, NULL);
			return ERR_UNAVAILABLE;
		} break;
	}

	//int rowsize = png_get_rowbytes(png, info);
	int rowsize = components * width;

	DVector<uint8_t> dstbuff;

	dstbuff.resize( rowsize * height + palette_components * 256 ); // alloc the entire palette? - yes always

	DVector<uint8_t>::Write dstbuff_write = dstbuff.write();

	uint8_t* data = dstbuff_write.ptr();

	uint8_t **row_p = memnew_arr( uint8_t*, height );

	for (unsigned int i = 0; i < height; i++) {
		row_p[i] = &data[components*width*i];
	}

	png_read_image(png, (png_bytep*)row_p);

	if (palette_colors) {

		uint8_t *r_pal = &data[components*width*height]; // end of the array
		png_colorp colors;
		int num;
		png_get_PLTE(png, info, &colors, &num);

		int ofs = 0;
		for (int i=0; i < palette_colors; i++) {

			r_pal[ofs + 0] = colors[i].red;
			r_pal[ofs + 1] = colors[i].green;
			r_pal[ofs + 2] = colors[i].blue;
			if (palette_components == 4) {
				r_pal[ofs + 3] = 255;
			};
			ofs += palette_components;
		};

		if (fmt == Image::FORMAT_INDEXED_ALPHA) {
			png_color_16p alphas;
			png_bytep alpha_idx;
			int count;
			png_get_tRNS(png, info, &alpha_idx, &count, &alphas);
			for (int i=0; i<count; i++) {

				//printf("%i: loading alpha fron transparent color %i, values %i, %i, %i, %i, %i\n", i, (int)alpha_idx[i], (int)alphas[i].index, (int)alphas[i].red, (int)alphas[i].green, (int)alphas[i].blue, (int)alphas[i].gray);
				//r_pal[alpha_idx[i]] = alphas[i].gray >> 8;
				r_pal[i*4+3] = alpha_idx[i];
			};
		};
	};

	memdelete_arr( row_p );

	p_image->create( width, height, 0,fmt, dstbuff );

	png_destroy_read_struct(&png, &info, NULL );

	return OK;
}
Example #9
0
static int load_png_sub(RefImage *image, Value r, int info_only)
{
    png_uint_32 width, height;
    int bit_depth, color_type, interlace_type;
    int compression_type,filter_type;
    png_colorp palette;
    int num_palette;
    png_uint_32 rowbytes;
    png_bytep data = NULL;
    png_bytepp rows = NULL;
    int i;

    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, png_error_callback, png_warn_callback);
    png_infop info_ptr = png_create_info_struct(png_ptr);

    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        free(data);
        free(rows);
        return FALSE;
    }

    png_set_read_fn(png_ptr, &r, png_read_callback);

    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);

    if (width > MAX_IMAGE_SIZE || height > MAX_IMAGE_SIZE) {
        fs->throw_errorf(mod_image, "ImageError", "Image size too large (max:%d)", MAX_IMAGE_SIZE);
        return FALSE;
    }

    image->width = width;
    image->height = height;

    if (bit_depth == 16) {
        png_set_strip_16(png_ptr);
    } else if (bit_depth < 8) {
        png_set_packing(png_ptr);
    }

    switch (color_type) {
    case PNG_COLOR_TYPE_GRAY:
        image->bands = BAND_L;
        break;
    case PNG_COLOR_TYPE_GRAY_ALPHA:
        image->bands = BAND_LA;
        break;
    case PNG_COLOR_TYPE_PALETTE: {
        uint32_t *col;

        image->bands = BAND_P;

        // パレットの読み込み
        col = malloc(sizeof(uint32_t) * PALETTE_NUM);
        for (i = 0; i < PALETTE_NUM; i++) {
            col[i] = COLOR_A_MASK;
        }
        image->palette = col;
        png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
        if (num_palette > PALETTE_NUM) {
            fs->throw_errorf(mod_image, "ImageError", "Invalid PNG format");
            return FALSE;
        }

        for (i = 0; i < num_palette; i++) {
            col[i] = (palette[i].red << COLOR_R_SHIFT) | (palette[i].green << COLOR_G_SHIFT) | (palette[i].blue << COLOR_B_SHIFT) | COLOR_A_MASK;
        }

        if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
            png_bytep trans;
            int num_trans;

            png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
            for (i = 0; i < num_trans; ++i) {
                col[i] &= ~COLOR_A_MASK;
                col[i] |= trans[i] << COLOR_A_SHIFT;
            }
        }
        break;
    }
    case PNG_COLOR_TYPE_RGB:
        image->bands = BAND_RGB;
        break;
    case PNG_COLOR_TYPE_RGB_ALPHA:
        image->bands = BAND_RGBA;
        break;
    default:
        break;
    }
    rowbytes = png_get_rowbytes(png_ptr, info_ptr);
    if (bit_depth < 8) {
        rowbytes *= 8 / bit_depth;
    }
    image->pitch = rowbytes;

    if (!info_only) {
        if (rowbytes * height > fs->max_alloc) {
            fs->throw_error_select(THROW_MAX_ALLOC_OVER__INT, fs->max_alloc);
            return FALSE;
        }
        data = malloc(rowbytes * height);
        rows = malloc(sizeof(png_bytep) * height);
        for (i = 0; i < height; i++) {
            rows[i] = data + rowbytes * i;
        }
        png_read_image(png_ptr, rows);
        free(rows);

        image->data = data;
        png_read_end(png_ptr, info_ptr);
    }
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

    return TRUE;
}
Example #10
0
SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src)
{
	SDL_Surface *volatile surface;
	png_structp png_ptr;
	png_infop info_ptr;
	png_uint_32 width, height;
	int bit_depth, color_type, interlace_type;
	Uint32 Rmask;
	Uint32 Gmask;
	Uint32 Bmask;
	Uint32 Amask;
	SDL_Palette *palette;
	png_bytep *volatile row_pointers;
	int row, i;
	volatile int ckey = -1;
	png_color_16 *transv;

	if ( !src ) {
		/* The error message has been set in SDL_RWFromFile */
		return NULL;
	}

	/* Initialize the data we will clean up when we're done */
	png_ptr = NULL; info_ptr = NULL; row_pointers = NULL; surface = NULL;

	/* Create the PNG loading context structure */
	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
					  NULL,NULL,NULL);
	if (png_ptr == NULL){
		IMG_SetError("Couldn't allocate memory for PNG file or incompatible PNG dll");
		goto done;
	}

	 /* Allocate/initialize the memory for image information.  REQUIRED. */
	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) {
		IMG_SetError("Couldn't create image information for PNG file");
		goto done;
	}

	/* Set error handling if you are using setjmp/longjmp method (this is
	 * the normal method of doing things with libpng).  REQUIRED unless you
	 * set up your own error handlers in png_create_read_struct() earlier.
	 */
	if ( setjmp(png_ptr->jmpbuf) ) {
		IMG_SetError("Error reading the PNG file.");
		goto done;
	}

	/* Set up the input control */
	png_set_read_fn(png_ptr, src, png_read_data);

	/* Read PNG header info */
	png_read_info(png_ptr, info_ptr);
	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
			&color_type, &interlace_type, NULL, NULL);

	/* tell libpng to strip 16 bit/color files down to 8 bits/color */
	png_set_strip_16(png_ptr) ;

	/* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
	 * byte into separate bytes (useful for paletted and grayscale images).
	 */
	png_set_packing(png_ptr);

	/* scale greyscale values to the range 0..255 */
	if(color_type == PNG_COLOR_TYPE_GRAY)
		png_set_expand(png_ptr);

	/* For images with a single "transparent colour", set colour key;
	   if more than one index has transparency, or if partially transparent
	   entries exist, use full alpha channel */
	if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
	        int num_trans;
		Uint8 *trans;
		png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans,
			     &transv);
		if(color_type == PNG_COLOR_TYPE_PALETTE) {
		    /* Check if all tRNS entries are opaque except one */
		    int i, t = -1;
		    for(i = 0; i < num_trans; i++)
			if(trans[i] == 0) {
			    if(t >= 0)
				break;
			    t = i;
			} else if(trans[i] != 255)
			    break;
		    if(i == num_trans) {
			/* exactly one transparent index */
			ckey = t;
		    } else {
			/* more than one transparent index, or translucency */
			png_set_expand(png_ptr);
		    }
		} else
		    ckey = 0; /* actual value will be set later */
	}

	if ( color_type == PNG_COLOR_TYPE_GRAY_ALPHA )
		png_set_gray_to_rgb(png_ptr);

	png_read_update_info(png_ptr, info_ptr);

	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
			&color_type, &interlace_type, NULL, NULL);

	/* Allocate the SDL surface to hold the image */
	Rmask = Gmask = Bmask = Amask = 0 ; 
	if ( color_type != PNG_COLOR_TYPE_PALETTE ) {
		if ( SDL_BYTEORDER == SDL_LIL_ENDIAN ) {
			Rmask = 0x000000FF;
			Gmask = 0x0000FF00;
			Bmask = 0x00FF0000;
			Amask = (info_ptr->channels == 4) ? 0xFF000000 : 0;
		} else {
		        int s = (info_ptr->channels == 4) ? 0 : 8;
			Rmask = 0xFF000000 >> s;
			Gmask = 0x00FF0000 >> s;
			Bmask = 0x0000FF00 >> s;
			Amask = 0x000000FF >> s;
		}
	}
	surface = SDL_AllocSurface(SDL_SWSURFACE, width, height,
			bit_depth*info_ptr->channels, Rmask,Gmask,Bmask,Amask);
	if ( surface == NULL ) {
		IMG_SetError("Out of memory");
		goto done;
	}

	if(ckey != -1) {
	        if(color_type != PNG_COLOR_TYPE_PALETTE)
			/* FIXME: Should these be truncated or shifted down? */
		        ckey = SDL_MapRGB(surface->format,
			                 (Uint8)transv->red,
			                 (Uint8)transv->green,
			                 (Uint8)transv->blue);
	        SDL_SetColorKey(surface, SDL_SRCCOLORKEY, ckey);
	}

	/* Create the array of pointers to image data */
	row_pointers = (png_bytep*) malloc(sizeof(png_bytep)*height);
	if ( (row_pointers == NULL) ) {
		IMG_SetError("Out of memory");
		SDL_FreeSurface(surface);
		surface = NULL;
		goto done;
	}
	for (row = 0; row < (int)height; row++) {
		row_pointers[row] = (png_bytep)
				(Uint8 *)surface->pixels + row*surface->pitch;
	}

	/* Read the entire image in one go */
	png_read_image(png_ptr, row_pointers);

	/* and we're done!  (png_read_end() can be omitted if no processing of
	 * post-IDAT text/time/etc. is desired)
	 * In some cases it can't read PNG's created by some popular programs (ACDSEE),
	 * we do not want to process comments, so we omit png_read_end

	png_read_end(png_ptr, info_ptr);
	*/

	/* Load the palette, if any */
	palette = surface->format->palette;
	if ( palette ) {
	    if(color_type == PNG_COLOR_TYPE_GRAY) {
		palette->ncolors = 256;
		for(i = 0; i < 256; i++) {
		    palette->colors[i].r = i;
		    palette->colors[i].g = i;
		    palette->colors[i].b = i;
		}
	    } else if (info_ptr->num_palette > 0 ) {
		palette->ncolors = info_ptr->num_palette; 
		for( i=0; i<info_ptr->num_palette; ++i ) {
		    palette->colors[i].b = info_ptr->palette[i].blue;
		    palette->colors[i].g = info_ptr->palette[i].green;
		    palette->colors[i].r = info_ptr->palette[i].red;
		}
	    }
	}

done:	/* Clean up and return */
	png_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : (png_infopp)0,
								(png_infopp)0);
	if ( row_pointers ) {
		free(row_pointers);
	}
	return(surface); 
}
/*
 * Reduce the image type from grayscale(+alpha) or RGB(+alpha) to palette,
 * if possible.
 * The parameter reductions indicates the intended reductions.
 * The function returns the successful reductions.
 */
static png_uint_32 opng_reduce_to_palette(png_structp png_ptr, png_infop info_ptr, png_uint_32 reductions)
{
   png_row_info row_info;
   png_bytep sample_ptr;
   png_uint_32 height, width;
   int color_type, interlace_type, compression_type, filter_type;
   int src_bit_depth;
   png_color palette[256];
   png_byte trans_alpha[256];
   int num_trans, index;
   unsigned gray, red, green, blue, alpha;
   unsigned prev_red, prev_green, prev_blue, prev_alpha;
   png_uint_32 j;
   png_get_IHDR(png_ptr, info_ptr, &width, &height, &src_bit_depth,
      &color_type, &interlace_type, &compression_type, &filter_type);
  if (src_bit_depth != 8 || !height || !width)
      return OPNG_REDUCE_NONE;  /* nothing is done in this case */
   OPNG_ASSERT(!(color_type & PNG_COLOR_MASK_PALETTE));

   png_bytepp row_ptr = png_get_rows(png_ptr, info_ptr);
   int channels = png_get_channels(png_ptr, info_ptr);
   png_bytep alpha_row = (png_bytep)png_malloc(png_ptr, width);
   if (!alpha_row){
     exit(1);
   }


   row_info.width = width;
   row_info.rowbytes = 0;  /* not used */
   row_info.color_type = (png_byte)color_type;
   row_info.bit_depth = (png_byte)src_bit_depth;
   row_info.channels = (png_byte)channels;
   row_info.pixel_depth = 0;  /* not used */

   /* Analyze the possibility of this reduction. */
   int num_palette = num_trans = 0;
   png_color_16p trans_color = 0;
   png_get_tRNS(png_ptr, info_ptr, 0, 0, &trans_color);
   unsigned prev_gray = prev_red = prev_green = prev_blue = prev_alpha = 256;
   png_uint_32 i;
   for (i = 0; i < height; ++i, ++row_ptr)
   {
      sample_ptr = *row_ptr;
      opng_get_alpha_row(&row_info, trans_color, *row_ptr, alpha_row);
      if (color_type & PNG_COLOR_MASK_COLOR)
      {
         for (j = 0; j < width; ++j, sample_ptr += channels)
         {
            red   = sample_ptr[0];
            green = sample_ptr[1];
            blue  = sample_ptr[2];
            alpha = alpha_row[j];
            /* Check the cache first. */
            if (red != prev_red || green != prev_green || blue != prev_blue ||
                alpha != prev_alpha)
            {
               prev_red   = red;
               prev_green = green;
               prev_blue  = blue;
               prev_alpha = alpha;
               if (opng_insert_palette_entry(palette, &num_palette,
                   trans_alpha, &num_trans, 256,
                   red, green, blue, alpha, &index) < 0)  /* overflow */
               {
                  OPNG_ASSERT(num_palette < 0);
                  i = height;  /* forced exit from outer loop */
                  break;
               }
            }
         }
      }
      else  /* grayscale */
      {
         for (j = 0; j < width; ++j, sample_ptr += channels)
         {
            gray  = sample_ptr[0];
            alpha = alpha_row[j];
            /* Check the cache first. */
            if (gray != prev_gray || alpha != prev_alpha)
            {
               prev_gray  = gray;
               prev_alpha = alpha;
               if (opng_insert_palette_entry(palette, &num_palette,
                   trans_alpha, &num_trans, 256,
                   gray, gray, gray, alpha, &index) < 0)  /* overflow */
               {
                  OPNG_ASSERT(num_palette < 0);
                  i = height;  /* forced exit from outer loop */
                  break;
               }
            }
         }
      }
   }
#ifdef PNG_bKGD_SUPPORTED
    png_color_16p background;
    if ((num_palette >= 0) && png_get_bKGD(png_ptr, info_ptr, &background))
    {
        /* bKGD has an alpha-agnostic palette entry. */
        if (color_type & PNG_COLOR_MASK_COLOR)
        {
            red   = background->red;
            green = background->green;
            blue  = background->blue;
        }
        else
            red = green = blue = background->gray;
        opng_insert_palette_entry(palette, &num_palette,
                                  trans_alpha, &num_trans, 256,
                                  red, green, blue, 256, &index);
        if (index >= 0)
            background->index = (png_byte)index;
    }
#endif

    /* Continue only if the uncompressed indexed image (pixels + PLTE + tRNS)
     * is smaller than the uncompressed RGB(A) image.
     * Casual overhead (headers, CRCs, etc.) is ignored.
     *
     * Compare:
     * num_pixels * (src_bit_depth * channels - dest_bit_depth) / 8
     * vs.
     * sizeof(PLTE) + sizeof(tRNS)
     */
       /* 5/3 times sizeof(PLTE) + sizeof(tRNS) as:
          1. Palette is uncompressed additional IDAT data is
          2. Headers */
    if (num_palette >= 0)
    {
        int dest_bit_depth;
        OPNG_ASSERT(num_palette > 0 && num_palette <= 256);
        OPNG_ASSERT(num_trans >= 0 && num_trans <= num_palette);
        if (num_palette <= 2)
            dest_bit_depth = 1;
        else if (num_palette <= 4)
            dest_bit_depth = 2;
        else if (num_palette <= 16)
            dest_bit_depth = 4;
        else
            dest_bit_depth = 8;
        /* Do the comparison in a way that does not cause overflow. */
        /*if (channels * 8 == dest_bit_depth || (3 * num_palette + num_trans) * 8 / (channels * 8 - dest_bit_depth) / width / height >= 1) */
        if (channels * 8 == dest_bit_depth || (12 + (5 * num_palette + num_trans)) * 8 / (channels * 8 - dest_bit_depth) / width / height >= 1)
        {num_palette = -1;}
        if ((num_palette && width * height < 12u * num_palette) || width * height < 8000){
            num_palette = -1;
        }
    }

   if (num_palette < 0)  /* can't reduce */
   {
      png_free(png_ptr, alpha_row);
      return OPNG_REDUCE_NONE;
   }

   /* Reduce. */
   row_ptr = png_get_rows(png_ptr, info_ptr);
   index = -1;
   prev_red = prev_green = prev_blue = prev_alpha = (unsigned int)(-1);
   for (i = 0; i < height; ++i, ++row_ptr)
   {
      sample_ptr = *row_ptr;
      opng_get_alpha_row(&row_info, trans_color, *row_ptr, alpha_row);
      if (color_type & PNG_COLOR_MASK_COLOR)
      {
         for (j = 0; j < width; ++j, sample_ptr += channels)
         {
            red   = sample_ptr[0];
            green = sample_ptr[1];
            blue  = sample_ptr[2];
            alpha = alpha_row[j];
            /* Check the cache first. */
            if (red != prev_red || green != prev_green || blue != prev_blue ||
                alpha != prev_alpha)
            {
               prev_red   = red;
               prev_green = green;
               prev_blue  = blue;
               prev_alpha = alpha;
               if (opng_insert_palette_entry(palette, &num_palette,
                   trans_alpha, &num_trans, 256,
                   red, green, blue, alpha, &index) != 0)
                  index = -1;  /* this should not happen */
            }
            OPNG_ASSERT(index >= 0);
            (*row_ptr)[j] = (png_byte)index;
         }
      }
      else  /* grayscale */
      {
         for (j = 0; j < width; ++j, sample_ptr += channels)
         {
            gray  = sample_ptr[0];
            alpha = alpha_row[j];
            /* Check the cache first. */
            if (gray != prev_gray || alpha != prev_alpha)
            {
               prev_gray  = gray;
               prev_alpha = alpha;
               if (opng_insert_palette_entry(palette, &num_palette,
                   trans_alpha, &num_trans, 256,
                   gray, gray, gray, alpha, &index) != 0)
                  index = -1;  /* this should not happen */
            }
            OPNG_ASSERT(index >= 0);
            (*row_ptr)[j] = (png_byte)index;
         }
      }
   }

   /* Update the image information. */
   png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_PALETTE,
      interlace_type, compression_type, filter_type);
   png_set_PLTE(png_ptr, info_ptr, palette, num_palette);
   if (num_trans > 0)
      png_set_tRNS(png_ptr, info_ptr, trans_alpha, num_trans, 0);
   /* bKGD (if present) is automatically updated. */

   png_free(png_ptr, alpha_row);

   png_uint_32 result = OPNG_REDUCE_RGB_TO_PALETTE;
   if (reductions & OPNG_REDUCE_8_TO_4_2_1)
      result |= opng_reduce_palette_bits(png_ptr, info_ptr, reductions);
   return result;
}
/*
 * Reduce the image type to a lower bit depth and color type,
 * by removing redundant bits.
 * Possible reductions: 16bpp to 8bpp; RGB to gray; strip alpha.
 * The parameter reductions indicates the intended reductions.
 * The function returns the successful reductions.
 * All reductions are performed in a single step.
 */
static png_uint_32  opng_reduce_bits(png_structp png_ptr, png_infop info_ptr, png_uint_32 reductions)
{
   png_bytep src_ptr, dest_ptr;
   png_uint_32 width, height;
   int interlace_type, compression_type, filter_type, src_bit_depth, dest_bit_depth, src_color_type;
   /* See which reductions may be performed. */
   reductions = opng_analyze_bits(png_ptr, info_ptr, reductions);
   if (reductions == OPNG_REDUCE_NONE)
      return OPNG_REDUCE_NONE;  /* exit early */

   png_get_IHDR(png_ptr, info_ptr, &width, &height,
      &src_bit_depth, &src_color_type,
      &interlace_type, &compression_type, &filter_type);
  if (!height || !width){
    return OPNG_REDUCE_NONE;
  }
   /* Compute the new image parameters bit_depth, color_type, etc. */
   OPNG_ASSERT(src_bit_depth >= 8);
   if (reductions & OPNG_REDUCE_16_TO_8)
   {
      OPNG_ASSERT(src_bit_depth == 16);
      dest_bit_depth = 8;
   }
   else
      dest_bit_depth = src_bit_depth;

   int src_byte_depth = src_bit_depth / 8;
   int dest_byte_depth = dest_bit_depth / 8;

   int dest_color_type = src_color_type;
   if (reductions & OPNG_REDUCE_RGB_TO_GRAY)
   {
      OPNG_ASSERT(src_color_type & PNG_COLOR_MASK_COLOR);
      dest_color_type &= ~PNG_COLOR_MASK_COLOR;
   }
   if (reductions & OPNG_REDUCE_STRIP_ALPHA)
   {
      OPNG_ASSERT(src_color_type & PNG_COLOR_MASK_ALPHA);
      dest_color_type &= ~PNG_COLOR_MASK_ALPHA;
   }

   int src_channels = png_get_channels(png_ptr, info_ptr);
   int dest_channels =
      ((dest_color_type & PNG_COLOR_MASK_COLOR) ? 3 : 1) +
      ((dest_color_type & PNG_COLOR_MASK_ALPHA) ? 1 : 0);

   int src_sample_size = src_channels * src_byte_depth;
   int dest_sample_size = dest_channels * dest_byte_depth;

   /* Pre-compute the intra-sample translation table. */
   int k;
   int tran_tbl[8];
   for (k = 0; k < 4 * dest_byte_depth; ++k)
      tran_tbl[k] = k * src_bit_depth / dest_bit_depth;
   /* If rgb --> gray, shift the alpha component two positions to the left. */
   if ((reductions & OPNG_REDUCE_RGB_TO_GRAY) &&
       (dest_color_type & PNG_COLOR_MASK_ALPHA))
   {
      tran_tbl[dest_byte_depth] = tran_tbl[3 * dest_byte_depth];
      if (dest_byte_depth == 2)
         tran_tbl[dest_byte_depth + 1] = tran_tbl[3 * dest_byte_depth + 1];
   }

   /* Translate the samples to the new image type. */
   OPNG_ASSERT(src_sample_size > dest_sample_size);
   png_bytepp row_ptr = png_get_rows(png_ptr, info_ptr);
   for (png_uint_32 i = 0; i < height; ++i, ++row_ptr)
   {
      src_ptr = dest_ptr = *row_ptr;
      for (png_uint_32 j = 0; j < width; ++j)
      {
         for (k = 0; k < dest_sample_size; ++k)
            dest_ptr[k] = src_ptr[tran_tbl[k]];
         src_ptr += src_sample_size;
         dest_ptr += dest_sample_size;
      }
   }
   png_color_16p trans_color;
   /* Update the ancillary information. */
   if (png_get_tRNS(png_ptr, info_ptr, 0, 0, &trans_color))
   {
      if (reductions & OPNG_REDUCE_16_TO_8)
      {
         if (trans_color->red   % 257 == 0 &&
             trans_color->green % 257 == 0 &&
             trans_color->blue  % 257 == 0 &&
             trans_color->gray  % 257 == 0)
         {
            trans_color->red   &= 255;
            trans_color->green &= 255;
            trans_color->blue  &= 255;
            trans_color->gray  &= 255;
         }
         else
         {
            /* 16-bit tRNS in 8-bit samples: all pixels are 100% opaque. */
            png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, -1);
            png_set_invalid(png_ptr, info_ptr, PNG_INFO_tRNS);
         }
      }
      if (reductions & OPNG_REDUCE_RGB_TO_GRAY)
      {
         if (trans_color->red == trans_color->green ||
             trans_color->red == trans_color->blue)
            trans_color->gray = trans_color->red;
         else
         {
            /* Non-gray tRNS in grayscale image: all pixels are 100% opaque. */
            png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, -1);
            png_set_invalid(png_ptr, info_ptr, PNG_INFO_tRNS);
         }
      }
   }
#ifdef PNG_bKGD_SUPPORTED
   png_color_16p background;
   if (png_get_bKGD(png_ptr, info_ptr, &background))
   {
      if (reductions & OPNG_REDUCE_16_TO_8)
      {
         background->red   &= 255;
         background->green &= 255;
         background->blue  &= 255;
         background->gray  &= 255;
      }
      if (reductions & OPNG_REDUCE_RGB_TO_GRAY)
         background->gray = background->red;
   }
#endif
#ifdef PNG_sBIT_SUPPORTED
    png_color_8p sig_bits;
   if (png_get_sBIT(png_ptr, info_ptr, &sig_bits))
   {
      if (reductions & OPNG_REDUCE_16_TO_8)
      {
         if (sig_bits->red > 8)
            sig_bits->red = 8;
         if (sig_bits->green > 8)
            sig_bits->green = 8;
         if (sig_bits->blue > 8)
            sig_bits->blue = 8;
         if (sig_bits->gray > 8)
            sig_bits->gray = 8;
         if (sig_bits->alpha > 8)
            sig_bits->alpha = 8;
      }
      if (reductions & OPNG_REDUCE_RGB_TO_GRAY)
      {
         png_byte max_sig_bits = sig_bits->red;
         if (max_sig_bits < sig_bits->green)
            max_sig_bits = sig_bits->green;
         if (max_sig_bits < sig_bits->blue)
            max_sig_bits = sig_bits->blue;
         sig_bits->gray = max_sig_bits;
      }
   }
#endif

   /* Update the image information. */
   png_set_IHDR(png_ptr, info_ptr, width, height,
      dest_bit_depth, dest_color_type,
      interlace_type, compression_type, filter_type);

   return reductions;
}
Example #13
0
/* TODO: I wonder why this function ALWAYS returns 0 */
int loadPNG(ePtr<gPixmap> &result, const char *filename, int accel)
{
	CFile fp(filename, "rb");

	if (!fp)
	{
		eDebug("[ePNG] couldn't open %s", filename );
		return 0;
	}
	{
		__u8 header[8];
		if (!fread(header, 8, 1, fp))
		{
			eDebug("[ePNG] failed to get png header");
			return 0;
		}
		if (png_sig_cmp(header, 0, 8))
		{
			eDebug("[ePNG] header size mismatch");
			return 0;
		}
	}
	png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
	if (!png_ptr)
	{
		eDebug("[ePNG] failed to create read struct");
		return 0;
	}
	png_infop info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr)
	{
		eDebug("[ePNG] failed to create info struct");
		png_destroy_read_struct(&png_ptr, (png_infopp)0, (png_infopp)0);
		return 0;
	}
	png_infop end_info = png_create_info_struct(png_ptr);
	if (!end_info)
	{
		eDebug("[ePNG] failed to create end info struct");
		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
		return 0;
	}
	if (setjmp(png_jmpbuf(png_ptr)))
	{
		eDebug("[ePNG] png setjump failed or activated");
		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
		result = 0;
		return 0;
	}
	png_init_io(png_ptr, fp);
	png_set_sig_bytes(png_ptr, 8);
	png_read_info(png_ptr, info_ptr);

	png_uint_32 width, height;
	int bit_depth;
	int color_type;
	int interlace_type;
	int channels;
	int trns;

	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, 0, 0);
	channels = png_get_channels(png_ptr, info_ptr);
	trns = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS);
	//eDebug("[ePNG] %s: before %dx%dx%dbpcx%dchan coltyp=%d", filename, (int)width, (int)height, bit_depth, channels, color_type);

	/*
	 * gPixmaps use 8 bits per channel. rgb pixmaps are stored as abgr.
	 * So convert 1,2 and 4 bpc to 8bpc images that enigma can blit
	 * so add 'empty' alpha channel
	 * Expand G+tRNS to GA, RGB+tRNS to RGBA
	 */
	if (bit_depth == 16)
		png_set_strip_16(png_ptr);
	if (bit_depth < 8)
		png_set_packing (png_ptr);

	if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
		png_set_expand_gray_1_2_4_to_8(png_ptr);
	if (color_type == PNG_COLOR_TYPE_GRAY && trns)
		png_set_tRNS_to_alpha(png_ptr);
	if ((color_type == PNG_COLOR_TYPE_GRAY && trns) || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
		png_set_gray_to_rgb(png_ptr);
		png_set_bgr(png_ptr);
	}

	if (color_type == PNG_COLOR_TYPE_RGB) {
		if (trns)
			png_set_tRNS_to_alpha(png_ptr);
		else
			png_set_add_alpha(png_ptr, 255, PNG_FILLER_AFTER);
	}

	if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA)
		png_set_bgr(png_ptr);

	// Update the info structures after the transformations take effect
	if (interlace_type != PNG_INTERLACE_NONE)
		png_set_interlace_handling(png_ptr);  // needed before read_update_info()
	png_read_update_info (png_ptr, info_ptr);
	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
	channels = png_get_channels(png_ptr, info_ptr);

	result = new gPixmap(eSize(width, height), bit_depth * channels, accel);
	gUnmanagedSurface *surface = result->surface;

	png_bytep *rowptr = new png_bytep[height];
	for (unsigned int i = 0; i < height; i++)
		rowptr[i] = ((png_byte*)(surface->data)) + i * surface->stride;
	png_read_image(png_ptr, rowptr);

	delete [] rowptr;

	int num_palette = -1, num_trans = -1;
	if (color_type == PNG_COLOR_TYPE_PALETTE) {
		if (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) {
			png_color *palette;
			png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
			if (num_palette)
				surface->clut.data = new gRGB[num_palette];
			else
				surface->clut.data = 0;
			surface->clut.colors = num_palette;

			for (int i = 0; i < num_palette; i++) {
				surface->clut.data[i].a = 0;
				surface->clut.data[i].r = palette[i].red;
				surface->clut.data[i].g = palette[i].green;
				surface->clut.data[i].b = palette[i].blue;
			}
			if (trns) {
				png_byte *trans;
				png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, 0);
				for (int i = 0; i < num_trans; i++)
					surface->clut.data[i].a = 255 - trans[i];
				for (int i = num_trans; i < num_palette; i++)
					surface->clut.data[i].a = 0;
			}
		}
		else {
			surface->clut.data = 0;
			surface->clut.colors = 0;
		}
		surface->clut.start = 0;
	}
	//eDebug("[ePNG] %s: after  %dx%dx%dbpcx%dchan coltyp=%d cols=%d trans=%d", filename, (int)width, (int)height, bit_depth, channels, color_type, num_palette, num_trans);

	png_read_end(png_ptr, end_info);
	png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
	return 0;
}
Example #14
0
static
void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, float screen_gamma=0.0)
{
    if (screen_gamma != 0.0 && png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) {
        double file_gamma;
        png_get_gAMA(png_ptr, info_ptr, &file_gamma);
        png_set_gamma(png_ptr, screen_gamma, file_gamma);
    }

    png_uint_32 width;
    png_uint_32 height;
    int bit_depth;
    int color_type;
    png_bytep trans_alpha = 0;
    png_color_16p trans_color_p = 0;
    int num_trans;
    png_colorp palette = 0;
    int num_palette;
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
    png_set_interlace_handling(png_ptr);

    if (color_type == PNG_COLOR_TYPE_GRAY) {
        // Black & White or 8-bit grayscale
        if (bit_depth == 1 && png_get_channels(png_ptr, info_ptr) == 1) {
            png_set_invert_mono(png_ptr);
            png_read_update_info(png_ptr, info_ptr);
            if (image.size() != QSize(width, height) || image.format() != QImage::Format_Mono) {
                image = QImage(width, height, QImage::Format_Mono);
                if (image.isNull())
                    return;
            }
            image.setColorCount(2);
            image.setColor(1, qRgb(0,0,0));
            image.setColor(0, qRgb(255,255,255));
        } else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
            png_set_expand(png_ptr);
            png_set_strip_16(png_ptr);
            png_set_gray_to_rgb(png_ptr);
            if (image.size() != QSize(width, height) || image.format() != QImage::Format_ARGB32) {
                image = QImage(width, height, QImage::Format_ARGB32);
                if (image.isNull())
                    return;
            }
            if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
                png_set_swap_alpha(png_ptr);

            png_read_update_info(png_ptr, info_ptr);
        } else {
            if (bit_depth == 16)
                png_set_strip_16(png_ptr);
            else if (bit_depth < 8)
                png_set_packing(png_ptr);
            int ncols = bit_depth < 8 ? 1 << bit_depth : 256;
            png_read_update_info(png_ptr, info_ptr);
            if (image.size() != QSize(width, height) || image.format() != QImage::Format_Indexed8) {
                image = QImage(width, height, QImage::Format_Indexed8);
                if (image.isNull())
                    return;
            }
            image.setColorCount(ncols);
            for (int i=0; i<ncols; i++) {
                int c = i*255/(ncols-1);
                image.setColor(i, qRgba(c,c,c,0xff));
            }
            if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_color_p) {
                const int g = trans_color_p->gray;
                if (g < ncols) {
                    image.setColor(g, 0);
                }
            }
        }
    } else if (color_type == PNG_COLOR_TYPE_PALETTE
               && png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)
               && num_palette <= 256)
    {
        // 1-bit and 8-bit color
        if (bit_depth != 1)
            png_set_packing(png_ptr);
        png_read_update_info(png_ptr, info_ptr);
        png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
        QImage::Format format = bit_depth == 1 ? QImage::Format_Mono : QImage::Format_Indexed8;
        if (image.size() != QSize(width, height) || image.format() != format) {
            image = QImage(width, height, format);
            if (image.isNull())
                return;
        }
        png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
        image.setColorCount(num_palette);
        int i = 0;
        if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_alpha) {
            while (i < num_trans) {
                image.setColor(i, qRgba(
                    palette[i].red,
                    palette[i].green,
                    palette[i].blue,
                    trans_alpha[i]
                   )
               );
                i++;
            }
        }
        while (i < num_palette) {
            image.setColor(i, qRgba(
                palette[i].red,
                palette[i].green,
                palette[i].blue,
                0xff
               )
           );
            i++;
        }
    } else {
        // 32-bit
        if (bit_depth == 16)
            png_set_strip_16(png_ptr);

        png_set_expand(png_ptr);

        if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
            png_set_gray_to_rgb(png_ptr);

        QImage::Format format = QImage::Format_ARGB32;
        // Only add filler if no alpha, or we can get 5 channel data.
        if (!(color_type & PNG_COLOR_MASK_ALPHA)
            && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
            png_set_filler(png_ptr, 0xff, QSysInfo::ByteOrder == QSysInfo::BigEndian ?
                           PNG_FILLER_BEFORE : PNG_FILLER_AFTER);
            // We want 4 bytes, but it isn't an alpha channel
            format = QImage::Format_RGB32;
        }
        if (image.size() != QSize(width, height) || image.format() != format) {
            image = QImage(width, height, format);
            if (image.isNull())
                return;
        }

        if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
            png_set_swap_alpha(png_ptr);

        png_read_update_info(png_ptr, info_ptr);
    }

    // Qt==ARGB==Big(ARGB)==Little(BGRA)
    if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) {
        png_set_bgr(png_ptr);
    }
}
Example #15
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);
}
Example #16
0
int load_png( char *file_name, int stype )
{
	char buf[PNG_BYTES_TO_CHECK], *mess;
	unsigned char *rgb, *rgb2, *rgb3;
	int i, row, do_prog, bit_depth, color_type, interlace_type, width, height;
	unsigned int sig_read = 0;
	FILE *fp;
	png_bytep *row_pointers, trans;
	png_color_16p trans_rgb;

	png_structp png_ptr;
	png_infop info_ptr;
	png_uint_32 pwidth, pheight;
	png_colorp png_palette;

	if ((fp = fopen(file_name, "rb")) == NULL) return -1;
	i = fread(buf, 1, PNG_BYTES_TO_CHECK, fp);
	if ( i != PNG_BYTES_TO_CHECK ) goto fail;
	i = !png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK);
	if ( i<=0 ) goto fail;
	rewind( fp );

	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

	if (png_ptr == NULL) goto fail;

	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL)
	{
		png_destroy_read_struct(&png_ptr, NULL, NULL);
		goto fail;
	}

	if (setjmp(png_jmpbuf(png_ptr)))
	{
		png_destroy_read_struct(&png_ptr, NULL, NULL);
		fclose(fp);
		return -1;
	}

	png_init_io(png_ptr, fp);
	png_set_sig_bytes(png_ptr, sig_read);

	png_read_info(png_ptr, info_ptr);

	png_get_IHDR(png_ptr, info_ptr, &pwidth, &pheight, &bit_depth, &color_type,
		&interlace_type, NULL, NULL);

	width = (int) pwidth;
	height = (int) pheight;

	if ( width > MAX_WIDTH || height > MAX_HEIGHT )
	{
		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
		fclose(fp);
		return TOO_BIG;
	}

	row_pointers = malloc( sizeof(png_bytep) * height );

	if (setjmp(png_jmpbuf(png_ptr)))	// If libpng generates an error now, clean up
	{
		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
		fclose(fp);
		free(row_pointers);
		return FILE_LIB_ERROR;
	}

	rgb = NULL;
	mess = NULL;
	if ( width*height > FILE_PROGRESS ) do_prog = 1;
	else do_prog = 0;

	if ( stype == 0 )
	{
		mess = _("Loading PNG image");
		rgb = mem_image;
	}
	if ( stype == 1 )
	{
		mess = _("Loading clipboard image");
		rgb = mem_clipboard;
		if ( rgb != NULL ) free( rgb );		// Lose old clipboard
		mem_clip_mask_clear();			// Lose old clipboard mask
	}

	if ( color_type != PNG_COLOR_TYPE_PALETTE || bit_depth>8 )	// RGB PNG file
	{
		png_set_strip_16(png_ptr);
		png_set_gray_1_2_4_to_8(png_ptr);
		png_set_palette_to_rgb(png_ptr);
		png_set_gray_to_rgb(png_ptr);

		if ( stype == 0 )
		{
			mem_pal_copy( mem_pal, mem_pal_def );
			mem_cols = 256;
			if ( mem_new( width, height, 3 ) != 0 ) goto file_too_huge;
			rgb = mem_image;
			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
			{
				// Image has a transparent index
				png_get_tRNS(png_ptr, info_ptr, 0, 0, &trans_rgb);
				mem_pal[255].red = trans_rgb->red;
				mem_pal[255].green = trans_rgb->green;
				mem_pal[255].blue = trans_rgb->blue;
				if (color_type == PNG_COLOR_TYPE_GRAY)
				{
					if ( bit_depth==4 ) i = trans_rgb->gray * 17;
					if ( bit_depth==8 ) i = trans_rgb->gray;
					if ( bit_depth==16 ) i = trans_rgb->gray >> (bit_depth-8);
					mem_pal[255].red = i;
					mem_pal[255].green = i;
					mem_pal[255].blue = i;
				}
				mem_xpm_trans = 255;
			}
		}
Example #17
0
AFRAMES OneFrameReader(png_structp png_ptr_read, png_infop info_ptr_read,
                 png_structp png_ptr_write, png_infop info_ptr_write,
                 png_uint_32 width, png_uint_32 height)
{
    /* IHDR */
    /* struct data need from background */
    AFRAMES pframe;
    png_uint_32 garbage;
    int bit_depth;
    int colour_type;
    int interlace_method;
    int compression_method;
    int filter_method;
    
    /* PLTE */
    png_colorp palette = NULL;
    int palette_size = 0;
    
    /* gAMA */
    double gamma;
    
    /* tRNS */
    png_bytep trans;
    int num_trans;
    png_color_16p trans_values;
    
    /* bKGD */
    png_color_16p background;
    
    png_get_IHDR(png_ptr_read, info_ptr_read, &garbage, &garbage,
                 &bit_depth, &colour_type, &interlace_method,
                 &compression_method, &filter_method);
    png_set_IHDR(png_ptr_write, info_ptr_write, width, height,
                 bit_depth, colour_type, interlace_method,
                 compression_method, filter_method);
                 
                 
    
    
    int r = 0, g = 0, b = 0;
    int bpp = bit_depth;
    
    switch (colour_type) {
                case PNG_COLOR_TYPE_GRAY      :           break;
                case PNG_COLOR_TYPE_RGB       : bpp *= 3; break;
                case PNG_COLOR_TYPE_PALETTE   :           break;
                case PNG_COLOR_TYPE_GRAY_ALPHA: bpp *= 2; break;
                case PNG_COLOR_TYPE_RGB_ALPHA : bpp *= 4; break;
                default: 
                return pframe;
    }
    
    pframe.colortype = colour_type;
    pframe.bytedep = bpp;
    pframe.pngBG = trans_values;
    
    /////////qDebug() << "### color type  " << colour_type << bpp << num_trans;
    
                 
    
    if(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_PLTE))
    {
        /////////qDebug() << "### PNG_INFO_PLTE";
        
        png_get_PLTE(png_ptr_read, info_ptr_read, &palette, &palette_size);
        png_set_PLTE(png_ptr_write, info_ptr_write, palette, palette_size);
    }
    
    if(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_gAMA))
    {
        /////////qDebug() << "### PNG_INFO_gAMA";
        
        png_get_gAMA(png_ptr_read, info_ptr_read, &gamma);
        png_set_gAMA(png_ptr_write, info_ptr_write, gamma);
    }
    
    if(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_tRNS))
    {
        //////////qDebug() << "### PNG_INFO_tRNS";
        
        png_get_tRNS(png_ptr_read, info_ptr_read, &trans, &num_trans, &trans_values);
        png_set_tRNS(png_ptr_write, info_ptr_write, trans, num_trans, trans_values);
    }
    
    if(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_bKGD))
    {
        ////////qDebug() << "### PNG_INFO_bKGD";
        
        png_get_bKGD(png_ptr_read, info_ptr_read, &background);
        png_set_bKGD(png_ptr_write, info_ptr_write, background);
        png_color_16p bkgd = background;
        pframe.pngBG = background;
        
        int r = 0, g = 0, b = 0;
        
                if(colour_type == PNG_COLOR_TYPE_RGB || colour_type == PNG_COLOR_TYPE_RGB_ALPHA) {
                r = bkgd->red;
                g = bkgd->green;
                b = bkgd->blue;
                }
                if(colour_type == PNG_COLOR_TYPE_GRAY || colour_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
                r = g = b = bkgd->gray;
                }
                if(colour_type == PNG_COLOR_TYPE_PALETTE) {
                r = palette[bkgd->index].red;
                g = palette[bkgd->index].green;
                b = palette[bkgd->index].blue;
                }
                    // scale down to 8 bit color since QColor doesn't support 16 bit colors
                if(bit_depth > 8) {
                r >>= 8;
                g >>= 8;
                b >>= 8;
                }
                
                ////////qDebug() << "### color  " << r << g << b;
                
                pframe.bg = QColor(r,g,b);
                pframe.foundcolor = true; 
        
    } else {
Example #18
0
image_t* readImage(const char* filename)
{
	image_t* img;
	uint8_t header[8];
	size_t cbhead;
	FILE* fp;

	fp = fopen(filename, "rb");
	if (!fp)
	{
		verbose(1, "Error: Could not open file %s: %s\n",
				filename, strerror(errno));
		return NULL;
	}

	cbhead = fread(header, 1, sizeof(header), fp);
	if (png_sig_cmp(header, 0, cbhead))
	{
		verbose(1, "Input file is not a PNG image\n");
		fclose(fp);
		return NULL;
	}

	img = malloc(sizeof(*img));
	if (!img)
	{
		verbose(1, "Out of memory reading image\n");
		fclose(fp);
		return NULL;
	}
	memset(img, 0, sizeof(*img));

	img->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (!img->png_ptr)
	{
		verbose(1, "png_create_read_struct failed\n");
		fclose(fp);
		return NULL;
	}
	img->info_ptr = png_create_info_struct(img->png_ptr);
	if (!img->info_ptr)
	{
		verbose(1, "png_create_info_struct failed\n");
		png_destroy_read_struct(&img->png_ptr, NULL, NULL);
		fclose(fp);
		return NULL;
	}

	img->end_info = png_create_info_struct(img->png_ptr);
	if (!img->end_info)
	{
		verbose(1, "png_create_info_struct failed\n");
		png_destroy_read_struct(&img->png_ptr, &img->info_ptr, NULL);
		fclose(fp);
		return NULL;
	}

	if (setjmp(png_jmpbuf(img->png_ptr)))
	{
		verbose(1, "PNG error\n");
		png_destroy_read_struct(&img->png_ptr, &img->info_ptr, &img->end_info);
		fclose(fp);
		return NULL;
	}

	png_init_io(img->png_ptr, fp);
	png_set_sig_bytes(img->png_ptr, cbhead);

	png_read_info(img->png_ptr, img->info_ptr);

	png_get_IHDR(img->png_ptr, img->info_ptr, &img->w, &img->h, &img->bit_depth,
			&img->color_type, &img->interlace_type, &img->compression_type,
			&img->filter_type);
	png_get_tRNS(img->png_ptr, img->info_ptr, &img->trans, &img->num_trans, &img->trans_values);
	if (img->trans_values)
		img->trans_scaled = *img->trans_values;
	png_get_sBIT(img->png_ptr, img->info_ptr, &img->sig_bit);
	if (!png_get_sRGB(img->png_ptr, img->info_ptr, &img->srgb_intent))
		img->srgb_intent = -1;
	img->channels = png_get_channels(img->png_ptr, img->info_ptr);

	if (img->bit_depth < 8)
	{	// make sure we get 1 pixel per byte
		png_set_packing(img->png_ptr);
	}
	else if (img->bit_depth == 16)
	{	// or 1 byte per channel
		png_set_strip_16(img->png_ptr);
		img->bit_depth = 8;
		if (img->sig_bit)
		{
			if (img->sig_bit->red > 8) img->sig_bit->red = 8;
			if (img->sig_bit->green > 8) img->sig_bit->green = 8;
			if (img->sig_bit->blue > 8) img->sig_bit->blue = 8;
			if (img->sig_bit->alpha > 8) img->sig_bit->alpha = 8;
			if (img->sig_bit->gray > 8) img->sig_bit->gray = 8;
		}
		img->trans_scaled.red >>= 8;
		img->trans_scaled.green >>= 8;
		img->trans_scaled.blue >>= 8;
	}
Example #19
0
int loadPNG(ePtr<gPixmap> &result, const char *filename)
{
	__u8 header[8];
	FILE *fp=fopen(filename, "rb");
	
	if (!fp)
	{
//		eDebug("couldn't open %s", filename );
		return 0;
	}
	if (!fread(header, 8, 1, fp))
	{
		eDebug("couldn't read");
		fclose(fp);
		return 0;
	}
	if (png_sig_cmp(header, 0, 8))
	{
		fclose(fp);
		return 0;
	}
	png_structp png_ptr=png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
	if (!png_ptr)
	{
		eDebug("no pngptr");
		fclose(fp);
		return 0;
	}
	png_infop info_ptr=png_create_info_struct(png_ptr);
	if (!info_ptr)
	{
		eDebug("no info ptr");
		png_destroy_read_struct(&png_ptr, (png_infopp)0, (png_infopp)0);
		fclose(fp);
		return 0;
	}
	png_infop end_info = png_create_info_struct(png_ptr);
	if (!end_info)
	{
		eDebug("no end");
		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
		fclose(fp);
		return 0;
	 }
	if (setjmp(png_ptr->jmpbuf))
	{
		eDebug("das war wohl nix");
		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
		fclose(fp);
		result = 0;
		return 0;
	}
	png_init_io(png_ptr, fp);
	png_set_sig_bytes(png_ptr, 8);
	png_set_invert_alpha(png_ptr);
	png_read_info(png_ptr, info_ptr);
	
	png_uint_32 width, height;
	int bit_depth;
	int color_type;
	
	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
	
	if (color_type == PNG_COLOR_TYPE_GRAY || color_type & PNG_COLOR_MASK_PALETTE)
	{
		result=new gPixmap(eSize(width, height), bit_depth);
		gSurface *surface = result->surface;
	
		png_bytep *rowptr=new png_bytep[height];
	
		for (unsigned int i=0; i<height; i++)
			rowptr[i]=((png_byte*)(surface->data))+i*surface->stride;
		png_read_rows(png_ptr, rowptr, 0, height);
	
		delete [] rowptr;
	
		if (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE))
		{
			png_color *palette;
			int num_palette;
			png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
			if (num_palette)
				surface->clut.data=new gRGB[num_palette];
			else
				surface->clut.data=0;
			surface->clut.colors=num_palette;
			
			for (int i=0; i<num_palette; i++)
			{
				surface->clut.data[i].a=0;
				surface->clut.data[i].r=palette[i].red;
				surface->clut.data[i].g=palette[i].green;
				surface->clut.data[i].b=palette[i].blue;
			}
			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
			{
				png_byte *trans;
				png_get_tRNS(png_ptr, info_ptr, &trans, &num_palette, 0);
				for (int i=0; i<num_palette; i++)
					surface->clut.data[i].a=255-trans[i];
			}
		} else
		{
			surface->clut.data=0;
			surface->clut.colors=0;
		}
		surface->clut.start=0;
		png_read_end(png_ptr, end_info);
#ifndef BUILD_VUPLUS
	} else {
		result=0;
		eDebug("%s: %dx%dx%d png, %d", filename, (int)width, (int)height, (int)bit_depth, color_type);
	}		
#else		//csh Support for 32bit png file.
	}else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA && bit_depth == 8){
Example #20
0
IMAGE* load_png(int fd)
{
	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;
	png_uint_32 width, height;
	int bit_depth, color_type, interlace_type;
	png_bytep * row_pointers;

	int ckey = -1;
	png_color_16 *transv;

	IMAGE* image = NULL;

	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
					  NULL,NULL,NULL);
	if (png_ptr == NULL) goto err;
	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) goto err;

	if ( setjmp(png_ptr->jmpbuf)) goto err;
	
	/* Set up the input control */
	png_set_read_fn(png_ptr, (void*)fd, png_read_data);

	/* Read PNG header info */
	png_read_info(png_ptr, info_ptr);
	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
			&color_type, &interlace_type, NULL, NULL);

	/* tell libpng to strip 16 bit/color files down to 8 bits/color */
	png_set_strip_16(png_ptr) ;

	/* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
	 * byte into separate bytes (useful for paletted and grayscale images).
	 */
	png_set_packing(png_ptr);

	/* scale greyscale values to the range 0..255 */
	if(color_type == PNG_COLOR_TYPE_GRAY)
		png_set_expand(png_ptr);

	/* For images with a single "transparent colour", set colour key;
	   if more than one index has transparency, or if partially transparent
	   entries exist, use full alpha channel */
	if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
	        int num_trans;
		unsigned char *trans;
		png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans,
			     &transv);
		if(color_type == PNG_COLOR_TYPE_PALETTE) {
		    /* Check if all tRNS entries are opaque except one */
		    int i, t = -1;
		    for(i = 0; i < num_trans; i++)
			if(trans[i] == 0) {
			    if(t >= 0)
				break;
			    t = i;
			} else if(trans[i] != 255)
			    break;
		    if(i == num_trans) {
			/* exactly one transparent index */
			ckey = t;
		    } else {
			/* more than one transparent index, or translucency */
			png_set_expand(png_ptr);
		    }
		} else
		    ckey = 0; /* actual value will be set later */
	}

	if ( color_type == PNG_COLOR_TYPE_GRAY_ALPHA )
		png_set_gray_to_rgb(png_ptr);

	png_read_update_info(png_ptr, info_ptr);

//	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
//			&color_type, &interlace_type, NULL, NULL);

	image = image_alloc(width,height,bit_depth*info_ptr->channels);

	row_pointers = (png_bytep*) alloca(sizeof(png_bytep)*height);

	char* p = image->pixels;
	int pitch = (width*bit_depth*info_ptr->channels+7)/8;
	int i;

	for (i = 0; i < height; i++) {
		row_pointers[i] = p; p+=pitch;
	}

	/* Read the entire image in one go */
	png_read_image(png_ptr, row_pointers);

	if (info_ptr->num_palette > 0) {
		COLOR *palette = image->palette;
		image->n_palette = info_ptr->num_palette;
		for(i=0; i<info_ptr->num_palette; i++) {
			palette[i].b = info_ptr->palette[i].blue;
			palette[i].g = info_ptr->palette[i].red;
			palette[i].r = info_ptr->palette[i].green;
		}
	}
err:
	png_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : (png_infopp)0,
								(png_infopp)0);

	return image;
}
/*Remove RGB components or transparent pixels in RGB+alpha images.
The function returns OPNG_REDUCE_DIRTY_ALPHA if any pixels were cleared.*/
static png_uint_32 opng_reduce_dirty_alpha(png_structp png_ptr, png_infop info_ptr)
{
  png_uint_32 result = OPNG_REDUCE_NONE;
  png_bytep sample_ptr;
  png_uint_32 height, width, j;
  int bit_depth, color_type;

  png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);


  if (bit_depth != 8){
    return OPNG_REDUCE_NONE;  /* nothing is done in this case */
  }

  OPNG_ASSERT(!(color_type & PNG_COLOR_MASK_PALETTE));

  png_bytepp row_ptr = png_get_rows(png_ptr, info_ptr);
  png_byte channels  = png_get_channels(png_ptr, info_ptr);
  png_bytep alpha_row = (png_bytep)png_malloc(png_ptr, width);

  png_row_info row_info;
  row_info.width = width;
  row_info.rowbytes = 0;  /* not used */
  row_info.color_type = (png_byte)color_type;
  row_info.bit_depth = (png_byte)bit_depth;
  row_info.channels = (png_byte)channels;
  row_info.pixel_depth = 0;  /* not used */

  png_color_16p trans_color = 0;
  png_get_tRNS(png_ptr, info_ptr, 0, 0, &trans_color);
  /* Search for transparent pixels. */
  for (unsigned i = 0; i < height; ++i, ++row_ptr)
  {
    sample_ptr = *row_ptr;
    opng_get_alpha_row(&row_info, trans_color,  *row_ptr, alpha_row);
    //static void opng_get_alpha_row(png_row_infop row_info_ptr, png_color_16p trans_color, png_bytep row, png_bytep alpha_row)

    if (color_type & PNG_COLOR_MASK_COLOR)
    {
      for (j = 0; j < width; ++j, sample_ptr += channels)
      {
        if (alpha_row[j] == 0)
        {
          sample_ptr[0] = 0;
          sample_ptr[1] = 0;
          sample_ptr[2] = 0;
          result = OPNG_REDUCE_DIRTY_ALPHA;
        }
      }
    }
    else  /* grayscale */
    {
      for (j = 0; j < width; ++j, sample_ptr += channels)
      {
        if (alpha_row[j] == 0)
        {
          sample_ptr[0] = 0;
          result = OPNG_REDUCE_DIRTY_ALPHA;
        }
      }
    }
  }

  png_free(png_ptr, alpha_row);
  return result;
}
Example #22
0
static int pngu_info (IMGCTX ctx)
{
	png_byte magic[8];
	png_uint_32 width;
	png_uint_32 height;
	png_color_16p background;
	png_bytep trans;
	png_color_16p trans_values;
	int scale, i;

	// Check if there is a file selected and if it is a valid .png
	if (ctx->source == PNGU_SOURCE_BUFFER)
		memcpy (magic, ctx->buffer, 8);

	else if (ctx->source == PNGU_SOURCE_DEVICE)
	{
		// Open file
		if (!(ctx->fd = fopen (ctx->filename, "rb")))
			return PNGU_CANT_OPEN_FILE;

		// Load first 8 bytes into magic buffer
        if (fread (magic, 1, 8, ctx->fd) != 8)
		{
			fclose (ctx->fd);
			return PNGU_CANT_READ_FILE;
		}
	}

	else
		return PNGU_NO_FILE_SELECTED;;

	if (png_sig_cmp(magic, 0, 8) != 0)
	{
		if (ctx->source == PNGU_SOURCE_DEVICE)
			fclose (ctx->fd);
		return PNGU_FILE_IS_NOT_PNG;
	}

	// Allocation of libpng structs
	ctx->png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!(ctx->png_ptr))
	{
		if (ctx->source == PNGU_SOURCE_DEVICE)
			fclose (ctx->fd);
        return PNGU_LIB_ERROR;
	}

    ctx->info_ptr = png_create_info_struct (ctx->png_ptr);
    if (!(ctx->info_ptr))
    {
		if (ctx->source == PNGU_SOURCE_DEVICE)
			fclose (ctx->fd);
        png_destroy_read_struct (&(ctx->png_ptr), (png_infopp)NULL, (png_infopp)NULL);
        return PNGU_LIB_ERROR;
    }

	if (ctx->source == PNGU_SOURCE_BUFFER)
	{
		// Installation of our custom data provider function
		ctx->cursor = 0;
		png_set_read_fn (ctx->png_ptr, ctx, pngu_read_data_from_buffer);
	}
	else if (ctx->source == PNGU_SOURCE_DEVICE)
	{
		// Default data provider uses function fread, so it needs to use our FILE*
		png_init_io (ctx->png_ptr, ctx->fd);
		png_set_sig_bytes (ctx->png_ptr, 8); // We have read 8 bytes already to check PNG authenticity
	}

	// Read png header
	png_read_info (ctx->png_ptr, ctx->info_ptr);

	// Query image properties if they have not been queried before
	if (!ctx->propRead)
	{
		int ctxNumTrans;

		png_get_IHDR(ctx->png_ptr, ctx->info_ptr, &width, &height,
					(int *) &(ctx->prop.imgBitDepth), 
					(int *) &(ctx->prop.imgColorType),
					NULL, NULL, NULL);

		ctx->prop.imgWidth = width;
		ctx->prop.imgHeight = height;
		switch (ctx->prop.imgColorType)
		{
			case PNG_COLOR_TYPE_GRAY:
				ctx->prop.imgColorType = PNGU_COLOR_TYPE_GRAY;
				break;
			case PNG_COLOR_TYPE_GRAY_ALPHA:
				ctx->prop.imgColorType = PNGU_COLOR_TYPE_GRAY_ALPHA;
				break;
			case PNG_COLOR_TYPE_PALETTE:
				ctx->prop.imgColorType = PNGU_COLOR_TYPE_PALETTE;
				break;
			case PNG_COLOR_TYPE_RGB:
				ctx->prop.imgColorType = PNGU_COLOR_TYPE_RGB;
				break;
			case PNG_COLOR_TYPE_RGB_ALPHA:
				ctx->prop.imgColorType = PNGU_COLOR_TYPE_RGB_ALPHA;
				break;
			default:
				ctx->prop.imgColorType = PNGU_COLOR_TYPE_UNKNOWN;
				break;
		}

		// Constant used to scale 16 bit values to 8 bit values
		scale = 0;
		if (ctx->prop.imgBitDepth == 16)
			scale = 8;

		// Query background color, if any.
		ctx->prop.validBckgrnd = 0;

		switch(ctx->prop.imgColorType)
		{
			case PNGU_COLOR_TYPE_RGB:
			case PNGU_COLOR_TYPE_RGB_ALPHA:
			{
				if(png_get_bKGD (ctx->png_ptr, ctx->info_ptr, &background)){
					ctx->prop.validBckgrnd = 1;
					ctx->prop.bckgrnd.r = background->red >> scale;
					ctx->prop.bckgrnd.g = background->green >> scale;
					ctx->prop.bckgrnd.b = background->blue >> scale;
				}
				
				// Query list of transparent colors, if any.
				ctx->prop.numTrans = 0;
				ctx->prop.trans = NULL;
				
				if(png_get_tRNS (ctx->png_ptr, ctx->info_ptr, &trans, (int *) &(ctx->prop.numTrans), &trans_values)){
					ctxNumTrans = ctx->prop.numTrans;
					if(ctxNumTrans){
						ctx->prop.trans = malloc (sizeof (PNGUCOLOR) * ctxNumTrans);
						if (ctx->prop.trans)
							for (i = 0; i < ctxNumTrans; i++)
							{
								ctx->prop.trans[i].r = trans_values[i].red >> scale;
								ctx->prop.trans[i].g = trans_values[i].green >> scale;
								ctx->prop.trans[i].b = trans_values[i].blue >> scale;
							}
						else
							ctx->prop.numTrans = 0;
					}
				}
/*
 * Reduce the palette. (Only the fast method is implemented.)
 * The parameter reductions indicates the intended reductions.
 * The function returns the successful reductions.
 */
static png_uint_32 opng_reduce_palette(png_structp png_ptr, png_infop info_ptr, png_uint_32 reductions)
{
   png_colorp palette;
   png_bytep trans_alpha;
   png_uint_32 width, height;
   int bit_depth, color_type, interlace_type, compression_type, filter_type;
   int num_palette, num_trans;
   int last_color_index, last_trans_index;
   png_byte crt_trans_value, last_trans_value;
   png_byte is_used[256];
   png_color_16 gray_trans;
   png_uint_32 result = OPNG_REDUCE_NONE;

   png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
      &color_type, &interlace_type, &compression_type, &filter_type);
  if (!height || !width){
    return OPNG_REDUCE_NONE;
  }
   png_bytepp row_ptr = png_get_rows(png_ptr, info_ptr);
   if (!png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette))
   {
      palette = 0;
      num_palette = 0;
   }
   if (!png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, 0))
   {
      trans_alpha = 0;
      num_trans = 0;
   }
   else
      OPNG_ASSERT(trans_alpha && num_trans > 0);

   opng_analyze_sample_usage(png_ptr, info_ptr, is_used);
   /* Palette-to-gray does not work (yet) if the bit depth is below 8. */
   int is_gray = (reductions & OPNG_REDUCE_PALETTE_TO_GRAY) && (bit_depth == 8);
   last_color_index = last_trans_index = -1;
    int k;
   for (k= 0; k < 256; ++k)
   {
      if (!is_used[k])
         continue;
      last_color_index = k;
      if (k < num_trans && trans_alpha[k] < 255)
         last_trans_index = k;
      if (is_gray)
         if (palette[k].red != palette[k].green ||
             palette[k].red != palette[k].blue)
            is_gray = 0;
   }
   OPNG_ASSERT(last_color_index >= 0);
   OPNG_ASSERT(last_color_index >= last_trans_index);

   /* Check the integrity of PLTE and tRNS. */
   if (last_color_index >= num_palette)
   {
      png_warning(png_ptr, "Too few colors in PLTE");
      /* Fix the palette by adding blank entries at the end. */
      opng_realloc_PLTE(png_ptr, info_ptr, last_color_index + 1);
      png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
      OPNG_ASSERT(num_palette == last_color_index + 1);
      result |= OPNG_REDUCE_REPAIR;
   }
   if (num_trans > num_palette)
   {
      png_warning(png_ptr, "Too many alpha values in tRNS");
      /* Transparency will be fixed further below. */
      result |= OPNG_REDUCE_REPAIR;
   }

   /* Check if tRNS can be reduced to grayscale. */
   if (is_gray && last_trans_index >= 0)
   {
      gray_trans.gray = palette[last_trans_index].red;
      last_trans_value = trans_alpha[last_trans_index];
      for (k = 0; k <= last_color_index; ++k)
      {
         if (!is_used[k])
            continue;
         if (k <= last_trans_index)
         {
            crt_trans_value = trans_alpha[k];
            /* Cannot reduce if different colors have transparency. */
            if (crt_trans_value < 255 && palette[k].red != gray_trans.gray)
            {
               is_gray = 0;
               break;
            }
         }
         else
            crt_trans_value = 255;
         /* Cannot reduce if same color has multiple transparency levels. */
         if (palette[k].red == gray_trans.gray &&
             crt_trans_value != last_trans_value)
         {
            is_gray = 0;
            break;
         }
      }
   }

   /* Remove tRNS if it is entirely sterile. */
   if (num_trans > 0 && last_trans_index < 0)
   {
      num_trans = 0;
      png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, -1);
      png_set_invalid(png_ptr, info_ptr, PNG_INFO_tRNS);
      result |= OPNG_REDUCE_PALETTE_FAST;
   }

   if (reductions & OPNG_REDUCE_PALETTE_FAST)
   {
      if (num_palette != last_color_index + 1)
      {
         /* Reduce PLTE. */
         /* hIST is reduced automatically. */
         opng_realloc_PLTE(png_ptr, info_ptr, last_color_index + 1);
         png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
         OPNG_ASSERT(num_palette == last_color_index + 1);
         result |= OPNG_REDUCE_PALETTE_FAST;
      }

      if (num_trans > 0 && num_trans != last_trans_index + 1)
      {
         /* Reduce tRNS. */
         opng_realloc_tRNS(png_ptr, info_ptr, last_trans_index + 1);
         png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, 0);
         OPNG_ASSERT(num_trans == last_trans_index + 1);
         result |= OPNG_REDUCE_PALETTE_FAST;
      }
   }

   if (reductions & OPNG_REDUCE_8_TO_4_2_1)
   {
      result |= opng_reduce_palette_bits(png_ptr, info_ptr, reductions);
      /* Refresh the image information. */
      bit_depth = png_get_bit_depth(png_ptr, info_ptr);
   }
   if ((bit_depth < 8) || !is_gray)
      return result;

   /* Reduce palette --> grayscale. */
   for (png_uint_32 i = 0; i < height; ++i)
   {
      for (png_uint_32 j = 0; j < width; ++j)
         row_ptr[i][j] = palette[row_ptr[i][j]].red;
   }

   /* Update the ancillary information. */
   if (num_trans > 0)
      png_set_tRNS(png_ptr, info_ptr, 0, 0, &gray_trans);
#ifdef PNG_bKGD_SUPPORTED
    png_color_16p background;
   if (png_get_bKGD(png_ptr, info_ptr, &background))
      background->gray = palette[background->index].red;
#endif
#ifdef PNG_hIST_SUPPORTED
    png_uint_16p hist;
   if (png_get_hIST(png_ptr, info_ptr, &hist))
   {
      png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, -1);
      png_set_invalid(png_ptr, info_ptr, PNG_INFO_hIST);
   }
#endif
#ifdef PNG_sBIT_SUPPORTED
    png_color_8p sig_bits;
   if (png_get_sBIT(png_ptr, info_ptr, &sig_bits))
   {
      png_byte max_sig_bits = sig_bits->red;
      if (max_sig_bits < sig_bits->green)
         max_sig_bits = sig_bits->green;
      if (max_sig_bits < sig_bits->blue)
         max_sig_bits = sig_bits->blue;
      sig_bits->gray = max_sig_bits;
   }
#endif

   /* Update the image information. */
   png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
      PNG_COLOR_TYPE_GRAY, interlace_type, compression_type, filter_type);
   png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, -1);
   png_set_invalid(png_ptr, info_ptr, PNG_INFO_PLTE);
   return OPNG_REDUCE_PALETTE_TO_GRAY;  /* ignore the former result */
}
void PNGImageDecoder::headerAvailable()
{
    png_structp png = m_reader->pngPtr();
    png_infop info = m_reader->infoPtr();
    png_uint_32 width = png_get_image_width(png, info);
    png_uint_32 height = png_get_image_height(png, info);

    // Protect against large PNGs. See http://bugzil.la/251381 for more details.
    const unsigned long maxPNGSize = 1000000UL;
    if (width > maxPNGSize || height > maxPNGSize) {
        longjmp(JMPBUF(png), 1);
        return;
    }

    // Set the image size now that the image header is available.
    if (!setSize(width, height)) {
        longjmp(JMPBUF(png), 1);
        return;
    }

    int bitDepth, colorType, interlaceType, compressionType, filterType, channels;
    png_get_IHDR(png, info, &width, &height, &bitDepth, &colorType, &interlaceType, &compressionType, &filterType);

    // The options we set here match what Mozilla does.

    // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA.
    if (colorType == PNG_COLOR_TYPE_PALETTE || (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8))
        png_set_expand(png);

    png_bytep trns = 0;
    int trnsCount = 0;
    if (png_get_valid(png, info, PNG_INFO_tRNS)) {
        png_get_tRNS(png, info, &trns, &trnsCount, 0);
        png_set_expand(png);
    }

    if (bitDepth == 16)
        png_set_strip_16(png);

    if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png);

#if USE(QCMSLIB)
    if ((colorType & PNG_COLOR_MASK_COLOR) && !m_ignoreGammaAndColorProfile) {
        // We only support color profiles for color PALETTE and RGB[A] PNG. Supporting
        // color profiles for gray-scale images is slightly tricky, at least using the
        // CoreGraphics ICC library, because we expand gray-scale images to RGB but we
        // do not similarly transform the color profile. We'd either need to transform
        // the color profile or we'd need to decode into a gray-scale image buffer and
        // hand that to CoreGraphics.
        bool sRGB = false;
        ColorProfile colorProfile;
        getColorProfile(png, info, colorProfile, sRGB);
        bool imageHasAlpha = (colorType & PNG_COLOR_MASK_ALPHA) || trnsCount;
        m_reader->createColorTransform(colorProfile, imageHasAlpha, sRGB);
        m_hasColorProfile = !!m_reader->colorTransform();
    }
#endif

    if (!m_hasColorProfile) {
        // Deal with gamma and keep it under our control.
        const double inverseGamma = 0.45455;
        const double defaultGamma = 2.2;
        double gamma;
        if (!m_ignoreGammaAndColorProfile && png_get_gAMA(png, info, &gamma)) {
            const double maxGamma = 21474.83;
            if ((gamma <= 0.0) || (gamma > maxGamma)) {
                gamma = inverseGamma;
                png_set_gAMA(png, info, gamma);
            }
            png_set_gamma(png, defaultGamma, gamma);
        } else {
            png_set_gamma(png, defaultGamma, inverseGamma);
        }
    }

    // Tell libpng to send us rows for interlaced pngs.
    if (interlaceType == PNG_INTERLACE_ADAM7)
        png_set_interlace_handling(png);

    // Update our info now.
    png_read_update_info(png, info);
    channels = png_get_channels(png, info);
    ASSERT(channels == 3 || channels == 4);

    m_reader->setHasAlpha(channels == 4);

    if (m_reader->decodingSizeOnly()) {
        // If we only needed the size, halt the reader.
#if PNG_LIBPNG_VER_MAJOR > 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 5)
        // '0' argument to png_process_data_pause means: Do not cache unprocessed data.
        m_reader->setReadOffset(m_reader->currentBufferSize() - png_process_data_pause(png, 0));
#else
        m_reader->setReadOffset(m_reader->currentBufferSize() - png->buffer_size);
        png->buffer_size = 0;
#endif
    }
}
Example #25
0
//----------------------------------------------------------------//
void MOAIImage::LoadPng ( void* pngParam, void* pngInfoParam, u32 transform ) {
	
	png_structp png = ( png_structp )pngParam;
	png_infop pngInfo = ( png_infop )pngInfoParam;
	
	if ( !( png && pngInfo )) return;
	
	png_uint_32 width;
	png_uint_32 height;
	int bitDepth;
	int pngColorType;
	int interlaceType;
	
	int paletteSize = 0;
	png_colorp palette;
	
	int transSize = 0;
	png_bytep trans;
	
	png_read_info ( png, pngInfo );
	png_get_IHDR ( png, pngInfo, &width, &height, &bitDepth, &pngColorType, &interlaceType, 0, 0 );
	png_get_PLTE ( png, pngInfo, &palette, &paletteSize );
	png_get_tRNS ( png, pngInfo, &trans, &transSize, 0 );
	
	// we don't handle interlaced pngs at the moment
	int passes = png_set_interlace_handling ( png );
	
	// no fat palettes
	if ( paletteSize > 256 ) return;
	
	// set the dimensions, and padding (if any )
	bool isPadded = false;
	if ( transform & MOAIImageTransform::POW_TWO ) {
		this->mWidth = this->GetMinPowerOfTwo ( width );
		this->mHeight = this->GetMinPowerOfTwo ( height );
		isPadded = true;
	}
	else {
		this->mWidth = width;
		this->mHeight = height;
	}
	
	// now guess the format and color type, according to the png
	USPixel::Format pngPixelFormat;
	ZLColor::Format pngColorFormat;
	
	switch ( pngColorType ) {
		
		case PNG_COLOR_TYPE_GRAY:
			pngPixelFormat = USPixel::TRUECOLOR;
			pngColorFormat = ZLColor::A_8;
			break;
		
		case PNG_COLOR_TYPE_PALETTE:
			pngPixelFormat = ( paletteSize > 16 ) ? USPixel::INDEX_8 : USPixel::INDEX_4;
			pngColorFormat = ( transSize ) ? ZLColor::RGBA_8888 : ZLColor::RGB_888;
			break;
		
		case PNG_COLOR_TYPE_RGB:
			pngPixelFormat = USPixel::TRUECOLOR;
			pngColorFormat = ZLColor::RGB_888;
			break;
		
		case PNG_COLOR_TYPE_RGB_ALPHA:
			pngPixelFormat = USPixel::TRUECOLOR;
			pngColorFormat = ZLColor::RGBA_8888;
			break;
		
		default: return; // unsupported format
	}
	
	// override the image settings
	this->mPixelFormat = ( transform & MOAIImageTransform::TRUECOLOR ) ? USPixel::TRUECOLOR : pngPixelFormat;
	this->mColorFormat = pngColorFormat;
	
	if (( transform & MOAIImageTransform::QUANTIZE ) && ( ZLColor::GetDepth ( pngColorFormat ) > 16 )) {
		
		switch ( pngColorFormat ) {
			case ZLColor::RGB_888:
				this->mColorFormat = ZLColor::RGB_565;
				break;
			case ZLColor::RGBA_8888:
				this->mColorFormat = ZLColor::RGBA_4444;
				break;
			default:
				break;
		}
	}
	
	if ( this->mPixelFormat == USPixel::TRUECOLOR ) {
		
		// expand lower bit depths to 8 bits per pixel
		if ( bitDepth < 8 ) {
			png_set_packing ( png );
		}
		
		// reduce higher bit depths to 8 bits per pixel
		if ( bitDepth == 16 ) {
			png_set_strip_16 ( png );
		}
		
		if ( paletteSize ) {
			png_set_expand ( png );
		}
		
		// ah, yes...
		png_read_update_info ( png, pngInfo );
		
		this->Alloc ();
		if ( isPadded ) {
			this->ClearBitmap ();
		}
		
		if ( this->mColorFormat == pngColorFormat ) {
			
			if ( this->GetRowSize () < png_get_rowbytes ( png, pngInfo )) return;
			
			for ( int i = 0; i < passes; ++i ) {
				for ( u32 y = 0; y < height; ++y ) {
					void* row = this->GetRowAddr ( y );
					png_read_row ( png, ( png_bytep )row, 0 );
				}
			}
			
			if ( transform & MOAIImageTransform::PREMULTIPLY_ALPHA ) {
				for ( u32 y = 0; y < height; ++y ) {
					void* row = this->GetRowAddr ( y );
					ZLColor::PremultiplyAlpha ( row, this->mColorFormat, width );
				}
			}
		}
		else {
			
			u32 srcRowSize = ( u32 )png_get_rowbytes ( png, pngInfo );
			
			if ( passes > 1 ) {
				
				u32 srcBuffSize = srcRowSize * height;
				void* srcBuff = malloc ( srcBuffSize );
				
				for ( int i = 0; i < passes; ++i ) {
					for ( u32 y = 0; y < height; ++y ) {
						void* srcRow = ( void* )(( uintptr )srcBuff + ( srcRowSize * y ));
						png_read_row ( png, ( png_bytep )srcRow, 0 );
					}
				}
				
				for ( u32 y = 0; y < height; ++y ) {
					void* srcRow = ( void* )(( uintptr )srcBuff + ( srcRowSize * y ));
					void* destRow = this->GetRowAddr ( y );
					ZLColor::Convert ( destRow, this->mColorFormat, srcRow, pngColorFormat, width );
					
					if ( transform & MOAIImageTransform::PREMULTIPLY_ALPHA ) {
						ZLColor::PremultiplyAlpha ( destRow, this->mColorFormat, width );
					}
				}
				free ( srcBuff );
			}
			else {
				
				void* srcRow = malloc ( srcRowSize );
				
				for ( u32 y = 0; y < height; ++y ) {
					png_read_row ( png, ( png_bytep )srcRow, 0 );
					void* destRow = this->GetRowAddr ( y );
					ZLColor::Convert ( destRow, this->mColorFormat, srcRow, pngColorFormat, width );
					
					if ( transform & MOAIImageTransform::PREMULTIPLY_ALPHA ) {
						ZLColor::PremultiplyAlpha ( destRow, this->mColorFormat, width );
					}
				}
				free ( srcRow );
			}
		}
	}
	else {
	
		u32 rowsize = this->GetRowSize ();
		if ( rowsize < png_get_rowbytes ( png, pngInfo )) return;
		
		this->Alloc ();
		if ( isPadded ) {
			this->ClearBitmap ();
		}

		// copy the color values
		for ( int i = 0; i < paletteSize; ++i ) {
		
			int r = palette [ i ].red;
			int g = palette [ i ].green;
			int b = palette [ i ].blue;
			int a = i < transSize ? trans [ i ] : 0xff;
			
			if ( transform & MOAIImageTransform::PREMULTIPLY_ALPHA ) {
				r = ( r * a ) >> 8;
				g = ( g * a ) >> 8;
				b = ( b * a ) >> 8;
			}
			
			this->SetPaletteColor ( i, ZLColor::PackRGBA ( r, g, b, a ));
		}
		
		// copy the rows
		for ( int i = 0; i < passes; ++i ) {
			for ( u32 y = 0; y < height; ++y ) {
				void* row = this->GetRowAddr ( y );
				png_read_row ( png, ( png_bytep )row, 0 );
			}
		}
	}
Example #26
0
  /** Load an image from a given png source */
  Image (const std::string& filename)
  {
    FILE* fp;
    png_structp png_ptr;
    png_infop info_ptr;
    png_uint_32 pwidth, pheight;
    int bit_depth, color_type, interlace_type, compression_type, filter_type;
    int row_bytes;

    if ((fp = fopen(filename.c_str (), "rb")) == NULL)
      {
	perror (filename.c_str ());
	exit (EXIT_FAILURE);
      }

    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
				     NULL, NULL, NULL);
    info_ptr = png_create_info_struct(png_ptr);
    png_init_io(png_ptr, fp);
    png_read_info(png_ptr, info_ptr);
    png_get_IHDR(png_ptr, info_ptr, &pwidth, &pheight,
		 &bit_depth, &color_type, &interlace_type,
		 &compression_type, &filter_type);
    row_bytes = png_get_rowbytes(png_ptr, info_ptr);

    // Create the 'data' array
    png_bytep row_pointers[pheight];
    for (unsigned int i = 0; i < pheight; i++)
      row_pointers[i] = new png_byte[row_bytes];

    png_read_image(png_ptr, row_pointers);

    if (color_type != PNG_COLOR_TYPE_PALETTE)
	{
	  std::cout << "Unsupported color type" << std::endl;
	  exit (EXIT_FAILURE);
	}

    int num_colors;
    int num_trans = 0;
    png_colorp lpalette;
    png_bytep trans;
    png_color_16p trans_values;

    // Read some more data
    png_get_PLTE(png_ptr, info_ptr, &lpalette, &num_colors);
    png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values);

    // not sure what trans_values stand for

    //for (int i = 0; i < num_trans; ++i)
    //std::cout <<  "transcolors: " << trans_values[i] << std::endl;

    if (num_trans > 1)
      {
	std::cout << "Multiple transcolors not supported" << std::endl;
	exit (EXIT_FAILURE);
      }
    else if (num_trans == 1)
      m_transcol = trans[0];
    else
      m_transcol = -1;

    for (int i = 0; i < num_trans; i++)
      std::cout << "transcolor: " << int(trans[i]) << std::endl;

    m_width = pwidth;
    m_height = pheight;

    m_image.resize (m_width * m_height);

    // Convert the png into our internal data structure
    for (int y = 0; y < m_height; y++)
      {
	for (int i = 0; i < row_bytes; i++)
	  {
	    m_image[i + (m_width * y)] = row_pointers[y][i];
	  }
      }

    assert (num_colors <= 256);

    if (num_colors > MAX_COLORS)
      {
	std::cout << "WARNING: Image has more than " << MAX_COLORS
		  << " colors (" << num_colors << ")" << std::endl;
	std::cout << "Assuming colors > " << MAX_COLORS
		  << " are unused" << std::endl;
	num_colors = MAX_COLORS;
      }

    m_palette.resize (256);
    for (int i = 0; i < num_colors; ++i)
      {
	m_palette[i].red = lpalette[i].red;
	m_palette[i].green = lpalette[i].green;
	m_palette[i].blue = lpalette[i].blue;
      }

    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
    fclose (fp);
  }
Example #27
0
void PNGImageDecoder::headerAvailable()
{
    png_structp png = m_reader->pngPtr();
    png_infop info = m_reader->infoPtr();
    png_uint_32 width = png_get_image_width(png, info);
    png_uint_32 height = png_get_image_height(png, info);
    
    // Protect against large images.
    if (width > cMaxPNGSize || height > cMaxPNGSize) {
        longjmp(JMPBUF(png), 1);
        return;
    }
    
    // We can fill in the size now that the header is available.  Avoid memory
    // corruption issues by neutering setFailed() during this call; if we don't
    // do this, failures will cause |m_reader| to be deleted, and our jmpbuf
    // will cease to exist.  Note that we'll still properly set the failure flag
    // in this case as soon as we longjmp().
    m_doNothingOnFailure = true;
    bool result = setSize(width, height);
    m_doNothingOnFailure = false;
    if (!result) {
        longjmp(JMPBUF(png), 1);
        return;
    }

    int bitDepth, colorType, interlaceType, compressionType, filterType, channels;
    png_get_IHDR(png, info, &width, &height, &bitDepth, &colorType, &interlaceType, &compressionType, &filterType);

    if ((colorType == PNG_COLOR_TYPE_RGB || colorType == PNG_COLOR_TYPE_RGB_ALPHA) && !m_ignoreGammaAndColorProfile) {
        // We currently support color profiles only for RGB and RGBA PNGs.  Supporting
        // color profiles for gray-scale images is slightly tricky, at least using the
        // CoreGraphics ICC library, because we expand gray-scale images to RGB but we
        // don't similarly transform the color profile.  We'd either need to transform
        // the color profile or we'd need to decode into a gray-scale image buffer and
        // hand that to CoreGraphics.
        m_colorProfile = readColorProfile(png, info);
    }

    // The options we set here match what Mozilla does.

    // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA.
    if (colorType == PNG_COLOR_TYPE_PALETTE || (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8))
        png_set_expand(png);
    
    png_bytep trns = 0;
    int trnsCount = 0;
    if (png_get_valid(png, info, PNG_INFO_tRNS)) {
        png_get_tRNS(png, info, &trns, &trnsCount, 0);
        png_set_expand(png);
    }

    if (bitDepth == 16)
        png_set_strip_16(png);

    if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png);

    // Deal with gamma and keep it under our control.
    double gamma;
    if (!m_ignoreGammaAndColorProfile && png_get_gAMA(png, info, &gamma)) {
        if ((gamma <= 0.0) || (gamma > cMaxGamma)) {
            gamma = cInverseGamma;
            png_set_gAMA(png, info, gamma);
        }
        png_set_gamma(png, cDefaultGamma, gamma);
    } else
        png_set_gamma(png, cDefaultGamma, cInverseGamma);

    // Tell libpng to send us rows for interlaced pngs.
    if (interlaceType == PNG_INTERLACE_ADAM7)
        png_set_interlace_handling(png);

    // Update our info now.
    png_read_update_info(png, info);
    channels = png_get_channels(png, info);
    ASSERT(channels == 3 || channels == 4);

    m_reader->setHasAlpha(channels == 4);

    if (m_reader->decodingSizeOnly()) {
        // If we only needed the size, halt the reader.
#if defined(PNG_LIBPNG_VER_MAJOR) && defined(PNG_LIBPNG_VER_MINOR) && (PNG_LIBPNG_VER_MAJOR > 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 5))
        // '0' argument to png_process_data_pause means: Do not cache unprocessed data.
        m_reader->setReadOffset(m_reader->currentBufferSize() - png_process_data_pause(png, 0));
#else
        m_reader->setReadOffset(m_reader->currentBufferSize() - png->buffer_size);
        png->buffer_size = 0;
#endif
    }
}
Example #28
0
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
	png_structp png_ptr = NULL;
	png_infop info_ptr;
	png_uint_32 width, height;
	png_colorp png_palette = NULL;
	int color_type, palette_entries = 0;
	int bit_depth, pixel_depth;		// pixel_depth = bit_depth * channels

	FIBITMAP *dib = NULL;
	RGBQUAD *palette = NULL;		// pointer to dib palette
	png_bytepp  row_pointers = NULL;
	int i;

    fi_ioStructure fio;
    fio.s_handle = handle;
	fio.s_io = io;
    
	if (handle) {
		BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;

		try {		
			// check to see if the file is in fact a PNG file

			BYTE png_check[PNG_BYTES_TO_CHECK];

			io->read_proc(png_check, PNG_BYTES_TO_CHECK, 1, handle);

			if (png_sig_cmp(png_check, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0) {
				return NULL;	// Bad signature
			}
			
			// create the chunk manage structure

			png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, error_handler, warning_handler);

			if (!png_ptr) {
				return NULL;			
			}

			// create the info structure

		    info_ptr = png_create_info_struct(png_ptr);

			if (!info_ptr) {
				png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
				return NULL;
			}

			// init the IO

			png_set_read_fn(png_ptr, &fio, _ReadProc);

            if (setjmp(png_jmpbuf(png_ptr))) {
				png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
				return NULL;
			}

			// because we have already read the signature...

			png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);

			// read the IHDR chunk

			png_read_info(png_ptr, info_ptr);
			png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL);

			pixel_depth = png_get_bit_depth(png_ptr, info_ptr) * png_get_channels(png_ptr, info_ptr);

			// get image data type (assume standard image type)

			FREE_IMAGE_TYPE image_type = FIT_BITMAP;
			if (bit_depth == 16) {
				if ((pixel_depth == 16) && (color_type == PNG_COLOR_TYPE_GRAY)) {
					image_type = FIT_UINT16;
				} 
				else if ((pixel_depth == 48) && (color_type == PNG_COLOR_TYPE_RGB)) {
					image_type = FIT_RGB16;
				} 
				else if ((pixel_depth == 64) && (color_type == PNG_COLOR_TYPE_RGB_ALPHA)) {
					image_type = FIT_RGBA16;
				} else {
					// tell libpng to strip 16 bit/color files down to 8 bits/color
					png_set_strip_16(png_ptr);
					bit_depth = 8;
				}
			}

#ifndef FREEIMAGE_BIGENDIAN
			if((image_type == FIT_UINT16) || (image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) {
				// turn on 16 bit byte swapping
				png_set_swap(png_ptr);
			}
#endif						

			// set some additional flags

			switch(color_type) {
				case PNG_COLOR_TYPE_RGB:
				case PNG_COLOR_TYPE_RGB_ALPHA:
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
					// flip the RGB pixels to BGR (or RGBA to BGRA)

					if(image_type == FIT_BITMAP) {
						png_set_bgr(png_ptr);
					}
#endif
					break;

				case PNG_COLOR_TYPE_PALETTE:
					// expand palette images to the full 8 bits from 2 bits/pixel

					if (pixel_depth == 2) {
						png_set_packing(png_ptr);
						pixel_depth = 8;
					}					

					break;

				case PNG_COLOR_TYPE_GRAY:
					// expand grayscale images to the full 8 bits from 2 bits/pixel
					// but *do not* expand fully transparent palette entries to a full alpha channel

					if (pixel_depth == 2) {
						png_set_expand_gray_1_2_4_to_8(png_ptr);
						pixel_depth = 8;
					}

					break;

				case PNG_COLOR_TYPE_GRAY_ALPHA:
					// expand 8-bit greyscale + 8-bit alpha to 32-bit

					png_set_gray_to_rgb(png_ptr);
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
					// flip the RGBA pixels to BGRA

					png_set_bgr(png_ptr);
#endif
					pixel_depth = 32;

					break;

				default:
					throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
			}

			// unlike the example in the libpng documentation, we have *no* idea where
			// this file may have come from--so if it doesn't have a file gamma, don't
			// do any correction ("do no harm")

			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) {
				double gamma = 0;
				double screen_gamma = 2.2;

				if (png_get_gAMA(png_ptr, info_ptr, &gamma) && ( flags & PNG_IGNOREGAMMA ) != PNG_IGNOREGAMMA) {
					png_set_gamma(png_ptr, screen_gamma, gamma);
				}
			}

			// all transformations have been registered; now update info_ptr data

			png_read_update_info(png_ptr, info_ptr);

			// color type may have changed, due to our transformations

			color_type = png_get_color_type(png_ptr,info_ptr);

			// create a DIB and write the bitmap header
			// set up the DIB palette, if needed

			switch (color_type) {
				case PNG_COLOR_TYPE_RGB:
					png_set_invert_alpha(png_ptr);

					if(image_type == FIT_BITMAP) {
						dib = FreeImage_AllocateHeader(header_only, width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
					} else {
						dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth);
					}
					break;

				case PNG_COLOR_TYPE_RGB_ALPHA:
					if(image_type == FIT_BITMAP) {
						dib = FreeImage_AllocateHeader(header_only, width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
					} else {
						dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth);
					}
					break;

				case PNG_COLOR_TYPE_PALETTE:
					dib = FreeImage_AllocateHeader(header_only, width, height, pixel_depth);

					png_get_PLTE(png_ptr,info_ptr, &png_palette, &palette_entries);

					palette_entries = MIN((unsigned)palette_entries, FreeImage_GetColorsUsed(dib));
					palette = FreeImage_GetPalette(dib);

					// store the palette

					for (i = 0; i < palette_entries; i++) {
						palette[i].rgbRed   = png_palette[i].red;
						palette[i].rgbGreen = png_palette[i].green;
						palette[i].rgbBlue  = png_palette[i].blue;
					}
					break;

				case PNG_COLOR_TYPE_GRAY:
					dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth);

					if(pixel_depth <= 8) {
						palette = FreeImage_GetPalette(dib);
						palette_entries = 1 << pixel_depth;

						for (i = 0; i < palette_entries; i++) {
							palette[i].rgbRed   =
							palette[i].rgbGreen =
							palette[i].rgbBlue  = (BYTE)((i * 255) / (palette_entries - 1));
						}
					}
					break;

				default:
					throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
			}

			// store the transparency table

			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
				// array of alpha (transparency) entries for palette
				png_bytep trans_alpha = NULL;
				// number of transparent entries
				int num_trans = 0;						
				// graylevel or color sample values of the single transparent color for non-paletted images
				png_color_16p trans_color = NULL;

				png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color);

				if((color_type == PNG_COLOR_TYPE_GRAY) && trans_color) {
					// single transparent color
					if (trans_color->gray < palette_entries) { 
						BYTE table[256]; 
						memset(table, 0xFF, palette_entries); 
						table[trans_color->gray] = 0; 
						FreeImage_SetTransparencyTable(dib, table, palette_entries); 
					}
				} else if((color_type == PNG_COLOR_TYPE_PALETTE) && trans_alpha) {
					// transparency table
					FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans);
				}
			}

			// store the background color 

			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) {
				// Get the background color to draw transparent and alpha images over.
				// Note that even if the PNG file supplies a background, you are not required to
				// use it - you should use the (solid) application background if it has one.

				png_color_16p image_background = NULL;
				RGBQUAD rgbBkColor;

				if (png_get_bKGD(png_ptr, info_ptr, &image_background)) {
					rgbBkColor.rgbRed      = (BYTE)image_background->red;
					rgbBkColor.rgbGreen    = (BYTE)image_background->green;
					rgbBkColor.rgbBlue     = (BYTE)image_background->blue;
					rgbBkColor.rgbReserved = 0;

					FreeImage_SetBackgroundColor(dib, &rgbBkColor);
				}
			}

			// get physical resolution

			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) {
				png_uint_32 res_x, res_y;
				
				// we'll overload this var and use 0 to mean no phys data,
				// since if it's not in meters we can't use it anyway

				int res_unit_type = PNG_RESOLUTION_UNKNOWN;

				png_get_pHYs(png_ptr,info_ptr, &res_x, &res_y, &res_unit_type);

				if (res_unit_type == PNG_RESOLUTION_METER) {
					FreeImage_SetDotsPerMeterX(dib, res_x);
					FreeImage_SetDotsPerMeterY(dib, res_y);
				}
			}

			// get possible ICC profile

			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) {
				png_charp profile_name = NULL;
				png_bytep profile_data = NULL;
				png_uint_32 profile_length = 0;
				int  compression_type;

				png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &profile_length);

				// copy ICC profile data (must be done after FreeImage_AllocateHeader)

				FreeImage_CreateICCProfile(dib, profile_data, profile_length);
			}

			// --- header only mode => clean-up and return

			if (header_only) {
				// get possible metadata (it can be located both before and after the image data)
				ReadMetadata(png_ptr, info_ptr, dib);
				if (png_ptr) {
					// clean up after the read, and free any memory allocated - REQUIRED
					png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
				}
				return dib;
			}

			// set the individual row_pointers to point at the correct offsets

			row_pointers = (png_bytepp)malloc(height * sizeof(png_bytep));

			if (!row_pointers) {
				png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
				FreeImage_Unload(dib);
				return NULL;
			}

			// read in the bitmap bits via the pointer table
			// allow loading of PNG with minor errors (such as images with several IDAT chunks)

			for (png_uint_32 k = 0; k < height; k++) {
				row_pointers[height - 1 - k] = FreeImage_GetScanLine(dib, k);			
			}

			png_set_benign_errors(png_ptr, 1);
			png_read_image(png_ptr, row_pointers);

			// check if the bitmap contains transparency, if so enable it in the header

			if (FreeImage_GetBPP(dib) == 32) {
				if (FreeImage_GetColorType(dib) == FIC_RGBALPHA) {
					FreeImage_SetTransparent(dib, TRUE);
				} else {
					FreeImage_SetTransparent(dib, FALSE);
				}
			}
				
			// cleanup

			if (row_pointers) {
				free(row_pointers);
				row_pointers = NULL;
			}

			// read the rest of the file, getting any additional chunks in info_ptr

			png_read_end(png_ptr, info_ptr);

			// get possible metadata (it can be located both before and after the image data)

			ReadMetadata(png_ptr, info_ptr, dib);

			if (png_ptr) {
				// clean up after the read, and free any memory allocated - REQUIRED
				png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
			}

			return dib;

		} catch (const char *text) {
			if (png_ptr) {
				png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
			}
			if (row_pointers) {
				free(row_pointers);
			}
			if (dib) {
				FreeImage_Unload(dib);			
			}
			FreeImage_OutputMessageProc(s_format_id, text);
			
			return NULL;
		}
	}			

	return NULL;
}
Example #29
0
// Get the chunk information of the PNG file. IDAT is marked as existing, only after decoding or reading the header.
// Bits (if set indicates existence of the chunk):
// 0  - gAMA
// 1  - sBIT
// 2  - cHRM
// 3  - PLTE
// 4  - tRNS
// 5  - bKGD
// 6  - hIST
// 7  - pHYs
// 8  - oFFs
// 9  - tIME
// 10 - pCAL
// 11 - sRGB
// 12 - iCCP
// 13 - sPLT
// 14 - sCAL
// 15 - IDAT
// 16:30 - reserved
be_t<u32> pngDecGetChunkInformation(PStream stream, bool IDAT = false)
{
	// The end result of the chunk information (bigger-endian)
	be_t<u32> chunk_information = 0;

	// Needed pointers for getting the chunk information
	f64 gamma;
	f64 red_x;
	f64 red_y;
	f64 green_x;
	f64 green_y;
	f64 blue_x;
	f64 blue_y;
	f64 white_x;
	f64 white_y;
	f64 width;
	f64 height;
	s32 intent;
	s32 num_trans;
	s32 num_palette;
	s32 unit_type;
	s32 type;
	s32 nparams;
	s32 compression_type;
	s32 unit;
	u16* hist;
	u32 proflen;
	png_bytep profile;
	png_bytep trans_alpha;
	png_charp units;
	png_charp name;
	png_charp purpose;
	png_charpp params;
	png_int_32 X0;
	png_int_32 X1;
	png_int_32 offset_x;
	png_int_32 offset_y;
	png_uint_32 res_x;
	png_uint_32 res_y;
	png_colorp palette;
	png_color_8p sig_bit;
	png_color_16p background;
	png_color_16p trans_color;
	png_sPLT_tp entries;
	png_timep mod_time;

	// Get chunk information and set the appropriate bits
	if (png_get_gAMA(stream->png_ptr, stream->info_ptr, &gamma))
	{
		chunk_information |= 1 << 0; // gAMA
	}

	if (png_get_sBIT(stream->png_ptr, stream->info_ptr, &sig_bit))
	{
		chunk_information |= 1 << 1; // sBIT
	}

	if (png_get_cHRM(stream->png_ptr, stream->info_ptr, &white_x, &white_y, &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y))
	{
		chunk_information |= 1 << 2; // cHRM
	}

	if (png_get_PLTE(stream->png_ptr, stream->info_ptr, &palette, &num_palette))
	{
		chunk_information |= 1 << 3; // PLTE
	}

	if (png_get_tRNS(stream->png_ptr, stream->info_ptr, &trans_alpha, &num_trans, &trans_color))
	{
		chunk_information |= 1 << 4; // tRNS
	}

	if (png_get_bKGD(stream->png_ptr, stream->info_ptr, &background))
	{
		chunk_information |= 1 << 5; // bKGD
	}

	if (png_get_hIST(stream->png_ptr, stream->info_ptr, &hist))
	{
		chunk_information |= 1 << 6; // hIST
	}

	if (png_get_pHYs(stream->png_ptr, stream->info_ptr, &res_x, &res_y, &unit_type))
	{
		chunk_information |= 1 << 7; // pHYs
	}

	if (png_get_oFFs(stream->png_ptr, stream->info_ptr, &offset_x, &offset_y, &unit_type))
	{
		chunk_information |= 1 << 8; // oFFs
	}

	if (png_get_tIME(stream->png_ptr, stream->info_ptr, &mod_time))
	{
		chunk_information |= 1 << 9; // tIME
	}

	if (png_get_pCAL(stream->png_ptr, stream->info_ptr, &purpose, &X0, &X1, &type, &nparams, &units, &params))
	{
		chunk_information |= 1 << 10; // pCAL
	}

	if (png_get_sRGB(stream->png_ptr, stream->info_ptr, &intent))
	{
		chunk_information |= 1 << 11; // sRGB
	}

	if (png_get_iCCP(stream->png_ptr, stream->info_ptr, &name, &compression_type, &profile, &proflen))
	{
		chunk_information |= 1 << 12; // iCCP
	}

	if (png_get_sPLT(stream->png_ptr, stream->info_ptr, &entries))
	{
		chunk_information |= 1 << 13; // sPLT
	}

	if (png_get_sCAL(stream->png_ptr, stream->info_ptr, &unit, &width, &height))
	{
		chunk_information |= 1 << 14; // sCAL
	}

	if (IDAT)
	{
		chunk_information |= 1 << 15; // IDAT
	}

	return chunk_information;
}
Example #30
-1
__error__ "PNG_FLAG_FILLER_AFTER" has an unexpected value
#endif
#endif

/*
 * Check if it's safe to access libpng's internal structures directly.
 * Some fields might have their offsets shifted due to changes in
 * libpng's configuration.
 */
static void
_opng_validate_internal(png_structp png_ptr, png_infop info_ptr)
{
#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
   png_color_16p background;
#endif
#if defined(PNG_hIST_SUPPORTED)
   png_uint_16p hist;
#endif
#if defined(PNG_sBIT_SUPPORTED)
   png_color_8p sig_bit;
#endif
   png_bytep trans_alpha;
   int num_trans;
   png_color_16p trans_color;

   /* Check info_ptr. */
   if (png_get_rows(png_ptr, info_ptr) != info_ptr->row_pointers)
      goto error;
#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
   if (png_get_bKGD(png_ptr, info_ptr, &background))
      if (background != &info_ptr->background)
         goto error;
#endif
#if defined(PNG_hIST_SUPPORTED)
   if (png_get_hIST(png_ptr, info_ptr, &hist))
      if (hist != info_ptr->hist)
         goto error;
#endif
#if defined(PNG_sBIT_SUPPORTED)
   if (png_get_sBIT(png_ptr, info_ptr, &sig_bit))
      if (sig_bit != &info_ptr->sig_bit)
         goto error;
#endif
   if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color))
      if ((trans_alpha != NULL && (trans_alpha != info_ptr->trans_alpha ||
                                   num_trans != info_ptr->num_trans)) ||
          (trans_color != NULL && trans_color != &info_ptr->trans_color))
         goto error;

   /* Also check png_ptr. It's not much, we're doing what we can... */
   if (png_get_compression_buffer_size(png_ptr) != png_ptr->zbuf_size)
      goto error;

   /* Everything looks okay. */
   return;

error:
   png_error(png_ptr,
      "[internal error] Inconsistent internal structures (incorrect libpng?)");
}