[gs-commits] ghostpdl branch, master, updated. jbig2dec-0.14-1558-ge9e253e
[email protected] (Ken Sharp)
| Newsgroups | gmane.comp.printing.ghostscript.cvs |
|---|---|
| Message-ID | <[email protected]> |
The ghostpdl branch, master has been updated
via e9e253e1dbc87d6ef772936130076e1ba3b81867 (commit)
from 009d44b855dcda9d0d9ecf5ca20944504648eebe (commit)
----------------------------------------------------------------------
commit e9e253e1dbc87d6ef772936130076e1ba3b81867
Author: Ken Sharp <[email protected]>
Date: Thu Aug 8 09:07:09 2019 +0100
pdfwrite - don't permit fallback font substitution with PDF/A
Bug #701373 "PDFA fails to validate by Preflight"
The inptu is a PDF file which is missing two fonts, Helvetica and
Calibri. For both fonts we use /Helvetica as a substitute. For the
missing Helvetica font this is correct, but for the missing Calibri font
this leads to problem when creating PDF/A otuput files.
Firstly, we now have two different fonts, with differing /Widths which
are potentially attempting to reference the same glyphs from a single
font. Secondly, no matter what we do, the /Widths from the Calibri font
are not going to match the actual glyph metrics from Helvetica.
Since there is no possible way to deal with the second problem, because
either the metrics won't match the /Widths, or the text will be misplaced
if we use Widths that are not those from Calibri, there is no point in
trying to tackle the first problem.
So here we introduce a new special_op 'EventInfo' which passes a single
name to the device. The name is the name of the event which occurred. For
now this can only be 'SubstitutedFont'. The only device which handles
this event is pdfwrite, all other devices simply ignore it. The pdfwrite
device checks to see if it is creating a PDF/A otuptu file, and if it is
then it emits a warnign and aborts the production of PDF/A.
diff --git a/Resource/Init/pdf_font.ps b/Resource/Init/pdf_font.ps
index 964d54c..da07da5 100644
--- a/Resource/Init/pdf_font.ps
+++ b/Resource/Init/pdf_font.ps
@@ -908,9 +908,16 @@ setglobal
% No available good substitution, use the standard one.
pop 1 index .substitutefont
} if
- dup 3 index ne QUIET not and {
+ dup 3 index ne {
+ QUIET not {
(Substituting font ) print dup =only
( for ) print 2 index =only (.) = flush
+ } if
+ % Send a warning to the device, in case its pdfwrite and we are in PDF/A mode
+ % In that case the substituted font may not (probably doesn't) have glyphs which
+ % match the /Widths of the original font, and that will cause a fault with PDF/A
+ % so we need to let the device know.
+ /SubstitutedFont /EventInfo .special_op
} if
pdffindcachedfont
% Stack: font-res fontname fontdesc font
diff --git a/base/gdevdflt.c b/base/gdevdflt.c
index 637c4a4..630becf 100644
--- a/base/gdevdflt.c
+++ b/base/gdevdflt.c
@@ -1062,6 +1062,9 @@ gx_default_dev_spec_op(gx_device *pdev, int dev_spec_op, void *data, int size)
return 0;
return (dev_proc(pdev, encode_color) == gx_default_encode_color ||
dev_proc(pdev, encode_color) == gx_default_rgb_map_rgb_color);
+ /* Just ignore information about events */
+ case gxdso_event_info:
+ return 0;
}
return_error(gs_error_undefined);
}
diff --git a/base/gdevp14.c b/base/gdevp14.c
index 18128ee..ac2e708 100644
--- a/base/gdevp14.c
+++ b/base/gdevp14.c
@@ -6438,8 +6438,13 @@ pdf14_dev_spec_op(gx_device *pdev, int dev_spec_op,
return 0;
}
}
+ /* This code seems wrong to everyone. Why do we pass certain specific spec_ops to the
+ * target device, and not all of them ? This should be regarded as a FIXME and I'll
+ * look into it as time permits. For now, add gxdso_warning_trigger to the list of
+ * spec_ops we pass on.
+ */
if (dev_spec_op == gxdso_get_dev_param || dev_spec_op == gxdso_restrict_bbox
- || dev_spec_op == gxdso_current_output_device) {
+ || dev_spec_op == gxdso_current_output_device || dev_spec_op == gxdso_event_info) {
return dev_proc(p14dev->target, dev_spec_op)(p14dev->target, dev_spec_op, data, size);
}
if (dev_spec_op == gxdso_is_encoding_direct)
diff --git a/base/gxdevsop.h b/base/gxdevsop.h
index 18c3084..2302b73 100644
--- a/base/gxdevsop.h
+++ b/base/gxdevsop.h
@@ -348,6 +348,12 @@ enum {
/* Private dso used to check that a printer device properly forwards to the default */
gxdso_debug_printer_check,
#endif
+ /* Used to send a warning to pdfwrite that some event has happened we want to know about.
+ * Currently this is used in pdf_font.ps to signal that a substittue font has been
+ * used. If we are emitting PDF/A then we need to abort it, as the Widths array of
+ * the PDF font may not match the widths of the glyphs in the font.
+ */
+ gxdso_event_info,
/* Add new gxdso_ keys above this. */
gxdso_pattern__LAST
};
diff --git a/devices/vector/gdevpdfi.c b/devices/vector/gdevpdfi.c
index 7dba5e6..6e8d238 100644
--- a/devices/vector/gdevpdfi.c
+++ b/devices/vector/gdevpdfi.c
@@ -2639,6 +2639,36 @@ gdev_pdf_dev_spec_op(gx_device *pdev1, int dev_spec_op, void *data, int size)
pdev->PassThroughWriter = 0;
return 0;
break;
+ case gxdso_event_info:
+ {
+ dev_param_req_t *request = (dev_param_req_t *)data;
+ if (memcmp(request->Param, "SubstitutedFont", 15) == 0 && pdev->PDFA) {
+ switch (pdev->PDFACompatibilityPolicy) {
+ case 0:
+ case 1:
+ emprintf(pdev->memory,
+ "\n **** A font missing from the input PDF has been substituted with a different font.\n\tWidths may differ, reverting to normal PDF output!\n");
+ pdev->AbortPDFAX = true;
+ pdev->PDFX = 0;
+ break;
+ case 2:
+ emprintf(pdev->memory,
+ "\n **** A font missing from the input PDF has been substituted with a different font.\n\tWidths may differ, aborting conversion!\n");
+ pdev->AbortPDFAX = true;
+ pdev->PDFX = 0;
+ return gs_note_error(gs_error_unknownerror);
+ break;
+ default:
+ emprintf(pdev->memory,
+ "\n **** A font missing from the input PDF has been substituted with a different font.\n\tWidths may differ, unknown PDFACompatibilityPolicy, reverting to normal PDF output!\n");
+ pdev->AbortPDFAX = true;
+ pdev->PDFX = 0;
+ break;
+ }
+ }
+ return 0;
+ }
+ break;
case gxdso_get_dev_param:
{
int code;
diff --git a/psi/zdevice.c b/psi/zdevice.c
index 3f2c957..cb980ae 100644
--- a/psi/zdevice.c
+++ b/psi/zdevice.c
@@ -588,7 +588,8 @@ struct spec_op_s {
* in the main code to execute the required spec_op code.
*/
spec_op_t spec_op_defs[] = {
- {(char *)"GetDeviceParam", 0}
+ {(char *)"GetDeviceParam", 0},
+ {(char *)"EventInfo", 1},
};
/* <any> <any> .... /spec_op name .special_op <any> <any> .....
@@ -678,6 +679,50 @@ zspec_op(i_ctx_t *i_ctx_p)
}
}
break;
+ case 1:
+ {
+ stack_param_list list;
+ dev_param_req_t request;
+ ref rkeys;
+ /* Get a single device parameter, we should be supplied with
+ * the name of the paramter, as a name object.
+ */
+ check_op(1);
+ if (!r_has_type(op, t_name))
+ return_error(gs_error_typecheck);
+
+ ref_assign(&opname, op);
+ name_string_ref(imemory, &opname, &namestr);
+
+ data = (char *)gs_alloc_bytes(imemory, r_size(&namestr) + 1, "temporary special_op string");
+ if (data == 0)
+ return_error(gs_error_VMerror);
+ memset(data, 0x00, r_size(&namestr) + 1);
+ memcpy(data, namestr.value.bytes, r_size(&namestr));
+
+ /* Discard the parameter name now, we're done with it */
+ pop (1);
+ /* Make a null object so that the stack param list won't check for requests */
+ make_null(&rkeys);
+ stack_param_list_write(&list, &o_stack, &rkeys, iimemory);
+ /* Stuff the data into a structure for passing to the spec_op */
+ request.Param = data;
+ request.list = &list;
+
+ code = dev_proc(dev, dev_spec_op)(dev, gxdso_event_info, &request, sizeof(dev_param_req_t));
+
+ gs_free_object(imemory, data, "temporary special_op string");
+
+ if (code < 0) {
+ if (code == gs_error_undefined) {
+ op = osp;
+ push(1);
+ make_bool(op, 0);
+ } else
+ return_error(code);
+ }
+ }
+ break;
default:
/* Belt and braces; it shold not be possible to get here, as the table
* containing the names should mirror the entries in this switch. If we
Summary of changes:
Resource/Init/pdf_font.ps | 9 ++++++++-
base/gdevdflt.c | 3 +++
base/gdevp14.c | 7 ++++++-
base/gxdevsop.h | 6 ++++++
devices/vector/gdevpdfi.c | 30 ++++++++++++++++++++++++++++++
psi/zdevice.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
6 files changed, 99 insertions(+), 3 deletions(-)