[gs-cvs] rev 7977 - branches/gs-esp-gpl-merger/src
till at ghostscript.com
till at ghostscript.com
Mon May 14 12:08:01 PDT 2007
Author: till
Date: 2007-05-14 12:08:00 -0700 (Mon, 14 May 2007)
New Revision: 7977
Modified:
branches/gs-esp-gpl-merger/src/gdevwts.c
Log:
Merged with trunk up to rev 7976.
Modified: branches/gs-esp-gpl-merger/src/gdevwts.c
===================================================================
--- branches/gs-esp-gpl-merger/src/gdevwts.c 2007-05-14 18:51:03 UTC (rev 7976)
+++ branches/gs-esp-gpl-merger/src/gdevwts.c 2007-05-14 19:08:00 UTC (rev 7977)
@@ -1,1043 +1,1043 @@
-/* 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 $ */
-/* ALPHA: Sample Device that provides WTS screening and IMDI color management */
-/* 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[4];
-} 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;
-
- /* guarantee the device bands */
- ((gx_device_printer *)dev)->space_params.banding_type = BandingAlways;
- 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_buffer == 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;
-}
+/* Copyright (C) 2006-2007 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$ */
+/* ALPHA: Sample Device that provides WTS screening and IMDI color management */
+/* 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[4];
+} 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;
+
+ /* guarantee the device bands */
+ ((gx_device_printer *)dev)->space_params.banding_type = BandingAlways;
+ 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_buffer == 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;
+}
Property changes on: branches/gs-esp-gpl-merger/src/gdevwts.c
___________________________________________________________________
Name: svn:keywords
+ Id
More information about the gs-cvs
mailing list