diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/fitz/draw-device.c | 36 | ||||
-rw-r--r-- | source/fitz/output-psd.c | 19 | ||||
-rw-r--r-- | source/fitz/separation.c | 110 | ||||
-rw-r--r-- | source/gprf/gprf-doc.c | 21 | ||||
-rw-r--r-- | source/pdf/pdf-page.c | 188 |
5 files changed, 267 insertions, 107 deletions
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; } |