1 | #include "mupdf/fitz.h" |
2 | |
3 | #include <stdio.h> |
4 | #include <jpeglib.h> |
5 | |
6 | #ifndef SHARE_JPEG |
7 | typedef void * backing_store_ptr; |
8 | #include "jmemcust.h" |
9 | #endif |
10 | |
11 | typedef struct fz_dctd_s fz_dctd; |
12 | |
13 | struct fz_dctd_s |
14 | { |
15 | fz_stream *chain; |
16 | fz_stream *jpegtables; |
17 | fz_stream *curr_stm; |
18 | fz_context *ctx; |
19 | int color_transform; |
20 | int init; |
21 | int stride; |
22 | int l2factor; |
23 | unsigned char *scanline; |
24 | unsigned char *rp, *wp; |
25 | struct jpeg_decompress_struct cinfo; |
26 | struct jpeg_source_mgr srcmgr; |
27 | struct jpeg_error_mgr errmgr; |
28 | jmp_buf jb; |
29 | char msg[JMSG_LENGTH_MAX]; |
30 | |
31 | unsigned char buffer[4096]; |
32 | }; |
33 | |
34 | #ifdef SHARE_JPEG |
35 | |
36 | #define JZ_DCT_STATE_FROM_CINFO(c) (fz_dctd *)((c)->client_data) |
37 | |
38 | static void fz_dct_mem_init(struct jpeg_decompress_struct *cinfo, fz_dctd *state) |
39 | { |
40 | cinfo->client_data = state; |
41 | } |
42 | |
43 | #define fz_dct_mem_term(cinfo) |
44 | |
45 | #else /* SHARE_JPEG */ |
46 | |
47 | #define JZ_DCT_STATE_FROM_CINFO(c) (fz_dctd *)(GET_CUST_MEM_DATA(c)->priv) |
48 | |
49 | static void * |
50 | fz_dct_mem_alloc(j_common_ptr cinfo, size_t size) |
51 | { |
52 | fz_dctd *state = JZ_DCT_STATE_FROM_CINFO(cinfo); |
53 | return fz_malloc_no_throw(state->ctx, size); |
54 | } |
55 | |
56 | static void |
57 | fz_dct_mem_free(j_common_ptr cinfo, void *object, size_t size) |
58 | { |
59 | fz_dctd *state = JZ_DCT_STATE_FROM_CINFO(cinfo); |
60 | fz_free(state->ctx, object); |
61 | } |
62 | |
63 | static void |
64 | fz_dct_mem_init(struct jpeg_decompress_struct *cinfo, fz_dctd *state) |
65 | { |
66 | jpeg_cust_mem_data *custmptr; |
67 | custmptr = fz_malloc_struct(state->ctx, jpeg_cust_mem_data); |
68 | if (!jpeg_cust_mem_init(custmptr, (void *) state, NULL, NULL, NULL, |
69 | fz_dct_mem_alloc, fz_dct_mem_free, |
70 | fz_dct_mem_alloc, fz_dct_mem_free, NULL)) |
71 | { |
72 | fz_free(state->ctx, custmptr); |
73 | fz_throw(state->ctx, FZ_ERROR_GENERIC, "cannot initialize custom JPEG memory handler" ); |
74 | } |
75 | cinfo->client_data = custmptr; |
76 | } |
77 | |
78 | static void |
79 | fz_dct_mem_term(struct jpeg_decompress_struct *cinfo) |
80 | { |
81 | if (cinfo->client_data) |
82 | { |
83 | fz_dctd *state = JZ_DCT_STATE_FROM_CINFO(cinfo); |
84 | fz_free(state->ctx, cinfo->client_data); |
85 | cinfo->client_data = NULL; |
86 | } |
87 | } |
88 | |
89 | #endif /* SHARE_JPEG */ |
90 | |
91 | static void error_exit_dct(j_common_ptr cinfo) |
92 | { |
93 | char msg[JMSG_LENGTH_MAX]; |
94 | fz_dctd *state = JZ_DCT_STATE_FROM_CINFO(cinfo); |
95 | fz_context *ctx = state->ctx; |
96 | cinfo->err->format_message(cinfo, msg); |
97 | fz_throw(ctx, FZ_ERROR_GENERIC, "jpeg error: %s" , msg); |
98 | } |
99 | |
100 | static void init_source_dct(j_decompress_ptr cinfo) |
101 | { |
102 | /* nothing to do */ |
103 | } |
104 | |
105 | static void term_source_dct(j_decompress_ptr cinfo) |
106 | { |
107 | /* nothing to do */ |
108 | } |
109 | |
110 | static boolean fill_input_buffer_dct(j_decompress_ptr cinfo) |
111 | { |
112 | struct jpeg_source_mgr *src = cinfo->src; |
113 | fz_dctd *state = JZ_DCT_STATE_FROM_CINFO(cinfo); |
114 | fz_context *ctx = state->ctx; |
115 | fz_stream *curr_stm = state->curr_stm; |
116 | |
117 | curr_stm->rp = curr_stm->wp; |
118 | fz_try(ctx) |
119 | { |
120 | src->bytes_in_buffer = fz_available(ctx, curr_stm, 1); |
121 | } |
122 | fz_catch(ctx) |
123 | { |
124 | return 0; |
125 | } |
126 | src->next_input_byte = curr_stm->rp; |
127 | |
128 | if (src->bytes_in_buffer == 0) |
129 | { |
130 | static unsigned char eoi[2] = { 0xFF, JPEG_EOI }; |
131 | fz_warn(state->ctx, "premature end of file in jpeg" ); |
132 | src->next_input_byte = eoi; |
133 | src->bytes_in_buffer = 2; |
134 | } |
135 | |
136 | return 1; |
137 | } |
138 | |
139 | static void skip_input_data_dct(j_decompress_ptr cinfo, long num_bytes) |
140 | { |
141 | struct jpeg_source_mgr *src = cinfo->src; |
142 | if (num_bytes > 0) |
143 | { |
144 | while ((size_t)num_bytes > src->bytes_in_buffer) |
145 | { |
146 | num_bytes -= (long)src->bytes_in_buffer; |
147 | (void) src->fill_input_buffer(cinfo); |
148 | } |
149 | src->next_input_byte += num_bytes; |
150 | src->bytes_in_buffer -= num_bytes; |
151 | } |
152 | } |
153 | |
154 | static int |
155 | next_dctd(fz_context *ctx, fz_stream *stm, size_t max) |
156 | { |
157 | fz_dctd *state = stm->state; |
158 | j_decompress_ptr cinfo = &state->cinfo; |
159 | unsigned char *p = state->buffer; |
160 | unsigned char *ep; |
161 | int c; |
162 | |
163 | if (max > sizeof(state->buffer)) |
164 | max = sizeof(state->buffer); |
165 | ep = state->buffer + max; |
166 | |
167 | fz_try(ctx) |
168 | { |
169 | if (!state->init) |
170 | { |
171 | state->init = 1; |
172 | |
173 | /* Skip over any stray whitespace at the start of the stream */ |
174 | while ((c = fz_peek_byte(ctx, state->chain)) == '\n' || c == '\r' || c == ' ') |
175 | (void)fz_read_byte(ctx, state->chain); |
176 | |
177 | jpeg_create_decompress(cinfo); |
178 | |
179 | cinfo->src = &state->srcmgr; |
180 | cinfo->src->init_source = init_source_dct; |
181 | cinfo->src->fill_input_buffer = fill_input_buffer_dct; |
182 | cinfo->src->skip_input_data = skip_input_data_dct; |
183 | cinfo->src->resync_to_restart = jpeg_resync_to_restart; |
184 | cinfo->src->term_source = term_source_dct; |
185 | |
186 | /* optionally load additional JPEG tables first */ |
187 | if (state->jpegtables) |
188 | { |
189 | state->curr_stm = state->jpegtables; |
190 | cinfo->src->next_input_byte = state->curr_stm->rp; |
191 | cinfo->src->bytes_in_buffer = state->curr_stm->wp - state->curr_stm->rp; |
192 | jpeg_read_header(cinfo, 0); |
193 | state->curr_stm->rp = state->curr_stm->wp - state->cinfo.src->bytes_in_buffer; |
194 | state->curr_stm = state->chain; |
195 | } |
196 | |
197 | cinfo->src->next_input_byte = state->curr_stm->rp; |
198 | cinfo->src->bytes_in_buffer = state->curr_stm->wp - state->curr_stm->rp; |
199 | |
200 | jpeg_read_header(cinfo, 1); |
201 | |
202 | /* default value if ColorTransform is not set */ |
203 | if (state->color_transform == -1) |
204 | { |
205 | if (state->cinfo.num_components == 3) |
206 | state->color_transform = 1; |
207 | else |
208 | state->color_transform = 0; |
209 | } |
210 | |
211 | if (cinfo->saw_Adobe_marker) |
212 | state->color_transform = cinfo->Adobe_transform; |
213 | |
214 | /* Guess the input colorspace, and set output colorspace accordingly */ |
215 | switch (cinfo->num_components) |
216 | { |
217 | case 3: |
218 | if (state->color_transform) |
219 | cinfo->jpeg_color_space = JCS_YCbCr; |
220 | else |
221 | cinfo->jpeg_color_space = JCS_RGB; |
222 | break; |
223 | case 4: |
224 | if (state->color_transform) |
225 | cinfo->jpeg_color_space = JCS_YCCK; |
226 | else |
227 | cinfo->jpeg_color_space = JCS_CMYK; |
228 | break; |
229 | } |
230 | |
231 | cinfo->scale_num = 8/(1<<state->l2factor); |
232 | cinfo->scale_denom = 8; |
233 | |
234 | jpeg_start_decompress(cinfo); |
235 | |
236 | state->stride = cinfo->output_width * cinfo->output_components; |
237 | state->scanline = fz_malloc(ctx, state->stride); |
238 | state->rp = state->scanline; |
239 | state->wp = state->scanline; |
240 | } |
241 | |
242 | while (state->rp < state->wp && p < ep) |
243 | *p++ = *state->rp++; |
244 | |
245 | while (p < ep) |
246 | { |
247 | if (cinfo->output_scanline == cinfo->output_height) |
248 | break; |
249 | |
250 | if (p + state->stride <= ep) |
251 | { |
252 | jpeg_read_scanlines(cinfo, &p, 1); |
253 | p += state->stride; |
254 | } |
255 | else |
256 | { |
257 | jpeg_read_scanlines(cinfo, &state->scanline, 1); |
258 | state->rp = state->scanline; |
259 | state->wp = state->scanline + state->stride; |
260 | } |
261 | |
262 | while (state->rp < state->wp && p < ep) |
263 | *p++ = *state->rp++; |
264 | } |
265 | stm->rp = state->buffer; |
266 | stm->wp = p; |
267 | stm->pos += (p - state->buffer); |
268 | } |
269 | fz_catch(ctx) |
270 | { |
271 | if (cinfo->src) |
272 | state->curr_stm->rp = state->curr_stm->wp - cinfo->src->bytes_in_buffer; |
273 | fz_rethrow(ctx); |
274 | } |
275 | |
276 | if (p == stm->rp) |
277 | return EOF; |
278 | |
279 | return *stm->rp++; |
280 | } |
281 | |
282 | static void |
283 | close_dctd(fz_context *ctx, void *state_) |
284 | { |
285 | fz_dctd *state = (fz_dctd *)state_; |
286 | |
287 | if (state->init) |
288 | { |
289 | /* We call jpeg_abort rather than the more usual |
290 | * jpeg_finish_decompress here. This has the same effect, |
291 | * but doesn't spew warnings if we didn't read enough data etc. |
292 | * Annoyingly jpeg_abort can throw |
293 | */ |
294 | fz_try(ctx) |
295 | jpeg_abort((j_common_ptr)&state->cinfo); |
296 | fz_catch(ctx) |
297 | { |
298 | /* Ignore any errors here */ |
299 | } |
300 | |
301 | jpeg_destroy_decompress(&state->cinfo); |
302 | } |
303 | |
304 | fz_dct_mem_term(&state->cinfo); |
305 | |
306 | if (state->cinfo.src) |
307 | state->curr_stm->rp = state->curr_stm->wp - state->cinfo.src->bytes_in_buffer; |
308 | |
309 | fz_free(ctx, state->scanline); |
310 | fz_drop_stream(ctx, state->chain); |
311 | fz_drop_stream(ctx, state->jpegtables); |
312 | fz_free(ctx, state); |
313 | } |
314 | |
315 | /* Default: color_transform = -1 (unset), l2factor = 0, jpegtables = NULL */ |
316 | fz_stream * |
317 | fz_open_dctd(fz_context *ctx, fz_stream *chain, int color_transform, int l2factor, fz_stream *jpegtables) |
318 | { |
319 | fz_dctd *state = fz_malloc_struct(ctx, fz_dctd); |
320 | j_decompress_ptr cinfo = &state->cinfo; |
321 | |
322 | state->ctx = ctx; |
323 | |
324 | fz_try(ctx) |
325 | fz_dct_mem_init(cinfo, state); |
326 | fz_catch(ctx) |
327 | { |
328 | fz_free(ctx, state); |
329 | fz_rethrow(ctx); |
330 | } |
331 | |
332 | state->color_transform = color_transform; |
333 | state->init = 0; |
334 | state->l2factor = l2factor; |
335 | state->chain = fz_keep_stream(ctx, chain); |
336 | state->jpegtables = fz_keep_stream(ctx, jpegtables); |
337 | state->curr_stm = state->chain; |
338 | |
339 | cinfo->src = NULL; |
340 | cinfo->err = &state->errmgr; |
341 | jpeg_std_error(cinfo->err); |
342 | cinfo->err->error_exit = error_exit_dct; |
343 | |
344 | return fz_new_stream(ctx, state, next_dctd, close_dctd); |
345 | } |
346 | |