[gs-commits] ghostpdl branch, pdfi, updated. jbig2dec-0.14-2195-g6a482bd

[email protected] (Ken Sharp)
Newsgroups gmane.comp.printing.ghostscript.cvs
Message-ID <[email protected]>
The ghostpdl branch, pdfi has been updated
       via  6a482bd7d905c7ffce923daa9146e935cdb8137d (commit)
      from  9bd1cd93933f77fa7ed5804299d884f1ae6dc177 (commit)

----------------------------------------------------------------------
commit 6a482bd7d905c7ffce923daa9146e935cdb8137d
Author: Ken Sharp <[email protected]>
Date:   Tue Sep 3 16:18:44 2019 +0100

    Implement TR, TR2, BG, BG2, UCR and UCR2
    
    In order to use the '2' variants, we need to store the mapping in
    force at the start of the page. So at the start of every page we take
    a copy of the proc and map values, so we can use those if needed.
    
    To implement the functions, we either set the gs_identity_transfer,
    saved function (Default) or gs_mapped_transfer function. If we are
    using the Default, then we simply copy the map values across. If we
    have been given a function, then we evaluate the function for inputs
    ranging form 0 to 1, in as many steps as a re required to satisfy
    transfer_map_size. We store each result in the map.
    
    This results in 2 files now causing seg faults in the PDf14 device at
    high resolution (clist). However I think this is simply due to memory
    changes, I don't believe the code itself causes the problems.

diff --git a/pdf/ghostpdf.c b/pdf/ghostpdf.c
index 6650630..b9b8a89 100644
--- a/pdf/ghostpdf.c
+++ b/pdf/ghostpdf.c
@@ -1587,6 +1587,48 @@ static int pdfi_render_page(pdf_context *ctx, uint64_t page_num)
     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... */
diff --git a/pdf/ghostpdf.h b/pdf/ghostpdf.h
index 67608c0..64ec2b3 100644
--- a/pdf/ghostpdf.h
+++ b/pdf/ghostpdf.h
@@ -76,11 +76,12 @@
 #include "gscms.h"
 #include "gsicc_cache.h"
 #include "gxpcolor.h"
-
 #include "gxdevsop.h"       /* For special ops */
-
 #include "gstext.h"         /* for gs_text_enum_t */
 
+#include "gxtmap.h"
+#include "gxfmap.h"
+
 #ifndef PDF_CONTEXT
 #define PDF_CONTEXT
 
@@ -151,6 +152,11 @@ typedef enum pdf_warning_flag_e {
 #define MAX_OBJECT_CACHE_SIZE 200
 #define INITIAL_LOOP_TRACKER_SIZE 32
 
+typedef struct pdf_transfer_s {
+    gs_mapping_proc proc;	/* typedef is in gxtmap.h */
+    frac values[transfer_map_size];
+} pdf_transfer;
+
 /* Items we want preserved around content stream executions */
 typedef struct stream_save_s {
     gs_offset_t stream_offset;
@@ -280,6 +286,11 @@ typedef struct pdf_context_s
     pdf_dict *SpotNames;
     pdf_dict *CurrentPageDict;      /* Last-ditch resource lookup */
 
+    /* Page leve 'Default' transfer functions, black generation and under colour removal */
+    pdf_transfer DefaultTransfers[4];
+    pdf_transfer DefaultBG;
+    pdf_transfer DefaultUCR;
+
     /* Document level PDF objects */
     xref_table *xref_table;
     pdf_dict *Trailer;
diff --git a/pdf/pdf_gstate.c b/pdf/pdf_gstate.c
index 6462d80..2a36784 100644
--- a/pdf/pdf_gstate.c
+++ b/pdf/pdf_gstate.c
@@ -648,66 +648,398 @@ static int GS_Font(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_di
     return 0;
 }
 
+static int pdfi_set_blackgeneration(pdf_context *ctx, pdf_obj *obj, pdf_dict *stream_dict, pdf_dict *page_dict, bool is_BG)
+{
+    int code = 0, i;
+    gs_function_t *pfn;
+
+    if (obj->type == PDF_NAME) {
+        if (pdfi_name_is((const pdf_name *)obj, "Identity")) {
+            code = gs_setblackgeneration_remap(ctx->pgs, gs_identity_transfer, false);
+            goto exit;
+        } else {
+            if (!is_BG && pdfi_name_is((const pdf_name *)obj, "Default")) {
+                code = gs_setblackgeneration_remap(ctx->pgs, ctx->DefaultBG.proc, false);
+                memcpy(ctx->pgs->black_generation->values, ctx->DefaultBG.values, transfer_map_size * sizeof(frac));
+                goto exit;
+            } else {
+                code = gs_note_error(gs_error_rangecheck);
+                goto exit;
+            }
+        }
+    } else {
+        if (obj->type != PDF_DICT)
+            return_error(gs_error_typecheck);
+
+        code = pdfi_build_function(ctx, &pfn, NULL, 1, (pdf_dict *)obj, page_dict);
+        if (code < 0)
+            return code;
+
+        gs_setblackgeneration_remap(ctx->pgs, gs_mapped_transfer, false);
+        for (i = 0; i < transfer_map_size; i++) {
+            float v, f;
+
+            f = (1.0f / transfer_map_size) * i;
+
+            code = gs_function_evaluate(pfn, (const float *)&f, &v);
+            if (code < 0) {
+                pdfi_free_function(ctx, pfn);
+                return code;
+            }
+
+            ctx->pgs->black_generation->values[i] =
+                (v < 0.0 ? float2frac(0.0) :
+                 v >= 1.0 ? frac_1 :
+                 float2frac(v));
+        }
+        code = pdfi_free_function(ctx, pfn);
+    }
+exit:
+    return code;
+}
+
 static int GS_BG(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_dict *page_dict)
 {
-    return 0;
+    int code;
+    pdf_obj *obj = NULL;
+
+    /* If the dictionary also has a BG2, then we must use that */
+    code = pdfi_dict_get(ctx, GS, "BG2", &obj);
+    if (code == 0) {
+        pdfi_countdown(obj);
+        return 0;
+    }
+
+    code = pdfi_dict_get(ctx, GS, "BG", &obj);
+    if (code < 0)
+        return code;
+
+    code = pdfi_set_blackgeneration(ctx, obj, stream_dict, page_dict, true);
+
+    pdfi_countdown(obj);
+
+    return code;
 }
 
 static int GS_BG2(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_dict *page_dict)
 {
-    return 0;
+    int code;
+    pdf_obj *obj = NULL;
+
+    code = pdfi_dict_get(ctx, GS, "BG2", &obj);
+    if (code < 0)
+        return code;
+
+    code = pdfi_set_blackgeneration(ctx, obj, stream_dict, page_dict, false);
+
+    pdfi_countdown(obj);
+
+    return code;
+}
+
+static int pdfi_set_undercolorremoval(pdf_context *ctx, pdf_obj *obj, pdf_dict *stream_dict, pdf_dict *page_dict, bool is_BG)
+{
+    int code = 0, i;
+    gs_function_t *pfn;
+
+    if (obj->type == PDF_NAME) {
+        if (pdfi_name_is((const pdf_name *)obj, "Identity")) {
+            code = gs_setundercolorremoval_remap(ctx->pgs, gs_identity_transfer, false);
+            goto exit;
+        } else {
+            if (!is_BG && pdfi_name_is((const pdf_name *)obj, "Default")) {
+                code = gs_setundercolorremoval_remap(ctx->pgs, ctx->DefaultUCR.proc, false);
+                memcpy(ctx->pgs->undercolor_removal->values, ctx->DefaultUCR.values, transfer_map_size * sizeof(frac));
+                goto exit;
+            } else {
+                code = gs_note_error(gs_error_rangecheck);
+                goto exit;
+            }
+        }
+    } else {
+        if (obj->type != PDF_DICT)
+            return_error(gs_error_typecheck);
+
+        code = pdfi_build_function(ctx, &pfn, NULL, 1, (pdf_dict *)obj, page_dict);
+        if (code < 0)
+            return code;
+
+        gs_setundercolorremoval_remap(ctx->pgs, gs_mapped_transfer, false);
+        for (i = 0; i < transfer_map_size; i++) {
+            float v, f;
+
+            f = (1.0f / transfer_map_size) * i;
+
+            code = gs_function_evaluate(pfn, (const float *)&f, &v);
+            if (code < 0) {
+                pdfi_free_function(ctx, pfn);
+                return code;
+            }
+
+            ctx->pgs->undercolor_removal->values[i] =
+                (v < 0.0 ? float2frac(0.0) :
+                 v >= 1.0 ? frac_1 :
+                 float2frac(v));
+        }
+        code = pdfi_free_function(ctx, pfn);
+    }
+exit:
+    return code;
 }
 
 static int GS_UCR(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_dict *page_dict)
 {
-    return 0;
+    int code;
+    pdf_obj *obj = NULL;
+
+    /* If the dictionary also has a UCR2, then we must use that and ignore the UCR */
+    code = pdfi_dict_get(ctx, GS, "UCR2", &obj);
+    if (code == 0) {
+        pdfi_countdown(obj);
+        return 0;
+    }
+
+    code = pdfi_dict_get(ctx, GS, "UCR", &obj);
+    if (code < 0)
+        return code;
+
+    code = pdfi_set_undercolorremoval(ctx, obj, stream_dict, page_dict, true);
+
+    pdfi_countdown(obj);
+
+    return code;
 }
 
 static int GS_UCR2(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_dict *page_dict)
 {
-    return 0;
+    int code;
+    pdf_obj *obj = NULL;
+
+    code = pdfi_dict_get(ctx, GS, "UCR2", &obj);
+    if (code < 0)
+        return code;
+
+    code = pdfi_set_undercolorremoval(ctx, obj, stream_dict, page_dict, false);
+
+    pdfi_countdown(obj);
+
+    return code;
+}
+
+typedef enum pdf_transfer_function_type_e {
+    E_IDENTITY,
+    E_DEFAULT,
+    E_FUNCTION
+};
+
+/* We use this for both TR and TR2, is_TR is true if this is a TR, in which case we don't want
+ * to permit /Default names for fucntions.
+ */
+static int pdfi_set_all_transfers(pdf_context *ctx, pdf_array *a, pdf_dict *page_dict, bool is_TR)
+{
+    int code = 0, i, j;
+    pdf_obj *o = NULL;
+    int proc_types[4];
+    gs_mapping_proc map_procs[4];
+    gs_function_t *pfn[4];
+
+    memset(pfn, 0x00, 4 * sizeof(gs_function_t *));
+    memset(map_procs, 0x00, 4 * sizeof(gs_mapping_proc *));
+
+    /* Two passes, the first one is to find the appropriate transfer procedures
+     * and do the majorty of the error checking;
+     */
+    for (i = 0; i < 4; i++) {
+        code = pdfi_array_get(ctx, a, (uint64_t)i, &o);
+        if (code < 0)
+            goto exit;
+        if (o->type == PDF_NAME) {
+            if (pdfi_name_is((const pdf_name *)o, "Identity")) {
+                proc_types[i] = E_IDENTITY;
+                map_procs[i] = gs_identity_transfer;
+            } else {
+                if (!is_TR && pdfi_name_is((const pdf_name *)o, "Default")) {
+                    proc_types[i] = E_DEFAULT;
+                    map_procs[i] = ctx->DefaultTransfers[i].proc;
+                } else {
+                    pdfi_countdown(o);
+                    code = gs_note_error(gs_error_typecheck);
+                    goto exit;
+                }
+            }
+        } else {
+            if (o->type == PDF_DICT) {
+                proc_types[i] = E_FUNCTION;
+                map_procs[i] = gs_mapped_transfer;
+                code = pdfi_build_function(ctx, &pfn[i], NULL, 1, (pdf_dict *)o, page_dict);
+                if (code < 0) {
+                    pdfi_countdown(o);
+                    goto exit;
+                }
+            } else {
+                pdfi_countdown(o);
+                code = gs_note_error(gs_error_typecheck);
+                goto exit;
+            }
+        }
+        pdfi_countdown(o);
+    }
+    code = gs_setcolortransfer_remap(ctx->pgs, map_procs[0], map_procs[1], map_procs[2], map_procs[3], false);
+    if (code < 0)
+        goto exit;
+
+    /* Second pass is to evaluate and set the transfer maps */
+    for (j = 0; j < 4; j++) {
+        if (proc_types[j] == E_DEFAULT) {
+            switch(j) {
+                case 0:
+                    memcpy(ctx->pgs->set_transfer.red->values, ctx->DefaultTransfers[j].values, transfer_map_size * sizeof(frac));
+                    break;
+                case 1:
+                    memcpy(ctx->pgs->set_transfer.green->values, ctx->DefaultTransfers[j].values, transfer_map_size * sizeof(frac));
+                    break;
+                case 2:
+                    memcpy(ctx->pgs->set_transfer.blue->values, ctx->DefaultTransfers[j].values, transfer_map_size * sizeof(frac));
+                    break;
+                case 3:
+                    memcpy(ctx->pgs->set_transfer.gray->values, ctx->DefaultTransfers[j].values, transfer_map_size * sizeof(frac));
+                    break;
+            }
+        }
+        if (proc_types[j] == E_FUNCTION) {
+            for (i = 0; i < transfer_map_size; i++) {
+                float v, f;
+                frac value;
+
+                f = (1.0f / transfer_map_size) * i;
+
+                code = gs_function_evaluate(pfn[j], (const float *)&f, &v);
+                if (code < 0)
+                    goto exit;
+
+                value =
+                    (v < 0.0 ? float2frac(0.0) :
+                     v >= 1.0 ? frac_1 :
+                     float2frac(v));
+                switch(j) {
+                    case 0:
+                        ctx->pgs->set_transfer.red->values[i] = value;
+                        break;
+                    case 1:
+                        ctx->pgs->set_transfer.green->values[i] = value;
+                        break;
+                    case 2:
+                        ctx->pgs->set_transfer.blue->values[i] = value;
+                        break;
+                    case 3:
+                        ctx->pgs->set_transfer.gray->values[i] = value;
+                        break;
+                }
+            }
+        }
+    }
+ exit:
+//    (void)pdfi_seek(ctx, ctx->main_stream, saved_stream_offset, SEEK_SET);
+    for (i = 0; i < 4; i++) {
+        pdfi_free_function(ctx, pfn[i]);
+    }
+    return code;
+}
+
+static int pdfi_set_gray_transfer(pdf_context *ctx, pdf_dict *d, pdf_dict *page_dict)
+{
+    int code = 0, i;
+    gs_function_t *pfn;
+
+    if (d->type != PDF_DICT)
+        return_error(gs_error_typecheck);
+
+    code = pdfi_build_function(ctx, &pfn, NULL, 1, d, page_dict);
+    if (code < 0)
+        return code;
+
+    gs_settransfer_remap(ctx->pgs, gs_mapped_transfer, false);
+    for (i = 0; i < transfer_map_size; i++) {
+        float v, f;
+
+        f = (1.0f / transfer_map_size) * i;
+
+        code = gs_function_evaluate(pfn, (const float *)&f, &v);
+        if (code < 0) {
+            pdfi_free_function(ctx, pfn);
+            return code;
+        }
+
+        ctx->pgs->set_transfer.gray->values[i] =
+            (v < 0.0 ? float2frac(0.0) :
+             v >= 1.0 ? frac_1 :
+             float2frac(v));
+    }
+    return pdfi_free_function(ctx, pfn);
+}
+
+static int pdfi_set_transfer(pdf_context *ctx, pdf_obj *obj, pdf_dict *stream_dict, pdf_dict *page_dict, bool is_TR)
+{
+    int code = 0;
+
+    if (obj->type == PDF_NAME) {
+        if (pdfi_name_is((const pdf_name *)obj, "Identity")) {
+            code = gs_settransfer_remap(ctx->pgs, gs_identity_transfer, false);
+            goto exit;
+        } else {
+            if (!is_TR && pdfi_name_is((const pdf_name *)obj, "Default")) {
+                code = gs_settransfer_remap(ctx->pgs, ctx->DefaultTransfers[3].proc, false);
+                memcpy(ctx->pgs->set_transfer.gray->values, ctx->DefaultTransfers[3].values, transfer_map_size * sizeof(frac));
+                goto exit;
+            } else {
+                code = gs_note_error(gs_error_rangecheck);
+                goto exit;
+            }
+        }
+    }
+
+    if (obj->type == PDF_ARRAY) {
+        if (pdfi_array_size((pdf_array *)obj) != 4) {
+            code = gs_note_error(gs_error_rangecheck);
+            goto exit;
+        } else {
+            code = pdfi_set_all_transfers(ctx, (pdf_array *)obj, page_dict, false);
+        }
+    } else
+        code = pdfi_set_gray_transfer(ctx, (pdf_dict *)obj, page_dict);
+
+exit:
+    return code;
 }
 
 static int GS_TR(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_dict *page_dict)
 {
-    return 0;
+    int code;
+    pdf_obj *obj = NULL;
+
+    code = pdfi_dict_get(ctx, GS, "TR", &obj);
+    if (code < 0)
+        return code;
+
+    code = pdfi_set_transfer(ctx, obj, stream_dict, page_dict, true);
+
+    pdfi_countdown(obj);
+
+    return code;
 }
 
 static int GS_TR2(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_dict *page_dict)
 {
-    int code;
+    int code, i, j;
     pdf_obj *obj = NULL;
     gs_offset_t saved_stream_offset;
-
     code = pdfi_dict_get(ctx, GS, "TR2", &obj);
     if (code < 0)
         return code;
 
-    saved_stream_offset = pdfi_unread_tell(ctx);
-    if (obj->type == PDF_NAME) {
-        /* TODO */
-        goto exit;
-    }
+    code = pdfi_set_transfer(ctx, obj, stream_dict, page_dict, false);
 
-    if (obj->type == PDF_ARRAY) {
-        /* TODO */
-    } else {
-        if (obj->type == PDF_DICT) {
-            gs_function_t *pfn;
-
-            code = pdfi_build_function(ctx, &pfn, NULL, 1, (pdf_dict *)obj, page_dict);
-            if (code < 0) {
-                goto exit;
-            }
-            /* TODO: incomplete code, pfn is built but need to do something with it? */
-            /* (so this probably causes a memory leak?) */
-        }
-    }
-
- exit:
-    (void)pdfi_seek(ctx, ctx->main_stream, saved_stream_offset, SEEK_SET);
     pdfi_countdown(obj);
-    dbgmprintf(ctx->memory, "ExtGState TR2 not yet implemented\n");
 
     return code;
 }


Summary of changes:
 pdf/ghostpdf.c   |  42 ++++++
 pdf/ghostpdf.h   |  15 ++-
 pdf/pdf_gstate.c | 386 +++++++++++++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 414 insertions(+), 29 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.