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