[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(-)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.