File indexing completed on 2024-05-12 15:38:28
0001 /* 0002 This file is part of the KDE libraries 0003 0004 Copyright (C) 2004 Maks Orlovich (maksim@kde.org) 0005 Copyright (C) 2000 Dirk Mueller (mueller@kde.org) 0006 0007 Permission is hereby granted, free of charge, to any person obtaining a copy 0008 of this software and associated documentation files (the "Software"), to deal 0009 in the Software without restriction, including without limitation the rights 0010 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 0011 copies of the Software, and to permit persons to whom the Software is 0012 furnished to do so, subject to the following conditions: 0013 0014 The above copyright notice and this permission notice shall be included in 0015 all copies or substantial portions of the Software. 0016 0017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 0018 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 0019 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 0020 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 0021 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 0022 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 0023 0024 */ 0025 #include "jpegloader.h" 0026 0027 //### FIXME: I removed all the fancy configury stuff. it needs to be put back 0028 0029 #include <stdio.h> 0030 #include <setjmp.h> 0031 #include <QDate> 0032 #include <QImage> 0033 #include <QElapsedTimer> 0034 0035 #include "imageloader.h" 0036 #include "imagemanager.h" 0037 0038 extern "C" { 0039 #define XMD_H 0040 #include <jpeglib.h> 0041 #undef const 0042 } 0043 0044 #undef BUFFER_DEBUG 0045 //#define BUFFER_DEBUG 0046 0047 #undef JPEG_DEBUG 0048 //#define JPEG_DEBUG 0049 0050 namespace khtmlImLoad 0051 { 0052 0053 class JPEGLoader: public ImageLoader 0054 { 0055 struct Private; 0056 friend struct Private; 0057 Private *d; 0058 public: 0059 JPEGLoader(); 0060 ~JPEGLoader(); 0061 int processData(uchar *data, int length) override; 0062 }; 0063 0064 ImageLoaderProvider::Type JPEGLoaderProvider::type() 0065 { 0066 return Efficient; 0067 } 0068 0069 ImageLoader *JPEGLoaderProvider::loaderFor(const QByteArray &prefix) 0070 { 0071 uchar *data = (uchar *)prefix.data(); 0072 if (prefix.size() < 3) { 0073 return nullptr; 0074 } 0075 0076 if (data[0] == 0377 && 0077 data[1] == 0330 && 0078 data[2] == 0377) { 0079 return new JPEGLoader; 0080 } 0081 0082 return nullptr; 0083 } 0084 0085 // ----------------------------------------------------------------------------- 0086 0087 struct khtml_error_mgr : public jpeg_error_mgr { 0088 jmp_buf setjmp_buffer; 0089 }; 0090 0091 extern "C" { 0092 0093 static 0094 void khtml_error_exit(j_common_ptr cinfo) 0095 { 0096 khtml_error_mgr *myerr = (khtml_error_mgr *) cinfo->err; 0097 char buffer[JMSG_LENGTH_MAX]; 0098 (*cinfo->err->format_message)(cinfo, buffer); 0099 qWarning("%s", buffer); 0100 longjmp(myerr->setjmp_buffer, 1); 0101 } 0102 } 0103 0104 static const int max_buf = 8192; 0105 static const int max_consumingtime = 500; 0106 0107 struct khtml_jpeg_source_mgr : public jpeg_source_mgr { 0108 JOCTET buffer[max_buf]; 0109 0110 int valid_buffer_len; 0111 size_t skip_input_bytes; 0112 int ateof; 0113 QElapsedTimer decoder_timestamp; 0114 bool final_pass; 0115 bool decoding_done; 0116 bool do_progressive; 0117 public: 0118 khtml_jpeg_source_mgr(); 0119 }; 0120 0121 extern "C" { 0122 0123 static 0124 void khtml_j_decompress_dummy(j_decompress_ptr) 0125 { 0126 } 0127 0128 static 0129 boolean khtml_fill_input_buffer(j_decompress_ptr cinfo) 0130 { 0131 #ifdef BUFFER_DEBUG 0132 qDebug("khtml_fill_input_buffer called!"); 0133 #endif 0134 0135 khtml_jpeg_source_mgr *src = (khtml_jpeg_source_mgr *)cinfo->src; 0136 0137 if (src->ateof) { 0138 /* Insert a fake EOI marker - as per jpeglib recommendation */ 0139 src->buffer[0] = (JOCTET) 0xFF; 0140 src->buffer[1] = (JOCTET) JPEG_EOI; 0141 src->bytes_in_buffer = 2; 0142 src->next_input_byte = (JOCTET *) src->buffer; 0143 #ifdef BUFFER_DEBUG 0144 qDebug("...returning true!"); 0145 #endif 0146 return TRUE; 0147 } else { 0148 return FALSE; /* I/O suspension mode */ 0149 } 0150 } 0151 0152 static 0153 void khtml_skip_input_data(j_decompress_ptr cinfo, long num_bytes) 0154 { 0155 if (num_bytes <= 0) { 0156 return; /* required noop */ 0157 } 0158 0159 #ifdef BUFFER_DEBUG 0160 qDebug("khtml_skip_input_data (%d) called!", num_bytes); 0161 #endif 0162 0163 khtml_jpeg_source_mgr *src = (khtml_jpeg_source_mgr *)cinfo->src; 0164 src->skip_input_bytes += num_bytes; 0165 0166 unsigned int skipbytes = qMin(src->bytes_in_buffer, src->skip_input_bytes); 0167 0168 #ifdef BUFFER_DEBUG 0169 qDebug("skip_input_bytes is now %d", src->skip_input_bytes); 0170 qDebug("skipbytes is now %d", skipbytes); 0171 qDebug("valid_buffer_len is before %d", src->valid_buffer_len); 0172 qDebug("bytes_in_buffer is %d", src->bytes_in_buffer); 0173 #endif 0174 0175 if (skipbytes < src->bytes_in_buffer) { 0176 memmove(src->buffer, src->next_input_byte + skipbytes, src->bytes_in_buffer - skipbytes); 0177 } 0178 0179 src->bytes_in_buffer -= skipbytes; 0180 src->valid_buffer_len = src->bytes_in_buffer; 0181 src->skip_input_bytes -= skipbytes; 0182 0183 /* adjust data for jpeglib */ 0184 cinfo->src->next_input_byte = (JOCTET *) src->buffer; 0185 cinfo->src->bytes_in_buffer = (size_t) src->valid_buffer_len; 0186 #ifdef BUFFER_DEBUG 0187 qDebug("valid_buffer_len is afterwards %d", src->valid_buffer_len); 0188 qDebug("skip_input_bytes is now %d", src->skip_input_bytes); 0189 #endif 0190 } 0191 } 0192 0193 khtml_jpeg_source_mgr::khtml_jpeg_source_mgr() 0194 { 0195 jpeg_source_mgr::init_source = khtml_j_decompress_dummy; 0196 jpeg_source_mgr::fill_input_buffer = khtml_fill_input_buffer; 0197 jpeg_source_mgr::skip_input_data = khtml_skip_input_data; 0198 jpeg_source_mgr::resync_to_restart = jpeg_resync_to_restart; 0199 jpeg_source_mgr::term_source = khtml_j_decompress_dummy; 0200 bytes_in_buffer = 0; 0201 valid_buffer_len = 0; 0202 skip_input_bytes = 0; 0203 ateof = 0; 0204 next_input_byte = buffer; 0205 final_pass = false; 0206 decoding_done = false; 0207 } 0208 0209 struct JPEGLoader::Private { 0210 int processData(uchar *data, int length); 0211 Private(); 0212 ~Private(); 0213 0214 JPEGLoader *owner; 0215 private: 0216 int passNum; 0217 uchar *scanline; 0218 0219 enum { 0220 Init, 0221 readHeader, 0222 startDecompress, 0223 decompressStarted, 0224 consumeInput, 0225 prepareOutputScan, 0226 doOutputScan, 0227 readDone, 0228 invalid 0229 } state; 0230 0231 // structs for the jpeglib 0232 struct jpeg_decompress_struct cinfo; 0233 struct khtml_error_mgr jerr; 0234 struct khtml_jpeg_source_mgr jsrc; 0235 }; 0236 0237 JPEGLoader::Private::Private() 0238 { 0239 scanline = nullptr; 0240 passNum = 0; 0241 0242 memset(&cinfo, 0, sizeof(cinfo)); 0243 cinfo.err = jpeg_std_error(&jerr); 0244 jpeg_create_decompress(&cinfo); 0245 cinfo.err = jpeg_std_error(&jerr); 0246 jerr.error_exit = khtml_error_exit; 0247 cinfo.src = &jsrc; 0248 state = Init; 0249 } 0250 0251 JPEGLoader::Private::~Private() 0252 { 0253 delete[] scanline; 0254 (void) jpeg_destroy_decompress(&cinfo); 0255 } 0256 0257 int JPEGLoader::Private::processData(uchar *buffer, int length) 0258 { 0259 if (jsrc.ateof) { 0260 #ifdef JPEG_DEBUG 0261 qDebug("ateof, eating"); 0262 #endif 0263 return ImageLoader::Done; 0264 } 0265 0266 if (setjmp(jerr.setjmp_buffer)) { 0267 #ifdef JPEG_DEBUG 0268 qDebug("jump into state invalid"); 0269 #endif 0270 0271 // this is fatal 0272 return ImageLoader::Error; 0273 } 0274 0275 int consumed = qMin(length, max_buf - jsrc.valid_buffer_len); 0276 0277 #ifdef BUFFER_DEBUG 0278 qDebug("consuming %d bytes", consumed); 0279 #endif 0280 0281 // filling buffer with the new data 0282 memcpy(jsrc.buffer + jsrc.valid_buffer_len, buffer, consumed); 0283 jsrc.valid_buffer_len += consumed; 0284 0285 if (jsrc.skip_input_bytes) { 0286 #ifdef BUFFER_DEBUG 0287 qDebug("doing skipping"); 0288 qDebug("valid_buffer_len %d", jsrc.valid_buffer_len); 0289 qDebug("skip_input_bytes %d", jsrc.skip_input_bytes); 0290 #endif 0291 int skipbytes = qMin((size_t) jsrc.valid_buffer_len, jsrc.skip_input_bytes); 0292 0293 if (skipbytes < jsrc.valid_buffer_len) { 0294 memmove(jsrc.buffer, jsrc.buffer + skipbytes, jsrc.valid_buffer_len - skipbytes); 0295 } 0296 0297 jsrc.valid_buffer_len -= skipbytes; 0298 jsrc.skip_input_bytes -= skipbytes; 0299 0300 // still more bytes to skip 0301 if (jsrc.skip_input_bytes) { 0302 if (consumed <= 0) { 0303 qDebug("ERROR!!!"); 0304 } 0305 return consumed; 0306 } 0307 } 0308 0309 cinfo.src->next_input_byte = (JOCTET *) jsrc.buffer; 0310 cinfo.src->bytes_in_buffer = (size_t) jsrc.valid_buffer_len; 0311 0312 #ifdef BUFFER_DEBUG 0313 qDebug("buffer contains %d bytes", jsrc.valid_buffer_len); 0314 #endif 0315 0316 if (state == Init) { 0317 if (jpeg_read_header(&cinfo, TRUE) != JPEG_SUSPENDED) { 0318 state = startDecompress; 0319 0320 // libJPEG can scale down 2x, 4x, and 8x, 0321 // so do this for oversize images. 0322 int scaleDown = 1; 0323 while (scaleDown <= 8 && !ImageManager::isAcceptableSize( 0324 cinfo.image_width / scaleDown, cinfo.image_height / scaleDown)) { 0325 scaleDown *= 2; 0326 } 0327 0328 cinfo.scale_denom *= scaleDown; 0329 0330 if (scaleDown > 8) { 0331 // Still didn't fit... Abort. 0332 return ImageLoader::Error; 0333 } 0334 } 0335 } 0336 0337 if (state == startDecompress) { 0338 jsrc.do_progressive = jpeg_has_multiple_scans(&cinfo); 0339 if (jsrc.do_progressive) { 0340 cinfo.buffered_image = TRUE; 0341 } else { 0342 cinfo.buffered_image = FALSE; 0343 } 0344 // setup image sizes 0345 jpeg_calc_output_dimensions(&cinfo); 0346 0347 if (cinfo.jpeg_color_space == JCS_YCbCr) { 0348 cinfo.out_color_space = JCS_RGB; 0349 } 0350 0351 if (cinfo.jpeg_color_space == JCS_YCCK) { 0352 cinfo.out_color_space = JCS_CMYK; 0353 } 0354 0355 cinfo.do_fancy_upsampling = TRUE; 0356 cinfo.do_block_smoothing = FALSE; 0357 cinfo.quantize_colors = FALSE; 0358 0359 // false: IO suspension 0360 if (jpeg_start_decompress(&cinfo)) { 0361 ImageFormat f; 0362 if (cinfo.output_components == 3 || cinfo.output_components == 4) { 0363 f.type = ImageFormat::Image_RGB_32; 0364 scanline = new uchar[cinfo.output_width * 4]; 0365 0366 } else if (cinfo.output_components == 1) { 0367 f.greyscaleSetup(); 0368 scanline = new uchar[cinfo.output_width]; 0369 } 0370 // ### else return Error? 0371 0372 owner->notifySingleFrameImage(cinfo.output_width, cinfo.output_height, f); 0373 0374 #ifdef JPEG_DEBUG 0375 qDebug("will create a picture %d/%d in size", cinfo.output_width, cinfo.output_height); 0376 #endif 0377 0378 #ifdef JPEG_DEBUG 0379 qDebug("ok, going to decompressStarted"); 0380 #endif 0381 0382 jsrc.decoder_timestamp.start(); 0383 state = jsrc.do_progressive ? decompressStarted : doOutputScan; 0384 } 0385 } 0386 0387 if (state == decompressStarted) { 0388 state = (!jsrc.final_pass && jsrc.decoder_timestamp.elapsed() < max_consumingtime) 0389 ? consumeInput : prepareOutputScan; 0390 } 0391 0392 if (state == consumeInput) { 0393 int retval; 0394 0395 do { 0396 retval = jpeg_consume_input(&cinfo); 0397 } while (retval != JPEG_SUSPENDED && retval != JPEG_REACHED_EOI); 0398 0399 if (jsrc.decoder_timestamp.elapsed() > max_consumingtime || jsrc.final_pass || 0400 retval == JPEG_REACHED_EOI || retval == JPEG_REACHED_SOS) { 0401 state = prepareOutputScan; 0402 } 0403 } 0404 0405 if (state == prepareOutputScan) { 0406 jsrc.decoder_timestamp.restart(); 0407 if (jpeg_start_output(&cinfo, cinfo.input_scan_number)) { 0408 state = doOutputScan; 0409 } 0410 } 0411 0412 if (state == doOutputScan) { 0413 if (!scanline || jsrc.decoding_done) { 0414 #ifdef JPEG_DEBUG 0415 qDebug("complete in doOutputscan, eating.."); 0416 #endif 0417 return consumed; 0418 } 0419 uchar *lines[1] = {scanline}; 0420 //int oldoutput_scanline = cinfo.output_scanline; 0421 0422 //Decode and feed line-by-line 0423 while (cinfo.output_scanline < cinfo.output_height) { 0424 if (!jpeg_read_scanlines(&cinfo, lines, 1)) { 0425 break; 0426 } 0427 0428 if (cinfo.output_components == 3) { 0429 // Expand 24->32 bpp. 0430 uchar *in = scanline + cinfo.output_width * 3; 0431 QRgb *out = (QRgb *)scanline; 0432 0433 for (uint i = cinfo.output_width; i--;) { 0434 in -= 3; 0435 out[i] = qRgb(in[0], in[1], in[2]); 0436 } 0437 } else if (cinfo.out_color_space == JCS_CMYK) { 0438 uchar *in = scanline + cinfo.output_width * 4; 0439 QRgb *out = (QRgb *) scanline; 0440 0441 for (uint i = cinfo.output_width; i--;) { 0442 in -= 4; 0443 int k = in[3]; 0444 out[i] = qRgb(k * in[0] / 255, k * in[1] / 255, k * in[2] / 255); 0445 } 0446 } 0447 0448 owner->notifyScanline(passNum + 1, scanline); 0449 } //per-line scan 0450 0451 if (cinfo.output_scanline >= cinfo.output_height) { 0452 passNum++; 0453 0454 if (jsrc.do_progressive) { 0455 jpeg_finish_output(&cinfo); 0456 jsrc.final_pass = jpeg_input_complete(&cinfo); 0457 jsrc.decoding_done = jsrc.final_pass && cinfo.input_scan_number == cinfo.output_scan_number; 0458 } else { 0459 jsrc.decoding_done = true; 0460 } 0461 0462 if (passNum > ImageLoader::FinalVersionID) { 0463 qWarning("JPEG Decoder: Too many interlacing passes needed"); 0464 jsrc.decoding_done = true; //Force exit 0465 } 0466 0467 #ifdef JPEG_DEBUG 0468 qDebug("one pass is completed, final_pass = %d, dec_done: %d, complete: %d", 0469 jsrc.final_pass, jsrc.decoding_done, jpeg_input_complete(&cinfo)); 0470 #endif 0471 if (!jsrc.decoding_done) { 0472 #ifdef JPEG_DEBUG 0473 qDebug("starting another one, input_scan_number is %d/%d", cinfo.input_scan_number, 0474 cinfo.output_scan_number); 0475 #endif 0476 jsrc.decoder_timestamp.restart(); 0477 state = decompressStarted; 0478 } 0479 } 0480 } 0481 0482 if (state == doOutputScan && jsrc.decoding_done) { 0483 #ifdef JPEG_DEBUG 0484 qDebug("input is complete, cleaning up, returning.."); 0485 #endif 0486 0487 jsrc.ateof = true; 0488 0489 (void) jpeg_finish_decompress(&cinfo); 0490 (void) jpeg_destroy_decompress(&cinfo); 0491 0492 state = readDone; 0493 0494 return Done; 0495 } 0496 0497 #ifdef BUFFER_DEBUG 0498 qDebug("valid_buffer_len is now %d", jsrc.valid_buffer_len); 0499 qDebug("bytes_in_buffer is now %d", jsrc.bytes_in_buffer); 0500 qDebug("consumed %d bytes", consumed); 0501 #endif 0502 if (jsrc.bytes_in_buffer && jsrc.buffer != jsrc.next_input_byte) { 0503 memmove(jsrc.buffer, jsrc.next_input_byte, jsrc.bytes_in_buffer); 0504 } 0505 jsrc.valid_buffer_len = jsrc.bytes_in_buffer; 0506 return consumed; 0507 } 0508 0509 JPEGLoader::JPEGLoader() 0510 { 0511 d = new Private; 0512 d->owner = this; 0513 } 0514 0515 JPEGLoader::~JPEGLoader() 0516 { 0517 delete d; 0518 } 0519 0520 int JPEGLoader::processData(uchar *data, int length) 0521 { 0522 return d->processData(data, length); 0523 } 0524 0525 } 0526