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