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
/* ICCBased */
5
 
6
static fz_error
7
load_icc_based(fz_colorspace **csp, pdf_xref *xref, fz_obj *dict)
8
{
9
	int n;
10
 
11
	n = fz_to_int(fz_dict_gets(dict, "N"));
12
 
13
	switch (n)
14
	{
15
	case 1: *csp = fz_device_gray; return fz_okay;
16
	case 3: *csp = fz_device_rgb; return fz_okay;
17
	case 4: *csp = fz_device_cmyk; return fz_okay;
18
	}
19
 
20
	return fz_throw("syntaxerror: ICCBased must have 1, 3 or 4 components");
21
}
22
 
23
/* Lab */
24
 
25
static inline float fung(float x)
26
{
27
	if (x >= 6.0f / 29.0f)
28
		return x * x * x;
29
	return (108.0f / 841.0f) * (x - (4.0f / 29.0f));
30
}
31
 
32
static void
33
lab_to_rgb(fz_colorspace *cs, float *lab, float *rgb)
34
{
35
	/* input is in range (0..100, -128..127, -128..127) not (0..1, 0..1, 0..1) */
36
	float lstar, astar, bstar, l, m, n, x, y, z, r, g, b;
37
	lstar = lab[0];
38
	astar = lab[1];
39
	bstar = lab[2];
40
	m = (lstar + 16) / 116;
41
	l = m + astar / 500;
42
	n = m - bstar / 200;
43
	x = fung(l);
44
	y = fung(m);
45
	z = fung(n);
46
	r = (3.240449f * x + -1.537136f * y + -0.498531f * z) * 0.830026f;
47
	g = (-0.969265f * x + 1.876011f * y + 0.041556f * z) * 1.05452f;
48
	b = (0.055643f * x + -0.204026f * y + 1.057229f * z) * 1.1003f;
49
	rgb[0] = sqrtf(CLAMP(r, 0, 1));
50
	rgb[1] = sqrtf(CLAMP(g, 0, 1));
51
	rgb[2] = sqrtf(CLAMP(b, 0, 1));
52
}
53
 
54
static void
55
rgb_to_lab(fz_colorspace *cs, float *rgb, float *lab)
56
{
57
	fz_warn("cannot convert into L*a*b colorspace");
58
	lab[0] = rgb[0];
59
	lab[1] = rgb[1];
60
	lab[2] = rgb[2];
61
}
62
 
63
static fz_colorspace k_device_lab = { -1, "Lab", 3, lab_to_rgb, rgb_to_lab };
64
static fz_colorspace *fz_device_lab = &k_device_lab;
65
 
66
/* Separation and DeviceN */
67
 
68
struct separation
69
{
70
	fz_colorspace *base;
71
	pdf_function *tint;
72
};
73
 
74
static void
75
separation_to_rgb(fz_colorspace *cs, float *color, float *rgb)
76
{
77
	struct separation *sep = cs->data;
78
	float alt[FZ_MAX_COLORS];
79
	pdf_eval_function(sep->tint, color, cs->n, alt, sep->base->n);
80
	sep->base->to_rgb(sep->base, alt, rgb);
81
}
82
 
83
static void
84
free_separation(fz_colorspace *cs)
85
{
86
	struct separation *sep = cs->data;
87
	fz_drop_colorspace(sep->base);
88
	pdf_drop_function(sep->tint);
89
	fz_free(sep);
90
}
91
 
92
static fz_error
93
load_separation(fz_colorspace **csp, pdf_xref *xref, fz_obj *array)
94
{
95
	fz_error error;
96
	fz_colorspace *cs;
97
	struct separation *sep;
98
	fz_obj *nameobj = fz_array_get(array, 1);
99
	fz_obj *baseobj = fz_array_get(array, 2);
100
	fz_obj *tintobj = fz_array_get(array, 3);
101
	fz_colorspace *base;
102
	pdf_function *tint;
103
	int n;
104
 
105
	if (fz_is_array(nameobj))
106
		n = fz_array_len(nameobj);
107
	else
108
		n = 1;
109
 
110
	if (n > FZ_MAX_COLORS)
111
		return fz_throw("too many components in colorspace");
112
 
113
	error = pdf_load_colorspace(&base, xref, baseobj);
114
	if (error)
115
		return fz_rethrow(error, "cannot load base colorspace (%d %d R)", fz_to_num(baseobj), fz_to_gen(baseobj));
116
 
117
	error = pdf_load_function(&tint, xref, tintobj);
118
	if (error)
119
	{
120
		fz_drop_colorspace(base);
121
		return fz_rethrow(error, "cannot load tint function (%d %d R)", fz_to_num(tintobj), fz_to_gen(tintobj));
122
	}
123
 
124
	sep = fz_malloc(sizeof(struct separation));
125
	sep->base = base;
126
	sep->tint = tint;
127
 
128
	cs = fz_new_colorspace(n == 1 ? "Separation" : "DeviceN", n);
129
	cs->to_rgb = separation_to_rgb;
130
	cs->free_data = free_separation;
131
	cs->data = sep;
132
 
133
	*csp = cs;
134
	return fz_okay;
135
}
136
 
137
/* Indexed */
138
 
139
struct indexed
140
{
141
	fz_colorspace *base;
142
	int high;
143
	unsigned char *lookup;
144
};
145
 
146
static void
147
indexed_to_rgb(fz_colorspace *cs, float *color, float *rgb)
148
{
149
	struct indexed *idx = cs->data;
150
	float alt[FZ_MAX_COLORS];
151
	int i, k;
152
	i = color[0] * 255;
153
	i = CLAMP(i, 0, idx->high);
154
	for (k = 0; k < idx->base->n; k++)
155
		alt[k] = idx->lookup[i * idx->base->n + k] / 255.0f;
156
	idx->base->to_rgb(idx->base, alt, rgb);
157
}
158
 
159
static void
160
free_indexed(fz_colorspace *cs)
161
{
162
	struct indexed *idx = cs->data;
163
	if (idx->base)
164
		fz_drop_colorspace(idx->base);
165
	fz_free(idx->lookup);
166
	fz_free(idx);
167
}
168
 
169
fz_pixmap *
170
pdf_expand_indexed_pixmap(fz_pixmap *src)
171
{
172
	struct indexed *idx;
173
	fz_pixmap *dst;
174
	unsigned char *s, *d;
175
	int y, x, k, n, high;
176
	unsigned char *lookup;
177
 
178
	assert(src->colorspace->to_rgb == indexed_to_rgb);
179
	assert(src->n == 2);
180
 
181
	idx = src->colorspace->data;
182
	high = idx->high;
183
	lookup = idx->lookup;
184
	n = idx->base->n;
185
 
186
	dst = fz_new_pixmap_with_rect(idx->base, fz_bound_pixmap(src));
187
	s = src->samples;
188
	d = dst->samples;
189
 
190
	for (y = 0; y < src->h; y++)
191
	{
192
		for (x = 0; x < src->w; x++)
193
		{
194
			int v = *s++;
195
			int a = *s++;
196
			v = MIN(v, high);
197
			for (k = 0; k < n; k++)
198
				*d++ = fz_mul255(lookup[v * n + k], a);
199
			*d++ = a;
200
		}
201
	}
202
 
203
	if (src->mask)
204
		dst->mask = fz_keep_pixmap(src->mask);
205
	dst->interpolate = src->interpolate;
206
 
207
	return dst;
208
}
209
 
210
static fz_error
211
load_indexed(fz_colorspace **csp, pdf_xref *xref, fz_obj *array)
212
{
213
	fz_error error;
214
	fz_colorspace *cs;
215
	struct indexed *idx;
216
	fz_obj *baseobj = fz_array_get(array, 1);
217
	fz_obj *highobj = fz_array_get(array, 2);
218
	fz_obj *lookup = fz_array_get(array, 3);
219
	fz_colorspace *base;
220
	int i, n;
221
 
222
	error = pdf_load_colorspace(&base, xref, baseobj);
223
	if (error)
224
		return fz_rethrow(error, "cannot load base colorspace (%d %d R)", fz_to_num(baseobj), fz_to_gen(baseobj));
225
 
226
	idx = fz_malloc(sizeof(struct indexed));
227
	idx->base = base;
228
	idx->high = fz_to_int(highobj);
229
	idx->high = CLAMP(idx->high, 0, 255);
230
	n = base->n * (idx->high + 1);
231
	idx->lookup = fz_malloc(n);
232
	memset(idx->lookup, 0, n);
233
 
234
	cs = fz_new_colorspace("Indexed", 1);
235
	cs->to_rgb = indexed_to_rgb;
236
	cs->free_data = free_indexed;
237
	cs->data = idx;
238
 
239
	if (fz_is_string(lookup) && fz_to_str_len(lookup) == n)
240
	{
241
		unsigned char *buf = (unsigned char *) fz_to_str_buf(lookup);
242
		for (i = 0; i < n; i++)
243
			idx->lookup[i] = buf[i];
244
	}
245
	else if (fz_is_indirect(lookup))
246
	{
247
		fz_stream *file;
248
 
249
		error = pdf_open_stream(&file, xref, fz_to_num(lookup), fz_to_gen(lookup));
250
		if (error)
251
		{
252
			fz_drop_colorspace(cs);
253
			return fz_rethrow(error, "cannot open colorspace lookup table (%d 0 R)", fz_to_num(lookup));
254
		}
255
 
256
		i = fz_read(file, idx->lookup, n);
257
		if (i < 0)
258
		{
259
			fz_drop_colorspace(cs);
260
			return fz_throw("cannot read colorspace lookup table (%d 0 R)", fz_to_num(lookup));
261
		}
262
 
263
		fz_close(file);
264
	}
265
	else
266
	{
267
		fz_drop_colorspace(cs);
268
		return fz_throw("cannot parse colorspace lookup table");
269
	}
270
 
271
	*csp = cs;
272
	return fz_okay;
273
}
274
 
275
/* Parse and create colorspace from PDF object */
276
 
277
static fz_error
278
pdf_load_colorspace_imp(fz_colorspace **csp, pdf_xref *xref, fz_obj *obj)
279
{
280
	if (fz_is_name(obj))
281
	{
282
		if (!strcmp(fz_to_name(obj), "Pattern"))
283
			*csp = fz_device_gray;
284
		else if (!strcmp(fz_to_name(obj), "G"))
285
			*csp = fz_device_gray;
286
		else if (!strcmp(fz_to_name(obj), "RGB"))
287
			*csp = fz_device_rgb;
288
		else if (!strcmp(fz_to_name(obj), "CMYK"))
289
			*csp = fz_device_cmyk;
290
		else if (!strcmp(fz_to_name(obj), "DeviceGray"))
291
			*csp = fz_device_gray;
292
		else if (!strcmp(fz_to_name(obj), "DeviceRGB"))
293
			*csp = fz_device_rgb;
294
		else if (!strcmp(fz_to_name(obj), "DeviceCMYK"))
295
			*csp = fz_device_cmyk;
296
		else
297
			return fz_throw("unknown colorspace: %s", fz_to_name(obj));
298
		return fz_okay;
299
	}
300
 
301
	else if (fz_is_array(obj))
302
	{
303
		fz_obj *name = fz_array_get(obj, 0);
304
 
305
		if (fz_is_name(name))
306
		{
307
			/* load base colorspace instead */
308
			if (!strcmp(fz_to_name(name), "Pattern"))
309
			{
310
				fz_error error;
311
 
312
				obj = fz_array_get(obj, 1);
313
				if (!obj)
314
				{
315
					*csp = fz_device_gray;
316
					return fz_okay;
317
				}
318
 
319
				error = pdf_load_colorspace(csp, xref, obj);
320
				if (error)
321
					return fz_rethrow(error, "cannot load pattern (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
322
			}
323
 
324
			else if (!strcmp(fz_to_name(name), "G"))
325
				*csp = fz_device_gray;
326
			else if (!strcmp(fz_to_name(name), "RGB"))
327
				*csp = fz_device_rgb;
328
			else if (!strcmp(fz_to_name(name), "CMYK"))
329
				*csp = fz_device_cmyk;
330
			else if (!strcmp(fz_to_name(name), "DeviceGray"))
331
				*csp = fz_device_gray;
332
			else if (!strcmp(fz_to_name(name), "DeviceRGB"))
333
				*csp = fz_device_rgb;
334
			else if (!strcmp(fz_to_name(name), "DeviceCMYK"))
335
				*csp = fz_device_cmyk;
336
			else if (!strcmp(fz_to_name(name), "CalGray"))
337
				*csp = fz_device_gray;
338
			else if (!strcmp(fz_to_name(name), "CalRGB"))
339
				*csp = fz_device_rgb;
340
			else if (!strcmp(fz_to_name(name), "CalCMYK"))
341
				*csp = fz_device_cmyk;
342
			else if (!strcmp(fz_to_name(name), "Lab"))
343
				*csp = fz_device_lab;
344
 
345
			else if (!strcmp(fz_to_name(name), "ICCBased"))
346
				return load_icc_based(csp, xref, fz_array_get(obj, 1));
347
 
348
			else if (!strcmp(fz_to_name(name), "Indexed"))
349
				return load_indexed(csp, xref, obj);
350
			else if (!strcmp(fz_to_name(name), "I"))
351
				return load_indexed(csp, xref, obj);
352
 
353
			else if (!strcmp(fz_to_name(name), "Separation"))
354
				return load_separation(csp, xref, obj);
355
 
356
			else if (!strcmp(fz_to_name(name), "DeviceN"))
357
				return load_separation(csp, xref, obj);
358
 
359
			else
360
				return fz_throw("syntaxerror: unknown colorspace %s", fz_to_name(name));
361
 
362
			return fz_okay;
363
		}
364
	}
365
 
366
	return fz_throw("syntaxerror: could not parse color space (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
367
}
368
 
369
fz_error
370
pdf_load_colorspace(fz_colorspace **csp, pdf_xref *xref, fz_obj *obj)
371
{
372
	fz_error error;
373
 
374
	if ((*csp = pdf_find_item(xref->store, fz_drop_colorspace, obj)))
375
	{
376
		fz_keep_colorspace(*csp);
377
		return fz_okay;
378
	}
379
 
380
	error = pdf_load_colorspace_imp(csp, xref, obj);
381
	if (error)
382
		return fz_rethrow(error, "cannot load colorspace (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
383
 
384
	pdf_store_item(xref->store, fz_keep_colorspace, fz_drop_colorspace, obj, *csp);
385
 
386
	return fz_okay;
387
}