Blame synfig-core/src/modules/mod_jpeg/mptr_jpeg.cpp

Carlos Lopez a09598
/* === S Y N F I G ========================================================= */
Carlos Lopez a09598
/*!	\file mptr_jpeg.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
[d.j.a.y] Jerome Blanchi 6485c7
**	Copyright (c) 2015 Jérôme Blanchi
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
/*! \todo Support 16 bit JPEG files
Carlos Lopez a09598
**	\todo Support for paletted JPEG 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_jpeg.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
#include <cstdio></cstdio>
Carlos Lopez a09598
#include <algorithm></algorithm>
Carlos Lopez a09598
#include <functional></functional>
[d.j.a.y] Jerome Blanchi 6485c7
#include <sstream></sstream>
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 JPEG_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(jpeg_mptr);
Carlos Lopez a09598
SYNFIG_IMPORTER_SET_NAME(jpeg_mptr,"jpeg");
Carlos Lopez a09598
SYNFIG_IMPORTER_SET_EXT(jpeg_mptr,"jpg");
Carlos Lopez a09598
SYNFIG_IMPORTER_SET_VERSION(jpeg_mptr,"0.1");
Carlos Lopez a09598
SYNFIG_IMPORTER_SET_CVS_ID(jpeg_mptr,"$Id$");
58094c
SYNFIG_IMPORTER_SET_SUPPORTS_FILE_SYSTEM_WRAPPER(jpeg_mptr, false);
Carlos Lopez a09598
Carlos Lopez a09598
/* === M E T H O D S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
struct my_error_mgr {
Carlos Lopez a09598
  struct jpeg_error_mgr pub;	/* "public" fields */
Carlos Lopez a09598
Carlos Lopez a09598
  jmp_buf setjmp_buffer;	/* for return to caller */
Carlos Lopez a09598
};
Carlos Lopez a09598
Carlos Lopez a09598
typedef struct my_error_mgr * my_error_ptr;
Carlos Lopez a09598
Carlos Lopez a09598
/*
Carlos Lopez a09598
 * Here's the routine that will replace the standard error_exit method:
Carlos Lopez a09598
 */
Carlos Lopez a09598
Carlos Lopez a09598
void
Carlos Lopez a09598
jpeg_mptr::my_error_exit (j_common_ptr cinfo)
Carlos Lopez a09598
{
Carlos Lopez a09598
  /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
Carlos Lopez a09598
  my_error_ptr myerr = (my_error_ptr) cinfo->err;
Carlos Lopez a09598
Carlos Lopez a09598
  /* Always display the message. */
Carlos Lopez a09598
  /* We could postpone this until after returning, if we chose. */
2da2e1
  //(*cinfo->err->output_message) (cinfo);
2da2e1
2da2e1
  char jpegLastErrorMsg[JMSG_LENGTH_MAX];
2da2e1
  ( *(cinfo->err->format_message) ) (cinfo, jpegLastErrorMsg);
2da2e1
  error(String("Jpeg error: ") + jpegLastErrorMsg);
Carlos Lopez a09598
Carlos Lopez a09598
  /* Return control to the setjmp point */
Carlos Lopez a09598
  longjmp(myerr->setjmp_buffer, 1);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
Carlos Lopez a09598
Carlos Lopez a09598
Carlos Lopez a09598
fcad0d
jpeg_mptr::jpeg_mptr(const synfig::FileSystem::Identifier &identifier):
fcad0d
	Importer(identifier)
Carlos Lopez a09598
{
718ada
}
718ada
718ada
jpeg_mptr::~jpeg_mptr()
718ada
{
718ada
}
718ada
718ada
bool
718ada
jpeg_mptr::get_frame(synfig::Surface &surface, const synfig::RendDesc &/*renddesc*/, Time, synfig::ProgressCallback */*cb*/)
718ada
{
718ada
	jpeg_decompress_struct cinfo;
[d.j.a.y] Jerome Blanchi 6485c7
	struct my_error_mgr jerr;
Carlos Lopez a09598
Carlos Lopez a09598
	/* Open the file pointer */
e59227
	FileSystem::ReadStream::Handle stream = identifier.get_read_stream();
[d.j.a.y] Jerome Blanchi 6485c7
	if (!stream)
[d.j.a.y] Jerome Blanchi 6485c7
	{
[d.j.a.y] Jerome Blanchi 0c77bd
		throw String("Error on jpeg importer, unable to physically open "+identifier.filename);
718ada
		return false;
[d.j.a.y] Jerome Blanchi 6485c7
	}
Carlos Lopez a09598
Carlos Lopez a09598
	/* Step 1: allocate and initialize JPEG decompression object */
Carlos Lopez a09598
Carlos Lopez a09598
	/* We set up the normal JPEG error routines, then override error_exit. */
Carlos Lopez a09598
	cinfo.err = jpeg_std_error(&jerr.pub);
Carlos Lopez a09598
	jerr.pub.error_exit = my_error_exit;
Carlos Lopez a09598
	/* Establish the setjmp return context for my_error_exit to use. */
Carlos Lopez a09598
	if (setjmp(jerr.setjmp_buffer)) {
Carlos Lopez a09598
		/* If we get here, the JPEG code has signaled an error.
Carlos Lopez a09598
		 * We need to clean up the JPEG object, close the input file, and return.
Carlos Lopez a09598
		 */
Carlos Lopez a09598
		jpeg_destroy_decompress(&cinfo);
[d.j.a.y] Jerome Blanchi 6485c7
		stream.reset();
[d.j.a.y] Jerome Blanchi 0c77bd
		throw String("Error on jpeg importer, unable to connect to jpeg library");
Carlos Lopez a09598
	}
Carlos Lopez a09598
	/* Now we can initialize the JPEG decompression object. */
Carlos Lopez a09598
	jpeg_create_decompress(&cinfo);
Carlos Lopez a09598
luz.paz 99f3ef
	/* Step 2: specify data source (eg, from memory thru a String) */
[d.j.a.y] Jerome Blanchi 6485c7
[d.j.a.y] Jerome Blanchi 6485c7
	std::ostringstream tmp;
[d.j.a.y] Jerome Blanchi 6485c7
	tmp << stream->rdbuf();
[d.j.a.y] Jerome Blanchi 6485c7
	String streamString = tmp.str();
[d.j.a.y] Jerome Blanchi 6485c7
	stream.reset();
Carlos Lopez a09598
[d.j.a.y] Jerome Blanchi 6485c7
	jpeg_mem_src(&cinfo, (unsigned char*)streamString.c_str(), streamString.size());
Carlos Lopez a09598
Carlos Lopez a09598
	/* Step 3: read file parameters with jpeg_read_header() */
Carlos Lopez a09598
Carlos Lopez a09598
	(void) jpeg_read_header(&cinfo, TRUE);
Carlos Lopez a09598
	/* We can ignore the return value from jpeg_read_header since
Carlos Lopez a09598
	*   (a) suspension is not possible with the stdio data source, and
Carlos Lopez a09598
	*   (b) we passed TRUE to reject a tables-only JPEG file as an error.
Carlos Lopez a09598
	* See libjpeg.doc for more info.
Carlos Lopez a09598
	*/
Carlos Lopez a09598
Carlos Lopez a09598
	/* Step 4: set parameters for decompression */
Carlos Lopez a09598
Carlos Lopez a09598
	/* In this example, we don't need to change any of the defaults set by
Carlos Lopez a09598
	* jpeg_read_header(), so we do nothing here.
Carlos Lopez a09598
	*/
Carlos Lopez a09598
Carlos Lopez a09598
	/* Step 5: Start decompressor */
Carlos Lopez a09598
Carlos Lopez a09598
	(void) jpeg_start_decompress(&cinfo);
Carlos Lopez a09598
	/* We can ignore the return value since suspension is not possible
Carlos Lopez a09598
	* with the stdio data source.
Carlos Lopez a09598
	*/
Carlos Lopez a09598
Carlos Lopez a09598
	JSAMPARRAY buffer;		/* Output row buffer */
Carlos Lopez a09598
	int row_stride;		/* physical row width in output buffer */
Carlos Lopez a09598
	row_stride = cinfo.output_width * cinfo.output_components;
Carlos Lopez a09598
	/* Make a one-row-high sample array that will go away when done with image */
Carlos Lopez a09598
	buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
Carlos Lopez a09598
Carlos Lopez a09598
	if(!buffer)
Carlos Lopez a09598
	{
[d.j.a.y] Jerome Blanchi 0c77bd
		synfig::error("Error on jpeg importer, alloc of \"buffer\" failed (bug?)");
[d.j.a.y] Jerome Blanchi 0c77bd
		throw String("Error on jpeg importer, alloc of \"buffer\" failed (bug?)");
Carlos Lopez a09598
	}
Carlos Lopez a09598
a4bbdd
	surface.set_wh(cinfo.output_width, cinfo.output_height);
a4bbdd
	const ColorReal k = 1/255.0;
Carlos Lopez a09598
	switch(cinfo.output_components)
Carlos Lopez a09598
	{
Carlos Lopez a09598
	case 3:
a4bbdd
		for(int y = 0; y < surface.get_h(); ++y) {
Carlos Lopez a09598
			jpeg_read_scanlines(&cinfo, buffer, 1);
a4bbdd
			for(int x = 0; x < surface.get_w(); ++x)
718ada
				surface[y][x]=Color(
a4bbdd
					((unsigned char)buffer[0][x*3+0])*k,
a4bbdd
					((unsigned char)buffer[0][x*3+1])*k,
a4bbdd
					((unsigned char)buffer[0][x*3+2])*k );
Carlos Lopez a09598
		}
Carlos Lopez a09598
		break;
Carlos Lopez a09598
	case 1:
a4bbdd
		for(int y = 0; y < surface.get_h(); ++y) {
Carlos Lopez a09598
			jpeg_read_scanlines(&cinfo, buffer, 1);
a4bbdd
			for(int x = 0; x < surface.get_w(); ++x) {
a4bbdd
				ColorReal gray = ((unsigned char)buffer[0][x])*k;
a4bbdd
				surface[y][x]=Color(gray, gray, gray);
Carlos Lopez a09598
			}
Carlos Lopez a09598
		}
Carlos Lopez a09598
		break;
Carlos Lopez a09598
	default:
[d.j.a.y] Jerome Blanchi 0c77bd
		synfig::error("Error on jpeg importer, Unsupported color type");
Carlos Lopez a09598
        //! \todo THROW SOMETHING
[d.j.a.y] Jerome Blanchi 0c77bd
		throw String("Error on jpeg importer, Unsupported color type");
718ada
		return false;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	/* Step 7: Finish decompression */
Carlos Lopez a09598
Carlos Lopez a09598
	(void) jpeg_finish_decompress(&cinfo);
Carlos Lopez a09598
	/* We can ignore the return value since suspension is not possible
Carlos Lopez a09598
	* with the stdio data source.
Carlos Lopez a09598
	*/
Carlos Lopez a09598
Carlos Lopez a09598
	/* Step 8: Release JPEG decompression object */
Carlos Lopez a09598
Carlos Lopez a09598
	/* This is an important step since it will release a good deal of memory. */
Carlos Lopez a09598
	jpeg_destroy_decompress(&cinfo);
Carlos Lopez a09598
Carlos Lopez a09598
	return true;
Carlos Lopez a09598
}