beta-0.89.2
[luatex.git] / source / libs / poppler / poppler-src / poppler / DCTStream.cc
blobbfdb0eaf80a3ce3758a0423db31cdb03a3f555e9
1 //========================================================================
2 //
3 // DCTStream.cc
4 //
5 // This file is licensed under the GPLv2 or later
6 //
7 // Copyright 2005 Jeff Muizelaar <jeff@infidigm.net>
8 // Copyright 2005-2010, 2012 Albert Astals Cid <aacid@kde.org>
9 // Copyright 2009 Ryszard Trojnacki <rysiek@menel.com>
10 // Copyright 2010 Carlos Garcia Campos <carlosgc@gnome.org>
11 // Copyright 2011 Daiki Ueno <ueno@unixuser.org>
12 // Copyright 2011 Tomas Hoger <thoger@redhat.com>
13 // Copyright 2012, 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
15 //========================================================================
17 #include "DCTStream.h"
19 static void str_init_source(j_decompress_ptr cinfo)
23 static boolean str_fill_input_buffer(j_decompress_ptr cinfo)
25 int c;
26 struct str_src_mgr * src = (struct str_src_mgr *)cinfo->src;
27 if (src->index == 0) {
28 c = 0xFF;
29 src->index++;
31 else if (src->index == 1) {
32 c = 0xD8;
33 src->index++;
35 else c = src->str->getChar();
36 if (c != EOF)
38 src->buffer = c;
39 src->pub.next_input_byte = &src->buffer;
40 src->pub.bytes_in_buffer = 1;
41 return TRUE;
43 else return FALSE;
46 static void str_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
48 struct str_src_mgr * src = (struct str_src_mgr *)cinfo->src;
49 if (num_bytes > 0) {
50 while (num_bytes > (long) src->pub.bytes_in_buffer) {
51 num_bytes -= (long) src->pub.bytes_in_buffer;
52 str_fill_input_buffer(cinfo);
54 src->pub.next_input_byte += (size_t) num_bytes;
55 src->pub.bytes_in_buffer -= (size_t) num_bytes;
59 static void str_term_source(j_decompress_ptr cinfo)
63 DCTStream::DCTStream(Stream *strA, int colorXformA, Object *dict, int recursion) :
64 FilterStream(strA) {
65 colorXform = colorXformA;
66 if (dict != NULL) {
67 Object obj;
69 dict->dictLookup("Width", &obj, recursion);
70 err.width = (obj.isInt() && obj.getInt() <= JPEG_MAX_DIMENSION) ? obj.getInt() : 0;
71 obj.free();
72 dict->dictLookup("Height", &obj, recursion);
73 err.height = (obj.isInt() && obj.getInt() <= JPEG_MAX_DIMENSION) ? obj.getInt() : 0;
74 obj.free();
75 } else
76 err.height = err.width = 0;
77 init();
80 DCTStream::~DCTStream() {
81 jpeg_destroy_decompress(&cinfo);
82 delete str;
85 static void exitErrorHandler(jpeg_common_struct *error) {
86 j_decompress_ptr cinfo = (j_decompress_ptr)error;
87 str_error_mgr * err = (struct str_error_mgr *)cinfo->err;
88 if (cinfo->err->msg_code == JERR_IMAGE_TOO_BIG && err->width != 0 && err->height != 0) {
89 cinfo->image_height = err->height;
90 cinfo->image_width = err->width;
91 } else {
92 longjmp(err->setjmp_buffer, 1);
96 void DCTStream::init()
98 jpeg_std_error(&err.pub);
99 err.pub.error_exit = &exitErrorHandler;
100 src.pub.init_source = str_init_source;
101 src.pub.fill_input_buffer = str_fill_input_buffer;
102 src.pub.skip_input_data = str_skip_input_data;
103 src.pub.resync_to_restart = jpeg_resync_to_restart;
104 src.pub.term_source = str_term_source;
105 src.pub.bytes_in_buffer = 0;
106 src.pub.next_input_byte = NULL;
107 src.str = str;
108 src.index = 0;
109 current = NULL;
110 limit = NULL;
112 cinfo.err = &err.pub;
113 if (!setjmp(err.setjmp_buffer)) {
114 jpeg_create_decompress(&cinfo);
115 cinfo.src = (jpeg_source_mgr *)&src;
117 row_buffer = NULL;
120 void DCTStream::reset() {
121 int row_stride;
123 str->reset();
125 if (row_buffer)
127 jpeg_destroy_decompress(&cinfo);
128 init();
131 // JPEG data has to start with 0xFF 0xD8
132 // but some pdf like the one on
133 // https://bugs.freedesktop.org/show_bug.cgi?id=3299
134 // does have some garbage before that this seeks for
135 // the start marker...
136 bool startFound = false;
137 int c = 0, c2 = 0;
138 while (!startFound)
140 if (!c)
142 c = str->getChar();
143 if (c == -1)
145 error(errSyntaxError, -1, "Could not find start of jpeg data");
146 return;
148 if (c != 0xFF) c = 0;
150 else
152 c2 = str->getChar();
153 if (c2 != 0xD8)
155 c = 0;
156 c2 = 0;
158 else startFound = true;
162 if (!setjmp(err.setjmp_buffer))
164 if (jpeg_read_header(&cinfo, TRUE) != JPEG_SUSPENDED)
166 // figure out color transform
167 if (colorXform == -1 && !cinfo.saw_Adobe_marker) {
168 if (cinfo.num_components == 3) {
169 if (cinfo.saw_JFIF_marker) {
170 colorXform = 1;
171 } else if (cinfo.cur_comp_info[0]->component_id == 82 &&
172 cinfo.cur_comp_info[1]->component_id == 71 &&
173 cinfo.cur_comp_info[2]->component_id == 66) { // ASCII "RGB"
174 colorXform = 0;
175 } else {
176 colorXform = 1;
178 } else {
179 colorXform = 0;
181 } else if (cinfo.saw_Adobe_marker) {
182 colorXform = cinfo.Adobe_transform;
185 switch (cinfo.num_components) {
186 case 3:
187 cinfo.jpeg_color_space = colorXform ? JCS_YCbCr : JCS_RGB;
188 break;
189 case 4:
190 cinfo.jpeg_color_space = colorXform ? JCS_YCCK : JCS_CMYK;
191 break;
194 jpeg_start_decompress(&cinfo);
196 row_stride = cinfo.output_width * cinfo.output_components;
197 row_buffer = cinfo.mem->alloc_sarray((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
202 // we can not go with inline since gcc
203 // refuses to inline because of setjmp
204 #define DO_GET_CHAR \
205 if (current == limit) { \
206 if (cinfo.output_scanline < cinfo.output_height) \
208 if (!setjmp(err.setjmp_buffer)) \
210 if (!jpeg_read_scanlines(&cinfo, row_buffer, 1)) c = EOF; \
211 else { \
212 current = &row_buffer[0][0]; \
213 limit = &row_buffer[0][(cinfo.output_width - 1) * cinfo.output_components] + cinfo.output_components; \
214 c = *current; \
215 ++current; \
218 else c = EOF; \
220 else c = EOF; \
221 } else { \
222 c = *current; \
223 ++current; \
226 int DCTStream::getChar() {
227 int c;
229 DO_GET_CHAR
231 return c;
234 int DCTStream::getChars(int nChars, Guchar *buffer) {
235 int c;
236 for (int i = 0; i < nChars; ++i) {
237 DO_GET_CHAR
238 if (likely(c != EOF)) buffer[i] = c;
239 else return i;
241 return nChars;
244 int DCTStream::lookChar() {
245 if (unlikely(current == NULL)) {
246 return EOF;
248 return *current;
251 GooString *DCTStream::getPSFilter(int psLevel, const char *indent) {
252 GooString *s;
254 if (psLevel < 2) {
255 return NULL;
257 if (!(s = str->getPSFilter(psLevel, indent))) {
258 return NULL;
260 s->append(indent)->append("<< >> /DCTDecode filter\n");
261 return s;
264 GBool DCTStream::isBinary(GBool last) {
265 return str->isBinary(gTrue);