summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2017-07-13 17:32:32 +0100
committerRobin Watts <robin.watts@artifex.com>2017-09-08 17:48:07 +0100
commit7e4a177d55b3a290300f6671c0670e5a5897da24 (patch)
tree81190342149dc508787247efa78854383997cad8
parenta7f36241cba4d1807ab4664201aa0975755d6772 (diff)
downloadmupdf-7e4a177d55b3a290300f6671c0670e5a5897da24.tar.xz
Update fz_separations equivalent color mechanism.
Incorporates fixes from Michael. Rather than specifically giving it rgb and cmyk values, separations now include the colorspace. Conversions can then be done into ANY colorspace we need. Note, that we maintain the old way of working for the gproof device. Also, fix pdf_page_separations to correctly find all separations. This involves recursively looking through colorspaces, forms and shadings for colorspaces therein, making sure we don't run into any circular references. We do 2 passes, so that we can pick up as many colorants as Separations as possible. On the second pass we pick up any colorants we missed in terms of DeviceN spaces. The purpose of this is to try to ensure that we get as many tint transforms as single input functions as we can. This may not be important in the grand scheme of things, but seems neater.
-rw-r--r--include/mupdf/fitz/pixmap.h4
-rw-r--r--include/mupdf/fitz/separation.h14
-rw-r--r--resources/pdf/names.txt1
-rw-r--r--source/fitz/draw-device.c36
-rw-r--r--source/fitz/output-psd.c19
-rw-r--r--source/fitz/separation.c110
-rw-r--r--source/gprf/gprf-doc.c21
-rw-r--r--source/pdf/pdf-page.c188
8 files changed, 280 insertions, 113 deletions
diff --git a/include/mupdf/fitz/pixmap.h b/include/mupdf/fitz/pixmap.h
index 580ccdf9..5c6fa607 100644
--- a/include/mupdf/fitz/pixmap.h
+++ b/include/mupdf/fitz/pixmap.h
@@ -422,8 +422,8 @@ int fz_valgrind_pixmap(const fz_pixmap *pix);
fz_clone_pixmap_area_with_different_seps: Convert between
different separation results.
*/
-fz_pixmap *fz_clone_pixmap_area_with_different_seps(fz_context *ctx, fz_pixmap *src, const fz_irect *bbox, fz_colorspace *dcs, fz_separations *seps, fz_colorspace *prf, fz_default_colorspaces *default_cs);
+fz_pixmap *fz_clone_pixmap_area_with_different_seps(fz_context *ctx, fz_pixmap *src, const fz_irect *bbox, fz_colorspace *dcs, fz_separations *seps, const fz_color_params *color_params, fz_colorspace *prf, fz_default_colorspaces *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);
+fz_pixmap *fz_copy_pixmap_area_converting_seps(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, const fz_color_params *color_params, fz_colorspace *prf, fz_default_colorspaces *default_cs);
#endif
diff --git a/include/mupdf/fitz/separation.h b/include/mupdf/fitz/separation.h
index 4b4be865..9bbb1845 100644
--- a/include/mupdf/fitz/separation.h
+++ b/include/mupdf/fitz/separation.h
@@ -40,8 +40,11 @@ fz_separations *fz_keep_separations(fz_context *ctx, fz_separations *sep);
/* Drop a reference */
void fz_drop_separations(fz_context *ctx, fz_separations *sep);
-/* Add a separation (RGBA and CYMK equivalents, null terminated name) */
-void fz_add_separation(fz_context *ctx, fz_separations *sep, uint32_t rgba, uint32_t cmyk, const char *name);
+/* Add a separation (null terminated name, colorspace) */
+void fz_add_separation(fz_context *ctx, fz_separations *sep, const char *name, fz_colorspace *cs, int cs_channel);
+
+/* Add a separation with equivalents (null terminated name, colorspace) (old, deprecated) */
+void fz_add_separation_equivalents(fz_context *ctx, fz_separations *sep, uint32_t rgba, uint32_t cmyk, const char *name);
/* Control the rendering of a given separation */
void fz_set_separation_behavior(fz_context *ctx, fz_separations *sep, int separation, fz_separation_behavior behavior);
@@ -52,8 +55,8 @@ fz_separation_behavior fz_separation_current_behavior(fz_context *ctx, const fz_
/* Quick test for all separations composite (the common case) */
int fz_separations_all_composite(fz_context *ctx, const fz_separations *sep);
-/* Read separation details */
-const char *fz_get_separation(fz_context *ctx, const fz_separations *sep, int separation, uint32_t *rgb, uint32_t *cmyk);
+/* Read separation name */
+const char *fz_separation_name(fz_context *ctx, const fz_separations *sep, int separation);
/* Count the number of separations */
int fz_count_separations(fz_context *ctx, const fz_separations *sep);
@@ -72,4 +75,7 @@ fz_separations *fz_clone_separations_for_overprint(fz_context *ctx, fz_separatio
* to a color in terms of another colorspace/separations. */
void fz_convert_separation_colors(fz_context *ctx, const fz_color_params *color_params, const fz_colorspace *dst_cs, const fz_separations *dst_sep, float *dst_color, const fz_colorspace *src_cs, const float *src_color);
+/* Get the equivalent separation color in a given colorspace. */
+void fz_separation_equivalent(fz_context *ctx, const fz_separations *seps, int i, const fz_color_params *color_params, const fz_colorspace *dst_cs, const fz_colorspace *prf, float *convert);
+
#endif
diff --git a/resources/pdf/names.txt b/resources/pdf/names.txt
index 19293009..5ba1c026 100644
--- a/resources/pdf/names.txt
+++ b/resources/pdf/names.txt
@@ -77,6 +77,7 @@ ClosedArrow
Collection
ColorSpace
ColorTransform
+Colorants
Colors
Columns
Configs
diff --git a/source/fitz/draw-device.c b/source/fitz/draw-device.c
index cadd7d57..6a6a7067 100644
--- a/source/fitz/draw-device.c
+++ b/source/fitz/draw-device.c
@@ -363,7 +363,7 @@ resolve_color(fz_context *ctx, const float *color, fz_colorspace *colorspace, fl
}
static fz_draw_state *
-push_group_for_separations(fz_context *ctx, fz_draw_device *dev, fz_colorspace *prf, fz_default_colorspaces *default_cs)
+push_group_for_separations(fz_context *ctx, fz_draw_device *dev, const fz_color_params *color_params, fz_colorspace *prf, fz_default_colorspaces *default_cs)
{
fz_separations *clone = fz_clone_separations_for_overprint(ctx, dev->stack[0].dest->seps);
@@ -379,7 +379,7 @@ push_group_for_separations(fz_context *ctx, fz_draw_device *dev, fz_colorspace *
{
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->stack[1].dest = fz_clone_pixmap_area_with_different_seps(ctx, dev->stack[0].dest, &dev->stack[0].scissor, fz_device_cmyk(ctx), clone, color_params, prf, default_cs);
dev->top++;
}
fz_always(ctx)
@@ -406,7 +406,7 @@ fz_draw_fill_path(fz_context *ctx, fz_device *devp, const fz_path *path, int eve
fz_draw_state *state = &dev->stack[dev->top];
if (dev->top == 0 && dev->resolve_spots)
- state = push_group_for_separations(ctx, dev, prf, dev->default_cs);
+ state = push_group_for_separations(ctx, dev, color_params, prf, dev->default_cs);
if (flatness < 0.001f)
flatness = 0.001f;
@@ -453,7 +453,7 @@ fz_draw_stroke_path(fz_context *ctx, fz_device *devp, const fz_path *path, const
float mlw = fz_rasterizer_graphics_min_line_width(rast);
if (dev->top == 0 && dev->resolve_spots)
- state = push_group_for_separations(ctx, dev, prf, dev->default_cs);
+ state = push_group_for_separations(ctx, dev, color_params, prf, dev->default_cs);
if (mlw > aa_level)
aa_level = mlw;
@@ -515,7 +515,7 @@ fz_draw_clip_path(fz_context *ctx, fz_device *devp, const fz_path *path, int eve
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);
+ state = push_group_for_separations(ctx, dev, fz_default_color_params(ctx)/* FIXME */, fz_proof_cs(ctx, dev), dev->default_cs);
if (flatness < 0.001f)
flatness = 0.001f;
@@ -586,7 +586,7 @@ fz_draw_clip_stroke_path(fz_context *ctx, fz_device *devp, const fz_path *path,
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);
+ state = push_group_for_separations(ctx, dev, fz_default_color_params(ctx) /* FIXME */, fz_proof_cs(ctx, dev), dev->default_cs);
if (mlw > aa_level)
aa_level = mlw;
@@ -736,7 +736,7 @@ fz_draw_fill_text(fz_context *ctx, fz_device *devp, const fz_text *text, const f
fz_rasterizer *rast = dev->rast;
if (dev->top == 0 && dev->resolve_spots)
- state = push_group_for_separations(ctx, dev, prf, dev->default_cs);
+ state = push_group_for_separations(ctx, dev, color_params, prf, dev->default_cs);
if (colorspace_in)
colorspace = fz_default_colorspace(ctx, dev->default_cs, colorspace_in);
@@ -827,7 +827,7 @@ fz_draw_stroke_text(fz_context *ctx, fz_device *devp, const fz_text *text, const
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);
+ state = push_group_for_separations(ctx, dev, color_params, prf, dev->default_cs);
if (colorspace_in)
colorspace = fz_default_colorspace(ctx, dev->default_cs, colorspace_in);
@@ -902,7 +902,7 @@ fz_draw_clip_text(fz_context *ctx, fz_device *devp, const fz_text *text, const f
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_group_for_separations(ctx, dev, fz_default_color_params(ctx)/* FIXME */, fz_proof_cs(ctx, dev), dev->default_cs);
state = push_stack(ctx, dev);
STACK_PUSHED("clip text");
@@ -1034,7 +1034,7 @@ fz_draw_clip_stroke_text(fz_context *ctx, fz_device *devp, const fz_text *text,
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);
+ state = push_group_for_separations(ctx, dev, fz_default_color_params(ctx)/* FIXME */, fz_proof_cs(ctx, dev), dev->default_cs);
STACK_PUSHED("clip stroke text");
/* make the mask the exact size needed */
@@ -1161,7 +1161,7 @@ fz_draw_fill_shade(fz_context *ctx, fz_device *devp, fz_shade *shade, const fz_m
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);
+ state = push_group_for_separations(ctx, dev, color_params, prf, dev->default_cs);
fz_bound_shade(ctx, shade, &ctm, &bounds);
scissor = state->scissor;
@@ -1331,7 +1331,7 @@ fz_draw_fill_image(fz_context *ctx, fz_device *devp, fz_image *image, const fz_m
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);
+ state = push_group_for_separations(ctx, dev, color_params, prf, dev->default_cs);
fz_intersect_irect(fz_pixmap_bbox(ctx, state->dest, &clip), &state->scissor);
@@ -1463,7 +1463,7 @@ fz_draw_fill_image_mask(fz_context *ctx, fz_device *devp, fz_image *image, const
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);
+ state = push_group_for_separations(ctx, dev, color_params, prf, dev->default_cs);
if (colorspace_in)
colorspace = fz_default_colorspace(ctx, dev->default_cs, colorspace_in);
@@ -1565,7 +1565,7 @@ fz_draw_clip_image_mask(fz_context *ctx, fz_device *devp, fz_image *image, const
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);
+ state = push_group_for_separations(ctx, dev, fz_default_color_params(ctx)/* FIXME */, fz_proof_cs(ctx, dev), dev->default_cs);
STACK_PUSHED("clip image mask");
fz_pixmap_bbox(ctx, state->dest, &clip);
@@ -1729,7 +1729,7 @@ fz_draw_begin_mask(fz_context *ctx, fz_device *devp, const fz_rect *rect, int lu
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);
+ state = push_group_for_separations(ctx, dev, color_params, fz_proof_cs(ctx, dev), dev->default_cs);
if (colorspace_in)
colorspace = fz_default_colorspace(ctx, dev->default_cs, colorspace_in);
@@ -1868,7 +1868,7 @@ fz_draw_begin_group(fz_context *ctx, fz_device *devp, const fz_rect *rect, fz_co
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);
+ state = push_group_for_separations(ctx, dev, fz_default_color_params(ctx)/* FIXME */, fz_proof_cs(ctx, dev), dev->default_cs);
if (cs != NULL)
model = fz_default_colorspace(ctx, dev->default_cs, cs);
@@ -2114,7 +2114,7 @@ fz_draw_begin_tile(fz_context *ctx, fz_device *devp, const fz_rect *area, const
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);
+ state = push_group_for_separations(ctx, dev, fz_default_color_params(ctx)/* FIXME */, fz_proof_cs(ctx, dev), dev->default_cs);
/* area, view, xstep, ystep are in pattern space */
/* ctm maps from pattern space to device space */
@@ -2402,7 +2402,7 @@ fz_draw_close_device(fz_context *ctx, fz_device *devp)
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_copy_pixmap_area_converting_seps(ctx, state[0].dest, state[1].dest, fz_default_color_params(ctx)/* FIXME */, prf, dev->default_cs);
fz_drop_pixmap(ctx, state[1].dest);
assert(state[1].mask == NULL);
assert(state[1].shape == NULL);
diff --git a/source/fitz/output-psd.c b/source/fitz/output-psd.c
index 4d0f9574..d39051dd 100644
--- a/source/fitz/output-psd.c
+++ b/source/fitz/output-psd.c
@@ -74,6 +74,9 @@ psd_write_header(fz_context *ctx, fz_band_writer *writer_, const fz_colorspace *
fz_buffer *buffer = fz_icc_data_from_icc_colorspace(ctx, cs);
unsigned char *data;
size_t size = fz_buffer_storage(ctx, buffer, &data);
+ const fz_colorspace *cs_cmyk = cs;
+ if (fz_colorspace_n(ctx, cs) != 4)
+ cs_cmyk = fz_device_cmyk(ctx);
if (!fz_colorspace_is_subtractive(ctx, cs))
writer->num_additive = fz_colorspace_n(ctx, cs);
@@ -110,7 +113,7 @@ psd_write_header(fz_context *ctx, fz_band_writer *writer_, const fz_colorspace *
len = 0;
for (i = 0; i < s; i++)
{
- const char *name = fz_get_separation(ctx, seps, i, NULL, NULL);
+ const char *name = fz_separation_name(ctx, seps, i);
char text[32];
size_t len2;
if (name == NULL)
@@ -140,7 +143,7 @@ psd_write_header(fz_context *ctx, fz_band_writer *writer_, const fz_colorspace *
fz_write_int32_be(ctx, out, (len + 1)&~1);
for (i = 0; i < s; i++) {
size_t len2;
- const char *name = fz_get_separation(ctx, seps, i, NULL, NULL);
+ const char *name = fz_separation_name(ctx, seps, i);
char text[32];
if (name == NULL)
{
@@ -164,14 +167,14 @@ psd_write_header(fz_context *ctx, fz_band_writer *writer_, const fz_colorspace *
fz_write_int16_be(ctx, out, 0); /* PString */
fz_write_int32_be(ctx, out, 14 * s); /* Length */
for (i = 0; i < s; i++) {
- uint32_t cmyk;
- (void)fz_get_separation(ctx, seps, i, NULL, &cmyk);
+ float cmyk[4];
+ fz_separation_equivalent(ctx, seps, i, NULL, cs_cmyk, NULL, cmyk);
fz_write_int16_be(ctx, out, 02); /* CMYK */
/* PhotoShop stores all component values as if they were additive. */
- fz_write_int16_be(ctx, out, 257 * (cmyk & 0xFF));/* Cyan */
- fz_write_int16_be(ctx, out, 257 * ((cmyk>>8) & 0xFF));/* Magenta */
- fz_write_int16_be(ctx, out, 257 * ((cmyk>>16) & 0xFF));/* Yellow */
- fz_write_int16_be(ctx, out, 257 * ((cmyk>>24) & 0xFF));/* Black */
+ fz_write_int16_be(ctx, out, 65535 * (1-cmyk[0]));/* Cyan */
+ fz_write_int16_be(ctx, out, 65535 * (1-cmyk[1]));/* Magenta */
+ fz_write_int16_be(ctx, out, 65535 * (1-cmyk[2]));/* Yellow */
+ fz_write_int16_be(ctx, out, 65535 * (1-cmyk[3]));/* Black */
fz_write_int16_be(ctx, out, 0); /* Opacity 0 to 100 */
fz_write_byte(ctx, out, 2); /* Don't know */
fz_write_byte(ctx, out, 0); /* Padding - Always Zero */
diff --git a/source/fitz/separation.c b/source/fitz/separation.c
index 0baf30b4..f202d1aa 100644
--- a/source/fitz/separation.c
+++ b/source/fitz/separation.c
@@ -12,8 +12,10 @@ struct fz_separations_s
int num_separations;
int controllable;
uint32_t state[(2*FZ_MAX_SEPARATIONS + 31) / 32];
- uint32_t equiv_rgb[FZ_MAX_SEPARATIONS];
- uint32_t equiv_cmyk[FZ_MAX_SEPARATIONS];
+ fz_colorspace *cs[FZ_MAX_SEPARATIONS];
+ uint8_t cs_pos[FZ_MAX_SEPARATIONS];
+ uint32_t rgba[FZ_MAX_SEPARATIONS];
+ uint32_t cmyk[FZ_MAX_SEPARATIONS];
char *name[FZ_MAX_SEPARATIONS];
};
@@ -39,12 +41,33 @@ void fz_drop_separations(fz_context *ctx, fz_separations *sep)
{
int i;
for (i = 0; i < sep->num_separations; i++)
+ {
fz_free(ctx, sep->name[i]);
+ fz_drop_colorspace(ctx, sep->cs[i]);
+ }
fz_free(ctx, sep);
}
}
-void fz_add_separation(fz_context *ctx, fz_separations *sep, uint32_t rgb, uint32_t cmyk, const char *name)
+void fz_add_separation(fz_context *ctx, fz_separations *sep, const char *name, fz_colorspace *cs, int colorant)
+{
+ int n;
+
+ if (!sep)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "can't add to non-existent separations");
+
+ n = sep->num_separations;
+ if (n == FZ_MAX_SEPARATIONS)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "too many separations");
+
+ sep->name[n] = fz_strdup(ctx, name);
+ sep->cs[n] = fz_keep_colorspace(ctx, cs);
+ sep->cs_pos[n] = colorant;
+
+ sep->num_separations++;
+}
+
+void fz_add_separation_equivalents(fz_context *ctx, fz_separations *sep, uint32_t rgba, uint32_t cmyk, const char *name)
{
int n;
@@ -56,8 +79,8 @@ void fz_add_separation(fz_context *ctx, fz_separations *sep, uint32_t rgb, uint3
fz_throw(ctx, FZ_ERROR_GENERIC, "too many separations");
sep->name[n] = fz_strdup(ctx, name);
- sep->equiv_rgb[n] = rgb;
- sep->equiv_cmyk[n] = cmyk;
+ sep->rgba[n] = rgba;
+ sep->cmyk[n] = cmyk;
sep->num_separations++;
}
@@ -128,22 +151,17 @@ int fz_separations_all_composite(fz_context *ctx, const fz_separations *sep)
return 1;
for (i = 0; i < (FZ_MAX_SEPARATIONS + 31) / 32; i++)
- if (sep->state[i] != FZ_SEPARATION_COMPOSITE)
+ if (sep_state(sep, i) != FZ_SEPARATION_COMPOSITE)
return 0;
return 1;
}
-const char *fz_get_separation(fz_context *ctx, const fz_separations *sep, int separation, uint32_t *rgb, uint32_t *cmyk)
+const char *fz_separation_name(fz_context *ctx, const fz_separations *sep, int separation)
{
if (!sep || separation < 0 || separation >= sep->num_separations)
fz_throw(ctx, FZ_ERROR_GENERIC, "can't access non-existent separation");
- if (rgb)
- *rgb = sep->equiv_rgb[separation];
- if (cmyk)
- *cmyk = sep->equiv_cmyk[separation];
-
return sep->name[separation];
}
@@ -207,8 +225,7 @@ fz_separations *fz_clone_separations_for_overprint(fz_context *ctx, fz_separatio
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];
+ clone->cs[j] = fz_keep_colorspace(ctx, sep->cs[i]);
}
}
fz_catch(ctx)
@@ -221,7 +238,7 @@ fz_separations *fz_clone_separations_for_overprint(fz_context *ctx, fz_separatio
}
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_clone_pixmap_area_with_different_seps(fz_context *ctx, fz_pixmap *src, const fz_irect *bbox, fz_colorspace *dcs, fz_separations *dseps, const fz_color_params *color_params, fz_colorspace *prf, fz_default_colorspaces *default_cs)
{
fz_irect local_bbox;
fz_pixmap *dst;
@@ -245,11 +262,11 @@ fz_clone_pixmap_area_with_different_seps(fz_context *ctx, fz_pixmap *src, const
else
dst->flags &= ~FZ_PIXMAP_FLAG_INTERPOLATE;
- return fz_copy_pixmap_area_converting_seps(ctx, dst, src, prf, default_cs);
+ return fz_copy_pixmap_area_converting_seps(ctx, dst, src, color_params, 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)
+fz_copy_pixmap_area_converting_seps(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, const fz_color_params *color_params, fz_colorspace *prf, fz_default_colorspaces *default_cs)
{
int dw = dst->w;
int dh = dst->h;
@@ -360,33 +377,12 @@ fz_copy_pixmap_area_converting_seps(fz_context *ctx, fz_pixmap *dst, fz_pixmap *
/* 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;
+ float convert[FZ_MAX_COLORS];
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;
- }
+ fz_separation_equivalent(ctx, sseps, i, color_params, dst->colorspace, prf, convert);
{
unsigned char *dd = ddata;
@@ -395,11 +391,11 @@ fz_copy_pixmap_area_converting_seps(fz_context *ctx, fz_pixmap *dst, fz_pixmap *
{
for (x = dw; x > 0; x--)
{
- unsigned char v = sd[i];
+ 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[i] = fz_clampi(dd[i] + v * convert[i], 0, 255);
dd += dn;
sd += sn;
}
@@ -501,3 +497,33 @@ found_process:
dst_color[i] += converted[i];
}
}
+
+void fz_separation_equivalent(fz_context *ctx, const fz_separations *seps, int i, const fz_color_params *color_params, const fz_colorspace *dst_cs, const fz_colorspace *prf, float *convert)
+{
+ float colors[FZ_MAX_COLORS];
+
+ if (!seps->cs[i])
+ {
+ switch (fz_colorspace_n(ctx, dst_cs))
+ {
+ case 3:
+ convert[0] = (seps->rgba[i] & 0xff)/ 255.0f;
+ convert[1] = ((seps->rgba[i]>>8) & 0xff)/ 255.0f;
+ convert[2] = ((seps->rgba[i]>>16) & 0xff)/ 255.0f;
+ convert[3] = ((seps->rgba[i]>>24) & 0xff)/ 255.0f;
+ return;
+ case 4:
+ convert[0] = (seps->cmyk[i] & 0xff)/ 255.0f;
+ convert[1] = ((seps->cmyk[i]>>8) & 0xff)/ 255.0f;
+ convert[2] = ((seps->cmyk[i]>>16) & 0xff)/ 255.0f;
+ convert[3] = ((seps->cmyk[i]>>24) & 0xff)/ 255.0f;
+ return;
+ default:
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Cannot return equivalent in this colorspace");
+ }
+ }
+
+ memset(colors, 0, sizeof(float) * fz_colorspace_n(ctx, seps->cs[i]));
+ colors[seps->cs_pos[i]] = 1;
+ fz_convert_color(ctx, color_params, prf, dst_cs, convert, seps->cs[i], colors);
+}
diff --git a/source/gprf/gprf-doc.c b/source/gprf/gprf-doc.c
index 74b50a9b..f66d78bb 100644
--- a/source/gprf/gprf-doc.c
+++ b/source/gprf/gprf-doc.c
@@ -368,13 +368,13 @@ gprf_get_pixmap(fz_context *ctx, fz_image *image_, fz_irect *area, int w, int h,
read_sep[i] = !FZ_SEPARATION_DISABLED(ctx, image->separations, i-3);
if (read_sep[i])
{
- uint32_t rgb, cmyk;
+ float cmyk[4];
- (void)fz_get_separation(ctx, image->separations, i - 3, &rgb, &cmyk);
- equiv[i][0] = (cmyk>> 0) & 0xFF;
- equiv[i][1] = (cmyk>> 8) & 0xFF;
- equiv[i][2] = (cmyk>>16) & 0xFF;
- equiv[i][3] = (cmyk>>24) & 0xFF;
+ (void)fz_separation_equivalent(ctx, image->separations, i - 3, NULL, fz_device_cmyk(ctx), NULL, cmyk);
+ equiv[i][0] = cmyk[0] * 0xFF;
+ equiv[i][1] = cmyk[1] * 0xFF;
+ equiv[i][2] = cmyk[2] * 0xFF;
+ equiv[i][3] = cmyk[3] * 0xFF;
}
}
}
@@ -744,7 +744,7 @@ read_tiles(fz_context *ctx, gprf_page *page)
int32_t rgba = fz_read_int32_le(ctx, file);
int32_t cmyk = fz_read_int32_le(ctx, file);
fz_read_string(ctx, file, blatter, sizeof(blatter));
- fz_add_separation(ctx, page->separations, rgba, cmyk, blatter);
+ fz_add_separation_equivalents(ctx, page->separations, rgba, cmyk, blatter);
}
/* Seek to the image data */
@@ -854,13 +854,6 @@ static int gprf_separation_disabled(fz_context *ctx, fz_page *page_, int sep)
return FZ_SEPARATION_DISABLED(ctx, page->separations, sep);
}
-static const char *gprf_get_separation(fz_context *ctx, fz_page *page_, int sep, uint32_t *rgba, uint32_t*cmyk)
-{
- gprf_page *page = (gprf_page *)page_;
-
- return fz_get_separation(ctx, page->separations, sep, rgba, cmyk);
-}
-
static fz_separations *
gprf_separations(fz_context *ctx, fz_page *page_)
{
diff --git a/source/pdf/pdf-page.c b/source/pdf/pdf-page.c
index 5b319e3a..9c7c8922 100644
--- a/source/pdf/pdf-page.c
+++ b/source/pdf/pdf-page.c
@@ -638,42 +638,115 @@ pdf_page_transform(fz_context *ctx, pdf_page *page, fz_rect *page_mediabox, fz_m
pdf_page_obj_transform(ctx, page->obj, page_mediabox, page_ctm);
}
-fz_separations *
-pdf_page_separations(fz_context *ctx, pdf_page *page)
+static void
+find_seps(fz_context *ctx, fz_separations **seps, pdf_obj *obj)
{
- pdf_obj *res = pdf_page_resources(ctx, page);
- fz_separations *seps = NULL;
- int i, len;
+ int i, n;
+ pdf_obj *nameobj = pdf_array_get(ctx, obj, 0);
- res = pdf_dict_get(ctx, res, PDF_NAME_ColorSpace);
- if (!res)
- return NULL;
+ if (pdf_name_eq(ctx, nameobj, PDF_NAME_Separation))
+ {
+ fz_colorspace *cs;
+ const char *name = pdf_to_name(ctx, pdf_array_get(ctx, obj, 1));
+
+ /* Skip 'special' colorants. */
+ if (!strcmp(name, "Black") ||
+ !strcmp(name, "Cyan") ||
+ !strcmp(name, "Magenta") ||
+ !strcmp(name, "Yellow") ||
+ !strcmp(name, "All") ||
+ !strcmp(name, "None"))
+ return;
+
+ n = fz_count_separations(ctx, *seps);
+ for (i = 0; i < n; i++)
+ {
+ if (!strcmp(name, fz_separation_name(ctx, *seps, i)))
+ return; /* Got that one already */
+ }
- fz_var(seps);
- fz_var(i);
+ cs = pdf_load_colorspace(ctx, obj);
+ if (!*seps)
+ *seps = fz_new_separations(ctx, 0);
+ fz_add_separation(ctx, *seps, name, cs, 0);
+ fz_drop_colorspace(ctx, cs);
+ }
+ else if (pdf_name_eq(ctx, nameobj, PDF_NAME_Indexed))
+ {
+ find_seps(ctx, seps, pdf_array_get(ctx, obj, 1));
+ }
+ else if (pdf_name_eq(ctx, nameobj, PDF_NAME_DeviceN))
+ {
+ /* If the separation colorants exists for this DeviceN color space
+ * add those prior to our search for DeviceN color */
+ pdf_obj *cols = pdf_dict_get(ctx, pdf_array_get(ctx, obj, 4), PDF_NAME_Colorants);
+ int i, n = pdf_dict_len(ctx, cols);
+ for (i = 0; i < n; i++)
+ find_seps(ctx, seps, pdf_dict_get_val(ctx, cols, i));
+ }
+}
- len = pdf_dict_len(ctx, res);
+static void
+find_devn(fz_context *ctx, fz_separations **seps, pdf_obj *obj)
+{
+ int i, j, n, m;
+ pdf_obj *arr;
+ pdf_obj *nameobj = pdf_array_get(ctx, obj, 0);
+
+ if (!pdf_name_eq(ctx, nameobj, PDF_NAME_DeviceN))
+ return;
+
+ arr = pdf_array_get(ctx, obj, 1);
+ m = pdf_array_len(ctx, arr);
+ for (j = 0; j < m; j++)
+ {
+ fz_colorspace *cs;
+ const char *name = pdf_to_name(ctx, pdf_array_get(ctx, arr, j));
+
+ /* Skip 'special' colorants. */
+ if (!strcmp(name, "Black") ||
+ !strcmp(name, "Cyan") ||
+ !strcmp(name, "Magenta") ||
+ !strcmp(name, "Yellow") ||
+ !strcmp(name, "All") ||
+ !strcmp(name, "None"))
+ continue;
+
+ n = fz_count_separations(ctx, *seps);
+ for (i = 0; i < n; i++)
+ {
+ if (!strcmp(name, fz_separation_name(ctx, *seps, i)))
+ break; /* Got that one already */
+ }
+
+ if (i == n)
+ {
+ cs = pdf_load_colorspace(ctx, obj);
+ if (!*seps)
+ *seps = fz_new_separations(ctx, 0);
+ fz_add_separation(ctx, *seps, name, cs, j);
+ fz_drop_colorspace(ctx, cs);
+ }
+ }
+}
+
+typedef void (res_finder_fn)(fz_context *ctx, fz_separations **seps, pdf_obj *obj);
+
+static void
+search_res(fz_context *ctx, fz_separations **seps, pdf_obj *res, res_finder_fn *fn)
+{
+ int i = 0;
+ int len = pdf_dict_len(ctx, res);
+
+ fz_var(i);
- i = 0;
while (i < len)
{
fz_try(ctx)
{
do
{
- pdf_obj *obj;
- i++;
- obj = pdf_dict_get_val(ctx, res, i-1);
-
- if (pdf_name_eq(ctx, pdf_array_get(ctx, obj, 0), PDF_NAME_Separation))
- {
- uint32_t rgba = 0; /* FIXME */
- uint32_t cmyk = 0; /* FIXME */
- const char *name = pdf_to_name(ctx, pdf_array_get(ctx, obj, 1));
- if (!seps)
- seps = fz_new_separations(ctx, 0);
- fz_add_separation(ctx, seps, rgba, cmyk, name);
- }
+ fn(ctx, seps, pdf_dict_get_val(ctx, res, i++));
}
while (i < len);
}
@@ -682,6 +755,71 @@ pdf_page_separations(fz_context *ctx, pdf_page *page)
/* Don't die because a single separation failed to load */
}
}
+}
+
+static void
+scan_page_seps(fz_context *ctx, pdf_obj *res, fz_separations **seps, res_finder_fn *fn)
+{
+ pdf_obj *forms;
+ pdf_obj *sh;
+ pdf_obj *xo = NULL;
+ int i, len;
+
+ fz_var(xo);
+
+ if (pdf_mark_obj(ctx, res))
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cycle in resources");
+
+ fz_try(ctx)
+ {
+ search_res(ctx, seps, pdf_dict_get(ctx, res, PDF_NAME_ColorSpace), fn);
+
+ sh = pdf_dict_get(ctx, res, PDF_NAME_Shading);
+ len = pdf_dict_len(ctx, sh);
+ for (i = 0; i < len; i++)
+ fn(ctx, seps, pdf_dict_get(ctx, pdf_dict_get_val(ctx, sh, i), PDF_NAME_ColorSpace));
+
+ forms = pdf_dict_get(ctx, res, PDF_NAME_XObject);
+ len = pdf_dict_len(ctx, forms);
+
+ /* Recurse on the forms. Throw if we cycle */
+ for (i = 0; i < len; i++)
+ {
+ xo = pdf_dict_get_val(ctx, forms, i++);
+
+ if (pdf_mark_obj(ctx, xo))
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cycle in forms");
+
+ scan_page_seps(ctx, pdf_dict_get(ctx, xo, PDF_NAME_Resources), seps, fn);
+ pdf_unmark_obj(ctx, xo);
+ xo = NULL;
+ }
+ }
+ fz_always(ctx)
+ {
+ pdf_unmark_obj(ctx, xo);
+ pdf_unmark_obj(ctx, res);
+ }
+ fz_catch(ctx)
+ fz_rethrow(ctx);
+}
+
+fz_separations *
+pdf_page_separations(fz_context *ctx, pdf_page *page)
+{
+ pdf_obj *res = pdf_page_resources(ctx, page);
+ fz_separations *seps = NULL;
+
+ /* Run through and look for separations first. This is
+ * because separations are simplest to deal with, and
+ * because DeviceN may be implemented on top of separations.
+ */
+ scan_page_seps(ctx, res, &seps, find_seps);
+
+ /* Now run through again, and look for DeviceNs. These may
+ * have spot colors in that aren't defined in terms of
+ * separations. */
+ scan_page_seps(ctx, res, &seps, find_devn);
return seps;
}