1 #include "mupdf/fitz.h"
2 
3 #include "color-imp.h"
4 #include "pixmap-imp.h"
5 
6 #include <assert.h>
7 #include <string.h>
8 
9 enum
10 {
11 	FZ_SEPARATION_DISABLED_RENDER = 3
12 };
13 
14 struct fz_separations
15 {
16 	int refs;
17 	int num_separations;
18 	int controllable;
19 	uint32_t state[(2*FZ_MAX_SEPARATIONS + 31) / 32];
20 	fz_colorspace *cs[FZ_MAX_SEPARATIONS];
21 	uint8_t cs_pos[FZ_MAX_SEPARATIONS];
22 	uint32_t rgba[FZ_MAX_SEPARATIONS];
23 	uint32_t cmyk[FZ_MAX_SEPARATIONS];
24 	char *name[FZ_MAX_SEPARATIONS];
25 };
26 
fz_new_separations(fz_context * ctx,int controllable)27 fz_separations *fz_new_separations(fz_context *ctx, int controllable)
28 {
29 	fz_separations *sep;
30 
31 	sep = fz_malloc_struct(ctx, fz_separations);
32 	sep->refs = 1;
33 	sep->controllable = controllable;
34 
35 	return sep;
36 }
37 
fz_keep_separations(fz_context * ctx,fz_separations * sep)38 fz_separations *fz_keep_separations(fz_context *ctx, fz_separations *sep)
39 {
40 	return fz_keep_imp(ctx, sep, &sep->refs);
41 }
42 
fz_drop_separations(fz_context * ctx,fz_separations * sep)43 void fz_drop_separations(fz_context *ctx, fz_separations *sep)
44 {
45 	if (fz_drop_imp(ctx, sep, &sep->refs))
46 	{
47 		int i;
48 		for (i = 0; i < sep->num_separations; i++)
49 		{
50 			fz_free(ctx, sep->name[i]);
51 			fz_drop_colorspace(ctx, sep->cs[i]);
52 		}
53 		fz_free(ctx, sep);
54 	}
55 }
56 
fz_add_separation(fz_context * ctx,fz_separations * sep,const char * name,fz_colorspace * cs,int colorant)57 void fz_add_separation(fz_context *ctx, fz_separations *sep, const char *name, fz_colorspace *cs, int colorant)
58 {
59 	int n;
60 
61 	if (!sep)
62 		fz_throw(ctx, FZ_ERROR_GENERIC, "can't add to non-existent separations");
63 
64 	n = sep->num_separations;
65 	if (n == FZ_MAX_SEPARATIONS)
66 		fz_throw(ctx, FZ_ERROR_GENERIC, "too many separations");
67 
68 	sep->name[n] = fz_strdup(ctx, name);
69 	sep->cs[n] = fz_keep_colorspace(ctx, cs);
70 	sep->cs_pos[n] = colorant;
71 
72 	sep->num_separations++;
73 }
74 
fz_add_separation_equivalents(fz_context * ctx,fz_separations * sep,uint32_t rgba,uint32_t cmyk,const char * name)75 void fz_add_separation_equivalents(fz_context *ctx, fz_separations *sep, uint32_t rgba, uint32_t cmyk, const char *name)
76 {
77 	int n;
78 
79 	if (!sep)
80 		fz_throw(ctx, FZ_ERROR_GENERIC, "can't add to non-existent separations");
81 
82 	n = sep->num_separations;
83 	if (n == FZ_MAX_SEPARATIONS)
84 		fz_throw(ctx, FZ_ERROR_GENERIC, "too many separations");
85 
86 	sep->name[n] = fz_strdup(ctx, name);
87 	sep->rgba[n] = rgba;
88 	sep->cmyk[n] = cmyk;
89 
90 	sep->num_separations++;
91 }
92 
fz_set_separation_behavior(fz_context * ctx,fz_separations * sep,int separation,fz_separation_behavior beh)93 void fz_set_separation_behavior(fz_context *ctx, fz_separations *sep, int separation, fz_separation_behavior beh)
94 {
95 	int shift;
96 	fz_separation_behavior old;
97 
98 	if (!sep || separation < 0 || separation >= sep->num_separations)
99 		fz_throw(ctx, FZ_ERROR_GENERIC, "can't control non-existent separation");
100 
101 	if (beh == FZ_SEPARATION_DISABLED && !sep->controllable)
102 		beh = FZ_SEPARATION_DISABLED_RENDER;
103 
104 	shift = ((2*separation) & 31);
105 	separation >>= 4;
106 
107 	old = (sep->state[separation]>>shift) & 3;
108 
109 	if (old == (fz_separation_behavior)FZ_SEPARATION_DISABLED_RENDER)
110 		old = FZ_SEPARATION_DISABLED;
111 
112 	/* If no change, great */
113 	if (old == beh)
114 		return;
115 
116 	sep->state[separation] = (sep->state[separation] & ~(3<<shift)) | (beh<<shift);
117 
118 	/* FIXME: Could only empty images from the store, or maybe only
119 	 * images that depend on separations. */
120 	fz_empty_store(ctx);
121 }
122 
123 static inline fz_separation_behavior
sep_state(const fz_separations * sep,int i)124 sep_state(const fz_separations *sep, int i)
125 {
126 	return (fz_separation_behavior)((sep->state[i>>5]>>((2*i) & 31)) & 3);
127 }
128 
fz_separation_current_behavior_internal(fz_context * ctx,const fz_separations * sep,int separation)129 fz_separation_behavior fz_separation_current_behavior_internal(fz_context *ctx, const fz_separations *sep, int separation)
130 {
131 	if (!sep || separation < 0 || separation >= sep->num_separations)
132 		fz_throw(ctx, FZ_ERROR_GENERIC, "can't disable non-existent separation");
133 
134 	return sep_state(sep, separation);
135 }
136 
fz_separation_current_behavior(fz_context * ctx,const fz_separations * sep,int separation)137 fz_separation_behavior fz_separation_current_behavior(fz_context *ctx, const fz_separations *sep, int separation)
138 {
139 	int beh = fz_separation_current_behavior_internal(ctx, sep, separation);
140 
141 	if (beh == FZ_SEPARATION_DISABLED_RENDER)
142 		return FZ_SEPARATION_DISABLED;
143 	return beh;
144 }
145 
fz_separation_name(fz_context * ctx,const fz_separations * sep,int separation)146 const char *fz_separation_name(fz_context *ctx, const fz_separations *sep, int separation)
147 {
148 	if (!sep || separation < 0 || separation >= sep->num_separations)
149 		fz_throw(ctx, FZ_ERROR_GENERIC, "can't access non-existent separation");
150 
151 	return sep->name[separation];
152 }
153 
fz_count_separations(fz_context * ctx,const fz_separations * sep)154 int fz_count_separations(fz_context *ctx, const fz_separations *sep)
155 {
156 	if (!sep)
157 		return 0;
158 	return sep->num_separations;
159 }
160 
fz_count_active_separations(fz_context * ctx,const fz_separations * sep)161 int fz_count_active_separations(fz_context *ctx, const fz_separations *sep)
162 {
163 	int i, n, c;
164 
165 	if (!sep)
166 		return 0;
167 	n = sep->num_separations;
168 	c = 0;
169 	for (i = 0; i < n; i++)
170 		if (sep_state(sep, i) == FZ_SEPARATION_SPOT)
171 			c++;
172 	return c;
173 }
174 
fz_clone_separations_for_overprint(fz_context * ctx,fz_separations * sep)175 fz_separations *fz_clone_separations_for_overprint(fz_context *ctx, fz_separations *sep)
176 {
177 	int i, j, n, c;
178 	fz_separations *clone;
179 
180 	if (!sep)
181 		return NULL;
182 
183 	n = sep->num_separations;
184 	if (n == 0)
185 		return NULL;
186 	c = 0;
187 	for (i = 0; i < n; i++)
188 	{
189 		fz_separation_behavior state = sep_state(sep, i);
190 		if (state == FZ_SEPARATION_COMPOSITE)
191 			c++;
192 	}
193 
194 	/* If no composites, then we don't need to create a new seps object
195 	 * with the composite ones enabled, so just reuse our current object. */
196 	if (c == 0)
197 		return fz_keep_separations(ctx, sep);
198 
199 	/* We need to clone us a separation structure, with all
200 	 * the composite separations marked as enabled. */
201 	clone = fz_malloc_struct(ctx, fz_separations);
202 	clone->refs = 1;
203 	clone->controllable = 0;
204 
205 	fz_try(ctx)
206 	{
207 		for (i = 0; i < n; i++)
208 		{
209 			fz_separation_behavior beh = sep_state(sep, i);
210 			if (beh == FZ_SEPARATION_DISABLED)
211 				continue;
212 			j = clone->num_separations++;
213 			if (beh == FZ_SEPARATION_COMPOSITE)
214 				beh = FZ_SEPARATION_SPOT;
215 			fz_set_separation_behavior(ctx, clone, j, beh);
216 			clone->name[j] = sep->name[i] ? fz_strdup(ctx, sep->name[i]) : NULL;
217 			clone->cs[j] = fz_keep_colorspace(ctx, sep->cs[i]);
218 			clone->cs_pos[j] = sep->cs_pos[i];
219 		}
220 	}
221 	fz_catch(ctx)
222 	{
223 		fz_drop_separations(ctx, clone);
224 		fz_rethrow(ctx);
225 	}
226 
227 	return clone;
228 }
229 
230 fz_pixmap *
fz_clone_pixmap_area_with_different_seps(fz_context * ctx,fz_pixmap * src,const fz_irect * bbox,fz_colorspace * dcs,fz_separations * dseps,fz_color_params color_params,fz_default_colorspaces * default_cs)231 fz_clone_pixmap_area_with_different_seps(fz_context *ctx, fz_pixmap *src, const fz_irect *bbox, fz_colorspace *dcs, fz_separations *dseps, fz_color_params color_params, fz_default_colorspaces *default_cs)
232 {
233 	fz_irect local_bbox;
234 	fz_pixmap *dst, *pix;
235 
236 	if (bbox == NULL)
237 	{
238 		local_bbox.x0 = src->x;
239 		local_bbox.y0 = src->y;
240 		local_bbox.x1 = src->x + src->w;
241 		local_bbox.y1 = src->y + src->h;
242 		bbox = &local_bbox;
243 	}
244 
245 	dst = fz_new_pixmap_with_bbox(ctx, dcs, *bbox, dseps, src->alpha);
246 	if (src->flags & FZ_PIXMAP_FLAG_INTERPOLATE)
247 		dst->flags |= FZ_PIXMAP_FLAG_INTERPOLATE;
248 	else
249 		dst->flags &= ~FZ_PIXMAP_FLAG_INTERPOLATE;
250 
251 	fz_try(ctx)
252 		pix = fz_copy_pixmap_area_converting_seps(ctx, src, dst, NULL, color_params, default_cs);
253 	fz_catch(ctx)
254 	{
255 		fz_drop_pixmap(ctx, dst);
256 		fz_rethrow(ctx);
257 	}
258 
259 	return pix;
260 }
261 
262 fz_pixmap *
fz_copy_pixmap_area_converting_seps(fz_context * ctx,fz_pixmap * src,fz_pixmap * dst,fz_colorspace * prf,fz_color_params color_params,fz_default_colorspaces * default_cs)263 fz_copy_pixmap_area_converting_seps(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst, fz_colorspace *prf, fz_color_params color_params, fz_default_colorspaces *default_cs)
264 {
265 	int dw = dst->w;
266 	int dh = dst->h;
267 	fz_separations *sseps = src->seps;
268 	fz_separations *dseps = dst->seps;
269 	int sseps_n = sseps ? sseps->num_separations : 0;
270 	int dseps_n = dseps ? dseps->num_separations : 0;
271 	int sstride = src->stride;
272 	int dstride = dst->stride;
273 	int sn = src->n;
274 	int dn = dst->n;
275 	int sa = src->alpha;
276 	int da = dst->alpha;
277 	int ss = src->s;
278 	int ds = dst->s;
279 	int sc = sn - ss - sa;
280 	int dc = dn - ds - da;
281 	const unsigned char *sdata = src->samples + sstride * (dst->y - src->y) + (dst->x - src->x) * sn;
282 	unsigned char *ddata = dst->samples;
283 	signed char map[FZ_MAX_COLORS];
284 	int x, y, i, j, k, n;
285 	unsigned char mapped[FZ_MAX_COLORS];
286 	int unmapped = sseps_n;
287 	int src_is_device_n = fz_colorspace_is_device_n(ctx, src->colorspace);
288 	fz_colorspace *proof_cs = (prf == src->colorspace ? NULL : prf);
289 
290 	assert(da == sa);
291 	assert(ss == fz_count_active_separations(ctx, sseps));
292 	assert(ds == fz_count_active_separations(ctx, dseps));
293 
294 	dstride -= dn * dw;
295 	sstride -= sn * dw;
296 
297 	/* Process colorants (and alpha) first */
298 	if (dst->colorspace == src->colorspace && proof_cs == NULL)
299 	{
300 		/* Simple copy */
301 		unsigned char *dd = ddata;
302 		const unsigned char *sd = sdata;
303 		for (y = dh; y > 0; y--)
304 		{
305 			for (x = dw; x > 0; x--)
306 			{
307 				for (i = 0; i < dc; i++)
308 					dd[i] = sd[i];
309 				dd += dn;
310 				sd += sn;
311 				if (da)
312 					dd[-1] = sd[-1];
313 			}
314 			dd += dstride;
315 			sd += sstride;
316 		}
317 	}
318 	else if (src_is_device_n)
319 	{
320 		fz_color_converter cc;
321 
322 		/* Init the target pixmap. */
323 		if (!da)
324 		{
325 			/* No alpha to worry about, just clear it. */
326 			fz_clear_pixmap(ctx, dst);
327 		}
328 		else if (fz_colorspace_is_subtractive(ctx, dst->colorspace))
329 		{
330 			/* Subtractive space, so copy the alpha, and set process and spot colors to 0. */
331 			unsigned char *dd = ddata;
332 			const unsigned char *sd = sdata;
333 			int dcs = dc + ds;
334 			for (y = dh; y > 0; y--)
335 			{
336 				for (x = dw; x > 0; x--)
337 				{
338 					for (i = 0; i < dcs; i++)
339 						dd[i] = 0;
340 					dd += dn;
341 					sd += sn;
342 					dd[-1] = sd[-1];
343 				}
344 				dd += dstride;
345 				sd += sstride;
346 			}
347 		}
348 		else
349 		{
350 			/* Additive space; tricky case. We need to copy the alpha, and
351 			 * init the process colors "full", and the spots to 0. Because
352 			 * we are in an additive space, and premultiplied, this means
353 			 * setting the process colors to alpha. */
354 			unsigned char *dd = ddata;
355 			const unsigned char *sd = sdata + sn - 1;
356 			int dcs = dc + ds;
357 			for (y = dh; y > 0; y--)
358 			{
359 				for (x = dw; x > 0; x--)
360 				{
361 					int a = *sd;
362 					for (i = 0; i < dc; i++)
363 						dd[i] = a;
364 					for (; i < dcs; i++)
365 						dd[i] = 0;
366 					dd[i] = a;
367 					dd += dn;
368 					sd += sn;
369 				}
370 				dd += dstride;
371 				sd += sstride;
372 			}
373 		}
374 
375 		/* Now map the colorants down. */
376 		n = fz_colorspace_n(ctx, src->colorspace);
377 
378 		fz_find_color_converter(ctx, &cc, src->colorspace, dst->colorspace, proof_cs, color_params);
379 
380 		fz_try(ctx)
381 		{
382 			unmapped = 0;
383 			for (i = 0; i < n; i++)
384 			{
385 				const char *name = fz_colorspace_colorant(ctx, src->colorspace, i);
386 
387 				mapped[i] = 1;
388 
389 				if (name)
390 				{
391 					if (!strcmp(name, "None")) {
392 						mapped[i] = 0;
393 						continue;
394 					}
395 					if (!strcmp(name, "All"))
396 					{
397 						int n1 = dn - da;
398 						unsigned char *dd = ddata;
399 						const unsigned char *sd = sdata + i;
400 
401 						for (y = dh; y > 0; y--)
402 						{
403 							for (x = dw; x > 0; x--)
404 							{
405 								unsigned char v = *sd;
406 								sd += sn;
407 								for (k = 0; k < n1; k++)
408 									dd[k] = v;
409 								dd += dn;
410 							}
411 							dd += dstride;
412 							sd += sstride;
413 						}
414 						continue;
415 					}
416 					for (j = 0; j < dc; j++)
417 					{
418 						const char *dname = fz_colorspace_colorant(ctx, dst->colorspace, j);
419 						if (dname && !strcmp(name, dname))
420 							goto map_device_n_spot;
421 					}
422 					for (j = 0; j < dseps_n; j++)
423 					{
424 						const char *dname = dseps->name[j];
425 						if (dname && !strcmp(name, dname))
426 						{
427 							j += dc;
428 							goto map_device_n_spot;
429 						}
430 					}
431 				}
432 				if (0)
433 				{
434 					unsigned char *dd;
435 					const unsigned char *sd;
436 	map_device_n_spot:
437 					/* Directly map a devicen colorant to a
438 					 * component (either process or spot)
439 					 * in the destination. */
440 					dd = ddata + j;
441 					sd = sdata + i;
442 
443 					for (y = dh; y > 0; y--)
444 					{
445 						for (x = dw; x > 0; x--)
446 						{
447 							*dd = *sd;
448 							dd += dn;
449 							sd += sn;
450 						}
451 						dd += dstride;
452 						sd += sstride;
453 					}
454 				}
455 				else
456 				{
457 					unmapped = 1;
458 					mapped[i] = 0;
459 				}
460 			}
461 			if (unmapped)
462 			{
463 /* The standard spot mapping algorithm assumes that it's reasonable
464  * to treat the components of deviceN spaces as being orthogonal,
465  * and to add them together at the end. This avoids a color lookup
466  * per pixel. The alternative mapping algorithm looks up each
467  * pixel at a time, and is hence slower. */
468 #define ALTERNATIVE_SPOT_MAP
469 #ifndef ALTERNATIVE_SPOT_MAP
470 				for (i = 0; i < n; i++)
471 				{
472 					unsigned char *dd = ddata;
473 					const unsigned char *sd = sdata;
474 					float convert[FZ_MAX_COLORS];
475 					float colors[FZ_MAX_COLORS];
476 
477 					if (mapped[i])
478 						continue;
479 
480 					/* Src component i is not mapped. We need to convert that down. */
481 					memset(colors, 0, sizeof(float) * n);
482 					colors[i] = 1;
483 					cc.convert(ctx, &cc, colors, convert);
484 
485 					if (fz_colorspace_is_subtractive(ctx, dst->colorspace))
486 					{
487 						if (sa)
488 						{
489 							for (y = dh; y > 0; y--)
490 							{
491 								for (x = dw; x > 0; x--)
492 								{
493 									unsigned char v = sd[i];
494 									sd += sn;
495 									if (v != 0)
496 									{
497 										int a = dd[-1];
498 										for (j = 0; j < dc; j++)
499 											dd[j] = fz_clampi(dd[j] + v * convert[j], 0, a);
500 									}
501 									dd += dn;
502 								}
503 								dd += dstride;
504 								sd += sstride;
505 							}
506 						}
507 						else
508 						{
509 							for (y = dh; y > 0; y--)
510 							{
511 								for (x = dw; x > 0; x--)
512 								{
513 									unsigned char v = sd[i];
514 									if (v != 0)
515 									{
516 										for (j = 0; j < dc; j++)
517 											dd[j] = fz_clampi(dd[j] + v * convert[j], 0, 255);
518 									}
519 									dd += dn;
520 									sd += sn;
521 								}
522 								dd += dstride;
523 								sd += sstride;
524 							}
525 						}
526 					}
527 					else
528 					{
529 						if (sa)
530 						{
531 							for (y = dh; y > 0; y--)
532 							{
533 								for (x = dw; x > 0; x--)
534 								{
535 									unsigned char v = sd[i];
536 									sd += sn;
537 									if (v != 0)
538 									{
539 										int a = sd[-1];
540 										for (j = 0; j < dc; j++)
541 											dd[j] = fz_clampi(dd[j] - v * (1-convert[j]), 0, a);
542 									}
543 									dd += dn;
544 								}
545 								dd += dstride;
546 								sd += sstride;
547 							}
548 						}
549 						else
550 						{
551 							for (y = dh; y > 0; y--)
552 							{
553 								for (x = dw; x > 0; x--)
554 								{
555 									unsigned char v = sd[i];
556 									if (v != 0)
557 									{
558 										for (j = 0; j < dc; j++)
559 											dd[j] = fz_clampi(dd[j] - v * (1-convert[j]), 0, 255);
560 									}
561 									dd += dn;
562 									sd += sn;
563 								}
564 								dd += dstride;
565 								sd += sstride;
566 							}
567 						}
568 					}
569 				}
570 #else
571 /* If space is subtractive then treat spots like Adobe does in Photoshop.
572  * Which is to just use an equivalent CMYK value.  If we are in an additive
573  * color space we will need to convert on a pixel-by-pixel basis.
574  */
575 				float convert[FZ_MAX_COLORS];
576 				float colors[FZ_MAX_COLORS];
577 
578 				if (fz_colorspace_is_subtractive(ctx, dst->colorspace))
579 				{
580 					for (i = 0; i < n; i++)
581 					{
582 						unsigned char *dd = ddata;
583 						const unsigned char *sd = sdata;
584 
585 						if (mapped[i])
586 							continue;
587 
588 						memset(colors, 0, sizeof(float) * n);
589 						colors[i] = 1;
590 						cc.convert(ctx, &cc, colors, convert);
591 
592 						if (sa)
593 						{
594 							for (y = dh; y > 0; y--)
595 							{
596 								for (x = dw; x > 0; x--)
597 								{
598 									unsigned char v = sd[i];
599 									if (v != 0)
600 									{
601 										unsigned char a = sd[sc];
602 										for (j = 0; j < dc; j++)
603 											dd[j] = fz_clampi(dd[j] + v * convert[j], 0, a);
604 									}
605 									dd += dn;
606 									sd += sn;
607 								}
608 								dd += dstride;
609 								sd += sstride;
610 							}
611 						}
612 						else
613 						{
614 							for (y = dh; y > 0; y--)
615 							{
616 								for (x = dw; x > 0; x--)
617 								{
618 									unsigned char v = sd[i];
619 									if (v != 0)
620 										for (j = 0; j < dc; j++)
621 											dd[j] = fz_clampi(dd[j] + v * convert[j], 0, 255);
622 									dd += dn;
623 									sd += sn;
624 								}
625 								dd += dstride;
626 								sd += sstride;
627 							}
628 						}
629 					}
630 				}
631 				else
632 				{
633 					unsigned char *dd = ddata;
634 					const unsigned char *sd = sdata;
635 					if (!sa)
636 					{
637 						for (y = dh; y > 0; y--)
638 						{
639 							for (x = dw; x > 0; x--)
640 							{
641 								for (j = 0; j < n; j++)
642 									colors[j] = mapped[j] ? 0 : sd[j] / 255.0f;
643 								cc.convert(ctx, &cc, colors, convert);
644 
645 								for (j = 0; j < dc; j++)
646 									dd[j] = fz_clampi(255 * convert[j], 0, 255);
647 								dd += dn;
648 								sd += sn;
649 							}
650 							dd += dstride;
651 							sd += sstride;
652 						}
653 					}
654 					else
655 					{
656 						for (y = dh; y > 0; y--)
657 						{
658 							for (x = dw; x > 0; x--)
659 							{
660 								unsigned char a = sd[sc];
661 								float inva = 1.0f/a;
662 								for (j = 0; j < n; j++)
663 									colors[j] = mapped[j] ? 0 : sd[j] * inva;
664 								cc.convert(ctx, &cc, colors, convert);
665 
666 								for (j = 0; j < dc; j++)
667 									dd[j] = fz_clampi(a * convert[j], 0, a);
668 								dd += dn;
669 								sd += sn;
670 							}
671 							dd += dstride;
672 							sd += sstride;
673 						}
674 					}
675 				}
676 #endif
677 			}
678 		}
679 		fz_always(ctx)
680 			fz_drop_color_converter(ctx, &cc);
681 		fz_catch(ctx)
682 			fz_rethrow(ctx);
683 	}
684 	else
685 	{
686 		/* Use a standard pixmap converter to convert the process + alpha. */
687 		fz_convert_pixmap_samples(ctx, src, dst, proof_cs, default_cs, fz_default_color_params, 0);
688 
689 		/* And handle the spots ourselves. First make a map of what spots go where. */
690 		/* We want to set it up so that:
691 		 *    For each source spot, i, mapped[i] != 0 implies that it maps directly to a dest spot.
692 		 *    For each dest spot, j, mapped[j] = the source spot that goes there (or -1 if none).
693 		 */
694 		for (i = 0; i < sseps_n; i++)
695 			mapped[i] = 0;
696 
697 		for (i = 0, k = 0; i < dseps_n; i++)
698 		{
699 			const char *name;
700 			int state = sep_state(dseps, i);
701 
702 			if (state != FZ_SEPARATION_SPOT)
703 				continue;
704 			name = dseps->name[i];
705 			if (name == NULL)
706 				continue;
707 			map[k] = -1;
708 			for (j = 0; j < sseps_n; j++)
709 			{
710 				const char *sname;
711 				if (mapped[j])
712 					continue;
713 				if (sep_state(sseps, j) != FZ_SEPARATION_SPOT)
714 					continue;
715 				sname = sseps->name[j];
716 				if (sname && !strcmp(name, sname))
717 				{
718 					map[k] = j;
719 					unmapped--;
720 					mapped[j] = 1;
721 					break;
722 				}
723 			}
724 			k++;
725 		}
726 		if (sa)
727 			map[k] = sseps_n;
728 
729 		/* Now we need to make d[i] = map[i] < 0 : 0 ? s[map[i]] */
730 		if (ds)
731 		{
732 			unsigned char *dd = ddata + dc;
733 			const unsigned char *sd = sdata + sc;
734 			for (y = dh; y > 0; y--)
735 			{
736 				for (x = dw; x > 0; x--)
737 				{
738 					for (i = 0; i < ds; i++)
739 						dd[i] = map[i] < 0 ? 0 : sd[map[i]];
740 					dd += dn;
741 					sd += sn;
742 				}
743 				dd += dstride;
744 				sd += sstride;
745 			}
746 		}
747 
748 		/* So that's all the process colors, the alpha, and the
749 		 * directly mapped spots done. Now, are there any that
750 		 * remain unmapped? */
751 		if (unmapped)
752 		{
753 			int m;
754 			/* Still need to handle mapping 'lost' spots down to process colors */
755 			for (i = -1, m = 0; m < sseps_n; m++)
756 			{
757 				float convert[FZ_MAX_COLORS];
758 
759 				if (mapped[m])
760 					continue;
761 				if (fz_separation_current_behavior(ctx, sseps, m) != FZ_SEPARATION_SPOT)
762 					continue;
763 				i++;
764 				/* Src spot m (the i'th one) is not mapped. We need to convert that down. */
765 				fz_separation_equivalent(ctx, sseps, m, dst->colorspace, convert, proof_cs, color_params);
766 
767 				if (fz_colorspace_is_subtractive(ctx, dst->colorspace))
768 				{
769 					if (fz_colorspace_is_subtractive(ctx, src->colorspace))
770 					{
771 						unsigned char *dd = ddata;
772 						const unsigned char *sd = sdata + sc;
773 						if (sa)
774 						{
775 							for (y = dh; y > 0; y--)
776 							{
777 								for (x = dw; x > 0; x--)
778 								{
779 									unsigned char v = sd[i];
780 									if (v != 0)
781 									{
782 										unsigned char a = sd[ss];
783 										for (k = 0; k < dc; k++)
784 											dd[k] = fz_clampi(dd[k] + v * convert[k], 0, a);
785 									}
786 									dd += dn;
787 									sd += sn;
788 								}
789 								dd += dstride;
790 								sd += sstride;
791 							}
792 						}
793 						else
794 						{
795 							for (y = dh; y > 0; y--)
796 							{
797 								for (x = dw; x > 0; x--)
798 								{
799 									unsigned char v = sd[i];
800 									if (v != 0)
801 										for (k = 0; k < dc; k++)
802 											dd[k] = fz_clampi(dd[k] + v * convert[k], 0, 255);
803 									dd += dn;
804 									sd += sn;
805 								}
806 								dd += dstride;
807 								sd += sstride;
808 							}
809 						}
810 					}
811 					else
812 					{
813 						unsigned char *dd = ddata;
814 						const unsigned char *sd = sdata + sc;
815 						if (sa)
816 						{
817 							for (y = dh; y > 0; y--)
818 							{
819 								for (x = dw; x > 0; x--)
820 								{
821 									unsigned char v = 0xff - sd[i];
822 									if (v != 0)
823 									{
824 										unsigned char a = sd[ss];
825 										for (k = 0; k < dc; k++)
826 											dd[k] = fz_clampi(dd[k] + v * convert[k], 0, a);
827 									}
828 									dd += dn;
829 									sd += sn;
830 								}
831 								dd += dstride;
832 								sd += sstride;
833 							}
834 						}
835 						else
836 						{
837 							for (y = dh; y > 0; y--)
838 							{
839 								for (x = dw; x > 0; x--)
840 								{
841 									unsigned char v = 0xff - sd[i];
842 									if (v != 0)
843 										for (k = 0; k < dc; k++)
844 											dd[k] = fz_clampi(dd[k] + v * convert[k], 0, 255);
845 									dd += dn;
846 									sd += sn;
847 								}
848 								dd += dstride;
849 								sd += sstride;
850 							}
851 						}
852 					}
853 				}
854 				else
855 				{
856 					for (k = 0; k < dc; k++)
857 						convert[k] = 1-convert[k];
858 					if (fz_colorspace_is_subtractive(ctx, src->colorspace))
859 					{
860 						unsigned char *dd = ddata;
861 						const unsigned char *sd = sdata + sc;
862 						if (sa)
863 						{
864 							for (y = dh; y > 0; y--)
865 							{
866 								for (x = dw; x > 0; x--)
867 								{
868 									unsigned char v = sd[i];
869 									if (v != 0)
870 									{
871 										unsigned char a = sd[ss];
872 										for (k = 0; k < dc; k++)
873 											dd[k] = fz_clampi(dd[k] - v * convert[k], 0, a);
874 									}
875 									dd += dn;
876 									sd += sn;
877 								}
878 								dd += dstride;
879 								sd += sstride;
880 							}
881 						}
882 						else
883 						{
884 							for (y = dh; y > 0; y--)
885 							{
886 								for (x = dw; x > 0; x--)
887 								{
888 									unsigned char v = sd[i];
889 									if (v != 0)
890 										for (k = 0; k < dc; k++)
891 											dd[k] = fz_clampi(dd[k] - v * convert[k], 0, 255);
892 									dd += dn;
893 									sd += sn;
894 								}
895 								dd += dstride;
896 								sd += sstride;
897 							}
898 						}
899 					}
900 					else
901 					{
902 						unsigned char *dd = ddata;
903 						const unsigned char *sd = sdata + sc;
904 						if (sa)
905 						{
906 							for (y = dh; y > 0; y--)
907 							{
908 								for (x = dw; x > 0; x--)
909 								{
910 									unsigned char v = 0xff - sd[i];
911 									if (v != 0)
912 									{
913 										unsigned char a = sd[ss];
914 										for (k = 0; k < dc; k++)
915 											dd[k] = fz_clampi(dd[k] - v * convert[k], 0, a);
916 									}
917 									dd += dn;
918 									sd += sn;
919 								}
920 								dd += dstride;
921 								sd += sstride;
922 							}
923 						}
924 						else
925 						{
926 							for (y = dh; y > 0; y--)
927 							{
928 								for (x = dw; x > 0; x--)
929 								{
930 									unsigned char v = 0xff - sd[i];
931 									if (v != 0)
932 										for (k = 0; k < dc; k++)
933 											dd[k] = fz_clampi(dd[k] - v * convert[k], 0, 255);
934 									dd += dn;
935 									sd += sn;
936 								}
937 								dd += dstride;
938 								sd += sstride;
939 							}
940 						}
941 					}
942 				}
943 			}
944 		}
945 	}
946 
947 	return dst;
948 }
949 
950 void
fz_convert_separation_colors(fz_context * ctx,fz_colorspace * src_cs,const float * src_color,fz_separations * dst_seps,fz_colorspace * dst_cs,float * dst_color,fz_color_params color_params)951 fz_convert_separation_colors(fz_context *ctx,
952 	fz_colorspace *src_cs, const float *src_color,
953 	fz_separations *dst_seps, fz_colorspace *dst_cs, float *dst_color,
954 	fz_color_params color_params)
955 {
956 	int i, j, n, dc, ds, dn, pred;
957 	float remainders[FZ_MAX_COLORS];
958 	int remaining = 0;
959 
960 	assert(dst_cs && src_cs && dst_color && src_color);
961 	assert(fz_colorspace_is_device_n(ctx, src_cs));
962 
963 	dc = fz_colorspace_n(ctx, dst_cs);
964 	ds = (dst_seps == NULL ? 0: dst_seps->num_separations);
965 	dn = dc + ds;
966 
967 	i = 0;
968 	if (!fz_colorspace_is_subtractive(ctx, dst_cs))
969 		for (; i < dc; i++)
970 			dst_color[i] = 1;
971 	for (; i < dn; i++)
972 		dst_color[i] = 0;
973 
974 	n = fz_colorspace_n(ctx, src_cs);
975 	pred = 0;
976 	for (i = 0; i < n; i++)
977 	{
978 		const char *name = fz_colorspace_colorant(ctx, src_cs, i);
979 
980 		if (name == NULL)
981 			continue;
982 		if (i == 0 && !strcmp(name, "All"))
983 		{
984 			/* This is only supposed to happen in separation spaces, not DeviceN */
985 			if (n != 1)
986 				fz_warn(ctx, "All found in DeviceN space");
987 			for (i = 0; i < dn; i++)
988 				dst_color[i] = src_color[0];
989 			break;
990 		}
991 		if (!strcmp(name, "None"))
992 			continue;
993 
994 		/* The most common case is that the colorant we match is the
995 		 * one after the one we matched before, so optimise for that. */
996 		for (j = pred; j < ds; j++)
997 		{
998 			const char *dname = dst_seps->name[j];
999 			if (dname && !strcmp(name, dname))
1000 				goto found_sep;
1001 		}
1002 		for (j = 0; j < pred; j++)
1003 		{
1004 			const char *dname = dst_seps->name[j];
1005 			if (dname && !strcmp(name, dname))
1006 				goto found_sep;
1007 		}
1008 		for (j = 0; j < dc; j++)
1009 		{
1010 			const char *dname = fz_colorspace_colorant(ctx, dst_cs, j);
1011 			if (dname && !strcmp(name, dname))
1012 				goto found_process;
1013 		}
1014 		if (0) {
1015 found_sep:
1016 			dst_color[j+dc] = src_color[i];
1017 			pred = j+1;
1018 		}
1019 		else if (0)
1020 		{
1021 found_process:
1022 			dst_color[j] += src_color[i];
1023 		}
1024 		else
1025 		{
1026 			if (remaining == 0)
1027 			{
1028 				memset(remainders, 0, sizeof(float) * n);
1029 				remaining = 1;
1030 			}
1031 			remainders[i] = src_color[i];
1032 		}
1033 	}
1034 
1035 	if (remaining)
1036 	{
1037 		/* There were some spots that didn't copy over */
1038 		float converted[FZ_MAX_COLORS];
1039 		fz_convert_color(ctx, src_cs, remainders, dst_cs, converted, NULL, color_params);
1040 		for (i = 0; i < dc; i++)
1041 			dst_color[i] += converted[i];
1042 	}
1043 }
1044 
1045 void
fz_separation_equivalent(fz_context * ctx,const fz_separations * seps,int i,fz_colorspace * dst_cs,float * convert,fz_colorspace * prf,fz_color_params color_params)1046 fz_separation_equivalent(fz_context *ctx,
1047 	const fz_separations *seps,
1048 	int i,
1049 	fz_colorspace *dst_cs, float *convert,
1050 	fz_colorspace *prf,
1051 	fz_color_params color_params)
1052 {
1053 	float colors[FZ_MAX_COLORS];
1054 
1055 	if (!seps->cs[i])
1056 	{
1057 		switch (fz_colorspace_n(ctx, dst_cs))
1058 		{
1059 		case 3:
1060 			convert[0] = (seps->rgba[i] & 0xff)/ 255.0f;
1061 			convert[1] = ((seps->rgba[i]>>8) & 0xff)/ 255.0f;
1062 			convert[2] = ((seps->rgba[i]>>16) & 0xff)/ 255.0f;
1063 			convert[3] = ((seps->rgba[i]>>24) & 0xff)/ 255.0f;
1064 			return;
1065 		case 4:
1066 			convert[0] = (seps->cmyk[i] & 0xff)/ 255.0f;
1067 			convert[1] = ((seps->cmyk[i]>>8) & 0xff)/ 255.0f;
1068 			convert[2] = ((seps->cmyk[i]>>16) & 0xff)/ 255.0f;
1069 			convert[3] = ((seps->cmyk[i]>>24) & 0xff)/ 255.0f;
1070 			return;
1071 		default:
1072 			fz_throw(ctx, FZ_ERROR_GENERIC, "Cannot return equivalent in this colorspace");
1073 		}
1074 	}
1075 
1076 	memset(colors, 0, sizeof(float) * fz_colorspace_n(ctx, seps->cs[i]));
1077 	colors[seps->cs_pos[i]] = 1;
1078 	fz_convert_color(ctx, seps->cs[i], colors, dst_cs, convert, prf, color_params);
1079 }
1080