Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef WIN32
Toshihiro Shimizu 890ddd
#pragma warning(disable : 4996)
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
//#include "texception.h"
Toshihiro Shimizu 890ddd
//#include "tfilepath.h"
Toshihiro Shimizu 890ddd
//#include "tiio_jpg.h"
Toshihiro Shimizu 890ddd
//#include "../compatibility/tnz4.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tiio_jpg.h"
Toshihiro Shimizu 890ddd
#include "tproperty.h"
Toshihiro Shimizu 890ddd
#include "tpixel.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
 * Include file for users of JPEG library.
Toshihiro Shimizu 890ddd
 * You will need to have included system headers that define at least
Toshihiro Shimizu 890ddd
 * the typedefs FILE and size_t before you can include jpeglib.h.
Toshihiro Shimizu 890ddd
 * (stdio.h is sufficient on ANSI-conforming systems.)
Toshihiro Shimizu 890ddd
 * You may also wish to include "jerror.h".
Toshihiro Shimizu 890ddd
 */
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <assert.h></assert.h>
Toshihiro Shimizu 890ddd
#include <stdio.h></stdio.h>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=========================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
const string Tiio::JpgWriterProperties::QUALITY("Quality");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=========================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
extern "C" void tnz_error_exit(j_common_ptr cinfo)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//  throw "merda";
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef CICCIO
Toshihiro Shimizu 890ddd
JMETHOD(void, error_exit, (j_common_ptr cinfo));
Toshihiro Shimizu 890ddd
/* Conditionally emit a trace or warning message */
Toshihiro Shimizu 890ddd
JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level));
Toshihiro Shimizu 890ddd
/* Routine that actually outputs a trace or error message */
Toshihiro Shimizu 890ddd
JMETHOD(void, output_message, (j_common_ptr cinfo));
Toshihiro Shimizu 890ddd
/* Format a message string for the most recent JPEG error or message */
Toshihiro Shimizu 890ddd
JMETHOD(void, format_message, (j_common_ptr cinfo, char *buffer));
Toshihiro Shimizu 890ddd
#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */
Toshihiro Shimizu 890ddd
/* Reset error state variables at start of a new image */
Toshihiro Shimizu 890ddd
JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo));
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace Tiio;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
JpgReader::JpgReader() : m_chan(0), m_isOpen(false)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	memset(&m_cinfo, 0, sizeof m_cinfo);
Toshihiro Shimizu 890ddd
	memset(&m_jerr, 0, sizeof m_jerr);
Toshihiro Shimizu 890ddd
	memset(&m_buffer, 0, sizeof m_buffer);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
JpgReader::~JpgReader()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_isOpen) {
Toshihiro Shimizu 890ddd
		try {
Toshihiro Shimizu 890ddd
			jpeg_finish_decompress(&m_cinfo);
Toshihiro Shimizu 890ddd
			jpeg_destroy_decompress(&m_cinfo);
Toshihiro Shimizu 890ddd
		} catch (...) {
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if (m_chan) {
Toshihiro Shimizu 890ddd
		m_chan = 0;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Tiio::RowOrder JpgReader::getRowOrder() const { return Tiio::TOP2BOTTOM; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void JpgReader::open(FILE *file)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_cinfo.err = jpeg_std_error(&m_jerr);
Toshihiro Shimizu 890ddd
	m_cinfo.err->error_exit = tnz_error_exit;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	jpeg_create_decompress(&m_cinfo);
Toshihiro Shimizu 890ddd
	m_chan = file;
Toshihiro Shimizu 890ddd
	jpeg_stdio_src(&m_cinfo, m_chan);
Toshihiro Shimizu 890ddd
	bool ret = jpeg_read_header(&m_cinfo, TRUE);
Toshihiro Shimizu 890ddd
	ret = ret && jpeg_start_decompress(&m_cinfo);
Toshihiro Shimizu 890ddd
	if (!ret)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int row_stride = m_cinfo.output_width * m_cinfo.output_components;
Toshihiro Shimizu 890ddd
	m_buffer = (*m_cinfo.mem->alloc_sarray)((j_common_ptr)&m_cinfo, JPOOL_IMAGE, row_stride, 1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_info.m_lx = m_cinfo.output_width;
Toshihiro Shimizu 890ddd
	m_info.m_ly = m_cinfo.output_height;
Toshihiro Shimizu 890ddd
	m_info.m_samplePerPixel = 3;
Toshihiro Shimizu 890ddd
	m_info.m_valid = true;
Toshihiro Shimizu 890ddd
	m_isOpen = true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void JpgReader::readLine(char *buffer, int x0, int x1, int shrink)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_cinfo.out_color_space == JCS_RGB && m_cinfo.out_color_components == 3) {
Toshihiro Shimizu 890ddd
		int ret = jpeg_read_scanlines(&m_cinfo, m_buffer, 1);
Toshihiro Shimizu 890ddd
		assert(ret == 1);
Toshihiro Shimizu 890ddd
		unsigned char *src = m_buffer[0];
Toshihiro Shimizu 890ddd
		TPixel32 *dst = (TPixel32 *)buffer;
Toshihiro Shimizu 890ddd
		dst += x0;
Toshihiro Shimizu 890ddd
		src += 3 * x0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int width = (m_cinfo.output_width - 1) / shrink + 1;
Toshihiro Shimizu 890ddd
		if (x1 >= x0)
Toshihiro Shimizu 890ddd
			width = (x1 - x0) / shrink + 1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		while (--width >= 0) {
Toshihiro Shimizu 890ddd
			dst->r = src[0];
Toshihiro Shimizu 890ddd
			dst->g = src[1];
Toshihiro Shimizu 890ddd
			dst->b = src[2];
Toshihiro Shimizu 890ddd
			dst->m = (char)255;
Toshihiro Shimizu 890ddd
			src += 3 * shrink;
Toshihiro Shimizu 890ddd
			dst += shrink;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	} else if (m_cinfo.out_color_components == 1) {
Toshihiro Shimizu 890ddd
		int ret = jpeg_read_scanlines(&m_cinfo, m_buffer, 1);
Toshihiro Shimizu 890ddd
		assert(ret == 1);
Toshihiro Shimizu 890ddd
		unsigned char *src = m_buffer[0];
Toshihiro Shimizu 890ddd
		TPixel32 *dst = (TPixel32 *)buffer;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		dst += x0;
Toshihiro Shimizu 890ddd
		src += x0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int width = (m_cinfo.output_width - 1) / shrink + 1;
Toshihiro Shimizu 890ddd
		if (x1 >= x0)
Toshihiro Shimizu 890ddd
			width = (x1 - x0) / shrink + 1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		while (--width >= 0) {
Toshihiro Shimizu 890ddd
			dst->r = *src;
Toshihiro Shimizu 890ddd
			dst->g = *src;
Toshihiro Shimizu 890ddd
			dst->b = *src;
Toshihiro Shimizu 890ddd
			dst->m = (char)255;
Toshihiro Shimizu 890ddd
			src += shrink;
Toshihiro Shimizu 890ddd
			dst += shrink;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
int JpgReader::skipLines(int lineCount)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	for (int i = 0; i < lineCount; i++) {
Toshihiro Shimizu 890ddd
		int ret = jpeg_read_scanlines(&m_cinfo, m_buffer, 1);
Toshihiro Shimizu 890ddd
		assert(ret == 1);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	return lineCount;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class JpgWriter : public Tiio::Writer
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	struct jpeg_compress_struct m_cinfo;
Toshihiro Shimizu 890ddd
	struct jpeg_error_mgr m_jerr;
Toshihiro Shimizu 890ddd
	FILE *m_chan;
Toshihiro Shimizu 890ddd
	JSAMPARRAY m_buffer;
Toshihiro Shimizu 890ddd
	bool m_headerWritten;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	JpgWriter()
Toshihiro Shimizu 890ddd
		: m_chan(0), m_headerWritten(false)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void open(FILE *file, const TImageInfo &info)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_cinfo.err = jpeg_std_error(&m_jerr);
Toshihiro Shimizu 890ddd
		jpeg_create_compress(&m_cinfo);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_cinfo.image_width = info.m_lx;
Toshihiro Shimizu 890ddd
		m_cinfo.image_height = info.m_ly;
Toshihiro Shimizu 890ddd
		m_cinfo.input_components = 3;
Toshihiro Shimizu 890ddd
		m_cinfo.in_color_space = JCS_RGB;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		jpeg_set_defaults(&m_cinfo);
Toshihiro Shimizu 890ddd
		if (!m_properties)
Toshihiro Shimizu 890ddd
			m_properties = new Tiio::JpgWriterProperties();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		jpeg_set_quality(&m_cinfo, ((TIntProperty *)(m_properties->getProperty("Quality")))->getValue(), TRUE);
Toshihiro Shimizu 890ddd
		m_cinfo.smoothing_factor = ((TIntProperty *)(m_properties->getProperty("Smoothing")))->getValue();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int row_stride = m_cinfo.image_width * m_cinfo.input_components;
Toshihiro Shimizu 890ddd
		m_buffer = (*m_cinfo.mem->alloc_sarray)((j_common_ptr)&m_cinfo, JPOOL_IMAGE, row_stride, 1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_chan = file;
Toshihiro Shimizu 890ddd
		jpeg_stdio_dest(&m_cinfo, m_chan);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	~JpgWriter()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		jpeg_finish_compress(&m_cinfo);
Toshihiro Shimizu 890ddd
		jpeg_destroy_compress(&m_cinfo);
Toshihiro Shimizu 890ddd
		delete m_properties;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void flush()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		fflush(m_chan);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	Tiio::RowOrder getRowOrder() const { return Tiio::TOP2BOTTOM; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void writeLine(char *buffer)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		if (!m_headerWritten) {
Toshihiro Shimizu 890ddd
			m_headerWritten = true;
Toshihiro Shimizu 890ddd
			jpeg_start_compress(&m_cinfo, TRUE);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		TPixel32 *src = (TPixel32 *)buffer;
Toshihiro Shimizu 890ddd
		unsigned char *dst = m_buffer[0];
Toshihiro Shimizu 890ddd
		int lx = m_cinfo.image_width;
Toshihiro Shimizu 890ddd
		while (--lx >= 0) {
Toshihiro Shimizu 890ddd
			dst[0] = src->r;
Toshihiro Shimizu 890ddd
			dst[1] = src->g;
Toshihiro Shimizu 890ddd
			dst[2] = src->b;
Toshihiro Shimizu 890ddd
			dst += 3;
Toshihiro Shimizu 890ddd
			++src;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		jpeg_write_scanlines(&m_cinfo, m_buffer, 1);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----
Toshihiro Shimizu 890ddd
//----
Toshihiro Shimizu 890ddd
//----
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Tiio::Reader *Tiio::makeJpgReader()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return new JpgReader();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Tiio::Writer *Tiio::makeJpgWriter()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return new JpgWriter();
Toshihiro Shimizu 890ddd
}