00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifdef HAVE_CONFIG_H
00026 #include <config.h>
00027 #endif
00028
00029 #ifdef HAVE_LIBJPEG
00030 #include "loader_jpeg.h"
00031
00032 #include <stdio.h>
00033 #include <setjmp.h>
00034 #include <qdatetime.h>
00035
00036 extern "C" {
00037 #define XMD_H
00038 #include <jpeglib.h>
00039 #undef const
00040 }
00041
00042
00043 #undef BUFFER_DEBUG
00044
00045
00046 #undef JPEG_DEBUG
00047
00048
00049
00050
00051 struct khtml_error_mgr : public jpeg_error_mgr {
00052 jmp_buf setjmp_buffer;
00053 };
00054
00055 extern "C" {
00056
00057 static
00058 void khtml_error_exit (j_common_ptr cinfo)
00059 {
00060 khtml_error_mgr* myerr = (khtml_error_mgr*) cinfo->err;
00061 char buffer[JMSG_LENGTH_MAX];
00062 (*cinfo->err->format_message)(cinfo, buffer);
00063 qWarning("%s", buffer);
00064 longjmp(myerr->setjmp_buffer, 1);
00065 }
00066 }
00067
00068 static const int max_buf = 8192;
00069 static const int max_consumingtime = 500;
00070
00071 struct khtml_jpeg_source_mgr : public jpeg_source_mgr {
00072 JOCTET buffer[max_buf];
00073
00074 int valid_buffer_len;
00075 unsigned int skip_input_bytes;
00076 int ateof;
00077 QTime decoder_timestamp;
00078 bool final_pass;
00079 bool decoding_done;
00080
00081 public:
00082 khtml_jpeg_source_mgr();
00083 };
00084
00085
00086 extern "C" {
00087
00088 static
00089 void khtml_j_decompress_dummy(j_decompress_ptr)
00090 {
00091 }
00092
00093 static
00094 boolean khtml_fill_input_buffer(j_decompress_ptr cinfo)
00095 {
00096 #ifdef BUFFER_DEBUG
00097 qDebug("khtml_fill_input_buffer called!");
00098 #endif
00099
00100 khtml_jpeg_source_mgr* src = (khtml_jpeg_source_mgr*)cinfo->src;
00101
00102 if ( src->ateof )
00103 {
00104
00105 src->buffer[0] = (JOCTET) 0xFF;
00106 src->buffer[1] = (JOCTET) JPEG_EOI;
00107 src->bytes_in_buffer = 2;
00108 #ifdef BUFFER_DEBUG
00109 qDebug("...returning TRUE!");
00110 #endif
00111 return TRUE;
00112 }
00113 else
00114 return FALSE;
00115 }
00116
00117 static
00118 void khtml_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
00119 {
00120 if(num_bytes <= 0)
00121 return;
00122
00123 #ifdef BUFFER_DEBUG
00124 qDebug("khtml_skip_input_data (%d) called!", num_bytes);
00125 #endif
00126
00127 khtml_jpeg_source_mgr* src = (khtml_jpeg_source_mgr*)cinfo->src;
00128 src->skip_input_bytes += num_bytes;
00129
00130 unsigned int skipbytes = QMIN(src->bytes_in_buffer, src->skip_input_bytes);
00131
00132 #ifdef BUFFER_DEBUG
00133 qDebug("skip_input_bytes is now %d", src->skip_input_bytes);
00134 qDebug("skipbytes is now %d", skipbytes);
00135 qDebug("valid_buffer_len is before %d", src->valid_buffer_len);
00136 qDebug("bytes_in_buffer is %d", src->bytes_in_buffer);
00137 #endif
00138
00139 if(skipbytes < src->bytes_in_buffer)
00140 memcpy(src->buffer, src->next_input_byte+skipbytes, src->bytes_in_buffer - skipbytes);
00141
00142 src->bytes_in_buffer -= skipbytes;
00143 src->valid_buffer_len = src->bytes_in_buffer;
00144 src->skip_input_bytes -= skipbytes;
00145
00146
00147 cinfo->src->next_input_byte = (JOCTET *) src->buffer;
00148 cinfo->src->bytes_in_buffer = (size_t) src->valid_buffer_len;
00149 #ifdef BUFFER_DEBUG
00150 qDebug("valid_buffer_len is afterwards %d", src->valid_buffer_len);
00151 qDebug("skip_input_bytes is now %d", src->skip_input_bytes);
00152 #endif
00153 }
00154 }
00155
00156
00157 khtml_jpeg_source_mgr::khtml_jpeg_source_mgr()
00158 {
00159 jpeg_source_mgr::init_source = khtml_j_decompress_dummy;
00160 jpeg_source_mgr::fill_input_buffer = khtml_fill_input_buffer;
00161 jpeg_source_mgr::skip_input_data = khtml_skip_input_data;
00162 jpeg_source_mgr::resync_to_restart = jpeg_resync_to_restart;
00163 jpeg_source_mgr::term_source = khtml_j_decompress_dummy;
00164 bytes_in_buffer = 0;
00165 valid_buffer_len = 0;
00166 skip_input_bytes = 0;
00167 ateof = 0;
00168 next_input_byte = buffer;
00169 final_pass = false;
00170 decoding_done = false;
00171 }
00172
00173
00174
00175
00176
00177 class KJPEGFormat : public QImageFormat
00178 {
00179 public:
00180 KJPEGFormat();
00181
00182 virtual ~KJPEGFormat();
00183
00184 virtual int decode(QImage& img, QImageConsumer* consumer,
00185 const uchar* buffer, int length);
00186 private:
00187
00188 enum {
00189 Init,
00190 readHeader,
00191 startDecompress,
00192 decompressStarted,
00193 consumeInput,
00194 prepareOutputScan,
00195 doOutputScan,
00196 readDone,
00197 invalid
00198 } state;
00199
00200
00201 struct jpeg_decompress_struct cinfo;
00202 struct khtml_error_mgr jerr;
00203 struct khtml_jpeg_source_mgr jsrc;
00204 };
00205
00206
00207
00208
00209 KJPEGFormat::KJPEGFormat()
00210 {
00211 memset(&cinfo, 0, sizeof(cinfo));
00212 cinfo.err = jpeg_std_error(&jerr);
00213 jpeg_create_decompress(&cinfo);
00214 cinfo.err = jpeg_std_error(&jerr);
00215 jerr.error_exit = khtml_error_exit;
00216 cinfo.src = &jsrc;
00217 state = Init;
00218 }
00219
00220
00221 KJPEGFormat::~KJPEGFormat()
00222 {
00223 jpeg_destroy_decompress(&cinfo);
00224 }
00225
00226
00227
00228
00229
00230
00231
00232 int KJPEGFormat::decode(QImage& image, QImageConsumer* consumer, const uchar* buffer, int length)
00233 {
00234 #ifdef JPEG_DEBUG
00235 qDebug("KJPEGFormat::decode(%08lx, %08lx, %08lx, %d)",
00236 &image, consumer, buffer, length);
00237 #endif
00238
00239 if(jsrc.ateof) {
00240 #ifdef JPEG_DEBUG
00241 qDebug("ateof, eating");
00242 #endif
00243 return length;
00244 }
00245
00246
00247 if(setjmp(jerr.setjmp_buffer))
00248 {
00249 #ifdef JPEG_DEBUG
00250 qDebug("jump into state invalid");
00251 #endif
00252 if(consumer)
00253 consumer->end();
00254
00255
00256 return -1;
00257 }
00258
00259 int consumed = QMIN(length, max_buf - jsrc.valid_buffer_len);
00260
00261 #ifdef BUFFER_DEBUG
00262 qDebug("consuming %d bytes", consumed);
00263 #endif
00264
00265
00266 memcpy(jsrc.buffer + jsrc.valid_buffer_len, buffer, consumed);
00267 jsrc.valid_buffer_len += consumed;
00268
00269 if(jsrc.skip_input_bytes)
00270 {
00271 #ifdef BUFFER_DEBUG
00272 qDebug("doing skipping");
00273 qDebug("valid_buffer_len %d", jsrc.valid_buffer_len);
00274 qDebug("skip_input_bytes %d", jsrc.skip_input_bytes);
00275 #endif
00276 int skipbytes = QMIN((unsigned) jsrc.valid_buffer_len, jsrc.skip_input_bytes);
00277
00278 if(skipbytes < jsrc.valid_buffer_len)
00279 memcpy(jsrc.buffer, jsrc.buffer+skipbytes, jsrc.valid_buffer_len - skipbytes);
00280
00281 jsrc.valid_buffer_len -= skipbytes;
00282 jsrc.skip_input_bytes -= skipbytes;
00283
00284
00285 if(jsrc.skip_input_bytes) {
00286 if(consumed <= 0) qDebug("ERROR!!!");
00287 return consumed;
00288 }
00289
00290 }
00291
00292 cinfo.src->next_input_byte = (JOCTET *) jsrc.buffer;
00293 cinfo.src->bytes_in_buffer = (size_t) jsrc.valid_buffer_len;
00294
00295 #ifdef BUFFER_DEBUG
00296 qDebug("buffer contains %d bytes", jsrc.valid_buffer_len);
00297 #endif
00298
00299 if(state == Init)
00300 {
00301 if(jpeg_read_header(&cinfo, TRUE) != JPEG_SUSPENDED) {
00302 if ( consumer )
00303 consumer->setSize(cinfo.output_width, cinfo.output_height);
00304
00305 state = startDecompress;
00306 }
00307 }
00308
00309 if(state == startDecompress)
00310 {
00311 cinfo.buffered_image = TRUE;
00312 cinfo.do_fancy_upsampling = FALSE;
00313 cinfo.do_block_smoothing = FALSE;
00314 cinfo.dct_method = JDCT_FASTEST;
00315
00316
00317 if(jpeg_start_decompress(&cinfo)) {
00318 if ( cinfo.output_components == 3 || cinfo.output_components == 4) {
00319 image.create( cinfo.output_width, cinfo.output_height, 32 );
00320 } else if ( cinfo.output_components == 1 ) {
00321 image.create( cinfo.output_width, cinfo.output_height, 8, 256 );
00322 for (int i=0; i<256; i++)
00323 image.setColor(i, qRgb(i,i,i));
00324 }
00325
00326 #ifdef JPEG_DEBUG
00327 qDebug("will create a picture %d/%d in size", cinfo.output_width, cinfo.output_height);
00328 #endif
00329
00330 #ifdef JPEG_DEBUG
00331 qDebug("ok, going to decompressStarted");
00332 #endif
00333
00334 jsrc.decoder_timestamp.start();
00335 state = decompressStarted;
00336 }
00337 }
00338
00339 if(state == decompressStarted) {
00340 state = (!jsrc.final_pass && jsrc.decoder_timestamp.elapsed() < max_consumingtime)
00341 ? consumeInput : prepareOutputScan;
00342 }
00343
00344 if(state == consumeInput)
00345 {
00346 int retval;
00347
00348 do {
00349 retval = jpeg_consume_input(&cinfo);
00350 } while (retval != JPEG_SUSPENDED && retval != JPEG_REACHED_EOI);
00351
00352 if(jsrc.decoder_timestamp.elapsed() > max_consumingtime || jsrc.final_pass ||
00353 retval == JPEG_REACHED_EOI || retval == JPEG_REACHED_SOS)
00354 state = prepareOutputScan;
00355 else
00356 state = consumeInput;
00357 }
00358
00359 if(state == prepareOutputScan)
00360 {
00361 jsrc.decoder_timestamp.restart();
00362 cinfo.buffered_image = TRUE;
00363 jpeg_start_output(&cinfo, cinfo.input_scan_number);
00364 state = doOutputScan;
00365 }
00366
00367 if(state == doOutputScan)
00368 {
00369 if(image.isNull() || jsrc.decoding_done)
00370 {
00371 #ifdef JPEG_DEBUG
00372 qDebug("complete in doOutputscan, eating..");
00373 #endif
00374 return consumed;
00375 }
00376 uchar** lines = image.jumpTable();
00377 int oldoutput_scanline = cinfo.output_scanline;
00378
00379 while(cinfo.output_scanline < cinfo.output_height &&
00380 jpeg_read_scanlines(&cinfo, lines+cinfo.output_scanline, cinfo.output_height))
00381 ;
00382
00383 int completed_scanlines = cinfo.output_scanline - oldoutput_scanline;
00384 #ifdef JPEG_DEBUG
00385 qDebug("completed now %d scanlines", completed_scanlines);
00386 #endif
00387
00388 if ( cinfo.output_components == 3 ) {
00389
00390 for (int j=oldoutput_scanline; j<oldoutput_scanline+completed_scanlines; j++) {
00391 uchar *in = image.scanLine(j) + cinfo.output_width * 3;
00392 QRgb *out = (QRgb*)image.scanLine(j);
00393
00394 for (uint i=cinfo.output_width; i--; ) {
00395 in-=3;
00396 out[i] = qRgb(in[0], in[1], in[2]);
00397 }
00398 }
00399 }
00400
00401 if(consumer && completed_scanlines)
00402 {
00403 QRect r(0, oldoutput_scanline, cinfo.output_width, completed_scanlines);
00404 #ifdef JPEG_DEBUG
00405 qDebug("changing %d/%d %d/%d", r.x(), r.y(), r.width(), r.height());
00406 #endif
00407 consumer->changed(r);
00408 }
00409
00410 if(cinfo.output_scanline >= cinfo.output_height)
00411 {
00412 jpeg_finish_output(&cinfo);
00413 jsrc.final_pass = jpeg_input_complete(&cinfo);
00414 jsrc.decoding_done = jsrc.final_pass && cinfo.input_scan_number == cinfo.output_scan_number;
00415
00416 #ifdef JPEG_DEBUG
00417 qDebug("one pass is completed, final_pass = %d, dec_done: %d, complete: %d",
00418 jsrc.final_pass, jsrc.decoding_done, jpeg_input_complete(&cinfo));
00419 #endif
00420 if(!jsrc.decoding_done)
00421 {
00422 #ifdef JPEG_DEBUG
00423 qDebug("starting another one, input_scan_number is %d/%d", cinfo.input_scan_number,
00424 cinfo.output_scan_number);
00425 #endif
00426
00427 jsrc.decoder_timestamp.restart();
00428 state = decompressStarted;
00429 }
00430 }
00431
00432 if(state == doOutputScan && jsrc.decoding_done) {
00433 #ifdef JPEG_DEBUG
00434 qDebug("input is complete, cleaning up, returning..");
00435 #endif
00436 (void) jpeg_finish_decompress(&cinfo);
00437 (void) jpeg_destroy_decompress(&cinfo);
00438
00439 if(consumer)
00440 consumer->end();
00441
00442 jsrc.ateof = true;
00443
00444 return 0;
00445 }
00446 }
00447
00448 #ifdef BUFFER_DEBUG
00449 qDebug("valid_buffer_len is now %d", jsrc.valid_buffer_len);
00450 qDebug("bytes_in_buffer is now %d", jsrc.bytes_in_buffer);
00451 qDebug("consumed %d bytes", consumed);
00452 #endif
00453 if(jsrc.bytes_in_buffer)
00454 memcpy(jsrc.buffer, jsrc.next_input_byte, jsrc.bytes_in_buffer);
00455 jsrc.valid_buffer_len = jsrc.bytes_in_buffer;
00456 return consumed;
00457 }
00458
00459
00460
00461
00462 QImageFormat* khtml::KJPEGFormatType::decoderFor(const unsigned char* buffer, int length)
00463 {
00464 if(length < 3) return 0;
00465
00466 if(buffer[0] == 0377 &&
00467 buffer[1] == 0330 &&
00468 buffer[2] == 0377)
00469 return new KJPEGFormat;
00470
00471 return 0;
00472 }
00473
00474 const char* khtml::KJPEGFormatType::formatName() const
00475 {
00476 return "JPEG";
00477 }
00478
00479 #else
00480 #ifdef __GNUC__
00481 #warning You don't seem to have libJPEG. jpeg support in khtml won't work
00482 #endif
00483 #endif // HAVE_LIBJPEG
00484
00485
00486