1/*
2 * "$Id: testdither.c,v 1.49 2006/05/07 13:26:27 rlk Exp $"
3 *
4 *   Test/profiling program for dithering code.
5 *
6 *   Copyright 1997-2000 Michael Sweet (mike@easysw.com)
7 *
8 *   This program is free software; you can redistribute it and/or modify it
9 *   under the terms of the GNU General Public License as published by the Free
10 *   Software Foundation; either version 2 of the License, or (at your option)
11 *   any later version.
12 *
13 *   This program is distributed in the hope that it will be useful, but
14 *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 *   for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include <config.h>
25#endif
26#include <gutenprint/gutenprint.h>
27#define STPI_TESTDITHER
28
29#include "../src/main/gutenprint-internal.h"
30#include <stdio.h>
31#include <sys/time.h>
32#include <unistd.h>
33#include <string.h>
34
35/*
36 * Definitions for dither test...
37 */
38
39#define IMAGE_WIDTH	5760	/* 8in * 720dpi */
40#define IMAGE_HEIGHT	2880	/* 4in * 720dpi */
41#define BUFFER_SIZE	IMAGE_WIDTH
42
43#define IMAGE_MIXED	0	/* Mix of line types */
44#define IMAGE_WHITE	1	/* All white image */
45#define IMAGE_BLACK	2	/* All black image */
46#define IMAGE_COLOR	3	/* All color image */
47#define IMAGE_RANDOM	4	/* All random image */
48
49#define DITHER_GRAY	0	/* Dither grayscale pixels */
50#define DITHER_COLOR	1	/* Dither color pixels */
51#define DITHER_PHOTO	2	/* Dither photo pixels */
52#define DITHER_CMYK	3	/* Dither photo pixels */
53#define DITHER_PHOTO_CMYK	4	/* Dither photo pixels */
54
55
56/*
57 * Globals...
58 */
59
60int		image_type = IMAGE_MIXED;
61int		stpi_dither_type = DITHER_COLOR;
62const char     *dither_name = NULL;
63int		dither_bits = 1;
64int		write_image = 1;
65int		quiet;
66unsigned short	white_line[IMAGE_WIDTH * 6],
67		black_line[IMAGE_WIDTH * 6],
68		color_line[IMAGE_WIDTH * 6],
69		random_line[IMAGE_WIDTH * 6];
70
71static const char	*stpi_dither_types[] =	/* Different dithering modes */
72	      {
73		"gray",
74		"color",
75		"photo",
76		"cmyk",
77		"photocmyk"
78	      };
79static const char	*image_types[] =	/* Different image types */
80	      {
81		"mixed",
82		"white",
83		"black",
84		"colorimage",
85		"random"
86	      };
87
88
89#define SHADE(density, name)					\
90{  density, sizeof(name)/sizeof(stp_dotsize_t), name  }
91
92static const stp_dotsize_t single_dotsize[] =
93{
94  { 0x1, 1.0 }
95};
96
97static const stp_dotsize_t variable_dotsizes[] =
98{
99  { 0x1, 0.28 },
100  { 0x2, 0.58 },
101  { 0x3, 1.0  }
102};
103
104static const stp_shade_t normal_1bit_shades[] =
105{
106  SHADE(1.0, single_dotsize)
107};
108
109static const stp_shade_t photo_1bit_shades[] =
110{
111  SHADE(0.33, single_dotsize),
112  SHADE(1.0, single_dotsize)
113};
114
115static const stp_shade_t normal_2bit_shades[] =
116{
117  SHADE(1.0, variable_dotsizes)
118};
119
120static const stp_shade_t photo_2bit_shades[] =
121{
122  SHADE(0.33, variable_dotsizes),
123  SHADE(1.0, variable_dotsizes)
124};
125
126
127double compute_interval(struct timeval *tv1, struct timeval *tv2);
128void   image_init(void);
129void   image_get_row(unsigned short *data, int row);
130void   write_gray(FILE *fp, unsigned char *black);
131void   write_color(FILE *fp, unsigned char *cyan, unsigned char *magenta,
132                   unsigned char *yellow, unsigned char *black);
133void   write_photo(FILE *fp, unsigned char *cyan, unsigned char *lcyan,
134                   unsigned char *magenta, unsigned char *lmagenta,
135                   unsigned char *yellow, unsigned char *black);
136
137
138double
139compute_interval(struct timeval *tv1, struct timeval *tv2)
140{
141  return ((double) tv2->tv_sec + (double) tv2->tv_usec / 1000000.) -
142    ((double) tv1->tv_sec + (double) tv1->tv_usec / 1000000.);
143}
144
145static void
146writefunc(void *file, const char *buf, size_t bytes)
147{
148  FILE *prn = (FILE *)file;
149  fwrite(buf, 1, bytes, prn);
150}
151
152static int
153image_width(stp_image_t *image)
154{
155  return IMAGE_WIDTH;
156}
157
158static stp_image_t theImage =
159{
160  NULL,
161  NULL,
162  image_width,
163  NULL,
164  NULL,
165  NULL,
166};
167
168/*
169 * 'main()' - Test dithering code for performance measurement.
170 */
171
172static int
173run_one_testdither(void)
174{
175  int print_progress = 0;
176  int		i;			/* Looping vars */
177  unsigned char	black[BUFFER_SIZE],	/* Black bitmap data */
178		cyan[BUFFER_SIZE],	/* Cyan bitmap data */
179		magenta[BUFFER_SIZE],	/* Magenta bitmap data */
180		lcyan[BUFFER_SIZE],	/* Light cyan bitmap data */
181		lmagenta[BUFFER_SIZE],	/* Light magenta bitmap data */
182		yellow[BUFFER_SIZE];	/* Yellow bitmap data */
183  unsigned short rgb[IMAGE_WIDTH * 6],	/* RGB buffer */
184		gray[IMAGE_WIDTH];	/* Grayscale buffer */
185  FILE		*fp = NULL;		/* PPM/PGM output file */
186  char		filename[1024];		/* Name of file */
187  stp_vars_t	*v; 		        /* Dither variables */
188  stp_parameter_t desc;
189  struct timeval tv1, tv2;
190
191 /*
192  * Initialise libgutenprint
193  */
194
195  stp_init();
196  v = stp_vars_create();
197  stp_set_driver(v, "escp2-ex");
198  stp_describe_parameter(v, "DitherAlgorithm", &desc);
199
200 /*
201  * Setup the image and color functions...
202  */
203
204  image_init();
205  stp_set_outfunc(v, writefunc);
206  stp_set_errfunc(v, writefunc);
207  stp_set_outdata(v, stdout);
208  stp_set_errdata(v, stderr);
209
210 /*
211  * Output the page...
212  */
213
214  if (dither_name)
215    stp_set_string_parameter(v, "DitherAlgorithm", dither_name);
216
217  stp_set_string_parameter(v, "ChannelBitDepth", "8");
218  switch (stpi_dither_type)
219    {
220    case DITHER_GRAY:
221      stp_set_string_parameter(v, "PrintingMode", "BW");
222      stp_set_string_parameter(v, "InputImageType", "Grayscale");
223      break;
224    case DITHER_COLOR:
225    case DITHER_PHOTO:
226      stp_set_string_parameter(v, "PrintingMode", "Color");
227      stp_set_string_parameter(v, "InputImageType", "RGB");
228      break;
229    case DITHER_CMYK:
230    case DITHER_PHOTO_CMYK:
231      stp_set_string_parameter(v, "PrintingMode", "Color");
232      stp_set_string_parameter(v, "InputImageType", "CMYK");
233      break;
234    }
235
236  stp_dither_init(v, &theImage, IMAGE_WIDTH, 1, 1);
237
238 /*
239  * Now dither the "page"...
240  */
241
242  switch (stpi_dither_type)
243    {
244    case DITHER_PHOTO:
245      stp_dither_add_channel(v, lcyan, STP_ECOLOR_C, 1);
246      stp_dither_add_channel(v, lmagenta, STP_ECOLOR_M, 1);
247      /* FALLTHROUGH */
248    case DITHER_COLOR:
249      stp_dither_add_channel(v, cyan, STP_ECOLOR_C, 0);
250      stp_dither_add_channel(v, magenta, STP_ECOLOR_M, 0);
251      stp_dither_add_channel(v, yellow, STP_ECOLOR_Y, 0);
252      break;
253    case DITHER_PHOTO_CMYK :
254      stp_dither_add_channel(v, lcyan, STP_ECOLOR_C, 1);
255      stp_dither_add_channel(v, lmagenta, STP_ECOLOR_M, 1);
256      /* FALLTHROUGH */
257    case DITHER_CMYK :
258      stp_dither_add_channel(v, cyan, STP_ECOLOR_C, 0);
259      stp_dither_add_channel(v, magenta, STP_ECOLOR_M, 0);
260      stp_dither_add_channel(v, yellow, STP_ECOLOR_Y, 0);
261      /* FALLTHROUGH */
262    case DITHER_GRAY:
263      stp_dither_add_channel(v, black, STP_ECOLOR_K, 0);
264    }
265
266  if (stpi_dither_type == DITHER_PHOTO)
267    stp_set_float_parameter(v, "GCRLower", 0.4 / dither_bits + 0.1);
268  else
269    stp_set_float_parameter(v, "GCRLower", 0.25 / dither_bits);
270
271  stp_set_float_parameter(v, "GCRUpper", .5);
272
273  switch (stpi_dither_type)
274  {
275    case DITHER_GRAY :
276        switch (dither_bits)
277	{
278	  case 1 :
279              stp_dither_set_inks_full(v, STP_ECOLOR_K, 1, normal_1bit_shades, 1.0, 1.0);
280	      break;
281	  case 2 :
282	      stp_dither_set_transition(v, 0.5);
283              stp_dither_set_inks_full(v, STP_ECOLOR_K, 1, normal_2bit_shades, 1.0, 1.0);
284	      break;
285       }
286       break;
287    case DITHER_COLOR :
288        switch (dither_bits)
289	{
290	  case 1 :
291              stp_dither_set_inks_full(v, STP_ECOLOR_C, 1, normal_1bit_shades, 1.0, 0.65);
292              stp_dither_set_inks_full(v, STP_ECOLOR_M, 1, normal_1bit_shades, 1.0, 0.6);
293              stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_1bit_shades, 1.0, 0.08);
294	      break;
295	  case 2 :
296	      stp_dither_set_transition(v, 0.5);
297              stp_dither_set_inks_full(v, STP_ECOLOR_C, 1, normal_2bit_shades, 1.0, 0.65);
298              stp_dither_set_inks_full(v, STP_ECOLOR_M, 1, normal_2bit_shades, 1.0, 0.6);
299              stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_2bit_shades, 1.0, 0.08);
300	      break;
301       }
302       break;
303    case DITHER_CMYK :
304        switch (dither_bits)
305	{
306	  case 1 :
307              stp_dither_set_inks_full(v, STP_ECOLOR_C, 1, normal_1bit_shades, 1.0, 0.65);
308              stp_dither_set_inks_full(v, STP_ECOLOR_M, 1, normal_1bit_shades, 1.0, 0.6);
309              stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_1bit_shades, 1.0, 0.08);
310              stp_dither_set_inks_full(v, STP_ECOLOR_K, 1, normal_1bit_shades, 1.0, 1.0);
311	      break;
312	  case 2 :
313	      stp_dither_set_transition(v, 0.5);
314              stp_dither_set_inks_full(v, STP_ECOLOR_C, 1, normal_2bit_shades, 1.0, 0.65);
315              stp_dither_set_inks_full(v, STP_ECOLOR_M, 1, normal_2bit_shades, 1.0, 0.6);
316              stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_2bit_shades, 1.0, 0.08);
317              stp_dither_set_inks_full(v, STP_ECOLOR_K, 1, normal_2bit_shades, 1.0, 1.0);
318	      break;
319       }
320       break;
321    case DITHER_PHOTO :
322        switch (dither_bits)
323	{
324	  case 1 :
325              stp_dither_set_inks_full(v, STP_ECOLOR_C, 2, photo_1bit_shades, 1.0, 0.65);
326              stp_dither_set_inks_full(v, STP_ECOLOR_M, 2, photo_1bit_shades, 1.0, 0.6);
327              stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_1bit_shades, 1.0, 0.08);
328	      break;
329	  case 2 :
330	      stp_dither_set_transition(v, 0.7);
331              stp_dither_set_inks_full(v, STP_ECOLOR_C, 2, photo_2bit_shades, 1.0, 0.65);
332              stp_dither_set_inks_full(v, STP_ECOLOR_M, 2, photo_2bit_shades, 1.0, 0.6);
333              stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_2bit_shades, 1.0, 0.08);
334	      break;
335       }
336       break;
337    case DITHER_PHOTO_CMYK :
338        switch (dither_bits)
339	{
340	  case 1 :
341              stp_dither_set_inks_full(v, STP_ECOLOR_C, 2, photo_1bit_shades, 1.0, 0.65);
342              stp_dither_set_inks_full(v, STP_ECOLOR_M, 2, photo_1bit_shades, 1.0, 0.6);
343              stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_1bit_shades, 1.0, 0.08);
344              stp_dither_set_inks_full(v, STP_ECOLOR_K, 1, normal_1bit_shades, 1.0, 1.0);
345	      break;
346	  case 2 :
347	      stp_dither_set_transition(v, 0.7);
348              stp_dither_set_inks_full(v, STP_ECOLOR_C, 2, photo_2bit_shades, 1.0, 0.65);
349              stp_dither_set_inks_full(v, STP_ECOLOR_M, 2, photo_2bit_shades, 1.0, 0.6);
350              stp_dither_set_inks_full(v, STP_ECOLOR_Y, 1, normal_2bit_shades, 1.0, 0.08);
351              stp_dither_set_inks_full(v, STP_ECOLOR_K, 1, normal_2bit_shades, 1.0, 1.0);
352	      break;
353       }
354       break;
355  }
356
357  stp_dither_set_ink_spread(v, 12 + dither_bits);
358
359 /*
360  * Open the PPM/PGM file...
361  */
362
363
364  sprintf(filename, "%s-%s-%s-%dbit.%s", image_types[image_type],
365	  stpi_dither_types[stpi_dither_type],
366	  dither_name ? dither_name : desc.deflt.str, dither_bits,
367	  (stpi_dither_type == DITHER_GRAY) ? "pgm" : "ppm");
368
369  stp_parameter_description_destroy(&desc);
370
371  if (isatty(1))
372    print_progress = 1;
373
374  if (print_progress && !quiet)
375    printf("%s ", filename);
376
377  if (write_image)
378    {
379      if ((fp = fopen(filename, "wb")) != NULL)
380	{
381	  if (stpi_dither_type == DITHER_GRAY)
382	    fputs("P5\n", fp);
383	  else
384	    fputs("P6\n", fp);
385
386	  fprintf(fp, "%d\n%d\n255\n", IMAGE_WIDTH, IMAGE_HEIGHT);
387	}
388      else
389	perror("Create");
390    }
391
392  (void) gettimeofday(&tv1, NULL);
393
394  for (i = 0; i < IMAGE_HEIGHT; i ++)
395  {
396    if (print_progress && !quiet && (i & 63) == 0)
397    {
398      printf("\rProcessing row %d...", i);
399      fflush(stdout);
400    }
401
402    switch (stpi_dither_type)
403      {
404      case DITHER_GRAY :
405          image_get_row(gray, i);
406	  stp_dither_internal(v, i, gray, 0, 0, NULL);
407	  if (fp)
408	    write_gray(fp, black);
409	  break;
410      case DITHER_COLOR :
411      case DITHER_CMYK :
412          image_get_row(rgb, i);
413	  stp_dither_internal(v, i, rgb, 0, 0, NULL);
414	  if (fp)
415	    write_color(fp, cyan, magenta, yellow, black);
416	  break;
417      case DITHER_PHOTO :
418      case DITHER_PHOTO_CMYK :
419          image_get_row(rgb, i);
420	  stp_dither_internal(v, i, rgb, 0, 0, NULL);
421	  if (fp)
422	    write_photo(fp, cyan, lcyan, magenta, lmagenta, yellow, black);
423	  break;
424    }
425  }
426
427  (void) gettimeofday(&tv2, NULL);
428
429  stp_vars_destroy(v);
430
431  if (fp != NULL)
432    fclose(fp);
433
434  if (!quiet)
435    {
436      if (print_progress)
437	fputc('\r', stdout);
438      printf("%-30s %d pix %.3f sec %.2f pix/sec\n",
439	     filename, IMAGE_WIDTH * IMAGE_HEIGHT, compute_interval(&tv1, &tv2),
440	     (float)(IMAGE_WIDTH * IMAGE_HEIGHT) / compute_interval(&tv1, &tv2));
441      fflush(stdout);
442    }
443  return 0;
444}
445
446static int
447run_testdither_from_cmdline(int argc, char **argv)
448{
449  int i, j;
450  int status;
451  for (i = 1; i < argc; i ++)
452    {
453      if (strcmp(argv[i], "no-image") == 0)
454	{
455	  write_image = 0;
456	  continue;
457	}
458
459      if (strcmp(argv[i], "quiet") == 0)
460	{
461	  quiet = 1;
462	  continue;
463	}
464
465      if (strcmp(argv[i], "1-bit") == 0)
466	{
467	  dither_bits = 1;
468	  continue;
469	}
470
471      if (strcmp(argv[i], "2-bit") == 0)
472	{
473	  dither_bits = 2;
474	  continue;
475	}
476
477      for (j = 0; j < 5; j ++)
478	if (strcmp(argv[i], stpi_dither_types[j]) == 0)
479	  break;
480
481      if (j < 5)
482	{
483	  stpi_dither_type = j;
484	  continue;
485	}
486
487      for (j = 0; j < 5; j ++)
488	if (strcmp(argv[i], image_types[j]) == 0)
489	  break;
490
491      if (j < 5)
492	{
493	  image_type = j;
494	  continue;
495	}
496
497      dither_name = argv[i];
498    }
499  status = run_one_testdither();
500  if (status)
501    return 1;
502  else
503    return 0;
504}
505
506static int
507run_standard_testdithers(void)
508{
509  stp_vars_t *v = stp_vars_create();
510  stp_parameter_t desc;
511  int j;
512  int failures = 0;
513  int status;
514
515  stp_set_driver(v, "escp2-ex");
516  stp_describe_parameter(v, "DitherAlgorithm", &desc);
517
518  write_image = 0;
519  quiet = 1;
520  for (j = 0; j < stp_string_list_count(desc.bounds.str); j ++)
521    {
522      dither_name = stp_string_list_param(desc.bounds.str, j)->name;
523      if (strcmp(dither_name, "None") == 0)
524	continue;
525      printf("%s", dither_name);
526      fflush(stdout);
527      for (dither_bits = 1; dither_bits <= 2; dither_bits++)
528	for (stpi_dither_type = 0;
529	     stpi_dither_type < sizeof(stpi_dither_types) / sizeof(const char *);
530	     stpi_dither_type++)
531	  for (image_type = 0;
532	       image_type < sizeof(image_types) / sizeof(const char *);
533	       image_type++)
534	    {
535	      status = run_one_testdither();
536	      if (status)
537		{
538		  printf("%s %d %s %s\n", dither_name, dither_bits,
539			 stpi_dither_types[stpi_dither_type],
540			 image_types[image_type]);
541		  failures++;
542		}
543	      else
544		printf(".");
545	      fflush(stdout);
546	    }
547      printf("\n");
548      fflush(stdout);
549    }
550  stp_parameter_description_destroy(&desc);
551  stp_vars_destroy(v);
552  return (failures ? 1 : 0);
553}
554
555int
556main(int argc, char **argv)
557{
558  stp_init();
559
560  if (argc == 1)
561    return run_standard_testdithers();
562  else
563    return run_testdither_from_cmdline(argc, argv);
564}
565
566
567void
568image_get_row(unsigned short *data,
569              int            row)
570{
571  unsigned short *src;
572
573
574  switch (image_type)
575    {
576    case IMAGE_MIXED :
577      switch ((row / 100) & 3)
578	{
579	case 0 :
580	  src = white_line;
581	  break;
582	case 1 :
583	  src = color_line;
584	  break;
585	case 2 :
586	  src = black_line;
587	  break;
588	case 3 :
589	default:
590	  src = random_line;
591	  break;
592	}
593      break;
594    case IMAGE_WHITE :
595      src = white_line;
596      break;
597    case IMAGE_BLACK :
598      src = black_line;
599      break;
600    case IMAGE_COLOR :
601      src = color_line;
602      break;
603    case IMAGE_RANDOM :
604    default:
605      src = random_line;
606      break;
607    }
608
609  switch (stpi_dither_type)
610    {
611    case DITHER_GRAY:
612      memcpy(data, src, IMAGE_WIDTH * 2);
613      break;
614    case DITHER_COLOR:
615      memcpy(data, src, IMAGE_WIDTH * 6);
616      break;
617    case DITHER_CMYK:
618      memcpy(data, src, IMAGE_WIDTH * 8);
619      break;
620    case DITHER_PHOTO:
621      memcpy(data, src, IMAGE_WIDTH * 10);
622      break;
623    case DITHER_PHOTO_CMYK:
624      memcpy(data, src, IMAGE_WIDTH * 12);
625      break;
626    }
627}
628
629
630void
631image_init(void)
632{
633  int			i, j;
634  unsigned short	*cptr,
635			*rptr;
636
637
638 /*
639  * Set the white and black line data...
640  */
641
642  memset(white_line, 0, sizeof(white_line));
643  memset(black_line, 255, sizeof(black_line));
644
645 /*
646  * Fill in the color and random data...
647  */
648
649  for (i = IMAGE_WIDTH, cptr = color_line, rptr = random_line; i > 0; i --)
650  {
651   /*
652    * Do 64 color or grayscale blocks over the line...
653    */
654
655    j = i / (IMAGE_WIDTH / 64);
656
657    switch (stpi_dither_type)
658      {
659      case DITHER_GRAY:
660	*cptr++ = 65535 * j / 63;
661	*rptr++ = 65535 * (rand() & 255) / 255;
662	break;
663      case DITHER_COLOR:
664	*cptr++ = 65535 * (j >> 4) / 3;
665	*cptr++ = 65535 * ((j >> 2) & 3) / 3;
666	*cptr++ = 65535 * (j & 3) / 3;
667	*rptr++ = 65535 * (rand() & 255) / 255;
668	*rptr++ = 65535 * (rand() & 255) / 255;
669	*rptr++ = 65535 * (rand() & 255) / 255;
670	break;
671      case DITHER_CMYK:
672	*cptr++ = 65535 * (j >> 4) / 3;
673	*cptr++ = 65535 * ((j >> 2) & 3) / 3;
674	*cptr++ = 65535 * (j & 3) / 3;
675	*cptr++ = 65535 * j / 63;
676	*rptr++ = 65535 * (rand() & 255) / 255;
677	*rptr++ = 65535 * (rand() & 255) / 255;
678	*rptr++ = 65535 * (rand() & 255) / 255;
679	*rptr++ = 65535 * (rand() & 255) / 255;
680	break;
681      case DITHER_PHOTO:
682	*cptr++ = 65535 * (j >> 4) / 3;
683	*cptr++ = 65535 * ((j >> 2) & 3) / 3;
684	*cptr++ = 65535 * (j & 3) / 3;
685	*cptr++ = 65535 * j / 63;
686	*cptr++ = 65535 * (j >> 4) / 3;
687	*rptr++ = 65535 * (rand() & 255) / 255;
688	*rptr++ = 65535 * (rand() & 255) / 255;
689	*rptr++ = 65535 * (rand() & 255) / 255;
690	*rptr++ = 65535 * (rand() & 255) / 255;
691	*rptr++ = 65535 * (rand() & 255) / 255;
692	break;
693      case DITHER_PHOTO_CMYK:
694	*cptr++ = 65535 * (j >> 4) / 3;
695	*cptr++ = 65535 * ((j >> 2) & 3) / 3;
696	*cptr++ = 65535 * (j & 3) / 3;
697	*cptr++ = 65535 * j / 63;
698	*cptr++ = 65535 * (j >> 4) / 3;
699	*cptr++ = 65535 * ((j >> 2) & 3) / 3;
700	*rptr++ = 65535 * (rand() & 255) / 255;
701	*rptr++ = 65535 * (rand() & 255) / 255;
702	*rptr++ = 65535 * (rand() & 255) / 255;
703	*rptr++ = 65535 * (rand() & 255) / 255;
704	*rptr++ = 65535 * (rand() & 255) / 255;
705	*rptr++ = 65535 * (rand() & 255) / 255;
706	break;
707      }
708  }
709}
710
711
712void
713write_gray(FILE          *fp,
714           unsigned char *black)
715{
716  int		count;
717  unsigned char	byte,
718		bit,
719		shift;
720
721
722  if (dither_bits == 1)
723  {
724    for (count = IMAGE_WIDTH, byte = *black++, bit = 128; count > 0; count --)
725    {
726      if (byte & bit)
727        putc(0, fp);
728      else
729        putc(255, fp);
730
731      if (bit > 1)
732        bit >>= 1;
733      else
734      {
735        byte = *black++;
736	bit  = 128;
737      }
738    }
739  }
740  else
741  {
742    unsigned char kb[BUFFER_SIZE];
743    unsigned char *kbuf = kb;
744    stp_fold(black, IMAGE_WIDTH / 8, kbuf);
745    for (count = IMAGE_WIDTH, byte = *kbuf++, shift = 6; count > 0; count --)
746    {
747      putc(255 - 255 * ((byte >> shift) & 3) / 3, fp);
748
749      if (shift > 0)
750        shift -= 2;
751      else
752      {
753        byte  = *kbuf++;
754	shift = 6;
755      }
756    }
757  }
758}
759
760
761void
762write_color(FILE          *fp,
763            unsigned char *cyan,
764	    unsigned char *magenta,
765            unsigned char *yellow,
766	    unsigned char *black)
767{
768  int		count;
769  unsigned char	cbyte,
770                mbyte,
771                ybyte,
772                kbyte,
773		bit,
774		shift;
775  int		r, g, b, k;
776
777
778  if (dither_bits == 1)
779  {
780    for (count = IMAGE_WIDTH, cbyte = *cyan++, mbyte = *magenta++,
781             ybyte = *yellow++, kbyte = *black++, bit = 128;
782	 count > 0;
783	 count --)
784    {
785      if (kbyte & bit)
786      {
787        putc(0, fp);
788        putc(0, fp);
789        putc(0, fp);
790      }
791      else
792      {
793	if (cbyte & bit)
794          putc(0, fp);
795	else
796          putc(255, fp);
797
798	if (mbyte & bit)
799          putc(0, fp);
800	else
801          putc(255, fp);
802
803	if (ybyte & bit)
804          putc(0, fp);
805	else
806          putc(255, fp);
807      }
808
809      if (bit > 1)
810        bit >>= 1;
811      else
812      {
813        cbyte = *cyan++;
814        mbyte = *magenta++;
815        ybyte = *yellow++;
816        kbyte = *black++;
817	bit   = 128;
818      }
819    }
820  }
821  else
822  {
823    unsigned char kb[BUFFER_SIZE];
824    unsigned char cb[BUFFER_SIZE];
825    unsigned char mb[BUFFER_SIZE];
826    unsigned char yb[BUFFER_SIZE];
827    unsigned char *kbuf = kb;
828    unsigned char *cbuf = cb;
829    unsigned char *mbuf = mb;
830    unsigned char *ybuf = yb;
831    stp_fold(black, IMAGE_WIDTH / 8, kbuf);
832    stp_fold(cyan, IMAGE_WIDTH / 8, cbuf);
833    stp_fold(magenta, IMAGE_WIDTH / 8, mbuf);
834    stp_fold(yellow, IMAGE_WIDTH / 8, ybuf);
835    for (count = IMAGE_WIDTH, cbyte = *cbuf++, mbyte = *mbuf++,
836             ybyte = *ybuf++, kbyte = *kbuf++, shift = 6;
837	 count > 0;
838	 count --)
839    {
840      k = 255 * ((kbyte >> shift) & 3) / 3;
841      r = 255 - 255 * ((cbyte >> shift) & 3) / 3 - k;
842      g = 255 - 255 * ((mbyte >> shift) & 3) / 3 - k;
843      b = 255 - 255 * ((ybyte >> shift) & 3) / 3 - k;
844
845      if (r < 0)
846        putc(0, fp);
847      else
848        putc(r, fp);
849
850      if (g < 0)
851        putc(0, fp);
852      else
853        putc(g, fp);
854
855      if (b < 0)
856        putc(0, fp);
857      else
858        putc(b, fp);
859
860      if (shift > 0)
861        shift -= 2;
862      else
863      {
864        cbyte = *cbuf++;
865        mbyte = *mbuf++;
866        ybyte = *ybuf++;
867        kbyte = *kbuf++;
868	shift = 6;
869      }
870    }
871  }
872}
873
874
875void
876write_photo(FILE          *fp,
877            unsigned char *cyan,
878            unsigned char *lcyan,
879            unsigned char *magenta,
880	    unsigned char *lmagenta,
881            unsigned char *yellow,
882            unsigned char *black)
883{
884  int		count;
885  unsigned char	cbyte,
886		lcbyte,
887                mbyte,
888                lmbyte,
889                ybyte,
890                kbyte,
891		bit,
892		shift;
893  int		r, g, b, k;
894
895
896  if (dither_bits == 1)
897  {
898    for (count = IMAGE_WIDTH, cbyte = *cyan++, lcbyte = *lcyan++,
899             mbyte = *magenta++, lmbyte = *lmagenta++,
900             ybyte = *yellow++, kbyte = *black++, bit = 128;
901	 count > 0;
902	 count --)
903    {
904      if (kbyte & bit)
905      {
906        putc(0, fp);
907        putc(0, fp);
908        putc(0, fp);
909      }
910      else
911      {
912	if (cbyte & bit)
913          putc(0, fp);
914	else if (lcbyte & bit)
915          putc(127, fp);
916	else
917          putc(255, fp);
918
919	if (mbyte & bit)
920          putc(0, fp);
921	else if (lmbyte & bit)
922          putc(127, fp);
923	else
924          putc(255, fp);
925
926	if (ybyte & bit)
927          putc(0, fp);
928	else
929          putc(255, fp);
930      }
931
932      if (bit > 1)
933        bit >>= 1;
934      else
935      {
936        cbyte  = *cyan++;
937        lcbyte = *lcyan++;
938        mbyte  = *magenta++;
939        lmbyte = *lmagenta++;
940        ybyte  = *yellow++;
941        kbyte  = *black++;
942	bit    = 128;
943      }
944    }
945  }
946  else
947  {
948    unsigned char kb[BUFFER_SIZE];
949    unsigned char cb[BUFFER_SIZE];
950    unsigned char mb[BUFFER_SIZE];
951    unsigned char lcb[BUFFER_SIZE];
952    unsigned char lmb[BUFFER_SIZE];
953    unsigned char yb[BUFFER_SIZE];
954    unsigned char *kbuf = kb;
955    unsigned char *cbuf = cb;
956    unsigned char *mbuf = mb;
957    unsigned char *lcbuf = lcb;
958    unsigned char *lmbuf = lmb;
959    unsigned char *ybuf = yb;
960    stp_fold(black, IMAGE_WIDTH / 8, kbuf);
961    stp_fold(cyan, IMAGE_WIDTH / 8, cbuf);
962    stp_fold(magenta, IMAGE_WIDTH / 8, mbuf);
963    stp_fold(yellow, IMAGE_WIDTH / 8, ybuf);
964    stp_fold(lcyan, IMAGE_WIDTH / 8, lcbuf);
965    stp_fold(lmagenta, IMAGE_WIDTH / 8, lmbuf);
966    for (count = IMAGE_WIDTH,  cbyte = *cbuf++, mbyte = *mbuf++,
967	   ybyte = *ybuf++, kbyte = *kbuf++, lmbyte = *lmbuf++,
968	   lcbyte = *lcyan++, shift = 6;
969	 count > 0;
970	 count --)
971    {
972      k = 255 * ((kbyte >> shift) & 3) / 3;
973      r = 255 - 255 * ((cbyte >> shift) & 3) / 3 -
974          127 * ((lcbyte >> shift) & 3) / 3 - k;
975      g = 255 - 255 * ((mbyte >> shift) & 3) / 3 -
976          127 * ((lmbyte >> shift) & 3) / 3 - k;
977      b = 255 - 255 * ((ybyte >> shift) & 3) / 3 - k;
978
979      if (r < 0)
980        putc(0, fp);
981      else
982        putc(r, fp);
983
984      if (g < 0)
985        putc(0, fp);
986      else
987        putc(g, fp);
988
989      if (b < 0)
990        putc(0, fp);
991      else
992        putc(b, fp);
993
994      if (shift > 0)
995        shift -= 2;
996      else
997      {
998        cbyte = *cbuf++;
999        mbyte = *mbuf++;
1000        ybyte = *ybuf++;
1001        kbyte = *kbuf++;
1002        lmbyte = *lmbuf++;
1003        lcbyte = *lcbuf++;
1004	shift  = 6;
1005      }
1006    }
1007  }
1008}
1009
1010
1011/*
1012 * End of "$Id: testdither.c,v 1.49 2006/05/07 13:26:27 rlk Exp $".
1013 */
1014