1/*
2 * "$Id: dither-eventone.c,v 1.42 2008/02/19 01:13:46 rlk Exp $"
3 *
4 *   EvenTone dither implementation for Gimp-Print
5 *
6 *   Copyright 2002-2003 Mark Tomlinson (mark@southern.co.nz)
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 *   This code uses the Eventone dither algorithm. This is described
23 *   at the website http://www.artofcode.com/eventone/
24 *   This algorithm is covered by US Patents 5,055,942 and 5,917,614
25 *   and was invented by Raph Levien <raph@acm.org>
26 *   It was made available to be used free of charge in GPL-licensed
27 */
28
29#ifdef HAVE_CONFIG_H
30#include <config.h>
31#endif
32#include <gutenprint/gutenprint.h>
33#include "gutenprint-internal.h"
34#include <gutenprint/gutenprint-intl-internal.h>
35#include <string.h>
36#include <math.h>
37#include <limits.h>
38#include "dither-impl.h"
39#include "dither-inlined-functions.h"
40
41typedef struct
42{
43  int dx;
44  int dy;
45  int r_sq;
46} distance_t;
47
48typedef struct
49{
50  int	d2x;
51  int   d2y;
52  distance_t	d_sq;
53  int	aspect;
54  int   unitone_aspect;
55  int	physical_aspect;
56  int	diff_factor;
57  stpi_dither_channel_t *dummy_channel;
58  double transition;		/* Exponential scaling for transition region */
59  stp_dither_matrix_impl_t transition_matrix;
60} eventone_t;
61
62typedef struct shade_segment
63{
64  distance_t dis;
65  distance_t *et_dis;
66  stpi_ink_defn_t lower;
67  stpi_ink_defn_t upper;
68  int share_this_channel;
69} shade_distance_t;
70
71
72#define EVEN_C1 256
73#define EVEN_C2 (EVEN_C1 * sqrt(3.0) / 2.0)
74#define UNITONE_C1 16384
75#define UNITONE_C2 (UNITONE_C1 * sqrt(3.0) / 2.0)
76
77static void
78free_eventone_data(stpi_dither_t *d)
79{
80  int i;
81  eventone_t *et = (eventone_t *) (d->aux_data);
82  for (i = 0; i < CHANNEL_COUNT(d); i++)
83    {
84      if (CHANNEL(d, i).aux_data)
85	{
86	  shade_distance_t *shade = (shade_distance_t *) CHANNEL(d,i).aux_data;
87	  STP_SAFE_FREE(shade->et_dis);
88	  STP_SAFE_FREE(CHANNEL(d, i).aux_data);
89	}
90    }
91  if (et->dummy_channel)
92    {
93      stpi_dither_channel_t *dc = et->dummy_channel;
94      shade_distance_t *shade = (shade_distance_t *) dc->aux_data;
95      STP_SAFE_FREE(shade->et_dis);
96      STP_SAFE_FREE(dc->aux_data);
97      stpi_dither_channel_destroy(dc);
98      STP_SAFE_FREE(et->dummy_channel);
99    }
100  if (d->stpi_dither_type & D_UNITONE)
101    stp_dither_matrix_destroy(&(et->transition_matrix));
102  STP_SAFE_FREE(et);
103}
104
105static void
106et_setup(stpi_dither_t *d)
107{
108  int size = 2 * MAX_SPREAD + ((d->dst_width + 7) & ~7);
109  static const int diff_factors[] = {1, 10, 16, 23, 32};
110  eventone_t *et = stp_zalloc(sizeof(eventone_t));
111  int xa, ya;
112  int i;
113  for (i = 0; i < CHANNEL_COUNT(d); i++)
114    {
115      CHANNEL(d, i).error_rows = 1;
116      CHANNEL(d, i).errs = stp_zalloc(1 * sizeof(int *));
117      CHANNEL(d, i).errs[0] = stp_zalloc(size * sizeof(int));
118    }
119  if (d->stpi_dither_type & D_UNITONE)
120    {
121      stpi_dither_channel_t *dc = stp_zalloc(sizeof(stpi_dither_channel_t));
122      stp_dither_matrix_clone(&(d->dither_matrix), &(dc->dithermat), 0, 0);
123      et->transition = 0.7;
124      stp_dither_matrix_destroy(&(et->transition_matrix));
125      stp_dither_matrix_copy(&(d->dither_matrix), &(et->transition_matrix));
126      stp_dither_matrix_scale_exponentially(&(et->transition_matrix), et->transition);
127      stp_dither_matrix_clone(&(et->transition_matrix), &(dc->pick), 0, 0);
128      dc->error_rows = 1;
129      dc->errs = stp_zalloc(1 * sizeof(int *));
130      dc->errs[0] = stp_zalloc(size * sizeof(int));
131      et->dummy_channel = dc;
132    }
133
134  xa = d->x_aspect / d->y_aspect;
135  if (xa == 0)
136    xa = 1;
137  et->d_sq.dx = xa * xa;
138  et->d2x = 2 * et->d_sq.dx;
139
140  ya = d->y_aspect / d->x_aspect;
141  if (ya == 0)
142    ya = 1;
143  et->d_sq.dy = ya * ya;
144  et->d2y = 2 * et->d_sq.dy;
145
146  et->aspect = EVEN_C2 / (xa * ya);
147  et->unitone_aspect = UNITONE_C2 / (xa * ya);
148  et->d_sq.r_sq = 0;
149
150  for (i = 0; i < CHANNEL_COUNT(d); i++)
151    {
152      int x;
153      shade_distance_t *shade = stp_zalloc(sizeof(shade_distance_t));
154      shade->dis = et->d_sq;
155      shade->et_dis = stp_malloc(sizeof(distance_t) * d->dst_width);
156      if (CHANNEL(d, i).darkness > .1)
157	shade->share_this_channel = 1;
158      else
159	shade->share_this_channel = 0;
160      for (x = 0; x < d->dst_width; x++)
161	shade->et_dis[x] = et->d_sq;
162      CHANNEL(d, i).aux_data = shade;
163    }
164  if (et->dummy_channel)
165    {
166      int x;
167      shade_distance_t *shade = stp_zalloc(sizeof(shade_distance_t));
168      shade->dis = et->d_sq;
169      shade->et_dis = stp_malloc(sizeof(distance_t) * d->dst_width);
170      for (x = 0; x < d->dst_width; x++)
171	shade->et_dis[x] = et->d_sq;
172      et->dummy_channel->aux_data = shade;
173    }
174
175  et->physical_aspect = d->y_aspect / d->x_aspect;
176  if (et->physical_aspect >= 4)
177    et->physical_aspect = 4;
178  else if (et->physical_aspect >= 2)
179    et->physical_aspect = 2;
180  else et->physical_aspect = 1;
181
182  et->diff_factor = diff_factors[et->physical_aspect];
183
184  d->aux_data = et;
185  d->aux_freefunc = free_eventone_data;
186}
187
188static int
189et_initializer(stpi_dither_t *d, int duplicate_line, int zero_mask)
190{
191  int i;
192  eventone_t *et;
193  if (!d->aux_data)
194    et_setup(d);
195
196  et = (eventone_t *) (d->aux_data);
197  if (!duplicate_line)
198    {
199      if ((zero_mask & ((1 << CHANNEL_COUNT(d)) - 1)) !=
200	  ((1 << CHANNEL_COUNT(d)) - 1))
201	d->last_line_was_empty = 0;
202      else
203	d->last_line_was_empty++;
204    }
205  else if (d->last_line_was_empty)
206    d->last_line_was_empty++;
207
208  if (d->last_line_was_empty >= 5)
209    return 0;
210  else if (d->last_line_was_empty == 4)
211    {
212      if (et->dummy_channel)
213	memset(et->dummy_channel->errs[0], 0, d->dst_width * sizeof(int));
214      for (i = 0; i < CHANNEL_COUNT(d); i++)
215	memset(CHANNEL(d, i).errs[0], 0, d->dst_width * sizeof(int));
216      return 0;
217    }
218  for (i = 0; i < CHANNEL_COUNT(d); i++)
219    CHANNEL(d, i).v = 0;
220  if (et->dummy_channel)
221    et->dummy_channel->v = 0;
222  return 1;
223}
224
225static inline void
226advance_eventone_pre(shade_distance_t *sp, eventone_t *et, int x)
227{
228  distance_t *etd = &sp->et_dis[x];
229  int t = sp->dis.r_sq + sp->dis.dx;
230  if (t <= etd->r_sq)
231    { 	/* Do eventone calculations */
232      sp->dis.r_sq = t;		/* Nearest pixel same as last one */
233      sp->dis.dx += et->d2x;
234    }
235  else
236    sp->dis = *etd;		/* Nearest pixel is from a previous line */
237}
238
239static inline void
240eventone_update(stpi_dither_channel_t *dc, eventone_t *et,
241		int x, int direction)
242{
243  shade_distance_t *sp = (shade_distance_t *) dc->aux_data;
244  distance_t *etd = &sp->et_dis[x];
245  int t = etd->r_sq + etd->dy;		/* r^2 from dot above */
246  int u = sp->dis.r_sq + sp->dis.dy;	/* r^2 from dot on this line */
247  if (u < t)
248    {				/* If dot from this line is close */
249      t = u;				/* Use it instead */
250      etd->dx = sp->dis.dx;
251      etd->dy = sp->dis.dy;
252    }
253  etd->dy += et->d2y;
254
255  if (t > 65535)
256    t = 65535;			/* Do some hard limiting */
257  etd->r_sq = t;
258}
259
260static inline void
261diffuse_error(stpi_dither_channel_t *dc, eventone_t *et, int x, int direction)
262{
263  /*
264   * Tests to date show that the second diffusion pattern works better
265   * than the first in most cases.  The previous code is being left here
266   * in case it is later determined that the original code works better.
267   * -- rlk 20031101
268   */
269#if 0
270  /*  int fraction = (dc->v + (et->diff_factor>>1)) / et->diff_factor; */
271  int frac_2 = dc->v + dc->v;
272  int frac_3 = frac_2 + dc->v;
273  dc->errs[0][x + MAX_SPREAD] = frac_3;
274  dc->errs[0][x + MAX_SPREAD - direction] += frac_2;
275  dc->v -= (frac_2 + frac_3) / 16;
276#else
277  dc->errs[0][x + MAX_SPREAD] = dc->v * 3;
278  dc->errs[0][x + MAX_SPREAD - direction] += dc->v * 5;
279  dc->errs[0][x + MAX_SPREAD - (direction * 2)] += dc->v * 1;
280  dc->v -= dc->v * 9 / 16;
281#endif
282}
283
284static inline int
285eventone_adjust(stpi_dither_channel_t *dc, eventone_t *et, int dither_point,
286		unsigned int desired)
287{
288  if (dither_point <= 0)
289    return 0;
290  else if (dither_point >= 65535)
291    return 65535;
292  if (desired == 0)
293    dither_point = 0;
294  else
295    {
296      shade_distance_t *shade = (shade_distance_t *) dc->aux_data;
297      dither_point += shade->dis.r_sq * et->aspect - (EVEN_C1 * 65535) / desired;
298      if (dither_point > 65535)
299	dither_point = 65535;
300      else if (dither_point < 0)
301	dither_point = 0;
302    }
303  return dither_point;
304}
305
306static inline int
307unitone_adjust(stpi_dither_channel_t *dc, eventone_t *et,
308	       int dither_point, unsigned int desired)
309{
310  if (dither_point <= 0)
311    return INT_MIN;
312  else if (dither_point >= 65535)
313    return dither_point;
314  if (desired == 0)
315    dither_point = INT_MIN;
316  else
317    {
318      shade_distance_t *shade = (shade_distance_t *) dc->aux_data;
319      dither_point += shade->dis.r_sq * et->unitone_aspect -
320	(UNITONE_C1 * 65535u) / desired;
321    }
322  return dither_point;
323}
324
325
326static inline void
327find_segment(stpi_dither_channel_t *dc, unsigned inkval,
328	     stpi_ink_defn_t *lower, stpi_ink_defn_t *upper)
329{
330  lower->range = 0;
331  lower->bits = 0;
332
333  if (dc->nlevels == 1)
334    {
335      upper->bits = dc->ink_list[1].bits;
336      upper->range = dc->ink_list[1].value;
337    }
338  else
339    {
340      int i;
341      stpi_ink_defn_t *ip;
342
343      for (i=0, ip = dc->ink_list; i < dc->nlevels - 1; i++, ip++)
344	{
345	  if (ip->value > inkval)
346	    break;
347	  lower->bits = ip->bits;
348	  lower->range = ip->value;
349	}
350
351      upper->bits = ip->bits;
352      upper->range = ip->value;
353    }
354}
355
356static inline int
357find_segment_and_ditherpoint(stpi_dither_channel_t *dc, unsigned inkval,
358			     stpi_ink_defn_t *lower, stpi_ink_defn_t *upper)
359{
360  find_segment(dc, inkval, lower, upper);
361  if (inkval <= lower->range)
362    return 0;
363  else if (inkval >= upper->range)
364    return 65535;
365  else
366    return (65535u * (inkval - lower->range)) / (upper->range - lower->range);
367}
368
369static inline void
370print_ink(stpi_dither_t *d, unsigned char *tptr, const stpi_ink_defn_t *ink,
371	  unsigned char bit, int length)
372{
373  int j;
374
375  if (tptr != 0)
376    {
377      tptr += d->ptr_offset;
378      switch(ink->bits)
379	{
380	case 1:
381	  tptr[0] |= bit;
382	  return;
383	case 2:
384	  tptr[length] |= bit;
385	  return;
386	case 3:
387	  tptr[0] |= bit;
388	  tptr[length] |= bit;
389	  return;
390	default:
391	  for (j=1; j <= ink->bits; j+=j, tptr += length)
392	    {
393	      if (j & ink->bits)
394		*tptr |= bit;
395	    }
396	  return;
397	}
398    }
399}
400
401void
402stpi_dither_et(stp_vars_t *v,
403	       int row,
404	       const unsigned short *raw,
405	       int duplicate_line,
406	       int zero_mask,
407	       const unsigned char *mask)
408{
409  stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
410  eventone_t *et;
411
412  int		x;
413  int	        length;
414  unsigned char	bit;
415  int		i;
416
417  int		terminate;
418  int		direction;
419  int		xerror, xstep, xmod;
420  int		channel_count = CHANNEL_COUNT(d);
421
422  if (!et_initializer(d, duplicate_line, zero_mask))
423    return;
424
425  et = (eventone_t *) d->aux_data;
426  if (d->stpi_dither_type & D_UNITONE)
427    stp_dither_matrix_set_row(&(et->transition_matrix), row);
428
429  length = (d->dst_width + 7) / 8;
430
431  if (row & 1)
432    {
433      direction = 1;
434      x = 0;
435      terminate = d->dst_width;
436      d->ptr_offset = 0;
437    }
438  else
439    {
440      direction = -1;
441      x = d->dst_width - 1;
442      terminate = -1;
443      d->ptr_offset = length - 1;
444      raw += channel_count * (d->src_width - 1);
445    }
446  bit = 1 << (7 - (x & 7));
447  xstep  = channel_count * (d->src_width / d->dst_width);
448  xmod   = d->src_width % d->dst_width;
449  xerror = (xmod * x) % d->dst_width;
450
451  for (; x != terminate; x += direction)
452    {
453
454      int point_error = 0;
455      int comparison = 32768;
456
457      if (d->stpi_dither_type & D_ORDERED_BASE)
458	comparison += (ditherpoint(d, &(d->dither_matrix), x) / 16) - 2048;
459
460      for (i=0; i < channel_count; i++)
461	{
462	  if (CHANNEL(d, i).ptr)
463	    {
464	      int inkspot;
465	      int range_point;
466	      stpi_dither_channel_t *dc = &CHANNEL(d, i);
467	      shade_distance_t *sp = (shade_distance_t *) dc->aux_data;
468	      stpi_ink_defn_t *inkp;
469	      stpi_ink_defn_t lower, upper;
470
471	      advance_eventone_pre(sp, et, x);
472
473	      /*
474	       * Find which are the two candidate dot sizes.
475	       * Rather than use the absolute value of the point to compute
476	       * the error, we will use the relative value of the point within
477	       * the range to find the two candidate dot sizes.
478	       */
479	      range_point =
480		find_segment_and_ditherpoint(dc, raw[i], &lower, &upper);
481
482	      /* Incorporate error data from previous line */
483	      dc->v += 2 * range_point + (dc->errs[0][x + MAX_SPREAD] + 8) / 16;
484	      inkspot = dc->v - range_point;
485
486	      point_error += eventone_adjust(dc, et, inkspot, range_point);
487
488	      /* Determine whether to print the larger or smaller dot */
489	      inkp = &lower;
490	      if (point_error >= comparison)
491		{
492		  point_error -= 65535;
493		  inkp = &upper;
494		  dc->v -= 131070;
495		  sp->dis = et->d_sq;
496		}
497
498	      /* Adjust the error to reflect the dot choice */
499	      if (inkp->bits)
500		{
501		  if (!mask || (*(mask + d->ptr_offset) & bit))
502		    {
503		      set_row_ends(dc, x);
504
505		      /* Do the printing */
506		      print_ink(d, dc->ptr, inkp, bit, length);
507		    }
508		}
509
510	      /* Spread the error around to the adjacent dots */
511	      eventone_update(dc, et, x, direction);
512	      diffuse_error(dc, et, x, direction);
513	    }
514	}
515      if (direction == 1)
516	ADVANCE_UNIDIRECTIONAL(d, bit, raw, channel_count, xerror, xstep, xmod);
517      else
518	ADVANCE_REVERSE(d, bit, raw, channel_count, xerror, xstep, xmod);
519    }
520  if (direction == -1)
521    stpi_dither_reverse_row_ends(d);
522}
523
524void
525stpi_dither_ut(stp_vars_t *v,
526	       int row,
527	       const unsigned short *raw,
528	       int duplicate_line,
529	       int zero_mask,
530	       const unsigned char *mask)
531{
532  stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
533  eventone_t *et;
534
535  int		x;
536  int	        length;
537  unsigned char	bit;
538  int		i;
539
540  int		terminate;
541  int		direction;
542  int		xerror, xstep, xmod;
543  int		channel_count = CHANNEL_COUNT(d);
544  stpi_dither_channel_t *ddc;
545
546  if (channel_count == 1)
547    {
548      stpi_dither_et(v, row, raw, duplicate_line, zero_mask, mask);
549      return;
550    }
551
552  if (!et_initializer(d, duplicate_line, zero_mask))
553    return;
554
555  et = (eventone_t *) d->aux_data;
556  ddc = et->dummy_channel;
557
558  length = (d->dst_width + 7) / 8;
559
560  if (row & 1)
561    {
562      direction = 1;
563      x = 0;
564      terminate = d->dst_width;
565      d->ptr_offset = 0;
566    }
567  else
568    {
569      direction = -1;
570      x = d->dst_width - 1;
571      terminate = -1;
572      d->ptr_offset = length - 1;
573      raw += channel_count * (d->src_width - 1);
574    }
575  bit = 1 << (7 - (x & 7));
576  xstep  = channel_count * (d->src_width / d->dst_width);
577  xmod   = d->src_width % d->dst_width;
578  xerror = (xmod * x) % d->dst_width;
579
580  for (; x != terminate; x += direction)
581    {
582
583      shade_distance_t *ssp = (shade_distance_t *) ddc->aux_data;
584      int point_error = 0;
585      int total_error = 0;
586      int channels_to_print = 0;
587      int print_all_channels = 0;
588      int maximum_value = 0;
589      int comparison = 32768;
590      stpi_dither_channel_t *best_channel = NULL;
591      stpi_dither_channel_t *second_best_channel = NULL;
592      int best_channel_value = INT_MIN;
593      int second_best_channel_value = INT_MIN;
594      int random_value = ditherpoint(d, &(d->dither_matrix), x);
595
596      if (d->stpi_dither_type & D_ORDERED_BASE)
597	comparison += (random_value / 16) - 2048;
598
599
600      ddc->b = 0;
601      advance_eventone_pre(ssp, et, x);
602
603      for (i=0; i < channel_count; i++)
604	{
605	  stpi_dither_channel_t *dc = &CHANNEL(d, i);
606	  if (dc->ptr)
607	    {
608	      shade_distance_t *sp = (shade_distance_t *) dc->aux_data;
609
610	      advance_eventone_pre(sp, et, x);
611
612	      /*
613	       * Find which are the two candidate dot sizes.
614	       * Rather than use the absolute value of the point to compute
615	       * the error, we will use the relative value of the point within
616	       * the range to find the two candidate dot sizes.
617	       */
618	      dc->b = find_segment_and_ditherpoint(dc, raw[i],
619						   &(sp->lower), &(sp->upper));
620	      if (sp->share_this_channel)
621		{
622		  if (dc->b > maximum_value)
623		    maximum_value = dc->b;
624		  ddc->b += dc->b;
625		}
626	      /* Incorporate error data from previous line */
627	      dc->v += 2 * dc->b + (dc->errs[0][x + MAX_SPREAD] + 8) / 16;
628	      dc->o = unitone_adjust(dc, et, dc->v - dc->b, dc->b);
629	    }
630	}
631
632#if 0
633      if ((2 * (ddc->b - maximum_value)) < (3 * maximum_value))
634	print_all_channels = 1;
635#endif
636
637      if (ddc->b > 131070)
638	print_all_channels = 1;
639      else if (ddc->b > 65535)
640	{
641	  ddc->b -= 65535;
642	  channels_to_print = 1;
643	}
644
645      if (ddc->b > 65535)
646	ddc->b = 65535;
647
648      ddc->v += 2 * ddc->b + (ddc->errs[0][x + MAX_SPREAD] + 8) / 16;
649      total_error += eventone_adjust(ddc, et, ddc->v - ddc->b, ddc->b);
650      if (total_error >= comparison)
651	channels_to_print += 1;
652
653      if (!print_all_channels)
654	{
655	  for (i=0; i < channel_count; i++)
656	    {
657	      stpi_dither_channel_t *dc = &CHANNEL(d, i);
658	      shade_distance_t *sp = (shade_distance_t *) dc->aux_data;
659
660	      if (dc->ptr)
661		{
662
663		  if (sp->share_this_channel)
664		    {
665		      if (dc->o > best_channel_value)
666			{
667			  second_best_channel = best_channel;
668			  best_channel = dc;
669			  second_best_channel_value = best_channel_value;
670			  if (dc->o >= 32768)
671			    best_channel_value = INT_MAX;
672			  else
673			    best_channel_value = dc->o;
674			}
675		      else if (dc->o > second_best_channel_value)
676			{
677			  second_best_channel = dc;
678			  if (dc->o >= 32768)
679			    second_best_channel_value = INT_MAX;
680			  else
681			    second_best_channel_value = dc->o;
682			}
683		    }
684		}
685	    }
686	}
687
688      for (i=0; i < channel_count; i++)
689	{
690	  stpi_dither_channel_t *dc = &CHANNEL(d, i);
691	  if (dc->ptr)
692	    {
693	      /* Determine whether to print the larger or smaller dot */
694	      shade_distance_t *sp = (shade_distance_t *) dc->aux_data;
695	      stpi_ink_defn_t *inkp = &(sp->lower);
696
697	      if (dc->o < 0)
698		dc->o = 0;
699	      else if (dc->o > 65535)
700		dc->o = 65535;
701	      if (print_all_channels || !sp->share_this_channel)
702		{
703		  point_error += dc->o;
704		  if (point_error >= comparison)
705		    {
706		      point_error -= 65535;
707		      inkp = &(sp->upper);
708		      dc->v -= 131070;
709		      sp->dis = et->d_sq;
710		    }
711		}
712	      else if ((channels_to_print >= 1 && best_channel == dc) ||
713		       (channels_to_print >= 2 && second_best_channel == dc))
714		{
715		  inkp = &(sp->upper);
716		  dc->v -= 131070;
717		  sp->dis = et->d_sq;
718		}
719	      if (inkp->bits)
720		{
721		  if (!mask || (*(mask + d->ptr_offset) & bit))
722		    {
723		      set_row_ends(dc, x);
724
725		      /* Do the printing */
726		      print_ink(d, dc->ptr, inkp, bit, length);
727		    }
728		}
729	    }
730	}
731      if (total_error >= comparison)
732	{
733	  ddc->v -= 131070;
734	  total_error -= 65535;
735	  ssp->dis = et->d_sq;
736	}
737
738      eventone_update(ddc, et, x, direction);
739      diffuse_error(ddc, et, x, direction);
740      for (i=0; i < channel_count; i++)
741	{
742	  stpi_dither_channel_t *dc = &CHANNEL(d, i);
743	  if (dc->ptr)
744	    {
745	      /* Spread the error around to the adjacent dots */
746	      eventone_update(dc, et, x, direction);
747	      diffuse_error(dc, et, x, direction);
748	    }
749	}
750      if (direction == 1)
751	ADVANCE_UNIDIRECTIONAL(d, bit, raw, channel_count, xerror, xstep, xmod);
752      else
753	ADVANCE_REVERSE(d, bit, raw, channel_count, xerror, xstep, xmod);
754    }
755  if (direction == -1)
756    stpi_dither_reverse_row_ends(d);
757}
758