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