diff options
author | Robin Watts <robin.watts@artifex.com> | 2017-09-21 14:10:33 +0100 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2017-10-24 15:16:36 +0100 |
commit | abd4c0da5d50cc5b81e430dea3eaa01502370dad (patch) | |
tree | 86df6381b21acc05eba42c2b884068ad96e45110 | |
parent | a1e696d27e0927855dd2e0d505afd571b0f37ed7 (diff) | |
download | mupdf-abd4c0da5d50cc5b81e430dea3eaa01502370dad.tar.xz |
Improved overprint (simulation) control.
First, we add an fz_page_overprint function to detect if a
page uses overprint. Only PDF implements this currently (other
formats all return false). PDF looks for '/OP true' in any
ExtGState entry.
We make Mutool check this. If it finds it, and spot rendering
is not completely disabled, then it ensures that the separation
object passed to the pixmap into which we draw is non NULL. This
causes the draw device to do overprint simulation.
We ensure that mutool draw defaults to having the spot rendering
mode default to simulation in builds that support it.
Finally, we ensure that if an output intent is set by the document,
and spot rendering is not completely disabled, then we ensure the
seps object is non NULL so that we render to a group in the
specified output intent, and THEN convert down to the required
colorspace for the output.
This should make us match acrobats behaviour.
-rw-r--r-- | include/mupdf/fitz/document.h | 13 | ||||
-rw-r--r-- | include/mupdf/pdf/object.h | 11 | ||||
-rw-r--r-- | include/mupdf/pdf/page.h | 1 | ||||
-rw-r--r-- | source/fitz/document.c | 7 | ||||
-rw-r--r-- | source/pdf/pdf-object.c | 22 | ||||
-rw-r--r-- | source/pdf/pdf-page.c | 106 | ||||
-rw-r--r-- | source/tools/mudraw.c | 29 |
7 files changed, 164 insertions, 25 deletions
diff --git a/include/mupdf/fitz/document.h b/include/mupdf/fitz/document.h index d3b9abd5..95e59632 100644 --- a/include/mupdf/fitz/document.h +++ b/include/mupdf/fitz/document.h @@ -178,6 +178,12 @@ typedef int (fz_page_separation_disabled_fn)(fz_context *ctx, fz_page *page, int */ typedef fz_separations *(fz_page_separations_fn)(fz_context *ctx, fz_page *page); +/* + fz_page_uses_overprint_fn: Type for a function to retrieve + whether or not a given page uses overprint. +*/ +typedef int (fz_page_uses_overprint_fn)(fz_context *ctx, fz_page *page); + typedef void (fz_annot_drop_fn)(fz_context *ctx, fz_annot *annot); typedef fz_annot *(fz_annot_next_fn)(fz_context *ctx, fz_annot *annot); typedef fz_rect *(fz_annot_bound_fn)(fz_context *ctx, fz_annot *annot, fz_rect *rect); @@ -212,6 +218,7 @@ struct fz_page_s fz_page_control_separation_fn *control_separation; fz_page_separation_disabled_fn *separation_disabled; fz_page_separations_fn *separations; + fz_page_uses_overprint_fn *overprint; }; /* @@ -610,6 +617,12 @@ fz_colorspace *fz_document_output_intent(fz_context *ctx, fz_document *doc); fz_separations *fz_page_separations(fz_context *ctx, fz_page *page); /* + fz_page_uses_overprint: Find out whether a given page requests + overprint. +*/ +int fz_page_uses_overprint(fz_context *ctx, fz_page *page); + +/* fz_save_gproof: Given a currently open document, create a gproof skeleton file from that document. diff --git a/include/mupdf/pdf/object.h b/include/mupdf/pdf/object.h index 5ceab1f0..285acf4d 100644 --- a/include/mupdf/pdf/object.h +++ b/include/mupdf/pdf/object.h @@ -66,8 +66,15 @@ void pdf_unmark_obj(fz_context *ctx, pdf_obj *obj); /* obj memo functions - allows us to secretly remember "a memo" (a bool) in * an object, and to read back whether there was a memo, and if so, what it * was. */ -void pdf_set_obj_memo(fz_context *ctx, pdf_obj *obj, int memo); -int pdf_obj_memo(fz_context *ctx, pdf_obj *obj, int *memo); + +enum +{ + PDF_FLAGS_MEMO_BM = 0, + PDF_FLAGS_MEMO_OP = 1 +}; + +void pdf_set_obj_memo(fz_context *ctx, pdf_obj *obj, int bit, int memo); +int pdf_obj_memo(fz_context *ctx, pdf_obj *obj, int bit, int *memo); /* obj dirty bit support. */ int pdf_obj_is_dirty(fz_context *ctx, pdf_obj *obj); diff --git a/include/mupdf/pdf/page.h b/include/mupdf/pdf/page.h index 13f61bfa..969aedf0 100644 --- a/include/mupdf/pdf/page.h +++ b/include/mupdf/pdf/page.h @@ -194,6 +194,7 @@ struct pdf_page_s pdf_obj *obj; int transparency; + int overprint; int incomplete; fz_link *links; diff --git a/source/fitz/document.c b/source/fitz/document.c index 0e511c05..6f9d1316 100644 --- a/source/fitz/document.c +++ b/source/fitz/document.c @@ -490,3 +490,10 @@ fz_page_separations(fz_context *ctx, fz_page *page) return page->separations(ctx, page); return NULL; } + +int fz_page_uses_overprint(fz_context *ctx, fz_page *page) +{ + if (page && page->overprint) + return page->overprint(ctx, page); + return 0; +} diff --git a/source/pdf/pdf-object.c b/source/pdf/pdf-object.c index 2d60edf1..def683d0 100644 --- a/source/pdf/pdf-object.c +++ b/source/pdf/pdf-object.c @@ -28,9 +28,9 @@ enum { PDF_FLAGS_MARKED = 1, PDF_FLAGS_SORTED = 2, - PDF_FLAGS_MEMO = 4, - PDF_FLAGS_MEMO_BOOL = 8, - PDF_FLAGS_DIRTY = 16 + PDF_FLAGS_DIRTY = 4, + PDF_FLAGS_MEMO_BASE = 8, + PDF_FLAGS_MEMO_BASE_BOOL = 16 }; struct pdf_obj_s @@ -1643,26 +1643,28 @@ pdf_unmark_obj(fz_context *ctx, pdf_obj *obj) } void -pdf_set_obj_memo(fz_context *ctx, pdf_obj *obj, int memo) +pdf_set_obj_memo(fz_context *ctx, pdf_obj *obj, int bit, int memo) { if (obj < PDF_OBJ__LIMIT) return; - obj->flags |= PDF_FLAGS_MEMO; + bit <<= 1; + obj->flags |= PDF_FLAGS_MEMO_BASE << bit; if (memo) - obj->flags |= PDF_FLAGS_MEMO_BOOL; + obj->flags |= PDF_FLAGS_MEMO_BASE_BOOL << bit; else - obj->flags &= ~PDF_FLAGS_MEMO_BOOL; + obj->flags &= ~(PDF_FLAGS_MEMO_BASE_BOOL << bit); } int -pdf_obj_memo(fz_context *ctx, pdf_obj *obj, int *memo) +pdf_obj_memo(fz_context *ctx, pdf_obj *obj, int bit, int *memo) { if (obj < PDF_OBJ__LIMIT) return 0; - if (!(obj->flags & PDF_FLAGS_MEMO)) + bit <<= 1; + if (!(obj->flags & (PDF_FLAGS_MEMO_BASE<<bit))) return 0; - *memo = !!(obj->flags & PDF_FLAGS_MEMO_BOOL); + *memo = !!(obj->flags & (PDF_FLAGS_MEMO_BASE_BOOL<<bit)); return 1; } diff --git a/source/pdf/pdf-page.c b/source/pdf/pdf-page.c index 12319678..da8a2394 100644 --- a/source/pdf/pdf-page.c +++ b/source/pdf/pdf-page.c @@ -436,7 +436,7 @@ pdf_resources_use_blending(fz_context *ctx, pdf_obj *rdb) return 0; /* Have we been here before and remembered an answer? */ - if (pdf_obj_memo(ctx, rdb, &useBM)) + if (pdf_obj_memo(ctx, rdb, PDF_FLAGS_MEMO_BM, &useBM)) return useBM; /* stop on cyclic resource dependencies */ @@ -477,10 +477,94 @@ found: fz_rethrow(ctx); } - pdf_set_obj_memo(ctx, rdb, useBM); + pdf_set_obj_memo(ctx, rdb, PDF_FLAGS_MEMO_BM, useBM); return useBM; } +static int pdf_resources_use_overprint(fz_context *ctx, pdf_obj *rdb); + +static int +pdf_extgstate_uses_overprint(fz_context *ctx, pdf_obj *dict) +{ + pdf_obj *obj = pdf_dict_get(ctx, dict, PDF_NAME_OP); + if (obj && pdf_to_bool(ctx, obj)) + return 1; + return 0; +} + +static int +pdf_pattern_uses_overprint(fz_context *ctx, pdf_obj *dict) +{ + pdf_obj *obj; + obj = pdf_dict_get(ctx, dict, PDF_NAME_Resources); + if (pdf_resources_use_overprint(ctx, obj)) + return 1; + obj = pdf_dict_get(ctx, dict, PDF_NAME_ExtGState); + return pdf_extgstate_uses_overprint(ctx, obj); +} + +static int +pdf_xobject_uses_overprint(fz_context *ctx, pdf_obj *dict) +{ + pdf_obj *obj = pdf_dict_get(ctx, dict, PDF_NAME_Resources); + return pdf_resources_use_overprint(ctx, obj); +} + +static int +pdf_resources_use_overprint(fz_context *ctx, pdf_obj *rdb) +{ + pdf_obj *obj; + int i, n, useOP = 0; + + if (!rdb) + return 0; + + /* Have we been here before and remembered an answer? */ + if (pdf_obj_memo(ctx, rdb, PDF_FLAGS_MEMO_OP, &useOP)) + return useOP; + + /* stop on cyclic resource dependencies */ + if (pdf_mark_obj(ctx, rdb)) + return 0; + + fz_try(ctx) + { + obj = pdf_dict_get(ctx, rdb, PDF_NAME_ExtGState); + n = pdf_dict_len(ctx, obj); + for (i = 0; i < n; i++) + if (pdf_extgstate_uses_overprint(ctx, pdf_dict_get_val(ctx, obj, i))) + goto found; + + obj = pdf_dict_get(ctx, rdb, PDF_NAME_Pattern); + n = pdf_dict_len(ctx, obj); + for (i = 0; i < n; i++) + if (pdf_pattern_uses_overprint(ctx, pdf_dict_get_val(ctx, obj, i))) + goto found; + + obj = pdf_dict_get(ctx, rdb, PDF_NAME_XObject); + n = pdf_dict_len(ctx, obj); + for (i = 0; i < n; i++) + if (pdf_xobject_uses_overprint(ctx, pdf_dict_get_val(ctx, obj, i))) + goto found; + if (0) + { +found: + useOP = 1; + } + } + fz_always(ctx) + { + pdf_unmark_obj(ctx, rdb); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } + + pdf_set_obj_memo(ctx, rdb, PDF_FLAGS_MEMO_OP, useOP); + return useOP; +} + fz_transition * pdf_page_presentation(fz_context *ctx, pdf_page *page, fz_transition *transition, float *duration) { @@ -823,6 +907,12 @@ pdf_page_separations(fz_context *ctx, pdf_page *page) return seps; } +int +pdf_page_uses_overprint(fz_context *ctx, pdf_page *page) +{ + return page ? page->overprint : 0; +} + static void pdf_drop_page_imp(fz_context *ctx, pdf_page *page) { @@ -856,6 +946,7 @@ pdf_new_page(fz_context *ctx, pdf_document *doc) page->super.run_page_contents = (fz_page_run_page_contents_fn*)pdf_run_page_contents; page->super.page_presentation = (fz_page_page_presentation_fn*)pdf_page_presentation; page->super.separations = (fz_page_separations_fn *)pdf_page_separations; + page->super.overprint = (fz_page_uses_overprint_fn *)pdf_page_uses_overprint; page->obj = NULL; @@ -1009,17 +1100,22 @@ pdf_load_page(fz_context *ctx, pdf_document *doc, int number) page->links = NULL; } - /* Scan for transparency */ + /* Scan for transparency and overprint */ fz_try(ctx) { pdf_obj *resources = pdf_page_resources(ctx, page); - if (pdf_resources_use_blending(ctx, resources)) + if (pdf_name_eq(ctx, pdf_dict_getp(ctx, pageobj, "Group/S"), PDF_NAME_Transparency)) page->transparency = 1; - else if (pdf_name_eq(ctx, pdf_dict_getp(ctx, pageobj, "Group/S"), PDF_NAME_Transparency)) + else if (pdf_resources_use_blending(ctx, resources)) page->transparency = 1; for (annot = page->annots; annot && !page->transparency; annot = annot->next) if (annot->ap && pdf_resources_use_blending(ctx, pdf_xobject_resources(ctx, annot->ap))) page->transparency = 1; + if (pdf_resources_use_overprint(ctx, resources)) + page->overprint = 1; + for (annot = page->annots; annot && !page->overprint; annot = annot->next) + if (annot->ap && pdf_resources_use_overprint(ctx, pdf_xobject_resources(ctx, annot->ap))) + page->overprint = 1; } fz_catch(ctx) { diff --git a/source/tools/mudraw.c b/source/tools/mudraw.c index d3cef7a2..f7b87626 100644 --- a/source/tools/mudraw.c +++ b/source/tools/mudraw.c @@ -256,7 +256,12 @@ static int lowmemory = 0; static int errored = 0; static fz_colorspace *colorspace; +static fz_colorspace *oi = NULL; +#ifdef FZ_ENABLE_SPOT_RENDERING +static int spots = SPOTS_OVERPRINT_SIM; +#else static int spots = SPOTS_NONE; +#endif static int alpha; static char *filename; static int files = 0; @@ -352,12 +357,14 @@ static void usage(void) "\t-P\tparallel interpretation/rendering (disabled in this non-threading build)\n" #endif "\t-N\tdisable ICC workflow (\"N\"o color management)\n" - "\t-O -\tControl spot rendering\n" + "\t-O -\tControl spot/overprint rendering\n" "\t\t 0 = No spot rendering\n" #ifdef FZ_ENABLE_SPOT_RENDERING - "\t\t 1 = Overprint simulation\n" + "\t\t 0 = No spot rendering\n" + "\t\t 1 = Overprint simulation (default)\n" "\t\t 2 = Full spot rendering\n" #else + "\t\t 0 = No spot rendering (default)\n" "\t\t 1 = Overprint simulation (Disabled in this build)\n" "\t\t 2 = Full spot rendering (Disabled in this build)\n" #endif @@ -1027,7 +1034,7 @@ static void drawpage(fz_context *ctx, fz_document *doc, int pagenum) page = fz_load_page(ctx, doc, pagenum - 1); - if (spots) + if (spots != SPOTS_NONE) { fz_try(ctx) { @@ -1042,11 +1049,18 @@ static void drawpage(fz_context *ctx, fz_document *doc, int pagenum) for (i = 0; i < n; i++) fz_set_separation_behavior(ctx, seps, i, FZ_SEPARATION_COMPOSITE); } - else + else if (fz_page_uses_overprint(ctx, page)) + { + /* This page uses overprint, so we need an empty + * sep object to force the overprint simulation on. */ + seps = fz_new_separations(ctx, 0); + } + else if (oi && fz_colorspace_n(ctx, oi) != fz_colorspace_n(ctx, colorspace)) { - /* If we are doing spot rendering (or overprint simulation) - * then we need (at least) an empty sep object to force the - * overprint simulation in the draw device. */ + /* We have an output intent, and it's incompatible + * with the colorspace our device needs. Force the + * overprint simulation on, because this ensures that + * we 'simulate' the output intent too. */ seps = fz_new_separations(ctx, 0); } } @@ -1446,7 +1460,6 @@ int mudraw_main(int argc, char **argv) trace_info info = { 0, 0, 0 }; fz_alloc_context alloc_ctx = { &info, trace_malloc, trace_realloc, trace_free }; fz_locks_context *locks = NULL; - fz_colorspace *oi = NULL; fz_var(doc); |