Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4680 right-hear 1
#include "fitz.h"
2
#include "mupdf.h"
3
 
4
/* TODO: store JPEG compressed samples */
5
/* TODO: store flate compressed samples */
6
 
7
static fz_error pdf_load_jpx_image(fz_pixmap **imgp, pdf_xref *xref, fz_obj *dict);
8
 
9
static void
10
pdf_mask_color_key(fz_pixmap *pix, int n, int *colorkey)
11
{
12
	unsigned char *p = pix->samples;
13
	int len = pix->w * pix->h;
14
	int k, t;
15
	while (len--)
16
	{
17
		t = 1;
18
		for (k = 0; k < n; k++)
19
			if (p[k] < colorkey[k * 2] || p[k] > colorkey[k * 2 + 1])
20
				t = 0;
21
		if (t)
22
			for (k = 0; k < pix->n; k++)
23
				p[k] = 0;
24
		p += pix->n;
25
	}
26
}
27
 
28
static fz_error
29
pdf_load_image_imp(fz_pixmap **imgp, pdf_xref *xref, fz_obj *rdb, fz_obj *dict, fz_stream *cstm, int forcemask)
30
{
31
	fz_stream *stm;
32
	fz_pixmap *tile;
33
	fz_obj *obj, *res;
34
	fz_error error;
35
 
36
	int w, h, bpc, n;
37
	int imagemask;
38
	int interpolate;
39
	int indexed;
40
	fz_colorspace *colorspace;
41
	fz_pixmap *mask; /* explicit mask/softmask image */
42
	int usecolorkey;
43
	int colorkey[FZ_MAX_COLORS * 2];
44
	float decode[FZ_MAX_COLORS * 2];
45
 
46
	int stride;
47
	unsigned char *samples;
48
	int i, len;
49
 
50
	/* special case for JPEG2000 images */
51
	if (pdf_is_jpx_image(dict))
52
	{
53
		tile = NULL;
54
		error = pdf_load_jpx_image(&tile, xref, dict);
55
		if (error)
56
			return fz_rethrow(error, "cannot load jpx image");
57
		if (forcemask)
58
		{
59
			if (tile->n != 2)
60
			{
61
				fz_drop_pixmap(tile);
62
				return fz_throw("softmask must be grayscale");
63
			}
64
			mask = fz_alpha_from_gray(tile, 1);
65
			fz_drop_pixmap(tile);
66
			*imgp = mask;
67
			return fz_okay;
68
		}
69
		*imgp = tile;
70
		return fz_okay;
71
	}
72
 
73
	w = fz_to_int(fz_dict_getsa(dict, "Width", "W"));
74
	h = fz_to_int(fz_dict_getsa(dict, "Height", "H"));
75
	bpc = fz_to_int(fz_dict_getsa(dict, "BitsPerComponent", "BPC"));
76
	imagemask = fz_to_bool(fz_dict_getsa(dict, "ImageMask", "IM"));
77
	interpolate = fz_to_bool(fz_dict_getsa(dict, "Interpolate", "I"));
78
 
79
	indexed = 0;
80
	usecolorkey = 0;
81
	colorspace = NULL;
82
	mask = NULL;
83
 
84
	if (imagemask)
85
		bpc = 1;
86
 
87
	if (w == 0)
88
		return fz_throw("image width is zero");
89
	if (h == 0)
90
		return fz_throw("image height is zero");
91
	if (bpc == 0)
92
		return fz_throw("image depth is zero");
93
	if (bpc > 16)
94
		return fz_throw("image depth is too large: %d", bpc);
95
	if (w > (1 << 16))
96
		return fz_throw("image is too wide");
97
	if (h > (1 << 16))
98
		return fz_throw("image is too high");
99
 
100
	obj = fz_dict_getsa(dict, "ColorSpace", "CS");
101
	if (obj && !imagemask && !forcemask)
102
	{
103
		/* colorspace resource lookup is only done for inline images */
104
		if (fz_is_name(obj))
105
		{
106
			res = fz_dict_get(fz_dict_gets(rdb, "ColorSpace"), obj);
107
			if (res)
108
				obj = res;
109
		}
110
 
111
		error = pdf_load_colorspace(&colorspace, xref, obj);
112
		if (error)
113
			return fz_rethrow(error, "cannot load image colorspace");
114
 
115
		if (!strcmp(colorspace->name, "Indexed"))
116
			indexed = 1;
117
 
118
		n = colorspace->n;
119
	}
120
	else
121
	{
122
		n = 1;
123
	}
124
 
125
	obj = fz_dict_getsa(dict, "Decode", "D");
126
	if (obj)
127
	{
128
		for (i = 0; i < n * 2; i++)
129
			decode[i] = fz_to_real(fz_array_get(obj, i));
130
	}
131
	else
132
	{
133
		float maxval = indexed ? (1 << bpc) - 1 : 1;
134
		for (i = 0; i < n * 2; i++)
135
			decode[i] = i & 1 ? maxval : 0;
136
	}
137
 
138
	obj = fz_dict_getsa(dict, "SMask", "Mask");
139
	if (fz_is_dict(obj))
140
	{
141
		/* Not allowed for inline images */
142
		if (!cstm)
143
		{
144
			error = pdf_load_image_imp(&mask, xref, rdb, obj, NULL, 1);
145
			if (error)
146
			{
147
				if (colorspace)
148
					fz_drop_colorspace(colorspace);
149
				return fz_rethrow(error, "cannot load image mask/softmask");
150
			}
151
		}
152
	}
153
	else if (fz_is_array(obj))
154
	{
155
		usecolorkey = 1;
156
		for (i = 0; i < n * 2; i++)
157
			colorkey[i] = fz_to_int(fz_array_get(obj, i));
158
	}
159
 
160
	/* Allocate now, to fail early if we run out of memory */
161
	tile = fz_new_pixmap_with_limit(colorspace, w, h);
162
	if (!tile)
163
	{
164
		if (colorspace)
165
			fz_drop_colorspace(colorspace);
166
		if (mask)
167
			fz_drop_pixmap(mask);
168
		return fz_throw("out of memory");
169
	}
170
 
171
	if (colorspace)
172
		fz_drop_colorspace(colorspace);
173
 
174
	tile->mask = mask;
175
	tile->interpolate = interpolate;
176
 
177
	stride = (w * n * bpc + 7) / 8;
178
 
179
	if (cstm)
180
	{
181
		stm = pdf_open_inline_stream(cstm, xref, dict, stride * h);
182
	}
183
	else
184
	{
185
		error = pdf_open_stream(&stm, xref, fz_to_num(dict), fz_to_gen(dict));
186
		if (error)
187
		{
188
			fz_drop_pixmap(tile);
189
			return fz_rethrow(error, "cannot open image data stream (%d 0 R)", fz_to_num(dict));
190
		}
191
	}
192
 
193
	samples = fz_calloc(h, stride);
194
 
195
	len = fz_read(stm, samples, h * stride);
196
	if (len < 0)
197
	{
198
		fz_close(stm);
199
		fz_free(samples);
200
		fz_drop_pixmap(tile);
201
		return fz_rethrow(len, "cannot read image data");
202
	}
203
 
204
	/* Make sure we read the EOF marker (for inline images only) */
205
	if (cstm)
206
	{
207
		unsigned char tbuf[512];
208
		int tlen = fz_read(stm, tbuf, sizeof tbuf);
209
		if (tlen < 0)
210
			fz_catch(tlen, "ignoring error at end of image");
211
		if (tlen > 0)
212
			fz_warn("ignoring garbage at end of image");
213
	}
214
 
215
	fz_close(stm);
216
 
217
	/* Pad truncated images */
218
	if (len < stride * h)
219
	{
220
		fz_warn("padding truncated image (%d 0 R)", fz_to_num(dict));
221
		memset(samples + len, 0, stride * h - len);
222
	}
223
 
224
	/* Invert 1-bit image masks */
225
	if (imagemask)
226
	{
227
		/* 0=opaque and 1=transparent so we need to invert */
228
		unsigned char *p = samples;
229
		len = h * stride;
230
		for (i = 0; i < len; i++)
231
			p[i] = ~p[i];
232
	}
233
 
234
	fz_unpack_tile(tile, samples, n, bpc, stride, indexed);
235
 
236
	fz_free(samples);
237
 
238
	if (usecolorkey)
239
		pdf_mask_color_key(tile, n, colorkey);
240
 
241
	if (indexed)
242
	{
243
		fz_pixmap *conv;
244
		fz_decode_indexed_tile(tile, decode, (1 << bpc) - 1);
245
		conv = pdf_expand_indexed_pixmap(tile);
246
		fz_drop_pixmap(tile);
247
		tile = conv;
248
	}
249
	else
250
	{
251
		fz_decode_tile(tile, decode);
252
	}
253
 
254
	*imgp = tile;
255
	return fz_okay;
256
}
257
 
258
fz_error
259
pdf_load_inline_image(fz_pixmap **pixp, pdf_xref *xref, fz_obj *rdb, fz_obj *dict, fz_stream *file)
260
{
261
	fz_error error;
262
 
263
	error = pdf_load_image_imp(pixp, xref, rdb, dict, file, 0);
264
	if (error)
265
		return fz_rethrow(error, "cannot load inline image");
266
 
267
	return fz_okay;
268
}
269
 
270
int
271
pdf_is_jpx_image(fz_obj *dict)
272
{
273
	fz_obj *filter;
274
	int i;
275
 
276
	filter = fz_dict_gets(dict, "Filter");
277
	if (!strcmp(fz_to_name(filter), "JPXDecode"))
278
		return 1;
279
	for (i = 0; i < fz_array_len(filter); i++)
280
		if (!strcmp(fz_to_name(fz_array_get(filter, i)), "JPXDecode"))
281
			return 1;
282
	return 0;
283
}
284
 
285
static fz_error
286
pdf_load_jpx_image(fz_pixmap **imgp, pdf_xref *xref, fz_obj *dict)
287
{
288
	fz_error error;
289
	fz_buffer *buf;
290
	fz_colorspace *colorspace;
291
	fz_pixmap *img;
292
	fz_obj *obj;
293
 
294
	colorspace = NULL;
295
 
296
	error = pdf_load_stream(&buf, xref, fz_to_num(dict), fz_to_gen(dict));
297
	if (error)
298
		return fz_rethrow(error, "cannot load jpx image data");
299
 
300
	obj = fz_dict_gets(dict, "ColorSpace");
301
	if (obj)
302
	{
303
		error = pdf_load_colorspace(&colorspace, xref, obj);
304
		if (error)
305
			fz_catch(error, "cannot load image colorspace");
306
	}
307
 
308
	error = fz_load_jpx_image(&img, buf->data, buf->len, colorspace);
309
	if (error)
310
	{
311
		if (colorspace)
312
			fz_drop_colorspace(colorspace);
313
		fz_drop_buffer(buf);
314
		return fz_rethrow(error, "cannot load jpx image");
315
	}
316
 
317
	if (colorspace)
318
		fz_drop_colorspace(colorspace);
319
	fz_drop_buffer(buf);
320
 
321
	obj = fz_dict_getsa(dict, "SMask", "Mask");
322
	if (fz_is_dict(obj))
323
	{
324
		error = pdf_load_image_imp(&img->mask, xref, NULL, obj, NULL, 1);
325
		if (error)
326
		{
327
			fz_drop_pixmap(img);
328
			return fz_rethrow(error, "cannot load image mask/softmask");
329
		}
330
	}
331
 
332
	*imgp = img;
333
	return fz_okay;
334
}
335
 
336
fz_error
337
pdf_load_image(fz_pixmap **pixp, pdf_xref *xref, fz_obj *dict)
338
{
339
	fz_error error;
340
 
341
	if ((*pixp = pdf_find_item(xref->store, fz_drop_pixmap, dict)))
342
	{
343
		fz_keep_pixmap(*pixp);
344
		return fz_okay;
345
	}
346
 
347
	error = pdf_load_image_imp(pixp, xref, NULL, dict, NULL, 0);
348
	if (error)
349
		return fz_rethrow(error, "cannot load image (%d 0 R)", fz_to_num(dict));
350
 
351
	pdf_store_item(xref->store, fz_keep_pixmap, fz_drop_pixmap, dict, *pixp);
352
 
353
	return fz_okay;
354
}