From 0a7b21172f7124439171e3921a12952a060c39fc Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 10 Oct 2013 23:49:06 +0300 Subject: [PATCH] Add native libjpeg loader --- Build | 16 +++ source/graphics/jpeg/jpegloader.cpp | 150 ++++++++++++++++++++++++++++ source/graphics/jpeg/jpegloader.h | 31 ++++++ 3 files changed, 197 insertions(+) create mode 100644 source/graphics/jpeg/jpegloader.cpp create mode 100644 source/graphics/jpeg/jpegloader.h diff --git a/Build b/Build index b96da4d..7972020 100644 --- a/Build +++ b/Build @@ -43,6 +43,18 @@ package "mspgui" require "libpng"; }; + feature "libjpeg" "Include libjpeg support for loading JPEG files" + { + default "yes"; + }; + if_feature "libjpeg" + { + build_info + { + library "jpeg"; + }; + }; + if_arch "darwin" { feature "quartz" "Include Quartz support for loading image files" @@ -84,6 +96,10 @@ package "mspgui" { source "source/graphics/png"; }; + if_feature "libjpeg" + { + source "source/graphics/jpeg"; + }; if_feature "devil" { source "source/graphics/devil"; 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 diff --git a/source/graphics/jpeg/jpegloader.h b/source/graphics/jpeg/jpegloader.h new file mode 100644 index 0000000..d45e599 --- /dev/null +++ b/source/graphics/jpeg/jpegloader.h @@ -0,0 +1,31 @@ +#ifndef MSP_GRAPHICS_JPEGLOADER_H_ +#define MSP_GRAPHICS_JPEGLOADER_H_ + +#include + +namespace Msp { +namespace Graphics { + +class JpegLoader: public ImageLoader +{ +private: + struct Private; + + Private *priv; + + static Register reg; + +public: + JpegLoader(IO::Seekable &); + virtual ~JpegLoader(); + + static unsigned get_signature_size() { return 3; } + static bool detect(const std::string &); + + virtual void load(Image::Data &); +}; + +} // namespace Graphics +} // namespace Msp + +#endif -- 2.45.2