示例#1
0
	void init()
	{
		char buf[PNG_BYTES_TO_CHECK];

		// read in some of the signature bytes
		io_error_if( fread( buf, 1, PNG_BYTES_TO_CHECK, get() ) != detail::PNG_BYTES_TO_CHECK,
			     "png_check_validity: fail to read file" );
		// compare the first PNG_BYTES_TO_CHECK bytes of the signature.
		io_error_if( png_sig_cmp( (png_bytep)buf, (png_size_t)0, detail::PNG_BYTES_TO_CHECK ) != 0,
			     "png_check_validity: invalid png file" );

		_png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
		io_error_if( _png_ptr == NULL, "png_get_file_size: fail to call png_create_write_struct()" );
		// allocate/initialize the image information data
		_info_ptr = png_create_info_struct( _png_ptr );
		if( _info_ptr == NULL )
		{
			png_destroy_read_struct( &_png_ptr, png_infopp_NULL, png_infopp_NULL );
			io_error( "png_get_file_size: fail to call png_create_info_struct()" );
		}
		if( setjmp( png_jmpbuf( _png_ptr ) ) )
		{
			//free all of the memory associated with the png_ptr and info_ptr
			png_destroy_read_struct( &_png_ptr, &_info_ptr, png_infopp_NULL );
			io_error( "png_get_file_size: fail to call setjmp()" );
		}
		png_init_io( _png_ptr, get() );
		png_set_sig_bytes( _png_ptr, PNG_BYTES_TO_CHECK );
		png_read_info( _png_ptr, _info_ptr );
		if( little_endian() && png_get_bit_depth( _png_ptr, _info_ptr ) > 8 )
			png_set_swap( _png_ptr );
	}
errort	WritePNG( FILE * fp , unsigned char * data, unsigned int sizeX, unsigned int sizeY, int img_depth, int img_alpha)
{
  png_structp png_ptr = png_create_write_struct
    (PNG_LIBPNG_VER_STRING, (png_voidp)NULL,NULL,NULL);
  if (!png_ptr)
    return BadFormat;
  
  png_infop info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr) {
    png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
    return BadFormat;
  }
  if (setjmp(png_ptr->jmpbuf)) {
    png_destroy_write_struct(&png_ptr, &info_ptr);
    return BadFormat;
  }

  png_init_io(png_ptr, fp);

  png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
  png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);

  /* set other zlib parameters */
  png_set_compression_mem_level(png_ptr, 8);
  png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
  png_set_compression_window_bits(png_ptr, 15);
  png_set_compression_method(png_ptr, 8);
  
  png_set_IHDR(png_ptr, 
	       info_ptr, 
	       sizeX,
	       sizeY,
	       img_depth, 
	       img_alpha?PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB, 
	       PNG_INTERLACE_NONE,
	       PNG_COMPRESSION_TYPE_DEFAULT, 
	       PNG_FILTER_TYPE_DEFAULT);
  
  png_write_info(png_ptr, info_ptr);
# if __BYTE_ORDER != __BIG_ENDIAN  
  if (img_depth==16) {
    png_set_swap(png_ptr);
  }
#endif
  int stride = (img_depth/8)*(img_alpha?4:3);
  png_byte **row_pointers = new png_byte*[sizeY];
  for (unsigned int i=0;i<sizeY;i++) {
    row_pointers[i]= (png_byte *)&data[stride*i*sizeX];
  }
  png_write_image (png_ptr,row_pointers);
  png_write_end(png_ptr, info_ptr);
  png_write_flush(png_ptr);
  png_destroy_write_struct(&png_ptr, &info_ptr);

  //free (data);
  delete [] row_pointers;
  return Ok;
}
示例#3
0
// part of this being separated allows for us to play nicely with the setjmp of libpng
bool ImageSourcePng::loadHeader()
{
	bool success = true;

	if( setjmp( png_jmpbuf(mPngPtr) ) ) {
		success = false;
	}
	else {
		png_read_info( mPngPtr, mInfoPtr );

		png_uint_32 width, height;
		int bitDepth, colorType, interlaceType, compressionType, filterMethod;

		if( ! png_get_IHDR( mPngPtr, mInfoPtr, &width, &height, &bitDepth, &colorType, &interlaceType, &compressionType, &filterMethod ) ) {
			png_destroy_read_struct( &mPngPtr, &mInfoPtr, (png_infopp)NULL );
			mPngPtr = 0;
			return false;
		}

		setSize( width, height );
		setDataType( ( bitDepth == 16 ) ? ImageIo::UINT16 : ImageIo::UINT8 );
		
	#ifdef CINDER_LITTLE_ENDIAN
		png_set_swap( mPngPtr );
	#endif

		switch( colorType ) {
			case PNG_COLOR_TYPE_GRAY:
				setColorModel( ImageIo::CM_GRAY );
				setChannelOrder( ImageIo::Y );			
			break;
			case PNG_COLOR_TYPE_GRAY_ALPHA:
				setColorModel( ImageIo::CM_GRAY );
				setChannelOrder( ImageIo::YA );
			break;
			case PNG_COLOR_TYPE_RGB:
			case PNG_COLOR_TYPE_PALETTE:
				setColorModel( ImageIo::CM_RGB );
				setChannelOrder( ImageIo::RGB );
			break;
			case PNG_COLOR_TYPE_RGB_ALPHA:
				setColorModel( ImageIo::CM_RGB );
				setChannelOrder( ImageIo::RGBA );
			break;
			default:
				throw ImageSourcePngException( "Unexpected png color type." );
		}	

		png_set_expand_gray_1_2_4_to_8( mPngPtr );
		png_set_palette_to_rgb( mPngPtr );
		png_set_tRNS_to_alpha( mPngPtr );
		
		png_read_update_info( mPngPtr, mInfoPtr );
	}
	
	return success;
}
void png_write( const char *myfile, unsigned char *data, unsigned int width, unsigned int height, bool alpha, char bpp )
{
    FILE *fp = VSFileSystem::vs_open( myfile, "wb" );
    png_structp png_ptr = png_create_write_struct
                              ( PNG_LIBPNG_VER_STRING, (png_voidp) NULL, NULL, NULL );
    if (!png_ptr)
        return;
    png_infop info_ptr = png_create_info_struct( png_ptr );
    if (!info_ptr) {
        png_destroy_write_struct( &png_ptr, (png_infopp) NULL );
        return;
    }
    if ( setjmp( png_ptr->jmpbuf ) ) {
        png_destroy_write_struct( &png_ptr, &info_ptr );
        VSFileSystem::vs_close( fp );
        return;
    }
    png_init_io( png_ptr, fp );
    png_set_filter( png_ptr, 0, PNG_FILTER_NONE );
    png_set_compression_level( png_ptr, Z_BEST_COMPRESSION );

    /* set other zlib parameters */
    png_set_compression_mem_level( png_ptr, 8 );
    png_set_compression_strategy( png_ptr, Z_DEFAULT_STRATEGY );
    png_set_compression_window_bits( png_ptr, 15 );
    png_set_compression_method( png_ptr, 8 );

    png_set_IHDR( png_ptr,
                  info_ptr,
                  width,
                  height,
                  bpp,
                  alpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB,
                  PNG_INTERLACE_NONE,
                  PNG_COMPRESSION_TYPE_DEFAULT,
                  PNG_FILTER_TYPE_DEFAULT );

    png_write_info( png_ptr, info_ptr );
# if __BYTE_ORDER != __BIG_ENDIAN
    if (bpp == 16)
        png_set_swap( png_ptr );
#endif
    int stride = (bpp/8)*(alpha ? 4 : 3);
    png_byte **row_pointers = new png_byte*[height];
    for (unsigned int i = 0; i < height; i++)
        row_pointers[i] = (png_byte*) &data[stride*i*width];
    png_write_image( png_ptr, row_pointers );
    png_write_end( png_ptr, info_ptr );
    png_write_flush( png_ptr );
    png_destroy_write_struct( &png_ptr, &info_ptr );

    VSFileSystem::vs_close( fp );
    free( data );
    delete[] row_pointers;
}
示例#5
0
文件: qImage.hpp 项目: qiangd6/QTK
			///
			/// LDR I/O, only available to LDR images
			void SavePng(const std::string& file_name)
			{
				BOOST_STATIC_ASSERT( (boost::is_same<T, UCHAR>::value) );
				BOOST_STATIC_ASSERT( channel == 3 );

				size_t pos = file_name.find_last_of(".");
				std::string file_type = file_name.substr(++pos, std::string::npos);
				boost::to_lower(file_type);
				assert(file_type == "png");

				FILE* fp;
				if((fp = fopen(file_name.c_str(), "wb")) == NULL)
					assert(0);

				png_structp _png_ptr;
				png_infop _info_ptr;
			    
				_png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
				if(!_png_ptr)
					assert(0);

				_info_ptr = png_create_info_struct(_png_ptr);
				if (!_info_ptr) 
				{
					png_destroy_write_struct(&_png_ptr, png_infopp_NULL);
					assert(0);
				}

				if (setjmp(png_jmpbuf(_png_ptr))) 
				{
					png_destroy_write_struct(&_png_ptr, &_info_ptr);
					assert(0);
				}
			    
				png_init_io(_png_ptr, fp);
					
				png_set_IHDR(_png_ptr, _info_ptr, GetWidth(), GetHeight(), 8,
								 PNG_COLOR_TYPE_RGB,
								 PNG_INTERLACE_NONE,
								 PNG_COMPRESSION_TYPE_DEFAULT,
								 PNG_FILTER_TYPE_DEFAULT);
			    
				png_write_info(_png_ptr, _info_ptr);

				if (little_endian() && false /* RGB depth always = 8 */)
					png_set_swap(_png_ptr);
			    
				for(UINT y = 0; y < GetHeight(); ++y) 
					png_write_row(_png_ptr, (png_bytep)GetPixelPtr(0, y));

				png_write_end(_png_ptr,_info_ptr);
				fclose(fp);
			}
示例#6
0
void Raster16ToPng16(
	const char*		name,
	const uint16*	raster,
	int				w,
	int				h,
	FILE*			flog )
{
	FILE*			f = FileOpenOrDie( name, "w", flog );
	png_structp		png_ptr;
	png_infop		info_ptr;
	png_byte**		prow;

// init I/O
	png_ptr		= png_create_write_struct(
					PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );

	info_ptr	= png_create_info_struct( png_ptr );

	png_init_io( png_ptr, f );

// header
	png_set_IHDR( png_ptr, info_ptr,
		w, h, 16, PNG_COLOR_TYPE_GRAY,
		PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
		PNG_FILTER_TYPE_BASE );

	png_write_info( png_ptr, info_ptr );

// data
	prow = (png_byte**)malloc( h * sizeof(png_byte*) );

	for( int i = 0; i < h; ++i )
		prow[i] = (png_byte*)(raster + w * i);

	png_set_swap( png_ptr );
	png_write_image( png_ptr, prow );
	free( prow );

// cleanup
	png_write_end( png_ptr, NULL );
	png_destroy_write_struct( &png_ptr, &info_ptr );
	fclose( f );
}
示例#7
0
PyObject*
_png_module::_read_png(const Py::Object& py_fileobj, const bool float_result,
                       int result_bit_depth)
{
    png_byte header[8];   // 8 is the maximum size that can be checked
    FILE* fp = NULL;
    bool close_file = false;
    bool close_dup_file = false;
    PyObject *py_file = NULL;

    if (py_fileobj.isString())
    {
        if ((py_file = npy_PyFile_OpenFile(py_fileobj.ptr(), (char *)"rb")) == NULL) {
            throw Py::Exception();
        }
        close_file = true;
    } else {
        py_file = py_fileobj.ptr();
    }

    if ((fp = npy_PyFile_Dup(py_file, "rb")))
    {
        close_dup_file = true;
    }
    else
    {
        PyErr_Clear();
        PyObject* read_method = PyObject_GetAttrString(py_file, "read");
        if (!(read_method && PyCallable_Check(read_method)))
        {
            Py_XDECREF(read_method);
            throw Py::TypeError(
                "Object does not appear to be a 8-bit string path or a Python "
                "file-like object");
        }
        Py_XDECREF(read_method);
    }

    if (fp)
    {
        if (fread(header, 1, 8, fp) != 8)
        {
            throw Py::RuntimeError(
                "_image_module::readpng: error reading PNG header");
        }
    }
    else
    {
        _read_png_data(py_file, header, 8);
    }
    if (png_sig_cmp(header, 0, 8))
    {
        throw Py::RuntimeError(
            "_image_module::readpng: file not recognized as a PNG file");
    }

    /* initialize stuff */
    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

    if (!png_ptr)
    {
        throw Py::RuntimeError(
            "_image_module::readpng:  png_create_read_struct failed");
    }

    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
        throw Py::RuntimeError(
            "_image_module::readpng:  png_create_info_struct failed");
    }

    if (setjmp(png_jmpbuf(png_ptr)))
    {
        throw Py::RuntimeError(
            "_image_module::readpng:  error during init_io");
    }

    if (fp)
    {
        png_init_io(png_ptr, fp);
    }
    else
    {
        png_set_read_fn(png_ptr, (void*)py_file, &read_png_data);
    }
    png_set_sig_bytes(png_ptr, 8);
    png_read_info(png_ptr, info_ptr);

    png_uint_32 width = png_get_image_width(png_ptr, info_ptr);
    png_uint_32 height = png_get_image_height(png_ptr, info_ptr);

    int bit_depth = png_get_bit_depth(png_ptr, info_ptr);

    // Unpack 1, 2, and 4-bit images
    if (bit_depth < 8)
        png_set_packing(png_ptr);

    // If sig bits are set, shift data
    png_color_8p sig_bit;
    if ((png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_PALETTE) &&
        png_get_sBIT(png_ptr, info_ptr, &sig_bit))
    {
        png_set_shift(png_ptr, sig_bit);
    }

    // Convert big endian to little
    if (bit_depth == 16)
    {
        png_set_swap(png_ptr);
    }

    // Convert palletes to full RGB
    if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE)
    {
        png_set_palette_to_rgb(png_ptr);
        bit_depth = 8;
    }

    // If there's an alpha channel convert gray to RGB
    if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY_ALPHA)
    {
        png_set_gray_to_rgb(png_ptr);
    }

    png_set_interlace_handling(png_ptr);
    png_read_update_info(png_ptr, info_ptr);

    /* read file */
    if (setjmp(png_jmpbuf(png_ptr)))
    {
        throw Py::RuntimeError(
            "_image_module::readpng: error during read_image");
    }

    png_bytep *row_pointers = new png_bytep[height];
    png_uint_32 row;

    for (row = 0; row < height; row++)
    {
        row_pointers[row] = new png_byte[png_get_rowbytes(png_ptr,info_ptr)];
    }

    png_read_image(png_ptr, row_pointers);

    npy_intp dimensions[3];
    dimensions[0] = height;  //numrows
    dimensions[1] = width;   //numcols
    if (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_ALPHA)
    {
        dimensions[2] = 4;     //RGBA images
    }
    else if (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_COLOR)
    {
        dimensions[2] = 3;     //RGB images
    }
    else
    {
        dimensions[2] = 1;     //Greyscale images
    }
    //For gray, return an x by y array, not an x by y by 1
    int num_dims  = (png_get_color_type(png_ptr, info_ptr)
                                & PNG_COLOR_MASK_COLOR) ? 3 : 2;

    PyArrayObject *A = NULL;
    if (float_result) {
        double max_value = (1 << bit_depth) - 1;

        A = (PyArrayObject *) PyArray_SimpleNew(num_dims, dimensions, NPY_FLOAT);

        if (A == NULL)
        {
            throw Py::MemoryError("Could not allocate image array");
        }

        for (png_uint_32 y = 0; y < height; y++)
        {
            png_byte* row = row_pointers[y];
            for (png_uint_32 x = 0; x < width; x++)
            {
                size_t offset = y * A->strides[0] + x * A->strides[1];
                if (bit_depth == 16)
                {
                    png_uint_16* ptr = &reinterpret_cast<png_uint_16*>(row)[x * dimensions[2]];
                    for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++)
                    {
                        *(float*)(A->data + offset + p*A->strides[2]) = (float)(ptr[p]) / max_value;
                    }
                }
                else
                {
                    png_byte* ptr = &(row[x * dimensions[2]]);
                    for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++)
                    {
                        *(float*)(A->data + offset + p*A->strides[2]) = (float)(ptr[p]) / max_value;
                    }
                }
            }
        }
    } else {
        if (result_bit_depth < 0) {
            result_bit_depth = bit_depth;
        }

        if (result_bit_depth == 8) {
            A = (PyArrayObject *) PyArray_SimpleNew(num_dims, dimensions, NPY_UBYTE);
        } else if (result_bit_depth == 16) {
            A = (PyArrayObject *) PyArray_SimpleNew(num_dims, dimensions, NPY_UINT16);
        } else {
            throw Py::RuntimeError(
                "_image_module::readpng: image has unknown bit depth");
        }

        if (A == NULL)
        {
            throw Py::MemoryError("Could not allocate image array");
        }

        for (png_uint_32 y = 0; y < height; y++)
        {
            png_byte* row = row_pointers[y];
            for (png_uint_32 x = 0; x < width; x++)
            {
                size_t offset = y * A->strides[0] + x * A->strides[1];
                if (bit_depth == 16)
                {
                    png_uint_16* ptr = &reinterpret_cast<png_uint_16*>(row)[x * dimensions[2]];

                    if (result_bit_depth == 16) {
                        for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++)
                        {
                            *(png_uint_16*)(A->data + offset + p*A->strides[2]) = ptr[p];
                        }
                    } else {
                        for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++)
                        {
                            *(png_byte*)(A->data + offset + p*A->strides[2]) = ptr[p] >> 8;
                        }
                    }
                }
                else
                {
                    png_byte* ptr = &(row[x * dimensions[2]]);
                    if (result_bit_depth == 16) {
                        for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++)
                        {
                            *(png_uint_16*)(A->data + offset + p*A->strides[2]) = ptr[p];
                        }
                    } else {
                        for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++)
                        {
                            *(png_byte*)(A->data + offset + p*A->strides[2]) = ptr[p];
                        }
                    }
                }
            }
        }
unsigned char *	ReadPNG(FILE * fp, unsigned int & sizeX, unsigned int &sizeY, int &img_depth, int &img_color_type, unsigned char *** row_pointer_ptr)
{
	png_structp png_ptr;
	png_bytepp row_pointers;
	png_infop info_ptr;
	int  interlace_type;

	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, (png_error_ptr)png_cexcept_error, (png_error_ptr)NULL);
	if (png_ptr == NULL)
	{
		exit(1);
		return NULL;
	}
	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL)
	{
		png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
		fprintf(stderr,"VSImage ERROR : PNG info_ptr == NULL !!!\n");
		exit(1);
		return NULL;
	}
	if (setjmp(png_jmpbuf(png_ptr)))
	{
		/* Free all of the memory associated with the png_ptr and info_ptr */
		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
		/* If we get here, we had a problem reading the file */
		exit(1);
		return NULL;
	}

        png_init_io(png_ptr, fp);

	//png_set_sig_bytes(png_ptr, 8);
	png_read_info(png_ptr, info_ptr);  /* read all PNG info up to image data */
	png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *)&sizeX, (png_uint_32 *)&sizeY, &img_depth, &img_color_type, &interlace_type, NULL, NULL);

# if __BYTE_ORDER != __BIG_ENDIAN
	if (img_depth==16)
		png_set_swap (png_ptr);
#endif

	if (img_depth==16)//for now
		png_set_strip_16(png_ptr);
	if (img_color_type == PNG_COLOR_TYPE_PALETTE)
		png_set_palette_to_rgb(png_ptr);
		   
	if (img_color_type == PNG_COLOR_TYPE_GRAY && img_depth < 8)
		png_set_gray_1_2_4_to_8(png_ptr);

	png_set_expand (png_ptr);
	png_read_update_info (png_ptr,info_ptr);
	png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *)&sizeX, (png_uint_32 *)&sizeY, &img_depth, &img_color_type, &interlace_type, NULL, NULL);
	row_pointers = (unsigned char **)malloc (sizeof (unsigned char *) *sizeY);
	int numchan=1;
	if (img_color_type&PNG_COLOR_MASK_COLOR)
		numchan =3;
	if (img_color_type &PNG_COLOR_MASK_PALETTE)
		numchan =1;
	if (img_color_type&PNG_COLOR_MASK_ALPHA)
		numchan++;
	unsigned long stride = numchan*sizeof (unsigned char)*img_depth/8;
	unsigned char * image = (unsigned char *) malloc (stride*sizeX*sizeY);
	for (unsigned int i=0;i<sizeY;i++)
	{
		row_pointers[i] = &image[i*stride*sizeX];
	}
	png_read_image (png_ptr,row_pointers);
	unsigned char * result;
        result = image;
	//free (row_pointers);
        *row_pointer_ptr=row_pointers;
	png_read_end(png_ptr, info_ptr);
	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

	return result;
}
示例#9
0
文件: qImage.hpp 项目: qiangd6/QTK
			///
			/// LDR I/O, only available to LDR images
			void LoadPng(const std::string& file_name)
			{
				BOOST_STATIC_ASSERT( (boost::is_same<T, UCHAR>::value) );
				BOOST_STATIC_ASSERT( channel == 3 );

				size_t pos = file_name.find_last_of(".");
				std::string file_type = file_name.substr(++pos, std::string::npos);
				boost::to_lower(file_type);
				assert(file_type == "png");

				FILE* fp = 0;
				fp = fopen(file_name.c_str(), "rb");
				if(fp == 0) 
				{
					assert(0);
					return;
				}
						
				char buf[PNG_BYTES_TO_CHECK];
				png_structp _png_ptr;
				png_infop _info_ptr;

				// read in some of the signature bytes
				if(fread(buf, 1, PNG_BYTES_TO_CHECK, fp) != PNG_BYTES_TO_CHECK)
					assert(0);

				// compare the first PNG_BYTES_TO_CHECK bytes of the signature.
				if(png_sig_cmp((png_bytep)buf, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0)
					assert(0);

				_png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
				if(_png_ptr == NULL)
					assert(0);

				// allocate/initialize the image information data
				_info_ptr = png_create_info_struct(_png_ptr);
				if (_info_ptr == NULL) 
				{
					png_destroy_read_struct(&_png_ptr,png_infopp_NULL,png_infopp_NULL);
					assert(0);
				}

				if (setjmp(png_jmpbuf(_png_ptr))) 
				{
					//free all of the memory associated with the png_ptr and info_ptr
					png_destroy_read_struct(&_png_ptr, &_info_ptr, png_infopp_NULL);
					assert(0);
				}

				png_init_io(_png_ptr, fp);
				png_set_sig_bytes(_png_ptr, PNG_BYTES_TO_CHECK);
				png_read_info(_png_ptr, _info_ptr);

				if (little_endian() && png_get_bit_depth(_png_ptr,_info_ptr)>8)
					png_set_swap(_png_ptr);
						
				SetSize((png_get_image_width(_png_ptr,_info_ptr)), (png_get_image_height(_png_ptr,_info_ptr)));
												  
				png_uint_32 width, height;
				int bit_depth, color_type, interlace_type;

				png_get_IHDR(_png_ptr, _info_ptr, &width, &height,&bit_depth,&color_type,&interlace_type, int_p_NULL, int_p_NULL);
			    
				for(png_uint_32 y = 0; y < height; ++y) 
					png_read_row(_png_ptr,(png_bytep)GetPixelPtr(0, y), NULL);

				png_read_end(_png_ptr,NULL);
				fclose(fp);
			}
示例#10
0
文件: png.c 项目: Gingar/port
void png_info_callback(png_structp png_ptr, png_infop info_ptr)
{
	int bit_depth, color_type, intent;
	double gamma;
	int bytes_per_pixel=3;
	struct cached_image *cimg;

	cimg=global_cimg;

	bit_depth=png_get_bit_depth(png_ptr, info_ptr);
	color_type=png_get_color_type(png_ptr, info_ptr);
	if (color_type == PNG_COLOR_TYPE_PALETTE)
        	png_set_expand(png_ptr);
    	if (color_type == PNG_COLOR_TYPE_GRAY &&
        	bit_depth < 8) png_set_expand(png_ptr);
	if (png_get_valid(png_ptr, info_ptr,
        	PNG_INFO_tRNS)){
		png_set_expand(png_ptr); /* Legacy version of
		png_set_tRNS_to_alpha(png_ptr); */
		bytes_per_pixel++;
	}
	if (color_type == PNG_COLOR_TYPE_GRAY ||
		color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
		png_set_gray_to_rgb(png_ptr);
	if (bit_depth==16){
#ifndef REPACK_16
#ifdef C_LITTLE_ENDIAN
		/* We use native endianity only if unsigned short is 2-byte
		 * because otherwise we have to reassemble the buffer so we
		 * will leave in the libpng-native big endian.
		 */
		png_set_swap(png_ptr);
#endif /* #ifdef C_LITTLE_ENDIAN */
#endif /* #ifndef REPACK_16 */
		bytes_per_pixel*=sizeof(unsigned short);
	}
	png_set_interlace_handling(png_ptr);
	if (color_type==PNG_COLOR_TYPE_RGB_ALPHA
		||color_type==PNG_COLOR_TYPE_GRAY_ALPHA){
		if (bytes_per_pixel==3
			||bytes_per_pixel==3*sizeof(unsigned short))
			bytes_per_pixel=4*bytes_per_pixel/3;
	}
	cimg->width=png_get_image_width(png_ptr,info_ptr);
	cimg->height=png_get_image_height(png_ptr,info_ptr);
	cimg->buffer_bytes_per_pixel=bytes_per_pixel;
	if (png_get_sRGB(png_ptr, info_ptr, &intent)){
		gamma=sRGB_gamma;
	}
	else
 	{              
  		if (!png_get_gAMA(png_ptr, info_ptr, &gamma)){
			gamma=sRGB_gamma;
		}
	}
	cimg->red_gamma=gamma;
	cimg->green_gamma=gamma;
	cimg->blue_gamma=gamma;
	png_read_update_info(png_ptr,info_ptr);                 
	cimg->strip_optimized=0;
	header_dimensions_known(cimg);
}
UInt64 PNGImageFileType::storeData(const Image  *OSG_PNG_ARG  (pImage  ), 
                                         UChar8 *OSG_PNG_ARG  (buffer ),
                                         Int32   OSG_CHECK_ARG(memSize))
{
#ifdef OSG_WITH_PNG

    png_structp png_ptr;
    png_infop info_ptr;

    if(pImage->getDimension() < 1 || pImage->getDimension() > 2)
    {
        FWARNING(("PNGImageFileType::write: invalid dimension %d!\n",
                  pImage->getDimension()));
        return 0;
    }

    /* Create and initialize the png_struct with the desired error handler
    * functions.  If you want to use the default stderr and longjump method,
    * you can supply NULL for the last three parameters.  We also check that
    * the library version is compatible with the one used at compile time,
    * in case we are using dynamically linked libraries.  REQUIRED.
    */

    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
                                      0, &errorOutput, &warningOutput);
    
    if (png_ptr == NULL)
    {
        return 0;
    }

    /* Allocate/initialize the image information data.  REQUIRED */
    info_ptr = png_create_info_struct(png_ptr);

    if(info_ptr == NULL)
    {
        png_destroy_write_struct(&png_ptr,  NULL);
        return 0;
    }
    
    BufferInfo bufferInfo;
    bufferInfo.buffer = buffer;
    bufferInfo.length = 0;

    png_set_write_fn(png_ptr, 
                     static_cast<void *>(&bufferInfo), 
                     user_write_data, 
                     user_flush_data);

    /* This is the hard way */

    /* Set the image information here.  Width and height are up to 2^31,
    * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
    * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
    * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
    * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
    * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
    * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
    */

    Int32 ctype;
    switch(pImage->getPixelFormat())
    {
        case Image::OSG_L_PF:
            ctype = PNG_COLOR_TYPE_GRAY;        
            break;
            
        case Image::OSG_LA_PF:
            ctype = PNG_COLOR_TYPE_GRAY_ALPHA;          
            break;
            
#if defined(GL_BGR) || defined(GL_BGR_EXT)
        case Image::OSG_BGR_PF:
#endif
        case Image::OSG_RGB_PF: 
            ctype = PNG_COLOR_TYPE_RGB;                 
            break;
            
#if defined(GL_BGRA) || defined(GL_BGRA_EXT)
        case Image::OSG_BGRA_PF:
#endif
        case Image::OSG_RGBA_PF:
            ctype = PNG_COLOR_TYPE_RGB_ALPHA;           
            break;
            
        default:
            FWARNING(("PNGImageFileType::write: unknown pixel format %d!\n",
                      pImage->getPixelFormat()));
            png_destroy_write_struct(&png_ptr,  NULL);

            return 0;
    }
    
    Int32 bit_depth;

    switch (pImage->getDataType()) 
    {
        case Image::OSG_UINT8_IMAGEDATA:
            bit_depth = 8;
            break;
        case Image::OSG_UINT16_IMAGEDATA:
            bit_depth = 16;
            break;
        default:
            FWARNING (("Invalid pixeldepth, cannot store data\n"));
            return 0;
    };

    png_set_IHDR(png_ptr, 
                 info_ptr, 
                 pImage->getWidth(), 
                 pImage->getHeight(),
                 bit_depth,
                 ctype,      
                 PNG_INTERLACE_NONE, 
                 PNG_COMPRESSION_TYPE_BASE, 
                 PNG_FILTER_TYPE_BASE);
    
    /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */
    /* note that if sRGB is present the gAMA and cHRM chunks must be ignored
    * on read and must be written in accordance with the sRGB profile */

    /* Write the file header information.  REQUIRED */

    png_write_info(png_ptr, info_ptr);

#if BYTE_ORDER == LITTLE_ENDIAN
    if (bit_depth == 16)
        png_set_swap(png_ptr);
#endif
    
    if(pImage->getPixelFormat() == Image::OSG_BGR_PF ||
       pImage->getPixelFormat() == Image::OSG_BGRA_PF)
    {
        /* flip BGR pixels to RGB */
        png_set_bgr(png_ptr);
        
        /* swap location of alpha bytes from ARGB to RGBA */
        png_set_swap_alpha(png_ptr);
    }
    
    /* The easiest way to write the image (you may have a different memory
     * layout, however, so choose what fits your needs best).  You need to
     * use the first method if you aren't handling interlacing yourself.
     */

    png_bytep *row_pointers = new png_bytep [pImage->getHeight()];
    
    for(Int32 k = 0; k < pImage->getHeight(); k++)
    {
        row_pointers[k] = 
            (const_cast<UInt8 *>(pImage->getData())) + 
            (pImage->getHeight() - 1 - k) * 
            pImage->getWidth() * pImage->getBpp();
    }
    
    /* write out the entire image data in one call */
    png_write_image(png_ptr, row_pointers);

    /* It is REQUIRED to call this to finish writing the rest of the file */
    png_write_end(png_ptr, info_ptr);
    
    /* clean up after the write, and free any memory allocated */
    png_destroy_write_struct(&png_ptr, &info_ptr);

    delete [] row_pointers;

    /* that's it */
    return bufferInfo.length;
#else
    SWARNING << getMimeType() 
             << " storeData is not compiled into the current binary " 
             << std::endl;

    return 0;
#endif
}
UInt64 PNGImageFileType::restoreData(      Image  *OSG_PNG_ARG  (pImage ),
                                     const UChar8 *OSG_PNG_ARG  (buffer ),
                                           Int32   OSG_CHECK_ARG(memSize))
{
#ifdef OSG_WITH_PNG

    UInt64              retCode;
    Image::PixelFormat  pixelFormat = Image::OSG_INVALID_PF;
    png_structp         png_ptr;
    png_infop           info_ptr;
    png_uint_32         width, wc, height, h, i;
    png_byte            bit_depth, channels, color_type;
    png_bytep           *row_pointers, base;

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

    if(!png_ptr)
    {
        return 0;
    }

    png_set_error_fn(png_ptr, 0, &errorOutput, &warningOutput);

    info_ptr = png_create_info_struct(png_ptr);

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

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

    BufferInfo bufferInfo;
    bufferInfo.buffer = const_cast<UChar8 *>(buffer);
    bufferInfo.length = 0;
    png_set_read_fn(png_ptr, static_cast<void *>(&bufferInfo), user_read_data);

    png_read_info(png_ptr, info_ptr);

    width = png_get_image_width(png_ptr, info_ptr);
    height = png_get_image_height(png_ptr, info_ptr);
    bit_depth = png_get_bit_depth(png_ptr, info_ptr);
    channels = png_get_channels(png_ptr, info_ptr);
    color_type = png_get_color_type(png_ptr, info_ptr);

    // Convert paletted images to RGB
    if(color_type == PNG_COLOR_TYPE_PALETTE)
    {
        png_set_palette_to_rgb(png_ptr);
        channels = 3;
        bit_depth = 8;
    }

    // Convert < 8 bit to 8 bit
    if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
    {
        png_set_gray_1_2_4_to_8(png_ptr);
        bit_depth = 8;
    }

#if BYTE_ORDER == LITTLE_ENDIAN
    if (bit_depth == 16)
        png_set_swap(png_ptr);
#endif
   
    // Add a full alpha channel if there is transparency
    // information in a tRNS chunk
    if(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
    {
        png_set_tRNS_to_alpha(png_ptr);
        ++channels;
    }   
                                                                 
    Int32 dataType;

    switch (bit_depth) 
    {
        case 8:
            dataType = Image::OSG_UINT8_IMAGEDATA;
            break;
        case 16:
            dataType = Image::OSG_UINT16_IMAGEDATA;
            break;
        default:
            FWARNING (( "Invalid bit_depth: %d, can not read png-data\n",
                        bit_depth ));
            return false;
    }
    
    switch(channels)
    {
        case 1:
            pixelFormat = Image::OSG_L_PF;
            break;
        case 2:
            pixelFormat = Image::OSG_LA_PF;
            break;
        case 3:
            pixelFormat = Image::OSG_RGB_PF;
            break;
        case 4:
            pixelFormat = Image::OSG_RGBA_PF;
            break;
    };
    
    if(pImage->set(pixelFormat, width, height,
                   1, 1, 1, 0.0, 0,
                   dataType))
    {
        // Calculate the row pointers
        row_pointers = new png_bytep[height];
        wc = width * channels * (bit_depth / 8);
        h = height - 1;
        base = pImage->editData();

        for(i = 0; i < height; ++i)
            row_pointers[i] = base + (h - i) * wc;

        // Read the image data
        png_read_image(png_ptr, row_pointers);
        
        delete[] row_pointers;
        
        retCode = bufferInfo.length;
    }
    else
    {
        retCode = 0;
    }

    png_destroy_read_struct(&png_ptr, &info_ptr, 0);
    
    return retCode;

#else
    SWARNING << getMimeType() 
             << " restoreData is not compiled into the current binary " 
             << std::endl;

    return 0;
#endif
}
示例#13
0
ImBuf *imb_loadpng(unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
	struct ImBuf *ibuf = NULL;
	png_structp png_ptr;
	png_infop info_ptr;
	unsigned char *pixels = NULL;
	unsigned short *pixels16 = NULL;
	png_bytepp row_pointers = NULL;
	png_uint_32 width, height;
	int bit_depth, color_type;
	PNGReadStruct ps;

	unsigned char *from, *to;
	unsigned short *from16;
	float *to_float;
	int i, bytesperpixel;

	if (imb_is_a_png(mem) == 0) return(NULL);

	/* both 8 and 16 bit PNGs are default to standard byte colorspace */
	colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);

	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
	                                 NULL, NULL, NULL);
	if (png_ptr == NULL) {
		printf("Cannot png_create_read_struct\n");
		return NULL;
	}

	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) {
		png_destroy_read_struct(&png_ptr, (png_infopp)NULL, 
		                        (png_infopp)NULL);
		printf("Cannot png_create_info_struct\n");
		return NULL;
	}

	ps.size = size; /* XXX, 4gig limit! */
	ps.data = mem;
	ps.seek = 0;

	png_set_read_fn(png_ptr, (void *) &ps, ReadData);

	if (setjmp(png_jmpbuf(png_ptr))) {
		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
		if (pixels) MEM_freeN(pixels);
		if (pixels16) MEM_freeN(pixels16);
		if (row_pointers) MEM_freeN(row_pointers);
		if (ibuf) IMB_freeImBuf(ibuf);
		return NULL;
	}

	// png_set_sig_bytes(png_ptr, 8);

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

	bytesperpixel = png_get_channels(png_ptr, info_ptr);

	switch (color_type) {
		case PNG_COLOR_TYPE_RGB:
		case PNG_COLOR_TYPE_RGB_ALPHA:
			break;
		case PNG_COLOR_TYPE_PALETTE:
			png_set_palette_to_rgb(png_ptr);
			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
				bytesperpixel = 4;
			}
			else {
				bytesperpixel = 3;
			}
			break;
		case PNG_COLOR_TYPE_GRAY:
		case PNG_COLOR_TYPE_GRAY_ALPHA:
			if (bit_depth < 8) {
				png_set_expand(png_ptr);
				bit_depth = 8;
			}
			break;
		default:
			printf("PNG format not supported\n");
			longjmp(png_jmpbuf(png_ptr), 1);
	}
	
	ibuf = IMB_allocImBuf(width, height, 8 * bytesperpixel, 0);

	if (ibuf) {
		ibuf->ftype = PNG;
		if (bit_depth == 16)
			ibuf->ftype |= PNG_16BIT;

		if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) {
			int unit_type;
			png_uint_32 xres, yres;

			if (png_get_pHYs(png_ptr, info_ptr, &xres, &yres, &unit_type))
				if (unit_type == PNG_RESOLUTION_METER) {
					ibuf->ppm[0] = xres;
					ibuf->ppm[1] = yres;
				}
		}
	}
	else {
		printf("Couldn't allocate memory for PNG image\n");
	}

	if (ibuf && ((flags & IB_test) == 0)) {
		if (bit_depth == 16) {
			imb_addrectfloatImBuf(ibuf);
			png_set_swap(png_ptr);

			pixels16 = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(png_uint_16), "pixels");
			if (pixels16 == NULL) {
				printf("Cannot allocate pixels array\n");
				longjmp(png_jmpbuf(png_ptr), 1);
			}

			/* allocate memory for an array of row-pointers */
			row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_uint_16p), "row_pointers");
			if (row_pointers == NULL) {
				printf("Cannot allocate row-pointers array\n");
				longjmp(png_jmpbuf(png_ptr), 1);
			}

			/* set the individual row-pointers to point at the correct offsets */
			for (i = 0; i < ibuf->y; i++) {
				row_pointers[ibuf->y - 1 - i] = (png_bytep)
				                                ((png_uint_16 *)pixels16 + (i * ibuf->x) * bytesperpixel);
			}

			png_read_image(png_ptr, row_pointers);

			/* copy image data */

			to_float = ibuf->rect_float;
			from16 = pixels16;

			switch (bytesperpixel) {
				case 4:
					for (i = ibuf->x * ibuf->y; i > 0; i--) {
						to_float[0] = from16[0] / 65535.0;
						to_float[1] = from16[1] / 65535.0;
						to_float[2] = from16[2] / 65535.0;
						to_float[3] = from16[3] / 65535.0;
						to_float += 4; from16 += 4;
					}
					break;
				case 3:
					for (i = ibuf->x * ibuf->y; i > 0; i--) {
						to_float[0] = from16[0] / 65535.0;
						to_float[1] = from16[1] / 65535.0;
						to_float[2] = from16[2] / 65535.0;
						to_float[3] = 1.0;
						to_float += 4; from16 += 3;
					}
					break;
				case 2:
					for (i = ibuf->x * ibuf->y; i > 0; i--) {
						to_float[0] = to_float[1] = to_float[2] = from16[0] / 65535.0;
						to_float[3] = from16[1] / 65535.0;
						to_float += 4; from16 += 2;
					}
					break;
				case 1:
					for (i = ibuf->x * ibuf->y; i > 0; i--) {
						to_float[0] = to_float[1] = to_float[2] = from16[0] / 65535.0;
						to_float[3] = 1.0;
						to_float += 4; from16++;
					}
					break;
			}
		}
		else {
			imb_addrectImBuf(ibuf);

			pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels");
			if (pixels == NULL) {
				printf("Cannot allocate pixels array\n");
				longjmp(png_jmpbuf(png_ptr), 1);
			}

			/* allocate memory for an array of row-pointers */
			row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers");
			if (row_pointers == NULL) {
				printf("Cannot allocate row-pointers array\n");
				longjmp(png_jmpbuf(png_ptr), 1);
			}

			/* set the individual row-pointers to point at the correct offsets */
			for (i = 0; i < ibuf->y; i++) {
				row_pointers[ibuf->y - 1 - i] = (png_bytep)
				                                ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char));
			}

			png_read_image(png_ptr, row_pointers);

			/* copy image data */

			to = (unsigned char *) ibuf->rect;
			from = pixels;

			switch (bytesperpixel) {
				case 4:
					for (i = ibuf->x * ibuf->y; i > 0; i--) {
						to[0] = from[0];
						to[1] = from[1];
						to[2] = from[2];
						to[3] = from[3];
						to += 4; from += 4;
					}
					break;
				case 3:
					for (i = ibuf->x * ibuf->y; i > 0; i--) {
						to[0] = from[0];
						to[1] = from[1];
						to[2] = from[2];
						to[3] = 0xff;
						to += 4; from += 3;
					}
					break;
				case 2:
					for (i = ibuf->x * ibuf->y; i > 0; i--) {
						to[0] = to[1] = to[2] = from[0];
						to[3] = from[1];
						to += 4; from += 2;
					}
					break;
				case 1:
					for (i = ibuf->x * ibuf->y; i > 0; i--) {
						to[0] = to[1] = to[2] = from[0];
						to[3] = 0xff;
						to += 4; from++;
					}
					break;
			}
		}

		if (flags & IB_metadata) {
			png_text *text_chunks;
			int count = png_get_text(png_ptr, info_ptr, &text_chunks, NULL);
			for (i = 0; i < count; i++) {
				IMB_metadata_add_field(ibuf, text_chunks[i].key, text_chunks[i].text);
				ibuf->flags |= IB_metadata;
			}
		}

		png_read_end(png_ptr, info_ptr);
	}

	/* clean up */
	if (pixels)
		MEM_freeN(pixels);
	if (pixels16)
		MEM_freeN(pixels16);
	if (row_pointers)
		MEM_freeN(row_pointers);
	png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);

	return(ibuf);
}
示例#14
0
FloatPixMapRef FPMCreateWithPNGCustom(png_voidp ioPtr, png_rw_ptr readDataFn, FPMGammaFactor desiredGamma, FPMPNGErrorHandler errorHandler)
{
    png_structp			png = NULL;
    png_infop			pngInfo = NULL;
    png_infop			pngEndInfo = NULL;
    FloatPixMapRef		result = NULL;
    png_uint_32			i, width, height, rowBytes;
    int					depth, colorType;
    png_bytepp			rows = NULL;
    void				*data = NULL;

    png = png_create_read_struct(PNG_LIBPNG_VER_STRING, errorHandler, PNGError, PNGWarning);
    if (png == NULL)  goto FAIL;

    pngInfo = png_create_info_struct(png);
    if (pngInfo == NULL)  goto FAIL;

    pngEndInfo = png_create_info_struct(png);
    if (pngEndInfo == NULL)  goto FAIL;

    if (setjmp(png_jmpbuf(png)))
    {
        // libpng will jump here on error.
        goto FAIL;
    }

    png_set_read_fn(png, ioPtr, readDataFn);

    png_read_info(png, pngInfo);
    if (!png_get_IHDR(png, pngInfo, &width, &height, &depth, &colorType, NULL, NULL, NULL))  goto FAIL;

#if __LITTLE_ENDIAN__
    if (depth == 16)  png_set_swap(png);
#endif
    if (depth <= 8 && !(colorType & PNG_COLOR_MASK_ALPHA))
    {
        png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
    }
    png_set_gray_to_rgb(png);
    if (depth < 8)
    {
        png_set_packing(png);
        png_set_expand(png);
    }

    png_read_update_info(png, pngInfo);
    rowBytes = png_get_rowbytes(png, pngInfo);

    rows = malloc(sizeof *rows * height);
    data = malloc(rowBytes * height);
    if (rows == NULL || data == NULL)  goto FAIL;

    // Set up row pointers.
    for (i = 0; i < height; i++)
    {
        rows[i] = (png_bytep)data + i * rowBytes;
    }

    png_read_image(png, rows);
    png_read_end(png, pngEndInfo);

    free(rows);

    result = ConvertPNGData(data, width, height, rowBytes, png_get_bit_depth(png, pngInfo), png_get_color_type(png, pngInfo));

    if (result != NULL)
    {
        double invGamma = 1.0/kFPMGammaSRGB;
        png_get_gAMA(png, pngInfo, &invGamma);
        FPMApplyGamma(result, 1.0/invGamma, desiredGamma, png_get_bit_depth(png, pngInfo) == 16 ? 65536 : 256);
    }

    png_destroy_read_struct(&png, &pngInfo, &pngEndInfo);
    free(data);

    return result;

FAIL:
    FPMRelease(&result);
    if (png != NULL)  png_destroy_read_struct(&png, &pngInfo, &pngEndInfo);
    free(rows);
    free(data);

    return NULL;
}
示例#15
0
文件: png.cpp 项目: 2asoft/xray
/* Read an PNG file, returning the storage where it's located */
BitmapStorage *
BitmapIO_PNG::ReadPNGFile(BitmapInfo *fbi, BitmapManager *manager) 
{
    BitmapStorage *storage = NULL;
	unsigned char magic_numbers[8];
    
    if((istream=_tfopen(fbi->Name(), _T("rb")))==NULL)
		return NULL;

	// grab the first 8 bytes for testing
	if (fread(magic_numbers, 1, 8, istream) != 8) {
		fclose(istream);
		return NULL;
	} else 
		rewind(istream);

	// Make sure we're a png file
	if (!png_check_sig(magic_numbers, 8)) {
		fclose(istream);
		return NULL;
	}

    png = png_create_read_struct (PNG_VERSION, (void *) this, error_func, warning_func);
    if (setjmp(png->jmpbuf)) {
        if (info)
		    for (png_uint_32 i = 0; i < info->height; i++)
    			if (row_pointers[i]) free(row_pointers[i]);
		if (row_pointers) {
			free(row_pointers);
			row_pointers = NULL;
		}

		if (storage) {
			delete storage;
			storage = NULL;
		}

        fclose(istream);
        png_destroy_read_struct (&png, &info, NULL);
        return NULL;
    }
    info = png_create_info_struct(png);

    png_init_io(png, istream);
	png_read_info(png, info);

    fbi->SetWidth((WORD)info->width);
    fbi->SetHeight((WORD)info->height);
	if (info->valid & PNG_INFO_gAMA)
		fbi->SetGamma(info->gamma);
//	else
//		fbi->SetGamma (1.0f);
	if (info->valid & PNG_INFO_pHYs)
		fbi->SetAspect((float)info->x_pixels_per_unit / (float)info->y_pixels_per_unit);
	else
		fbi->SetAspect(1.0f);
    fbi->SetFlags(0);

	/* expand grayscale images to the full 8 bits */
	/* expand images with transparency to full alpha channels */
	/* I'm going to ignore lineart and just expand it to 8 bits */
	if ((info->color_type == PNG_COLOR_TYPE_PALETTE && info->bit_depth < 8) ||
		(info->color_type == PNG_COLOR_TYPE_GRAY && info->bit_depth < 8) ||
		(info->valid & PNG_INFO_tRNS))
		png_set_expand(png);

	int number_passes = 1;

	if (info->interlace_type)
		number_passes = png_set_interlace_handling(png);

	if (info->bit_depth == 16)
		png_set_swap(png);

	png_read_update_info(png, info);
   
	int bmtype = BMM_NO_TYPE;

	if (info->bit_depth == 1) {
			bmtype = BMM_LINE_ART;
	} else {
		switch(info->color_type) {
		case PNG_COLOR_TYPE_PALETTE:
			bmtype = BMM_PALETTED;
			break;
		case PNG_COLOR_TYPE_RGB:
		case PNG_COLOR_TYPE_RGB_ALPHA:
			switch(info->bit_depth) {
			case 2:
			case 4:
				// Not allowed
				break;
			case 8:
				bmtype = BMM_TRUE_32;  // zero alpha for those that don't have it
				break;
			case 16:
				bmtype = BMM_TRUE_64;
				break;
			}
			break;
		case PNG_COLOR_TYPE_GRAY_ALPHA:
		case PNG_COLOR_TYPE_GRAY:
			switch(info->bit_depth) {
			case 2:
			case 4:
				// we should never get here because of the expand code so drop through
				break;
			case 8:
				bmtype = BMM_GRAY_8;
				break;
			case 16:
				bmtype = BMM_GRAY_16;
				break;
			}
			break;
		}
	}

	if (bmtype == BMM_NO_TYPE) {
		fclose(istream);
        png_destroy_read_struct (&png, &info, NULL);
		return NULL;
	}

    // Create a storage for this bitmap...
	// (we may need to special case GRAY since it has a problem with alpha)
	if(info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
		if (info->bit_depth == 16) {
			storage = BMMCreateStorage(manager, BMM_TRUE_64);
			fbi->SetType(BMM_TRUE_64);
		} else {
			storage = BMMCreateStorage(manager, BMM_TRUE_32);
			fbi->SetType(BMM_TRUE_32);
		}
	} else {
		storage = BMMCreateStorage(manager, bmtype);
		fbi->SetType(bmtype);
	}

	if (info->channels == 2 || info->channels == 4)
		fbi->SetFlags(MAP_HAS_ALPHA);


    if(storage == NULL) {
		fclose(istream);
        png_destroy_read_struct (&png, &info, NULL);
		return NULL;
	}

    if(storage->Allocate(fbi, manager, BMM_OPEN_R)==0) {
		delete storage;
		storage = NULL;
		fclose(istream);
        png_destroy_read_struct (&png, &info, NULL);
		return NULL;
	}

	row_pointers = (png_bytep *)malloc(info->height * sizeof(png_bytep));

	for (png_uint_32 i = 0; i < info->height; i++)
		row_pointers[i] = (png_bytep)malloc(info->rowbytes);

	// now read the image
	png_read_image(png, row_pointers);

	switch(bmtype) {
	case BMM_LINE_ART: {
		BMM_Color_64 *line64 = (BMM_Color_64 *) calloc(info->width, sizeof(BMM_Color_64));
		for (png_uint_32 iy = 0; iy < info->height; iy++) {
			BMM_Color_64 *l64 = line64;
			for (png_uint_32 ix = 0; ix < info->width; ix++,l64++) {
				png_uint_32 abyte = ix / 8;
				png_uint_32 abit = ix % 8;
				unsigned char tbyte = row_pointers[iy][abyte];
				unsigned char c = tbyte & (0x80 >> abit);
				l64->r = l64->g = l64->b = c ? 0xffff : 0;
				l64->a = 0;
			}
			storage->PutPixels(0, iy, info->width, line64);
		}
		free(line64);
		}
		break;
	case BMM_PALETTED: {
		if (info->bit_depth == 8) {
			for (png_uint_32 iy = 0; iy < info->height; iy++)
				storage->PutIndexPixels(0, iy, info->width, row_pointers[iy]);
		} else {
			unsigned char *pixels = (unsigned char *)calloc(info->width, sizeof(unsigned char));
			for (png_uint_32 iy = 0; iy < info->height; iy++) {
				// now fill a row of pixels
				unsigned char *inbyte = row_pointers[iy];
				for (png_uint_32 ix = 0; ix < info->width; inbyte++) {
					switch(info->bit_depth) {
					case 2:
						pixels[ix] = (*inbyte & 0xc0) >> 6;
						ix++; if (ix >= info->width) break;
						pixels[ix] = (*inbyte & 0x30) >> 4;
						ix++; if (ix >= info->width) break;
						pixels[ix] = (*inbyte & 0x0c) >> 2;
						ix++; if (ix >= info->width) break;
						pixels[ix] = *inbyte & 0x03;
						ix++;
						break;
					case 4:
						pixels[ix] = (*inbyte & 0xf0) >> 4;
						ix++; if (ix >= info->width) break;
						pixels[ix] = *inbyte & 0x0f;
						ix++;
						break;
					}
				}
				storage->PutIndexPixels(0, iy, info->width, pixels);
			}
			free(pixels);
		}
		// Now the palette
		PixelBuf48 palette(256);
		BMM_Color_48 *palout = palette.Ptr();
		for(int i = 0; i < png->num_palette; ++i,++palout) {
			palout->r = (USHORT)png->palette[i].red << 8;
			palout->g = (USHORT)png->palette[i].green << 8;
			palout->b = (USHORT)png->palette[i].blue << 8;
		}
		storage->SetPalette(0, png->num_palette, palette.Ptr());
		}
		break;
	case BMM_TRUE_32: {
		BMM_Color_64 *line64 = (BMM_Color_64 *) calloc(info->width, sizeof(BMM_Color_64));
		for (png_uint_32 iy = 0; iy < info->height; iy++) {
			BMM_Color_64 *l64 = line64;
			for (png_uint_32 ix = 0; ix < info->rowbytes; l64++) {
				l64->r = (unsigned short) (row_pointers[iy][ix++]) << 8;
				l64->g = (unsigned short) (row_pointers[iy][ix++]) << 8;
				l64->b = (unsigned short) (row_pointers[iy][ix++]) << 8;
				if (info->channels == 4) {
					l64->a = (unsigned short) (row_pointers[iy][ix++]) << 8;
				} else
					l64->a = 0;
			}
			storage->PutPixels(0, iy, info->width, line64);
		}
		free(line64);
		}
		break;
	case BMM_TRUE_64: {
		BMM_Color_64 *line64 = (BMM_Color_64 *) calloc(info->width, sizeof(BMM_Color_64));
		for (png_uint_32 iy = 0; iy < info->height; iy++) {
			BMM_Color_64 *l64 = line64;
			unsigned short *row = (unsigned short *) row_pointers[iy];
			for (png_uint_32 ix = 0; ix < info->width; ix++, l64++) {
				l64->r = *row++;
				l64->g = *row++;
				l64->b = *row++;
				if (info->channels == 4) {
					l64->a = *row++;
				} else
					l64->a = 0;
			}
			storage->PutPixels(0, iy, info->width, line64);
		}
		free(line64);
		}
		break;
	case BMM_GRAY_8: {
		BMM_Color_64 *line64 = (BMM_Color_64 *) calloc(info->width, sizeof(BMM_Color_64));
		for (png_uint_32 iy = 0; iy < info->height; iy++) {
			BMM_Color_64 *l64 = line64;
			for (png_uint_32 ix = 0; ix < info->rowbytes; l64++) {
				l64->r = l64->g = l64->b = (unsigned short) (row_pointers[iy][ix++]) << 8;
				if (info->channels == 2)
					l64->a = (unsigned short) (row_pointers[iy][ix++]) << 8;
				else
					l64->a = 0;
			}
			storage->PutPixels(0, iy, info->width, line64);
		}
		free(line64);
		}
		break;
	case BMM_GRAY_16: {
		BMM_Color_64 *line64 = (BMM_Color_64 *) calloc(info->width, sizeof(BMM_Color_64));
		for (png_uint_32 iy = 0; iy < info->height; iy++) {
			BMM_Color_64 *l64 = line64;
			unsigned short *row = (unsigned short *) row_pointers[iy];
			for (png_uint_32 ix = 0; ix < info->width; ix++, l64++) {
				l64->r = l64->g = l64->b = *row++;
				if (info->channels == 2) {
					l64->a = *row++;
				} else
					l64->a = 0;
			}
			storage->PutPixels(0, iy, info->width, line64);
		}
		free(line64);
		}
		break;
	}

	png_read_end(png, info);

	for (i = 0; i < info->height; i++)
		free(row_pointers[i]);

	free(row_pointers);

	fclose(istream);
    png_destroy_read_struct (&png, &info, NULL);

    return storage;
}
示例#16
0
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
	png_structp png_ptr = NULL;
	png_infop info_ptr;
	png_uint_32 width, height;
	png_colorp png_palette = NULL;
	int color_type, palette_entries = 0;
	int bit_depth, pixel_depth;		// pixel_depth = bit_depth * channels

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

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

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

			BYTE png_check[PNG_BYTES_TO_CHECK];

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

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

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

			if (!png_ptr) {
				return NULL;			
			}

			// create the info structure

		    info_ptr = png_create_info_struct(png_ptr);

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

			// init the IO

			png_set_read_fn(png_ptr, &fio, _ReadProc);

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

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

			png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);

			// read the IHDR chunk

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

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

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

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

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

			// set some additional flags

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

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

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

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

					break;

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

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

					break;

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

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

					png_set_bgr(png_ptr);
#endif
					pixel_depth = 32;

					break;

				default:
					throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
			}

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

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

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

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

			png_read_update_info(png_ptr, info_ptr);

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

			color_type = png_get_color_type(png_ptr,info_ptr);

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

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

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

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

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

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

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

					// store the palette

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

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

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

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

				default:
					throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
			}

			// store the transparency table

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

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

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

			// store the background color 

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

				png_color_16p image_background = NULL;
				RGBQUAD rgbBkColor;

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

					FreeImage_SetBackgroundColor(dib, &rgbBkColor);
				}
			}

			// get physical resolution

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

				int res_unit_type = PNG_RESOLUTION_UNKNOWN;

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

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

			// get possible ICC profile

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

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

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

				FreeImage_CreateICCProfile(dib, profile_data, profile_length);
			}

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

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

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

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

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

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

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

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

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

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

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

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

			png_read_end(png_ptr, info_ptr);

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

			ReadMetadata(png_ptr, info_ptr, dib);

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

			return dib;

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

	return NULL;
}
示例#17
0
文件: grfmt_png.cpp 项目: 2693/opencv
bool  PngDecoder::readData( Mat& img )
{
    bool result = false;
    AutoBuffer<uchar*> _buffer(m_height);
    uchar** buffer = _buffer;
    int color = img.channels() > 1;
    uchar* data = img.data;
    int step = (int)img.step;

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

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

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

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

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

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

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

            png_read_update_info( png_ptr, info_ptr );

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

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

            result = true;
        }
    }

    close();
    return result;
}
示例#18
0
/* read a png file.  You may want to return an error code if the read
   fails (depending upon the failure). */
void read_png(char *file_name)
{
   FILE *fp;
   png_structp png_ptr;
   png_infop info_ptr;

   /* open the file */
   fp = fopen(file_name, "rb");
   if (!fp)
      return;

   /* Create and initialize the png_struct with the desired error handler
      functions.  If you want to use the default stderr and longjump method,
      you can supply NULL for the last three parameters.  We also check that
      the header file is compatible with the library version.
    */
   png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
      (void *)user_error_ptr, user_error_fn, user_warning_fn);

   if (!png_ptr)
   {
      fclose(fp);
      return;
   }

   info_ptr = png_create_info_struct();
   if (!info_ptr)
   {
      fclose(fp);
      png_destroy_read_struct(&png_ptr,  (png_infopp)NULL, (png_infopp)NULL);
      return;
   }

   /* set error handling if you are using the setjmp/longjmp method */
   if (setjmp(png_ptr->jmpbuf))
   {
      /* Free all of the memory associated with the png_ptr and info_ptr */
      png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
      fclose(fp);
      /* If we get here, we had a problem reading the file */
      return;
   }

   /* set up the input control if you are using standard C streams */
   png_init_io(png_ptr, fp);

   /* if you are using replacement read functions, instead of calling
      png_init_io() here you would call */
   png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn);
   /* where user_io_ptr is a structure you want available to the callbacks */

   /* read the file information */
   png_read_info(png_ptr, info_ptr);

   /* set up the transformations you want.  Note that these are
      all optional.  Only call them if you want them */

   /* expand paletted colors into true RGB triplets */
   if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
      png_set_expand(png_ptr);

   /* expand grayscale images to the full 8 bits */
   if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY && info_ptr->bit_depth < 8)
      png_set_expand(png_ptr);

   /* expand paletted or RGB images with transparency to full alpha channels
    * so the data will be available as RGBA quartets */
   if (info_ptr->valid & PNG_INFO_tRNS)
      png_set_expand(png_ptr);

   /* Set the background color to draw transparent and alpha
      images over.  It is possible to set the red, green, and blue
      components directly for paletted images. */

   png_color_16 my_background;

   if (info_ptr->valid & PNG_INFO_bKGD)
      png_set_background(png_ptr, &(info_ptr->background),
                         PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
   else
      png_set_background(png_ptr, &my_background,
                         PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);

   /* tell libpng to handle the gamma conversion for you */
   if (info_ptr->valid & PNG_INFO_gAMA)
      png_set_gamma(png_ptr, screen_gamma, info_ptr->gamma);
   else
      png_set_gamma(png_ptr, screen_gamma, 0.45);

   /* tell libpng to strip 16 bit/color files down to 8 bits/color */
   if (info_ptr->bit_depth == 16)
      png_set_strip_16(png_ptr);

   /* dither rgb files down to 8 bit palette & reduce palettes
      to the number of colors available on your screen */
   if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
   {
      if (info_ptr->valid & PNG_INFO_PLTE)
         png_set_dither(png_ptr, info_ptr->palette, info_ptr->num_palette,
                        max_screen_colors, info_ptr->histogram);
      else
      {
         png_color std_color_cube[MAX_SCREEN_COLORS] =
            {/* ... colors ... */};

         png_set_dither(png_ptr, std_color_cube, MAX_SCREEN_COLORS,
            MAX_SCREEN_COLORS, NULL);
      }
   }

   /* invert monocrome files to have 0 as white and 1 as black */
   if (info_ptr->bit_depth == 1 && info_ptr->color_type == PNG_COLOR_GRAY)
      png_set_invert(png_ptr);

   /* shift the pixels down to their true bit depth */
   if (info_ptr->valid & PNG_INFO_sBIT &&
      info_ptr->bit_depth > info_ptr->sig_bit)
      png_set_shift(png_ptr, &(info_ptr->sig_bit));

   /* pack multiple pixels with bit depths of 1, 2, and 4 into bytes
      (useful only for paletted and grayscale images) */
   if (info_ptr->bit_depth < 8)
      png_set_packing(png_ptr);

   /* flip the rgb pixels to bgr */
   if (info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
      info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
      png_set_bgr(png_ptr);

   /* swap bytes of 16 bit files to least significant bit first */
   if (info_ptr->bit_depth == 16)
      png_set_swap(png_ptr);

   /* add a filler byte to RGB files (before or after each RGB triplet) */
   if (info_ptr->bit_depth == 8 && info_ptr->color_type == PNG_COLOR_TYPE_RGB)
      png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);

   /* turn on interlace handling if you are not using png_read_image() */
   number_passes = png_set_interlace_handling(png_ptr);

   /* optional call to gamma correct and add the background to the palette
      and update info structure. */
   png_read_update_info(png_ptr, info_ptr);

   /* allocate the memory to hold the image using the fields
      of png_info. */

   /* the easiest way to read the image */
   png_bytep row_pointers[height];

   for (row = 0; row < height; row++)
   {
     row_pointers[row] = malloc(info_ptr->rowbytes);
   }

   png_read_image(png_ptr, row_pointers);

   /* the other way to read images - deal with interlacing */

   for (pass = 0; pass < number_passes; pass++)
   {
      /* Read the image using the "sparkle" effect. */
      png_read_rows(png_ptr, row_pointers, NULL, number_of_rows);

      /* If you are only reading on row at a time, this works */
      for (y = 0; y < height; y++)
      {
         png_bytep row_pointers = row[y];
         png_read_rows(png_ptr, &row_pointers, NULL, 1);
      }

      /* to get the rectangle effect, use the third parameter */
      png_read_rows(png_ptr, NULL, row_pointers, number_of_rows);

      /* if you want to display the image after every pass, do
         so here */
   }

   /* read the rest of the file, getting any additional chunks in info_ptr */
   png_read_end(png_ptr, info_ptr);

   /* clean up after the read, and free any memory allocated */
   png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);

   /* close the file */
   fclose(fp);

   /* that's it */
   return;
}
示例#19
0
void Texture::Load (const GLenum &target, const std::string &filename, GLuint internalformat)
{
    // open the file
    std::ifstream file (filename.c_str (), std::ios_base::in|std::ios_base::binary);
    if (!file.is_open ())
        throw std::runtime_error (std::string ("Cannot open texture: ") + filename);

    png_structp png_ptr;
    png_infop info_ptr;

    // initialize libpng
    png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,
        NULL, NULL, NULL);
    if (!png_ptr)
        throw std::runtime_error ("Cannot create png read struct");
    info_ptr = png_create_info_struct (png_ptr);
    if (!info_ptr)
    {
        png_destroy_read_struct (&png_ptr, NULL, NULL);
        throw std::runtime_error ("Cannot create png info struct.");
    }

    // long jump error handling
    if (setjmp (png_jmpbuf (png_ptr)))
    {
        png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
        throw std::runtime_error ("libpng error.");
    }

    // set I/O callback
    png_set_read_fn (png_ptr, &file, _PngReadFn);

    // read header information and request a usable format
    png_read_info (png_ptr, info_ptr);
    png_set_packing (png_ptr);
    png_set_expand (png_ptr);
    if (png_get_bit_depth (png_ptr, info_ptr) == 16)
        png_set_swap (png_ptr);
    png_read_update_info (png_ptr, info_ptr);

    // obtain information about the image
    int rowbytes = png_get_rowbytes (png_ptr, info_ptr);
    int channels= png_get_channels (png_ptr, info_ptr);
    int width = png_get_image_width (png_ptr, info_ptr);
    int height = png_get_image_height (png_ptr, info_ptr);
    int depth = png_get_bit_depth (png_ptr, info_ptr);

    // assure a valid pixel depth
    if (depth != 8 && depth != 16 && depth != 32)
    {
        png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
        throw std::runtime_error (std::string ("Invalid bit depth in ") + filename);
    }

    // convert depth to OpenGL data type
    const GLuint types[] = {
        GL_UNSIGNED_BYTE,
        GL_UNSIGNED_SHORT,
        0,
        GL_UNSIGNED_INT
    };
    GLuint type = types [(depth / 8) - 1];

    // assure a valid number of channels
    if (channels < 1 || channels > 4)
    {
        png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
        throw std::runtime_error (std::string ("Invalid number of channels.") + filename);
    }

    // convert the number of channels to an OpenGL format
    const GLuint formats[] = {
        GL_RED, GL_RG, GL_RGB, GL_RGBA
    };
    GLuint format = formats[channels - 1];

    // read the image data
    std::vector<GLubyte> data;
    data.resize (rowbytes * height);
    int i;
    for (i = 0; i < height; i++)
    {
        png_read_row (png_ptr, &data[i * rowbytes], NULL);
    }

    // cleanup libpng
    png_destroy_read_struct (&png_ptr, &info_ptr, NULL);

    // pass the image data to OpenGL
    glTexImage2D (target, 0, internalformat, width, height, 0, format, type, &data[0]);
}
示例#20
0
BOOL OutputPNG::OutputPNGHeader(CCLexFile *File, LPBITMAPINFOHEADER pInfo,
                                BOOL InterlaceState, INT32 TransparentColour,
                                LPLOGPALETTE pPalette, LPRGBQUAD pQuadPalette)
{
    ERROR2IF(File==NULL,FALSE,"OutputPNG::OutputPNGHeader File pointer is null");
    if (pInfo == NULL)
        pInfo = &(DestBitmapInfo->bmiHeader);
    ERROR2IF(pInfo==NULL,FALSE,"OutputPNG::OutputPNGHeader BitmapInfo pointer is null");
    //ERROR2IF(pPalette==NULL && pQuadPalette==NULL,FALSE,"OutputPNG::OutputPNGHeader Bitmap palette pointer is null");

    TRACEUSER( "Jonathan", _T("PNG write: Interlace: %s\n"), InterlaceState ? _T("Yes") : _T("No"));

    // Note file in our class variable as used by all the low level routines
    OutputFile = File;

    // Note the specified transparency and interlace states in our class variables
    Interlace = InterlaceState;
    if (TransparentColour != -1)
        Transparent = TRUE;
    else
        Transparent = FALSE;

    // We are just about to start so set the PNG exception handling up with our CCFile pointer
    PNGUtil::SetCCFilePointer(File);

    // Must set the exception throwing flag to True and force reporting of errors to False.
    // This means that the caller must report an error if the function returns False.
    // Any calls to CCFile::GotError will now throw a file exception and should fall into
    // the catch handler at the end of the function.
    // Replaces the goto's that handled this before.
    BOOL OldThrowingState = File->SetThrowExceptions( TRUE );
    BOOL OldReportingState = File->SetReportErrors( FALSE );

    // PNG related items (NOTE: p at end means pointer and hence implied *)
    png_ptr		= NULL;
    info_ptr	= NULL;

    palette = NULL;

    try
    {
        // Work out the palette size
        INT32 PalSize = pInfo->biClrUsed;		// How many entries in palette
        TRACEUSER( "Jonathan", _T("PNG write: PalSize = %d\n"),PalSize);

        // Set up the class variables
        // First the width/height of the bitmap
        Width = pInfo->biWidth;
        Height = pInfo->biHeight;
        TRACEUSER( "Jonathan", _T("PNG write: Width = %d Height = %d\n"),Width,Height);

        BitsPerPixel = pInfo->biBitCount;

        // Start up the PNG writing code

        // allocate the necessary structures
        // Use the default handlers
        png_ptr = png_create_write_struct_2(
                      PNG_LIBPNG_VER_STRING,	// libpng version
                      0,						// Optional pointer to be sent with errors
                      camelot_png_error,		// Function called in case of error
                      camelot_png_warning,	// Function called for warnings
                      0,						// Optional pointer to be sent with mem ops
                      camelot_png_malloc,		// Function called to alloc memory
                      camelot_png_free		// Function called to free memory
                  );

        if (!png_ptr)
            File->GotError( _R(IDS_OUT_OF_MEMORY) );

        info_ptr = png_create_info_struct(png_ptr);
        if (!info_ptr)
        {
            png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
            File->GotError( _R(IDS_OUT_OF_MEMORY) );
        }

        // set up the input control to the fstream class
        // If not a disk file then panic for the present moment
        // Could use the memfile functions for reading and writing as they give us what
        // we want. Use the io_ptr and
        iostream* pFStream = File->GetIOFile();
        if (pFStream == NULL)
        {
            TRACEUSER( "Jonathan", _T("PNG write: OutputPNG::OutputPNGHeader No access to IOStream!"));
            File->GotError( _R(IDS_UNKNOWN_PNG_ERROR) );
        }

        // Should use our own function
        png_set_write_fn(png_ptr, pFStream, camelot_png_write_data, camelot_png_flush_data);
        // png_init_io(png_ptr, pFStream);

        // You now have the option of modifying how the compression library
        // will run.  The following functions are mainly for testing, but
        // may be useful in certain special cases, like if you need to
        // write png files extremely fast and are willing to give up some
        // compression, or if you want to get the maximum possible compression
        // at the expense of slower writing.  If you have no special needs
        // in this area, let the library do what it wants, as it has been
        // carefully tuned to deliver the best speed/compression ratio.
        // See the compression library for more details.

        // turn on or off filtering (1 or 0)
        //png_set_filtering(png_ptr, 1);

        // compression level (0 - none, 6 - default, 9 - maximum)
        //png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
        //png_set_compression_mem_level(png_ptr, 8);
        //png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
        //png_set_compression_window_bits(png_ptr, 15);
        //png_set_compression_method(png_ptr, 8);

        // - this describes which optional chunks to write to the
        // file.  Note that if you are writing a
        // PNG_COLOR_TYPE_PALETTE file, the PLTE chunk is not
        // optional, but must still be marked for writing.  To
        // mark chunks for writing, OR valid with the
        // appropriate PNG_INFO_<chunk name> define.
        png_get_valid(png_ptr, info_ptr, 0);

        // resolution of image
        png_set_invalid(png_ptr, info_ptr, PNG_INFO_pHYs);
        png_set_pHYs(png_ptr, info_ptr,
                     pInfo->biXPelsPerMeter,
                     pInfo->biYPelsPerMeter,
                     1); //meter
        TRACEUSER( "Jonathan", _T("PNG write: x,y px per cm = %d %d\n"),
                   png_get_x_pixels_per_meter(png_ptr, info_ptr) / 1000,
                   png_get_y_pixels_per_meter(png_ptr, info_ptr) / 1000);

        BitsPerPixel				= pInfo->biBitCount;
        TRACEUSER( "Jonathan", _T("PNG write: Bitdepth = %d\n"), BitsPerPixel);
        palette		= NULL;
        num_palette	= 0;
        trans		= NULL;	// - array of transparent entries for paletted images
        num_trans	= 0;	// - number of transparent entries
        TRACEUSER( "Jonathan", _T("PNG write: TransColour = %d\n"), TransparentColour);
        if ( BitsPerPixel <= 8 )
        {
            png_set_IHDR(png_ptr, info_ptr,
                         Width,
                         Height,
                         BitsPerPixel,
                         PNG_COLOR_TYPE_PALETTE,
                         PNG_INTERLACE_NONE,
                         PNG_COMPRESSION_TYPE_BASE,
                         PNG_FILTER_TYPE_BASE);

            // set the palette if there is one
            png_set_invalid(png_ptr, info_ptr, PNG_INFO_PLTE);
            INT32 PaletteEntries = pInfo->biClrUsed;

            palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof (png_color));
            if (palette == NULL)
                File->GotError( _R(IDS_OUT_OF_MEMORY) );

            png_set_PLTE(png_ptr, info_ptr, palette, num_palette);
            png_color_struct * pPNGPalette = palette;
            // ... set palette colors ...
            if (pQuadPalette && PaletteEntries > 0)
            {
                // Palette supplied in RGBQUAD form
                for (INT32 i = 0; i < PaletteEntries; i++)
                {
                    pPNGPalette->red 	= pQuadPalette->rgbRed;
                    pPNGPalette->green 	= pQuadPalette->rgbGreen;
                    pPNGPalette->blue 	= pQuadPalette->rgbBlue;
                    // skip to the next palette entry
                    pQuadPalette++;
                    pPNGPalette++;
                }
            }
            else if (pPalette && PaletteEntries > 0)
            {
                // Palette supplied in LOGPALETTE form
                for (INT32 i = 0; i < PaletteEntries; i++)
                {
                    pPNGPalette->red  	= pPalette->palPalEntry[i].peRed;
                    pPNGPalette->green 	= pPalette->palPalEntry[i].peGreen;
                    pPNGPalette->blue 	= pPalette->palPalEntry[i].peBlue;
                    pPNGPalette++;
                }
            }
            else
                File->GotError(_R(IDS_PNG_ERR_WRITE_PALETTE));

            // Now check to see if transparency is present or not
            if (TransparentColour >= 0 && TransparentColour <= PaletteEntries )
            {
                // Create the array of transparent entries for this palette
                // 0 is fully transparent, 255 is fully opaque, regardless of image bit depth
                // We will only create as many as we require, i.e. up to the transparent colour entry
                // rather a full palettes worth
                INT32 NumEntries = TransparentColour + 1;
                trans = (png_byte*)png_malloc(png_ptr, NumEntries * sizeof (png_byte));
                if (trans)
                {
                    // Set the number of transparent entries
                    num_trans			= NumEntries;
                    png_byte * pTransEntry		= trans;
                    png_set_invalid(png_ptr, info_ptr, PNG_INFO_tRNS);
                    for (INT32 i = 0; i < TransparentColour; i++)
                    {
                        *pTransEntry = 255;	// set it fully opaque
                        pTransEntry++;
                    }
                    // We should now be at the transparent entry so set it fully transparent
                    *pTransEntry = 0;
                }
            }
        }
        else if (BitsPerPixel == 24)
        {
            png_set_IHDR(png_ptr, info_ptr,
                         Width,
                         Height,
                         8, /* bit_depth */
                         PNG_COLOR_TYPE_RGB,
                         PNG_INTERLACE_NONE,
                         PNG_COMPRESSION_TYPE_BASE,
                         PNG_FILTER_TYPE_BASE);
        }
        else if (BitsPerPixel == 32)
        {
            png_set_IHDR(png_ptr, info_ptr,
                         Width,
                         Height,
                         8, /* bit_depth */
                         PNG_COLOR_TYPE_RGB_ALPHA,
                         PNG_INTERLACE_NONE,
                         PNG_COMPRESSION_TYPE_BASE,
                         PNG_FILTER_TYPE_BASE);
        }
        else
            ERROR2(FALSE,"OutputPNG::OutputPNGHeader Unknown bit depth");

        TRACEUSER( "Jonathan", _T("PNG write: bit_depth = %d color_type = %d\n"),
                   png_get_bit_depth(png_ptr, info_ptr),
                   png_get_color_type(png_ptr, info_ptr));

        // Could use:-
        // if we are dealing with a grayscale image then
        //info_ptr->sig_bit.gray = true_bit_depth;

        png_set_hIST(png_ptr, info_ptr, NULL);
        png_set_text(png_ptr, info_ptr, NULL, 0);


        // write the file information
        png_write_info(png_ptr, info_ptr);

        TRACEUSER( "Jonathan", _T("PNG write: pixel_depth %d channels %d\n"),
                   png_get_bit_depth(png_ptr, info_ptr),
                   png_get_channels(png_ptr, info_ptr));
        TRACEUSER( "Jonathan", _T("PNG write: rowbytes %d color_type %d\n"),
                   png_get_rowbytes(png_ptr, info_ptr),
                   png_get_color_type(png_ptr, info_ptr));
        // Set up the transformations you want.
        // Note: that these are all optional.  Only call them if you want them

        // invert monocrome pixels
        //png_set_invert(png_ptr);

        // shift the pixels up to a legal bit depth and fill in as appropriate
        // to correctly scale the image
        //png_set_shift(png_ptr, &(info_ptr->sig_bit));

        // pack pixels into bytes
        //png_set_packing(png_ptr);

        png_set_bgr(png_ptr);

        // swap bytes of 16 bit files to most significant bit first
        png_set_swap(png_ptr);

        // Must set the exception throwing and reporting flags back to their entry states
        File->SetThrowExceptions( OldThrowingState );
        File->SetReportErrors( OldReportingState );

        // er, we seem to have finished OK so say so
        return TRUE;
    }

    catch (...)
    {
        // catch our form of a file exception
        TRACE( _T("OutputPNG::OutputPNGHeader CC catch handler\n"));

        // Call up function to clean up the png structures
        CleanUpPngStructures();

        // Must set the exception throwing and reporting flags back to their entry states
        File->SetThrowExceptions( OldThrowingState );
        File->SetReportErrors( OldReportingState );

        // We have finished so reset the PNG exception handling
        PNGUtil::SetCCFilePointer(NULL);

        return FALSE;
    }

    ERROR2( FALSE, "Escaped exception clause somehow" );
}
示例#21
0
文件: png.cpp 项目: 2asoft/xray
BMMRES
BitmapIO_PNG::Save(const TCHAR *filename, Bitmap *map) 
{
    if(!map)
		return(ProcessImageIOError(&bi,BMMRES_INTERNALERROR));
    
    openMode = BMM_OPEN_W;
    
    if((ostream = _tfopen(filename,_T("wb"))) == NULL)
		return (ProcessImageIOError(&bi));

	BitmapStorage *palettedStorage = NULL;

    png = png_create_write_struct (PNG_VERSION, (void *) this, error_func, warning_func);
    if (setjmp(png->jmpbuf)) {
		if (info)
            for (png_uint_32 i = 0; i < info->height; i++)
			    if (row_pointers[i]) free(row_pointers[i]);
		if (row_pointers) {
			free(row_pointers);
			row_pointers = NULL;
		}

		if (palettedStorage) delete palettedStorage;
        fclose(ostream);
		_tremove(filename);
        png_destroy_write_struct (&png, &info);
        return BMMRES_IOERROR;
    }
    info = png_create_info_struct(png);

    png_init_io(png, ostream);

	switch(cfg.color_type) {
	case PngPalette:
		info->color_type = PNG_COLOR_TYPE_PALETTE;
		info->pixel_depth = 8;
		info->valid |= PNG_INFO_PLTE;
		info->num_palette = 256;
		break;
	case PngRGB:
		info->color_type = PNG_COLOR_TYPE_RGB;
		break;
	case PngRGBA:
		info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
		break;
	case PngGray:
		info->color_type = PNG_COLOR_TYPE_GRAY;
		break;
	case PngGrayA:
		info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
		break;
	}
	info->width = map->Width();
	info->height = map->Height();
	if (OutputGamma() != 1.0f) {
		info->valid |= PNG_INFO_gAMA;
		info->gamma = OutputGamma();
	} else info->gamma = 1.0f;

	if (map->Aspect() != 1.0f) {
		info->valid |= PNG_INFO_pHYs;
		info->x_pixels_per_unit = (png_uint_32)(1024.0f * map->Aspect());
		info->y_pixels_per_unit = 1024;
		info->phys_unit_type = 0;
	}

	if (cfg.interlaced)
		info->interlace_type = 1;
	else
		info->interlace_type = 0;

	switch( info->color_type) {
	case PNG_COLOR_TYPE_PALETTE:
	case PNG_COLOR_TYPE_GRAY:
		info->channels = 1;
		break;
	case PNG_COLOR_TYPE_GRAY_ALPHA:
		info->channels = 2;
		break;
	case PNG_COLOR_TYPE_RGB:
		info->channels = 3;
		break;
	case PNG_COLOR_TYPE_RGB_ALPHA:
		info->channels = 4;
		break;
	}

	info->bit_depth = cfg.bitdepth;
	info->rowbytes = info->width * info->channels * info->bit_depth / 8;

	row_pointers = (png_bytep *)malloc(info->height * sizeof(png_bytep));
	for (png_uint_32 i = 0; i < info->height; i++)
		row_pointers[i] = (png_bytep)malloc(info->rowbytes);

	switch (info->bit_depth) {
	case 16:  // this is only RGB/RGBA/Gray/GrayA
		switch(info->color_type) {
		case PNG_COLOR_TYPE_RGB:
		case PNG_COLOR_TYPE_RGB_ALPHA:
			{
			BMM_Color_64 *line64 = (BMM_Color_64 *) calloc(info->width,sizeof(BMM_Color_64));
			for (png_uint_32 iy = 0; iy < info->height; ++iy) {
				if (GetOutputPixels(0, iy, info->width, line64) != 1) {
					for (png_uint_32 i = 0; i < info->height; i++)
						if (row_pointers[i]) free(row_pointers[i]);
					if (row_pointers) {
						free(row_pointers);
						row_pointers = NULL;
					}

					fclose(ostream);
					_tremove(filename);
					free(line64);
                    png_destroy_write_struct (&png, &info);
					return BMMRES_IOERROR;
				}
				BMM_Color_64 *l64=line64;
				unsigned short *oshort = (unsigned short *)row_pointers[iy];
				for (png_uint_32 ix = 0; ix < info->width; ++l64, ix++) {
					*oshort = (unsigned short)l64->r; oshort++;
					*oshort = (unsigned short)l64->g; oshort++;
					*oshort = (unsigned short)l64->b; oshort++;
					if (info->channels == 4) {
						*oshort = (unsigned short)l64->a; oshort++;
					}
				}
			}
			free(line64);
			}
			break;
		case PNG_COLOR_TYPE_GRAY:
			{
			for (png_uint_32 iy = 0; iy < info->height; ++iy)
				if (map->Get16Gray(0, iy, info->width, (unsigned short *)row_pointers[iy]) != 1) {
					for (png_uint_32 i = 0; i < info->height; i++)
						if (row_pointers[i]) free(row_pointers[i]);
					if (row_pointers) {
						free(row_pointers);
						row_pointers = NULL;
					}

					fclose(ostream);
					_tremove(filename);
                    png_destroy_write_struct (&png, &info);
					return BMMRES_IOERROR;
				}
			}
			break;
		case PNG_COLOR_TYPE_GRAY_ALPHA:
			{
			BMM_Color_64 *line64 = (BMM_Color_64 *) calloc(info->width, sizeof(BMM_Color_64));
			unsigned short *line = (unsigned short *) calloc(info->width, sizeof(unsigned short));
			for (png_uint_32 iy = 0; iy < info->height; ++iy) {
				if (GetOutputPixels(0, iy, info->width, line64) != 1 ||
					map->Get16Gray(0, iy, info->width, line) != 1) {
					for (png_uint_32 i = 0; i < info->height; i++)
						if (row_pointers[i]) free(row_pointers[i]);
					if (row_pointers) {
						free(row_pointers);
						row_pointers = NULL;
					}
					free(line64);
					free(line);
					fclose(ostream);
					_tremove(filename);
                    png_destroy_write_struct (&png, &info);
					return BMMRES_IOERROR;
				}
				BMM_Color_64 *l64 = line64;
				unsigned short *l=line;
				unsigned short *oshort = (unsigned short *)row_pointers[iy];
				for (png_uint_32 ix = 0; ix < info->width; ix++, l64++) {
					*oshort++ = *l++;
					*oshort++ = (unsigned short)l64->a;
				}
			}
			free(line64);
			free(line);
			}
			break;
		}
		break;

	case 8: // this can be any type
		switch(info->color_type) {
		case PNG_COLOR_TYPE_PALETTE: {
			// Set up a palette buffer
			PixelBuf48 palettebuf(info->num_palette);
			BMM_Color_48 *pal = palettebuf.Ptr();
			// Must compute a color palette, and reduce the image to 256 colors!
			// this calculates a palette based on the gamma corrected values, which
			// corresponds to what GetOutputPixels returns.
			if(CalcOutputPalette(256, pal) == 0) {
				for (png_uint_32 i = 0; i < info->height; i++)
					if (row_pointers[i]) free(row_pointers[i]);
				if (row_pointers) {
					free(row_pointers);
					row_pointers = NULL;
				}
				fclose(ostream);
				_tremove(filename);
                png_destroy_write_struct (&png, &info);
				return BMMRES_IOERROR;
			}
			info->palette = (png_color *)malloc(info->num_palette * sizeof(png_color));
			for (int i = 0; i < info->num_palette; i++) {
				info->palette[i].red = (unsigned char)(pal[i].r >> 8);
				info->palette[i].green = (unsigned char)(pal[i].g >> 8);
				info->palette[i].blue = (unsigned char)(pal[i].b >> 8);
			}
			PixelBuf64 line(info->width);
			ColorPacker* cpack = BMMNewColorPacker(info->width, pal, info->num_palette);
			for (png_uint_32 iy=0; iy < info->height; ++iy) {
				if(!GetOutputPixels(0, iy, info->width, line.Ptr())) {
					for (png_uint_32 i = 0; i < info->height; i++)
						if (row_pointers[i]) free(row_pointers[i]);
					if (row_pointers) {
						free(row_pointers);
						row_pointers = NULL;
					}
					fclose(ostream);
					_tremove(filename);
                    png_destroy_write_struct (&png, &info);
					return BMMRES_IOERROR;
				}
				cpack->PackLine(line.Ptr(), row_pointers[iy], info->width);
			}
			cpack->DeleteThis();
			}
			break;
		case PNG_COLOR_TYPE_RGB:
		case PNG_COLOR_TYPE_RGB_ALPHA:
			{
			BMM_Color_32 *line32 = (BMM_Color_32 *) calloc(info->width,sizeof(BMM_Color_32));
			for (png_uint_32 iy = 0; iy < info->height; ++iy) {
				if (GetDitheredOutputPixels(0, iy, info->width, line32) != 1) {
					for (png_uint_32 i = 0; i < info->height; i++)
						if (row_pointers[i]) free(row_pointers[i]);
					if (row_pointers) {
						free(row_pointers);
						row_pointers = NULL;
					}

					fclose(ostream);
					_tremove(filename);
					free(line32);
                    png_destroy_write_struct (&png, &info);
					return BMMRES_IOERROR;
				}
				BMM_Color_32 *l32=line32;
				unsigned char *obyte = (unsigned char *)row_pointers[iy];
				for (png_uint_32 ix = 0; ix < info->width; ++l32, ix++) {
					*obyte = (unsigned char)l32->r; obyte++;
					*obyte = (unsigned char)l32->g; obyte++;
					*obyte = (unsigned char)l32->b; obyte++;
					if (info->channels == 4) {
						*obyte = (unsigned char)l32->a; obyte++;
					}
				}
			}
			free(line32);
			}
			break;
		case PNG_COLOR_TYPE_GRAY:
			{
			unsigned short *line = (unsigned short *) calloc(info->width * info->channels, sizeof(unsigned short));
			for (png_uint_32 iy = 0; iy < info->height; ++iy) {
				if (map->Get16Gray(0, iy, info->width, line) != 1) {
					for (png_uint_32 i = 0; i < info->height; i++)
						if (row_pointers[i]) free(row_pointers[i]);
					if (row_pointers) {
						free(row_pointers);
						row_pointers = NULL;
					}

					fclose(ostream);
					_tremove(filename);
					free(line);
                    png_destroy_write_struct (&png, &info);
					return BMMRES_IOERROR;
				}
				unsigned short *l=line;
				unsigned char *obyte = (unsigned char *)row_pointers[iy];
				for (png_uint_32 ix = 0; ix < info->width; ix++) {
					*obyte++ = (unsigned char)(*l >> 8); l++;
				}
			}
			free(line);
			}
			break;
		case PNG_COLOR_TYPE_GRAY_ALPHA:
			{
			BMM_Color_64 *line64 = (BMM_Color_64 *) calloc(info->width,sizeof(BMM_Color_64));
			unsigned short *line = (unsigned short *) calloc(info->width, sizeof(unsigned short));
			for (png_uint_32 iy = 0; iy < info->height; ++iy) {
				if (GetOutputPixels(0, iy, info->width, line64) != 1 ||
					map->Get16Gray(0, iy, info->width, line) != 1) {
					for (png_uint_32 i = 0; i < info->height; i++)
						if (row_pointers[i]) free(row_pointers[i]);
					if (row_pointers) {
						free(row_pointers);
						row_pointers = NULL;
					}

					fclose(ostream);
					_tremove(filename);
					free(line);
					free(line64);
                    png_destroy_write_struct (&png, &info);
					return BMMRES_IOERROR;
				}
				unsigned short *l=line;
				BMM_Color_64 *l64 = line64;
				unsigned char *obyte = (unsigned char *)row_pointers[iy];
				for (png_uint_32 ix = 0; ix < info->width; ix++, l64++) {
					*obyte++ = (unsigned char)(*l >> 8); l++;
					*obyte++ = (unsigned char)(l64->a >> 8);
				}
			}
			free(line);
			free(line64);
			}
			break;
		}
		break;
#ifdef OUTPUT_1_2_4
	case 4: { // Paletted only
		}
		break;
	case 2: { // Paletted only
		}
		break;
	case 1: { // Paletted only
		}
#endif
		break;
	}

	png_write_info(png, info);

	png_set_swap(png);

	png_write_image(png, row_pointers);

	png_write_end(png, info);
	fclose(ostream);

 	for (i = 0; i < info->height; i++)
		free(row_pointers[i]);

	free(row_pointers);

    png_destroy_write_struct (&png, &info);

    return BMMRES_SUCCESS;
}
示例#22
0
unsigned char * readPNG(const char * filename, int & width, int & height, int & channels) {


    FILE * file = fopen(filename, "r");

    unsigned char sig[8];
    size_t nRead = fread(sig, 1, 8, file);

    if (!png_check_sig(sig,8) || nRead != 8) {
        std::cerr << filename << " is not a valid png file" << std::endl;
        fclose(file);
        return 0;
    }

    mainprog_info progInfo;

    png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, &progInfo, png_error_handler, NULL);
    if (!pngPtr) {
        std::cerr << "could not create png pointer" << std::endl;
        fclose(file);
        return 0;
    }

    png_infop infoPtr = png_create_info_struct(pngPtr);
    if (!infoPtr) {
        png_destroy_read_struct(&pngPtr,NULL,NULL);
        std::cerr << "could not create info pointer" << std::endl;
        fclose(file);
        return 0;
    }

    if (setjmp(progInfo.jmpbuf)) {
        png_destroy_read_struct(&pngPtr, &infoPtr, NULL);
        fclose(file);
        return 0;
    }

    png_init_io(pngPtr, file);
    png_set_sig_bytes(pngPtr, 8);
    png_read_info(pngPtr, infoPtr);
    png_set_swap(pngPtr);

    int colorType, bitDepth;
    png_uint_32 pngWidth, pngHeight;
    png_get_IHDR(pngPtr, infoPtr, &pngWidth, &pngHeight, &bitDepth, &colorType, NULL, NULL, NULL);

    channels = (int)png_get_channels(pngPtr, infoPtr);
    width = pngWidth;
    height = pngHeight;

    png_uint_32 i;
    png_bytep rowPointers[height];

    unsigned char * data = new unsigned char[width*height*channels*bitDepth/8];

    png_read_update_info(pngPtr,infoPtr);
    for (i=0; i<height; ++i) {
        rowPointers[i] = ((png_bytep)data) + i*png_get_rowbytes(pngPtr,infoPtr);
    }

    png_read_image(pngPtr,rowPointers);

    png_read_end(pngPtr, NULL);

    png_destroy_read_struct(&pngPtr, &infoPtr, NULL);

    fclose(file);
    return data;

}
示例#23
0
static BOOL DLL_CALLCONV
Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
	png_structp png_ptr;
	png_infop info_ptr;
	png_colorp palette = NULL;
	png_uint_32 width, height;
	BOOL has_alpha_channel = FALSE;

	RGBQUAD *pal;					// pointer to dib palette
	int bit_depth, pixel_depth;		// pixel_depth = bit_depth * channels
	int palette_entries;
	int	interlace_type;

	fi_ioStructure fio;
    fio.s_handle = handle;
	fio.s_io = io;

	if ((dib) && (handle)) {
		try {
			// create the chunk manage structure

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

			if (!png_ptr)  {
				return FALSE;
			}

			// allocate/initialize the image information data.

			info_ptr = png_create_info_struct(png_ptr);

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

			// Set error handling.  REQUIRED if you aren't supplying your own
			// error handling functions in the png_create_write_struct() call.

			if (setjmp(png_jmpbuf(png_ptr)))  {
				// if we get here, we had a problem reading the file

				png_destroy_write_struct(&png_ptr, &info_ptr);

				return FALSE;
			}

			// init the IO
            
			png_set_write_fn(png_ptr, &fio, _WriteProc, _FlushProc);

			// set physical resolution

			png_uint_32 res_x = (png_uint_32)FreeImage_GetDotsPerMeterX(dib);
			png_uint_32 res_y = (png_uint_32)FreeImage_GetDotsPerMeterY(dib);

			if ((res_x > 0) && (res_y > 0))  {
				png_set_pHYs(png_ptr, info_ptr, res_x, res_y, PNG_RESOLUTION_METER);
			}
	
			// Set the image information here.  Width and height are up to 2^31,
			// bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
			// the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
			// PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
			// or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
			// PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
			// currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED

			width = FreeImage_GetWidth(dib);
			height = FreeImage_GetHeight(dib);
			pixel_depth = FreeImage_GetBPP(dib);

			BOOL bInterlaced = FALSE;
			if( (flags & PNG_INTERLACED) == PNG_INTERLACED) {
				interlace_type = PNG_INTERLACE_ADAM7;
				bInterlaced = TRUE;
			} else {
				interlace_type = PNG_INTERLACE_NONE;
			}

			// set the ZLIB compression level or default to PNG default compression level (ZLIB level = 6)
			int zlib_level = flags & 0x0F;
			if((zlib_level >= 1) && (zlib_level <= 9)) {
				png_set_compression_level(png_ptr, zlib_level);
			} else if((flags & PNG_Z_NO_COMPRESSION) == PNG_Z_NO_COMPRESSION) {
				png_set_compression_level(png_ptr, Z_NO_COMPRESSION);
			}

			// filtered strategy works better for high color images
			if(pixel_depth >= 16){
				png_set_compression_strategy(png_ptr, Z_FILTERED);
				png_set_filter(png_ptr, 0, PNG_FILTER_NONE|PNG_FILTER_SUB|PNG_FILTER_PAETH);
			} else {
				png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
			}

			FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
			if(image_type == FIT_BITMAP) {
				// standard image type
				bit_depth = (pixel_depth > 8) ? 8 : pixel_depth;
			} else {
				// 16-bit greyscale or 16-bit RGB(A)
				bit_depth = 16;
			}

			switch (FreeImage_GetColorType(dib)) {
				case FIC_MINISWHITE:
					// Invert monochrome files to have 0 as black and 1 as white (no break here)
					png_set_invert_mono(png_ptr);

				case FIC_MINISBLACK:
					png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, 
						PNG_COLOR_TYPE_GRAY, interlace_type, 
						PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

					break;

				case FIC_PALETTE:
				{
					png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, 
						PNG_COLOR_TYPE_PALETTE, interlace_type, 
						PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

					// set the palette

					palette_entries = 1 << bit_depth;
					palette = (png_colorp)png_malloc(png_ptr, palette_entries * sizeof (png_color));
					pal = FreeImage_GetPalette(dib);

					for (int i = 0; i < palette_entries; i++) {
						palette[i].red   = pal[i].rgbRed;
						palette[i].green = pal[i].rgbGreen;
						palette[i].blue  = pal[i].rgbBlue;
					}
					
					png_set_PLTE(png_ptr, info_ptr, palette, palette_entries);

					// You must not free palette here, because png_set_PLTE only makes a link to
					// the palette that you malloced.  Wait until you are about to destroy
					// the png structure.

					break;
				}

				case FIC_RGBALPHA :
					has_alpha_channel = TRUE;

					png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, 
						PNG_COLOR_TYPE_RGBA, interlace_type, 
						PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
					// flip BGR pixels to RGB
					if(image_type == FIT_BITMAP) {
						png_set_bgr(png_ptr);
					}
#endif
					break;
	
				case FIC_RGB:
					png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, 
						PNG_COLOR_TYPE_RGB, interlace_type, 
						PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
					// flip BGR pixels to RGB
					if(image_type == FIT_BITMAP) {
						png_set_bgr(png_ptr);
					}
#endif
					break;
					
				case FIC_CMYK:
					break;
			}

			// write possible ICC profile

			FIICCPROFILE *iccProfile = FreeImage_GetICCProfile(dib);
			if (iccProfile->size && iccProfile->data) {
				png_set_iCCP(png_ptr, info_ptr, "Embedded Profile", 0, (png_const_bytep)iccProfile->data, iccProfile->size);
			}

			// write metadata

			WriteMetadata(png_ptr, info_ptr, dib);

			// Optional gamma chunk is strongly suggested if you have any guess
			// as to the correct gamma of the image.
			// png_set_gAMA(png_ptr, info_ptr, gamma);

			// set the transparency table

			if (FreeImage_IsTransparent(dib) && (FreeImage_GetTransparencyCount(dib) > 0)) {
				png_set_tRNS(png_ptr, info_ptr, FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib), NULL);
			}

			// set the background color

			if(FreeImage_HasBackgroundColor(dib)) {
				png_color_16 image_background;
				RGBQUAD rgbBkColor;

				FreeImage_GetBackgroundColor(dib, &rgbBkColor);
				memset(&image_background, 0, sizeof(png_color_16));
				image_background.blue  = rgbBkColor.rgbBlue;
				image_background.green = rgbBkColor.rgbGreen;
				image_background.red   = rgbBkColor.rgbRed;
				image_background.index = rgbBkColor.rgbReserved;

				png_set_bKGD(png_ptr, info_ptr, &image_background);
			}
			
			// Write the file header information.

			png_write_info(png_ptr, info_ptr);

			// write out the image data

#ifndef FREEIMAGE_BIGENDIAN
			if (bit_depth == 16) {
				// turn on 16 bit byte swapping
				png_set_swap(png_ptr);
			}
#endif

			int number_passes = 1;
			if (bInterlaced) {
				number_passes = png_set_interlace_handling(png_ptr);
			}

			if ((pixel_depth == 32) && (!has_alpha_channel)) {
				BYTE *buffer = (BYTE *)malloc(width * 3);

				// transparent conversion to 24-bit
				// the number of passes is either 1 for non-interlaced images, or 7 for interlaced images
				for (int pass = 0; pass < number_passes; pass++) {
					for (png_uint_32 k = 0; k < height; k++) {
						FreeImage_ConvertLine32To24(buffer, FreeImage_GetScanLine(dib, height - k - 1), width);			
						png_write_row(png_ptr, buffer);
					}
				}
				free(buffer);
			} else {
				// the number of passes is either 1 for non-interlaced images, or 7 for interlaced images
				for (int pass = 0; pass < number_passes; pass++) {
					for (png_uint_32 k = 0; k < height; k++) {			
						png_write_row(png_ptr, FreeImage_GetScanLine(dib, height - k - 1));					
					}
				}
			}

			// It is REQUIRED to call this to finish writing the rest of the file
			// Bug with png_flush

			png_write_end(png_ptr, info_ptr);

			// clean up after the write, and free any memory allocated
			if (palette) {
				png_free(png_ptr, palette);
			}

			png_destroy_write_struct(&png_ptr, &info_ptr);

			return TRUE;
		} catch (const char *text) {
			FreeImage_OutputMessageProc(s_format_id, text);
		}
	}

	return FALSE;
}
示例#24
0
static int VS_CC read_png(img_hnd_t *ih, int n)
{
    FILE *fp = imgr_fopen(ih->src[n].name);
    if (!fp) {
        return -1;
    }

    png_structp p_str =
        png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!p_str) {
        fclose(fp);
        return -1;
    }

    png_infop p_info = png_create_info_struct(p_str);
    if (!p_info) {
        fclose(fp);
        png_destroy_read_struct(&p_str, NULL, NULL);
        return -1;
    }

    png_init_io(p_str, fp);
    png_read_info(p_str, p_info);

    png_uint_32 width, height;
    int color_type, bit_depth;
    png_get_IHDR(p_str, p_info, &width, &height, &bit_depth, &color_type,
                 NULL, NULL, NULL);
    if (color_type & PNG_COLOR_TYPE_PALETTE) {
        png_set_palette_to_rgb(p_str);
    }
    if (bit_depth < 8) {
        png_set_packing(p_str);
    }
    if (bit_depth > 8) {
        png_set_swap(p_str);
    }
    if (ih->enable_alpha == 0) {
        if (color_type & PNG_COLOR_MASK_ALPHA) {
            png_set_strip_alpha(p_str);
        }
    } else if ((color_type & PNG_COLOR_MASK_ALPHA) == 0) {
        png_set_add_alpha(p_str, 0x00, PNG_FILLER_AFTER);
    }
    png_read_update_info(p_str, p_info);
    png_read_image(p_str, ih->png_row_index);

    fclose(fp);
    png_destroy_read_struct(&p_str, &p_info, NULL);

    ih->misc = IMG_ORDER_RGB;
    ih->row_adjust = 1;

    switch ((ih->src[n].format->id << 1) | ih->enable_alpha) {
    case (pfRGB24 << 1 | 0):
        ih->write_frame = func_write_rgb24;
        break;
    case (pfRGB24 << 1 | 1):
        ih->write_frame = func_write_rgb32;
        break;
    case (pfRGB48 << 1 | 0):
        ih->write_frame = func_write_rgb48;
        break;
    case (pfRGB48 << 1 | 1):
        ih->write_frame = func_write_rgb64;
        break;
    case (pfGray8 << 1 | 0):
    case (pfGray16 << 1 | 0):
        ih->write_frame = func_write_planar;
        break;
    case (pfGray8 << 1 | 1):
        ih->write_frame = func_write_gray8_a;
        break;
    case (pfGray16 << 1 | 1):
        ih->write_frame = func_write_gray16_a;
        break;
    default:
        break;
    }

    return 0;
}
示例#25
0
文件: grfmt_png.cpp 项目: 2693/opencv
bool  PngEncoder::write( const Mat& img, const vector<int>& params )
{
    png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
    png_infop info_ptr = 0;
    FILE* f = 0;
    int y, width = img.cols, height = img.rows;
    int depth = img.depth(), channels = img.channels();
    bool result = false;
    AutoBuffer<uchar*> buffer;

    if( depth != CV_8U && depth != CV_16U )
        return false;

    if( png_ptr )
    {
        info_ptr = png_create_info_struct( png_ptr );

        if( info_ptr )
        {
            if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 )
            {
                if( m_buf )
                {
                    png_set_write_fn(png_ptr, this,
                        (png_rw_ptr)writeDataToBuf, (png_flush_ptr)flushBuf);
                }
                else
                {
                    f = fopen( m_filename.c_str(), "wb" );
                    if( f )
                        png_init_io( png_ptr, f );
                }

                int compression_level = -1; // Invalid value to allow setting 0-9 as valid
                int compression_strategy = Z_RLE; // Default strategy
                bool isBilevel = false;

                for( size_t i = 0; i < params.size(); i += 2 )
                {
                    if( params[i] == CV_IMWRITE_PNG_COMPRESSION )
                    {
                        compression_level = params[i+1];
                        compression_level = MIN(MAX(compression_level, 0), Z_BEST_COMPRESSION);
                    }
                    if( params[i] == CV_IMWRITE_PNG_STRATEGY )
                    {
                        compression_strategy = params[i+1];
                        compression_strategy = MIN(MAX(compression_strategy, 0), Z_FIXED);
                    }
                    if( params[i] == CV_IMWRITE_PNG_BILEVEL )
                    {
                        isBilevel = params[i+1] != 0;
                    }
                }

                if( m_buf || f )
                {
                    if( compression_level >= 0 )
                    {
                        png_set_compression_level( png_ptr, compression_level );
                    }
                    else
                    {
                        // tune parameters for speed
                        // (see http://wiki.linuxquestions.org/wiki/Libpng)
                        png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_SUB);
                        png_set_compression_level(png_ptr, Z_BEST_SPEED);
                    }
                    png_set_compression_strategy(png_ptr, compression_strategy);

                    png_set_IHDR( png_ptr, info_ptr, width, height, depth == CV_8U ? isBilevel?1:8 : 16,
                        channels == 1 ? PNG_COLOR_TYPE_GRAY :
                        channels == 3 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA,
                        PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
                        PNG_FILTER_TYPE_DEFAULT );

                    png_write_info( png_ptr, info_ptr );

                    if (isBilevel)
                        png_set_packing(png_ptr);

                    png_set_bgr( png_ptr );
                    if( !isBigEndian() )
                        png_set_swap( png_ptr );

                    buffer.allocate(height);
                    for( y = 0; y < height; y++ )
                        buffer[y] = img.data + y*img.step;

                    png_write_image( png_ptr, buffer );
                    png_write_end( png_ptr, info_ptr );

                    result = true;
                }
            }
        }
    }

    png_destroy_write_struct( &png_ptr, &info_ptr );
    if(f) fclose( f );

    return result;
}
示例#26
0
static int png_save(BPGDecoderContext *img, mem_encode * mempng, int bit_depth)
{
	BPGImageInfo img_info_s, *img_info = &img_info_s;
	FILE *f;
	png_structp png_ptr;
	png_infop info_ptr;
	png_bytep row_pointer;
	int y, color_type, bpp;
	BPGDecoderOutputFormat out_fmt;


	mempng->buffer = 0;
	mempng->size = 0;

	if (bit_depth != 8 && bit_depth != 16) {
		fprintf(stderr, "Only bit_depth = 8 or 16 are supported for PNG output\n");
		return -1;
	}

	bpg_decoder_get_info(img, img_info);

	png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING,
		NULL,
		NULL,  /* error */
		NULL, /* warning */
		NULL,
		NULL,
		NULL);
	info_ptr = png_create_info_struct(png_ptr);

	png_set_write_fn(png_ptr, (png_voidp)mempng, &png_write_data_buffer, NULL);

	if (setjmp(png_jmpbuf(png_ptr)) != 0) {
		fprintf(stderr, "PNG write error\n");
		return -1;
	}

	if (img_info->has_alpha)
		color_type = PNG_COLOR_TYPE_RGB_ALPHA;
	else
		color_type = PNG_COLOR_TYPE_RGB;

	png_set_IHDR(png_ptr, info_ptr, img_info->width, img_info->height,
		bit_depth, color_type, PNG_INTERLACE_NONE,
		PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

	png_write_info(png_ptr, info_ptr);

#if __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__
	if (bit_depth == 16) {
		png_set_swap(png_ptr);
	}
#endif

	if (bit_depth == 16) {
		if (img_info->has_alpha)
			out_fmt = BPG_OUTPUT_FORMAT_RGBA64;
		else
			out_fmt = BPG_OUTPUT_FORMAT_RGB48;
	}
	else {
		if (img_info->has_alpha)
			out_fmt = BPG_OUTPUT_FORMAT_RGBA32;
		else
			out_fmt = BPG_OUTPUT_FORMAT_RGB24;
	}

	bpg_decoder_start(img, out_fmt);

	bpp = (3 + img_info->has_alpha) * (bit_depth / 8);
	row_pointer = (png_bytep)png_malloc(png_ptr, img_info->width * bpp);
	for (y = 0; y < img_info->height; y++) {
		bpg_decoder_get_line(img, row_pointer);
		png_write_row(png_ptr, row_pointer);
	}
	png_free(png_ptr, row_pointer);

	png_write_end(png_ptr, NULL);

	png_destroy_write_struct(&png_ptr, &info_ptr);

	return 0;
}
示例#27
0
static GstFlowReturn
gst_pngdec_caps_create_and_set (GstPngDec * pngdec)
{
  GstFlowReturn ret = GST_FLOW_OK;
  gint bpc = 0, color_type;
  png_uint_32 width, height;
  GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;

  g_return_val_if_fail (GST_IS_PNGDEC (pngdec), GST_FLOW_ERROR);

  /* Get bits per channel */
  bpc = png_get_bit_depth (pngdec->png, pngdec->info);

  /* Get Color type */
  color_type = png_get_color_type (pngdec->png, pngdec->info);

  /* Add alpha channel if 16-bit depth, but not for GRAY images */
  if ((bpc > 8) && (color_type != PNG_COLOR_TYPE_GRAY)) {
    png_set_add_alpha (pngdec->png, 0xffff, PNG_FILLER_BEFORE);
    png_set_swap (pngdec->png);
  }
#if 0
  /* We used to have this HACK to reverse the outgoing bytes, but the problem
   * that originally required the hack seems to have been in videoconvert's
   * RGBA descriptions. It doesn't seem needed now that's fixed, but might
   * still be needed on big-endian systems, I'm not sure. J.S. 6/7/2007 */
  if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
    png_set_bgr (pngdec->png);
#endif

  /* Gray scale with alpha channel converted to RGB */
  if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
    GST_LOG_OBJECT (pngdec,
        "converting grayscale png with alpha channel to RGB");
    png_set_gray_to_rgb (pngdec->png);
  }

  /* Gray scale converted to upscaled to 8 bits */
  if ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
      (color_type == PNG_COLOR_TYPE_GRAY)) {
    if (bpc < 8) {              /* Convert to 8 bits */
      GST_LOG_OBJECT (pngdec, "converting grayscale image to 8 bits");
#if PNG_LIBPNG_VER < 10400
      png_set_gray_1_2_4_to_8 (pngdec->png);
#else
      png_set_expand_gray_1_2_4_to_8 (pngdec->png);
#endif
    }
  }

  /* Palette converted to RGB */
  if (color_type == PNG_COLOR_TYPE_PALETTE) {
    GST_LOG_OBJECT (pngdec, "converting palette png to RGB");
    png_set_palette_to_rgb (pngdec->png);
  }

  png_set_interlace_handling (pngdec->png);

  /* Update the info structure */
  png_read_update_info (pngdec->png, pngdec->info);

  /* Get IHDR header again after transformation settings */
  png_get_IHDR (pngdec->png, pngdec->info, &width, &height,
      &bpc, &pngdec->color_type, NULL, NULL, NULL);

  GST_LOG_OBJECT (pngdec, "this is a %dx%d PNG image", (gint) width,
      (gint) height);

  switch (pngdec->color_type) {
    case PNG_COLOR_TYPE_RGB:
      GST_LOG_OBJECT (pngdec, "we have no alpha channel, depth is 24 bits");
      if (bpc == 8)
        format = GST_VIDEO_FORMAT_RGB;
      break;
    case PNG_COLOR_TYPE_RGB_ALPHA:
      GST_LOG_OBJECT (pngdec,
          "we have an alpha channel, depth is 32 or 64 bits");
      if (bpc == 8)
        format = GST_VIDEO_FORMAT_RGBA;
      else if (bpc == 16)
        format = GST_VIDEO_FORMAT_ARGB64;
      break;
    case PNG_COLOR_TYPE_GRAY:
      GST_LOG_OBJECT (pngdec,
          "We have an gray image, depth is 8 or 16 (be) bits");
      if (bpc == 8)
        format = GST_VIDEO_FORMAT_GRAY8;
      else if (bpc == 16)
        format = GST_VIDEO_FORMAT_GRAY16_BE;
      break;
    default:
      break;
  }

  if (format == GST_VIDEO_FORMAT_UNKNOWN) {
    GST_ELEMENT_ERROR (pngdec, STREAM, NOT_IMPLEMENTED, (NULL),
        ("pngdec does not support this color type"));
    ret = GST_FLOW_NOT_SUPPORTED;
    goto beach;
  }

  /* Check if output state changed */
  if (pngdec->output_state) {
    GstVideoInfo *info = &pngdec->output_state->info;

    if (width == GST_VIDEO_INFO_WIDTH (info) &&
        height == GST_VIDEO_INFO_HEIGHT (info) &&
        GST_VIDEO_INFO_FORMAT (info) == format) {
      goto beach;
    }
    gst_video_codec_state_unref (pngdec->output_state);
  }

  pngdec->output_state =
      gst_video_decoder_set_output_state (GST_VIDEO_DECODER (pngdec), format,
      width, height, pngdec->input_state);
  gst_video_decoder_negotiate (GST_VIDEO_DECODER (pngdec));
  GST_DEBUG ("Final %d %d", GST_VIDEO_INFO_WIDTH (&pngdec->output_state->info),
      GST_VIDEO_INFO_HEIGHT (&pngdec->output_state->info));

beach:
  return ret;
}
示例#28
0
gint
gegl_buffer_export_png (GeglBuffer  *gegl_buffer,
                        const gchar *path,
                        gint         compression,
                        gint         bd,
                        gint         src_x,
                        gint         src_y,
                        gint         width,
                        gint         height)
{
    FILE          *fp;
    gint           i;
    png_struct    *png;
    png_info      *info;
    guchar        *pixels;
    png_color_16   white;
    int            png_color_type;
    gchar          format_string[16];
    const Babl    *format;
    gint           bit_depth = 8;

    if (!strcmp (path, "-"))
    {
        fp = stdout;
    }
    else
    {
        fp = fopen (path, "wb");
    }
    if (!fp)
    {
        return -1;
    }

    {
        const Babl *babl = gegl_buffer_get_format (gegl_buffer);

        if (bd == 16)
            bit_depth = 16;
        else
            bit_depth = 8;

        if (babl_format_has_alpha (babl))
            if (babl_format_get_n_components (babl) != 2)
            {
                png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
                strcpy (format_string, "R'G'B'A ");
            }
            else
            {
                png_color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
                strcpy (format_string, "Y'A ");
            }
        else if (babl_format_get_n_components (babl) != 1)
        {
            png_color_type = PNG_COLOR_TYPE_RGB;
            strcpy (format_string, "R'G'B' ");
        }
        else
        {
            png_color_type = PNG_COLOR_TYPE_GRAY;
            strcpy (format_string, "Y' ");
        }
    }

    if (bit_depth == 16)
        strcat (format_string, "u16");
    else
        strcat (format_string, "u8");

    png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (png == NULL)
    {
        if (stdout != fp)
            fclose (fp);

        return -1;
    }

    info = png_create_info_struct (png);

    if (setjmp (png_jmpbuf (png)))
    {
        if (stdout != fp)
            fclose (fp);

        return -1;
    }

    png_set_compression_level (png, compression);
    png_init_io (png, fp);

    png_set_IHDR (png, info,
                  width, height, bit_depth, png_color_type,
                  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_DEFAULT);

    if (png_color_type == PNG_COLOR_TYPE_RGB || png_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
    {
        white.red = 0xff;
        white.blue = 0xff;
        white.green = 0xff;
    }
    else
        white.gray = 0xff;
    png_set_bKGD (png, info, &white);

    png_write_info (png, info);

#if BYTE_ORDER == LITTLE_ENDIAN
    if (bit_depth > 8)
        png_set_swap (png);
#endif

    format = babl_format (format_string);
    pixels = g_malloc0 (width * babl_format_get_bytes_per_pixel (format));

    for (i=0; i< height; i++)
    {
        GeglRectangle rect;

        rect.x = src_x;
        rect.y = src_y+i;
        rect.width = width;
        rect.height = 1;

        gegl_buffer_get (gegl_buffer, &rect, 1.0, babl_format (format_string), pixels, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);

        png_write_rows (png, &pixels, 1);
    }

    png_write_end (png, info);

    png_destroy_write_struct (&png, &info);
    g_free (pixels);

    if (stdout != fp)
        fclose (fp);

    return 0;
}
void PNGAPI
png_read_png(png_structp png_ptr, png_infop info_ptr,
                           int transforms,
                           voidp params)
{
   int row;

   if (png_ptr == NULL)
      return;

   /* 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);
   if (info_ptr->height > PNG_UINT_32_MAX/png_sizeof(png_bytep))
      png_error(png_ptr, "Image is too high to process with png_read_png()");

   /* -------------- image transformations start here ------------------- */

#ifdef PNG_READ_16_TO_8_SUPPORTED
   /* Tell libpng to strip 16 bit/color files down to 8 bits per color.
    */
   if (transforms & PNG_TRANSFORM_STRIP_16)
      png_set_strip_16(png_ptr);
#endif

#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
   /* Strip alpha bytes from the input data without combining with
    * the background (not recommended).
    */
   if (transforms & PNG_TRANSFORM_STRIP_ALPHA)
      png_set_strip_alpha(png_ptr);
#endif

#if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED)
   /* Extract multiple pixels with bit depths of 1, 2, or 4 from a single
    * byte into separate bytes (useful for paletted and grayscale images).
    */
   if (transforms & PNG_TRANSFORM_PACKING)
      png_set_packing(png_ptr);
#endif

#ifdef PNG_READ_PACKSWAP_SUPPORTED
   /* Change the order of packed pixels to least significant bit first
    * (not useful if you are using png_set_packing).
    */
   if (transforms & PNG_TRANSFORM_PACKSWAP)
      png_set_packswap(png_ptr);
#endif

#ifdef PNG_READ_EXPAND_SUPPORTED
   /* Expand paletted colors into true RGB triplets
    * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel
    * Expand paletted or RGB images with transparency to full alpha
    * channels so the data will be available as RGBA quartets.
    */
   if (transforms & PNG_TRANSFORM_EXPAND)
      if ((png_ptr->bit_depth < 8) ||
          (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ||
          (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
         png_set_expand(png_ptr);
#endif

   /* We don't handle background color or gamma transformation or quantizing.
    */

#ifdef PNG_READ_INVERT_SUPPORTED
   /* Invert monochrome files to have 0 as white and 1 as black
    */
   if (transforms & PNG_TRANSFORM_INVERT_MONO)
      png_set_invert_mono(png_ptr);
#endif

#ifdef PNG_READ_SHIFT_SUPPORTED
   /* If you want to shift the pixel values from the range [0,255] or
    * [0,65535] to the original [0,7] or [0,31], or whatever range the
    * colors were originally in:
    */
   if ((transforms & PNG_TRANSFORM_SHIFT)
       && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT))
   {
      png_color_8p sig_bit;

      png_get_sBIT(png_ptr, info_ptr, &sig_bit);
      png_set_shift(png_ptr, sig_bit);
   }
#endif

#ifdef PNG_READ_BGR_SUPPORTED
   /* Flip the RGB pixels to BGR (or RGBA to BGRA)
    */
   if (transforms & PNG_TRANSFORM_BGR)
      png_set_bgr(png_ptr);
#endif

#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED
   /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR)
    */
   if (transforms & PNG_TRANSFORM_SWAP_ALPHA)
       png_set_swap_alpha(png_ptr);
#endif

#ifdef PNG_READ_SWAP_SUPPORTED
   /* Swap bytes of 16 bit files to least significant byte first
    */
   if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)
      png_set_swap(png_ptr);
#endif

/* Added at libpng-1.2.41 */
#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
   /* Invert the alpha channel from opacity to transparency
    */
   if (transforms & PNG_TRANSFORM_INVERT_ALPHA)
       png_set_invert_alpha(png_ptr);
#endif

/* Added at libpng-1.2.41 */
#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
   /* Expand grayscale image to RGB
    */
   if (transforms & PNG_TRANSFORM_GRAY_TO_RGB)
       png_set_gray_to_rgb(png_ptr);
#endif

   /* We don't handle adding filler bytes */

   /* 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 (i.e., you selected such a transform above).
    */
   png_read_update_info(png_ptr, info_ptr);

   /* -------------- image transformations end here ------------------- */

   png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
   if (info_ptr->row_pointers == NULL)
   {
    png_uint_32 iptr;

      info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr,
         info_ptr->height * png_sizeof(png_bytep));
      for (iptr=0; iptr<info_ptr->height; iptr++)
         info_ptr->row_pointers[iptr] = NULL;

      info_ptr->free_me |= PNG_FREE_ROWS;

      for (row = 0; row < (int)info_ptr->height; row++)
         info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr,
            png_get_rowbytes(png_ptr, info_ptr));
   }

   png_read_image(png_ptr, info_ptr->row_pointers);
   info_ptr->valid |= PNG_INFO_IDAT;

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

   transforms = transforms; /* Quiet compiler warnings */
   params = params;

}
示例#30
0
int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
{
	png_structp png_ptr;
	png_infop info_ptr;

	unsigned char *pixels = NULL;
	unsigned char *from, *to;
	unsigned short *pixels16 = NULL, *to16;
	float *from_float, from_straight[4];
	png_bytepp row_pointers = NULL;
	int i, bytesperpixel, color_type = PNG_COLOR_TYPE_GRAY;
	FILE *fp = NULL;

	int is_16bit = (ibuf->ftype & PNG_16BIT) && ibuf->rect_float;

	/* use the jpeg quality setting for compression */
	int compression;
	compression = (int)(((float)(ibuf->ftype & 0xff) / 11.1111f));
	compression = compression < 0 ? 0 : (compression > 9 ? 9 : compression);

	/* for prints */
	if (flags & IB_mem)
		name = "<memory>";

	bytesperpixel = (ibuf->planes + 7) >> 3;
	if ((bytesperpixel > 4) || (bytesperpixel == 2)) {
		printf("imb_savepng: Cunsupported bytes per pixel: %d for file: '%s'\n", bytesperpixel, name);
		return (0);
	}

	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
	                                  NULL, NULL, NULL);
	if (png_ptr == NULL) {
		printf("imb_savepng: Cannot png_create_write_struct for file: '%s'\n", name);
		return 0;
	}

	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) {
		png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
		printf("imb_savepng: Cannot png_create_info_struct for file: '%s'\n", name);
		return 0;
	}

	if (setjmp(png_jmpbuf(png_ptr))) {
		png_destroy_write_struct(&png_ptr, &info_ptr);
		printf("imb_savepng: Cannot setjmp for file: '%s'\n", name);
		return 0;
	}

	/* copy image data */

	if (is_16bit)
		pixels16 = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned short), "png 16bit pixels");
	else
		pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "png 8bit pixels");

	if (pixels == NULL && pixels16 == NULL) {
		png_destroy_write_struct(&png_ptr, &info_ptr);
		printf("imb_savepng: Cannot allocate pixels array of %dx%d, %d bytes per pixel for file: '%s'\n", ibuf->x, ibuf->y, bytesperpixel, name);
		return 0;
	}

	from = (unsigned char *) ibuf->rect;
	to = pixels;
	from_float = ibuf->rect_float;
	to16 = pixels16;

	switch (bytesperpixel) {
		case 4:
			color_type = PNG_COLOR_TYPE_RGBA;
			if (is_16bit) {
				for (i = ibuf->x * ibuf->y; i > 0; i--) {
					premul_to_straight_v4(from_straight, from_float);
					to16[0] = FTOUSHORT(from_straight[0]);
					to16[1] = FTOUSHORT(from_straight[1]);
					to16[2] = FTOUSHORT(from_straight[2]);
					to16[3] = FTOUSHORT(from_straight[3]);
					to16 += 4; from_float += 4;
				}
			}
			else {
				for (i = ibuf->x * ibuf->y; i > 0; i--) {
					to[0] = from[0];
					to[1] = from[1];
					to[2] = from[2];
					to[3] = from[3];
					to += 4; from += 4;
				}
			}
			break;
		case 3:
			color_type = PNG_COLOR_TYPE_RGB;
			if (is_16bit) {
				for (i = ibuf->x * ibuf->y; i > 0; i--) {
					premul_to_straight_v4(from_straight, from_float);
					to16[0] = FTOUSHORT(from_straight[0]);
					to16[1] = FTOUSHORT(from_straight[1]);
					to16[2] = FTOUSHORT(from_straight[2]);
					to16 += 3; from_float += 4;
				}
			}
			else {
				for (i = ibuf->x * ibuf->y; i > 0; i--) {
					to[0] = from[0];
					to[1] = from[1];
					to[2] = from[2];
					to += 3; from += 4;
				}
			}
			break;
		case 1:
			color_type = PNG_COLOR_TYPE_GRAY;
			if (is_16bit) {
				for (i = ibuf->x * ibuf->y; i > 0; i--) {
					premul_to_straight_v4(from_straight, from_float);
					to16[0] = FTOUSHORT(from_straight[0]);
					to16++; from_float += 4;
				}
			}
			else {
				for (i = ibuf->x * ibuf->y; i > 0; i--) {
					to[0] = from[0];
					to++; from += 4;
				}
			}
			break;
	}

	if (flags & IB_mem) {
		/* create image in memory */
		imb_addencodedbufferImBuf(ibuf);
		ibuf->encodedsize = 0;

		png_set_write_fn(png_ptr,
		                 (png_voidp) ibuf,
		                 WriteData,
		                 Flush);
	}
	else {
		fp = BLI_fopen(name, "wb");
		if (!fp) {
			png_destroy_write_struct(&png_ptr, &info_ptr);
			if (pixels)
				MEM_freeN(pixels);
			if (pixels16)
				MEM_freeN(pixels16);
			printf("imb_savepng: Cannot open file for writing: '%s'\n", name);
			return 0;
		}
		png_init_io(png_ptr, fp);
	}

#if 0
	png_set_filter(png_ptr, 0,
	               PNG_FILTER_NONE  | PNG_FILTER_VALUE_NONE  |
	               PNG_FILTER_SUB   | PNG_FILTER_VALUE_SUB   |
	               PNG_FILTER_UP    | PNG_FILTER_VALUE_UP    |
	               PNG_FILTER_AVG   | PNG_FILTER_VALUE_AVG   |
	               PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH |
	               PNG_ALL_FILTERS);
#endif

	png_set_compression_level(png_ptr, compression);

	/* png image settings */
	png_set_IHDR(png_ptr,
	             info_ptr,
	             ibuf->x,
	             ibuf->y,
	             is_16bit ? 16 : 8,
	             color_type,
	             PNG_INTERLACE_NONE,
	             PNG_COMPRESSION_TYPE_DEFAULT,
	             PNG_FILTER_TYPE_DEFAULT);

	/* image text info */
	if (ibuf->metadata) {
		png_text *metadata;
		ImMetaData *iptr;
		int num_text = 0;
		iptr = ibuf->metadata;
		while (iptr) {
			num_text++;
			iptr = iptr->next;
		}
		
		metadata = MEM_callocN(num_text * sizeof(png_text), "png_metadata");
		iptr = ibuf->metadata;
		num_text = 0;
		while (iptr) {
			
			metadata[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
			metadata[num_text].key = iptr->key;
			metadata[num_text].text = iptr->value;
			num_text++;
			iptr = iptr->next;
		}
		
		png_set_text(png_ptr, info_ptr, metadata, num_text);
		MEM_freeN(metadata);

	}

	if (ibuf->ppm[0] > 0.0 && ibuf->ppm[1] > 0.0) {
		png_set_pHYs(png_ptr, info_ptr, (unsigned int)(ibuf->ppm[0] + 0.5), (unsigned int)(ibuf->ppm[1] + 0.5), PNG_RESOLUTION_METER);
	}

	/* write the file header information */
	png_write_info(png_ptr, info_ptr);

#ifdef __LITTLE_ENDIAN__
	png_set_swap(png_ptr);
#endif

	/* allocate memory for an array of row-pointers */
	row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers");
	if (row_pointers == NULL) {
		printf("imb_savepng: Cannot allocate row-pointers array for file '%s'\n", name);
		png_destroy_write_struct(&png_ptr, &info_ptr);
		if (pixels)
			MEM_freeN(pixels);
		if (pixels16)
			MEM_freeN(pixels16);
		if (fp) {
			fclose(fp);
		}
		return 0;
	}

	/* set the individual row-pointers to point at the correct offsets */
	if (is_16bit) {
		for (i = 0; i < ibuf->y; i++) {
			row_pointers[ibuf->y - 1 - i] = (png_bytep)
			                                ((unsigned short *)pixels16 + (i * ibuf->x) * bytesperpixel);
		}
	}
	else {
		for (i = 0; i < ibuf->y; i++) {
			row_pointers[ibuf->y - 1 - i] = (png_bytep)
			                                ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char));
		}
	}

	/* write out the entire image data in one call */
	png_write_image(png_ptr, row_pointers);

	/* write the additional chunks to the PNG file (not really needed) */
	png_write_end(png_ptr, info_ptr);

	/* clean up */
	if (pixels)
		MEM_freeN(pixels);
	if (pixels16)
		MEM_freeN(pixels16);
	MEM_freeN(row_pointers);
	png_destroy_write_struct(&png_ptr, &info_ptr);

	if (fp) {
		fflush(fp);
		fclose(fp);
	}

	return(1);
}