summaryrefslogtreecommitdiff
path: root/gs/src/gdevstc4.c
diff options
context:
space:
mode:
Diffstat (limited to 'gs/src/gdevstc4.c')
-rw-r--r--gs/src/gdevstc4.c301
1 files changed, 301 insertions, 0 deletions
diff --git a/gs/src/gdevstc4.c b/gs/src/gdevstc4.c
new file mode 100644
index 000000000..61a9313f2
--- /dev/null
+++ b/gs/src/gdevstc4.c
@@ -0,0 +1,301 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* gdevstc4.c */
+/* Epson Stylus-Color Printer-Driver */
+
+/***
+ This file holds a byte-Implementation of the Floyd-Steinberg error
+ diffusion-algorithm. This algorithm is an alternative for high quality
+ printing in conjunction with the PostScript-Header stcolor.ps:
+
+ gs -sDEVICE=stcolor -sDithering=fs2 <other options> stcolor.ps ...
+
+ THIS ALGORIHM WAS WRITTEN BY STEVEN SINGER (S.Singer@ph.surrey.ac.uk)
+ AS PART OF escp2cfs2.
+ THIS IMPLEMENTATION INCORPORATES ONLY FEW CHANGES TO THE ORIGINAL CODE.
+
+ ***/
+
+#include "gdevstc.h"
+
+/*
+ * escp2c_pick best scans for best matching color
+ */
+private byte *
+escp2c_pick_best(byte *col)
+{
+ static byte colour[8][3] = {
+ { 0, 0, 0},{255, 0, 0},{ 0,255, 0},{255,255, 0},
+ { 0, 0,255},{255, 0,255},{ 0,255,255},{255,255,255}};
+ register int x, y, z, dx, dy, dz, dz2, dx2, dx3, dx4;
+ register byte *p;
+ register long md, d;
+
+ md = 16777216; /* plenty */
+
+/*
+ Note that I don't use a simple distance algorithm. That can lead to a block
+ of (130,127,127) being dithered as red-cyan. This algorithm should make
+ it use black-white-red. This is very important, as a coloured block in
+ the middle of a grey block can, via error diffusion, perturb the
+ surrounding colours sufficiently for this to happen.
+*/
+
+/*
+ The next bit is equivalent to this, but faster.
+
+ x = col[0];
+ y = col[1];
+ z = col[2];
+ for(n=8; n--; )
+ {
+ dx = x - colour[n][0];
+ dy = y - colour[n][1];
+ dz = z - colour[n][2];
+ d = dx*(dx-(dy>>1)) + dy*(dy-(dz>>1)) + dz*(dz-(dx>>1));
+ if (d < md)
+ {
+ md = d;
+ p = n;
+ }
+ }
+*/
+
+/*
+ * Test colours in gray code order to reduce number of recalculations.
+ * I bet you can't find an optimiser that would do this automatically.
+ */
+
+ x = col[0];
+ y = col[1];
+ z = col[2];
+ dx = x*(x-(y>>1));
+ dy = y*(y-(z>>1));
+ dz = z*(z-(x>>1));
+ md = dx + dy + dz;
+ p = colour[0];
+ x -= 255;
+ dx2 = x*(x-(y>>1));
+ dz2 = z*(z-(x>>1));
+ if ((d = dx2 + dy + dz2) < md) {md = d; p = colour[1];}
+ y -= 255;
+ dx3 = x*(x-(y>>1));
+ dy = y*(y-(z>>1));
+ if ((d = dx3 + dy + dz2) < md) {md = d; p = colour[3];}
+ x += 255;
+ dx4 = x*(x-(y>>1));
+ if ((d = dx4 + dy + dz) < md) {md = d; p = colour[2];}
+ z -= 255;
+ dy = y*(y-(z>>1));
+ dz = z*(z-(x>>1));
+ if ((d = dx4 + dy + dz) < md) {md = d; p = colour[6];}
+ x -= 255;
+ dz2 = z*(z-(x>>1));
+ if ((d = dx3 + dy + dz2) < md) {md = d; p = colour[7];}
+ y += 255;
+ dy = y*(y-(z>>1));
+ if ((d = dx2 + dy + dz2) < md) {md = d; p = colour[5];}
+ if ((d = dx + dy + dz) < md) {p = colour[4];}
+ return(p);
+}
+
+/*
+ * escp2c_conv_stc converts into the ouput format used by stcolor
+ */
+private void
+escp2c_conv_stc(byte *p, byte *q, int i)
+{
+ for(; i; p+=3, i-=3)
+ *q++ = (*p & RED) | (p[1] & GREEN) | (p[2] & BLUE);
+}
+
+
+/*
+ * Limit byte-values
+ */
+#define LIMIT(a) if (a > 255) a = 255; if (a < 0) a = 0
+#define LIMIT2(a) if (a > 127) a = 127; if (a < -128) a = -128; \
+ if (a < 0) a += 256
+/*
+ * Main routine of the algorithm
+ */
+int
+stc_fs2(stcolor_device *sd,int npixel,byte *in,byte *buf,byte *out)
+{
+ int fullcolor_line_size = npixel*3;
+
+/* ============================================================= */
+ if(npixel > 0) { /* npixel > 0 -> scanline-processing */
+/* ============================================================= */
+
+/* -------------------------------------------------------------------- */
+ if(in == NULL) { /* clear the error-buffer upon white-lines */
+/* -------------------------------------------------------------------- */
+
+ memset(buf,0,fullcolor_line_size);
+
+/* ------------------------------------------------------------------- */
+ } else { /* do the actual dithering */
+/* ------------------------------------------------------------------- */
+ int i, j, k, e, l, i2, below[3][3], *fb, *b, *bb, *tb;
+ byte *p, *q, *cp;
+ static int dir = 1;
+
+ p = buf;
+ if (*p != 0 || memcmp((char *) p, (char *) p + 1, fullcolor_line_size - 1))
+ {
+ for(p = in, q=buf, i=fullcolor_line_size;
+ i--; p++, q++ )
+ {
+ j = *p + ((*q & 128) ? *q - 256 : *q);
+ LIMIT(j);
+ *p = j;
+ }
+ }
+
+ p = in;
+
+ fb = below[2];
+ b = below[1];
+ bb = below[0];
+ *b = b[1] = b[2] = *bb = bb[1] = bb[2] = 0;
+
+ if (dir)
+ {
+ for(p = in, q=buf-3,
+ i=fullcolor_line_size; i; i-=3)
+ {
+ cp = escp2c_pick_best(p);
+ for(i2=3; i2--; p++, q++, fb++, b++, bb++)
+ {
+ j = *p;
+ *p = *cp++;
+ j -= *p;
+ if (j != 0)
+ {
+ l = (e = (j>>1)) - (*fb = (j>>4));
+ if (i > 2)
+ {
+ k = p[3] + l;
+ LIMIT(k);
+ p[3] = k;
+ }
+ *b += e - (l = (j>>2) - *fb);
+ if (i < fullcolor_line_size)
+ {
+ l += *bb;
+ LIMIT2(l);
+ *q = l;
+ }
+ }
+ else
+ *fb = 0;
+ }
+ tb = bb-3;
+ bb = b-3;
+ b = fb-3;
+ fb = tb;
+ }
+ *q = *bb;
+ q[1] = bb[1];
+ q[2] = bb[2];
+ dir = 0;
+ }
+ else
+ {
+ for(p = in+fullcolor_line_size-1,
+ q = buf+fullcolor_line_size+2, i=fullcolor_line_size;
+ i; i-=3)
+ {
+ cp = escp2c_pick_best(p-2) + 2;
+ for(i2=3; i2--; p--, q--, fb++, b++, bb++)
+ {
+ j = *p;
+ *p = *cp--;
+ j -= *p;
+ if (j != 0)
+ {
+ l = (e = (j>>1)) - (*fb = (j>>4));
+ if (i > 2)
+ {
+ k = p[-3] + l;
+ LIMIT(k);
+ p[-3] = k;
+ }
+ *b += e - (l = (j>>2) - *fb);
+ if (i < fullcolor_line_size)
+ {
+ l += *bb;
+ LIMIT2(l);
+ *q = l;
+ }
+ }
+ else
+ *fb = 0;
+ }
+ tb = bb-3;
+ bb = b-3;
+ b = fb-3;
+ fb = tb;
+ }
+ *q = *bb;
+ q[1] = bb[1];
+ q[2] = bb[2];
+ dir = 1;
+ }
+
+ escp2c_conv_stc(in, out, fullcolor_line_size);
+
+/* ------------------------------------------------------------------- */
+ } /* buffer-reset | dithering */
+/* ------------------------------------------------------------------- */
+
+
+/* ============================================================= */
+ } else { /* npixel <= 0 -> initialisation */
+/* ============================================================= */
+
+
+/*
+ * check wether the number of components is valid
+ */
+ if(sd->color_info.num_components != 3) return -1;
+
+/*
+ * check wether stcdither & TYPE are correct
+ */
+ if(( sd->stc.dither == NULL) ||
+ ((sd->stc.dither->flags & STC_TYPE) != STC_BYTE)) return -2;
+
+/*
+ * check wether the buffer-size is sufficiently large
+ */
+ if((sd->stc.dither->flags/STC_SCAN) < 1) return -3;
+
+/*
+ * finally clear the buffer
+ */
+ memset(buf,0,-fullcolor_line_size);
+
+/* ============================================================= */
+ } /* scanline-processing or initialisation */
+/* ============================================================= */
+
+ return 0;
+}