// Copyright (C) 2004-2021 Artifex Software, Inc. // // This file is part of MuPDF. // // MuPDF is free software: you can redistribute it and/or modify it under the // terms of the GNU Affero General Public License as published by the Free // Software Foundation, either version 3 of the License, or (at your option) // any later version. // // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more // details. // // You should have received a copy of the GNU Affero General Public License // along with MuPDF. If not, see // // Alternative licensing terms are available from the licensor. // For commercial licensing, see or contact // Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, // CA 94945, U.S.A., +1(415)492-9861, for further information. #include "mupdf/fitz.h" #include "color-imp.h" #include /* Fast color transforms */ static void gray_to_gray(fz_context *ctx, fz_color_converter *cc, const float *gray, float *xyz) { xyz[0] = gray[0]; } static void gray_to_rgb(fz_context *ctx, fz_color_converter *cc, const float *gray, float *rgb) { rgb[0] = gray[0]; rgb[1] = gray[0]; rgb[2] = gray[0]; } static void rgb_to_gray(fz_context *ctx, fz_color_converter *cc, const float *rgb, float *gray) { gray[0] = rgb[0] * 0.3f + rgb[1] * 0.59f + rgb[2] * 0.11f; } static void bgr_to_gray(fz_context *ctx, fz_color_converter *cc, const float *bgr, float *gray) { gray[0] = bgr[0] * 0.11f + bgr[1] * 0.59f + bgr[2] * 0.3f; } static void rgb_to_rgb(fz_context *ctx, fz_color_converter *cc, const float *rgb, float *xyz) { xyz[0] = rgb[0]; xyz[1] = rgb[1]; xyz[2] = rgb[2]; } static void rgb_to_bgr(fz_context *ctx, fz_color_converter *cc, const float *rgb, float *bgr) { bgr[0] = rgb[2]; bgr[1] = rgb[1]; bgr[2] = rgb[0]; } static void cmyk_to_cmyk(fz_context *ctx, fz_color_converter *cc, const float *cmyk, float *xyz) { xyz[0] = cmyk[0]; xyz[1] = cmyk[1]; xyz[2] = cmyk[2]; xyz[3] = cmyk[3]; } static void gray_to_cmyk(fz_context *ctx, fz_color_converter *cc, const float *gray, float *cmyk) { cmyk[0] = 0; cmyk[1] = 0; cmyk[2] = 0; cmyk[3] = 1 - gray[0]; } static void cmyk_to_gray(fz_context *ctx, fz_color_converter *cc, const float *cmyk, float *gray) { float c = cmyk[0] * 0.3f; float m = cmyk[1] * 0.59f; float y = cmyk[2] * 0.11f; gray[0] = 1 - fz_min(c + m + y + cmyk[3], 1); } static void rgb_to_cmyk(fz_context *ctx, fz_color_converter *cc, const float *rgb, float *cmyk) { float c, m, y, k; c = 1 - rgb[0]; m = 1 - rgb[1]; y = 1 - rgb[2]; k = fz_min(c, fz_min(m, y)); cmyk[0] = c - k; cmyk[1] = m - k; cmyk[2] = y - k; cmyk[3] = k; } static void bgr_to_cmyk(fz_context *ctx, fz_color_converter *cc, const float *bgr, float *cmyk) { float c, m, y, k; c = 1 - bgr[2]; m = 1 - bgr[1]; y = 1 - bgr[0]; k = fz_min(c, fz_min(m, y)); cmyk[0] = c - k; cmyk[1] = m - k; cmyk[2] = y - k; cmyk[3] = k; } static void cmyk_to_rgb(fz_context *ctx, fz_color_converter *cc, const float *cmyk, float *rgb) { rgb[0] = 1 - fz_min(1, cmyk[0] + cmyk[3]); rgb[1] = 1 - fz_min(1, cmyk[1] + cmyk[3]); rgb[2] = 1 - fz_min(1, cmyk[2] + cmyk[3]); } static void cmyk_to_bgr(fz_context *ctx, fz_color_converter *cc, const float *cmyk, float *bgr) { bgr[0] = 1 - fz_min(cmyk[2] + cmyk[3], 1); bgr[1] = 1 - fz_min(cmyk[1] + cmyk[3], 1); bgr[2] = 1 - fz_min(cmyk[0] + cmyk[3], 1); } static inline float fung(float x) { if (x >= 6.0f / 29.0f) return x * x * x; return (108.0f / 841.0f) * (x - (4.0f / 29.0f)); } static void lab_to_rgb(fz_context *ctx, fz_color_converter *cc, const float *lab, float *rgb) { /* input is in range (0..100, -128..127, -128..127) not (0..1, 0..1, 0..1) */ float lstar, astar, bstar, l, m, n, x, y, z, r, g, b; lstar = lab[0]; astar = lab[1]; bstar = lab[2]; m = (lstar + 16) / 116; l = m + astar / 500; n = m - bstar / 200; x = fung(l); y = fung(m); z = fung(n); r = (3.240449f * x + -1.537136f * y + -0.498531f * z) * 0.830026f; g = (-0.969265f * x + 1.876011f * y + 0.041556f * z) * 1.05452f; b = (0.055643f * x + -0.204026f * y + 1.057229f * z) * 1.1003f; rgb[0] = sqrtf(fz_clamp(r, 0, 1)); rgb[1] = sqrtf(fz_clamp(g, 0, 1)); rgb[2] = sqrtf(fz_clamp(b, 0, 1)); } static void lab_to_gray(fz_context *ctx, fz_color_converter *cc, const float *lab, float *gray) { gray[0] = lab[0] / 100; } static void lab_to_bgr(fz_context *ctx, fz_color_converter *cc, const float *lab, float *bgr) { float rgb[3]; lab_to_rgb(ctx, cc, lab, rgb); rgb_to_bgr(ctx, cc, rgb, bgr); } static void lab_to_cmyk(fz_context *ctx, fz_color_converter *cc, const float *lab, float *cmyk) { float rgb[3]; lab_to_rgb(ctx, cc, lab, rgb); rgb_to_cmyk(ctx, cc, rgb, cmyk); } fz_color_convert_fn * fz_lookup_fast_color_converter(fz_context *ctx, fz_colorspace *ss, fz_colorspace *ds) { int stype = ss->type; int dtype = ds->type; if (stype == FZ_COLORSPACE_GRAY) { if (dtype == FZ_COLORSPACE_GRAY) return gray_to_gray; if (dtype == FZ_COLORSPACE_RGB) return gray_to_rgb; if (dtype == FZ_COLORSPACE_BGR) return gray_to_rgb; if (dtype == FZ_COLORSPACE_CMYK) return gray_to_cmyk; } else if (stype == FZ_COLORSPACE_RGB) { if (dtype == FZ_COLORSPACE_GRAY) return rgb_to_gray; if (dtype == FZ_COLORSPACE_RGB) return rgb_to_rgb; if (dtype == FZ_COLORSPACE_BGR) return rgb_to_bgr; if (dtype == FZ_COLORSPACE_CMYK) return rgb_to_cmyk; } else if (stype == FZ_COLORSPACE_BGR) { if (dtype == FZ_COLORSPACE_GRAY) return bgr_to_gray; if (dtype == FZ_COLORSPACE_RGB) return rgb_to_bgr; if (dtype == FZ_COLORSPACE_BGR) return rgb_to_rgb; if (dtype == FZ_COLORSPACE_CMYK) return bgr_to_cmyk; } else if (stype == FZ_COLORSPACE_CMYK) { if (dtype == FZ_COLORSPACE_GRAY) return cmyk_to_gray; if (dtype == FZ_COLORSPACE_RGB) return cmyk_to_rgb; if (dtype == FZ_COLORSPACE_BGR) return cmyk_to_bgr; if (dtype == FZ_COLORSPACE_CMYK) return cmyk_to_cmyk; } else if (stype == FZ_COLORSPACE_LAB) { if (dtype == FZ_COLORSPACE_GRAY) return lab_to_gray; if (dtype == FZ_COLORSPACE_RGB) return lab_to_rgb; if (dtype == FZ_COLORSPACE_BGR) return lab_to_bgr; if (dtype == FZ_COLORSPACE_CMYK) return lab_to_cmyk; } fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find color converter"); } /* Fast pixmap color conversions */ static void fast_gray_to_rgb(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, int copy_spots) { unsigned char *s = src->samples; unsigned char *d = dst->samples; size_t w = src->w; int h = src->h; int sn = src->n; int ss = src->s; int sa = src->alpha; int dn = dst->n; int ds = dst->s; int da = dst->alpha; ptrdiff_t d_line_inc = dst->stride - w * dn; ptrdiff_t s_line_inc = src->stride - w * sn; /* If copying spots, they must match, and we can never drop alpha (but we can invent it) */ if (copy_spots && ss != ds) fz_throw(ctx, FZ_ERROR_GENERIC, "incompatible number of spots when converting pixmap"); if (!da && sa) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot drop alpha when converting pixmap"); if ((int)w < 0 || h < 0) return; if (d_line_inc == 0 && s_line_inc == 0) { w *= h; h = 1; } if (ss == 0 && ds == 0) { /* Common, no spots case */ if (da) { if (sa) { while (h--) { size_t ww = w; while (ww--) { d[0] = s[0]; d[1] = s[0]; d[2] = s[0]; d[3] = s[1]; s += 2; d += 4; } d += d_line_inc; s += s_line_inc; } } else { while (h--) { size_t ww = w; while (ww--) { d[0] = s[0]; d[1] = s[0]; d[2] = s[0]; d[3] = 255; s++; d += 4; } d += d_line_inc; s += s_line_inc; } } } else { while (h--) { size_t ww = w; while (ww--) { d[0] = s[0]; d[1] = s[0]; d[2] = s[0]; s++; d += 3; } d += d_line_inc; s += s_line_inc; } } } else if (copy_spots) { /* Slower, spots capable version */ int i; while (h--) { size_t ww = w; while (ww--) { d[0] = s[0]; d[1] = s[0]; d[2] = s[0]; s += 1; d += 3; for (i=ss; i > 0; i--) *d++ = *s++; if (da) *d++ = sa ? *s++ : 255; } d += d_line_inc; s += s_line_inc; } } else { while (h--) { size_t ww = w; while (ww--) { d[0] = s[0]; d[1] = s[0]; d[2] = s[0]; s += sn; d += dn; if (da) d[-1] = sa ? s[-1] : 255; } d += d_line_inc; s += s_line_inc; } } } static void fast_gray_to_cmyk(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, int copy_spots) { unsigned char *s = src->samples; unsigned char *d = dst->samples; size_t w = src->w; int h = src->h; int sn = src->n; int ss = src->s; int sa = src->alpha; int dn = dst->n; int ds = dst->s; int da = dst->alpha; ptrdiff_t d_line_inc = dst->stride - w * dn; ptrdiff_t s_line_inc = src->stride - w * sn; int k, g; int a = 255; int i; if (copy_spots && ss != ds) fz_throw(ctx, FZ_ERROR_GENERIC, "incompatible number of spots when converting pixmap"); if ((int)w < 0 || h < 0) fz_throw(ctx, FZ_ERROR_GENERIC, "integer overflow"); while (h--) { size_t ww = w; while (ww--) { g = s[0]; if (sa) { a = s[1+ss]; g = fz_div255(g, a); } k = 255 - g; if (da) { *d++ = 0; *d++ = 0; *d++ = 0; *d++ = fz_mul255(k, a); } else { *d++ = 0; *d++ = 0; *d++ = 0; *d++ = k; } if (copy_spots) { s += 1; for (i=ss; i > 0; --i) *d++ = *s++; s += sa; } else { s += 1 + ss + sa; d += ds; } if (da) { *d++ = a; } } d += d_line_inc; s += s_line_inc; } } static void fast_rgb_to_gray(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, int copy_spots) { unsigned char *s = src->samples; unsigned char *d = dst->samples; size_t w = src->w; int h = src->h; int sn = src->n; int ss = src->s; int sa = src->alpha; int dn = dst->n; int ds = dst->s; int da = dst->alpha; ptrdiff_t d_line_inc = dst->stride - w * dn; ptrdiff_t s_line_inc = src->stride - w * sn; /* If copying spots, they must match, and we can never drop alpha (but we can invent it) */ if (copy_spots && ss != ds) fz_throw(ctx, FZ_ERROR_GENERIC, "incompatible number of spots when converting pixmap"); if (!da && sa) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot drop alpha when converting pixmap"); if ((int)w < 0 || h < 0) return; if (d_line_inc == 0 && s_line_inc == 0) { w *= h; h = 1; } if (ss == 0 && ds == 0) { /* Common, no spots case */ if (da) { if (sa) { while (h--) { size_t ww = w; while (ww--) { d[0] = ((s[0]+1) * 77 + (s[1]+1) * 150 + (s[2]+1) * 28) >> 8; d[1] = s[3]; s += 4; d += 2; } d += d_line_inc; s += s_line_inc; } } else { while (h--) { size_t ww = w; while (ww--) { d[0] = ((s[0]+1) * 77 + (s[1]+1) * 150 + (s[2]+1) * 28) >> 8; d[1] = 255; s += 3; d += 2; } d += d_line_inc; s += s_line_inc; } } } else { while (h--) { size_t ww = w; while (ww--) { d[0] = ((s[0]+1) * 77 + (s[1]+1) * 150 + (s[2]+1) * 28) >> 8; s += 3; d++; } d += d_line_inc; s += s_line_inc; } } } else if (copy_spots) { /* Slower, spots capable version */ int i; while (h--) { size_t ww = w; while (ww--) { d[0] = ((s[0]+1) * 77 + (s[1]+1) * 150 + (s[2]+1) * 28) >> 8; s += 3; d++; for (i=ss; i > 0; i--) *d++ = *s++; if (da) *d++ = sa ? *s++ : 255; } d += d_line_inc; s += s_line_inc; } } else { while (h--) { size_t ww = w; while (ww--) { d[0] = ((s[0]+1) * 77 + (s[1]+1) * 150 + (s[2]+1) * 28) >> 8; s += sn; d += dn; if (da) d[-1] = sa ? s[-1] : 255; } d += d_line_inc; s += s_line_inc; } } } static void fast_bgr_to_gray(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, int copy_spots) { unsigned char *s = src->samples; unsigned char *d = dst->samples; size_t w = src->w; int h = src->h; int sn = src->n; int ss = src->s; int sa = src->alpha; int dn = dst->n; int ds = dst->s; int da = dst->alpha; ptrdiff_t d_line_inc = dst->stride - w * dn; ptrdiff_t s_line_inc = src->stride - w * sn; /* If copying spots, they must match, and we can never drop alpha (but we can invent it) */ if (copy_spots && ss != ds) fz_throw(ctx, FZ_ERROR_GENERIC, "incompatible number of spots when converting pixmap"); if (!da && sa) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot drop alpha when converting pixmap"); if ((int)w < 0 || h < 0) return; if (d_line_inc == 0 && s_line_inc == 0) { w *= h; h = 1; } if (ss == 0 && ds == 0) { /* Common, no spots case */ if (da) { if (sa) { while (h--) { size_t ww = w; while (ww--) { d[0] = ((s[0]+1) * 28 + (s[1]+1) * 150 + (s[2]+1) * 77) >> 8; d[1] = s[3]; s += 4; d += 2; } d += d_line_inc; s += s_line_inc; } } else { while (h--) { size_t ww = w; while (ww--) { d[0] = ((s[0]+1) * 28 + (s[1]+1) * 150 + (s[2]+1) * 77) >> 8; d[1] = 255; s += 3; d += 2; } d += d_line_inc; s += s_line_inc; } } } else { int si = 3 + src->alpha; while (h--) { size_t ww = w; while (ww--) { d[0] = ((s[0]+1) * 28 + (s[1]+1) * 150 + (s[2]+1) * 77) >> 8; s += si; d++; } d += d_line_inc; s += s_line_inc; } } } else if (copy_spots) { /* Slower, spots capable version */ while (h--) { int i; size_t ww = w; while (ww--) { d[0] = ((s[0]+1) * 28 + (s[1]+1) * 150 + (s[2]+1) * 77) >> 8; s += 3; d++; for (i=ss; i > 0; i--) *d++ = *s++; if (da) *d++ = sa ? *s++ : 255; } d += d_line_inc; s += s_line_inc; } } else { /* Slower, spots capable version */ while (h--) { size_t ww = w; while (ww--) { d[0] = ((s[0]+1) * 28 + (s[1]+1) * 150 + (s[2]+1) * 77) >> 8; s += sn; d += dn; if (da) d[-1] = sa ? s[-1] : 255; } d += d_line_inc; s += s_line_inc; } } } static void fast_rgb_to_cmyk(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, int copy_spots) { unsigned char *s = src->samples; unsigned char *d = dst->samples; size_t w = src->w; int h = src->h; int sn = src->n; int ss = src->s; int sa = src->alpha; int dn = dst->n; int ds = dst->s; int da = dst->alpha; ptrdiff_t d_line_inc = dst->stride - w * dn; ptrdiff_t s_line_inc = src->stride - w * sn; int c, m, y, k, r, g, b; int a = 255; int i; if (copy_spots && ss != ds) fz_throw(ctx, FZ_ERROR_GENERIC, "incompatible number of spots when converting pixmap"); if ((int)w < 0 || h < 0) fz_throw(ctx, FZ_ERROR_GENERIC, "integer overflow"); while (h--) { size_t ww = w; while (ww--) { r = s[0]; g = s[1]; b = s[2]; if (sa) { a = s[3+ss]; r = fz_div255(r, a); g = fz_div255(g, a); b = fz_div255(b, a); } c = 255 - r; m = 255 - g; y = 255 - b; k = fz_mini(c, fz_mini(m, y)); c = c - k; m = m - k; y = y - k; if (da) { *d++ = fz_mul255(c, a); *d++ = fz_mul255(m, a); *d++ = fz_mul255(y, a); *d++ = fz_mul255(k, a); } else { *d++ = c; *d++ = m; *d++ = y; *d++ = k; } if (copy_spots) { s += 3; for (i=ss; i > 0; --i) *d++ = *s++; s += sa; } else { s += 3 + ss + sa; d += ds; } if (da) { *d++ = a; } } d += d_line_inc; s += s_line_inc; } } static void fast_bgr_to_cmyk(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, int copy_spots) { unsigned char *s = src->samples; unsigned char *d = dst->samples; size_t w = src->w; int h = src->h; int sn = src->n; int ss = src->s; int sa = src->alpha; int dn = dst->n; int ds = dst->s; int da = dst->alpha; ptrdiff_t d_line_inc = dst->stride - w * dn; ptrdiff_t s_line_inc = src->stride - w * sn; int c, m, y, k, r, g, b; int a = 255; int i; if (copy_spots && ss != ds) fz_throw(ctx, FZ_ERROR_GENERIC, "incompatible number of spots when converting pixmap"); if ((int)w < 0 || h < 0) fz_throw(ctx, FZ_ERROR_GENERIC, "integer overflow"); while (h--) { size_t ww = w; while (ww--) { b = s[0]; g = s[1]; r = s[2]; if (sa) { a = s[3+ss]; r = fz_div255(r, a); g = fz_div255(g, a); b = fz_div255(b, a); } c = 255 - r; m = 255 - g; y = 255 - b; k = fz_mini(c, fz_mini(m, y)); c = c - k; m = m - k; y = y - k; if (da) { *d++ = fz_mul255(c, a); *d++ = fz_mul255(m, a); *d++ = fz_mul255(y, a); *d++ = fz_mul255(k, a); } else { *d++ = c; *d++ = m; *d++ = y; *d++ = k; } if (copy_spots) { s += 3; for (i=ss; i > 0; --i) *d++ = *s++; s += sa; } else { s += 3 + ss + sa; d += ds; } if (da) { *d++ = a; } } d += d_line_inc; s += s_line_inc; } } static void fast_cmyk_to_gray(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, int copy_spots) { unsigned char *s = src->samples; unsigned char *d = dst->samples; size_t w = src->w; int h = src->h; int sn = src->n; int ss = src->s; int sa = src->alpha; int dn = dst->n; int ds = dst->s; int da = dst->alpha; ptrdiff_t d_line_inc = dst->stride - w * dn; ptrdiff_t s_line_inc = src->stride - w * sn; int c, m, y, k, g; int a = 255; int i; if (copy_spots && ss != ds) fz_throw(ctx, FZ_ERROR_GENERIC, "incompatible number of spots when converting pixmap"); if ((int)w < 0 || h < 0) fz_throw(ctx, FZ_ERROR_GENERIC, "integer overflow"); while (h--) { size_t ww = w; while (ww--) { c = s[0]; m = s[1]; y = s[2]; k = s[3]; if (sa) { a = s[4+ss]; c = fz_div255(c, a); m = fz_div255(m, a); y = fz_div255(y, a); k = fz_div255(k, a); } g = 255 - fz_mini(c + m + y + k, 255); if (da) { *d++ = fz_mul255(g, a); } else { *d++ = g; } if (copy_spots) { s += 4; for (i=ss; i > 0; --i) *d++ = *s++; s += sa; } else { s += 4 + ss + sa; d += ds; } if (da) { *d++ = a; } } d += d_line_inc; s += s_line_inc; } } static void fast_cmyk_to_rgb(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, int copy_spots) { unsigned char *s = src->samples; unsigned char *d = dst->samples; size_t w = src->w; int h = src->h; int sn = src->n; int ss = src->s; int sa = src->alpha; int dn = dst->n; int ds = dst->s; int da = dst->alpha; ptrdiff_t d_line_inc = dst->stride - w * dn; ptrdiff_t s_line_inc = src->stride - w * sn; int c, m, y, k, r, g, b; int a = 255; int i; if (copy_spots && ss != ds) fz_throw(ctx, FZ_ERROR_GENERIC, "incompatible number of spots when converting pixmap"); if ((int)w < 0 || h < 0) fz_throw(ctx, FZ_ERROR_GENERIC, "integer overflow"); while (h--) { size_t ww = w; while (ww--) { c = s[0]; m = s[1]; y = s[2]; k = s[3]; if (sa) { a = s[4+ss]; c = fz_div255(c, a); m = fz_div255(m, a); y = fz_div255(y, a); k = fz_div255(k, a); } r = 255 - fz_mini(c + k, 255); g = 255 - fz_mini(m + k, 255); b = 255 - fz_mini(y + k, 255); if (da) { *d++ = fz_mul255(r, a); *d++ = fz_mul255(g, a); *d++ = fz_mul255(b, a); } else { *d++ = r; *d++ = g; *d++ = b; } if (copy_spots) { s += 4; for (i=ss; i > 0; --i) *d++ = *s++; s += sa; } else { s += 4 + ss + sa; d += ds; } if (da) { *d++ = a; } } d += d_line_inc; s += s_line_inc; } } static void fast_cmyk_to_bgr(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, int copy_spots) { unsigned char *s = src->samples; unsigned char *d = dst->samples; size_t w = src->w; int h = src->h; int sn = src->n; int ss = src->s; int sa = src->alpha; int dn = dst->n; int ds = dst->s; int da = dst->alpha; ptrdiff_t d_line_inc = dst->stride - w * dn; ptrdiff_t s_line_inc = src->stride - w * sn; int c, m, y, k, r, g, b; int a = 255; int i; if (copy_spots && ss != ds) fz_throw(ctx, FZ_ERROR_GENERIC, "incompatible number of spots when converting pixmap"); if ((int)w < 0 || h < 0) fz_throw(ctx, FZ_ERROR_GENERIC, "integer overflow"); while (h--) { size_t ww = w; while (ww--) { c = s[0]; m = s[1]; y = s[2]; k = s[3]; if (sa) { a = s[4+ss]; c = fz_div255(c, a); m = fz_div255(m, a); y = fz_div255(y, a); k = fz_div255(k, a); } r = 255 - fz_mini(c + k, 255); g = 255 - fz_mini(m + k, 255); b = 255 - fz_mini(y + k, 255); if (da) { *d++ = fz_mul255(b, a); *d++ = fz_mul255(g, a); *d++ = fz_mul255(r, a); } else { *d++ = b; *d++ = g; *d++ = r; } if (copy_spots) { s += 4; for (i=ss; i > 0; --i) *d++ = *s++; s += sa; } else { s += 4 + ss + sa; d += ds; } if (da) { *d++ = a; } } d += d_line_inc; s += s_line_inc; } } static void fast_rgb_to_bgr(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, int copy_spots) { unsigned char *s = src->samples; unsigned char *d = dst->samples; size_t w = src->w; int h = src->h; int sn = src->n; int ss = src->s; int sa = src->alpha; int dn = dst->n; int ds = dst->s; int da = dst->alpha; ptrdiff_t d_line_inc = dst->stride - w * dn; ptrdiff_t s_line_inc = src->stride - w * sn; /* If copying spots, they must match, and we can never drop alpha (but we can invent it) */ if (copy_spots && ss != ds) fz_throw(ctx, FZ_ERROR_GENERIC, "incompatible number of spots when converting pixmap"); if (!da && sa) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot drop alpha when converting pixmap"); if ((int)w < 0 || h < 0) return; if (d_line_inc == 0 && s_line_inc == 0) { w *= h; h = 1; } if (ss == 0 && ds == 0) { /* Common, no spots case */ if (da) { if (sa) { while (h--) { size_t ww = w; while (ww--) { d[0] = s[2]; d[1] = s[1]; d[2] = s[0]; d[3] = s[3]; s += 4; d += 4; } } } else { while (h--) { size_t ww = w; while (ww--) { d[0] = s[2]; d[1] = s[1]; d[2] = s[0]; d[3] = 255; s += 3; d += 4; } } } } else { while (h--) { size_t ww = w; while (ww--) { d[0] = s[2]; d[1] = s[1]; d[2] = s[0]; s += 3; d += 3; } } } } else if (copy_spots) { /* Slower, spots capable version */ while (h--) { int i; size_t ww = w; while (ww--) { d[0] = s[2]; d[1] = s[1]; d[2] = s[0]; s += 3; d += 3; for (i=ss; i > 0; i--) *d++ = *s++; if (da) *d++ = sa ? *s++ : 255; } d += d_line_inc; s += s_line_inc; } } else { while (h--) { size_t ww = w; while (ww--) { d[0] = s[2]; d[1] = s[1]; d[2] = s[0]; s += sn; d += dn; if (da) d[-1] = sa ? s[-1] : 255; } d += d_line_inc; s += s_line_inc; } } } static void fast_gray_to_gray(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, int copy_spots) { unsigned char *s = src->samples; unsigned char *d = dst->samples; size_t w = src->w; int h = src->h; int sn = src->n; int ss = src->s; int sa = src->alpha; int dn = dst->n; int ds = dst->s; int da = dst->alpha; ptrdiff_t d_line_inc = dst->stride - w * dn; ptrdiff_t s_line_inc = src->stride - w * sn; /* If copying spots, they must match, and we can never drop alpha (but we can invent it) */ if (copy_spots && ss != ds) fz_throw(ctx, FZ_ERROR_GENERIC, "incompatible number of spots when converting pixmap"); if (!da && sa) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot drop alpha when converting pixmap"); if ((int)w < 0 || h < 0) return; if (d_line_inc == 0 && s_line_inc == 0) { w *= h; h = 1; } if (ss == 0 && ds == 0) { /* Common, no spots case */ if (da) { if (sa) { while (h--) { size_t ww = w; while (ww--) { d[0] = s[0]; d[1] = s[1]; s += 2; d += 2; } } } else { while (h--) { size_t ww = w; while (ww--) { d[0] = s[0]; d[1] = 255; s += 1; d += 2; } } } } else { while (h--) { size_t ww = w; while (ww--) { d[0] = s[0]; s += 1; d += 1; } } } } else if (copy_spots) { /* Slower, spots capable version */ while (h--) { int i; size_t ww = w; while (ww--) { d[0] = s[0]; s += 1; d += 1; for (i=ss; i > 0; i--) *d++ = *s++; if (da) *d++ = sa ? *s++ : 255; } d += d_line_inc; s += s_line_inc; } } else { while (h--) { size_t ww = w; while (ww--) { d[0] = s[0]; s += sn; d += dn; if (da) d[-1] = sa ? s[-1] : 255; } d += d_line_inc; s += s_line_inc; } } } static void fast_rgb_to_rgb(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, int copy_spots) { unsigned char *s = src->samples; unsigned char *d = dst->samples; size_t w = src->w; int h = src->h; int sn = src->n; int ss = src->s; int sa = src->alpha; int dn = dst->n; int ds = dst->s; int da = dst->alpha; ptrdiff_t d_line_inc = dst->stride - w * dn; ptrdiff_t s_line_inc = src->stride - w * sn; /* If copying spots, they must match, and we can never drop alpha (but we can invent it) */ if (copy_spots && ss != ds) fz_throw(ctx, FZ_ERROR_GENERIC, "incompatible number of spots when converting pixmap"); if (!da && sa) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot drop alpha when converting pixmap"); if ((int)w < 0 || h < 0) return; if (d_line_inc == 0 && s_line_inc == 0) { w *= h; h = 1; } if (ss == 0 && ds == 0) { /* Common, no spots case */ if (da) { if (sa) { while (h--) { size_t ww = w; while (ww--) { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; d[3] = s[3]; s += 4; d += 4; } } } else { while (h--) { size_t ww = w; while (ww--) { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; d[3] = 255; s += 3; d += 4; } } } } else { while (h--) { size_t ww = w; while (ww--) { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } } } } else if (copy_spots) { /* Slower, spots capable version */ while (h--) { int i; size_t ww = w; while (ww--) { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; for (i=ss; i > 0; i--) *d++ = *s++; if (da) *d++ = sa ? *s++ : 255; } d += d_line_inc; s += s_line_inc; } } else { while (h--) { size_t ww = w; while (ww--) { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += sn; d += dn; if (da) d[-1] = sa ? s[-1] : 255; } d += d_line_inc; s += s_line_inc; } } } static void fast_cmyk_to_cmyk(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, int copy_spots) { unsigned char *s = src->samples; unsigned char *d = dst->samples; size_t w = src->w; int h = src->h; int sn = src->n; int ss = src->s; int sa = src->alpha; int dn = dst->n; int ds = dst->s; int da = dst->alpha; ptrdiff_t d_line_inc = dst->stride - w * dn; ptrdiff_t s_line_inc = src->stride - w * sn; /* If copying spots, they must match, and we can never drop alpha (but we can invent it) */ if (copy_spots && ss != ds) fz_throw(ctx, FZ_ERROR_GENERIC, "incompatible number of spots when converting pixmap"); if (!da && sa) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot drop alpha when converting pixmap"); if ((int)w < 0 || h < 0) return; if (d_line_inc == 0 && s_line_inc == 0) { w *= h; h = 1; } if (ss == 0 && ds == 0) { /* Common, no spots case */ if (da) { if (sa) { while (h--) { size_t ww = w; while (ww--) { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; d[3] = s[3]; d[4] = s[4]; s += 5; d += 5; } } } else { while (h--) { size_t ww = w; while (ww--) { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; d[3] = s[3]; d[4] = 255; s += 4; d += 5; } } } } else { while (h--) { size_t ww = w; while (ww--) { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; d[3] = s[3]; s += 4; d += 4; } } } } else if (copy_spots) { /* Slower, spots capable version */ while (h--) { int i; size_t ww = w; while (ww--) { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; d[3] = s[3]; s += 4; d += 4; for (i=ss; i > 0; i--) *d++ = *s++; if (da) *d++ = sa ? *s++ : 255; } d += d_line_inc; s += s_line_inc; } } else { while (h--) { size_t ww = w; while (ww--) { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; d[3] = s[3]; s += sn; d += dn; if (da) d[-1] = sa ? s[-1] : 255; } d += d_line_inc; s += s_line_inc; } } } void fz_fast_any_to_alpha(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, int copy_spots) { if (!src->alpha) fz_clear_pixmap_with_value(ctx, dst, 255); else { unsigned char *s = src->samples; unsigned char *d = dst->samples; size_t w = src->w; int h = src->h; int n = src->n; ptrdiff_t d_line_inc = dst->stride - w * dst->n; ptrdiff_t s_line_inc = src->stride - w * src->n; if ((int)w < 0 || h < 0) return; if (d_line_inc == 0 && s_line_inc == 0) { w *= h; h = 1; } s += n-1; while (h--) { size_t ww = w; while (ww--) { *d++ = *s; s += n; } d += d_line_inc; s += s_line_inc; } } } void fz_convert_fast_pixmap_samples(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, int copy_spots) { fz_colorspace *ss = src->colorspace; fz_colorspace *ds = dst->colorspace; int dtype = ds ? ds->type : FZ_COLORSPACE_GRAY; int stype = ss ? ss->type : FZ_COLORSPACE_GRAY; if (!ds) { fz_fast_any_to_alpha(ctx, src, dst, copy_spots); } else if (stype == FZ_COLORSPACE_GRAY) { if (dtype == FZ_COLORSPACE_GRAY) fast_gray_to_gray(ctx, src, dst, copy_spots); else if (dtype == FZ_COLORSPACE_RGB) fast_gray_to_rgb(ctx, src, dst, copy_spots); else if (dtype == FZ_COLORSPACE_BGR) fast_gray_to_rgb(ctx, src, dst, copy_spots); else if (dtype == FZ_COLORSPACE_CMYK) fast_gray_to_cmyk(ctx, src, dst, copy_spots); else goto slow; } else if (stype == FZ_COLORSPACE_RGB) { if (dtype == FZ_COLORSPACE_GRAY) fast_rgb_to_gray(ctx, src, dst, copy_spots); else if (dtype == FZ_COLORSPACE_RGB) fast_rgb_to_rgb(ctx, src, dst, copy_spots); else if (dtype == FZ_COLORSPACE_BGR) fast_rgb_to_bgr(ctx, src, dst, copy_spots); else if (dtype == FZ_COLORSPACE_CMYK) fast_rgb_to_cmyk(ctx, src, dst, copy_spots); else goto slow; } else if (stype == FZ_COLORSPACE_BGR) { if (dtype == FZ_COLORSPACE_GRAY) fast_bgr_to_gray(ctx, src, dst, copy_spots); else if (dtype == FZ_COLORSPACE_RGB) fast_rgb_to_bgr(ctx, src, dst, copy_spots); else if (dtype == FZ_COLORSPACE_BGR) fast_rgb_to_rgb(ctx, src, dst, copy_spots); else if (dtype == FZ_COLORSPACE_CMYK) fast_bgr_to_cmyk(ctx, src, dst, copy_spots); else goto slow; } else if (stype == FZ_COLORSPACE_CMYK) { if (dtype == FZ_COLORSPACE_GRAY) fast_cmyk_to_gray(ctx, src, dst, copy_spots); else if (dtype == FZ_COLORSPACE_RGB) fast_cmyk_to_rgb(ctx, src, dst, copy_spots); else if (dtype == FZ_COLORSPACE_BGR) fast_cmyk_to_bgr(ctx, src, dst, copy_spots); else if (dtype == FZ_COLORSPACE_CMYK) fast_cmyk_to_cmyk(ctx, src, dst, copy_spots); else goto slow; } else { goto slow; } return; slow: fz_convert_slow_pixmap_samples(ctx, src, dst, NULL, fz_default_color_params, copy_spots); }