/** \brief Constructor.
     *
     * @param fd File handle to adapt.
     * @param skip How many bytes of file have already been read
     */
    PngReader(FILE *fd, unsigned skip) :
      m_fd(fd),
      m_png(NULL),
      m_info(NULL),
      m_end(NULL),
      m_block(NULL)
    {
      m_png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
      if(!m_png)
      {
        std::stringstream sstr;
        sstr << "could not create a PNG read struct";
        BOOST_THROW_EXCEPTION(std::runtime_error(sstr.str()));
      }
      m_info = png_create_info_struct(m_png);
      if(!m_info)
      {
        std::stringstream sstr;
        sstr << "could not create a PNG info struct";
        BOOST_THROW_EXCEPTION(std::runtime_error(sstr.str()));
      }
      m_end = png_create_info_struct(m_png);
      if(!m_end)
      {
        std::stringstream sstr;
        sstr << "could not create a PNG end info struct";
        BOOST_THROW_EXCEPTION(std::runtime_error(sstr.str()));
      }

      png_byte keep_chunks[] = { 0 };
      png_set_keep_unknown_chunks(m_png, PNG_HANDLE_CHUNK_NEVER, keep_chunks, 0);

      png_init_io(m_png, m_fd); 
      png_set_sig_bytes(m_png, static_cast<int>(skip));
    }
Exemple #2
0
bool PNGInstallChunkHandler(png_structp png, void* context, ChunkHandler handler, const char* chunkName) {
	if (setjmp(png_jmpbuf(png))) {
		return false;
	}
	png_set_read_user_chunk_fn(png, context, handler);
	png_set_keep_unknown_chunks(png, PNG_HANDLE_CHUNK_ALWAYS, (png_bytep) chunkName, 1);
	return true;
}
/*
 * Extension to libpng's unknown chunk handler.
 */
static void opng_set_keep_unknown_chunk(png_structp png_ptr, int keep, png_bytep chunk_type)
{
    png_byte chunk_name[5];

    /* Call png_set_keep_unknown_chunks() once per each chunk type only. */
    memcpy(chunk_name, chunk_type, 4);
    chunk_name[4] = 0;
    if (!png_handle_as_unknown(png_ptr, chunk_name))
        png_set_keep_unknown_chunks(png_ptr, keep, chunk_name, 1);
}
Exemple #4
0
// Reads the header and initializes the output fields, if not NULL.
//
// @param stream Input data. Will be read to get enough information to properly
//      setup the codec.
// @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL.
//      If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is
//      expected to continue to own it for the lifetime of the png_ptr.
// @param outCodec Optional output variable.  If non-NULL, will be set to a new
//      SkPngCodec on success.
// @param png_ptrp Optional output variable. If non-NULL, will be set to a new
//      png_structp on success.
// @param info_ptrp Optional output variable. If non-NULL, will be set to a new
//      png_infop on success;
// @return true on success, in which case the caller is responsible for calling
//      png_destroy_read_struct(png_ptrp, info_ptrp).
//      If it returns false, the passed in fields (except stream) are unchanged.
static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, SkCodec** outCodec,
                        png_structp* png_ptrp, png_infop* info_ptrp) {
    // The image is known to be a PNG. Decode enough to know the SkImageInfo.
    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr,
                                                 sk_error_fn, sk_warning_fn);
    if (!png_ptr) {
        return false;
    }

    AutoCleanPng autoClean(png_ptr, stream, chunkReader, outCodec);

    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == nullptr) {
        return false;
    }

    autoClean.setInfoPtr(info_ptr);

    // FIXME: Could we use the return value of setjmp to specify the type of
    // error?
    if (setjmp(png_jmpbuf(png_ptr))) {
        return false;
    }

#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
    // Hookup our chunkReader so we can see any user-chunks the caller may be interested in.
    // This needs to be installed before we read the png header.  Android may store ninepatch
    // chunks in the header.
    if (chunkReader) {
        png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
        png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_user_chunk);
    }
#endif

    const bool decodedBounds = autoClean.decodeBounds();

    if (!decodedBounds) {
        return false;
    }

    // On success, decodeBounds releases ownership of png_ptr and info_ptr.
    if (png_ptrp) {
        *png_ptrp = png_ptr;
    }
    if (info_ptrp) {
        *info_ptrp = info_ptr;
    }

    // decodeBounds takes care of setting outCodec
    if (outCodec) {
        SkASSERT(*outCodec);
    }
    return true;
}
Exemple #5
0
int main(int argc, char *argv[]) {
	FILE *fp;
	const char *filename;
	unsigned char header[8];
	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;
	int result = 1;

	if (argc != 2) {
		fprintf(stderr, "Usage: %s <png>\n", argv[0]);
		return -1;
	}
	filename = argv[1];
	fp = fopen(filename, "rb");
	if (!fp) {
		perror(filename);
		return -1;
	}

	if (fread(header, 8, 1, fp) != 1)
		FAIL("%s: Couldn't read header.", filename);
	if (png_sig_cmp(header, 0, 8))
		FAIL("%s: Not a PNG.", filename);
	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
			NULL, NULL, NULL);
	if (!png_ptr)
		FAIL("Couldn't set up PNG reader.");
	info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr)
		FAIL("Couldn't set up PNG info reader.");

	if (setjmp(png_jmpbuf(png_ptr)))
		goto done;

	png_init_io(png_ptr, fp);
	png_set_sig_bytes(png_ptr, 8);
	png_set_read_user_chunk_fn(png_ptr, NULL, &read_chunk);
	png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_NEVER, NULL, 0);
	png_read_info(png_ptr, info_ptr);

	puts(apng ? "APNG" : "PNG");
	result = 0;
done:
	if (png_ptr)
		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
	fclose(fp);
	return result;
}
/*
 * Imports an image from an PNG file stream.
 * The function returns 0 on success or -1 on error.
 */
int opng_decode_image(struct opng_codec_context *context, FILE *stream, const char *fname, bool force_no_palette)
{
    context->libpng_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, opng_read_error, opng_read_warning);
    context->info_ptr = png_create_info_struct(context->libpng_ptr);
    if (!context->libpng_ptr || !context->info_ptr)
    {
        opng_error(0, "Out of memory");
        png_destroy_read_struct(&context->libpng_ptr, &context->info_ptr, 0);
        exit(1);
    }

    opng_init_image(context->image);
    const char * volatile err_msg;  /* volatile is required by cexcept */
    struct opng_encoding_stats * stats = context->stats;
    opng_init_stats(stats);
    context->stream = stream;
    context->fname = fname;
    if (force_no_palette) {
        png_set_palette_to_rgb(context->libpng_ptr);
    }

    Try
    {
        png_set_keep_unknown_chunks(context->libpng_ptr, PNG_HANDLE_CHUNK_ALWAYS, 0, 0);
        png_set_read_fn(context->libpng_ptr, context, opng_read_data);
        png_read_png(context->libpng_ptr, context->info_ptr, 0, 0);
    }
    Catch (err_msg)
    {
        if (opng_validate_image(context->libpng_ptr, context->info_ptr))
        {
            /* The critical image info has already been loaded.
             * Treat this error as a warning in order to allow data recovery.
             */
            opng_warning(fname, err_msg);
        }
        else
        {
            opng_error(fname, err_msg);
            return -1;
        }
    }
    opng_load_image(context->image, context->libpng_ptr, context->info_ptr);
    return 0;
}
/*
 * Encodes an image to a PNG file stream.
 */
int opng_encode_image(struct opng_codec_context *context, int filtered, FILE *stream, const char *fname, int level)
{
    const char * volatile err_msg;  /* volatile is required by cexcept */

    context->libpng_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, opng_write_error, opng_write_warning);
    context->info_ptr = png_create_info_struct(context->libpng_ptr);
    if (!context->libpng_ptr || !context->info_ptr)
    {
        opng_error(0, "Out of memory");
        png_destroy_write_struct(&context->libpng_ptr, &context->info_ptr);
        exit(1);
    }

    struct opng_encoding_stats * stats = context->stats;
    opng_init_stats(stats);
    context->stream = stream;
    context->fname = fname;

    Try
    {

        png_set_filter(context->libpng_ptr, PNG_FILTER_TYPE_BASE, filtered ? PNG_ALL_FILTERS : PNG_FILTER_NONE);
        if (level != 6) {
            png_set_compression_level(context->libpng_ptr, level);
        }
        png_set_compression_mem_level(context->libpng_ptr, 8);
        png_set_compression_window_bits(context->libpng_ptr, 15);
        png_set_compression_strategy(context->libpng_ptr, 0);
        png_set_keep_unknown_chunks(context->libpng_ptr, PNG_HANDLE_CHUNK_ALWAYS, 0, 0);
        opng_store_image(context->image, context->libpng_ptr, context->info_ptr);

        /* Write the PNG stream. */
        png_set_write_fn(context->libpng_ptr, context, opng_write_data, 0);
        png_write_png(context->libpng_ptr, context->info_ptr, 0, 0);
    }
    Catch (err_msg)
    {
        stats->idat_size = OPTK_INT64_MAX;
        opng_error(fname, err_msg);
        return -1;
    }
    png_data_freer(context->libpng_ptr, context->info_ptr, PNG_USER_WILL_FREE_DATA, PNG_FREE_ALL);
    png_destroy_write_struct(&context->libpng_ptr, &context->info_ptr);
    return 0;
}
Exemple #8
0
void
nsPNGDecoder::InitInternal()
{
  mCMSMode = gfxPlatform::GetCMSMode();
  if ((mDecodeFlags & DECODER_NO_COLORSPACE_CONVERSION) != 0)
    mCMSMode = eCMSMode_Off;
  mDisablePremultipliedAlpha = (mDecodeFlags & DECODER_NO_PREMULTIPLY_ALPHA) != 0;

#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
  static png_byte color_chunks[]=
       { 99,  72,  82,  77, '\0',   /* cHRM */
        105,  67,  67,  80, '\0'};  /* iCCP */
  static png_byte unused_chunks[]=
       { 98,  75,  71,  68, '\0',   /* bKGD */
        104,  73,  83,  84, '\0',   /* hIST */
        105,  84,  88, 116, '\0',   /* iTXt */
        111,  70,  70, 115, '\0',   /* oFFs */
        112,  67,  65,  76, '\0',   /* pCAL */
        115,  67,  65,  76, '\0',   /* sCAL */
        112,  72,  89, 115, '\0',   /* pHYs */
        115,  66,  73,  84, '\0',   /* sBIT */
        115,  80,  76,  84, '\0',   /* sPLT */
        116,  69,  88, 116, '\0',   /* tEXt */
        116,  73,  77,  69, '\0',   /* tIME */
        122,  84,  88, 116, '\0'};  /* zTXt */
#endif

  // For size decodes, we only need a small buffer
  if (IsSizeDecode()) {
    mHeaderBuf = (PRUint8 *)moz_xmalloc(BYTES_NEEDED_FOR_DIMENSIONS);
    return;
  }

  /* For full decodes, do png init stuff */

  /* Initialize the container's source image header. */
  /* Always decode to 24 bit pixdepth */

  mPNG = png_create_read_struct(PNG_LIBPNG_VER_STRING,
                                NULL, nsPNGDecoder::error_callback,
                                nsPNGDecoder::warning_callback);
  if (!mPNG) {
    PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
    return;
  }

  mInfo = png_create_info_struct(mPNG);
  if (!mInfo) {
    PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
    png_destroy_read_struct(&mPNG, NULL, NULL);
    return;
  }

#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
  /* Ignore unused chunks */
  if (mCMSMode == eCMSMode_Off)
    png_set_keep_unknown_chunks(mPNG, 1, color_chunks, 2);

  png_set_keep_unknown_chunks(mPNG, 1, unused_chunks,
                              (int)sizeof(unused_chunks)/5);   
#endif

#ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED
  if (mCMSMode != eCMSMode_Off)
    png_set_chunk_malloc_max(mPNG, 4000000L);
#endif

  /* use this as libpng "progressive pointer" (retrieve in callbacks) */
  png_set_progressive_read_fn(mPNG, static_cast<png_voidp>(this),
                              nsPNGDecoder::info_callback,
                              nsPNGDecoder::row_callback,
                              nsPNGDecoder::end_callback);

}
Exemple #9
0
//---------------------------------------------------------------------------
void __fastcall TDeePNG::LoadFromStream(Classes::TStream * Stream)
{
	// LoadFromStream

	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;
	png_infop end_info = NULL;

	png_bytep *row_pointers = NULL;
	BYTE *image = NULL;

	png_uint_32 i;

	try
	{
		// create png_struct
		png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING,
			(png_voidp)this, DeePNG_error, DeePNG_warning,
			(png_voidp)this, DeePNG_malloc, DeePNG_free);

		// set read_chunk_callback
		png_set_read_user_chunk_fn(png_ptr,
			reinterpret_cast<void*>(this),
			PNG_read_chunk_callback);
		png_set_keep_unknown_chunks(png_ptr, 2, NULL, 0);
			// keep only if safe-to-copy chunks, for all unknown chunks

		// create png_info
		info_ptr = png_create_info_struct(png_ptr);

		// create end_info
		end_info = png_create_info_struct(png_ptr);

		// set stream input functions
		png_set_read_fn(png_ptr, (voidp)Stream, DeePNG_read_data);

		// set read_row_callback
		png_set_read_status_fn(png_ptr, DeePNG_read_row_callback);

		// call png_read_info
		png_read_info(png_ptr, info_ptr);

		// retrieve IHDR
		png_uint_32 width, height;
		int bit_depth, color_type, interlace_type, compression_type, filter_type;
		png_get_IHDR(png_ptr,info_ptr, &width, &height, &bit_depth, &color_type,
			&interlace_type, &compression_type, &filter_type);

		// expand palletted image which has transparent color, to 32bpp
		if (png_get_valid(png_ptr, info_ptr,PNG_INFO_tRNS))
		{
			png_set_expand(png_ptr);
			color_type=PNG_COLOR_TYPE_RGB_ALPHA;
		}

		// analyse IHDR ( color_type )
		switch(color_type)
		{
		case PNG_COLOR_TYPE_GRAY_ALPHA:
			PixelFormat=pf32bit;
			break;
		case PNG_COLOR_TYPE_GRAY:
			// w/b
			SetGrayscalePalette(this,bit_depth);
			break;
		case PNG_COLOR_TYPE_PALETTE:
			SetColorDepth(this,bit_depth);
			break;
		case PNG_COLOR_TYPE_RGB_ALPHA:
			PixelFormat=pf32bit;
			break;
		case PNG_COLOR_TYPE_RGB:
			PixelFormat=pf24bit;
			break;
		default:
			throw EDeePNG("EDeePNG : Non-supported color type.");
		}

		// retrieve offset information
		png_int_32 offset_x, offset_y;
		int offset_unit_type;
		if(png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, &offset_unit_type))
		{
			ofs_x = offset_x;
			ofs_y = offset_y;
			ofs_unit = offset_unit_type;
			ofs_set = true;
		}
		else
		{
			ofs_set = false;
		}

		// check size
		if(width>=65536 || height>=65536)
		{
			throw EDeePNG("EDeePNG : Too large image size.");
		}


		// retrieve palette
		if(color_type == PNG_COLOR_TYPE_PALETTE)
		{
			int num_palette;
			png_color *palette = NULL;
			png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);

			int i;
		#pragma pack(push, 1)
			struct
			{
				WORD	palVersion;
				WORD	palNumEntries;
				PALETTEENTRY entry[256];
			} pal;
		#pragma pack(pop)
			pal.palVersion = 0x300;
			pal.palNumEntries = num_palette;
			for(i = 0; i < num_palette; i++)
			{
				pal.entry[i].peRed = palette[i].red;
				pal.entry[i].peGreen = palette[i].green;
				pal.entry[i].peBlue = palette[i].blue;
				pal.entry[i].peFlags = 0;
			}
			Palette = CreatePalette((const LOGPALETTE*)&pal);
		}

		// collapse 16bit precision data to 8bit
		if(bit_depth == 16) png_set_strip_16(png_ptr);

		// change color component order
		if (color_type == PNG_COLOR_TYPE_RGB ||
			color_type == PNG_COLOR_TYPE_RGB_ALPHA)
				png_set_bgr(png_ptr);

		// call png_read_update_info ...
		png_read_update_info(png_ptr, info_ptr);

		// set size
		Width=width, Height=height;

		// allocate memory for row_pointers
		row_pointers = new png_bytep[height];
		png_uint_32 rowbytes = png_get_rowbytes(png_ptr, info_ptr);
		image = new BYTE[rowbytes*height];
		for(i = 0;i < height; i++)
		{
			row_pointers[i] = image + i*rowbytes;
		}

		// load image
		png_read_image(png_ptr, row_pointers);

		// finish loading image
		png_read_end(png_ptr, info_ptr);

		// set image to ScanLines

		BYTE *imageptr = image;
		if(color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
		{
			// IA IA IA ....

			for(i = 0; i < height; i++)
			{
				BYTE *scanptr = (BYTE*)ScanLine[i];
				png_uint_32 j;
				for(j = 0; j < width; j++)
				{
					BYTE i = *(imageptr++);
					scanptr[0] = i;
					scanptr[1] = i;
					scanptr[2] = i;
					scanptr[3] = *(imageptr++);
					scanptr += 4;
				}
			}
		}
		else
		{
			// intact copy

			for(i = 0; i < height; i++)
			{
				BYTE *scanptr = (BYTE*)ScanLine[i];
				memcpy(scanptr, imageptr, rowbytes);
				imageptr += rowbytes;
			}


		}
	}
	catch(...)
	{
		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
		if(row_pointers) delete [] row_pointers;
		if(image) delete [] image;
		throw;
	}

	png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
	if(row_pointers) delete [] row_pointers;
	if(image) delete [] image;
}
bool SkPNGImageDecoder::onDecodeInit(SkStream* sk_stream,
        png_structp *png_ptrp, png_infop *info_ptrp)
{
    /* Create and initialize the png_struct with the desired error handler
    * functions.  If you want to use the default stderr and longjump method,
    * you can supply NULL for the last three parameters.  We also supply the
    * the compiler header file version, so that we know if the application
    * was compiled with a compatible version of the library.  */
    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
        NULL, sk_error_fn, NULL);
    //   png_voidp user_error_ptr, user_error_fn, user_warning_fn);
    if (png_ptr == NULL) {
        return false;
    }
    *png_ptrp = png_ptr;

    /* Allocate/initialize the memory for image information. */
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) {
        png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
        return false;
    }
    *info_ptrp = info_ptr;

    /* Set error handling if you are using the setjmp/longjmp method (this is
    * the normal method of doing things with libpng).  REQUIRED unless you
    * set up your own error handlers in the png_create_read_struct() earlier.
    */
    if (setjmp(png_jmpbuf(png_ptr))) {
        return false;
    }

    /* If you are using replacement read functions, instead of calling
    * png_init_io() here you would call:
    */
    png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn);
    png_set_seek_fn(png_ptr, sk_seek_fn);
    /* where user_io_ptr is a structure you want available to the callbacks */
    /* If we have already read some of the signature */
    // png_set_sig_bytes(png_ptr, 0 /* sig_read */ );

    // hookup our peeker so we can see any user-chunks the caller may be interested in
    png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
    if (this->getPeeker()) {
        png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk);
    }

    /* The call to png_read_info() gives us all of the information from the
    * PNG file before the first IDAT (image data chunk). */
    png_read_info(png_ptr, info_ptr);
    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);

    /* tell libpng to strip 16 bit/color files down to 8 bits/color */
    if (bit_depth == 16) {
        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). */
    if (bit_depth < 8) {
        png_set_packing(png_ptr);
    }
    /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
        png_set_gray_1_2_4_to_8(png_ptr);
    }

    /* Make a grayscale image into RGB. */
    if (color_type == PNG_COLOR_TYPE_GRAY ||
        color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
        png_set_gray_to_rgb(png_ptr);
    }
    return true;
}
Exemple #11
0
static int read_png(FILE *fp)
{
    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0,
            0);
    png_infop info_ptr = NULL;
    png_bytep row = NULL, display = NULL;

    if (png_ptr == NULL) return 0;

    if (setjmp(png_jmpbuf(png_ptr)))
    {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        if (row != NULL) free(row);
        if (display != NULL) free(display);
        return 0;
    }

    png_init_io(png_ptr, fp);

    info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) png_error(png_ptr, "OOM allocating info structure");

    png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, NULL, 0);

    png_read_info(png_ptr, info_ptr);

    {
        png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr);

        row = malloc(rowbytes);
        display = malloc(rowbytes);

        if (row == NULL || display == NULL) png_error(png_ptr,
                "OOM allocating row buffers");

        {
            png_uint_32 height = png_get_image_height(png_ptr, info_ptr);
            int passes = png_set_interlace_handling(png_ptr);
            int pass;

            png_start_read_image(png_ptr);

            for (pass = 0; pass < passes; ++pass)
            {
                png_uint_32 y = height;

                /* NOTE: this trashes the row each time; interlace handling won't
                 * work, but this avoids memory thrashing for speed testing.
                 */
                while (y-- > 0)
                    png_read_row(png_ptr, row, display);
            }
        }
    }

    /* Make sure to read to the end of the file: */
    png_read_end(png_ptr, info_ptr);
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    free(row);
    free(display);
    return 1;
}
Exemple #12
0
void
nsPNGDecoder::InitInternal()
{
  // For size decodes, we don't need to initialize the png decoder
  if (IsSizeDecode()) {
    return;
  }

  mCMSMode = gfxPlatform::GetCMSMode();
  if (GetDecodeFlags() & imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION) {
    mCMSMode = eCMSMode_Off;
  }
  mDisablePremultipliedAlpha =
    GetDecodeFlags() & imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA;

#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
  static png_byte color_chunks[]=
       { 99,  72,  82,  77, '\0',   // cHRM
        105,  67,  67,  80, '\0'};  // iCCP
  static png_byte unused_chunks[]=
       { 98,  75,  71,  68, '\0',   // bKGD
        104,  73,  83,  84, '\0',   // hIST
        105,  84,  88, 116, '\0',   // iTXt
        111,  70,  70, 115, '\0',   // oFFs
        112,  67,  65,  76, '\0',   // pCAL
        115,  67,  65,  76, '\0',   // sCAL
        112,  72,  89, 115, '\0',   // pHYs
        115,  66,  73,  84, '\0',   // sBIT
        115,  80,  76,  84, '\0',   // sPLT
        116,  69,  88, 116, '\0',   // tEXt
        116,  73,  77,  69, '\0',   // tIME
        122,  84,  88, 116, '\0'};  // zTXt
#endif

  // For full decodes, do png init stuff

  // Initialize the container's source image header
  // Always decode to 24 bit pixdepth

  mPNG = png_create_read_struct(PNG_LIBPNG_VER_STRING,
                                nullptr, nsPNGDecoder::error_callback,
                                nsPNGDecoder::warning_callback);
  if (!mPNG) {
    PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
    return;
  }

  mInfo = png_create_info_struct(mPNG);
  if (!mInfo) {
    PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
    png_destroy_read_struct(&mPNG, nullptr, nullptr);
    return;
  }

#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
  // Ignore unused chunks
  if (mCMSMode == eCMSMode_Off) {
    png_set_keep_unknown_chunks(mPNG, 1, color_chunks, 2);
  }

  png_set_keep_unknown_chunks(mPNG, 1, unused_chunks,
                              (int)sizeof(unused_chunks)/5);
#endif

#ifdef PNG_SET_USER_LIMITS_SUPPORTED
  if (mCMSMode != eCMSMode_Off) {
    png_set_chunk_malloc_max(mPNG, 4000000L);
  }
#endif

#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
  // Disallow palette-index checking, for speed; we would ignore the warning
  // anyhow.  This feature was added at libpng version 1.5.10 and is disabled
  // in the embedded libpng but enabled by default in the system libpng.  This
  // call also disables it in the system libpng, for decoding speed.
  // Bug #745202.
  png_set_check_for_invalid_index(mPNG, 0);
#endif

#if defined(PNG_SET_OPTION_SUPPORTED) && defined(PNG_sRGB_PROFILE_CHECKS) && \
            PNG_sRGB_PROFILE_CHECKS >= 0
  // Skip checking of sRGB ICC profiles
  png_set_option(mPNG, PNG_SKIP_sRGB_CHECK_PROFILE, PNG_OPTION_ON);
#endif

  // use this as libpng "progressive pointer" (retrieve in callbacks)
  png_set_progressive_read_fn(mPNG, static_cast<png_voidp>(this),
                              nsPNGDecoder::info_callback,
                              nsPNGDecoder::row_callback,
                              nsPNGDecoder::end_callback);

}
Exemple #13
0
/* Test one file */
int
test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
{
   static FILE *fpin, *fpout;  /* "static" prevents setjmp corruption */
   png_structp read_ptr, write_ptr;
   png_infop read_info_ptr, write_info_ptr, end_info_ptr, write_end_info_ptr;
   png_bytep row_buf;
   png_uint_32 y;
   png_uint_32 width, height;
   int num_pass, pass;
   int bit_depth, color_type;
#ifdef PNG_SETJMP_SUPPORTED
#ifdef USE_FAR_KEYWORD
   jmp_buf jmp_env;
#endif
#endif

   char inbuf[256], outbuf[256];

   row_buf = (png_bytep)NULL;

   if ((fpin = fopen(inname, "rb")) == NULL)
   {
      fprintf(STDERR, "Could not find input file %s\n", inname);
      return (1);
   }

   if ((fpout = fopen(outname, "wb")) == NULL)
   {
      fprintf(STDERR, "Could not open output file %s\n", outname);
      fclose(fpin);
      return (1);
   }

   png_debug(0, "Allocating read and write structures\n");
#ifdef PNG_USER_MEM_SUPPORTED
   read_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
      (png_error_ptr)NULL, (png_error_ptr)NULL, (png_voidp)NULL,
      (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free);
#else
   read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
      (png_error_ptr)NULL, (png_error_ptr)NULL);
#endif
#if defined(PNG_NO_STDIO)
   png_set_error_fn(read_ptr, (png_voidp)inname, png_default_error,
       png_default_warning);
#endif
#ifdef PNG_USER_MEM_SUPPORTED
   write_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
      (png_error_ptr)NULL, (png_error_ptr)NULL, (png_voidp)NULL,
      (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free);
#else
   write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
      (png_error_ptr)NULL, (png_error_ptr)NULL);
#endif
#if defined(PNG_NO_STDIO)
   png_set_error_fn(write_ptr, (png_voidp)inname, png_default_error,
       png_default_warning);
#endif
   png_debug(0, "Allocating read_info, write_info and end_info structures\n");
   read_info_ptr = png_create_info_struct(read_ptr);
   write_info_ptr = png_create_info_struct(write_ptr);
   end_info_ptr = png_create_info_struct(read_ptr);
   write_end_info_ptr = png_create_info_struct(write_ptr);
#ifdef PNG_USER_MEM_SUPPORTED
#endif

#ifdef PNG_SETJMP_SUPPORTED
   png_debug(0, "Setting jmp_env for read struct\n");
#ifdef USE_FAR_KEYWORD
   if (setjmp(jmp_env))
#else
   if (setjmp(png_jmp_env(read_ptr)))
#endif
   {
      fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
      fclose(fpin);
      fclose(fpout);
      return (1);
   }
#ifdef USE_FAR_KEYWORD
   png_memcpy(png_jmp_env(read_ptr),jmp_env,sizeof(jmp_buf));
#endif

   png_debug(0, "Setting jmp_env for write struct\n");
#ifdef USE_FAR_KEYWORD
   if (setjmp(jmp_env))
#else
   if (setjmp(png_jmp_env(write_ptr)))
#endif
   {
      fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
      fclose(fpin);
      fclose(fpout);
      return (1);
   }
#ifdef USE_FAR_KEYWORD
   png_memcpy(png_jmp_env(write_ptr),jmp_env,sizeof(jmp_buf));
#endif
#endif

   png_debug(0, "Initializing input and output streams\n");
#if !defined(PNG_NO_STDIO)
   png_init_io(read_ptr, fpin);
   png_init_io(write_ptr, fpout);
#else
   png_set_read_fn(read_ptr, (png_voidp)fpin, png_default_read_data);
   png_set_write_fn(write_ptr, (png_voidp)fpout,  png_default_write_data,
#if defined(PNG_WRITE_FLUSH_SUPPORTED)
      png_default_flush);
#else
      NULL);
#endif
#endif
   if(status_dots_requested == 1)
   {
      png_set_write_status_fn(write_ptr, write_row_callback);
      png_set_read_status_fn(read_ptr, read_row_callback);
   }
   else
   {
      png_set_write_status_fn(write_ptr, NULL);
      png_set_read_status_fn(read_ptr, NULL);
   }

#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
   {
     int i;
     for(i=0; i<256; i++)
        filters_used[i]=0;
     png_set_read_user_transform_fn(read_ptr, count_filters);
   }
#endif
#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
   zero_samples=0;
   png_set_write_user_transform_fn(write_ptr, count_zero_samples);
#endif

#define HANDLE_CHUNK_IF_SAFE      2
#define HANDLE_CHUNK_ALWAYS       3
#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
   png_set_keep_unknown_chunks(read_ptr, HANDLE_CHUNK_ALWAYS, NULL, 0);
#endif
#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
   png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_IF_SAFE, NULL, 0);
#endif

   png_debug(0, "Reading info struct\n");
   png_read_info(read_ptr, read_info_ptr);

   png_debug(0, "Transferring info struct\n");
   {
      int interlace_type, compression_type, filter_type;

      if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth,
          &color_type, &interlace_type, &compression_type, &filter_type))
      {
         png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth,
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
            color_type, interlace_type, compression_type, filter_type);
#else
            color_type, PNG_INTERLACE_NONE, compression_type, filter_type);
#endif
      }
   }
Exemple #14
0
static int
ReadPNG(char *Path, unsigned char **ImgData, int *width, int *length)
{
  FILE *f;
  unsigned char *tmpRow = NULL;
  unsigned char *Tempstr = NULL;
  png_structp png_ptr;
  png_infop info_ptr;
  png_uint_32 png_width, png_height, scanline_width;
  int bit_depth, color_type, interlace_type, row;
  int channels;

  f = fopen(Path, "r");

  if (!f)
    return (FALSE);

/* we have to load the first 4 bytes of the png file, this contains png version info */
  Tempstr = calloc(1, 4);
  if (fread(Tempstr, 1, 4, f) != 4)
  {
    free(Tempstr);
    fclose(f);
    return (FALSE);
  }

/* check if valid png */
  if (png_sig_cmp(Tempstr, (png_size_t) 0, 4))
    printf("%s not a png?\n", Path);
  /* create the png reading structure, errors go to stderr */
  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (png_ptr == NULL)
  {
    fclose(f);
    free(Tempstr);
    return (FALSE);
  }


  /* allocate info struct */
  info_ptr = png_create_info_struct(png_ptr);
  if (info_ptr == NULL)
  {
    fclose(f);
    png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
    free(Tempstr);
    return (FALSE);
  }

  /* set error handling */
#if PNG_LIBPNG_VER_SONUM >= 15
  if (setjmp(png_jmpbuf(png_ptr)))
#else /*PNG_LIBPNG_VER_SONUM >= 15*/
  if (setjmp(png_ptr->jmpbuf))
#endif /*PNG_LIBPNG_VER_SONUM >= 15*/
  {
    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
    free(Tempstr);
    fclose(f);
    return (FALSE);
  }


  /* prepare the reader to ignore all recognized chunks whose data isn't
   * going to be used, i.e., all chunks recognized by libpng except for
   * IHDR, PLTE, IDAT, IEND, tRNS, bKGD, gAMA, and sRGB : */

  {
#ifndef HANDLE_CHUNK_NEVER

/* prior to libpng-1.2.5, this macro was internal, so we define it here. */
# define HANDLE_CHUNK_NEVER 1
#endif
    /* these byte strings were copied from png.h.
     * If a future libpng version recognizes more chunks, add them
     * to this list.  If a future version of readpng2.c recognizes
     * more chunks, delete them from this list. */
    png_byte png_chunk_types_to_ignore[] = { 99, 72, 82, 77, '\0',	/* cHRM */
      104, 73, 83, 84, '\0',	/* hIST */
      105, 67, 67, 80, '\0',	/* iCCP */
      105, 84, 88, 116, '\0',	/* iTXt */
      111, 70, 70, 115, '\0',	/* oFFs */
      112, 67, 65, 76, '\0',	/* pCAL */
      115, 67, 65, 76, '\0',	/* sCAL */
      112, 72, 89, 115, '\0',	/* pHYs */
      115, 66, 73, 84, '\0',	/* sBIT */
      115, 80, 76, 84, '\0',	/* sPLT */
      116, 69, 88, 116, '\0',	/* tEXt */
      116, 73, 77, 69, '\0',	/* tIME */
      122, 84, 88, 116, '\0'
    };				/* zTXt */
#define NUM_PNG_CHUNK_TYPES_TO_IGNORE 13

    png_set_keep_unknown_chunks(png_ptr, HANDLE_CHUNK_NEVER, png_chunk_types_to_ignore, NUM_PNG_CHUNK_TYPES_TO_IGNORE);
  }


  /* set input method */
  png_init_io(png_ptr, f);

  /* tell libpng we have already read some bytes */
  png_set_sig_bytes(png_ptr, 4);
  /* read all info */
  png_read_info(png_ptr, info_ptr);
  /* get some characteristics of the file */
  png_get_IHDR(png_ptr, info_ptr, &png_width, &png_height, &bit_depth, &color_type, &interlace_type, NULL, NULL);

  *width = (int)png_width;
  *length = (int)png_height;

  /*expand bit depth */
  png_set_expand(png_ptr);
  png_set_interlace_handling(png_ptr);
  png_read_update_info(png_ptr, info_ptr);

  /* get size of scanline */
  scanline_width = png_get_rowbytes(png_ptr, info_ptr);

  channels = png_get_channels(png_ptr, info_ptr);

/* allocate texture memory */
  *ImgData = (unsigned char *)malloc(png_width * png_height * 4);
  if (channels == 3)
    tmpRow = (unsigned char *)malloc(scanline_width * sizeof(unsigned char));

  /* read the image line by line into the user's buffer */
  for (row = 0; row < png_height; row++)
  {
    if (channels == 3)
    {
      Read3ByteRow(png_ptr, tmpRow, *ImgData, row, png_width);
    }
    else
      png_read_row(png_ptr, (unsigned char *)((*ImgData) + (row * scanline_width)), NULL);
  }


  /* finish reading the file */
  png_read_end(png_ptr, NULL);

  png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

  fclose(f);

  free(Tempstr);
  if (tmpRow)
    free(tmpRow);

  return (TRUE);
}
Exemple #15
0
int readpng2_init(mainprog_info *mainprog_ptr)
{
    png_structp  png_ptr;       /* note:  temporary variables! */
    png_infop  info_ptr;


    /* could also replace libpng warning-handler (final NULL), but no need: */

    png_ptr = png_create_read_struct(png_get_libpng_ver(NULL), mainprog_ptr,
      readpng2_error_handler, readpng2_warning_handler);
    if (!png_ptr)
        return 4;   /* out of memory */

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return 4;   /* out of memory */
    }


    /* we could create a second info struct here (end_info), but it's only
     * useful if we want to keep pre- and post-IDAT chunk info separated
     * (mainly for PNG-aware image editors and converters) */


    /* setjmp() must be called in every function that calls a PNG-reading
     * libpng function, unless an alternate error handler was installed--
     * but compatible error handlers must either use longjmp() themselves
     * (as in this program) or exit immediately, so here we are: */

    if (setjmp(mainprog_ptr->jmpbuf)) {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        return 2;
    }


#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
    /* prepare the reader to ignore all recognized chunks whose data won't be
     * used, i.e., all chunks recognized by libpng except for IHDR, PLTE, IDAT,
     * IEND, tRNS, bKGD, gAMA, and sRGB (small performance improvement) */
    {
        /* These byte strings were copied from png.h.  If a future version
         * of readpng2.c recognizes more chunks, add them to this list.
         */
        static PNG_CONST png_byte chunks_to_process[] = {
            98,  75,  71,  68, '\0',  /* bKGD */
           103,  65,  77,  65, '\0',  /* gAMA */
           115,  82,  71,  66, '\0',  /* sRGB */
           };

       /* Ignore all chunks except for IHDR, PLTE, tRNS, IDAT, and IEND */
       png_set_keep_unknown_chunks(png_ptr, -1 /* PNG_HANDLE_CHUNK_NEVER */,
          NULL, -1);

       /* But do not ignore chunks in the "chunks_to_process" list */
       png_set_keep_unknown_chunks(png_ptr,
          0 /* PNG_HANDLE_CHUNK_AS_DEFAULT */, chunks_to_process,
          sizeof(chunks_to_process)/5);
    }
#endif /* PNG_HANDLE_AS_UNKNOWN_SUPPORTED */


    /* instead of doing png_init_io() here, now we set up our callback
     * functions for progressive decoding */

    png_set_progressive_read_fn(png_ptr, mainprog_ptr,
      readpng2_info_callback, readpng2_row_callback, readpng2_end_callback);


    /* make sure we save our pointers for use in readpng2_decode_data() */

    mainprog_ptr->png_ptr = png_ptr;
    mainprog_ptr->info_ptr = info_ptr;


    /* and that's all there is to initialization */

    return 0;
}
Exemple #16
0
	int Read ( byte **data, int *width, int *height )
	{
		// Setup the pointers
		*data = NULL;
		*width = 0;
		*height = 0;

		// Make sure we're actually reading PNG data.
		const int SIGNATURE_LEN = 8;

		byte ident[SIGNATURE_LEN];
		memcpy (ident, buf, SIGNATURE_LEN);

		if ( !png_check_sig (ident, SIGNATURE_LEN) )
		{
			ri->Printf (PRINT_ERROR, "PNG signature not found in given image.");
			return 0;
		}

		png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, png_print_error, png_print_warning);
		if ( png_ptr == NULL )
		{
			ri->Printf (PRINT_ERROR, "Could not allocate enough memory to load the image.");
			return 0;
		}

		info_ptr = png_create_info_struct (png_ptr);
		if ( setjmp (png_jmpbuf (png_ptr)) )
		{
			return 0;
		}

		// We've read the signature
		offset += SIGNATURE_LEN;

		// Setup reading information, and read header
		png_set_read_fn (png_ptr, (png_voidp)this, &user_read_data);
#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
		// This generic "ignore all, except required chunks" requires 1.6.0 or newer"
		png_set_keep_unknown_chunks (png_ptr, PNG_HANDLE_CHUNK_NEVER, NULL, -1);
#endif
		png_set_sig_bytes (png_ptr, SIGNATURE_LEN);
		png_read_info (png_ptr, info_ptr);

		png_uint_32 width_;
		png_uint_32 height_;
		int depth;
		int colortype;

		png_get_IHDR (png_ptr, info_ptr, &width_, &height_, &depth, &colortype, NULL, NULL, NULL);

		// While modern OpenGL can handle non-PoT textures, it's faster to handle only PoT
		// so that the graphics driver doesn't have to fiddle about with the texture when uploading.
		if ( !IsPowerOfTwo (width_) || !IsPowerOfTwo (height_) )
		{
			ri->Printf (PRINT_ERROR, "Width or height is not a power-of-two.\n");
			return 0;
		}

		// This function is equivalent to using what used to be LoadPNG32. LoadPNG8 also existed,
		// but this only seemed to be used by the RMG system which does not work in JKA. If this
		// does need to be re-implemented, then colortype should be PNG_COLOR_TYPE_PALETTE or
		// PNG_COLOR_TYPE_GRAY.
		if ( colortype != PNG_COLOR_TYPE_RGB && colortype != PNG_COLOR_TYPE_RGBA )
		{
			ri->Printf (PRINT_ERROR, "Image is not 24-bit or 32-bit.");
			return 0;
		}

		// Read the png data
		if ( colortype == PNG_COLOR_TYPE_RGB )
		{
			// Expand RGB -> RGBA
			png_set_add_alpha (png_ptr, 0xff, PNG_FILLER_AFTER);
		}

		png_read_update_info (png_ptr, info_ptr);

		// We always assume there are 4 channels. RGB channels are expanded to RGBA when read.
		byte *tempData = (byte *)ri->Z_Malloc (width_ * height_ * 4, TAG_TEMP_PNG, qfalse, 4);
		if ( !tempData )
		{
			ri->Printf (PRINT_ERROR, "Could not allocate enough memory to load the image.");
			return 0;
		}

		// Dynamic array of row pointers, with 'height' elements, initialized to NULL.
		byte **row_pointers = (byte **)ri->Hunk_AllocateTempMemory (sizeof (byte *) * height_);
		if ( !row_pointers )
		{
			ri->Printf (PRINT_ERROR, "Could not allocate enough memory to load the image.");

			ri->Z_Free (tempData);

			return 0;
		}

		// Re-set the jmp so that these new memory allocations can be reclaimed
		if ( setjmp (png_jmpbuf (png_ptr)) )
		{
			ri->Hunk_FreeTempMemory (row_pointers);
			ri->Z_Free (tempData);
			return 0;
		}

		for ( unsigned int i = 0, j = 0; i < height_; i++, j += 4 )
		{
			row_pointers[i] = tempData + j * width_;
		}

		png_read_image (png_ptr, row_pointers);

		// Finish reading
		png_read_end (png_ptr, NULL);

		ri->Hunk_FreeTempMemory (row_pointers);

		// Finally assign all the parameters
		*data = tempData;
		*width = width_;
		*height = height_;

		return 1;
	}
Exemple #17
0
static int
read_png(FILE *fp)
{
   png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0);
   png_infop info_ptr = NULL;
   png_bytep row = NULL, display = NULL;

   if (png_ptr == NULL)
      return 0;

   if (setjmp(png_jmpbuf(png_ptr)))
   {
      png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
      if (row != NULL) free(row);
      if (display != NULL) free(display);
      return 0;
   }

   png_init_io(png_ptr, fp);

   info_ptr = png_create_info_struct(png_ptr);
   if (info_ptr == NULL)
      png_error(png_ptr, "OOM allocating info structure");

   png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, NULL, 0);

   png_read_info(png_ptr, info_ptr);

   {
      png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr);

      /* Failure to initialize these is harmless */
      row = malloc(rowbytes);
      display = malloc(rowbytes);

      if (row == NULL || display == NULL)
         png_error(png_ptr, "OOM allocating row buffers");

      {
         png_uint_32 height = png_get_image_height(png_ptr, info_ptr);
#        ifdef PNG_READ_INTERLACING_SUPPORTED
            int passes = png_set_interlace_handling(png_ptr);
#        else /* !READ_INTERLACING */
            int passes = png_get_interlace_type(png_ptr, info_ptr) ==
               PNG_INTERLACE_ADAM7 ? PNG_INTERLACE_ADAM7_PASSES : 1;
#        endif /* !READ_INTERLACING */
         int pass;

         png_start_read_image(png_ptr);

         for (pass = 0; pass < passes; ++pass)
         {
            png_uint_32 y = height;

#           ifndef PNG_READ_INTERLACING_SUPPORTED
               if (passes == PNG_INTERLACE_ADAM7_PASSES)
                  y = PNG_PASS_ROWS(y, pass);
#           endif /* READ_INTERLACING */

            /* NOTE: this trashes the row each time; interlace handling won't
             * work, but this avoids memory thrashing for speed testing.
             */
            while (y-- > 0)
               png_read_row(png_ptr, row, display);
         }
      }
   }

   /* Make sure to read to the end of the file: */
   png_read_end(png_ptr, info_ptr);
   png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
   free(row);
   free(display);
   return 1;
}
// Reads the header and initializes the output fields, if not NULL.
//
// @param stream Input data. Will be read to get enough information to properly
//      setup the codec.
// @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL.
//      If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is
//      expected to continue to own it for the lifetime of the png_ptr.
// @param outCodec Optional output variable.  If non-NULL, will be set to a new
//      SkPngCodec on success.
// @param png_ptrp Optional output variable. If non-NULL, will be set to a new
//      png_structp on success.
// @param info_ptrp Optional output variable. If non-NULL, will be set to a new
//      png_infop on success;
// @return true on success, in which case the caller is responsible for calling
//      png_destroy_read_struct(png_ptrp, info_ptrp).
//      If it returns false, the passed in fields (except stream) are unchanged.
static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, SkCodec** outCodec,
                        png_structp* png_ptrp, png_infop* info_ptrp) {
    // The image is known to be a PNG. Decode enough to know the SkImageInfo.
    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr,
                                                 sk_error_fn, sk_warning_fn);
    if (!png_ptr) {
        return false;
    }

    AutoCleanPng autoClean(png_ptr);

    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == nullptr) {
        return false;
    }

    autoClean.setInfoPtr(info_ptr);

    // FIXME: Could we use the return value of setjmp to specify the type of
    // error?
    if (setjmp(png_jmpbuf(png_ptr))) {
        return false;
    }

    png_set_read_fn(png_ptr, static_cast<void*>(stream), sk_read_fn);

#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
    // Hookup our chunkReader so we can see any user-chunks the caller may be interested in.
    // This needs to be installed before we read the png header.  Android may store ninepatch
    // chunks in the header.
    if (chunkReader) {
        png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
        png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_user_chunk);
    }
#endif

    // The call to png_read_info() gives us all of the information from the
    // PNG file before the first IDAT (image data chunk).
    png_read_info(png_ptr, info_ptr);
    png_uint_32 origWidth, origHeight;
    int bitDepth, encodedColorType;
    png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
                 &encodedColorType, nullptr, nullptr, nullptr);

    // Tell libpng to strip 16 bit/color files down to 8 bits/color.
    // TODO: Should we handle this in SkSwizzler?  Could this also benefit
    //       RAW decodes?
    if (bitDepth == 16) {
        SkASSERT(PNG_COLOR_TYPE_PALETTE != encodedColorType);
        png_set_strip_16(png_ptr);
    }

    // Now determine the default colorType and alphaType and set the required transforms.
    // Often, we depend on SkSwizzler to perform any transforms that we need.  However, we
    // still depend on libpng for many of the rare and PNG-specific cases.
    SkEncodedInfo::Color color;
    SkEncodedInfo::Alpha alpha;
    switch (encodedColorType) {
        case PNG_COLOR_TYPE_PALETTE:
            // Extract multiple pixels with bit depths of 1, 2, and 4 from a single
            // byte into separate bytes (useful for paletted and grayscale images).
            if (bitDepth < 8) {
                // TODO: Should we use SkSwizzler here?
                png_set_packing(png_ptr);
            }

            color = SkEncodedInfo::kPalette_Color;
            // Set the alpha depending on if a transparency chunk exists.
            alpha = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ?
                    SkEncodedInfo::kUnpremul_Alpha : SkEncodedInfo::kOpaque_Alpha;
            break;
        case PNG_COLOR_TYPE_RGB:
            if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
                // Convert to RGBA if transparency chunk exists.
                png_set_tRNS_to_alpha(png_ptr);
                color = SkEncodedInfo::kRGBA_Color;
                alpha = SkEncodedInfo::kBinary_Alpha;
            } else {
                color = SkEncodedInfo::kRGB_Color;
                alpha = SkEncodedInfo::kOpaque_Alpha;
            }
            break;
        case PNG_COLOR_TYPE_GRAY:
            // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel.
            if (bitDepth < 8) {
                // TODO: Should we use SkSwizzler here?
                png_set_expand_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);
                color = SkEncodedInfo::kGrayAlpha_Color;
                alpha = SkEncodedInfo::kBinary_Alpha;
            } else {
                color = SkEncodedInfo::kGray_Color;
                alpha = SkEncodedInfo::kOpaque_Alpha;
            }
            break;
        case PNG_COLOR_TYPE_GRAY_ALPHA:
            color = SkEncodedInfo::kGrayAlpha_Color;
            alpha = SkEncodedInfo::kUnpremul_Alpha;
            break;
        case PNG_COLOR_TYPE_RGBA:
            color = SkEncodedInfo::kRGBA_Color;
            alpha = SkEncodedInfo::kUnpremul_Alpha;
            break;
        default:
            // All the color types have been covered above.
            SkASSERT(false);
            color = SkEncodedInfo::kRGBA_Color;
            alpha = SkEncodedInfo::kUnpremul_Alpha;
    }

    int numberPasses = png_set_interlace_handling(png_ptr);

    autoClean.release();
    if (png_ptrp) {
        *png_ptrp = png_ptr;
    }
    if (info_ptrp) {
        *info_ptrp = info_ptr;
    }

    if (outCodec) {
        sk_sp<SkColorSpace> colorSpace = read_color_space(png_ptr, info_ptr);
        if (!colorSpace) {
            // Treat unmarked pngs as sRGB.
            colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
        }

        SkEncodedInfo info = SkEncodedInfo::Make(color, alpha, 8);

        if (1 == numberPasses) {
            *outCodec = new SkPngScanlineDecoder(origWidth, origHeight, info, stream,
                    chunkReader, png_ptr, info_ptr, bitDepth, colorSpace);
        } else {
            *outCodec = new SkPngInterlacedScanlineDecoder(origWidth, origHeight, info, stream,
                    chunkReader, png_ptr, info_ptr, bitDepth, numberPasses, colorSpace);
        }
    }

    return true;
}
Exemple #19
0
void
nsPNGDecoder::InitInternal()
{
    mCMSMode = gfxPlatform::GetCMSMode();
    if ((mDecodeFlags & DECODER_NO_COLORSPACE_CONVERSION) != 0)
        mCMSMode = eCMSMode_Off;
    mDisablePremultipliedAlpha = (mDecodeFlags & DECODER_NO_PREMULTIPLY_ALPHA) != 0;

#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
    static png_byte color_chunks[]=
    {   99,  72,  82,  77, '\0',   /* cHRM */
        105,  67,  67,  80, '\0'
    };  /* iCCP */
    static png_byte unused_chunks[]=
    {   98,  75,  71,  68, '\0',   /* bKGD */
        104,  73,  83,  84, '\0',   /* hIST */
        105,  84,  88, 116, '\0',   /* iTXt */
        111,  70,  70, 115, '\0',   /* oFFs */
        112,  67,  65,  76, '\0',   /* pCAL */
        115,  67,  65,  76, '\0',   /* sCAL */
        112,  72,  89, 115, '\0',   /* pHYs */
        115,  66,  73,  84, '\0',   /* sBIT */
        115,  80,  76,  84, '\0',   /* sPLT */
        116,  69,  88, 116, '\0',   /* tEXt */
        116,  73,  77,  69, '\0',   /* tIME */
        122,  84,  88, 116, '\0'
    };  /* zTXt */
#endif

    // For size decodes, we only need a small buffer
    if (IsSizeDecode()) {
        mHeaderBuf = (uint8_t *)moz_xmalloc(BYTES_NEEDED_FOR_DIMENSIONS);
        return;
    }

    /* For full decodes, do png init stuff */

    /* Initialize the container's source image header. */
    /* Always decode to 24 bit pixdepth */

    mPNG = png_create_read_struct(PNG_LIBPNG_VER_STRING,
                                  NULL, nsPNGDecoder::error_callback,
                                  nsPNGDecoder::warning_callback);
    if (!mPNG) {
        PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
        return;
    }

    mInfo = png_create_info_struct(mPNG);
    if (!mInfo) {
        PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
        png_destroy_read_struct(&mPNG, NULL, NULL);
        return;
    }

#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
    /* Ignore unused chunks */
    if (mCMSMode == eCMSMode_Off)
        png_set_keep_unknown_chunks(mPNG, 1, color_chunks, 2);

    png_set_keep_unknown_chunks(mPNG, 1, unused_chunks,
                                (int)sizeof(unused_chunks)/5);
#endif

#ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED
    if (mCMSMode != eCMSMode_Off)
        png_set_chunk_malloc_max(mPNG, 4000000L);
#endif

#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
#ifndef PR_LOGGING
    /* Disallow palette-index checking, for speed; we would ignore the warning
     * anyhow unless we have defined PR_LOGGING.  This feature was added at
     * libpng version 1.5.10 and is disabled in the embedded libpng but enabled
     * by default in the system libpng.  This call also disables it in the
     * system libpng, for decoding speed.  Bug #745202.
     */
    png_set_check_for_invalid_index(mPNG, 0);
#endif
#endif

    /* use this as libpng "progressive pointer" (retrieve in callbacks) */
    png_set_progressive_read_fn(mPNG, static_cast<png_voidp>(this),
                                nsPNGDecoder::info_callback,
                                nsPNGDecoder::row_callback,
                                nsPNGDecoder::end_callback);

}
Exemple #20
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;
}
bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
                                 SkBitmap::Config prefConfig, Mode mode) {
//    SkAutoTrace    apr("SkPNGImageDecoder::onDecode");

    /* Create and initialize the png_struct with the desired error handler
    * functions.  If you want to use the default stderr and longjump method,
    * you can supply NULL for the last three parameters.  We also supply the
    * the compiler header file version, so that we know if the application
    * was compiled with a compatible version of the library.  */
    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
        NULL, sk_error_fn, NULL);
    //   png_voidp user_error_ptr, user_error_fn, user_warning_fn);
    if (png_ptr == NULL) {
        return false;
    }

    /* Allocate/initialize the memory for image information. */
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) {
        png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
        return false;
    }

    PNGAutoClean autoClean(png_ptr, info_ptr);

    /* Set error handling if you are using the setjmp/longjmp method (this is
    * the normal method of doing things with libpng).  REQUIRED unless you
    * set up your own error handlers in the png_create_read_struct() earlier.
    */
    if (setjmp(png_jmpbuf(png_ptr))) {
        return false;
    }

    /* If you are using replacement read functions, instead of calling
    * png_init_io() here you would call:
    */
    png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn);
    /* where user_io_ptr is a structure you want available to the callbacks */
    /* If we have already read some of the signature */
//  png_set_sig_bytes(png_ptr, 0 /* sig_read */ );

    // hookup our peeker so we can see any user-chunks the caller may be interested in
    png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
    if (this->getPeeker()) {
        png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk);
    }

    /* The call to png_read_info() gives us all of the information from the
    * PNG file before the first IDAT (image data chunk). */
    png_read_info(png_ptr, info_ptr);
    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);

    SkBitmap::Config    config;
    bool                hasAlpha = false;
    bool                doDither = this->getDitherImage();
    
    // check for sBIT chunk data, in case we should disable dithering because
    // our data is not truely 8bits per component
    if (doDither) {
#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)) {
            doDither = false;
        }
    }
    
    if (color_type == PNG_COLOR_TYPE_PALETTE) {
        config = SkBitmap::kIndex8_Config;  // defer sniffing for hasAlpha
    } else {
        png_color_16p   transColor;
        
        png_get_tRNS(png_ptr, info_ptr, NULL, NULL, &transColor);
        
        if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ||
                PNG_COLOR_TYPE_RGB_ALPHA == color_type ||
                PNG_COLOR_TYPE_GRAY_ALPHA == color_type) {
            hasAlpha = true;
            config = SkBitmap::kARGB_8888_Config;
        } else {    // we get to choose the config
            config = prefConfig;
            if (config == SkBitmap::kNo_Config) {
                config = SkImageDecoder::GetDeviceConfig();
            }
            if (config != SkBitmap::kRGB_565_Config &&
                    config != SkBitmap::kARGB_4444_Config) {
                config = SkBitmap::kARGB_8888_Config;
            }
        }
    }
    
    if (!this->chooseFromOneChoice(config, origWidth, origHeight)) {
        return false;
    }
    
    const int sampleSize = this->getSampleSize();
    SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize);

    decodedBitmap->setConfig(config, sampler.scaledWidth(),
                             sampler.scaledHeight(), 0);
    if (SkImageDecoder::kDecodeBounds_Mode == mode) {
        return true;
    }
    
    // from here down we are concerned with colortables and pixels

    /* tell libpng to strip 16 bit/color files down to 8 bits/color */
    if (bit_depth == 16) {
        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). */
    if (bit_depth < 8) {
        png_set_packing(png_ptr);
    }
    /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
        png_set_gray_1_2_4_to_8(png_ptr);
    }

    /* Make a grayscale image into RGB. */
    if (color_type == PNG_COLOR_TYPE_GRAY ||
            color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
        png_set_gray_to_rgb(png_ptr);
    }

    // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype
    // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we
    // draw lots faster if we can flag the bitmap has being opaque
    bool reallyHasAlpha = false;

    SkColorTable* colorTable = NULL;

    if (color_type == PNG_COLOR_TYPE_PALETTE) {
        int num_palette;
        png_colorp palette;
        png_bytep trans;
        int num_trans;

        png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
        
        /*  BUGGY IMAGE WORKAROUND
            
            We hit some images (e.g. fruit_.png) who contain bytes that are == colortable_count
            which is a problem since we use the byte as an index. To work around this we grow
            the colortable by 1 (if its < 256) and duplicate the last color into that slot.
        */
        int colorCount = num_palette + (num_palette < 256);

        colorTable = SkNEW_ARGS(SkColorTable, (colorCount));

        SkPMColor* colorPtr = colorTable->lockColors();
        if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
            png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
            hasAlpha = (num_trans > 0);
        } else {
            num_trans = 0;
            colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOpaque_Flag);
        }        
        // check for bad images that might make us crash
        if (num_trans > num_palette) {
            num_trans = num_palette;
        }

        int index = 0;
        int transLessThanFF = 0;

        for (; index < num_trans; index++) {
            transLessThanFF |= (int)*trans - 0xFF;
            *colorPtr++ = SkPreMultiplyARGB(*trans++, palette->red, palette->green, palette->blue);
            palette++;
        }
        reallyHasAlpha |= (transLessThanFF < 0);

        for (; index < num_palette; index++) {
            *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue);
            palette++;
        }

        // see BUGGY IMAGE WORKAROUND comment above
        if (num_palette < 256) {
            *colorPtr = colorPtr[-1];
        }
        colorTable->unlockColors(true);
    }
    
    SkAutoUnref aur(colorTable);

    if (!this->allocPixelRef(decodedBitmap, colorTable)) {
        delete colorTable;
        return false;
    }
    
    SkAutoLockPixels alp(*decodedBitmap);

    /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
//  if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
//      ; // png_set_swap_alpha(png_ptr);

    /* swap bytes of 16 bit files to least significant byte first */
    //   png_set_swap(png_ptr);

    /* Add filler (or alpha) byte (before/after each RGB triplet) */
    if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) {
        png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
    }

    /* Turn on interlace handling.  REQUIRED if you are not using
    * png_read_image().  To see how to handle interlacing passes,
    * see the png_read_row() method below:
    */
    const int number_passes = interlace_type != PNG_INTERLACE_NONE ? 
                        png_set_interlace_handling(png_ptr) : 1;

    /* Optional call to gamma correct and add the background to the palette
    * and update info structure.  REQUIRED if you are expecting libpng to
    * update the palette for you (ie you selected such a transform above).
    */
    png_read_update_info(png_ptr, info_ptr);

    if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) {
        for (int i = 0; i < number_passes; i++) {
            for (png_uint_32 y = 0; y < origHeight; y++) {
                uint8_t* bmRow = decodedBitmap->getAddr8(0, y);
                png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
            }
        }
    } else {
        SkScaledBitmapSampler::SrcConfig sc;
        int srcBytesPerPixel = 4;
        
        if (SkBitmap::kIndex8_Config == config) {
            sc = SkScaledBitmapSampler::kIndex;
            srcBytesPerPixel = 1;
        } else if (hasAlpha) {
            sc = SkScaledBitmapSampler::kRGBA;
        } else {
            sc = SkScaledBitmapSampler::kRGBX;
        }

        SkAutoMalloc storage(origWidth * srcBytesPerPixel);
        const int height = decodedBitmap->height();

        for (int i = 0; i < number_passes; i++) {
            if (!sampler.begin(decodedBitmap, sc, doDither)) {
                return false;
            }

            uint8_t* srcRow = (uint8_t*)storage.get();
            skip_src_rows(png_ptr, srcRow, sampler.srcY0());

            for (int y = 0; y < height; y++) {
                uint8_t* tmp = srcRow;
                png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
                reallyHasAlpha |= sampler.next(srcRow);
                if (y < height - 1) {
                    skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1);
                }
            }
            
            // skip the rest of the rows (if any)
            png_uint_32 read = (height - 1) * sampler.srcDY() +
                               sampler.srcY0() + 1;
            SkASSERT(read <= origHeight);
            skip_src_rows(png_ptr, srcRow, origHeight - read);
        }

        if (hasAlpha && !reallyHasAlpha) {
            SkDEBUGF(("Image doesn't really have alpha [%d %d]\n",
                      origWidth, origHeight));
        }
    }

    /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
    png_read_end(png_ptr, info_ptr);

    decodedBitmap->setIsOpaque(!reallyHasAlpha);
    return true;
}
Exemple #22
0
int readpng2_init(mainprog_info *mainprog_ptr)
{
    png_structp  png_ptr;       /* note:  temporary variables! */
    png_infop  info_ptr;


    /* could also replace libpng warning-handler (final NULL), but no need: */

    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, mainprog_ptr,
      readpng2_error_handler, NULL);
    if (!png_ptr)
        return 4;   /* out of memory */

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return 4;   /* out of memory */
    }


    /* we could create a second info struct here (end_info), but it's only
     * useful if we want to keep pre- and post-IDAT chunk info separated
     * (mainly for PNG-aware image editors and converters) */


    /* setjmp() must be called in every function that calls a PNG-reading
     * libpng function, unless an alternate error handler was installed--
     * but compatible error handlers must either use longjmp() themselves
     * (as in this program) or exit immediately, so here we are: */

    if (setjmp(mainprog_ptr->jmpbuf)) {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        return 2;
    }


#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
    /* prepare the reader to ignore all recognized chunks whose data won't be
     * used, i.e., all chunks recognized by libpng except for IHDR, PLTE, IDAT,
     * IEND, tRNS, bKGD, gAMA, and sRGB (small performance improvement) */
    {
        /* These byte strings were copied from png.h.  If a future libpng
         * version recognizes more chunks, add them to this list.  If a
         * future version of readpng2.c recognizes more chunks, delete them
         * from this list. */
        static /* const */ png_byte chunks_to_ignore[] = {
             99,  72,  82,  77, '\0',  /* cHRM */
            104,  73,  83,  84, '\0',  /* hIST */
            105,  67,  67,  80, '\0',  /* iCCP */
            105,  84,  88, 116, '\0',  /* iTXt */
            111,  70,  70, 115, '\0',  /* oFFs */
            112,  67,  65,  76, '\0',  /* pCAL */
            112,  72,  89, 115, '\0',  /* pHYs */
            115,  66,  73,  84, '\0',  /* sBIT */
            115,  67,  65,  76, '\0',  /* sCAL */
            115,  80,  76,  84, '\0',  /* sPLT */
            115,  84,  69,  82, '\0',  /* sTER */
            116,  69,  88, 116, '\0',  /* tEXt */
            116,  73,  77,  69, '\0',  /* tIME */
            122,  84,  88, 116, '\0'   /* zTXt */
        };

        png_set_keep_unknown_chunks(png_ptr, 1 /* PNG_HANDLE_CHUNK_NEVER */,
          chunks_to_ignore, sizeof(chunks_to_ignore)/5);
    }
#endif /* PNG_HANDLE_AS_UNKNOWN_SUPPORTED */


    /* instead of doing png_init_io() here, now we set up our callback
     * functions for progressive decoding */

    png_set_progressive_read_fn(png_ptr, mainprog_ptr,
      readpng2_info_callback, readpng2_row_callback, readpng2_end_callback);


    /* make sure we save our pointers for use in readpng2_decode_data() */

    mainprog_ptr->png_ptr = png_ptr;
    mainprog_ptr->info_ptr = info_ptr;


    /* and that's all there is to initialization */

    return 0;
}
bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
                                 Mode mode) {
//    SkAutoTrace    apr("SkPNGImageDecoder::onDecode");

    /* Create and initialize the png_struct with the desired error handler
    * functions.  If you want to use the default stderr and longjump method,
    * you can supply NULL for the last three parameters.  We also supply the
    * the compiler header file version, so that we know if the application
    * was compiled with a compatible version of the library.  */
    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
        NULL, sk_error_fn, NULL);
    //   png_voidp user_error_ptr, user_error_fn, user_warning_fn);
    if (png_ptr == NULL) {
        return false;
    }

    /* Allocate/initialize the memory for image information. */
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) {
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return false;
    }

    PNGAutoClean autoClean(png_ptr, info_ptr);

    /* Set error handling if you are using the setjmp/longjmp method (this is
    * the normal method of doing things with libpng).  REQUIRED unless you
    * set up your own error handlers in the png_create_read_struct() earlier.
    */
    if (setjmp(png_jmpbuf(png_ptr))) {
        return false;
    }

    /* If you are using replacement read functions, instead of calling
    * png_init_io() here you would call:
    */
    png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn);
    /* where user_io_ptr is a structure you want available to the callbacks */
    /* If we have already read some of the signature */
//  png_set_sig_bytes(png_ptr, 0 /* sig_read */ );

    // hookup our peeker so we can see any user-chunks the caller may be interested in
    png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
    if (this->getPeeker()) {
        png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk);
    }

    /* The call to png_read_info() gives us all of the information from the
    * PNG file before the first IDAT (image data chunk). */
    png_read_info(png_ptr, info_ptr);
    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, NULL, NULL);

    /* tell libpng to strip 16 bit/color files down to 8 bits/color */
    if (bit_depth == 16) {
        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). */
    if (bit_depth < 8) {
        png_set_packing(png_ptr);
    }
    /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
        png_set_expand_gray_1_2_4_to_8(png_ptr);
    }
    
    /* Make a grayscale image into RGB. */
    if (color_type == PNG_COLOR_TYPE_GRAY ||
        color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
        png_set_gray_to_rgb(png_ptr);
    }
        
    SkBitmap::Config    config;
    bool                hasAlpha = false;
    bool                doDither = this->getDitherImage();
    SkPMColor           theTranspColor = 0; // 0 tells us not to try to match
    
    // check for sBIT chunk data, in case we should disable dithering because
    // our data is not truely 8bits per component
    if (doDither) {
        png_color_8p sig_bit = NULL;
        bool has_sbit = PNG_INFO_sBIT == png_get_sBIT(png_ptr, info_ptr,
                                                      &sig_bit);
#if 0
        if (has_sbit) {
            SkDebugf("----- sBIT %d %d %d %d\n", sig_bit->red, sig_bit->green,
                     sig_bit->blue, sig_bit->alpha);
        }
#endif
        // 0 seems to indicate no information available
        if (has_sbit && pos_le(sig_bit->red, SK_R16_BITS) &&
                pos_le(sig_bit->green, SK_G16_BITS) &&
                pos_le(sig_bit->blue, SK_B16_BITS)) {
            doDither = false;
        }
    }
    
    if (color_type == PNG_COLOR_TYPE_PALETTE) {
        bool paletteHasAlpha = hasTransparencyInPalette(png_ptr, info_ptr);
        config = this->getPrefConfig(kIndex_SrcDepth, paletteHasAlpha);
        // now see if we can upscale to their requested config
        if (!canUpscalePaletteToConfig(config, paletteHasAlpha)) {
            config = 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) {
                    theTranspColor = SkPackARGB32(0xFF, transpColor->red >> 8,
                              transpColor->green >> 8, transpColor->blue >> 8);
                } else {
                    theTranspColor = SkPackARGB32(0xFF, transpColor->red,
                                      transpColor->green, transpColor->blue);
                }
            } else {    // gray
                if (16 == bit_depth) {
Exemple #24
0
/* Test one file */
int
test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
{
   static png_FILE_p fpin;
   static png_FILE_p fpout;  /* "static" prevents setjmp corruption */
   png_structp read_ptr;
   png_infop read_info_ptr, end_info_ptr;
#ifdef PNG_WRITE_SUPPORTED
   png_structp write_ptr;
   png_infop write_info_ptr;
   png_infop write_end_info_ptr;
#else
   png_structp write_ptr = NULL;
   png_infop write_info_ptr = NULL;
   png_infop write_end_info_ptr = NULL;
#endif
   png_bytep row_buf;
   png_uint_32 y;
   png_uint_32 width, height;
   int num_pass, pass;
   int bit_depth, color_type;
#ifdef PNG_SETJMP_SUPPORTED
#ifdef USE_FAR_KEYWORD
   jmp_buf jmpbuf;
#endif
#endif

#if defined(_WIN32_WCE)
   TCHAR path[MAX_PATH];
#endif
   char inbuf[256], outbuf[256];

   row_buf = NULL;

#if defined(_WIN32_WCE)
   MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH);
   if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
#else
   if ((fpin = fopen(inname, "rb")) == NULL)
#endif
   {
      fprintf(STDERR, "Could not find input file %s\n", inname);
      return (1);
   }

#if defined(_WIN32_WCE)
   MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH);
   if ((fpout = CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL)) == INVALID_HANDLE_VALUE)
#else
   if ((fpout = fopen(outname, "wb")) == NULL)
#endif
   {
      fprintf(STDERR, "Could not open output file %s\n", outname);
      FCLOSE(fpin);
      return (1);
   }

   png_debug(0, "Allocating read and write structures\n");
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
   read_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
      png_error_ptr_NULL, png_error_ptr_NULL, png_voidp_NULL,
      (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free);
#else
   read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
      png_error_ptr_NULL, png_error_ptr_NULL);
#endif
#if defined(PNG_NO_STDIO)
   png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error,
       pngtest_warning);
#endif
#ifdef PNG_WRITE_SUPPORTED
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
   write_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
      png_error_ptr_NULL, png_error_ptr_NULL, png_voidp_NULL,
      (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free);
#else
   write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
      png_error_ptr_NULL, png_error_ptr_NULL);
#endif
#if defined(PNG_NO_STDIO)
   png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error,
       pngtest_warning);
#endif
#endif
   png_debug(0, "Allocating read_info, write_info and end_info structures\n");
   read_info_ptr = png_create_info_struct(read_ptr);
   end_info_ptr = png_create_info_struct(read_ptr);
#ifdef PNG_WRITE_SUPPORTED
   write_info_ptr = png_create_info_struct(write_ptr);
   write_end_info_ptr = png_create_info_struct(write_ptr);
#endif

#ifdef PNG_SETJMP_SUPPORTED
   png_debug(0, "Setting jmpbuf for read struct\n");
#ifdef USE_FAR_KEYWORD
   if (setjmp(jmpbuf))
#else
   if (setjmp(png_jmpbuf(read_ptr)))
#endif
   {
      fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
      if (row_buf)
         png_free(read_ptr, row_buf);
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
#ifdef PNG_WRITE_SUPPORTED
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
#endif
      FCLOSE(fpin);
      FCLOSE(fpout);
      return (1);
   }
#ifdef USE_FAR_KEYWORD
   png_memcpy(png_jmpbuf(read_ptr),jmpbuf,png_sizeof(jmp_buf));
#endif

#ifdef PNG_WRITE_SUPPORTED
   png_debug(0, "Setting jmpbuf for write struct\n");
#ifdef USE_FAR_KEYWORD
   if (setjmp(jmpbuf))
#else
   if (setjmp(png_jmpbuf(write_ptr)))
#endif
   {
      fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
#ifdef PNG_WRITE_SUPPORTED
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
#endif
      FCLOSE(fpin);
      FCLOSE(fpout);
      return (1);
   }
#ifdef USE_FAR_KEYWORD
   png_memcpy(png_jmpbuf(write_ptr),jmpbuf,png_sizeof(jmp_buf));
#endif
#endif
#endif

   png_debug(0, "Initializing input and output streams\n");
#if !defined(PNG_NO_STDIO)
   png_init_io(read_ptr, fpin);
#  ifdef PNG_WRITE_SUPPORTED
   png_init_io(write_ptr, fpout);
#  endif
#else
   png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data);
#  ifdef PNG_WRITE_SUPPORTED
   png_set_write_fn(write_ptr, (png_voidp)fpout,  pngtest_write_data,
#    if defined(PNG_WRITE_FLUSH_SUPPORTED)
      pngtest_flush);
#    else
      NULL);
#    endif
#  endif
#endif
   if(status_dots_requested == 1)
   {
#ifdef PNG_WRITE_SUPPORTED
      png_set_write_status_fn(write_ptr, write_row_callback);
#endif
      png_set_read_status_fn(read_ptr, read_row_callback);
   }
   else
   {
#ifdef PNG_WRITE_SUPPORTED
      png_set_write_status_fn(write_ptr, png_write_status_ptr_NULL);
#endif
      png_set_read_status_fn(read_ptr, png_read_status_ptr_NULL);
   }

#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
   {
     int i;
     for(i=0; i<256; i++)
        filters_used[i]=0;
     png_set_read_user_transform_fn(read_ptr, count_filters);
   }
#endif
#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
   zero_samples=0;
   png_set_write_user_transform_fn(write_ptr, count_zero_samples);
#endif

#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
#  ifndef PNG_HANDLE_CHUNK_ALWAYS
#    define PNG_HANDLE_CHUNK_ALWAYS       3
#  endif
   png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS,
      png_bytep_NULL, 0);
#endif
#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
#  ifndef PNG_HANDLE_CHUNK_IF_SAFE
#    define PNG_HANDLE_CHUNK_IF_SAFE      2
#  endif
   png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_IF_SAFE,
      png_bytep_NULL, 0);
#endif

   png_debug(0, "Reading info struct\n");
   png_read_info(read_ptr, read_info_ptr);

   png_debug(0, "Transferring info struct\n");
   {
      int interlace_type, compression_type, filter_type;

      if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth,
          &color_type, &interlace_type, &compression_type, &filter_type))
      {
         png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth,
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
            color_type, interlace_type, compression_type, filter_type);
#else
            color_type, PNG_INTERLACE_NONE, compression_type, filter_type);
#endif
      }
   }
Exemple #25
0
int readpng2_init(mainprog_info *mainprog_ptr)
{
    png_structp  png_ptr;       /* note:  temporary variables! */
    png_infop  info_ptr;


    /* could also replace libpng warning-handler (final NULL), but no need: */

    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, mainprog_ptr,
      readpng2_error_handler, NULL);
    if (!png_ptr)
        return 4;   /* out of memory */

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return 4;   /* out of memory */
    }


    /* we could create a second info struct here (end_info), but it's only
     * useful if we want to keep pre- and post-IDAT chunk info separated
     * (mainly for PNG-aware image editors and converters) */


    /* setjmp() must be called in every function that calls a PNG-reading
     * libpng function, unless an alternate error handler was installed--
     * but compatible error handlers must either use longjmp() themselves
     * (as in this program) or exit immediately, so here we are: */

    if (setjmp(mainprog_ptr->jmpbuf)) {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        return 2;
    }


#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
    /* prepare the reader to ignore all recognized chunks whose data won't be
     * used, i.e., all chunks recognized by libpng except for IHDR, PLTE, IDAT,
     * IEND, tRNS, bKGD, gAMA, and sRGB (small performance improvement) */
    {
        /* These byte strings were copied from png.h.  If a future libpng
         * version recognizes more chunks, add them to this list.  If a
         * future version of readpng2.c recognizes more chunks, delete them
         * from this list. */
        static const png_byte chunks_to_ignore[] = {
             99,  72,  82,  77, '\0',  /* cHRM */
            104,  73,  83,  84, '\0',  /* hIST */
            105,  67,  67,  80, '\0',  /* iCCP */
            105,  84,  88, 116, '\0',  /* iTXt */
            111,  70,  70, 115, '\0',  /* oFFs */
            112,  67,  65,  76, '\0',  /* pCAL */
            112,  72,  89, 115, '\0',  /* pHYs */
            115,  66,  73,  84, '\0',  /* sBIT */
            115,  67,  65,  76, '\0',  /* sCAL */
            115,  80,  76,  84, '\0',  /* sPLT */
            115,  84,  69,  82, '\0',  /* sTER */
            116,  69,  88, 116, '\0',  /* tEXt */
            116,  73,  77,  69, '\0',  /* tIME */
            122,  84,  88, 116, '\0'   /* zTXt */
        };

        png_set_keep_unknown_chunks(png_ptr, 1 /* PNG_HANDLE_CHUNK_NEVER */,
          chunks_to_ignore, sizeof(chunks_to_ignore)/5);
    }
#endif /* PNG_UNKNOWN_CHUNKS_SUPPORTED */


    /* instead of doing png_init_io() here, now we set up our callback
     * functions for progressive decoding */

    png_set_progressive_read_fn(png_ptr, mainprog_ptr,
      readpng2_info_callback, readpng2_row_callback, readpng2_end_callback);


    /*
     * may as well enable or disable MMX routines here, if supported;
     *
     * to enable all:  mask = png_get_mmx_flagmask (
     *                   PNG_SELECT_READ | PNG_SELECT_WRITE, &compilerID);
     *                 flags = png_get_asm_flags (png_ptr);
     *                 flags |= mask;
     *                 png_set_asm_flags (png_ptr, flags);
     *
     * to disable all:  mask = png_get_mmx_flagmask (
     *                   PNG_SELECT_READ | PNG_SELECT_WRITE, &compilerID);
     *                  flags = png_get_asm_flags (png_ptr);
     *                  flags &= ~mask;
     *                  png_set_asm_flags (png_ptr, flags);
     */

#if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__)) && \
    defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
    /*
     * WARNING:  This preprocessor approach means that the following code
     *           cannot be used with a libpng DLL older than 1.2.0--the
     *           compiled-in symbols for the new functions will not exist.
     *           (Could use dlopen() and dlsym() on Unix and corresponding
     *           calls for Windows, but not portable...)
     */
    {
#ifdef PNG_ASSEMBLER_CODE_SUPPORTED
        png_uint_32 mmx_disable_mask = 0;
        png_uint_32 asm_flags, mmx_mask;
        int compilerID;

        if (mainprog_ptr->nommxfilters)
            mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_FILTER_SUB   \
                                | PNG_ASM_FLAG_MMX_READ_FILTER_UP    \
                                | PNG_ASM_FLAG_MMX_READ_FILTER_AVG   \
                                | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
        if (mainprog_ptr->nommxcombine)
            mmx_disable_mask |= PNG_ASM_FLAG_MMX_READ_COMBINE_ROW;
        if (mainprog_ptr->nommxinterlace)
            mmx_disable_mask |= PNG_ASM_FLAG_MMX_READ_INTERLACE;
        asm_flags = png_get_asm_flags(png_ptr);
        png_set_asm_flags(png_ptr, asm_flags & ~mmx_disable_mask);


        /* Now query libpng's asm settings, just for yuks.  Note that this
         * differs from the querying of its *potential* MMX capabilities
         * in readpng2_version_info(); this is true runtime verification. */

        asm_flags = png_get_asm_flags(png_ptr);
        mmx_mask = png_get_mmx_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE,
          &compilerID);
        if (asm_flags & PNG_ASM_FLAG_MMX_SUPPORT_COMPILED)
            fprintf(stderr,
              "  MMX support (%s version) is compiled into libpng\n",
              compilerID == 1? "MSVC++" :
              (compilerID == 2? "GNU C" : "unknown"));
        else
            fprintf(stderr, "  MMX support is not compiled into libpng\n");
        fprintf(stderr, "  MMX instructions are %ssupported by CPU\n",
          (asm_flags & PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU)? "" : "not ");
        fprintf(stderr, "  MMX read support for combining rows is %sabled\n",
          (asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)? "en" : "dis");
        fprintf(stderr,
          "  MMX read support for expanding interlacing is %sabled\n",
          (asm_flags & PNG_ASM_FLAG_MMX_READ_INTERLACE)? "en" : "dis");
        fprintf(stderr, "  MMX read support for \"sub\" filter is %sabled\n",
          (asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB)? "en" : "dis");
        fprintf(stderr, "  MMX read support for \"up\" filter is %sabled\n",
          (asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_UP)? "en" : "dis");
        fprintf(stderr, "  MMX read support for \"avg\" filter is %sabled\n",
          (asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_AVG)? "en" : "dis");
        fprintf(stderr, "  MMX read support for \"Paeth\" filter is %sabled\n",
          (asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH)? "en" : "dis");
        asm_flags &= (mmx_mask & ~( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW  \
                                  | PNG_ASM_FLAG_MMX_READ_INTERLACE    \
                                  | PNG_ASM_FLAG_MMX_READ_FILTER_SUB   \
                                  | PNG_ASM_FLAG_MMX_READ_FILTER_UP    \
                                  | PNG_ASM_FLAG_MMX_READ_FILTER_AVG   \
                                  | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ));
        if (asm_flags)
            fprintf(stderr,
              "  additional MMX support is also enabled (0x%02lx)\n",
              asm_flags);
#else  /* !PNG_ASSEMBLER_CODE_SUPPORTED */
        fprintf(stderr, "  MMX querying is disabled in libpng.\n");
#endif /* ?PNG_ASSEMBLER_CODE_SUPPORTED */
    }
#endif


    /* make sure we save our pointers for use in readpng2_decode_data() */

    mainprog_ptr->png_ptr = png_ptr;
    mainprog_ptr->info_ptr = info_ptr;


    /* and that's all there is to initialization */

    return 0;
}
Exemple #26
0
DEF_TEST(Codec_pngChunkReader, r) {
    // Create a dummy bitmap. Use unpremul RGBA for libpng.
    SkBitmap bm;
    const int w = 1;
    const int h = 1;
    const SkImageInfo bmInfo = SkImageInfo::Make(w, h, kRGBA_8888_SkColorType,
                                                 kUnpremul_SkAlphaType);
    bm.setInfo(bmInfo);
    bm.allocPixels();
    bm.eraseColor(SK_ColorBLUE);
    SkMD5::Digest goodDigest;
    md5(bm, &goodDigest);

    // Write to a png file.
    png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
    REPORTER_ASSERT(r, png);
    if (!png) {
        return;
    }

    png_infop info = png_create_info_struct(png);
    REPORTER_ASSERT(r, info);
    if (!info) {
        png_destroy_write_struct(&png, nullptr);
        return;
    }

    if (setjmp(png_jmpbuf(png))) {
        ERRORF(r, "failed writing png");
        png_destroy_write_struct(&png, &info);
        return;
    }

    SkDynamicMemoryWStream wStream;
    png_set_write_fn(png, (void*) (&wStream), codex_test_write_fn, nullptr);

    png_set_IHDR(png, info, (png_uint_32)w, (png_uint_32)h, 8,
                 PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
                 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

    // Create some chunks that match the Android framework's use.
    static png_unknown_chunk gUnknowns[] = {
        { "npOl", (png_byte*)"outline", sizeof("outline"), PNG_HAVE_IHDR },
        { "npLb", (png_byte*)"layoutBounds", sizeof("layoutBounds"), PNG_HAVE_IHDR },
        { "npTc", (png_byte*)"ninePatchData", sizeof("ninePatchData"), PNG_HAVE_IHDR },
    };

    png_set_keep_unknown_chunks(png, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"npOl\0npLb\0npTc\0", 3);
    png_set_unknown_chunks(png, info, gUnknowns, SK_ARRAY_COUNT(gUnknowns));
#if PNG_LIBPNG_VER < 10600
    /* Deal with unknown chunk location bug in 1.5.x and earlier */
    png_set_unknown_chunk_location(png, info, 0, PNG_HAVE_IHDR);
    png_set_unknown_chunk_location(png, info, 1, PNG_HAVE_IHDR);
#endif

    png_write_info(png, info);

    for (int j = 0; j < h; j++) {
        png_bytep row = (png_bytep)(bm.getAddr(0, j));
        png_write_rows(png, &row, 1);
    }
    png_write_end(png, info);
    png_destroy_write_struct(&png, &info);

    class ChunkReader : public SkPngChunkReader {
    public:
        ChunkReader(skiatest::Reporter* r)
            : fReporter(r)
        {
            this->reset();
        }

        bool readChunk(const char tag[], const void* data, size_t length) override {
            for (size_t i = 0; i < SK_ARRAY_COUNT(gUnknowns); ++i) {
                if (!strcmp(tag, (const char*) gUnknowns[i].name)) {
                    // Tag matches. This should have been the first time we see it.
                    REPORTER_ASSERT(fReporter, !fSeen[i]);
                    fSeen[i] = true;

                    // Data and length should match
                    REPORTER_ASSERT(fReporter, length == gUnknowns[i].size);
                    REPORTER_ASSERT(fReporter, !strcmp((const char*) data,
                                                       (const char*) gUnknowns[i].data));
                    return true;
                }
            }
            ERRORF(fReporter, "Saw an unexpected unknown chunk.");
            return true;
        }

        bool allHaveBeenSeen() {
            bool ret = true;
            for (auto seen : fSeen) {
                ret &= seen;
            }
            return ret;
        }

        void reset() {
            sk_bzero(fSeen, sizeof(fSeen));
        }

    private:
        skiatest::Reporter* fReporter;  // Unowned
        bool fSeen[3];
    };

    ChunkReader chunkReader(r);

    // Now read the file with SkCodec.
    SkAutoTUnref<SkData> data(wStream.copyToData());
    SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(data, &chunkReader));
    REPORTER_ASSERT(r, codec);
    if (!codec) {
        return;
    }

    // Now compare to the original.
    SkBitmap decodedBm;
    decodedBm.setInfo(codec->getInfo());
    decodedBm.allocPixels();
    SkCodec::Result result = codec->getPixels(codec->getInfo(), decodedBm.getPixels(),
                                              decodedBm.rowBytes());
    REPORTER_ASSERT(r, SkCodec::kSuccess == result);

    if (decodedBm.colorType() != bm.colorType()) {
        SkBitmap tmp;
        bool success = decodedBm.copyTo(&tmp, bm.colorType());
        REPORTER_ASSERT(r, success);
        if (!success) {
            return;
        }

        tmp.swap(decodedBm);
    }

    compare_to_good_digest(r, goodDigest, decodedBm);
    REPORTER_ASSERT(r, chunkReader.allHaveBeenSeen());

    // Decoding again will read the chunks again.
    chunkReader.reset();
    REPORTER_ASSERT(r, !chunkReader.allHaveBeenSeen());
    result = codec->getPixels(codec->getInfo(), decodedBm.getPixels(), decodedBm.rowBytes());
    REPORTER_ASSERT(r, SkCodec::kSuccess == result);
    REPORTER_ASSERT(r, chunkReader.allHaveBeenSeen());
}
Exemple #27
0
static uint8_t png_read( png_structp readPtr, png_image * image, uint32_t flags )
{
//	png_set_error_fn( readPtr, NULL, png_user_error, NULL );

	png_infop infoPtr = png_create_info_struct( readPtr );
	if (!infoPtr) 
	{
		pngio_error( "Couldn't initialize PNG info struct." );
		png_destroy_read_struct( & readPtr, NULL, NULL );
		return 0;
	}
	
	if (setjmp( png_jmpbuf( readPtr ) ))
	{
		pngio_error( "An error occured while reading the PNG file." );
		png_destroy_read_struct( & readPtr, & infoPtr, NULL );
		png_image_free( image );
		return 0;
	}

	png_set_sig_bytes( readPtr, 8 );
	
	#ifdef PNG_APPLE_MODE_SUPPORTED 
	if (png_get_apple_mode())
	{
		png_set_keep_unknown_chunks( readPtr, PNG_HANDLE_CHUNK_ALWAYS, NULL, 0 );
		png_set_read_user_chunk_fn( readPtr, NULL, png_read_user_chunk );
	}
	#endif
	
	png_read_info( readPtr, infoPtr );
	
	png_uint_32 w = png_get_image_width( readPtr, infoPtr );
	png_uint_32 h = png_get_image_height( readPtr, infoPtr );
	png_uint_32 bitDepth = png_get_bit_depth( readPtr, infoPtr );
	png_uint_32 channels = png_get_channels( readPtr, infoPtr );
	png_uint_32 interlaceType = png_get_interlace_type( readPtr, infoPtr );
	png_uint_32 colorType = png_get_color_type( readPtr, infoPtr );
	
	switch (colorType) 
	{
		case PNG_COLOR_TYPE_PALETTE:
			png_set_palette_to_rgb( readPtr );
			channels = 3;           
			break;
		case PNG_COLOR_TYPE_GRAY:
			if (bitDepth < 8)
			{
				png_set_expand_gray_1_2_4_to_8( readPtr );
				bitDepth = 8;
			}
			png_set_gray_to_rgb( readPtr );
			break;
	}
	
	if (png_get_valid( readPtr, infoPtr, PNG_INFO_tRNS )) 
	{
		png_set_tRNS_to_alpha( readPtr );
		channels += 1;
	}
	else if (!(colorType & PNG_COLOR_MASK_ALPHA)) 
	{
		png_set_add_alpha( readPtr, 0xff, PNG_FILLER_AFTER );
	}
	
	if (bitDepth == 16)
	{
		png_set_strip_16( readPtr );
	}

	#ifdef PNG_APPLE_MODE_SUPPORTED
	if (png_get_apple_mode())
	{
		if (flags & PNG_IMAGE_PREMULTIPLY_ALPHA)
		{
			png_set_read_user_transform_fn( readPtr, png_read_swap_transform );
		}
		else
		{
			png_set_read_user_transform_fn( readPtr, png_read_swap_and_unpremultiply_transform );
		}
		png_set_user_transform_info( readPtr, NULL, bitDepth, channels );
		png_read_update_info( readPtr, infoPtr );
	}
	else
	#endif
	{
		if (flags & PNG_IMAGE_PREMULTIPLY_ALPHA)
		{
			png_set_read_user_transform_fn( readPtr, png_read_premultiply_transform );
		}
	}

	png_image_alloc( image, w, h );
	png_bytep p = image->data;
	
	const size_t passCount = interlaceType == PNG_INTERLACE_NONE ? 1 : png_set_interlace_handling( readPtr );
	const size_t bytesPerRow = w * 4;
	if (flags & PNG_IMAGE_FLIP_VERTICAL)
	{
		for (size_t pass = 0; pass < passCount; pass++)
		{
			for (size_t i = 0; i < h; i++) 
			{
				png_read_row( readPtr, p + (bytesPerRow * (h - i - 1)), NULL );
			}
		}
	}
	else
	{
//		png_bytep rp[h];
//		for (size_t i = 0; i < h; i++) 
//		{
//			rp[i] = p + (bytesPerRow * i);
//		}
//		png_read_image( readPtr, rp );
		for (size_t pass = 0; pass < passCount; pass++)
		{
			for (size_t i = 0; i < h; i++) 
			{
				png_read_row( readPtr, p + (bytesPerRow * i), NULL );
			}
		}
	}
	
	png_destroy_read_struct( & readPtr, & infoPtr, NULL );
	
	return 1;
}