diff options
Diffstat (limited to 'khtml/misc/loader_jpeg.cpp')
-rw-r--r-- | khtml/misc/loader_jpeg.cpp | 548 |
1 files changed, 0 insertions, 548 deletions
diff --git a/khtml/misc/loader_jpeg.cpp b/khtml/misc/loader_jpeg.cpp deleted file mode 100644 index 15057e0be..000000000 --- a/khtml/misc/loader_jpeg.cpp +++ /dev/null @@ -1,548 +0,0 @@ -/* - This file is part of the KDE libraries - - Copyright (C) 2000 Dirk Mueller (mueller@kde.org) - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#ifdef HAVE_LIBJPEG -// on some systems, libjpeg installs its config.h file which causes a conflict -// and makes the compiler barf with "XXX already defined". -#ifdef HAVE_STDLIB_H -#undef HAVE_STDLIB_H -#endif -#include "loader_jpeg.h" - -#include <stdio.h> -#include <setjmp.h> -#include <tqdatetime.h> -#include <kglobal.h> - -extern "C" { -#define XMD_H -#include <jpeglib.h> -#undef const -} - - -#undef BUFFER_DEBUG -//#define BUFFER_DEBUG - -#undef JPEG_DEBUG -//#define JPEG_DEBUG - -// ----------------------------------------------------------------------------- - -struct khtml_error_mgr : public jpeg_error_mgr { - jmp_buf setjmp_buffer; -}; - -extern "C" { - - static - void khtml_error_exit (j_common_ptr cinfo) - { - khtml_error_mgr* myerr = (khtml_error_mgr*) cinfo->err; - char buffer[JMSG_LENGTH_MAX]; - (*cinfo->err->format_message)(cinfo, buffer); -#ifdef JPEG_DEBUG - tqWarning("%s", buffer); -#endif - longjmp(myerr->setjmp_buffer, 1); - } -} - -static const int max_buf = 32768; -static const int max_consumingtime = 2000; - -struct khtml_jpeg_source_mgr : public jpeg_source_mgr { - JOCTET buffer[max_buf]; - - int valid_buffer_len; - size_t skip_input_bytes; - int ateof; - TQRect change_rect; - TQRect old_change_rect; - TQTime decoder_timestamp; - bool final_pass; - bool decoding_done; - bool do_progressive; - -public: - khtml_jpeg_source_mgr() KDE_NO_EXPORT; -}; - - -extern "C" { - - static - void khtml_j_decompress_dummy(j_decompress_ptr) - { - } - - static - boolean khtml_fill_input_buffer(j_decompress_ptr cinfo) - { -#ifdef BUFFER_DEBUG - tqDebug("khtml_fill_input_buffer called!"); -#endif - - khtml_jpeg_source_mgr* src = (khtml_jpeg_source_mgr*)cinfo->src; - - if ( src->ateof ) - { - /* Insert a fake EOI marker - as per jpeglib recommendation */ - src->buffer[0] = (JOCTET) 0xFF; - src->buffer[1] = (JOCTET) JPEG_EOI; - src->bytes_in_buffer = 2; - src->next_input_byte = (JOCTET *) src->buffer; -#ifdef BUFFER_DEBUG - tqDebug("...returning true!"); -#endif - return true; - } - else - return false; /* I/O suspension mode */ - } - - static - void khtml_skip_input_data(j_decompress_ptr cinfo, long num_bytes) - { - if(num_bytes <= 0) - return; /* required noop */ - -#ifdef BUFFER_DEBUG - tqDebug("khtml_skip_input_data (%d) called!", num_bytes); -#endif - - khtml_jpeg_source_mgr* src = (khtml_jpeg_source_mgr*)cinfo->src; - src->skip_input_bytes += num_bytes; - - unsigned int skipbytes = kMin(src->bytes_in_buffer, src->skip_input_bytes); - -#ifdef BUFFER_DEBUG - tqDebug("skip_input_bytes is now %d", src->skip_input_bytes); - tqDebug("skipbytes is now %d", skipbytes); - tqDebug("valid_buffer_len is before %d", src->valid_buffer_len); - tqDebug("bytes_in_buffer is %d", src->bytes_in_buffer); -#endif - - if(skipbytes < src->bytes_in_buffer) - memmove(src->buffer, src->next_input_byte+skipbytes, src->bytes_in_buffer - skipbytes); - - src->bytes_in_buffer -= skipbytes; - src->valid_buffer_len = src->bytes_in_buffer; - src->skip_input_bytes -= skipbytes; - - /* adjust data for jpeglib */ - cinfo->src->next_input_byte = (JOCTET *) src->buffer; - cinfo->src->bytes_in_buffer = (size_t) src->valid_buffer_len; -#ifdef BUFFER_DEBUG - tqDebug("valid_buffer_len is afterwards %d", src->valid_buffer_len); - tqDebug("skip_input_bytes is now %d", src->skip_input_bytes); -#endif - } -} - - -khtml_jpeg_source_mgr::khtml_jpeg_source_mgr() -{ - jpeg_source_mgr::init_source = khtml_j_decompress_dummy; - jpeg_source_mgr::fill_input_buffer = khtml_fill_input_buffer; - jpeg_source_mgr::skip_input_data = khtml_skip_input_data; - jpeg_source_mgr::resync_to_restart = jpeg_resync_to_restart; - jpeg_source_mgr::term_source = khtml_j_decompress_dummy; - bytes_in_buffer = 0; - valid_buffer_len = 0; - skip_input_bytes = 0; - ateof = 0; - next_input_byte = buffer; - final_pass = false; - decoding_done = false; -} - - - -// ----------------------------------------------------------------------------- - -class KJPEGFormat : public TQImageFormat -{ -public: - KJPEGFormat(); - - virtual ~KJPEGFormat(); - - virtual int decode(TQImage& img, TQImageConsumer* consumer, - const uchar* buffer, int length); -private: - - enum { - Init, - readHeader, - startDecompress, - decompressStarted, - consumeInput, - prepareOutputScan, - doOutputScan, - readDone, - invalid - } state; - - // structs for the jpeglib - struct jpeg_decompress_struct cinfo; - struct khtml_error_mgr jerr; - struct khtml_jpeg_source_mgr jsrc; -}; - - -// ----------------------------------------------------------------------------- - -KJPEGFormat::KJPEGFormat() -{ - memset(&cinfo, 0, sizeof(cinfo)); - cinfo.err = jpeg_std_error(&jerr); - jpeg_create_decompress(&cinfo); - cinfo.err = jpeg_std_error(&jerr); - jerr.error_exit = khtml_error_exit; - cinfo.src = &jsrc; - state = Init; -} - - -KJPEGFormat::~KJPEGFormat() -{ - (void) jpeg_destroy_decompress(&cinfo); -} - -/* - * return > 0 means "consumed x bytes, need more" - * return == 0 means "end of frame reached" - * return < 0 means "fatal error in image decoding, don't call me ever again" - */ - -int KJPEGFormat::decode(TQImage& image, TQImageConsumer* consumer, const uchar* buffer, int length) -{ -#ifdef JPEG_DEBUG - tqDebug("KJPEGFormat::decode(%08lx, %08lx, %08lx, %d)", - &image, consumer, buffer, length); -#endif - - if(jsrc.ateof) { -#ifdef JPEG_DEBUG - tqDebug("ateof, eating"); -#endif - return length; - } - - - if(setjmp(jerr.setjmp_buffer)) - { -#ifdef JPEG_DEBUG - tqDebug("jump into state invalid"); -#endif - if(consumer) - consumer->end(); - - // this is fatal - return -1; - } - - int consumed = kMin(length, max_buf - jsrc.valid_buffer_len); - -#ifdef BUFFER_DEBUG - tqDebug("consuming %d bytes", consumed); -#endif - - // filling buffer with the new data - memcpy(jsrc.buffer + jsrc.valid_buffer_len, buffer, consumed); - jsrc.valid_buffer_len += consumed; - - if(jsrc.skip_input_bytes) - { -#ifdef BUFFER_DEBUG - tqDebug("doing skipping"); - tqDebug("valid_buffer_len %d", jsrc.valid_buffer_len); - tqDebug("skip_input_bytes %d", jsrc.skip_input_bytes); -#endif - int skipbytes = kMin((size_t) jsrc.valid_buffer_len, jsrc.skip_input_bytes); - - if(skipbytes < jsrc.valid_buffer_len) - memmove(jsrc.buffer, jsrc.buffer+skipbytes, jsrc.valid_buffer_len - skipbytes); - - jsrc.valid_buffer_len -= skipbytes; - jsrc.skip_input_bytes -= skipbytes; - - // still more bytes to skip - if(jsrc.skip_input_bytes) { - if(consumed <= 0) tqDebug("ERROR!!!"); - return consumed; - } - - } - - cinfo.src->next_input_byte = (JOCTET *) jsrc.buffer; - cinfo.src->bytes_in_buffer = (size_t) jsrc.valid_buffer_len; - -#ifdef BUFFER_DEBUG - tqDebug("buffer contains %d bytes", jsrc.valid_buffer_len); -#endif - - if(state == Init) - { - if(jpeg_read_header(&cinfo, true) != JPEG_SUSPENDED) { - // do some simple memory requirements limitations - // as long as we use that stupid TQt stuff - int s = cinfo.image_width * cinfo.image_height; - if ( s > 16384 * 12388 ) - cinfo.scale_denom = 8; - else if ( s > 8192 * 6144 ) - cinfo.scale_denom = 4; - else if ( s > 4096 * 3072 ) - cinfo.scale_denom = 2; - - if ( consumer ) - consumer->setSize(cinfo.image_width/cinfo.scale_denom, - cinfo.image_height/cinfo.scale_denom); - - state = startDecompress; - } - } - - if(state == startDecompress) - { - jsrc.do_progressive = jpeg_has_multiple_scans( &cinfo ); - -#ifdef JPEG_DEBUG - tqDebug( "**** DOPROGRESSIVE: %d", jsrc.do_progressive ); -#endif - if ( jsrc.do_progressive ) - cinfo.buffered_image = true; - else - cinfo.buffered_image = false; - - // setup image sizes - jpeg_calc_output_dimensions( &cinfo ); - - if ( cinfo.jpeg_color_space == JCS_YCbCr ) - cinfo.out_color_space = JCS_RGB; - - cinfo.do_fancy_upsampling = true; - cinfo.do_block_smoothing = false; - cinfo.quantize_colors = false; - - // false: IO suspension - if(jpeg_start_decompress(&cinfo)) { - if ( cinfo.output_components == 3 || cinfo.output_components == 4) { - image.create( cinfo.output_width, cinfo.output_height, 32 ); - } else if ( cinfo.output_components == 1 ) { - image.create( cinfo.output_width, cinfo.output_height, 8, 256 ); - for (int i=0; i<256; i++) - image.setColor(i, tqRgb(i,i,i)); - } - -#ifdef JPEG_DEBUG - tqDebug("will create a picture %d/%d in size", cinfo.output_width, cinfo.output_height); -#endif - -#ifdef JPEG_DEBUG - tqDebug("ok, going to decompressStarted"); -#endif - - jsrc.decoder_timestamp.start(); - state = jsrc.do_progressive ? decompressStarted : doOutputScan; - } - } - -again: - - if(state == decompressStarted) { - state = (!jsrc.final_pass && jsrc.decoder_timestamp.elapsed() < max_consumingtime) - ? consumeInput : prepareOutputScan; - } - - if(state == consumeInput) - { - int retval; - - do { - retval = jpeg_consume_input(&cinfo); - } while (retval != JPEG_SUSPENDED && retval != JPEG_REACHED_EOI - && (retval != JPEG_REACHED_SOS || jsrc.decoder_timestamp.elapsed() < max_consumingtime)); - - if(jsrc.decoder_timestamp.elapsed() >= max_consumingtime || - jsrc.final_pass || - retval == JPEG_REACHED_EOI || retval == JPEG_REACHED_SOS) - state = prepareOutputScan; - } - - if(state == prepareOutputScan) - { - if ( jpeg_start_output(&cinfo, cinfo.input_scan_number) ) - state = doOutputScan; - } - - if(state == doOutputScan) - { - if(image.isNull() || jsrc.decoding_done) - { -#ifdef JPEG_DEBUG - tqDebug("complete in doOutputscan, eating.."); -#endif - return consumed; - } - uchar** lines = image.jumpTable(); - int oldoutput_scanline = cinfo.output_scanline; - - while(cinfo.output_scanline < cinfo.output_height && - jpeg_read_scanlines(&cinfo, lines+cinfo.output_scanline, cinfo.output_height)) - ; // here happens all the magic of decoding - - int completed_scanlines = cinfo.output_scanline - oldoutput_scanline; -#ifdef JPEG_DEBUG - tqDebug("completed now %d scanlines", completed_scanlines); -#endif - - if ( cinfo.output_components == 3 ) { - // Expand 24->32 bpp. - for (int j=oldoutput_scanline; j<oldoutput_scanline+completed_scanlines; j++) { - uchar *in = image.scanLine(j) + cinfo.output_width * 3; - TQRgb *out = (TQRgb*)image.scanLine(j); - - for (uint i=cinfo.output_width; i--; ) { - in-=3; - out[i] = tqRgb(in[0], in[1], in[2]); - } - } - } - - if(consumer && completed_scanlines) - { - TQRect r(0, oldoutput_scanline, cinfo.output_width, completed_scanlines); -#ifdef JPEG_DEBUG - tqDebug("changing %d/%d %d/%d", r.x(), r.y(), r.width(), r.height()); -#endif - jsrc.change_rect |= r; - - if ( jsrc.decoder_timestamp.elapsed() >= max_consumingtime ) { - if( !jsrc.old_change_rect.isEmpty()) { - consumer->changed(jsrc.old_change_rect); - jsrc.old_change_rect = TQRect(); - } - consumer->changed(jsrc.change_rect); - jsrc.change_rect = TQRect(); - jsrc.decoder_timestamp.restart(); - } - } - - if(cinfo.output_scanline >= cinfo.output_height) - { - if ( jsrc.do_progressive ) { - jpeg_finish_output(&cinfo); - jsrc.final_pass = jpeg_input_complete(&cinfo); - jsrc.decoding_done = jsrc.final_pass && cinfo.input_scan_number == cinfo.output_scan_number; - if ( !jsrc.decoding_done ) { - jsrc.old_change_rect |= jsrc.change_rect; - jsrc.change_rect = TQRect(); - } - } - else - jsrc.decoding_done = true; - -#ifdef JPEG_DEBUG - tqDebug("one pass is completed, final_pass = %d, dec_done: %d, complete: %d", - jsrc.final_pass, jsrc.decoding_done, jpeg_input_complete(&cinfo)); -#endif - if(!jsrc.decoding_done) - { -#ifdef JPEG_DEBUG - tqDebug("starting another one, input_scan_number is %d/%d", cinfo.input_scan_number, - cinfo.output_scan_number); -#endif - jsrc.decoder_timestamp.restart(); - state = decompressStarted; - // don't return until necessary! - goto again; - } - } - - if(state == doOutputScan && jsrc.decoding_done) { -#ifdef JPEG_DEBUG - tqDebug("input is complete, cleaning up, returning.."); -#endif - if ( consumer && !jsrc.change_rect.isEmpty() ) - consumer->changed( jsrc.change_rect ); - - if(consumer) - consumer->end(); - - jsrc.ateof = true; - - (void) jpeg_finish_decompress(&cinfo); - (void) jpeg_destroy_decompress(&cinfo); - - state = readDone; - - return 0; - } - } - -#ifdef BUFFER_DEBUG - tqDebug("valid_buffer_len is now %d", jsrc.valid_buffer_len); - tqDebug("bytes_in_buffer is now %d", jsrc.bytes_in_buffer); - tqDebug("consumed %d bytes", consumed); -#endif - if(jsrc.bytes_in_buffer && jsrc.buffer != jsrc.next_input_byte) - memmove(jsrc.buffer, jsrc.next_input_byte, jsrc.bytes_in_buffer); - jsrc.valid_buffer_len = jsrc.bytes_in_buffer; - return consumed; -} - -// ----------------------------------------------------------------------------- -// This is the factory that teaches TQt about progressive JPEG's - -TQImageFormat* khtml::KJPEGFormatType::decoderFor(const unsigned char* buffer, int length) -{ - if(length < 3) return 0; - - if(buffer[0] == 0377 && - buffer[1] == 0330 && - buffer[2] == 0377) - return new KJPEGFormat; - - return 0; -} - -const char* khtml::KJPEGFormatType::formatName() const -{ - return "JPEG"; -} - -#else -#ifdef __GNUC__ -#warning You don't seem to have libJPEG. jpeg support in khtml won't work -#endif -#endif // HAVE_LIBJPEG - -// ----------------------------------------------------------------------------- - |