]> git.tdb.fi Git - libs/gui.git/commitdiff
Add native libjpeg loader
authorMikko Rasa <tdb@tdb.fi>
Thu, 10 Oct 2013 20:49:06 +0000 (23:49 +0300)
committerMikko Rasa <tdb@tdb.fi>
Thu, 10 Oct 2013 20:49:06 +0000 (23:49 +0300)
Build
source/graphics/jpeg/jpegloader.cpp [new file with mode: 0644]
source/graphics/jpeg/jpegloader.h [new file with mode: 0644]

diff --git a/Build b/Build
index b96da4d66d3388b53b0c062a25fff18b33af1e1b..7972020fb1fd0471b8ea771eeaa6c566cef3025f 100644 (file)
--- 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 (file)
index 0000000..415e79f
--- /dev/null
@@ -0,0 +1,150 @@
+#include <stdio.h>
+#include <setjmp.h>
+#include <jpeglib.h>
+#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<ErrorManager *>(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<SourceManager *>(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<SourceManager *>(jpeg->src);
+       src->next_input_byte = src->buffer;
+       src->bytes_in_buffer = src->io->read(reinterpret_cast<char *>(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<SourceManager *>(jpeg->src);
+       if(static_cast<unsigned long>(count)<src->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> 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()<sizeof(jpeg_sig))
+               return false;
+       return !sig.compare(0, 3, jpeg_sig);
+}
+
+void JpegLoader::load(Image::Data &data)
+{
+       if(setjmp(priv->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_scanline<data.height)
+       {
+               unsigned y = data.height-priv->jpeg.output_scanline;
+               unsigned count = min(y, 8U);
+               for(unsigned i=0; i<count; ++i)
+                       rows[i] = reinterpret_cast<JSAMPROW>(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 (file)
index 0000000..d45e599
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef MSP_GRAPHICS_JPEGLOADER_H_
+#define MSP_GRAPHICS_JPEGLOADER_H_
+
+#include <msp/graphics/imageloader.h>
+
+namespace Msp {
+namespace Graphics {
+
+class JpegLoader: public ImageLoader
+{
+private:
+       struct Private;
+
+       Private *priv;
+
+       static Register<JpegLoader> 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