libgimpprint API Reference: src/main/dither-eventone.c Source File

Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

# src/main/dither-eventone.c

Go to the documentation of this file.

    00001 /*
    00002  * "$Id: dither-eventone_8c-source.html,v 1.1.1.2 2004/12/22 23:48:58 jlovell Exp $"
    00003  *
    00004  *   EvenTone dither implementation for Gimp-Print
    00005  *
    00006  *   Copyright 2002-2003 Mark Tomlinson (mark@southern.co.nz)
    00007  *
    00008  *   This program is free software; you can redistribute it and/or modify it
    00009  *   under the terms of the GNU General Public License as published by the Free
    00010  *   Software Foundation; either version 2 of the License, or (at your option)
    00011  *   any later version.
    00012  *
    00013  *   This program is distributed in the hope that it will be useful, but
    00014  *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    00015  *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    00016  *   for more details.
    00017  *
    00018  *   You should have received a copy of the GNU General Public License
    00019  *   along with this program; if not, write to the Free Software
    00020  *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    00021  *
    00022  *   This code uses the Eventone dither algorithm. This is described
    00023  *   at the website http://www.artofcode.com/eventone/
    00024  *   This algorithm is covered by US Patents 5,055,942 and 5,917,614
    00025  *   and was invented by Raph Levien <raph@acm.org>
    00026  *   It was made available to be used free of charge in GPL-licensed
    00027  */
    00028
    00029 #ifdef HAVE_CONFIG_H
    00030 #include <config.h>
    00031 #endif
    00032 #include <gimp-print/gimp-print.h>
    00033 #include "gimp-print-internal.h"
    00034 #include <gimp-print/gimp-print-intl-internal.h>
    00035 #include <string.h>
    00036 #include <math.h>
    00037 #include <limits.h>
    00038 #include "dither-impl.h"
    00039 #include "dither-inlined-functions.h"
    00040
    00041 typedef struct
    00042 {
    00043   int dx;
    00044   int dy;
    00045   int r_sq;
    00046 } distance_t;
    00047
    00048 typedef struct
    00049 {
    00050   int   d2x;
    00051   int   d2y;
    00052   distance_t    d_sq;
    00053   int   aspect;
    00054   int   unitone_aspect;
    00055   int   physical_aspect;
    00056   int   diff_factor;
    00057   stpi_dither_channel_t *dummy_channel;
    00058 } eventone_t;
    00059
    00060 typedef struct shade_segment
    00061 {
    00062   distance_t dis;
    00063   distance_t *et_dis;
    00064   stpi_ink_defn_t lower;
    00065   stpi_ink_defn_t upper;
    00066   int share_this_channel;
    00067 } shade_distance_t;
    00068
    00069
    00070 #define EVEN_C1 256
    00071 #define EVEN_C2 (EVEN_C1 * sqrt(3.0) / 2.0)
    00072 #define UNITONE_C1 16384
    00073 #define UNITONE_C2 (UNITONE_C1 * sqrt(3.0) / 2.0)
    00074
    00075 static void
    00076 free_eventone_data(stpi_dither_t *d)
    00077 {
    00078   int i;
    00079   eventone_t *et = (eventone_t *) (d->aux_data);
    00080   for (i = 0; i < CHANNEL_COUNT(d); i++)
    00081     {
    00082       if (CHANNEL(d, i).aux_data)
    00083         {
    00084           shade_distance_t *shade = (shade_distance_t *) CHANNEL(d,i).aux_data;
    00085           STP_SAFE_FREE(shade->et_dis);
    00086           STP_SAFE_FREE(CHANNEL(d, i).aux_data);
    00087         }
    00088     }
    00089   if (et->dummy_channel) {
    00090     stpi_dither_channel_t *dc = et->dummy_channel;
    00091     shade_distance_t *shade = (shade_distance_t *) dc->aux_data;
    00092     STP_SAFE_FREE(shade->et_dis);
    00093     STP_SAFE_FREE(dc->aux_data);
    00094     stpi_dither_channel_destroy(dc);
    00095     STP_SAFE_FREE(et->dummy_channel);
    00096   }
    00097   STP_SAFE_FREE(et);
    00098 }
    00099
    00100 static void
    00101 et_setup(stpi_dither_t *d)
    00102 {
    00103   int size = 2 * MAX_SPREAD + ((d->dst_width + 7) & ~7);
    00104   static const int diff_factors[] = {1, 10, 16, 23, 32};
    00105   eventone_t *et = stp_zalloc(sizeof(eventone_t));
    00106   int xa, ya;
    00107   int i;
    00108   for (i = 0; i < CHANNEL_COUNT(d); i++) {
    00109     CHANNEL(d, i).error_rows = 1;
    00110     CHANNEL(d, i).errs = stp_zalloc(1 * sizeof(int *));
    00111     CHANNEL(d, i).errs[0] = stp_zalloc(size * sizeof(int));
    00112   }
    00113   if (d->stpi_dither_type & D_UNITONE) {
    00114     stpi_dither_channel_t *dc = stp_zalloc(sizeof(stpi_dither_channel_t));
    00115     stp_dither_matrix_clone(&(d->dither_matrix), &(dc->dithermat), 0, 0);
    00116     stp_dither_matrix_clone(&(d->transition_matrix), &(dc->pick), 0, 0);
    00117     dc->error_rows = 1;
    00118     dc->errs = stp_zalloc(1 * sizeof(int *));
    00119     dc->errs[0] = stp_zalloc(size * sizeof(int));
    00120     et->dummy_channel = dc;
    00121   }
    00122
    00123   xa = d->x_aspect / d->y_aspect;
    00124   if (xa == 0)
    00125     xa = 1;
    00126   et->d_sq.dx = xa * xa;
    00127   et->d2x = 2 * et->d_sq.dx;
    00128
    00129   ya = d->y_aspect / d->x_aspect;
    00130   if (ya == 0)
    00131     ya = 1;
    00132   et->d_sq.dy = ya * ya;
    00133   et->d2y = 2 * et->d_sq.dy;
    00134
    00135   et->aspect = EVEN_C2 / (xa * ya);
    00136   et->unitone_aspect = UNITONE_C2 / (xa * ya);
    00137   et->d_sq.r_sq = 0;
    00138
    00139   for (i = 0; i < CHANNEL_COUNT(d); i++) {
    00140     int x;
    00141     shade_distance_t *shade = stp_zalloc(sizeof(shade_distance_t));
    00142     shade->dis = et->d_sq;
    00143     shade->et_dis = stp_malloc(sizeof(distance_t) * d->dst_width);
    00144     if (CHANNEL(d, i).darkness > .1)
    00145       shade->share_this_channel = 1;
    00146     else
    00147       shade->share_this_channel = 0;
    00148     for (x = 0; x < d->dst_width; x++) {
    00149       shade->et_dis[x] = et->d_sq;
    00150     }
    00151     CHANNEL(d, i).aux_data = shade;
    00152   }
    00153   if (et->dummy_channel) {
    00154     int x;
    00155     shade_distance_t *shade = stp_zalloc(sizeof(shade_distance_t));
    00156     shade->dis = et->d_sq;
    00157     shade->et_dis = stp_malloc(sizeof(distance_t) * d->dst_width);
    00158     for (x = 0; x < d->dst_width; x++) {
    00159       shade->et_dis[x] = et->d_sq;
    00160     }
    00161     et->dummy_channel->aux_data = shade;
    00162   }
    00163
    00164   et->physical_aspect = d->y_aspect / d->x_aspect;
    00165   if (et->physical_aspect >= 4)
    00166     et->physical_aspect = 4;
    00167   else if (et->physical_aspect >= 2)
    00168     et->physical_aspect = 2;
    00169   else et->physical_aspect = 1;
    00170
    00171   et->diff_factor = diff_factors[et->physical_aspect];
    00172
    00173   d->aux_data = et;
    00174   d->aux_freefunc = free_eventone_data;
    00175 }
    00176
    00177 static int
    00178 et_initializer(stpi_dither_t *d, int duplicate_line, int zero_mask)
    00179 {
    00180   int i;
    00181   eventone_t *et;
    00182   if (!d->aux_data)
    00183     et_setup(d);
    00184
    00185   et = (eventone_t *) (d->aux_data);
    00186   if (!duplicate_line) {
    00187     if ((zero_mask & ((1 << CHANNEL_COUNT(d)) - 1)) !=
    00188         ((1 << CHANNEL_COUNT(d)) - 1)) {
    00189       d->last_line_was_empty = 0;
    00190     } else {
    00191       d->last_line_was_empty++;
    00192     }
    00193   } else if (d->last_line_was_empty) {
    00194     d->last_line_was_empty++;
    00195   }
    00196
    00197   if (d->last_line_was_empty >= 5) {
    00198     return 0;
    00199   } else if (d->last_line_was_empty == 4) {
    00200     if (et->dummy_channel) {
    00201       memset(et->dummy_channel->errs[0], 0, d->dst_width * sizeof(int));
    00202     }
    00203     for (i = 0; i < CHANNEL_COUNT(d); i++)
    00204       memset(CHANNEL(d, i).errs[0], 0, d->dst_width * sizeof(int));
    00205     return 0;
    00206   }
    00207   for (i = 0; i < CHANNEL_COUNT(d); i++)
    00208     CHANNEL(d, i).v = 0;
    00209   if (et->dummy_channel)
    00210     et->dummy_channel->v = 0;
    00211   return 1;
    00212 }
    00213
    00214 static inline void
    00215 advance_eventone_pre(shade_distance_t *sp, eventone_t *et, int x)
    00216 {
    00217   distance_t *etd = &sp->et_dis[x];
    00218   int t = sp->dis.r_sq + sp->dis.dx;
    00219   if (t <= etd->r_sq) {         /* Do eventone calculations */
    00220     sp->dis.r_sq = t;           /* Nearest pixel same as last one */
    00221     sp->dis.dx += et->d2x;
    00222   } else {
    00223     sp->dis = *etd;             /* Nearest pixel is from a previous line */
    00224   }
    00225 }
    00226
    00227 static inline void
    00228 eventone_update(stpi_dither_channel_t *dc, eventone_t *et,
    00229                 int x, int direction)
    00230 {
    00231   shade_distance_t *sp = (shade_distance_t *) dc->aux_data;
    00232   distance_t *etd = &sp->et_dis[x];
    00233   int t = etd->r_sq + etd->dy;          /* r^2 from dot above */
    00234   int u = sp->dis.r_sq + sp->dis.dy;    /* r^2 from dot on this line */
    00235   if (u < t) {                          /* If dot from this line is close */
    00236     t = u;                              /* Use it instead */
    00237     etd->dx = sp->dis.dx;
    00238     etd->dy = sp->dis.dy;
    00239   }
    00240   etd->dy += et->d2y;
    00241
    00242   if (t > 65535) {                      /* Do some hard limiting */
    00243     t = 65535;
    00244   }
    00245   etd->r_sq = t;
    00246 }
    00247
    00248 static inline void
    00249 diffuse_error(stpi_dither_channel_t *dc, eventone_t *et, int x, int direction)
    00250 {
    00251   /*
    00252    * Tests to date show that the second diffusion pattern works better
    00253    * than the first in most cases.  The previous code is being left here
    00254    * in case it is later determined that the original code works better.
    00255    * -- rlk 20031101
    00256    */
    00257 #if 0
    00258 /*  int fraction = (dc->v + (et->diff_factor>>1)) / et->diff_factor; */
    00259   int frac_2 = dc->v + dc->v;
    00260   int frac_3 = frac_2 + dc->v;
    00261   dc->errs[0][x + MAX_SPREAD] = frac_3;
    00262   dc->errs[0][x + MAX_SPREAD - direction] += frac_2;
    00263   dc->v -= (frac_2 + frac_3) / 16;
    00264 #else
    00265   dc->errs[0][x + MAX_SPREAD] = dc->v * 3;
    00266   dc->errs[0][x + MAX_SPREAD - direction] += dc->v * 5;
    00267   dc->errs[0][x + MAX_SPREAD - (direction * 2)] += dc->v * 1;
    00268   dc->v -= dc->v * 9 / 16;
    00269 #endif
    00270 }
    00271
    00272 static inline int
    00273 eventone_adjust(stpi_dither_channel_t *dc, eventone_t *et, int dither_point,
    00274                 unsigned int desired)
    00275 {
    00276   if (dither_point <= 0)
    00277     return 0;
    00278   else if (dither_point >= 65535)
    00279     return 65535;
    00280   if (desired == 0) {
    00281     dither_point = 0;
    00282   } else {
    00283     shade_distance_t *shade = (shade_distance_t *) dc->aux_data;
    00284     dither_point += shade->dis.r_sq * et->aspect - (EVEN_C1 * 65535) / desired;
    00285     if (dither_point > 65535)
    00286       dither_point = 65535;
    00287     else if (dither_point < 0)
    00288       dither_point = 0;
    00289   }
    00290   return dither_point;
    00291 }
    00292
    00293 static inline int
    00294 unitone_adjust(stpi_dither_channel_t *dc, eventone_t *et,
    00295                int dither_point, unsigned int desired)
    00296 {
    00297   if (dither_point <= 0)
    00298     return INT_MIN;
    00299   else if (dither_point >= 65535)
    00300     return dither_point;
    00301   if (desired == 0) {
    00302     dither_point = INT_MIN;
    00303   } else {
    00304     shade_distance_t *shade = (shade_distance_t *) dc->aux_data;
    00305     dither_point += shade->dis.r_sq * et->unitone_aspect -
    00306       (UNITONE_C1 * 65535u) / desired;
    00307   }
    00308   return dither_point;
    00309 }
    00310
    00311
    00312 static inline void
    00313 find_segment(stpi_dither_channel_t *dc, unsigned inkval,
    00314              stpi_ink_defn_t *lower, stpi_ink_defn_t *upper)
    00315 {
    00316   lower->range = 0;
    00317   lower->bits = 0;
    00318
    00319   if (dc->nlevels == 1)
    00320     {
    00321       upper->bits = dc->ink_list[1].bits;
    00322       upper->range = dc->ink_list[1].value;
    00323     }
    00324   else
    00325     {
    00326       int i;
    00327       stpi_ink_defn_t *ip;
    00328
    00329       for (i=0, ip = dc->ink_list; i < dc->nlevels - 1; i++, ip++) {
    00330         if (ip->value > inkval)
    00331           break;
    00332         lower->bits = ip->bits;
    00333         lower->range = ip->value;
    00334       }
    00335
    00336       upper->bits = ip->bits;
    00337       upper->range = ip->value;
    00338     }
    00339 }
    00340
    00341 static inline int
    00342 find_segment_and_ditherpoint(stpi_dither_channel_t *dc, unsigned inkval,
    00343                              stpi_ink_defn_t *lower, stpi_ink_defn_t *upper)
    00344 {
    00345   find_segment(dc, inkval, lower, upper);
    00346   if (inkval <= lower->range)
    00347     return 0;
    00348   else if (inkval >= upper->range)
    00349     return 65535;
    00350   else
    00351     return (65535u * (inkval - lower->range)) / (upper->range - lower->range);
    00352 }
    00353
    00354 static inline void
    00355 print_ink(stpi_dither_t *d, unsigned char *tptr, const stpi_ink_defn_t *ink,
    00356           unsigned char bit, int length)
    00357 {
    00358   int j;
    00359
    00360   if (tptr != 0)
    00361     {
    00362       tptr += d->ptr_offset;
    00363       switch(ink->bits)
    00364         {
    00365         case 1:
    00366           tptr[0] |= bit;
    00367           return;
    00368         case 2:
    00369           tptr[length] |= bit;
    00370           return;
    00371         case 3:
    00372           tptr[0] |= bit;
    00373           tptr[length] |= bit;
    00374           return;
    00375         default:
    00376           for (j=1; j <= ink->bits; j+=j, tptr += length) {
    00377             if (j & ink->bits)
    00378               *tptr |= bit;
    00379           }
    00380           return;
    00381         }
    00382     }
    00383 }
    00384
    00385 void
    00386 stpi_dither_et(stp_vars_t *v,
    00387                int row,
    00388                const unsigned short *raw,
    00389                int duplicate_line,
    00390                int zero_mask,
    00391                const unsigned char *mask)
    00392 {
    00393   stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
    00394   eventone_t *et;
    00395
    00396   int           x,
    00397                 length;
    00398   unsigned char bit;
    00399   int           i;
    00400
    00401   int           terminate;
    00402   int           direction;
    00403   int           xerror, xstep, xmod;
    00404   int           channel_count = CHANNEL_COUNT(d);
    00405
    00406   if (!et_initializer(d, duplicate_line, zero_mask))
    00407     return;
    00408
    00409   et = (eventone_t *) d->aux_data;
    00410
    00411   length = (d->dst_width + 7) / 8;
    00412
    00413   if (row & 1) {
    00414     direction = 1;
    00415     x = 0;
    00416     terminate = d->dst_width;
    00417     d->ptr_offset = 0;
    00418   } else {
    00419     direction = -1;
    00420     x = d->dst_width - 1;
    00421     terminate = -1;
    00422     d->ptr_offset = length - 1;
    00423     raw += channel_count * (d->src_width - 1);
    00424   }
    00425   bit = 1 << (7 - (x & 7));
    00426   xstep  = channel_count * (d->src_width / d->dst_width);
    00427   xmod   = d->src_width % d->dst_width;
    00428   xerror = (xmod * x) % d->dst_width;
    00429
    00430   for (; x != terminate; x += direction) {
    00431
    00432     int point_error = 0;
    00433     int comparison = 32768;
    00434
    00435     if (d->stpi_dither_type & D_ORDERED_BASE)
    00436       comparison += (ditherpoint(d, &(d->dither_matrix), x) / 16) - 2048;
    00437
    00438     for (i=0; i < channel_count; i++) {
    00439       if (CHANNEL(d, i).ptr)
    00440         {
    00441           int inkspot;
    00442           int range_point;
    00443           stpi_dither_channel_t *dc = &CHANNEL(d, i);
    00444           shade_distance_t *sp = (shade_distance_t *) dc->aux_data;
    00445           stpi_ink_defn_t *inkp;
    00446           stpi_ink_defn_t lower, upper;
    00447
    00448           advance_eventone_pre(sp, et, x);
    00449
    00450           /*
    00451            * Find which are the two candidate dot sizes.
    00452            * Rather than use the absolute value of the point to compute
    00453            * the error, we will use the relative value of the point within
    00454            * the range to find the two candidate dot sizes.
    00455            */
    00456           range_point =
    00457             find_segment_and_ditherpoint(dc, raw[i], &lower, &upper);
    00458
    00459           /* Incorporate error data from previous line */
    00460           dc->v += 2 * range_point + (dc->errs[0][x + MAX_SPREAD] + 8) / 16;
    00461           inkspot = dc->v - range_point;
    00462
    00463           point_error += eventone_adjust(dc, et, inkspot, range_point);
    00464
    00465           /* Determine whether to print the larger or smaller dot */
    00466           inkp = &lower;
    00467           if (point_error >= comparison) {
    00468             point_error -= 65535;
    00469             inkp = &upper;
    00470             dc->v -= 131070;
    00471             sp->dis = et->d_sq;
    00472           }
    00473
    00474           /* Adjust the error to reflect the dot choice */
    00475           if (inkp->bits) {
    00476             if (!mask || (*(mask + d->ptr_offset) & bit)) {
    00477               set_row_ends(dc, x);
    00478
    00479               /* Do the printing */
    00480               print_ink(d, dc->ptr, inkp, bit, length);
    00481             }
    00482           }
    00483
    00484           /* Spread the error around to the adjacent dots */
    00485           eventone_update(dc, et, x, direction);
    00486           diffuse_error(dc, et, x, direction);
    00487         }
    00488     }
    00489     if (direction == 1)
    00490       ADVANCE_UNIDIRECTIONAL(d, bit, raw, channel_count, xerror, xstep, xmod);
    00491     else
    00492       ADVANCE_REVERSE(d, bit, raw, channel_count, xerror, xstep, xmod);
    00493   }
    00494   if (direction == -1)
    00495     stpi_dither_reverse_row_ends(d);
    00496 }
    00497
    00498 void
    00499 stpi_dither_ut(stp_vars_t *v,
    00500                int row,
    00501                const unsigned short *raw,
    00502                int duplicate_line,
    00503                int zero_mask,
    00504                const unsigned char *mask)
    00505 {
    00506   stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
    00507   eventone_t *et;
    00508
    00509   int           x,
    00510                 length;
    00511   unsigned char bit;
    00512   int           i;
    00513
    00514   int           terminate;
    00515   int           direction;
    00516   int           xerror, xstep, xmod;
    00517   int           channel_count = CHANNEL_COUNT(d);
    00518   stpi_dither_channel_t *ddc;
    00519
    00520   if (channel_count == 1) {
    00521     stpi_dither_et(v, row, raw, duplicate_line, zero_mask, mask);
    00522     return;
    00523   }
    00524
    00525   if (!et_initializer(d, duplicate_line, zero_mask))
    00526     return;
    00527
    00528   et = (eventone_t *) d->aux_data;
    00529   ddc = et->dummy_channel;
    00530
    00531   length = (d->dst_width + 7) / 8;
    00532
    00533   if (row & 1) {
    00534     direction = 1;
    00535     x = 0;
    00536     terminate = d->dst_width;
    00537     d->ptr_offset = 0;
    00538   } else {
    00539     direction = -1;
    00540     x = d->dst_width - 1;
    00541     terminate = -1;
    00542     d->ptr_offset = length - 1;
    00543     raw += channel_count * (d->src_width - 1);
    00544   }
    00545   bit = 1 << (7 - (x & 7));
    00546   xstep  = channel_count * (d->src_width / d->dst_width);
    00547   xmod   = d->src_width % d->dst_width;
    00548   xerror = (xmod * x) % d->dst_width;
    00549
    00550   for (; x != terminate; x += direction) {
    00551
    00552     shade_distance_t *ssp = (shade_distance_t *) ddc->aux_data;
    00553     int point_error = 0;
    00554     int total_error = 0;
    00555     int channels_to_print = 0;
    00556     int print_all_channels = 0;
    00557     int maximum_value = 0;
    00558     int comparison = 32768;
    00559     stpi_dither_channel_t *best_channel = NULL;
    00560     stpi_dither_channel_t *second_best_channel = NULL;
    00561     int best_channel_value = INT_MIN;
    00562     int second_best_channel_value = INT_MIN;
    00563     int random_value = ditherpoint(d, &(d->dither_matrix), x);
    00564
    00565     if (d->stpi_dither_type & D_ORDERED_BASE)
    00566       comparison += (random_value / 16) - 2048;
    00567
    00568
    00569     ddc->b = 0;
    00570     advance_eventone_pre(ssp, et, x);
    00571
    00572     for (i=0; i < channel_count; i++) {
    00573       stpi_dither_channel_t *dc = &CHANNEL(d, i);
    00574       if (dc->ptr) {
    00575         shade_distance_t *sp = (shade_distance_t *) dc->aux_data;
    00576
    00577         advance_eventone_pre(sp, et, x);
    00578
    00579         /*
    00580          * Find which are the two candidate dot sizes.
    00581          * Rather than use the absolute value of the point to compute
    00582          * the error, we will use the relative value of the point within
    00583          * the range to find the two candidate dot sizes.
    00584          */
    00585         dc->b = find_segment_and_ditherpoint(dc, raw[i],
    00586                                              &(sp->lower), &(sp->upper));
    00587         if (sp->share_this_channel) {
    00588           if (dc->b > maximum_value)
    00589             maximum_value = dc->b;
    00590           ddc->b += dc->b;
    00591         }
    00592         /* Incorporate error data from previous line */
    00593         dc->v += 2 * dc->b + (dc->errs[0][x + MAX_SPREAD] + 8) / 16;
    00594         dc->o = unitone_adjust(dc, et, dc->v - dc->b, dc->b);
    00595       }
    00596     }
    00597
    00598 #if 0
    00599     if ((2 * (ddc->b - maximum_value)) < (3 * maximum_value))
    00600       print_all_channels = 1;
    00601 #endif
    00602
    00603     if (ddc->b > 131070)
    00604       print_all_channels = 1;
    00605     else if (ddc->b > 65535) {
    00606       ddc->b -= 65535;
    00607       channels_to_print = 1;
    00608     }
    00609
    00610     if (ddc->b > 65535) {
    00611       ddc->b = 65535;
    00612     }
    00613
    00614     ddc->v += 2 * ddc->b + (ddc->errs[0][x + MAX_SPREAD] + 8) / 16;
    00615     total_error += eventone_adjust(ddc, et, ddc->v - ddc->b, ddc->b);
    00616     if (total_error >= comparison) {
    00617       channels_to_print += 1;
    00618     }
    00619
    00620     if (!print_all_channels) {
    00621       for (i=0; i < channel_count; i++) {
    00622         stpi_dither_channel_t *dc = &CHANNEL(d, i);
    00623         shade_distance_t *sp = (shade_distance_t *) dc->aux_data;
    00624
    00625         if (dc->ptr) {
    00626
    00627           if (sp->share_this_channel) {
    00628             if (dc->o > best_channel_value) {
    00629               second_best_channel = best_channel;
    00630               best_channel = dc;
    00631               second_best_channel_value = best_channel_value;
    00632               if (dc->o >= 32768)
    00633                 best_channel_value = INT_MAX;
    00634               else
    00635                 best_channel_value = dc->o;
    00636             } else if (dc->o > second_best_channel_value) {
    00637               second_best_channel = dc;
    00638               if (dc->o >= 32768)
    00639                 second_best_channel_value = INT_MAX;
    00640               else
    00641                 second_best_channel_value = dc->o;
    00642             }
    00643           }
    00644         }
    00645       }
    00646     }
    00647
    00648     for (i=0; i < channel_count; i++) {
    00649       stpi_dither_channel_t *dc = &CHANNEL(d, i);
    00650       if (dc->ptr) {
    00651
    00652         /* Determine whether to print the larger or smaller dot */
    00653         shade_distance_t *sp = (shade_distance_t *) dc->aux_data;
    00654         stpi_ink_defn_t *inkp = &(sp->lower);
    00655
    00656         if (dc->o < 0)
    00657           dc->o = 0;
    00658         else if (dc->o > 65535)
    00659           dc->o = 65535;
    00660         if (print_all_channels || !sp->share_this_channel) {
    00661           point_error += dc->o;
    00662           if (point_error >= comparison) {
    00663             point_error -= 65535;
    00664             inkp = &(sp->upper);
    00665             dc->v -= 131070;
    00666             sp->dis = et->d_sq;
    00667           }
    00668         } else if ((channels_to_print >= 1 && best_channel == dc) ||
    00669                    (channels_to_print >= 2 && second_best_channel == dc)) {
    00670           inkp = &(sp->upper);
    00671           dc->v -= 131070;
    00672           sp->dis = et->d_sq;
    00673         }
    00674         if (inkp->bits) {
    00675           if (!mask || (*(mask + d->ptr_offset) & bit)) {
    00676             set_row_ends(dc, x);
    00677
    00678             /* Do the printing */
    00679             print_ink(d, dc->ptr, inkp, bit, length);
    00680           }
    00681         }
    00682       }
    00683     }
    00684     if (total_error >= comparison) {
    00685       ddc->v -= 131070;
    00686       total_error -= 65535;
    00687       ssp->dis = et->d_sq;
    00688     }
    00689
    00690     eventone_update(ddc, et, x, direction);
    00691     diffuse_error(ddc, et, x, direction);
    00692     for (i=0; i < channel_count; i++) {
    00693       stpi_dither_channel_t *dc = &CHANNEL(d, i);
    00694       if (dc->ptr) {
    00695
    00696         /* Spread the error around to the adjacent dots */
    00697         eventone_update(dc, et, x, direction);
    00698         diffuse_error(dc, et, x, direction);
    00699       }
    00700     }
    00701
    00702
    00703     if (direction == 1)
    00704       ADVANCE_UNIDIRECTIONAL(d, bit, raw, channel_count, xerror, xstep, xmod);
    00705     else
    00706       ADVANCE_REVERSE(d, bit, raw, channel_count, xerror, xstep, xmod);
    00707   }
    00708   if (direction == -1)
    00709     stpi_dither_reverse_row_ends(d);
    00710 }