// Copyright (C) 2004-2022 Artifex Software, Inc. // // This file is part of MuPDF. // // MuPDF is free software: you can redistribute it and/or modify it under the // terms of the GNU Affero General Public License as published by the Free // Software Foundation, either version 3 of the License, or (at your option) // any later version. // // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more // details. // // You should have received a copy of the GNU Affero General Public License // along with MuPDF. If not, see // // Alternative licensing terms are available from the licensor. // For commercial licensing, see or contact // Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, // CA 94945, U.S.A., +1(415)492-9861, for further information. #include "mupdf/fitz.h" #include "mupdf/pdf.h" #include enum { UNMARKED_STROKE = 1, UNMARKED_FILL = 2 }; typedef struct gstate_stack { struct gstate_stack *next; pdf_obj *cs_stroke; pdf_obj *cs_fill; int unmarked; } gstate_stack; typedef struct resources_stack { struct resources_stack *next; pdf_obj *old_rdb; pdf_obj *new_rdb; } resources_stack; typedef struct { pdf_obj *cs; float color[FZ_MAX_COLORS]; } cs_color; #define MAX_REWRITTEN_NAME 32 typedef struct { fz_image *before; fz_image *after; char name[MAX_REWRITTEN_NAME]; } rewritten_image; typedef struct { int max; int len; rewritten_image *res; } rewritten_images; typedef struct { pdf_obj *before; fz_shade *after; char name[MAX_REWRITTEN_NAME]; } rewritten_shade; typedef struct { int max; int len; rewritten_shade *res; } rewritten_shades; typedef struct { pdf_processor super; pdf_document *doc; int structparents; pdf_processor *chain; pdf_filter_options *global_options; pdf_color_filter_options *options; resources_stack *rstack; gstate_stack *gstate; cs_color *stroke; cs_color *fill; rewritten_images images; rewritten_shades shades; } pdf_color_processor; static void push_rewritten_image(fz_context *ctx, pdf_color_processor *p, fz_image *before, fz_image *after, char *name) { rewritten_images *list = &p->images; if (list->max == list->len) { int new_max = list->max * 2; if (new_max == 0) new_max = 32; list->res = fz_realloc(ctx, list->res, sizeof(*list->res) * new_max); list->max = new_max; } list->res[list->len].before = fz_keep_image(ctx, before); list->res[list->len].after = fz_keep_image(ctx, after); memcpy(list->res[list->len].name, name, MAX_REWRITTEN_NAME); list->len++; } static fz_image * find_rewritten_image(fz_context *ctx, pdf_color_processor *p, fz_image *before, char *name) { rewritten_images *list = &p->images; int i; for (i = 0; i < list->len; i++) if (list->res[i].before == before) { memcpy(name, list->res[i].name, MAX_REWRITTEN_NAME); return list->res[i].after; } return NULL; } static void drop_rewritten_images(fz_context *ctx, pdf_color_processor *p) { rewritten_images *list = &p->images; int i; for (i = 0; i < list->len; i++) { fz_drop_image(ctx, list->res[i].before); fz_drop_image(ctx, list->res[i].after); } fz_free(ctx, list->res); list->res = NULL; list->len = 0; list->max = 0; } static void push_rewritten_shade(fz_context *ctx, pdf_color_processor *p, pdf_obj *before, fz_shade *after, char *name) { rewritten_shades *list = &p->shades; if (list->max == list->len) { int new_max = list->max * 2; if (new_max == 0) new_max = 32; list->res = fz_realloc(ctx, list->res, sizeof(*list->res) * new_max); list->max = new_max; } list->res[list->len].before = pdf_keep_obj(ctx, before); list->res[list->len].after = fz_keep_shade(ctx, after); memcpy(list->res[list->len].name, name, MAX_REWRITTEN_NAME); list->len++; } static fz_shade * find_rewritten_shade(fz_context *ctx, pdf_color_processor *p, pdf_obj *before, char *name) { rewritten_shades *list = &p->shades; int i; for (i = 0; i < list->len; i++) if (list->res[i].before == before) { memcpy(name, list->res[i].name, MAX_REWRITTEN_NAME); return list->res[i].after; } return NULL; } static void drop_rewritten_shades(fz_context *ctx, pdf_color_processor *p) { rewritten_shades *list = &p->shades; int i; for (i = 0; i < list->len; i++) { pdf_drop_obj(ctx, list->res[i].before); fz_drop_shade(ctx, list->res[i].after); } fz_free(ctx, list->res); list->res = NULL; list->len = 0; list->max = 0; } static void make_resource_instance(fz_context *ctx, pdf_color_processor *p, pdf_obj *key, const char *prefix, char *buf, int len, pdf_obj *target) { int i; /* key gives us our category. Make sure we have such a category. */ pdf_obj *res = pdf_dict_get(ctx, p->rstack->new_rdb, key); if (!res) res = pdf_dict_put_dict(ctx, p->rstack->new_rdb, key, 8); /* Now check through the category for each possible prefixed name * in turn. */ for (i = 1; i < 65536; ++i) { pdf_obj *obj; fz_snprintf(buf, len, "%s%d", prefix, i); obj = pdf_dict_gets(ctx, res, buf); if (!obj) { /* We've run out of names. At least that means we haven't * previously added one ourselves. So add it now. */ pdf_dict_puts(ctx, res, buf, target); return; } if (pdf_objcmp_resolve(ctx, obj, target) == 0) { /* We've found this one before! */ return; } } fz_throw(ctx, FZ_ERROR_GENERIC, "Cannot create unique resource name"); } static void rewrite_cs(fz_context *ctx, pdf_color_processor *p, pdf_obj *cs_obj, int n, float *color, int stroking) { char new_name[MAX_REWRITTEN_NAME]; pdf_obj *obj; fz_colorspace *cs = NULL; pdf_pattern *pat = NULL; fz_shade *shade = NULL; if (stroking) p->gstate->unmarked &= ~UNMARKED_STROKE; else p->gstate->unmarked &= ~UNMARKED_FILL; /* Otherwise, if it's a name, look it up as a colorspace. */ if (pdf_name_eq(ctx, cs_obj, PDF_NAME(DeviceGray)) || pdf_name_eq(ctx, cs_obj, PDF_NAME(DeviceCMYK)) || pdf_name_eq(ctx, cs_obj, PDF_NAME(DeviceRGB)) || pdf_name_eq(ctx, cs_obj, PDF_NAME(Pattern))) { /* These names should not be looked up. */ } else if (pdf_is_name(ctx, cs_obj)) { /* Any other names should be looked up in the resource dict, * because our rewrite function doesn't have access to that. */ cs_obj = pdf_dict_get(ctx, pdf_dict_get(ctx, p->rstack->old_rdb, PDF_NAME(ColorSpace)), cs_obj); } /* Until now, cs_obj has been a borrowed reference. Make it a real one. */ pdf_keep_obj(ctx, cs_obj); /* Whatever happens, from here on in, we must drop cs_obj. */ fz_var(cs); fz_var(pat); fz_var(shade); fz_try(ctx) { /* Our gstate always has to contain colorspaces BEFORE rewriting. * Consider the case where we are given a separation space, and * we rewrite it to be RGB. Then we change the 'amount' of that * separation; we can't do that with the RGB value. */ if (stroking) { pdf_drop_obj(ctx, p->gstate->cs_stroke); p->gstate->cs_stroke = pdf_keep_obj(ctx, cs_obj); } else { pdf_drop_obj(ctx, p->gstate->cs_fill); p->gstate->cs_fill = pdf_keep_obj(ctx, cs_obj); } /* Now, do any rewriting. This might drop the reference to cs_obj and * return with a different one. */ p->options->color_rewrite(ctx, p->options->opaque, &cs_obj, &n, color); /* If we've rewritten it to be a simple name, great! */ if (pdf_name_eq(ctx, cs_obj, PDF_NAME(DeviceGray))) { if (stroking) { if (n == 1) p->chain->op_G(ctx, p->chain, color[0]); else p->chain->op_CS(ctx, p->chain, "DeviceGray", fz_device_gray(ctx)); } else { if (n == 1) p->chain->op_g(ctx, p->chain, color[0]); else p->chain->op_cs(ctx, p->chain, "DeviceGray", fz_device_gray(ctx)); } break; } if (pdf_name_eq(ctx, cs_obj, PDF_NAME(DeviceRGB))) { if (stroking) { if (n == 3) p->chain->op_RG(ctx, p->chain, color[0], color[1], color[2]); else p->chain->op_CS(ctx, p->chain, "DeviceRGB", fz_device_rgb(ctx)); } else { if (n == 3) p->chain->op_rg(ctx, p->chain, color[0], color[1], color[2]); else p->chain->op_cs(ctx, p->chain, "DeviceRGB", fz_device_rgb(ctx)); } break; } if (pdf_name_eq(ctx, cs_obj, PDF_NAME(DeviceCMYK))) { if (stroking) { if (n == 4) p->chain->op_K(ctx, p->chain, color[0], color[1], color[2], color[3]); else p->chain->op_CS(ctx, p->chain, "DeviceCMYK", fz_device_cmyk(ctx)); } else { if (n == 4) p->chain->op_k(ctx, p->chain, color[0], color[1], color[2], color[3]); else p->chain->op_cs(ctx, p->chain, "DeviceCMYK", fz_device_cmyk(ctx)); } break; } /* Accept both /Pattern and [ /Pattern ] */ if (pdf_name_eq(ctx, cs_obj, PDF_NAME(Pattern)) || (pdf_array_len(ctx, cs_obj) == 1 && pdf_name_eq(ctx, pdf_array_get(ctx, cs_obj, 0), PDF_NAME(Pattern)))) { assert(n == 0); if (stroking) p->chain->op_CS(ctx, p->chain, "Pattern", NULL); else p->chain->op_cs(ctx, p->chain, "Pattern", NULL); break; } /* Has it been rewritten to be an array? */ if (pdf_is_array(ctx, cs_obj)) { /* Make a new entry (or find an existing one), and send that. */ make_resource_instance(ctx, p, PDF_NAME(ColorSpace), "CS", new_name, sizeof(new_name), cs_obj); cs = pdf_load_colorspace(ctx, cs_obj); if (stroking) p->chain->op_CS(ctx, p->chain, new_name, cs); else p->chain->op_cs(ctx, p->chain, new_name, cs); break; } /* Has it been rewritten to be a pattern? */ obj = pdf_dict_get(ctx, cs_obj, PDF_NAME(PatternType)); if (obj) { /* Make a new entry (or find an existing one), and send that. */ make_resource_instance(ctx, p, PDF_NAME(Pattern), "Pa", new_name, sizeof(new_name), cs_obj); if (pdf_to_int(ctx, obj) == 1) { pat = pdf_load_pattern(ctx, p->doc, cs_obj); if (stroking) p->chain->op_SC_pattern(ctx, p->chain, new_name, pat, n, color); else p->chain->op_sc_pattern(ctx, p->chain, new_name, pat, n, color); break; } else if (pdf_to_int(ctx, obj) == 2) { shade = pdf_load_shading(ctx, p->doc, cs_obj); if (stroking) p->chain->op_SC_shade(ctx, p->chain, new_name, shade); else p->chain->op_sc_shade(ctx, p->chain, new_name, shade); break; } else fz_throw(ctx, FZ_ERROR_GENERIC, "Bad PatternType"); } fz_throw(ctx, FZ_ERROR_GENERIC, "Illegal rewritten colorspace"); } fz_always(ctx) { fz_drop_shade(ctx, shade); fz_drop_colorspace(ctx, cs); pdf_drop_pattern(ctx, pat); pdf_drop_obj(ctx, cs_obj); } fz_catch(ctx) fz_rethrow(ctx); } static void mark_stroke(fz_context *ctx, pdf_color_processor *p) { float zero[FZ_MAX_COLORS] = { 0 }; rewrite_cs(ctx, p, PDF_NAME(DeviceGray), 1, zero, 1); p->gstate->unmarked &= ~UNMARKED_STROKE; } static void mark_fill(fz_context *ctx, pdf_color_processor *p) { float zero[FZ_MAX_COLORS] = { 0 }; rewrite_cs(ctx, p, PDF_NAME(DeviceGray), 1, zero, 0); p->gstate->unmarked &= ~UNMARKED_FILL; } /* general graphics state */ static void pdf_color_w(fz_context *ctx, pdf_processor *proc, float linewidth) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_w) p->chain->op_w(ctx, p->chain, linewidth); } static void pdf_color_j(fz_context *ctx, pdf_processor *proc, int linejoin) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_j) p->chain->op_j(ctx, p->chain, linejoin); } static void pdf_color_J(fz_context *ctx, pdf_processor *proc, int linecap) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_J) p->chain->op_J(ctx, p->chain, linecap); } static void pdf_color_M(fz_context *ctx, pdf_processor *proc, float miterlimit) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_M) p->chain->op_M(ctx, p->chain, miterlimit); } static void pdf_color_d(fz_context *ctx, pdf_processor *proc, pdf_obj *array, float phase) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_d) p->chain->op_d(ctx, p->chain, array, phase); } static void pdf_color_ri(fz_context *ctx, pdf_processor *proc, const char *intent) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_ri) p->chain->op_ri(ctx, p->chain, intent); } static void pdf_color_gs_OP(fz_context *ctx, pdf_processor *proc, int b) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_gs_OP) p->chain->op_gs_OP(ctx, p->chain, b); } static void pdf_color_gs_op(fz_context *ctx, pdf_processor *proc, int b) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_gs_op) p->chain->op_gs_op(ctx, p->chain, b); } static void pdf_color_gs_OPM(fz_context *ctx, pdf_processor *proc, int i) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_gs_OPM) p->chain->op_gs_OPM(ctx, p->chain, i); } static void pdf_color_gs_UseBlackPtComp(fz_context *ctx, pdf_processor *proc, pdf_obj *name) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_gs_UseBlackPtComp) p->chain->op_gs_UseBlackPtComp(ctx, p->chain, name); } static void pdf_color_i(fz_context *ctx, pdf_processor *proc, float flatness) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_i) p->chain->op_i(ctx, p->chain, flatness); } static void pdf_color_gs_begin(fz_context *ctx, pdf_processor *proc, const char *name, pdf_obj *extgstate) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_gs_begin) p->chain->op_gs_begin(ctx, p->chain, name, extgstate); } static void pdf_color_gs_BM(fz_context *ctx, pdf_processor *proc, const char *blendmode) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_gs_BM) p->chain->op_gs_BM(ctx, p->chain, blendmode); } static void pdf_color_gs_CA(fz_context *ctx, pdf_processor *proc, float alpha) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_gs_CA) p->chain->op_gs_CA(ctx, p->chain, alpha); } static void pdf_color_gs_ca(fz_context *ctx, pdf_processor *proc, float alpha) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_gs_ca) p->chain->op_gs_ca(ctx, p->chain, alpha); } static void pdf_color_gs_SMask(fz_context *ctx, pdf_processor *proc, pdf_obj *smask, float *bc, int luminosity) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_gs_SMask) p->chain->op_gs_SMask(ctx, p->chain, smask, bc, luminosity); } static void pdf_color_gs_end(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_gs_end) p->chain->op_gs_end(ctx, p->chain); } /* special graphics state */ static void pdf_color_q(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; gstate_stack *gs = fz_malloc_struct(ctx, gstate_stack); gs->next = p->gstate; gs->cs_fill = pdf_keep_obj(ctx, p->gstate->cs_fill); gs->cs_stroke = pdf_keep_obj(ctx, p->gstate->cs_stroke); gs->unmarked = p->gstate->unmarked; p->gstate = gs; if (p->chain->op_q) p->chain->op_q(ctx, p->chain); } static void pdf_color_cm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_cm) p->chain->op_cm(ctx, p->chain, a, b, c, d, e, f); } /* path construction */ static void pdf_color_m(fz_context *ctx, pdf_processor *proc, float x, float y) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_m) p->chain->op_m(ctx, p->chain, x, y); } static void pdf_color_l(fz_context *ctx, pdf_processor *proc, float x, float y) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_l) p->chain->op_l(ctx, p->chain, x, y); } static void pdf_color_c(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x2, float y2, float x3, float y3) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_c) p->chain->op_c(ctx, p->chain, x1, y1, x2, y2, x3, y3); } static void pdf_color_v(fz_context *ctx, pdf_processor *proc, float x2, float y2, float x3, float y3) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_v) p->chain->op_v(ctx, p->chain, x2, y2, x3, y3); } static void pdf_color_y(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x3, float y3) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_y) p->chain->op_y(ctx, p->chain, x1, y1, x3, y3); } static void pdf_color_h(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_h) p->chain->op_h(ctx, p->chain); } static void pdf_color_re(fz_context *ctx, pdf_processor *proc, float x, float y, float w, float h) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_re) p->chain->op_re(ctx, p->chain, x, y, w, h); } /* path painting */ static void pdf_color_S(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->gstate->unmarked & UNMARKED_STROKE) mark_stroke(ctx, p); if (p->chain->op_S) p->chain->op_S(ctx, p->chain); } static void pdf_color_s(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->gstate->unmarked & UNMARKED_FILL) mark_fill(ctx, p); if (p->chain->op_s) p->chain->op_s(ctx, p->chain); } static void pdf_color_F(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->gstate->unmarked & UNMARKED_FILL) mark_fill(ctx, p); if (p->chain->op_F) p->chain->op_F(ctx, p->chain); } static void pdf_color_f(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->gstate->unmarked & UNMARKED_FILL) mark_fill(ctx, p); if (p->chain->op_f) p->chain->op_f(ctx, p->chain); } static void pdf_color_fstar(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->gstate->unmarked & UNMARKED_FILL) mark_fill(ctx, p); if (p->chain->op_fstar) p->chain->op_fstar(ctx, p->chain); } static void pdf_color_B(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->gstate->unmarked & UNMARKED_STROKE) mark_stroke(ctx, p); if (p->gstate->unmarked & UNMARKED_FILL) mark_fill(ctx, p); if (p->chain->op_B) p->chain->op_B(ctx, p->chain); } static void pdf_color_Bstar(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->gstate->unmarked & UNMARKED_STROKE) mark_stroke(ctx, p); if (p->gstate->unmarked & UNMARKED_FILL) mark_fill(ctx, p); if (p->chain->op_Bstar) p->chain->op_Bstar(ctx, p->chain); } static void pdf_color_b(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->gstate->unmarked & UNMARKED_STROKE) mark_stroke(ctx, p); if (p->gstate->unmarked & UNMARKED_FILL) mark_fill(ctx, p); if (p->chain->op_b) p->chain->op_b(ctx, p->chain); } static void pdf_color_bstar(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->gstate->unmarked & UNMARKED_STROKE) mark_stroke(ctx, p); if (p->gstate->unmarked & UNMARKED_FILL) mark_fill(ctx, p); if (p->chain->op_bstar) p->chain->op_bstar(ctx, p->chain); } static void pdf_color_n(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_n) p->chain->op_n(ctx, p->chain); } /* clipping paths */ static void pdf_color_W(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_W) p->chain->op_W(ctx, p->chain); } static void pdf_color_Wstar(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_Wstar) p->chain->op_Wstar(ctx, p->chain); } /* text objects */ static void pdf_color_BT(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_BT) p->chain->op_BT(ctx, p->chain); } static void pdf_color_ET(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_ET) p->chain->op_ET(ctx, p->chain); } static void pdf_color_Q(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; gstate_stack *gs = p->gstate; p->gstate = gs->next; pdf_drop_obj(ctx, gs->cs_fill); pdf_drop_obj(ctx, gs->cs_stroke); fz_try(ctx) if (p->chain->op_Q) p->chain->op_Q(ctx, p->chain); fz_always(ctx) fz_free(ctx, gs); fz_catch(ctx) fz_rethrow(ctx); } /* text state */ static void pdf_color_Tc(fz_context *ctx, pdf_processor *proc, float charspace) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_Tc) p->chain->op_Tc(ctx, p->chain, charspace); } static void pdf_color_Tw(fz_context *ctx, pdf_processor *proc, float wordspace) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_Tw) p->chain->op_Tw(ctx, p->chain, wordspace); } static void pdf_color_Tz(fz_context *ctx, pdf_processor *proc, float scale) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_Tz) p->chain->op_Tz(ctx, p->chain, scale); } static void pdf_color_TL(fz_context *ctx, pdf_processor *proc, float leading) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_TL) p->chain->op_TL(ctx, p->chain, leading); } static void pdf_color_Tf(fz_context *ctx, pdf_processor *proc, const char *name, pdf_font_desc *font, float size) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_Tf) p->chain->op_Tf(ctx, p->chain, name, font, size); } static void pdf_color_Tr(fz_context *ctx, pdf_processor *proc, int render) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_Tr) p->chain->op_Tr(ctx, p->chain, render); } static void pdf_color_Ts(fz_context *ctx, pdf_processor *proc, float rise) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_Ts) p->chain->op_Ts(ctx, p->chain, rise); } /* text positioning */ static void pdf_color_Td(fz_context *ctx, pdf_processor *proc, float tx, float ty) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_Td) p->chain->op_Td(ctx, p->chain, tx, ty); } static void pdf_color_TD(fz_context *ctx, pdf_processor *proc, float tx, float ty) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_TD) p->chain->op_TD(ctx, p->chain, tx, ty); } static void pdf_color_Tm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_Tm) p->chain->op_Tm(ctx, p->chain, a, b, c, d, e, f); } static void pdf_color_Tstar(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_Tstar) p->chain->op_Tstar(ctx, p->chain); } /* text showing */ static void pdf_color_TJ(fz_context *ctx, pdf_processor *proc, pdf_obj *array) { pdf_color_processor *p = (pdf_color_processor*)proc; /* FIXME: We could optimise this if we knew the Tr, maybe. */ if (p->gstate->unmarked & UNMARKED_STROKE) mark_stroke(ctx, p); if (p->gstate->unmarked & UNMARKED_FILL) mark_fill(ctx, p); if (p->chain->op_TJ) p->chain->op_TJ(ctx, p->chain, array); } static void pdf_color_Tj(fz_context *ctx, pdf_processor *proc, char *str, size_t len) { pdf_color_processor *p = (pdf_color_processor*)proc; /* FIXME: We could optimise this if we knew the Tr, maybe. */ if (p->gstate->unmarked & UNMARKED_STROKE) mark_stroke(ctx, p); if (p->gstate->unmarked & UNMARKED_FILL) mark_fill(ctx, p); if (p->chain->op_Tj) p->chain->op_Tj(ctx, p->chain, str, len); } static void pdf_color_squote(fz_context *ctx, pdf_processor *proc, char *str, size_t len) { pdf_color_processor *p = (pdf_color_processor*)proc; /* FIXME: We could optimise this if we knew the Tr, maybe. */ if (p->gstate->unmarked & UNMARKED_STROKE) mark_stroke(ctx, p); if (p->gstate->unmarked & UNMARKED_FILL) mark_fill(ctx, p); if (p->chain->op_squote) p->chain->op_squote(ctx, p->chain, str, len); } static void pdf_color_dquote(fz_context *ctx, pdf_processor *proc, float aw, float ac, char *str, size_t len) { pdf_color_processor *p = (pdf_color_processor*)proc; /* FIXME: We could optimise this if we knew the Tr, maybe. */ if (p->gstate->unmarked & UNMARKED_STROKE) mark_stroke(ctx, p); if (p->gstate->unmarked & UNMARKED_FILL) mark_fill(ctx, p); if (p->chain->op_dquote) p->chain->op_dquote(ctx, p->chain, aw, ac, str, len); } /* type 3 fonts */ static void pdf_color_d0(fz_context *ctx, pdf_processor *proc, float wx, float wy) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_d0) p->chain->op_d0(ctx, p->chain, wx, wy); } static void pdf_color_d1(fz_context *ctx, pdf_processor *proc, float wx, float wy, float llx, float lly, float urx, float ury) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_d1) p->chain->op_d1(ctx, p->chain, wx, wy, llx, lly, urx, ury); } /* color */ static void pdf_color_CS(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *cs) { pdf_color_processor *p = (pdf_color_processor *)proc; pdf_obj *cs_obj = pdf_new_name(ctx, name); float color[FZ_MAX_COLORS] = { 1 }; fz_try(ctx) rewrite_cs(ctx, p, cs_obj, 0, color, 1); fz_always(ctx) pdf_drop_obj(ctx, cs_obj); fz_catch(ctx) fz_rethrow(ctx); } static void pdf_color_cs(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *cs) { pdf_color_processor *p = (pdf_color_processor*)proc; pdf_obj *cs_obj = pdf_new_name(ctx, name); float color[FZ_MAX_COLORS] = { 1 }; fz_try(ctx) rewrite_cs(ctx, p, cs_obj, 0, color, 0); fz_always(ctx) pdf_drop_obj(ctx, cs_obj); fz_catch(ctx) fz_rethrow(ctx); } static void pdf_color_SC_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color) { pdf_color_processor *p = (pdf_color_processor*)proc; float local_color[FZ_MAX_COLORS] = { 0 }; pdf_obj *cs_obj = pdf_dict_gets(ctx, pdf_dict_get(ctx, p->rstack->old_rdb, PDF_NAME(Pattern)), name); memcpy(local_color, color, sizeof(float) * n); rewrite_cs(ctx, p, cs_obj, n, local_color, 1); } static void pdf_color_sc_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color) { pdf_color_processor *p = (pdf_color_processor*)proc; float local_color[FZ_MAX_COLORS] = { 0 }; pdf_obj *cs_obj = pdf_dict_gets(ctx, pdf_dict_get(ctx, p->rstack->old_rdb, PDF_NAME(Pattern)), name); memcpy(local_color, color, sizeof(float) * n); rewrite_cs(ctx, p, cs_obj, n, local_color, 0); } static void pdf_color_SC_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade) { pdf_color_processor *p = (pdf_color_processor*)proc; pdf_obj *orig; pdf_obj *dict = NULL; char new_name[MAX_REWRITTEN_NAME]; pdf_obj *rewritten; fz_shade *new_shade = NULL; orig = pdf_dict_gets(ctx, pdf_dict_get(ctx, p->rstack->old_rdb, PDF_NAME(Pattern)), name); orig = pdf_dict_get(ctx, orig, PDF_NAME(Shading)); new_shade = find_rewritten_shade(ctx, p, orig, new_name); if (new_shade) { if (p->chain->op_SC_shade) p->chain->op_SC_shade(ctx, p->chain, new_name, new_shade); return; } rewritten = pdf_recolor_shade(ctx, orig, p->options->shade_rewrite, p->options->opaque); fz_var(new_shade); fz_var(dict); fz_try(ctx) { dict = pdf_new_dict(ctx, p->doc, 1); pdf_dict_put_int(ctx, dict, PDF_NAME(PatternType), 2); pdf_dict_put(ctx, dict, PDF_NAME(Shading), rewritten); dict = pdf_add_object(ctx, p->doc, dict); make_resource_instance(ctx, p, PDF_NAME(Pattern), "Pa", new_name, sizeof(new_name), dict); new_shade = pdf_load_shading(ctx, p->doc, rewritten); /* Remember that we've done this one before. */ push_rewritten_shade(ctx, p, orig, new_shade, new_name); if (p->chain->op_sh) p->chain->op_SC_shade(ctx, p->chain, new_name, new_shade); } fz_always(ctx) { fz_drop_shade(ctx, new_shade); pdf_drop_obj(ctx, rewritten); pdf_drop_obj(ctx, dict); } fz_catch(ctx) fz_rethrow(ctx); } static void pdf_color_sc_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade) { pdf_color_processor *p = (pdf_color_processor*)proc; pdf_obj *orig; pdf_obj *dict = NULL; char new_name[MAX_REWRITTEN_NAME]; pdf_obj *rewritten; fz_shade *new_shade = NULL; orig = pdf_dict_gets(ctx, pdf_dict_get(ctx, p->rstack->old_rdb, PDF_NAME(Pattern)), name); orig = pdf_dict_get(ctx, orig, PDF_NAME(Shading)); new_shade = find_rewritten_shade(ctx, p, orig, new_name); if (new_shade) { if (p->chain->op_sc_shade) p->chain->op_sc_shade(ctx, p->chain, new_name, new_shade); return; } rewritten = pdf_recolor_shade(ctx, orig, p->options->shade_rewrite, p->options->opaque); fz_var(new_shade); fz_var(dict); fz_try(ctx) { dict = pdf_new_dict(ctx, p->doc, 1); pdf_dict_put_int(ctx, dict, PDF_NAME(PatternType), 2); pdf_dict_put(ctx, dict, PDF_NAME(Shading), rewritten); dict = pdf_add_object(ctx, p->doc, dict); make_resource_instance(ctx, p, PDF_NAME(Pattern), "Pa", new_name, sizeof(new_name), dict); new_shade = pdf_load_shading(ctx, p->doc, rewritten); /* Remember that we've done this one before. */ push_rewritten_shade(ctx, p, orig, new_shade, new_name); if (p->chain->op_sh) p->chain->op_sc_shade(ctx, p->chain, new_name, new_shade); } fz_always(ctx) { fz_drop_shade(ctx, new_shade); pdf_drop_obj(ctx, rewritten); pdf_drop_obj(ctx, dict); } fz_catch(ctx) fz_rethrow(ctx); } static void pdf_color_SC_color(fz_context *ctx, pdf_processor *proc, int n, float *color) { pdf_color_processor *p = (pdf_color_processor*)proc; float local_color[FZ_MAX_COLORS] = { 0 }; pdf_obj *cs_obj = p->gstate->cs_stroke; memcpy(local_color, color, sizeof(float) * n); rewrite_cs(ctx, p, cs_obj, n, local_color, 1); } static void pdf_color_sc_color(fz_context *ctx, pdf_processor *proc, int n, float *color) { pdf_color_processor *p = (pdf_color_processor*)proc; float local_color[FZ_MAX_COLORS] = { 0 }; pdf_obj *cs_obj = p->gstate->cs_fill; memcpy(local_color, color, sizeof(float) * n); rewrite_cs(ctx, p, cs_obj, n, local_color, 0); } static void pdf_color_G(fz_context *ctx, pdf_processor *proc, float g) { pdf_color_processor *p = (pdf_color_processor*)proc; float local_color[FZ_MAX_COLORS] = { g }; rewrite_cs(ctx, p, PDF_NAME(DeviceGray), 1, local_color, 1); } static void pdf_color_g(fz_context *ctx, pdf_processor *proc, float g) { pdf_color_processor *p = (pdf_color_processor*)proc; float local_color[FZ_MAX_COLORS] = { g }; rewrite_cs(ctx, p, PDF_NAME(DeviceGray), 1, local_color, 0); } static void pdf_color_RG(fz_context *ctx, pdf_processor *proc, float r, float g, float b) { pdf_color_processor *p = (pdf_color_processor*)proc; float local_color[FZ_MAX_COLORS] = { r, g, b }; rewrite_cs(ctx, p, PDF_NAME(DeviceRGB), 3, local_color, 1); } static void pdf_color_rg(fz_context *ctx, pdf_processor *proc, float r, float g, float b) { pdf_color_processor *p = (pdf_color_processor*)proc; float local_color[FZ_MAX_COLORS] = { r, g, b }; rewrite_cs(ctx, p, PDF_NAME(DeviceRGB), 3, local_color, 0); } static void pdf_color_K(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k) { pdf_color_processor *p = (pdf_color_processor*)proc; float local_color[FZ_MAX_COLORS] = { c, m, y, k }; rewrite_cs(ctx, p, PDF_NAME(DeviceCMYK), 4, local_color, 1); } static void pdf_color_k(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k) { pdf_color_processor *p = (pdf_color_processor*)proc; float local_color[FZ_MAX_COLORS] = { c, m, y, k }; rewrite_cs(ctx, p, PDF_NAME(DeviceCMYK), 4, local_color, 0); } /* shadings, images, xobjects */ static void pdf_color_BI(fz_context *ctx, pdf_processor *proc, fz_image *image, const char *colorspace) { pdf_color_processor *p = (pdf_color_processor*)proc; if (image->imagemask) { /* Imagemasks require the color to have been set. */ if (p->gstate->unmarked & UNMARKED_FILL) mark_fill(ctx, p); } fz_keep_image(ctx, image); p->options->image_rewrite(ctx, p->options->opaque, &image); if (p->chain->op_BI) p->chain->op_BI(ctx, p->chain, image, colorspace); fz_drop_image(ctx, image); } static void pdf_color_sh(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade) { pdf_color_processor *p = (pdf_color_processor*)proc; pdf_obj *orig; char new_name[MAX_REWRITTEN_NAME]; pdf_obj *rewritten; fz_shade *new_shade = NULL; orig = pdf_dict_gets(ctx, pdf_dict_get(ctx, p->rstack->old_rdb, PDF_NAME(Shading)), name); new_shade = find_rewritten_shade(ctx, p, orig, new_name); if (new_shade) { if (p->chain->op_sh) p->chain->op_sh(ctx, p->chain, new_name, new_shade); return; } rewritten = pdf_recolor_shade(ctx, orig, p->options->shade_rewrite, p->options->opaque); fz_var(new_shade); fz_try(ctx) { make_resource_instance(ctx, p, PDF_NAME(Shading), "Sh", new_name, sizeof(new_name), rewritten); new_shade = pdf_load_shading(ctx, p->doc, rewritten); /* Remember that we've done this one before. */ push_rewritten_shade(ctx, p, orig, new_shade, new_name); if (p->chain->op_sh) p->chain->op_sh(ctx, p->chain, new_name, new_shade); } fz_always(ctx) { fz_drop_shade(ctx, new_shade); pdf_drop_obj(ctx, rewritten); } fz_catch(ctx) fz_rethrow(ctx); } static void pdf_color_Do_image(fz_context *ctx, pdf_processor *proc, const char *name, fz_image *image) { pdf_color_processor *p = (pdf_color_processor*)proc; fz_image *orig = image; char new_name[MAX_REWRITTEN_NAME]; pdf_obj *im_obj; /* Have we done this one before? */ image = find_rewritten_image(ctx, p, image, new_name); if (image) { if (p->chain->op_Do_image) p->chain->op_Do_image(ctx, p->chain, new_name, image); return; } image = orig; fz_keep_image(ctx, image); fz_try(ctx) { if (image->imagemask) { /* Imagemasks require the color to have been set. */ if (p->gstate->unmarked & UNMARKED_FILL) mark_fill(ctx, p); } else { p->options->image_rewrite(ctx, p->options->opaque, &image); } /* If it's been rewritten add the new one, otherwise copy the old one across. */ if (image != orig) im_obj = pdf_add_image(ctx, p->doc, image); else im_obj = pdf_dict_gets(ctx, pdf_dict_get(ctx, p->rstack->old_rdb, PDF_NAME(XObject)), name); make_resource_instance(ctx, p, PDF_NAME(XObject), "Im", new_name, sizeof(new_name), im_obj); /* Remember that we've done this one before. */ push_rewritten_image(ctx, p, orig, image, new_name); if (p->chain->op_Do_image) p->chain->op_Do_image(ctx, p->chain, new_name, image); } fz_always(ctx) { pdf_drop_obj(ctx, im_obj); fz_drop_image(ctx, image); } fz_catch(ctx) fz_rethrow(ctx); } static void pdf_color_Do_form(fz_context *ctx, pdf_processor *proc, const char *name, pdf_obj *xobj) { pdf_color_processor *p = (pdf_color_processor*)proc; char new_name[MAX_REWRITTEN_NAME]; pdf_obj *xres; pdf_obj *new_xres = NULL; fz_var(new_xres); /* FIXME: Ideally we'd look at p->global_options->instance_forms here * to avoid flattening all the XObjects. This is non-trivial, and * currently incomplete, hence disabled. We have to find some way to * tell the underlying filters (in particular the output filter) that * we are in a new XObject (so the output filter can start a new buffer). * Maybe it could look at p->global_options->instance_forms too on a * push/pop of the resources? For now, let's just leave it disabled. */ if (0 && p->global_options->instance_forms) { make_resource_instance(ctx, p, PDF_NAME(XObject), "Xo", new_name, sizeof(new_name), xobj); xres = pdf_xobject_resources(ctx, xobj); fz_try(ctx) pdf_process_contents(ctx, (pdf_processor *)p, p->doc, xres, xobj, NULL, &new_xres); fz_catch(ctx) { pdf_drop_obj(ctx, new_xres); fz_rethrow(ctx); } pdf_dict_put_drop(ctx, xobj, PDF_NAME(Resources), new_xres); if (p->chain->op_Do_form) p->chain->op_Do_form(ctx, p->chain, new_name, xobj); } else { /* In this case, we just copy the XObject across (renaming it). Our caller will arrange to * filter it. */ make_resource_instance(ctx, p, PDF_NAME(XObject), "Xo", new_name, sizeof(new_name), xobj); if (p->chain->op_Do_form) p->chain->op_Do_form(ctx, p->chain, new_name, xobj); } } /* marked content */ static void pdf_color_MP(fz_context *ctx, pdf_processor *proc, const char *tag) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_MP) p->chain->op_MP(ctx, p->chain, tag); } static void pdf_color_DP(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *raw, pdf_obj *cooked) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_DP) p->chain->op_DP(ctx, p->chain, tag, raw, cooked); } static void pdf_color_BMC(fz_context *ctx, pdf_processor *proc, const char *tag) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_BMC) p->chain->op_BMC(ctx, p->chain, tag); } static void pdf_color_BDC(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *raw, pdf_obj *cooked) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_BDC) p->chain->op_BDC(ctx, p->chain, tag, raw, cooked); } static void pdf_color_EMC(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_EMC) p->chain->op_EMC(ctx, p->chain); } /* compatibility */ static void pdf_color_BX(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_BX) p->chain->op_BX(ctx, p->chain); } static void pdf_color_EX(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_EX) p->chain->op_EX(ctx, p->chain); } static void pdf_color_END(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; if (p->chain->op_END) p->chain->op_END(ctx, p->chain); } static void pdf_close_color_processor(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; pdf_close_processor(ctx, p->chain); } static void pdf_drop_color_processor(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; gstate_stack *gs = p->gstate; while (gs) { gstate_stack *gs_next = gs->next; pdf_drop_obj(ctx, gs->cs_fill); pdf_drop_obj(ctx, gs->cs_stroke); fz_free(ctx, gs); gs = gs_next; } drop_rewritten_images(ctx, p); drop_rewritten_shades(ctx, p); pdf_drop_document(ctx, p->doc); } static void pdf_color_push_resources(fz_context *ctx, pdf_processor *proc, pdf_obj *res) { pdf_color_processor *p = (pdf_color_processor*)proc; resources_stack *stk = fz_malloc_struct(ctx, resources_stack); pdf_obj *obj; p->gstate->unmarked = UNMARKED_STROKE | UNMARKED_FILL; stk->next = p->rstack; p->rstack = stk; fz_try(ctx) { stk->old_rdb = pdf_keep_obj(ctx, res); /* At the moment we know that we'll always be flattening XObjects. * So only the top level 'push' makes a new resource dict. Any * subsequent one will share the previous levels one. */ if (stk->next) stk->new_rdb = pdf_keep_obj(ctx, stk->next->new_rdb); else stk->new_rdb = pdf_new_dict(ctx, p->doc, 1); obj = pdf_dict_get(ctx, res, PDF_NAME(Properties)); if (obj) pdf_dict_put(ctx, stk->new_rdb, PDF_NAME(Properties), obj); obj = pdf_dict_get(ctx, res, PDF_NAME(ExtGState)); if (obj) pdf_dict_put(ctx, stk->new_rdb, PDF_NAME(ExtGState), obj); obj = pdf_dict_get(ctx, res, PDF_NAME(Font)); if (obj) pdf_dict_put(ctx, stk->new_rdb, PDF_NAME(Font), obj); pdf_processor_push_resources(ctx, p->chain, stk->new_rdb); } fz_catch(ctx) { pdf_drop_obj(ctx, stk->old_rdb); pdf_drop_obj(ctx, stk->new_rdb); fz_free(ctx, stk); p->rstack = stk->next; fz_rethrow(ctx); } } static pdf_obj * pdf_color_pop_resources(fz_context *ctx, pdf_processor *proc) { pdf_color_processor *p = (pdf_color_processor*)proc; resources_stack *stk = p->rstack; p->rstack = stk->next; pdf_drop_obj(ctx, stk->old_rdb); pdf_drop_obj(ctx, stk->new_rdb); fz_free(ctx, stk); return pdf_processor_pop_resources(ctx, p->chain); } pdf_processor * pdf_new_color_filter( fz_context *ctx, pdf_document *doc, pdf_processor *chain, int struct_parents, fz_matrix transform, pdf_filter_options *global_options, void *options_) { pdf_color_processor *proc = pdf_new_processor(ctx, sizeof * proc); pdf_color_filter_options *options = (pdf_color_filter_options *)options_; proc->super.close_processor = pdf_close_color_processor; proc->super.drop_processor = pdf_drop_color_processor; proc->super.push_resources = pdf_color_push_resources; proc->super.pop_resources = pdf_color_pop_resources; /* general graphics state */ proc->super.op_w = pdf_color_w; proc->super.op_j = pdf_color_j; proc->super.op_J = pdf_color_J; proc->super.op_M = pdf_color_M; proc->super.op_d = pdf_color_d; proc->super.op_ri = pdf_color_ri; proc->super.op_i = pdf_color_i; proc->super.op_gs_begin = pdf_color_gs_begin; proc->super.op_gs_end = pdf_color_gs_end; /* transparency graphics state */ proc->super.op_gs_BM = pdf_color_gs_BM; proc->super.op_gs_CA = pdf_color_gs_CA; proc->super.op_gs_ca = pdf_color_gs_ca; proc->super.op_gs_SMask = pdf_color_gs_SMask; /* special graphics state */ proc->super.op_q = pdf_color_q; proc->super.op_Q = pdf_color_Q; proc->super.op_cm = pdf_color_cm; /* path construction */ proc->super.op_m = pdf_color_m; proc->super.op_l = pdf_color_l; proc->super.op_c = pdf_color_c; proc->super.op_v = pdf_color_v; proc->super.op_y = pdf_color_y; proc->super.op_h = pdf_color_h; proc->super.op_re = pdf_color_re; /* path painting */ proc->super.op_S = pdf_color_S; proc->super.op_s = pdf_color_s; proc->super.op_F = pdf_color_F; proc->super.op_f = pdf_color_f; proc->super.op_fstar = pdf_color_fstar; proc->super.op_B = pdf_color_B; proc->super.op_Bstar = pdf_color_Bstar; proc->super.op_b = pdf_color_b; proc->super.op_bstar = pdf_color_bstar; proc->super.op_n = pdf_color_n; /* clipping paths */ proc->super.op_W = pdf_color_W; proc->super.op_Wstar = pdf_color_Wstar; /* text objects */ proc->super.op_BT = pdf_color_BT; proc->super.op_ET = pdf_color_ET; /* text state */ proc->super.op_Tc = pdf_color_Tc; proc->super.op_Tw = pdf_color_Tw; proc->super.op_Tz = pdf_color_Tz; proc->super.op_TL = pdf_color_TL; proc->super.op_Tf = pdf_color_Tf; proc->super.op_Tr = pdf_color_Tr; proc->super.op_Ts = pdf_color_Ts; /* text positioning */ proc->super.op_Td = pdf_color_Td; proc->super.op_TD = pdf_color_TD; proc->super.op_Tm = pdf_color_Tm; proc->super.op_Tstar = pdf_color_Tstar; /* text showing */ proc->super.op_TJ = pdf_color_TJ; proc->super.op_Tj = pdf_color_Tj; proc->super.op_squote = pdf_color_squote; proc->super.op_dquote = pdf_color_dquote; /* type 3 fonts */ proc->super.op_d0 = pdf_color_d0; proc->super.op_d1 = pdf_color_d1; /* color */ proc->super.op_CS = pdf_color_CS; proc->super.op_cs = pdf_color_cs; proc->super.op_SC_color = pdf_color_SC_color; proc->super.op_sc_color = pdf_color_sc_color; proc->super.op_SC_pattern = pdf_color_SC_pattern; proc->super.op_sc_pattern = pdf_color_sc_pattern; proc->super.op_SC_shade = pdf_color_SC_shade; proc->super.op_sc_shade = pdf_color_sc_shade; proc->super.op_G = pdf_color_G; proc->super.op_g = pdf_color_g; proc->super.op_RG = pdf_color_RG; proc->super.op_rg = pdf_color_rg; proc->super.op_K = pdf_color_K; proc->super.op_k = pdf_color_k; /* shadings, images, xobjects */ proc->super.op_BI = pdf_color_BI; proc->super.op_sh = pdf_color_sh; proc->super.op_Do_image = pdf_color_Do_image; proc->super.op_Do_form = pdf_color_Do_form; /* marked content */ proc->super.op_MP = pdf_color_MP; proc->super.op_DP = pdf_color_DP; proc->super.op_BMC = pdf_color_BMC; proc->super.op_BDC = pdf_color_BDC; proc->super.op_EMC = pdf_color_EMC; /* compatibility */ proc->super.op_BX = pdf_color_BX; proc->super.op_EX = pdf_color_EX; /* extgstate */ proc->super.op_gs_OP = pdf_color_gs_OP; proc->super.op_gs_op = pdf_color_gs_op; proc->super.op_gs_OPM = pdf_color_gs_OPM; proc->super.op_gs_UseBlackPtComp = pdf_color_gs_UseBlackPtComp; proc->super.op_END = pdf_color_END; fz_try(ctx) proc->gstate = fz_malloc_struct(ctx, gstate_stack); fz_catch(ctx) { fz_free(ctx, proc); fz_rethrow(ctx); } proc->doc = pdf_keep_document(ctx, doc); proc->chain = chain; proc->global_options = global_options; proc->options = options; return (pdf_processor*)proc; }