Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7643 views
1
#include "mupdf/pdf.h"
2
3
static fz_image *pdf_load_jpx(fz_context *ctx, pdf_document *doc, pdf_obj *dict, int forcemask);
4
5
static fz_image *
6
pdf_load_image_imp(fz_context *ctx, pdf_document *doc, pdf_obj *rdb, pdf_obj *dict, fz_stream *cstm, int forcemask)
7
{
8
fz_stream *stm = NULL;
9
fz_image *image = NULL;
10
pdf_obj *obj, *res;
11
12
int w, h, bpc, n;
13
int imagemask;
14
int interpolate;
15
int indexed;
16
fz_image *mask = NULL; /* explicit mask/soft mask image */
17
int usecolorkey = 0;
18
fz_colorspace *colorspace = NULL;
19
float decode[FZ_MAX_COLORS * 2];
20
int colorkey[FZ_MAX_COLORS * 2];
21
int stride;
22
23
int i;
24
fz_compressed_buffer *buffer;
25
26
fz_var(stm);
27
fz_var(mask);
28
fz_var(image);
29
fz_var(colorspace);
30
31
fz_try(ctx)
32
{
33
/* special case for JPEG2000 images */
34
if (pdf_is_jpx_image(ctx, dict))
35
{
36
image = pdf_load_jpx(ctx, doc, dict, forcemask);
37
38
if (forcemask)
39
{
40
fz_pixmap *mask_pixmap;
41
if (image->n != 2)
42
{
43
fz_pixmap *gray;
44
fz_irect bbox;
45
fz_warn(ctx, "soft mask should be grayscale");
46
gray = fz_new_pixmap_with_bbox(ctx, fz_device_gray(ctx), fz_pixmap_bbox(ctx, image->tile, &bbox));
47
fz_convert_pixmap(ctx, gray, image->tile);
48
fz_drop_pixmap(ctx, image->tile);
49
image->tile = gray;
50
}
51
mask_pixmap = fz_alpha_from_gray(ctx, image->tile, 1);
52
fz_drop_pixmap(ctx, image->tile);
53
image->tile = mask_pixmap;
54
}
55
break; /* Out of fz_try */
56
}
57
58
w = pdf_to_int(ctx, pdf_dict_geta(ctx, dict, PDF_NAME_Width, PDF_NAME_W));
59
h = pdf_to_int(ctx, pdf_dict_geta(ctx, dict, PDF_NAME_Height, PDF_NAME_H));
60
bpc = pdf_to_int(ctx, pdf_dict_geta(ctx, dict, PDF_NAME_BitsPerComponent, PDF_NAME_BPC));
61
if (bpc == 0)
62
bpc = 8;
63
imagemask = pdf_to_bool(ctx, pdf_dict_geta(ctx, dict, PDF_NAME_ImageMask, PDF_NAME_IM));
64
interpolate = pdf_to_bool(ctx, pdf_dict_geta(ctx, dict, PDF_NAME_Interpolate, PDF_NAME_I));
65
66
indexed = 0;
67
usecolorkey = 0;
68
69
if (imagemask)
70
bpc = 1;
71
72
if (w <= 0)
73
fz_throw(ctx, FZ_ERROR_GENERIC, "image width is zero (or less)");
74
if (h <= 0)
75
fz_throw(ctx, FZ_ERROR_GENERIC, "image height is zero (or less)");
76
if (bpc <= 0)
77
fz_throw(ctx, FZ_ERROR_GENERIC, "image depth is zero (or less)");
78
if (bpc > 16)
79
fz_throw(ctx, FZ_ERROR_GENERIC, "image depth is too large: %d", bpc);
80
if (w > (1 << 16))
81
fz_throw(ctx, FZ_ERROR_GENERIC, "image is too wide");
82
if (h > (1 << 16))
83
fz_throw(ctx, FZ_ERROR_GENERIC, "image is too high");
84
85
obj = pdf_dict_geta(ctx, dict, PDF_NAME_ColorSpace, PDF_NAME_CS);
86
if (obj && !imagemask && !forcemask)
87
{
88
/* colorspace resource lookup is only done for inline images */
89
if (pdf_is_name(ctx, obj))
90
{
91
res = pdf_dict_get(ctx, pdf_dict_get(ctx, rdb, PDF_NAME_ColorSpace), obj);
92
if (res)
93
obj = res;
94
}
95
96
colorspace = pdf_load_colorspace(ctx, doc, obj);
97
indexed = fz_colorspace_is_indexed(ctx, colorspace);
98
99
n = colorspace->n;
100
}
101
else
102
{
103
n = 1;
104
}
105
106
obj = pdf_dict_geta(ctx, dict, PDF_NAME_Decode, PDF_NAME_D);
107
if (obj)
108
{
109
for (i = 0; i < n * 2; i++)
110
decode[i] = pdf_to_real(ctx, pdf_array_get(ctx, obj, i));
111
}
112
else
113
{
114
float maxval = indexed ? (1 << bpc) - 1 : 1;
115
for (i = 0; i < n * 2; i++)
116
decode[i] = i & 1 ? maxval : 0;
117
}
118
119
obj = pdf_dict_geta(ctx, dict, PDF_NAME_SMask, PDF_NAME_Mask);
120
if (pdf_is_dict(ctx, obj))
121
{
122
/* Not allowed for inline images or soft masks */
123
if (cstm)
124
fz_warn(ctx, "Ignoring invalid inline image soft mask");
125
else if (forcemask)
126
fz_warn(ctx, "Ignoring recursive image soft mask");
127
else
128
{
129
mask = pdf_load_image_imp(ctx, doc, rdb, obj, NULL, 1);
130
obj = pdf_dict_get(ctx, obj, PDF_NAME_Matte);
131
if (pdf_is_array(ctx, obj))
132
{
133
usecolorkey = 1;
134
for (i = 0; i < n; i++)
135
colorkey[i] = pdf_to_real(ctx, pdf_array_get(ctx, obj, i)) * 255;
136
}
137
}
138
}
139
else if (pdf_is_array(ctx, obj))
140
{
141
usecolorkey = 1;
142
for (i = 0; i < n * 2; i++)
143
{
144
if (!pdf_is_int(ctx, pdf_array_get(ctx, obj, i)))
145
{
146
fz_warn(ctx, "invalid value in color key mask");
147
usecolorkey = 0;
148
}
149
colorkey[i] = pdf_to_int(ctx, pdf_array_get(ctx, obj, i));
150
}
151
}
152
153
/* Do we load from a ref, or do we load an inline stream? */
154
if (cstm == NULL)
155
{
156
/* Just load the compressed image data now and we can
157
* decode it on demand. */
158
int num = pdf_to_num(ctx, dict);
159
int gen = pdf_to_gen(ctx, dict);
160
buffer = pdf_load_compressed_stream(ctx, doc, num, gen);
161
image = fz_new_image(ctx, w, h, bpc, colorspace, 96, 96, interpolate, imagemask, decode, usecolorkey ? colorkey : NULL, buffer, mask);
162
}
163
else
164
{
165
/* Inline stream */
166
stride = (w * n * bpc + 7) / 8;
167
image = fz_new_image(ctx, w, h, bpc, colorspace, 96, 96, interpolate, imagemask, decode, usecolorkey ? colorkey : NULL, NULL, mask);
168
pdf_load_compressed_inline_image(ctx, doc, dict, stride * h, cstm, indexed, image);
169
}
170
171
}
172
fz_catch(ctx)
173
{
174
fz_drop_colorspace(ctx, colorspace);
175
fz_drop_image(ctx, mask);
176
fz_drop_image(ctx, image);
177
fz_rethrow(ctx);
178
}
179
return image;
180
}
181
182
fz_image *
183
pdf_load_inline_image(fz_context *ctx, pdf_document *doc, pdf_obj *rdb, pdf_obj *dict, fz_stream *file)
184
{
185
return pdf_load_image_imp(ctx, doc, rdb, dict, file, 0);
186
}
187
188
int
189
pdf_is_jpx_image(fz_context *ctx, pdf_obj *dict)
190
{
191
pdf_obj *filter;
192
int i, n;
193
194
filter = pdf_dict_get(ctx, dict, PDF_NAME_Filter);
195
if (pdf_name_eq(ctx, filter, PDF_NAME_JPXDecode))
196
return 1;
197
n = pdf_array_len(ctx, filter);
198
for (i = 0; i < n; i++)
199
if (pdf_name_eq(ctx, pdf_array_get(ctx, filter, i), PDF_NAME_JPXDecode))
200
return 1;
201
return 0;
202
}
203
204
static fz_image *
205
pdf_load_jpx(fz_context *ctx, pdf_document *doc, pdf_obj *dict, int forcemask)
206
{
207
fz_buffer *buf = NULL;
208
fz_colorspace *colorspace = NULL;
209
fz_pixmap *pix = NULL;
210
pdf_obj *obj;
211
int indexed = 0;
212
fz_image *mask = NULL;
213
fz_image *img = NULL;
214
215
fz_var(pix);
216
fz_var(buf);
217
fz_var(colorspace);
218
fz_var(mask);
219
220
buf = pdf_load_stream(ctx, doc, pdf_to_num(ctx, dict), pdf_to_gen(ctx, dict));
221
222
/* FIXME: We can't handle decode arrays for indexed images currently */
223
fz_try(ctx)
224
{
225
obj = pdf_dict_get(ctx, dict, PDF_NAME_ColorSpace);
226
if (obj)
227
{
228
colorspace = pdf_load_colorspace(ctx, doc, obj);
229
indexed = fz_colorspace_is_indexed(ctx, colorspace);
230
}
231
232
pix = fz_load_jpx(ctx, buf->data, buf->len, colorspace, indexed);
233
234
obj = pdf_dict_geta(ctx, dict, PDF_NAME_SMask, PDF_NAME_Mask);
235
if (pdf_is_dict(ctx, obj))
236
{
237
if (forcemask)
238
fz_warn(ctx, "Ignoring recursive JPX soft mask");
239
else
240
mask = pdf_load_image_imp(ctx, doc, NULL, obj, NULL, 1);
241
}
242
243
obj = pdf_dict_geta(ctx, dict, PDF_NAME_Decode, PDF_NAME_D);
244
if (obj && !indexed)
245
{
246
float decode[FZ_MAX_COLORS * 2];
247
int i;
248
249
for (i = 0; i < pix->n * 2; i++)
250
decode[i] = pdf_to_real(ctx, pdf_array_get(ctx, obj, i));
251
252
fz_decode_tile(ctx, pix, decode);
253
}
254
255
img = fz_new_image_from_pixmap(ctx, pix, mask);
256
}
257
fz_always(ctx)
258
{
259
fz_drop_colorspace(ctx, colorspace);
260
fz_drop_buffer(ctx, buf);
261
fz_drop_pixmap(ctx, pix);
262
}
263
fz_catch(ctx)
264
{
265
fz_rethrow(ctx);
266
}
267
268
return img;
269
}
270
271
static int
272
fz_image_size(fz_context *ctx, fz_image *im)
273
{
274
if (im == NULL)
275
return 0;
276
return sizeof(*im) + fz_pixmap_size(ctx, im->tile) + (im->buffer && im->buffer->buffer ? im->buffer->buffer->cap : 0);
277
}
278
279
fz_image *
280
pdf_load_image(fz_context *ctx, pdf_document *doc, pdf_obj *dict)
281
{
282
fz_image *image;
283
284
if ((image = pdf_find_item(ctx, fz_drop_image_imp, dict)) != NULL)
285
{
286
return (fz_image *)image;
287
}
288
289
image = pdf_load_image_imp(ctx, doc, NULL, dict, NULL, 0);
290
291
pdf_store_item(ctx, dict, image, fz_image_size(ctx, image));
292
293
return (fz_image *)image;
294
}
295
296