Blame synfig-core/src/modules/mod_png/mptr_png.cpp

Carlos Lopez a09598
/* === S Y N F I G ========================================================= */
Carlos Lopez a09598
/*!	\file mptr_png.cpp
Carlos Lopez a09598
**	\brief ppm Target Module
Carlos Lopez a09598
**
Carlos Lopez a09598
**	$Id$
Carlos Lopez a09598
**
Carlos Lopez a09598
**	\legal
Carlos Lopez a09598
**	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
Carlos Lopez a09598
**	Copyright (c) 2007 Chris Moore
Carlos Lopez a09598
**
Carlos Lopez a09598
**	This package is free software; you can redistribute it and/or
Carlos Lopez a09598
**	modify it under the terms of the GNU General Public License as
Carlos Lopez a09598
**	published by the Free Software Foundation; either version 2 of
Carlos Lopez a09598
**	the License, or (at your option) any later version.
Carlos Lopez a09598
**
Carlos Lopez a09598
**	This package is distributed in the hope that it will be useful,
Carlos Lopez a09598
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
Carlos Lopez a09598
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Carlos Lopez a09598
**	General Public License for more details.
Carlos Lopez a09598
**	\endlegal
Carlos Lopez a09598
**
Carlos Lopez a09598
** === N O T E S ===========================================================
Carlos Lopez a09598
**
Carlos Lopez a09598
** ========================================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
/*!
Carlos Lopez a09598
**  \todo Support 16 bit PNG files
Carlos Lopez a09598
**	\todo Support GAMMA correction
Carlos Lopez a09598
**	\todo Fix memory leaks
Carlos Lopez a09598
*/
Carlos Lopez a09598
Carlos Lopez a09598
/* === H E A D E R S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
#ifdef USING_PCH
Carlos Lopez a09598
#	include "pch.h"
Carlos Lopez a09598
#else
Carlos Lopez a09598
#ifdef HAVE_CONFIG_H
Carlos Lopez a09598
#	include <config.h></config.h>
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
#include "mptr_png.h"
Carlos Lopez a09598
#include <synfig importer.h=""></synfig>
Carlos Lopez a09598
#include <synfig time.h=""></synfig>
Carlos Lopez a09598
#include <synfig general.h=""></synfig>
bw 94d8a6
#include <synfig localization.h=""></synfig>
Carlos Lopez a09598
Carlos Lopez a09598
Carlos Lopez a09598
#include <cstdio></cstdio>
Carlos Lopez a09598
#include <algorithm></algorithm>
Carlos Lopez a09598
#include <functional></functional>
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
/* === M A C R O S ========================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
using namespace synfig;
Carlos Lopez a09598
using namespace std;
Carlos Lopez a09598
using namespace etl;
Carlos Lopez a09598
Carlos Lopez a09598
#define PNG_CHECK_BYTES 	8
Carlos Lopez a09598
Carlos Lopez a09598
/* === G L O B A L S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
SYNFIG_IMPORTER_INIT(png_mptr);
Carlos Lopez a09598
SYNFIG_IMPORTER_SET_NAME(png_mptr,"png");
Carlos Lopez a09598
SYNFIG_IMPORTER_SET_EXT(png_mptr,"png");
Carlos Lopez a09598
SYNFIG_IMPORTER_SET_VERSION(png_mptr,"0.1");
Carlos Lopez a09598
SYNFIG_IMPORTER_SET_CVS_ID(png_mptr,"$Id$");
292dfb
SYNFIG_IMPORTER_SET_SUPPORTS_FILE_SYSTEM_WRAPPER(png_mptr, true);
Carlos Lopez a09598
Carlos Lopez a09598
/* === M E T H O D S ======================================================= */
Carlos Lopez a09598
1c09d1
namespace {
611304
	inline ColorReal get_channel(png_bytep *rows, int bit_depth, int row, int col) {
611304
		int x = bit_depth > 8
611304
			  ? ((unsigned short*)(rows[row]))[col]
611304
			  :                    rows[row]  [col];
611304
		int max = (1 << bit_depth) - 1;
611304
		return x/ColorReal(max);
1c09d1
	}
1c09d1
}
1c09d1
Carlos Lopez a09598
void
Carlos Lopez a09598
png_mptr::png_out_error(png_struct */*png_data*/,const char *msg)
Carlos Lopez a09598
{
Carlos Lopez a09598
	//png_mptr *me=(png_mptr*)png_data->error_ptr;
Carlos Lopez a09598
	synfig::error(strprintf("png_mptr: error: %s",msg));
Carlos Lopez a09598
	//me->ready=false;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
void
Carlos Lopez a09598
png_mptr::png_out_warning(png_struct */*png_data*/,const char *msg)
Carlos Lopez a09598
{
Carlos Lopez a09598
	//png_mptr *me=(png_mptr*)png_data->error_ptr;
Carlos Lopez a09598
	synfig::warning(strprintf("png_mptr: warning: %s",msg));
Carlos Lopez a09598
	//me->ready=false;
Carlos Lopez a09598
}
Carlos Lopez a09598
292dfb
void
292dfb
png_mptr::read_callback(png_structp png_ptr, png_bytep out_bytes, png_size_t bytes_count_to_read)
Carlos Lopez a09598
{
b91d17
	FileSystem::ReadStream *stream = (FileSystem::ReadStream*)png_get_io_ptr(png_ptr);
b91d17
	png_size_t s = stream == NULL
292dfb
				 ? 0
133e55
				 : stream->read_block(out_bytes, bytes_count_to_read);
292dfb
	if (s < bytes_count_to_read)
292dfb
		memset(out_bytes + s, 0, bytes_count_to_read - s);
Carlos Lopez a09598
}
Carlos Lopez a09598
fcad0d
png_mptr::png_mptr(const synfig::FileSystem::Identifier &identifier):
fcad0d
	Importer(identifier)
Carlos Lopez a09598
{
b4ec83
}
b4ec83
b4ec83
png_mptr::~png_mptr()
b4ec83
{
b4ec83
}
b4ec83
b4ec83
bool
b4ec83
png_mptr::get_frame(synfig::Surface &surface, const synfig::RendDesc &/*renddesc*/, Time, synfig::ProgressCallback */*cb*/)
b4ec83
{
Carlos Lopez a09598
	/* Open the file pointer */
e59227
	FileSystem::ReadStream::Handle stream = identifier.get_read_stream();
292dfb
    if (!stream)
Carlos Lopez a09598
    {
Carlos Lopez a09598
        //! \todo THROW SOMETHING
57ca32
		throw strprintf("Unable to physically open %s",identifier.filename.c_str());
b4ec83
		return false;
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
	/* Make sure we are dealing with a PNG format file */
Carlos Lopez a09598
	png_byte header[PNG_CHECK_BYTES];
292dfb
	if (!stream->read_variable(header))
292dfb
	{
292dfb
        //! \todo THROW SOMETHING
292dfb
		throw strprintf("Cannot read header from \"%s\"",identifier.filename.c_str());
b4ec83
		return false;
292dfb
	}
292dfb
292dfb
    if (0 != png_sig_cmp(header, 0, PNG_CHECK_BYTES))
Carlos Lopez a09598
    {
Carlos Lopez a09598
        //! \todo THROW SOMETHING
57ca32
		throw strprintf("This (\"%s\") doesn't appear to be a PNG file",identifier.filename.c_str());
b4ec83
		return false;
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
	png_structp png_ptr = png_create_read_struct
Carlos Lopez a09598
       (PNG_LIBPNG_VER_STRING, (png_voidp)this,
Carlos Lopez a09598
        &png_mptr::png_out_error, &png_mptr::png_out_warning);
Carlos Lopez a09598
	if (!png_ptr)
Carlos Lopez a09598
    {
Carlos Lopez a09598
        //! \todo THROW SOMETHING
Carlos Lopez a09598
		throw String("error on importer construction, *WRITEME*3");
b4ec83
		return false;
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    png_infop info_ptr = png_create_info_struct(png_ptr);
Carlos Lopez a09598
    if (!info_ptr)
Carlos Lopez a09598
    {
Carlos Lopez a09598
        png_destroy_read_struct(&png_ptr,
Carlos Lopez a09598
           (png_infopp)NULL, (png_infopp)NULL);
Carlos Lopez a09598
        //! \todo THROW SOMETHING
Carlos Lopez a09598
		throw String("error on importer construction, *WRITEME*4");
b4ec83
		return false;
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    png_infop end_info = png_create_info_struct(png_ptr);
Carlos Lopez a09598
    if (!end_info)
Carlos Lopez a09598
    {
Carlos Lopez a09598
        png_destroy_read_struct(&png_ptr, &info_ptr,
Carlos Lopez a09598
          (png_infopp)NULL);
Carlos Lopez a09598
        //! \todo THROW SOMETHING
Carlos Lopez a09598
		throw String("error on importer construction, *WRITEME*4");
b4ec83
		return false;
Carlos Lopez a09598
    }
Carlos Lopez a09598
292dfb
    png_set_read_fn(png_ptr, stream.get(), read_callback);
Carlos Lopez a09598
	png_set_sig_bytes(png_ptr,PNG_CHECK_BYTES);
Carlos Lopez a09598
Carlos Lopez a09598
	png_read_info(png_ptr, info_ptr);
Carlos Lopez a09598
Carlos Lopez a09598
	int bit_depth,color_type,interlace_type, compression_type,filter_method;
Carlos Lopez a09598
	png_uint_32 width,height;
Carlos Lopez a09598
Carlos Lopez a09598
	png_get_IHDR(png_ptr, info_ptr, &width, &height,
Carlos Lopez a09598
				 &bit_depth, &color_type, &interlace_type,
Carlos Lopez a09598
				 &compression_type, &filter_method);
Carlos Lopez a09598
1c09d1
	if (bit_depth > 16) {
1c09d1
		synfig::error("png_mptr: error: bit depth not supported: %d", bit_depth);
1c09d1
		throw etl::strprintf("png_mptr: error: bit depth not supported: %d", bit_depth);
1c09d1
		return false;
1c09d1
	}
Carlos Lopez a09598
Carlos Lopez a09598
	if (bit_depth < 8)
Carlos Lopez a09598
		png_set_packing(png_ptr);
Carlos Lopez a09598
Carlos Lopez a09598
	double fgamma;
Carlos Lopez a09598
	if (png_get_gAMA(png_ptr, info_ptr, &fgamma))
Carlos Lopez a09598
	{
Carlos Lopez a09598
		synfig::info("PNG: Image gamma is %f",fgamma);
Carlos Lopez a09598
		png_set_gamma(png_ptr, gamma().get_gamma(), fgamma);
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
Carlos Lopez a09598
	/*
Carlos Lopez a09598
	if (setjmp(png_jmpbuf(png_ptr)))
Carlos Lopez a09598
	{
Carlos Lopez a09598
		synfig::error("Unable to setup longjump");
Carlos Lopez a09598
		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
Carlos Lopez a09598
		fclose(file);
Carlos Lopez a09598
        //! \todo THROW SOMETHING
Carlos Lopez a09598
		throw String("error on importer construction, *WRITEME*5");
Carlos Lopez a09598
		return;
Carlos Lopez a09598
	}
Carlos Lopez a09598
	*/
Carlos Lopez a09598
Carlos Lopez a09598
	// man libpng tells me:
Carlos Lopez a09598
	//   You must use png_transforms and not call any
Carlos Lopez a09598
	//   png_set_transform() functions when you use png_read_png().
Carlos Lopez a09598
	// but we used png_set_gamma(), which may be why we were seeing a crash at the end
Carlos Lopez a09598
	//   png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_PACKING|PNG_TRANSFORM_STRIP_16, NULL);
Carlos Lopez a09598
Carlos Lopez a09598
	png_read_update_info(png_ptr, info_ptr);
Carlos Lopez a09598
	png_uint_32 rowbytes = png_get_rowbytes(png_ptr, info_ptr);
Carlos Lopez a09598
Carlos Lopez a09598
	// allocate buffer to read image data into
Carlos Lopez a09598
	png_bytep *row_pointers=new png_bytep[height];
Carlos Lopez a09598
	png_byte *data = new png_byte[rowbytes*height];
Carlos Lopez a09598
	for (png_uint_32 i = 0; i < height; i++)
Carlos Lopez a09598
		row_pointers[i] = &(data[rowbytes*i]);
Carlos Lopez a09598
Carlos Lopez a09598
	png_read_image(png_ptr, row_pointers);
Carlos Lopez a09598
Carlos Lopez a09598
	png_uint_32 x, y;
b4ec83
	surface.set_wh(width,height);
Carlos Lopez a09598
Carlos Lopez a09598
	switch(color_type)
Carlos Lopez a09598
	{
Carlos Lopez a09598
	case PNG_COLOR_TYPE_RGB:
Carlos Lopez a09598
		for(y=0;y
Carlos Lopez a09598
			for(x=0;x
Carlos Lopez a09598
			{
611304
				float r=gamma().r_F32_to_F32( get_channel(row_pointers, bit_depth, y, x*3+0) );
611304
				float g=gamma().g_F32_to_F32( get_channel(row_pointers, bit_depth, y, x*3+1) );
611304
				float b=gamma().b_F32_to_F32( get_channel(row_pointers, bit_depth, y, x*3+2) );
1c09d1
				surface[y][x]=Color(r, g, b, 1.0);
Carlos Lopez a09598
			}
Carlos Lopez a09598
		break;
Carlos Lopez a09598
Carlos Lopez a09598
	case PNG_COLOR_TYPE_RGB_ALPHA:
Carlos Lopez a09598
		for(y=0;y
Carlos Lopez a09598
			for(x=0;x
Carlos Lopez a09598
			{
611304
				float r=gamma().r_F32_to_F32( get_channel(row_pointers, bit_depth, y, x*4+0) );
611304
				float g=gamma().g_F32_to_F32( get_channel(row_pointers, bit_depth, y, x*4+1) );
611304
				float b=gamma().b_F32_to_F32( get_channel(row_pointers, bit_depth, y, x*4+2) );
611304
				float a=gamma().a_F32_to_F32( get_channel(row_pointers, bit_depth, y, x*4+3) );
23b4d4
				surface[y][x]=Color(r, g, b, a);
Carlos Lopez a09598
			}
Carlos Lopez a09598
		break;
Carlos Lopez a09598
Carlos Lopez a09598
	case PNG_COLOR_TYPE_GRAY:
Carlos Lopez a09598
		for(y=0;y
Carlos Lopez a09598
			for(x=0;x
Carlos Lopez a09598
			{
611304
				float gray=gamma().g_F32_to_F32( get_channel(row_pointers, bit_depth, y, x) );
1c09d1
				surface[y][x]=Color(gray, gray, gray, 1.0);
Carlos Lopez a09598
			}
Carlos Lopez a09598
		break;
Carlos Lopez a09598
Carlos Lopez a09598
	case PNG_COLOR_TYPE_GRAY_ALPHA:
Carlos Lopez a09598
		for(y=0;y
Carlos Lopez a09598
			for(x=0;x
Carlos Lopez a09598
			{
611304
				float gray=gamma().g_F32_to_F32( get_channel(row_pointers, bit_depth, y, x*2+0) );
611304
				float a   =gamma().a_F32_to_F32( get_channel(row_pointers, bit_depth, y, x*2+1) );
23b4d4
				surface[y][x]=Color(gray, gray, gray, a);
Carlos Lopez a09598
			}
Carlos Lopez a09598
		break;
Carlos Lopez a09598
Carlos Lopez a09598
	case PNG_COLOR_TYPE_PALETTE:
[d.j.a.y] Jerome Blanchi 676e43
	{
1c09d1
		if (bit_depth > 8) {
1c09d1
			synfig::error("png_mptr: error: bit depth with palette not supported: %d", bit_depth);
1c09d1
			throw etl::strprintf("png_mptr: error: bit depth with palette not supported: %d", bit_depth);
1c09d1
			return false;
1c09d1
		}
1c09d1
		png_colorp palette;
1c09d1
		int num_palette;
1c09d1
		png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
1c09d1
		png_bytep trans_alpha = NULL;
1c09d1
		int num_trans = 0;
1c09d1
		bool has_alpha = png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, NULL)
1c09d1
		               & PNG_INFO_tRNS;
Carlos Lopez a09598
		for(y=0;y
Carlos Lopez a09598
			for(x=0;x
Carlos Lopez a09598
			{
62afcf
				float r=gamma().r_U8_to_F32((unsigned char)palette[row_pointers[y][x]].red);
62afcf
				float g=gamma().g_U8_to_F32((unsigned char)palette[row_pointers[y][x]].green);
62afcf
				float b=gamma().b_U8_to_F32((unsigned char)palette[row_pointers[y][x]].blue);
[d.j.a.y] Jerome Blanchi f73e51
23b4d4
				unsigned char ac = 255;
23b4d4
                if (has_alpha && num_trans > 0 && trans_alpha != NULL && row_pointers[y][x] < num_trans)
23b4d4
                    ac = trans_alpha[row_pointers[y][x]];
23b4d4
				float a=gamma().a_U8_to_F32(ac);
23b4d4
				
23b4d4
				surface[y][x]=Color(r, g, b, a);
Carlos Lopez a09598
			}
Carlos Lopez a09598
		break;
[d.j.a.y] Jerome Blanchi 676e43
	}
Carlos Lopez a09598
	default:
292dfb
		png_read_end(png_ptr, end_info);
292dfb
		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
Carlos Lopez a09598
		synfig::error("png_mptr: error: Unsupported color type");
Carlos Lopez a09598
        //! \todo THROW SOMETHING
Carlos Lopez a09598
		throw String("error on importer construction, *WRITEME*6");
b4ec83
		return false;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	png_read_end(png_ptr, end_info);
Carlos Lopez a09598
	png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
Carlos Lopez a09598
Carlos Lopez a09598
	return true;
Carlos Lopez a09598
}