Exemplo n.º 1
0
    void set_rgb_to_gray(rgb_to_gray_error_action error_action
                         = rgb_to_gray_silent,
                         double red_weight   = -1.0,
                         double green_weight = -1.0) const
    {
        TRACE_IO_TRANSFORM("png_set_rgb_to_gray: error_action=%d,"
                           " red_weight=%lf, green_weight=%lf\n",
                           error_action, red_weight, green_weight);

        png_set_rgb_to_gray(m_png, error_action, red_weight, green_weight);
    }
Exemplo n.º 2
0
bool  PngDecoder::readData( Mat& img )
{
    bool result = false;
    AutoBuffer<uchar*> _buffer(m_height);
    uchar** buffer = _buffer;
    int color = img.channels() > 1;
    uchar* data = img.data;
    int step = (int)img.step;

    if( m_png_ptr && m_info_ptr && m_end_info && m_width && m_height )
    {
        png_structp png_ptr = (png_structp)m_png_ptr;
        png_infop info_ptr = (png_infop)m_info_ptr;
        png_infop end_info = (png_infop)m_end_info;

        if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 )
        {
            int y;

            if( img.depth() == CV_8U && m_bit_depth == 16 )
                png_set_strip_16( png_ptr );
            else if( !isBigEndian() )
                png_set_swap( png_ptr );

            if(img.channels() < 4)
            {
                /* observation: png_read_image() writes 400 bytes beyond
                 * end of data when reading a 400x118 color png
                 * "mpplus_sand.png".  OpenCV crashes even with demo
                 * programs.  Looking at the loaded image I'd say we get 4
                 * bytes per pixel instead of 3 bytes per pixel.  Test
                 * indicate that it is a good idea to always ask for
                 * stripping alpha..  18.11.2004 Axel Walthelm
                 */
                 png_set_strip_alpha( png_ptr );
            }

            if( m_color_type == PNG_COLOR_TYPE_PALETTE )
                png_set_palette_to_rgb( png_ptr );

            if( m_color_type == PNG_COLOR_TYPE_GRAY && m_bit_depth < 8 )
#if (PNG_LIBPNG_VER_MAJOR*10000 + PNG_LIBPNG_VER_MINOR*100 + PNG_LIBPNG_VER_RELEASE >= 10209) || \
    (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR == 0 && PNG_LIBPNG_VER_RELEASE >= 18)
                png_set_expand_gray_1_2_4_to_8( png_ptr );
#else
                png_set_gray_1_2_4_to_8( png_ptr );
#endif

            if( CV_MAT_CN(m_type) > 1 && color )
                png_set_bgr( png_ptr ); // convert RGB to BGR
            else if( color )
                png_set_gray_to_rgb( png_ptr ); // Gray->RGB
            else
                png_set_rgb_to_gray( png_ptr, 1, 0.299, 0.587 ); // RGB->Gray

            png_read_update_info( png_ptr, info_ptr );

            for( y = 0; y < m_height; y++ )
                buffer[y] = data + y*step;

            png_read_image( png_ptr, buffer );
            png_read_end( png_ptr, end_info );

            result = true;
        }
    }

    close();
    return result;
}
Exemplo n.º 3
0
s32 pngDecodeData(PPUThread& ppu, PHandle handle, PStream stream, vm::ptr<u8> data, PDataControlParam data_control_param, PDataOutInfo data_out_info, PCbControlDisp cb_control_disp = vm::null, PDispParam disp_param = vm::null)
{
	if (cb_control_disp || disp_param)
	{
		throw EXCEPTION("Partial image decoding is not supported");
	}

	// Indicate, that the PNG decoding is stopped/failed. This is incase, we return an error code in the middle of decoding
	data_out_info->status = CELL_PNGDEC_DEC_STATUS_STOP;

	// Possibilities for decoding in different sizes aren't tested, so if anyone finds any of these cases, we'll know about it.
	if (stream->info.imageWidth != stream->out_param.outputWidth)
	{
		throw EXCEPTION("Image width doesn't match output width! (%d/%d)", stream->out_param.outputWidth, stream->info.imageWidth);
	}

	if (stream->info.imageHeight != stream->out_param.outputHeight)
	{
		throw EXCEPTION("Image width doesn't match output height! (%d/%d)", stream->out_param.outputHeight, stream->info.imageHeight);
	}

	// Get the amount of output bytes per line
	const u32 bytes_per_line = data_control_param->outputBytesPerLine;

	// Whether to recaculate bytes per row
	bool recalculate_bytes_per_row = false;

	// Check if the game is expecting the number of bytes per line to be lower, than the actual bytes per line on the image. (Arkedo Pixel for example)
	// In such case we strip the bit depth to be lower.
	if ((bytes_per_line < stream->out_param.outputWidthByte) && stream->out_param.outputBitDepth != 8)
	{
		// Check if the packing is really 1 byte per 1 pixel
		if (stream->packing != CELL_PNGDEC_1BYTE_PER_1PIXEL)
		{
			throw EXCEPTION("Unexpected packing value! (%d)", stream->packing);
		}

		// Scale 16 bit depth down to 8 bit depth. PS3 uses png_set_strip_16, since png_set_scale_16 wasn't available back then.
		png_set_strip_16(stream->png_ptr);
		recalculate_bytes_per_row = true;
	}
	// Check if the outputWidthByte is smaller than the intended output length of a line. For example an image might be in RGB, but we need to output 4 components, so we need to perform alpha padding.
	else if (stream->out_param.outputWidthByte < (stream->out_param.outputWidth * stream->out_param.outputComponents))
	{
		// If fixed alpha is not specified in such a case, the default value for the alpha is 0xFF (255)
		if (!stream->fixed_alpha)
		{
			stream->fixed_alpha_colour = 0xFF;
		}

		// We need to fill alpha (before or after, depending on the output colour format) using the fixed alpha value passed by the game.
		png_set_add_alpha(stream->png_ptr, stream->fixed_alpha_colour, stream->out_param.outputColorSpace == CELL_PNGDEC_RGBA ? PNG_FILLER_AFTER : PNG_FILLER_BEFORE);
		recalculate_bytes_per_row = true;
	}
	// We decode as RGBA, so we need to swap the alpha
	else if (stream->out_param.outputColorSpace == CELL_PNGDEC_ARGB)
	{
		// Swap the alpha channel for the ARGB output format, if the padding isn't needed
		png_set_swap_alpha(stream->png_ptr);
	}
	// Sometimes games pass in a RBG/RGBA image and want it as grayscale
	else if ((stream->out_param.outputColorSpace == CELL_PNGDEC_GRAYSCALE_ALPHA || stream->out_param.outputColorSpace == CELL_PNGDEC_GRAYSCALE)
		  && (stream->info.colorSpace == CELL_PNGDEC_RGB || stream->info.colorSpace == CELL_PNGDEC_RGBA))
	{
		// Tell libpng to convert it to grayscale
		png_set_rgb_to_gray(stream->png_ptr, PNG_ERROR_ACTION_NONE, PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT);
		recalculate_bytes_per_row = true;
	}

	if (recalculate_bytes_per_row)
	{
		// Update the info structure
		png_read_update_info(stream->png_ptr, stream->info_ptr);

		// Recalculate the bytes per row
		stream->out_param.outputWidthByte = png_get_rowbytes(stream->png_ptr, stream->info_ptr);
	}

	// Calculate the image size
	u32 image_size = stream->out_param.outputWidthByte * stream->out_param.outputHeight;

	// Buffer for storing the image
	std::vector<u8> png(image_size);
	
	// Make an unique pointer for the row pointers
	std::vector<u8*> row_pointers(stream->out_param.outputHeight);

	// Allocate memory for rows
	for (u32 y = 0; y < stream->out_param.outputHeight; y++)
	{
		row_pointers[y] = &png[y * stream->out_param.outputWidthByte];
	}

	// Decode the image
	png_read_image(stream->png_ptr, row_pointers.data());

	// Check if the image needs to be flipped
	const bool flip = stream->out_param.outputMode == CELL_PNGDEC_BOTTOM_TO_TOP;

	// Copy the result to the output buffer
	switch (stream->out_param.outputColorSpace)
	{
	case CELL_PNGDEC_RGB:
	case CELL_PNGDEC_RGBA:
	case CELL_PNGDEC_ARGB:
	case CELL_PNGDEC_GRAYSCALE_ALPHA:
	{
		// Check if we need to flip the image or need to leave empty bytes at the end of a line
		if ((bytes_per_line > stream->out_param.outputWidthByte) || flip)
		{
			// Get how many bytes per line we need to output - bytesPerLine is total amount of bytes per line, rest is unused and the game can do as it pleases.
			const u32 line_size = std::min(bytes_per_line, stream->out_param.outputWidth * 4);

			// If the game wants more bytes per line to be output, than the image has, then we simply copy what we have for each line,
			// and continue on the next line, thus leaving empty bytes at the end of the line.
			for (u32 i = 0; i < stream->out_param.outputHeight; i++)
			{
				const u32 dst = i * bytes_per_line;
				const u32 src = stream->out_param.outputWidth * 4 * (flip ? stream->out_param.outputHeight - i - 1 : i);
				memcpy(&data[dst], &png[src], line_size);
			}
		}
		else
		{
			// We can simply copy the output to the data pointer specified by the game, since we already do alpha channel transformations in libpng, if needed
			memcpy(data.get_ptr(), png.data(), image_size);
		}
		break;
	}

	default: throw EXCEPTION("Unsupported color space (%d)", stream->out_param.outputColorSpace);
	}

	// Get the number of iTXt, tEXt and zTXt chunks
	s32 text_chunks = 0;
	png_get_text(stream->png_ptr, stream->info_ptr, nullptr, &text_chunks);

	// Set the chunk information and the previously obtained number of text chunks
	data_out_info->numText = (u32)text_chunks;
	data_out_info->chunkInformation = pngDecGetChunkInformation(stream, true);
	data_out_info->numUnknownChunk = 0; // TODO: Get this somehow. Does anything even use or need this?

	// Indicate that the decoding succeeded
	data_out_info->status = CELL_PNGDEC_DEC_STATUS_FINISH;

	return CELL_OK;
}
Exemplo n.º 4
0
GrayMap *ReadGrayMapFile(FILE *file, const char *name)
{
	GrayMap						*result = NULL;
	struct png_struct_def		*png = NULL;
	struct png_info_struct		*pngInfo = NULL;
	struct png_info_struct		*pngEndInfo = NULL;
	png_bytepp					rows = NULL;
	png_uint_32					pngWidth,
	pngHeight;
	int							depth,
	colorType;
	
	if (file == NULL)  return NULL;
	
	// Set up PNG decoding.
	png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (png == NULL)
	{
		fprintf(stderr, "Error preparing to read %s.\n", name);
		return NULL;
	}
	
	pngInfo = png_create_info_struct(png);
	if (pngInfo == NULL)
	{
		fprintf(stderr, "Error preparing to read %s.\n", name);
		return NULL;
	}
	
	pngEndInfo = png_create_info_struct(png);
	if (pngInfo == NULL)
	{
		fprintf(stderr, "Error preparing to read %s.\n", name);
		return NULL;
	}
	
	if (setjmp(png_jmpbuf(png)))
	{
		// libpng will jump here on error.
		free(rows);
		return NULL;
	}
	
	png_init_io(png, file);
	png_read_info(png, pngInfo);
	
	if (!png_get_IHDR(png, pngInfo, &pngWidth, &pngHeight, &depth, &colorType, NULL, NULL, NULL))
	{
		fprintf(stderr, "Failed to get metadata from PNG %s", name);
		return NULL;
	}
	
	// Set to transform to 8-bit greyscale without alpha.
	if (colorType & PNG_COLOR_MASK_ALPHA)
	{
		png_set_strip_alpha(png);
	}
	
	if (colorType == PNG_COLOR_TYPE_GRAY ||
		colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
	{
		png_set_strip_16(png);
		png_set_expand(png);
	}
	else if (colorType == PNG_COLOR_TYPE_PALETTE ||
			 colorType == PNG_COLOR_TYPE_RGB ||
			 colorType == PNG_COLOR_TYPE_RGB_ALPHA)
	{
		png_set_rgb_to_gray(png, 3, -1, -1);
	}
	else
	{
		fprintf(stderr, "Unknown colour type (0x%.X) in %s.\n", colorType, name);
		return NULL;
	}
	
	png_read_update_info(png, pngInfo);
	
	result = NewGrayMap(pngWidth, pngHeight, png_get_rowbytes(png, pngInfo));
	if (result == NULL)
	{
		fprintf(stderr, "Could not allocate memory for source image.\n");
		return NULL;
	}
	
	// Create array of row pointers.
	rows = MakeGrayMapRowPointers(result);
	if (rows == NULL)
	{
		fprintf(stderr, "Could not allocate memory for source image.\n");
		DisposeGrayMap(result);
		return NULL;
	}
	
	// Read.
	png_read_image(png, rows);
	png_read_end(png, pngEndInfo);
	
	free(rows);
	png_destroy_read_struct(&png, &pngInfo, &pngEndInfo);
	
	return result;
}
Exemplo n.º 5
0
static void _png_get_header_func(png_structp png_ptr, png_infop info_ptr) {
  FXPNG_Context* p = (FXPNG_Context*)png_get_progressive_ptr(png_ptr);
  if (!p)
    return;

  CCodec_PngModule* pModule = (CCodec_PngModule*)p->parent_ptr;
  if (!pModule)
    return;

  png_uint_32 width = 0, height = 0;
  int bpc = 0, color_type = 0, color_type1 = 0, pass = 0;
  double gamma = 1.0;
  png_get_IHDR(png_ptr, info_ptr, &width, &height, &bpc, &color_type, nullptr,
               nullptr, nullptr);
  color_type1 = color_type;
  if (bpc > 8) {
    png_set_strip_16(png_ptr);
  } else if (bpc < 8) {
    png_set_expand_gray_1_2_4_to_8(png_ptr);
  }
  bpc = 8;
  if (color_type == PNG_COLOR_TYPE_PALETTE) {
    png_set_palette_to_rgb(png_ptr);
  }
  pass = png_set_interlace_handling(png_ptr);
  if (!pModule->ReadHeaderCallback(p->child_ptr, width, height, bpc, pass,
                                   &color_type, &gamma)) {
    png_error(p->png_ptr, "Read Header Callback Error");
  }
  int intent;
  if (png_get_sRGB(png_ptr, info_ptr, &intent)) {
    png_set_gamma(png_ptr, gamma, 0.45455);
  } else {
    double image_gamma;
    if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) {
      png_set_gamma(png_ptr, gamma, image_gamma);
    } else {
      png_set_gamma(png_ptr, gamma, 0.45455);
    }
  }
  switch (color_type) {
    case PNG_COLOR_TYPE_GRAY:
    case PNG_COLOR_TYPE_GRAY_ALPHA: {
      if (color_type1 & PNG_COLOR_MASK_COLOR) {
        png_set_rgb_to_gray(png_ptr, 1, 0.299, 0.587);
      }
    } break;
    case PNG_COLOR_TYPE_PALETTE:
      if (color_type1 != PNG_COLOR_TYPE_PALETTE) {
        png_error(p->png_ptr, "Not Support Output Palette Now");
      }
    case PNG_COLOR_TYPE_RGB:
    case PNG_COLOR_TYPE_RGB_ALPHA:
      if (!(color_type1 & PNG_COLOR_MASK_COLOR)) {
        png_set_gray_to_rgb(png_ptr);
      }
      png_set_bgr(png_ptr);
      break;
  }
  if (!(color_type & PNG_COLOR_MASK_ALPHA)) {
    png_set_strip_alpha(png_ptr);
  }
  if (color_type & PNG_COLOR_MASK_ALPHA &&
      !(color_type1 & PNG_COLOR_MASK_ALPHA)) {
    png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
  }
  png_read_update_info(png_ptr, info_ptr);
}
Exemplo n.º 6
0
bool  GrFmtPngReader::ReadData( uchar* data, int step, int color )
{
    bool result = false;
    uchar** buffer = 0;

    color = color > 0 || ( m_iscolor && color < 0 );
    
    if( m_png_ptr && m_info_ptr && m_end_info && m_width && m_height )
    {
        png_structp png_ptr = (png_structp)m_png_ptr;
        png_infop info_ptr = (png_infop)m_info_ptr;
        png_infop end_info = (png_infop)m_end_info;
        
        if( setjmp(png_ptr->jmpbuf) == 0 )
        {
            int y;

            if( m_bit_depth > 8 && !m_native_depth )
                png_set_strip_16( png_ptr );
            else if( !isBigEndian() )
                png_set_swap( png_ptr );

            /* observation: png_read_image() writes 400 bytes beyond
             * end of data when reading a 400x118 color png
             * "mpplus_sand.png".  OpenCV crashes even with demo
             * programs.  Looking at the loaded image I'd say we get 4
             * bytes per pixel instead of 3 bytes per pixel.  Test
             * indicate that it is a good idea to always ask for
             * stripping alpha..  18.11.2004 Axel Walthelm
             */
            png_set_strip_alpha( png_ptr );

            if( m_color_type == PNG_COLOR_TYPE_PALETTE )
                png_set_palette_to_rgb( png_ptr );

            if( m_color_type == PNG_COLOR_TYPE_GRAY && m_bit_depth < 8 )
                png_set_gray_1_2_4_to_8( png_ptr );

            if( m_iscolor && color )
                png_set_bgr( png_ptr ); // convert RGB to BGR
            else if( color )
                png_set_gray_to_rgb( png_ptr ); // Gray->RGB
            else
                png_set_rgb_to_gray( png_ptr, 1, -1, -1 ); // RGB->Gray

            png_read_update_info( png_ptr, info_ptr );

            buffer = new uchar*[m_height];

            for( y = 0; y < m_height; y++ )
                buffer[y] = data + y*step;

            png_read_image( png_ptr, buffer );
            png_read_end( png_ptr, end_info );

            result = true;
        }
    }

    Close();
    delete[] buffer;

    return result;
}
Exemplo n.º 7
0
struct IplImage *ipl_readimg(char *path, int mode)
{
	FILE *f;
	unsigned char head[8];
	int numb = 8, w, h, nchans = 3, y; 
	size_t sznumb;
	struct IplImage *res;
	png_bytep* rows;
	png_structp pngp;
	png_infop infop;
	
	if (!(f = fopen(path, "rb"))) { 
		perror("error opening file\n");
		return NULL;
	}

	sznumb = fread(head, sizeof(char), numb, f);
	
	if (png_sig_cmp(head, 0, 8)) {
		perror("is not png");
		fclose(f);
		return NULL;
	}
	
	if (!(pngp = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) {
		perror("can't create read struct");
		fclose(f);
		return NULL;
	}
	
	if (!(infop = png_create_info_struct(pngp))) {
		perror("can't create info");
		png_destroy_read_struct(&pngp, NULL, NULL);
		fclose(f);
		return NULL;
	}

	if (setjmp(png_jmpbuf(pngp))) {
		perror("error in jumpbuf");
		png_destroy_read_struct(&pngp, &infop, NULL);
		fclose(f);
		return NULL;
	}

	png_init_io(pngp, f);
	png_set_sig_bytes(pngp, sznumb);

	png_read_info(pngp, infop);
	
	png_set_strip_alpha(pngp);	
	png_set_strip_16(pngp);
	if (mode) {
		nchans = 3;
		png_set_palette_to_rgb(pngp);
	} else {	
		nchans = 1;
		png_set_rgb_to_gray(pngp, 1, 0.0f, 0.0f);
		png_set_expand_gray_1_2_4_to_8(pngp);
	}
	
	png_set_interlace_handling(pngp);
	png_read_update_info(pngp, infop);

	w = png_get_image_width(pngp, infop);
	h = png_get_image_height(pngp, infop);

	rows = (png_bytep *)malloc(sizeof(png_bytep) * h);
	for (y = 0; y < h; y++) {
		rows[y] = (png_byte *)malloc(png_get_rowbytes(pngp, infop));
	}

	png_read_image(pngp, rows);

	
	
	res = (struct IplImage *)malloc(sizeof(struct IplImage));
	res->width = w;
	res->height = h;
	res->nchans = nchans;
	res->data = (unsigned char *)malloc(sizeof(unsigned char) * w * h * 3);

	for (y = 0; y < h; y++) 
		memcpy(&(res->data[nchans * y * w]), rows[y], sizeof(png_byte) * png_get_rowbytes(pngp, infop));
 
	for (y = 0; y < h; y++)
		free(rows[y]); 
	
	free(rows);

	fclose(f);
	return res;
}
Exemplo n.º 8
0
s32 pngDecSetParameter(PStream stream, PInParam in_param, POutParam out_param, PExtInParam extra_in_param = vm::null, PExtOutParam extra_out_param = vm::null)
{
	if (in_param->outputPackFlag == CELL_PNGDEC_1BYTE_PER_NPIXEL)
	{
		fmt::throw_exception("Packing not supported! (%d)" HERE, in_param->outputPackFlag);
	}

	// flag to keep unknown chunks
	png_set_keep_unknown_chunks(stream->png_ptr, PNG_HANDLE_CHUNK_IF_SAFE, 0, 0);

	// Scale 16 bit depth down to 8 bit depth.
	if (stream->info.bitDepth == 16 && in_param->outputBitDepth == 8)
	{
		// PS3 uses png_set_strip_16, since png_set_scale_16 wasn't available back then.
		png_set_strip_16(stream->png_ptr);
	}

	// This shouldnt ever happen, but not sure what to do if it does, just want it logged for now
	if (stream->info.bitDepth != 16 && in_param->outputBitDepth == 16)
		cellPngDec.error("Output depth of 16 with non input depth of 16 specified!");
	if (in_param->commandPtr != vm::null)
		cellPngDec.warning("Ignoring CommandPtr.");

	if (stream->info.colorSpace != in_param->outputColorSpace)
	{
		// check if we need to set alpha
		const bool inputHasAlpha = cellPngColorSpaceHasAlpha(stream->info.colorSpace);
		const bool outputWantsAlpha = cellPngColorSpaceHasAlpha(in_param->outputColorSpace);

		if (outputWantsAlpha && !inputHasAlpha)
		{
			if (in_param->outputAlphaSelect == CELL_PNGDEC_FIX_ALPHA)
				png_set_add_alpha(stream->png_ptr, in_param->outputColorAlpha, in_param->outputColorSpace == CELL_PNGDEC_ARGB ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER);
			else
			{
				// Check if we can steal the alpha from a trns block
				if (png_get_valid(stream->png_ptr, stream->info_ptr, PNG_INFO_tRNS))
					png_set_tRNS_to_alpha(stream->png_ptr);
				// if not, just set default of 0xff
				else
					png_set_add_alpha(stream->png_ptr, 0xff, in_param->outputColorSpace == CELL_PNGDEC_ARGB ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER);
			}
		}
		else if (inputHasAlpha && !outputWantsAlpha)
			png_set_strip_alpha(stream->png_ptr);
		else if (in_param->outputColorSpace == CELL_PNGDEC_ARGB && stream->info.colorSpace == CELL_PNGDEC_RGBA)
			png_set_swap_alpha(stream->png_ptr);

		// Handle gray<->rgb colorspace conversions
		// rgb output
		if (in_param->outputColorSpace == CELL_PNGDEC_ARGB
			|| in_param->outputColorSpace == CELL_PNGDEC_RGBA
			|| in_param->outputColorSpace == CELL_PNGDEC_RGB)
		{

			if (stream->info.colorSpace == CELL_PNGDEC_PALETTE)
				png_set_palette_to_rgb(stream->png_ptr);
			if ((stream->info.colorSpace == CELL_PNGDEC_GRAYSCALE || stream->info.colorSpace == CELL_PNGDEC_GRAYSCALE_ALPHA)
				&& stream->info.bitDepth < 8)
				png_set_expand_gray_1_2_4_to_8(stream->png_ptr);
		}
		// grayscale output
		else
		{
			if (stream->info.colorSpace == CELL_PNGDEC_ARGB
				|| stream->info.colorSpace == CELL_PNGDEC_RGBA
				|| stream->info.colorSpace == CELL_PNGDEC_RGB)
			{

				png_set_rgb_to_gray(stream->png_ptr, PNG_ERROR_ACTION_NONE, PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT);
			}
			else {
				// not sure what to do here
				cellPngDec.error("Grayscale / Palette to Grayscale / Palette conversion currently unsupported.");
			}
		}
	}

	stream->passes = png_set_interlace_handling(stream->png_ptr);

	// Update the info structure
	png_read_update_info(stream->png_ptr, stream->info_ptr);

	stream->out_param.outputWidth = stream->info.imageWidth;
	stream->out_param.outputHeight = stream->info.imageHeight;
	stream->out_param.outputBitDepth = in_param->outputBitDepth;
	stream->out_param.outputColorSpace = in_param->outputColorSpace;
	stream->out_param.outputMode = in_param->outputMode;

	stream->out_param.outputWidthByte = png_get_rowbytes(stream->png_ptr, stream->info_ptr);
	stream->out_param.outputComponents = png_get_channels(stream->png_ptr, stream->info_ptr);

	stream->packing = in_param->outputPackFlag;

	// Set the memory usage. We currently don't actually allocate memory for libpng through the callbacks, due to libpng needing a lot more memory compared to PS3 variant.
	stream->out_param.useMemorySpace = 0;

	if (extra_in_param)
	{
		if (extra_in_param->bufferMode != CELL_PNGDEC_LINE_MODE)
		{
			cellPngDec.error("Invalid Buffermode specified.");
			return CELL_PNGDEC_ERROR_ARG;
		}

		if (stream->passes > 1)
		{
			stream->outputCounts = 1;
		}
		else
			stream->outputCounts = extra_in_param->outputCounts;

		if (extra_out_param)
		{
			if (stream->outputCounts == 0)
				extra_out_param->outputHeight = stream->out_param.outputHeight;
			else
				extra_out_param->outputHeight = std::min(stream->outputCounts, stream->out_param.outputHeight.value());
			extra_out_param->outputWidthByte = stream->out_param.outputWidthByte;
		}
	}

	*out_param = stream->out_param;

	return CELL_OK;
}
Exemplo n.º 9
0
BitmapImage * PNGImageIO_loadPNGData(const void * data, size_t length, int pixelFormat, bool flipVertical) {
	png_byte headerBytes[PNG_HEADER_SIZE];
	png_structp pngReadStruct;
	png_infop pngInfoStruct;
	struct memreadContext readContext;
	unsigned int width, height;
	png_int_32 bitDepth, colorType;
	png_bytep * rows = NULL;
	unsigned char * pixels = NULL;
	unsigned int rowIndex;
	enum BitmapPixelFormat chosenPixelFormat = BITMAP_PIXEL_FORMAT_RGBA_8888;
	BitmapImage * image;
	
	readContext = memreadContextInit(data, length);
	if (!memread(&readContext, PNG_HEADER_SIZE, headerBytes) || png_sig_cmp(headerBytes, 0, PNG_HEADER_SIZE)) {
		return NULL;
	}
	
	pngReadStruct = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	pngInfoStruct = png_create_info_struct(pngReadStruct);
	
	if (setjmp(png_jmpbuf(pngReadStruct))) {
		png_destroy_read_struct(&pngReadStruct, &pngInfoStruct, NULL);
		free(rows);
		free(pixels);
		return NULL;
	}
	
	png_set_read_fn(pngReadStruct, &readContext, pngReadFnMemread);
	png_set_sig_bytes(pngReadStruct, PNG_HEADER_SIZE);
	png_read_info(pngReadStruct, pngInfoStruct);
	
	width = png_get_image_width(pngReadStruct, pngInfoStruct);
	height = png_get_image_height(pngReadStruct, pngInfoStruct);
	bitDepth = png_get_bit_depth(pngReadStruct, pngInfoStruct);
	colorType = png_get_color_type(pngReadStruct, pngInfoStruct);
	
	if (colorType == PNG_COLOR_TYPE_PALETTE) {
		png_set_palette_to_rgb(pngReadStruct);
		colorType = PNG_COLOR_TYPE_RGB;
	}
	if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) {
		png_set_expand_gray_1_2_4_to_8(pngReadStruct);
	}
	if (png_get_valid(pngReadStruct, pngInfoStruct, PNG_INFO_tRNS)) {
		png_set_tRNS_to_alpha(pngReadStruct);
	}
	if (bitDepth == 16) {
		png_set_strip_16(pngReadStruct);
	}
	
	switch (pixelFormat) {
		case PNG_PIXEL_FORMAT_AUTOMATIC:
			switch (colorType) {
				case PNG_COLOR_TYPE_GRAY:
					chosenPixelFormat = BITMAP_PIXEL_FORMAT_GRAY_8;
					break;
					
				case PNG_COLOR_TYPE_GRAY_ALPHA:
					chosenPixelFormat = BITMAP_PIXEL_FORMAT_GRAYALPHA_88;
					break;
					
				case PNG_COLOR_TYPE_RGB:
					chosenPixelFormat = BITMAP_PIXEL_FORMAT_RGB_888;
					break;
					
				case PNG_COLOR_TYPE_RGB_ALPHA:
					chosenPixelFormat = BITMAP_PIXEL_FORMAT_RGBA_8888;
					break;
			}
			png_read_update_info(pngReadStruct, pngInfoStruct);
			break;
			
		case BITMAP_PIXEL_FORMAT_RGBA_8888:
			if (!(colorType & PNG_COLOR_MASK_ALPHA)) {
				png_set_add_alpha(pngReadStruct, 0xFF, PNG_FILLER_AFTER);
			}
			png_read_update_info(pngReadStruct, pngInfoStruct);
			if (!(colorType & PNG_COLOR_MASK_COLOR)) {
				png_set_gray_to_rgb(pngReadStruct);
			}
			chosenPixelFormat = BITMAP_PIXEL_FORMAT_RGBA_8888;
			break;
			
		case BITMAP_PIXEL_FORMAT_RGB_888:
			if (colorType & PNG_COLOR_MASK_ALPHA) {
				png_set_strip_alpha(pngReadStruct);
			}
			png_read_update_info(pngReadStruct, pngInfoStruct);
			if (!(colorType & PNG_COLOR_MASK_COLOR)) {
				png_set_gray_to_rgb(pngReadStruct);
			}
			chosenPixelFormat = BITMAP_PIXEL_FORMAT_RGB_888;
			break;
			
		case BITMAP_PIXEL_FORMAT_GRAYALPHA_88:
			if (!(colorType & PNG_COLOR_MASK_ALPHA)) {
				png_set_add_alpha(pngReadStruct, 0xFF, PNG_FILLER_AFTER);
			}
			png_read_update_info(pngReadStruct, pngInfoStruct);
			if (colorType & PNG_COLOR_MASK_COLOR) {
				png_set_rgb_to_gray(pngReadStruct, 1, (float) 0x55 / 0xFF, (float) 0x55 / 0xFF);
			}
			chosenPixelFormat = BITMAP_PIXEL_FORMAT_GRAYALPHA_88;
			break;
			
		case BITMAP_PIXEL_FORMAT_GRAY_8:
			if (colorType & PNG_COLOR_MASK_ALPHA) {
				png_set_strip_alpha(pngReadStruct);
			}
			png_read_update_info(pngReadStruct, pngInfoStruct);
			if (colorType & PNG_COLOR_MASK_COLOR) {
				png_set_rgb_to_gray(pngReadStruct, 1, (float) 0x55 / 0xFF, (float) 0x55 / 0xFF);
			}
			chosenPixelFormat = BITMAP_PIXEL_FORMAT_GRAY_8;
			break;
	}
	
	pixels = calloc(width * height, BitmapImage_pixelFormatBytes(chosenPixelFormat));
	rows = malloc(sizeof(png_bytep) * height);
	for (rowIndex = 0; rowIndex < height; rowIndex++) {
		rows[rowIndex] = pixels + ((flipVertical ? height - rowIndex - 1 : rowIndex) * width * BitmapImage_pixelFormatBytes(chosenPixelFormat));
	}
	
	png_read_rows(pngReadStruct, rows, NULL, height);
	png_read_end(pngReadStruct, NULL);
	
	png_destroy_read_struct(&pngReadStruct, &pngInfoStruct, NULL);
	free(rows);
	
	image = BitmapImage_createWithPixelsNoCopy(chosenPixelFormat, width, height, width * BitmapImage_pixelFormatBytes(chosenPixelFormat), pixels, true);
	
	return image;
}
void ZLEwlImageManager::convertImageDirectPng(const std::string &stringData, ZLImageData &data) const {
	struct s_my_png my_png;
	my_png.p = (char*)stringData.data();
	my_png.size = stringData.length();

	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;
	unsigned int *row = NULL;

	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
			(png_voidp)&my_png, mypng_error_func, mypng_warning_func);
	if ( !png_ptr )
		return;

	if (setjmp( png_ptr->jmpbuf )) {
		data.init(0, 0);
		if (png_ptr)
		{
			png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
		}
		if ( row )
			delete row;
		return;
	}

	info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr)
		mypng_error_func(png_ptr, "cannot create png info struct");
	png_set_read_fn(png_ptr,
			(voidp)&my_png, mypng_read_func);
	png_read_info( png_ptr, info_ptr );


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

	data.init(width, height);

	row = new unsigned int[ width ];

	// SET TRANSFORMS
	if (color_type & PNG_COLOR_MASK_PALETTE)
		png_set_palette_to_rgb(png_ptr);

	if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
		png_set_gray_1_2_4_to_8(png_ptr);

	if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
		png_set_tRNS_to_alpha(png_ptr);

	if (bit_depth == 16) png_set_strip_16(png_ptr);


	if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
		png_set_invert_alpha(png_ptr);
	} else {
		png_color_16 bg = {0, 0xffff, 0xffff, 0xffff, 0xffff};
		png_set_background(png_ptr, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 0.0);

		png_set_strip_alpha(png_ptr);
	}

	if (bit_depth < 8)
		png_set_packing(png_ptr);

	//if (color_type == PNG_COLOR_TYPE_RGB)
	//png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);

	//if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
	//    png_set_swap_alpha(png_ptr);

	if (! (color_type == PNG_COLOR_TYPE_GRAY ||
			color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
		png_set_rgb_to_gray(png_ptr, 1, -1, -1);

	int number_passes = png_set_interlace_handling(png_ptr);
	//if (color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
	//    color_type == PNG_COLOR_TYPE_GRAY_ALPHA)

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


	ZLIntegerOption myDitherAlgo(ZLCategoryKey::LOOK_AND_FEEL, "Options", "DitherAlgo", 0);
	register int dalgo = myDitherAlgo.value();
	char *c;	
	for(int pass = 0; pass < number_passes; pass++) {
		for(unsigned int y = 0; y < height; y++) {

			png_read_rows(png_ptr, (unsigned char **)&row, png_bytepp_NULL, 1);

			c = ((ZLEwlImageData&)data).getImageData() + width * y;


			if ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) {
				unsigned char *s = (unsigned char*)row;
				if(dalgo == 1)
					for(unsigned int i = 0; i < width; i++)
						*c++ = Dither2BitColor(*(++s)++, i, y);
				else
					for(unsigned int i = 0; i < width; i++)
						*c++ = *(++s)++;
			} else if(dalgo == 1) {
				unsigned char *s = (unsigned char*)row;
				for(unsigned int i = 0; i < width; i++)
					*c++ = Dither2BitColor(*s++, i, y);
			} else 
				memcpy(c, (char*)row, width);
		}
	}

	png_read_end(png_ptr, info_ptr);

	png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
}