Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7643 views
1
#include "mupdf/pdf.h"
2
3
/* ICCBased */
4
5
static fz_colorspace *
6
load_icc_based(fz_context *ctx, pdf_document *doc, pdf_obj *dict)
7
{
8
int n;
9
pdf_obj *obj;
10
11
n = pdf_to_int(ctx, pdf_dict_get(ctx, dict, PDF_NAME_N));
12
obj = pdf_dict_get(ctx, dict, PDF_NAME_Alternate);
13
14
if (obj)
15
{
16
fz_colorspace *cs_alt = NULL;
17
18
fz_try(ctx)
19
{
20
cs_alt = pdf_load_colorspace(ctx, doc, obj);
21
if (cs_alt->n != n)
22
{
23
fz_drop_colorspace(ctx, cs_alt);
24
fz_throw(ctx, FZ_ERROR_GENERIC, "ICCBased /Alternate colorspace must have %d components", n);
25
}
26
}
27
fz_catch(ctx)
28
{
29
cs_alt = NULL;
30
}
31
32
if (cs_alt)
33
return cs_alt;
34
}
35
36
switch (n)
37
{
38
case 1: return fz_device_gray(ctx);
39
case 3: return fz_device_rgb(ctx);
40
case 4: return fz_device_cmyk(ctx);
41
}
42
43
fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: ICCBased must have 1, 3 or 4 components");
44
}
45
46
/* Lab */
47
48
static inline float fung(float x)
49
{
50
if (x >= 6.0f / 29.0f)
51
return x * x * x;
52
return (108.0f / 841.0f) * (x - (4.0f / 29.0f));
53
}
54
55
static void
56
lab_to_rgb(fz_context *ctx, fz_colorspace *cs, const float *lab, float *rgb)
57
{
58
/* input is in range (0..100, -128..127, -128..127) not (0..1, 0..1, 0..1) */
59
float lstar, astar, bstar, l, m, n, x, y, z, r, g, b;
60
lstar = lab[0];
61
astar = lab[1];
62
bstar = lab[2];
63
m = (lstar + 16) / 116;
64
l = m + astar / 500;
65
n = m - bstar / 200;
66
x = fung(l);
67
y = fung(m);
68
z = fung(n);
69
r = (3.240449f * x + -1.537136f * y + -0.498531f * z) * 0.830026f;
70
g = (-0.969265f * x + 1.876011f * y + 0.041556f * z) * 1.05452f;
71
b = (0.055643f * x + -0.204026f * y + 1.057229f * z) * 1.1003f;
72
rgb[0] = sqrtf(fz_clamp(r, 0, 1));
73
rgb[1] = sqrtf(fz_clamp(g, 0, 1));
74
rgb[2] = sqrtf(fz_clamp(b, 0, 1));
75
}
76
77
static void
78
rgb_to_lab(fz_context *ctx, fz_colorspace *cs, const float *rgb, float *lab)
79
{
80
fz_warn(ctx, "cannot convert into L*a*b colorspace");
81
lab[0] = rgb[0];
82
lab[1] = rgb[1];
83
lab[2] = rgb[2];
84
}
85
86
static fz_colorspace k_device_lab = { {-1, fz_drop_colorspace_imp}, 0, "Lab", 3, lab_to_rgb, rgb_to_lab };
87
static fz_colorspace *fz_device_lab = &k_device_lab;
88
89
/* Separation and DeviceN */
90
91
struct separation
92
{
93
fz_colorspace *base;
94
fz_function *tint;
95
};
96
97
static void
98
separation_to_rgb(fz_context *ctx, fz_colorspace *cs, const float *color, float *rgb)
99
{
100
struct separation *sep = cs->data;
101
float alt[FZ_MAX_COLORS];
102
fz_eval_function(ctx, sep->tint, color, cs->n, alt, sep->base->n);
103
sep->base->to_rgb(ctx, sep->base, alt, rgb);
104
}
105
106
static void
107
free_separation(fz_context *ctx, fz_colorspace *cs)
108
{
109
struct separation *sep = cs->data;
110
fz_drop_colorspace(ctx, sep->base);
111
fz_drop_function(ctx, sep->tint);
112
fz_free(ctx, sep);
113
}
114
115
static fz_colorspace *
116
load_separation(fz_context *ctx, pdf_document *doc, pdf_obj *array)
117
{
118
fz_colorspace *cs;
119
struct separation *sep = NULL;
120
pdf_obj *nameobj = pdf_array_get(ctx, array, 1);
121
pdf_obj *baseobj = pdf_array_get(ctx, array, 2);
122
pdf_obj *tintobj = pdf_array_get(ctx, array, 3);
123
fz_colorspace *base;
124
fz_function *tint = NULL;
125
int n;
126
127
fz_var(tint);
128
fz_var(sep);
129
130
if (pdf_is_array(ctx, nameobj))
131
n = pdf_array_len(ctx, nameobj);
132
else
133
n = 1;
134
135
if (n > FZ_MAX_COLORS)
136
fz_throw(ctx, FZ_ERROR_GENERIC, "too many components in colorspace");
137
138
base = pdf_load_colorspace(ctx, doc, baseobj);
139
140
fz_try(ctx)
141
{
142
tint = pdf_load_function(ctx, doc, tintobj, n, base->n);
143
/* RJW: fz_drop_colorspace(ctx, base);
144
* "cannot load tint function (%d %d R)", pdf_to_num(ctx, tintobj), pdf_to_gen(ctx, tintobj) */
145
146
sep = fz_malloc_struct(ctx, struct separation);
147
sep->base = base;
148
sep->tint = tint;
149
150
cs = fz_new_colorspace(ctx, n == 1 ? "Separation" : "DeviceN", n);
151
cs->to_rgb = separation_to_rgb;
152
cs->free_data = free_separation;
153
cs->data = sep;
154
cs->size += sizeof(struct separation) + (base ? base->size : 0) + fz_function_size(ctx, tint);
155
}
156
fz_catch(ctx)
157
{
158
fz_drop_colorspace(ctx, base);
159
fz_drop_function(ctx, tint);
160
fz_free(ctx, sep);
161
fz_rethrow(ctx);
162
}
163
164
return cs;
165
}
166
167
int
168
pdf_is_tint_colorspace(fz_context *ctx, fz_colorspace *cs)
169
{
170
return cs && cs->to_rgb == separation_to_rgb;
171
}
172
173
/* Indexed */
174
175
static fz_colorspace *
176
load_indexed(fz_context *ctx, pdf_document *doc, pdf_obj *array)
177
{
178
pdf_obj *baseobj = pdf_array_get(ctx, array, 1);
179
pdf_obj *highobj = pdf_array_get(ctx, array, 2);
180
pdf_obj *lookupobj = pdf_array_get(ctx, array, 3);
181
fz_colorspace *base = NULL;
182
fz_colorspace *cs;
183
int i, n, high;
184
unsigned char *lookup = NULL;
185
186
fz_var(base);
187
fz_var(lookup);
188
189
fz_try(ctx)
190
{
191
base = pdf_load_colorspace(ctx, doc, baseobj);
192
193
high = pdf_to_int(ctx, highobj);
194
high = fz_clampi(high, 0, 255);
195
n = base->n * (high + 1);
196
lookup = fz_malloc_array(ctx, 1, n);
197
198
if (pdf_is_string(ctx, lookupobj) && pdf_to_str_len(ctx, lookupobj) >= n)
199
{
200
unsigned char *buf = (unsigned char *) pdf_to_str_buf(ctx, lookupobj);
201
for (i = 0; i < n; i++)
202
lookup[i] = buf[i];
203
}
204
else if (pdf_is_indirect(ctx, lookupobj))
205
{
206
fz_stream *file = NULL;
207
208
fz_var(file);
209
210
fz_try(ctx)
211
{
212
file = pdf_open_stream(ctx, doc, pdf_to_num(ctx, lookupobj), pdf_to_gen(ctx, lookupobj));
213
i = fz_read(ctx, file, lookup, n);
214
if (i < n)
215
memset(lookup+i, 0, n-i);
216
}
217
fz_always(ctx)
218
{
219
fz_drop_stream(ctx, file);
220
}
221
fz_catch(ctx)
222
{
223
fz_rethrow_message(ctx, "cannot open colorspace lookup table (%d 0 R)", pdf_to_num(ctx, lookupobj));
224
}
225
}
226
else
227
{
228
fz_rethrow_message(ctx, "cannot parse colorspace lookup table");
229
}
230
231
cs = fz_new_indexed_colorspace(ctx, base, high, lookup);
232
}
233
fz_catch(ctx)
234
{
235
fz_drop_colorspace(ctx, base);
236
fz_free(ctx, lookup);
237
fz_rethrow(ctx);
238
}
239
240
return cs;
241
}
242
243
/* Parse and create colorspace from PDF object */
244
245
static fz_colorspace *
246
pdf_load_colorspace_imp(fz_context *ctx, pdf_document *doc, pdf_obj *obj)
247
{
248
249
if (pdf_obj_marked(ctx, obj))
250
fz_throw(ctx, FZ_ERROR_GENERIC, "Recursion in colorspace definition");
251
252
if (pdf_is_name(ctx, obj))
253
{
254
if (pdf_name_eq(ctx, obj, PDF_NAME_Pattern))
255
return fz_device_gray(ctx);
256
else if (pdf_name_eq(ctx, obj, PDF_NAME_G))
257
return fz_device_gray(ctx);
258
else if (pdf_name_eq(ctx, obj, PDF_NAME_RGB))
259
return fz_device_rgb(ctx);
260
else if (pdf_name_eq(ctx, obj, PDF_NAME_CMYK))
261
return fz_device_cmyk(ctx);
262
else if (pdf_name_eq(ctx, obj, PDF_NAME_DeviceGray))
263
return fz_device_gray(ctx);
264
else if (pdf_name_eq(ctx, obj, PDF_NAME_DeviceRGB))
265
return fz_device_rgb(ctx);
266
else if (pdf_name_eq(ctx, obj, PDF_NAME_DeviceCMYK))
267
return fz_device_cmyk(ctx);
268
else
269
fz_throw(ctx, FZ_ERROR_GENERIC, "unknown colorspace: %s", pdf_to_name(ctx, obj));
270
}
271
272
else if (pdf_is_array(ctx, obj))
273
{
274
pdf_obj *name = pdf_array_get(ctx, obj, 0);
275
276
if (pdf_is_name(ctx, name))
277
{
278
/* load base colorspace instead */
279
if (pdf_name_eq(ctx, name, PDF_NAME_G))
280
return fz_device_gray(ctx);
281
else if (pdf_name_eq(ctx, name, PDF_NAME_RGB))
282
return fz_device_rgb(ctx);
283
else if (pdf_name_eq(ctx, name, PDF_NAME_CMYK))
284
return fz_device_cmyk(ctx);
285
else if (pdf_name_eq(ctx, name, PDF_NAME_DeviceGray))
286
return fz_device_gray(ctx);
287
else if (pdf_name_eq(ctx, name, PDF_NAME_DeviceRGB))
288
return fz_device_rgb(ctx);
289
else if (pdf_name_eq(ctx, name, PDF_NAME_DeviceCMYK))
290
return fz_device_cmyk(ctx);
291
else if (pdf_name_eq(ctx, name, PDF_NAME_CalGray))
292
return fz_device_gray(ctx);
293
else if (pdf_name_eq(ctx, name, PDF_NAME_CalRGB))
294
return fz_device_rgb(ctx);
295
else if (pdf_name_eq(ctx, name, PDF_NAME_CalCMYK))
296
return fz_device_cmyk(ctx);
297
else if (pdf_name_eq(ctx, name, PDF_NAME_Lab))
298
return fz_device_lab;
299
else
300
{
301
fz_colorspace *cs;
302
fz_try(ctx)
303
{
304
pdf_mark_obj(ctx, obj);
305
if (pdf_name_eq(ctx, name, PDF_NAME_ICCBased))
306
cs = load_icc_based(ctx, doc, pdf_array_get(ctx, obj, 1));
307
308
else if (pdf_name_eq(ctx, name, PDF_NAME_Indexed))
309
cs = load_indexed(ctx, doc, obj);
310
else if (pdf_name_eq(ctx, name, PDF_NAME_I))
311
cs = load_indexed(ctx, doc, obj);
312
313
else if (pdf_name_eq(ctx, name, PDF_NAME_Separation))
314
cs = load_separation(ctx, doc, obj);
315
316
else if (pdf_name_eq(ctx, name, PDF_NAME_DeviceN))
317
cs = load_separation(ctx, doc, obj);
318
else if (pdf_name_eq(ctx, name, PDF_NAME_Pattern))
319
{
320
pdf_obj *pobj;
321
322
pobj = pdf_array_get(ctx, obj, 1);
323
if (!pobj)
324
{
325
cs = fz_device_gray(ctx);
326
break;
327
}
328
329
cs = pdf_load_colorspace(ctx, doc, pobj);
330
}
331
else
332
fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: unknown colorspace %s", pdf_to_name(ctx, name));
333
}
334
fz_always(ctx)
335
{
336
pdf_unmark_obj(ctx, obj);
337
}
338
fz_catch(ctx)
339
{
340
fz_rethrow(ctx);
341
}
342
return cs;
343
}
344
}
345
}
346
347
fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: could not parse color space (%d %d R)", pdf_to_num(ctx, obj), pdf_to_gen(ctx, obj));
348
}
349
350
fz_colorspace *
351
pdf_load_colorspace(fz_context *ctx, pdf_document *doc, pdf_obj *obj)
352
{
353
fz_colorspace *cs;
354
355
if ((cs = pdf_find_item(ctx, fz_drop_colorspace_imp, obj)) != NULL)
356
{
357
return cs;
358
}
359
360
cs = pdf_load_colorspace_imp(ctx, doc, obj);
361
362
pdf_store_item(ctx, obj, cs, cs->size);
363
364
return cs;
365
}
366
367