summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'psi/zpdfops.c')
-rw-r--r--psi/zpdfops.c690
1 files changed, 426 insertions, 264 deletions
diff --git a/psi/zpdfops.c b/psi/zpdfops.c
index 4c01de03..45bd7803 100644
--- a/psi/zpdfops.c
+++ b/psi/zpdfops.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -25,6 +25,7 @@
#include "iminst.h"
#include "dstack.h"
+#include "gsicc_profilecache.h"
#endif
#include "ghost.h"
@@ -272,51 +273,123 @@ zsaslprep(i_ctx_t *i_ctx_p)
#if defined(BUILD_PDF) && BUILD_PDF == 1
-/*
- This cannot fail. If gs doesn't have these settings it will never reach here.
- Because the lives of the string values here are all tied to the Postscript
- context, and the Postscript context *must* outlast the pdfi context, we can
- safely just take references, marking the strings as "persistent" so destroying
- the pdfi context doesn't try to free the string bodies.
- */
-static void zpdfi_populate_search_paths(i_ctx_t *i_ctx_p, pdf_context *ctx)
+static int zpdfi_populate_search_paths(i_ctx_t *i_ctx_p, pdf_context *ctx)
{
+ int code = 0;
/* This should only be called once per pdfi context
if the paths are already populated, just skip it.
*/
if (ctx->search_paths.resource_paths == NULL) {
ref *l2dictref, *grdref, *fpathref;
- int code, i;
+ int i;
const gs_file_path *pfpath = i_ctx_p->lib_path;
gs_main_instance *minst = get_minst_from_memory(imemory);
code = dict_find_string(systemdict, "pssystemparams", &l2dictref);
if (code >= 0 && r_has_type(l2dictref, t_dictionary)) {
code = dict_find_string(l2dictref, "GenericResourceDir", &grdref);
if (code >= 0 && r_has_type(grdref, t_string)) {
- ctx->search_paths.genericresourcedir.data = grdref->value.const_bytes;
+ ctx->search_paths.genericresourcedir.data = gs_alloc_bytes(ctx->memory, r_size(grdref), "zpdfi_populate_search_paths");
+ if (ctx->search_paths.genericresourcedir.data == NULL) {
+ code = gs_note_error(gs_error_VMerror);
+ goto done;
+ }
+ memcpy((char *)ctx->search_paths.genericresourcedir.data, grdref->value.const_bytes, r_size(grdref));
ctx->search_paths.genericresourcedir.size = r_size(grdref);
- ctx->search_paths.genericresourcedir.persistent = true;
+ ctx->search_paths.genericresourcedir.persistent = false;
}
}
+
ctx->search_paths.resource_paths = (gs_param_string *)gs_alloc_bytes(ctx->memory, sizeof(gs_param_string) * r_size(&pfpath->list), "array of paths");
+ if (ctx->search_paths.resource_paths == NULL) {
+ code = gs_note_error(gs_error_VMerror);
+ goto done;
+ }
+ memset(ctx->search_paths.resource_paths, 0x00, sizeof(gs_param_string) * r_size(&pfpath->list));
+
ctx->search_paths.num_resource_paths = r_size(&pfpath->list);
for (i = 0; i < r_size(&pfpath->list); i++) {
const ref *prdir = pfpath->list.value.refs + i; /* By nature, this cannot be a short/mixed array, only a "normal" array */
- ctx->search_paths.resource_paths[i].data = prdir->value.const_bytes;
+ ctx->search_paths.resource_paths[i].data = gs_alloc_bytes(ctx->memory, r_size(prdir), "zpdfi_populate_search_paths");
+ if (ctx->search_paths.resource_paths[i].data == NULL) {
+ code = gs_note_error(gs_error_VMerror);
+ goto done;
+ }
+ memcpy((char *)ctx->search_paths.resource_paths[i].data, prdir->value.const_bytes, r_size(prdir));
ctx->search_paths.resource_paths[i].size = r_size(prdir);
- ctx->search_paths.resource_paths[i].persistent = true;
+ ctx->search_paths.resource_paths[i].persistent = false;
}
code = dict_find_string(systemdict, "FONTPATH", &fpathref);
- ctx->search_paths.font_paths = (gs_param_string *)gs_alloc_bytes(ctx->memory, sizeof(gs_param_string) * r_size(fpathref), "array of font paths");
- ctx->search_paths.num_font_paths = r_size(fpathref);
- for (i = 0; i < r_size(fpathref); i++) {
- const ref *prdir = pfpath->list.value.refs + i; /* By nature, this cannot be a short/mixed array, only a "normal" array */
- ctx->search_paths.resource_paths[i].data = prdir->value.const_bytes;
- ctx->search_paths.resource_paths[i].size = r_size(prdir);
- ctx->search_paths.resource_paths[i].persistent = true;
+ if (code >= 0 && r_has_type(fpathref, t_array)) {
+ ctx->search_paths.font_paths = (gs_param_string *)gs_alloc_bytes(ctx->memory, sizeof(gs_param_string) * r_size(fpathref), "array of font paths");
+ memset(ctx->search_paths.font_paths, 0x00, sizeof(gs_param_string) * r_size(fpathref));
+
+ ctx->search_paths.num_font_paths = r_size(fpathref);
+ for (i = 0; i < r_size(fpathref); i++) {
+ const ref *prdir = fpathref->value.refs + i; /* By nature, this cannot be a short/mixed array, only a "normal" array */
+ ctx->search_paths.font_paths[i].data = gs_alloc_bytes(ctx->memory, r_size(prdir), "zpdfi_populate_search_paths");
+ if (ctx->search_paths.font_paths[i].data == NULL) {
+ code = gs_note_error(gs_error_VMerror);
+ goto done;
+ }
+ memcpy((char *)ctx->search_paths.font_paths[i].data, prdir->value.const_bytes, r_size(prdir));
+ ctx->search_paths.font_paths[i].size = r_size(prdir);
+ ctx->search_paths.font_paths[i].persistent = false;
+ }
}
ctx->search_paths.search_here_first = minst->search_here_first;
}
+done:
+ return code >= 0 ? 0 : code;
+}
+
+static int zpdfi_populate_fontmap_files(i_ctx_t *i_ctx_p, pdf_context *ctx)
+{
+ int code, i;
+ ref *fontmaps;
+
+ code = dict_find_string(systemdict, "FONTMAP", &fontmaps);
+ if (code >= 0 && r_has_type(fontmaps, t_array)) {
+ ctx->fontmapfiles = (gs_string *)gs_alloc_bytes(ctx->memory, sizeof(gs_string) * r_size(fontmaps), "array of fontmap files");
+ if (ctx->fontmapfiles != 0) {
+ memset(ctx->fontmapfiles, 0x00, sizeof(gs_string) * r_size(fontmaps));
+ ctx->num_fontmapfiles = r_size(fontmaps);
+ for (i = 0; i < r_size(fontmaps); i++) {
+ const ref *fmapfile = fontmaps->value.refs + i; /* By nature, this cannot be a short/mixed array, only a "normal" array */
+ ctx->fontmapfiles[i].data = gs_alloc_bytes(ctx->memory, r_size(fmapfile), "zpdfi_populate_fontmap_files");
+ if (ctx->fontmapfiles[i].data == NULL) {
+ code = gs_note_error(gs_error_VMerror);
+ goto done;
+ }
+ memcpy((char *)ctx->fontmapfiles[i].data, fmapfile->value.const_bytes, r_size(fmapfile));
+ ctx->fontmapfiles[i].size = r_size(fmapfile);
+ }
+ }
+ else {
+ code = gs_note_error(gs_error_VMerror);
+ goto done;
+ }
+ }
+ else if (code >= 0 && r_has_type(fontmaps, t_string)) {
+ ctx->fontmapfiles = (gs_string *)gs_alloc_bytes(ctx->memory, sizeof(gs_string), "array of fontmap files");
+ if (ctx->fontmapfiles != 0) {
+ ctx->num_fontmapfiles = 1;
+ ctx->fontmapfiles[0].data = gs_alloc_bytes(ctx->memory, r_size(fontmaps), "zpdfi_populate_fontmap_files");
+ if (ctx->fontmapfiles[0].data == NULL) {
+ code = gs_note_error(gs_error_VMerror);
+ goto done;
+ }
+ memcpy((char *)ctx->fontmapfiles[0].data, fontmaps->value.const_bytes, r_size(fontmaps));
+ ctx->fontmapfiles[0].size = r_size(fontmaps);
+ }
+ else {
+ code = gs_note_error(gs_error_VMerror);
+ goto done;
+ }
+ }
+ else
+ code = 0;
+done:
+ return code;
}
/*
@@ -329,8 +402,44 @@ typedef struct pdfctx_s {
gs_memory_t *pdf_memory; /* The 'wrapped' memory allocator used by the PDF interpreter. Not exposed to garbager */
gs_memory_t *pdf_stream_memory; /* The memory allocator used to copy the PostScript stream to pdf_stream. Not exposed to garbager */
stream *pdf_stream;
+ gsicc_profile_cache_t *profile_cache;
+ gs_memory_t *cache_memory; /* The memory allocator used to allocate the working (GC'ed) profile cache */
} pdfctx_t;
+/* There is some unfortunately necessary complication in the structure above regarding the ICC profile cache.
+ * Initially the problem was due to adding the colour space name to the 'interpreter data' part of the colour
+ * space, in order to be able to identify the case where we switch to the current colour space.
+ *
+ * This caused problems with ICC spaces, because these maintain a reference to the colour space. If the profile
+ * was stored in the PostScript profile cache (which it would be, because the profile cache is stored in the
+ * grapchis state, which we inherit from the PostScript interpreter) then it would outlive the PDF interpreter,
+ * and when we came to free the cache it would try to free the colour space, which would try to free the PDF
+ * name object, which had already been freed.
+ *
+ * To work around this we replaced the profile cache in the graphics state with the profile cache from the PDF
+ * interpreter. Now when we free the PDF profile cache, it frees the colour spaces, and the PDF names, while they
+ * are still valid.
+ *
+ * However, we then discovered that the garbage collector could reclaim the colour spaces. This happens because
+ * no GC-visible object declares it has a reference to the colour space. It doesn't matter that the colour
+ * space has been counted up, the GC frees it. Now the profile cache in pdfi is pointing to a colour space which
+ * has gone away....
+ *
+ * To get round this, we create a brand-new profile cache, using GC'ed memory (well actually the interpreter
+ * allocator, which is GC'ed for Ghostscript). When we switch to pdfi we replace the graphics state pdfi is
+ * using with the one from the PostScript environment, and at the same time we swap out the profile cache
+ * being used by that graphics state, so it uses our new one. On return to PostScript we swap them back.
+ * This allows the lifetime of the profiles in the profile cache to be correct, because they are visible to the
+ * garbage collector (the PDF context is a GC-visible object and enumerates it's member profile cache)
+ * When we finalize the PDF context we count down the profile cache which dereferences all its entries. This
+ * effectively frees the colour space (the memory may not be reclaimed yet) which calls the interpreter
+ * specific cleanup, which frees the (still valid at this point) PDF name object and sets the pointer to NULL.
+ *
+ * The net result is that we have the profiles visible to the garbage collector during their lifetime, but
+ * still have control over the cache, so we can empty it of the profiles created for pdfi when we close the
+ * PDF interpreter.
+ */
+
/* Structure descriptors */
static void pdfctx_finalize(const gs_memory_t *cmem, void *vptr);
@@ -339,11 +448,11 @@ gs_private_st_composite_final(st_pdfctx_t, pdfctx_t, "pdfctx_struct",\
static
ENUM_PTRS_BEGIN(pdfctx_enum_ptrs) return 0;
-ENUM_PTR2(0, pdfctx_t, ps_stream, pdf_stream);
+ENUM_PTR3(0, pdfctx_t, ps_stream, pdf_stream, profile_cache);
ENUM_PTRS_END
static RELOC_PTRS_BEGIN(pdfctx_reloc_ptrs);
-RELOC_PTR2(pdfctx_t, ps_stream, pdf_stream);
+RELOC_PTR3(pdfctx_t, ps_stream, pdf_stream, profile_cache);
RELOC_PTRS_END
static void
@@ -354,6 +463,10 @@ pdfctx_finalize(const gs_memory_t *cmem, void *vptr)
* on the same object - hence we null the entries.
*/
+ if (pdfctx->profile_cache != NULL) {
+ rc_decrement(pdfctx->profile_cache, "free the working profile cache");
+ pdfctx->profile_cache = NULL;
+ }
if (cmem != NULL) {
if (pdfctx->ctx != NULL) {
if (pdfctx->pdf_stream) {
@@ -385,9 +498,7 @@ static int zPDFstream(i_ctx_t *i_ctx_p)
int code = 0;
stream *s;
pdfctx_t *pdfctx;
- gs_gstate *pgs = NULL;
- gs_gstate_client_procs procs;
- void *client_data;
+ pdfi_switch_t i_switch;
check_op(2);
@@ -409,20 +520,13 @@ static int zPDFstream(i_ctx_t *i_ctx_p)
*(pdfctx->pdf_stream) = *(pdfctx->ps_stream);
- pgs = pdfctx->ctx->pgs;
- procs = igs->client_procs;
- client_data = igs->client_data;
- pdfi_gstate_from_PS(pdfctx->ctx, igs, &client_data, &procs);
- pdfctx->ctx->pgs = igs;
+ code = pdfi_gstate_from_PS(pdfctx->ctx, igs, &i_switch, pdfctx->profile_cache);
- code = pdfi_set_input_stream(pdfctx->ctx, pdfctx->pdf_stream);
+ if (code >= 0) {
+ code = pdfi_set_input_stream(pdfctx->ctx, pdfctx->pdf_stream);
- pdfi_gstate_to_PS(pdfctx->ctx, igs, client_data, &procs);
- if (code == 0)
- code = gs_grestore(igs);
- else
- (void)gs_grestore(igs);
- pdfctx->ctx->pgs = pgs;
+ pdfi_gstate_to_PS(pdfctx->ctx, igs, &i_switch);
+ }
if (code < 0) {
memset(pdfctx->pdf_stream, 0x00, sizeof(stream));
@@ -445,9 +549,7 @@ static int zPDFfile(i_ctx_t *i_ctx_p)
pdfctx_t *pdfctx;
char pdffilename[gp_file_name_sizeof];
int code = 0;
- gs_gstate *pgs = NULL;
- gs_gstate_client_procs procs;
- void *client_data;
+ pdfi_switch_t i_switch;
check_op(2);
@@ -467,20 +569,13 @@ static int zPDFfile(i_ctx_t *i_ctx_p)
memcpy(pdffilename, (op - 1)->value.bytes, r_size(op - 1));
pdffilename[r_size(op - 1)] = 0;
- pgs = pdfctx->ctx->pgs;
- procs = igs->client_procs;
- client_data = igs->client_data;
- pdfi_gstate_from_PS(pdfctx->ctx, igs, &client_data, &procs);
- pdfctx->ctx->pgs = igs;
+ code = pdfi_gstate_from_PS(pdfctx->ctx, igs, &i_switch, pdfctx->profile_cache);
- code = pdfi_open_pdf_file(pdfctx->ctx, pdffilename);
+ if (code >= 0) {
+ code = pdfi_open_pdf_file(pdfctx->ctx, pdffilename);
- pdfi_gstate_to_PS(pdfctx->ctx, igs, client_data, &procs);
- if (code == 0)
- code = gs_grestore(igs);
- else
- (void)gs_grestore(igs);
- pdfctx->ctx->pgs = pgs;
+ pdfi_gstate_to_PS(pdfctx->ctx, igs, &i_switch);
+ }
if (code < 0)
return code;
@@ -500,12 +595,18 @@ static int zPDFclose(i_ctx_t *i_ctx_p)
check_type(*op, t_pdfctx);
pdfctx = r_ptr(op, pdfctx_t);
+ if (pdfctx->profile_cache != NULL) {
+ rc_decrement(pdfctx->profile_cache, "free the working profile cache");
+ pdfctx->profile_cache = NULL;
+ }
+
if (pdfctx->ctx != NULL) {
+ pdfi_report_errors(pdfctx->ctx);
if (pdfctx->ps_stream) {
/* Detach the PostScript stream from the PDF context, otherwise the
* close code will close the main stream
*/
- pdfctx->ctx->main_stream = NULL;
+ pdfctx->ctx->main_stream->s = NULL;
}
code = pdfi_free_context(pdfctx->ctx);
pdfctx->ctx = NULL;
@@ -533,75 +634,79 @@ static int zPDFinfo(i_ctx_t *i_ctx_p)
check_type(*(op), t_pdfctx);
pdfctx = r_ptr(op, pdfctx_t);
- code = dict_create(4, op);
- if (code < 0)
- return code;
-
- code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"NumPages", 8, &nameref, 1);
- if (code < 0)
- return code;
-
- make_int(&intref, pdfctx->ctx->num_pages);
+ if (pdfctx->pdf_stream != NULL) {
+ code = dict_create(4, op);
+ if (code < 0)
+ return code;
- code = dict_put(op, &nameref, &intref, &i_ctx_p->dict_stack);
- if (code < 0)
- return code;
+ code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"NumPages", 8, &nameref, 1);
+ if (code < 0)
+ return code;
- /* Code to process Collections. The pdfi_prep_collection() function returns an
- * array of descriptions and filenames. Because the descriptions can contain
- * UTF16-BE encoded data we can't sue a NULL terminated string, so the description
- * strings are terminated with a triple-NULL sequence of bytes.
- * We copy the contents into a PostScript array, which we store in the info
- * dictionary using the /Collection key.
- */
- if (pdfctx->ctx->Collection != NULL) {
- code = pdfi_prep_collection(pdfctx->ctx, &TotalFiles, &names_array);
- if (code >= 0 && TotalFiles > 0) {
- uint size;
- ref collection, stringref;
+ make_int(&intref, pdfctx->ctx->num_pages);
- code = ialloc_ref_array(&collection, a_all, TotalFiles * 2, "names array");
- if (code < 0)
- goto error;
+ code = dict_put(op, &nameref, &intref, &i_ctx_p->dict_stack);
+ if (code < 0)
+ return code;
- code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"Collection", 10, &nameref, 1);
- if (code < 0)
- goto error;
+ /* Code to process Collections. The pdfi_prep_collection() function returns an
+ * array of descriptions and filenames. Because the descriptions can contain
+ * UTF16-BE encoded data we can't sue a NULL terminated string, so the description
+ * strings are terminated with a triple-NULL sequence of bytes.
+ * We copy the contents into a PostScript array, which we store in the info
+ * dictionary using the /Collection key.
+ */
+ if (pdfctx->ctx->Collection != NULL) {
+ code = pdfi_prep_collection(pdfctx->ctx, &TotalFiles, &names_array);
+ if (code >= 0 && TotalFiles > 0) {
+ uint size;
+ ref collection, stringref;
+
+ code = ialloc_ref_array(&collection, a_all, TotalFiles * 2, "names array");
+ if (code < 0)
+ goto error;
- code = dict_put(op, &nameref, &collection, &i_ctx_p->dict_stack);
- if (code < 0)
- goto error;
+ code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"Collection", 10, &nameref, 1);
+ if (code < 0)
+ goto error;
- for (ix=0; ix < TotalFiles * 2; ix++) {
- char *ptr = names_array[ix];
- byte *sbody;
- ref *pelement;
-
- size = 0;
- do {
- if (ptr[0] == 0x00 && ptr[1] == 0x00 && ptr[2] == 0x00)
- break;
- ptr++;
- size++;
- } while (1);
- sbody = ialloc_string(size, "string");
- if (sbody == 0) {
- code = gs_error_VMerror;
+ code = dict_put(op, &nameref, &collection, &i_ctx_p->dict_stack);
+ if (code < 0)
goto error;
+
+ for (ix=0; ix < TotalFiles * 2; ix++) {
+ char *ptr = names_array[ix];
+ byte *sbody;
+ ref *pelement;
+
+ size = 0;
+ do {
+ if (ptr[0] == 0x00 && ptr[1] == 0x00 && ptr[2] == 0x00)
+ break;
+ ptr++;
+ size++;
+ } while (1);
+ sbody = ialloc_string(size, "string");
+ if (sbody == 0) {
+ code = gs_error_VMerror;
+ goto error;
+ }
+ make_string(&stringref, a_all | icurrent_space, size, sbody);
+ memset(sbody, 0x00, size);
+ memcpy(sbody, names_array[ix], size);
+ gs_free_object(pdfctx->ctx->memory, names_array[ix], "free collection temporary filenames");
+ names_array[ix] = NULL;
+ pelement = collection.value.refs + ix;
+ ref_assign_old(&collection, pelement, &stringref, "put names string");
}
- make_string(&stringref, a_all | icurrent_space, size, sbody);
- memset(sbody, 0x00, size);
- memcpy(sbody, names_array[ix], size);
- gs_free_object(pdfctx->ctx->memory, names_array[ix], "free collection temporary filenames");
- names_array[ix] = NULL;
- pelement = collection.value.refs + ix;
- ref_assign_old(&collection, pelement, &stringref, "put names string");
}
+ gs_free_object(pdfctx->ctx->memory, names_array, "free collection temporary filenames");
+ code = 0;
}
- gs_free_object(pdfctx->ctx->memory, names_array, "free collection temporary filenames");
- code = 0;
}
-
+ else {
+ return_error(gs_error_ioerror);
+ }
return code;
error:
@@ -618,9 +723,7 @@ static int zPDFpageinfo(i_ctx_t *i_ctx_p)
int page = 0, code = 0, i;
pdfctx_t *pdfctx;
pdf_info_t info;
- gs_gstate *pgs = NULL;
- gs_gstate_client_procs procs;
- void *client_data;
+ pdfi_switch_t i_switch;
check_op(2);
@@ -630,163 +733,160 @@ static int zPDFpageinfo(i_ctx_t *i_ctx_p)
check_type(*(op - 1), t_pdfctx);
pdfctx = r_ptr(op - 1, pdfctx_t);
- pgs = pdfctx->ctx->pgs;
- procs = igs->client_procs;
- client_data = igs->client_data;
- pdfi_gstate_from_PS(pdfctx->ctx, igs, &client_data, &procs);
- pdfctx->ctx->pgs = igs;
-
- code = pdfi_page_info(pdfctx->ctx, (uint64_t)page, &info);
-
- pdfi_gstate_to_PS(pdfctx->ctx, igs, client_data, &procs);
- if (code == 0)
- code = gs_grestore(igs);
- else
- (void)gs_grestore(igs);
- pdfctx->ctx->pgs = pgs;
+ if (pdfctx->pdf_stream != NULL) {
+ code = pdfi_gstate_from_PS(pdfctx->ctx, igs, &i_switch, pdfctx->profile_cache);
- if (code < 0)
- return code;
+ if (code >= 0) {
+ code = pdfi_page_info(pdfctx->ctx, (uint64_t)page, &info);
- pop(1);
- op = osp;
-
- code = dict_create(4, op);
- if (code < 0)
- return code;
-
- code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"HasAnnots", 9, &nameref, 1);
- if (code < 0)
- return code;
- make_bool(&boolref, false);
- code = dict_put(op, &nameref, &boolref, &i_ctx_p->dict_stack);
- if (code < 0)
- return code;
+ pdfi_gstate_to_PS(pdfctx->ctx, igs, &i_switch);
+ }
- code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"UsesTransparency", 16, &nameref, 1);
- if (code < 0)
- return code;
- make_bool(&boolref, info.HasTransparency);
- code = dict_put(op, &nameref, &boolref, &i_ctx_p->dict_stack);
- if (code < 0)
- return code;
+ if (code < 0)
+ return code;
- code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"NumSpots", 8, &nameref, 1);
- if (code < 0)
- return code;
- make_int(&numref, info.NumSpots);
- code = dict_put(op, &nameref, &numref, &i_ctx_p->dict_stack);
- if (code < 0)
- return code;
+ pop(1);
+ op = osp;
- if (info.boxes & MEDIA_BOX) {
- code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"MediaBox", 8, &nameref, 1);
+ code = dict_create(4, op);
if (code < 0)
return code;
- code = ialloc_ref_array(&aref, a_all, 4, "array");
+
+ code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"HasAnnots", 9, &nameref, 1);
if (code < 0)
return code;
- refset_null(aref.value.refs, 4);
- for (i=0;i < 4;i++) {
- make_real(&numref, info.MediaBox[i]);
- eltp = aref.value.refs + i;
- ref_assign_old(&aref, eltp, &numref, "put");
- }
- code = dict_put(op, &nameref, &aref, &i_ctx_p->dict_stack);
+ make_bool(&boolref, false);
+ code = dict_put(op, &nameref, &boolref, &i_ctx_p->dict_stack);
if (code < 0)
return code;
- }
- if (info.boxes & CROP_BOX) {
- code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"CropBox", 7, &nameref, 1);
+ code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"UsesTransparency", 16, &nameref, 1);
if (code < 0)
return code;
- code = ialloc_ref_array(&aref, a_all, 4, "array");
+ make_bool(&boolref, info.HasTransparency);
+ code = dict_put(op, &nameref, &boolref, &i_ctx_p->dict_stack);
if (code < 0)
return code;
- refset_null(aref.value.refs, 4);
- for (i=0;i < 4;i++) {
- make_real(&numref, info.CropBox[i]);
- eltp = aref.value.refs + i;
- ref_assign_old(&aref, eltp, &numref, "put");
- }
- code = dict_put(op, &nameref, &aref, &i_ctx_p->dict_stack);
- if (code < 0)
- return code;
- }
- if (info.boxes & TRIM_BOX) {
- code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"TrimBox", 7, &nameref, 1);
+ code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"NumSpots", 8, &nameref, 1);
if (code < 0)
return code;
- code = ialloc_ref_array(&aref, a_all, 4, "array");
+ make_int(&numref, info.NumSpots);
+ code = dict_put(op, &nameref, &numref, &i_ctx_p->dict_stack);
if (code < 0)
return code;
- refset_null(aref.value.refs, 4);
- for (i=0;i < 4;i++) {
- make_real(&numref, info.TrimBox[i]);
- eltp = aref.value.refs + i;
- ref_assign_old(&aref, eltp, &numref, "put");
+
+ if (info.boxes & MEDIA_BOX) {
+ code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"MediaBox", 8, &nameref, 1);
+ if (code < 0)
+ return code;
+ code = ialloc_ref_array(&aref, a_all, 4, "array");
+ if (code < 0)
+ return code;
+ refset_null(aref.value.refs, 4);
+ for (i=0;i < 4;i++) {
+ make_real(&numref, info.MediaBox[i]);
+ eltp = aref.value.refs + i;
+ ref_assign_old(&aref, eltp, &numref, "put");
+ }
+ code = dict_put(op, &nameref, &aref, &i_ctx_p->dict_stack);
+ if (code < 0)
+ return code;
}
- code = dict_put(op, &nameref, &aref, &i_ctx_p->dict_stack);
- if (code < 0)
- return code;
- }
- if (info.boxes & ART_BOX) {
- code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"ArtBox", 6, &nameref, 1);
- if (code < 0)
- return code;
- code = ialloc_ref_array(&aref, a_all, 4, "array");
- if (code < 0)
- return code;
- refset_null(aref.value.refs, 4);
- for (i=0;i < 4;i++) {
- make_real(&numref, info.ArtBox[i]);
- eltp = aref.value.refs + i;
- ref_assign_old(&aref, eltp, &numref, "put");
+ if (info.boxes & CROP_BOX) {
+ code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"CropBox", 7, &nameref, 1);
+ if (code < 0)
+ return code;
+ code = ialloc_ref_array(&aref, a_all, 4, "array");
+ if (code < 0)
+ return code;
+ refset_null(aref.value.refs, 4);
+ for (i=0;i < 4;i++) {
+ make_real(&numref, info.CropBox[i]);
+ eltp = aref.value.refs + i;
+ ref_assign_old(&aref, eltp, &numref, "put");
+ }
+ code = dict_put(op, &nameref, &aref, &i_ctx_p->dict_stack);
+ if (code < 0)
+ return code;
}
- code = dict_put(op, &nameref, &aref, &i_ctx_p->dict_stack);
- if (code < 0)
- return code;
- }
- if (info.boxes & BLEED_BOX) {
- code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"BleedBox", 8, &nameref, 1);
- if (code < 0)
- return code;
- code = ialloc_ref_array(&aref, a_all, 4, "array");
- if (code < 0)
- return code;
- refset_null(aref.value.refs, 4);
- for (i=0;i < 4;i++) {
- make_real(&numref, info.BleedBox[i]);
- eltp = aref.value.refs + i;
- ref_assign_old(&aref, eltp, &numref, "put");
+ if (info.boxes & TRIM_BOX) {
+ code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"TrimBox", 7, &nameref, 1);
+ if (code < 0)
+ return code;
+ code = ialloc_ref_array(&aref, a_all, 4, "array");
+ if (code < 0)
+ return code;
+ refset_null(aref.value.refs, 4);
+ for (i=0;i < 4;i++) {
+ make_real(&numref, info.TrimBox[i]);
+ eltp = aref.value.refs + i;
+ ref_assign_old(&aref, eltp, &numref, "put");
+ }
+ code = dict_put(op, &nameref, &aref, &i_ctx_p->dict_stack);
+ if (code < 0)
+ return code;
}
- code = dict_put(op, &nameref, &aref, &i_ctx_p->dict_stack);
- if (code < 0)
- return code;
- }
- code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"Rotate", 6, &nameref, 1);
- if (code < 0)
- return code;
- make_real(&numref, info.Rotate);
- code = dict_put(op, &nameref, &numref, &i_ctx_p->dict_stack);
- if (code < 0)
- return code;
+ if (info.boxes & ART_BOX) {
+ code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"ArtBox", 6, &nameref, 1);
+ if (code < 0)
+ return code;
+ code = ialloc_ref_array(&aref, a_all, 4, "array");
+ if (code < 0)
+ return code;
+ refset_null(aref.value.refs, 4);
+ for (i=0;i < 4;i++) {
+ make_real(&numref, info.ArtBox[i]);
+ eltp = aref.value.refs + i;
+ ref_assign_old(&aref, eltp, &numref, "put");
+ }
+ code = dict_put(op, &nameref, &aref, &i_ctx_p->dict_stack);
+ if (code < 0)
+ return code;
+ }
- if (info.UserUnit != 1) {
- code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"UserUnit", 8, &nameref, 1);
+ if (info.boxes & BLEED_BOX) {
+ code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"BleedBox", 8, &nameref, 1);
+ if (code < 0)
+ return code;
+ code = ialloc_ref_array(&aref, a_all, 4, "array");
+ if (code < 0)
+ return code;
+ refset_null(aref.value.refs, 4);
+ for (i=0;i < 4;i++) {
+ make_real(&numref, info.BleedBox[i]);
+ eltp = aref.value.refs + i;
+ ref_assign_old(&aref, eltp, &numref, "put");
+ }
+ code = dict_put(op, &nameref, &aref, &i_ctx_p->dict_stack);
+ if (code < 0)
+ return code;
+ }
+
+ code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"Rotate", 6, &nameref, 1);
if (code < 0)
return code;
- make_real(&numref, info.UserUnit);
+ make_real(&numref, info.Rotate);
code = dict_put(op, &nameref, &numref, &i_ctx_p->dict_stack);
if (code < 0)
return code;
- }
+ if (info.UserUnit != 1) {
+ code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"UserUnit", 8, &nameref, 1);
+ if (code < 0)
+ return code;
+ make_real(&numref, info.UserUnit);
+ code = dict_put(op, &nameref, &numref, &i_ctx_p->dict_stack);
+ if (code < 0)
+ return code;
+ }
+ }
+ else {
+ return_error(gs_error_ioerror);
+ }
return 0;
}
@@ -809,9 +909,7 @@ static int zPDFdrawpage(i_ctx_t *i_ctx_p)
int code = 0;
uint64_t page = 0;
pdfctx_t *pdfctx;
- gs_gstate *pgs = NULL;
- gs_gstate_client_procs procs;
- void *client_data;
+ pdfi_switch_t i_switch;
check_op(2);
@@ -821,27 +919,28 @@ static int zPDFdrawpage(i_ctx_t *i_ctx_p)
check_type(*(op - 1), t_pdfctx);
pdfctx = r_ptr(op - 1, pdfctx_t);
- code = gs_gsave(igs);
- if (code < 0)
- return code;
-
- pgs = pdfctx->ctx->pgs;
- procs = igs->client_procs;
- client_data = igs->client_data;
- pdfi_gstate_from_PS(pdfctx->ctx, igs, &client_data, &procs);
- pdfctx->ctx->pgs = igs;
+ if (pdfctx->pdf_stream != NULL) {
+ code = gs_gsave(igs);
+ if (code < 0)
+ return code;
- code = pdfi_page_render(pdfctx->ctx, page, false);
- if (code >= 0)
- pop(2);
+ code = pdfi_gstate_from_PS(pdfctx->ctx, igs, &i_switch, pdfctx->profile_cache);
- pdfi_gstate_to_PS(pdfctx->ctx, igs, client_data, &procs);
- if (code == 0)
- code = gs_grestore(igs);
- else
- (void)gs_grestore(igs);
- pdfctx->ctx->pgs = pgs;
+ if (code >= 0) {
+ code = pdfi_page_render(pdfctx->ctx, page, false);
+ if (code >= 0)
+ pop(2);
+ pdfi_gstate_to_PS(pdfctx->ctx, igs, &i_switch);
+ }
+ if (code == 0)
+ code = gs_grestore(igs);
+ else
+ (void)gs_grestore(igs);
+ }
+ else {
+ return_error(gs_error_ioerror);
+ }
return code;
}
@@ -906,6 +1005,12 @@ static int zPDFInit(i_ctx_t *i_ctx_p)
pdfctx->ps_stream = NULL;
pdfctx->pdf_stream = NULL;
pdfctx->pdf_stream_memory = NULL;
+ pdfctx->profile_cache = gsicc_profilecache_new(imemory);
+ if (pdfctx->profile_cache == NULL) {
+ code = gs_note_error(gs_error_VMerror);
+ goto error;
+ }
+ pdfctx->cache_memory = imemory;
ctx = pdfi_create_context(cmem);
if (ctx == NULL) {
@@ -914,7 +1019,7 @@ static int zPDFInit(i_ctx_t *i_ctx_p)
}
pdfctx->ctx = ctx;
- get_zfont_glyph_name((void **)&pdfctx->ctx->get_glyph_name);
+ get_zfont_glyph_name(&pdfctx->ctx->get_glyph_name);
pdfctx->ctx->get_glyph_index = zpdfi_glyph_index;
if (ref_stack_count(&o_stack) > 0 && r_has_type(op, t_dictionary)) {
@@ -984,7 +1089,7 @@ static int zPDFInit(i_ctx_t *i_ctx_p)
pdfctx->ctx->args.last_page = pvalueref->value.intval;
}
- if (dict_find_string(pdictref, "NOCIDFALLBACK", &pvalueref) > 0) {
+ if (dict_find_string(pdictref, "PDFNOCIDFALLBACK", &pvalueref) > 0) {
if (!r_has_type(pvalueref, t_boolean))
goto error;
pdfctx->ctx->args.nocidfallback = pvalueref->value.boolval;
@@ -996,6 +1101,21 @@ static int zPDFInit(i_ctx_t *i_ctx_p)
pdfctx->ctx->args.no_pdfmark_outlines = pvalueref->value.boolval;
}
+ /* This one can be a boolean OR an integer */
+ if (dict_find_string(pdictref, "UsePDFX3Profile", &pvalueref) > 0) {
+ if (!r_has_type(pvalueref, t_boolean)) {
+ if (!r_has_type(pvalueref, t_integer))
+ goto error;
+ else {
+ pdfctx->ctx->args.UsePDFX3Profile = true;
+ pdfctx->ctx->args.PDFX3Profile_num = pvalueref->value.intval;
+ }
+ } else {
+ pdfctx->ctx->args.UsePDFX3Profile = pvalueref->value.boolval;
+ pdfctx->ctx->args.PDFX3Profile_num = 0;
+ }
+ }
+
if (dict_find_string(pdictref, "NO_PDFMARK_DESTS", &pvalueref) > 0) {
if (!r_has_type(pvalueref, t_boolean))
goto error;
@@ -1056,6 +1176,12 @@ static int zPDFInit(i_ctx_t *i_ctx_p)
pdfctx->ctx->args.preserveannots = pvalueref->value.boolval;
}
+ if (dict_find_string(pdictref, "PreserveMarkedContent", &pvalueref) > 0) {
+ if (!r_has_type(pvalueref, t_boolean))
+ goto error;
+ pdfctx->ctx->args.preservemarkedcontent = pvalueref->value.boolval;
+ }
+
if (dict_find_string(pdictref, "NoUserUnit", &pvalueref) > 0) {
if (!r_has_type(pvalueref, t_boolean))
goto error;
@@ -1091,21 +1217,57 @@ static int zPDFInit(i_ctx_t *i_ctx_p)
if (code < 0)
goto error;
}
+ if (dict_find_string(pdictref, "CIDSubstPath", &pvalueref) > 0) {
+ if (!r_has_type(pvalueref, t_string))
+ goto error;
+ pdfctx->ctx->args.cidsubstpath.data = (byte *)gs_alloc_bytes(pdfctx->ctx->memory, r_size(pvalueref) + 1, "PDF CIDSubstPath from zpdfops");
+ memcpy(pdfctx->ctx->args.cidsubstpath.data, pvalueref->value.const_bytes, r_size(pvalueref));
+ pdfctx->ctx->args.cidsubstpath.size = r_size(pvalueref);
+ }
+ if (dict_find_string(pdictref, "CIDSubstFont", &pvalueref) > 0) {
+ if (!r_has_type(pvalueref, t_string))
+ goto error;
+ pdfctx->ctx->args.cidsubstfont.data = (byte *)gs_alloc_bytes(pdfctx->ctx->memory, r_size(pvalueref) + 1, "PDF CIDSubstPath from zpdfops");
+ memcpy(pdfctx->ctx->args.cidsubstfont.data, pvalueref->value.const_bytes, r_size(pvalueref));
+ pdfctx->ctx->args.cidsubstfont.size = r_size(pvalueref);
+ }
+ if (dict_find_string(pdictref, "IgnoreToUnicode", &pvalueref) > 0) {
+ if (!r_has_type(pvalueref, t_boolean))
+ goto error;
+ pdfctx->ctx->args.ignoretounicode = pvalueref->value.boolval;
+ }
+ if (dict_find_string(pdictref, "NONATIVEFONTMAP", &pvalueref) > 0) {
+ if (!r_has_type(pvalueref, t_boolean))
+ goto error;
+ pdfctx->ctx->args.nonativefontmap = pvalueref->value.boolval;
+ }
code = 0;
pop(1);
}
- zpdfi_populate_search_paths(i_ctx_p, ctx);
+ code = zpdfi_populate_search_paths(i_ctx_p, ctx);
+ if (code < 0)
+ goto error;
+
+ code = zpdfi_populate_fontmap_files(i_ctx_p, ctx);
+ if (code < 0)
+ goto error;
+
op = osp;
push(1);
make_tav(op, t_pdfctx, icurrent_space | a_all, pstruct, (obj_header_t *)(pdfctx));
return 0;
error:
- if (ctx)
+ if (ctx != NULL)
pdfi_free_context(ctx);
/* gs_memory_chunk_unwrap() returns the "wrapped" allocator, which we don't need */
(void)gs_memory_chunk_unwrap(cmem);
- if (pdfctx) {
+ if (pdfctx != NULL) {
+ pdfctx->ctx = NULL; /* Freed already above! */
+ if (pdfctx->profile_cache != NULL) {
+ gs_free_object(imemory, pdfctx->profile_cache, "discard temporary profile cache");
+ pdfctx->profile_cache = NULL;
+ }
pdfctx->pdf_memory = NULL;
gs_free_object(imemory, pdfctx, "PDFcontext");
}