Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7643 views
1
#include "mupdf/fitz.h"
2
3
#include <jpeglib.h>
4
5
#ifdef SHARE_JPEG
6
7
#define JZ_CTX_FROM_CINFO(c) (fz_context *)(c->client_data)
8
9
#define fz_jpg_mem_init(ctx, cinfo)
10
#define fz_jpg_mem_term(cinfo)
11
12
#else /* SHARE_JPEG */
13
14
typedef void * backing_store_ptr;
15
#include "jmemcust.h"
16
17
#define JZ_CTX_FROM_CINFO(c) (fz_context *)(GET_CUST_MEM_DATA(c)->priv)
18
19
static void *
20
fz_jpg_mem_alloc(j_common_ptr cinfo, size_t size)
21
{
22
fz_context *ctx = JZ_CTX_FROM_CINFO(cinfo);
23
return fz_malloc(ctx, size);
24
}
25
26
static void
27
fz_jpg_mem_free(j_common_ptr cinfo, void *object, size_t size)
28
{
29
fz_context *ctx = JZ_CTX_FROM_CINFO(cinfo);
30
UNUSED(size);
31
fz_free(ctx, object);
32
}
33
34
static void
35
fz_jpg_mem_init(fz_context *ctx, struct jpeg_decompress_struct *cinfo)
36
{
37
jpeg_cust_mem_data *custmptr;
38
39
custmptr = fz_malloc_struct(ctx, jpeg_cust_mem_data);
40
41
if (!jpeg_cust_mem_init(custmptr, (void *) ctx, NULL, NULL, NULL,
42
fz_jpg_mem_alloc, fz_jpg_mem_free,
43
fz_jpg_mem_alloc, fz_jpg_mem_free, NULL))
44
{
45
fz_free(ctx, custmptr);
46
fz_throw(ctx, FZ_ERROR_GENERIC, "cannot initialize custom JPEG memory handler");
47
}
48
49
cinfo->client_data = custmptr;
50
}
51
52
static void
53
fz_jpg_mem_term(struct jpeg_decompress_struct *cinfo)
54
{
55
if(cinfo->client_data)
56
{
57
fz_context *ctx = JZ_CTX_FROM_CINFO(cinfo);
58
fz_free(ctx, cinfo->client_data);
59
cinfo->client_data = NULL;
60
}
61
}
62
63
#endif /* SHARE_JPEG */
64
65
static void error_exit(j_common_ptr cinfo)
66
{
67
char msg[JMSG_LENGTH_MAX];
68
fz_context *ctx = (fz_context *)cinfo->client_data;
69
70
cinfo->err->format_message(cinfo, msg);
71
fz_throw(ctx, FZ_ERROR_GENERIC, "jpeg error: %s", msg);
72
}
73
74
static void init_source(j_decompress_ptr cinfo)
75
{
76
/* nothing to do */
77
}
78
79
static void term_source(j_decompress_ptr cinfo)
80
{
81
/* nothing to do */
82
}
83
84
static boolean fill_input_buffer(j_decompress_ptr cinfo)
85
{
86
static unsigned char eoi[2] = { 0xFF, JPEG_EOI };
87
struct jpeg_source_mgr *src = cinfo->src;
88
src->next_input_byte = eoi;
89
src->bytes_in_buffer = 2;
90
return 1;
91
}
92
93
static void skip_input_data(j_decompress_ptr cinfo, long num_bytes)
94
{
95
struct jpeg_source_mgr *src = cinfo->src;
96
if (num_bytes > 0)
97
{
98
size_t skip = (size_t)num_bytes; /* size_t may be 64bit */
99
if (skip > src->bytes_in_buffer)
100
skip = (size_t)src->bytes_in_buffer;
101
src->next_input_byte += skip;
102
src->bytes_in_buffer -= skip;
103
}
104
}
105
106
static inline int read_value(const unsigned char *data, int bytes, int is_big_endian)
107
{
108
int value = 0;
109
if (!is_big_endian)
110
data += bytes;
111
for (; bytes > 0; bytes--)
112
value = (value << 8) | (is_big_endian ? *data++ : *--data);
113
return value;
114
}
115
116
static int extract_exif_resolution(jpeg_saved_marker_ptr marker, int *xres, int *yres)
117
{
118
int is_big_endian;
119
const unsigned char *data;
120
unsigned int offset, ifd_len, res_type = 0;
121
float x_res = 0, y_res = 0;
122
123
if (!marker || marker->marker != JPEG_APP0 + 1 || marker->data_length < 14)
124
return 0;
125
data = (const unsigned char *)marker->data;
126
if (read_value(data, 4, 1) != 0x45786966 /* Exif */ || read_value(data + 4, 2, 1) != 0x0000)
127
return 0;
128
if (read_value(data + 6, 4, 1) == 0x49492A00)
129
is_big_endian = 0;
130
else if (read_value(data + 6, 4, 1) == 0x4D4D002A)
131
is_big_endian = 1;
132
else
133
return 0;
134
135
offset = read_value(data + 10, 4, is_big_endian) + 6;
136
if (offset < 14 || offset > marker->data_length - 2)
137
return 0;
138
ifd_len = read_value(data + offset, 2, is_big_endian);
139
for (offset += 2; ifd_len > 0 && offset + 12 < marker->data_length; ifd_len--, offset += 12)
140
{
141
int tag = read_value(data + offset, 2, is_big_endian);
142
int type = read_value(data + offset + 2, 2, is_big_endian);
143
int count = read_value(data + offset + 4, 4, is_big_endian);
144
unsigned int value_off = read_value(data + offset + 8, 4, is_big_endian) + 6;
145
switch (tag)
146
{
147
case 0x11A:
148
if (type == 5 && value_off > offset && value_off <= marker->data_length - 8)
149
x_res = 1.0f * read_value(data + value_off, 4, is_big_endian) / read_value(data + value_off + 4, 4, is_big_endian);
150
break;
151
case 0x11B:
152
if (type == 5 && value_off > offset && value_off <= marker->data_length - 8)
153
y_res = 1.0f * read_value(data + value_off, 4, is_big_endian) / read_value(data + value_off + 4, 4, is_big_endian);
154
break;
155
case 0x128:
156
if (type == 3 && count == 1)
157
res_type = read_value(data + offset + 8, 2, is_big_endian);
158
break;
159
}
160
}
161
162
if (x_res <= 0 || x_res > INT_MAX || y_res <= 0 || y_res > INT_MAX)
163
return 0;
164
if (res_type == 2)
165
{
166
*xres = (int)x_res;
167
*yres = (int)y_res;
168
}
169
else if (res_type == 3)
170
{
171
*xres = (int)(x_res * 254 / 100);
172
*yres = (int)(y_res * 254 / 100);
173
}
174
else
175
{
176
*xres = 0;
177
*yres = 0;
178
}
179
return 1;
180
}
181
182
static int extract_app13_resolution(jpeg_saved_marker_ptr marker, int *xres, int *yres)
183
{
184
const unsigned char *data, *data_end;
185
186
if (!marker || marker->marker != JPEG_APP0 + 13 || marker->data_length < 42 ||
187
strcmp((const char *)marker->data, "Photoshop 3.0") != 0)
188
{
189
return 0;
190
}
191
192
data = (const unsigned char *)marker->data;
193
data_end = data + marker->data_length;
194
for (data += 14; data + 12 < data_end; ) {
195
int data_size = -1;
196
int tag = read_value(data + 4, 2, 1);
197
int value_off = 11 + read_value(data + 6, 2, 1);
198
if (value_off % 2 == 1)
199
value_off++;
200
if (read_value(data, 4, 1) == 0x3842494D /* 8BIM */ && value_off <= data_end - data)
201
data_size = read_value(data + value_off - 4, 4, 1);
202
if (data_size < 0 || data_size > data_end - data - value_off)
203
return 0;
204
if (tag == 0x3ED && data_size == 16)
205
{
206
*xres = read_value(data + value_off, 2, 1);
207
*yres = read_value(data + value_off + 8, 2, 1);
208
return 1;
209
}
210
if (data_size % 2 == 1)
211
data_size++;
212
data += value_off + data_size;
213
}
214
215
return 0;
216
}
217
218
void
219
fz_load_jpeg_info(fz_context *ctx, unsigned char *rbuf, int rlen, int *xp, int *yp, int *xresp, int *yresp, fz_colorspace **cspacep)
220
{
221
struct jpeg_decompress_struct cinfo;
222
struct jpeg_error_mgr err;
223
struct jpeg_source_mgr src;
224
225
fz_try(ctx)
226
{
227
cinfo.client_data = ctx;
228
cinfo.err = jpeg_std_error(&err);
229
err.error_exit = error_exit;
230
231
fz_jpg_mem_init(ctx, &cinfo);
232
233
jpeg_create_decompress(&cinfo);
234
235
cinfo.src = &src;
236
src.init_source = init_source;
237
src.fill_input_buffer = fill_input_buffer;
238
src.skip_input_data = skip_input_data;
239
src.resync_to_restart = jpeg_resync_to_restart;
240
src.term_source = term_source;
241
src.next_input_byte = rbuf;
242
src.bytes_in_buffer = rlen;
243
244
jpeg_save_markers(&cinfo, JPEG_APP0+1, 0xffff);
245
jpeg_save_markers(&cinfo, JPEG_APP0+13, 0xffff);
246
247
jpeg_read_header(&cinfo, 1);
248
249
if (cinfo.num_components == 1)
250
*cspacep = fz_device_gray(ctx);
251
else if (cinfo.num_components == 3)
252
*cspacep = fz_device_rgb(ctx);
253
else if (cinfo.num_components == 4)
254
*cspacep = fz_device_cmyk(ctx);
255
else
256
fz_throw(ctx, FZ_ERROR_GENERIC, "bad number of components in jpeg: %d", cinfo.num_components);
257
258
*xp = cinfo.image_width;
259
*yp = cinfo.image_height;
260
261
if (extract_exif_resolution(cinfo.marker_list, xresp, yresp))
262
/* XPS prefers EXIF resolution to JFIF density */;
263
else if (extract_app13_resolution(cinfo.marker_list, xresp, yresp))
264
/* XPS prefers APP13 resolution to JFIF density */;
265
else if (cinfo.density_unit == 1)
266
{
267
*xresp = cinfo.X_density;
268
*yresp = cinfo.Y_density;
269
}
270
else if (cinfo.density_unit == 2)
271
{
272
*xresp = cinfo.X_density * 254 / 100;
273
*yresp = cinfo.Y_density * 254 / 100;
274
}
275
else
276
{
277
*xresp = 0;
278
*yresp = 0;
279
}
280
281
if (*xresp <= 0) *xresp = 96;
282
if (*yresp <= 0) *yresp = 96;
283
}
284
fz_always(ctx)
285
{
286
jpeg_destroy_decompress(&cinfo);
287
fz_jpg_mem_term(&cinfo);
288
}
289
fz_catch(ctx)
290
{
291
fz_rethrow(ctx);
292
}
293
}
294
295