r15165 by jghali - - new ScJpegEncodeFilter class : allow compression of image data directly to a stream without having to use a temporary file, use it in ScImage::convert2JPG() - small fix for ScRC4EncodeFilter class - fix broken conversion to cmyk when loading images

scribus-commit scribus-commit at lists.scribus.net
Sun Jun 6 22:20:34 CEST 2010


Revision: 15165
Author: jghali
Date: 2010-06-06T20:15:13.869571Z
Commit message: - new ScJpegEncodeFilter class : 
allow compression of image data directly to a stream without having to use a temporary file, use it in ScImage::convert2JPG()
- small fix for ScRC4EncodeFilter class
- fix broken conversion to cmyk when loading images

Changeset: 
M  /trunk/Scribus/scribus/scimage.cpp
M  /trunk/Scribus/scribus/CMakeLists.txt
A  /trunk/Scribus/scribus/scstreamfilter_jpeg.cpp
M  /trunk/Scribus/scribus/scstreamfilter_rc4.cpp
A  /trunk/Scribus/scribus/scstreamfilter_jpeg.h
M  /trunk/Scribus/win32/vc8/Scribus.vcproj

Diffs:
Index: scribus/scstreamfilter_rc4.cpp
===================================================================
--- scribus/scstreamfilter_rc4.cpp	(revision 15164)
+++ scribus/scstreamfilter_rc4.cpp	(revision 15165)
@@ -57,6 +57,7 @@
 
 	rc4_init(&m_filterData->rc4_context, (uchar*) m_key.data(),m_key.length());
 	m_filterData->available_in  = 0;
+	m_openedFilter = true;
 	return true;
 }
 
Index: scribus/scstreamfilter_jpeg.h
===================================================================
--- scribus/scstreamfilter_jpeg.h	(revision 0)
+++ scribus/scstreamfilter_jpeg.h	(revision 15165)
@@ -0,0 +1,52 @@
+/*
+For general Scribus (>=1.3.2) copyright and licensing information please refer
+to the COPYING file provided with the program. Following this notice may exist
+a copyright and/or license notice that predates the release of Scribus 1.3.2
+for which a new license (GPL+exception) is in place.
+*/
+
+#ifndef SCSTREAMFILTER_JPEG_H
+#define SCSTREAMFILTER_JPEG_H
+
+#include <QGlobalStatic>
+#include "scstreamfilter.h"
+
+struct ScJpegEncodeFilterData;
+
+class ScJpegEncodeFilter : public ScStreamFilter
+{
+	friend struct ScJpegDestinationMgr;
+
+public:
+
+	typedef enum  {
+		RGB,
+		CMYK,
+		GRAY
+	} Color;
+
+	ScJpegEncodeFilter(QDataStream* stream, unsigned int imgWidth, unsigned int imgHeight, ScJpegEncodeFilter::Color color);
+	ScJpegEncodeFilter(ScStreamFilter* filter, unsigned int imgWidth, unsigned int imgHeight, ScJpegEncodeFilter::Color color);
+	~ScJpegEncodeFilter();
+
+	virtual bool openFilter (void);
+	virtual bool closeFilter(void);
+
+	virtual bool writeData(const char* data, int dataLen);
+
+	void setQuality(int quality) { m_quality = qMin(qMax(0, quality), 100); }
+
+protected:
+
+	ScJpegEncodeFilterData* m_filterData;
+
+	void  freeData(void);
+	bool  m_openedFilter;
+
+	unsigned int m_width;
+	unsigned int m_height;
+	int          m_quality;
+	Color        m_color;
+};
+
+#endif
Index: scribus/scimage.cpp
===================================================================
--- scribus/scimage.cpp	(revision 15164)
+++ scribus/scimage.cpp	(revision 15165)
@@ -23,7 +23,9 @@
 #include "scimgdataloader_qt.h"
 #include "scimgdataloader_tiff.h"
 #include "scimgdataloader_wpg.h"
+#include "scstreamfilter_jpeg.h"
 #include "sctextstream.h"
+#include <QFile>
 #include <QMessageBox>
 #include <QList>
 #include <QByteArray>
@@ -45,36 +47,8 @@
 #include "util_ghostscript.h"
 #include "rawimage.h"
 
-extern "C"
-{
-#define XMD_H           // shut JPEGlib up
-#if defined(Q_OS_UNIXWARE)
-#  define HAVE_BOOLEAN  // libjpeg under Unixware seems to need this
-#endif
-#include <jpeglib.h>
-#include <jerror.h>
-#undef HAVE_STDLIB_H
-#ifdef const
-#  undef const          // remove crazy C hackery in jconfig.h
-#endif
-}
-
 using namespace std;
 
-typedef struct my_error_mgr
-{
-	struct jpeg_error_mgr pub;            /* "public" fields */
-	jmp_buf setjmp_buffer;  /* for return to caller */
-}
-*my_error_ptr;
-
-static void my_error_exit (j_common_ptr cinfo)
-{
-	my_error_ptr myerr = (my_error_ptr) cinfo->err;
-	(*cinfo->err->output_message) (cinfo);
-	longjmp (myerr->setjmp_buffer, 1);
-}
-
 ScImage::ScImage(const QImage & image) : QImage(image)
 {
 	initialize();
@@ -1201,96 +1175,32 @@
 
 bool ScImage::convert2JPG(QString fn, int Quality, bool isCMYK, bool isGray)
 {
-	struct jpeg_compress_struct cinfo;
-	struct my_error_mgr         jerr;
-	FILE     *outfile;
-	JSAMPROW row_pointer[1];
-	row_pointer[0] = 0;
-	cinfo.err = jpeg_std_error (&jerr.pub);
-	jerr.pub.error_exit = my_error_exit;
-	outfile = NULL;
-	if (setjmp (jerr.setjmp_buffer))
+	bool success = false;
+	QFile file(fn);
+	if (file.open(QIODevice::WriteOnly))
 	{
-		jpeg_destroy_compress (&cinfo);
-		if (outfile)
-			fclose (outfile);
-		return false;
-	}
-	jpeg_create_compress (&cinfo);
-	if ((outfile = fopen (fn.toLocal8Bit(), "wb")) == NULL)
-		return false;
-	jpeg_stdio_dest (&cinfo, outfile);
-	cinfo.image_width  = width();
-	cinfo.image_height = height();
-	if (isCMYK)
-	{
-		cinfo.in_color_space = JCS_CMYK;
-		cinfo.input_components = 4;
-	}
-	else
-	{
-		if (isGray)
-		{
-			cinfo.in_color_space = JCS_GRAYSCALE;
-			cinfo.input_components = 1;
-		}
-		else
-		{
-			cinfo.in_color_space = JCS_RGB;
-			cinfo.input_components = 3;
-		}
-	}
-	jpeg_set_defaults (&cinfo);
-	int qual[] = { 95, 85, 75, 50, 25 };  // These are the JPEG Quality settings 100 means best, 0 .. don't discuss
-	jpeg_set_quality (&cinfo, qual[Quality], true);
-	jpeg_start_compress (&cinfo, true);
-	row_pointer[0] = new uchar[cinfo.image_width*cinfo.input_components];
-	int w = cinfo.image_width;
-	while (cinfo.next_scanline < cinfo.image_height)
-	{
-		uchar *row = row_pointer[0];
+		ScJpegEncodeFilter::Color imgColor = ScJpegEncodeFilter::GRAY;
 		if (isCMYK)
+			imgColor = ScJpegEncodeFilter::CMYK;
+		else if (!isGray)
+			imgColor = ScJpegEncodeFilter::RGB;
+		int qual[] = { 95, 85, 75, 50, 25 };  // These are the JPEG Quality settings 100 means best, 0 .. don't discuss
+		QDataStream dataStream(&file);
+		ScJpegEncodeFilter jpegFilter(&dataStream, width(), height(), imgColor);
+		jpegFilter.setQuality(qual[Quality]);
+		if (jpegFilter.openFilter())
 		{
-			QRgb* rgba = (QRgb*)scanLine(cinfo.next_scanline);
-			for (int i=0; i<w; ++i)
-			{
-				*row++ = qRed(*rgba);
-				*row++ = qGreen(*rgba);
-				*row++ = qBlue(*rgba);
-				*row++ = qAlpha(*rgba);
-				++rgba;
-			}
-		}
-		else
-		{
-			if (isGray)
-			{
-				QRgb* rgba = (QRgb*)scanLine(cinfo.next_scanline);
-				for (int i=0; i<w; ++i)
-				{
-					*row++ = qRed(*rgba);
-					++rgba;
-				}
-			}
+			if (isCMYK)
+				success = writeCMYKDataToFilter(&jpegFilter);
+			else if (isGray)
+				success = writeGrayDataToFilter(&jpegFilter, true);
 			else
-			{
-				QRgb* rgb = (QRgb*)scanLine(cinfo.next_scanline);
-				for (int i=0; i<w; i++)
-				{
-					*row++ = qRed(*rgb);
-					*row++ = qGreen(*rgb);
-					*row++ = qBlue(*rgb);
-					++rgb;
-				}
-			}
+				success = writeRGBDataToFilter(&jpegFilter);
+			success &= jpegFilter.closeFilter();
 		}
-		jpeg_write_scanlines (&cinfo, row_pointer, 1);
+		file.close();
 	}
-	jpeg_finish_compress (&cinfo);
-	fclose (outfile);
-	jpeg_destroy_compress (&cinfo);
-	delete [] row_pointer[0];
-	return true;
+	return success;
 }
 
 QByteArray ScImage::ImageToArray()
@@ -2234,6 +2144,7 @@
 				xform = inputCSpace.createTransform(printerProf, outputProfFormat, cmSettings.imageRenderingIntent(), cmsFlags);
 			if (outputProfColorSpace != ColorSpace_Cmyk )
 				*realCMYK = isCMYK = false;
+			outputCSpace = engine.createColorSpace(printerProf, outputProfFormat);
 			break;
 		case Thumbnail:
 		case RGBData: // RGB
Index: scribus/scstreamfilter_jpeg.cpp
===================================================================
--- scribus/scstreamfilter_jpeg.cpp	(revision 0)
+++ scribus/scstreamfilter_jpeg.cpp	(revision 15165)
@@ -0,0 +1,276 @@
+/*
+For general Scribus (>=1.3.2) copyright and licensing information please refer
+to the COPYING file provided with the program. Following this notice may exist
+a copyright and/or license notice that predates the release of Scribus 1.3.2
+for which a new license (GPL+exception) is in place.
+*/
+
+#include "scconfig.h"
+#include "scstreamfilter_jpeg.h"
+
+#include <cstdlib>
+#include <setjmp.h>
+#include <stdio.h>
+#include <string.h>
+
+extern "C"
+{
+#define XMD_H           // shut JPEGlib up
+#if defined(Q_OS_UNIXWARE)
+#  define HAVE_BOOLEAN  // libjpeg under Unixware seems to need this
+#endif
+#include <jpeglib.h>
+#include <jerror.h>
+#undef HAVE_STDLIB_H
+#ifdef const
+#  undef const          // remove crazy C hackery in jconfig.h
+#endif
+}
+
+#define BUFFER_SIZE 65536
+
+struct ScJpegErrorMgr
+{
+	struct  jpeg_error_mgr pub;            /* "public" fields */
+	jmp_buf setjmp_buffer;  /* for return to caller */
+
+	static void jpegErrorExit (j_common_ptr cinfo);
+};
+
+void ScJpegErrorMgr::jpegErrorExit (j_common_ptr cinfo)
+{
+	ScJpegErrorMgr* myerr = (ScJpegErrorMgr*) cinfo->err;
+	(*cinfo->err->output_message) (cinfo);
+	longjmp (myerr->setjmp_buffer, 1);
+}
+
+struct ScJpegDestinationMgr : public jpeg_destination_mgr 
+{
+    ScJpegEncodeFilter *filter;
+    JOCTET buffer[BUFFER_SIZE];
+
+public:
+    ScJpegDestinationMgr(ScJpegEncodeFilter *);
+
+	static boolean jpegEmptyBuffer(j_compress_ptr cinfo);
+	static void    jpegDestinationInit(j_compress_ptr);
+	static void    jpegDestinationTerm(j_compress_ptr cinfo);
+};
+
+void ScJpegDestinationMgr::jpegDestinationInit(j_compress_ptr)
+{
+}
+
+boolean ScJpegDestinationMgr::jpegEmptyBuffer(j_compress_ptr cinfo)
+{
+    ScJpegDestinationMgr* dest = (ScJpegDestinationMgr*) cinfo->dest;
+
+    bool written = dest->filter->writeDataInternal((const char*) dest->buffer, BUFFER_SIZE);
+    if (!written)
+        (*cinfo->err->error_exit)((j_common_ptr) cinfo);
+
+    dest->next_output_byte = dest->buffer;
+    dest->free_in_buffer   = BUFFER_SIZE;
+
+    return boolean(true);
+}
+
+void ScJpegDestinationMgr::jpegDestinationTerm(j_compress_ptr cinfo)
+{
+    ScJpegDestinationMgr* dest = (ScJpegDestinationMgr*) cinfo->dest;
+    int n = BUFFER_SIZE - dest->free_in_buffer;
+
+    bool written = dest->filter->writeDataInternal((const char*) dest->buffer, BUFFER_SIZE);
+    if (!written)
+        (*cinfo->err->error_exit)((j_common_ptr)cinfo);
+}
+
+ScJpegDestinationMgr::ScJpegDestinationMgr(ScJpegEncodeFilter *filter)
+{
+	jpeg_destination_mgr::empty_output_buffer = jpegEmptyBuffer;
+    jpeg_destination_mgr::init_destination    = jpegDestinationInit;
+    jpeg_destination_mgr::term_destination    = jpegDestinationTerm;
+    this->filter     = filter;
+    next_output_byte = buffer;
+    free_in_buffer   = BUFFER_SIZE;
+}
+
+struct ScJpegEncodeFilterData
+{
+	struct   jpeg_compress_struct  cinfo;
+	struct   ScJpegDestinationMgr* cdest;
+	JSAMPROW row_pointer[1];
+
+	ScJpegEncodeFilterData();
+	~ScJpegEncodeFilterData();
+};
+
+ScJpegEncodeFilterData::ScJpegEncodeFilterData() : cdest(NULL)
+{
+	row_pointer[0] = NULL;
+}
+
+ScJpegEncodeFilterData::~ScJpegEncodeFilterData()
+{
+	if (cdest)
+		delete cdest;
+	if (row_pointer[0])
+		delete row_pointer[0];
+}
+
+ScJpegEncodeFilter::ScJpegEncodeFilter(QDataStream* stream, unsigned int imgWidth, unsigned int imgHeight, 
+		            ScJpegEncodeFilter::Color color) : ScStreamFilter(stream), m_width(imgWidth), m_height(imgHeight),
+					m_color(color), m_quality(75)
+{
+	m_filterData = NULL;
+	m_openedFilter = false;
+}
+
+ScJpegEncodeFilter::ScJpegEncodeFilter(ScStreamFilter* filter, unsigned int imgWidth, unsigned int imgHeight, 
+					ScJpegEncodeFilter::Color color) : ScStreamFilter(filter), m_width(imgWidth), m_height(imgHeight),
+					m_color(color), m_quality(75)
+{
+	m_filterData = NULL;
+	m_openedFilter = false;
+}
+
+ScJpegEncodeFilter::~ScJpegEncodeFilter()
+{
+	if (m_filterData && m_openedFilter)
+		closeFilter();
+	freeData();
+}
+
+void ScJpegEncodeFilter::freeData(void)
+{
+	if (m_filterData)
+		delete m_filterData;
+	m_filterData = NULL;
+}
+
+bool ScJpegEncodeFilter::openFilter (void)
+{
+	freeData();
+
+	if (m_width == 0 || m_height == 0)
+		return false;
+
+	m_filterData = new ScJpegEncodeFilterData();
+	if (m_filterData == NULL)
+		return false;
+
+	struct ScJpegErrorMgr jerr;
+	jerr.pub.error_exit     = ScJpegErrorMgr::jpegErrorExit;
+	m_filterData->cinfo.err = jpeg_std_error (&jerr.pub);
+	m_filterData->row_pointer[0] = 0;
+
+	m_filterData->cdest = new ScJpegDestinationMgr(this);
+	if (m_filterData->cdest == NULL)
+		return false;
+
+	bool success = false;
+
+	if (!setjmp (jerr.setjmp_buffer))
+	{
+		jpeg_create_compress (&m_filterData->cinfo);
+		m_filterData->cinfo.dest         = m_filterData->cdest;
+		m_filterData->cinfo.image_width  = m_width;
+		m_filterData->cinfo.image_height = m_height;
+		if (m_color == ScJpegEncodeFilter::RGB)
+		{
+			m_filterData->cinfo.in_color_space   = JCS_RGB;
+			m_filterData->cinfo.input_components = 3;
+		}
+		else if (m_color == ScJpegEncodeFilter::CMYK)
+		{
+			m_filterData->cinfo.in_color_space   = JCS_CMYK;
+			m_filterData->cinfo.input_components = 4;
+		}
+		else // m_color == ScJpegEncodeFilter::GRAY
+		{
+			m_filterData->cinfo.in_color_space   = JCS_GRAYSCALE;
+			m_filterData->cinfo.input_components = 1;
+		}
+		jpeg_set_defaults  (&m_filterData->cinfo);
+		jpeg_set_quality   (&m_filterData->cinfo, m_quality, true);
+		jpeg_start_compress(&m_filterData->cinfo, true);
+		success = true;
+	}
+
+	if (success)
+	{
+		m_filterData->row_pointer[0] = new uchar[m_filterData->cinfo.image_width * m_filterData->cinfo.input_components];
+		if (m_filterData->row_pointer[0] == NULL)
+			success = false;
+	}
+	if (!success || !ScStreamFilter::openFilter())
+	{
+		jpeg_destroy_compress (&m_filterData->cinfo);
+		return false;
+	}
+	m_openedFilter = true;
+	return true;
+}
+
+bool ScJpegEncodeFilter::closeFilter(void)
+{
+	bool closeSucceed = true;
+
+	if (!m_filterData)
+		return false;
+
+	struct ScJpegErrorMgr jerr;
+	jerr.pub.error_exit     = ScJpegErrorMgr::jpegErrorExit;
+	m_filterData->cinfo.err = jpeg_std_error (&jerr.pub);
+
+	if (!setjmp (jerr.setjmp_buffer))
+	{
+		jpeg_finish_compress (&m_filterData->cinfo);
+		jpeg_destroy_compress(&m_filterData->cinfo);
+	}
+	else
+	{
+		closeSucceed = false;
+	}
+	m_openedFilter = false;
+	return closeSucceed;
+}
+
+bool ScJpegEncodeFilter::writeData(const char* data, int dataLen)
+{
+	bool succeed = false;
+
+	if ((!m_filterData) || (dataLen < 0))
+		return false;
+	if (dataLen == 0)
+		return true;
+
+	// For now dataLen must be a multiple of scanline width
+	int scanLineSize = m_filterData->cinfo.image_width * m_filterData->cinfo.input_components;
+	if ((dataLen % scanLineSize) != 0)
+		return false;
+
+	struct ScJpegErrorMgr jerr;
+	jerr.pub.error_exit     = ScJpegErrorMgr::jpegErrorExit;
+	m_filterData->cinfo.err = jpeg_std_error (&jerr.pub);
+
+	if (!setjmp (jerr.setjmp_buffer))
+	{
+		int nScanLines = dataLen / scanLineSize;
+		for (int i = 0; i  < nScanLines; ++i)
+		{
+			memcpy(m_filterData->row_pointer[0], data, scanLineSize);
+			jpeg_write_scanlines (&m_filterData->cinfo, m_filterData->row_pointer, 1);
+			data += scanLineSize;
+		}
+		succeed = true;
+	}
+	else
+	{
+		// Subsequent calls to writeData() or closeFilter() will return false
+		jpeg_destroy_compress(&m_filterData->cinfo);
+		freeData(); 
+	}
+
+	return succeed;
+}
Index: scribus/CMakeLists.txt
===================================================================
--- scribus/CMakeLists.txt	(revision 15164)
+++ scribus/CMakeLists.txt	(revision 15165)
@@ -720,6 +720,7 @@
   scstreamfilter.cpp
   scstreamfilter_ascii85.cpp
   scstreamfilter_flate.cpp
+  scstreamfilter_jpeg.cpp
   scstreamfilter_rc4.cpp
   ui/sctablewidget.cpp
   ui/sctextbrowser.cpp
Index: win32/vc8/Scribus.vcproj
===================================================================
--- win32/vc8/Scribus.vcproj	(revision 15164)
+++ win32/vc8/Scribus.vcproj	(revision 15165)
@@ -1787,6 +1787,10 @@
 				>
 			</File>
 			<File
+				RelativePath="..\..\scribus\scstreamfilter_jpeg.cpp"
+				>
+			</File>
+			<File
 				RelativePath="..\..\scribus\scstreamfilter_rc4.cpp"
 				>
 			</File>
@@ -9636,6 +9640,10 @@
 				>
 			</File>
 			<File
+				RelativePath="..\..\scribus\scstreamfilter_jpeg.h"
+				>
+			</File>
+			<File
 				RelativePath="..\..\scribus\scstreamfilter_rc4.h"
 				>
 			</File>




More information about the scribus-commit mailing list