Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/source/fitz/color-fast.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/source/fitz/color-fast.c Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,1736 @@ +// Copyright (C) 2004-2024 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 <https://www.gnu.org/licenses/agpl-3.0.en.html> +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see <https://www.artifex.com/> or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + +#include "mupdf/fitz.h" + +#include "color-imp.h" + +#include <math.h> + +/* 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_ARGUMENT, "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_ARGUMENT, "incompatible number of spots when converting pixmap"); + if (!da && sa) + fz_throw(ctx, FZ_ERROR_ARGUMENT, "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_ARGUMENT, "incompatible number of spots when converting pixmap"); + + if ((int)w < 0 || h < 0) + fz_throw(ctx, FZ_ERROR_LIMIT, "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_ARGUMENT, "incompatible number of spots when converting pixmap"); + if (!da && sa) + fz_throw(ctx, FZ_ERROR_ARGUMENT, "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_ARGUMENT, "incompatible number of spots when converting pixmap"); + if (!da && sa) + fz_throw(ctx, FZ_ERROR_ARGUMENT, "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_ARGUMENT, "incompatible number of spots when converting pixmap"); + + if ((int)w < 0 || h < 0) + fz_throw(ctx, FZ_ERROR_LIMIT, "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_ARGUMENT, "incompatible number of spots when converting pixmap"); + + if ((int)w < 0 || h < 0) + fz_throw(ctx, FZ_ERROR_LIMIT, "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_ARGUMENT, "incompatible number of spots when converting pixmap"); + + if ((int)w < 0 || h < 0) + fz_throw(ctx, FZ_ERROR_LIMIT, "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_ARGUMENT, "incompatible number of spots when converting pixmap"); + + if ((int)w < 0 || h < 0) + fz_throw(ctx, FZ_ERROR_LIMIT, "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_ARGUMENT, "incompatible number of spots when converting pixmap"); + + if ((int)w < 0 || h < 0) + fz_throw(ctx, FZ_ERROR_LIMIT, "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_ARGUMENT, "incompatible number of spots when converting pixmap"); + if (!da && sa) + fz_throw(ctx, FZ_ERROR_ARGUMENT, "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 ((int)w < 0 || h < 0) + return; + + /* Alpha-only pixmaps count as device_gray with no alpha. */ + if (sn == 1 && sa) + sa = 0; + if (dn == 1 && da) + da = 0; + + /* 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_ARGUMENT, "incompatible number of spots when converting pixmap"); + if (!da && sa) + fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot drop alpha when converting pixmap"); + + 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_ARGUMENT, "incompatible number of spots when converting pixmap"); + if (!da && sa) + fz_throw(ctx, FZ_ERROR_ARGUMENT, "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_ARGUMENT, "incompatible number of spots when converting pixmap"); + if (!da && sa) + fz_throw(ctx, FZ_ERROR_ARGUMENT, "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); +}
