summaryrefslogtreecommitdiff
path: root/base
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2018-04-19 12:45:14 +0100
committerRobin Watts <Robin.Watts@artifex.com>2019-06-25 10:37:09 +0100
commit140a9359f3cc6739c7caf0796430bc3112cb3cd5 (patch)
tree91ef3f7e59c06fe13ecfff2d7d2461ebd8da1c2b /base
parentdd75f619d0ae98e21e30ad89d2e7d2cd4277cc2e (diff)
downloadghostpdl-140a9359f3cc6739c7caf0796430bc3112cb3cd5.tar.gz
Initial import of CAL.
Diffstat (limited to 'base')
-rw-r--r--base/cal.mak77
-rw-r--r--base/gdevdrop.c372
-rw-r--r--base/gs.mak1
-rw-r--r--base/gxicolor.c180
-rw-r--r--base/gxidata.c12
-rw-r--r--base/gximage.h5
-rw-r--r--base/gximono.c203
-rw-r--r--base/gxiscale.c15
-rw-r--r--base/lib.mak74
-rw-r--r--base/siscale_cal.c393
-rw-r--r--base/sisparam.h25
-rw-r--r--base/unix-gcc.mak1
-rw-r--r--base/winlib.mak1
13 files changed, 1313 insertions, 46 deletions
diff --git a/base/cal.mak b/base/cal.mak
new file mode 100644
index 000000000..004379624
--- /dev/null
+++ b/base/cal.mak
@@ -0,0 +1,77 @@
+# Copyright (C) 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., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
+# CA 94903, U.S.A., +1(415)492-9861, for further information.
+#
+
+# makefile for CAL library code.
+# Users of this makefile must define the following:
+# WITH_CAL - whether to compile in or link to the library
+# CALSRCDIR - the library source directory
+#
+# gs.mak and friends define the following:
+# CALOBJDIR - the output obj directory
+# CALGENDIR - generated (.dev) file directory
+#
+
+CAL_MAK=$(GLSRC)cal.mak $(TOP_MAKEFILES)
+
+CAL_GEN=$(CALOBJDIR)$(D)
+
+CAL_PREFIX=cal_
+CAL_OBJ=$(CALOBJDIR)$(D)
+CAL_SRC=$(CALSRCDIR)$(D)
+
+# source files to build from the CSDK source
+
+cal_OBJS = \
+ $(CAL_OBJ)$(CAL_PREFIX)cal.$(OBJ) \
+ $(CAL_OBJ)$(CAL_PREFIX)rescale.$(OBJ) \
+ $(CAL_OBJ)$(CAL_PREFIX)halftone.$(OBJ) \
+ $(CAL_OBJ)$(CAL_PREFIX)doubler.$(OBJ)
+
+cal_HDRS = \
+ $(CAL_SRC)cal.h \
+ $(CAL_SRC)cal-impl.h \
+
+# external link .dev - empty, as we add the lib to LDFLAGS
+#$(GLOBJ)cal.dev : $(CAL_MAK) $(ECHOGS_XE) \
+# $(CAL_MAK) $(MAKEDIRS)
+# $(SETMOD) $(CAL_GEN)cal
+
+# compile our own .dev
+$(GLOBJ)cal.dev : $(ECHOGS_XE) $(cal_OBJS) \
+ $(CAL_MAK) $(MAKEDIRS)
+ $(SETMOD) $(GLOBJ)cal $(cal_OBJS)
+
+# define our specific compiler
+CAL_CC=$(CC) $(CFLAGS) $(D_)OPJ_STATIC$(_D) $(D_)STANDARD_SLOW_VERSION$(_D) $(I_)$(CAL_GEN)$(_I) $(I_)$(CAL_SRC)$(_I)
+CAL_O=$(O_)$(CAL_OBJ)$(CAL_PREFIX)
+
+CAL_DEP=$(AK) $(CAL_MAK) $(MAKEDIRS)
+
+# explicit rules for building each source file
+# for simplicity we have every source file depend on all headers
+
+$(CAL_OBJ)$(CAL_PREFIX)cal.$(OBJ) : $(CAL_SRC)cal.c $(cal_HDRS) $(CAL_DEP)
+ $(CAL_CC) $(CAL_O)cal.$(OBJ) $(C_) $(CAL_SRC)cal.c
+
+$(CAL_OBJ)$(CAL_PREFIX)rescale.$(OBJ) : $(CAL_SRC)rescale.c $(cal_HDRS) $(CAL_DEP) $(CAL_SRC)rescale_c.h $(CAL_SRC)rescale_sse.h
+ $(CAL_CC) $(CAL_O)rescale.$(OBJ) $(C_) $(CAL_SRC)rescale.c
+
+$(CAL_OBJ)$(CAL_PREFIX)halftone.$(OBJ) : $(CAL_SRC)halftone.c $(cal_HDRS) $(CAL_DEP) $(CAL_SRC)halftone_c.h $(CAL_SRC)halftone_sse.h
+ $(CAL_CC) $(CAL_O)halftone.$(OBJ) $(C_) $(CAL_SRC)halftone.c
+
+$(CAL_OBJ)$(CAL_PREFIX)doubler.$(OBJ) : $(CAL_SRC)doubler.c $(cal_HDRS) $(CAL_DEP) $(CAL_SRC)double_c.h $(CAL_SRC)double_sse.h
+ $(CAL_CC) $(CAL_O)doubler.$(OBJ) $(C_) $(CAL_SRC)doubler.c
+
+# end of file
diff --git a/base/gdevdrop.c b/base/gdevdrop.c
index fe78cfc86..82e10fc8c 100644
--- a/base/gdevdrop.c
+++ b/base/gdevdrop.c
@@ -30,6 +30,38 @@
#include "gdevmrop.h"
#include "gxdevsop.h"
#include "stdint_.h"
+#ifdef WITH_CAL
+#include "cal.h"
+
+static void *
+cal_do_malloc(void *opaque, size_t size)
+{
+ gs_memory_t *mem = (gs_memory_t *)opaque;
+ return gs_alloc_bytes(mem, size, "cal_do_malloc");
+}
+
+static void *
+cal_do_realloc(void *opaque, void *ptr, size_t newsize)
+{
+ gs_memory_t *mem = (gs_memory_t *)opaque;
+ return gs_resize_object(mem, ptr, newsize, "cal_do_malloc");
+}
+
+static void
+cal_do_free(void *opaque, void *ptr)
+{
+ gs_memory_t *mem = (gs_memory_t *)opaque;
+ gs_free_object(mem, ptr, "cal_do_malloc");
+}
+
+static cal_allocators cal_allocs =
+{
+ cal_do_malloc,
+ cal_do_realloc,
+ cal_do_free
+};
+
+#endif
/*
* Define the maximum amount of space we are willing to allocate for a
@@ -1037,6 +1069,10 @@ struct mem_transform_pixel_region_state_s
transform_pixel_region_posture posture;
mem_transform_pixel_region_render_fn *render;
void *passthru;
+#ifdef WITH_CAL
+ cal_context *cal_ctx;
+ cal_doubler *cal_dbl;
+#endif
};
static void
@@ -1307,6 +1343,295 @@ mem_transform_pixel_region_render_portrait_1to1(gx_device *dev, mem_transform_pi
}
}
+#ifdef WITH_CAL
+static inline int
+template_mem_transform_pixel_region_render_portrait_1to2(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs, int spp)
+{
+ gx_device_memory *mdev = (gx_device_memory *)dev;
+ gx_dda_fixed_point pnext;
+ int vci, vdi;
+ int w = state->w;
+ int h = state->h;
+ int oleft, left, right;
+
+ if (h == 0)
+ return 0;
+
+ /* Clip on y */
+ get_portrait_y_extent(state, &vci, &vdi);
+ if (vci < state->clip.p.y)
+ vdi += vci - state->clip.p.y, vci = state->clip.p.y;
+ if (vci+vdi > state->clip.q.y)
+ vdi = state->clip.q.y - vci;
+ if (vdi <= 0)
+ return 0;
+
+ pnext = state->pixels;
+ dda_translate(pnext.x, (-fixed_epsilon));
+ left = fixed2int_var_rounded(dda_current(pnext.x));
+ if_debug5m('b', dev->memory, "[b]y=%d data_x=%d w=%d xt=%f yt=%f\n",
+ vci, data_x, w, fixed2float(dda_current(pnext.x)), fixed2float(dda_current(pnext.y)));
+ right = fixed2int_var_rounded(dda_current(pnext.x)) + w * 2;
+
+ if (left > right) {
+ int tmp = left; left = right; right = tmp;
+ }
+ oleft = left;
+ if (left < state->clip.p.x)
+ left = state->clip.p.x;
+ if (right > state->clip.q.x)
+ right = state->clip.q.x;
+ if (left < right) {
+ byte *out[2];
+ const byte *in = buffer[0] + (data_x + left - oleft) * spp;
+ int lines_out;
+ out[0] = mdev->base + left * spp + mdev->raster * vci;
+ out[1] = out[0] + (vdi > 1 ? mdev->raster : 0);
+ lines_out = cal_doubler_process(state->cal_dbl, dev->memory,
+ &in, &out[0]);
+ (void)lines_out;
+ /* assert(lines_out == 2) */
+ }
+
+ return 0;
+}
+
+static int
+mem_transform_pixel_region_render_portrait_1to2_1(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs)
+{
+ return template_mem_transform_pixel_region_render_portrait_1to2(dev, state, buffer, data_x, cmapper, pgs, 1);
+}
+
+static int
+mem_transform_pixel_region_render_portrait_1to2_3(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs)
+{
+ return template_mem_transform_pixel_region_render_portrait_1to2(dev, state, buffer, data_x, cmapper, pgs, 3);
+}
+
+static int
+mem_transform_pixel_region_render_portrait_1to2_4(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs)
+{
+ return template_mem_transform_pixel_region_render_portrait_1to2(dev, state, buffer, data_x, cmapper, pgs, 4);
+}
+
+static int
+mem_transform_pixel_region_render_portrait_1to2_n(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs)
+{
+ return template_mem_transform_pixel_region_render_portrait_1to2(dev, state, buffer, data_x, cmapper, pgs, state->spp);
+}
+
+static int
+mem_transform_pixel_region_render_portrait_1to2(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs)
+{
+ if (!cmapper->direct)
+ return mem_transform_pixel_region_render_portrait(dev, state, buffer, data_x, cmapper, pgs);
+ switch(state->spp) {
+ case 1:
+ return mem_transform_pixel_region_render_portrait_1to2_1(dev, state, buffer, data_x, cmapper, pgs);
+ case 3:
+ return mem_transform_pixel_region_render_portrait_1to2_3(dev, state, buffer, data_x, cmapper, pgs);
+ case 4:
+ return mem_transform_pixel_region_render_portrait_1to2_4(dev, state, buffer, data_x, cmapper, pgs);
+ default:
+ return mem_transform_pixel_region_render_portrait_1to2_n(dev, state, buffer, data_x, cmapper, pgs);
+ }
+}
+
+static inline int
+template_mem_transform_pixel_region_render_portrait_1to4(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs, int spp)
+{
+ gx_device_memory *mdev = (gx_device_memory *)dev;
+ gx_dda_fixed_point pnext;
+ int vci, vdi;
+ int w = state->w;
+ int h = state->h;
+ int oleft, left, right;
+
+ if (h == 0)
+ return 0;
+
+ /* Clip on y */
+ get_portrait_y_extent(state, &vci, &vdi);
+ if (vci < state->clip.p.y)
+ vdi += vci - state->clip.p.y, vci = state->clip.p.y;
+ if (vci+vdi > state->clip.q.y)
+ vdi = state->clip.q.y - vci;
+ if (vdi <= 0)
+ return 0;
+
+ pnext = state->pixels;
+ dda_translate(pnext.x, (-fixed_epsilon));
+ left = fixed2int_var_rounded(dda_current(pnext.x));
+ if_debug5m('b', dev->memory, "[b]y=%d data_x=%d w=%d xt=%f yt=%f\n",
+ vci, data_x, w, fixed2float(dda_current(pnext.x)), fixed2float(dda_current(pnext.y)));
+ right = fixed2int_var_rounded(dda_current(pnext.x)) + w * 4 * spp;
+
+ if (left > right) {
+ int tmp = left; left = right; right = tmp;
+ }
+ oleft = left;
+ if (left < state->clip.p.x)
+ left = state->clip.p.x;
+ if (right > state->clip.q.x)
+ right = state->clip.q.x;
+ if (left < right) {
+ byte *out[4];
+ const byte *in = buffer[0] + (data_x + left - oleft) * spp;
+ int lines_out;
+ out[0] = mdev->base + left * spp + mdev->raster * vci;
+ out[1] = out[0] + (vdi > 1 ? mdev->raster : 0);
+ out[2] = out[1] + (vdi > 2 ? mdev->raster : 0);
+ out[3] = out[2] + (vdi > 3 ? mdev->raster : 0);
+ lines_out = cal_doubler_process(state->cal_dbl, dev->memory,
+ &in, &out[0]);
+ (void)lines_out;
+ /* assert(lines_out == 4) */
+ }
+
+ return 0;
+}
+
+static int
+mem_transform_pixel_region_render_portrait_1to4_1(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs)
+{
+ return template_mem_transform_pixel_region_render_portrait_1to4(dev, state, buffer, data_x, cmapper, pgs, 1);
+}
+
+static int
+mem_transform_pixel_region_render_portrait_1to4_3(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs)
+{
+ return template_mem_transform_pixel_region_render_portrait_1to4(dev, state, buffer, data_x, cmapper, pgs, 3);
+}
+
+static int
+mem_transform_pixel_region_render_portrait_1to4_4(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs)
+{
+ return template_mem_transform_pixel_region_render_portrait_1to4(dev, state, buffer, data_x, cmapper, pgs, 4);
+}
+
+static int
+mem_transform_pixel_region_render_portrait_1to4_n(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs)
+{
+ return template_mem_transform_pixel_region_render_portrait_1to4(dev, state, buffer, data_x, cmapper, pgs, state->spp);
+}
+
+static int
+mem_transform_pixel_region_render_portrait_1to4(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs)
+{
+ if (!cmapper->direct)
+ return mem_transform_pixel_region_render_portrait(dev, state, buffer, data_x, cmapper, pgs);
+ switch(state->spp) {
+ case 1:
+ return mem_transform_pixel_region_render_portrait_1to4_1(dev, state, buffer, data_x, cmapper, pgs);
+ case 3:
+ return mem_transform_pixel_region_render_portrait_1to4_3(dev, state, buffer, data_x, cmapper, pgs);
+ case 4:
+ return mem_transform_pixel_region_render_portrait_1to4_4(dev, state, buffer, data_x, cmapper, pgs);
+ default:
+ return mem_transform_pixel_region_render_portrait_1to4_n(dev, state, buffer, data_x, cmapper, pgs);
+ }
+}
+
+static inline int
+template_mem_transform_pixel_region_render_portrait_1to8(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs, int spp)
+{
+ gx_device_memory *mdev = (gx_device_memory *)dev;
+ gx_dda_fixed_point pnext;
+ int vci, vdi;
+ int w = state->w;
+ int h = state->h;
+ int oleft, left, right;
+
+ if (h == 0)
+ return 0;
+
+ /* Clip on y */
+ get_portrait_y_extent(state, &vci, &vdi);
+ if (vci < state->clip.p.y)
+ vdi += vci - state->clip.p.y, vci = state->clip.p.y;
+ if (vci+vdi > state->clip.q.y)
+ vdi = state->clip.q.y - vci;
+ if (vdi <= 0)
+ return 0;
+
+ pnext = state->pixels;
+ dda_translate(pnext.x, (-fixed_epsilon));
+ left = fixed2int_var_rounded(dda_current(pnext.x));
+ if_debug5m('b', dev->memory, "[b]y=%d data_x=%d w=%d xt=%f yt=%f\n",
+ vci, data_x, w, fixed2float(dda_current(pnext.x)), fixed2float(dda_current(pnext.y)));
+ right = fixed2int_var_rounded(dda_current(pnext.x)) + w * 8;
+
+ if (left > right) {
+ int tmp = left; left = right; right = tmp;
+ }
+ oleft = left;
+ if (left < state->clip.p.x)
+ left = state->clip.p.x;
+ if (right > state->clip.q.x)
+ right = state->clip.q.x;
+ if (left < right) {
+ byte *out[8];
+ const byte *in = buffer[0] + (data_x + left - oleft) * spp;
+ int lines_out;
+ out[0] = mdev->base + left * spp + mdev->raster * vci;
+ out[1] = out[0] + (vdi > 1 ? mdev->raster : 0);
+ out[2] = out[1] + (vdi > 2 ? mdev->raster : 0);
+ out[3] = out[2] + (vdi > 3 ? mdev->raster : 0);
+ out[4] = out[3] + (vdi > 4 ? mdev->raster : 0);
+ out[5] = out[4] + (vdi > 5 ? mdev->raster : 0);
+ out[6] = out[5] + (vdi > 6 ? mdev->raster : 0);
+ out[7] = out[6] + (vdi > 7 ? mdev->raster : 0);
+ lines_out = cal_doubler_process(state->cal_dbl, dev->memory,
+ &in, &out[0]);
+ (void)lines_out;
+ /* assert(lines_out == 8) */
+ }
+
+ return 0;
+}
+
+static int
+mem_transform_pixel_region_render_portrait_1to8_1(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs)
+{
+ return template_mem_transform_pixel_region_render_portrait_1to8(dev, state, buffer, data_x, cmapper, pgs, 1);
+}
+
+static int
+mem_transform_pixel_region_render_portrait_1to8_3(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs)
+{
+ return template_mem_transform_pixel_region_render_portrait_1to8(dev, state, buffer, data_x, cmapper, pgs, 3);
+}
+
+static int
+mem_transform_pixel_region_render_portrait_1to8_4(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs)
+{
+ return template_mem_transform_pixel_region_render_portrait_1to8(dev, state, buffer, data_x, cmapper, pgs, 4);
+}
+
+static int
+mem_transform_pixel_region_render_portrait_1to8_n(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs)
+{
+ return template_mem_transform_pixel_region_render_portrait_1to8(dev, state, buffer, data_x, cmapper, pgs, state->spp);
+}
+
+static int
+mem_transform_pixel_region_render_portrait_1to8(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs)
+{
+ if (!cmapper->direct)
+ return mem_transform_pixel_region_render_portrait(dev, state, buffer, data_x, cmapper, pgs);
+ switch(state->spp) {
+ case 1:
+ return mem_transform_pixel_region_render_portrait_1to8_1(dev, state, buffer, data_x, cmapper, pgs);
+ case 3:
+ return mem_transform_pixel_region_render_portrait_1to8_3(dev, state, buffer, data_x, cmapper, pgs);
+ case 4:
+ return mem_transform_pixel_region_render_portrait_1to8_4(dev, state, buffer, data_x, cmapper, pgs);
+ default:
+ return mem_transform_pixel_region_render_portrait_1to8_n(dev, state, buffer, data_x, cmapper, pgs);
+ }
+}
+#endif
+
static inline int
template_mem_transform_pixel_region_render_landscape(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs, int spp)
{
@@ -1482,8 +1807,55 @@ mem_transform_pixel_region_begin(gx_device *dev, int w, int h, int spp,
state->h = h;
state->spp = spp;
state->posture = posture;
+#ifdef WITH_CAL
+ state->cal_ctx = NULL;
+ state->cal_dbl = NULL;
+#endif
if (state->posture == transform_pixel_region_portrait) {
+#ifdef WITH_CAL
+ int factor;
+ if (pixels->x.step.dQ == fixed_1*8 && pixels->x.step.dR == 0 && rows->y.step.dQ == fixed_1*8 && rows->y.step.dR == 0) {
+ state->render = mem_transform_pixel_region_render_portrait_1to8;
+ factor = 8;
+ goto use_doubler;
+ } else if (pixels->x.step.dQ == fixed_1*4 && pixels->x.step.dR == 0 && rows->y.step.dQ == fixed_1*4 && rows->y.step.dR == 0) {
+ state->render = mem_transform_pixel_region_render_portrait_1to4;
+ factor = 4;
+ goto use_doubler;
+ } else if (pixels->x.step.dQ == fixed_1*2 && pixels->x.step.dR == 0 && rows->y.step.dQ == fixed_1*2 && rows->y.step.dR == 0) {
+ unsigned int in_lines;
+ int l, r;
+ factor = 2;
+ state->render = mem_transform_pixel_region_render_portrait_1to2;
+ use_doubler:
+ l = fixed2int_var_rounded(dda_current(pixels->x));
+ r = fixed2int_var_rounded(dda_current(pixels->x) - fixed_epsilon) + w * factor;
+ if (l > r) {
+ int t = l; l = r; r = t;
+ }
+ if (l < state->clip.p.x || r > state->clip.q.x)
+ goto no_cal;
+ state->cal_ctx = cal_init(&cal_allocs, mem);
+ if (state->cal_ctx == NULL)
+ goto no_cal;
+ state->cal_dbl = cal_doubler_init(state->cal_ctx,
+ mem,
+ w,
+ h,
+ factor,
+ CAL_DOUBLE_NEAREST,
+ spp,
+ &in_lines);
+ /* assert(in_lines == 1) */
+ if (state->cal_dbl == NULL) {
+ cal_fin(state->cal_ctx, mem);
+ state->cal_ctx = NULL;
+ goto no_cal;
+ }
+ } else
+no_cal:
+#endif
if (pixels->x.step.dQ == fixed_1 && pixels->x.step.dR == 0)
state->render = mem_transform_pixel_region_render_portrait_1to1;
else
diff --git a/base/gs.mak b/base/gs.mak
index c011d51a8..ffb31e366 100644
--- a/base/gs.mak
+++ b/base/gs.mak
@@ -232,6 +232,7 @@ LCUPSGENDIR=$(GLGENDIR)
LCUPSOBJDIR=$(GLOBJDIR)
LCUPSIGENDIR=$(GLGENDIR)
LCUPSIOBJDIR=$(GLOBJDIR)
+CALOBJDIR=$(GLOBJDIR)
#**************** END PATCHES
diff --git a/base/gxicolor.c b/base/gxicolor.c
index 34cfaa469..7d7ea4aa3 100644
--- a/base/gxicolor.c
+++ b/base/gxicolor.c
@@ -59,7 +59,139 @@ iclass_proc(gs_image_class_4_color);
static irender_proc(image_render_color_DeviceN);
static irender_proc(image_render_color_icc_tpr);
+#ifndef WITH_CAL
static irender_proc(image_render_color_thresh);
+#else
+static irender_proc(image_render_color_ht_cal);
+
+static void *
+cal_do_malloc(void *opaque, size_t size)
+{
+ gs_memory_t *mem = (gs_memory_t *)opaque;
+ return gs_alloc_bytes(mem, size, "cal_do_malloc");
+}
+
+static void *
+cal_do_realloc(void *opaque, void *ptr, size_t newsize)
+{
+ gs_memory_t *mem = (gs_memory_t *)opaque;
+ return gs_resize_object(mem, ptr, newsize, "cal_do_malloc");
+}
+
+static void
+cal_do_free(void *opaque, void *ptr)
+{
+ gs_memory_t *mem = (gs_memory_t *)opaque;
+ gs_free_object(mem, ptr, "cal_do_malloc");
+}
+
+static cal_allocators cal_allocs =
+{
+ cal_do_malloc,
+ cal_do_realloc,
+ cal_do_free
+};
+
+static void
+color_halftone_callback(cal_halftone_data_t *ht, void *arg)
+{
+ gx_device *dev = arg;
+ gx_color_index dev_white = gx_device_white(dev);
+ gx_color_index dev_black = gx_device_black(dev);
+
+ if (dev->is_planar) {
+ (*dev_proc(dev, copy_planes)) (dev, ht->data, ht->x + (ht->offset_x<<3), ht->raster,
+ gx_no_bitmap_id, ht->x, ht->y, ht->w, ht->h,
+ ht->plane_raster);
+ } else {
+ (*dev_proc(dev, copy_mono)) (dev, ht->data, ht->x + (ht->offset_x<<3), ht->raster,
+ gx_no_bitmap_id, ht->x, ht->y, ht->w, ht->h, dev_white,
+ dev_black);
+ }
+}
+
+static cal_halftone*
+color_halftone_init(gx_image_enum *penum)
+{
+ void *callback;
+ void *args;
+ int ox;
+ int dd_curr_y;
+ int dev_width;
+ cal_halftone *cal_ht = NULL;
+ gx_dda_fixed dda_ht;
+ cal_context *ctx;
+ int k;
+ gx_ht_order *d_order;
+ int code;
+ byte *cache = (penum->color_cache != NULL ? penum->color_cache->device_contone : NULL);
+ cal_matrix matrix;
+ int clip_x, clip_y;
+
+ if (!gx_device_must_halftone(penum->dev))
+ return NULL;
+
+ if (penum->pgs == NULL || penum->pgs->dev_ht == NULL)
+ return NULL;
+ ctx = cal_init(&cal_allocs, penum->memory->non_gc_memory);
+ if (ctx == NULL)
+ return NULL;
+ penum->cal_ctx = ctx;
+ dda_ht = penum->dda.pixel0.x;
+ if (penum->dxx > 0)
+ dda_translate(dda_ht, -fixed_epsilon);
+ ox = dda_current(dda_ht);
+ dd_curr_y = dda_current(penum->dda.pixel0.y);
+ dev_width = gxht_dda_length(&dda_ht, penum->rect.w);
+ matrix.xx = penum->matrix.xx;
+ matrix.xy = penum->matrix.xy;
+ matrix.yx = penum->matrix.yx;
+ matrix.yy = penum->matrix.yy;
+ matrix.tx = penum->matrix.tx + matrix.xx * penum->rect.x + matrix.yx * penum->rect.y;
+ matrix.ty = penum->matrix.ty + matrix.xy * penum->rect.x + matrix.yy * penum->rect.y;
+ clip_x = fixed2int(penum->clip_outer.p.x);
+ clip_y = fixed2int(penum->clip_outer.p.y);
+ cal_ht = cal_halftone_init(ctx,
+ penum->memory->non_gc_memory,
+ penum->rect.w,
+ penum->rect.h,
+ &matrix,
+ penum->dev->color_info.num_components,
+ cache,
+ clip_x,
+ clip_y,
+ fixed2int_ceiling(penum->clip_outer.q.x) - clip_x,
+ fixed2int_ceiling(penum->clip_outer.q.y) - clip_y,
+ penum->adjust);
+ if (cal_ht == NULL)
+ goto fail;
+
+ for (k = 0; k < penum->pgs->dev_ht->num_comp; k++) {
+ d_order = &(penum->pgs->dev_ht->components[k].corder);
+ code = gx_ht_construct_threshold(d_order, penum->dev, penum->pgs, k);
+ if (code < 0)
+ goto fail;
+ if (cal_halftone_add_screen(ctx,
+ penum->memory->non_gc_memory,
+ cal_ht,
+ penum->pgs->dev_ht->components[k].corder.threshold_inverted,
+ penum->pgs->dev_ht->components[k].corder.width,
+ penum->pgs->dev_ht->components[k].corder.full_height,
+ -penum->pgs->screen_phase[k].x,
+ -penum->pgs->screen_phase[k].y,
+ penum->pgs->dev_ht->components[k].corder.threshold) < 0)
+ goto fail;
+ }
+
+ return cal_ht;
+
+fail:
+ cal_halftone_fin(cal_ht, penum->memory->non_gc_memory);
+ cal_fin(ctx, penum->memory->non_gc_memory);
+ penum->cal_ctx = NULL;
+ return NULL;
+}
+#endif
static int image_skip_color_icc_tpr(gx_image_enum *penum, gx_device *dev);
@@ -190,6 +322,14 @@ gs_image_class_4_color(gx_image_enum * penum, irender_proc_t *render_fn)
if ((bpc == 1) && transfer_is_monotonic &&
(penum->dev->color_info.num_components == 1 || penum->dev->is_planar) &&
penum->bps == 8) {
+#ifdef WITH_CAL
+ penum->cal_ht = color_halftone_init(penum);
+ if (penum->cal_ht != NULL)
+ {
+ penum->skip_render = image_render_color_ht_cal;
+ return code;
+ }
+#else
code = gxht_thresh_image_init(penum);
if (code == 0) {
/* NB: transfer function is pickled into the threshold arrray */
@@ -197,6 +337,7 @@ gs_image_class_4_color(gx_image_enum * penum, irender_proc_t *render_fn)
*render_fn = &image_render_color_thresh;
return code;
}
+#endif
}
}
{
@@ -469,9 +610,41 @@ image_color_icc_prep(gx_image_enum *penum_orig, const byte *psrc, uint w,
return 0;
}
+#ifdef WITH_CAL
+static int
+image_render_color_ht_cal(gx_image_enum *penum, const byte *buffer, int data_x,
+ uint w, int h, gx_device * dev)
+{
+ const byte *psrc = buffer + data_x;
+ int code = 0;
+ int spp_cm = 0;
+ byte *psrc_cm = NULL, *psrc_cm_start = NULL;
+ byte *bufend = NULL;
+ byte *input[GX_DEVICE_COLOR_MAX_COMPONENTS]; /* to ensure 128 bit boundary */
+
+ if (h == 0 || penum->line_size == 0) /* line_size == 0, nothing to do */
+ return 0;
+
+ /* Get the buffer into the device color space */
+ code = image_color_icc_prep(penum, psrc, w, dev, &spp_cm, &psrc_cm,
+ &psrc_cm_start, &bufend, true);
+ if (code < 0)
+ return code;
+
+ code = cal_halftone_process_planar(penum->cal_ht, penum->memory->non_gc_memory,
+ input, halftone_callback, dev);
+
+ /* Free cm buffer, if it was used */
+ if (psrc_cm_start != NULL) {
+ gs_free_object(penum->pgs->memory, (byte *)psrc_cm_start,
+ "image_render_color_thresh");
+ }
+ return code;
+}
+#else
static int
image_render_color_thresh(gx_image_enum *penum_orig, const byte *buffer, int data_x,
- uint w, int h, gx_device * dev)
+ uint w, int h, gx_device * dev)
{
gx_image_enum *penum = penum_orig; /* const within proc */
image_posture posture = penum->posture;
@@ -884,7 +1057,7 @@ flush:
thresh_align = penum->thresh_buffer + offset_threshold;
code = gxht_thresh_planes(penum, xrun, dest_width, dest_height,
thresh_align, dev, offset_contone,
- contone_stride);
+ contone_stride);
/* Free cm buffer, if it was used */
if (psrc_cm_start != NULL) {
gs_free_object(penum->pgs->memory, (byte *)psrc_cm_start,
@@ -892,9 +1065,10 @@ flush:
}
return code;
}
+#endif
/* Render a color image with 8 or fewer bits per sample using ICC profile. */
-static int
+static int
image_skip_color_icc_tpr(gx_image_enum *penum, gx_device *dev)
{
transform_pixel_region_data data;
diff --git a/base/gxidata.c b/base/gxidata.c
index dcdb2c41e..e55e5791c 100644
--- a/base/gxidata.c
+++ b/base/gxidata.c
@@ -22,6 +22,9 @@
#include "gxcpath.h"
#include "gximage.h"
#include "gsicc_cache.h"
+#ifdef WITH_CAL
+#include "cal.h"
+#endif
/* Forward declarations */
static void update_strip(gx_image_enum *penum);
@@ -519,6 +522,15 @@ gx_image1_end_image(gx_image_enum_common_t * info, bool draw_last)
}
gs_free_object(mem, penum->line, "image line");
gs_free_object(mem, penum->buffer, "image buffer");
+
+#ifdef WITH_CAL
+ if (penum->cal_ht != NULL) {
+ cal_halftone_fin(penum->cal_ht, mem->non_gc_memory);
+ }
+ if (penum->cal_ctx != NULL) {
+ cal_fin(penum->cal_ctx, mem->non_gc_memory);
+ }
+#endif
gx_image_free_enum(&info);
return 0;
}
diff --git a/base/gximage.h b/base/gximage.h
index 70e7c6b6a..08281e9e7 100644
--- a/base/gximage.h
+++ b/base/gximage.h
@@ -294,6 +294,11 @@ struct gx_image_enum_s {
gx_image_icc_setup_t icc_setup;
bool use_cie_range; /* Needed potentially if CS was PS CIE based */
void *tpr_state;
+ /* The following 2 pointers are only used if the CAL library is
+ * in place, but it's too much makefile upheaval to only have them
+ * here in CAL builds, so we live with them in all builds. */
+ void *cal_ht; /* CAL halftone state pointer */
+ void *cal_ctx; /* CAL context pointer */
};
/* Enumerate the pointers in an image enumerator. */
diff --git a/base/gximono.c b/base/gximono.c
index 5516b5cd6..709294431 100644
--- a/base/gximono.c
+++ b/base/gximono.c
@@ -42,6 +42,9 @@
#include "gxht_thresh.h"
#include "gxdda.h"
#include "gxdevsop.h"
+#ifdef WITH_CAL
+#include "cal.h"
+#endif
#define fastfloor(x) (((int)(x)) - (((x)<0) && ((x) != (float)(int)(x))))
@@ -57,7 +60,133 @@
iclass_proc(gs_image_class_3_mono);
static irender_proc(image_render_mono);
+#ifndef WITH_CAL
static irender_proc(image_render_mono_ht);
+#else
+static irender_proc(image_render_mono_ht_cal);
+static int image_render_mono_ht_cal_skip_line(gx_image_enum *penum);
+
+static void *
+cal_do_malloc(void *opaque, size_t size)
+{
+ gs_memory_t *mem = (gs_memory_t *)opaque;
+ return gs_alloc_bytes(mem, size, "cal_do_malloc");
+}
+
+static void *
+cal_do_realloc(void *opaque, void *ptr, size_t newsize)
+{
+ gs_memory_t *mem = (gs_memory_t *)opaque;
+ return gs_resize_object(mem, ptr, newsize, "cal_do_malloc");
+}
+
+static void
+cal_do_free(void *opaque, void *ptr)
+{
+ gs_memory_t *mem = (gs_memory_t *)opaque;
+ gs_free_object(mem, ptr, "cal_do_malloc");
+}
+
+static cal_allocators cal_allocs =
+{
+ cal_do_malloc,
+ cal_do_realloc,
+ cal_do_free
+};
+
+static void
+halftone_callback(cal_halftone_data_t *ht, void *arg)
+{
+ gx_device *dev = arg;
+ gx_color_index dev_white = gx_device_white(dev);
+ gx_color_index dev_black = gx_device_black(dev);
+
+ if (dev->is_planar) {
+ (*dev_proc(dev, copy_planes)) (dev, ht->data, ht->x + (ht->offset_x<<3), ht->raster,
+ gx_no_bitmap_id, ht->x, ht->y, ht->w, ht->h,
+ ht->plane_raster);
+ } else {
+ (*dev_proc(dev, copy_mono)) (dev, ht->data, ht->x + (ht->offset_x<<3), ht->raster,
+ gx_no_bitmap_id, ht->x, ht->y, ht->w, ht->h, dev_white,
+ dev_black);
+ }
+}
+
+static cal_halftone*
+halftone_init(gx_image_enum *penum)
+{
+ cal_halftone *cal_ht = NULL;
+ gx_dda_fixed dda_ht;
+ cal_context *ctx;
+ int k;
+ gx_ht_order *d_order;
+ int code;
+ byte *cache = (penum->color_cache != NULL ? penum->color_cache->device_contone : NULL);
+ cal_matrix matrix;
+ int clip_x, clip_y;
+
+ if (!gx_device_must_halftone(penum->dev))
+ return NULL;
+
+ if (penum->pgs == NULL || penum->pgs->dev_ht == NULL)
+ return NULL;
+ ctx = cal_init(&cal_allocs, penum->memory->non_gc_memory);
+ if (ctx == NULL)
+ return NULL;
+ penum->cal_ctx = ctx;
+ dda_ht = penum->dda.pixel0.x;
+ if (penum->dxx > 0)
+ dda_translate(dda_ht, -fixed_epsilon);
+ matrix.xx = penum->matrix.xx;
+ matrix.xy = penum->matrix.xy;
+ matrix.yx = penum->matrix.yx;
+ matrix.yy = penum->matrix.yy;
+ matrix.tx = penum->matrix.tx + matrix.xx * penum->rect.x + matrix.yx * penum->rect.y;
+ matrix.ty = penum->matrix.ty + matrix.xy * penum->rect.x + matrix.yy * penum->rect.y;
+
+ clip_x = fixed2int(penum->clip_outer.p.x);
+ clip_y = fixed2int(penum->clip_outer.p.y);
+ cal_ht = cal_halftone_init(ctx,
+ penum->memory->non_gc_memory,
+ penum->rect.w,
+ penum->rect.h,
+ &matrix,
+ penum->dev->color_info.num_components,
+ cache,
+ clip_x,
+ clip_y,
+ fixed2int_ceiling(penum->clip_outer.q.x) - clip_x,
+ fixed2int_ceiling(penum->clip_outer.q.y) - clip_y,
+ penum->adjust);
+ if (cal_ht == NULL)
+ goto fail;
+
+ for (k = 0; k < penum->pgs->dev_ht->num_comp; k++) {
+ d_order = &(penum->pgs->dev_ht->components[k].corder);
+ code = gx_ht_construct_threshold(d_order, penum->dev, penum->pgs, k);
+ if (code < 0)
+ goto fail;
+ if (cal_halftone_add_screen(ctx,
+ penum->memory->non_gc_memory,
+ cal_ht,
+ penum->pgs->dev_ht->components[k].corder.threshold_inverted,
+ penum->pgs->dev_ht->components[k].corder.width,
+ penum->pgs->dev_ht->components[k].corder.full_height,
+ -penum->pgs->screen_phase[k].x,
+ -penum->pgs->screen_phase[k].y,
+ penum->pgs->dev_ht->components[k].corder.threshold) < 0)
+ goto fail;
+ }
+
+ return cal_ht;
+
+fail:
+ cal_halftone_fin(cal_ht, penum->memory->non_gc_memory);
+ cal_fin(ctx, penum->memory->non_gc_memory);
+ penum->cal_ctx = NULL;
+ return NULL;
+}
+#endif
int
gs_image_class_3_mono(gx_image_enum * penum, irender_proc_t *render_fn)
@@ -169,11 +298,21 @@ gs_image_class_3_mono(gx_image_enum * penum, irender_proc_t *render_fn)
be done via thresholding we will keep clues in continuous tone */
code = image_init_color_cache(penum, penum->bps, penum->spp);
if (code >= 0) {
+#ifdef WITH_CAL
+ penum->cal_ht = halftone_init(penum);
+ if (penum->cal_ht != NULL)
+ {
+ penum->skip_next_line = image_render_mono_ht_cal_skip_line;
+ *render_fn = &image_render_mono_ht_cal;
+ return code;
+ }
+#else
code = gxht_thresh_image_init(penum);
if (code >= 0) {
*render_fn = &image_render_mono_ht;
return code;
}
+#endif
}
}
not_fast_halftoning:
@@ -879,6 +1018,25 @@ err:
return code;
}
+#ifdef WITH_CAL
+static int image_render_mono_ht_cal_skip_line(gx_image_enum *penum)
+{
+ return !cal_halftone_next_line_required(penum->cal_ht);
+}
+
+static int
+image_render_mono_ht_cal(gx_image_enum * penum, const byte * buffer, int data_x,
+ uint w, int h, gx_device * dev)
+{
+ const byte *input = buffer + data_x;
+
+ if (buffer == NULL)
+ return 0;
+
+ return cal_halftone_process_planar(penum->cal_ht, penum->memory->non_gc_memory,
+ &input, halftone_callback, dev);
+}
+#else
/*
An image render case where the source color is monochrome or indexed and
the output is to be halftoned. If the source color requires decoding,
@@ -1044,26 +1202,26 @@ image_render_mono_ht(gx_image_enum * penum_orig, const byte * buffer, int data_x
} else {
/* Mono case, forward */
for (k=0; k<src_size; k++) {
+ byte c = *psrc++;
dda_next(dda_ht);
xn = fixed2int_var_rounded(dda_current(dda_ht));
while (xr < xn) {
- *devc_contone_gray++ = *psrc;
+ *devc_contone_gray++ = c;
xr++;
} /* at loop exit xn will be >= xr */
- psrc++;
}
}
} else {
/* Mono case, backwards */
devc_contone_gray += (data_length - 1);
for (k=0; k<src_size; k++) {
+ byte c = *psrc++;
dda_next(dda_ht);
xn = fixed2int_var_rounded(dda_current(dda_ht));
while (xr > xn) {
- *devc_contone_gray-- = *psrc;
+ *devc_contone_gray-- = c;
xr--;
} /* at loop exit xn will be >= xr */
- psrc++;
}
}
break;
@@ -1075,14 +1233,14 @@ image_render_mono_ht(gx_image_enum * penum_orig, const byte * buffer, int data_x
position = penum->ht_landscape.curr_pos +
LAND_BITS * (data_length - 1);
for (k=0; k<src_size; k++) {
+ byte c = *psrc++;
dda_next(dda_ht);
xn = fixed2int_var_rounded(dda_current(dda_ht));
while (xr > xn) {
- devc_contone_gray[position] = *psrc;
+ devc_contone_gray[position] = c;
position -= LAND_BITS;
xr--;
} /* at loop exit xn will be <= xr */
- psrc++;
}
} else {
position = penum->ht_landscape.curr_pos;
@@ -1104,14 +1262,14 @@ image_render_mono_ht(gx_image_enum * penum_orig, const byte * buffer, int data_x
} else {
/* use dda */
for (k=0; k<src_size; k++) {
+ byte c = *psrc++;
dda_next(dda_ht);
xn = fixed2int_var_rounded(dda_current(dda_ht));
while (xr < xn) {
- devc_contone_gray[position] = *psrc;
+ devc_contone_gray[position] = c;
position += LAND_BITS;
xr++;
} /* at loop exit xn will be >= xr */
- psrc++;
}
}
}
@@ -1137,27 +1295,26 @@ image_render_mono_ht(gx_image_enum * penum_orig, const byte * buffer, int data_x
if (spp_out == 1) {
/* Mono case, forward */
for (k=0; k<src_size; k++) {
+ byte c = color_cache[*psrc++];
dda_next(dda_ht);
xn = fixed2int_var_rounded(dda_current(dda_ht));
while (xr < xn) {
- *devc_contone_gray++ = color_cache[*psrc];
+ *devc_contone_gray++ = c;
xr++;
} /* at loop exit xn will be >= xr */
- psrc++;
}
} else {
/* CMYK case, forward */
for (k=0; k<src_size; k++) {
+ dev_value = &(color_cache[*psrc++ * spp_out]);
dda_next(dda_ht);
xn = fixed2int_var_rounded(dda_current(dda_ht));
while (xr < xn) {
- dev_value = &(color_cache[*psrc * spp_out]);
for (j = 0; j < spp_out; j++) {
*(devc_contone[j])++ = dev_value[j];
}
xr++;
} /* at loop exit xn will be >= xr */
- psrc++;
}
}
} else {
@@ -1165,13 +1322,13 @@ image_render_mono_ht(gx_image_enum * penum_orig, const byte * buffer, int data_x
/* Mono case, backwards */
devc_contone_gray += data_length - 1; /* move to end */
for (k=0; k<src_size; k++) {
+ byte c = color_cache[*psrc++];
dda_next(dda_ht);
xn = fixed2int_var_rounded(dda_current(dda_ht));
while (xr > xn) {
- *devc_contone_gray-- = color_cache[*psrc];
+ *devc_contone_gray-- = c;
xr--;
} /* at loop exit xn will be <= xr */
- psrc++;
}
} else {
/* CMYK case, backwards */
@@ -1180,16 +1337,15 @@ image_render_mono_ht(gx_image_enum * penum_orig, const byte * buffer, int data_x
devc_contone[j] = devc_contone[j] + data_length - 1;
}
for (k=0; k<src_size; k++) {
+ dev_value = &(color_cache[*psrc++ * spp_out]);
dda_next(dda_ht);
xn = fixed2int_var_rounded(dda_current(dda_ht));
while (xr > xn) {
- dev_value = &(color_cache[*psrc * spp_out]);
for (j = 0; j < spp_out; j++) {
*(devc_contone[j])-- = dev_value[j];
}
xr--;
} /* at loop exit xn will be <= xr */
- psrc++;
}
}
}
@@ -1206,29 +1362,28 @@ image_render_mono_ht(gx_image_enum * penum_orig, const byte * buffer, int data_x
/* Mono case */
/* loop filling contone values selected from the source */
for (k=0; k<src_size; k++) {
+ byte c = color_cache[*psrc++];
dda_next(dda_ht);
xn = fixed2int_var_rounded(dda_current(dda_ht));
while (xr > xn) {
- devc_contone_gray[position] = color_cache[*psrc];
+ devc_contone_gray[position] = c;
position -= LAND_BITS;
xr--;
} /* at loop exit xn will be <= xr */
- psrc++;
}
} else {
/* CMYK case */
for (k=0; k<src_size; k++) {
+ dev_value = &(color_cache[*psrc++ * spp_out]);
dda_next(dda_ht);
xn = fixed2int_var_rounded(dda_current(dda_ht));
while (xr > xn) {
- dev_value = &(color_cache[*psrc * spp_out]);
for (j = 0; j < spp_out; j++) {
*(devc_contone[j] + position) = dev_value[j];
}
position -= LAND_BITS;
xr--;
} /* at loop exit xn will be <= xr */
- psrc++;
}
}
} else { /* Not flipped in Y */
@@ -1238,14 +1393,14 @@ image_render_mono_ht(gx_image_enum * penum_orig, const byte * buffer, int data_x
/* Mono case */
/* loop filling contone values selected from the source */
for (k=0; k<src_size; k++) {
+ byte c = color_cache[*psrc++];
dda_next(dda_ht);
xn = fixed2int_var_rounded(dda_current(dda_ht));
while (xr < xn) {
- devc_contone_gray[position] = color_cache[*psrc];
+ devc_contone_gray[position] = c;
position += LAND_BITS;
xr++;
} /* at loop exit xn will be >= xr */
- psrc++;
}
} else {
/* CMYK case */
@@ -1255,17 +1410,16 @@ image_render_mono_ht(gx_image_enum * penum_orig, const byte * buffer, int data_x
}
/* CMYK case */
for (k=0; k<src_size; k++) {
+ dev_value = &(color_cache[*psrc++ * spp_out]);
dda_next(dda_ht);
xn = fixed2int_var_rounded(dda_current(dda_ht));
while (xr < xn) {
- dev_value = &(color_cache[*psrc * spp_out]);
for (j = 0; j < spp_out; j++) {
*(devc_contone[j] + position) = dev_value[j];
}
position += LAND_BITS;
xr++;
} /* at loop exit xn will be >= xr */
- psrc++;
}
}
}
@@ -1288,3 +1442,4 @@ flush:
contone_stride);
return code;
}
+#endif
diff --git a/base/gxiscale.c b/base/gxiscale.c
index 4a5414435..8d733ba58 100644
--- a/base/gxiscale.c
+++ b/base/gxiscale.c
@@ -338,6 +338,15 @@ gs_image_class_0_interpolate(gx_image_enum * penum, irender_proc_t *render_fn)
dw / penum->Width));
iss.LeftMarginOut = fixed2int_pixround_perfect((fixed)((int64_t)(penum->rrect.x - penum->rect.x) *
dw / penum->Width));
+ iss.TopMarginOut2 = fixed2int_pixround_perfect((fixed)((int64_t)penum->rrect.y *
+ dh / penum->Height));
+ iss.PatchHeightOut2 = fixed2int_pixround_perfect((fixed)((int64_t)(penum->rrect.y + penum->rrect.h) *
+ dh / penum->Height))
+ - iss.TopMarginOut2;
+ iss.pad_y = iss.TopMarginOut2
+ - fixed2int_pixround_perfect(
+ (fixed)((int64_t)penum->rect.y *
+ dh / penum->Height));
} else {
fixed dw = any_abs(penum->dst_width);
fixed dh = any_abs(penum->dst_height);
@@ -362,6 +371,12 @@ gs_image_class_0_interpolate(gx_image_enum * penum, irender_proc_t *render_fn)
dh / penum->Width));
iss.LeftMarginOut = fixed2int_pixround_perfect((fixed)((int64_t)(penum->rrect.x - penum->rect.x) *
dh / penum->Width));
+ iss.TopMarginOut2 = fixed2int_pixround_perfect((fixed)((int64_t)penum->rrect.y *
+ dw / penum->Height));
+ iss.PatchHeightOut2 = fixed2int_pixround_perfect((fixed)((int64_t)(penum->rrect.y + penum->rrect.h) *
+ dw / penum->Height))
+ - iss.TopMarginOut2;
+ iss.pad_y = 0;
}
iss.PatchWidthOut = any_abs(iss.PatchWidthOut);
if (iss.LeftMarginOut + iss.PatchWidthOut >= iss.WidthOut) {
diff --git a/base/lib.mak b/base/lib.mak
index ffea9be34..eddf10919 100644
--- a/base/lib.mak
+++ b/base/lib.mak
@@ -151,6 +151,8 @@ jerror_h=$(JSRCDIR)$(D)jerror.h
jerror__h=$(GLSRC)jerror_.h $(MAKEFILE)
jpeglib__h=$(GLGEN)jpeglib_.h
+cal_h=$(CALSRCDIR)$(D)cal.h
+
# Miscellaneous
gsio_h=$(GLSRC)gsio.h
@@ -753,10 +755,20 @@ $(GLOBJ)gxht_thresh.$(OBJ) : $(GLSRC)gxht_thresh.c $(AK) $(memory__h)\
$(gxdevice_h) $(gxdht_h) $(gxht_thresh_h) $(gzht_h) $(gxdevsop_h) $(LIB_MAK) $(MAKEDIRS)
$(GLCC) $(GLO_)gxht_thresh.$(OBJ) $(C_) $(GLSRC)gxht_thresh.c
-$(GLOBJ)gxidata.$(OBJ) : $(GLSRC)gxidata.c $(AK) $(gx_h) $(gserrors_h)\
+$(GLOBJ)gxidata_0.$(OBJ) : $(GLSRC)gxidata.c $(AK) $(gx_h) $(gserrors_h)\
+ $(memory__h) $(gxcpath_h) $(gxdevice_h) $(gximage_h) $(gsicc_cache_h)\
+ $(LIB_MAK) $(MAKEDIRS)
+ $(GLCC) $(GLO_)gxidata_0.$(OBJ) $(C_) $(GLSRC)gxidata.c
+
+$(GLOBJ)gxidata_1.$(OBJ) : $(GLSRC)gxidata.c $(AK) $(cal_h) $(gx_h) $(gserrors_h)\
$(memory__h) $(gxcpath_h) $(gxdevice_h) $(gximage_h) $(gsicc_cache_h)\
$(LIB_MAK) $(MAKEDIRS)
- $(GLCC) $(GLO_)gxidata.$(OBJ) $(C_) $(GLSRC)gxidata.c
+ $(GLCC) -DWITH_CAL $(I_)$(CALSRCDIR)$(_I) $(GLO_)gxidata_1.$(OBJ) $(C_) $(GLSRC)gxidata.c
+
+$(GLOBJ)gxidata.$(OBJ) : $(GLOBJ)gxidata_$(WITH_CAL).$(OBJ) $(AK) $(gx_h) $(gserrors_h)\
+ $(memory__h) $(gxcpath_h) $(gxdevice_h) $(gximage_h) $(gsicc_cache_h)\
+ $(LIB_MAK) $(MAKEDIRS)
+ $(CP_) $(GLOBJ)gxidata_$(WITH_CAL).$(OBJ) $(GLOBJ)gxidata.$(OBJ)
$(GLOBJ)gxifast.$(OBJ) : $(GLSRC)gxifast.c $(AK) $(gx_h) $(gserrors_h)\
$(memory__h) $(gpcheck_h) $(gdevmem_h) $(gsbittab_h) $(gsccolor_h)\
@@ -774,13 +786,29 @@ $(GLOBJ)gximage1.$(OBJ) : $(GLSRC)gximage1.c $(AK) $(gx_h)\
$(gserrors_h) $(gximage_h) $(gxiparam_h) $(stream_h) $(memory__h) $(LIB_MAK) $(MAKEDIRS)
$(GLCC) $(GLO_)gximage1.$(OBJ) $(C_) $(GLSRC)gximage1.c
-$(GLOBJ)gximono.$(OBJ) : $(GLSRC)gximono.c $(AK) $(gx_h) $(gserrors_h)\
+$(GLOBJ)gximono_0.$(OBJ) : $(GLSRC)gximono.c $(AK) $(gx_h) $(gserrors_h)\
+ $(memory__h) $(gpcheck_h) $(gdevmem_h) $(gsccolor_h) $(gspaint_h) $(gsutil_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
+ $(gxdevmem_h) $(gxfixed_h) $(gximage_h) $(gxgstate_h) $(gxmatrix_h)\
+ $(gzht_h) $(gsicc_h) $(gsicc_cache_h) $(gsicc_cms_h)\
+ $(gxcie_h) $(gscie_h) $(gxht_thresh_h) $(gxdda_h) $(gxdevsop_h) $(LIB_MAK) $(MAKEDIRS)
+ $(GLCC) $(GLO_)gximono_0.$(OBJ) $(C_) $(GLSRC)gximono.c
+
+$(GLOBJ)gximono_1.$(OBJ) : $(GLSRC)gximono.c $(AK) $(cal_h) $(gx_h) $(gserrors_h)\
$(memory__h) $(gpcheck_h) $(gdevmem_h) $(gsccolor_h) $(gspaint_h) $(gsutil_h)\
$(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
$(gxdevmem_h) $(gxfixed_h) $(gximage_h) $(gxgstate_h) $(gxmatrix_h)\
$(gzht_h) $(gsicc_h) $(gsicc_cache_h) $(gsicc_cms_h)\
$(gxcie_h) $(gscie_h) $(gxht_thresh_h) $(gxdda_h) $(gxdevsop_h) $(LIB_MAK) $(MAKEDIRS)
- $(GLCC) $(GLO_)gximono.$(OBJ) $(C_) $(GLSRC)gximono.c
+ $(GLCC) -DWITH_CAL $(I_)$(CALSRCDIR)$(_I) $(GLO_)gximono_1.$(OBJ) $(C_) $(GLSRC)gximono.c
+
+$(GLOBJ)gximono.$(OBJ) : $(GLOBJ)gximono_$(WITH_CAL).$(OBJ) $(AK) $(gx_h) $(gserrors_h)\
+ $(memory__h) $(gpcheck_h) $(gdevmem_h) $(gsccolor_h) $(gspaint_h) $(gsutil_h)\
+ $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
+ $(gxdevmem_h) $(gxfixed_h) $(gximage_h) $(gxgstate_h) $(gxmatrix_h)\
+ $(gzht_h) $(gsicc_h) $(gsicc_cache_h) $(gsicc_cms_h)\
+ $(gxcie_h) $(gscie_h) $(gxht_thresh_h) $(gxdda_h) $(gxdevsop_h) $(LIB_MAK) $(MAKEDIRS)
+ $(CP_) $(GLOBJ)gximono_$(WITH_CAL).$(OBJ) $(GLOBJ)gximono.$(OBJ)
$(GLOBJ)gximask.$(OBJ) : $(GLSRC)gximask.c $(AK) $(gx_h) $(gserrors_h)\
$(memory__h) $(gsptype1_h) $(gsptype2_h) $(gxdevice_h) $(gxdcolor_h)\
@@ -2275,10 +2303,31 @@ $(GLOBJ)siinterp.$(OBJ) : $(GLSRC)siinterp.c $(AK)\
$(siinterp_h) $(strimpl_h) $(LIB_MAK) $(MAKEDIRS)
$(GLCC) $(GLO_)siinterp.$(OBJ) $(C_) $(GLSRC)siinterp.c
-$(GLOBJ)siscale.$(OBJ) : $(GLSRC)siscale.c $(AK)\
+$(GLOBJ)siscale_0.$(OBJ) : $(GLSRC)siscale.c $(AK)\
+ $(math__h) $(memory__h) $(stdio__h) $(stdint__h) $(gdebug_h) $(gxfrac_h)\
+ $(siscale_h) $(strimpl_h) $(LIB_MAK) $(MAKEDIRS)
+ $(GLCC) $(GLO_)siscale_0.$(OBJ) $(C_) $(GLSRC)siscale.c
+
+$(GLOBJ)siscale_1.$(OBJ) : $(GLSRC)siscale_cal.c $(AK) $(cal_h)\
+ $(math__h) $(memory__h) $(stdio__h) $(stdint__h) $(gdebug_h) $(gxfrac_h)\
+ $(siscale_h) $(strimpl_h) $(LIB_MAK) $(MAKEDIRS)
+ $(GLCC) $(GLO_)siscale_1.$(OBJ) $(I_)$(CALSRCDIR)$(_I) $(C_) $(GLSRC)siscale_cal.c
+
+$(GLOBJ)siscale.$(OBJ) : $(GLOBJ)siscale_$(WITH_CAL).$(OBJ) $(AK)\
$(math__h) $(memory__h) $(stdio__h) $(stdint__h) $(gdebug_h) $(gxfrac_h)\
$(siscale_h) $(strimpl_h) $(LIB_MAK) $(MAKEDIRS)
- $(GLCC) $(GLO_)siscale.$(OBJ) $(C_) $(GLSRC)siscale.c
+ $(CP_) $(GLOBJ)siscale_$(WITH_CAL).$(OBJ) $(GLOBJ)siscale.$(OBJ)
+
+# Dev file contains library files (or nothing)
+$(GLOBJ)siscale.dev : $(GLOBJ)siscale_$(WITH_CAL).dev\
+ $(CAL_MAK) $(MAKEDIRS)
+ $(CP_) $(GLOBJ)siscale_$(WITH_CAL).dev $(GLOBJ)siscale.dev
+
+$(GLOBJ)siscale_0.dev: $(ECHOGS_XE) $(MAKEDIRS)
+ $(SETMOD) $(GLOBJ)siscale_0
+
+$(GLOBJ)siscale_1.dev: $(GLOBJ)cal.dev $(ECHOGS_XE) $(CAL_OBJS) $(MAKEDIRS)
+ $(SETMOD) $(GLOBJ)siscale_1 -include $(GLOBJ)cal.dev
$(GLOBJ)sidscale.$(OBJ) : $(GLSRC)sidscale.c $(AK)\
$(math__h) $(memory__h) $(stdio__h) $(gdebug_h) $(gxdda_h) $(gxfixed_h)\
@@ -2321,11 +2370,20 @@ $(GLD)roplib.dev : $(LIB_MAK) $(ECHOGS_XE) $(roplib_) $(LIB_MAK) $(MAKEDIRS)
$(ADDMOD) $(GLD)roplib $(roplib2_)
$(ADDMOD) $(GLD)roplib $(roplib3_)
-$(GLOBJ)gdevdrop.$(OBJ) : $(GLSRC)gdevdrop.c $(AK) $(gx_h) $(gserrors_h) \
+$(GLOBJ)gdevdrop_1.$(OBJ) : $(GLSRC)gdevdrop.c $(AK) $(gx_h) $(gserrors_h) \
+ $(memory__h) $(gxdevsop_h) $(gsbittab_h) $(gsropt_h) $(gxcindex_h) \
+ $(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h) $(gxdevrop_h) $(gxgetbit_h) \
+ $(gdevmem_h) $(gdevmrop_h) $(gdevmpla_h) $(stdint__h) $(LIB_MAK) $(MAKEDIRS)
+ $(GLCC) -DWITH_CAL $(I_)$(CALSRCDIR)$(_I) $(GLO_)gdevdrop_1.$(OBJ) $(C_) $(GLSRC)gdevdrop.c
+
+$(GLOBJ)gdevdrop_0.$(OBJ) : $(GLSRC)gdevdrop.c $(AK) $(gx_h) $(gserrors_h) \
$(memory__h) $(gxdevsop_h) $(gsbittab_h) $(gsropt_h) $(gxcindex_h) \
$(gxdcolor_h) $(gxdevice_h) $(gxdevmem_h) $(gxdevrop_h) $(gxgetbit_h) \
$(gdevmem_h) $(gdevmrop_h) $(gdevmpla_h) $(stdint__h) $(LIB_MAK) $(MAKEDIRS)
- $(GLCC) $(GLO_)gdevdrop.$(OBJ) $(C_) $(GLSRC)gdevdrop.c
+ $(GLCC) $(GLO_)gdevdrop_0.$(OBJ) $(C_) $(GLSRC)gdevdrop.c
+
+$(GLOBJ)gdevdrop.$(OBJ) : $(GLOBJ)gdevdrop_$(WITH_CAL).$(OBJ)
+ $(CP_) $(GLOBJ)gdevdrop_$(WITH_CAL).$(OBJ) $(GLOBJ)gdevdrop.$(OBJ)
$(GLOBJ)gdevmr1.$(OBJ) : $(GLSRC)gdevmr1.c $(AK) $(gx_h) $(gserrors_h)\
$(memory__h) $(gsbittab_h) $(gsropt_h)\
diff --git a/base/siscale_cal.c b/base/siscale_cal.c
new file mode 100644
index 000000000..c8323aa0b
--- /dev/null
+++ b/base/siscale_cal.c
@@ -0,0 +1,393 @@
+/* Copyright (C) 2001-2017 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., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
+ CA 94903, U.S.A., +1(415)492-9861, for further information.
+*/
+
+/* Image scaling filters */
+#include "math_.h"
+#include "memory_.h"
+#include "stdio_.h"
+#include "stdint_.h"
+#include "gdebug.h"
+#include "strimpl.h"
+#include "siscale.h"
+#include "gxfrac.h"
+#include "cal.h"
+#include "assert_.h"
+
+/* ImageScaleEncode / ImageScaleDecode */
+typedef struct stream_IScale_cal_state_s {
+ /* The client sets the params values before initialization. */
+ stream_image_scale_state_common; /* = state_common + params */
+ /* The init procedure sets the following. */
+ cal_context *context;
+ cal_rescaler *rescaler;
+ uint8_t *src;
+ uint8_t *dst;
+ byte *tmp;
+ int pre_scan_bytes;
+ int post_scan_bytes;
+ /* The following are updated dynamically. */
+ int src_y;
+ uint src_offset, src_size;
+ int dst_y;
+ uint dst_offset, dst_size;
+} stream_IScale_cal_state;
+
+/* FIXME: */
+gs_private_st_ptrs2(st_IScale_cal_state, stream_IScale_cal_state,
+ "ImageScaleEncode/Decode state",
+ iscale_state_enum_ptrs, iscale_state_reloc_ptrs,
+ dst, src);
+
+/* ------ Stream implementation ------ */
+
+/* Forward references */
+static void s_IScale_cal_release(stream_state * st);
+
+/* Set default parameter values (actually, just clear pointers) */
+static void
+s_IScale_cal_set_defaults(stream_state * st)
+{
+ stream_IScale_cal_state *const ss = (stream_IScale_cal_state *) st;
+
+ ss->rescaler = NULL;
+}
+
+static void *
+cal_do_malloc(void *opaque, size_t size)
+{
+ gs_memory_t *mem = (gs_memory_t *)opaque;
+ return gs_alloc_bytes(mem, size, "cal_do_malloc");
+}
+
+static void *
+cal_do_realloc(void *opaque, void *ptr, size_t newsize)
+{
+ gs_memory_t *mem = (gs_memory_t *)opaque;
+ return gs_resize_object(mem, ptr, newsize, "cal_do_malloc");
+}
+
+static void
+cal_do_free(void *opaque, void *ptr)
+{
+ gs_memory_t *mem = (gs_memory_t *)opaque;
+ gs_free_object(mem, ptr, "cal_do_malloc");
+}
+
+static cal_allocators cal_allocs =
+{
+ cal_do_malloc,
+ cal_do_realloc,
+ cal_do_free
+};
+
+/*
+
+ Some notes:
+
+ (ss->params.XXXX is shown as XXXX in the following for sanity)
+
+ Conceptually we are scaling a bitmap that was EntireWidthIn x EntireHeightIn
+ in size, to be EntireWidthOut x EntireHeightOut in size.
+
+ But, we only actually care about a sub rectangle of this in the destination,
+ given by (LeftMarginOut, TopMarginOut) + (PatchWidthOut, PatchHeightOut).
+ Anything else is clipped away. There are times when this sub rectangle can
+ be very "sub" indeed, so the ability to avoid rescaling all the data we
+ don't care about is a vital one.
+
+ To confuse this further, we don't get fed scanlines of EntireWidthIn pixels,
+ instead we get WidthIn pixels. Similarly we don't feed scanlines out of
+ EntireWidthOut pixels, but rather of WidthOut pixels. Width{In,Out} are not
+ (always) the same as PatchWidth{In,Out} either.
+
+ Accordingly there may be padding before and after the active region. We make
+ the effort to ensure these bytes are set to zero.
+*/
+
+
+static int
+s_IScale_cal_init(stream_state * st)
+{
+ stream_IScale_cal_state *const ss = (stream_IScale_cal_state *) st;
+ gs_memory_t *mem = ss->memory;
+ int abs_interp_limit = ss->params.abs_interp_limit;
+ int limited_WidthOut = (ss->params.WidthOut + abs_interp_limit - 1) / abs_interp_limit;
+ int limited_PatchWidthOut = (ss->params.PatchWidthOut + abs_interp_limit - 1) / abs_interp_limit;
+ int limited_PatchHeightOut = (ss->params.PatchHeightOut2 + abs_interp_limit - 1) / abs_interp_limit;
+ int limited_EntireWidthOut = (ss->params.EntireWidthOut + abs_interp_limit - 1) / abs_interp_limit;
+ int limited_EntireHeightOut = (ss->params.EntireHeightOut + abs_interp_limit - 1) / abs_interp_limit;
+ int limited_LeftMarginOut = (ss->params.LeftMarginOut) / abs_interp_limit;
+ int limited_TopMarginOut = (ss->params.TopMarginOut2) / abs_interp_limit;
+ int limited_PadY = (ss->params.pad_y + abs_interp_limit/2 ) / abs_interp_limit;
+ int dst_bytes_per_pixel = ss->params.BitsPerComponentOut / 8;
+ int src_bytes_per_pixel = ss->params.BitsPerComponentIn / 8;
+
+ ss->context = cal_init(&cal_allocs, mem->non_gc_memory);
+ if (ss->context == NULL)
+ return ERRC;
+
+ ss->src_offset = 0;
+ ss->src_size = ss->params.WidthIn * ss->params.spp_interp * src_bytes_per_pixel;
+ ss->dst_offset = 0;
+ ss->dst_size = limited_WidthOut * ss->params.spp_interp * dst_bytes_per_pixel;
+ ss->dst_y = -limited_PadY;
+ ss->pre_scan_bytes = limited_LeftMarginOut * ss->params.spp_interp * dst_bytes_per_pixel;
+ ss->post_scan_bytes = (limited_WidthOut - limited_PatchWidthOut - limited_LeftMarginOut) * ss->params.spp_interp * dst_bytes_per_pixel;
+
+ ss->dst = gs_alloc_byte_array(mem, ss->dst_size, 1, "image_scale dst");
+ if (ss->dst == NULL)
+ goto fail;
+
+ ss->src = gs_alloc_byte_array(mem, ss->params.EntireWidthIn * ss->params.spp_interp,
+ src_bytes_per_pixel, "image_scale dst");
+ if (ss->src == NULL)
+ goto fail;
+
+ ss->rescaler = cal_rescaler_init(ss->context,
+ mem->non_gc_memory,
+ ss->params.EntireWidthIn,
+ ss->params.EntireHeightIn,
+ 0,
+ ss->params.src_y_offset,
+ ss->params.WidthIn,
+ ss->params.HeightIn,
+ limited_EntireWidthOut,
+ limited_EntireHeightOut,
+ limited_LeftMarginOut,
+ limited_TopMarginOut,
+ limited_PatchWidthOut,
+ limited_PatchHeightOut,
+ CAL_MITCHELL,
+ src_bytes_per_pixel,
+ dst_bytes_per_pixel,
+ ss->params.spp_interp,
+ ss->params.MaxValueIn,
+ ss->params.MaxValueOut);
+ if (ss->rescaler == NULL)
+ goto fail;
+
+ if (ss->pre_scan_bytes)
+ memset(ss->dst, 0, ss->pre_scan_bytes);
+ if (ss->post_scan_bytes)
+ memset(ss->dst + ss->dst_size - ss->post_scan_bytes, 0, ss->post_scan_bytes);
+
+ return 0;
+
+fail:
+ if (ss->rescaler)
+ cal_rescaler_fin(ss->rescaler, mem->non_gc_memory);
+ if (ss->context != NULL)
+ cal_fin(ss->context, mem->non_gc_memory);
+ gs_free_object(mem, ss->src, "image_scale src");
+ gs_free_object(mem, ss->dst, "image_scale dst");
+ return ERRC;
+}
+
+/* Process a buffer. Note that this handles Encode and Decode identically. */
+static int
+s_IScale_cal_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_IScale_cal_state *const ss = (stream_IScale_cal_state *) st;
+ gs_memory_t *mem = ss->memory;
+ int abs_interp_limit = ss->params.abs_interp_limit;
+ int limited_HeightOut = (ss->params.HeightOut + abs_interp_limit - 1) / abs_interp_limit;
+ uint wleft;
+ uint rleft;
+ int any_output = 0;
+ const byte *input = NULL;
+
+ /* If we have no more data to pull out, we're done. */
+ if (ss->dst_y == limited_HeightOut)
+ return EOFC;
+
+ /* How much room do we have left in the output buffer? */
+ wleft = pw->limit - pw->ptr;
+
+ /* If no room left, exit */
+ if (wleft == 0)
+ return 1;
+
+ /* If we need to send some padding at the top, do so */
+ if (ss->dst_y < 0)
+ {
+ uint wcount = ss->dst_size - ss->dst_offset;
+ uint ncopy = wcount;
+
+ if (ncopy > wleft)
+ ncopy = wleft;
+ memset(pw->ptr + 1, 0, ncopy);
+ pw->ptr += ncopy;
+ wcount -= ncopy;
+ if (wcount == 0)
+ {
+ ss->dst_offset = 0;
+ ss->dst_y++;
+ }
+ else
+ ss->dst_offset += ncopy;
+ wleft -= ncopy;
+ /* Unless we can get a whole new line out, pass out what we have */
+ if (wleft < ss->dst_size)
+ return 1;
+ any_output = 1;
+ }
+
+ /* Pass out any buffered data we have */
+ if (ss->dst_offset != 0)
+ {
+ uint wcount = ss->dst_size - ss->dst_offset;
+ uint ncopy = wcount;
+
+ if (ncopy > wleft)
+ ncopy = wleft;
+ memcpy(pw->ptr + 1, (byte *) ss->dst + ss->dst_offset, ncopy);
+ pw->ptr += ncopy;
+ wcount -= ncopy;
+ if (wcount == 0)
+ {
+ ss->dst_offset = 0;
+ ss->dst_y++;
+ }
+ else
+ ss->dst_offset += ncopy;
+ wleft -= ncopy;
+ /* Unless we can get a whole new line out, pass out what we have */
+ if (wleft < ss->dst_size)
+ return 1;
+ any_output = 1;
+ }
+
+ /* How much data do we have in the incoming buffer? */
+ rleft = pr->limit - pr->ptr;
+ if (rleft > 0 && ss->src_offset > 0) {
+ /* We have part of a line buffered. Let's fill that out. */
+ uint ncopy = ss->src_size - ss->src_offset;
+ if (ncopy > rleft)
+ ncopy = rleft;
+ memcpy(ss->src + ss->src_offset, pr->ptr + 1, ncopy);
+ pr->ptr += ncopy;
+ rleft -= ncopy;
+ ss->src_offset += ncopy;
+ if (ss->src_offset == ss->src_size)
+ {
+ ss->src_offset = 0;
+ input = ss->src;
+ }
+ }
+ else if (rleft >= ss->src_size)
+ input = pr->ptr+1;
+
+ /* If we can extract a whole extra output line, then try for that.
+ * Try anyway if we haven't managed to output anything. */
+ while (wleft >= ss->dst_size || any_output == 0)
+ {
+ uint8_t *row;
+ int ret;
+
+ if (wleft >= ss->dst_size) {
+ /* We can scale the row directly into the output. */
+ row = pw->ptr + 1;
+ } else {
+ /* We'll have to buffer the row. */
+ row = ss->dst;
+ }
+ ret = cal_rescaler_process(ss->rescaler, mem, input, row + ss->pre_scan_bytes);
+ if (ret & 1)
+ {
+ /* Input consumed */
+ if (input != ss->src)
+ {
+ pr->ptr += ss->src_size;
+ rleft -= ss->src_size;
+ }
+ input = (rleft >= ss->src_size) ? pr->ptr+1 : NULL;
+ ss->src_y++;
+ }
+ if (ret & 2)
+ {
+ /* Output given */
+ if (row == ss->dst)
+ {
+ /* Copy as much of the the buffered data out as
+ * possible - we can't manage a whole line. */
+ memcpy(pw->ptr+1, ss->dst, wleft);
+ pw->ptr += wleft;
+ ss->dst_offset = wleft;
+ return 1;
+ }
+ else
+ {
+ /* We are scaling direct into the output. Clear any pre and
+ * post sections for neatness. */
+ if (ss->pre_scan_bytes != 0)
+ memset(row, 0, ss->pre_scan_bytes);
+ if (ss->post_scan_bytes != 0)
+ memset(row + ss->dst_size - ss->post_scan_bytes, 0, ss->post_scan_bytes);
+ }
+ pw->ptr += ss->dst_size;
+ ss->dst_y++;
+ wleft -= ss->dst_size;
+ any_output = 1;
+ }
+ /* If nothing happened, nothing to be gained from calling again */
+ if (ret == 0)
+ break;
+ }
+
+ if (any_output == 0 && rleft > 0)
+ {
+ /* We've not managed to output anything, so the rescaler
+ * must be waiting for input data. If we had a whole line of
+ * data, we'd have tried to pass it in above. So we must
+ * have only the start of a line. */
+ assert(rleft < ss->src_size && ss->dst_offset == 0);
+ memcpy(ss->src, pr->ptr + 1, rleft);
+ ss->src_offset += rleft;
+ pr->ptr += rleft;
+ return 1;
+ }
+
+ return any_output;
+}
+
+/* Release the filter's storage. */
+static void
+s_IScale_cal_release(stream_state * st)
+{
+ stream_IScale_cal_state *const ss = (stream_IScale_cal_state *) st;
+ gs_memory_t *mem = ss->memory;
+
+ if (ss->rescaler)
+ {
+ cal_rescaler_fin(ss->rescaler, mem->non_gc_memory);
+ ss->rescaler = NULL;
+ }
+ if (ss->context != NULL)
+ {
+ cal_fin(ss->context, mem->non_gc_memory);
+ ss->context = NULL;
+ }
+ gs_free_object(mem, ss->src, "image_scale src");
+ ss->src = NULL;
+ gs_free_object(mem, ss->dst, "image_scale dst");
+ ss->dst = NULL;
+}
+
+/* Stream template */
+const stream_template s_IScale_template = {
+ &st_IScale_cal_state, s_IScale_cal_init, s_IScale_cal_process, 1, 1,
+ s_IScale_cal_release, s_IScale_cal_set_defaults
+};
diff --git a/base/sisparam.h b/base/sisparam.h
index 70010f72f..8082270b5 100644
--- a/base/sisparam.h
+++ b/base/sisparam.h
@@ -100,17 +100,17 @@
*
* <--------------------EntireWidthOut---------------------->
* +--------------------------------------------------------+ ^
- * | Conceptual Destination Image ^ | |
- * | | | |
- * | DY | |
- * | | | |
- * |<-DX-><---------------WidthOut--------------> v | |
- * | +-------------------------------------+ ^ | |
- * | | ^ | | | EntireHeightOut
- * | | | | | | |
- * | | TopMarginOut | | | |
- * | | | | | | |
- * | | v | | | |
+ * | Conceptual Destination Image ^ ^ | |
+ * | | | | |
+ * | | DY | |
+ * | | | | |
+ * |<-DX-><---------------WidthOut------|-------> v | |
+ * | +-----------------------------|-------+ ^ | |
+ * | | ^ | | | | EntireHeightOut
+ * | | | | | | | |
+ * | | TopMarginOut TopMarginOut2 | | | |
+ * | | | | | | | |
+ * | | v v | | | |
* | | +-penum->rrect*--+ | | | |
* | | | ^ | | HeightOut | |
* | | | | | | | | |
@@ -160,6 +160,9 @@ typedef struct stream_image_scale_params_s {
int LeftMarginOut;
int TopMarginIn;
int TopMarginOut;
+ int TopMarginOut2;
+ int PatchHeightOut2;
+ int pad_y;
int Active;
gx_dda_fixed_point scale_dda; /* used to scale limited interpolation up to actual size */
} stream_image_scale_params_t;
diff --git a/base/unix-gcc.mak b/base/unix-gcc.mak
index 933bd7750..a316038f2 100644
--- a/base/unix-gcc.mak
+++ b/base/unix-gcc.mak
@@ -666,6 +666,7 @@ include $(GLSRCDIR)/jbig2.mak
include $(GLSRCDIR)/ldf_jb2.mak
include $(GLSRCDIR)/lwf_jp2.mak
include $(GLSRCDIR)/openjpeg.mak
+include $(GLSRCDIR)/cal.mak
include $(GLSRCDIR)/jpegxr.mak
include $(GLSRCDIR)/expat.mak
diff --git a/base/winlib.mak b/base/winlib.mak
index 1e65b6db2..7767b6337 100644
--- a/base/winlib.mak
+++ b/base/winlib.mak
@@ -149,6 +149,7 @@ BEGINFILES=$(GLGENDIR)\ccf32.tr\
!include $(GLSRCDIR)\ldf_jb2.mak
!include $(GLSRCDIR)\lwf_jp2.mak
!include $(GLSRCDIR)\openjpeg.mak
+!include $(GLSRCDIR)\cal.mak
!include $(GLSRCDIR)\expat.mak
!include $(GLSRCDIR)\jpegxr.mak