summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Deutschmann <whissi@gentoo.org>2019-10-15 12:24:12 +0200
committerThomas Deutschmann <whissi@gentoo.org>2020-08-13 11:26:55 +0200
commite088156d5b620e5e639580dacf85c6dc13823c74 (patch)
tree57f5c025e203279944da512166c20bc0521d8ccd /base/gsht1.c
downloadghostscript-gpl-patches-e088156d5b620e5e639580dacf85c6dc13823c74.tar.gz
ghostscript-gpl-patches-e088156d5b620e5e639580dacf85c6dc13823c74.tar.bz2
ghostscript-gpl-patches-e088156d5b620e5e639580dacf85c6dc13823c74.zip
Import Ghostscript 9.50ghostscript-9.50
Signed-off-by: Thomas Deutschmann <whissi@gentoo.org>
Diffstat (limited to 'base/gsht1.c')
-rw-r--r--base/gsht1.c544
1 files changed, 544 insertions, 0 deletions
diff --git a/base/gsht1.c b/base/gsht1.c
new file mode 100644
index 00000000..41cc7f51
--- /dev/null
+++ b/base/gsht1.c
@@ -0,0 +1,544 @@
+/* Copyright (C) 2001-2019 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied,
+ modified or distributed except as expressly authorized under the terms
+ of the license contained in the file LICENSE in this distribution.
+
+ Refer to licensing information at http://www.artifex.com or contact
+ Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
+ CA 94945, U.S.A., +1(415)492-9861, for further information.
+*/
+
+
+/* Extended halftone operators for Ghostscript library */
+#include "memory_.h"
+#include "string_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsutil.h" /* for gs_next_ids */
+#include "gzstate.h"
+#include "gxdevice.h" /* for gzht.h */
+#include "gzht.h"
+
+
+/* Imports from gscolor.c */
+void load_transfer_map(gs_gstate *, gx_transfer_map *, double);
+
+/* Forward declarations */
+static int process_spot(gx_ht_order *, gs_gstate *,
+ gs_spot_halftone *, gs_memory_t *);
+static int process_threshold(gx_ht_order *, gs_gstate *,
+ gs_threshold_halftone *, gs_memory_t *);
+static int process_threshold2(gx_ht_order *, gs_gstate *,
+ gs_threshold2_halftone *, gs_memory_t *);
+static int process_client_order(gx_ht_order *, gs_gstate *,
+ gs_client_order_halftone *, gs_memory_t *);
+
+/* Structure types */
+public_st_halftone_component();
+public_st_ht_component_element();
+
+/* GC procedures */
+
+static
+ENUM_PTRS_WITH(halftone_component_enum_ptrs, gs_halftone_component *hptr) return 0;
+case 0:
+switch (hptr->type)
+{
+ case ht_type_spot:
+ENUM_RETURN((hptr->params.spot.transfer == 0 ?
+ hptr->params.spot.transfer_closure.data :
+ 0));
+ case ht_type_threshold:
+ENUM_RETURN_CONST_STRING_PTR(gs_halftone_component,
+ params.threshold.thresholds);
+ case ht_type_threshold2:
+return ENUM_CONST_BYTESTRING(&hptr->params.threshold2.thresholds);
+ case ht_type_client_order:
+ENUM_RETURN(hptr->params.client_order.client_data);
+ default: /* not possible */
+return 0;
+}
+case 1:
+switch (hptr->type) {
+ case ht_type_threshold:
+ ENUM_RETURN((hptr->params.threshold.transfer == 0 ?
+ hptr->params.threshold.transfer_closure.data :
+ 0));
+ case ht_type_threshold2:
+ ENUM_RETURN(hptr->params.threshold2.transfer_closure.data);
+ case ht_type_client_order:
+ ENUM_RETURN(hptr->params.client_order.transfer_closure.data);
+ default:
+ return 0;
+}
+ENUM_PTRS_END
+static RELOC_PTRS_WITH(halftone_component_reloc_ptrs, gs_halftone_component *hptr)
+{
+ switch (hptr->type) {
+ case ht_type_spot:
+ if (hptr->params.spot.transfer == 0)
+ RELOC_VAR(hptr->params.spot.transfer_closure.data);
+ break;
+ case ht_type_threshold:
+ RELOC_CONST_STRING_VAR(hptr->params.threshold.thresholds);
+ if (hptr->params.threshold.transfer == 0)
+ RELOC_VAR(hptr->params.threshold.transfer_closure.data);
+ break;
+ case ht_type_threshold2:
+ RELOC_CONST_BYTESTRING_VAR(hptr->params.threshold2.thresholds);
+ RELOC_OBJ_VAR(hptr->params.threshold2.transfer_closure.data);
+ break;
+ case ht_type_client_order:
+ RELOC_VAR(hptr->params.client_order.client_data);
+ RELOC_VAR(hptr->params.client_order.transfer_closure.data);
+ break;
+ default:
+ break;
+ }
+}
+RELOC_PTRS_END
+
+/* setcolorscreen */
+int
+gs_setcolorscreen(gs_gstate * pgs, gs_colorscreen_halftone * pht)
+{
+ gs_halftone ht;
+
+ ht.type = ht_type_colorscreen;
+ ht.params.colorscreen = *pht;
+ return gs_sethalftone(pgs, &ht);
+}
+
+/* currentcolorscreen */
+int
+gs_currentcolorscreen(gs_gstate * pgs, gs_colorscreen_halftone * pht)
+{
+ int code;
+
+ switch (pgs->halftone->type) {
+ case ht_type_colorscreen:
+ *pht = pgs->halftone->params.colorscreen;
+ return 0;
+ default:
+ code = gs_currentscreen(pgs, &pht->screens.colored.gray);
+ if (code < 0)
+ return code;
+ pht->screens.colored.red = pht->screens.colored.gray;
+ pht->screens.colored.green = pht->screens.colored.gray;
+ pht->screens.colored.blue = pht->screens.colored.gray;
+ return 0;
+ }
+}
+
+/* Set the halftone in the graphics state. */
+int
+gs_sethalftone(gs_gstate * pgs, gs_halftone * pht)
+{
+ gs_halftone ht;
+
+ ht = *pht;
+ ht.rc.memory = pgs->memory;
+ return gs_sethalftone_allocated(pgs, &ht);
+}
+int
+gs_sethalftone_allocated(gs_gstate * pgs, gs_halftone * pht)
+{
+ gx_device_halftone dev_ht;
+ int code = gs_sethalftone_prepare(pgs, pht, &dev_ht);
+
+ if (code < 0)
+ return code;
+ dev_ht.rc.memory = pht->rc.memory;
+ if ((code = gx_ht_install(pgs, pht, &dev_ht)) < 0)
+ gx_device_halftone_release(&dev_ht, pht->rc.memory);
+ return code;
+}
+
+/* Prepare the halftone, but don't install it. */
+int
+gs_sethalftone_prepare(gs_gstate * pgs, gs_halftone * pht,
+ gx_device_halftone * pdht)
+{
+ gs_memory_t *mem = pht->rc.memory;
+ gx_ht_order_component *pocs = 0;
+ int code = 0;
+
+ switch (pht->type) {
+ case ht_type_colorscreen:
+ {
+ gs_screen_halftone *phc =
+ pht->params.colorscreen.screens.indexed;
+ static const int cindex[4] = {3, 0, 1, 2};
+ static const char * color_names[4] = {"Gray", "Red", "Green", "Blue"};
+ int i;
+
+ pocs = gs_alloc_struct_array(mem, 4,
+ gx_ht_order_component,
+ &st_ht_order_component_element,
+ "gs_sethalftone");
+ if (pocs == 0)
+ return_error(gs_error_VMerror);
+ for (i = 0; i < 4; i++) {
+ gs_screen_enum senum;
+ int ci = cindex[i];
+ gx_ht_order_component *poc = &pocs[i];
+
+ code = gx_ht_process_screen_memory(&senum, pgs, &phc[ci],
+ gs_currentaccuratescreens(mem), mem);
+ if (code < 0)
+ break;
+ poc->corder = senum.order;
+ poc->comp_number = gs_color_name_component_number(pgs->device,
+ color_names[i], strlen(color_names[i]), pht->type);
+ poc->cname = 0; /* name index values are not known (or needed) */
+ if (i == 0) /* Gray = Default */
+ pdht->order = poc->corder; /* Save default value */
+ }
+ if (code < 0)
+ break;
+ pdht->components = pocs;
+ pdht->num_comp = 4;
+ }
+ break;
+ case ht_type_spot:
+ code = process_spot(&pdht->order, pgs, &pht->params.spot, mem);
+ if (code < 0)
+ return code;
+ pdht->components = 0;
+ break;
+ case ht_type_threshold:
+ code = process_threshold(&pdht->order, pgs,
+ &pht->params.threshold, mem);
+ if (code < 0)
+ return code;
+ pdht->components = 0;
+ break;
+ case ht_type_threshold2:
+ code = process_threshold2(&pdht->order, pgs,
+ &pht->params.threshold2, mem);
+ if (code < 0)
+ return code;
+ pdht->components = 0;
+ break;
+ case ht_type_client_order:
+ code = process_client_order(&pdht->order, pgs,
+ &pht->params.client_order, mem);
+ if (code < 0)
+ return code;
+ pdht->components = 0;
+ break;
+ case ht_type_multiple:
+ case ht_type_multiple_colorscreen:
+ {
+ uint count = pht->params.multiple.num_comp;
+ bool have_Default = false;
+ uint i;
+ gs_halftone_component *phc = pht->params.multiple.components;
+ gx_ht_order_component *poc_next;
+
+ pocs = gs_alloc_struct_array(mem, count,
+ gx_ht_order_component,
+ &st_ht_order_component_element,
+ "gs_sethalftone");
+ if (pocs == 0)
+ return_error(gs_error_VMerror);
+ poc_next = pocs + 1;
+ for (i = 0; i < count; i++, phc++) {
+ gx_ht_order_component *poc;
+
+ if (phc->comp_number == GX_DEVICE_COLOR_MAX_COMPONENTS) {
+ if (have_Default) {
+ /* Duplicate Default */
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ }
+ poc = pocs;
+ have_Default = true;
+ } else if (i == count - 1 && !have_Default) {
+ /* No Default */
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ } else
+ poc = poc_next++;
+
+ poc->comp_number = phc->comp_number;
+ poc->cname = phc->cname;
+ switch (phc->type) {
+ case ht_type_spot:
+ code = process_spot(&poc->corder, pgs,
+ &phc->params.spot, mem);
+ break;
+ case ht_type_threshold:
+ code = process_threshold(&poc->corder, pgs,
+ &phc->params.threshold, mem);
+ break;
+ case ht_type_threshold2:
+ code = process_threshold2(&poc->corder, pgs,
+ &phc->params.threshold2, mem);
+ break;
+ case ht_type_client_order:
+ code = process_client_order(&poc->corder, pgs,
+ &phc->params.client_order, mem);
+ break;
+ default:
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ }
+ if (code < 0)
+ break;
+ }
+ if (code < 0)
+ break;
+ pdht->order = pocs[0].corder; /* Default */
+ if (count == 1) {
+ /* We have only a Default; */
+ /* we don't need components. */
+ gs_free_object(mem, pocs, "gs_sethalftone");
+ pdht->components = 0;
+ pdht->num_comp = 0;
+ } else {
+ pdht->components = pocs;
+ pdht->num_comp = count;
+ }
+ }
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ if (code < 0)
+ gs_free_object(mem, pocs, "gs_sethalftone");
+ return code;
+}
+
+/* ------ Internal routines ------ */
+
+/* Process a transfer function override, if any. */
+static int
+process_transfer(gx_ht_order * porder, gs_gstate * pgs,
+ gs_mapping_proc proc, gs_mapping_closure_t * pmc,
+ gs_memory_t * mem)
+{
+ gx_transfer_map *pmap;
+
+ if (proc == 0 && pmc->proc == 0)
+ return 0;
+ /*
+ * The transfer funtion is referenced by the order, so start the
+ * reference count at 1.
+ */
+ rc_alloc_struct_1(pmap, gx_transfer_map, &st_transfer_map, mem,
+ return_error(gs_error_VMerror),
+ "process_transfer");
+ pmap->proc = proc; /* 0 => use closure */
+ pmap->closure = *pmc;
+ pmap->id = gs_next_ids(mem, 1);
+ porder->transfer = pmap;
+ if (proc == gs_mapped_transfer)
+ return 0; /* nothing to load, the source is uninitialzed */
+ load_transfer_map(pgs, pmap, 0.0);
+ return 0;
+}
+
+/* Process a spot plane. */
+static int
+process_spot(gx_ht_order * porder, gs_gstate * pgs,
+ gs_spot_halftone * phsp, gs_memory_t * mem)
+{
+ gs_screen_enum senum;
+
+ int code = gx_ht_process_screen_memory(&senum, pgs, &phsp->screen,
+ phsp->accurate_screens, mem);
+
+ if (code < 0)
+ return code;
+ *porder = senum.order;
+ return process_transfer(porder, pgs, phsp->transfer,
+ &phsp->transfer_closure, mem);
+}
+
+/* Construct the halftone order from a threshold array. */
+void
+gx_ht_complete_threshold_order(gx_ht_order * porder)
+{
+ int num_levels = porder->num_levels;
+ uint *levels = porder->levels;
+ uint size = porder->num_bits;
+ gx_ht_bit *bits = porder->bit_data;
+ uint i, j;
+
+ /* The caller has set bits[i] = max(1, thresholds[i]). */
+ gx_sort_ht_order(bits, size);
+ /* We want to set levels[j] to the lowest value of i */
+ /* such that bits[i].mask > j. */
+ for (i = 0, j = 0; i < size; i++) {
+ if (bits[i].mask != j) {
+ if_debug3('h', "[h]levels[%u..%u] = %u\n",
+ j, (uint) bits[i].mask, i);
+ while (j < bits[i].mask)
+ levels[j++] = i;
+ }
+ }
+ while (j < num_levels)
+ levels[j++] = size;
+ gx_ht_construct_bits(porder);
+}
+int
+gx_ht_construct_threshold_order(gx_ht_order * porder, const byte * thresholds)
+{
+ return porder->procs->construct_order(porder, thresholds);
+}
+
+/* Process a threshold plane. */
+static int
+process_threshold(gx_ht_order * porder, gs_gstate * pgs,
+ gs_threshold_halftone * phtp, gs_memory_t * mem)
+{
+ int code;
+
+ porder->params.M = phtp->width, porder->params.N = 0;
+ porder->params.R = 1;
+ porder->params.M1 = phtp->height, porder->params.N1 = 0;
+ porder->params.R1 = 1;
+ code = gx_ht_alloc_threshold_order(porder, phtp->width, phtp->height,
+ 256, mem);
+ if (code < 0)
+ return code;
+ gx_ht_construct_threshold_order(porder, phtp->thresholds.data);
+ return process_transfer(porder, pgs, phtp->transfer,
+ &phtp->transfer_closure, mem);
+}
+
+/* Process an extended threshold plane. */
+static int
+process_threshold2(gx_ht_order * porder, gs_gstate * pgs,
+ gs_threshold2_halftone * phtp, gs_memory_t * mem)
+{
+ int code;
+ /*
+ * There are potentially 64K different levels for this plane, but this
+ * is more than we're willing to handle. Try to reduce the number of
+ * levels by dropping leading or trailing zero bits from the thresholds;
+ * as a last resort, drop (possibly significant) trailing bits.
+ */
+#define LOG2_MAX_HT_LEVELS 14
+#define MAX_HT_LEVELS (1 << LOG2_MAX_HT_LEVELS)
+ int bps = phtp->bytes_per_sample;
+ const byte *data = phtp->thresholds.data;
+ const int w1 = phtp->width, h1 = phtp->height, size1 = w1 * h1;
+ const int w2 = phtp->width2, h2 = phtp->height2, size2 = w2 * h2;
+ const uint size = size1 + size2;
+ const int d = (h2 == 0 ? h1 : igcd(h1, h2));
+ const int sod = size / d;
+ uint num_levels;
+ uint i;
+ int rshift = 0;
+ int shift;
+
+ {
+ uint mask = 0, max_thr = 0;
+
+ for (i = 0; i < size; ++i) {
+ uint thr =
+ (bps == 1 ? data[i] : (data[i * 2] << 8) + data[i * 2 + 1]);
+
+ mask |= thr;
+ max_thr = max(max_thr, thr);
+ }
+ if (mask == 0)
+ mask = 1, max_thr = 1;
+ while (!(mask & 1) || max_thr > MAX_HT_LEVELS)
+ mask >>= 1, max_thr >>= 1, rshift++;
+ num_levels = max_thr + 1;
+ }
+ /*
+ * Set nominal values for the params, and don't bother to call
+ * gx_compute_cell_values -- the values are only needed for spot
+ * halftones.
+ */
+ porder->params.M = sod, porder->params.N = d;
+ porder->params.R = 1;
+ porder->params.M1 = d, porder->params.N1 = sod;
+ porder->params.R1 = 1;
+ /*
+ * Determine the shift between strips. We don't know a closed formula
+ * for this, so we do it by enumeration.
+ */
+ shift = 0;
+ {
+ int x = 0, y = 0;
+
+ do {
+ if (y < h1)
+ x += w1, y += h2;
+ else
+ x += w2, y -= h1;
+ } while (y > d);
+ if (y)
+ shift = x;
+ }
+ code = gx_ht_alloc_ht_order(porder, sod, d, num_levels, size, shift,
+ &ht_order_procs_default, mem);
+ if (code < 0)
+ return code;
+ {
+ gx_ht_bit *bits = (gx_ht_bit *)porder->bit_data;
+ int row, di;
+
+ if_debug7m('h', mem, "[h]rect1=(%d,%d), rect2=(%d,%d), strip=(%d,%d), shift=%d\n",
+ w1, h1, w2, h2, sod, d, shift);
+ for (row = 0, di = 0; row < d; ++row) {
+ /* Iterate over destination rows. */
+ int dx, sy = row; /* sy = row mod d */
+ int w;
+
+ for (dx = 0; dx < sod; dx += w) {
+ /* Iterate within a destination row, over source rows. */
+ int si, j;
+
+ if (sy < h1) {
+ /* Copy a row from rect1. */
+ si = sy * w1;
+ w = w1;
+ sy += h2;
+ } else {
+ /* Copy a row from rect2. */
+ si = size1 + (sy - h1) * w2;
+ w = w2;
+ sy -= h1;
+ }
+ for (j = 0; j < w; ++j, ++si, ++di) {
+ uint thr =
+ (bps == 1 ? data[si] :
+ (data[si * 2] << 8) + data[si * 2 + 1])
+ >> rshift;
+
+ if_debug3('H', "[H]sy=%d, si=%d, di=%d\n", sy, si, di);
+ bits[di].mask = max(thr, 1);
+ }
+ }
+ }
+ }
+ gx_ht_complete_threshold_order(porder);
+ return process_transfer(porder, pgs, phtp->transfer, &phtp->transfer_closure, mem);
+#undef LOG2_MAX_HT_LEVELS
+#undef MAX_HT_LEVELS
+}
+
+/* Process a client-order plane. */
+static int
+process_client_order(gx_ht_order * porder, gs_gstate * pgs,
+ gs_client_order_halftone * phcop, gs_memory_t * mem)
+{
+ int code = (*phcop->procs->create_order) (porder, pgs, phcop, mem);
+
+ if (code < 0)
+ return code;
+ return process_transfer(porder, pgs, NULL,
+ &phcop->transfer_closure, mem);
+}