1#include "mupdf/fitz.h"
2
3#include "fitz-imp.h"
4
5#include <assert.h>
6#include <math.h>
7#include <string.h>
8
9#if FZ_ENABLE_ICC
10
11#include "icc/gray.icc.h"
12#include "icc/rgb.icc.h"
13#include "icc/cmyk.icc.h"
14#include "icc/lab.icc.h"
15
16void fz_new_colorspace_context(fz_context *ctx)
17{
18 fz_colorspace_context *cct;
19
20 fz_buffer *gray = NULL;
21 fz_buffer *rgb = NULL;
22 fz_buffer *cmyk = NULL;
23 fz_buffer *lab = NULL;
24
25 fz_var(gray);
26 fz_var(rgb);
27 fz_var(cmyk);
28 fz_var(lab);
29
30 cct = ctx->colorspace = fz_malloc_struct(ctx, fz_colorspace_context);
31 cct->ctx_refs = 1;
32
33 fz_new_icc_context(ctx);
34
35 ctx->icc_enabled = 1;
36
37 fz_try(ctx)
38 {
39 gray = fz_new_buffer_from_shared_data(ctx, resources_icc_gray_icc, resources_icc_gray_icc_len);
40 rgb = fz_new_buffer_from_shared_data(ctx, resources_icc_rgb_icc, resources_icc_rgb_icc_len);
41 cmyk = fz_new_buffer_from_shared_data(ctx, resources_icc_cmyk_icc, resources_icc_cmyk_icc_len);
42 lab = fz_new_buffer_from_shared_data(ctx, resources_icc_lab_icc, resources_icc_lab_icc_len);
43 cct->gray = fz_new_icc_colorspace(ctx, FZ_COLORSPACE_GRAY, FZ_COLORSPACE_IS_DEVICE, "DeviceGray", gray);
44 cct->rgb = fz_new_icc_colorspace(ctx, FZ_COLORSPACE_RGB, FZ_COLORSPACE_IS_DEVICE, "DeviceRGB", rgb);
45 cct->bgr = fz_new_icc_colorspace(ctx, FZ_COLORSPACE_BGR, FZ_COLORSPACE_IS_DEVICE, "DeviceBGR", rgb);
46 cct->cmyk = fz_new_icc_colorspace(ctx, FZ_COLORSPACE_CMYK, FZ_COLORSPACE_IS_DEVICE, "DeviceCMYK", cmyk);
47 cct->lab = fz_new_icc_colorspace(ctx, FZ_COLORSPACE_LAB, FZ_COLORSPACE_IS_DEVICE, "Lab", lab);
48 }
49 fz_always(ctx)
50 {
51 fz_drop_buffer(ctx, gray);
52 fz_drop_buffer(ctx, rgb);
53 fz_drop_buffer(ctx, cmyk);
54 fz_drop_buffer(ctx, lab);
55 }
56 fz_catch(ctx)
57 {
58 fz_rethrow(ctx);
59 }
60}
61
62void fz_enable_icc(fz_context *ctx)
63{
64 ctx->icc_enabled = 1;
65}
66
67void fz_disable_icc(fz_context *ctx)
68{
69 ctx->icc_enabled = 0;
70}
71
72#else
73
74void fz_new_colorspace_context(fz_context *ctx)
75{
76 fz_colorspace_context *cct;
77
78 cct = ctx->colorspace = fz_malloc_struct(ctx, fz_colorspace_context);
79 cct->ctx_refs = 1;
80
81 cct->gray = fz_new_colorspace(ctx, FZ_COLORSPACE_GRAY, FZ_COLORSPACE_IS_DEVICE, 1, "DeviceGray");
82 cct->rgb = fz_new_colorspace(ctx, FZ_COLORSPACE_RGB, FZ_COLORSPACE_IS_DEVICE, 3, "DeviceRGB");
83 cct->bgr = fz_new_colorspace(ctx, FZ_COLORSPACE_BGR, FZ_COLORSPACE_IS_DEVICE, 3, "DeviceBGR");
84 cct->cmyk = fz_new_colorspace(ctx, FZ_COLORSPACE_CMYK, FZ_COLORSPACE_IS_DEVICE, 4, "DeviceCMYK");
85 cct->lab = fz_new_colorspace(ctx, FZ_COLORSPACE_LAB, FZ_COLORSPACE_IS_DEVICE, 3, "Lab");
86}
87
88void fz_enable_icc(fz_context *ctx)
89{
90 fz_warn(ctx, "ICC support is not available");
91}
92
93void fz_disable_icc(fz_context *ctx)
94{
95}
96
97#endif
98
99fz_colorspace_context *fz_keep_colorspace_context(fz_context *ctx)
100{
101 fz_keep_imp(ctx, ctx->colorspace, &ctx->colorspace->ctx_refs);
102 return ctx->colorspace;
103}
104
105void fz_drop_colorspace_context(fz_context *ctx)
106{
107 if (fz_drop_imp(ctx, ctx->colorspace, &ctx->colorspace->ctx_refs))
108 {
109 fz_drop_colorspace(ctx, ctx->colorspace->gray);
110 fz_drop_colorspace(ctx, ctx->colorspace->rgb);
111 fz_drop_colorspace(ctx, ctx->colorspace->bgr);
112 fz_drop_colorspace(ctx, ctx->colorspace->cmyk);
113 fz_drop_colorspace(ctx, ctx->colorspace->lab);
114#if FZ_ENABLE_ICC
115 fz_drop_icc_context(ctx);
116#endif
117 fz_free(ctx, ctx->colorspace);
118 ctx->colorspace = NULL;
119 }
120}
121
122fz_colorspace *fz_device_gray(fz_context *ctx)
123{
124 return ctx->colorspace->gray;
125}
126
127fz_colorspace *fz_device_rgb(fz_context *ctx)
128{
129 return ctx->colorspace->rgb;
130}
131
132fz_colorspace *fz_device_bgr(fz_context *ctx)
133{
134 return ctx->colorspace->bgr;
135}
136
137fz_colorspace *fz_device_cmyk(fz_context *ctx)
138{
139 return ctx->colorspace->cmyk;
140}
141
142fz_colorspace *fz_device_lab(fz_context *ctx)
143{
144 return ctx->colorspace->lab;
145}
146
147/* Same order as needed by LCMS */
148static const char *fz_intent_names[] =
149{
150 "Perceptual",
151 "RelativeColorimetric",
152 "Saturation",
153 "AbsoluteColorimetric",
154};
155
156int fz_lookup_rendering_intent(const char *name)
157{
158 int i;
159 for (i = 0; i < nelem(fz_intent_names); i++)
160 if (!strcmp(name, fz_intent_names[i]))
161 return i;
162 return FZ_RI_RELATIVE_COLORIMETRIC;
163}
164
165const char *fz_rendering_intent_name(int ri)
166{
167 if (ri >= 0 && ri < nelem(fz_intent_names))
168 return fz_intent_names[ri];
169 return "RelativeColorimetric";
170}
171
172/* Colorspace feature tests */
173
174const char *fz_colorspace_name(fz_context *ctx, fz_colorspace *cs)
175{
176 return cs ? cs->name : "None";
177}
178
179enum fz_colorspace_type fz_colorspace_type(fz_context *ctx, fz_colorspace *cs)
180{
181 return cs ? cs->type : FZ_COLORSPACE_NONE;
182}
183
184int fz_colorspace_n(fz_context *ctx, fz_colorspace *cs)
185{
186 return cs ? cs->n : 0;
187}
188
189int fz_colorspace_is_gray(fz_context *ctx, fz_colorspace *cs)
190{
191 return cs && cs->type == FZ_COLORSPACE_GRAY;
192}
193
194int fz_colorspace_is_rgb(fz_context *ctx, fz_colorspace *cs)
195{
196 return cs && cs->type == FZ_COLORSPACE_RGB;
197}
198
199int fz_colorspace_is_cmyk(fz_context *ctx, fz_colorspace *cs)
200{
201 return cs && cs->type == FZ_COLORSPACE_CMYK;
202}
203
204int fz_colorspace_is_lab(fz_context *ctx, fz_colorspace *cs)
205{
206 return cs && cs->type == FZ_COLORSPACE_LAB;
207}
208
209int fz_colorspace_is_indexed(fz_context *ctx, fz_colorspace *cs)
210{
211 return cs && (cs->type == FZ_COLORSPACE_INDEXED);
212}
213
214int fz_colorspace_is_device_n(fz_context *ctx, fz_colorspace *cs)
215{
216 return cs && (cs->type == FZ_COLORSPACE_SEPARATION);
217}
218
219/* True for CMYK, Separation and DeviceN colorspaces. */
220int fz_colorspace_is_subtractive(fz_context *ctx, fz_colorspace *cs)
221{
222 return cs && (cs->type == FZ_COLORSPACE_CMYK || cs->type == FZ_COLORSPACE_SEPARATION);
223}
224
225int fz_colorspace_is_device(fz_context *ctx, fz_colorspace *cs)
226{
227 return cs && (cs->flags & FZ_COLORSPACE_IS_DEVICE);
228}
229
230int fz_colorspace_is_lab_icc(fz_context *ctx, fz_colorspace *cs)
231{
232 return cs && (cs->type == FZ_COLORSPACE_LAB) && (cs->flags & FZ_COLORSPACE_IS_ICC);
233}
234
235int fz_colorspace_is_device_gray(fz_context *ctx, fz_colorspace *cs)
236{
237 return fz_colorspace_is_device(ctx, cs) && fz_colorspace_is_gray(ctx, cs);
238}
239
240int fz_colorspace_is_device_cmyk(fz_context *ctx, fz_colorspace *cs)
241{
242 return fz_colorspace_is_device(ctx, cs) && fz_colorspace_is_cmyk(ctx, cs);
243}
244
245/* True if DeviceN color space has only colorants from the CMYK set. */
246int fz_colorspace_device_n_has_only_cmyk(fz_context *ctx, fz_colorspace *cs)
247{
248 return cs && ((cs->flags & FZ_COLORSPACE_HAS_CMYK_AND_SPOTS) == FZ_COLORSPACE_HAS_CMYK);
249}
250
251/* True if DeviceN color space has cyan magenta yellow or black as one of its colorants. */
252int fz_colorspace_device_n_has_cmyk(fz_context *ctx, fz_colorspace *cs)
253{
254 return cs && (cs->flags & FZ_COLORSPACE_HAS_CMYK);
255}
256
257int fz_is_valid_blend_colorspace(fz_context *ctx, fz_colorspace *cs)
258{
259 return cs == NULL ||
260 cs->type == FZ_COLORSPACE_GRAY ||
261 cs->type == FZ_COLORSPACE_RGB ||
262 cs->type == FZ_COLORSPACE_CMYK;
263}
264
265fz_colorspace *
266fz_keep_colorspace(fz_context *ctx, fz_colorspace *cs)
267{
268 return fz_keep_key_storable(ctx, &cs->key_storable);
269}
270
271void
272fz_drop_colorspace(fz_context *ctx, fz_colorspace *cs)
273{
274 fz_drop_key_storable(ctx, &cs->key_storable);
275}
276
277fz_colorspace *
278fz_keep_colorspace_store_key(fz_context *ctx, fz_colorspace *cs)
279{
280 return fz_keep_key_storable_key(ctx, &cs->key_storable);
281}
282
283void
284fz_drop_colorspace_store_key(fz_context *ctx, fz_colorspace *cs)
285{
286 fz_drop_key_storable_key(ctx, &cs->key_storable);
287}
288
289void
290fz_drop_colorspace_imp(fz_context *ctx, fz_storable *cs_)
291{
292 fz_colorspace *cs = (fz_colorspace *)cs_;
293 int i;
294
295 if (cs->type == FZ_COLORSPACE_INDEXED)
296 {
297 fz_drop_colorspace(ctx, cs->u.indexed.base);
298 fz_free(ctx, cs->u.indexed.lookup);
299 }
300 if (cs->type == FZ_COLORSPACE_SEPARATION)
301 {
302 fz_drop_colorspace(ctx, cs->u.separation.base);
303 cs->u.separation.drop(ctx, cs->u.separation.tint);
304 for (i = 0; i < FZ_MAX_COLORS; i++)
305 fz_free(ctx, cs->u.separation.colorant[i]);
306 }
307#if FZ_ENABLE_ICC
308 if (cs->flags & FZ_COLORSPACE_IS_ICC)
309 {
310 fz_drop_icc_profile(ctx, cs->u.icc.profile);
311 fz_drop_buffer(ctx, cs->u.icc.buffer);
312 }
313#endif
314
315 fz_free(ctx, cs->name);
316 fz_free(ctx, cs);
317}
318
319fz_colorspace *
320fz_new_colorspace(fz_context *ctx, enum fz_colorspace_type type, int flags, int n, const char *name)
321{
322 fz_colorspace *cs = fz_malloc_struct(ctx, fz_colorspace);
323 FZ_INIT_KEY_STORABLE(cs, 1, fz_drop_colorspace_imp);
324
325 fz_try(ctx)
326 {
327 cs->type = type;
328 cs->flags = flags;
329 cs->n = n;
330 cs->name = fz_strdup(ctx, name ? name : "UNKNOWN");
331 }
332 fz_catch(ctx)
333 {
334 fz_free(ctx, cs);
335 fz_rethrow(ctx);
336 }
337
338 return cs;
339}
340
341fz_colorspace *
342fz_new_indexed_colorspace(fz_context *ctx, fz_colorspace *base, int high, unsigned char *lookup)
343{
344 fz_colorspace *cs;
345 char name[100];
346 if (high < 0 || high > 255)
347 fz_throw(ctx, FZ_ERROR_SYNTAX, "invalid maximum value in indexed colorspace");
348 fz_snprintf(name, sizeof name, "Indexed(%d,%s)", high, base->name);
349 cs = fz_new_colorspace(ctx, FZ_COLORSPACE_INDEXED, 0, 1, name);
350 cs->u.indexed.base = fz_keep_colorspace(ctx, base);
351 cs->u.indexed.high = high;
352 cs->u.indexed.lookup = lookup;
353 return cs;
354}
355
356fz_colorspace *
357fz_new_icc_colorspace(fz_context *ctx, enum fz_colorspace_type type, int flags, const char *name, fz_buffer *buf)
358{
359#if FZ_ENABLE_ICC
360 fz_icc_profile *profile = NULL;
361 fz_colorspace *cs = NULL;
362 unsigned char *data;
363 char name_buf[100];
364 size_t size;
365 int n;
366
367 fz_var(profile);
368 fz_var(cs);
369 fz_var(type);
370
371 fz_try(ctx)
372 {
373 size = fz_buffer_storage(ctx, buf, &data);
374 profile = fz_new_icc_profile(ctx, data, size);
375 n = fz_icc_profile_components(ctx, profile);
376 switch (type)
377 {
378 default:
379 fz_throw(ctx, FZ_ERROR_SYNTAX, "invalid colorspace type for ICC profile");
380 case FZ_COLORSPACE_NONE:
381 switch (n)
382 {
383 default:
384 fz_throw(ctx, FZ_ERROR_SYNTAX, "ICC profile has unexpected number of channels: %d", n);
385 case 1:
386 type = FZ_COLORSPACE_GRAY;
387 break;
388 case 3:
389 if (fz_icc_profile_is_lab(ctx, profile))
390 type = FZ_COLORSPACE_LAB;
391 else
392 type = FZ_COLORSPACE_RGB;
393 break;
394 case 4:
395 type = FZ_COLORSPACE_CMYK;
396 break;
397 }
398 break;
399 case FZ_COLORSPACE_GRAY:
400 if (n != 1)
401 fz_throw(ctx, FZ_ERROR_SYNTAX, "ICC profile (N=%d) is not Gray", n);
402 break;
403 case FZ_COLORSPACE_RGB:
404 case FZ_COLORSPACE_BGR:
405 if (n != 3 || fz_icc_profile_is_lab(ctx, profile))
406 fz_throw(ctx, FZ_ERROR_SYNTAX, "ICC profile (N=%d) is not RGB", n);
407 break;
408 case FZ_COLORSPACE_LAB:
409 if (n != 3 || !fz_icc_profile_is_lab(ctx, profile))
410 fz_throw(ctx, FZ_ERROR_SYNTAX, "ICC profile (N=%d) is not Lab", n);
411 break;
412 case FZ_COLORSPACE_CMYK:
413 if (n != 4)
414 fz_throw(ctx, FZ_ERROR_SYNTAX, "ICC profile (N=%d) is not CMYK", n);
415 break;
416 }
417
418 if (!name)
419 {
420 char cmm_name[100];
421 fz_icc_profile_name(ctx, profile, cmm_name, sizeof cmm_name);
422 switch (type)
423 {
424 default: fz_snprintf(name_buf, sizeof name_buf, "ICCBased(%d,%s)", n, cmm_name); break;
425 case FZ_COLORSPACE_GRAY: fz_snprintf(name_buf, sizeof name_buf, "ICCBased(Gray,%s)", cmm_name); break;
426 case FZ_COLORSPACE_RGB: fz_snprintf(name_buf, sizeof name_buf, "ICCBased(RGB,%s)", cmm_name); break;
427 case FZ_COLORSPACE_BGR: fz_snprintf(name_buf, sizeof name_buf, "ICCBased(BGR,%s)", cmm_name); break;
428 case FZ_COLORSPACE_CMYK: fz_snprintf(name_buf, sizeof name_buf, "ICCBased(CMYK,%s)", cmm_name); break;
429 case FZ_COLORSPACE_LAB: fz_snprintf(name_buf, sizeof name_buf, "ICCBased(Lab,%s)", cmm_name); break;
430 }
431 name = name_buf;
432 }
433
434 cs = fz_new_colorspace(ctx, type, flags | FZ_COLORSPACE_IS_ICC, n, name);
435 cs->u.icc.buffer = fz_keep_buffer(ctx, buf);
436 cs->u.icc.profile = profile;
437 fz_md5_buffer(ctx, buf, cs->u.icc.md5);
438 }
439 fz_catch(ctx)
440 {
441 fz_drop_icc_profile(ctx, profile);
442 fz_drop_colorspace(ctx, cs);
443 fz_rethrow(ctx);
444 }
445 return cs;
446#else
447 switch (type)
448 {
449 default: fz_throw(ctx, FZ_ERROR_SYNTAX, "unknown colorspace type");
450 case FZ_COLORSPACE_GRAY: return fz_keep_colorspace(ctx, fz_device_gray(ctx));
451 case FZ_COLORSPACE_RGB: return fz_keep_colorspace(ctx, fz_device_rgb(ctx));
452 case FZ_COLORSPACE_BGR: return fz_keep_colorspace(ctx, fz_device_bgr(ctx));
453 case FZ_COLORSPACE_CMYK: return fz_keep_colorspace(ctx, fz_device_cmyk(ctx));
454 case FZ_COLORSPACE_LAB: return fz_keep_colorspace(ctx, fz_device_lab(ctx));
455 }
456#endif
457}
458
459fz_colorspace *fz_new_cal_gray_colorspace(fz_context *ctx, float wp[3], float bp[3], float gamma)
460{
461#if FZ_ENABLE_ICC
462 fz_buffer *buf = fz_new_icc_data_from_cal(ctx, wp, bp, &gamma, NULL, 1);
463 fz_colorspace *cs;
464 fz_try(ctx)
465 cs = fz_new_icc_colorspace(ctx, FZ_COLORSPACE_GRAY, 0, "CalGray", buf);
466 fz_always(ctx)
467 fz_drop_buffer(ctx, buf);
468 fz_catch(ctx)
469 fz_rethrow(ctx);
470 return cs;
471#else
472 return fz_keep_colorspace(ctx, fz_device_gray(ctx));
473#endif
474}
475
476fz_colorspace *fz_new_cal_rgb_colorspace(fz_context *ctx, float wp[3], float bp[3], float gamma[3], float matrix[9])
477{
478#if FZ_ENABLE_ICC
479 fz_buffer *buf = fz_new_icc_data_from_cal(ctx, wp, bp, gamma, matrix, 3);
480 fz_colorspace *cs;
481 fz_try(ctx)
482 cs = fz_new_icc_colorspace(ctx, FZ_COLORSPACE_RGB, 0, "CalRGB", buf);
483 fz_always(ctx)
484 fz_drop_buffer(ctx, buf);
485 fz_catch(ctx)
486 fz_rethrow(ctx);
487 return cs;
488#else
489 return fz_keep_colorspace(ctx, fz_device_rgb(ctx));
490#endif
491}
492
493void fz_colorspace_name_colorant(fz_context *ctx, fz_colorspace *cs, int i, const char *name)
494{
495 if (i < 0 || i >= cs->n)
496 fz_throw(ctx, FZ_ERROR_GENERIC, "Attempt to name out of range colorant");
497 if (cs->type != FZ_COLORSPACE_SEPARATION)
498 fz_throw(ctx, FZ_ERROR_GENERIC, "Attempt to name colorant for non-separation colorspace");
499
500 fz_free(ctx, cs->u.separation.colorant[i]);
501 cs->u.separation.colorant[i] = NULL;
502 cs->u.separation.colorant[i] = fz_strdup(ctx, name);
503
504 if (!strcmp(name, "Cyan") || !strcmp(name, "Magenta") || !strcmp(name, "Yellow") || !strcmp(name, "Black"))
505 cs->flags |= FZ_COLORSPACE_HAS_CMYK;
506 else
507 cs->flags |= FZ_COLORSPACE_HAS_SPOTS;
508}
509
510const char *fz_colorspace_colorant(fz_context *ctx, fz_colorspace *cs, int i)
511{
512 if (!cs || i < 0 || i >= cs->n)
513 fz_throw(ctx, FZ_ERROR_GENERIC, "Colorant out of range");
514 switch (cs->type)
515 {
516 case FZ_COLORSPACE_NONE:
517 return "None";
518 case FZ_COLORSPACE_GRAY:
519 return "Gray";
520 case FZ_COLORSPACE_RGB:
521 if (i == 0) return "Red";
522 if (i == 1) return "Green";
523 if (i == 2) return "Blue";
524 break;
525 case FZ_COLORSPACE_BGR:
526 if (i == 0) return "Blue";
527 if (i == 1) return "Green";
528 if (i == 2) return "Red";
529 break;
530 case FZ_COLORSPACE_CMYK:
531 if (i == 0) return "Cyan";
532 if (i == 1) return "Magenta";
533 if (i == 2) return "Yellow";
534 if (i == 3) return "Black";
535 break;
536 case FZ_COLORSPACE_LAB:
537 if (i == 0) return "L*";
538 if (i == 1) return "a*";
539 if (i == 2) return "b*";
540 break;
541 case FZ_COLORSPACE_INDEXED:
542 return "Index";
543 case FZ_COLORSPACE_SEPARATION:
544 return cs->u.separation.colorant[i];
545 }
546 return "None";
547}
548
549void
550fz_clamp_color(fz_context *ctx, fz_colorspace *cs, const float *in, float *out)
551{
552 if (cs->type == FZ_COLORSPACE_LAB)
553 {
554 out[0] = fz_clamp(in[0], 0, 100);
555 out[1] = fz_clamp(in[1], -128, 127);
556 out[2] = fz_clamp(in[2], -128, 127);
557 }
558 else if (cs->type == FZ_COLORSPACE_INDEXED)
559 {
560 out[0] = fz_clamp(in[0], 0, cs->u.indexed.high) / 255.0f;
561 }
562 else
563 {
564 int i, n = cs->n;
565 for (i = 0; i < n; ++i)
566 out[i] = fz_clamp(in[i], 0, 1);
567 }
568}
569
570const fz_color_params fz_default_color_params = { FZ_RI_RELATIVE_COLORIMETRIC, 1, 0, 0 };
571
572/* Handle page specific default colorspace settings that PDF holds in its page resources.
573 * Also track the output intent.
574 */
575
576fz_default_colorspaces *fz_new_default_colorspaces(fz_context *ctx)
577{
578 fz_default_colorspaces *default_cs = fz_malloc_struct(ctx, fz_default_colorspaces);
579 default_cs->refs = 1;
580 default_cs->gray = fz_keep_colorspace(ctx, fz_device_gray(ctx));
581 default_cs->rgb = fz_keep_colorspace(ctx, fz_device_rgb(ctx));
582 default_cs->cmyk = fz_keep_colorspace(ctx, fz_device_cmyk(ctx));
583 default_cs->oi = NULL;
584 return default_cs;
585}
586
587fz_default_colorspaces *fz_clone_default_colorspaces(fz_context *ctx, fz_default_colorspaces *base)
588{
589 fz_default_colorspaces *default_cs = fz_malloc_struct(ctx, fz_default_colorspaces);
590 default_cs->refs = 1;
591 if (base)
592 {
593 default_cs->gray = fz_keep_colorspace(ctx, base->gray);
594 default_cs->rgb = fz_keep_colorspace(ctx, base->rgb);
595 default_cs->cmyk = fz_keep_colorspace(ctx, base->cmyk);
596 default_cs->oi = fz_keep_colorspace(ctx, base->oi);
597 }
598 return default_cs;
599}
600
601fz_default_colorspaces *fz_keep_default_colorspaces(fz_context *ctx, fz_default_colorspaces *default_cs)
602{
603 return fz_keep_imp(ctx, default_cs, &default_cs->refs);
604}
605
606void
607fz_drop_default_colorspaces(fz_context *ctx, fz_default_colorspaces *default_cs)
608{
609 if (fz_drop_imp(ctx, default_cs, &default_cs->refs))
610 {
611 fz_drop_colorspace(ctx, default_cs->gray);
612 fz_drop_colorspace(ctx, default_cs->rgb);
613 fz_drop_colorspace(ctx, default_cs->cmyk);
614 fz_drop_colorspace(ctx, default_cs->oi);
615 fz_free(ctx, default_cs);
616 }
617}
618
619fz_colorspace *fz_default_gray(fz_context *ctx, const fz_default_colorspaces *default_cs)
620{
621 return default_cs ? default_cs->gray : fz_device_gray(ctx);
622}
623
624fz_colorspace *fz_default_rgb(fz_context *ctx, const fz_default_colorspaces *default_cs)
625{
626 return default_cs ? default_cs->rgb : fz_device_rgb(ctx);
627}
628
629fz_colorspace *fz_default_cmyk(fz_context *ctx, const fz_default_colorspaces *default_cs)
630{
631 return default_cs ? default_cs->cmyk : fz_device_cmyk(ctx);
632}
633
634fz_colorspace *fz_default_output_intent(fz_context *ctx, const fz_default_colorspaces *default_cs)
635{
636 return default_cs ? default_cs->oi : NULL;
637}
638
639void fz_set_default_gray(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs)
640{
641 if (cs->type == FZ_COLORSPACE_GRAY && cs->n == 1)
642 {
643 fz_drop_colorspace(ctx, default_cs->gray);
644 default_cs->gray = fz_keep_colorspace(ctx, cs);
645 }
646}
647
648void fz_set_default_rgb(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs)
649{
650 if (cs->type == FZ_COLORSPACE_RGB && cs->n == 3)
651 {
652 fz_drop_colorspace(ctx, default_cs->rgb);
653 default_cs->rgb = fz_keep_colorspace(ctx, cs);
654 }
655}
656
657void fz_set_default_cmyk(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs)
658{
659 if (cs->type == FZ_COLORSPACE_CMYK && cs->n == 4)
660 {
661 fz_drop_colorspace(ctx, default_cs->cmyk);
662 default_cs->cmyk = fz_keep_colorspace(ctx, cs);
663 }
664}
665
666void fz_set_default_output_intent(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs)
667{
668 fz_drop_colorspace(ctx, default_cs->oi);
669 default_cs->oi = NULL;
670
671 /* FIXME: Why do we set DefaultXXX along with the output intent?! */
672 switch (cs->type)
673 {
674 default:
675 fz_warn(ctx, "Ignoring incompatible output intent: %s.", cs->name);
676 break;
677 case FZ_COLORSPACE_GRAY:
678 default_cs->oi = fz_keep_colorspace(ctx, cs);
679 if (default_cs->gray == fz_device_gray(ctx))
680 fz_set_default_gray(ctx, default_cs, cs);
681 break;
682 case FZ_COLORSPACE_RGB:
683 default_cs->oi = fz_keep_colorspace(ctx, cs);
684 if (default_cs->rgb == fz_device_rgb(ctx))
685 fz_set_default_rgb(ctx, default_cs, cs);
686 break;
687 case FZ_COLORSPACE_CMYK:
688 default_cs->oi = fz_keep_colorspace(ctx, cs);
689 if (default_cs->cmyk == fz_device_cmyk(ctx))
690 fz_set_default_cmyk(ctx, default_cs, cs);
691 break;
692 }
693}
694
695/* Link cache */
696
697#if FZ_ENABLE_ICC
698
699typedef struct fz_link_key_s fz_link_key;
700
701struct fz_link_key_s {
702 int refs;
703 unsigned char src_md5[16];
704 unsigned char dst_md5[16];
705 fz_color_params rend;
706 unsigned char src_extras;
707 unsigned char dst_extras;
708 unsigned char copy_spots;
709 unsigned char format;
710 unsigned char proof;
711 unsigned char bgr;
712};
713
714static void *
715fz_keep_link_key(fz_context *ctx, void *key_)
716{
717 fz_link_key *key = (fz_link_key *)key_;
718 return fz_keep_imp(ctx, key, &key->refs);
719}
720
721static void
722fz_drop_link_key(fz_context *ctx, void *key_)
723{
724 fz_link_key *key = (fz_link_key *)key_;
725 if (fz_drop_imp(ctx, key, &key->refs))
726 fz_free(ctx, key);
727}
728
729static int
730fz_cmp_link_key(fz_context *ctx, void *k0_, void *k1_)
731{
732 fz_link_key *k0 = (fz_link_key *)k0_;
733 fz_link_key *k1 = (fz_link_key *)k1_;
734 return
735 memcmp(k0->src_md5, k1->src_md5, 16) == 0 &&
736 memcmp(k0->dst_md5, k1->dst_md5, 16) == 0 &&
737 k0->src_extras == k1->src_extras &&
738 k0->dst_extras == k1->dst_extras &&
739 k0->rend.bp == k1->rend.bp &&
740 k0->rend.ri == k1->rend.ri &&
741 k0->copy_spots == k1->copy_spots &&
742 k0->format == k1->format &&
743 k0->proof == k1->proof &&
744 k0->bgr == k1->bgr;
745}
746
747static void
748fz_format_link_key(fz_context *ctx, char *s, int n, void *key_)
749{
750 static const char *hex = "0123456789abcdef";
751 fz_link_key *key = (fz_link_key *)key_;
752 char sm[33], dm[33];
753 int i;
754 for (i = 0; i < 16; ++i)
755 {
756 sm[i*2+0] = hex[key->src_md5[i]>>4];
757 sm[i*2+1] = hex[key->src_md5[i]&15];
758 dm[i*2+0] = hex[key->dst_md5[i]>>4];
759 dm[i*2+1] = hex[key->dst_md5[i]&15];
760 }
761 sm[32] = 0;
762 dm[32] = 0;
763 fz_snprintf(s, n, "(link src_md5=%s dst_md5=%s)", sm, dm);
764}
765
766static int
767fz_make_hash_link_key(fz_context *ctx, fz_store_hash *hash, void *key_)
768{
769 fz_link_key *key = (fz_link_key *)key_;
770 memcpy(hash->u.link.dst_md5, key->dst_md5, 16);
771 memcpy(hash->u.link.src_md5, key->src_md5, 16);
772 hash->u.link.ri = key->rend.ri;
773 hash->u.link.bp = key->rend.bp;
774 hash->u.link.src_extras = key->src_extras;
775 hash->u.link.dst_extras = key->dst_extras;
776 hash->u.link.format = key->format;
777 hash->u.link.proof = key->proof;
778 hash->u.link.copy_spots = key->copy_spots;
779 hash->u.link.bgr = key->bgr;
780 return 1;
781}
782
783static fz_store_type fz_link_store_type =
784{
785 fz_make_hash_link_key,
786 fz_keep_link_key,
787 fz_drop_link_key,
788 fz_cmp_link_key,
789 fz_format_link_key,
790 NULL
791};
792
793fz_icc_link *
794fz_find_icc_link(fz_context *ctx,
795 fz_colorspace *src, int src_extras,
796 fz_colorspace *dst, int dst_extras,
797 fz_colorspace *prf,
798 fz_color_params rend,
799 int format,
800 int copy_spots)
801{
802 fz_icc_link *link, *old_link;
803 fz_link_key key, *new_key;
804
805 fz_var(link);
806
807 /* Check the storable to see if we have a copy. */
808 key.refs = 1;
809 memcpy(&key.src_md5, src->u.icc.md5, 16);
810 memcpy(&key.dst_md5, dst->u.icc.md5, 16);
811 key.rend = rend;
812 key.src_extras = src_extras;
813 key.dst_extras = dst_extras;
814 key.copy_spots = copy_spots;
815 key.format = format;
816 key.proof = (prf != NULL);
817 key.bgr = (dst->type == FZ_COLORSPACE_BGR);
818
819 link = fz_find_item(ctx, fz_drop_icc_link_imp, &key, &fz_link_store_type);
820 if (!link)
821 {
822 new_key = fz_malloc(ctx, sizeof (fz_link_key));
823 memcpy(new_key, &key, sizeof (fz_link_key));
824 fz_try(ctx)
825 {
826 link = fz_new_icc_link(ctx, src, src_extras, dst, dst_extras, prf, rend, format, copy_spots);
827 old_link = fz_store_item(ctx, new_key, link, 1000, &fz_link_store_type);
828 if (old_link)
829 {
830 /* Found one while adding! Perhaps from another thread? */
831 fz_drop_icc_link(ctx, link);
832 link = old_link;
833 }
834 }
835 fz_always(ctx)
836 {
837 fz_drop_link_key(ctx, new_key);
838 }
839 fz_catch(ctx)
840 {
841 fz_drop_icc_link(ctx, link);
842 fz_rethrow(ctx);
843 }
844 }
845 return link;
846}
847
848#endif
849
850/* Color conversions */
851
852static void indexed_via_base(fz_context *ctx, fz_color_converter *cc, const float *src, float *dst)
853{
854 fz_colorspace *ss = cc->ss_via;
855 const unsigned char *lookup = ss->u.indexed.lookup;
856 int high = ss->u.indexed.high;
857 int n = ss->u.indexed.base->n;
858 float base[4];
859 int i, k;
860
861 i = src[0] * 255;
862 i = fz_clampi(i, 0, high);
863 if (ss->u.indexed.base->type == FZ_COLORSPACE_LAB)
864 {
865 base[0] = lookup[i * 3 + 0] * 100 / 255.0f;
866 base[1] = lookup[i * 3 + 1] - 128;
867 base[2] = lookup[i * 3 + 2] - 128;
868 }
869 else
870 {
871 for (k = 0; k < n; ++k)
872 base[k] = lookup[i * n + k] / 255.0f;
873 }
874
875 cc->convert_via(ctx, cc, base, dst);
876}
877
878static void separation_via_base(fz_context *ctx, fz_color_converter *cc, const float *src, float *dst)
879{
880 fz_colorspace *ss = cc->ss_via;
881 float base[4];
882 ss->u.separation.eval(ctx, ss->u.separation.tint, src, ss->n, base, ss->u.separation.base->n);
883 cc->convert_via(ctx, cc, base, dst);
884}
885
886static void
887fz_init_process_color_converter(fz_context *ctx, fz_color_converter *cc, fz_colorspace *ss, fz_colorspace *ds, fz_colorspace *is, fz_color_params params)
888{
889 if (ss->type == FZ_COLORSPACE_INDEXED)
890 fz_throw(ctx, FZ_ERROR_GENERIC, "base colorspace must not be indexed");
891 if (ss->type == FZ_COLORSPACE_SEPARATION)
892 fz_throw(ctx, FZ_ERROR_GENERIC, "base colorspace must not be separation");
893
894#if FZ_ENABLE_ICC
895 if (ctx->icc_enabled)
896 {
897 /* Handle identity case. */
898 if (ss == ds || (!memcmp(ss->u.icc.md5, ds->u.icc.md5, 16)))
899 {
900 cc->convert = fz_lookup_fast_color_converter(ctx, ss, ds);
901 return;
902 }
903
904 /* Handle DeviceGray to CMYK as K only. See note in Section 6.3 of PDF spec 1.7. */
905 if (ss->type == FZ_COLORSPACE_GRAY && (ss->flags & FZ_COLORSPACE_IS_DEVICE))
906 {
907 if (ds->type == FZ_COLORSPACE_CMYK)
908 {
909 cc->convert = fz_lookup_fast_color_converter(ctx, ss, ds);
910 return;
911 }
912 }
913
914 fz_try(ctx)
915 {
916 cc->link = fz_find_icc_link(ctx, ss, 0, ds, 0, is, params, 1, 0);
917 cc->convert = fz_icc_transform_color;
918 }
919 fz_catch(ctx)
920 {
921 fz_warn(ctx, "cannot create ICC link, falling back to fast color conversion");
922 cc->convert = fz_lookup_fast_color_converter(ctx, ss, ds);
923 }
924 }
925 else
926 {
927 cc->convert = fz_lookup_fast_color_converter(ctx, ss, ds);
928 }
929#else
930 cc->convert = fz_lookup_fast_color_converter(ctx, ss, ds);
931#endif
932}
933
934void
935fz_find_color_converter(fz_context *ctx, fz_color_converter *cc, fz_colorspace *ss, fz_colorspace *ds, fz_colorspace *is, fz_color_params params)
936{
937 cc->ds = ds;
938#if FZ_ENABLE_ICC
939 cc->link = NULL;
940#endif
941
942 if (ds->type == FZ_COLORSPACE_INDEXED)
943 fz_throw(ctx, FZ_ERROR_GENERIC, "Cannot convert into Indexed colorspace.");
944 if (ds->type == FZ_COLORSPACE_SEPARATION)
945 fz_throw(ctx, FZ_ERROR_GENERIC, "Cannot convert into Separation colorspace.");
946
947 if (ss->type == FZ_COLORSPACE_INDEXED)
948 {
949 cc->ss = ss->u.indexed.base;
950 cc->ss_via = ss;
951 fz_init_process_color_converter(ctx, cc, ss->u.indexed.base, ds, is, params);
952 cc->convert_via = cc->convert;
953 cc->convert = indexed_via_base;
954 }
955 else if (ss->type == FZ_COLORSPACE_SEPARATION)
956 {
957 cc->ss = ss->u.separation.base;
958 cc->ss_via = ss;
959 fz_init_process_color_converter(ctx, cc, ss->u.separation.base, ds, is, params);
960 cc->convert_via = cc->convert;
961 cc->convert = separation_via_base;
962 }
963 else
964 {
965 cc->ss = ss;
966 fz_init_process_color_converter(ctx, cc, ss, ds, is, params);
967 }
968}
969
970void
971fz_drop_color_converter(fz_context *ctx, fz_color_converter *cc)
972{
973#if FZ_ENABLE_ICC
974 if (cc->link)
975 {
976 fz_drop_icc_link(ctx, cc->link);
977 cc->link = NULL;
978 }
979#endif
980}
981
982void
983fz_convert_color(fz_context *ctx, fz_colorspace *ss, const float *sv, fz_colorspace *ds, float *dv, fz_colorspace *is, fz_color_params params)
984{
985 fz_color_converter cc;
986 fz_find_color_converter(ctx, &cc, ss, ds, is, params);
987 cc.convert(ctx, &cc, sv, dv);
988 fz_drop_color_converter(ctx, &cc);
989}
990
991/* Cached color converter using hash table. */
992
993typedef struct fz_cached_color_converter
994{
995 fz_color_converter base;
996 fz_hash_table *hash;
997} fz_cached_color_converter;
998
999static void fz_cached_color_convert(fz_context *ctx, fz_color_converter *cc_, const float *ss, float *ds)
1000{
1001 fz_cached_color_converter *cc = cc_->opaque;
1002 float *val = fz_hash_find(ctx, cc->hash, ss);
1003 int n = cc->base.ds->n * sizeof(float);
1004
1005 if (val)
1006 {
1007 memcpy(ds, val, n);
1008 return;
1009 }
1010
1011 cc->base.convert(ctx, &cc->base, ss, ds);
1012
1013 val = fz_malloc(ctx, n);
1014 memcpy(val, ds, n);
1015 fz_try(ctx)
1016 fz_hash_insert(ctx, cc->hash, ss, val);
1017 fz_catch(ctx)
1018 fz_free(ctx, val);
1019}
1020
1021void fz_init_cached_color_converter(fz_context *ctx, fz_color_converter *cc, fz_colorspace *ss, fz_colorspace *ds, fz_colorspace *is, fz_color_params params)
1022{
1023 int n = ss->n;
1024 fz_cached_color_converter *cached = fz_malloc_struct(ctx, fz_cached_color_converter);
1025
1026 cc->opaque = cached;
1027 cc->convert = fz_cached_color_convert;
1028 cc->ss = ss;
1029 cc->ds = ds;
1030#if FZ_ENABLE_ICC
1031 cc->link = NULL;
1032#endif
1033
1034 fz_try(ctx)
1035 {
1036 fz_find_color_converter(ctx, &cached->base, ss, ds, is, params);
1037 cached->hash = fz_new_hash_table(ctx, 256, n * sizeof(float), -1, fz_free);
1038 }
1039 fz_catch(ctx)
1040 {
1041 fz_drop_color_converter(ctx, &cached->base);
1042 fz_drop_hash_table(ctx, cached->hash);
1043 fz_free(ctx, cached);
1044 cc->opaque = NULL;
1045 fz_rethrow(ctx);
1046 }
1047}
1048
1049void fz_fin_cached_color_converter(fz_context *ctx, fz_color_converter *cc_)
1050{
1051 fz_cached_color_converter *cc;
1052 if (cc_ == NULL)
1053 return;
1054 cc = cc_->opaque;
1055 if (cc == NULL)
1056 return;
1057 cc_->opaque = NULL;
1058 fz_drop_hash_table(ctx, cc->hash);
1059 fz_drop_color_converter(ctx, &cc->base);
1060 fz_free(ctx, cc);
1061}
1062
1063/* Pixmap color conversion */
1064
1065void
1066fz_convert_slow_pixmap_samples(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst, fz_colorspace *is, fz_color_params params, int copy_spots)
1067{
1068 float srcv[FZ_MAX_COLORS];
1069 float dstv[FZ_MAX_COLORS];
1070 int srcn, dstn;
1071 int k, i;
1072 size_t w = src->w;
1073 int h = src->h;
1074 ptrdiff_t d_line_inc = dst->stride - w * dst->n;
1075 ptrdiff_t s_line_inc = src->stride - w * src->n;
1076 int da = dst->alpha;
1077 int sa = src->alpha;
1078 int alpha = 255;
1079
1080 fz_colorspace *ss = src->colorspace;
1081 fz_colorspace *ds = dst->colorspace;
1082
1083 unsigned char *s = src->samples;
1084 unsigned char *d = dst->samples;
1085
1086 if ((int)w < 0 || h < 0)
1087 return;
1088
1089 srcn = ss->n;
1090 dstn = ds->n;
1091
1092 /* No spot colors allowed here! */
1093 assert(src->s == 0);
1094 assert(dst->s == 0);
1095
1096 assert(src->w == dst->w && src->h == dst->h);
1097 assert(src->n == srcn + sa);
1098 assert(dst->n == dstn + da);
1099
1100 if (d_line_inc == 0 && s_line_inc == 0)
1101 {
1102 w *= h;
1103 h = 1;
1104 }
1105
1106 /* Special case for Lab colorspace (scaling of components to float) */
1107 if (ss->type == FZ_COLORSPACE_LAB)
1108 {
1109 fz_color_converter cc;
1110
1111 fz_find_color_converter(ctx, &cc, ss, ds, is, params);
1112 while (h--)
1113 {
1114 size_t ww = w;
1115 while (ww--)
1116 {
1117 if (sa)
1118 {
1119 alpha = s[4];
1120 srcv[0] = fz_div255(s[0], alpha) / 255.0f * 100;
1121 srcv[1] = fz_div255(s[1], alpha) - 128;
1122 srcv[2] = fz_div255(s[2], alpha) - 128;
1123 s += 4;
1124 }
1125 else
1126 {
1127 srcv[0] = s[0] / 255.0f * 100;
1128 srcv[1] = s[1] - 128;
1129 srcv[2] = s[2] - 128;
1130 s += 3;
1131 }
1132
1133 cc.convert(ctx, &cc, srcv, dstv);
1134
1135 if (da)
1136 {
1137 for (k = 0; k < dstn; k++)
1138 *d++ = fz_mul255(dstv[k] * 255, alpha);
1139 *d++ = alpha;
1140 }
1141 else
1142 {
1143 for (k = 0; k < dstn; k++)
1144 *d++ = dstv[k] * 255;
1145 }
1146 }
1147 d += d_line_inc;
1148 s += s_line_inc;
1149 }
1150 fz_drop_color_converter(ctx, &cc);
1151 }
1152
1153 /* Brute-force for small images */
1154 else if (w*h < 256)
1155 {
1156 fz_color_converter cc;
1157
1158 fz_find_color_converter(ctx, &cc, ss, ds, is, params);
1159 while (h--)
1160 {
1161 size_t ww = w;
1162 while (ww--)
1163 {
1164 if (sa)
1165 {
1166 alpha = s[srcn];
1167 for (k = 0; k < srcn; k++)
1168 srcv[k] = fz_div255(s[k], alpha) / 255.0f;
1169 s += srcn + 1;
1170 }
1171 else
1172 {
1173 for (k = 0; k < srcn; k++)
1174 srcv[k] = s[k] / 255.0f;
1175 s += srcn;
1176 }
1177
1178 cc.convert(ctx, &cc, srcv, dstv);
1179
1180 if (da)
1181 {
1182 for (k = 0; k < dstn; k++)
1183 *d++ = fz_mul255(dstv[k] * 255, alpha);
1184 *d++ = alpha;
1185 }
1186 else
1187 {
1188 for (k = 0; k < dstn; k++)
1189 *d++ = dstv[k] * 255;
1190 }
1191 }
1192 d += d_line_inc;
1193 s += s_line_inc;
1194 }
1195 fz_drop_color_converter(ctx, &cc);
1196 }
1197
1198 /* 1-d lookup table for single channel colorspaces */
1199 else if (srcn == 1)
1200 {
1201 unsigned char lookup[FZ_MAX_COLORS * 256];
1202 fz_color_converter cc;
1203
1204 fz_find_color_converter(ctx, &cc, ss, ds, is, params);
1205 for (i = 0; i < 256; i++)
1206 {
1207 srcv[0] = i / 255.0f;
1208 cc.convert(ctx, &cc, srcv, dstv);
1209 for (k = 0; k < dstn; k++)
1210 lookup[i * dstn + k] = dstv[k] * 255;
1211 }
1212 fz_drop_color_converter(ctx, &cc);
1213
1214 while (h--)
1215 {
1216 size_t ww = w;
1217 while (ww--)
1218 {
1219 if (sa)
1220 {
1221 alpha = s[1];
1222 i = fz_div255(s[0], alpha);
1223 s += 2;
1224 }
1225 else
1226 {
1227 i = *s++;
1228 }
1229
1230 if (da)
1231 {
1232 for (k = 0; k < dstn; k++)
1233 *d++ = fz_mul255(lookup[i * dstn + k], alpha);
1234 *d++ = alpha;
1235 }
1236 else
1237 {
1238 for (k = 0; k < dstn; k++)
1239 *d++ = lookup[i * dstn + k];
1240 }
1241 }
1242 d += d_line_inc;
1243 s += s_line_inc;
1244 }
1245 }
1246
1247 /* Memoize colors using a hash table for the general case */
1248 else
1249 {
1250 fz_hash_table *lookup;
1251 unsigned char *color;
1252 unsigned char dummy = s[0] ^ 255;
1253 unsigned char *sold = &dummy;
1254 unsigned char *dold;
1255 fz_color_converter cc;
1256
1257 lookup = fz_new_hash_table(ctx, 509, srcn+sa, -1, NULL);
1258 fz_find_color_converter(ctx, &cc, ss, ds, is, params);
1259
1260 fz_try(ctx)
1261 {
1262 while (h--)
1263 {
1264 size_t ww = w;
1265 while (ww--)
1266 {
1267 if (*s == *sold && memcmp(sold,s,srcn+sa) == 0)
1268 {
1269 sold = s;
1270 memcpy(d, dold, dstn+da);
1271 }
1272 else
1273 {
1274 sold = s;
1275 dold = d;
1276 color = fz_hash_find(ctx, lookup, s);
1277 if (color)
1278 {
1279 memcpy(d, color, dstn+da);
1280 }
1281 else
1282 {
1283 if (sa)
1284 {
1285 alpha = s[srcn];
1286 for (k = 0; k < srcn; k++)
1287 srcv[k] = fz_div255(s[k], alpha) / 255.0f;
1288 }
1289 else
1290 {
1291 for (k = 0; k < srcn; k++)
1292 srcv[k] = s[k] / 255.0f;
1293 }
1294
1295 cc.convert(ctx, &cc, srcv, dstv);
1296
1297 if (da)
1298 {
1299 for (k = 0; k < dstn; k++)
1300 d[k] = fz_mul255(dstv[k] * 255, alpha);
1301 d[k] = alpha;
1302 }
1303 else
1304 {
1305 for (k = 0; k < dstn; k++)
1306 d[k] = dstv[k] * 255;
1307 }
1308
1309 fz_hash_insert(ctx, lookup, s, d);
1310 }
1311 }
1312 s += srcn + sa;
1313 d += dstn + da;
1314 }
1315 d += d_line_inc;
1316 s += s_line_inc;
1317 }
1318 }
1319 fz_always(ctx)
1320 {
1321 fz_drop_color_converter(ctx, &cc);
1322 fz_drop_hash_table(ctx, lookup);
1323 }
1324 fz_catch(ctx)
1325 fz_rethrow(ctx);
1326
1327 }
1328}
1329
1330void
1331fz_convert_pixmap_samples(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst,
1332 fz_colorspace *prf,
1333 const fz_default_colorspaces *default_cs,
1334 fz_color_params params,
1335 int copy_spots)
1336{
1337#if FZ_ENABLE_ICC
1338 fz_colorspace *ss = src->colorspace;
1339 fz_colorspace *ds = dst->colorspace;
1340 fz_pixmap *base_idx = NULL;
1341 fz_pixmap *base_sep = NULL;
1342 fz_icc_link *link = NULL;
1343
1344 fz_var(link);
1345 fz_var(base_idx);
1346 fz_var(base_sep);
1347
1348 if (!ds)
1349 {
1350 fz_fast_any_to_alpha(ctx, src, dst, copy_spots);
1351 return;
1352 }
1353
1354 fz_try(ctx)
1355 {
1356 /* Convert indexed into base colorspace. */
1357 if (ss->type == FZ_COLORSPACE_INDEXED)
1358 {
1359 src = base_idx = fz_convert_indexed_pixmap_to_base(ctx, src);
1360 ss = src->colorspace;
1361 }
1362
1363 /* Convert separation into base colorspace. */
1364 if (ss->type == FZ_COLORSPACE_SEPARATION)
1365 {
1366 src = base_sep = fz_convert_separation_pixmap_to_base(ctx, src);
1367 ss = src->colorspace;
1368 }
1369
1370 /* Substitute Device colorspace with page Default colorspace: */
1371 if (ss->flags & FZ_COLORSPACE_IS_DEVICE)
1372 {
1373 switch (ss->type)
1374 {
1375 default: break;
1376 case FZ_COLORSPACE_GRAY: ss = fz_default_gray(ctx, default_cs); break;
1377 case FZ_COLORSPACE_RGB: ss = fz_default_rgb(ctx, default_cs); break;
1378 case FZ_COLORSPACE_CMYK: ss = fz_default_cmyk(ctx, default_cs); break;
1379 }
1380 }
1381
1382 if (!ctx->icc_enabled)
1383 {
1384 fz_convert_fast_pixmap_samples(ctx, src, dst, copy_spots);
1385 }
1386
1387 /* Handle identity case. */
1388 else if (ss == ds || (!memcmp(ss->u.icc.md5, ds->u.icc.md5, 16)))
1389 {
1390 fz_convert_fast_pixmap_samples(ctx, src, dst, copy_spots);
1391 }
1392
1393 /* Handle DeviceGray to CMYK as K only. See note in Section 6.3 of PDF spec 1.7. */
1394 else if ((ss->flags & FZ_COLORSPACE_IS_DEVICE) &&
1395 (ss->type == FZ_COLORSPACE_GRAY) &&
1396 (ds->type == FZ_COLORSPACE_CMYK))
1397 {
1398 fz_convert_fast_pixmap_samples(ctx, src, dst, copy_spots);
1399 }
1400
1401 /* Use slow conversion path for indexed. */
1402 else if (ss->type == FZ_COLORSPACE_INDEXED)
1403 {
1404 fz_convert_slow_pixmap_samples(ctx, src, dst, prf, params, copy_spots);
1405 }
1406
1407 /* Use slow conversion path for separation. */
1408 else if (ss->type == FZ_COLORSPACE_SEPARATION)
1409 {
1410 fz_convert_slow_pixmap_samples(ctx, src, dst, prf, params, copy_spots);
1411 }
1412
1413 else
1414 {
1415 fz_try(ctx)
1416 {
1417 int sx = src->s + src->alpha;
1418 int dx = dst->s + dst->alpha;
1419 link = fz_find_icc_link(ctx, ss, sx, ds, dx, prf, params, 0, copy_spots);
1420 fz_icc_transform_pixmap(ctx, link, src, dst, copy_spots);
1421 }
1422 fz_catch(ctx)
1423 {
1424 fz_warn(ctx, "falling back to fast color conversion");
1425 fz_convert_fast_pixmap_samples(ctx, src, dst, copy_spots);
1426 }
1427 }
1428 }
1429 fz_always(ctx)
1430 {
1431 fz_drop_icc_link(ctx, link);
1432 fz_drop_pixmap(ctx, base_sep);
1433 fz_drop_pixmap(ctx, base_idx);
1434 }
1435 fz_catch(ctx)
1436 fz_rethrow(ctx);
1437#else
1438 fz_convert_fast_pixmap_samples(ctx, src, dst, copy_spots);
1439#endif
1440}
1441