~ubuntu-branches/ubuntu/warty/gwenview/warty

« back to all changes in this revision

Viewing changes to src/gvjpegformattype.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Christopher Martin
  • Date: 2004-06-13 18:55:04 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040613185504-net8ekxoswwvyxs9
Tags: 1.1.3-1
New upstream release. Translations now included.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* This file is based on kdelibs-3.2.0/khtml/misc/loader_jpeg.cpp. Original
 
2
 * copyright follows.
 
3
 */
 
4
/*
 
5
    This file is part of the KDE libraries
 
6
 
 
7
    Copyright (C) 2000 Dirk Mueller (mueller@kde.org)
 
8
 
 
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:
 
15
 
 
16
    The above copyright notice and this permission notice shall be included in
 
17
    all copies or substantial portions of the Software.
 
18
 
 
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.
 
25
 
 
26
*/
 
27
 
 
28
 
 
29
// System
 
30
#include <stdio.h>
 
31
#include <setjmp.h>
 
32
extern "C" {
 
33
#define XMD_H
 
34
#include <jpeglib.h>
 
35
#undef const
 
36
}
 
37
 
 
38
// Qt
 
39
#include <qdatetime.h>
 
40
 
 
41
// KDE
 
42
#include <kdebug.h>
 
43
#include <kglobal.h>
 
44
 
 
45
// Local
 
46
#include "gvjpegformattype.h"
 
47
 
 
48
#undef BUFFER_DEBUG
 
49
//#define BUFFER_DEBUG
 
50
 
 
51
#undef JPEG_DEBUG
 
52
//#define JPEG_DEBUG
 
53
 
 
54
 
 
55
static const int MAX_BUFFER = 32768;
 
56
 
 
57
//-----------------------------------------------------------------------------
 
58
//
 
59
// GVJPEGErrorManager
 
60
// (Does not follow HACKING naming recommandation to be consistent with
 
61
// jpeg_error_mgr naming)
 
62
//
 
63
//-----------------------------------------------------------------------------
 
64
struct GVJPEGErrorManager : public jpeg_error_mgr {
 
65
        jmp_buf jmp_buffer;
 
66
 
 
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);
 
73
        }
 
74
};
 
75
 
 
76
 
 
77
//-----------------------------------------------------------------------------
 
78
//
 
79
// GVJPEGSourceManager
 
80
// (Does not follow HACKING file recommandation to be consistent with
 
81
// jpeg_source_mgr naming)
 
82
//
 
83
//-----------------------------------------------------------------------------
 
84
struct GVJPEGSourceManager : public jpeg_source_mgr {
 
85
        JOCTET jpeg_buffer[MAX_BUFFER];
 
86
 
 
87
        int valid_buffer_length;
 
88
        size_t skip_input_bytes;
 
89
        bool at_eof;
 
90
        QRect change_rect;
 
91
        bool final_pass;
 
92
        bool decoding_done;
 
93
        bool do_progressive;
 
94
 
 
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;
 
102
                
 
103
                bytes_in_buffer = 0;
 
104
                next_input_byte = jpeg_buffer;
 
105
                
 
106
                // GVJPEGSourceManager fields
 
107
                valid_buffer_length = 0;
 
108
                skip_input_bytes = 0;
 
109
                at_eof = 0;
 
110
                final_pass = false;
 
111
                decoding_done = false;
 
112
        }
 
113
        
 
114
        static void gvJPEGDummyDecompress(j_decompress_ptr) {}
 
115
 
 
116
        /* Do not replace boolean with bool, it's the libjpeg boolean type */
 
117
        static boolean gvFillInputBuffer(j_decompress_ptr cinfo) {
 
118
#ifdef BUFFER_DEBUG
 
119
                qDebug("gvFillInputBuffer called!");
 
120
#endif
 
121
 
 
122
                GVJPEGSourceManager* src = (GVJPEGSourceManager*)cinfo->src;
 
123
 
 
124
                if ( src->at_eof ) {
 
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;
 
130
#ifdef BUFFER_DEBUG
 
131
                        qDebug("...returning true!");
 
132
#endif
 
133
                        return true;
 
134
                } else {
 
135
                        return false;  /* I/O suspension mode */
 
136
                }
 
137
        }
 
138
 
 
139
        static void gvSkipInputData(j_decompress_ptr cinfo, long num_bytes) {
 
140
                if(num_bytes <= 0) return; /* required noop */
 
141
 
 
142
#ifdef BUFFER_DEBUG
 
143
                qDebug("gvSkipInputData (%d) called!", num_bytes);
 
144
#endif
 
145
 
 
146
                GVJPEGSourceManager* src = (GVJPEGSourceManager*)cinfo->src;
 
147
                src->skip_input_bytes += num_bytes;
 
148
 
 
149
                unsigned int skipbytes = kMin(src->bytes_in_buffer, src->skip_input_bytes);
 
150
 
 
151
#ifdef BUFFER_DEBUG
 
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);
 
156
#endif
 
157
 
 
158
                if(skipbytes < src->bytes_in_buffer) {
 
159
                        memmove(src->jpeg_buffer,
 
160
                                src->next_input_byte+skipbytes,
 
161
                                src->bytes_in_buffer - skipbytes);
 
162
                }
 
163
 
 
164
                src->bytes_in_buffer -= skipbytes;
 
165
                src->valid_buffer_length = src->bytes_in_buffer;
 
166
                src->skip_input_bytes -= skipbytes;
 
167
 
 
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;
 
171
#ifdef BUFFER_DEBUG
 
172
                qDebug("valid_buffer_length is afterwards %d", src->valid_buffer_length);
 
173
                qDebug("skip_input_bytes is now %d", src->skip_input_bytes);
 
174
#endif
 
175
 
 
176
        }
 
177
};
 
178
 
 
179
 
 
180
//-----------------------------------------------------------------------------
 
181
//
 
182
// GVJPEGFormat
 
183
//
 
184
//-----------------------------------------------------------------------------
 
185
class GVJPEGFormat : public QImageFormat {
 
186
public:
 
187
        GVJPEGFormat();
 
188
 
 
189
        virtual ~GVJPEGFormat();
 
190
 
 
191
        virtual int decode(QImage& img, QImageConsumer* consumer,
 
192
                const uchar* buffer, int length);
 
193
private:
 
194
 
 
195
        enum {
 
196
                INIT,
 
197
                START_DECOMPRESS,
 
198
                DECOMPRESS_STARTED,
 
199
                CONSUME_INPUT,
 
200
                PREPARE_OUTPUT_SCAN,
 
201
                DO_OUTPUT_SCAN,
 
202
                READ_DONE,
 
203
                INVALID
 
204
        } mState;
 
205
 
 
206
        // structs for the jpeglib
 
207
        jpeg_decompress_struct mDecompress;
 
208
        GVJPEGErrorManager mErrorManager;
 
209
        GVJPEGSourceManager mSourceManager;
 
210
};
 
211
 
 
212
 
 
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;
 
219
        mState = INIT;
 
220
}
 
221
 
 
222
 
 
223
GVJPEGFormat::~GVJPEGFormat() {
 
224
        (void) jpeg_destroy_decompress(&mDecompress);
 
225
}
 
226
 
 
227
/*
 
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"
 
231
 */
 
232
 
 
233
int GVJPEGFormat::decode(QImage& image, QImageConsumer* consumer, const uchar* buffer, int length) {
 
234
#ifdef JPEG_DEBUG
 
235
        qDebug("GVJPEGFormat::decode(%08lx, %08lx, %08lx, %d)",
 
236
               &image, consumer, buffer, length);
 
237
#endif
 
238
 
 
239
        if(mSourceManager.at_eof) {
 
240
#ifdef JPEG_DEBUG
 
241
                qDebug("at_eof, eating");
 
242
#endif
 
243
                return length;
 
244
        }
 
245
 
 
246
        if(setjmp(mErrorManager.jmp_buffer)) {
 
247
#ifdef JPEG_DEBUG
 
248
                qDebug("jump into state INVALID");
 
249
#endif
 
250
                if(consumer) consumer->end();
 
251
 
 
252
                // this is fatal
 
253
                return -1;
 
254
        }
 
255
 
 
256
        int consumed = kMin(length, MAX_BUFFER - mSourceManager.valid_buffer_length);
 
257
 
 
258
#ifdef BUFFER_DEBUG
 
259
        qDebug("consuming %d bytes", consumed);
 
260
#endif
 
261
 
 
262
        // filling buffer with the new data
 
263
        memcpy(mSourceManager.jpeg_buffer + mSourceManager.valid_buffer_length, buffer, consumed);
 
264
        mSourceManager.valid_buffer_length += consumed;
 
265
 
 
266
        if(mSourceManager.skip_input_bytes) {
 
267
#ifdef BUFFER_DEBUG
 
268
                qDebug("doing skipping");
 
269
                qDebug("valid_buffer_length %d", mSourceManager.valid_buffer_length);
 
270
                qDebug("skip_input_bytes %d", mSourceManager.skip_input_bytes);
 
271
#endif
 
272
                int skipbytes = kMin((size_t) mSourceManager.valid_buffer_length, mSourceManager.skip_input_bytes);
 
273
 
 
274
                if(skipbytes < mSourceManager.valid_buffer_length) {
 
275
                        memmove(mSourceManager.jpeg_buffer,
 
276
                                mSourceManager.jpeg_buffer+skipbytes,
 
277
                                mSourceManager.valid_buffer_length - skipbytes);
 
278
                }
 
279
 
 
280
                mSourceManager.valid_buffer_length -= skipbytes;
 
281
                mSourceManager.skip_input_bytes -= skipbytes;
 
282
 
 
283
                // still more bytes to skip
 
284
                if(mSourceManager.skip_input_bytes) {
 
285
                        if(consumed <= 0) qDebug("ERROR!!!");
 
286
                        return consumed;
 
287
                }
 
288
 
 
289
        }
 
290
 
 
291
        mDecompress.src->next_input_byte = (JOCTET *) mSourceManager.jpeg_buffer;
 
292
        mDecompress.src->bytes_in_buffer = (size_t) mSourceManager.valid_buffer_length;
 
293
 
 
294
#ifdef BUFFER_DEBUG
 
295
        qDebug("buffer contains %d bytes", mSourceManager.valid_buffer_length);
 
296
#endif
 
297
 
 
298
        if(mState == INIT) {
 
299
                if(jpeg_read_header(&mDecompress, true) != JPEG_SUSPENDED) {
 
300
                        if (consumer) {
 
301
                                consumer->setSize(
 
302
                                        mDecompress.image_width/mDecompress.scale_denom,
 
303
                                        mDecompress.image_height/mDecompress.scale_denom);
 
304
                        }
 
305
 
 
306
                        mState = START_DECOMPRESS;
 
307
                }
 
308
        }
 
309
 
 
310
        if(mState == START_DECOMPRESS) {
 
311
                mSourceManager.do_progressive = jpeg_has_multiple_scans( &mDecompress );
 
312
 
 
313
#ifdef JPEG_DEBUG
 
314
                qDebug( "**** DOPROGRESSIVE: %d",  mSourceManager.do_progressive );
 
315
#endif
 
316
                mDecompress.buffered_image = mSourceManager.do_progressive;
 
317
 
 
318
                // setup image sizes
 
319
                jpeg_calc_output_dimensions( &mDecompress );
 
320
 
 
321
                if (mDecompress.jpeg_color_space == JCS_YCbCr) {
 
322
                        mDecompress.out_color_space = JCS_RGB;
 
323
                }
 
324
 
 
325
                mDecompress.do_fancy_upsampling = true;
 
326
                mDecompress.do_block_smoothing = false;
 
327
                mDecompress.quantize_colors = false;
 
328
                mDecompress.dct_method = JDCT_FASTEST;
 
329
 
 
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));
 
338
                                }
 
339
                        }
 
340
 
 
341
#ifdef JPEG_DEBUG
 
342
                        qDebug("will create a picture %d/%d in size", mDecompress.output_width, mDecompress.output_height);
 
343
#endif
 
344
 
 
345
#ifdef JPEG_DEBUG
 
346
                        qDebug("ok, going to DECOMPRESS_STARTED");
 
347
#endif
 
348
 
 
349
                        mState = mSourceManager.do_progressive ? DECOMPRESS_STARTED : DO_OUTPUT_SCAN;
 
350
                }
 
351
        }
 
352
 
 
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;
 
357
        }
 
358
 
 
359
        if(mState == CONSUME_INPUT) {
 
360
                int retval;
 
361
 
 
362
                do {
 
363
                        retval = jpeg_consume_input(&mDecompress);
 
364
                } while (retval != JPEG_SUSPENDED && retval != JPEG_REACHED_EOI);
 
365
 
 
366
                if( mSourceManager.final_pass
 
367
                        || retval == JPEG_REACHED_EOI
 
368
                        || retval == JPEG_REACHED_SOS) {
 
369
                        mState = PREPARE_OUTPUT_SCAN;
 
370
                }
 
371
        }
 
372
 
 
373
        if(mState == PREPARE_OUTPUT_SCAN) {
 
374
                if ( jpeg_start_output(&mDecompress, mDecompress.input_scan_number) ) {
 
375
                        mState = DO_OUTPUT_SCAN;
 
376
                }
 
377
        }
 
378
 
 
379
        if(mState == DO_OUTPUT_SCAN) {
 
380
                if(image.isNull() || mSourceManager.decoding_done) {
 
381
#ifdef JPEG_DEBUG
 
382
                        qDebug("complete in doOutputscan, eating..");
 
383
#endif
 
384
                        return consumed;
 
385
                }
 
386
                uchar** lines = image.jumpTable();
 
387
                int oldoutput_scanline = mDecompress.output_scanline;
 
388
 
 
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
 
392
 
 
393
                int completed_scanlines = mDecompress.output_scanline - oldoutput_scanline;
 
394
#ifdef JPEG_DEBUG
 
395
                qDebug("completed now %d scanlines", completed_scanlines);
 
396
#endif
 
397
 
 
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);
 
403
 
 
404
                                for (uint i=mDecompress.output_width; i--; ) {
 
405
                                        in-=3;
 
406
                                        out[i] = qRgb(in[0], in[1], in[2]);
 
407
                                }
 
408
                        }
 
409
                }
 
410
 
 
411
                if(consumer && completed_scanlines) {
 
412
                        QRect r(0, oldoutput_scanline, mDecompress.output_width, completed_scanlines);
 
413
#ifdef JPEG_DEBUG
 
414
                        qDebug("changing %d/%d %d/%d", r.x(), r.y(), r.width(), r.height());
 
415
#endif
 
416
                        mSourceManager.change_rect |= r;
 
417
 
 
418
                        consumer->changed(mSourceManager.change_rect);
 
419
                        mSourceManager.change_rect = QRect();
 
420
                }
 
421
 
 
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();
 
429
                                }
 
430
                        } else {
 
431
                                mSourceManager.decoding_done = true;
 
432
                        }
 
433
#ifdef JPEG_DEBUG
 
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));
 
436
#endif
 
437
                        if(!mSourceManager.decoding_done) {
 
438
#ifdef JPEG_DEBUG
 
439
                                qDebug("starting another one, input_scan_number is %d/%d", mDecompress.input_scan_number,
 
440
                                        mDecompress.output_scan_number);
 
441
#endif
 
442
                                // don't return until necessary!
 
443
                                mState = DECOMPRESS_STARTED;
 
444
                        }
 
445
                }
 
446
 
 
447
                if(mState == DO_OUTPUT_SCAN && mSourceManager.decoding_done) {
 
448
#ifdef JPEG_DEBUG
 
449
                        qDebug("input is complete, cleaning up, returning..");
 
450
#endif
 
451
                        if ( consumer && !mSourceManager.change_rect.isEmpty() ) {
 
452
                                consumer->changed( mSourceManager.change_rect );
 
453
                        }
 
454
 
 
455
                        if(consumer) consumer->end();
 
456
 
 
457
                        mSourceManager.at_eof = true;
 
458
 
 
459
                        (void) jpeg_finish_decompress(&mDecompress);
 
460
                        (void) jpeg_destroy_decompress(&mDecompress);
 
461
 
 
462
                        mState = READ_DONE;
 
463
 
 
464
                        return 0;
 
465
                }
 
466
        }
 
467
 
 
468
#ifdef BUFFER_DEBUG
 
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);
 
472
#endif
 
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);
 
478
        }
 
479
        mSourceManager.valid_buffer_length = mSourceManager.bytes_in_buffer;
 
480
        return consumed;
 
481
}
 
482
 
 
483
 
 
484
//-----------------------------------------------------------------------------
 
485
//
 
486
// GVJPEGFormatType
 
487
//
 
488
//-----------------------------------------------------------------------------
 
489
QImageFormat* GVJPEGFormatType::decoderFor(const uchar* buffer, int length) {
 
490
        if(length < 3) return 0;
 
491
 
 
492
        if(buffer[0] == 0377 &&
 
493
           buffer[1] == 0330 &&
 
494
           buffer[2] == 0377) {
 
495
                return new GVJPEGFormat;
 
496
        }
 
497
 
 
498
        return 0;
 
499
}
 
500
 
 
501
const char* GVJPEGFormatType::formatName() const {
 
502
        return "JPEG";
 
503
}
 
504