1
/* This file is based on kdelibs-3.2.0/khtml/misc/loader_jpeg.cpp. Original
5
This file is part of the KDE libraries
7
Copyright (C) 2000 Dirk Mueller (mueller@kde.org)
9
Permission is hereby granted, free of charge, to any person obtaining a copy
10
of this software and associated documentation files (the "Software"), to deal
11
in the Software without restriction, including without limitation the rights
12
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
copies of the Software, and to permit persons to whom the Software is
14
furnished to do so, subject to the following conditions:
16
The above copyright notice and this permission notice shall be included in
17
all copies or substantial portions of the Software.
19
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39
#include <qdatetime.h>
46
#include "gvjpegformattype.h"
49
//#define BUFFER_DEBUG
55
static const int MAX_BUFFER = 32768;
57
//-----------------------------------------------------------------------------
60
// (Does not follow HACKING naming recommandation to be consistent with
61
// jpeg_error_mgr naming)
63
//-----------------------------------------------------------------------------
64
struct GVJPEGErrorManager : public jpeg_error_mgr {
67
static void errorExitCallBack (j_common_ptr cinfo) {
68
GVJPEGErrorManager* myerr = (GVJPEGErrorManager*) cinfo->err;
69
char buffer[JMSG_LENGTH_MAX];
70
(*cinfo->err->format_message)(cinfo, buffer);
71
kdWarning() << buffer << endl;
72
longjmp(myerr->jmp_buffer, 1);
77
//-----------------------------------------------------------------------------
79
// GVJPEGSourceManager
80
// (Does not follow HACKING file recommandation to be consistent with
81
// jpeg_source_mgr naming)
83
//-----------------------------------------------------------------------------
84
struct GVJPEGSourceManager : public jpeg_source_mgr {
85
JOCTET jpeg_buffer[MAX_BUFFER];
87
int valid_buffer_length;
88
size_t skip_input_bytes;
95
GVJPEGSourceManager() {
96
// jpeg_source_mgr fields
97
init_source = gvJPEGDummyDecompress;
98
fill_input_buffer = gvFillInputBuffer;
99
skip_input_data = gvSkipInputData;
100
resync_to_restart = jpeg_resync_to_restart;
101
term_source = gvJPEGDummyDecompress;
104
next_input_byte = jpeg_buffer;
106
// GVJPEGSourceManager fields
107
valid_buffer_length = 0;
108
skip_input_bytes = 0;
111
decoding_done = false;
114
static void gvJPEGDummyDecompress(j_decompress_ptr) {}
116
/* Do not replace boolean with bool, it's the libjpeg boolean type */
117
static boolean gvFillInputBuffer(j_decompress_ptr cinfo) {
119
qDebug("gvFillInputBuffer called!");
122
GVJPEGSourceManager* src = (GVJPEGSourceManager*)cinfo->src;
125
/* Insert a fake EOI marker - as per jpeglib recommendation */
126
src->jpeg_buffer[0] = (JOCTET) 0xFF;
127
src->jpeg_buffer[1] = (JOCTET) JPEG_EOI;
128
src->bytes_in_buffer = 2;
129
src->next_input_byte = (JOCTET *) src->jpeg_buffer;
131
qDebug("...returning true!");
135
return false; /* I/O suspension mode */
139
static void gvSkipInputData(j_decompress_ptr cinfo, long num_bytes) {
140
if(num_bytes <= 0) return; /* required noop */
143
qDebug("gvSkipInputData (%d) called!", num_bytes);
146
GVJPEGSourceManager* src = (GVJPEGSourceManager*)cinfo->src;
147
src->skip_input_bytes += num_bytes;
149
unsigned int skipbytes = kMin(src->bytes_in_buffer, src->skip_input_bytes);
152
qDebug("skip_input_bytes is now %d", src->skip_input_bytes);
153
qDebug("skipbytes is now %d", skipbytes);
154
qDebug("valid_buffer_length is before %d", src->valid_buffer_length);
155
qDebug("bytes_in_buffer is %d", src->bytes_in_buffer);
158
if(skipbytes < src->bytes_in_buffer) {
159
memmove(src->jpeg_buffer,
160
src->next_input_byte+skipbytes,
161
src->bytes_in_buffer - skipbytes);
164
src->bytes_in_buffer -= skipbytes;
165
src->valid_buffer_length = src->bytes_in_buffer;
166
src->skip_input_bytes -= skipbytes;
168
/* adjust data for jpeglib */
169
cinfo->src->next_input_byte = (JOCTET *) src->jpeg_buffer;
170
cinfo->src->bytes_in_buffer = (size_t) src->valid_buffer_length;
172
qDebug("valid_buffer_length is afterwards %d", src->valid_buffer_length);
173
qDebug("skip_input_bytes is now %d", src->skip_input_bytes);
180
//-----------------------------------------------------------------------------
184
//-----------------------------------------------------------------------------
185
class GVJPEGFormat : public QImageFormat {
189
virtual ~GVJPEGFormat();
191
virtual int decode(QImage& img, QImageConsumer* consumer,
192
const uchar* buffer, int length);
206
// structs for the jpeglib
207
jpeg_decompress_struct mDecompress;
208
GVJPEGErrorManager mErrorManager;
209
GVJPEGSourceManager mSourceManager;
213
GVJPEGFormat::GVJPEGFormat() {
214
memset(&mDecompress, 0, sizeof(mDecompress));
215
mDecompress.err = jpeg_std_error(&mErrorManager);
216
mErrorManager.error_exit=GVJPEGErrorManager::errorExitCallBack;
217
jpeg_create_decompress(&mDecompress);
218
mDecompress.src = &mSourceManager;
223
GVJPEGFormat::~GVJPEGFormat() {
224
(void) jpeg_destroy_decompress(&mDecompress);
228
* return > 0 means "consumed x bytes, need more"
229
* return == 0 means "end of frame reached"
230
* return < 0 means "fatal error in image decoding, don't call me ever again"
233
int GVJPEGFormat::decode(QImage& image, QImageConsumer* consumer, const uchar* buffer, int length) {
235
qDebug("GVJPEGFormat::decode(%08lx, %08lx, %08lx, %d)",
236
&image, consumer, buffer, length);
239
if(mSourceManager.at_eof) {
241
qDebug("at_eof, eating");
246
if(setjmp(mErrorManager.jmp_buffer)) {
248
qDebug("jump into state INVALID");
250
if(consumer) consumer->end();
256
int consumed = kMin(length, MAX_BUFFER - mSourceManager.valid_buffer_length);
259
qDebug("consuming %d bytes", consumed);
262
// filling buffer with the new data
263
memcpy(mSourceManager.jpeg_buffer + mSourceManager.valid_buffer_length, buffer, consumed);
264
mSourceManager.valid_buffer_length += consumed;
266
if(mSourceManager.skip_input_bytes) {
268
qDebug("doing skipping");
269
qDebug("valid_buffer_length %d", mSourceManager.valid_buffer_length);
270
qDebug("skip_input_bytes %d", mSourceManager.skip_input_bytes);
272
int skipbytes = kMin((size_t) mSourceManager.valid_buffer_length, mSourceManager.skip_input_bytes);
274
if(skipbytes < mSourceManager.valid_buffer_length) {
275
memmove(mSourceManager.jpeg_buffer,
276
mSourceManager.jpeg_buffer+skipbytes,
277
mSourceManager.valid_buffer_length - skipbytes);
280
mSourceManager.valid_buffer_length -= skipbytes;
281
mSourceManager.skip_input_bytes -= skipbytes;
283
// still more bytes to skip
284
if(mSourceManager.skip_input_bytes) {
285
if(consumed <= 0) qDebug("ERROR!!!");
291
mDecompress.src->next_input_byte = (JOCTET *) mSourceManager.jpeg_buffer;
292
mDecompress.src->bytes_in_buffer = (size_t) mSourceManager.valid_buffer_length;
295
qDebug("buffer contains %d bytes", mSourceManager.valid_buffer_length);
299
if(jpeg_read_header(&mDecompress, true) != JPEG_SUSPENDED) {
302
mDecompress.image_width/mDecompress.scale_denom,
303
mDecompress.image_height/mDecompress.scale_denom);
306
mState = START_DECOMPRESS;
310
if(mState == START_DECOMPRESS) {
311
mSourceManager.do_progressive = jpeg_has_multiple_scans( &mDecompress );
314
qDebug( "**** DOPROGRESSIVE: %d", mSourceManager.do_progressive );
316
mDecompress.buffered_image = mSourceManager.do_progressive;
319
jpeg_calc_output_dimensions( &mDecompress );
321
if (mDecompress.jpeg_color_space == JCS_YCbCr) {
322
mDecompress.out_color_space = JCS_RGB;
325
mDecompress.do_fancy_upsampling = true;
326
mDecompress.do_block_smoothing = false;
327
mDecompress.quantize_colors = false;
328
mDecompress.dct_method = JDCT_FASTEST;
330
// false: IO suspension
331
if(jpeg_start_decompress(&mDecompress)) {
332
if ( mDecompress.output_components == 3 || mDecompress.output_components == 4) {
333
image.create( mDecompress.output_width, mDecompress.output_height, 32 );
334
} else if ( mDecompress.output_components == 1 ) {
335
image.create( mDecompress.output_width, mDecompress.output_height, 8, 256 );
336
for (int i=0; i<256; i++) {
337
image.setColor(i, qRgb(i,i,i));
342
qDebug("will create a picture %d/%d in size", mDecompress.output_width, mDecompress.output_height);
346
qDebug("ok, going to DECOMPRESS_STARTED");
349
mState = mSourceManager.do_progressive ? DECOMPRESS_STARTED : DO_OUTPUT_SCAN;
353
if(mState == DECOMPRESS_STARTED) {
354
// mState = (!mSourceManager.final_pass && decoder_time_stamp.elapsed() < MAX_CONSUMING_TIME)
355
// ? CONSUME_INPUT : PREPARE_OUTPUT_SCAN;
356
mState = CONSUME_INPUT;
359
if(mState == CONSUME_INPUT) {
363
retval = jpeg_consume_input(&mDecompress);
364
} while (retval != JPEG_SUSPENDED && retval != JPEG_REACHED_EOI);
366
if( mSourceManager.final_pass
367
|| retval == JPEG_REACHED_EOI
368
|| retval == JPEG_REACHED_SOS) {
369
mState = PREPARE_OUTPUT_SCAN;
373
if(mState == PREPARE_OUTPUT_SCAN) {
374
if ( jpeg_start_output(&mDecompress, mDecompress.input_scan_number) ) {
375
mState = DO_OUTPUT_SCAN;
379
if(mState == DO_OUTPUT_SCAN) {
380
if(image.isNull() || mSourceManager.decoding_done) {
382
qDebug("complete in doOutputscan, eating..");
386
uchar** lines = image.jumpTable();
387
int oldoutput_scanline = mDecompress.output_scanline;
389
while(mDecompress.output_scanline < mDecompress.output_height &&
390
jpeg_read_scanlines(&mDecompress, lines+mDecompress.output_scanline, mDecompress.output_height))
391
; // here happens all the magic of decoding
393
int completed_scanlines = mDecompress.output_scanline - oldoutput_scanline;
395
qDebug("completed now %d scanlines", completed_scanlines);
398
if ( mDecompress.output_components == 3 ) {
399
// Expand 24->32 bpp.
400
for (int j=oldoutput_scanline; j<oldoutput_scanline+completed_scanlines; j++) {
401
uchar *in = image.scanLine(j) + mDecompress.output_width * 3;
402
QRgb *out = (QRgb*)image.scanLine(j);
404
for (uint i=mDecompress.output_width; i--; ) {
406
out[i] = qRgb(in[0], in[1], in[2]);
411
if(consumer && completed_scanlines) {
412
QRect r(0, oldoutput_scanline, mDecompress.output_width, completed_scanlines);
414
qDebug("changing %d/%d %d/%d", r.x(), r.y(), r.width(), r.height());
416
mSourceManager.change_rect |= r;
418
consumer->changed(mSourceManager.change_rect);
419
mSourceManager.change_rect = QRect();
422
if(mDecompress.output_scanline >= mDecompress.output_height) {
423
if ( mSourceManager.do_progressive ) {
424
jpeg_finish_output(&mDecompress);
425
mSourceManager.final_pass = jpeg_input_complete(&mDecompress);
426
mSourceManager.decoding_done = mSourceManager.final_pass && mDecompress.input_scan_number == mDecompress.output_scan_number;
427
if ( !mSourceManager.decoding_done ) {
428
mSourceManager.change_rect = QRect();
431
mSourceManager.decoding_done = true;
434
qDebug("one pass is completed, final_pass = %d, dec_done: %d, complete: %d",
435
mSourceManager.final_pass, mSourceManager.decoding_done, jpeg_input_complete(&mDecompress));
437
if(!mSourceManager.decoding_done) {
439
qDebug("starting another one, input_scan_number is %d/%d", mDecompress.input_scan_number,
440
mDecompress.output_scan_number);
442
// don't return until necessary!
443
mState = DECOMPRESS_STARTED;
447
if(mState == DO_OUTPUT_SCAN && mSourceManager.decoding_done) {
449
qDebug("input is complete, cleaning up, returning..");
451
if ( consumer && !mSourceManager.change_rect.isEmpty() ) {
452
consumer->changed( mSourceManager.change_rect );
455
if(consumer) consumer->end();
457
mSourceManager.at_eof = true;
459
(void) jpeg_finish_decompress(&mDecompress);
460
(void) jpeg_destroy_decompress(&mDecompress);
469
qDebug("valid_buffer_length is now %d", mSourceManager.valid_buffer_length);
470
qDebug("bytes_in_buffer is now %d", mSourceManager.bytes_in_buffer);
471
qDebug("consumed %d bytes", consumed);
473
if(mSourceManager.bytes_in_buffer
474
&& mSourceManager.jpeg_buffer != mSourceManager.next_input_byte) {
475
memmove(mSourceManager.jpeg_buffer,
476
mSourceManager.next_input_byte,
477
mSourceManager.bytes_in_buffer);
479
mSourceManager.valid_buffer_length = mSourceManager.bytes_in_buffer;
484
//-----------------------------------------------------------------------------
488
//-----------------------------------------------------------------------------
489
QImageFormat* GVJPEGFormatType::decoderFor(const uchar* buffer, int length) {
490
if(length < 3) return 0;
492
if(buffer[0] == 0377 &&
495
return new GVJPEGFormat;
501
const char* GVJPEGFormatType::formatName() const {