[gs-commits] ghostpdl branch, pdfi, updated. jbig2dec-0.14-2647-g62572ba

[email protected] (Nancy Durgin) Wed, 11 Dec 2019 23:04:56 +0000 (UTC)
Newsgroups gmane.comp.printing.ghostscript.cvs
Message-ID <[email protected]>
The ghostpdl branch, pdfi has been updated
       via  62572baee1390a4ee59faec1bc037ee69249a199 (commit)
      from  100783e3848941b7cb2ebf46e3b41e625a36c38a (commit)

----------------------------------------------------------------------
commit 62572baee1390a4ee59faec1bc037ee69249a199
Author: Nancy Durgin <[email protected]>
Date:   Tue Dec 10 14:05:26 2019 -0800

    Implemented a bunch more annotation things
    
    Test files:
    tests_private/pdf/sumatra/x_-_annotations_galore.pdf
    tests_private/comparefiles/annots.pdf

diff --git a/pdf/pdf_annot.c b/pdf/pdf_annot.c
index 29f10b0..09dbedf 100644
--- a/pdf/pdf_annot.c
+++ b/pdf/pdf_annot.c
@@ -38,6 +38,7 @@ typedef int (*annot_func)(pdf_context *ctx, pdf_dict *annot, pdf_dict *NormAP, b
 typedef struct {
     const char *subtype;
     annot_func func;
+    bool simpleAP;
 } annot_dispatch_t;
 
 
@@ -68,16 +69,6 @@ static int pdfi_annot_end_transparency(pdf_context *ctx, pdf_dict *annot)
     return pdfi_trans_end_simple_group(ctx);
 }
 
-/* See pdf_draw.ps/calc_annot_scale */
-static int pdfi_annot_calcscale(pdf_context *ctx, pdf_dict *annot, double *xscale, double *yscale)
-{
-    /* TODO: Implement this */
-
-    *xscale = 1.0;
-    *yscale = 1.0;
-    return 0;
-}
-
 static int pdfi_annot_rect(pdf_context *ctx, pdf_dict *annot, gs_rect *rect)
 {
     int code;
@@ -97,9 +88,7 @@ static int pdfi_annot_rect(pdf_context *ctx, pdf_dict *annot, gs_rect *rect)
 }
 
 /* See pdf_draw.ps/drawwidget (draws the AP for any type of thingy) */
-static int pdfi_annot_draw_AP(pdf_context *ctx, pdf_dict *annot,
-                                  double xscale, double yscale,
-                                  pdf_dict *NormAP)
+static int pdfi_annot_draw_AP(pdf_context *ctx, pdf_dict *annot, pdf_dict *NormAP)
 {
     int code = 0;
     gs_rect rect;
@@ -107,14 +96,11 @@ static int pdfi_annot_draw_AP(pdf_context *ctx, pdf_dict *annot,
     gs_rect bbox;
     pdf_array *Matrix = NULL;
     gs_matrix matrix;
+    double xscale, yscale;
 
-    /* TODO: Just rendering the Norm AP for now.  Lots of other convoluted things
-     *  I am not handling...
-     */
     if (NormAP == NULL)
         return 0;
 
-
     code = pdfi_op_q(ctx);
     if (code < 0)
         return code;
@@ -147,31 +133,44 @@ static int pdfi_annot_draw_AP(pdf_context *ctx, pdf_dict *annot,
     code = pdfi_annot_rect(ctx, annot, &rect);
     if (code < 0) goto exit;
 
-    code = gs_translate(ctx->pgs, rect.p.x, rect.p.y);
-    if (code < 0) goto exit;
-
-    code = gs_scale(ctx->pgs, xscale, yscale);
-    if (code < 0) goto exit;
-
     code = pdfi_dict_knownget_type(ctx, NormAP, "BBox", PDF_ARRAY, (pdf_obj **)&BBox);
     if (code < 0) goto exit;
-    if (code > 0) {
-        code = pdfi_array_to_gs_rect(ctx, BBox, &bbox);
-        if (code < 0) goto exit;
+    code = pdfi_array_to_gs_rect(ctx, BBox, &bbox);
+    if (code < 0) goto exit;
 
-        code = pdfi_dict_knownget_type(ctx, annot, "Matrix", PDF_ARRAY, (pdf_obj **)&Matrix);
-        if (code < 0) goto exit;
+    code = pdfi_dict_knownget_type(ctx, NormAP, "Matrix", PDF_ARRAY, (pdf_obj **)&Matrix);
+    if (code < 0) goto exit;
+    code = pdfi_array_to_gs_matrix(ctx, Matrix, &matrix);
+    if (code < 0) goto exit;
 
-        code = pdfi_array_to_gs_matrix(ctx, Matrix, &matrix);
-        if (code < 0) goto exit;
+    xscale = yscale = 1.0;
 
+    code = gs_translate(ctx->pgs, rect.p.x, rect.p.y);
+    if (code < 0) goto exit;
+
+    if (BBox != NULL) {
         pdfi_bbox_transform(ctx, &bbox, &matrix);
 
+        /* Calculate scale factor */
+        xscale = (rect.q.x - rect.p.x) / (bbox.q.x - bbox.p.x);
+        yscale = (rect.q.y - rect.p.y) / (bbox.q.y - bbox.p.y);
+
+        if (xscale * yscale <= 0) {
+            dbgmprintf(ctx->memory, "ANNOT: Ignoring annotation with scale factor of 0\n");
+            code = 0;
+            goto exit;
+        }
+
+        /* Scale it */
+        code = gs_scale(ctx->pgs, xscale, yscale);
+        if (code < 0) goto exit;
+
         /* Compensate for non-zero origin of BBox */
         code = gs_translate(ctx->pgs, -bbox.p.x, -bbox.p.y);
         if (code < 0) goto exit;
-
     }
+
+    /* Render the annotation */
     code = pdfi_do_image_or_form(ctx, NULL, ctx->CurrentPageDict, NormAP);
     if (code < 0) goto exit;
 
@@ -384,18 +383,45 @@ static int pdfi_annot_get_NormAP(pdf_context *ctx, pdf_dict *annot, pdf_dict **N
 {
     int code;
     pdf_dict *AP = NULL;
+    pdf_dict *baseAP = NULL;
+    pdf_name *AS = NULL;
 
     *NormAP = NULL;
 
     code = pdfi_dict_knownget_type(ctx, annot, "AP", PDF_DICT, (pdf_obj **)&AP);
     if (code <= 0) goto exit;
 
-    code = pdfi_dict_knownget_type(ctx, AP, "N", PDF_DICT, (pdf_obj **)NormAP);
-    if (code > 0)
-        code = 0;
+    code = pdfi_dict_knownget_type(ctx, AP, "N", PDF_DICT, (pdf_obj **)&baseAP);
+    if (code <= 0) goto exit;
+
+    code = 0;
+
+    if (pdfi_dict_is_stream(ctx, baseAP)) {
+        AP = baseAP;
+        pdfi_countup(AP);
+    } else {
+        code = pdfi_dict_knownget_type(ctx, annot, "AS", PDF_NAME, (pdf_obj **)&AS);
+        if (code < 0) goto exit;
+        if (code == 0) {
+            dbgmprintf(ctx->memory, "WARNING Annotation has non-stream AP but no AS.  Don't know what to render. Skipping\n");
+            goto exit;
+        }
+
+        /* Lookup the AS in the NormAP and use that as the AP */
+        code = pdfi_dict_get_by_key(ctx, baseAP, AS, (pdf_obj **)&AP);
+        if (code < 0) goto exit;
+        if (AP->type != PDF_DICT) {
+            code = gs_note_error(gs_error_typecheck);
+            goto exit;
+        }
+    }
+
+   *NormAP = AP;
 
  exit:
     pdfi_countdown(AP);
+    pdfi_countdown(AS);
+    pdfi_countdown(baseAP);
     return code;
 }
 
@@ -403,7 +429,6 @@ static int pdfi_annot_draw_Link(pdf_context *ctx, pdf_dict *annot, pdf_dict *Nor
 {
     int code;
     int code1;
-    double xscale, yscale;
 
     dbgmprintf(ctx->memory, "ANNOT: Drawing Link\n");
 
@@ -414,14 +439,8 @@ static int pdfi_annot_draw_Link(pdf_context *ctx, pdf_dict *annot, pdf_dict *Nor
     code = pdfi_annot_draw_border(ctx, annot);
     if (code < 0) goto exit;
 
-    code = pdfi_annot_calcscale(ctx, annot, &xscale, &yscale);
-    if (code < 0) goto exit;
 
-    if (xscale * yscale > 0.0) {
-        code = pdfi_annot_draw_AP(ctx, annot, xscale, yscale, NormAP);
-    } else {
-        dbgmprintf(ctx->memory, "ANNOT: Ignoring annotation with scale factor of 0\n");
-    }
+    code = pdfi_annot_draw_AP(ctx, annot, NormAP);
 
  exit:
     code1 = pdfi_annot_end_transparency(ctx, annot);
@@ -433,37 +452,190 @@ static int pdfi_annot_draw_Link(pdf_context *ctx, pdf_dict *annot, pdf_dict *Nor
 
 static int pdfi_annot_draw_Ink(pdf_context *ctx, pdf_dict *annot, pdf_dict *NormAP, bool *render_done)
 {
+    int code = 0;
+
+    /* TODO: Generate appearance (see pdf_draw.ps/Ink) */
     *render_done = true;
-    return 0;
+
+    return code;
 }
 
 static int pdfi_annot_draw_Circle(pdf_context *ctx, pdf_dict *annot, pdf_dict *NormAP, bool *render_done)
 {
     int code = 0;
 
+    /* TODO: Generate appearance (see pdf_draw.ps/Circle) */
+    *render_done = true;
+
+    return code;
+}
+
+static int pdfi_annot_draw_Stamp(pdf_context *ctx, pdf_dict *annot, pdf_dict *NormAP, bool *render_done)
+{
+    int code = 0;
+
+    /* TODO: Generate appearance (see pdf_draw.ps/Stamp) */
+    *render_done = true;
+
+    return code;
+}
+
+static int pdfi_annot_draw_FreeText(pdf_context *ctx, pdf_dict *annot, pdf_dict *NormAP, bool *render_done)
+{
+    int code = 0;
+
+    /* TODO: Generate appearance (see pdf_draw.ps/FreeText) */
+    *render_done = true;
+
+    return code;
+}
+
+static int pdfi_annot_draw_Text(pdf_context *ctx, pdf_dict *annot, pdf_dict *NormAP, bool *render_done)
+{
+    int code = 0;
+
+    /* TODO: Generate appearance (see pdf_draw.ps/Text) */
+    *render_done = true;
+
+    return code;
+}
+
+static int pdfi_annot_draw_StrikeOut(pdf_context *ctx, pdf_dict *annot, pdf_dict *NormAP, bool *render_done)
+{
+    int code = 0;
+
+    /* TODO: Generate appearance (see pdf_draw.ps/StrikeOut) */
+    *render_done = true;
+
+    return code;
+}
+
+static int pdfi_annot_draw_Underline(pdf_context *ctx, pdf_dict *annot, pdf_dict *NormAP, bool *render_done)
+{
+    int code = 0;
+
+    /* TODO: Generate appearance (see pdf_draw.ps/Underline) */
+    *render_done = true;
+
+    return code;
+}
+
+static int pdfi_annot_draw_Highlight(pdf_context *ctx, pdf_dict *annot, pdf_dict *NormAP, bool *render_done)
+{
+    int code = 0;
+
+    /* TODO: Generate appearance (see pdf_draw.ps/StrikeOut) */
+    *render_done = true;
+
+    return code;
+}
+
+static int pdfi_annot_draw_Redact(pdf_context *ctx, pdf_dict *annot, pdf_dict *NormAP, bool *render_done)
+{
+    int code = 0;
+
+    /* TODO: Generate appearance (see pdf_draw.ps/Redact) */
+    *render_done = true;
+
+    return code;
+}
+
+static int pdfi_annot_draw_Popup(pdf_context *ctx, pdf_dict *annot, pdf_dict *NormAP, bool *render_done)
+{
+    int code = 0;
+    bool Open = false;
+
+    /* Render only if open */
+    code = pdfi_dict_get_bool(ctx, annot, "Annots", &Open);
+    if (code < 0 && (code != gs_error_undefined))
+        goto exit;
+
+    code = 0;
+
+    if (!Open) {
+        *render_done = true;
+        goto exit;
+    }
+
     if (NormAP) {
         *render_done = false;
         goto exit;
     }
 
-    /* TODO: Generate appearance (see pdf_draw.ps/Circle) */
+    /* TODO: Generate appearance (see pdf_draw.ps/Popup) */
     *render_done = true;
 
  exit:
     return code;
 }
 
+static int pdfi_annot_draw_Line(pdf_context *ctx, pdf_dict *annot, pdf_dict *NormAP, bool *render_done)
+{
+    int code = 0;
+
+    /* TODO: Generate appearance (see pdf_draw.ps/Line) */
+    *render_done = true;
+
+    return code;
+}
+
+static int pdfi_annot_draw_PolyLine(pdf_context *ctx, pdf_dict *annot, pdf_dict *NormAP, bool *render_done)
+{
+   int code = 0;
+
+    /* TODO: Generate appearance (see pdf_draw.ps/PolyLine) */
+    *render_done = true;
+
+    return code;
+}
+
+static int pdfi_annot_draw_Polygon(pdf_context *ctx, pdf_dict *annot, pdf_dict *NormAP, bool *render_done)
+{
+    int code = 0;
+
+    /* TODO: Generate appearance (see pdf_draw.ps/Polygon) */
+    *render_done = true;
+
+    return code;
+}
+
+static int pdfi_annot_draw_Square(pdf_context *ctx, pdf_dict *annot, pdf_dict *NormAP, bool *render_done)
+{
+    int code = 0;
+
+    /* TODO: Generate appearance (see pdf_draw.ps/Square) */
+    *render_done = true;
+
+    return code;
+}
+
 /* Draws a thing of type /Widget */
 static int pdfi_annot_draw_Widget(pdf_context *ctx, pdf_dict *annot, pdf_dict *NormAP, bool *render_done)
 {
+    /* TODO: See top part of pdf_draw.ps/drawwidget
+     * check for /FT and /T and stuff
+     */
+    *render_done = false;
     return 0;
 }
 
 annot_dispatch_t annot_dispatch[] = {
-    {"Link", pdfi_annot_draw_Link},
-    {"Ink", pdfi_annot_draw_Ink},
-    {"Circle", pdfi_annot_draw_Circle},
-    {"Widget", pdfi_annot_draw_Widget},
+    {"Ink", pdfi_annot_draw_Ink, true},
+    {"Circle", pdfi_annot_draw_Circle, true},
+    {"Stamp", pdfi_annot_draw_Stamp, true},
+    {"FreeText", pdfi_annot_draw_FreeText, true},
+    {"Text", pdfi_annot_draw_Text, true},
+    {"StrikeOut", pdfi_annot_draw_StrikeOut, true},
+    {"Underline", pdfi_annot_draw_Underline, true},
+    {"Redact", pdfi_annot_draw_Redact, true},
+    {"Highlight", pdfi_annot_draw_Highlight, true},
+    {"Polygon", pdfi_annot_draw_Polygon, true},
+    {"Square", pdfi_annot_draw_Square, true},
+    {"Line", pdfi_annot_draw_Line, true},
+    {"PolyLine", pdfi_annot_draw_PolyLine, true},
+    {"Link", pdfi_annot_draw_Link, false},
+    {"Popup", pdfi_annot_draw_Popup, false},
+    {"Widget", pdfi_annot_draw_Widget, false},
     { NULL, NULL},
 };
 
@@ -564,12 +736,25 @@ static int pdfi_annot_draw(pdf_context *ctx, pdf_dict *annot)
     /* Draw the annotation */
     for (dispatch_ptr = annot_dispatch; dispatch_ptr->subtype; dispatch_ptr ++) {
         if (pdfi_name_is(Subtype, dispatch_ptr->subtype)) {
-            code = dispatch_ptr->func(ctx, annot, NormAP, &render_done);
+            if (NormAP && dispatch_ptr->simpleAP)
+                render_done = false;
+            else
+                code = dispatch_ptr->func(ctx, annot, NormAP, &render_done);
             break;
         }
     }
+    if (!dispatch_ptr->subtype) {
+        char str[100];
+        memcpy(str, (const char *)Subtype->data, Subtype->length);
+        str[Subtype->length] = '\0';
+        dbgmprintf1(ctx->memory, "ANNOT: No handler for subtype %s\n", str);
+
+        /* Not necessarily an error? We can just render the AP if there is one */
+        render_done = false;
+    }
+
     if (!render_done)
-        code = pdfi_annot_draw_AP(ctx, annot, 1.0, 1.0, NormAP);
+        code = pdfi_annot_draw_AP(ctx, annot, NormAP);
 
     (void)pdfi_grestore(ctx);
 
diff --git a/pdf/pdf_dict.c b/pdf/pdf_dict.c
index 1b8a928..feda7f1 100644
--- a/pdf/pdf_dict.c
+++ b/pdf/pdf_dict.c
@@ -158,6 +158,40 @@ int pdfi_dict_get(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj **o)
     return_error(gs_error_undefined);
 }
 
+/* Get by pdf_name rather than by char *
+ * The object returned by pdfi_dict_get has its reference count incremented by 1 to
+ * indicate the reference now held by the caller, in **o.
+ */
+int pdfi_dict_get_by_key(pdf_context *ctx, pdf_dict *d, const pdf_name *Key, pdf_obj **o)
+{
+    int i=0, code;
+    pdf_name *t;
+
+    *o = NULL;
+
+    for (i=0;i< d->entries;i++) {
+        t = (pdf_name *)d->keys[i];
+
+        if (t && t->type == PDF_NAME) {
+            if (pdfi_name_cmp((pdf_name *)t, Key)== 0) {
+                if (d->values[i]->type == PDF_INDIRECT) {
+                    pdf_indirect_ref *r = (pdf_indirect_ref *)d->values[i];
+
+                    code = pdfi_deref_loop_detect(ctx, r->ref_object_num, r->ref_generation_num, o);
+                    if (code < 0)
+                        return code;
+                    pdfi_countdown(d->values[i]);
+                    d->values[i] = *o;
+                }
+                *o = d->values[i];
+                pdfi_countup(*o);
+                return 0;
+            }
+        }
+    }
+    return_error(gs_error_undefined);
+}
+
 /* As per pdfi_dict_get(), but doesn't replace an indirect reference in a dictionary with a
  * new object. This is for Resources following, such as Do, where we will have to seek and
  * read the indirect object anyway, and we need to ensure that Form XObjects (for example)
diff --git a/pdf/pdf_dict.h b/pdf/pdf_dict.h
index cddb1e9..16c0869 100644
--- a/pdf/pdf_dict.h
+++ b/pdf/pdf_dict.h
@@ -35,6 +35,7 @@ int pdfi_dict_put_bool(pdf_context *ctx, pdf_dict *d, const char *Key, bool valu
 int pdfi_dict_put_name(pdf_context *ctx, pdf_dict *d, const char *Key, const char *name);
 int pdfi_dict_get2(pdf_context *ctx, pdf_dict *d, const char *Key1, const char *Key2, pdf_obj **o);
 int pdfi_dict_get(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj **o);
+int pdfi_dict_get_by_key(pdf_context *ctx, pdf_dict *d, const pdf_name *Key, pdf_obj **o);
 int pdfi_dict_get_no_store_R(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj **o);
 int pdfi_dict_get_type2(pdf_context *ctx, pdf_dict *d, const char *Key1, const char *Key2, pdf_obj_type type, pdf_obj **o);
 int pdfi_dict_get_type(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj_type t, pdf_obj **o);


Summary of changes:
 pdf/pdf_annot.c | 281 ++++++++++++++++++++++++++++++++++++++++++++++----------
 pdf/pdf_dict.c  |  34 +++++++
 pdf/pdf_dict.h  |   1 +
 3 files changed, 268 insertions(+), 48 deletions(-)