X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fgraphics%2Fjpeg%2Fjpegloader.cpp;fp=source%2Fgraphics%2Fjpeg%2Fjpegloader.cpp;h=415e79f95927959c6d667233e7734e5ed657d226;hb=0a7b21172f7124439171e3921a12952a060c39fc;hp=0000000000000000000000000000000000000000;hpb=06bc1c43ef26b3256dd92a20dbdf7ed9e08bab04;p=libs%2Fgui.git diff --git a/source/graphics/jpeg/jpegloader.cpp b/source/graphics/jpeg/jpegloader.cpp new file mode 100644 index 0000000..415e79f --- /dev/null +++ b/source/graphics/jpeg/jpegloader.cpp @@ -0,0 +1,150 @@ +#include +#include +#include +#include "jpegloader.h" + +using namespace std; + +namespace { + +struct ErrorManager: jpeg_error_mgr +{ + jmp_buf jmp; + string message; +}; + +void error_exit(j_common_ptr jpeg) +{ + ErrorManager *err = reinterpret_cast(jpeg->err); + char buf[JMSG_LENGTH_MAX]; + err->format_message(jpeg, buf); + err->message = buf; + longjmp(err->jmp, 1); +} + +void emit_message(j_common_ptr, int) +{ +} + + +struct SourceManager: jpeg_source_mgr +{ + Msp::IO::Seekable *io; + JOCTET buffer[4096]; +}; + +void init_source(j_decompress_ptr jpeg) +{ + SourceManager *src = reinterpret_cast(jpeg->src); + src->next_input_byte = src->buffer; + src->bytes_in_buffer = 0; +} + +int fill_input_buffer(j_decompress_ptr jpeg) +{ + SourceManager *src = reinterpret_cast(jpeg->src); + src->next_input_byte = src->buffer; + src->bytes_in_buffer = src->io->read(reinterpret_cast(src->buffer), sizeof(src->buffer)); + return true; +} + +void skip_input_data(j_decompress_ptr jpeg, long count) +{ + if(count<=0) + return; + + SourceManager *src = reinterpret_cast(jpeg->src); + if(static_cast(count)bytes_in_buffer) + { + src->next_input_byte += count; + src->bytes_in_buffer -= count; + } + else + { + src->io->seek(count, Msp::IO::S_CUR); + src->bytes_in_buffer = 0; + } +} + +void term_source(j_decompress_ptr) +{ +} + +} // namespace + + +namespace Msp { +namespace Graphics { + +struct JpegLoader::Private +{ + jpeg_decompress_struct jpeg; + ErrorManager err_mgr; + SourceManager src_mgr; +}; + + +ImageLoader::Register JpegLoader::reg; + +JpegLoader::JpegLoader(IO::Seekable &io): + priv(new Private) +{ + priv->jpeg.err = jpeg_std_error(&priv->err_mgr); + priv->err_mgr.error_exit = &error_exit; + priv->err_mgr.emit_message = &emit_message; + + jpeg_create_decompress(&priv->jpeg); + + priv->jpeg.src = &priv->src_mgr; + priv->src_mgr.init_source = &init_source; + priv->src_mgr.fill_input_buffer = &fill_input_buffer; + priv->src_mgr.skip_input_data = &skip_input_data; + priv->src_mgr.resync_to_restart = &jpeg_resync_to_restart; + priv->src_mgr.term_source = &term_source; + priv->src_mgr.io = &io; +} + +JpegLoader::~JpegLoader() +{ + jpeg_destroy_decompress(&priv->jpeg); + delete priv; +} + +bool JpegLoader::detect(const string &sig) +{ + static const char jpeg_sig[] = "\xFF\xD8\xFF"; + if(sig.size()err_mgr.jmp)) + throw bad_image_data(priv->err_mgr.message); + + jpeg_read_header(&priv->jpeg, true); + priv->jpeg.out_color_space = JCS_RGB; + jpeg_start_decompress(&priv->jpeg); + + data.width = priv->jpeg.output_width; + data.height = priv->jpeg.output_height; + data.stride = priv->jpeg.output_width*priv->jpeg.output_components; + data.fmt = RGB; + + data.data = new char[data.stride*data.height]; + JSAMPROW rows[8]; + while(priv->jpeg.output_scanlinejpeg.output_scanline; + unsigned count = min(y, 8U); + for(unsigned i=0; i(data.data+(y-i-1)*data.stride); + jpeg_read_scanlines(&priv->jpeg, rows, count); + } + + jpeg_finish_decompress(&priv->jpeg); +} + +} // namespace Graphics +} // namespace Msp