[gs-cvs] rev 7819 - trunk/gs/src
stefan at ghostscript.com
stefan at ghostscript.com
Tue Apr 3 09:08:50 PDT 2007
Author: stefan
Date: 2007-04-03 09:08:49 -0700 (Tue, 03 Apr 2007)
New Revision: 7819
Added:
trunk/gs/src/gdevwts.c
Modified:
trunk/gs/src/gdevdbit.c
trunk/gs/src/gdevpng.c
trunk/gs/src/gdevppla.c
trunk/gs/src/gdevppla.h
trunk/gs/src/gdevprn.c
trunk/gs/src/gdevprn.h
trunk/gs/src/gswts.c
trunk/gs/src/gxbitfmt.h
trunk/gs/src/gxcldev.h
trunk/gs/src/gxclimag.c
trunk/gs/src/gxclist.c
trunk/gs/src/gxclist.h
trunk/gs/src/gxclpath.c
trunk/gs/src/gxclread.c
trunk/gs/src/gxclrect.c
trunk/gs/src/gxclutil.c
trunk/gs/src/gxdevbuf.h
trunk/gs/src/gxgetbit.h
trunk/gs/src/gxwts.c
trunk/gs/src/gxwts.h
Log:
Committing Raph's wtsimdi device
DETAILS:
-r600 -sDEVICE=wtsimdi does a performance optimized clist reader that either directly halftones
or uses an intermediate rgb buffer to do non-trivial ROPS correctly then post halftones
on a per band basis.
Uses icc color profiles to convert to device color.
Uses wts halftone algorithm.
The device reads in a link icc profile from "link.icc", and WTS
halftone files from wts_plane_[0123]. It generates a ppm file that
can be used to visualize the halftoned file (it is prepared from the
CMYK bits in the procedure write_pkmraw_row in gdevwts.c - if an
actual device is available, that routine should be modified to produce
data for the device).
This device _does_ switch on a per-band basis between continuous
tone pathways (true branch of the "if" statement in
wtsimdi_create_buf_device) and halftone, based on whether there are
rops. That is the major point of the work.
This is not yet production ready, but is useful for performance and integration work.
Known issues:
1. Banding only, low res non-banding will crash,
the device is intended for printer resolution halftoning, at 600dpi
The halftones are designed for 600dpi.
2. Color profiles and halftone screens are not in romfs,
These need to be copied into the same object/binary directory
that the application is in for now.
./pspcl6 and ./wts_* and ./*.icc in the same directory.
Failure to find these files will crash.
3. Halftone phase not set correctly in halftone band.
4. copy_mono doesn't optimize all-0 and all-1 colors as much as it
should - it can avoid processing the screen at that point.
5. halftone mode implemented only for rgb color model, not CMYK.
6. size of band_colors_used[] array is statically determined
EXPECTED DIFFERENCES :
None, unless -sDEVICE=wtsimdi is used.
Modified: trunk/gs/src/gdevdbit.c
===================================================================
--- trunk/gs/src/gdevdbit.c 2007-04-02 22:34:51 UTC (rev 7818)
+++ trunk/gs/src/gdevdbit.c 2007-04-03 16:08:49 UTC (rev 7819)
@@ -49,8 +49,12 @@
bool invert;
gx_color_index color;
gx_device_color devc;
-
+
+ if (!data)
+ gs_throw(-997, __FUNCTION__ );
fit_copy(dev, data, dx, raster, id, x, y, w, h);
+ if (!data)
+ gs_throw(-997, __FUNCTION__ );
if (one != gx_no_color_index) {
invert = false;
color = one;
@@ -65,7 +69,11 @@
invert = true;
color = zero;
}
+ if (!data)
+ gs_throw(-997, __FUNCTION__ );
set_nonclient_dev_color(&devc, color);
+ if (!data)
+ gs_throw(-997, __FUNCTION__ );
return gx_dc_default_fill_masked
(&devc, data, dx, raster, id, x, y, w, h, dev, rop3_T, invert);
}
Modified: trunk/gs/src/gdevpng.c
===================================================================
--- trunk/gs/src/gdevpng.c 2007-04-02 22:34:51 UTC (rev 7818)
+++ trunk/gs/src/gdevpng.c 2007-04-03 16:08:49 UTC (rev 7819)
@@ -449,11 +449,11 @@
private int
pngalpha_create_buf_device(gx_device **pbdev, gx_device *target,
const gx_render_plane_t *render_plane, gs_memory_t *mem,
- bool for_band)
+ gx_band_complexity_t *band_complexity)
{
gx_device_printer *ptarget = (gx_device_printer *)target;
int code = gx_default_create_buf_device(pbdev, target,
- render_plane, mem, for_band);
+ render_plane, mem, band_complexity);
/* Now set copy_alpha to one that handles RGBA */
set_dev_proc(*pbdev, copy_alpha, ptarget->orig_procs.copy_alpha);
return code;
Modified: trunk/gs/src/gdevppla.c
===================================================================
--- trunk/gs/src/gdevppla.c 2007-04-02 22:34:51 UTC (rev 7818)
+++ trunk/gs/src/gdevppla.c 2007-04-03 16:08:49 UTC (rev 7819)
@@ -95,7 +95,7 @@
int
gdev_prn_create_buf_planar(gx_device **pbdev, gx_device *target,
const gx_render_plane_t *render_plane,
- gs_memory_t *mem, bool for_band)
+ gs_memory_t *mem, gx_band_complexity_t *for_band)
{
int code = gx_default_create_buf_device(pbdev, target, render_plane, mem,
for_band);
Modified: trunk/gs/src/gdevppla.h
===================================================================
--- trunk/gs/src/gdevppla.h 2007-04-02 22:34:51 UTC (rev 7818)
+++ trunk/gs/src/gdevppla.h 2007-04-03 16:08:49 UTC (rev 7819)
@@ -34,7 +34,7 @@
/* Use this instead of the default if UsePlanarBuffer is true. */
int gdev_prn_create_buf_planar(gx_device **pbdev, gx_device *target,
const gx_render_plane_t *render_plane,
- gs_memory_t *mem, bool for_band);
+ gs_memory_t *mem, gx_band_complexity_t *for_band);
/* Determine the space needed by a planar buffer device. */
/* Use this instead of the default if UsePlanarBuffer is true. */
Modified: trunk/gs/src/gdevprn.c
===================================================================
--- trunk/gs/src/gdevprn.c 2007-04-02 22:34:51 UTC (rev 7818)
+++ trunk/gs/src/gdevprn.c 2007-04-03 16:08:49 UTC (rev 7819)
@@ -351,7 +351,7 @@
ppdev->buffer_space = 0;
if ((code = gdev_create_buf_device
(ppdev->printer_procs.buf_procs.create_buf_device,
- &bdev, pdev, NULL, NULL, false)) < 0 ||
+ &bdev, pdev, NULL, NULL, NULL)) < 0 ||
(code = ppdev->printer_procs.buf_procs.setup_buf_device
(bdev, base, buf_space.raster,
(byte **)(base + buf_space.bits), 0, pdev->height,
@@ -968,9 +968,9 @@
gdev_create_buf_device(create_buf_device_proc_t cbd_proc, gx_device **pbdev,
gx_device *target,
const gx_render_plane_t *render_plane,
- gs_memory_t *mem, bool for_band)
+ gs_memory_t *mem, gx_band_complexity_t *band_complexity)
{
- int code = cbd_proc(pbdev, target, render_plane, mem, for_band);
+ int code = cbd_proc(pbdev, target, render_plane, mem, band_complexity);
if (code < 0)
return code;
@@ -985,7 +985,7 @@
*/
int
gx_default_create_buf_device(gx_device **pbdev, gx_device *target,
- const gx_render_plane_t *render_plane, gs_memory_t *mem, bool for_band)
+ const gx_render_plane_t *render_plane, gs_memory_t *mem, gx_band_complexity_t *band_complexity)
{
int plane_index = (render_plane ? render_plane->index : -1);
int depth;
@@ -1014,7 +1014,7 @@
check_device_separable((gx_device *)mdev);
gx_device_fill_in_procs((gx_device *)mdev);
} else
- gs_make_mem_device(mdev, mdproto, mem, (for_band ? 1 : 0),
+ gs_make_mem_device(mdev, mdproto, mem, (band_complexity == NULL ? 1 : 0),
(target == (gx_device *)mdev ? NULL : target));
mdev->width = target->width;
/*
@@ -1050,7 +1050,7 @@
int
gx_default_size_buf_device(gx_device_buf_space_t *space, gx_device *target,
const gx_render_plane_t *render_plane,
- int height, bool for_band)
+ int height, bool not_used)
{
gx_device_memory mdev;
Modified: trunk/gs/src/gdevprn.h
===================================================================
--- trunk/gs/src/gdevprn.h 2007-04-02 22:34:51 UTC (rev 7818)
+++ trunk/gs/src/gdevprn.h 2007-04-03 16:08:49 UTC (rev 7819)
@@ -637,7 +637,7 @@
int gdev_create_buf_device(create_buf_device_proc_t cbd_proc,
gx_device **pbdev, gx_device *target,
const gx_render_plane_t *render_plane,
- gs_memory_t *mem, bool for_band);
+ gs_memory_t *mem, gx_band_complexity_t *band_complexity);
/* BACKWARD COMPATIBILITY */
#define dev_print_scan_lines(dev)\
Added: trunk/gs/src/gdevwts.c
===================================================================
--- trunk/gs/src/gdevwts.c 2007-04-02 22:34:51 UTC (rev 7818)
+++ trunk/gs/src/gdevwts.c 2007-04-03 16:08:49 UTC (rev 7819)
@@ -0,0 +1,1041 @@
+/* Copyright (C) 2006 artofcode LLC. 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.
+
+ For more information about licensing, please refer to
+ http://www.ghostscript.com/licensing/. For information on
+ commercial licensing, go to http://www.artifex.com/licensing/ or
+ contact Artifex Software, Inc., 101 Lucas Valley Road #110,
+ San Rafael, CA 94903, U.S.A., +1(415)492-9861.
+*/
+
+/* $Id: gdevwts.c 6300 2005-12-28 19:56:24Z giles $ */
+
+/* TODO: this should be configurable */
+#define LINK_ICC_NAME "../../link.icc"
+
+#include "errno_.h"
+#include "string_.h"
+
+#include "gdevprn.h"
+#include "gsdevice.h"
+#include "gxfrac.h"
+#include "gsht.h"
+#include "gxwts.h"
+#include "gswts.h"
+#include "gxgetbit.h"
+
+#include "icc.h"
+#include "imdi.h"
+
+/* Memory arg is included in ghostpcl branch but not main branch. */
+#define GS_NOTE_ERROR(m, e) gs_note_error(e)
+
+#ifndef X_DPI
+# define X_DPI 72
+#endif
+#ifndef Y_DPI
+# define Y_DPI 72
+#endif
+
+typedef struct {
+ wts_screen_t *wts;
+ byte *cell;
+ int width_padded;
+} wts_cooked_halftone;
+
+typedef struct gx_device_wts_s {
+ gx_device_common;
+ gx_prn_device_common;
+ wts_cooked_halftone wcooked[4];
+} gx_device_wts;
+
+private dev_proc_print_page(wtscmyk_print_page);
+
+/* 8-bit-per-plane separated CMYK color. */
+
+private const gx_device_procs wtscmyk_procs = {
+ gdev_prn_open, NULL, NULL, gdev_prn_output_page, gdev_prn_close,
+ NULL, cmyk_8bit_map_color_cmyk, NULL, NULL, NULL, NULL, NULL, NULL,
+ gdev_prn_get_params, gdev_prn_put_params,
+ cmyk_8bit_map_cmyk_color, NULL, NULL, NULL, gx_page_device_get_page_device
+};
+
+const gx_device_wts gs_wtscmyk_device = {
+ prn_device_body(gx_device_wts, wtscmyk_procs, "wtscmyk",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0, 0, 0, 0, /* Margins */
+ 4, 32, 255, 255, 256, 256, wtscmyk_print_page)
+};
+
+/* RGB with imdi conversion to CMYK and wts halftoning */
+
+private dev_proc_open_device(wtsimdi_open_device);
+private dev_proc_close_device(wtsimdi_close_device);
+private dev_proc_print_page(wtsimdi_print_page);
+private dev_proc_create_buf_device(wtsimdi_create_buf_device);
+private dev_proc_get_bits(wtsimdi_get_bits);
+private dev_proc_get_bits_rectangle(wtsimdi_contone_get_bits_rectangle);
+private dev_proc_get_bits_rectangle(wtsimdi_halftoned_get_bits_rectangle);
+
+typedef struct cached_color_s {
+ gx_color_index color_index;
+ byte cmyk[0];
+} cached_color;
+
+typedef struct gx_device_wtsimdi_s {
+ gx_device_common;
+ gx_prn_device_common;
+ wts_cooked_halftone wcooked[4];
+
+ icmFile *fp;
+ icc *icco;
+ icmLuBase *luo;
+ imdi *mdo;
+ cached_color zero, one;
+} gx_device_wtsimdi;
+
+private const gx_device_procs wtsimdi_procs =
+{
+ wtsimdi_open_device, NULL, NULL, gdev_prn_output_page, wtsimdi_close_device,
+ gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb,
+ NULL, NULL, NULL, NULL, NULL, wtsimdi_get_bits,
+ gdev_prn_get_params, gdev_prn_put_params,
+ NULL, NULL, NULL, NULL, gx_page_device_get_page_device
+};
+
+const gx_device_wtsimdi gs_wtsimdi_device = {
+ prn_device_body(gx_device_wtsimdi, wtsimdi_procs, "wtsimdi",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0, 0, 0, 0, /* Margins */
+ 3, 24, 255, 255, 256, 256, wtsimdi_print_page)
+};
+
+private void
+wts_halftone_line(void **wts, int y, int width, int n_planes,
+ byte **dst, const byte *src)
+{
+ int x;
+ int plane_ix;
+
+ for (plane_ix = 0; plane_ix < n_planes; plane_ix++) {
+ byte *dline = dst[plane_ix];
+ for (x = 0; x < width; x += 8) {
+ byte b = 0;
+ if (src[(x + 0) * n_planes + plane_ix] > 0x20) b |= 0x80;
+ if (src[(x + 1) * n_planes + plane_ix] > 0x40) b |= 0x40;
+ if (src[(x + 2) * n_planes + plane_ix] > 0x60) b |= 0x20;
+ if (src[(x + 3) * n_planes + plane_ix] > 0x80) b |= 0x10;
+ if (src[(x + 4) * n_planes + plane_ix] > 0xa0) b |= 0x08;
+ if (src[(x + 5) * n_planes + plane_ix] > 0xc0) b |= 0x04;
+ if (src[(x + 6) * n_planes + plane_ix] > 0xe0) b |= 0x02;
+ if (src[(x + 7) * n_planes + plane_ix] > 0xfe) b |= 0x01;
+ dline[x >> 3] = b;
+ }
+ }
+}
+
+private void
+wts_halftone_line_16(wts_cooked_halftone *wch, int y, int width, int n_planes,
+ byte **dst, const byte *src)
+{
+ int x;
+ int plane_ix;
+ wts_screen_sample_t *samples;
+
+ for (plane_ix = 0; plane_ix < n_planes; plane_ix++) {
+ wts_screen_t *w = wch[plane_ix].wts;
+ byte *dline = dst[plane_ix];
+ int imax;
+
+ for (x = 0; x < width;) {
+ int i;
+ int n_samples;
+ int cx, cy;
+
+ wts_get_samples(w, x, y, &cx, &cy, &n_samples);
+ samples = w->samples + cy * w->cell_width + cx;
+
+ imax = min(width - x, n_samples);
+ for (i = 0; i < imax; i += 8) {
+ byte b = 0;
+ int src_ix = x * 4 + plane_ix;
+#if 0
+ if (src[src_ix + 0 * 4] > (samples[i + 0] >> 7)) b |= 0x80;
+ if (src[src_ix + 1 * 4] > (samples[i + 1] >> 7)) b |= 0x40;
+ if (src[src_ix + 2 * 4] > (samples[i + 2] >> 7)) b |= 0x20;
+ if (src[src_ix + 3 * 4] > (samples[i + 3] >> 7)) b |= 0x10;
+ if (src[src_ix + 4 * 4] > (samples[i + 4] >> 7)) b |= 0x08;
+ if (src[src_ix + 5 * 4] > (samples[i + 5] >> 7)) b |= 0x04;
+ if (src[src_ix + 6 * 4] > (samples[i + 6] >> 7)) b |= 0x02;
+ if (src[src_ix + 7 * 4] > (samples[i + 7] >> 7)) b |= 0x01;
+#else
+#if 0
+ b |= (src[src_ix + 0 * 4] > (samples[i + 0] >> 7)) << 7;
+ b |= (src[src_ix + 1 * 4] > (samples[i + 1] >> 7)) << 6;
+ b |= (src[src_ix + 2 * 4] > (samples[i + 2] >> 7)) << 5;
+ b |= (src[src_ix + 3 * 4] > (samples[i + 3] >> 7)) << 4;
+ b |= (src[src_ix + 4 * 4] > (samples[i + 4] >> 7)) << 3;
+ b |= (src[src_ix + 5 * 4] > (samples[i + 5] >> 7)) << 2;
+ b |= (src[src_ix + 6 * 4] > (samples[i + 6] >> 7)) << 1;
+ b |= (src[src_ix + 7 * 4] > (samples[i + 7] >> 7)) << 0;
+#else
+ b = (((unsigned int)(((int)(samples[i + 0] >> 7)) - ((int)src[src_ix + 0 * 4]))) >> 24) & 0x80;
+ b |= (((unsigned int)(((int)(samples[i + 1] >> 7)) - ((int)src[src_ix + 1 * 4]))) >> 24) & 0x40;
+ b |= (((unsigned int)(((int)(samples[i + 2] >> 7)) - ((int)src[src_ix + 2 * 4]))) >> 24) & 0x20;
+ b |= (((unsigned int)(((int)(samples[i + 3] >> 7)) - ((int)src[src_ix + 3 * 4]))) >> 24) & 0x10;
+ b |= (((unsigned int)(((int)(samples[i + 4] >> 7)) - ((int)src[src_ix + 4 * 4]))) >> 24) & 0x08;
+ b |= (((unsigned int)(((int)(samples[i + 5] >> 7)) - ((int)src[src_ix + 5 * 4]))) >> 24) & 0x04;
+ b |= (((unsigned int)(((int)(samples[i + 6] >> 7)) - ((int)src[src_ix + 6 * 4]))) >> 24) & 0x02;
+ b |= (((unsigned int)(((int)(samples[i + 7] >> 7)) - ((int)src[src_ix + 7 * 4]))) >> 24) & 0x01;
+#endif
+#endif
+ dline[x >> 3] = b;
+ x += 8;
+ }
+ }
+ }
+}
+
+private void
+wts_halftone_line_8(wts_cooked_halftone *wch, int y, int width, int n_planes,
+ byte * dst, const byte * src)
+{
+ int x;
+ int plane_ix;
+ byte *samples;
+ int halftoned_bytes = (width + 7) >> 3;
+
+ for (plane_ix = 0; plane_ix < n_planes; plane_ix++) {
+ wts_screen_t *w = wch[plane_ix].wts;
+ int width_padded = wch[plane_ix].width_padded;
+ byte * dline = dst + plane_ix * halftoned_bytes;
+ //byte * dline = dst[plane_ix];
+ int imax;
+
+ for (x = 0; x < width;) {
+ int i;
+ int n_samples;
+ int cx, cy;
+
+ wts_get_samples(w, x, y, &cx, &cy, &n_samples);
+ samples = wch[plane_ix].cell + cy * width_padded + cx;
+
+ imax = min(width - x, n_samples);
+ for (i = 0; i < imax; i += 8) {
+ byte b = 0;
+ int src_ix = x * 4 + plane_ix;
+ b = (((unsigned int)(((int)(samples[i + 0])) - ((int)src[src_ix + 0 * 4]))) >> 24) & 0x80;
+ b |= (((unsigned int)(((int)(samples[i + 1])) - ((int)src[src_ix + 1 * 4]))) >> 24) & 0x40;
+ b |= (((unsigned int)(((int)(samples[i + 2])) - ((int)src[src_ix + 2 * 4]))) >> 24) & 0x20;
+ b |= (((unsigned int)(((int)(samples[i + 3])) - ((int)src[src_ix + 3 * 4]))) >> 24) & 0x10;
+ b |= (((unsigned int)(((int)(samples[i + 4])) - ((int)src[src_ix + 4 * 4]))) >> 24) & 0x08;
+ b |= (((unsigned int)(((int)(samples[i + 5])) - ((int)src[src_ix + 5 * 4]))) >> 24) & 0x04;
+ b |= (((unsigned int)(((int)(samples[i + 6])) - ((int)src[src_ix + 6 * 4]))) >> 24) & 0x02;
+ b |= (((unsigned int)(((int)(samples[i + 7])) - ((int)src[src_ix + 7 * 4]))) >> 24) & 0x01;
+ *dline++ = b;
+ x += 8;
+ }
+ }
+ }
+}
+
+private int
+wts_load_halftone(gs_memory_t *mem, wts_cooked_halftone *wch, const char *fn)
+{
+ FILE *f = fopen(fn, "rb");
+ int size;
+ byte *buf;
+ wts_screen_t *wts;
+ int width_padded;
+ byte *cooked_cell;
+ int y;
+
+ if (f == 0) return gs_error_undefinedfilename;
+ fseek(f, 0, 2);
+ size = ftell(f);
+ fseek(f, 0, 0);
+ buf = gs_malloc(mem, size, 1, "wts_load_halftone");
+ if (buf == 0) {
+ return gs_error_VMerror;
+ }
+ fread(buf, 1, size, f);
+ fclose(f);
+ wts = gs_wts_from_buf(buf);
+ gs_free(mem, buf, size, 1, "wts_load_halftone");
+ wch->wts = wts;
+ width_padded = wts->cell_width + 7;
+ wch->width_padded = width_padded;
+ cooked_cell = gs_malloc(mem, width_padded * wts->cell_height, 1,
+ "wts_load_halftone");
+ if (cooked_cell == 0) {
+ return gs_error_VMerror;
+ }
+
+ wch->cell = cooked_cell;
+ for (y = 0; y < wts->cell_height; y++) {
+ wts_screen_sample_t *line = &wts->samples[y * wts->cell_width];
+ byte *dstline = cooked_cell + y * width_padded;
+ int x;
+ for (x = 0; x < width_padded; x++) {
+ wts_screen_sample_t sample = line[x % wts->cell_width];
+ dstline[x] = (254 * (int)sample + 0x7fc0) / 0x8ff0;
+ }
+ }
+
+#if 0
+ /* Note: we'll need to fix the free discipline here when we change it
+ in gswts.c */
+ free(wts->samples);
+ wts->samples = NULL;
+#endif
+
+ return 0;
+}
+
+private int
+wts_init_halftones(gx_device_wts *wdev, int n_planes)
+{
+ int i;
+ int code;
+
+ for (i = 0; i < n_planes; i++) {
+ if (wdev->wcooked[i].wts == 0) {
+ char wts_fn[256];
+
+ sprintf(wts_fn, "wts_plane_%d", i);
+ code = wts_load_halftone(wdev->memory, &wdev->wcooked[i], wts_fn);
+ if (code < 0)
+ return code;
+ }
+ }
+ return 0;
+}
+
+private int
+wtscmyk_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{
+ gx_device_wts *wdev = (gx_device_wts *)pdev;
+ int cmyk_bytes = gdev_mem_bytes_per_scan_line((gx_device *) pdev);
+ /* Output bytes have to be padded to 16 bits. */
+ int y;
+ char *cmyk_line = 0;
+ byte *data;
+ int code = 0;
+ int pbm_bytes;
+ int n_planes = pdev->color_info.num_components;
+ byte *dst;
+ FILE *ostream[4] = {0};
+ int i;
+
+ /* Initialize the wts halftones. */
+ wts_init_halftones(wdev, n_planes);
+
+ cmyk_line = gs_malloc(pdev->memory, cmyk_bytes, 1, "wtscmyk_print_page(in)");
+ if (cmyk_line == 0) {
+ code = GS_NOTE_ERROR(pdev->memory, gs_error_VMerror);
+ goto out;
+ }
+ pbm_bytes = (pdev->width + 7) >> 3;
+ dst = gs_malloc(pdev->memory, pbm_bytes * n_planes, 1,
+ "wtscmyk_print_page");
+ if (dst == 0) {
+ code = GS_NOTE_ERROR(pdev->memory, gs_error_VMerror);
+ goto out;
+ }
+
+ /* Create additional output streams. */
+ for (i = 0; i < n_planes; i++) {
+ if (i == 0) {
+ ostream[i] = prn_stream;
+ } else {
+ char fn[256];
+ char plane_name[4] = "cmyk";
+ int fname_len = strlen(pdev->fname);
+
+ if (fname_len >= 5 && fname_len < 256) {
+ strcpy(fn, pdev->fname);
+ if (!strcmp(fn + fname_len - 5, "c.pbm"))
+ fn[fname_len - 5] = plane_name[i];
+ }
+ ostream[i] = fopen(fn, "wb");
+ }
+ fprintf(ostream[i], "P4\n%d %d\n", pdev->width, pdev->height);
+ }
+#if 0
+ dprintf2(OPTIONAL_MEM(pdev->memory) "Output file name: %s %d\n", pdev->fname, sizeof(dst));
+#endif
+
+ /* For each raster line */
+ for (y = 0; y < pdev->height; y++) {
+ gdev_prn_get_bits(pdev, y, cmyk_line, &data);
+ wts_halftone_line_8(wdev->wcooked, y, pdev->width, n_planes, dst, data);
+ for (i = 0; i < n_planes; i++)
+ if (ostream[i])
+ fwrite(dst + i * pbm_bytes, 1, pbm_bytes, ostream[i]);
+ }
+out:
+ /* Clean up... */
+ gs_free(pdev->memory, cmyk_line, cmyk_bytes, 1, "wtscmyk_print_page(in)");
+ gs_free(pdev->memory, dst, pbm_bytes, 1, "wtscmyk_print_page");
+ for (i = 1; i < n_planes; i++) {
+ /* Don't close ostream[0], because gdev_prn_close will. */
+ if (ostream[i])
+ fclose(ostream[i]);
+ }
+ return code;
+}
+
+/* Code that follows is adapted from imdi device */
+
+private double incurve(void *ctx, int ch, double val)
+{
+ return val;
+}
+
+private double outcurve(void *ctx, int ch, double val)
+{
+ return val;
+}
+
+private void mdtable(void *ctx, double *outvals, double *invals)
+{
+ icmLuBase *luo = ctx;
+ luo->lookup(luo, outvals, invals);
+}
+
+/*
+ * Open IMDI device.
+ * Load ICC device link profile (to map sRGB to FOGRA CMYK).
+ */
+
+private int
+wtsimdi_open_device(gx_device *dev)
+{
+ gx_device_wtsimdi *idev = (gx_device_wtsimdi*)dev;
+ int code;
+
+ icColorSpaceSignature ins, outs;
+ int inn, outn;
+ icmLuAlgType alg;
+
+ icmFile *fp;
+ icc *icco;
+ icmLuBase *luo;
+ imdi *mdo;
+
+ /*
+ * We replace create_buf_device so we can replace copy_alpha
+ * for memory device, but not clist.
+ */
+ idev->printer_procs.buf_procs.create_buf_device =
+ wtsimdi_create_buf_device;
+ /* Open and read profile */
+
+ fp = new_icmFileStd_name(LINK_ICC_NAME, "rb");
+ if (!fp)
+ return gs_throw1(-1, "could not open file '%s'", LINK_ICC_NAME);
+
+ icco = new_icc();
+ if (!icco)
+ return gs_throw(-1, "could not create ICC object");
+
+ code = icco->read(icco, fp, 0);
+ if (code != 0)
+ return gs_throw1(-1, "could not read ICC profile: %s", icco->err);
+
+ /* Get conversion object */
+
+ luo = icco->get_luobj(icco, icmFwd, icPerceptual, icmSigDefaultData, icmLuOrdNorm);
+ if (!luo)
+ return gs_throw1(-1, "could not create ICC conversion object: %s", icco->err);
+
+ luo->spaces(luo, &ins, &inn, &outs, &outn, &alg, NULL, NULL, NULL);
+
+ dprintf3("%s -> %s [%s]\n",
+ icm2str(icmColorSpaceSignature, ins),
+ icm2str(icmColorSpaceSignature, outs),
+ icm2str(icmLuAlg, alg));
+
+ if (inn != 3)
+ return gs_throw1(-1, "profile must have 3 input channels. got %d.", inn);
+ if (outn != 4)
+ return gs_throw1(-1, "profile must have 4 output channels. got %d.", outn);
+
+ /* Create IMDI optimized lookup object */
+
+ mdo = new_imdi(inn, outn, pixint8, 0, pixint8, 0,
+ 33, incurve, mdtable, outcurve, luo);
+ if (!mdo)
+ return gs_throw(-1, "new_imdi failed");
+
+ idev->fp = fp;
+ idev->icco = icco;
+ idev->luo = luo;
+ idev->mdo = mdo;
+ idev->zero.color_index = gx_no_color_index;
+ idev->one.color_index = gx_no_color_index;
+
+ return gdev_prn_open(dev);
+}
+
+
+/*
+ * Close device and clean up ICC structures.
+ */
+
+private int
+wtsimdi_close_device(gx_device *dev)
+{
+ gx_device_wtsimdi *idev = (gx_device_wtsimdi*)dev;
+
+ idev->mdo->done(idev->mdo);
+ idev->luo->del(idev->luo);
+ idev->icco->del(idev->icco);
+ idev->fp->del(idev->fp);
+
+ return gdev_prn_close(dev);
+}
+
+/* Resolve a color to cmyk values, using the one-element cache. */
+private int
+wtsimdi_resolve_one(gx_device_wtsimdi *idev, gx_color_index color)
+{
+ if (color != idev->one.color_index) {
+ int code;
+ int r = (color >> 16) & 0xff;
+ int g = (color >> 8) & 0xff;
+ int b = color & 0xff;
+ double rgb[3];
+ double cmyk[4];
+
+ rgb[0] = r / 255.0;
+ rgb[1] = g / 255.0;
+ rgb[2] = b / 255.0;
+ code = idev->luo->lookup(idev->luo, cmyk, rgb);
+ if (code > 1)
+ return_error(gs_error_unknownerror);
+ idev->one.color_index = color;
+ idev->one.cmyk[0] = cmyk[0] * 255 + 0.5;
+ idev->one.cmyk[1] = cmyk[1] * 255 + 0.5;
+ idev->one.cmyk[2] = cmyk[2] * 255 + 0.5;
+ idev->one.cmyk[3] = cmyk[3] * 255 + 0.5;
+ }
+ return 0;
+}
+
+/* Fill a rectangle with a color. */
+private int
+wtsimdi_fill_rectangle(gx_device * dev,
+ int x, int y, int w, int h, gx_color_index color)
+{
+ gx_device_memory * const mdev = (gx_device_memory *)dev;
+ gx_device_wtsimdi * idev = (gx_device_wtsimdi *)
+ ((mdev->target) ? (gx_device_wts *)(mdev->target)
+ : dev);
+ wts_cooked_halftone * wch = idev->wcooked;
+ int n_planes = 4;
+ int code, comp_value;
+ int halftoned_bytes = (idev-> width + 7) >> 3;
+ int width_padded, imax;
+ byte * dst, * base, halftoned_data;
+ byte * samples;
+ uint raster, plane_ix, bit_loc, xi;
+ int first_byte, end_x;
+
+ fit_fill(dev, x, y, w, h);
+
+ base = scan_line_base(mdev, y);
+ raster = mdev->raster;
+
+ end_x = x + w - 1;
+ first_byte = x >> 3;
+
+ /*
+ * Check if this is a new color. To minimize color conversion
+ * time, we keep a couple of values cached in the wtsimdi device.
+ */
+ if ((code = wtsimdi_resolve_one(idev, color)) < 0)
+ return code;
+
+ for (; h--; y++) {
+ base = scan_line_base(mdev, y);
+ for (plane_ix = 0; plane_ix < 4; plane_ix++) {
+ int nfill = (end_x >> 3) - first_byte;
+
+ width_padded = wch[plane_ix].width_padded;
+ dst = base + first_byte + plane_ix * halftoned_bytes;
+ comp_value = idev->one.cmyk[plane_ix];
+ if (comp_value == 0) {
+ if (nfill == 0) {
+ dst[0] &= (0xff << (8 - (x & 7))) |
+ ((1 << (7 - (end_x & 7))) - 1);
+ } else {
+ int i;
+
+ dst[0] &= (0xff << (8 - (x & 7)));
+ for (i = 1; i < nfill; i++)
+ dst[i] = 0;
+ dst[i] &= ((1 << (7 - (end_x & 7))) - 1);
+ }
+ } else if (comp_value == 0xff) {
+ if (nfill == 0) {
+ dst[0] |= ~((0xff << (8 - (x & 7))) |
+ ((1 << (7 - (end_x & 7))) - 1));
+ } else {
+ int i;
+
+ dst[0] |= ~(0xff << (8 - (x & 7)));
+ for (i = 1; i < nfill; i++)
+ dst[i] = 0xff;
+ dst[i] |= ~((1 << (7 - (end_x & 7))) - 1);
+ }
+ } else {
+ byte save_left = dst[0];
+ byte save_right = dst[nfill];
+ int i;
+
+ for (i = 0; i < nfill + 1;) {
+ int n_samples;
+ int cx, cy;
+ int j;
+
+ wts_get_samples(wch[plane_ix].wts, (x & -8) + (i << 3), y, &cx, &cy, &n_samples);
+ samples = wch[plane_ix].cell + cy * width_padded + cx;
+
+ imax = min((nfill + 1 - i) << 3, n_samples);
+ for (j = 0; j < imax; j += 8) {
+ int b;
+ b = (((unsigned int)(((int)(samples[j + 0])) - comp_value) >> 24)) & 0x80;
+ b |= (((unsigned int)(((int)(samples[j + 1])) - comp_value) >> 24)) & 0x40;
+ b |= (((unsigned int)(((int)(samples[j + 2])) - comp_value) >> 24)) & 0x20;
+ b |= (((unsigned int)(((int)(samples[j + 3])) - comp_value) >> 24)) & 0x10;
+ b |= (((unsigned int)(((int)(samples[j + 4])) - comp_value) >> 24)) & 0x08;
+ b |= (((unsigned int)(((int)(samples[j + 5])) - comp_value) >> 24)) & 0x04;
+ b |= (((unsigned int)(((int)(samples[j + 6])) - comp_value) >> 24)) & 0x02;
+ b |= (((unsigned int)(((int)(samples[j + 7])) - comp_value) >> 24)) & 0x01;
+ dst[i + (j >> 3)] = b;
+ }
+ dst[0] = (save_left & (0xff << (8 - (x & 7)))) |
+ (dst[0] & ~(0xff << (8 - (x & 7))));
+ dst[nfill] = (save_right & ((1 << (7 - (end_x & 7))) - 1)) |
+ (dst[nfill] & ~((1 << (7 - (end_x & 7))) - 1));
+ i += (j >> 3);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+private int
+wtsimdi_copy_mono(gx_device * dev,
+ const byte * data, int sourcex, int sraster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
+{
+ gx_device_memory * const mdev = (gx_device_memory *)dev;
+ gx_device_wtsimdi * idev = (gx_device_wtsimdi *)
+ ((mdev->target) ? (gx_device_wts *)(mdev->target)
+ : dev);
+ wts_cooked_halftone * wch = idev->wcooked;
+ int n_planes = 4;
+ int code, comp_value;
+ int halftoned_bytes = (idev-> width + 7) >> 3;
+ int width_padded, imax;
+ byte * dst, * base, halftoned_data;
+ byte * samples;
+ uint raster, plane_ix, bit_loc, xi;
+ int first_byte, end_x;
+ const byte *src;
+ int sshift;
+
+ if (zero != gx_no_color_index)
+ return gx_default_copy_mono(dev, data, sourcex, sraster, id,
+ x, y, w, h, zero, one);
+ if (x < 0) {
+ sourcex -= x;
+ w += x;
+ x = 0;
+ }
+ src = data + ((sourcex - (x & 7)) >> 3);
+ if (y < 0) {
+ src -= sraster * y;
+ h += y;
+ y = 0;
+ }
+ fit_fill(dev, x, y, w, h);
+
+ base = scan_line_base(mdev, y);
+ raster = mdev->raster;
+
+ end_x = x + w - 1;
+ first_byte = x >> 3;
+
+ /*
+ * Check if this is a new color. To minimize color conversion
+ * time, we keep a couple of values cached in the wtsimdi device.
+ */
+ if ((code = wtsimdi_resolve_one(idev, one)) < 0)
+ return code;
+
+ sshift = 8 - ((sourcex - x) & 7);
+
+ for (; h--; y++) {
+ base = scan_line_base(mdev, y);
+ for (plane_ix = 0; plane_ix < 4; plane_ix++) {
+ int nfill = (end_x >> 3) - first_byte;
+
+ width_padded = wch[plane_ix].width_padded;
+ dst = base + first_byte + plane_ix * halftoned_bytes;
+ comp_value = idev->one.cmyk[plane_ix];
+ if (0 && comp_value == 0) {
+ /* TODO: these cases should be optimized, avoiding a screen */
+ if (nfill == 0) {
+ dst[0] &= (0xff << (8 - (x & 7))) |
+ ((1 << (7 - (end_x & 7))) - 1);
+ } else {
+ int i;
+
+ dst[0] &= (0xff << (8 - (x & 7)));
+ for (i = 1; i < nfill; i++)
+ dst[i] = 0;
+ dst[i] &= ((1 << (7 - (end_x & 7))) - 1);
+ }
+ } else if (0 && comp_value == 0xff) {
+ if (nfill == 0) {
+ dst[0] |= ~((0xff << (8 - (x & 7))) |
+ ((1 << (7 - (end_x & 7))) - 1));
+ } else {
+ int i;
+
+ dst[0] |= ~(0xff << (8 - (x & 7)));
+ for (i = 1; i < nfill; i++)
+ dst[i] = 0xff;
+ dst[i] |= ~((1 << (7 - (end_x & 7))) - 1);
+ }
+ } else {
+ byte save_left = dst[0];
+ byte save_right = dst[nfill];
+ int i;
+
+ for (i = 0; i < nfill + 1;) {
+ int n_samples;
+ int cx, cy;
+ int j;
+
+ wts_get_samples(wch[plane_ix].wts, (x & -8) + (i << 3), y, &cx, &cy, &n_samples);
+ samples = wch[plane_ix].cell + cy * width_padded + cx;
+
+ imax = min((nfill + 1 - i) << 3, n_samples);
+ for (j = 0; j < imax; j += 8) {
+ byte smask = (src[i] << 8 | src[i + 1]) >> sshift;
+ if (smask) {
+ byte b;
+ b = (((unsigned int)(((int)(samples[j + 0])) - comp_value) >> 24)) & 0x80;
+ b |= (((unsigned int)(((int)(samples[j + 1])) - comp_value) >> 24)) & 0x40;
+ b |= (((unsigned int)(((int)(samples[j + 2])) - comp_value) >> 24)) & 0x20;
+ b |= (((unsigned int)(((int)(samples[j + 3])) - comp_value) >> 24)) & 0x10;
+ b |= (((unsigned int)(((int)(samples[j + 4])) - comp_value) >> 24)) & 0x08;
+ b |= (((unsigned int)(((int)(samples[j + 5])) - comp_value) >> 24)) & 0x04;
+ b |= (((unsigned int)(((int)(samples[j + 6])) - comp_value) >> 24)) & 0x02;
+ b |= (((unsigned int)(((int)(samples[j + 7])) - comp_value) >> 24)) & 0x01;
+ dst[i] = (b & smask) | (dst[i] & ~smask);
+ }
+ i++;
+ }
+ dst[0] = (save_left & (0xff << (8 - (x & 7)))) |
+ (dst[0] & ~(0xff << (8 - (x & 7))));
+ dst[nfill] = (save_right & ((1 << (7 - (end_x & 7))) - 1)) |
+ (dst[nfill] & ~((1 << (7 - (end_x & 7))) - 1));
+ }
+ }
+ }
+ src += sraster;
+ }
+ return 0;
+}
+
+
+/*
+ * This is a clone of gx_default_get_bits except that we are adding
+ * GB_HALFTONED to the parameter options. This will tell the buffer
+ * device to halftone the data (if it is not already halftoned).
+ */
+wtsimdi_get_bits(gx_device * dev, int y, byte * data, byte ** actual_data)
+{ /*
+ * Hand off to get_bits_rectangle, being careful to avoid a
+ * possible recursion loop.
+ */
+ dev_proc_get_bits((*save_get_bits)) = dev_proc(dev, get_bits);
+ gs_int_rect rect;
+ gs_get_bits_params_t params;
+ int code;
+
+ rect.p.x = 0, rect.p.y = y;
+ rect.q.x = dev->width, rect.q.y = y + 1;
+ params.options =
+ (actual_data ? GB_RETURN_POINTER : 0) | GB_RETURN_COPY |
+ (GB_ALIGN_STANDARD | GB_OFFSET_0 | GB_RASTER_STANDARD |
+ /* No depth specified, we always use native colors. */
+ GB_PACKING_CHUNKY | GB_COLORS_NATIVE | GB_ALPHA_NONE |
+ GB_HALFTONED);
+ params.x_offset = 0;
+ params.raster = bitmap_raster(dev->width * dev->color_info.depth);
+ params.data[0] = data;
+ params.original_y = y;
+ set_dev_proc(dev, get_bits, gx_no_get_bits);
+ code = (*dev_proc(dev, get_bits_rectangle))
+ (dev, &rect, ¶ms, NULL);
+ if (actual_data)
+ *actual_data = params.data[0];
+ set_dev_proc(dev, get_bits, save_get_bits);
+ return code;
+}
+
+int
+wtsimdi_halftoned_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect,
+ gs_get_bits_params_t * params, gs_int_rect ** unread)
+{
+ /*
+ * We should only get to this routine if the caller wants the halftoned
+ * version of our output. In all other cases we should be in
+ * wtsimdi_contone_get_bits_rectangle.
+ */
+ if (!(params->options & GB_HALFTONED))
+ return_error(gs_error_unknownerror);
+ return mem_get_bits_rectangle(dev, prect, params, unread);
+}
+
+
+int
+wtsimdi_contone_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect,
+ gs_get_bits_params_t * params, gs_int_rect ** unread)
+{
+ /*
+ * Save the options since mem_get_bits_rectangle will change them to
+ * indicate what it actually did. We need the unmodified values.
+ */
+ gs_get_bits_options_t options = params->options;
+ int original_y = params->original_y;
+ byte * buffer = params->data[0];
+ int code = mem_get_bits_rectangle(dev, prect, params, unread);
+
+ if (code < 0)
+ return code;
+ if (options & GB_HALFTONED) {
+ gx_device_memory * const mdev = (gx_device_memory *)dev;
+ gx_device_wtsimdi * idev = (gx_device_wtsimdi *)
+ ((mdev->target) ? (gx_device_wts *)(mdev->target)
+ : dev);
+ int width = dev->width;
+ int n_planes = 4;
+ int r_last = -1, g_last = -1, b_last = -1, r, g, b;
+ int c, m, y, k, x;
+ double rgb[3];
+ double cmyk[4];
+ byte * src = params->data[0];
+ byte * cmyk_buffer = gs_malloc(dev->memory,
+ (width + 7) * n_planes, 1,
+ "wtsimdi_contone_get_bits(cmyk_buffer)");
+ byte * cmyk_data = cmyk_buffer;
+
+ if (cmyk_data == NULL)
+ return_error(gs_error_VMerror);
+ /*
+ */
+ for (x = 0; x < width; x++) {
+ r = *src++;
+ g = *src++;
+ b = *src++;
+ if (r != r_last || g != g_last || b != b_last) {
+ r_last = r, g_last = g, b_last = b;
+ rgb[0] = r * (1 / 255.0);
+ rgb[1] = g * (1 / 255.0);
+ rgb[2] = b * (1 / 255.0);
+ code = idev->luo->lookup(idev->luo, cmyk, rgb);
+ if (code > 1)
+ return_error(gs_error_unknownerror);
+ c = cmyk[0] * 255 + 0.5;
+ m = cmyk[1] * 255 + 0.5;
+ y = cmyk[2] * 255 + 0.5;
+ k = cmyk[3] * 255 + 0.5;
+ }
+ *cmyk_data++ = c;
+ *cmyk_data++ = m;
+ *cmyk_data++ = y;
+ *cmyk_data++ = k;
+ }
+ wts_halftone_line_8(idev->wcooked, original_y, width,
+ n_planes, buffer, cmyk_buffer);
+ params->data[0] = buffer;
+ gs_free(dev->memory, cmyk_buffer, halftoned_bytes * n_planes, 1,
+ "wtsimdi_print_page(halftoned_data)");
+ }
+ return code;
+}
+
+/*
+ * We need to create custom memory buffer devices. We use the default
+ * create_buf_device routine and then we set our custom device procedures.
+ */
+private int
+wtsimdi_create_buf_device(gx_device **pbdev, gx_device *target,
+ const gx_render_plane_t *render_plane, gs_memory_t *mem,
+ gx_band_complexity_t *band_complexity)
+{
+ gx_device_printer *ptarget = (gx_device_printer *)target;
+ int code = gx_default_create_buf_device(pbdev, target,
+ render_plane, mem, band_complexity);
+ /* Now set our custom device procedures. */
+ if (band_complexity && band_complexity->nontrivial_rops) {
+ set_dev_proc(*pbdev, get_bits_rectangle,
+ wtsimdi_contone_get_bits_rectangle);
+ } else {
+ set_dev_proc(*pbdev, get_bits_rectangle,
+ wtsimdi_halftoned_get_bits_rectangle);
+ set_dev_proc(*pbdev, fill_rectangle, wtsimdi_fill_rectangle);
+ set_dev_proc(*pbdev, copy_mono, wtsimdi_copy_mono);
+ /* All procedures which are defined as mem_true24_* need to be either
+ implemented or replaced with a default implementation. The following
+ three don't have significant usage in testing with Altona.
+ */
+ set_dev_proc(*pbdev, strip_copy_rop, gx_default_strip_copy_rop);
+ set_dev_proc(*pbdev, copy_alpha, gx_default_copy_alpha);
+ set_dev_proc(*pbdev, copy_color, gx_default_copy_color);
+ }
+ return code;
+}
+
+/*
+ * Create a row of output data. The output is the same as the pkmraw
+ * device. This a pseudo 1 bit CMYK output. Actually the output is
+ * 3 byte RGB with each byte being either 0 or 1.
+ *
+ * The input data is 1 bit per component CMYK. The data is separated
+ * into planes.
+ */
+write_pkmraw_row(int width, byte * data, FILE * pstream)
+{
+#define noSKIP_OUTPUT
+#ifndef SKIP_OUTPUT
+ int x, bit;
+ int halftoned_bytes = (width + 7) >> 3;
+ byte * cdata = data;
+ byte * mdata = data + halftoned_bytes;
+ byte * ydata = mdata + halftoned_bytes;
+ byte * kdata = ydata + halftoned_bytes;
+ byte c = *cdata++;
+ byte m = *mdata++;
+ byte y = *ydata++;
+ byte k = *kdata++;
+
+ /*
+ * Contrary to what the documentation implies, gcc compiles putc
+ * as a procedure call. This is ridiculous, but since we can't
+ * change it, we buffer groups of pixels ourselves and use fwrite.
+ */
+ for (bit = 7, x = 0; x < width;) {
+ byte raw[80 * 3]; /* 80 is arbitrary, must be a multiple of 8 */
+ int end = min(x + sizeof(raw) / 3, width);
+ byte *outp = raw;
+
+ for (; x < end; x++) {
+
+ if ((k >> bit) & 1) {
+ *outp++ = 0; /* Set output color = black */
+ *outp++ = 0;
+ *outp++ = 0;
+ } else {
+ *outp++ = 1 - ((c >> bit) & 1);
+ *outp++ = 1 - ((m >> bit) & 1);
+ *outp++ = 1 - ((y >> bit) & 1);
+ }
+ if (bit == 0) {
+ c = *cdata++;
+ m = *mdata++;
+ y = *ydata++;
+ k = *kdata++;
+ bit = 7;
+ } else
+ bit--;
+ }
+ fwrite(raw, 1, outp - raw, pstream);
+ }
+#endif
+ return 0;
+}
+
+/*
+ * Output the page raster.
+ */
+
+private int
+wtsimdi_print_page(gx_device_printer *pdev, FILE *prn_stream)
+{
+ gx_device_wtsimdi *idev = (gx_device_wtsimdi*)pdev;
+ int n_planes = 4;
+ byte * halftoned_data;
+ byte * halftoned_buffer;
+ int halftoned_bytes, y;
+ int code = 0;
+ int width = pdev->width;
+ int height = pdev->height;
+ dev_proc_get_bits((*save_get_bits)) = dev_proc(pdev, get_bits);
+
+ /*
+ * The printer device setup changed the get_bits routine to
+ * gx_default_get_bits. We want to use our own.
+ */
+ set_dev_proc(pdev, get_bits, wtsimdi_get_bits);
+
+ /*
+ * Initialize the WTS halftones.
+ */
+ wts_init_halftones((gx_device_wts *)idev, n_planes);
+
+ /*
+ * Allocate a buffer to hold the halftoned data. This is 1 bit per
+ * component CMYK data.
+ */
+ halftoned_bytes = (width + 7) >> 3; /* bytes per component */
+ halftoned_buffer = gs_malloc(pdev->memory, halftoned_bytes * n_planes, 1,
+ "wtsimdi_print_page(halftoned_data)");
+ if (halftoned_data == NULL) {
+ code = GS_NOTE_ERROR(pdev->memory, gs_error_VMerror);
+ goto cleanup;
+ }
+
+ /* Initialize output file header. */
+ fprintf(prn_stream, "P6\n%d %d\n", width, height);
+ fprintf(prn_stream, "# Image generated by %s %d.%02d (device=wtsimdi)\n",
+ gs_program_name(), gs_revision_number() / 100,
+ gs_revision_number() % 100);
+ fprintf(prn_stream, "%d\n", 1);
+
+ /*
+ * Get raster data and then write data to output file.
+ */
+ for (y = 0; y < height; y++) {
+ /*
+ * The get_bit routines for our device returns a halftoned copy of
+ * the output data. Print this data to the output file.
+ */
+ gdev_prn_get_bits(pdev, y, halftoned_buffer, &halftoned_data);
+#if 1
+ write_pkmraw_row(width, halftoned_data, prn_stream);
+#endif
+ }
+cleanup:
+ if (halftoned_buffer != NULL)
+ gs_free(pdev->memory, halftoned_buffer, halftoned_bytes * n_planes, 1,
+ "wtsimdi_print_page(halftoned_buffer)");
+ set_dev_proc(pdev, get_bits, save_get_bits);
+ return 0;
+}
Modified: trunk/gs/src/gswts.c
===================================================================
--- trunk/gs/src/gswts.c 2007-04-02 22:34:51 UTC (rev 7818)
+++ trunk/gs/src/gswts.c 2007-04-03 16:08:49 UTC (rev 7819)
@@ -760,6 +760,15 @@
return malloc(bytes);
}
+private void *
+store_be32(byte *ptr, int x)
+{
+ ptr[0] = (x >> 24) & 0xff;
+ ptr[1] = (x >> 16) & 0xff;
+ ptr[2] = (x >> 8) & 0xff;
+ ptr[3] = x & 0xff;
+}
+
/**
* wts_pick_cell_size: Choose cell size for WTS screen.
* @ph: The halftone parameters.
@@ -780,17 +789,38 @@
double memw = 8.0;
wts_cell_size_key key;
int len;
+ byte *keyptr = NULL;
+ byte intkey[12];
+ int keysize;
octangle = sangledeg;
while (octangle >= 45.0) octangle -= 45.0;
while (octangle < -45.0) octangle += 45.0;
/* try persistent cache */
- key.sratiox = sratiox;
- key.sratioy = sratioy;
- key.sangledeg = sangledeg;
- key.memw = memw;
- len = gp_cache_query(GP_CACHE_TYPE_WTS_SIZE, (byte *)&key, sizeof(key),
+ if (sangledeg == 45.0) {
+ int srxi, sryi;
+
+ srxi = (int)floor(sratiox / sqrt(2) + 0.5);
+ sryi = (int)floor(sratioy / sqrt(2) + 0.5);
+ if (fabs(srxi * sqrt(2) - sratiox) < 2e-6 &&
+ fabs(sryi * sqrt(2) - sratioy) < 2e-6) {
+ store_be32(intkey, (int)sangledeg);
+ store_be32(intkey + 4, srxi);
+ store_be32(intkey + 8, sryi);
+ keyptr = intkey;
+ keysize = sizeof(intkey);
+ }
+ }
+ if (keyptr == NULL) {
+ key.sratiox = sratiox;
+ key.sratioy = sratioy;
+ key.sangledeg = sangledeg;
+ key.memw = memw;
+ keyptr = (byte *)&key;
+ keysize = sizeof(key);
+ }
+ len = gp_cache_query(GP_CACHE_TYPE_WTS_SIZE, keyptr, keysize,
(void **)&result, wts_cache_alloc_callback, NULL);
if (len >= 0)
return result;
@@ -1256,6 +1286,13 @@
samples[i] = wsej->base.cell[i] >> WTS_EXTRA_SORT_BITS;
}
+#ifdef WTS_CACHE_SIZE_X
+ for (i = 0; i < WTS_CACHE_SIZE_X; i++)
+ wsj->xcache[i].tag = -1;
+ for (i = 0; i < WTS_CACHE_SIZE_Y; i++)
+ wsj->ycache[i].tag = -1;
+#endif
+
return &wsj->base;
}
@@ -1295,6 +1332,12 @@
int height;
} wts_key_j;
+typedef struct {
+ wts_screen_type t;
+ int width;
+ int height;
+} wts_key_h;
+
wts_screen_t *
wts_screen_from_enum(const gs_wts_screen_enum_t *wse)
{
@@ -1317,6 +1360,15 @@
/* todo: more params */
memcpy(key, &k, cell_off);
memcpy(key + cell_off, wse->cell, wse->size * sizeof(bits32));
+ } else if (wse->t == WTS_SCREEN_H) {
+ wts_key_h k;
+ k.t = wse->t;
+ k.width = wse->width;
+ k.height = wse->height;
+ key_size = sizeof(k);
+ key = (byte *)malloc(key_size);
+ /* todo: more params */
+ memcpy(key, &k, key_size);
}
if (key != NULL)
@@ -1406,6 +1458,18 @@
free(result);
return NULL;
}
+#ifdef WTS_SCREEN_J_SIZE_NOCACHE
+ if (ws->type == WTS_SCREEN_J) {
+ wts_screen_j_t *wsj = (wts_screen_j_t *)result;
+ int i;
+
+ for (i = 0; i < WTS_CACHE_SIZE_X; i++)
+ wsj->xcache[i].tag = -1;
+ for (i = 0; i < WTS_CACHE_SIZE_Y; i++)
+ wsj->ycache[i].tag = -1;
+ size = WTS_SCREEN_J_SIZE_NOCACHE;
+ }
+#endif
memcpy(result->samples, buf + size, cell_size);
return result;
Modified: trunk/gs/src/gxbitfmt.h
===================================================================
--- trunk/gs/src/gxbitfmt.h 2007-04-02 22:34:51 UTC (rev 7818)
+++ trunk/gs/src/gxbitfmt.h 2007-04-03 16:08:49 UTC (rev 7819)
@@ -190,10 +190,19 @@
#define GB_RASTER_NAMES\
"raster_standard", "raster_specified", "raster_any"
+ /*
+ * Return halftoned raster. (This requires a custom get_bit_rectangle
+ * device procedure. See the wtsimdi device. Most devices ignore this
+ * bit.
+ */
+#define GB_HALFTONED (1L<<31)
+#define GB_HALFTONED_NAMES\
+ "halftoned_no", "halftoned_yes"
+
/* Define names for debugging printout. */
#define GX_BITMAP_FORMAT_NAMES\
GB_COLORS_NAMES, GB_ALPHA_NAMES, GB_DEPTH_NAMES, GB_PACKING_NAMES,\
GB_SELECT_NAMES, GB_RETURN_NAMES, GB_ALIGN_NAMES, GB_OFFSET_NAMES,\
- GB_RASTER_NAMES
+ GB_RASTER_NAMES, GB_HALFTONE_NAMES
#endif /* gxbitfmt_INCLUDED */
Modified: trunk/gs/src/gxcldev.h
===================================================================
--- trunk/gs/src/gxcldev.h 2007-04-02 22:34:51 UTC (rev 7818)
+++ trunk/gs/src/gxcldev.h 2007-04-03 16:08:49 UTC (rev 7819)
@@ -216,6 +216,8 @@
int band_min, band_max;
#define cmd_band_end (-1) /* end of band file */
int64_t pos; /* starting position in cfile */
+ gx_band_complexity_t band_complexity;
+
} cmd_block;
/* ---------------- Band state ---------------- */
@@ -252,7 +254,7 @@
/* Following are only used when writing */
cmd_list list; /* list of commands for band */
/* Following are set when writing, read when reading */
- ulong cost; /* cost of rendering the band */
+ gx_band_complexity_t band_complexity;
gx_colors_used_t colors_used;
};
Modified: trunk/gs/src/gxclimag.c
===================================================================
--- trunk/gs/src/gxclimag.c 2007-04-02 22:34:51 UTC (rev 7818)
+++ trunk/gs/src/gxclimag.c 2007-04-03 16:08:49 UTC (rev 7819)
@@ -129,7 +129,8 @@
code = cmd_set_color1(cdev, pcls, pdcolor->colors.pure);
} HANDLE_RECT(code);
pcls->colors_used.slow_rop |= slow_rop;
-
+ pcls->band_complexity.nontrivial_rops |= slow_rop;
+ pcls->band_complexity.uses_color |= (pdcolor->colors.pure != 0 && pdcolor->colors.pure != 0xffffff);
/* Put it in the cache if possible. */
if (!cls_has_tile_id(cdev, pcls, id, offset_temp)) {
gx_strip_bitmap tile;
@@ -620,7 +621,9 @@
}
pcls->colors_used.or |= pie->colors_used.or;
- pcls->colors_used.slow_rop |= pie->colors_used.slow_rop;
+ pcls->band_complexity.nontrivial_rops |=
+ pcls->colors_used.slow_rop |= pie->colors_used.slow_rop;
+ pcls->band_complexity.uses_color |= (pie->colors_used.or != 0 || pie->colors_used.or != 0xffffff);
/* Write out begin_image & its preamble for this band */
if (!(pcls->known & begin_image_known)) {
Modified: trunk/gs/src/gxclist.c
===================================================================
--- trunk/gs/src/gxclist.c 2007-04-02 22:34:51 UTC (rev 7818)
+++ trunk/gs/src/gxclist.c 2007-04-03 16:08:49 UTC (rev 7819)
@@ -302,7 +302,7 @@
int code;
/* Call create_buf_device to get the memory planarity set up. */
- cdev->buf_procs.create_buf_device(&pbdev, target, NULL, NULL, true);
+ cdev->buf_procs.create_buf_device(&pbdev, target, NULL, NULL, clist_get_band_complexity(0, 0));
/* HACK - if the buffer device can't do copy_alpha, disallow */
/* copy_alpha in the commmand list device as well. */
if (dev_proc(pbdev, copy_alpha) == gx_no_copy_alpha)
@@ -663,7 +663,13 @@
return 0;
}
-/* Compute the set of used colors in the page_info structure. */
+/* Compute the set of used colors in the page_info structure.
+ *
+ * NB: Area for improvement, move states[band] and page_info to clist
+ * rather than writer device, or remove completely as this is used by the old planar devices
+ * to operate on a plane at a time.
+ */
+
void
clist_compute_colors_used(gx_device_clist_writer *cldev)
{
@@ -684,6 +690,7 @@
cldev->states[band].colors_used.or;
cldev->page_info.band_colors_used[entry].slow_rop |=
cldev->states[band].colors_used.slow_rop;
+
}
}
@@ -804,3 +811,27 @@
*band_start = start = y - y % band_height;
return min(dev->height - start, band_height);
}
+
+
+
+
+/* copy constructor if from != NULL
+ * default constructor if from == NULL
+ */
+void
+clist_copy_band_complexity(gx_band_complexity_t *this, const gx_band_complexity_t *from)
+{
+ if (from) {
+ memcpy(this, from, sizeof(gx_band_complexity_t));
+ } else {
+ /* default */
+ this->uses_color = false;
+ this->nontrivial_rops = false;
+#if 0
+ /* todo: halftone phase */
+
+ this->x0 = 0;
+ this->y0 = 0;
+#endif
+ }
+}
Modified: trunk/gs/src/gxclist.h
===================================================================
--- trunk/gs/src/gxclist.h 2007-04-02 22:34:51 UTC (rev 7818)
+++ trunk/gs/src/gxclist.h 2007-04-03 16:08:49 UTC (rev 7819)
@@ -261,6 +261,7 @@
/* means all planes */
const gx_placed_page *pages;
int num_pages;
+ gx_band_complexity_t band_complexity_array[100]; /* NB: should be: num_bands elements */
} gx_device_clist_reader;
typedef union gx_device_clist_s {
@@ -344,4 +345,31 @@
const gx_render_plane_t *render_plane,
bool clear);
+/* A null pointer is used to denote not banding.
+ * Since false == NULL the old usage of for_banding = false works even if it's hackish.
+ *
+ * returns the complexity for a band given the y offset from top of page.
+ */
+gx_band_complexity_t *
+clist_get_band_complexity(gx_device *dev, int y);
+
+/* deep copy constructor if from != NULL
+ * default constructor if from == NULL
+ */
+void
+clist_copy_band_complexity(gx_band_complexity_t *this, const gx_band_complexity_t *from);
+
+#ifdef DEBUG
+#define clist_debug_rect clist_debug_rect_imp
+void clist_debug_rect_imp(int x, int y, int width, int height);
+#define clist_debug_image_rect clist_debug_image_rect_imp
+void clist_debug_image_rect_imp(int x, int y, int width, int height);
+#define clist_debug_set_ctm clist_debug_set_ctm_imp
+void clist_debug_set_ctm_imp(const gs_matrix *m);
+#else
+#define clist_debug_rect (void)
+#define clist_debug_image_rect (void)
+#define clist_debug_set_ctm (void)
+#endif
+
#endif /* gxclist_INCLUDED */
Modified: trunk/gs/src/gxclpath.c
===================================================================
--- trunk/gs/src/gxclpath.c 2007-04-02 22:34:51 UTC (rev 7818)
+++ trunk/gs/src/gxclpath.c 2007-04-03 16:08:49 UTC (rev 7819)
@@ -171,6 +171,8 @@
/* should properly calculate colors_used, but for now just punt */
pcls->colors_used.or = ((gx_color_index)1 << cldev->color_info.depth) - 1;
+ pcls->band_complexity.uses_color |= (pdcolor->colors.pure != 0 && pdcolor->colors.pure != 0xffffff);
+
/* record the color we have just serialized color */
pdcolor->type->save_dc(pdcolor, &pcls->sdc);
Modified: trunk/gs/src/gxclread.c
===================================================================
--- trunk/gs/src/gxclread.c 2007-04-02 22:34:51 UTC (rev 7818)
+++ trunk/gs/src/gxclread.c 2007-04-03 16:08:49 UTC (rev 7819)
@@ -36,6 +36,9 @@
#include "stream.h"
#include "strimpl.h"
+/* forward decl */
+private int gx_clist_reader_read_band_complexity(gx_device_clist *dev);
+
/* ------ Band file reading stream ------ */
/*
@@ -113,10 +116,12 @@
goto rb;
clist_fseek(cfile, pos, SEEK_SET, ss->page_cfname);
left = (uint) (ss->b_this.pos - pos);
- if_debug5('l', "[l]reading for bands (%d,%d) at bfile %ld, cfile %ld, length %u\n",
+ if_debug7('l',
+ "[l]reading for bands (%d,%d) at bfile %ld, cfile %ld, length %u color %d rop %d\n",
bmin, bmax,
- (long)(clist_ftell(bfile) - 2 * sizeof(ss->b_this)),
- (long)pos, left);
+ (long)(clist_ftell(bfile) - sizeof(ss->b_this)), /* stefan foo was: 2 * sizeof ?? */
+ (long)pos, left, ss->b_this.band_complexity.uses_color,
+ ss->b_this.band_complexity.nontrivial_rops);
}
}
pw->ptr = q;
@@ -198,6 +203,39 @@
return code;
}
+private int
+clist_reader_init(gx_device_clist *cdev)
+{
+ gx_device_clist_reader * const crdev = &cdev->reader;
+
+ int code = 0;
+
+ /* Initialize for rendering if we haven't done so yet. */
+ if (crdev->ymin < 0) {
+ code = clist_end_page(&cdev->writer);
+ if (code < 0)
+ return code;
+ code = clist_render_init(cdev);
+ }
+ return code;
+}
+
+/* Initialize for reading. */
+private int
+clist_render_init(gx_device_clist *dev)
+{
+ gx_device_clist_reader * const crdev = &dev->reader;
+
+ crdev->ymin = crdev->ymax = 0;
+ crdev->yplane.index = -1;
+ /* For normal rasterizing, pages and num_pages are zero. */
+ crdev->pages = 0;
+ crdev->num_pages = 0;
+
+ return gx_clist_reader_read_band_complexity(dev);
+}
+
+
/* Copy a rasterized rectangle to the client, rasterizing if needed. */
int
clist_get_bits_rectangle(gx_device *dev, const gs_int_rect * prect,
@@ -245,10 +283,14 @@
plane_index = i;
}
}
+
+ if (0 > (code = clist_reader_init(cdev)))
+ return code;
+
clist_select_render_plane(dev, y, line_count, &render_plane, plane_index);
code = gdev_create_buf_device(cdev->buf_procs.create_buf_device,
&bdev, cdev->target, &render_plane,
- dev->memory, true);
+ dev->memory, clist_get_band_complexity(dev,y));
if (code < 0)
return code;
code = clist_rasterize_lines(dev, y, line_count, bdev, &render_plane, &my);
@@ -286,7 +328,7 @@
code = gdev_create_buf_device(cdev->buf_procs.create_buf_device,
&bdev, cdev->target, &render_plane,
- dev->memory, true);
+ dev->memory, clist_get_band_complexity(dev, y));
if (code < 0)
return code;
band_params = *params;
@@ -382,20 +424,6 @@
return line_count;
}
-/* Initialize for reading. */
-private int
-clist_render_init(gx_device_clist *dev)
-{
- gx_device_clist_reader * const crdev = &dev->reader;
-
- crdev->ymin = crdev->ymax = 0;
- crdev->yplane.index = -1;
- /* For normal rasterizing, pages and num_pages are zero. */
- crdev->pages = 0;
- crdev->num_pages = 0;
- return 0;
-}
-
/*
* Render a rectangle to a client-supplied device. There is no necessary
* relationship between band boundaries and the region being rendered.
@@ -416,15 +444,6 @@
int code = 0;
int i;
- /* Initialize for rendering if we haven't done so yet. */
- if (crdev->ymin < 0) {
- code = clist_end_page(&cdev->writer);
- if (code < 0)
- return code;
- code = clist_render_init(cdev);
- if (code < 0)
- return code;
- }
if (render_plane)
crdev->yplane = *render_plane;
else
@@ -520,3 +539,59 @@
return code;
}
+
+/*
+ * return pointer to list indexed by (y /band_height)
+ * Don't free the returned pointer.
+ */
+gx_band_complexity_t *
+clist_get_band_complexity(gx_device *dev, int y)
+{
+ if (dev != NULL) {
+ gx_device_clist_reader * const crdev = &((gx_device_clist *)dev)->reader;
+ int band_number = y / crdev->page_info.band_params.BandHeight;
+
+ if (crdev->band_complexity_array == NULL)
+ return NULL;
+
+ return &crdev->band_complexity_array[band_number];
+ }
+ return NULL;
+}
+
+
+/* call once per read page to read the band complexity from clist file
+ */
+private int
+gx_clist_reader_read_band_complexity(gx_device_clist *dev)
+{
+ int code = -1; /* no dev bad call */
+
+ if (dev) {
+ gx_device_clist_reader * const crdev = &((gx_device_clist *)dev)->reader;
+ gx_device_clist *cdev = (gx_device_clist *)dev;
+ int i;
+ stream_band_read_state rs;
+ cmd_block cb;
+ int64_t save_pos;
+ int pos = 0;
+
+ /* setup stream */
+ s_init_state((stream_state *)&rs, &s_band_read_template, (gs_memory_t *)0);
+ rs.band_first = 0;
+ rs.band_last = crdev->nbands;
+ rs.page_info = crdev->page_info;
+
+ save_pos = clist_ftell(rs.page_bfile);
+ clist_fseek(rs.page_bfile, pos, SEEK_SET, rs.page_bfname);
+
+ for (i=0; i < crdev->nbands; i++) {
+ clist_fread_chars(&cb, sizeof(cb), rs.page_bfile);
+ crdev->band_complexity_array[i] = cb.band_complexity;
+ }
+
+ clist_fseek(rs.page_bfile, save_pos, SEEK_SET, rs.page_bfname);
+ code = 0;
+ }
+ return code;
+}
Modified: trunk/gs/src/gxclrect.c
===================================================================
--- trunk/gs/src/gxclrect.c 2007-04-02 22:34:51 UTC (rev 7818)
+++ trunk/gs/src/gxclrect.c 2007-04-03 16:08:49 UTC (rev 7819)
@@ -145,6 +145,7 @@
fit_fill(dev, x, y, width, height);
FOR_RECTS {
pcls->colors_used.or |= color;
+ pcls->band_complexity.uses_color |= ((color != 0xffffff) && (color != 0));
TRY_RECT {
code = cmd_disable_lop(cdev, pcls);
if (code >= 0 && color != pcls->colors[1])
@@ -180,7 +181,11 @@
FOR_RECTS {
ulong offset_temp;
- pcls->colors_used.or |= colors_used;
+ pcls->colors_used.or |= colors_used;
+ pcls->band_complexity.uses_color |=
+ ((color0 != gx_no_color_index) && (color0 != 0xffffff) && (color0 != 0)) ||
+ ((color1 != gx_no_color_index) && (color1 != 0xffffff) && (color1 != 0));
+
TRY_RECT {
code = cmd_disable_lop(cdev, pcls);
} HANDLE_RECT(code);
@@ -234,7 +239,11 @@
gx_color_index colors_used =
(color0 == gx_no_color_index ? 0 : color0) |
(color1 == gx_no_color_index ? 0 : color1);
+ bool uses_color =
+ ((color0 != gx_no_color_index) && (color0 != 0xffffff) && (color0 != 0)) ||
+ ((color1 != gx_no_color_index) && (color1 != 0xffffff) && (color1 != 0));
+
fit_copy(dev, data, data_x, raster, id, x, y, width, height);
y0 = y;
FOR_RECTS {
@@ -244,6 +253,8 @@
int code;
pcls->colors_used.or |= colors_used;
+ pcls->band_complexity.uses_color |= uses_color;
+
TRY_RECT {
code = cmd_disable_lop(cdev, pcls);
if (code >= 0)
@@ -340,6 +351,8 @@
int code;
pcls->colors_used.or |= colors_used;
+ pcls->band_complexity.uses_color = 1;
+
TRY_RECT {
code = cmd_disable_lop(cdev, pcls);
if (code >= 0)
@@ -585,6 +598,7 @@
pcls->colors_used.or =
((rop_proc_table[color_rop])((rop_operand)D, (rop_operand)S, (rop_operand)T) & all) | D;
pcls->colors_used.slow_rop |= slow_rop;
+ pcls->band_complexity.nontrivial_rops |= slow_rop;
if (rop3_uses_T(rop)) {
if (tcolors == 0 || tcolors[0] != tcolors[1]) {
ulong offset_temp;
Modified: trunk/gs/src/gxclutil.c
===================================================================
--- trunk/gs/src/gxclutil.c 2007-04-02 22:34:51 UTC (rev 7818)
+++ trunk/gs/src/gxclutil.c 2007-04-03 16:08:49 UTC (rev 7819)
@@ -127,7 +127,7 @@
/* Write the commands for one band or band range. */
private int /* ret 0 all ok, -ve error code, or +1 ok w/low-mem warning */
cmd_write_band(gx_device_clist_writer * cldev, int band_min, int band_max,
- cmd_list * pcl, byte cmd_end)
+ cmd_list * pcl, gx_band_complexity_t *band_complexity, byte cmd_end)
{
const cmd_prefix *cp = pcl->head;
int code_b = 0;
@@ -144,8 +144,9 @@
cb.band_min = band_min;
cb.band_max = band_max;
cb.pos = clist_ftell(cfile);
- if_debug3('l', "[l]writing for bands (%d,%d) at %ld\n",
- band_min, band_max, (long)cb.pos);
+ clist_copy_band_complexity(&cb.band_complexity, band_complexity);
+ if_debug4('l', "[l]writing for bands (%d,%d) at %ld K %d \n",
+ band_min, band_max, (long)cb.pos, cb.band_complexity.uses_color);
clist_fwrite_chars(&cb, sizeof(cb), bfile);
if (cp != 0) {
pcl->tail->next = 0; /* terminate the list */
@@ -184,13 +185,16 @@
int band;
int code = cmd_write_band(cldev, cldev->band_range_min,
cldev->band_range_max,
- &cldev->band_range_list, cmd_opv_end_run);
+ &cldev->band_range_list,
+ NULL,
+ cmd_opv_end_run);
+
int warning = code;
for (band = 0, pcls = cldev->states;
code >= 0 && band < nbands; band++, pcls++
) {
- code = cmd_write_band(cldev, band, band, &pcls->list, cmd_end);
+ code = cmd_write_band(cldev, band, band, &pcls->list, &pcls->band_complexity, cmd_end);
warning |= code;
}
/* If an error occurred, finish cleaning up the pointers. */
Modified: trunk/gs/src/gxdevbuf.h
===================================================================
--- trunk/gs/src/gxdevbuf.h 2007-04-02 22:34:51 UTC (rev 7818)
+++ trunk/gs/src/gxdevbuf.h 2007-04-03 16:08:49 UTC (rev 7819)
@@ -41,6 +41,21 @@
uint raster;
} gx_device_buf_space_t;
+/* clist contents analysis per band */
+typedef struct gx_band_complexity_s {
+ /* use null or contents to denote non banding case: */
+
+ bool uses_color;
+ bool nontrivial_rops;
+
+#if 0
+ /* halftone phase */
+ int x0;
+ int y0;
+#endif
+} gx_band_complexity_t;
+
+
typedef struct gx_device_buf_procs_s {
/*
@@ -58,7 +73,7 @@
#define dev_proc_create_buf_device(proc)\
int proc(gx_device **pbdev, gx_device *target,\
const gx_render_plane_t *render_plane, gs_memory_t *mem,\
- bool for_band)
+ gx_band_complexity_t *band_complexity)
dev_proc_create_buf_device((*create_buf_device));
Modified: trunk/gs/src/gxgetbit.h
===================================================================
--- trunk/gs/src/gxgetbit.h 2007-04-02 22:34:51 UTC (rev 7818)
+++ trunk/gs/src/gxgetbit.h 2007-04-03 16:08:49 UTC (rev 7819)
@@ -43,6 +43,7 @@
gs_get_bits_options_t options;
byte *data[32];
int x_offset; /* in returned data */
+ int original_y;
uint raster;
};
Modified: trunk/gs/src/gxwts.c
===================================================================
--- trunk/gs/src/gxwts.c 2007-04-02 22:34:51 UTC (rev 7818)
+++ trunk/gs/src/gxwts.c 2007-04-03 16:08:49 UTC (rev 7819)
@@ -80,21 +80,92 @@
#if 0
private int
wts_get_samples_rat(const wts_screen_t *ws, int x, int y,
- wts_screen_sample_t **samples, int *p_nsamples)
+ int *pcellx, int *pcelly, int *p_nsamples)
{
int d = y / ws->cell_height;
int r = y % ws->cell_height;
int x_ix = ((d * ws->cell_shift) + x) % ws->cell_width;
*p_nsamples = ws->cell_width - x_ix;
- *samples = ws->samples + x_ix + r * ws->cell_width;
+ *pcellx = x_ix;
+ *pcelly = y_ix;
return 0;
}
#endif
+#define MOD_IS_SLOWER_THAN_BRANCH
+
+#ifdef WTS_CACHE_SIZE_X
+/* Implementation of wts_get_samples for Screen J, with cache. */
+private int
+wts_get_samples_j(wts_screen_t *ws, int x, int y,
+ int *pcellx, int *pcelly, int *p_nsamples)
+{
+ int x_ix, y_ix;
+ int nsamples;
+ const wts_screen_j_t *wsj = (const wts_screen_j_t *)ws;
+ wts_j_cache_el *xcache = &wsj->xcache[(x >> 3) & (WTS_CACHE_SIZE_X - 1)];
+ wts_j_cache_el *ycache = &wsj->ycache[y & (WTS_CACHE_SIZE_Y - 1)];
+
+ if (xcache->tag != x || (x & 7)) {
+ double pad = (wsj->pa) * (1.0 / (1 << 16));
+ double pbd = (wsj->pb) * (1.0 / (1 << 16));
+ double afrac = x * pad;
+ double bfrac = x * pbd;
+ int acount = (int)floor(afrac);
+ int bcount = (int)floor(bfrac);
+ int nsa = (int)ceil((acount + 1 - afrac) / pad);
+ int nsb = (int)ceil((acount + 1 - afrac) / pad);
+
+ xcache->x = x + acount * wsj->XA + bcount * wsj->XB;
+ xcache->y = acount * wsj->YA + bcount * wsj->YB;
+#ifdef MOD_IS_SLOWER_THAN_BRANCH
+ xcache->x += (xcache->y / ws->cell_height) * ws->cell_shift;
+ xcache->y %= ws->cell_height;
+#endif
+ xcache->nsamples = min(nsa, nsb);
+ xcache->tag = x;
+ }
+ x_ix = xcache->x;
+ y_ix = xcache->y;
+ nsamples = xcache->nsamples;
+
+ if (ycache->tag != y) {
+ int ccount = mul_shr_16(y, wsj->pc);
+ int dcount = mul_shr_16(y, wsj->pd);
+
+ ycache->x = ccount * wsj->XC + dcount * wsj->XD;
+ ycache->y = y + ccount * wsj->YC + dcount * wsj->YD;
+#ifdef MOD_IS_SLOWER_THAN_BRANCH
+ ycache->x += (ycache->y / ws->cell_height) * ws->cell_shift;
+ ycache->y %= ws->cell_height;
+#endif
+ ycache->tag = y;
+ }
+ x_ix += ycache->x;
+ y_ix += ycache->y;
+
+#ifdef MOD_IS_SLOWER_THAN_BRANCH
+ if (y_ix >= ws->cell_height) {
+ x_ix += ws->cell_shift;
+ y_ix -= ws->cell_height;
+ }
+#else
+ x_ix += (y_ix / ws->cell_height) * ws->cell_shift;
+ y_ix %= ws->cell_height;
+#endif
+ x_ix %= ws->cell_width;
+
+ nsamples = min(nsamples, ws->cell_width - x_ix);
+ *p_nsamples = nsamples;
+ *pcellx = x_ix;
+ *pcelly = y_ix;
+ return 0;
+}
+#else
/* Implementation of wts_get_samples for Screen J. */
private int
-wts_get_samples_j(const wts_screen_t *ws, int x, int y,
- wts_screen_sample_t **samples, int *p_nsamples)
+wts_get_samples_j(wts_screen_t *ws, int x, int y,
+ int *pcellx, int *pcelly, int *p_nsamples)
{
const wts_screen_j_t *wsj = (const wts_screen_j_t *)ws;
/* int d = y / ws->cell_height; */
@@ -130,9 +201,11 @@
x, y, x_ix, y_ix, nsamples, ccount);
#endif
*p_nsamples = nsamples;
- *samples = ws->samples + x_ix + y_ix * ws->cell_width;
+ *pcellx = x_ix;
+ *pcelly = y_ix;
return 0;
}
+#endif
private int
wts_screen_h_offset(int x, double p1, int m1, int m2)
@@ -159,7 +232,7 @@
/* Implementation of wts_get_samples for Screen H. */
private int
wts_get_samples_h(const wts_screen_t *ws, int x, int y,
- wts_screen_sample_t **samples, int *p_nsamples)
+ int *pcellx, int *pcelly, int *p_nsamples)
{
const wts_screen_h_t *wsh = (const wts_screen_h_t *)ws;
int x_ix = wts_screen_h_offset(x, wsh->px,
@@ -167,7 +240,8 @@
int y_ix = wts_screen_h_offset(y, wsh->py,
wsh->y1, ws->cell_height - wsh->y1);
*p_nsamples = (x_ix >= wsh->x1 ? ws->cell_width : wsh->x1) - x_ix;
- *samples = ws->samples + x_ix + y_ix * ws->cell_width;
+ *pcellx = x_ix;
+ *pcelly = y_ix;
return 0;
}
@@ -195,13 +269,13 @@
* Return value: 0 on success.
**/
int
-wts_get_samples(const wts_screen_t *ws, int x, int y,
- wts_screen_sample_t **samples, int *p_nsamples)
+wts_get_samples(wts_screen_t *ws, int x, int y,
+ int *pcellx, int *pcelly, int *p_nsamples)
{
if (ws->type == WTS_SCREEN_J)
- return wts_get_samples_j(ws, x, y, samples, p_nsamples);
+ return wts_get_samples_j(ws, x, y, pcellx, pcelly, p_nsamples);
if (ws->type == WTS_SCREEN_H)
- return wts_get_samples_h(ws, x, y, samples, p_nsamples);
+ return wts_get_samples_h(ws, x, y, pcellx, pcelly, p_nsamples);
else
return -1;
}
@@ -270,8 +344,10 @@
for (xo = 0; xo < w; xo += imax) {
wts_screen_sample_t *samples;
int n_samples, i;
+ int cx, cy;
- wts_get_samples(ws, x + xo, y + yo, &samples, &n_samples);
+ wts_get_samples(ws, x + xo, y + yo, &cx, &cy, &n_samples);
+ samples = ws->samples + cy * ws->cell_width + cx;
imax = min(w - xo, n_samples);
for (i = 0; i < imax; i++) {
if (shade > samples[i])
@@ -310,6 +386,8 @@
wts_screen_t *ws = components[0].corder.wts;
wts_screen_sample_t shade = pdevc->colors.wts.levels[0];
gx_color_index color0, color1;
+ int xph = pdevc->phase.x;
+ int yph = pdevc->phase.y;
color0 = dev->color_info.separable_and_linear == GX_CINFO_SEP_LIN ? 0 :
pdevc->colors.wts.plane_vector[1];
@@ -317,7 +395,7 @@
tile_data = malloc(tile_size);
- wts_draw(ws, shade, tile_data, tile_raster, x, y, w, h);
+ wts_draw(ws, shade, tile_data, tile_raster, x - xph, y - yph, w, h);
/* See gx_dc_ht_binary_fill_rectangle() for explanation. */
if (dev->color_info.depth > 1)
@@ -441,6 +519,8 @@
int code = 0;
bool invert = 0 && dev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE;
int i;
+ int xph = pdevc->phase.x;
+ int yph = pdevc->phase.y;
for (i = 0; i < num_comp; i++) {
wts_screen_sample_t shade = pdevc->colors.wts.levels[i];
@@ -448,7 +528,7 @@
wts_screen_t *ws = components[i].corder.wts;
tile_data[i] = malloc(tile_size);
- wts_draw(ws, shade, tile_data[i], tile_raster, x, y, w, h);
+ wts_draw(ws, shade, tile_data[i], tile_raster, x - xph, y - yph, w, h);
}
ctile_data = malloc(ctile_size);
Modified: trunk/gs/src/gxwts.h
===================================================================
--- trunk/gs/src/gxwts.h 2007-04-02 22:34:51 UTC (rev 7818)
+++ trunk/gs/src/gxwts.h 2007-04-03 16:08:49 UTC (rev 7819)
@@ -21,6 +21,11 @@
typedef struct wts_screen_s wts_screen_t;
#endif
+/* We cache intermediate results for wts_get_samples_j. In general, if these
+ are set so that a band fits, then the hit rate will be excellent. */
+#define WTS_CACHE_SIZE_X 512
+#define WTS_CACHE_SIZE_Y 512
+
typedef enum {
WTS_SCREEN_RAT,
WTS_SCREEN_J,
@@ -36,6 +41,13 @@
};
typedef struct {
+ int tag;
+ int x;
+ int y;
+ int nsamples;
+} wts_j_cache_el;
+
+typedef struct {
wts_screen_t base;
/* Probabilities of "jumps". A and B jumps can happen when moving
@@ -54,6 +66,12 @@
int YC;
int XD;
int YD;
+
+#ifdef WTS_CACHE_SIZE_X
+#define WTS_SCREEN_J_SIZE_NOCACHE 68
+ wts_j_cache_el xcache[WTS_CACHE_SIZE_X];
+ wts_j_cache_el ycache[WTS_CACHE_SIZE_Y];
+#endif
} wts_screen_j_t;
typedef struct {
@@ -68,7 +86,8 @@
int y1;
} wts_screen_h_t;
-int wts_get_samples(const wts_screen_t *ws, int x, int y,
- wts_screen_sample_t **samples, int *p_nsamples);
+int
+wts_get_samples(wts_screen_t *ws, int x, int y,
+ int *pcellx, int *pcelly, int *p_nsamples);
#endif
More information about the gs-cvs
mailing list