1 #include "mupdf/fitz.h"
6 fz_free_colorspace_imp(fz_context *ctx, fz_storable *cs_)
8 fz_colorspace *cs = (fz_colorspace *)cs_;
10 if (cs->free_data && cs->data)
11 cs->free_data(ctx, cs);
16 fz_new_colorspace(fz_context *ctx, char *name, int n)
18 fz_colorspace *cs = fz_malloc(ctx, sizeof(fz_colorspace));
19 FZ_INIT_STORABLE(cs, 1, fz_free_colorspace_imp);
20 cs->size = sizeof(fz_colorspace);
21 fz_strlcpy(cs->name, name, sizeof cs->name);
31 fz_keep_colorspace(fz_context *ctx, fz_colorspace *cs)
33 return (fz_colorspace *)fz_keep_storable(ctx, &cs->storable);
37 fz_drop_colorspace(fz_context *ctx, fz_colorspace *cs)
39 fz_drop_storable(ctx, &cs->storable);
42 /* Device colorspace definitions */
44 static void gray_to_rgb(fz_context *ctx, fz_colorspace *cs, const float *gray, float *rgb)
51 static void rgb_to_gray(fz_context *ctx, fz_colorspace *cs, const float *rgb, float *gray)
56 gray[0] = r * 0.3f + g * 0.59f + b * 0.11f;
59 static void rgb_to_rgb(fz_context *ctx, fz_colorspace *cs, const float *rgb, float *xyz)
66 static void bgr_to_rgb(fz_context *ctx, fz_colorspace *cs, const float *bgr, float *rgb)
73 static void rgb_to_bgr(fz_context *ctx, fz_colorspace *cs, const float *rgb, float *bgr)
80 static void cmyk_to_rgb(fz_context *ctx, fz_colorspace *cs, const float *cmyk, float *rgb)
82 #ifdef SLOWCMYK /* from poppler */
83 float c = cmyk[0], m = cmyk[1], y = cmyk[2], k = cmyk[3];
88 float c1m1 = 1 - m - cm1;
89 float c1m1y = c1m1 * y;
90 float c1m1y1 = c1m1 - c1m1y;
92 float c1my1 = c1m - c1my;
94 float cm1y1 = cm1 - cm1y;
96 float cmy1 = cm - cmy;
98 /* this is a matrix multiplication, unrolled for performance */
99 x = c1m1y1 * k; /* 0 0 0 1 */
100 r = g = b = c1m1y1 - x; /* 0 0 0 0 */
105 x = c1m1y * k; /* 0 0 1 1 */
108 x = c1m1y - x; /* 0 0 1 0 */
112 x = c1my1 * k; /* 0 1 0 1 */
114 x = c1my1 - x; /* 0 1 0 0 */
118 x = c1my * k; /* 0 1 1 1 */
120 x = c1my - x; /* 0 1 1 0 */
125 x = cm1y1 * k; /* 1 0 0 1 */
128 x = cm1y1 - x; /* 1 0 0 0 */
132 x = cm1y * k; /* 1 0 1 1 */
134 x = cm1y - x; /* 1 0 1 0 */
138 x = cmy1 * k; /* 1 1 0 1 */
140 x = cmy1 - x; /* 1 1 0 0 */
145 x = cmy * (1-k); /* 1 1 1 0 */
149 rgb[0] = fz_clamp(r, 0, 1);
150 rgb[1] = fz_clamp(g, 0, 1);
151 rgb[2] = fz_clamp(b, 0, 1);
153 rgb[0] = 1 - fz_min(1, cmyk[0] + cmyk[3]);
154 rgb[1] = 1 - fz_min(1, cmyk[1] + cmyk[3]);
155 rgb[2] = 1 - fz_min(1, cmyk[2] + cmyk[3]);
159 static void rgb_to_cmyk(fz_context *ctx, fz_colorspace *cs, const float *rgb, float *cmyk)
165 k = fz_min(c, fz_min(m, y));
172 static fz_colorspace k_default_gray = { {-1, fz_free_colorspace_imp}, 0, "DeviceGray", 1, gray_to_rgb, rgb_to_gray };
173 static fz_colorspace k_default_rgb = { {-1, fz_free_colorspace_imp}, 0, "DeviceRGB", 3, rgb_to_rgb, rgb_to_rgb };
174 static fz_colorspace k_default_bgr = { {-1, fz_free_colorspace_imp}, 0, "DeviceBGR", 3, bgr_to_rgb, rgb_to_bgr };
175 static fz_colorspace k_default_cmyk = { {-1, fz_free_colorspace_imp}, 0, "DeviceCMYK", 4, cmyk_to_rgb, rgb_to_cmyk };
177 static fz_colorspace *fz_default_gray = &k_default_gray;
178 static fz_colorspace *fz_default_rgb = &k_default_rgb;
179 static fz_colorspace *fz_default_bgr = &k_default_bgr;
180 static fz_colorspace *fz_default_cmyk = &k_default_cmyk;
182 struct fz_colorspace_context_s
185 fz_colorspace *gray, *rgb, *bgr, *cmyk;
188 void fz_new_colorspace_context(fz_context *ctx)
190 ctx->colorspace = fz_malloc_struct(ctx, fz_colorspace_context);
191 ctx->colorspace->ctx_refs = 1;
192 ctx->colorspace->gray = fz_default_gray;
193 ctx->colorspace->rgb = fz_default_rgb;
194 ctx->colorspace->bgr = fz_default_bgr;
195 ctx->colorspace->cmyk = fz_default_cmyk;
198 fz_colorspace_context *
199 fz_keep_colorspace_context(fz_context *ctx)
201 if (!ctx || !ctx->colorspace)
203 fz_lock(ctx, FZ_LOCK_ALLOC);
204 ctx->colorspace->ctx_refs++;
205 fz_unlock(ctx, FZ_LOCK_ALLOC);
206 return ctx->colorspace;
209 void fz_drop_colorspace_context(fz_context *ctx)
212 if (!ctx || !ctx->colorspace)
214 fz_lock(ctx, FZ_LOCK_ALLOC);
215 drop = --ctx->colorspace->ctx_refs;
216 fz_unlock(ctx, FZ_LOCK_ALLOC);
218 fz_free(ctx, ctx->colorspace);
222 fz_device_gray(fz_context *ctx)
224 return ctx->colorspace->gray;
228 fz_device_rgb(fz_context *ctx)
230 return ctx->colorspace->rgb;
234 fz_device_bgr(fz_context *ctx)
236 return ctx->colorspace->bgr;
240 fz_device_cmyk(fz_context *ctx)
242 return ctx->colorspace->cmyk;
246 fz_lookup_device_colorspace(fz_context *ctx, char *name)
248 if (!strcmp(name, "DeviceGray"))
249 return fz_device_gray(ctx);
250 if (!strcmp(name, "DeviceRGB"))
251 return fz_device_rgb(ctx);
252 if (!strcmp(name, "DeviceBGR"))
253 return fz_device_bgr(ctx);
254 if (!strcmp(name, "DeviceCMYK"))
255 return fz_device_cmyk(ctx);
256 assert(!"unknown device colorspace");
261 fz_set_device_gray(fz_context *ctx, fz_colorspace *cs)
263 fz_drop_colorspace(ctx, ctx->colorspace->gray);
264 ctx->colorspace->gray = fz_keep_colorspace(ctx, cs);
268 fz_set_device_rgb(fz_context *ctx, fz_colorspace *cs)
270 fz_drop_colorspace(ctx, ctx->colorspace->rgb);
271 ctx->colorspace->rgb = fz_keep_colorspace(ctx, cs);
275 fz_set_device_bgr(fz_context *ctx, fz_colorspace *cs)
277 fz_drop_colorspace(ctx, ctx->colorspace->bgr);
278 ctx->colorspace->bgr = fz_keep_colorspace(ctx, cs);
282 fz_set_device_cmyk(fz_context *ctx, fz_colorspace *cs)
284 fz_drop_colorspace(ctx, ctx->colorspace->cmyk);
285 ctx->colorspace->cmyk = fz_keep_colorspace(ctx, cs);
289 fz_colorspace_is_indexed(fz_colorspace *cs)
291 return (cs && !strcmp(cs->name, "Indexed"));
294 /* Fast pixmap color conversions */
296 static void fast_gray_to_rgb(fz_pixmap *dst, fz_pixmap *src)
298 unsigned char *s = src->samples;
299 unsigned char *d = dst->samples;
300 int n = src->w * src->h;
312 static void fast_gray_to_cmyk(fz_pixmap *dst, fz_pixmap *src)
314 unsigned char *s = src->samples;
315 unsigned char *d = dst->samples;
316 int n = src->w * src->h;
329 static void fast_rgb_to_gray(fz_pixmap *dst, fz_pixmap *src)
331 unsigned char *s = src->samples;
332 unsigned char *d = dst->samples;
333 int n = src->w * src->h;
336 d[0] = ((s[0]+1) * 77 + (s[1]+1) * 150 + (s[2]+1) * 28) >> 8;
343 static void fast_bgr_to_gray(fz_pixmap *dst, fz_pixmap *src)
345 unsigned char *s = src->samples;
346 unsigned char *d = dst->samples;
347 int n = src->w * src->h;
350 d[0] = ((s[0]+1) * 28 + (s[1]+1) * 150 + (s[2]+1) * 77) >> 8;
357 static void fast_rgb_to_cmyk(fz_pixmap *dst, fz_pixmap *src)
359 unsigned char *s = src->samples;
360 unsigned char *d = dst->samples;
361 int n = src->w * src->h;
364 unsigned char c = 255 - s[0];
365 unsigned char m = 255 - s[1];
366 unsigned char y = 255 - s[2];
367 unsigned char k = (unsigned char)fz_mini(c, fz_mini(m, y));
378 static void fast_bgr_to_cmyk(fz_pixmap *dst, fz_pixmap *src)
380 unsigned char *s = src->samples;
381 unsigned char *d = dst->samples;
382 int n = src->w * src->h;
385 unsigned char c = 255 - s[2];
386 unsigned char m = 255 - s[1];
387 unsigned char y = 255 - s[0];
388 unsigned char k = (unsigned char)fz_mini(c, fz_mini(m, y));
399 static void fast_cmyk_to_gray(fz_pixmap *dst, fz_pixmap *src)
401 unsigned char *s = src->samples;
402 unsigned char *d = dst->samples;
403 int n = src->w * src->h;
406 unsigned char c = fz_mul255(s[0], 77);
407 unsigned char m = fz_mul255(s[1], 150);
408 unsigned char y = fz_mul255(s[2], 28);
409 d[0] = 255 - (unsigned char)fz_mini(c + m + y + s[3], 255);
418 fast_cmyk_to_rgb_ARM(unsigned char *dst, unsigned char *src, int n)
419 __attribute__((naked));
422 fast_cmyk_to_rgb_ARM(unsigned char *dst, unsigned char *src, int n)
426 "stmfd r13!,{r4-r11,r14} \n"
430 "mov r12, #0 @ r12= CMYK = 0 \n"
431 "b 2f @ enter loop \n"
432 "1: @ White or Black \n"
433 "@ Cunning trick: On entry r11 = 0 if black, r11 = FF if white \n"
434 "eor r12,r11,#0xFF @ r12= FF if black, 0 if white \n"
435 "ldrb r7, [r1],#1 @ r8 = s[4] \n"
436 "strb r11,[r0],#1 @ d[0] = r \n"
437 "strb r11,[r0],#1 @ d[1] = g \n"
438 "strb r11,[r0],#1 @ d[2] = b \n"
439 "strb r7, [r0],#1 @ d[3] = s[4] \n"
440 "mov r12,r12,LSL #24 @ r12 = CMYK \n"
441 "subs r2, r2, #1 @ r2 = n-- \n"
443 "2: @ Main loop starts here \n"
444 "ldrb r3, [r1], #4 @ r3 = c \n"
445 "ldrb r6, [r1, #-1] @ r6 = k \n"
446 "ldrb r5, [r1, #-2] @ r5 = y \n"
447 "ldrb r4, [r1, #-3] @ r4 = m \n"
448 "eors r11,r6, #0xFF @ if (k == 255) \n"
449 "beq 1b @ goto black \n"
450 "orr r7, r3, r4, LSL #8 \n"
451 "orr r14,r5, r6, LSL #8 \n"
452 "orrs r7, r7, r14,LSL #16 @ r7 = cmyk \n"
453 "beq 1b @ if (cmyk == 0) white \n"
454 "@ At this point, we have to decode a new pixel \n"
455 "@ r0 = dst r1 = src r2 = n r7 = cmyk \n"
457 "stmfd r13!,{r0-r1,r7} @ stash regs for space \n"
458 "add r3, r3, r3, LSR #7 @ r3 = c += c>>7 \n"
459 "add r4, r4, r4, LSR #7 @ r4 = m += m>>7 \n"
460 "add r5, r5, r5, LSR #7 @ r5 = y += y>>7 \n"
461 "add r6, r6, r6, LSR #7 @ r6 = k += k>>7 \n"
462 "mov r5, r5, LSR #1 @ sacrifice 1 bit of Y \n"
463 "mul r8, r3, r4 @ r8 = cm = c * m \n"
464 "rsb r9, r8, r4, LSL #8 @ r9 = c1m = (m<<8) - cm \n"
465 "rsb r3, r8, r3, LSL #8 @ r3 = cm1 = (c<<8) - cm \n"
466 "rsb r4, r4, #0x100 @ r4 = 256-m \n"
467 "rsb r4, r3, r4, LSL #8 @ r4 = c1m1 =((256-m)<<8)-cm1 \n"
468 "mul r7, r4, r5 @ r7 = c1m1y = c1m1 * y \n"
469 "rsb r4, r7, r4, LSL #7 @ r4 = c1m1y1 = (c1m1<<7)-c1m1y \n"
470 "mul r10,r9, r5 @ r10= c1my = c1m * y \n"
471 "rsb r9, r10,r9, LSL #7 @ r9 = c1my1 = (c1m<<7) - c1my \n"
472 "mul r11,r3, r5 @ r11= cm1y = cm1 * y \n"
473 "rsb r3, r11,r3, LSL #7 @ r3 = cm1y1 = (cm1<<7) - cm1y \n"
474 "mul r5, r8, r5 @ r5 = cmy = cm * y \n"
475 "rsb r8, r5, r8, LSL #7 @ r8 = cmy1 = (cm<<7) - cmy \n"
476 "@ Register recap: \n"
486 "@ The actual matrix multiplication \n"
487 "mul r14,r4, r6 @ r14= x1 = c1m1y1 * k \n"
488 "rsb r4, r14,r4, LSL #8 @ r4 = x0 = (c1m1y1<<8) - x1 \n"
489 "add r4, r4, r14,LSR #8-5 @ r4 = b = x0 + 32*(x1>>8) \n"
490 "sub r1, r4, r14,LSR #8 @ r1 = g = x0 + 31*(x1>>8) \n"
491 "add r0, r1, r14,LSR #8-2 @ r0 = r = x0 + 35*(x1>>8) \n"
493 "mul r14,r7, r6 @ r14= x1 = c1m1y * k \n"
494 "rsb r7, r14,r7, LSL #8 @ r7 = x0 = (c1m1y<<8) - x1 \n"
495 "add r0, r0, r7 @ r0 = r += x0 \n"
496 "add r1, r1, r7 @ r1 = g += (x0>>8 * 256) \n"
497 "sub r1, r1, r7, LSR #8-3 @ 248 \n"
498 "sub r1, r1, r7, LSR #8-2 @ 244 \n"
499 "sub r1, r1, r7, LSR #8 @ 243 \n"
500 "sub r7, r14,r14,LSR #3 @ r7 = 28*(x1>>5) \n"
501 "add r0, r0, r7, LSR #8-5 @ r0 = r += 28 * x1 \n"
502 "sub r7, r7, r14,LSR #4 @ r7 = 26*(x1>>5) \n"
503 "add r1, r1, r7, LSR #8-5 @ r1 = g += 26 * x1 \n"
505 "mul r14,r9, r6 @ r14= x1 = c1my1 * k \n"
506 "sub r9, r9, r14,LSR #8 @ r9 = x0>>8 = c1my1 - (x1>>8) \n"
507 "add r0, r0, r14,LSR #8-5 @ r0 = r += (x1>>8)*32 \n"
508 "add r0, r0, r14,LSR #8-2 @ r0 = r += (x1>>8)*36 \n"
509 "mov r14,#237 @ r14= 237 \n"
510 "mla r0,r14,r9,r0 @ r14= r += x0*237 \n"
511 "mov r14,#141 @ r14= 141 \n"
512 "mla r4,r14,r9,r4 @ r14= b += x0*141 \n"
514 "mul r14,r10,r6 @ r14= x1 = c1my * k \n"
515 "sub r10,r10,r14,LSR #8 @ r10= x0>>8 = c1my - (x1>>8) \n"
516 "add r0, r0, r14,LSR #8-5 @ r0 = r += 32 * x1 \n"
517 "add r0, r0, r14,LSR #8-1 @ r0 = r += 34 * x1 \n"
518 "mov r14,#238 @ r14= 238 \n"
519 "mla r0,r14,r10,r0 @ r0 = r += 238 * x0 \n"
520 "mov r14,#28 @ r14= 28 \n"
521 "mla r1,r14,r10,r1 @ r1 = g += 28 * x0 \n"
522 "mov r14,#36 @ r14= 36 \n"
523 "mla r4,r14,r10,r4 @ r4 = b += 36 * x0 \n"
525 "mul r14,r3, r6 @ r14= x1 = cm1y1 * k \n"
526 "sub r3, r3, r14,LSR #8 @ r3 = x1>>8 = cm1y1 - (x1>>8) \n"
527 "add r1, r1, r14,LSR #8-4 @ r1 = g += 16*x1 \n"
528 "sub r1, r1, r14,LSR #8 @ 15*x1 \n"
529 "add r4, r4, r14,LSR #8-5 @ r4 = b += 32*x1 \n"
530 "add r4, r4, r14,LSR #8-2 @ 36*x1 \n"
531 "mov r14,#174 @ r14= 174 \n"
532 "mla r1, r14,r3, r1 @ r1 = g += 174 * x0 \n"
533 "mov r14,#240 @ r14= 240 \n"
534 "mla r4, r14,r3, r4 @ r4 = b += 240 * x0 \n"
536 "mul r14,r11,r6 @ r14= x1 = cm1y * k \n"
537 "sub r11,r11,r14,LSR #8 @ r11= x0>>8 = cm1y - (x1>>8) \n"
538 "add r1, r1, r14,LSR #8-4 @ r1 = g += x1 * 16 \n"
539 "add r1, r1, r14,LSR #8 @ x1 * 17 \n"
540 "add r1, r1, r14,LSR #8-1 @ x1 * 19 \n"
541 "mov r14,#167 @ r14 = 167 \n"
542 "mla r1, r14,r11,r1 @ r1 = g += 167 * x0 \n"
543 "mov r14,#80 @ r14 = 80 \n"
544 "mla r4, r14,r11,r4 @ r4 = b += 80 * x0 \n"
546 "mul r14,r8, r6 @ r14= x1 = cmy1 * k \n"
547 "sub r8, r8, r14,LSR #8 @ r8 = x0>>8 = cmy1 - (x1>>8) \n"
548 "add r4, r4, r14,LSR #8-1 @ r4 = b += x1 * 2 \n"
549 "mov r14,#46 @ r14=46 \n"
550 "mla r0, r14,r8, r0 @ r0 = r += 46 * x0 \n"
551 "mov r14,#49 @ r14=49 \n"
552 "mla r1, r14,r8, r1 @ r1 = g += 49 * x0 \n"
553 "mov r14,#147 @ r14=147 \n"
554 "mla r4, r14,r8, r4 @ r4 = b += 147 * x0 \n"
556 "rsb r6, r6, #256 @ r6 = k = 256-k \n"
557 "mul r14,r5, r6 @ r14= x0 = cmy * (256-k) \n"
558 "mov r11,#54 @ r11= 54 \n"
559 "mov r14,r14,LSR #8 @ r14= (x0>>8) \n"
560 "mov r8,#57 @ r8 = 57 \n"
561 "mla r0,r14,r11,r0 @ r0 = r += 54*x0 \n"
562 "mla r1,r14,r11,r1 @ r1 = g += 54*x0 \n"
563 "mla r4,r14,r8, r4 @ r4 = b += 57*x0 \n"
565 "sub r8, r0, r0, LSR #8 @ r8 = r -= (r>>8) \n"
566 "sub r9, r1, r1, LSR #8 @ r9 = g -= (r>>8) \n"
567 "sub r10,r4, r4, LSR #8 @ r10= b -= (r>>8) \n"
568 "ldmfd r13!,{r0-r1,r12} \n"
569 "mov r8, r8, LSR #23 @ r8 = r>>23 \n"
570 "mov r9, r9, LSR #23 @ r9 = g>>23 \n"
571 "mov r10,r10,LSR #23 @ r10= b>>23 \n"
572 "ldrb r14,[r1],#1 @ r8 = s[4] \n"
573 "strb r8, [r0],#1 @ d[0] = r \n"
574 "strb r9, [r0],#1 @ d[1] = g \n"
575 "strb r10,[r0],#1 @ d[2] = b \n"
576 "strb r14,[r0],#1 @ d[3] = s[4] \n"
577 "subs r2, r2, #1 @ r2 = n-- \n"
579 "@ At this point, we've just decoded a pixel \n"
580 "@ r0 = dst r1 = src r2 = n r8 = r r9 = g r10= b r12= CMYK \n"
582 "ldrb r3, [r1], #4 @ r3 = c \n"
583 "ldrb r6, [r1, #-1] @ r6 = k \n"
584 "ldrb r5, [r1, #-2] @ r5 = y \n"
585 "ldrb r4, [r1, #-3] @ r4 = m \n"
586 "eors r11,r6, #0xFF @ if (k == 255) \n"
587 "beq 1b @ goto black \n"
588 "orr r7, r3, r4, LSL #8 \n"
589 "orr r14,r5, r6, LSL #8 \n"
590 "orrs r7, r7, r14,LSL #16 @ r7 = cmyk \n"
591 "beq 1b @ if (cmyk == 0) white \n"
592 "cmp r7, r12 @ if (cmyk != CMYK) \n"
593 "bne 3b @ not the same, loop \n"
594 "@ If we get here, we just matched a pixel we have just decoded \n"
595 "ldrb r3, [r1],#1 @ r8 = s[4] \n"
596 "strb r8, [r0],#1 @ d[0] = r \n"
597 "strb r9, [r0],#1 @ d[1] = g \n"
598 "strb r10,[r0],#1 @ d[2] = b \n"
599 "strb r3, [r0],#1 @ d[3] = s[4] \n"
600 "subs r2, r2, #1 @ r2 = n-- \n"
603 "ldmfd r13!,{r4-r11,PC} @ pop, return to thumb \n"
609 static void fast_cmyk_to_rgb(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
611 unsigned char *s = src->samples;
612 unsigned char *d = dst->samples;
613 int n = src->w * src->h;
615 fast_cmyk_to_rgb_ARM(d, s, n);
617 unsigned int C,M,Y,K,r,g,b;
630 unsigned int c = s[0];
631 unsigned int m = s[1];
632 unsigned int y = s[2];
633 unsigned int k = s[3];
634 unsigned int cm, c1m, cm1, c1m1, c1m1y, c1m1y1, c1my, c1my1, cm1y, cm1y1, cmy, cmy1;
637 if (c == C && m == M && y == Y && k == K)
641 else if (k == 0 && c == 0 && m == 0 && y == 0)
663 y >>= 1; /* Ditch 1 bit of Y to avoid overflow */
667 c1m1 = ((256 - m)<<8) - cm1;
669 c1m1y1 = (c1m1<<7) - c1m1y;
671 c1my1 = (c1m<<7) - c1my;
673 cm1y1 = (cm1<<7) - cm1y;
675 cmy1 = (cm<<7) - cmy;
677 /* this is a matrix multiplication, unrolled for performance */
678 x1 = c1m1y1 * k; /* 0 0 0 1 */
679 x0 = (c1m1y1<<8) - x1; /* 0 0 0 0 */
680 x1 = x1>>8; /* From 23 fractional bits to 15 */
682 r += 35 * x1; /* 0.1373 */
683 g += 31 * x1; /* 0.1216 */
684 b += 32 * x1; /* 0.1255 */
686 x1 = c1m1y * k; /* 0 0 1 1 */
687 x0 = (c1m1y<<8) - x1; /* 0 0 1 0 */
688 x1 >>= 8; /* From 23 fractional bits to 15 */
689 r += 28 * x1; /* 0.1098 */
690 g += 26 * x1; /* 0.1020 */
692 x0 >>= 8; /* From 23 fractional bits to 15 */
693 g += 243 * x0; /* 0.9490 */
695 x1 = c1my1 * k; /* 0 1 0 1 */
696 x0 = (c1my1<<8) - x1; /* 0 1 0 0 */
697 x1 >>= 8; /* From 23 fractional bits to 15 */
698 x0 >>= 8; /* From 23 fractional bits to 15 */
699 r += 36 * x1; /* 0.1412 */
700 r += 237 * x0; /* 0.9255 */
701 b += 141 * x0; /* 0.5490 */
703 x1 = c1my * k; /* 0 1 1 1 */
704 x0 = (c1my<<8) - x1; /* 0 1 1 0 */
705 x1 >>= 8; /* From 23 fractional bits to 15 */
706 x0 >>= 8; /* From 23 fractional bits to 15 */
707 r += 34 * x1; /* 0.1333 */
708 r += 238 * x0; /* 0.9294 */
709 g += 28 * x0; /* 0.1098 */
710 b += 36 * x0; /* 0.1412 */
712 x1 = cm1y1 * k; /* 1 0 0 1 */
713 x0 = (cm1y1<<8) - x1; /* 1 0 0 0 */
714 x1 >>= 8; /* From 23 fractional bits to 15 */
715 x0 >>= 8; /* From 23 fractional bits to 15 */
716 g += 15 * x1; /* 0.0588 */
717 b += 36 * x1; /* 0.1412 */
718 g += 174 * x0; /* 0.6784 */
719 b += 240 * x0; /* 0.9373 */
721 x1 = cm1y * k; /* 1 0 1 1 */
722 x0 = (cm1y<<8) - x1; /* 1 0 1 0 */
723 x1 >>= 8; /* From 23 fractional bits to 15 */
724 x0 >>= 8; /* From 23 fractional bits to 15 */
725 g += 19 * x1; /* 0.0745 */
726 g += 167 * x0; /* 0.6510 */
727 b += 80 * x0; /* 0.3137 */
729 x1 = cmy1 * k; /* 1 1 0 1 */
730 x0 = (cmy1<<8) - x1; /* 1 1 0 0 */
731 x1 >>= 8; /* From 23 fractional bits to 15 */
732 x0 >>= 8; /* From 23 fractional bits to 15 */
733 b += 2 * x1; /* 0.0078 */
734 r += 46 * x0; /* 0.1804 */
735 g += 49 * x0; /* 0.1922 */
736 b += 147 * x0; /* 0.5725 */
738 x0 = cmy * (256-k); /* 1 1 1 0 */
739 x0 >>= 8; /* From 23 fractional bits to 15 */
740 r += 54 * x0; /* 0.2118 */
741 g += 54 * x0; /* 0.2119 */
742 b += 57 * x0; /* 0.2235 */
759 d[0] = 255 - (unsigned char)fz_mini(s[0] + s[3], 255);
760 d[1] = 255 - (unsigned char)fz_mini(s[1] + s[3], 255);
761 d[2] = 255 - (unsigned char)fz_mini(s[2] + s[3], 255);
770 static void fast_cmyk_to_bgr(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
772 unsigned char *s = src->samples;
773 unsigned char *d = dst->samples;
774 int n = src->w * src->h;
778 float cmyk[4], rgb[3];
779 cmyk[0] = s[0] / 255.0f;
780 cmyk[1] = s[1] / 255.0f;
781 cmyk[2] = s[2] / 255.0f;
782 cmyk[3] = s[3] / 255.0f;
783 cmyk_to_rgb(ctx, NULL, cmyk, rgb);
788 d[0] = 255 - (unsigned char)fz_mini(s[2] + s[3], 255);
789 d[1] = 255 - (unsigned char)fz_mini(s[1] + s[3], 255);
790 d[2] = 255 - (unsigned char)fz_mini(s[0] + s[3], 255);
798 static void fast_rgb_to_bgr(fz_pixmap *dst, fz_pixmap *src)
800 unsigned char *s = src->samples;
801 unsigned char *d = dst->samples;
802 int n = src->w * src->h;
815 fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
817 float srcv[FZ_MAX_COLORS];
818 float dstv[FZ_MAX_COLORS];
823 fz_colorspace *ss = src->colorspace;
824 fz_colorspace *ds = dst->colorspace;
826 unsigned char *s = src->samples;
827 unsigned char *d = dst->samples;
829 assert(src->w == dst->w && src->h == dst->h);
830 assert(src->n == ss->n + 1);
831 assert(dst->n == ds->n + 1);
836 xy = (unsigned int)(src->w * src->h);
838 /* Special case for Lab colorspace (scaling of components to float) */
839 if (!strcmp(ss->name, "Lab") && srcn == 3)
841 fz_color_converter cc;
843 fz_lookup_color_converter(&cc, ctx, ds, ss);
846 srcv[0] = *s++ / 255.0f * 100;
847 srcv[1] = *s++ - 128;
848 srcv[2] = *s++ - 128;
850 cc.convert(&cc, dstv, srcv);
852 for (k = 0; k < dstn; k++)
853 *d++ = dstv[k] * 255;
859 /* Brute-force for small images */
862 fz_color_converter cc;
864 fz_lookup_color_converter(&cc, ctx, ds, ss);
867 for (k = 0; k < srcn; k++)
868 srcv[k] = *s++ / 255.0f;
870 cc.convert(&cc, dstv, srcv);
872 for (k = 0; k < dstn; k++)
873 *d++ = dstv[k] * 255;
879 /* 1-d lookup table for separation and similar colorspaces */
882 unsigned char lookup[FZ_MAX_COLORS * 256];
883 fz_color_converter cc;
885 fz_lookup_color_converter(&cc, ctx, ds, ss);
886 for (i = 0; i < 256; i++)
888 srcv[0] = i / 255.0f;
889 cc.convert(&cc, dstv, srcv);
890 for (k = 0; k < dstn; k++)
891 lookup[i * dstn + k] = dstv[k] * 255;
897 for (k = 0; k < dstn; k++)
898 *d++ = lookup[i * dstn + k];
903 /* Memoize colors using a hash table for the general case */
906 fz_hash_table *lookup;
907 unsigned char *color;
908 unsigned char dummy = s[0] ^ 255;
909 unsigned char *sold = &dummy;
910 fz_color_converter cc;
912 fz_lookup_color_converter(&cc, ctx, ds, ss);
913 lookup = fz_new_hash_table(ctx, 509, srcn, -1);
917 if (*s == *sold && memcmp(sold,s,srcn) == 0)
920 memcpy(d, d-dstn-1, dstn);
928 color = fz_hash_find(ctx, lookup, s);
931 memcpy(d, color, dstn);
938 for (k = 0; k < srcn; k++)
939 srcv[k] = *s++ / 255.0f;
940 cc.convert(&cc, dstv, srcv);
941 for (k = 0; k < dstn; k++)
942 *d++ = dstv[k] * 255;
944 fz_hash_insert(ctx, lookup, s - srcn, d - dstn);
951 fz_free_hash(ctx, lookup);
956 fz_convert_pixmap(fz_context *ctx, fz_pixmap *dp, fz_pixmap *sp)
958 fz_colorspace *ss = sp->colorspace;
959 fz_colorspace *ds = dp->colorspace;
963 dp->interpolate = sp->interpolate;
965 if (ss == fz_default_gray)
967 if (ds == fz_default_rgb) fast_gray_to_rgb(dp, sp);
968 else if (ds == fz_default_bgr) fast_gray_to_rgb(dp, sp); /* bgr == rgb here */
969 else if (ds == fz_default_cmyk) fast_gray_to_cmyk(dp, sp);
970 else fz_std_conv_pixmap(ctx, dp, sp);
973 else if (ss == fz_default_rgb)
975 if (ds == fz_default_gray) fast_rgb_to_gray(dp, sp);
976 else if (ds == fz_default_bgr) fast_rgb_to_bgr(dp, sp);
977 else if (ds == fz_default_cmyk) fast_rgb_to_cmyk(dp, sp);
978 else fz_std_conv_pixmap(ctx, dp, sp);
981 else if (ss == fz_default_bgr)
983 if (ds == fz_default_gray) fast_bgr_to_gray(dp, sp);
984 else if (ds == fz_default_rgb) fast_rgb_to_bgr(dp, sp); /* bgr = rgb here */
985 else if (ds == fz_default_cmyk) fast_bgr_to_cmyk(sp, dp);
986 else fz_std_conv_pixmap(ctx, dp, sp);
989 else if (ss == fz_default_cmyk)
991 if (ds == fz_default_gray) fast_cmyk_to_gray(dp, sp);
992 else if (ds == fz_default_bgr) fast_cmyk_to_bgr(ctx, dp, sp);
993 else if (ds == fz_default_rgb) fast_cmyk_to_rgb(ctx, dp, sp);
994 else fz_std_conv_pixmap(ctx, dp, sp);
997 else fz_std_conv_pixmap(ctx, dp, sp);
1000 /* Convert a single color */
1003 std_conv_color(fz_color_converter *cc, float *dstv, const float *srcv)
1007 fz_colorspace *srcs = cc->ss;
1008 fz_colorspace *dsts = cc->ds;
1009 fz_context *ctx = cc->ctx;
1013 assert(srcs->to_rgb && dsts->from_rgb);
1014 srcs->to_rgb(ctx, srcs, srcv, rgb);
1015 dsts->from_rgb(ctx, dsts, rgb, dstv);
1016 for (i = 0; i < dsts->n; i++)
1017 dstv[i] = fz_clamp(dstv[i], 0, 1);
1021 for (i = 0; i < srcs->n; i++)
1027 g2rgb(fz_color_converter *cc, float *dv, const float *sv)
1035 g2cmyk(fz_color_converter *cc, float *dv, const float *sv)
1044 rgb2g(fz_color_converter *cc, float *dv, const float *sv)
1046 dv[0] = sv[0] * 0.3f + sv[1] * 0.59f + sv[2] * 0.11f;
1050 rgb2bgr(fz_color_converter *cc, float *dv, const float *sv)
1058 rgb2cmyk(fz_color_converter *cc, float *dv, const float *sv)
1060 float c = 1 - sv[0];
1061 float m = 1 - sv[1];
1062 float y = 1 - sv[2];
1063 float k = fz_min(c, fz_min(m, y));
1071 bgr2g(fz_color_converter *cc, float *dv, const float *sv)
1073 dv[0] = sv[0] * 0.11f + sv[1] * 0.59f + sv[2] * 0.3f;
1077 bgr2cmyk(fz_color_converter *cc, float *dv, const float *sv)
1079 float c = 1 - sv[2];
1080 float m = 1 - sv[1];
1081 float y = 1 - sv[0];
1082 float k = fz_min(c, fz_min(m, y));
1090 cmyk2g(fz_color_converter *cc, float *dv, const float *sv)
1092 float c = sv[0] * 0.3f;
1093 float m = sv[1] * 0.59f;
1094 float y = sv[2] * 0.11f;
1095 dv[0] = 1 - fz_min(c + m + y + sv[3], 1);
1099 cmyk2rgb(fz_color_converter *cc, float *dv, const float *sv)
1102 cmyk_to_rgb(cc->ctx, NULL, sv, dv);
1104 dv[0] = 1 - fz_min(sv[0] + sv[3], 1);
1105 dv[1] = 1 - fz_min(sv[1] + sv[3], 1);
1106 dv[2] = 1 - fz_min(sv[2] + sv[3], 1);
1111 cmyk2bgr(fz_color_converter *cc, float *dv, const float *sv)
1115 cmyk_to_rgb(cc->ctx, NULL, sv, rgb);
1120 dv[0] = 1 - fz_min(sv[2] + sv[3], 1);
1121 dv[1] = 1 - fz_min(sv[1] + sv[3], 1);
1122 dv[2] = 1 - fz_min(sv[0] + sv[3], 1);
1126 void fz_lookup_color_converter(fz_color_converter *cc, fz_context *ctx, fz_colorspace *ds, fz_colorspace *ss)
1131 if (ss == fz_default_gray)
1133 if ((ds == fz_default_rgb) || (ds == fz_default_bgr))
1134 cc->convert = g2rgb;
1135 else if (ds == fz_default_cmyk)
1136 cc->convert = g2cmyk;
1138 cc->convert = std_conv_color;
1141 else if (ss == fz_default_rgb)
1143 if (ds == fz_default_gray)
1144 cc->convert = rgb2g;
1145 else if (ds == fz_default_bgr)
1146 cc->convert = rgb2bgr;
1147 else if (ds == fz_default_cmyk)
1148 cc->convert = rgb2cmyk;
1150 cc->convert = std_conv_color;
1153 else if (ss == fz_default_bgr)
1155 if (ds == fz_default_gray)
1156 cc->convert = bgr2g;
1157 else if (ds == fz_default_rgb)
1158 cc->convert = rgb2bgr;
1159 else if (ds == fz_default_cmyk)
1160 cc->convert = bgr2cmyk;
1162 cc->convert = std_conv_color;
1165 else if (ss == fz_default_cmyk)
1167 if (ds == fz_default_gray)
1168 cc->convert = cmyk2g;
1169 else if (ds == fz_default_rgb)
1170 cc->convert = cmyk2rgb;
1171 else if (ds == fz_default_bgr)
1172 cc->convert = cmyk2bgr;
1174 cc->convert = std_conv_color;
1178 cc->convert = std_conv_color;
1182 fz_convert_color(fz_context *ctx, fz_colorspace *ds, float *dv, fz_colorspace *ss, const float *sv)
1184 fz_color_converter cc;
1185 fz_lookup_color_converter(&cc, ctx, ds, ss);
1186 cc.convert(&cc, dv, sv);
1193 fz_colorspace *base;
1195 unsigned char *lookup;
1199 indexed_to_rgb(fz_context *ctx, fz_colorspace *cs, const float *color, float *rgb)
1201 struct indexed *idx = cs->data;
1202 float alt[FZ_MAX_COLORS];
1205 i = fz_clampi(i, 0, idx->high);
1206 for (k = 0; k < idx->base->n; k++)
1207 alt[k] = idx->lookup[i * idx->base->n + k] / 255.0f;
1208 idx->base->to_rgb(ctx, idx->base, alt, rgb);
1212 free_indexed(fz_context *ctx, fz_colorspace *cs)
1214 struct indexed *idx = cs->data;
1216 fz_drop_colorspace(ctx, idx->base);
1217 fz_free(ctx, idx->lookup);
1222 fz_new_indexed_colorspace(fz_context *ctx, fz_colorspace *base, int high, unsigned char *lookup)
1225 struct indexed *idx;
1227 idx = fz_malloc_struct(ctx, struct indexed);
1228 idx->lookup = lookup;
1234 cs = fz_new_colorspace(ctx, "Indexed", 1);
1235 cs->to_rgb = indexed_to_rgb;
1236 cs->free_data = free_indexed;
1238 cs->size += sizeof(*idx) + (base->n * (idx->high + 1)) + base->size;
1243 fz_rethrow_message(ctx, "failed to create indexed colorspace");
1249 fz_expand_indexed_pixmap(fz_context *ctx, fz_pixmap *src)
1251 struct indexed *idx;
1253 unsigned char *s, *d;
1254 int y, x, k, n, high;
1255 unsigned char *lookup;
1258 assert(src->colorspace->to_rgb == indexed_to_rgb);
1259 assert(src->n == 2);
1261 idx = src->colorspace->data;
1263 lookup = idx->lookup;
1266 dst = fz_new_pixmap_with_bbox(ctx, idx->base, fz_pixmap_bbox(ctx, src, &bbox));
1270 for (y = 0; y < src->h; y++)
1272 for (x = 0; x < src->w; x++)
1276 v = fz_mini(v, high);
1277 for (k = 0; k < n; k++)
1278 *d++ = fz_mul255(lookup[v * n + k], a);
1283 dst->interpolate = src->interpolate;
1288 typedef struct fz_cached_color_converter
1290 fz_color_converter base;
1291 fz_hash_table *hash;
1294 fz_cached_color_converter;
1296 static void fz_cached_color_convert(fz_color_converter *cc_, float *ds, const float *ss)
1298 fz_cached_color_converter *cc = cc_->opaque;
1299 fz_context *ctx = cc->base.ctx;
1300 void *val = fz_hash_find(ctx, cc->hash, ss);
1301 int n = cc->base.ds->n * sizeof(float);
1302 fz_color_converter *base_cc = &cc->base;
1310 base_cc->convert(base_cc, ds, ss);
1311 val = fz_malloc(ctx, n);
1315 fz_hash_insert(ctx, cc->hash, ss, val);
1323 void fz_init_cached_color_converter(fz_context *ctx, fz_color_converter *cc, fz_colorspace *ds, fz_colorspace *ss)
1326 fz_cached_color_converter *cached = fz_malloc_struct(ctx, fz_cached_color_converter);
1330 fz_lookup_color_converter(&cached->base, ctx, ds, ss);
1331 cached->hash = fz_new_hash_table(ctx, 256, n * sizeof(float), -1);
1332 cc->convert = fz_cached_color_convert;
1336 cc->opaque = cached;
1340 fz_free_hash(ctx, cached->hash);
1345 void fz_fin_cached_color_converter(fz_color_converter *cc_)
1347 fz_cached_color_converter *cc;
1359 n = fz_hash_len(ctx, cc->hash);
1360 for (i = 0; i < n; i++)
1362 void *v = fz_hash_get_val(ctx, cc->hash, i);
1366 fz_free_hash(ctx, cc->hash);