1 /* BJC-210/240/250/265/1000 Bubble Jet Printer driver for GhostScript
2  * utility subroutines and dithering code
3  *
4  * Copyright 2000, 2001, 2002 Gergely Sz�sz (Gergely Sza'sz)
5  * mailto://szaszg@hu.inter.net http://bjc250gs.sourceforge.net
6  *
7  *   This program may be distributed and/or modified under the terms of
8  *   the GNU General Public License as published by the Free Software
9  *   Foundation (the "GPL"); either version 2 of the GPL, or (at your option)
10  *   any later version.
11  *
12  *   When distributed under the terms of the GPL, this program is distributed
13  *   in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
14  *   even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  *   PURPOSE.  See the GPL for more details.
16  *
17  *   If this program is being distributed under the terms of the GPL, you
18  *   should have received a copy of the GPL along with this program, normally
19  *   in a plain ASCII text file named COPYING; if not, write to the Free
20  *   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111
21  *   U.S.A.
22  */
23 
24 /* Copyright (C) 1989, 2000 Aladdin Enterprises.  All rights reserved.
25 
26    This program may also be distributed as part of AFPL Ghostscript, under the
27    terms of the Aladdin Free Public License (the "License").
28 
29    AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No
30    author or distributor accepts any responsibility for the consequences of
31    using it, or for whether it serves any particular purpose or works at
32    all, unless he or she says so in writing.  Refer to the License for full
33    details.
34 
35    Every copy of AFPL Ghostscript must include a copy of the License,
36    normally in a plain ASCII text file named PUBLIC.  The License grants you
37    the right to copy, modify and redistribute AFPL Ghostscript, but only
38    under certain conditions described in the License.  Among other things,
39    the License requires that the copyright notice and this notice be
40    preserved on all copies.
41 */
42 
43 /* BJC printer drivers utilities */
44 #include "gdevprn.h"
45 #include "gdevbjc_.h"
46 #include <math.h>
47 #include <time.h>
48 
49 private void bjc_put_bytes(P3(FILE *file, const char *data, int count));
50 private void bjc_put_hi_lo(P2(FILE *file, int value));
51 private void bjc_put_lo_hi(P2(FILE *file, int value));
52 private void bjc_put_command(P3(FILE *file, char command, int count));
53 
54 /* ---------------- Utilities ---------------- */
55 
56 private void
bjc_put_bytes(FILE * file,const char * data,int count)57 bjc_put_bytes(FILE *file, const char *data, int count)
58 {
59 
60     fwrite(data, count, 1, file);
61 }
62 
63 private void
bjc_put_hi_lo(FILE * file,int value)64 bjc_put_hi_lo(FILE *file, int value)
65 {
66     fputc(((value & 0xffff) >> 8), file);
67     fputc(value & 0xff, file);
68 }
69 
70 private void
bjc_put_lo_hi(FILE * file,int value)71 bjc_put_lo_hi(FILE *file, int value)
72 {
73     fputc(value & 0xff, file);
74     fputc(((value & 0xffff) >> 8), file);
75 }
76 
77 private void
bjc_put_command(FILE * file,char command,int count)78 bjc_put_command(FILE *file, char command, int count)
79 {   char tmp[3] = { '\033', '(', ' '};
80     tmp[2] = command;
81     fwrite( tmp, 3, 1, file);
82     bjc_put_lo_hi(file, count);
83 }
84 
85 /* ---------------- Commands ---------------- */
86 
87 /* Line feed (^J) */
88 void
bjc_put_LF(FILE * file)89 bjc_put_LF(FILE *file)
90 {
91     fputc(0x0a, file);
92 }
93 
94 /* Form feed (^L) */
95 void
bjc_put_FF(FILE * file)96 bjc_put_FF(FILE *file)
97 {
98     fputc(0x0c, file);
99 }
100 
101 /* Carriage return (^M) */
102 void
bjc_put_CR(FILE * file)103 bjc_put_CR(FILE *file)
104 {
105     fputc(0x0d, file);
106 }
107 
108 /* Return to initial condition (ESC @) */
109 void
bjc_put_initialize(FILE * file)110 bjc_put_initialize(FILE *file)
111 {
112     bjc_put_bytes(file, "\033@", 2);
113 }
114 
115 /* Set initial condition (ESC [ K <count> <init> <id> <parm1> <parm2>) */
116 void
bjc_put_set_initial(FILE * file)117 bjc_put_set_initial(FILE *file)
118 {
119     bjc_put_bytes(file, "\033[K\002\000\000\017", 7);
120 }
121 
122 /* Set data compression (ESC [ b <count> <state>) */
123 void
bjc_put_set_compression(FILE * file,char compression)124 bjc_put_set_compression(FILE *file, char compression)
125 {
126     bjc_put_command(file, 'b', 1);
127     fputc(compression, file);
128 }
129 
130 /* Select print method (ESC ( c <count> <parm1> <parm2> [<parm3>]) */
131 void
bjc_put_print_method_short(FILE * file,char color)132 bjc_put_print_method_short(FILE *file, char color)
133 {
134     bjc_put_command(file, 'c', 1);
135     fputc(color, file);
136 }
137 void
bjc_put_print_method(FILE * file,char color,char media,char quality,char density)138 bjc_put_print_method(FILE *file, char color, char media, char quality,
139 		     char density)
140 {
141     bjc_put_command(file, 'c', 2 + (density != 0));
142     fputc(color, file);
143     fputc(media | quality, file);
144     if (density)
145 	fputc(density, file);
146 }
147 
148 /* Set raster resolution (ESC ( d <count> <y_res> [<x_res>]) */
149 void
bjc_put_raster_resolution(FILE * file,int x_resolution,int y_resolution)150 bjc_put_raster_resolution(FILE *file, int x_resolution, int y_resolution)
151 {
152     if (x_resolution == y_resolution) {
153 	bjc_put_command(file, 'd', 2);
154     } else {
155 	bjc_put_command(file, 'd', 4);
156 	bjc_put_hi_lo(file, y_resolution);
157     }
158     bjc_put_hi_lo(file, x_resolution);
159 }
160 
161 /* Raster skip (ESC ( e <count> <skip>) */
162 void
bjc_put_raster_skip(FILE * file,int skip)163 bjc_put_raster_skip(FILE *file, int skip)
164 {
165     bjc_put_command(file, 'e', 2);
166     bjc_put_hi_lo(file, skip);
167 }
168 
169 /* Set page margins (ESC ( g <count> <length> <lm> <rm> <top>) */
170 void
bjc_put_page_margins(FILE * file,int length,int lm,int rm,int top)171 bjc_put_page_margins(FILE *file, int length, int lm, int rm, int top)
172 {
173     char parms[4];
174 
175     parms[0] = length, parms[1] = lm, parms[2] = rm, parms[3] = top;
176 /*    count = 4;       */ 	/* could be 1..3 */
177     bjc_put_command(file, 'g', 4);
178     bjc_put_bytes(file, parms, 4);
179 }
180 
181 /* Set media supply method (ESC * l <count> <parm1> <parm2>) */
182 void
bjc_put_media_supply(FILE * file,char supply,char type)183 bjc_put_media_supply(FILE *file, char supply, char type)
184 {
185     bjc_put_command(file, 'l', 2);
186     fputc(supply, file);
187     fputc(type << 4, file);
188 }
189 
190 /* Identify ink cartridge (ESC ( m <count> <type>) */ /*
191 void
192 bjc_put_identify_cartridge(FILE *file,
193 			   bjc_identify_cartridge_command_t command)
194 {
195     bjc_put_command(s, 'm', 1);
196     spputc(s, command);
197 }                      */
198 
199 /* CMYK raster image (ESC ( A <count> <color>) */
200 void
bjc_put_cmyk_image(FILE * file,char component,const char * data,int count)201 bjc_put_cmyk_image(FILE *file, char component,
202 		   const char *data, int count)
203 {
204     bjc_put_command(file, 'A', count + 1);
205     fputc(component, file);
206     bjc_put_bytes(file, data, count);
207 }
208 
209 /* Move by raster lines (ESC ( n <count> <lines>) */
210 void
bjc_put_move_lines(FILE * file,int lines)211 bjc_put_move_lines(FILE *file, int lines)
212 {
213     bjc_put_command(file, 'n', 2);
214     bjc_put_hi_lo(file, lines);
215 }
216 
217 /* Set unit for movement by raster lines (ESC ( o <count> <unit>) */
218 void
bjc_put_move_lines_unit(FILE * file,int unit)219 bjc_put_move_lines_unit(FILE *file, int unit)
220 {
221     bjc_put_command(file, 'o', 2);
222     bjc_put_hi_lo(file, unit);
223 }
224 
225 /* Set extended margins (ESC ( p <count> <length60ths> <lm60ths> */
226 /*   <rm60ths> <top60ths>) */
227 void
bjc_put_extended_margins(FILE * file,int length,int lm,int rm,int top)228 bjc_put_extended_margins(FILE *file, int length, int lm, int rm, int top)
229 {
230     bjc_put_command(file, 'p', 8);
231     bjc_put_hi_lo(file, length);
232     bjc_put_hi_lo(file, lm);
233     bjc_put_hi_lo(file, rm);
234     bjc_put_hi_lo(file, top);
235 }
236 
237 /* Set image format (ESC ( t <count> <depth> <format> <ink>) */
238 void
bjc_put_image_format(FILE * file,char depth,char format,char ink)239 bjc_put_image_format(FILE *file, char depth, char format, char ink)
240 {
241     bjc_put_command(file, 't', 3);
242     fputc(depth, file);
243     fputc(format, file);
244     fputc(ink, file);
245 }
246 
247 /* Page ID (ESC ( q <count> <id>) */
248 void
bjc_put_page_id(FILE * file,int id)249 bjc_put_page_id(FILE *file, int id)
250 {
251     bjc_put_command(file, 'q', 1);
252     fputc(id, file);
253 }
254 
255 /* Continue raster image (ESC ( F <count> <data>) */
256 void
bjc_put_continue_image(FILE * file,const char * data,int count)257 bjc_put_continue_image(FILE *file, const char *data, int count)
258 {
259     bjc_put_command(file, 'F', count);
260     bjc_put_bytes(file, data, count);
261 }
262 
263 /* BJ indexed image (ESC ( f <count> R <dot_rows> <dot_cols> <layers> */
264 /*   <index>) */
265 void
bjc_put_indexed_image(FILE * file,int dot_rows,int dot_cols,int layers)266 bjc_put_indexed_image(FILE *file, int dot_rows, int dot_cols, int layers)
267 {
268     bjc_put_command(file, 'f', 5);
269     fputc('R', file);			/* per spec */
270     fputc(dot_rows, file);
271     fputc(dot_cols, file);
272     fputc(layers, file);
273 }
274 
275 
276 /* ------------------------------------------------------------------ */
277 
278 /* Invert a raster line ( we need it for Black -> K ) */
279 bool
bjc_invert_bytes(byte * row,uint raster,bool inverse,byte lastmask)280 bjc_invert_bytes(byte *row, uint raster, bool inverse, byte lastmask)
281 {   bool ret=false;
282 
283     for(; raster > 1; row++, raster--) {
284 	if(!(inverse)) *row = ~(*row);
285 	if(*row) ret = true;
286     }
287 	if(!(inverse)) *row ^= 0xff;
288                        *row &= lastmask;
289     return ret;
290 }
291 
292 bool
bjc_invert_cmyk_bytes(byte * rowC,byte * rowM,byte * rowY,byte * rowK,uint raster,bool inverse,byte lastmask,skip_t * skip)293 bjc_invert_cmyk_bytes(byte *rowC, byte *rowM, byte *rowY, byte *rowK,
294                       uint raster, bool inverse, byte lastmask,
295                      skip_t *skip)
296 {   bool ret=false;
297     byte tmpC, tmpM, tmpY;
298 
299     skip->skipC=false;
300     skip->skipM=false;
301     skip->skipY=false;
302     skip->skipK=false;
303 
304     for(; raster > 1; rowC++, rowM++, rowY++, rowK++, raster--) {
305 	if(inverse) {
306 	              tmpC = ~(*rowC|*rowK);
307 	              tmpM = ~(*rowM|*rowK);
308 		      tmpY = ~(*rowY|*rowK);
309 		     *rowK = ~(*rowC|*rowM|*rowY|*rowK);
310                      *rowC = tmpC;
311                      *rowM = tmpM;
312                      *rowY = tmpY;
313         }
314         if(*rowC) skip->skipC=true;
315         if(*rowM) skip->skipM=true;
316         if(*rowY) skip->skipY=true;
317         if(*rowK) skip->skipK=true;
318 	if(*rowC|*rowM|*rowY|*rowK) ret = true;
319     }
320     return ret;
321 }
322 
323 /* "1D runlength compression for BJC-600
324  *  this code is borrowed from gdevpcl.c:gdev_pcl_mode2compress."
325  * I copy it from gdevcdj.c
326  * It is return with the compressed length. 'compressed' point to the
327  * compression buffer
328  */
329 uint
bjc_compress(const byte * row,uint raster,byte * compressed)330 bjc_compress(const byte *row, uint raster, byte *compressed)
331 {
332   const byte *end_row = row;
333   register const byte *exam = row;
334   register byte *cptr = compressed; /* output pointer into compressed bytes */
335 
336   end_row += raster;
337 
338   while ( exam < end_row ) {
339     /* Search ahead in the input looking for a run */
340     /* of at least 4 identical bytes. */
341     const byte *compr = exam;
342     const byte *end_dis;
343     const byte *next;
344     register byte test, test2;
345 
346     test = *exam;
347     while ( exam < end_row ) {
348       test2 = *++exam;
349       if ( test == test2 )
350 	  break;
351       test = test2;
352     }
353 
354 
355     /* Find out how long the run is */
356     end_dis = exam - 1;
357     if ( exam == end_row ) { /* no run */
358       next = --end_row;
359     } else {
360 
361       next = exam + 1;
362       while ( next < end_row && *next == test ) next++;
363     }
364 
365 
366     /* Now [compr..end_dis) should be encoded as dissimilar, */
367     /* and [end_dis..next) should be encoded as similar. */
368     /* Note that either of these ranges may be empty. */
369 
370 
371     for ( ; ; ) {	/* Encode up to 128 dissimilar bytes */
372       uint count = end_dis - compr; /* uint for faster switch */
373       switch ( count ) { /* Use memcpy only if it's worthwhile. */
374       case 6: cptr[6] = compr[5];
375       case 5: cptr[5] = compr[4];
376       case 4: cptr[4] = compr[3];
377       case 3: cptr[3] = compr[2];
378       case 2: cptr[2] = compr[1];
379       case 1: cptr[1] = compr[0];
380 	*cptr = count - 1;
381 	cptr += count + 1;
382       case 0: /* all done */
383 	break;
384       default:
385 	if ( count > 128 ) count = 128;
386 	*cptr++ = count - 1;
387 	memcpy(cptr, compr, count);
388 	cptr += count, compr += count;
389 	continue;
390       }
391       break;
392     }
393 
394 
395     {	/* Encode up to 128 similar bytes. */
396       /* Note that count may be <0 at end of row. */
397       int count = next - end_dis;
398       if (next < end_row || test != 0)
399 	while ( count > 0 ) {
400 
401 	  int this = (count > 128 ? 128 : count);
402 	  *cptr++ = 257 - this;
403 	  *cptr++ = (byte)test;
404 	  count -= this;
405 	}
406       exam = next;
407     }
408   }
409   return (uint)(cptr - compressed);
410 }
411 
bjc_rgb_to_cmy(byte r,byte g,byte b,int * c,int * m,int * y)412 void bjc_rgb_to_cmy(byte r, byte g, byte b,
413                      int *c, int *m, int *y)
414 {   *c=255-r;
415     *m=255-g;
416     *y=255-b;
417 }
418 
bjc_rgb_to_gray(byte r,byte g,byte b,int * k)419 void bjc_rgb_to_gray(byte r, byte g, byte b,
420 		     int *k)
421 {
422     *k = ( (int)r * 77 + (int)g * 151 + (int)b * 28) >> 8;
423 }
424 
425 int bjc_gamma_tableC[256];
426 int bjc_gamma_tableM[256];
427 int bjc_gamma_tableY[256];
428 #define bjc_gamma_tableK bjc_gamma_tableC
429 
bjc_build_gamma_table(float gamma,char color)430 void bjc_build_gamma_table(float gamma, char color)
431 { int i;
432   int *table;
433 
434     switch(color) {
435     case CMYK_C:
436 	table = bjc_gamma_tableC;
437 	break;
438     case CMYK_M:
439 	table = bjc_gamma_tableM;
440 	break;
441     case CMYK_Y:
442 	table = bjc_gamma_tableY;
443 	break;
444     case CMYK_K:
445     default:
446         table = bjc_gamma_tableK;
447         break;
448     }
449 
450     if(gamma == 1.0) for (i = 0; i < 256; i++) table[i] = (255 - i) << 4;
451     else for (i = 0; i < 256; i++) table[i] =
452                   4080 - (int)(pow((double)i / 255.0, gamma) * 4080.0 + .5);
453 }
454 
455 /* -------------------------------------------------------------------------*/
456 /*                 Subroutines and tables for randomization                 */
457 /* -------------------------------------------------------------------------*/
458 
459 int bjc_rand_seed[55] = {
460 3627, 15177, 6104, 15555, 14210, 9940, 11987, 7070, 6147, 15691, 14536, 12896,
461 8959, 14926, 9034, 13544, 13665, 3175, 10177, 14856, 16042, 4265, 13976, 10805,
462 14817, 8216,  695, 8656, 9189, 15304, 1469, 9641, 1648, 16218, 12421, 5451,
463 255, 11268, 16121, 11645, 1855, 5982, 9983, 1052, 5255, 15264, 6123, 3577,
464 9712, 14629, 4593, 15670
465 };
466 int bjc_j=0, bjc_k=31;
467 
468 int bjc_treshold[1024];
469 
bjc_rand(void)470 uint bjc_rand(void)
471 {
472     uint ret=bjc_rand_seed[bjc_j] = bjc_rand_seed[bjc_j++] +
473                                         bjc_rand_seed[bjc_k++];
474     if(bjc_j==55) bjc_j = 0;
475     if(bjc_k==55) bjc_k = 0;
476     return ret & 0x03ff;
477 }                                             /* random numbers 0-1023 */
478 
479 
bjc_init_tresh(int rnd)480 void bjc_init_tresh(int rnd)
481 {
482     int i=(int)(time(NULL) & 0x0ff);
483     float delta=40.64*rnd;
484     for(;i>0;i--) bjc_rand();
485     for(i=-512; i<512; i++) bjc_treshold[i+512] =
486                                 (int)(delta * i / 1024.0 + 2040);
487 }                      /* init treshold array ~rnd% around halfway (127*16) */
488 
489 
490 /* Declarations for Floyd-Steinberg dithering.
491  *
492  * Errors are accumulated into the array fserrors[], at a resolution of
493  * 1/16th of a pixel count.  The error at a given pixel is propagated
494  * to its not-yet-processed neighbors using the standard F-S fractions,
495  *		...	(here)	7/16
496  *		3/16	5/16	1/16
497  * We work left-to-right on even rows, right-to-left on odd rows.
498  *
499  * We can get away with a single array (holding one row's worth of errors)
500  * by using it to store the current row's errors at pixel columns not yet
501  * processed, but the next row's errors at columns already processed.  We
502  * need only a few extra variables to hold the errors immediately around the
503  * current column.  (If we are lucky, those variables are in registers, but
504  * even if not, they're probably cheaper to access than array elements are.)
505  *
506  * The fserrors[] array has (#columns + 2) entries; the extra entry at
507  * each end saves us from special-casing the first and last pixels.
508  * Each entry is three values long, one value for each color component.
509  */
510 
511 bool FloydSteinbergDirectionForward = true;
512 
513 int *FloydSteinbergErrorsC;
514 int *FloydSteinbergErrorsM;
515 int *FloydSteinbergErrorsY;
516 int *FloydSteinbergErrorsK;
517 int *FloydSteinbergErrorsG;
518 
519 int FloydSteinbergC;
520 int FloydSteinbergM;
521 int FloydSteinbergY;
522 int FloydSteinbergK;
523 int FloydSteinbergG;
524 
525 int
FloydSteinbergInitG(gx_device_printer * pdev)526 FloydSteinbergInitG(gx_device_printer * pdev)
527 {  int i;
528 #define ppdev ((gx_device_bjc_printer *) pdev)
529 
530 FloydSteinbergErrorsG = (int *) gs_alloc_bytes(pdev->memory,
531                                               sizeof(int)*(pdev->width+3),
532                                               "bjc error buffer");
533 if (FloydSteinbergErrorsG == 0)		/* can't allocate error buffer */
534 	return -1;
535 FloydSteinbergDirectionForward=true;
536 
537 for (i=0; i < pdev->width+3; i++) FloydSteinbergErrorsG[i] = 0;
538                                                               /* clear */
539 bjc_rgb_to_gray(ppdev->paperColor.red,
540 		ppdev->paperColor.green,
541 		ppdev->paperColor.blue,
542                 &FloydSteinbergG);
543 FloydSteinbergG = (255 - FloydSteinbergG) << 4;  /* Maybe */
544 bjc_init_tresh(ppdev->rnd);
545 return 0;
546 #undef ppdev
547 }
548 
549 void
FloydSteinbergDitheringG(byte * row,byte * dithered,uint width,uint raster,bool limit_extr)550 FloydSteinbergDitheringG(byte *row, byte *dithered, uint width,
551 			uint raster, bool limit_extr)
552 {
553     byte byteG=0, bitmask = 0x80; /* first bit */
554     int i;
555     int error = 0, delta;
556     int err_corr;
557     int *err_vect;
558 
559     if (FloydSteinbergDirectionForward) {
560         /* First  point */
561         err_vect = FloydSteinbergErrorsG + 1;
562 
563 	for( i=width; i>0; i--, row++, err_vect++) { /* i, sample, error */
564 	    err_corr = bjc_gamma_tableK[255-(*row)] + FloydSteinbergG;
565             if(err_corr > 4080 && limit_extr) err_corr = 4080;
566 	    error += err_corr + *(err_vect+1);     /* the error in 1/16 */
567 
568             if(error > bjc_treshold[bjc_rand()])  {
569                 error -=  4080;
570                 byteG |=  bitmask;
571             }
572 
573             *(err_vect+1) = (error + 8) >> 4;
574             delta = error << 1;                                 /* 2 err */
575             error += delta;                                     /* 3/16  */
576             *(err_vect-1) += (error + 8) >> 4;
577             error += delta;                                     /* 5/16  */
578             *err_vect += (error + 8) >> 4;
579             error += delta + 8;                                 /* 7/16  */
580             error >>= 4;
581 
582             if (bitmask == 0x01) {
583                 *dithered = byteG;
584                 bitmask = 0x80;
585                 byteG = 0;
586                 dithered++;
587             }
588             else if (i == 1) {
589                 *dithered = byteG;
590             }
591             else bitmask >>= 1;
592 	}
593         FloydSteinbergDirectionForward=false;
594     }
595     else {
596         row += width - 1;                   /* point to the end of the row */
597         dithered += raster - 1;
598         bitmask = 1 << ((raster << 3 ) - width) ;
599         err_vect = FloydSteinbergErrorsG + width + 1;
600 
601 	for( i=width; i>0; i--, row--, err_vect--) {
602 	    err_corr = bjc_gamma_tableK[255-(*row)] + FloydSteinbergG;
603             if(err_corr > 4080 && limit_extr) err_corr = 4080;
604 
605             error += err_corr + *(err_vect - 1);
606 
607             if(error > bjc_treshold[bjc_rand()])  {
608                 error -=  4080;
609                 byteG |=  bitmask;
610             }
611 
612             *(err_vect-1) = (error + 8) >> 4;                  /* 1/16 */
613             delta = error << 1;                                 /* 2 err */
614             error += delta;
615             *(err_vect+1) += (error +8)  >> 4;                   /* 3/16  */
616             error += delta;
617             *err_vect += (error + 8)  >> 4;                      /* 5/16  */
618             error += delta + 8;                                  /* 7/16  */
619             error >>= 4;
620 
621             if (bitmask == 0x80) {
622                 *dithered = byteG;
623                 bitmask = 0x01;
624                 byteG = 0;
625                 dithered--;
626             } else if(i==1) {
627                 *dithered = byteG;
628             }
629             else bitmask <<= 1;
630 	}
631         FloydSteinbergDirectionForward=true;
632     }
633 }
634 
FloydSteinbergCloseG(gx_device_printer * pdev)635 void FloydSteinbergCloseG(gx_device_printer *pdev)
636 {
637     gs_free_object(pdev->memory, FloydSteinbergErrorsG, "bjc error buffer");
638 }
639 
640 int
FloydSteinbergInitC(gx_device_printer * pdev)641 FloydSteinbergInitC(gx_device_printer * pdev)
642 { int i;
643 #define ppdev ((gx_device_bjc_printer *) pdev)
644 
645 FloydSteinbergErrorsC = (int *) gs_alloc_bytes(pdev->memory,
646                                             3*sizeof(int)*(pdev->width+3),
647                                               "bjc CMY error buffer");
648 if (FloydSteinbergErrorsC == 0 )      	/* can't allocate error buffer */
649 	return -1;
650 
651 for (i=0; i < 3 * (pdev->width+3); i++) FloydSteinbergErrorsC[i] = 0;
652 
653 FloydSteinbergDirectionForward=true;
654 bjc_rgb_to_cmy(ppdev->paperColor.red,
655 	       ppdev->paperColor.green,
656 	       ppdev->paperColor.blue,
657 	       &FloydSteinbergC,
658 	       &FloydSteinbergM,
659                &FloydSteinbergY);
660 
661 FloydSteinbergC <<= 4;
662 FloydSteinbergM <<= 4;
663 FloydSteinbergY <<= 4;
664 bjc_init_tresh(ppdev->rnd);
665 return 0;
666 #undef ppdev
667 }
668 
669 void
FloydSteinbergDitheringC(byte * row,byte * dithered,uint width,uint raster,bool limit_extr,bool composeK)670 FloydSteinbergDitheringC(byte *row, byte *dithered, uint width,
671 			uint raster, bool limit_extr, bool composeK)
672 {   byte byteC=0, byteM=0, byteY=0, byteK=0, bitmask = 0x80; /* first bit */
673     int i;
674     int errorC = 0, errorM = 0, errorY = 0, delta;
675     int err_corrC, err_corrM, err_corrY;
676     int *err_vect;
677 
678     if (FloydSteinbergDirectionForward) {
679         err_vect = FloydSteinbergErrorsC + 3;         /* errCMY */
680 	/* First  point */
681 
682         for( i=width; i>0; i--, row+=4, err_vect+=3) { /*separate components */
683 
684 /*                                          C     +       K           */
685             err_corrC = bjc_gamma_tableC[ (*row)    + (*(row+3))]
686                           + FloydSteinbergC;
687             err_corrM = bjc_gamma_tableM[(*(row+1)) + (*(row+3))]
688                           + FloydSteinbergM;
689             err_corrY = bjc_gamma_tableY[(*(row+2)) + (*(row+3))]
690                           + FloydSteinbergY;
691 
692             if(err_corrC > 4080 && limit_extr) err_corrC = 4080;
693             if(err_corrM > 4080 && limit_extr) err_corrM = 4080;
694             if(err_corrY > 4080 && limit_extr) err_corrY = 4080;
695 
696             errorC += err_corrC + (*(err_vect + 3));       /* CMYCMYCMY */
697             errorM += err_corrM + (*(err_vect + 4));       /* |  ^  !   */
698             errorY += err_corrY + (*(err_vect + 5));
699 
700             if(errorC > bjc_treshold[bjc_rand()])  {
701                 errorC -=  4080;
702                 byteC |=  bitmask;
703             }
704 
705             if(errorM > bjc_treshold[bjc_rand()])  {
706                 errorM -=  4080;
707                 byteM |=  bitmask;
708             }
709 
710             if(errorY > bjc_treshold[bjc_rand()])  {
711                 errorY -=  4080;
712                 byteY |=  bitmask;
713             }
714 
715             *(err_vect+3) = (errorC + 8) >> 4;                   /* 1/16 */
716             delta = errorC << 1;                                 /* 2 err */
717             errorC += delta;
718             *(err_vect-3) += (errorC + 8) >> 4;                  /* 3/16  */
719             errorC += delta;
720             *err_vect += (errorC + 8) >> 4;                           /* 5/16  */
721             errorC += delta + 8;                                  /* 7/16  */
722             errorC >>= 4;
723 
724             *(err_vect+4) = (errorM + 8) >> 4;                    /* 1/16 */
725             delta = errorM << 1;                                 /* 2 err */
726             errorM += delta;
727             *(err_vect-2) += (errorM + 8) >> 4;                       /* 3/16  */
728             errorM += delta;
729             *(err_vect+1) += (errorM + 8) >> 4;                           /* 5/16  */
730             errorM += delta + 8;                                     /* 7/16  */
731             errorM >>= 4;
732 
733             *(err_vect+5) = (errorY + 8) >> 4;                      /* 1/16 */
734             delta = errorY << 1;                                 /* 2 err */
735             errorY += delta;
736             *(err_vect-1) += (errorY + 8) >> 4;                       /* 3/16  */
737             errorY += delta;
738             *(err_vect+2) += (errorY + 8) >> 4;                           /* 5/16  */
739             errorY += delta + 8;                                     /* 7/16  */
740             errorY >>= 4;
741 
742             if (bitmask == 0x01) {
743                 bitmask = 0x80;
744                 if(composeK) {
745                     byteK = byteC & byteM & byteY;
746                     byteC = byteC & ~byteK;
747                     byteM = byteM & ~byteK;
748                     byteY = byteY & ~byteK;
749                 }                               /* if no K byteK always 0 */
750                 *dithered            = byteC;
751                 *(dithered+  raster) = byteM;
752                 *(dithered+2*raster) = byteY;
753                 *(dithered+3*raster) = byteK;
754                 byteC = byteM = byteY = byteK = 0;
755                 dithered++;
756             }
757             else if(i == 1) {
758                 if(composeK) {
759                     byteK = byteC & byteM & byteY;
760                     byteC = byteC & ~byteK;
761                     byteM = byteM & ~byteK;
762                     byteY = byteY & ~byteK;
763                 }                               /* if no K byteK always 0 */
764                 *dithered            = byteC;
765                 *(dithered+  raster) = byteM;
766                 *(dithered+2*raster) = byteY;
767                 *(dithered+3*raster) = byteK;
768             }
769             else bitmask >>= 1;
770         }
771         FloydSteinbergDirectionForward=false;
772     }
773     else {
774 	row += (width << 2) - 4;   /* point to the end of the row */
775         dithered += raster - 1;
776         err_vect = FloydSteinbergErrorsC + 3 * width + 3;       /* errCMY */
777         bitmask = 1 << ((raster << 3 ) - width) ;
778 
779 	for( i=width; i>0; i--, row-=4, err_vect-=3) {
780 
781             err_corrC = bjc_gamma_tableC[  (*row)   + (*(row+3))]
782                           + FloydSteinbergC;
783             err_corrM = bjc_gamma_tableM[(*(row+1)) + (*(row+3))]
784                           + FloydSteinbergM;
785             err_corrY = bjc_gamma_tableY[(*(row+2)) + (*(row+3))]
786                           + FloydSteinbergY;
787 
788             if(err_corrC > 4080 && limit_extr) err_corrC = 4080;
789             if(err_corrM > 4080 && limit_extr) err_corrM = 4080;
790             if(err_corrY > 4080 && limit_extr) err_corrY = 4080;
791 
792             errorC += err_corrC + (*(err_vect - 3));       /* CMYCMYCMY */
793             errorM += err_corrM + (*(err_vect - 2));       /* !  ^  |   */
794             errorY += err_corrY + (*(err_vect - 1));
795 
796             if(errorC > bjc_treshold[bjc_rand()])  {
797                 errorC -=  4080;
798                 byteC |=  bitmask;
799             }
800 
801             if(errorM > bjc_treshold[bjc_rand()])  {
802                 errorM -=  4080;
803                 byteM |=  bitmask;
804             }
805 
806             if(errorY > bjc_treshold[bjc_rand()])  {
807                 errorY -=  4080;
808                 byteY |=  bitmask;
809             }
810 
811             *(err_vect-3) = (errorC + 8) >> 4;                      /* 1/16 */
812             delta = errorC << 1;                                 /* 2 err */
813             errorC += delta;
814             *(err_vect+3) += (errorC + 8) >> 4;                       /* 3/16  */
815             errorC += delta;
816             *err_vect += (errorC + 8) >> 4;                           /* 5/16  */
817             errorC += delta + 8;                                     /* 7/16  */
818             errorC >>= 4;
819 
820             *(err_vect-2) = (errorM + 8) >> 4;                      /* 1/16 */
821             delta = errorM << 1;                                 /* 2 err */
822             errorM += delta;
823             *(err_vect+4) += (errorM + 8) >> 4;                       /* 3/16  */
824             errorM += delta;
825             *(err_vect+1) += (errorM + 8) >> 4;                           /* 5/16  */
826             errorM += delta + 8;                                     /* 7/16  */
827             errorM >>= 4;
828 
829             *(err_vect-1) = (errorY + 8) >> 4;                      /* 1/16 */
830             delta = errorY << 1;                                 /* 2 err */
831             errorY += delta;
832             *(err_vect+5) += (errorY + 8) >> 4;                       /* 3/16  */
833             errorY += delta;
834             *(err_vect+2) += (errorY + 8) >> 4;                           /* 5/16  */
835             errorY += delta + 8;                                     /* 7/16  */
836             errorY >>= 4;
837 
838             if (bitmask == 0x80) {
839                 bitmask = 0x01;
840                 if(composeK) {
841                     byteK = byteC & byteM & byteY;
842                     byteC = byteC & ~byteK;
843                     byteM = byteM & ~byteK;
844                     byteY = byteY & ~byteK;
845                 }                               /* if no K byteK always 0 */
846                 *dithered            = byteC;
847                 *(dithered+  raster) = byteM;
848                 *(dithered+2*raster) = byteY;
849                 *(dithered+3*raster) = byteK;
850                 byteC = byteM = byteY = byteK = 0;
851                 dithered--;
852             }
853             else if(i == 1) {
854                 if(composeK) {
855                     byteK = byteC & byteM & byteY;
856                     byteC = byteC & ~byteK;
857                     byteM = byteM & ~byteK;
858                     byteY = byteY & ~byteK;
859                 }                               /* if no K byteK always 0 */
860                 *dithered            = byteC;
861                 *(dithered+  raster) = byteM;
862                 *(dithered+2*raster) = byteY;
863                 *(dithered+3*raster) = byteK;
864             }
865 	    else bitmask <<= 1;
866         }
867         FloydSteinbergDirectionForward=true;
868     }
869 }
870 
FloydSteinbergCloseC(gx_device_printer * pdev)871 void FloydSteinbergCloseC(gx_device_printer *pdev)
872 {
873     gs_free_object(pdev->memory, FloydSteinbergErrorsC,
874                                            "bjc CMY error buffer");
875 }
876