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