summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2017-07-07 14:27:33 +0100
committerRobin Watts <robin.watts@artifex.com>2017-09-08 17:46:50 +0100
commita7f36241cba4d1807ab4664201aa0975755d6772 (patch)
tree6a15ab1b47af54d9f733915a20c0f609b07bc72f /source
parentd4afa7b72e0b7d774250f13c3c36d04a5e1415d0 (diff)
downloadmupdf-a7f36241cba4d1807ab4664201aa0975755d6772.tar.xz
Update draw device to cope with spots.
If draw device is passed a pixmap with disabled separations, it may have to push an extra group at the top to allow for the actual rendering to properly happen in cmyk+spots, and then get folded down at the end. This pushing cannot happen at create time, due to it being dependent on the defualt_cs settings. Accordingly, we push it (just once) on the first drawing operation. This means we need to be able to convert from "colorspace + set of spots" to "different colorspace + different set of spots". This in turn means we need to be able to drive lcms slightly differently (to tell it whether to copy the spots unchanged or not), so we have to amend the CMS interface code a bit for that. Currently we lack plotters to properly cope with plotting images and shades with spots, so this will give a warning and do nothing. To be filled in in future commits. Ensure fz_get_icc_link accepts NULL to mean default color params. Incorporates fixes from Michel Vrhel: With transparency groups we can have RGB + spot pixmaps. When drawing into those we need a mixture of colorant polarity. Ensure that fz_convert_separation_colors takes account of this. Fix C1 of Altona_Technical_1v1_x3.pdf (allow for output intent in fz_clone_pixmap_area_with_different_seps).
Diffstat (limited to 'source')
-rw-r--r--source/fitz/color-lcms.c12
-rw-r--r--source/fitz/colorspace-imp.h8
-rw-r--r--source/fitz/colorspace.c394
-rw-r--r--source/fitz/draw-affine.c6
-rw-r--r--source/fitz/draw-device.c316
-rw-r--r--source/fitz/draw-paint.c5
-rw-r--r--source/fitz/pixmap.c4
-rw-r--r--source/fitz/separation.c334
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];
+ }
+}