59
59
struct JpegFatalError : public jpeg_error_mgr {
62
static void handler(j_common_ptr cinfo) {
63
JpegFatalError* error=static_cast<JpegFatalError*>(cinfo->err);
64
(error->output_message)(cinfo);
65
longjmp(error->mJmpBuffer,1);
62
static void handler(j_common_ptr cinfo)
64
JpegFatalError* error = static_cast<JpegFatalError*>(cinfo->err);
65
(error->output_message)(cinfo);
66
longjmp(error->mJmpBuffer, 1);
70
static void expand24to32bpp(QImage* image) {
71
for (int j = 0; j < image->height(); ++j) {
72
uchar *in = image->scanLine(j) + (image->width() - 1)*3;
73
QRgb *out = (QRgb*)( image->scanLine(j) ) + image->width() - 1;
75
for (int i=image->width() - 1; i>=0; --i, --out, in -= 3) {
76
*out = qRgb(in[0], in[1], in[2]);
82
static void convertCmykToRgb(QImage* image) {
83
for (int j = 0; j < image->height(); ++j) {
84
uchar *in = image->scanLine(j) + image->width() * 4;
85
QRgb *out = (QRgb*)image->scanLine(j);
87
for (int i = image->width() - 1; i>=0; --i) {
90
out[i] = qRgb(k * in[0] / 255, k * in[1] / 255, k * in[2] / 255);
96
static QSize getJpegSize(QIODevice* ioDevice) {
97
struct jpeg_decompress_struct cinfo;
101
struct JpegFatalError jerr;
102
cinfo.err = jpeg_std_error(&jerr);
103
cinfo.err->error_exit = JpegFatalError::handler;
104
if (setjmp(jerr.mJmpBuffer)) {
105
jpeg_destroy_decompress(&cinfo);
109
// Init decompression
110
jpeg_create_decompress(&cinfo);
111
Gwenview::IODeviceJpegSourceManager::setup(&cinfo, ioDevice);
112
jpeg_read_header(&cinfo, true);
114
size = QSize(cinfo.image_width, cinfo.image_height);
115
jpeg_destroy_decompress(&cinfo);
120
static bool loadJpeg(QImage* image, QIODevice* ioDevice, QSize scaledSize) {
121
struct jpeg_decompress_struct cinfo;
124
struct JpegFatalError jerr;
125
cinfo.err = jpeg_std_error(&jerr);
126
cinfo.err->error_exit = JpegFatalError::handler;
127
if (setjmp(jerr.mJmpBuffer)) {
128
jpeg_destroy_decompress(&cinfo);
132
// Init decompression
133
jpeg_create_decompress(&cinfo);
134
Gwenview::IODeviceJpegSourceManager::setup(&cinfo, ioDevice);
135
jpeg_read_header(&cinfo, true);
137
// Compute scale value
139
if (!scaledSize.isEmpty()) {
140
// Use !scaledSize.isEmpty(), not scaledSize.isValid() because
141
// isValid() returns true if both the width and height is equal to or
142
// greater than 0, so it is possible to get a division by 0.
143
cinfo.scale_denom = qMin(cinfo.image_width / scaledSize.width(),
144
cinfo.image_height / scaledSize.height());
145
if (cinfo.scale_denom < 2) {
146
cinfo.scale_denom = 1;
147
} else if (cinfo.scale_denom < 4) {
148
cinfo.scale_denom = 2;
149
} else if (cinfo.scale_denom < 8) {
150
cinfo.scale_denom = 4;
152
cinfo.scale_denom = 8;
155
cinfo.scale_denom = 1;
157
LOG("cinfo.scale_denom=" << cinfo.scale_denom);
160
jpeg_start_decompress(&cinfo);
161
switch(cinfo.output_components) {
164
*image = QImage(cinfo.output_width, cinfo.output_height, QImage::Format_RGB32);
167
*image = QImage(cinfo.output_width, cinfo.output_height, QImage::Format_Indexed8);
168
image->setNumColors(256);
169
for (int i=0; i<256; ++i) {
170
image->setColor(i, qRgba(i, i, i, 255));
174
jpeg_destroy_decompress(&cinfo);
178
while (cinfo.output_scanline < cinfo.output_height) {
179
uchar *line = image->scanLine(cinfo.output_scanline);
180
jpeg_read_scanlines(&cinfo, &line, 1);
183
switch (cinfo.out_color_space) {
185
convertCmykToRgb(image);
191
kWarning() << "Unhandled JPEG colorspace" << cinfo.out_color_space;
195
if ( cinfo.output_components == 3 ) {
196
expand24to32bpp(image);
199
if (scaledSize.isValid()) {
200
*image = image->scaled(scaledSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
203
jpeg_finish_decompress(&cinfo);
204
jpeg_destroy_decompress(&cinfo);
70
static void expand24to32bpp(QImage* image)
72
for (int j = 0; j < image->height(); ++j) {
73
uchar *in = image->scanLine(j) + (image->width() - 1) * 3;
74
QRgb *out = (QRgb*)(image->scanLine(j)) + image->width() - 1;
76
for (int i = image->width() - 1; i >= 0; --i, --out, in -= 3) {
77
*out = qRgb(in[0], in[1], in[2]);
82
static void convertCmykToRgb(QImage* image)
84
for (int j = 0; j < image->height(); ++j) {
85
uchar *in = image->scanLine(j) + image->width() * 4;
86
QRgb *out = (QRgb*)image->scanLine(j);
88
for (int i = image->width() - 1; i >= 0; --i) {
91
out[i] = qRgb(k * in[0] / 255, k * in[1] / 255, k * in[2] / 255);
96
static QSize getJpegSize(QIODevice* ioDevice)
98
struct jpeg_decompress_struct cinfo;
102
struct JpegFatalError jerr;
103
cinfo.err = jpeg_std_error(&jerr);
104
cinfo.err->error_exit = JpegFatalError::handler;
105
if (setjmp(jerr.mJmpBuffer)) {
106
jpeg_destroy_decompress(&cinfo);
110
// Init decompression
111
jpeg_create_decompress(&cinfo);
112
Gwenview::IODeviceJpegSourceManager::setup(&cinfo, ioDevice);
113
jpeg_read_header(&cinfo, true);
115
size = QSize(cinfo.image_width, cinfo.image_height);
116
jpeg_destroy_decompress(&cinfo);
120
static bool loadJpeg(QImage* image, QIODevice* ioDevice, QSize scaledSize)
122
struct jpeg_decompress_struct cinfo;
125
struct JpegFatalError jerr;
126
cinfo.err = jpeg_std_error(&jerr);
127
cinfo.err->error_exit = JpegFatalError::handler;
128
if (setjmp(jerr.mJmpBuffer)) {
129
jpeg_destroy_decompress(&cinfo);
133
// Init decompression
134
jpeg_create_decompress(&cinfo);
135
Gwenview::IODeviceJpegSourceManager::setup(&cinfo, ioDevice);
136
jpeg_read_header(&cinfo, true);
138
// Compute scale value
140
if (!scaledSize.isEmpty()) {
141
// Use !scaledSize.isEmpty(), not scaledSize.isValid() because
142
// isValid() returns true if both the width and height is equal to or
143
// greater than 0, so it is possible to get a division by 0.
144
cinfo.scale_denom = qMin(cinfo.image_width / scaledSize.width(),
145
cinfo.image_height / scaledSize.height());
146
if (cinfo.scale_denom < 2) {
147
cinfo.scale_denom = 1;
148
} else if (cinfo.scale_denom < 4) {
149
cinfo.scale_denom = 2;
150
} else if (cinfo.scale_denom < 8) {
151
cinfo.scale_denom = 4;
153
cinfo.scale_denom = 8;
156
cinfo.scale_denom = 1;
158
LOG("cinfo.scale_denom=" << cinfo.scale_denom);
161
jpeg_start_decompress(&cinfo);
162
switch (cinfo.output_components) {
165
*image = QImage(cinfo.output_width, cinfo.output_height, QImage::Format_RGB32);
168
*image = QImage(cinfo.output_width, cinfo.output_height, QImage::Format_Indexed8);
169
image->setNumColors(256);
170
for (int i = 0; i < 256; ++i) {
171
image->setColor(i, qRgba(i, i, i, 255));
175
jpeg_destroy_decompress(&cinfo);
179
while (cinfo.output_scanline < cinfo.output_height) {
180
uchar *line = image->scanLine(cinfo.output_scanline);
181
jpeg_read_scanlines(&cinfo, &line, 1);
184
switch (cinfo.out_color_space) {
186
convertCmykToRgb(image);
192
kWarning() << "Unhandled JPEG colorspace" << cinfo.out_color_space;
196
if (cinfo.output_components == 3) {
197
expand24to32bpp(image);
200
if (scaledSize.isValid()) {
201
*image = image->scaled(scaledSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
204
jpeg_finish_decompress(&cinfo);
205
jpeg_destroy_decompress(&cinfo);
210
210
/****************************************************************************
211
211
This code is a copy of qjpeghandler.cpp because I can't find a way to fallback
245
244
my_jpeg_destination_mgr(QIODevice *);
249
247
#if defined(Q_C_CALLBACKS)
253
static void qt_init_destination(j_compress_ptr)
257
static boolean qt_empty_output_buffer(j_compress_ptr cinfo)
259
my_jpeg_destination_mgr* dest = (my_jpeg_destination_mgr*)cinfo->dest;
261
int written = dest->device->write((char*)dest->buffer, max_buf);
263
(*cinfo->err->error_exit)((j_common_ptr)cinfo);
265
dest->next_output_byte = dest->buffer;
266
dest->free_in_buffer = max_buf;
251
static void qt_init_destination(j_compress_ptr)
255
static boolean qt_empty_output_buffer(j_compress_ptr cinfo)
257
my_jpeg_destination_mgr* dest = (my_jpeg_destination_mgr*)cinfo->dest;
259
int written = dest->device->write((char*)dest->buffer, max_buf);
261
(*cinfo->err->error_exit)((j_common_ptr)cinfo);
263
dest->next_output_byte = dest->buffer;
264
dest->free_in_buffer = max_buf;
268
266
#if defined(Q_OS_UNIXWARE)
275
static void qt_term_destination(j_compress_ptr cinfo)
277
my_jpeg_destination_mgr* dest = (my_jpeg_destination_mgr*)cinfo->dest;
278
qint64 n = max_buf - dest->free_in_buffer;
280
qint64 written = dest->device->write((char*)dest->buffer, n);
282
(*cinfo->err->error_exit)((j_common_ptr)cinfo);
273
static void qt_term_destination(j_compress_ptr cinfo)
275
my_jpeg_destination_mgr* dest = (my_jpeg_destination_mgr*)cinfo->dest;
276
qint64 n = max_buf - dest->free_in_buffer;
278
qint64 written = dest->device->write((char*)dest->buffer, n);
280
(*cinfo->err->error_exit)((j_common_ptr)cinfo);
285
283
#if defined(Q_C_CALLBACKS)
453
449
****************************************************************************/
457
451
struct JpegHandlerPrivate {
463
456
JpegHandler::JpegHandler()
464
: d(new JpegHandlerPrivate) {
469
JpegHandler::~JpegHandler() {
474
bool JpegHandler::canRead() const {
475
if (canRead(device())) {
483
bool JpegHandler::canRead(QIODevice* device) {
485
kWarning() << "called with no device";
489
return device->peek(2) == "\xFF\xD8";
493
bool JpegHandler::read(QImage* image) {
498
return loadJpeg(image, device(), d->mScaledSize);
502
bool JpegHandler::write(const QImage& image) {
504
return write_jpeg_image(image, device(), d->mQuality);
508
bool JpegHandler::supportsOption(ImageOption option) const {
457
: d(new JpegHandlerPrivate)
462
JpegHandler::~JpegHandler()
467
bool JpegHandler::canRead() const
469
if (canRead(device())) {
476
bool JpegHandler::canRead(QIODevice* device)
479
kWarning() << "called with no device";
483
return device->peek(2) == "\xFF\xD8";
486
bool JpegHandler::read(QImage* image)
492
return loadJpeg(image, device(), d->mScaledSize);
495
bool JpegHandler::write(const QImage& image)
498
return write_jpeg_image(image, device(), d->mQuality);
501
bool JpegHandler::supportsOption(ImageOption option) const
509
503
return option == ScaledSize || option == Size || option == Quality;
513
QVariant JpegHandler::option(ImageOption option) const {
514
if (option == ScaledSize) {
515
return d->mScaledSize;
516
} else if (option == Size) {
517
if (canRead() && !device()->isSequential()) {
518
qint64 pos = device()->pos();
519
QSize size = getJpegSize(device());
523
} else if (option == Quality) {
530
void JpegHandler::setOption(ImageOption option, const QVariant &value) {
531
if (option == ScaledSize) {
532
d->mScaledSize = value.toSize();
533
} else if (option == Quality) {
534
d->mQuality = value.toInt();
506
QVariant JpegHandler::option(ImageOption option) const
508
if (option == ScaledSize) {
509
return d->mScaledSize;
510
} else if (option == Size) {
511
if (canRead() && !device()->isSequential()) {
512
qint64 pos = device()->pos();
513
QSize size = getJpegSize(device());
517
} else if (option == Quality) {
523
void JpegHandler::setOption(ImageOption option, const QVariant &value)
525
if (option == ScaledSize) {
526
d->mScaledSize = value.toSize();
527
} else if (option == Quality) {
528
d->mQuality = value.toInt();