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