[gs-commits] ghostpdl branch, pdfi, updated. jbig2dec-0.14-2214-g6d2cc1a
[email protected] (Nancy Durgin)
| Newsgroups | gmane.comp.printing.ghostscript.cvs |
|---|---|
| Message-ID | <[email protected]> |
The ghostpdl branch, pdfi has been updated
via 6d2cc1ab2064254e6734f013908bdb9b5a73dca8 (commit)
via e0ffeda75b00f7d864cdfb785cdded5baa88c849 (commit)
from f86f9fef1d8e43847342faa49a77d3560b9b14e4 (commit)
----------------------------------------------------------------------
commit 6d2cc1ab2064254e6734f013908bdb9b5a73dca8
Author: Nancy Durgin <[email protected]>
Date: Wed Sep 18 09:34:14 2019 -0700
Clean up some optcontext stuff
-- wasn't calling the routine to free it
-- cleaned up the implementation, fixed bug in untested code
diff --git a/pdf/ghostpdf.c b/pdf/ghostpdf.c
index bb7aeeb..442455f 100644
--- a/pdf/ghostpdf.c
+++ b/pdf/ghostpdf.c
@@ -883,6 +883,7 @@ int pdfi_free_context(gs_memory_t *pmem, pdf_context *ctx)
}
pdfi_free_DefaultQState(ctx);
+ pdfi_oc_free(ctx);
if (ctx->pdfi_param_list.head != NULL)
gs_c_param_list_release(&ctx->pdfi_param_list);
diff --git a/pdf/pdf_optcontent.c b/pdf/pdf_optcontent.c
index 61f3461..70bb0c5 100644
--- a/pdf/pdf_optcontent.c
+++ b/pdf/pdf_optcontent.c
@@ -310,7 +310,7 @@ pdfi_oc_is_ocg_visible(pdf_context *ctx, pdf_dict *ocdict)
return is_visible;
}
-#define INIT_CONTENT_LEVELS 100
+#define NUM_CONTENT_LEVELS 100
typedef struct {
byte *flags;
uint64_t num_off;
@@ -329,16 +329,16 @@ static int pdfi_oc_levels_init(pdf_context *ctx, pdfi_oc_levels_t **levels)
if (!new)
return_error(gs_error_VMerror);
- data = (byte *)gs_alloc_bytes(ctx->memory, INIT_CONTENT_LEVELS, "pdfi_oc_levels_init (data)");
+ data = (byte *)gs_alloc_bytes(ctx->memory, NUM_CONTENT_LEVELS, "pdfi_oc_levels_init (data)");
if (!data) {
gs_free_object(ctx->memory, new, "pdfi_oc_levels_init (levels (error))");
return_error(gs_error_VMerror);
}
- memset(data, 0, INIT_CONTENT_LEVELS);
+ memset(data, 0, NUM_CONTENT_LEVELS);
new->flags = data;
new->num_off = 0;
- new->max_flags = INIT_CONTENT_LEVELS;
+ new->max_flags = NUM_CONTENT_LEVELS;
*levels = new;
return 0;
@@ -359,7 +359,7 @@ static int pdfi_oc_levels_set(pdf_context *ctx, pdfi_oc_levels_t *levels, uint64
if (index > levels->max_flags) {
/* Expand the flags buffer */
- newmax = levels->max_flags + INIT_CONTENT_LEVELS;
+ newmax = levels->max_flags + NUM_CONTENT_LEVELS;
if (index > newmax)
return_error(gs_error_Fatal); /* shouldn't happen */
new = gs_alloc_bytes(ctx->memory, newmax, "pdfi_oc_levels_set (new data)");
@@ -369,6 +369,7 @@ static int pdfi_oc_levels_set(pdf_context *ctx, pdfi_oc_levels_t *levels, uint64
memcpy(new, levels->flags, levels->max_flags);
gs_free_object(ctx->memory, levels->flags, "pdfi_oc_levels_set (old data)");
levels->flags = new;
+ levels->max_flags += NUM_CONTENT_LEVELS;
}
if (levels->flags[index] == 0)
@@ -414,6 +415,15 @@ int pdfi_oc_init(pdf_context *ctx)
return 0;
}
+int pdfi_oc_free(pdf_context *ctx)
+{
+ int code;
+
+ code = pdfi_oc_levels_free(ctx, (pdfi_oc_levels_t *)ctx->OFFlevels);
+ ctx->OFFlevels = NULL;
+ return code;
+}
+
/* begin marked content sequence */
/* TODO: Incomplete implementation, it is ignoring the argument */
int pdfi_op_BMC(pdf_context *ctx)
diff --git a/pdf/pdf_optcontent.h b/pdf/pdf_optcontent.h
index 71d5366..61c9d69 100644
--- a/pdf/pdf_optcontent.h
+++ b/pdf/pdf_optcontent.h
@@ -19,6 +19,7 @@
bool pdfi_oc_is_ocg_visible(pdf_context *ctx, pdf_dict *ocdict);
int pdfi_oc_init(pdf_context *ctx);
+int pdfi_oc_free(pdf_context *ctx);
bool pdfi_oc_is_off(pdf_context *ctx);
int pdfi_op_BMC(pdf_context *ctx);
int pdfi_op_BDC(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict);
----------------------------------------------------------------------
commit e0ffeda75b00f7d864cdfb785cdded5baa88c849
Author: Nancy Durgin <[email protected]>
Date: Wed Sep 18 09:09:54 2019 -0700
Create pdf_check.c and move a bunch of code out of ghostpdf.c
Move some page code to pdf_page.c
Move the transparency and spot checking code to pdf_check.c
No functional changes, just moving code around.
diff --git a/pdf/ghostpdf.c b/pdf/ghostpdf.c
index 49a0dff..bb7aeeb 100644
--- a/pdf/ghostpdf.c
+++ b/pdf/ghostpdf.c
@@ -31,1141 +31,8 @@
#include "pdf_colour.h"
#include "pdf_font.h"
#include "pdf_text.h"
-#include "pdf_optcontent.h"
-
-/* This routine is slightly misnamed, as it also checks ColorSpaces for spot colours.
- * This is done at the page level, so we maintain a dictionary of the spot colours
- * encountered so far, which we consult before adding any new ones.
- */
-static int pdfi_check_Resources_for_transparency(pdf_context *ctx, pdf_dict *Resources_dict, pdf_dict *page_dict, bool *transparent, int *num_spots);
-
-/* For performance and resource reasons we do not want to install the transparency blending
- * compositor unless we need it. Similarly, if a device handles spot colours it can minimise
- * memory usage if it knows ahead of time how many spot colours there will be.
- *
- * The PDF interpreter written in PostScript performed these as two separate tasks, on opening
- * a PDF file it would count spot colour usage and then for each page it would chek if the page
- * used any transparency. The code below is used to check for both transparency and spot colours.
- * If the int pointer to num_spots is NULL then we aren't interested in spot colours (not supported
- * by the device), if the int pointer to transparent is NULL then we aren't interested in transparency
- * (-dNOTRANSPARENCY is set).
- *
- * Currenlty the code is run when we open the PDF file, the existence of transparency on any given
- * page is recorded in a bit array for later use. If it turns out that checking every page when we
- * open the file is a performance burden then we could do it on a per-page basis instead. NB if
- * the device supports spot colours then we do need to scan the file before starting any page.
- *
- * The technique is fairly straight-forward, we start with each page, and open its Resources
- * dictionary, we then check by type each possible resource. Some resources (eg Pattern, XObject)
- * can themselves contain Resources, in which case we recursively check that dictionary. Note; not
- * all Resource types need to be checked for both transparency and spot colours, some types can
- * only contain one or the other.
- *
- * Routines with the name pdfi_check_xxx_dict are intended to check a Resource dictionary entry, this
- * will be a dictioanry of names and values, where the values are objects of the given Resource type.
- *
- */
-
-/*
- * Check the Resources dictionary ColorSpace entry. pdfi_check_ColorSpace_for_spots is defined
- * in pdf_colour.c
- */
-static int pdfi_check_ColorSpace_dict(pdf_context *ctx, pdf_dict *cspace_dict, pdf_dict *page_dict, int *num_spots)
-{
- int code, i, index;
- pdf_obj *Key = NULL, *Value = NULL;
-
- if (pdfi_dict_entries(cspace_dict) > 0) {
- code = pdfi_loop_detector_mark(ctx); /* Mark the start of the ColorSpace dictionary loop */
- if (code < 0)
- return code;
-
- code = pdfi_dict_first(ctx, cspace_dict, &Key, &Value, (void *)&index);
- if (code < 0)
- goto error1;
-
- i = 1;
- do {
- code = pdfi_check_ColorSpace_for_spots(ctx, Value, cspace_dict, page_dict, num_spots);
- if (code < 0)
- goto error2;
-
- pdfi_countdown(Key);
- Key = NULL;
- pdfi_countdown(Value);
- Value = NULL;
-
- (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the Shading dictionary loop */
-
- code = pdfi_loop_detector_mark(ctx); /* Mark the new start of the Shading dictionary loop */
- if (code < 0)
- goto error1;
-
- do {
- if (i++ >= pdfi_dict_entries(cspace_dict)) {
- code = 0;
- goto transparency_exit;
- }
-
- code = pdfi_dict_next(ctx, cspace_dict, &Key, &Value, (void *)&index);
- if (code == 0 && Value->type == PDF_ARRAY)
- break;
- pdfi_countdown(Key);
- Key = NULL;
- pdfi_countdown(Value);
- Value = NULL;
- } while(1);
- }while (1);
- }
- return 0;
-
-transparency_exit:
-error2:
- pdfi_countdown(Key);
- pdfi_countdown(Value);
-
-error1:
- (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the current resource loop */
- return code;
-}
-
-/*
- * Process an individual Shading dictionary to see if it contains a ColorSpace with a spot colour
- */
-static int pdfi_check_Shading(pdf_context *ctx, pdf_dict *shading, pdf_dict *page_dict, int *num_spots)
-{
- int code;
- pdf_obj *o = NULL;
-
- code = pdfi_dict_knownget(ctx, shading, "ColorSpace", (pdf_obj **)&o);
- if (code > 0) {
- code = pdfi_check_ColorSpace_for_spots(ctx, o, shading, page_dict, num_spots);
- pdfi_countdown(o);
- return code;
- }
- return 0;
-}
-
-/*
- * Check the Resources dictionary Shading entry.
- */
-static int pdfi_check_Shading_dict(pdf_context *ctx, pdf_dict *shading_dict, pdf_dict *page_dict, int *num_spots)
-{
- int code, i, index;
- pdf_obj *Key = NULL, *Value = NULL;
-
- if (pdfi_dict_entries(shading_dict) > 0) {
- code = pdfi_loop_detector_mark(ctx); /* Mark the start of the Shading dictionary loop */
- if (code < 0)
- return code;
-
- code = pdfi_dict_first(ctx, shading_dict, &Key, &Value, (void *)&index);
- if (code < 0 || Value->type != PDF_DICT)
- goto error1;
-
- i = 1;
- do {
- code = pdfi_check_Shading(ctx, (pdf_dict *)Value, page_dict, num_spots);
- if (code < 0)
- goto error2;
-
- pdfi_countdown(Key);
- Key = NULL;
- pdfi_countdown(Value);
- Value = NULL;
-
- (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the Shading dictionary loop */
-
- code = pdfi_loop_detector_mark(ctx); /* Mark the new start of the Shading dictionary loop */
- if (code < 0)
- goto error1;
-
- do {
- if (i++ >= pdfi_dict_entries(shading_dict)) {
- code = 0;
- goto transparency_exit;
- }
-
- code = pdfi_dict_next(ctx, shading_dict, &Key, &Value, (void *)&index);
- if (code == 0 && Value->type == PDF_DICT)
- break;
- pdfi_countdown(Key);
- Key = NULL;
- pdfi_countdown(Value);
- Value = NULL;
- } while(1);
- }while (1);
- }
- return 0;
-
-transparency_exit:
-error2:
- pdfi_countdown(Key);
- pdfi_countdown(Value);
-
-error1:
- (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the current resource loop */
- return code;
-}
-
-/*
- * This routine checks an XObject to see if it contains any spot
- * colour definitions, or transparency usage.
- */
-static int pdfi_check_XObject(pdf_context *ctx, pdf_dict *xobject, pdf_dict *page_dict, bool *transparent, int *num_spots)
-{
- int code = 0;
- pdf_name *n = NULL;
- bool known = false;
- double f;
-
- code = pdfi_dict_get_type(ctx, xobject, "Subtype", PDF_NAME, (pdf_obj **)&n);
- if (code >= 0) {
- if (pdfi_name_is((const pdf_name *)n, "Image")) {
- pdf_obj *CS = NULL;
-
- pdfi_countdown(n);
- n = NULL;
- code = pdfi_dict_known(xobject, "SMask", &known);
- if (code >= 0) {
- if (known == true) {
- *transparent = true;
- if (num_spots == NULL)
- goto transparency_exit;
- }
- code = pdfi_dict_knownget_number(ctx, xobject, "SMaskInData", &f);
- if (code > 0) {
- code = 0;
- if (f != 0.0)
- *transparent = true;
- if (num_spots == NULL)
- goto transparency_exit;
- }
- /* Check the image dictionary for a ColorSpace entry, if we are checking spot names */
- if (num_spots) {
- code = pdfi_dict_knownget(ctx, xobject, "ColorSpace", (pdf_obj **)&CS);
- if (code > 0) {
- /* We don't care if there's an error here, it'll be picked up if we use the ColorSpace later */
- (void)pdfi_check_ColorSpace_for_spots(ctx, CS, xobject, page_dict, num_spots);
- pdfi_countdown(CS);
- }
- }
- }
- } else {
- if (pdfi_name_is((const pdf_name *)n, "Form")) {
- pdf_dict *group_dict = NULL, *resource_dict = NULL;
- pdf_obj *CS = NULL;
-
- pdfi_countdown(n);
- code = pdfi_dict_knownget_type(ctx, xobject, "Group", PDF_DICT, (pdf_obj **)&group_dict);
- if (code > 0) {
- *transparent = true;
- if (num_spots == NULL) {
- pdfi_countdown(group_dict);
- goto transparency_exit;
- }
-
- /* Start a new loop detector group to avoid this being detected in the Resources check below */
- code = pdfi_loop_detector_mark(ctx); /* Mark the start of the XObject dictionary loop */
- if (code > 0) {
- code = pdfi_dict_knownget(ctx, group_dict, "CS", &CS);
- if (code > 0)
- /* We don't care if there's an error here, it'll be picked up if we use the ColorSpace later */
- (void)pdfi_check_ColorSpace_for_spots(ctx, CS, group_dict, page_dict, num_spots);
- }
- pdfi_countdown(group_dict);
- pdfi_countdown(CS);
- (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the XObject dictionary loop */
- }
-
- code = pdfi_dict_knownget_type(ctx, xobject, "Resources", PDF_DICT, (pdf_obj **)&resource_dict);
- if (code > 0) {
- code = pdfi_check_Resources_for_transparency(ctx, resource_dict, page_dict, transparent, num_spots);
- pdfi_countdown(resource_dict);
- if (code < 0)
- goto transparency_exit;
- }
- } else
- pdfi_countdown(n);
- }
- }
-
- return 0;
-
-transparency_exit:
- return code;
-}
-
-/*
- * Check the Resources dictionary XObject entry.
- */
-static int pdfi_check_XObject_dict(pdf_context *ctx, pdf_dict *xobject_dict, pdf_dict *page_dict, bool *transparent, int *num_spots)
-{
- int code, i, index;
- pdf_obj *Key = NULL, *Value = NULL; //, *o = NULL;
-
- if (pdfi_dict_entries(xobject_dict) > 0) {
- code = pdfi_loop_detector_mark(ctx); /* Mark the start of the XObject dictionary loop */
- if (code < 0)
- return code;
-
- code = pdfi_dict_first(ctx, xobject_dict, &Key, &Value, (void *)&index);
- if (code < 0 || Value->type != PDF_DICT)
- goto error1;
-
- i = 1;
- do {
- code = pdfi_check_XObject(ctx, (pdf_dict *)Value, page_dict, transparent, num_spots);
- if (code < 0)
- goto error2;
-
- (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the XObject dictionary loop */
-
- code = pdfi_loop_detector_mark(ctx); /* Mark the new start of the XObject dictionary loop */
- if (code < 0)
- goto error1;
-
- pdfi_countdown(Key);
- Key = NULL;
- pdfi_countdown(Value);
- Value = NULL;
-
- do {
- if (i++ >= pdfi_dict_entries(xobject_dict)) {
- code = 0;
- goto transparency_exit;
- }
-
- code = pdfi_dict_next(ctx, xobject_dict, &Key, &Value, (void *)&index);
- if (code == 0 && Value->type == PDF_DICT)
- break;
- pdfi_countdown(Key);
- Key = NULL;
- pdfi_countdown(Value);
- Value = NULL;
- } while(1);
- }while(1);
- }
- return 0;
-
-transparency_exit:
-error2:
- pdfi_countdown(Key);
- pdfi_countdown(Value);
-
-error1:
- (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the current resource loop */
- return code;
-}
-
-/*
- * This routine checks an ExtGState dictionary to see if it contains any spot
- * colour definitions, or transparency usage.
- */
-static int pdfi_check_ExtGState(pdf_context *ctx, pdf_dict *extgstate_dict, pdf_dict *page_dict, bool *transparent, int *num_spots)
-{
- int code;
- pdf_obj *o = NULL;
- double f;
-
- if (pdfi_dict_entries(extgstate_dict) > 0) {
- /* Check SMask first, because if we test spot colours first we can exit as
- * soon as we detect transparency.
- */
- code = pdfi_dict_knownget(ctx, extgstate_dict, "SMask", &o);
- if (code > 0) {
- if (o->type == PDF_NAME) {
- if (!pdfi_name_is((pdf_name *)o, "None")) {
- pdfi_countdown(o);
- *transparent = true;
- return 0;
- }
- } else {
- if (o->type == PDF_DICT) {
- pdf_obj *G = NULL;
-
- *transparent = true;
-
- if (num_spots != NULL) {
- /* Check if the SMask has a /G (Group) */
- code = pdfi_dict_knownget(ctx, (pdf_dict *)o, "G", &G);
- if (code > 0) {
- code = pdfi_check_XObject(ctx, (pdf_dict *)G, page_dict, transparent, num_spots);
- pdfi_countdown(G);
- }
- }
- pdfi_countdown(o);
- return code;
- }
- }
- }
- pdfi_countdown(o);
- o = NULL;
-
- code = pdfi_dict_knownget_type(ctx, extgstate_dict, "BM", PDF_NAME, &o);
- if (code > 0) {
- if (!pdfi_name_is((pdf_name *)o, "Normal")) {
- if (!pdfi_name_is((pdf_name *)o, "Compatible")) {
- pdfi_countdown(o);
- *transparent = true;
- return 0;
- }
- }
- }
- pdfi_countdown(o);
- o = NULL;
-
- code = pdfi_dict_knownget_number(ctx, extgstate_dict, "CA", &f);
- if (code > 0) {
- if (f != 1.0) {
- *transparent = true;
- return 0;
- }
- }
-
- code = pdfi_dict_knownget_number(ctx, extgstate_dict, "ca", &f);
- if (code > 0) {
- if (f != 1.0) {
- *transparent = true;
- return 0;
- }
- }
- }
- return 0;
-}
-
-/*
- * Check the Resources dictionary ExtGState entry.
- */
-static int pdfi_check_ExtGState_dict(pdf_context *ctx, pdf_dict *extgstate_dict, pdf_dict *page_dict, bool *transparent, int *num_spots)
-{
- int code, i, index;
- pdf_obj *Key = NULL, *Value = NULL;
-
- if (pdfi_dict_entries(extgstate_dict) > 0) {
- code = pdfi_loop_detector_mark(ctx); /* Mark the start of the ColorSpace dictionary loop */
- if (code < 0)
- return code;
-
- code = pdfi_dict_first(ctx, extgstate_dict, &Key, &Value, (void *)&index);
- if (code < 0)
- goto error1;
-
- i = 1;
- do {
-
- (void)pdfi_check_ExtGState(ctx, (pdf_dict *)Value, page_dict, transparent, num_spots);
- if (*transparent == true && num_spots == NULL)
- goto transparency_exit;
-
- pdfi_countdown(Key);
- Key = NULL;
- pdfi_countdown(Value);
- Value = NULL;
-
- (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the ExtGState dictionary loop */
-
- code = pdfi_loop_detector_mark(ctx); /* Mark the new start of the ExtGState dictionary loop */
- if (code < 0)
- goto error1;
-
- do {
- if (i++ >= pdfi_dict_entries(extgstate_dict)) {
- code = 0;
- goto transparency_exit;
- }
-
- code = pdfi_dict_next(ctx, extgstate_dict, &Key, &Value, (void *)&index);
- if (code == 0 && Value->type == PDF_DICT)
- break;
- pdfi_countdown(Key);
- Key = NULL;
- pdfi_countdown(Value);
- Value = NULL;
- } while(1);
- }while (1);
- }
- return 0;
-
-transparency_exit:
- pdfi_countdown(Key);
- pdfi_countdown(Value);
-
-error1:
- (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the current resource loop */
- return code;
-}
-
-/*
- * This routine checks a Pattern dictionary to see if it contains any spot
- * colour definitions, or transparency usage.
- */
-int pdfi_check_Pattern(pdf_context *ctx, pdf_dict *pattern, pdf_dict *page_dict, bool *transparent, int *num_spots)
-{
- int code = 0;
- pdf_obj *o = NULL;
-
- if (num_spots != NULL) {
- code = pdfi_dict_knownget_type(ctx, pattern, "Shading", PDF_DICT, &o);
- if (code > 0)
- (void)pdfi_check_Shading(ctx, (pdf_dict *)o, page_dict, num_spots);
- pdfi_countdown(o);
- o = NULL;
- }
-
- code = pdfi_dict_knownget_type(ctx, pattern, "Resources", PDF_DICT, &o);
- if (code > 0)
- (void)pdfi_check_Resources_for_transparency(ctx, (pdf_dict *)o, page_dict, transparent, num_spots);
- pdfi_countdown(o);
- o = NULL;
- if (*transparent == true && num_spots == NULL)
- goto transparency_exit;
-
- code = pdfi_dict_knownget_type(ctx, pattern, "ExtGState", PDF_DICT, &o);
- if (code > 0)
- (void)pdfi_check_ExtGState(ctx, (pdf_dict *)o, page_dict, transparent, num_spots);
- pdfi_countdown(o);
- o = NULL;
-
-transparency_exit:
- return 0;
-}
-
-/*
- * Check the Resources dictionary Pattern entry.
- */
-static int pdfi_check_Pattern_dict(pdf_context *ctx, pdf_dict *pattern_dict, pdf_dict *page_dict, bool *transparent, int *num_spots)
-{
- int code, i, index;
- pdf_obj *Key = NULL, *Value = NULL;
-
- if (pdfi_dict_entries(pattern_dict) > 0) {
- code = pdfi_loop_detector_mark(ctx); /* Mark the start of the Pattern dictionary loop */
- if (code < 0)
- return code;
-
- code = pdfi_dict_first(ctx, pattern_dict, &Key, &Value, (void *)&index);
- if (code < 0)
- goto error1;
-
- if (Value->type != PDF_DICT)
- goto transparency_exit;
-
- i = 1;
- do {
- code = pdfi_check_Pattern(ctx, (pdf_dict *)Value, page_dict, transparent, num_spots);
- if (code < 0)
- goto transparency_exit;
-
- pdfi_countdown(Key);
- Key = NULL;
- pdfi_countdown(Value);
- Value = NULL;
- (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the Shading dictionary loop */
-
- code = pdfi_loop_detector_mark(ctx); /* Mark the new start of the Shading dictionary loop */
- if (code < 0)
- goto error1;
-
- do {
- if (i++ >= pdfi_dict_entries(pattern_dict)) {
- code = 0;
- goto transparency_exit;
- }
-
- code = pdfi_dict_next(ctx, pattern_dict, &Key, &Value, (void *)&index);
- if (code == 0 && Value->type == PDF_DICT)
- break;
- pdfi_countdown(Key);
- Key = NULL;
- pdfi_countdown(Value);
- Value = NULL;
- } while(1);
- }while (1);
- }
- return 0;
-
-transparency_exit:
- pdfi_countdown(Key);
- pdfi_countdown(Value);
-
-error1:
- (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the current resource loop */
- return code;
-}
-
-/*
- * This routine checks a Font dictionary to see if it contains any spot
- * colour definitions, or transparency usage.
- */
-static int pdfi_check_Font(pdf_context *ctx, pdf_dict *font, pdf_dict *page_dict, bool *transparent, int *num_spots)
-{
- int code = 0;
- pdf_obj *o = NULL;
-
- code = pdfi_dict_knownget_type(ctx, font, "Subtype", PDF_NAME, &o);
- if (code > 0) {
- if (pdfi_name_is((pdf_name *)o, "Type3")) {
- pdfi_countdown(o);
- o = NULL;
-
- code = pdfi_dict_knownget_type(ctx, font, "Resources", PDF_DICT, &o);
- if (code > 0)
- (void)pdfi_check_Resources_for_transparency(ctx, (pdf_dict *)o, page_dict, transparent, num_spots);
- }
- }
- pdfi_countdown(o);
- o = NULL;
-
- return 0;
-}
-
-/*
- * Check the Resources dictionary Font entry.
- */
-static int pdfi_check_Font_dict(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *page_dict, bool *transparent, int *num_spots)
-{
- int code, i, index;
- pdf_obj *Key = NULL, *Value = NULL;
-
- if (pdfi_dict_entries(font_dict) > 0) {
- code = pdfi_loop_detector_mark(ctx); /* Mark the start of the Font dictionary loop */
- if (code < 0)
- return code;
-
- code = pdfi_dict_first(ctx, font_dict, &Key, &Value, (void *)&index);
- if (code < 0)
- goto error1;
-
- i = 1;
- do {
- code = pdfi_check_Font(ctx, (pdf_dict *)Value, page_dict, transparent, num_spots);
-
- pdfi_countdown(Key);
- Key = NULL;
- pdfi_countdown(Value);
- Value = NULL;
-
- (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the Font dictionary loop */
-
- code = pdfi_loop_detector_mark(ctx); /* Mark the new start of the Font dictionary loop */
- if (code < 0)
- goto error1;
-
- do {
- if (i++ >= pdfi_dict_entries(font_dict)) {
- code = 0;
- goto transparency_exit;
- }
-
- code = pdfi_dict_next(ctx, font_dict, &Key, &Value, (void *)&index);
- if (code == 0 && Value->type == PDF_DICT)
- break;
- pdfi_countdown(Key);
- Key = NULL;
- pdfi_countdown(Value);
- Value = NULL;
- } while(1);
- }while (1);
- }
- return 0;
-
-transparency_exit:
- pdfi_countdown(Key);
- pdfi_countdown(Value);
-
-error1:
- (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the current resource loop */
- return code;
-}
-
-static int pdfi_check_Resources_for_transparency(pdf_context *ctx, pdf_dict *Resources_dict, pdf_dict *page_dict, bool *transparent, int *num_spots)
-{
- int code;
- pdf_obj *d = NULL;
-
- /* First up, check any colour spaces, for new spot colours.
- * We only do this if asked because its expensive. num_spots being NULL
- * means we aren't interested in spot colours (not a DeviceN or Separation device)
- */
- if (num_spots != NULL) {
- code = pdfi_dict_knownget_type(ctx, Resources_dict, "ColorSpace", PDF_DICT, &d);
- if (code > 0)
- (void)pdfi_check_ColorSpace_dict(ctx, (pdf_dict *)d, page_dict, num_spots);
-
- pdfi_countdown(d);
- d = NULL;
-
- code = pdfi_dict_knownget_type(ctx, Resources_dict, "Shading", PDF_DICT, &d);
- if (code > 0)
- (void)pdfi_check_Shading_dict(ctx, (pdf_dict *)d, page_dict, num_spots);
- pdfi_countdown(d);
- d = NULL;
- }
-
- code = pdfi_dict_knownget_type(ctx, Resources_dict, "XObject", PDF_DICT, &d);
- if (code > 0)
- (void)pdfi_check_XObject_dict(ctx, (pdf_dict *)d, page_dict, transparent, num_spots);
- pdfi_countdown(d);
- d = NULL;
-
- code = pdfi_dict_knownget_type(ctx, Resources_dict, "Pattern", PDF_DICT, &d);
- if (code > 0)
- (void)pdfi_check_Pattern_dict(ctx, (pdf_dict *)d, page_dict, transparent, num_spots);
- pdfi_countdown(d);
- d = NULL;
-
- code = pdfi_dict_knownget_type(ctx, Resources_dict, "Font", PDF_DICT, &d);
- if (code > 0)
- (void)pdfi_check_Font_dict(ctx, (pdf_dict *)d, page_dict, transparent, num_spots);
- /* From this point onwards, if we detect transparency (or have already detected it) we
- * can exit, we have already counted up any spot colours.
- */
- pdfi_countdown(d);
- d = NULL;
-
- code = pdfi_dict_knownget_type(ctx, Resources_dict, "ExtGState", PDF_DICT, &d);
- if (code > 0)
- (void)pdfi_check_ExtGState_dict(ctx, (pdf_dict *)d, page_dict, transparent, num_spots);
- pdfi_countdown(d);
- d = NULL;
-
- return 0;
-}
-
-static int pdfi_check_annot_for_transparency(pdf_context *ctx, pdf_dict *annot, pdf_dict *page_dict, bool *transparent, int *num_spots)
-{
- int code;
- pdf_name *n;
- pdf_dict *ap = NULL, *N = NULL, *Resources = NULL;
- double f;
-
- /* Check #1 Does the (Normal) Appearnce stream use any Resources which include transparency.
- * We check this first, because this also checks for spot colour spaces. Once we've done that we
- * can exit the checks as soon as we detect transparency.
- */
- code = pdfi_dict_knownget_type(ctx, annot, "AP", PDF_DICT, (pdf_obj **)&ap);
- if (code > 0)
- {
- code = pdfi_dict_knownget_type(ctx, ap, "N", PDF_DICT, (pdf_obj **)&N);
- if (code > 0) {
- code = pdfi_dict_knownget_type(ctx, N, "Resources", PDF_DICT, (pdf_obj **)&Resources);
- if (code > 0)
- code = pdfi_check_Resources_for_transparency(ctx, (pdf_dict *)Resources, page_dict, transparent, num_spots);
- }
- }
- pdfi_countdown(ap);
- pdfi_countdown(N);
- pdfi_countdown(Resources);
- if (code < 0)
- return code;
- /* We've checked the Resources, and nothing else in an annotation can define spot colours, so
- * if we detected transparency in the Resources we need not check further.
- */
- if (*transparent == true)
- return 0;
-
- code = pdfi_dict_get_type(ctx, annot, "Subtype", PDF_NAME, (pdf_obj **)&n);
- if (code < 0) {
- if (ctx->pdfstoponerror)
- return code;
- } else {
- /* Check #2, Highlight annotations are always preformed with transparency */
- if (pdfi_name_is((const pdf_name *)n, "Highlight")) {
- pdfi_countdown(n);
- *transparent = true;
- return 0;
- }
- pdfi_countdown(n);
- n = NULL;
-
- /* Check #3 Blend Mode (BM) not being 'Normal' or 'Compatible' */
- code = pdfi_dict_knownget_type(ctx, annot, "BM", PDF_NAME, (pdf_obj **)&n);
- if (code > 0) {
- if (!pdfi_name_is((const pdf_name *)n, "Normal")) {
- if (!pdfi_name_is((const pdf_name *)n, "Compatible")) {
- pdfi_countdown(n);
- *transparent = true;
- return 0;
- }
- }
- code = 0;
- }
- pdfi_countdown(n);
- if (code < 0)
- return code;
-
- /* Check #4 stroke constant alpha (CA) is not 1 (100% opaque) */
- code = pdfi_dict_knownget_number(ctx, annot, "CA", &f);
- if (code > 0) {
- if (f != 1.0) {
- *transparent = true;
- return 0;
- }
- }
- if (code < 0)
- return code;
-
- /* Check #5 non-stroke constant alpha (ca) is not 1 (100% opaque) */
- code = pdfi_dict_knownget_number(ctx, annot, "ca", &f);
- if (code > 0) {
- if (f != 1.0) {
- *transparent = true;
- return 0;
- }
- }
- if (code < 0)
- return code;
- }
-
- return 0;
-}
-
-static int pdfi_check_Annots_for_transparency(pdf_context *ctx, pdf_array *annots_array, pdf_dict *page_dict, bool *transparent, int *num_spots)
-{
- int i, code = 0;
- pdf_dict *annot = NULL;
-
- for (i=0; i < pdfi_array_size(annots_array); i++) {
- code = pdfi_array_get_type(ctx, annots_array, (uint64_t)i, PDF_DICT, (pdf_obj **)&annot);
- if (code > 0) {
- code = pdfi_check_annot_for_transparency(ctx, annot, page_dict, transparent, num_spots);
- if (code < 0 && ctx->pdfstoponerror)
- goto exit;
-
- /* If we've found transparency, and don't need to continue checkign for spot colours
- * just exit as fast as possible.
- */
- if (*transparent == true && num_spots == NULL)
- goto exit;
-
- pdfi_countdown(annot);
- annot = NULL;
- }
- }
-exit:
- pdfi_countdown(annot);
- return code;
-}
-
-/* From the original PDF interpreter written in PostScript:
- * Note: we deliberately don't check to see whether a Group is defined,
- * because Adobe Illustrator 10 (and possibly other applications) define
- * a page-level group whether transparency is actually used or not.
- * Ignoring the presence of Group is justified because, in the absence
- * of any other transparency features, they have no effect.
- */
-static int pdfi_check_page_transparency(pdf_context *ctx, pdf_dict *page_dict, bool *transparent, int *spots)
-{
- int code;
- pdf_obj *d = NULL;
- int num_spots = 0;
- pdf_dict *group_dict = NULL;
-
- /* Note that we don't reset 'spots' to 0 because these accumulate across pages */
- *transparent = false;
-
- ctx->spot_capable_device = false;
- gs_c_param_list_read(&ctx->pdfi_param_list);
- code = param_read_int((gs_param_list *)&ctx->pdfi_param_list, "PageSpotColors", &ctx->spot_capable_device);
- if (code < 0)
- return code;
- if (code > 0)
- ctx->spot_capable_device = 0;
- else
- ctx->spot_capable_device = 1;
-
- /* Check if the page dictionary has a page Group entry */
- code = pdfi_dict_knownget_type(ctx, page_dict, "Group", PDF_DICT, (pdf_obj **)&group_dict);
- if (code > 0) {
- pdf_obj *CS = NULL;
-
- /* Page group means the page is transparent but we ignore it for the purposes
- * of transparency detection. See above.
- */
- if (ctx->spot_capable_device) {
- /* Check the Group to see if it has a ColorSpace (CS) and if it
- * does whether it has any spot colours */
- code = pdfi_dict_knownget(ctx, group_dict, "CS", &CS);
- if (code > 0) {
- code = pdfi_check_ColorSpace_for_spots(ctx, CS, group_dict, page_dict, spots);
- if (code < 0 && ctx->pdfstoponerror) {
- pdfi_countdown(CS);
- pdfi_countdown(group_dict);
- pdfi_countdown(ctx->SpotNames);
- return code;
- }
- pdfi_countdown(CS);
- }
- }
- pdfi_countdown(group_dict);
- }
-
- /* Now check any Resources dictionary in the Page dictionary */
- code = pdfi_dict_get_type(ctx, page_dict, "Resources", PDF_DICT, &d);
- if (code >= 0) {
- if (ctx->spot_capable_device)
- code = pdfi_check_Resources_for_transparency(ctx, (pdf_dict *)d, page_dict, transparent, &num_spots);
- else
- code = pdfi_check_Resources_for_transparency(ctx, (pdf_dict *)d, page_dict, transparent, NULL);
- pdfi_countdown(d);
- if (code < 0)
- return code;
- }
- if (code < 0 && code != gs_error_undefined && ctx->pdfstoponerror)
- return code;
-
- /* If we are drawing Annotations, check to see if the page uses any Annots */
- if (ctx->showannots) {
- code = pdfi_dict_get_type(ctx, page_dict, "Annots", PDF_ARRAY, &d);
- if (code >= 0) {
- if (ctx->spot_capable_device)
- code = pdfi_check_Annots_for_transparency(ctx, (pdf_array *)d, page_dict, transparent, &num_spots);
- else
- code = pdfi_check_Annots_for_transparency(ctx, (pdf_array *)d, page_dict, transparent, NULL);
- pdfi_countdown(d);
- if (code < 0)
- return code;
- }
- if (code < 0 && code != gs_error_undefined && ctx->pdfstoponerror)
- return code;
- }
-
- if (ctx->spot_capable_device)
- *spots += num_spots;
- else
- *spots = 0;
-
- return 0;
-}
-
-static int pdfi_check_transparency_spots(pdf_context *ctx)
-{
- int code = 0;
-
- /* Loop round all the pages looking for spot colours and transparency. We only check
- * for spot colours if the device is capable of spot colours (the code checks). We
- * only store the transparency setting if NOTRANSPARENCY is not set
- */
- if (ctx->num_pages) {
- pdf_dict *page_dict = NULL;
- uint64_t page_offset = 0;
- bool uses_transparency = false;
- int spots = 0;
- uint64_t ix;
-
- int bytes = (int)ceil((float)ctx->num_pages / 8.0f);
- ctx->PageTransparencyArray = (char *)gs_alloc_bytes(ctx->memory, bytes, "pdfi_process_file, allocate page transparency tracking array");
- memset(ctx->PageTransparencyArray, 0x00, bytes);
-
- code = pdfi_alloc_object(ctx, PDF_DICT, 32, (pdf_obj **)&ctx->SpotNames);
- if (code < 0)
- goto exit;
-
- pdfi_countup(ctx->SpotNames);
-
- for (ix=0;ix < ctx->num_pages;ix++) {
- if (ctx->pdfdebug)
- dmprintf1(ctx->memory, "%% Checking Page %"PRIi64" for transparency and spot plates\n", ix + 1);
-
- uses_transparency = false;
-
- /* Get the page dictionary */
- code = pdfi_loop_detector_mark(ctx);
- if (code < 0)
- goto exit;
-
- code = pdfi_loop_detector_add_object(ctx, ctx->Pages->object_num);
- if (code < 0) {
- pdfi_loop_detector_cleartomark(ctx);
- goto exit;
- }
-
- page_offset = 0;
- code = pdfi_get_page_dict(ctx, ctx->Pages, ix, &page_offset, &page_dict, NULL);
- pdfi_loop_detector_cleartomark(ctx);
- if (code < 0) {
- if (code == gs_error_VMerror || ctx->pdfstoponerror)
- goto exit;
- return 0;
- }
-
- if (code > 0) {
- /* This can happen if the number of declared pages (/Count) is larger than the number of pages in the Pages array
- * We'll ignore that for the purposes of transparency checking. If the user tries to render this
- * page it'll fail in the page rendering code.
- */
- pdfi_countdown(page_dict);
- page_dict = NULL;
- break;
- }
-
- /* Check the page dictionary for spots and transparency */
- code = pdfi_check_page_transparency(ctx, page_dict, &uses_transparency, &spots);
- if (code < 0) {
- pdfi_countdown(ctx->SpotNames);
- pdfi_countdown(page_dict);
- ctx->SpotNames = NULL;
- goto exit;
- }
- if (uses_transparency && !ctx->notransparency) {
- uint64_t index = ix >> 3;
- char value = 0x80 >> (ix % 8);
-
- ctx->PageTransparencyArray[index] |= value;
- }
- pdfi_countdown(page_dict);
- page_dict = NULL;
- }
-
- pdfi_countdown(ctx->SpotNames);
- ctx->SpotNames = NULL;
-
- /* If there are spot colours (and by inference, the device renders spot plates) then
- * send the number of Spots to the device, so it can setup correctly.
- */
- if (spots > 0) {
- gs_c_param_list_write(&ctx->pdfi_param_list, ctx->memory);
- param_write_int((gs_param_list *)&ctx->pdfi_param_list, "PageSpotColors", &spots);
- gs_c_param_list_read(&ctx->pdfi_param_list);
- code = gs_putdeviceparams(ctx->pgs->device, (gs_param_list *)&ctx->pdfi_param_list);
- if (code > 0) {
- /* The device was closed, we need to reopen it */
- code = gs_setdevice_no_erase(ctx->pgs, ctx->pgs->device);
- if (code < 0) {
- if (uses_transparency)
- (void)gs_abort_pdf14trans_device(ctx->pgs);
- pdfi_countdown(ctx->SpotNames);
- pdfi_countdown(page_dict);
- goto exit;
- }
- gs_erasepage(ctx->pgs);
- }
- }
- }
-exit:
- return code;
-}
-
-static int pdfi_set_media_size(pdf_context *ctx, pdf_dict *page_dict)
-{
- gs_c_param_list list;
- gs_param_float_array fa;
- pdf_array *a = NULL, *default_media = NULL;
- float fv[2];
- double d[4];
- int code;
- uint64_t i;
- int64_t rotate = 0;
-
- gs_c_param_list_write(&list, ctx->memory);
-
- code = pdfi_dict_get_type(ctx, page_dict, "MediaBox", PDF_ARRAY, (pdf_obj **)&default_media);
- if (code < 0) {
- code = gs_erasepage(ctx->pgs);
- return 0;
- }
-
- if (ctx->usecropbox) {
- if (a != NULL)
- pdfi_countdown(a);
- (void)pdfi_dict_get_type(ctx, page_dict, "CropBox", PDF_ARRAY, (pdf_obj **)&a);
- }
- if (ctx->useartbox) {
- if (a != NULL)
- pdfi_countdown(a);
- (void)pdfi_dict_get_type(ctx, page_dict, "ArtBox", PDF_ARRAY, (pdf_obj **)&a);
- }
- if (ctx->usebleedbox) {
- if (a != NULL)
- pdfi_countdown(a);
- (void)pdfi_dict_get_type(ctx, page_dict, "BleedBox", PDF_ARRAY, (pdf_obj **)&a);
- }
- if (ctx->usetrimbox) {
- if (a != NULL)
- pdfi_countdown(a);
- (void)pdfi_dict_get_type(ctx, page_dict, "MediaBox", PDF_ARRAY, (pdf_obj **)&a);
- }
- if (a == NULL)
- a = default_media;
-
- for (i=0;i<4;i++) {
- code = pdfi_array_get_number(ctx, a, i, &d[i]);
- }
- pdfi_countdown(a);
-
- normalize_rectangle(d);
- memcpy(ctx->PageSize, d, 4 * sizeof(double));
-
- code = pdfi_dict_get_int(ctx, page_dict, "Rotate", &rotate);
-
- rotate = rotate % 360;
-
- switch(rotate) {
- default:
- case 0:
- case 360:
- case -180:
- case 180:
- fv[0] = (float)(d[2] - d[0]);
- fv[1] = (float)(d[3] - d[1]);
- break;
- case -90:
- case 90:
- case -270:
- case 270:
- fv[1] = (float)(d[2] - d[0]);
- fv[0] = (float)(d[3] - d[1]);
- break;
- }
-
- fa.persistent = false;
- fa.data = fv;
- fa.size = 2;
-
- code = param_write_float_array((gs_param_list *)&list, ".MediaSize", &fa);
- if (code >= 0)
- {
- gx_device *dev = gs_currentdevice(ctx->pgs);
-
- gs_c_param_list_read(&list);
- code = gs_putdeviceparams(dev, (gs_param_list *)&list);
- if (code < 0) {
- gs_c_param_list_release(&list);
- return code;
- }
- }
- gs_c_param_list_release(&list);
-
- gs_initgraphics(ctx->pgs);
-
- switch(rotate) {
- case 0:
- break;
- case -270:
- case 90:
- gs_translate(ctx->pgs, 0, fv[1]);
- gs_rotate(ctx->pgs, -90);
- break;
- case -180:
- case 180:
- gs_translate(ctx->pgs, fv[0], fv[1]);
- gs_rotate(ctx->pgs, 180);
- break;
- case -90:
- case 270:
- gs_translate(ctx->pgs, fv[0], 0);
- gs_rotate(ctx->pgs, 90);
- break;
- default:
- break;
- }
-
- gs_translate(ctx->pgs, d[0] * -1, d[1] * -1);
-
- code = gs_erasepage(ctx->pgs);
- return 0;
-}
+#include "pdf_page.h"
+#include "pdf_check.h"
/*
* Convenience routine to check if a given string exists in a dictionary
@@ -1429,299 +296,6 @@ static int pdfi_output_page_info(pdf_context *ctx, uint64_t page_num)
return 0;
}
-static int pdfi_process_page_contents(pdf_context *ctx, pdf_dict *page_dict)
-{
- int i, code = 0;
- pdf_obj *o, *o1;
-
- code = pdfi_dict_get(ctx, page_dict, "Contents", &o);
- if (code == gs_error_undefined)
- /* Don't throw an error if there are no contents, just render nothing.... */
- return 0;
- if (code < 0)
- return code;
-
- if (o->type == PDF_INDIRECT) {
- if (((pdf_indirect_ref *)o)->ref_object_num == page_dict->object_num)
- return_error(gs_error_circular_reference);
-
- code = pdfi_dereference(ctx, ((pdf_indirect_ref *)o)->ref_object_num, ((pdf_indirect_ref *)o)->ref_generation_num, &o1);
- pdfi_countdown(o);
- if (code < 0) {
- if (code == gs_error_VMerror)
- return code;
- return 0;
- }
- o = o1;
- }
-
- code = pdfi_gsave(ctx);
- if (code < 0) {
- pdfi_countdown(o);
- return code;
- }
-
- if (o->type == PDF_ARRAY) {
- pdf_array *a = (pdf_array *)o;
-
- for (i=0;i < pdfi_array_size(a); i++) {
- pdf_indirect_ref *r;
- code = pdfi_array_get_no_deref(ctx, a, i, (pdf_obj **)&r);
- if (code < 0)
- goto page_error;
- if (r->type == PDF_DICT) {
- code = pdfi_interpret_content_stream(ctx, (pdf_dict *)r, page_dict);
- pdfi_countdown(r);
- if (code < 0)
- goto page_error;
- } else {
- if (r->type != PDF_INDIRECT) {
- pdfi_countdown(r);
- code = gs_note_error(gs_error_typecheck);
- goto page_error;
- } else {
- if (r->ref_object_num == page_dict->object_num) {
- pdfi_countdown(r);
- code = gs_note_error(gs_error_circular_reference);
- goto page_error;
- }
- code = pdfi_dereference(ctx, r->ref_object_num, r->ref_generation_num, &o1);
- pdfi_countdown(r);
- if (code < 0) {
- if (code != gs_error_VMerror || ctx->pdfstoponerror == false)
- code = 0;
- goto page_error;
- }
- if (o1->type != PDF_DICT) {
- pdfi_countdown(o1);
- code = gs_note_error(gs_error_typecheck);
- goto page_error;
- }
- code = pdfi_interpret_content_stream(ctx, (pdf_dict *)o1, page_dict);
- pdfi_countdown(o1);
- if (code < 0) {
- if (code == gs_error_VMerror || ctx->pdfstoponerror == true)
- goto page_error;
- }
- }
- }
- }
- } else {
- if (o->type == PDF_DICT) {
- code = pdfi_interpret_content_stream(ctx, (pdf_dict *)o, page_dict);
- } else {
- pdfi_countdown(o);
- return_error(gs_error_typecheck);
- }
- }
-page_error:
- pdfi_grestore(ctx);
- pdfi_countdown(o);
- return code;
-}
-
-static int pdfi_render_page(pdf_context *ctx, uint64_t page_num)
-{
- int code, code1=0;
- uint64_t page_offset = 0;
- pdf_dict *page_dict = NULL;
- bool uses_transparency = false;
- bool page_group_known = false;
- int page_index = page_num >> 3;
- char page_bit = 0x80 >> (page_num % 8);
- stream_save local_entry_save;
- pdf_dict *group_dict = NULL;
-
- if (page_num > ctx->num_pages)
- return_error(gs_error_rangecheck);
-
- if (ctx->pdfdebug)
- dmprintf1(ctx->memory, "%% Processing Page %"PRIi64" content stream\n", page_num + 1);
-
- code = pdfi_loop_detector_mark(ctx);
- if (code < 0)
- return code;
-
- code = pdfi_loop_detector_add_object(ctx, ctx->Pages->object_num);
- if (code < 0) {
- pdfi_loop_detector_cleartomark(ctx);
- goto exit2;
- }
-
- code = pdfi_get_page_dict(ctx, ctx->Pages, page_num, &page_offset, &page_dict, NULL);
- pdfi_loop_detector_cleartomark(ctx);
- if (code < 0) {
- if (code == gs_error_VMerror || ctx->pdfstoponerror)
- goto exit2;
- code = 0;
- goto exit2;
- }
-
- if (code > 0) {
- code = gs_note_error(gs_error_unknownerror);
- goto exit2;
- }
-
- code = pdfi_set_media_size(ctx, page_dict);
- if (code < 0) {
- goto exit2;
- }
-
- code = pdfi_dict_knownget_type(ctx, page_dict, "Group", PDF_DICT, (pdf_obj **)&group_dict);
- if (code < 0)
- goto exit2;
- if (group_dict != NULL)
- page_group_known = true;
-
- pdfi_countdown(ctx->CurrentPageDict);
- ctx->CurrentPageDict = page_dict;
- pdfi_countup(ctx->CurrentPageDict);
-
- code = gs_setstrokeconstantalpha(ctx->pgs, 1.0);
- code = gs_setfillconstantalpha(ctx->pgs, 1.0);
- code = gs_setalphaisshape(ctx->pgs, 0);
- code = gs_setblendmode(ctx->pgs, BLEND_MODE_Compatible);
- code = gs_settextknockout(ctx->pgs, true);
- code = gs_settextspacing(ctx->pgs, (double)0.0);
- code = gs_settextleading(ctx->pgs, (double)0.0);
- gs_settextrenderingmode(ctx->pgs, 0);
- code = gs_setwordspacing(ctx->pgs, (double)0.0);
- code = gs_settexthscaling(ctx->pgs, (double)100.0);
- ctx->TextBlockDepth = 0;
-
- if (ctx->pgs->set_transfer.red == 0x00) {
- ctx->DefaultTransfers[0].proc = gs_identity_transfer;
- memset(ctx->DefaultTransfers[0].values, 0x00, transfer_map_size * sizeof(frac));
- } else {
- ctx->DefaultTransfers[0].proc = ctx->pgs->set_transfer.red->proc;
- memcpy(ctx->DefaultTransfers[0].values, ctx->pgs->set_transfer.red->values, transfer_map_size * sizeof(frac));
- }
- if (ctx->pgs->set_transfer.green == 0x00) {
- ctx->DefaultTransfers[1].proc = gs_identity_transfer;
- memset(ctx->DefaultTransfers[1].values, 0x00, transfer_map_size * sizeof(frac));
- } else {
- ctx->DefaultTransfers[1].proc = ctx->pgs->set_transfer.green->proc;
- memcpy(ctx->DefaultTransfers[1].values, ctx->pgs->set_transfer.green->values, transfer_map_size * sizeof(frac));
- }
- if (ctx->pgs->set_transfer.blue == 0x00) {
- ctx->DefaultTransfers[2].proc = gs_identity_transfer;
- memset(ctx->DefaultTransfers[2].values, 0x00, transfer_map_size * sizeof(frac));
- } else {
- ctx->DefaultTransfers[2].proc = ctx->pgs->set_transfer.blue->proc;
- memcpy(ctx->DefaultTransfers[2].values, ctx->pgs->set_transfer.blue->values, transfer_map_size * sizeof(frac));
- }
- if (ctx->pgs->set_transfer.gray == 0x00) {
- ctx->DefaultTransfers[3].proc = gs_identity_transfer;
- memset(ctx->DefaultTransfers[3].values, 0x00, transfer_map_size * sizeof(frac));
- } else {
- ctx->DefaultTransfers[3].proc = ctx->pgs->set_transfer.gray->proc;
- memcpy(ctx->DefaultTransfers[3].values, ctx->pgs->set_transfer.gray->values, transfer_map_size * sizeof(frac));
- }
- if (ctx->pgs->black_generation == 0x00) {
- ctx->DefaultBG.proc = gs_identity_transfer;
- memset(ctx->DefaultBG.values, 0x00, transfer_map_size * sizeof(frac));
- } else {
- ctx->DefaultBG.proc = ctx->pgs->black_generation->proc;
- memcpy(ctx->DefaultBG.values, ctx->pgs->black_generation->values, transfer_map_size * sizeof(frac));
- }
- if (ctx->pgs->undercolor_removal == 0x00) {
- ctx->DefaultUCR.proc = gs_identity_transfer;
- memset(ctx->DefaultUCR.values, 0x00, transfer_map_size * sizeof(frac));
- } else {
- ctx->DefaultUCR.proc = ctx->pgs->undercolor_removal->proc;
- memcpy(ctx->DefaultUCR.values, ctx->pgs->undercolor_removal->values, transfer_map_size * sizeof(frac));
- }
- dbgmprintf1(ctx->memory, "Current page transparency setting is %d\n", ctx->PageTransparencyArray[page_index] & page_bit ? 1 : 0);
-
- /* Force NOTRANSPARENCY here if required, until we can get it working... */
- ctx->page_has_transparency = ctx->PageTransparencyArray[page_index] & page_bit ? 1 : 0;
-
- /* Set whether device needs OP support
- * This needs to be before transparency device is pushed, if applicable
- */
- pdfi_trans_set_needs_OP(ctx);
- pdfi_oc_init(ctx);
-
- pdfi_gsave(ctx);
-
- if (ctx->page_has_transparency) {
- if (code >= 0) {
- /* We don't retain the PDF14 device */
- code = gs_push_pdf14trans_device(ctx->pgs, false, false);
- if (code >= 0) {
- if (page_group_known) {
- code = pdfi_trans_begin_page_group(ctx, page_dict, group_dict);
- /* If setting the page group failed for some reason, abandon the page group, but continue with the page */
- if (code < 0)
- page_group_known = false;
- }
- } else {
- /* Couldn't push the transparency compositor.
- * This is probably fatal, but attempt to recover by abandoning transparency
- */
- ctx->page_has_transparency = uses_transparency = false;
- }
- } else {
- /* Couldn't gsave round the transparency compositor.
- * This is probably fatal, but attempt to recover by abandoning transparency
- */
- ctx->page_has_transparency = uses_transparency = false;
- }
- }
-
- /* Init a base_pgs graphics state for Patterns
- * (this has to be after transparency device pushed, if applicable)
- */
- pdfi_set_DefaultQState(ctx, ctx->pgs);
-
- /* Save the current stream state, for later cleanup, in a local variable */
- local_save_stream_state(ctx, &local_entry_save);
- initialise_stream_save(ctx);
-
- code = pdfi_process_page_contents(ctx, page_dict);
-
- /* Put our state back the way it was before we ran the contents
- * and check if the stream had problems
- */
-#ifdef PROBE_STREAMS
- if (ctx->pgs->level > ctx->current_stream_save.gsave_level ||
- pdfi_count_stack(ctx) > ctx->current_stream_save.stack_count)
- code = ((pdf_context *)0)->first_page;
-#endif
-
- cleanup_context_interpretation(ctx, &local_entry_save);
- local_restore_stream_state(ctx, &local_entry_save);
-
- if (ctx->page_has_transparency && page_group_known) {
- code1 = pdfi_trans_end_group(ctx);
- }
-
- pdfi_countdown(ctx->CurrentPageDict);
- ctx->CurrentPageDict = NULL;
-
- if (ctx->page_has_transparency) {
- if (code1 < 0) {
- (void)gs_abort_pdf14trans_device(ctx->pgs);
- goto exit1;
- }
-
- code = gs_pop_pdf14trans_device(ctx->pgs, false);
- if (code < 0) {
- goto exit1;
- }
- }
-
- exit1:
- pdfi_grestore(ctx);
- exit2:
- pdfi_countdown(page_dict);
- pdfi_countdown(group_dict);
-
- if (code == 0)
- code = pl_finish_page(ctx->memory->gs_lib_ctx->top_of_system, ctx->pgs, 1, true);
- return code;
-}
-
static void
pdfi_report_errors(pdf_context *ctx)
{
@@ -1976,7 +550,7 @@ read_root:
if (ctx->pdfinfo)
code = pdfi_output_page_info(ctx, i);
else
- code = pdfi_render_page(ctx, i);
+ code = pdfi_page_render(ctx, i);
if (code < 0 && ctx->pdfstoponerror)
goto exit;
diff --git a/pdf/ghostpdf.h b/pdf/ghostpdf.h
index d8e2651..ac90c60 100644
--- a/pdf/ghostpdf.h
+++ b/pdf/ghostpdf.h
@@ -343,7 +343,4 @@ int pdfi_open_pdf_file(pdf_context *ctx, char *filename);
int pdfi_process_pdf_file(pdf_context *ctx, char *filename);
int pdfi_close_pdf_file(pdf_context *ctx);
-/* Transparency stuff, should be moved */
-int pdfi_check_Pattern(pdf_context *ctx, pdf_dict *pattern, pdf_dict *page_dict, bool *transparent, int *num_spots);
-
#endif
diff --git a/pdf/pdf.mak b/pdf/pdf.mak
index a9d0082..b758ca2 100644
--- a/pdf/pdf.mak
+++ b/pdf/pdf.mak
@@ -131,6 +131,9 @@ $(PDFOBJ)pdf_misc.$(OBJ): $(PDFSRC)pdf_misc.c $(PDFINCLUDES) $(PDF_MAK) $(MAKEDI
$(PDFOBJ)pdf_optcontent.$(OBJ): $(PDFSRC)pdf_optcontent.c $(PDFINCLUDES) $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_optcontent.c $(PDFO_)pdf_optcontent.$(OBJ)
+$(PDFOBJ)pdf_check.$(OBJ): $(PDFSRC)pdf_check.c $(PDFINCLUDES) $(PDF_MAK) $(MAKEDIRS)
+ $(PDFCCC) $(PDFSRC)pdf_check.c $(PDFO_)pdf_check.$(OBJ)
+
$(PDFGEN)pdfimpl.c: $(PLSRC)plimpl.c $(PDF_MAK) $(MAKEDIRS)
$(CP_) $(PLSRC)plimpl.c $(PDFGEN)pdfimpl.c
@@ -178,6 +181,7 @@ PDF_OBJS=\
$(PDFOBJ)pdf_device.$(OBJ)\
$(PDFOBJ)pdf_misc.$(OBJ)\
$(PDFOBJ)pdf_optcontent.$(OBJ)\
+ $(PDFOBJ)pdf_check.$(OBJ)\
# NB - note this is a bit squirrely. Right now the pjl interpreter is
diff --git a/pdf/pdf_check.c b/pdf/pdf_check.c
new file mode 100644
index 0000000..ea6bfb1
--- /dev/null
+++ b/pdf/pdf_check.c
@@ -0,0 +1,1043 @@
+/* Copyright (C) 2001-2019 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied,
+ modified or distributed except as expressly authorized under the terms
+ of the license contained in the file LICENSE in this distribution.
+
+ Refer to licensing information at http://www.artifex.com or contact
+ Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
+ CA 94945, U.S.A., +1(415)492-9861, for further information.
+*/
+
+/* Checks for transparency and spots for the PDF interpreter */
+
+#include "pdf_int.h"
+#include "pdf_stack.h"
+#include "pdf_page.h"
+#include "pdf_file.h"
+#include "pdf_dict.h"
+#include "pdf_array.h"
+#include "pdf_loop_detect.h"
+#include "pdf_colour.h"
+#include "pdf_trans.h"
+#include "pdf_gstate.h"
+#include "pdf_misc.h"
+#include "pdf_check.h"
+
+/* This routine is slightly misnamed, as it also checks ColorSpaces for spot colours.
+ * This is done at the page level, so we maintain a dictionary of the spot colours
+ * encountered so far, which we consult before adding any new ones.
+ */
+static int pdfi_check_Resources_for_transparency(pdf_context *ctx, pdf_dict *Resources_dict, pdf_dict *page_dict, bool *transparent, int *num_spots);
+
+/* For performance and resource reasons we do not want to install the transparency blending
+ * compositor unless we need it. Similarly, if a device handles spot colours it can minimise
+ * memory usage if it knows ahead of time how many spot colours there will be.
+ *
+ * The PDF interpreter written in PostScript performed these as two separate tasks, on opening
+ * a PDF file it would count spot colour usage and then for each page it would chek if the page
+ * used any transparency. The code below is used to check for both transparency and spot colours.
+ * If the int pointer to num_spots is NULL then we aren't interested in spot colours (not supported
+ * by the device), if the int pointer to transparent is NULL then we aren't interested in transparency
+ * (-dNOTRANSPARENCY is set).
+ *
+ * Currenlty the code is run when we open the PDF file, the existence of transparency on any given
+ * page is recorded in a bit array for later use. If it turns out that checking every page when we
+ * open the file is a performance burden then we could do it on a per-page basis instead. NB if
+ * the device supports spot colours then we do need to scan the file before starting any page.
+ *
+ * The technique is fairly straight-forward, we start with each page, and open its Resources
+ * dictionary, we then check by type each possible resource. Some resources (eg Pattern, XObject)
+ * can themselves contain Resources, in which case we recursively check that dictionary. Note; not
+ * all Resource types need to be checked for both transparency and spot colours, some types can
+ * only contain one or the other.
+ *
+ * Routines with the name pdfi_check_xxx_dict are intended to check a Resource dictionary entry, this
+ * will be a dictioanry of names and values, where the values are objects of the given Resource type.
+ *
+ */
+
+/*
+ * Check the Resources dictionary ColorSpace entry. pdfi_check_ColorSpace_for_spots is defined
+ * in pdf_colour.c
+ */
+static int pdfi_check_ColorSpace_dict(pdf_context *ctx, pdf_dict *cspace_dict, pdf_dict *page_dict, int *num_spots)
+{
+ int code, i, index;
+ pdf_obj *Key = NULL, *Value = NULL;
+
+ if (pdfi_dict_entries(cspace_dict) > 0) {
+ code = pdfi_loop_detector_mark(ctx); /* Mark the start of the ColorSpace dictionary loop */
+ if (code < 0)
+ return code;
+
+ code = pdfi_dict_first(ctx, cspace_dict, &Key, &Value, (void *)&index);
+ if (code < 0)
+ goto error1;
+
+ i = 1;
+ do {
+ code = pdfi_check_ColorSpace_for_spots(ctx, Value, cspace_dict, page_dict, num_spots);
+ if (code < 0)
+ goto error2;
+
+ pdfi_countdown(Key);
+ Key = NULL;
+ pdfi_countdown(Value);
+ Value = NULL;
+
+ (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the Shading dictionary loop */
+
+ code = pdfi_loop_detector_mark(ctx); /* Mark the new start of the Shading dictionary loop */
+ if (code < 0)
+ goto error1;
+
+ do {
+ if (i++ >= pdfi_dict_entries(cspace_dict)) {
+ code = 0;
+ goto transparency_exit;
+ }
+
+ code = pdfi_dict_next(ctx, cspace_dict, &Key, &Value, (void *)&index);
+ if (code == 0 && Value->type == PDF_ARRAY)
+ break;
+ pdfi_countdown(Key);
+ Key = NULL;
+ pdfi_countdown(Value);
+ Value = NULL;
+ } while(1);
+ }while (1);
+ }
+ return 0;
+
+transparency_exit:
+error2:
+ pdfi_countdown(Key);
+ pdfi_countdown(Value);
+
+error1:
+ (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the current resource loop */
+ return code;
+}
+
+/*
+ * Process an individual Shading dictionary to see if it contains a ColorSpace with a spot colour
+ */
+static int pdfi_check_Shading(pdf_context *ctx, pdf_dict *shading, pdf_dict *page_dict, int *num_spots)
+{
+ int code;
+ pdf_obj *o = NULL;
+
+ code = pdfi_dict_knownget(ctx, shading, "ColorSpace", (pdf_obj **)&o);
+ if (code > 0) {
+ code = pdfi_check_ColorSpace_for_spots(ctx, o, shading, page_dict, num_spots);
+ pdfi_countdown(o);
+ return code;
+ }
+ return 0;
+}
+
+/*
+ * Check the Resources dictionary Shading entry.
+ */
+static int pdfi_check_Shading_dict(pdf_context *ctx, pdf_dict *shading_dict, pdf_dict *page_dict, int *num_spots)
+{
+ int code, i, index;
+ pdf_obj *Key = NULL, *Value = NULL;
+
+ if (pdfi_dict_entries(shading_dict) > 0) {
+ code = pdfi_loop_detector_mark(ctx); /* Mark the start of the Shading dictionary loop */
+ if (code < 0)
+ return code;
+
+ code = pdfi_dict_first(ctx, shading_dict, &Key, &Value, (void *)&index);
+ if (code < 0 || Value->type != PDF_DICT)
+ goto error1;
+
+ i = 1;
+ do {
+ code = pdfi_check_Shading(ctx, (pdf_dict *)Value, page_dict, num_spots);
+ if (code < 0)
+ goto error2;
+
+ pdfi_countdown(Key);
+ Key = NULL;
+ pdfi_countdown(Value);
+ Value = NULL;
+
+ (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the Shading dictionary loop */
+
+ code = pdfi_loop_detector_mark(ctx); /* Mark the new start of the Shading dictionary loop */
+ if (code < 0)
+ goto error1;
+
+ do {
+ if (i++ >= pdfi_dict_entries(shading_dict)) {
+ code = 0;
+ goto transparency_exit;
+ }
+
+ code = pdfi_dict_next(ctx, shading_dict, &Key, &Value, (void *)&index);
+ if (code == 0 && Value->type == PDF_DICT)
+ break;
+ pdfi_countdown(Key);
+ Key = NULL;
+ pdfi_countdown(Value);
+ Value = NULL;
+ } while(1);
+ }while (1);
+ }
+ return 0;
+
+transparency_exit:
+error2:
+ pdfi_countdown(Key);
+ pdfi_countdown(Value);
+
+error1:
+ (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the current resource loop */
+ return code;
+}
+
+/*
+ * This routine checks an XObject to see if it contains any spot
+ * colour definitions, or transparency usage.
+ */
+static int pdfi_check_XObject(pdf_context *ctx, pdf_dict *xobject, pdf_dict *page_dict, bool *transparent, int *num_spots)
+{
+ int code = 0;
+ pdf_name *n = NULL;
+ bool known = false;
+ double f;
+
+ code = pdfi_dict_get_type(ctx, xobject, "Subtype", PDF_NAME, (pdf_obj **)&n);
+ if (code >= 0) {
+ if (pdfi_name_is((const pdf_name *)n, "Image")) {
+ pdf_obj *CS = NULL;
+
+ pdfi_countdown(n);
+ n = NULL;
+ code = pdfi_dict_known(xobject, "SMask", &known);
+ if (code >= 0) {
+ if (known == true) {
+ *transparent = true;
+ if (num_spots == NULL)
+ goto transparency_exit;
+ }
+ code = pdfi_dict_knownget_number(ctx, xobject, "SMaskInData", &f);
+ if (code > 0) {
+ code = 0;
+ if (f != 0.0)
+ *transparent = true;
+ if (num_spots == NULL)
+ goto transparency_exit;
+ }
+ /* Check the image dictionary for a ColorSpace entry, if we are checking spot names */
+ if (num_spots) {
+ code = pdfi_dict_knownget(ctx, xobject, "ColorSpace", (pdf_obj **)&CS);
+ if (code > 0) {
+ /* We don't care if there's an error here, it'll be picked up if we use the ColorSpace later */
+ (void)pdfi_check_ColorSpace_for_spots(ctx, CS, xobject, page_dict, num_spots);
+ pdfi_countdown(CS);
+ }
+ }
+ }
+ } else {
+ if (pdfi_name_is((const pdf_name *)n, "Form")) {
+ pdf_dict *group_dict = NULL, *resource_dict = NULL;
+ pdf_obj *CS = NULL;
+
+ pdfi_countdown(n);
+ code = pdfi_dict_knownget_type(ctx, xobject, "Group", PDF_DICT, (pdf_obj **)&group_dict);
+ if (code > 0) {
+ *transparent = true;
+ if (num_spots == NULL) {
+ pdfi_countdown(group_dict);
+ goto transparency_exit;
+ }
+
+ /* Start a new loop detector group to avoid this being detected in the Resources check below */
+ code = pdfi_loop_detector_mark(ctx); /* Mark the start of the XObject dictionary loop */
+ if (code > 0) {
+ code = pdfi_dict_knownget(ctx, group_dict, "CS", &CS);
+ if (code > 0)
+ /* We don't care if there's an error here, it'll be picked up if we use the ColorSpace later */
+ (void)pdfi_check_ColorSpace_for_spots(ctx, CS, group_dict, page_dict, num_spots);
+ }
+ pdfi_countdown(group_dict);
+ pdfi_countdown(CS);
+ (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the XObject dictionary loop */
+ }
+
+ code = pdfi_dict_knownget_type(ctx, xobject, "Resources", PDF_DICT, (pdf_obj **)&resource_dict);
+ if (code > 0) {
+ code = pdfi_check_Resources_for_transparency(ctx, resource_dict, page_dict, transparent, num_spots);
+ pdfi_countdown(resource_dict);
+ if (code < 0)
+ goto transparency_exit;
+ }
+ } else
+ pdfi_countdown(n);
+ }
+ }
+
+ return 0;
+
+transparency_exit:
+ return code;
+}
+
+/*
+ * Check the Resources dictionary XObject entry.
+ */
+static int pdfi_check_XObject_dict(pdf_context *ctx, pdf_dict *xobject_dict, pdf_dict *page_dict, bool *transparent, int *num_spots)
+{
+ int code, i, index;
+ pdf_obj *Key = NULL, *Value = NULL; //, *o = NULL;
+
+ if (pdfi_dict_entries(xobject_dict) > 0) {
+ code = pdfi_loop_detector_mark(ctx); /* Mark the start of the XObject dictionary loop */
+ if (code < 0)
+ return code;
+
+ code = pdfi_dict_first(ctx, xobject_dict, &Key, &Value, (void *)&index);
+ if (code < 0 || Value->type != PDF_DICT)
+ goto error1;
+
+ i = 1;
+ do {
+ code = pdfi_check_XObject(ctx, (pdf_dict *)Value, page_dict, transparent, num_spots);
+ if (code < 0)
+ goto error2;
+
+ (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the XObject dictionary loop */
+
+ code = pdfi_loop_detector_mark(ctx); /* Mark the new start of the XObject dictionary loop */
+ if (code < 0)
+ goto error1;
+
+ pdfi_countdown(Key);
+ Key = NULL;
+ pdfi_countdown(Value);
+ Value = NULL;
+
+ do {
+ if (i++ >= pdfi_dict_entries(xobject_dict)) {
+ code = 0;
+ goto transparency_exit;
+ }
+
+ code = pdfi_dict_next(ctx, xobject_dict, &Key, &Value, (void *)&index);
+ if (code == 0 && Value->type == PDF_DICT)
+ break;
+ pdfi_countdown(Key);
+ Key = NULL;
+ pdfi_countdown(Value);
+ Value = NULL;
+ } while(1);
+ }while(1);
+ }
+ return 0;
+
+transparency_exit:
+error2:
+ pdfi_countdown(Key);
+ pdfi_countdown(Value);
+
+error1:
+ (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the current resource loop */
+ return code;
+}
+
+/*
+ * This routine checks an ExtGState dictionary to see if it contains any spot
+ * colour definitions, or transparency usage.
+ */
+static int pdfi_check_ExtGState(pdf_context *ctx, pdf_dict *extgstate_dict, pdf_dict *page_dict, bool *transparent, int *num_spots)
+{
+ int code;
+ pdf_obj *o = NULL;
+ double f;
+
+ if (pdfi_dict_entries(extgstate_dict) > 0) {
+ /* Check SMask first, because if we test spot colours first we can exit as
+ * soon as we detect transparency.
+ */
+ code = pdfi_dict_knownget(ctx, extgstate_dict, "SMask", &o);
+ if (code > 0) {
+ if (o->type == PDF_NAME) {
+ if (!pdfi_name_is((pdf_name *)o, "None")) {
+ pdfi_countdown(o);
+ *transparent = true;
+ return 0;
+ }
+ } else {
+ if (o->type == PDF_DICT) {
+ pdf_obj *G = NULL;
+
+ *transparent = true;
+
+ if (num_spots != NULL) {
+ /* Check if the SMask has a /G (Group) */
+ code = pdfi_dict_knownget(ctx, (pdf_dict *)o, "G", &G);
+ if (code > 0) {
+ code = pdfi_check_XObject(ctx, (pdf_dict *)G, page_dict, transparent, num_spots);
+ pdfi_countdown(G);
+ }
+ }
+ pdfi_countdown(o);
+ return code;
+ }
+ }
+ }
+ pdfi_countdown(o);
+ o = NULL;
+
+ code = pdfi_dict_knownget_type(ctx, extgstate_dict, "BM", PDF_NAME, &o);
+ if (code > 0) {
+ if (!pdfi_name_is((pdf_name *)o, "Normal")) {
+ if (!pdfi_name_is((pdf_name *)o, "Compatible")) {
+ pdfi_countdown(o);
+ *transparent = true;
+ return 0;
+ }
+ }
+ }
+ pdfi_countdown(o);
+ o = NULL;
+
+ code = pdfi_dict_knownget_number(ctx, extgstate_dict, "CA", &f);
+ if (code > 0) {
+ if (f != 1.0) {
+ *transparent = true;
+ return 0;
+ }
+ }
+
+ code = pdfi_dict_knownget_number(ctx, extgstate_dict, "ca", &f);
+ if (code > 0) {
+ if (f != 1.0) {
+ *transparent = true;
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * Check the Resources dictionary ExtGState entry.
+ */
+static int pdfi_check_ExtGState_dict(pdf_context *ctx, pdf_dict *extgstate_dict, pdf_dict *page_dict, bool *transparent, int *num_spots)
+{
+ int code, i, index;
+ pdf_obj *Key = NULL, *Value = NULL;
+
+ if (pdfi_dict_entries(extgstate_dict) > 0) {
+ code = pdfi_loop_detector_mark(ctx); /* Mark the start of the ColorSpace dictionary loop */
+ if (code < 0)
+ return code;
+
+ code = pdfi_dict_first(ctx, extgstate_dict, &Key, &Value, (void *)&index);
+ if (code < 0)
+ goto error1;
+
+ i = 1;
+ do {
+
+ (void)pdfi_check_ExtGState(ctx, (pdf_dict *)Value, page_dict, transparent, num_spots);
+ if (*transparent == true && num_spots == NULL)
+ goto transparency_exit;
+
+ pdfi_countdown(Key);
+ Key = NULL;
+ pdfi_countdown(Value);
+ Value = NULL;
+
+ (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the ExtGState dictionary loop */
+
+ code = pdfi_loop_detector_mark(ctx); /* Mark the new start of the ExtGState dictionary loop */
+ if (code < 0)
+ goto error1;
+
+ do {
+ if (i++ >= pdfi_dict_entries(extgstate_dict)) {
+ code = 0;
+ goto transparency_exit;
+ }
+
+ code = pdfi_dict_next(ctx, extgstate_dict, &Key, &Value, (void *)&index);
+ if (code == 0 && Value->type == PDF_DICT)
+ break;
+ pdfi_countdown(Key);
+ Key = NULL;
+ pdfi_countdown(Value);
+ Value = NULL;
+ } while(1);
+ }while (1);
+ }
+ return 0;
+
+transparency_exit:
+ pdfi_countdown(Key);
+ pdfi_countdown(Value);
+
+error1:
+ (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the current resource loop */
+ return code;
+}
+
+/*
+ * This routine checks a Pattern dictionary to see if it contains any spot
+ * colour definitions, or transparency usage.
+ */
+int pdfi_check_Pattern(pdf_context *ctx, pdf_dict *pattern, pdf_dict *page_dict, bool *transparent, int *num_spots)
+{
+ int code = 0;
+ pdf_obj *o = NULL;
+
+ if (num_spots != NULL) {
+ code = pdfi_dict_knownget_type(ctx, pattern, "Shading", PDF_DICT, &o);
+ if (code > 0)
+ (void)pdfi_check_Shading(ctx, (pdf_dict *)o, page_dict, num_spots);
+ pdfi_countdown(o);
+ o = NULL;
+ }
+
+ code = pdfi_dict_knownget_type(ctx, pattern, "Resources", PDF_DICT, &o);
+ if (code > 0)
+ (void)pdfi_check_Resources_for_transparency(ctx, (pdf_dict *)o, page_dict, transparent, num_spots);
+ pdfi_countdown(o);
+ o = NULL;
+ if (*transparent == true && num_spots == NULL)
+ goto transparency_exit;
+
+ code = pdfi_dict_knownget_type(ctx, pattern, "ExtGState", PDF_DICT, &o);
+ if (code > 0)
+ (void)pdfi_check_ExtGState(ctx, (pdf_dict *)o, page_dict, transparent, num_spots);
+ pdfi_countdown(o);
+ o = NULL;
+
+transparency_exit:
+ return 0;
+}
+
+/*
+ * Check the Resources dictionary Pattern entry.
+ */
+static int pdfi_check_Pattern_dict(pdf_context *ctx, pdf_dict *pattern_dict, pdf_dict *page_dict, bool *transparent, int *num_spots)
+{
+ int code, i, index;
+ pdf_obj *Key = NULL, *Value = NULL;
+
+ if (pdfi_dict_entries(pattern_dict) > 0) {
+ code = pdfi_loop_detector_mark(ctx); /* Mark the start of the Pattern dictionary loop */
+ if (code < 0)
+ return code;
+
+ code = pdfi_dict_first(ctx, pattern_dict, &Key, &Value, (void *)&index);
+ if (code < 0)
+ goto error1;
+
+ if (Value->type != PDF_DICT)
+ goto transparency_exit;
+
+ i = 1;
+ do {
+ code = pdfi_check_Pattern(ctx, (pdf_dict *)Value, page_dict, transparent, num_spots);
+ if (code < 0)
+ goto transparency_exit;
+
+ pdfi_countdown(Key);
+ Key = NULL;
+ pdfi_countdown(Value);
+ Value = NULL;
+ (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the Shading dictionary loop */
+
+ code = pdfi_loop_detector_mark(ctx); /* Mark the new start of the Shading dictionary loop */
+ if (code < 0)
+ goto error1;
+
+ do {
+ if (i++ >= pdfi_dict_entries(pattern_dict)) {
+ code = 0;
+ goto transparency_exit;
+ }
+
+ code = pdfi_dict_next(ctx, pattern_dict, &Key, &Value, (void *)&index);
+ if (code == 0 && Value->type == PDF_DICT)
+ break;
+ pdfi_countdown(Key);
+ Key = NULL;
+ pdfi_countdown(Value);
+ Value = NULL;
+ } while(1);
+ }while (1);
+ }
+ return 0;
+
+transparency_exit:
+ pdfi_countdown(Key);
+ pdfi_countdown(Value);
+
+error1:
+ (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the current resource loop */
+ return code;
+}
+
+/*
+ * This routine checks a Font dictionary to see if it contains any spot
+ * colour definitions, or transparency usage.
+ */
+static int pdfi_check_Font(pdf_context *ctx, pdf_dict *font, pdf_dict *page_dict, bool *transparent, int *num_spots)
+{
+ int code = 0;
+ pdf_obj *o = NULL;
+
+ code = pdfi_dict_knownget_type(ctx, font, "Subtype", PDF_NAME, &o);
+ if (code > 0) {
+ if (pdfi_name_is((pdf_name *)o, "Type3")) {
+ pdfi_countdown(o);
+ o = NULL;
+
+ code = pdfi_dict_knownget_type(ctx, font, "Resources", PDF_DICT, &o);
+ if (code > 0)
+ (void)pdfi_check_Resources_for_transparency(ctx, (pdf_dict *)o, page_dict, transparent, num_spots);
+ }
+ }
+ pdfi_countdown(o);
+ o = NULL;
+
+ return 0;
+}
+
+/*
+ * Check the Resources dictionary Font entry.
+ */
+static int pdfi_check_Font_dict(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *page_dict, bool *transparent, int *num_spots)
+{
+ int code, i, index;
+ pdf_obj *Key = NULL, *Value = NULL;
+
+ if (pdfi_dict_entries(font_dict) > 0) {
+ code = pdfi_loop_detector_mark(ctx); /* Mark the start of the Font dictionary loop */
+ if (code < 0)
+ return code;
+
+ code = pdfi_dict_first(ctx, font_dict, &Key, &Value, (void *)&index);
+ if (code < 0)
+ goto error1;
+
+ i = 1;
+ do {
+ code = pdfi_check_Font(ctx, (pdf_dict *)Value, page_dict, transparent, num_spots);
+
+ pdfi_countdown(Key);
+ Key = NULL;
+ pdfi_countdown(Value);
+ Value = NULL;
+
+ (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the Font dictionary loop */
+
+ code = pdfi_loop_detector_mark(ctx); /* Mark the new start of the Font dictionary loop */
+ if (code < 0)
+ goto error1;
+
+ do {
+ if (i++ >= pdfi_dict_entries(font_dict)) {
+ code = 0;
+ goto transparency_exit;
+ }
+
+ code = pdfi_dict_next(ctx, font_dict, &Key, &Value, (void *)&index);
+ if (code == 0 && Value->type == PDF_DICT)
+ break;
+ pdfi_countdown(Key);
+ Key = NULL;
+ pdfi_countdown(Value);
+ Value = NULL;
+ } while(1);
+ }while (1);
+ }
+ return 0;
+
+transparency_exit:
+ pdfi_countdown(Key);
+ pdfi_countdown(Value);
+
+error1:
+ (void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the current resource loop */
+ return code;
+}
+
+static int pdfi_check_Resources_for_transparency(pdf_context *ctx, pdf_dict *Resources_dict, pdf_dict *page_dict, bool *transparent, int *num_spots)
+{
+ int code;
+ pdf_obj *d = NULL;
+
+ /* First up, check any colour spaces, for new spot colours.
+ * We only do this if asked because its expensive. num_spots being NULL
+ * means we aren't interested in spot colours (not a DeviceN or Separation device)
+ */
+ if (num_spots != NULL) {
+ code = pdfi_dict_knownget_type(ctx, Resources_dict, "ColorSpace", PDF_DICT, &d);
+ if (code > 0)
+ (void)pdfi_check_ColorSpace_dict(ctx, (pdf_dict *)d, page_dict, num_spots);
+
+ pdfi_countdown(d);
+ d = NULL;
+
+ code = pdfi_dict_knownget_type(ctx, Resources_dict, "Shading", PDF_DICT, &d);
+ if (code > 0)
+ (void)pdfi_check_Shading_dict(ctx, (pdf_dict *)d, page_dict, num_spots);
+ pdfi_countdown(d);
+ d = NULL;
+ }
+
+ code = pdfi_dict_knownget_type(ctx, Resources_dict, "XObject", PDF_DICT, &d);
+ if (code > 0)
+ (void)pdfi_check_XObject_dict(ctx, (pdf_dict *)d, page_dict, transparent, num_spots);
+ pdfi_countdown(d);
+ d = NULL;
+
+ code = pdfi_dict_knownget_type(ctx, Resources_dict, "Pattern", PDF_DICT, &d);
+ if (code > 0)
+ (void)pdfi_check_Pattern_dict(ctx, (pdf_dict *)d, page_dict, transparent, num_spots);
+ pdfi_countdown(d);
+ d = NULL;
+
+ code = pdfi_dict_knownget_type(ctx, Resources_dict, "Font", PDF_DICT, &d);
+ if (code > 0)
+ (void)pdfi_check_Font_dict(ctx, (pdf_dict *)d, page_dict, transparent, num_spots);
+ /* From this point onwards, if we detect transparency (or have already detected it) we
+ * can exit, we have already counted up any spot colours.
+ */
+ pdfi_countdown(d);
+ d = NULL;
+
+ code = pdfi_dict_knownget_type(ctx, Resources_dict, "ExtGState", PDF_DICT, &d);
+ if (code > 0)
+ (void)pdfi_check_ExtGState_dict(ctx, (pdf_dict *)d, page_dict, transparent, num_spots);
+ pdfi_countdown(d);
+ d = NULL;
+
+ return 0;
+}
+
+static int pdfi_check_annot_for_transparency(pdf_context *ctx, pdf_dict *annot, pdf_dict *page_dict, bool *transparent, int *num_spots)
+{
+ int code;
+ pdf_name *n;
+ pdf_dict *ap = NULL, *N = NULL, *Resources = NULL;
+ double f;
+
+ /* Check #1 Does the (Normal) Appearnce stream use any Resources which include transparency.
+ * We check this first, because this also checks for spot colour spaces. Once we've done that we
+ * can exit the checks as soon as we detect transparency.
+ */
+ code = pdfi_dict_knownget_type(ctx, annot, "AP", PDF_DICT, (pdf_obj **)&ap);
+ if (code > 0)
+ {
+ code = pdfi_dict_knownget_type(ctx, ap, "N", PDF_DICT, (pdf_obj **)&N);
+ if (code > 0) {
+ code = pdfi_dict_knownget_type(ctx, N, "Resources", PDF_DICT, (pdf_obj **)&Resources);
+ if (code > 0)
+ code = pdfi_check_Resources_for_transparency(ctx, (pdf_dict *)Resources, page_dict, transparent, num_spots);
+ }
+ }
+ pdfi_countdown(ap);
+ pdfi_countdown(N);
+ pdfi_countdown(Resources);
+ if (code < 0)
+ return code;
+ /* We've checked the Resources, and nothing else in an annotation can define spot colours, so
+ * if we detected transparency in the Resources we need not check further.
+ */
+ if (*transparent == true)
+ return 0;
+
+ code = pdfi_dict_get_type(ctx, annot, "Subtype", PDF_NAME, (pdf_obj **)&n);
+ if (code < 0) {
+ if (ctx->pdfstoponerror)
+ return code;
+ } else {
+ /* Check #2, Highlight annotations are always preformed with transparency */
+ if (pdfi_name_is((const pdf_name *)n, "Highlight")) {
+ pdfi_countdown(n);
+ *transparent = true;
+ return 0;
+ }
+ pdfi_countdown(n);
+ n = NULL;
+
+ /* Check #3 Blend Mode (BM) not being 'Normal' or 'Compatible' */
+ code = pdfi_dict_knownget_type(ctx, annot, "BM", PDF_NAME, (pdf_obj **)&n);
+ if (code > 0) {
+ if (!pdfi_name_is((const pdf_name *)n, "Normal")) {
+ if (!pdfi_name_is((const pdf_name *)n, "Compatible")) {
+ pdfi_countdown(n);
+ *transparent = true;
+ return 0;
+ }
+ }
+ code = 0;
+ }
+ pdfi_countdown(n);
+ if (code < 0)
+ return code;
+
+ /* Check #4 stroke constant alpha (CA) is not 1 (100% opaque) */
+ code = pdfi_dict_knownget_number(ctx, annot, "CA", &f);
+ if (code > 0) {
+ if (f != 1.0) {
+ *transparent = true;
+ return 0;
+ }
+ }
+ if (code < 0)
+ return code;
+
+ /* Check #5 non-stroke constant alpha (ca) is not 1 (100% opaque) */
+ code = pdfi_dict_knownget_number(ctx, annot, "ca", &f);
+ if (code > 0) {
+ if (f != 1.0) {
+ *transparent = true;
+ return 0;
+ }
+ }
+ if (code < 0)
+ return code;
+ }
+
+ return 0;
+}
+
+static int pdfi_check_Annots_for_transparency(pdf_context *ctx, pdf_array *annots_array, pdf_dict *page_dict, bool *transparent, int *num_spots)
+{
+ int i, code = 0;
+ pdf_dict *annot = NULL;
+
+ for (i=0; i < pdfi_array_size(annots_array); i++) {
+ code = pdfi_array_get_type(ctx, annots_array, (uint64_t)i, PDF_DICT, (pdf_obj **)&annot);
+ if (code > 0) {
+ code = pdfi_check_annot_for_transparency(ctx, annot, page_dict, transparent, num_spots);
+ if (code < 0 && ctx->pdfstoponerror)
+ goto exit;
+
+ /* If we've found transparency, and don't need to continue checkign for spot colours
+ * just exit as fast as possible.
+ */
+ if (*transparent == true && num_spots == NULL)
+ goto exit;
+
+ pdfi_countdown(annot);
+ annot = NULL;
+ }
+ }
+exit:
+ pdfi_countdown(annot);
+ return code;
+}
+
+int pdfi_check_transparency_spots(pdf_context *ctx)
+{
+ int code = 0;
+
+ /* Loop round all the pages looking for spot colours and transparency. We only check
+ * for spot colours if the device is capable of spot colours (the code checks). We
+ * only store the transparency setting if NOTRANSPARENCY is not set
+ */
+ if (ctx->num_pages) {
+ pdf_dict *page_dict = NULL;
+ uint64_t page_offset = 0;
+ bool uses_transparency = false;
+ int spots = 0;
+ uint64_t ix;
+
+ int bytes = (int)ceil((float)ctx->num_pages / 8.0f);
+ ctx->PageTransparencyArray = (char *)gs_alloc_bytes(ctx->memory, bytes, "pdfi_process_file, allocate page transparency tracking array");
+ memset(ctx->PageTransparencyArray, 0x00, bytes);
+
+ code = pdfi_alloc_object(ctx, PDF_DICT, 32, (pdf_obj **)&ctx->SpotNames);
+ if (code < 0)
+ goto exit;
+
+ pdfi_countup(ctx->SpotNames);
+
+ for (ix=0;ix < ctx->num_pages;ix++) {
+ if (ctx->pdfdebug)
+ dmprintf1(ctx->memory, "%% Checking Page %"PRIi64" for transparency and spot plates\n", ix + 1);
+
+ uses_transparency = false;
+
+ /* Get the page dictionary */
+ code = pdfi_loop_detector_mark(ctx);
+ if (code < 0)
+ goto exit;
+
+ code = pdfi_loop_detector_add_object(ctx, ctx->Pages->object_num);
+ if (code < 0) {
+ pdfi_loop_detector_cleartomark(ctx);
+ goto exit;
+ }
+
+ page_offset = 0;
+ code = pdfi_get_page_dict(ctx, ctx->Pages, ix, &page_offset, &page_dict, NULL);
+ pdfi_loop_detector_cleartomark(ctx);
+ if (code < 0) {
+ if (code == gs_error_VMerror || ctx->pdfstoponerror)
+ goto exit;
+ return 0;
+ }
+
+ if (code > 0) {
+ /* This can happen if the number of declared pages (/Count) is larger than the number of pages in the Pages array
+ * We'll ignore that for the purposes of transparency checking. If the user tries to render this
+ * page it'll fail in the page rendering code.
+ */
+ pdfi_countdown(page_dict);
+ page_dict = NULL;
+ break;
+ }
+
+ /* Check the page dictionary for spots and transparency */
+ code = pdfi_check_page_transparency(ctx, page_dict, &uses_transparency, &spots);
+ if (code < 0) {
+ pdfi_countdown(ctx->SpotNames);
+ pdfi_countdown(page_dict);
+ ctx->SpotNames = NULL;
+ goto exit;
+ }
+ if (uses_transparency && !ctx->notransparency) {
+ uint64_t index = ix >> 3;
+ char value = 0x80 >> (ix % 8);
+
+ ctx->PageTransparencyArray[index] |= value;
+ }
+ pdfi_countdown(page_dict);
+ page_dict = NULL;
+ }
+
+ pdfi_countdown(ctx->SpotNames);
+ ctx->SpotNames = NULL;
+
+ /* If there are spot colours (and by inference, the device renders spot plates) then
+ * send the number of Spots to the device, so it can setup correctly.
+ */
+ if (spots > 0) {
+ gs_c_param_list_write(&ctx->pdfi_param_list, ctx->memory);
+ param_write_int((gs_param_list *)&ctx->pdfi_param_list, "PageSpotColors", &spots);
+ gs_c_param_list_read(&ctx->pdfi_param_list);
+ code = gs_putdeviceparams(ctx->pgs->device, (gs_param_list *)&ctx->pdfi_param_list);
+ if (code > 0) {
+ /* The device was closed, we need to reopen it */
+ code = gs_setdevice_no_erase(ctx->pgs, ctx->pgs->device);
+ if (code < 0) {
+ if (uses_transparency)
+ (void)gs_abort_pdf14trans_device(ctx->pgs);
+ pdfi_countdown(ctx->SpotNames);
+ pdfi_countdown(page_dict);
+ goto exit;
+ }
+ gs_erasepage(ctx->pgs);
+ }
+ }
+ }
+exit:
+ return code;
+}
+
+/* From the original PDF interpreter written in PostScript:
+ * Note: we deliberately don't check to see whether a Group is defined,
+ * because Adobe Illustrator 10 (and possibly other applications) define
+ * a page-level group whether transparency is actually used or not.
+ * Ignoring the presence of Group is justified because, in the absence
+ * of any other transparency features, they have no effect.
+ */
+int pdfi_check_page_transparency(pdf_context *ctx, pdf_dict *page_dict, bool *transparent, int *spots)
+{
+ int code;
+ pdf_obj *d = NULL;
+ int num_spots = 0;
+ pdf_dict *group_dict = NULL;
+
+ /* Note that we don't reset 'spots' to 0 because these accumulate across pages */
+ *transparent = false;
+
+ ctx->spot_capable_device = false;
+ gs_c_param_list_read(&ctx->pdfi_param_list);
+ code = param_read_int((gs_param_list *)&ctx->pdfi_param_list, "PageSpotColors", &ctx->spot_capable_device);
+ if (code < 0)
+ return code;
+ if (code > 0)
+ ctx->spot_capable_device = 0;
+ else
+ ctx->spot_capable_device = 1;
+
+ /* Check if the page dictionary has a page Group entry */
+ code = pdfi_dict_knownget_type(ctx, page_dict, "Group", PDF_DICT, (pdf_obj **)&group_dict);
+ if (code > 0) {
+ pdf_obj *CS = NULL;
+
+ /* Page group means the page is transparent but we ignore it for the purposes
+ * of transparency detection. See above.
+ */
+ if (ctx->spot_capable_device) {
+ /* Check the Group to see if it has a ColorSpace (CS) and if it
+ * does whether it has any spot colours */
+ code = pdfi_dict_knownget(ctx, group_dict, "CS", &CS);
+ if (code > 0) {
+ code = pdfi_check_ColorSpace_for_spots(ctx, CS, group_dict, page_dict, spots);
+ if (code < 0 && ctx->pdfstoponerror) {
+ pdfi_countdown(CS);
+ pdfi_countdown(group_dict);
+ pdfi_countdown(ctx->SpotNames);
+ return code;
+ }
+ pdfi_countdown(CS);
+ }
+ }
+ pdfi_countdown(group_dict);
+ }
+
+ /* Now check any Resources dictionary in the Page dictionary */
+ code = pdfi_dict_get_type(ctx, page_dict, "Resources", PDF_DICT, &d);
+ if (code >= 0) {
+ if (ctx->spot_capable_device)
+ code = pdfi_check_Resources_for_transparency(ctx, (pdf_dict *)d, page_dict, transparent, &num_spots);
+ else
+ code = pdfi_check_Resources_for_transparency(ctx, (pdf_dict *)d, page_dict, transparent, NULL);
+ pdfi_countdown(d);
+ if (code < 0)
+ return code;
+ }
+ if (code < 0 && code != gs_error_undefined && ctx->pdfstoponerror)
+ return code;
+
+ /* If we are drawing Annotations, check to see if the page uses any Annots */
+ if (ctx->showannots) {
+ code = pdfi_dict_get_type(ctx, page_dict, "Annots", PDF_ARRAY, &d);
+ if (code >= 0) {
+ if (ctx->spot_capable_device)
+ code = pdfi_check_Annots_for_transparency(ctx, (pdf_array *)d, page_dict, transparent, &num_spots);
+ else
+ code = pdfi_check_Annots_for_transparency(ctx, (pdf_array *)d, page_dict, transparent, NULL);
+ pdfi_countdown(d);
+ if (code < 0)
+ return code;
+ }
+ if (code < 0 && code != gs_error_undefined && ctx->pdfstoponerror)
+ return code;
+ }
+
+ if (ctx->spot_capable_device)
+ *spots += num_spots;
+ else
+ *spots = 0;
+
+ return 0;
+}
diff --git a/pdf/pdf_page.h b/pdf/pdf_check.h
similarity index 59%
copy from pdf/pdf_page.h
copy to pdf/pdf_check.h
index c1213e3..7d67447 100644
--- a/pdf/pdf_page.h
+++ b/pdf/pdf_check.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2018 Artifex Software, Inc.
+/* Copyright (C) 2001-2019 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -13,11 +13,12 @@
CA 94945, U.S.A., +1(415)492-9861, for further information.
*/
-/* Page-level operations for the PDF interpreter */
+#ifndef PDF_CHECK
+#define PDF_CHECK
-#ifndef PDF_PAGE_OPERATORS
-#define PDF_PAGE_OPERATORS
+int pdfi_check_transparency_spots(pdf_context *ctx);
+int pdfi_check_page_transparency(pdf_context *ctx, pdf_dict *page_dict, bool *transparent, int *spots);
-/* NOTE: used to have OC stuff here, moved to pdf_optcontent.h */
+int pdfi_check_Pattern(pdf_context *ctx, pdf_dict *pattern, pdf_dict *page_dict, bool *transparent, int *num_spots);
#endif
diff --git a/pdf/pdf_page.c b/pdf/pdf_page.c
index b8aef1a..d0216f8 100644
--- a/pdf/pdf_page.c
+++ b/pdf/pdf_page.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2018 Artifex Software, Inc.
+/* Copyright (C) 2001-2019 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -16,6 +16,7 @@
/* Page-level operations for the PDF interpreter */
#include "pdf_int.h"
+#include "plmain.h"
#include "pdf_stack.h"
#include "pdf_page.h"
#include "pdf_file.h"
@@ -24,13 +25,419 @@
#include "pdf_loop_detect.h"
#include "pdf_colour.h"
#include "pdf_trans.h"
+#include "pdf_gstate.h"
#include "pdf_misc.h"
+#include "pdf_optcontent.h"
-#include "gsiparm4.h"
-#include "gsiparm3.h"
+static int pdfi_process_page_contents(pdf_context *ctx, pdf_dict *page_dict)
+{
+ int i, code = 0;
+ pdf_obj *o, *o1;
-#include "gstrans.h"
+ code = pdfi_dict_get(ctx, page_dict, "Contents", &o);
+ if (code == gs_error_undefined)
+ /* Don't throw an error if there are no contents, just render nothing.... */
+ return 0;
+ if (code < 0)
+ return code;
-/* NOTE: I used to have the OC stuff here, moved it to pdf_optcontent.c
- * Maybe this file will have other things at some point, else it could be deleted.
- */
+ if (o->type == PDF_INDIRECT) {
+ if (((pdf_indirect_ref *)o)->ref_object_num == page_dict->object_num)
+ return_error(gs_error_circular_reference);
+
+ code = pdfi_dereference(ctx, ((pdf_indirect_ref *)o)->ref_object_num, ((pdf_indirect_ref *)o)->ref_generation_num, &o1);
+ pdfi_countdown(o);
+ if (code < 0) {
+ if (code == gs_error_VMerror)
+ return code;
+ return 0;
+ }
+ o = o1;
+ }
+
+ code = pdfi_gsave(ctx);
+ if (code < 0) {
+ pdfi_countdown(o);
+ return code;
+ }
+
+ if (o->type == PDF_ARRAY) {
+ pdf_array *a = (pdf_array *)o;
+
+ for (i=0;i < pdfi_array_size(a); i++) {
+ pdf_indirect_ref *r;
+ code = pdfi_array_get_no_deref(ctx, a, i, (pdf_obj **)&r);
+ if (code < 0)
+ goto page_error;
+ if (r->type == PDF_DICT) {
+ code = pdfi_interpret_content_stream(ctx, (pdf_dict *)r, page_dict);
+ pdfi_countdown(r);
+ if (code < 0)
+ goto page_error;
+ } else {
+ if (r->type != PDF_INDIRECT) {
+ pdfi_countdown(r);
+ code = gs_note_error(gs_error_typecheck);
+ goto page_error;
+ } else {
+ if (r->ref_object_num == page_dict->object_num) {
+ pdfi_countdown(r);
+ code = gs_note_error(gs_error_circular_reference);
+ goto page_error;
+ }
+ code = pdfi_dereference(ctx, r->ref_object_num, r->ref_generation_num, &o1);
+ pdfi_countdown(r);
+ if (code < 0) {
+ if (code != gs_error_VMerror || ctx->pdfstoponerror == false)
+ code = 0;
+ goto page_error;
+ }
+ if (o1->type != PDF_DICT) {
+ pdfi_countdown(o1);
+ code = gs_note_error(gs_error_typecheck);
+ goto page_error;
+ }
+ code = pdfi_interpret_content_stream(ctx, (pdf_dict *)o1, page_dict);
+ pdfi_countdown(o1);
+ if (code < 0) {
+ if (code == gs_error_VMerror || ctx->pdfstoponerror == true)
+ goto page_error;
+ }
+ }
+ }
+ }
+ } else {
+ if (o->type == PDF_DICT) {
+ code = pdfi_interpret_content_stream(ctx, (pdf_dict *)o, page_dict);
+ } else {
+ pdfi_countdown(o);
+ return_error(gs_error_typecheck);
+ }
+ }
+page_error:
+ pdfi_grestore(ctx);
+ pdfi_countdown(o);
+ return code;
+}
+
+static int pdfi_set_media_size(pdf_context *ctx, pdf_dict *page_dict)
+{
+ gs_c_param_list list;
+ gs_param_float_array fa;
+ pdf_array *a = NULL, *default_media = NULL;
+ float fv[2];
+ double d[4];
+ int code;
+ uint64_t i;
+ int64_t rotate = 0;
+
+ gs_c_param_list_write(&list, ctx->memory);
+
+ code = pdfi_dict_get_type(ctx, page_dict, "MediaBox", PDF_ARRAY, (pdf_obj **)&default_media);
+ if (code < 0) {
+ code = gs_erasepage(ctx->pgs);
+ return 0;
+ }
+
+ if (ctx->usecropbox) {
+ if (a != NULL)
+ pdfi_countdown(a);
+ (void)pdfi_dict_get_type(ctx, page_dict, "CropBox", PDF_ARRAY, (pdf_obj **)&a);
+ }
+ if (ctx->useartbox) {
+ if (a != NULL)
+ pdfi_countdown(a);
+ (void)pdfi_dict_get_type(ctx, page_dict, "ArtBox", PDF_ARRAY, (pdf_obj **)&a);
+ }
+ if (ctx->usebleedbox) {
+ if (a != NULL)
+ pdfi_countdown(a);
+ (void)pdfi_dict_get_type(ctx, page_dict, "BleedBox", PDF_ARRAY, (pdf_obj **)&a);
+ }
+ if (ctx->usetrimbox) {
+ if (a != NULL)
+ pdfi_countdown(a);
+ (void)pdfi_dict_get_type(ctx, page_dict, "MediaBox", PDF_ARRAY, (pdf_obj **)&a);
+ }
+ if (a == NULL)
+ a = default_media;
+
+ for (i=0;i<4;i++) {
+ code = pdfi_array_get_number(ctx, a, i, &d[i]);
+ }
+ pdfi_countdown(a);
+
+ normalize_rectangle(d);
+ memcpy(ctx->PageSize, d, 4 * sizeof(double));
+
+ code = pdfi_dict_get_int(ctx, page_dict, "Rotate", &rotate);
+
+ rotate = rotate % 360;
+
+ switch(rotate) {
+ default:
+ case 0:
+ case 360:
+ case -180:
+ case 180:
+ fv[0] = (float)(d[2] - d[0]);
+ fv[1] = (float)(d[3] - d[1]);
+ break;
+ case -90:
+ case 90:
+ case -270:
+ case 270:
+ fv[1] = (float)(d[2] - d[0]);
+ fv[0] = (float)(d[3] - d[1]);
+ break;
+ }
+
+ fa.persistent = false;
+ fa.data = fv;
+ fa.size = 2;
+
+ code = param_write_float_array((gs_param_list *)&list, ".MediaSize", &fa);
+ if (code >= 0)
+ {
+ gx_device *dev = gs_currentdevice(ctx->pgs);
+
+ gs_c_param_list_read(&list);
+ code = gs_putdeviceparams(dev, (gs_param_list *)&list);
+ if (code < 0) {
+ gs_c_param_list_release(&list);
+ return code;
+ }
+ }
+ gs_c_param_list_release(&list);
+
+ gs_initgraphics(ctx->pgs);
+
+ switch(rotate) {
+ case 0:
+ break;
+ case -270:
+ case 90:
+ gs_translate(ctx->pgs, 0, fv[1]);
+ gs_rotate(ctx->pgs, -90);
+ break;
+ case -180:
+ case 180:
+ gs_translate(ctx->pgs, fv[0], fv[1]);
+ gs_rotate(ctx->pgs, 180);
+ break;
+ case -90:
+ case 270:
+ gs_translate(ctx->pgs, fv[0], 0);
+ gs_rotate(ctx->pgs, 90);
+ break;
+ default:
+ break;
+ }
+
+ gs_translate(ctx->pgs, d[0] * -1, d[1] * -1);
+
+ code = gs_erasepage(ctx->pgs);
+ return 0;
+}
+
+int pdfi_page_render(pdf_context *ctx, uint64_t page_num)
+{
+ int code, code1=0;
+ uint64_t page_offset = 0;
+ pdf_dict *page_dict = NULL;
+ bool uses_transparency = false;
+ bool page_group_known = false;
+ int page_index = page_num >> 3;
+ char page_bit = 0x80 >> (page_num % 8);
+ stream_save local_entry_save;
+ pdf_dict *group_dict = NULL;
+
+ if (page_num > ctx->num_pages)
+ return_error(gs_error_rangecheck);
+
+ if (ctx->pdfdebug)
+ dmprintf1(ctx->memory, "%% Processing Page %"PRIi64" content stream\n", page_num + 1);
+
+ code = pdfi_loop_detector_mark(ctx);
+ if (code < 0)
+ return code;
+
+ code = pdfi_loop_detector_add_object(ctx, ctx->Pages->object_num);
+ if (code < 0) {
+ pdfi_loop_detector_cleartomark(ctx);
+ goto exit2;
+ }
+
+ code = pdfi_get_page_dict(ctx, ctx->Pages, page_num, &page_offset, &page_dict, NULL);
+ pdfi_loop_detector_cleartomark(ctx);
+ if (code < 0) {
+ if (code == gs_error_VMerror || ctx->pdfstoponerror)
+ goto exit2;
+ code = 0;
+ goto exit2;
+ }
+
+ if (code > 0) {
+ code = gs_note_error(gs_error_unknownerror);
+ goto exit2;
+ }
+
+ code = pdfi_set_media_size(ctx, page_dict);
+ if (code < 0) {
+ goto exit2;
+ }
+
+ code = pdfi_dict_knownget_type(ctx, page_dict, "Group", PDF_DICT, (pdf_obj **)&group_dict);
+ if (code < 0)
+ goto exit2;
+ if (group_dict != NULL)
+ page_group_known = true;
+
+ pdfi_countdown(ctx->CurrentPageDict);
+ ctx->CurrentPageDict = page_dict;
+ pdfi_countup(ctx->CurrentPageDict);
+
+ code = gs_setstrokeconstantalpha(ctx->pgs, 1.0);
+ code = gs_setfillconstantalpha(ctx->pgs, 1.0);
+ code = gs_setalphaisshape(ctx->pgs, 0);
+ code = gs_setblendmode(ctx->pgs, BLEND_MODE_Compatible);
+ code = gs_settextknockout(ctx->pgs, true);
+ code = gs_settextspacing(ctx->pgs, (double)0.0);
+ code = gs_settextleading(ctx->pgs, (double)0.0);
+ gs_settextrenderingmode(ctx->pgs, 0);
+ code = gs_setwordspacing(ctx->pgs, (double)0.0);
+ code = gs_settexthscaling(ctx->pgs, (double)100.0);
+ ctx->TextBlockDepth = 0;
+
+ if (ctx->pgs->set_transfer.red == 0x00) {
+ ctx->DefaultTransfers[0].proc = gs_identity_transfer;
+ memset(ctx->DefaultTransfers[0].values, 0x00, transfer_map_size * sizeof(frac));
+ } else {
+ ctx->DefaultTransfers[0].proc = ctx->pgs->set_transfer.red->proc;
+ memcpy(ctx->DefaultTransfers[0].values, ctx->pgs->set_transfer.red->values, transfer_map_size * sizeof(frac));
+ }
+ if (ctx->pgs->set_transfer.green == 0x00) {
+ ctx->DefaultTransfers[1].proc = gs_identity_transfer;
+ memset(ctx->DefaultTransfers[1].values, 0x00, transfer_map_size * sizeof(frac));
+ } else {
+ ctx->DefaultTransfers[1].proc = ctx->pgs->set_transfer.green->proc;
+ memcpy(ctx->DefaultTransfers[1].values, ctx->pgs->set_transfer.green->values, transfer_map_size * sizeof(frac));
+ }
+ if (ctx->pgs->set_transfer.blue == 0x00) {
+ ctx->DefaultTransfers[2].proc = gs_identity_transfer;
+ memset(ctx->DefaultTransfers[2].values, 0x00, transfer_map_size * sizeof(frac));
+ } else {
+ ctx->DefaultTransfers[2].proc = ctx->pgs->set_transfer.blue->proc;
+ memcpy(ctx->DefaultTransfers[2].values, ctx->pgs->set_transfer.blue->values, transfer_map_size * sizeof(frac));
+ }
+ if (ctx->pgs->set_transfer.gray == 0x00) {
+ ctx->DefaultTransfers[3].proc = gs_identity_transfer;
+ memset(ctx->DefaultTransfers[3].values, 0x00, transfer_map_size * sizeof(frac));
+ } else {
+ ctx->DefaultTransfers[3].proc = ctx->pgs->set_transfer.gray->proc;
+ memcpy(ctx->DefaultTransfers[3].values, ctx->pgs->set_transfer.gray->values, transfer_map_size * sizeof(frac));
+ }
+ if (ctx->pgs->black_generation == 0x00) {
+ ctx->DefaultBG.proc = gs_identity_transfer;
+ memset(ctx->DefaultBG.values, 0x00, transfer_map_size * sizeof(frac));
+ } else {
+ ctx->DefaultBG.proc = ctx->pgs->black_generation->proc;
+ memcpy(ctx->DefaultBG.values, ctx->pgs->black_generation->values, transfer_map_size * sizeof(frac));
+ }
+ if (ctx->pgs->undercolor_removal == 0x00) {
+ ctx->DefaultUCR.proc = gs_identity_transfer;
+ memset(ctx->DefaultUCR.values, 0x00, transfer_map_size * sizeof(frac));
+ } else {
+ ctx->DefaultUCR.proc = ctx->pgs->undercolor_removal->proc;
+ memcpy(ctx->DefaultUCR.values, ctx->pgs->undercolor_removal->values, transfer_map_size * sizeof(frac));
+ }
+ dbgmprintf1(ctx->memory, "Current page transparency setting is %d\n", ctx->PageTransparencyArray[page_index] & page_bit ? 1 : 0);
+
+ /* Force NOTRANSPARENCY here if required, until we can get it working... */
+ ctx->page_has_transparency = ctx->PageTransparencyArray[page_index] & page_bit ? 1 : 0;
+
+ /* Set whether device needs OP support
+ * This needs to be before transparency device is pushed, if applicable
+ */
+ pdfi_trans_set_needs_OP(ctx);
+ pdfi_oc_init(ctx);
+
+ pdfi_gsave(ctx);
+
+ if (ctx->page_has_transparency) {
+ if (code >= 0) {
+ /* We don't retain the PDF14 device */
+ code = gs_push_pdf14trans_device(ctx->pgs, false, false);
+ if (code >= 0) {
+ if (page_group_known) {
+ code = pdfi_trans_begin_page_group(ctx, page_dict, group_dict);
+ /* If setting the page group failed for some reason, abandon the page group, but continue with the page */
+ if (code < 0)
+ page_group_known = false;
+ }
+ } else {
+ /* Couldn't push the transparency compositor.
+ * This is probably fatal, but attempt to recover by abandoning transparency
+ */
+ ctx->page_has_transparency = uses_transparency = false;
+ }
+ } else {
+ /* Couldn't gsave round the transparency compositor.
+ * This is probably fatal, but attempt to recover by abandoning transparency
+ */
+ ctx->page_has_transparency = uses_transparency = false;
+ }
+ }
+
+ /* Init a base_pgs graphics state for Patterns
+ * (this has to be after transparency device pushed, if applicable)
+ */
+ pdfi_set_DefaultQState(ctx, ctx->pgs);
+
+ /* Save the current stream state, for later cleanup, in a local variable */
+ local_save_stream_state(ctx, &local_entry_save);
+ initialise_stream_save(ctx);
+
+ code = pdfi_process_page_contents(ctx, page_dict);
+
+ /* Put our state back the way it was before we ran the contents
+ * and check if the stream had problems
+ */
+#ifdef PROBE_STREAMS
+ if (ctx->pgs->level > ctx->current_stream_save.gsave_level ||
+ pdfi_count_stack(ctx) > ctx->current_stream_save.stack_count)
+ code = ((pdf_context *)0)->first_page;
+#endif
+
+ cleanup_context_interpretation(ctx, &local_entry_save);
+ local_restore_stream_state(ctx, &local_entry_save);
+
+ if (ctx->page_has_transparency && page_group_known) {
+ code1 = pdfi_trans_end_group(ctx);
+ }
+
+ pdfi_countdown(ctx->CurrentPageDict);
+ ctx->CurrentPageDict = NULL;
+
+ if (ctx->page_has_transparency) {
+ if (code1 < 0) {
+ (void)gs_abort_pdf14trans_device(ctx->pgs);
+ goto exit1;
+ }
+
+ code = gs_pop_pdf14trans_device(ctx->pgs, false);
+ if (code < 0) {
+ goto exit1;
+ }
+ }
+
+ exit1:
+ pdfi_grestore(ctx);
+ exit2:
+ pdfi_countdown(page_dict);
+ pdfi_countdown(group_dict);
+
+ if (code == 0)
+ code = pl_finish_page(ctx->memory->gs_lib_ctx->top_of_system, ctx->pgs, 1, true);
+ return code;
+}
diff --git a/pdf/pdf_page.h b/pdf/pdf_page.h
index c1213e3..17ab3af 100644
--- a/pdf/pdf_page.h
+++ b/pdf/pdf_page.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2018 Artifex Software, Inc.
+/* Copyright (C) 2001-2019 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -18,6 +18,6 @@
#ifndef PDF_PAGE_OPERATORS
#define PDF_PAGE_OPERATORS
-/* NOTE: used to have OC stuff here, moved to pdf_optcontent.h */
+int pdfi_page_render(pdf_context *ctx, uint64_t page_num);
#endif
diff --git a/pdf/pdf_pattern.c b/pdf/pdf_pattern.c
index 00d396b..a6f965c 100644
--- a/pdf/pdf_pattern.c
+++ b/pdf/pdf_pattern.c
@@ -31,6 +31,7 @@
#include "pdf_loop_detect.h"
#include "pdf_func.h"
#include "pdf_shading.h"
+#include "pdf_check.h"
#include "gscsepr.h"
#include "stream.h"
#include "strmio.h"
Summary of changes:
pdf/ghostpdf.c | 1433 +-------------------------------------
pdf/ghostpdf.h | 3 -
pdf/pdf.mak | 4 +
pdf/pdf_check.c | 1043 +++++++++++++++++++++++++++
base/gsstrl.h => pdf/pdf_check.h | 12 +-
pdf/pdf_optcontent.c | 20 +-
pdf/pdf_optcontent.h | 1 +
pdf/pdf_page.c | 421 ++++++++++-
pdf/pdf_page.h | 4 +-
pdf/pdf_pattern.c | 1 +
10 files changed, 1489 insertions(+), 1453 deletions(-)
create mode 100644 pdf/pdf_check.c
copy base/gsstrl.h => pdf/pdf_check.h (65%)