diff options
Diffstat (limited to 'source/fitz')
-rw-r--r-- | source/fitz/color-lcms.c | 12 | ||||
-rw-r--r-- | source/fitz/colorspace-imp.h | 8 | ||||
-rw-r--r-- | source/fitz/colorspace.c | 394 | ||||
-rw-r--r-- | source/fitz/draw-affine.c | 6 | ||||
-rw-r--r-- | source/fitz/draw-device.c | 316 | ||||
-rw-r--r-- | source/fitz/draw-paint.c | 5 | ||||
-rw-r--r-- | source/fitz/pixmap.c | 4 | ||||
-rw-r--r-- | source/fitz/separation.c | 334 |
8 files changed, 866 insertions, 213 deletions
diff --git a/source/fitz/color-lcms.c b/source/fitz/color-lcms.c index 1bc344f4..3714ea45 100644 --- a/source/fitz/color-lcms.c +++ b/source/fitz/color-lcms.c @@ -180,7 +180,7 @@ fz_lcms_transform_color(fz_cmm_instance *instance, fz_icclink *link, unsigned sh } void -fz_lcms_init_link(fz_cmm_instance *instance, fz_icclink *link, const fz_color_params *rend, int cmm_flags, int num_bytes, int extras, const fz_iccprofile *src, const fz_iccprofile *prf, const fz_iccprofile *dst) +fz_lcms_init_link(fz_cmm_instance *instance, fz_icclink *link, const fz_iccprofile *dst, int dst_extras, const fz_iccprofile *src, int src_extras, const fz_iccprofile *prf, const fz_color_params *rend, int cmm_flags, int num_bytes, int copy_spots) { cmsContext cmm_ctx = (cmsContext)instance; fz_context *ctx = (fz_context *)cmsGetContextUserData(cmm_ctx); @@ -199,7 +199,7 @@ fz_lcms_init_link(fz_cmm_instance *instance, fz_icclink *link, const fz_color_pa if (lcms_src_cs < 0) lcms_src_cs = 0; src_num_chan = cmsChannelsOf(cmm_ctx, src_cs); - src_data_type = (COLORSPACE_SH(lcms_src_cs) | CHANNELS_SH(src_num_chan) | DOSWAP_SH(src->bgr) | BYTES_SH(num_bytes) | EXTRA_SH(extras)); + src_data_type = (COLORSPACE_SH(lcms_src_cs) | CHANNELS_SH(src_num_chan) | DOSWAP_SH(src->bgr) | BYTES_SH(num_bytes) | EXTRA_SH(src_extras)); /* dst */ des_cs = cmsGetColorSpace(cmm_ctx, dst->cmm_handle); @@ -207,17 +207,19 @@ fz_lcms_init_link(fz_cmm_instance *instance, fz_icclink *link, const fz_color_pa if (lcms_des_cs < 0) lcms_des_cs = 0; des_num_chan = cmsChannelsOf(cmm_ctx, des_cs); - des_data_type = (COLORSPACE_SH(lcms_des_cs) | CHANNELS_SH(des_num_chan) | DOSWAP_SH(dst->bgr) | BYTES_SH(num_bytes) | EXTRA_SH(extras)); + des_data_type = (COLORSPACE_SH(lcms_des_cs) | CHANNELS_SH(des_num_chan) | DOSWAP_SH(dst->bgr) | BYTES_SH(num_bytes) | EXTRA_SH(dst_extras)); /* flags */ if (rend->bp) flag |= cmsFLAGS_BLACKPOINTCOMPENSATION; - if (extras) + if (copy_spots) flag |= cmsFLAGS_COPY_ALPHA; link->depth = num_bytes; - link->extras = extras; + link->src_extras = src_extras; + link->dst_extras = dst_extras; + link->copy_spots = copy_spots; if (prf == NULL) { diff --git a/source/fitz/colorspace-imp.h b/source/fitz/colorspace-imp.h index c4e94f03..0ca960a0 100644 --- a/source/fitz/colorspace-imp.h +++ b/source/fitz/colorspace-imp.h @@ -15,7 +15,7 @@ int fz_cmm_avoid_white_fix_flag(fz_context *ctx); void fz_cmm_transform_pixmap(fz_context *ctx, fz_icclink *link, fz_pixmap *dst, fz_pixmap *src); void fz_cmm_transform_color(fz_context *ctx, fz_icclink *link, unsigned short *dst, const unsigned short *src); -void fz_cmm_init_link(fz_context *ctx, fz_icclink *link, const fz_color_params *rend, int cmm_flags, int num_bytes, int extras, const fz_iccprofile *src, const fz_iccprofile *prf, const fz_iccprofile *des); +void fz_cmm_init_link(fz_context *ctx, fz_icclink *link, const fz_iccprofile *dst, int dst_extras, const fz_iccprofile *src, int src_extras, const fz_iccprofile *prf, const fz_color_params *rend, int cmm_flags, int num_bytes, int copy_spots); void fz_cmm_fin_link(fz_context *ctx, fz_icclink *link); fz_cmm_instance *fz_cmm_new_instance(fz_context *ctx); void fz_cmm_drop_instance(fz_context *ctx); @@ -51,10 +51,10 @@ struct fz_iccprofile_s struct fz_icclink_s { fz_storable storable; - int num_in; - int num_out; int depth; - int extras; + int src_extras; + int dst_extras; + int copy_spots; int is_identity; void *cmm_handle; }; diff --git a/source/fitz/colorspace.c b/source/fitz/colorspace.c index 29ad18d3..3e322bd9 100644 --- a/source/fitz/colorspace.c +++ b/source/fitz/colorspace.c @@ -32,10 +32,10 @@ fz_cmm_transform_color(fz_context *ctx, fz_icclink *link, unsigned short *dst, c } void -fz_cmm_init_link(fz_context *ctx, fz_icclink *link, const fz_color_params *rend, int cmm_flags, int num_bytes, int extras, const fz_iccprofile *src, const fz_iccprofile *prf, const fz_iccprofile *des) +fz_cmm_init_link(fz_context *ctx, fz_icclink *link, const fz_iccprofile *dst, int dst_extras, const fz_iccprofile *src, int src_extras, const fz_iccprofile *prf, const fz_color_params *rend, int cmm_flags, int num_bytes, int copy_spots) { if (ctx && ctx->colorspace && ctx->colorspace->cmm && ctx->cmm_instance) - ctx->colorspace->cmm->init_link(ctx->cmm_instance, link, rend, cmm_flags, num_bytes, extras, src, prf, des); + ctx->colorspace->cmm->init_link(ctx->cmm_instance, link, dst, dst_extras, src, src_extras, prf, rend, cmm_flags, num_bytes, copy_spots); } void @@ -201,7 +201,9 @@ struct fz_link_key_s { unsigned char src_md5[16]; unsigned char dst_md5[16]; fz_color_params rend; - int extras; + int src_extras; + int dst_extras; + int copy_spots; int depth; int proof; }; @@ -227,7 +229,9 @@ fz_cmp_link_key(fz_context *ctx, void *k0_, void *k1_) fz_link_key *k0 = (fz_link_key *)k0_; fz_link_key *k1 = (fz_link_key *)k1_; return k0->proof == k1->proof && - k0->extras == k1->extras && + k0->src_extras == k1->src_extras && + k0->dst_extras == k1->dst_extras && + k0->copy_spots == k1->copy_spots && k0->depth == k1->depth && k0->rend.bp == k1->rend.bp && k0->rend.ri == k1->rend.ri && @@ -260,10 +264,13 @@ fz_make_hash_link_key(fz_context *ctx, fz_store_hash *hash, void *key_) fz_link_key *key = (fz_link_key *)key_; memcpy(hash->u.link.dst_md5, key->dst_md5, 16); memcpy(hash->u.link.src_md5, key->src_md5, 16); - hash->u.link.ri_bp = (key->rend.ri<<1) | key->rend.bp; - hash->u.link.extras = key->extras; - hash->u.link.depth = key->depth; + hash->u.link.ri = key->rend.ri; + hash->u.link.bp = key->rend.bp; + hash->u.link.src_extras = key->src_extras; + hash->u.link.dst_extras = key->dst_extras; + hash->u.link.bpp16 = key->depth == 2; hash->u.link.proof = key->proof; + hash->u.link.copy_spots = key->copy_spots; return 1; } @@ -319,14 +326,11 @@ get_base_icc_profile(fz_context *ctx, const fz_colorspace *cs) } static fz_icclink * -fz_new_icc_link(fz_context *ctx, fz_iccprofile *src, fz_iccprofile *prf, fz_iccprofile *dst, const fz_color_params *rend, int num_bytes, int extras) +fz_new_icc_link(fz_context *ctx, fz_iccprofile *dst, int dst_extras, fz_iccprofile *src, int src_extras, fz_iccprofile *prf, const fz_color_params *rend, int num_bytes, int copy_extras) { fz_icclink *link = fz_malloc_struct(ctx, fz_icclink); FZ_INIT_STORABLE(link, 1, fz_drop_link_imp); - link->num_in = src->num_devcomp; - link->num_out = dst->num_devcomp; - if (memcmp(src->md5, dst->md5, 16) == 0 && prf == NULL) { link->is_identity = 1; @@ -334,7 +338,7 @@ fz_new_icc_link(fz_context *ctx, fz_iccprofile *src, fz_iccprofile *prf, fz_iccp } fz_try(ctx) - fz_cmm_init_link(ctx, link, rend, 0, num_bytes, extras, src, prf, dst); + fz_cmm_init_link(ctx, link, dst, dst_extras, src, src_extras, prf, rend, 0, num_bytes, copy_extras); fz_catch(ctx) { fz_free(ctx, link); @@ -378,7 +382,7 @@ fz_icc_from_cal(fz_context *ctx, const fz_colorspace *cs) } static fz_icclink * -fz_get_icc_link(fz_context *ctx, const fz_colorspace *src, const fz_colorspace *prf, const fz_colorspace *dst, const fz_color_params *rend, int num_bytes, int extras, int *src_n) +fz_get_icc_link(fz_context *ctx, const fz_colorspace *dst, int dst_extras, const fz_colorspace *src, int src_extras, const fz_colorspace *prf, const fz_color_params *rend, int num_bytes, int copy_spots, int *src_n) { fz_icclink *link = NULL; fz_iccprofile *src_icc = NULL; @@ -387,6 +391,8 @@ fz_get_icc_link(fz_context *ctx, const fz_colorspace *src, const fz_colorspace * fz_link_key *key = NULL; fz_icclink *new_link; + assert(!copy_spots || src_extras == dst_extras); + if (prf != NULL) prf_icc = prf->data; @@ -440,6 +446,9 @@ fz_get_icc_link(fz_context *ctx, const fz_colorspace *src, const fz_colorspace * fz_var(link); fz_var(key); + if (rend == NULL) + rend = fz_default_color_params(ctx); + fz_try(ctx) { /* Check the storable to see if we have a copy. */ @@ -449,15 +458,17 @@ fz_get_icc_link(fz_context *ctx, const fz_colorspace *src, const fz_colorspace * memcpy(&key->src_md5, src_icc->md5, 16); key->rend.ri = rend->ri; key->rend.bp = rend->bp; - key->extras = extras; + key->src_extras = src_extras; + key->dst_extras = dst_extras; key->depth = num_bytes; key->proof = (prf_icc != NULL); + key->copy_spots = copy_spots; link = fz_find_item(ctx, fz_drop_link_imp, key, &fz_link_store_type); /* Not found. Make new one add to store. */ if (link == NULL) { - link = fz_new_icc_link(ctx, src_icc, prf_icc, dst_icc, rend, num_bytes, extras); + link = fz_new_icc_link(ctx, dst_icc, dst_extras, src_icc, src_extras, prf_icc, rend, num_bytes, copy_spots); new_link = fz_store_item(ctx, key, link, sizeof(fz_icclink), &fz_link_store_type); if (new_link != NULL) { @@ -828,21 +839,23 @@ fz_default_color_params(fz_context *ctx) /* Fast pixmap color conversions */ -static void fast_gray_to_rgb(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params) +static void fast_gray_to_rgb(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params, 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 * (da + ds + 3); - ptrdiff_t s_line_inc = src->stride - w * (sa + ss + 1); + ptrdiff_t d_line_inc = dst->stride - w * dn; + ptrdiff_t s_line_inc = src->stride - w * sn; - /* Spots must match, and we can never drop alpha (but we can invent it) */ - if (dst->n != 3 + ds + da || src->n != 1 + ss + sa || ss != ds || (!da && sa)) + /* If copying spots, they must match, and we can never drop alpha (but we can invent it) */ + if ((copy_spots && ss != ds) || (!da && sa)) { assert("This should never happen" == NULL); fz_throw(ctx, FZ_ERROR_GENERIC, "Cannot convert between incompatible pixmaps"); @@ -917,7 +930,7 @@ static void fast_gray_to_rgb(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz } } } - else + else if (copy_spots) { /* Slower, spots capable version */ int i; @@ -940,23 +953,44 @@ static void fast_gray_to_rgb(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz 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, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params) +static void fast_gray_to_cmyk(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params, 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 * (da + ds + 4); - ptrdiff_t s_line_inc = src->stride - w * (sa + ss + 1); + ptrdiff_t d_line_inc = dst->stride - w * dn; + ptrdiff_t s_line_inc = src->stride - w * sn; - /* Spots must match, and we can never drop alpha (but we can invent it) */ - if (dst->n != 4 + ds + da || src->n != 1 + ss + sa || ss != ds || (!da && sa)) + /* If copying spots, they must match, and we can never drop alpha (but we can invent it) */ + if ((copy_spots && ss != ds) || (!da && sa)) { assert("This should never happen" == NULL); fz_throw(ctx, FZ_ERROR_GENERIC, "Cannot convert between incompatible pixmaps"); @@ -1034,7 +1068,7 @@ static void fast_gray_to_cmyk(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, f } } } - else + else if (copy_spots) { /* Slower, spots capable version */ int i; @@ -1058,23 +1092,45 @@ static void fast_gray_to_cmyk(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, f s += s_line_inc; } } + else + { + while (h--) + { + size_t ww = w; + while (ww--) + { + d[0] = 0; + d[1] = 0; + d[2] = 0; + d[3] = 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_gray(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params) +static void fast_rgb_to_gray(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params, 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 * (da + ds + 1); - ptrdiff_t s_line_inc = src->stride - w * (sa + ss + 3); + ptrdiff_t d_line_inc = dst->stride - w * dn; + ptrdiff_t s_line_inc = src->stride - w * sn; - /* Spots must match, and we can never drop alpha (but we can invent it) */ - if (dst->n != 1 + ds + da || src->n != 3 + ss + sa || ss != ds || (!da && sa)) + /* If copying spots, they must match, and we can never drop alpha (but we can invent it) */ + if ((copy_spots && ss != ds) || (!da && sa)) { assert("This should never happen" == NULL); fz_throw(ctx, FZ_ERROR_GENERIC, "Cannot convert between incompatible pixmaps"); @@ -1143,7 +1199,7 @@ static void fast_rgb_to_gray(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz } } } - else + else if (copy_spots) { /* Slower, spots capable version */ int i; @@ -1164,23 +1220,42 @@ static void fast_rgb_to_gray(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz 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, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params) +static void fast_bgr_to_gray(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params, 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 * (da + ds + 1); - ptrdiff_t s_line_inc = src->stride - w * (sa + ss + 3); + ptrdiff_t d_line_inc = dst->stride - w * dn; + ptrdiff_t s_line_inc = src->stride - w * sn; - /* Spots must match, and we can never drop alpha (but we can invent it) */ - if (dst->n != 1 + ds + da || src->n != 3 + ss + sa || ss != ds || (!da && sa)) + /* If copying spots, they must match, and we can never drop alpha (but we can invent it) */ + if ((copy_spots && ss != ds) || (!da && sa)) { assert("This should never happen" == NULL); fz_throw(ctx, FZ_ERROR_GENERIC, "Cannot convert between incompatible pixmaps"); @@ -1251,7 +1326,7 @@ static void fast_bgr_to_gray(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz } } } - else + else if (copy_spots) { /* Slower, spots capable version */ while (h--) @@ -1272,23 +1347,43 @@ static void fast_bgr_to_gray(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz 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, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params) +static void fast_rgb_to_cmyk(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params, 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 * (da + ds + 4); - ptrdiff_t s_line_inc = src->stride - w * (sa + ss + 3); + ptrdiff_t d_line_inc = dst->stride - w * dn; + ptrdiff_t s_line_inc = src->stride - w * sn; /* Spots must match, and we can never drop alpha (but we can invent it) */ - if (dst->n != 4 + ds + da || src->n != 3 + ss + sa || ss != ds || (!da && sa)) + if ((copy_spots || ss != ds) || (!da && sa)) { assert("This should never happen" == NULL); fz_throw(ctx, FZ_ERROR_GENERIC, "Cannot convert between incompatible pixmaps"); @@ -1378,7 +1473,7 @@ static void fast_rgb_to_cmyk(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz } } } - else + else if (copy_spots) { /* Slower, spots capable version */ while (h--) @@ -1406,23 +1501,49 @@ static void fast_rgb_to_cmyk(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz s += s_line_inc; } } + else + { + while (h--) + { + size_t ww = w; + while (ww--) + { + unsigned char c = s[0]; + unsigned char m = s[1]; + unsigned char y = s[2]; + unsigned char k = (unsigned char)(255 - fz_maxi(c, fz_maxi(m, y))); + d[0] = c + k; + d[1] = m + k; + d[2] = y + k; + d[3] = 255 - k; + 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_cmyk(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params) +static void fast_bgr_to_cmyk(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params, 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 * (da + ds + 4); - ptrdiff_t s_line_inc = src->stride - w * (sa + ss + 3); + ptrdiff_t d_line_inc = dst->stride - w * dn; + ptrdiff_t s_line_inc = src->stride - w * sn; /* Spots must match, and we can never drop alpha (but we can invent it) */ - if (dst->n != 4 + ds + da || src->n != 3 + ss + sa || ss != ds || (!da && sa)) + if ((copy_spots && ss != ds) || (!da && sa)) { assert("This should never happen" == NULL); fz_throw(ctx, FZ_ERROR_GENERIC, "Cannot convert between incompatible pixmaps"); @@ -1512,7 +1633,7 @@ static void fast_bgr_to_cmyk(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz } } } - else + else if (copy_spots) { /* Slower, spots capable version */ while (h--) @@ -1540,23 +1661,49 @@ static void fast_bgr_to_cmyk(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz s += s_line_inc; } } + else + { + while (h--) + { + size_t ww = w; + while (ww--) + { + unsigned char c = s[2]; + unsigned char m = s[1]; + unsigned char y = s[0]; + unsigned char k = (unsigned char)(255 - fz_maxi(c, fz_maxi(m, y))); + d[0] = c + k; + d[1] = m + k; + d[2] = y + k; + d[3] = 255 - k; + 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_gray(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params) +static void fast_cmyk_to_gray(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params, 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 * (da + ds + 1); - ptrdiff_t s_line_inc = src->stride - w * (sa + ss + 4); + ptrdiff_t d_line_inc = dst->stride - w * dn; + ptrdiff_t s_line_inc = src->stride - w * sn; /* Spots must match, and we can never drop alpha (but we can invent it) */ - if (dst->n != 1 + ds + da || src->n != 4 + ss + sa || ss != ds || (!da && sa)) + if ((copy_spots && ss != ds) || (!da && sa)) { assert("This should never happen" == NULL); fz_throw(ctx, FZ_ERROR_GENERIC, "Cannot convert between incompatible pixmaps"); @@ -1634,7 +1781,7 @@ static void fast_cmyk_to_gray(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, f } } } - else + else if (copy_spots) { /* Slower, spots capable version */ while (h--) @@ -1658,6 +1805,26 @@ static void fast_cmyk_to_gray(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, f s += s_line_inc; } } + else + { + while (h--) + { + size_t ww = w; + while (ww--) + { + unsigned char c = fz_mul255(255 - s[0], 77); + unsigned char m = fz_mul255(255 - s[1], 150); + unsigned char y = fz_mul255(255 - s[2], 28); + d[0] = (unsigned char)fz_maxi(s[3] - c - m - y, 0); + s += sn; + d += dn; + if (da) + d[-1] = sa ? s[-1] : 255; + } + d += d_line_inc; + s += s_line_inc; + } + } } #ifdef ARCH_ARM @@ -1987,23 +2154,25 @@ static inline void cached_cmyk_conv(unsigned char *restrict const pr, unsigned c #endif } -static void fast_cmyk_to_rgb(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params) +static void fast_cmyk_to_rgb(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params, 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 * (da + ds + 3); - ptrdiff_t s_line_inc = src->stride - w * (sa + ss + 4); + ptrdiff_t d_line_inc = dst->stride - w * dn; + ptrdiff_t s_line_inc = src->stride - w * sn; unsigned int C,M,Y,K; unsigned char r,g,b; /* Spots must match, and we can never drop alpha (but we can invent it) */ - if (dst->n != 3 + ds + da || src->n != 4 + ss + sa || ss != ds || (!da && sa)) + if ((copy_spots && ss != ds) || (!da && sa)) { assert("This should never happen" == NULL); fz_throw(ctx, FZ_ERROR_GENERIC, "Cannot convert between incompatible pixmaps"); @@ -2033,13 +2202,13 @@ static void fast_cmyk_to_rgb(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz { if (sa) { - #ifdef ARCH_ARM +#ifdef ARCH_ARM if (h == 1) { fast_cmyk_to_rgb_ARM(d, s, w); return; } - #endif +#endif while (h--) { size_t ww = w; @@ -2096,7 +2265,7 @@ static void fast_cmyk_to_rgb(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz } } } - else + else if (copy_spots) { /* Slower, spots capable version */ while (h--) @@ -2120,25 +2289,48 @@ static void fast_cmyk_to_rgb(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz s += s_line_inc; } } + else + { + /* Slower, spots capable version */ + while (h--) + { + size_t ww = w; + while (ww--) + { + cached_cmyk_conv(&r, &g, &b, &C, &M, &Y, &K, s[0], s[1], s[2], s[3]); + d[0] = r; + d[1] = g; + d[2] = b; + 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_bgr(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params) +static void fast_cmyk_to_bgr(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params, 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 * (da + ds + 3); - ptrdiff_t s_line_inc = src->stride - w * (sa + ss + 4); + ptrdiff_t d_line_inc = dst->stride - w * dn; + ptrdiff_t s_line_inc = src->stride - w * sn; unsigned int C,M,Y,K; unsigned char r,g,b; /* Spots must match, and we can never drop alpha (but we can invent it) */ - if (dst->n != 3 + ds + da || src->n != 4 + ss + sa || ss != ds || (!da && sa)) + if ((copy_spots && ss != ds) || (!da && sa)) { assert("This should never happen" == NULL); fz_throw(ctx, FZ_ERROR_GENERIC, "Cannot convert between incompatible pixmaps"); @@ -2227,7 +2419,7 @@ static void fast_cmyk_to_bgr(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz } } } - else + else if (copy_spots) { /* Slower, spots capable version */ while (h--) @@ -2251,23 +2443,46 @@ static void fast_cmyk_to_bgr(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz s += s_line_inc; } } + else + { + /* Slower, spots capable version */ + while (h--) + { + size_t ww = w; + while (ww--) + { + cached_cmyk_conv(&r, &g, &b, &C, &M, &Y, &K, s[0], s[1], s[2], s[3]); + d[0] = b; + d[1] = g; + d[2] = r; + 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_bgr(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params) +static void fast_rgb_to_bgr(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params, 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 * (da + ds + 3); - ptrdiff_t s_line_inc = src->stride - w * (sa + ss + 3); + ptrdiff_t d_line_inc = dst->stride - w * dn; + ptrdiff_t s_line_inc = src->stride - w * sn; - /* Spots must match, and we can never drop alpha (but we can invent it) */ - if (dst->n != 3 + ds + da || src->n != 3 + ss + sa || ss != ds || (!da && sa)) + /* If copying spots, they must match, and we can never drop alpha (but we can invent it) */ + if ((copy_spots && ss != ds) || (!da && sa)) { assert("This should never happen" == NULL); fz_throw(ctx, FZ_ERROR_GENERIC, "Cannot convert between incompatible pixmaps"); @@ -2336,7 +2551,7 @@ static void fast_rgb_to_bgr(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_ } } } - else + else if (copy_spots) { /* Slower, spots capable version */ while (h--) @@ -2359,10 +2574,29 @@ static void fast_rgb_to_bgr(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_ 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 -icc_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params) +icc_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params, int copy_spots) { fz_colorspace *srcs = src->colorspace; fz_colorspace *dsts = dst->colorspace; @@ -2394,7 +2628,7 @@ icc_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace * inputpos = src->samples; outputpos = dst->samples; - link = fz_get_icc_link(ctx, srcs, prf, dsts, color_params, 1, dst->alpha, &src_n); + link = fz_get_icc_link(ctx, dsts, dst->s + dst->alpha, srcs, src->s + src->alpha, prf, color_params, 1, copy_spots, &src_n); if (link->is_identity) { @@ -2450,7 +2684,7 @@ convert_to_icc_base(fz_context *ctx, fz_colorspace *srcs, float *src_f, float *d * be handled. Realize those can map from index->devn->pdf-cal->icc for * example. */ static void -icc_base_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params) +icc_base_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params, int copy_spots) { fz_colorspace *srcs = src->colorspace; fz_colorspace *base_cs = get_base_icc_space(ctx, srcs); @@ -2501,7 +2735,7 @@ icc_base_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorsp } fz_try(ctx) - icc_conv_pixmap(ctx, dst, base, prf, default_cs, color_params); + icc_conv_pixmap(ctx, dst, base, prf, default_cs, color_params, copy_spots); fz_always(ctx) fz_drop_pixmap(ctx, base); fz_catch(ctx) @@ -2509,7 +2743,7 @@ icc_base_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorsp } static void -std_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params) +std_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params, int copy_spots) { float srcv[FZ_MAX_COLORS]; float dstv[FZ_MAX_COLORS]; @@ -2710,8 +2944,10 @@ std_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace * } } -static void fast_any_to_alpha(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params) +static void fast_any_to_alpha(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params, int copy_spots) { + assert(copy_spots && dst->s == 0 && src->s == 0); + if (!src->alpha) fz_clear_pixmap_with_value(ctx, dst, 255); else @@ -3060,7 +3296,7 @@ void fz_find_color_converter(fz_context *ctx, fz_color_converter *cc, const fz_c cc->convert = icc_conv_color; else cc->convert = icc_base_conv_color; - cc->link = fz_get_icc_link(ctx, ss_base, is, ds, params, 2, 0, &cc->n); + cc->link = fz_get_icc_link(ctx, ds, 0, ss_base, 0, is, params, 2, 0, &cc->n); } else cc->convert = std_conv_color; diff --git a/source/fitz/draw-affine.c b/source/fitz/draw-affine.c index b67e3e0d..6ece799f 100644 --- a/source/fitz/draw-affine.c +++ b/source/fitz/draw-affine.c @@ -3356,6 +3356,12 @@ fz_paint_image_with_color(fz_pixmap * restrict dst, const fz_irect * restrict sc void fz_paint_image(fz_pixmap * restrict dst, const fz_irect * restrict scissor, fz_pixmap * restrict shape, const fz_pixmap * restrict img, const fz_matrix * restrict ctm, int alpha, int lerp_allowed, int as_tiled) { + // FIXME + if (dst->n - dst->alpha != img->n - img->alpha && (dst->n != 3 + dst->alpha || img->n != 1 + img->alpha)) + { + fprintf(stderr, "Skipping image plot - FIXME\n"); + return; + } assert(dst->n - dst->alpha == img->n - img->alpha|| (dst->n == 3 + dst->alpha && img->n == 1 + img->alpha)); fz_paint_image_imp(dst, scissor, shape, img, ctm, NULL, alpha, lerp_allowed, as_tiled); } diff --git a/source/fitz/draw-device.c b/source/fitz/draw-device.c index 3a5ae1db..cadd7d57 100644 --- a/source/fitz/draw-device.c +++ b/source/fitz/draw-device.c @@ -46,6 +46,7 @@ struct fz_draw_device_s fz_rasterizer *rast; fz_default_colorspaces *default_cs; int flags; + int resolve_spots; int top; fz_scale_cache *cache_x; fz_scale_cache *cache_y; @@ -116,9 +117,8 @@ static void stack_change(fz_context *ctx, fz_draw_device *dev, char *s) * in a color space that is our target color space or a transparency group * color space decide if we should be using the proof color space at this time */ static fz_colorspace * -fz_proof_cs(fz_context *ctx, fz_device *devp) +fz_proof_cs(fz_context *ctx, fz_draw_device *dev) { - fz_draw_device *dev = (fz_draw_device*)devp; fz_colorspace *prf = fz_default_output_intent(ctx, dev->default_cs); fz_draw_state *state = &dev->stack[dev->top]; fz_colorspace *model = state->dest->colorspace; @@ -329,6 +329,68 @@ static inline fz_matrix concat(const fz_matrix *one, const fz_matrix *two) } static void +resolve_color(fz_context *ctx, const float *color, fz_colorspace *colorspace, float alpha, const fz_color_params *color_params, unsigned char *colorbv, fz_pixmap *dest, fz_colorspace *prf) +{ + float colorfv[FZ_MAX_COLORS]; + int i; + int n = dest->n - dest->alpha; + fz_colorspace *model = dest->colorspace; + + if (colorspace == NULL && model != NULL) + fz_throw(ctx, FZ_ERROR_GENERIC, "color destination requires source color"); + + if (color_params == NULL) + color_params = fz_default_color_params(ctx); + + if (n == 0) + i = 0; + else if (fz_colorspace_is_device_n(ctx, colorspace) && dest->seps) + { + fz_convert_separation_colors(ctx, color_params, dest->colorspace, dest->seps, colorfv, colorspace, color); + for (i = 0; i < n; i++) + colorbv[i] = colorfv[i] * 255; + } + else + { + int c = n - dest->s; + fz_convert_color(ctx, color_params, prf, dest->colorspace, colorfv, colorspace, color); + for (i = 0; i < c; i++) + colorbv[i] = colorfv[i] * 255; + for (; i < n; i++) + colorbv[i] = 0; + } + colorbv[i] = alpha * 255; +} + +static fz_draw_state * +push_group_for_separations(fz_context *ctx, fz_draw_device *dev, fz_colorspace *prf, fz_default_colorspaces *default_cs) +{ + fz_separations *clone = fz_clone_separations_for_overprint(ctx, dev->stack[0].dest->seps); + + /* Not needed */ + if (clone == NULL) + { + dev->resolve_spots = 0; + return &dev->stack[0]; + } + + /* Make a new pixmap to render to. */ + fz_try(ctx) + { + dev->stack[1] = dev->stack[0]; + dev->stack[1].dest = NULL; /* So we are safe to destroy */ + dev->stack[1].dest = fz_clone_pixmap_area_with_different_seps(ctx, dev->stack[0].dest, &dev->stack[0].scissor, fz_device_cmyk(ctx), clone, prf, default_cs); + dev->top++; + } + fz_always(ctx) + fz_drop_separations(ctx, clone); + fz_catch(ctx) + fz_rethrow(ctx); + + return &dev->stack[1]; +} + +static void fz_draw_fill_path(fz_context *ctx, fz_device *devp, const fz_path *path, int even_odd, const fz_matrix *in_ctm, fz_colorspace *colorspace_in, const float *color, float alpha, const fz_color_params *color_params) { @@ -336,21 +398,15 @@ fz_draw_fill_path(fz_context *ctx, fz_device *devp, const fz_path *path, int eve fz_matrix ctm = concat(in_ctm, &dev->transform); fz_rasterizer *rast = dev->rast; fz_colorspace *colorspace = fz_default_colorspace(ctx, dev->default_cs, colorspace_in); - fz_colorspace *prf = fz_proof_cs(ctx, devp); + fz_colorspace *prf = fz_proof_cs(ctx, dev); float expansion = fz_matrix_expansion(&ctm); float flatness = 0.3f / expansion; unsigned char colorbv[FZ_MAX_COLORS + 1]; - float colorfv[FZ_MAX_COLORS]; fz_irect bbox; - int i, n; fz_draw_state *state = &dev->stack[dev->top]; - fz_colorspace *model = state->dest->colorspace; - - if (colorspace == NULL && model != NULL) - fz_throw(ctx, FZ_ERROR_GENERIC, "color destination requires source color"); - if (color_params == NULL) - color_params = fz_default_color_params(ctx); + if (dev->top == 0 && dev->resolve_spots) + state = push_group_for_separations(ctx, dev, prf, dev->default_cs); if (flatness < 0.001f) flatness = 0.001f; @@ -362,16 +418,7 @@ fz_draw_fill_path(fz_context *ctx, fz_device *devp, const fz_path *path, int eve if (state->blendmode & FZ_BLEND_KNOCKOUT) state = fz_knockout_begin(ctx, dev); - n = fz_colorspace_n(ctx, model); - if (n > 0) - { - fz_convert_color(ctx, color_params, prf, model, colorfv, colorspace, color); - for (i = 0; i < n; i++) - colorbv[i] = colorfv[i] * 255; - } - else - i = 0; - colorbv[i] = alpha * 255; + resolve_color(ctx, color, colorspace, alpha, color_params, colorbv, state->dest, prf); fz_convert_rasterizer(ctx, rast, even_odd, state->dest, colorbv); if (state->shape) @@ -395,25 +442,18 @@ fz_draw_stroke_path(fz_context *ctx, fz_device *devp, const fz_path *path, const fz_matrix ctm = concat(in_ctm, &dev->transform); fz_rasterizer *rast = dev->rast; fz_colorspace *colorspace = fz_default_colorspace(ctx, dev->default_cs, colorspace_in); - fz_colorspace *prf = fz_proof_cs(ctx, devp); + fz_colorspace *prf = fz_proof_cs(ctx, dev); float expansion = fz_matrix_expansion(&ctm); float flatness = 0.3f / expansion; float linewidth = stroke->linewidth; unsigned char colorbv[FZ_MAX_COLORS + 1]; - float colorfv[FZ_MAX_COLORS]; fz_irect bbox; - int i, n; float aa_level = 2.0f/(fz_rasterizer_graphics_aa_level(rast)+2); fz_draw_state *state = &dev->stack[dev->top]; - fz_colorspace *model = state->dest->colorspace; float mlw = fz_rasterizer_graphics_min_line_width(rast); - - if (colorspace == NULL && model != NULL) - fz_throw(ctx, FZ_ERROR_GENERIC, "color destination requires source color"); - - if (color_params == NULL) - color_params = fz_default_color_params(ctx); + if (dev->top == 0 && dev->resolve_spots) + state = push_group_for_separations(ctx, dev, prf, dev->default_cs); if (mlw > aa_level) aa_level = mlw; @@ -429,16 +469,7 @@ fz_draw_stroke_path(fz_context *ctx, fz_device *devp, const fz_path *path, const if (state->blendmode & FZ_BLEND_KNOCKOUT) state = fz_knockout_begin(ctx, dev); - n = fz_colorspace_n(ctx, model); - if (n > 0) - { - fz_convert_color(ctx, color_params, prf, model, colorfv, colorspace, color); - for (i = 0; i < n; i++) - colorbv[i] = colorfv[i] * 255; - } - else - i = 0; - colorbv[i] = alpha * 255; + resolve_color(ctx, color, colorspace, alpha, color_params, colorbv, state->dest, prf); #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top, ""); @@ -483,6 +514,9 @@ fz_draw_clip_path(fz_context *ctx, fz_device *devp, const fz_path *path, int eve fz_irect local_scissor; fz_irect *scissor_ptr = &state->scissor; + if (dev->top == 0 && dev->resolve_spots) + state = push_group_for_separations(ctx, dev, fz_proof_cs(ctx, dev), dev->default_cs); + if (flatness < 0.001f) flatness = 0.001f; @@ -551,6 +585,9 @@ fz_draw_clip_stroke_path(fz_context *ctx, fz_device *devp, const fz_path *path, fz_irect local_scissor; fz_irect *scissor_ptr = &state->scissor; + if (dev->top == 0 && dev->resolve_spots) + state = push_group_for_separations(ctx, dev, fz_proof_cs(ctx, dev), dev->default_cs); + if (mlw > aa_level) aa_level = mlw; if (linewidth * expansion < aa_level) @@ -692,13 +729,15 @@ fz_draw_fill_text(fz_context *ctx, fz_device *devp, const fz_text *text, const f fz_colorspace *model = state->dest->colorspace; unsigned char colorbv[FZ_MAX_COLORS + 1]; unsigned char shapebv; - float colorfv[FZ_MAX_COLORS]; fz_text_span *span; - int i, n; + int i; fz_colorspace *colorspace = NULL; - fz_colorspace *prf = fz_proof_cs(ctx, devp); + fz_colorspace *prf = fz_proof_cs(ctx, dev); fz_rasterizer *rast = dev->rast; + if (dev->top == 0 && dev->resolve_spots) + state = push_group_for_separations(ctx, dev, prf, dev->default_cs); + if (colorspace_in) colorspace = fz_default_colorspace(ctx, dev->default_cs, colorspace_in); @@ -711,16 +750,7 @@ fz_draw_fill_text(fz_context *ctx, fz_device *devp, const fz_text *text, const f if (state->blendmode & FZ_BLEND_KNOCKOUT) state = fz_knockout_begin(ctx, dev); - n = fz_colorspace_n(ctx, model); - if (n > 0) - { - fz_convert_color(ctx, color_params, prf, model, colorfv, colorspace, color); - for (i = 0; i < n; i++) - colorbv[i] = colorfv[i] * 255; - } - else - i = 0; - colorbv[i] = alpha * 255; + resolve_color(ctx, color, colorspace, alpha, color_params, colorbv, state->dest, prf); shapebv = 255; for (span = text->head; span; span = span->next) @@ -789,37 +819,23 @@ fz_draw_stroke_text(fz_context *ctx, fz_device *devp, const fz_text *text, const fz_draw_device *dev = (fz_draw_device*)devp; fz_matrix ctm = concat(in_ctm, &dev->transform); fz_draw_state *state = &dev->stack[dev->top]; - fz_colorspace *model = state->dest->colorspace; unsigned char colorbv[FZ_MAX_COLORS + 1]; - float colorfv[FZ_MAX_COLORS]; fz_text_span *span; - int i, n; + int i; fz_colorspace *colorspace = NULL; - fz_colorspace *prf = fz_proof_cs(ctx, devp); + fz_colorspace *prf = fz_proof_cs(ctx, dev); int aa = fz_rasterizer_text_aa_level(dev->rast); + if (dev->top == 0 && dev->resolve_spots) + state = push_group_for_separations(ctx, dev, prf, dev->default_cs); + if (colorspace_in) colorspace = fz_default_colorspace(ctx, dev->default_cs, colorspace_in); - if (colorspace == NULL && model != NULL) - fz_throw(ctx, FZ_ERROR_GENERIC, "color destination requires source color"); - - if (color_params == NULL) - color_params = fz_default_color_params(ctx); - if (state->blendmode & FZ_BLEND_KNOCKOUT) state = fz_knockout_begin(ctx, dev); - n = fz_colorspace_n(ctx, model); - if (n > 0) - { - fz_convert_color(ctx, color_params, prf, model, colorfv, colorspace, color); - for (i = 0; i < n; i++) - colorbv[i] = colorfv[i] * 255; - } - else - i = 0; - colorbv[i] = alpha * 255; + resolve_color(ctx, color, colorspace, alpha, color_params, colorbv, state->dest, prf); for (span = text->head; span; span = span->next) { @@ -885,6 +901,9 @@ fz_draw_clip_text(fz_context *ctx, fz_device *devp, const fz_text *text, const f fz_rect rect; fz_rasterizer *rast = dev->rast; + if (dev->top == 0 && dev->resolve_spots) + state = push_group_for_separations(ctx, dev, fz_proof_cs(ctx, dev), dev->default_cs); + state = push_stack(ctx, dev); STACK_PUSHED("clip text"); model = state->dest->colorspace; @@ -1014,6 +1033,9 @@ fz_draw_clip_stroke_text(fz_context *ctx, fz_device *devp, const fz_text *text, fz_rect rect; int aa = fz_rasterizer_text_aa_level(dev->rast); + if (dev->top == 0 && dev->resolve_spots) + state = push_group_for_separations(ctx, dev, fz_proof_cs(ctx, dev), dev->default_cs); + STACK_PUSHED("clip stroke text"); /* make the mask the exact size needed */ fz_irect_from_rect(&bbox, fz_bound_text(ctx, text, stroke, &ctm, &rect)); @@ -1134,11 +1156,12 @@ fz_draw_fill_shade(fz_context *ctx, fz_device *devp, fz_shade *shade, const fz_m fz_rect bounds; fz_irect bbox, scissor; fz_pixmap *dest, *shape; - float colorfv[FZ_MAX_COLORS]; unsigned char colorbv[FZ_MAX_COLORS + 1]; fz_draw_state *state = &dev->stack[dev->top]; - fz_colorspace *model = state->dest->colorspace; - fz_colorspace *prf = fz_proof_cs(ctx, devp); + fz_colorspace *prf = fz_proof_cs(ctx, dev); + + if (dev->top == 0 && dev->resolve_spots) + state = push_group_for_separations(ctx, dev, prf, dev->default_cs); fz_bound_shade(ctx, shade, &ctm, &bounds); scissor = state->scissor; @@ -1174,16 +1197,8 @@ fz_draw_fill_shade(fz_context *ctx, fz_device *devp, fz_shade *shade, const fz_m { unsigned char *s; int x, y, n, i; - n = fz_colorspace_n(ctx, model); - if (n > 0) - { - fz_convert_color(ctx, color_params, prf, model, colorfv, fz_default_colorspace(ctx, dev->default_cs, shade->colorspace), shade->background); - for (i = 0; i < n; i++) - colorbv[i] = colorfv[i] * 255; - } - else - i = 0; - colorbv[i] = 255; + + resolve_color(ctx, shade->background, fz_default_colorspace(ctx, dev->default_cs, shade->colorspace), alpha, color_params, colorbv, state->dest, prf); n = dest->n; for (y = scissor.y0; y < scissor.y1; y++) @@ -1313,7 +1328,10 @@ fz_draw_fill_image(fz_context *ctx, fz_device *devp, fz_image *image, const fz_m fz_matrix inverse; fz_irect src_area; fz_colorspace *src_cs; - fz_colorspace *prf = fz_proof_cs(ctx, devp); + fz_colorspace *prf = fz_proof_cs(ctx, dev); + + if (dev->top == 0 && dev->resolve_spots) + state = push_group_for_separations(ctx, dev, prf, dev->default_cs); fz_intersect_irect(fz_pixmap_bbox(ctx, state->dest, &clip), &state->scissor); @@ -1434,28 +1452,22 @@ fz_draw_fill_image_mask(fz_context *ctx, fz_device *devp, fz_image *image, const fz_draw_device *dev = (fz_draw_device*)devp; fz_matrix local_ctm = concat(in_ctm, &dev->transform); unsigned char colorbv[FZ_MAX_COLORS + 1]; - float colorfv[FZ_MAX_COLORS]; fz_pixmap *scaled = NULL; fz_pixmap *pixmap; int dx, dy; - int i, n; fz_draw_state *state = &dev->stack[dev->top]; - fz_colorspace *model = state->dest->colorspace; fz_irect clip; fz_matrix inverse; fz_irect src_area; fz_colorspace *colorspace = NULL; - fz_colorspace *prf = fz_proof_cs(ctx, devp); + fz_colorspace *prf = fz_proof_cs(ctx, dev); + + if (dev->top == 0 && dev->resolve_spots) + state = push_group_for_separations(ctx, dev, prf, dev->default_cs); if (colorspace_in) colorspace = fz_default_colorspace(ctx, dev->default_cs, colorspace_in); - if (color_params == NULL) - color_params = fz_default_color_params(ctx); - - if (colorspace == NULL && model != NULL) - fz_throw(ctx, FZ_ERROR_GENERIC, "color destination requires source color"); - fz_pixmap_bbox(ctx, state->dest, &clip); fz_intersect_irect(&clip, &state->scissor); @@ -1525,16 +1537,7 @@ fz_draw_fill_image_mask(fz_context *ctx, fz_device *devp, fz_image *image, const } } - n = fz_colorspace_n(ctx, model); - if (n > 0) - { - fz_convert_color(ctx, color_params, prf, model, colorfv, colorspace, color); - for (i = 0; i < n; i++) - colorbv[i] = colorfv[i] * 255; - } - else - i = 0; - colorbv[i] = alpha * 255; + resolve_color(ctx, color, colorspace, alpha, color_params, colorbv, state->dest, prf); fz_paint_image_with_color(state->dest, &state->scissor, state->shape, pixmap, &local_ctm, colorbv, !(devp->hints & FZ_DONT_INTERPOLATE_IMAGES), devp->flags & FZ_DEVFLAG_GRIDFIT_AS_TILED); @@ -1561,6 +1564,9 @@ fz_draw_clip_image_mask(fz_context *ctx, fz_device *devp, fz_image *image, const fz_irect clip; fz_rect urect; + if (dev->top == 0 && dev->resolve_spots) + state = push_group_for_separations(ctx, dev, fz_proof_cs(ctx, dev), dev->default_cs); + STACK_PUSHED("clip image mask"); fz_pixmap_bbox(ctx, state->dest, &clip); fz_intersect_irect(&clip, &state->scissor); @@ -1722,6 +1728,9 @@ fz_draw_begin_mask(fz_context *ctx, fz_device *devp, const fz_rect *rect, int lu fz_rect trect = *rect; fz_colorspace *colorspace = NULL; + if (dev->top == 0 && dev->resolve_spots) + state = push_group_for_separations(ctx, dev, fz_proof_cs(ctx, dev), dev->default_cs); + if (colorspace_in) colorspace = fz_default_colorspace(ctx, dev->default_cs, colorspace_in); @@ -1858,6 +1867,9 @@ fz_draw_begin_group(fz_context *ctx, fz_device *devp, const fz_rect *rect, fz_co fz_colorspace *model = state->dest->colorspace; fz_rect trect = *rect; + if (dev->top == 0 && dev->resolve_spots) + state = push_group_for_separations(ctx, dev, fz_proof_cs(ctx, dev), dev->default_cs); + if (cs != NULL) model = fz_default_colorspace(ctx, dev->default_cs, cs); @@ -2101,6 +2113,9 @@ fz_draw_begin_tile(fz_context *ctx, fz_device *devp, const fz_rect *area, const fz_colorspace *model = state->dest->colorspace; fz_rect local_view = *view; + if (dev->top == 0 && dev->resolve_spots) + state = push_group_for_separations(ctx, dev, fz_proof_cs(ctx, dev), dev->default_cs); + /* area, view, xstep, ystep are in pattern space */ /* ctm maps from pattern space to device space */ @@ -2364,6 +2379,37 @@ fz_draw_set_default_colorspaces(fz_context *ctx, fz_device *devp, fz_default_col } static void +fz_draw_close_device(fz_context *ctx, fz_device *devp) +{ + fz_draw_device *dev = (fz_draw_device*)devp; + fz_colorspace *prf = fz_proof_cs(ctx, dev); + + /* pop and free the stacks */ + if (dev->top > dev->resolve_spots) + fz_warn(ctx, "items left on stack in draw device: %d", dev->top); + + while(dev->top > dev->resolve_spots) + { + fz_draw_state *state = &dev->stack[--dev->top]; + if (state[1].mask != state[0].mask) + fz_drop_pixmap(ctx, state[1].mask); + if (state[1].dest != state[0].dest) + fz_drop_pixmap(ctx, state[1].dest); + if (state[1].shape != state[0].shape) + fz_drop_pixmap(ctx, state[1].shape); + } + + if (dev->resolve_spots && dev->top) + { + fz_draw_state *state = &dev->stack[--dev->top]; + fz_copy_pixmap_area_converting_seps(ctx, state[0].dest, state[1].dest, prf, dev->default_cs); + fz_drop_pixmap(ctx, state[1].dest); + assert(state[1].mask == NULL); + assert(state[1].shape == NULL); + } +} + +static void fz_draw_drop_device(fz_context *ctx, fz_device *devp) { fz_draw_device *dev = (fz_draw_device*)devp; @@ -2373,7 +2419,7 @@ fz_draw_drop_device(fz_context *ctx, fz_device *devp) /* pop and free the stacks */ if (dev->top > 0) - fz_warn(ctx, "items left on stack in draw device: %d", dev->top+1); + fz_warn(ctx, "items left on stack in draw device: %d", dev->top); while(dev->top-- > 0) { @@ -2385,6 +2431,7 @@ fz_draw_drop_device(fz_context *ctx, fz_device *devp) if (state[1].shape != state[0].shape) fz_drop_pixmap(ctx, state[1].shape); } + /* We never free the dest/mask/shape at level 0, as: * 1) dest is passed in and ownership remains with the caller. * 2) shape and mask are NULL at level 0. @@ -2397,11 +2444,12 @@ fz_draw_drop_device(fz_context *ctx, fz_device *devp) } fz_device * -new_draw_device(fz_context *ctx, const fz_matrix *transform, fz_pixmap *dest, const fz_aa_context *aa) +new_draw_device(fz_context *ctx, const fz_matrix *transform, fz_pixmap *dest, const fz_aa_context *aa, const fz_irect *clip) { fz_draw_device *dev = fz_new_derived_device(ctx, fz_draw_device); dev->super.drop_device = fz_draw_drop_device; + dev->super.close_device = fz_draw_close_device; dev->super.fill_path = fz_draw_fill_path; dev->super.stroke_path = fz_draw_stroke_path; @@ -2434,6 +2482,7 @@ new_draw_device(fz_context *ctx, const fz_matrix *transform, fz_pixmap *dest, co dev->transform = transform ? *transform : fz_identity; dev->flags = 0; + dev->resolve_spots = 0; dev->top = 0; dev->stack = &dev->init_stack[0]; dev->stack_cap = STACK_SIZE; @@ -2446,6 +2495,38 @@ new_draw_device(fz_context *ctx, const fz_matrix *transform, fz_pixmap *dest, co dev->stack[0].scissor.x1 = dest->x + dest->w; dev->stack[0].scissor.y1 = dest->y + dest->h; + if (clip) + { + if (clip->x0 > dev->stack[0].scissor.x0) + dev->stack[0].scissor.x0 = clip->x0; + if (clip->x1 < dev->stack[0].scissor.x1) + dev->stack[0].scissor.x1 = clip->x1; + if (clip->y0 > dev->stack[0].scissor.y0) + dev->stack[0].scissor.y0 = clip->y0; + if (clip->y1 < dev->stack[0].scissor.y1) + dev->stack[0].scissor.y1 = clip->y1; + } + + /* If we have no separations structure at all, then we want a + * simple composite rendering (with no overprint simulation). + * If we do have a separations structure, so: 1) Any + * 'disabled' separations are ignored. 2) Any 'composite' + * separations means we will need to do an overprint + * simulation. + * + * The supplied pixmaps 's' will match the number of + * 'spots' separations. If we have any 'composite' + * separations therefore, we'll need to make a new pixmap + * with a new (completely 'spots') separations structure, + * render to that, and then map down at the end. + * + * Unfortunately we can't produce this until we know what + * the default_colorspaces etc are, so set a flag for us + * to trigger on later. + */ + if (dest->seps) + dev->resolve_spots = 1; + fz_try(ctx) { dev->rast = fz_new_rasterizer(ctx, aa); @@ -2464,24 +2545,13 @@ new_draw_device(fz_context *ctx, const fz_matrix *transform, fz_pixmap *dest, co fz_device * fz_new_draw_device(fz_context *ctx, const fz_matrix *transform, fz_pixmap *dest) { - return new_draw_device(ctx, transform, dest, NULL); + return new_draw_device(ctx, transform, dest, NULL, NULL); } fz_device * fz_new_draw_device_with_bbox(fz_context *ctx, const fz_matrix *transform, fz_pixmap *dest, const fz_irect *clip) { - fz_draw_device *dev = (fz_draw_device*)fz_new_draw_device(ctx, transform, dest); - - if (clip->x0 > dev->stack[0].scissor.x0) - dev->stack[0].scissor.x0 = clip->x0; - if (clip->x1 < dev->stack[0].scissor.x1) - dev->stack[0].scissor.x1 = clip->x1; - if (clip->y0 > dev->stack[0].scissor.y0) - dev->stack[0].scissor.y0 = clip->y0; - if (clip->y1 < dev->stack[0].scissor.y1) - dev->stack[0].scissor.y1 = clip->y1; - - return (fz_device*)dev; + return new_draw_device(ctx, transform, dest, NULL, clip); } fz_device * diff --git a/source/fitz/draw-paint.c b/source/fitz/draw-paint.c index 8357d5a1..76f9638a 100644 --- a/source/fitz/draw-paint.c +++ b/source/fitz/draw-paint.c @@ -1906,6 +1906,11 @@ fz_paint_pixmap(fz_pixmap * restrict dst, const fz_pixmap * restrict src, int al if (alpha == 0) return; + if (dst->n - dst->alpha != src->n - src->alpha) + { + fprintf(stderr, "fz_paint_pixmap - FIXME\n"); + return; + } assert(dst->n - dst->alpha == src->n - src->alpha); fz_pixmap_bbox_no_ctx(dst, &bbox); diff --git a/source/fitz/pixmap.c b/source/fitz/pixmap.c index bef5b6a5..c5112985 100644 --- a/source/fitz/pixmap.c +++ b/source/fitz/pixmap.c @@ -599,7 +599,7 @@ fz_copy_pixmap_rect(fz_context *ctx, fz_pixmap *dest, fz_pixmap *src, const fz_i fake_src.h = y; fake_src.samples = srcp; - pc(ctx, dest, &fake_src, NULL, default_cs, fz_default_color_params(ctx)); + pc(ctx, dest, &fake_src, NULL, default_cs, fz_default_color_params(ctx), 0); } } @@ -892,7 +892,7 @@ fz_convert_pixmap(fz_context *ctx, fz_pixmap *pix, fz_colorspace *ds, fz_colorsp fz_try(ctx) { fz_pixmap_converter *pc = fz_lookup_pixmap_converter(ctx, ds, pix->colorspace); - pc(ctx, cvt, pix, prf, default_cs, color_params); + pc(ctx, cvt, pix, prf, default_cs, color_params, 1); } fz_catch(ctx) { diff --git a/source/fitz/separation.c b/source/fitz/separation.c index 45b60b92..0baf30b4 100644 --- a/source/fitz/separation.c +++ b/source/fitz/separation.c @@ -167,3 +167,337 @@ int fz_count_active_separations(fz_context *ctx, const fz_separations *sep) c++; return c; } + +fz_separations *fz_clone_separations_for_overprint(fz_context *ctx, fz_separations *sep) +{ + int i, j, n, c; + fz_separations *clone; + + if (!sep) + return NULL; + + n = sep->num_separations; + c = 0; + for (i = 0; i < n; i++) + { + fz_separation_behavior state = sep_state(sep, i); + if (state == FZ_SEPARATION_COMPOSITE) + c++; + } + + /* If no composites, then we are fine to render direct. */ + if (c == 0) + return NULL; + + /* We need to clone us a separation structure, with all + * the composite separations marked as enabled. */ + clone = fz_malloc_struct(ctx, fz_separations); + + fz_try(ctx) + { + clone->refs = 1; + clone->controllable = 0; + for (i = 0; i < n; i++) + { + fz_separation_behavior beh = sep_state(sep, i); + if (beh == FZ_SEPARATION_DISABLED) + continue; + j = clone->num_separations++; + if (beh == FZ_SEPARATION_COMPOSITE) + beh = FZ_SEPARATION_SPOT; + fz_set_separation_behavior(ctx, clone, j, beh); + clone->name[j] = sep->name[i] ? fz_strdup(ctx, sep->name[i]) : NULL; + clone->equiv_rgb[j] = sep->equiv_rgb[i]; + clone->equiv_cmyk[j] = sep->equiv_cmyk[i]; + } + } + fz_catch(ctx) + { + fz_drop_separations(ctx, clone); + fz_rethrow(ctx); + } + + return clone; +} + +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_colorspace *prf, fz_default_colorspaces *default_cs) +{ + fz_irect local_bbox; + fz_pixmap *dst; + fz_colorspace *oi = fz_default_output_intent(ctx, default_cs); + + if (fz_colorspace_n(ctx, dcs) == fz_colorspace_n(ctx, oi)) + dcs = oi; + + if (bbox == NULL) + { + local_bbox.x0 = src->x; + local_bbox.y0 = src->y; + local_bbox.x1 = src->x + src->w; + local_bbox.y1 = src->y + src->h; + bbox = &local_bbox; + } + + dst = fz_new_pixmap_with_bbox(ctx, dcs, bbox, dseps, src->alpha); + if (src->flags & FZ_PIXMAP_FLAG_INTERPOLATE) + dst->flags |= FZ_PIXMAP_FLAG_INTERPOLATE; + else + dst->flags &= ~FZ_PIXMAP_FLAG_INTERPOLATE; + + return fz_copy_pixmap_area_converting_seps(ctx, dst, src, prf, default_cs); +} + +fz_pixmap * +fz_copy_pixmap_area_converting_seps(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, fz_default_colorspaces *default_cs) +{ + int dw = dst->w; + int dh = dst->h; + fz_separations *sseps = src->seps; + fz_separations *dseps = dst->seps; + int sseps_n = sseps ? sseps->num_separations : 0; + int dseps_n = dseps ? dseps->num_separations : 0; + int sstride = src->stride; + int dstride = dst->stride; + int sn = src->n; + int dn = dst->n; + int sa = src->alpha; + int da = dst->alpha; + int ss = src->s; + int ds = dst->s; + int sc = sn - ss - sa; + int dc = dn - ds - da; + const unsigned char *sdata = src->samples + sstride * (dst->y - src->y) + (dst->x - src->x) * sn; + unsigned char *ddata = dst->samples; + signed char map[FZ_MAX_COLORS]; + int x, y, i, j, k; + unsigned char mapped[FZ_MAX_COLORS]; + int unmapped = sseps_n; + + assert(da == sa); + assert(ss == fz_count_active_separations(ctx, sseps)); + assert(ds == fz_count_active_separations(ctx, dseps)); + + dstride -= dn * dw; + sstride -= sn * dw; + + /* Process colorants first */ + if (dst->colorspace == src->colorspace) + { + /* Simple copy */ + unsigned char *dd = ddata; + const unsigned char *sd = sdata; + for (y = dh; y > 0; y--) + { + for (x = dw; x > 0; x--) + { + for (i = 0; i < dn; i++) + dd[i] = sd[i]; + dd += dn; + sd += sn; + } + dd += dstride; + sd += sstride; + } + } + else + { + fz_pixmap_converter *pc = fz_lookup_pixmap_converter(ctx, dst->colorspace, src->colorspace); + + pc(ctx, dst, src, prf, default_cs, NULL, 0); + } + + /* Make a map of what spots go where */ + for (i = 0, k = 0; i < dseps_n; i++) + { + const char *name; + + if (sep_state(dseps, i) >= FZ_SEPARATION_DISABLED) + continue; + name = dseps->name[i]; + map[k] = -1; + mapped[k] = 0; + for (j = 0; j < sseps_n; j++) + { + if (sep_state(sseps, j) >= FZ_SEPARATION_DISABLED) + continue; + if (!strcmp(name, sseps->name[j])) + { + map[k] = j; + unmapped--; + mapped[k] = 1; + break; + } + } + k++; + } + if (sa) + map[k] = sseps_n; + + /* Now we need to make d[i] = map[i] < 0 : 255 ? s[map[i]] */ + + { + unsigned char *dd = ddata + dc; + const unsigned char *sd = sdata + sc; + for (y = dh; y > 0; y--) + { + for (x = dw; x > 0; x--) + { + for (i = 0; i < ds; i++) + dd[i] = map[i] < 0 ? 255 : sd[map[i]]; + dd += dn; + sd += sn; + } + dd += dstride; + sd += sstride; + } + } + + /* If we've handled all the spots, we're done. */ + if (unmapped == 0) + return dst; + + /* Still need to handle mapping 'lost' spots down to process colors */ + for (i = 0; i < sseps_n; i++) + { + uint8_t convert[4]; + uint32_t c; + + if (mapped[i]) + continue; + /* Src spot i is not mapped. We need to convert that down. */ + switch (dc) + { + case 1: /* Grey */ + /* FIXME: Should we hold a grey equivalent in each spot? */ + c = sseps->equiv_rgb[i]; + convert[0] = ((c & 0xff) * 77 + ((c>>8) & 0xff) * 150 + ((c>>16) & 0xff) * 28 + 255)>>8; + break; + case 3: /* RGB */ + c = sseps->equiv_rgb[i]; + convert[0] = c; + convert[1] = c>>8; + convert[2] = c>>16; + break; + case 4: /* CMYK */ + c = sseps->equiv_cmyk[i]; + convert[0] = c; + convert[1] = c>>8; + convert[2] = c>>16; + convert[3] = c>>24; + break; + } + + { + unsigned char *dd = ddata; + const unsigned char *sd = sdata + sc; + for (y = dh; y > 0; y--) + { + for (x = dw; x > 0; x--) + { + unsigned char v = sd[i]; + if (v == 0) + continue; + for (i = 0; i < dc; i++) + dd[i] = fz_clampi(dd[i] + fz_mul255(v, convert[i]), 0, 255); + dd += dn; + sd += sn; + } + dd += dstride; + sd += sstride; + } + } + } + + return dst; +} + +void fz_convert_separation_colors(fz_context *ctx, const fz_color_params *color_params, const fz_colorspace *dst_cs, const fz_separations *dst_seps, float *dst_color, const fz_colorspace *src_cs, const float *src_color) +{ + int i, j, n, dc, ds, dn, pred; + float remainders[FZ_MAX_COLORS]; + int remaining = 0; + + assert(dst_cs && dst_seps && src_cs && dst_color && src_color); + assert(fz_colorspace_is_device_n(ctx, src_cs)); + + dc = fz_colorspace_n(ctx, dst_cs); + ds = dst_seps->num_separations; + dn = dc + ds; + + i = 0; + if (!fz_colorspace_is_subtractive(ctx, dst_cs)) + for (; i < dc; i++) + dst_color[i] = 1; + for (; i < dn; i++) + dst_color[i] = 0; + + n = fz_colorspace_n(ctx, src_cs); + pred = 0; + for (i = 0; i < n; i++) + { + const char *name = fz_colorspace_colorant(ctx, src_cs, i); + + if (i == 0 && !strcmp(name, "All")) + { + /* This is only supposed to happen in separation spaces, not DeviceN */ + if (n != 1) + fz_warn(ctx, "All found in DeviceN space"); + for (i = 0; i < dn; i++) + dst_color[i] = src_color[0]; + break; + } + if (!strcmp(name, "None")) + continue; + + /* The most common case is that the colorant we match is the + * one after the one we matched before, so optimise for that. */ + for (j = pred; j < ds; j++) + { + const char *dname = dst_seps->name[j]; + if (!strcmp(name, dname)) + goto found_sep; + } + for (j = 0; j < pred; j++) + { + const char *dname = dst_seps->name[j]; + if (!strcmp(name, dname)) + goto found_sep; + } + for (j = 0; j < dc; j++) + { + const char *dname = fz_colorspace_colorant(ctx, dst_cs, j); + if (!strcmp(name, dname)) + goto found_process; + } + if (0) { +found_sep: + dst_color[j+dc] = src_color[i]; + pred = j+1; + } + else if (0) + { +found_process: + dst_color[j] += src_color[i]; + } + else + { + if (remaining == 0) + { + memset(remainders, 0, sizeof(float) * n); + remaining = 1; + } + remainders[i] = src_color[i]; + } + } + + if (remaining) + { + /* There were some spots that didn't copy over */ + float converted[FZ_MAX_COLORS]; + fz_convert_color(ctx, color_params, NULL, dst_cs, converted, src_cs, remainders); + + for (i = 0; i < dc; i++) + dst_color[i] += converted[i]; + } +} |