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