Main Page   Modules   Alphabetical List   Data Structures   File List   Data Fields   Globals  

src/main/dither-eventone.c

Go to the documentation of this file.
00001 /*
00002  * "$Id: dither-eventone.c,v 1.39 2004/05/07 19:20:29 rleigh 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 }

Generated on Wed May 12 20:21:28 2004 for libgimpprint API Reference by doxygen1.2.17