]> git.tdb.fi Git - libs/gui.git/blob - source/graphics/jpeg/jpegloader.cpp
Add decorations for things which should be exported from the library
[libs/gui.git] / source / graphics / jpeg / jpegloader.cpp
1 #include "jpegloader.h"
2 #include <stdio.h>
3 #include <setjmp.h>
4 #include <jpeglib.h>
5
6 using namespace std;
7
8 namespace {
9
10 struct ErrorManager: jpeg_error_mgr
11 {
12         jmp_buf jmp;
13         string message;
14 };
15
16 void error_exit(j_common_ptr jpeg)
17 {
18         ErrorManager *err = reinterpret_cast<ErrorManager *>(jpeg->err);
19         char buf[JMSG_LENGTH_MAX];
20         err->format_message(jpeg, buf);
21         err->message = buf;
22         longjmp(err->jmp, 1);
23 }
24
25 void emit_message(j_common_ptr, int)
26 {
27 }
28
29
30 struct SourceManager: jpeg_source_mgr
31 {
32         Msp::IO::Seekable *io;
33         JOCTET buffer[4096];
34 };
35
36 void init_source(j_decompress_ptr jpeg)
37 {
38         SourceManager *src = reinterpret_cast<SourceManager *>(jpeg->src);
39         src->next_input_byte = src->buffer;
40         src->bytes_in_buffer = 0;
41 }
42
43 boolean fill_input_buffer(j_decompress_ptr jpeg)
44 {
45         SourceManager *src = reinterpret_cast<SourceManager *>(jpeg->src);
46         src->next_input_byte = src->buffer;
47         src->bytes_in_buffer = src->io->read(reinterpret_cast<char *>(src->buffer), sizeof(src->buffer));
48         return TRUE;
49 }
50
51 void skip_input_data(j_decompress_ptr jpeg, long count)
52 {
53         if(count<=0)
54                 return;
55
56         SourceManager *src = reinterpret_cast<SourceManager *>(jpeg->src);
57         if(static_cast<unsigned long>(count)<src->bytes_in_buffer)
58         {
59                 src->next_input_byte += count;
60                 src->bytes_in_buffer -= count;
61         }
62         else
63         {
64                 src->io->seek(count-src->bytes_in_buffer, Msp::IO::S_CUR);
65                 src->bytes_in_buffer = 0;
66         }
67 }
68
69 void term_source(j_decompress_ptr)
70 {
71 }
72
73 } // namespace
74
75
76 namespace Msp {
77 namespace Graphics {
78
79 struct JpegLoader::Private
80 {
81         jpeg_decompress_struct jpeg;
82         ErrorManager err_mgr;
83         SourceManager src_mgr;
84 };
85
86
87 JpegLoader::JpegLoader(IO::Seekable &io):
88         priv(new Private)
89 {
90         priv->jpeg.err = jpeg_std_error(&priv->err_mgr);
91         priv->err_mgr.error_exit = &error_exit;
92         priv->err_mgr.emit_message = &emit_message;
93
94         if(setjmp(priv->err_mgr.jmp))
95                 throw runtime_error("error creating jpeg decompressor: "+priv->err_mgr.message);
96
97         jpeg_create_decompress(&priv->jpeg);
98
99         priv->jpeg.src = &priv->src_mgr;
100         priv->src_mgr.init_source = &init_source;
101         priv->src_mgr.fill_input_buffer = &fill_input_buffer;
102         priv->src_mgr.skip_input_data = &skip_input_data;
103         priv->src_mgr.resync_to_restart = &jpeg_resync_to_restart;
104         priv->src_mgr.term_source = &term_source;
105         priv->src_mgr.io = &io;
106 }
107
108 JpegLoader::~JpegLoader()
109 {
110         jpeg_destroy_decompress(&priv->jpeg);
111         delete priv;
112 }
113
114 bool JpegLoader::detect(const string &sig)
115 {
116         static const char jpeg_sig[] = { '\xFF', '\xD8', '\xFF' };
117         if(sig.size()<sizeof(jpeg_sig))
118                 return false;
119         return !sig.compare(0, sizeof(jpeg_sig), jpeg_sig, sizeof(jpeg_sig));
120 }
121
122 void JpegLoader::load_headers_(Image::Data &data)
123 {
124         if(setjmp(priv->err_mgr.jmp))
125                 throw bad_image_data(priv->err_mgr.message);
126
127         jpeg_read_header(&priv->jpeg, TRUE);
128         priv->jpeg.out_color_space = JCS_RGB;
129         jpeg_start_decompress(&priv->jpeg);
130
131         data.width = priv->jpeg.output_width;
132         data.height = priv->jpeg.output_height;
133         data.stride = priv->jpeg.output_width*priv->jpeg.output_components;
134         data.fmt = RGB;
135 }
136
137 void JpegLoader::load_pixels_(Image::Data &data)
138 {
139         JSAMPROW rows[8];
140         while(priv->jpeg.output_scanline<data.height)
141         {
142                 unsigned y = data.height-priv->jpeg.output_scanline;
143                 unsigned count = min(y, 8U);
144                 for(unsigned i=0; i<count; ++i)
145                         rows[i] = reinterpret_cast<JSAMPROW>(data.pixels+(y-i-1)*data.stride);
146                 jpeg_read_scanlines(&priv->jpeg, rows, count);
147         }
148
149         jpeg_finish_decompress(&priv->jpeg);
150 }
151
152 } // namespace Graphics
153 } // namespace Msp