1/* 2 * "$Id: print-weave.c,v 1.76 2010/08/04 00:33:57 rlk Exp $" 3 * 4 * Softweave calculator for Gutenprint. 5 * 6 * Copyright 2000 Charles Briscoe-Smith <cpbs@debian.org> 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the Free 10 * Software Foundation; either version 2 of the License, or (at your option) 11 * any later version. 12 * 13 * This program is distributed in the hope that it will be useful, but 14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 * for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 21 */ 22 23/* 24 * This file must include only standard C header files. The core code must 25 * compile on generic platforms that don't support glib, gimp, gtk, etc. 26 */ 27 28#ifdef HAVE_CONFIG_H 29#include <config.h> 30#endif 31#include <string.h> 32#include <gutenprint/gutenprint.h> 33#include "gutenprint-internal.h" 34#include <gutenprint/gutenprint-intl-internal.h> 35#ifdef HAVE_LIMITS_H 36#include <limits.h> 37#endif 38 39static int 40gcd(int x, int y) 41{ 42 if (y == 0) 43 return x; 44 while (x != 0) { 45 if (y > x) { 46 int t = x; 47 x = y; 48 y = t; 49 } 50 x %= y; 51 } 52 return y; 53} 54 55typedef struct stpi_softweave 56{ 57 stp_linebufs_t *linebases; /* Base address of each row buffer */ 58 stp_lineoff_t *lineoffsets; /* Offsets within each row buffer */ 59 stp_lineactive_t *lineactive; /* Does this line have anything printed? */ 60 stp_linecount_t *linecounts; /* How many rows we've printed this pass */ 61 stp_linebounds_t *linebounds; /* Starting and ending print column */ 62 stp_pass_t *passes; /* Circular list of pass numbers */ 63 int last_pass_offset; /* Starting row (offset from the start of */ 64 /* the page) of the most recently printed */ 65 /* pass (so we can determine how far to */ 66 /* advance the paper) */ 67 int last_pass; /* Number of the most recently printed pass */ 68 69 int jets; /* Number of jets per color */ 70 int virtual_jets; /* Number of jets per color, taking into */ 71 /* account the head offset */ 72 int separation; /* Offset from one jet to the next in rows */ 73 void *weaveparm; /* Weave calculation parameter block */ 74 75 int horizontal_weave; /* Number of horizontal passes required */ 76 /* This is > 1 for some of the ultra-high */ 77 /* resolution modes */ 78 int vertical_subpasses; /* Number of passes per line (for better */ 79 /* quality) */ 80 int vmod; /* Number of banks of passes */ 81 int oversample; /* Excess precision per row */ 82 int repeat_count; /* How many times a pass is repeated */ 83 int ncolors; /* How many colors */ 84 int linewidth; /* Line width in input pixels */ 85 int vertical_height; /* Image height in output pixels */ 86 int firstline; /* Actual first line (referenced to paper) */ 87 88 int bitwidth; /* Bits per pixel */ 89 int lineno; 90 int vertical_oversample; /* Vertical oversampling */ 91 int current_vertical_subpass; 92 int horizontal_width; /* Horizontal width, in bits */ 93 int *head_offset; /* offset of printheads */ 94 unsigned char *s[STP_MAX_WEAVE]; 95 unsigned char *fold_buf; 96 unsigned char *comp_buf; 97 stp_weave_t wcache; 98 int rcache; 99 int vcache; 100 stp_flushfunc *flushfunc; 101 stp_fillfunc *fillfunc; 102 stp_packfunc *pack; 103 stp_compute_linewidth_func *compute_linewidth; 104} stpi_softweave_t; 105 106/* RAW WEAVE */ 107 108typedef struct raw { 109 int separation; 110 int jets; 111 int oversampling; 112 int advancebasis; 113 int subblocksperpassblock; 114 int passespersubblock; 115 stp_weave_strategy_t strategy; 116 stp_vars_t *v; 117} raw_t; 118 119/* 120 * Strategy types currently defined: 121 * 122 * 0: zig-zag type pass block filling 123 * 1: ascending pass block filling 124 * 2: descending pass block filling 125 * 3: ascending fill with 2x expansion 126 * 4: staggered zig-zag neighbour-avoidance fill 127 * 5: ascending fill with 3x expansion 128 * 129 * In theory, strategy 0 should be optimal; in practice, it can lead 130 * to visible areas of banding. If it's necessary to avoid filling 131 * neighbouring rows in neighbouring passes, strategy 4 should be optimal, 132 * at least for some weaves. 133 */ 134 135static void 136initialize_raw_weave(raw_t *w, /* I - weave struct to be filled in */ 137 int separation, /* I - jet separation */ 138 int jets, /* I - number of jets */ 139 int oversample, /* I - oversampling factor */ 140 stp_weave_strategy_t strat, /* I - weave pattern variation to use */ 141 stp_vars_t *v) 142{ 143 w->separation = separation; 144 w->jets = jets; 145 w->oversampling = oversample; 146 w->advancebasis = jets / oversample; 147 if (w->advancebasis == 0) 148 w->advancebasis++; 149 w->subblocksperpassblock = gcd(separation, w->advancebasis); 150 w->passespersubblock = separation / w->subblocksperpassblock; 151 w->strategy = strat; 152 w->v = v; 153} 154 155static void 156calculate_raw_pass_parameters(raw_t *w, /* I - weave parameters */ 157 int pass, /* I - pass number ( >= 0) */ 158 int *startrow, /* O - print head position */ 159 int *subpass) /* O - subpass number */ 160{ 161 int band, passinband, subpassblock, subpassoffset; 162 163 band = pass / (w->separation * w->oversampling); 164 passinband = pass % (w->separation * w->oversampling); 165 subpassblock = pass % w->separation 166 * w->subblocksperpassblock / w->separation; 167 168 switch (w->strategy) { 169 case STP_WEAVE_ZIGZAG: 170 if (subpassblock * 2 < w->subblocksperpassblock) 171 subpassoffset = 2 * subpassblock; 172 else 173 subpassoffset = 2 * (w->subblocksperpassblock 174 - subpassblock) - 1; 175 break; 176 case STP_WEAVE_ASCENDING: 177 subpassoffset = subpassblock; 178 break; 179 case STP_WEAVE_DESCENDING: 180 subpassoffset = w->subblocksperpassblock - 1 - subpassblock; 181 break; 182 case STP_WEAVE_ASCENDING_2X: 183 if (subpassblock * 2 < w->subblocksperpassblock) 184 subpassoffset = 2 * subpassblock; 185 else 186 subpassoffset = 1 + 2 * (subpassblock 187 - (w->subblocksperpassblock 188 + 1) / 2); 189 break; 190 case STP_WEAVE_ASCENDING_3X: 191 if (subpassblock * 3 < w->subblocksperpassblock) 192 subpassoffset = 3 * subpassblock; 193 else if (3 * (subpassblock - (w->subblocksperpassblock + 2) / 3) 194 < w->subblocksperpassblock - 2) 195 subpassoffset = 2 + 3 * (subpassblock 196 - (w->subblocksperpassblock 197 + 2) / 3); 198 else 199 subpassoffset = 1 + 3 * (subpassblock 200 - (w->subblocksperpassblock 201 + 2) / 3 202 - w->subblocksperpassblock 203 / 3); 204 break; 205 case STP_WEAVE_STAGGERED: 206 if (subpassblock * 2 < w->subblocksperpassblock) 207 subpassoffset = 2 * subpassblock; 208 else if (subpassblock * 2 < w->subblocksperpassblock + 2) 209 subpassoffset = 1; 210 else 211 subpassoffset = 2 * (w->subblocksperpassblock 212 - subpassblock) + 1; 213 break; 214 default: 215 subpassoffset = subpassblock; 216 break; 217 } 218 219 *startrow = w->separation * w->jets * band 220 + w->advancebasis * passinband + subpassoffset; 221 *subpass = passinband / w->separation; 222} 223 224static void 225calculate_raw_row_parameters(raw_t *w, /* I - weave parameters */ 226 int row, /* I - row number */ 227 int subpass, /* I - subpass number */ 228 int *pass, /* O - pass number */ 229 int *jet, /* O - jet number in pass */ 230 int *startrow) /* O - starting row of pass */ 231{ 232 int subblockoffset, subpassblock, band, baserow, passinband, offset; 233 int pass_div_separation; 234 int pass_mod_separation; 235 int off_mod_separation; 236 237 subblockoffset = row % w->subblocksperpassblock; 238 switch (w->strategy) { 239 case STP_WEAVE_ZIGZAG: 240 if (subblockoffset % 2 == 0) 241 subpassblock = subblockoffset / 2; 242 else 243 subpassblock = w->subblocksperpassblock 244 - (subblockoffset + 1) / 2; 245 break; 246 case STP_WEAVE_ASCENDING: 247 subpassblock = subblockoffset; 248 break; 249 case STP_WEAVE_DESCENDING: 250 subpassblock = w->subblocksperpassblock - 1 - subblockoffset; 251 break; 252 case STP_WEAVE_ASCENDING_2X: 253 if (subblockoffset % 2 == 0) 254 subpassblock = subblockoffset / 2; 255 else 256 subpassblock = (subblockoffset - 1) / 2 257 + (w->subblocksperpassblock + 1) / 2; 258 break; 259 case STP_WEAVE_ASCENDING_3X: 260 if (subblockoffset % 3 == 0) 261 subpassblock = subblockoffset / 3; 262 else if (subblockoffset % 3 == 1) 263 subpassblock = (subblockoffset - 1) / 3 264 + (w->subblocksperpassblock + 2) / 3; 265 else 266 subpassblock = (subblockoffset - 2) / 3 267 + (w->subblocksperpassblock + 2) / 3 268 + (w->subblocksperpassblock + 1) / 3; 269 break; 270 case STP_WEAVE_STAGGERED: 271 if (subblockoffset % 2 == 0) 272 subpassblock = subblockoffset / 2; 273 else if (subblockoffset == 1) 274 subpassblock = (w->subblocksperpassblock + 1) / 2; 275 else 276 subpassblock = w->subblocksperpassblock 277 - (subblockoffset - 1) / 2; 278 break; 279 default: 280 subpassblock = subblockoffset; 281 break; 282 } 283 284 band = row / (w->separation * w->jets); 285 baserow = row - subblockoffset - band * w->separation * w->jets; 286 passinband = baserow / w->advancebasis; 287 offset = baserow % w->advancebasis; 288 pass_div_separation = passinband / w->separation; 289 pass_mod_separation = passinband % w->separation; 290 off_mod_separation = offset % w->separation; 291 292 while (off_mod_separation != 0 293 || pass_div_separation != subpass 294 || pass_mod_separation / w->passespersubblock 295 != subpassblock) 296 { 297 offset += w->advancebasis; 298 passinband--; 299 if (passinband >= 0) 300 { 301 pass_mod_separation--; 302 if (pass_mod_separation < 0) 303 { 304 pass_mod_separation += w->separation; 305 pass_div_separation--; 306 } 307 if (w->advancebasis < w->separation) 308 { 309 off_mod_separation += w->advancebasis; 310 if (off_mod_separation >= w->separation) 311 off_mod_separation -= w->separation; 312 } 313 else if (w->advancebasis > w->separation) 314 off_mod_separation = offset % w->separation; 315 } 316 else 317 { 318 const int roundedjets = 319 (w->advancebasis * w->oversampling) % w->jets; 320 band--; 321 passinband += w->separation * w->oversampling; 322 offset += w->separation * (w->jets - roundedjets); 323 pass_div_separation = passinband / w->separation; 324 pass_mod_separation = passinband % w->separation; 325 off_mod_separation = offset % w->separation; 326 } 327 } 328 329 *pass = band * w->oversampling * w->separation + passinband; 330 *jet = (offset / w->separation) % w->jets; 331 *startrow = row - (*jet * w->separation); 332} 333 334/* COOKED WEAVE */ 335 336typedef struct cooked { 337 raw_t rw; 338 int first_row_printed; 339 int last_row_printed; 340 341 int first_premapped_pass; /* First raw pass used by this page */ 342 int first_normal_pass; 343 int first_postmapped_pass; 344 int first_unused_pass; 345 346 int *pass_premap; 347 int *stagger_premap; 348 int *pass_postmap; 349 int *stagger_postmap; 350} cooked_t; 351 352typedef struct startmap { 353 int startrow; 354 int map; 355 int pos; /* Secondary key for stable sort */ 356} startmap_t; 357 358static int 359smap_compare(const void *p1, const void *p2) 360{ 361 const startmap_t *s1 = (const startmap_t *)p1; 362 const startmap_t *s2 = (const startmap_t *)p2; 363 if (s1->startrow < s2->startrow) 364 return -1; 365 else if (s1->startrow > s2->startrow) 366 return 1; 367 else if (s1->pos < s2->pos) 368 return -1; 369 else 370 return 1; 371} 372 373static void 374sort_by_start_row(int *map, int *startrows, int count) 375{ 376 startmap_t *smap = stp_malloc(sizeof(startmap_t) * count); 377 int i; 378 for (i = 0; i < count; i++) 379 { 380 smap[i].startrow = startrows[i]; 381 smap[i].map = map[i]; 382 smap[i].pos = i; 383 } 384 qsort(smap, count, sizeof(startmap_t), smap_compare); 385 for (i = 0; i < count; i++) 386 { 387 startrows[i] = smap[i].startrow; 388 map[i] = smap[i].map; 389 } 390 stp_free(smap); 391} 392 393static void 394calculate_stagger(raw_t *w, int *map, int *startrows_stagger, int count) 395{ 396 int i; 397 398 for (i = 0; i < count; i++) { 399 int startrow, subpass; 400 calculate_raw_pass_parameters(w, map[i], &startrow, &subpass); 401 startrow -= w->separation * w->jets; 402 startrows_stagger[i] = (startrows_stagger[i] - startrow) 403 / w->separation; 404 } 405} 406 407static void 408invert_map(int *map, int *stagger, int count, int oldfirstpass, 409 int newfirstpass) 410{ 411 int i; 412 int *newmap, *newstagger; 413 newmap = stp_malloc(count * sizeof(int)); 414 newstagger = stp_malloc(count * sizeof(int)); 415 416 for (i = 0; i < count; i++) { 417 newmap[map[i] - oldfirstpass] = i + newfirstpass; 418 newstagger[map[i] - oldfirstpass] = stagger[i]; 419 } 420 421 memcpy(map, newmap, count * sizeof(int)); 422 memcpy(stagger, newstagger, count * sizeof(int)); 423 stp_free(newstagger); 424 stp_free(newmap); 425} 426 427static void 428make_passmap(raw_t *w, int **map, int **starts, int first_pass_number, 429 int first_pass_to_map, int first_pass_after_map, 430 int first_pass_to_stagger, int first_pass_after_stagger, 431 int first_row_of_maximal_pass, int separations_to_distribute) 432{ 433 int *passmap, *startrows; 434 int passes_to_map = first_pass_after_map - first_pass_to_map; 435 int i; 436 437 STPI_ASSERT(first_pass_to_map <= first_pass_after_map, w->v); 438 STPI_ASSERT(first_pass_to_stagger <= first_pass_after_stagger, w->v); 439 440 *map = passmap = stp_malloc(passes_to_map * sizeof(int)); 441 *starts = startrows = stp_malloc(passes_to_map * sizeof(int)); 442 443 for (i = 0; i < passes_to_map; i++) { 444 int startrow, subpass; 445 int pass = i + first_pass_to_map; 446 calculate_raw_pass_parameters(w, pass, &startrow, &subpass); 447 passmap[i] = pass; 448 if (first_row_of_maximal_pass >= 0) 449 startrow = first_row_of_maximal_pass - startrow 450 + w->separation * w->jets; 451 else 452 startrow -= w->separation * w->jets; 453 while (startrow < 0) 454 startrow += w->separation; 455 startrows[i] = startrow; 456 } 457 458 sort_by_start_row(passmap, startrows, passes_to_map); 459 460 separations_to_distribute++; 461 462 for (i = 0; i < first_pass_after_stagger - first_pass_to_stagger; i++) { 463 int offset = first_pass_to_stagger - first_pass_to_map; 464 if (startrows[i + offset] / w->separation 465 < i % separations_to_distribute) 466 { 467 startrows[i + offset] 468 = startrows[i + offset] % w->separation 469 + w->separation * (i % separations_to_distribute); 470 } 471 } 472 473 if (first_row_of_maximal_pass >= 0) { 474 for (i = 0; i < passes_to_map; i++) { 475 startrows[i] = first_row_of_maximal_pass - startrows[i]; 476 } 477 } 478 479 sort_by_start_row(passmap, startrows, passes_to_map); 480 calculate_stagger(w, passmap, startrows, passes_to_map); 481 482 invert_map(passmap, startrows, passes_to_map, first_pass_to_map, 483 first_pass_to_map - first_pass_number); 484} 485 486static void 487calculate_pass_map(stp_vars_t *v, 488 cooked_t *w, /* I - weave parameters */ 489 int pageheight, /* I - number of rows on page */ 490 int firstrow, /* I - first printed row */ 491 int lastrow) /* I - last printed row */ 492{ 493 int startrow, subpass; 494 int pass = -1; 495 496 w->first_row_printed = firstrow; 497 w->last_row_printed = lastrow; 498 499 if (pageheight <= lastrow) 500 pageheight = lastrow + 1; 501 502 do { 503 calculate_raw_pass_parameters(&w->rw, ++pass, 504 &startrow, &subpass); 505 } while (startrow - w->rw.separation < firstrow); 506 507 w->first_premapped_pass = pass; 508 509 while (startrow < w->rw.separation * w->rw.jets 510 && startrow - w->rw.separation < pageheight 511 && startrow <= lastrow + w->rw.separation * w->rw.jets) 512 { 513 calculate_raw_pass_parameters(&w->rw, ++pass, 514 &startrow, &subpass); 515 } 516 w->first_normal_pass = pass; 517 518 while (startrow - w->rw.separation < pageheight 519 && startrow <= lastrow + w->rw.separation * w->rw.jets) 520 { 521 calculate_raw_pass_parameters(&w->rw, ++pass, 522 &startrow, &subpass); 523 } 524 w->first_postmapped_pass = pass; 525 526 while (startrow <= lastrow + w->rw.separation * w->rw.jets) { 527 calculate_raw_pass_parameters(&w->rw, ++pass, 528 &startrow, &subpass); 529 } 530 w->first_unused_pass = pass; 531 532 stp_dprintf(STP_DBG_WEAVE_PARAMS, v, 533 "first premapped %d first normal %d first postmapped %d " 534 "first unused %d\n", 535 w->first_premapped_pass, w->first_normal_pass, 536 w->first_postmapped_pass, w->first_unused_pass); 537 /* 538 * FIXME: make sure first_normal_pass doesn't advance beyond 539 * first_postmapped_pass, or first_postmapped_pass doesn't 540 * retreat before first_normal_pass. 541 */ 542 543 if (w->first_normal_pass > w->first_premapped_pass) { 544 int spread, separations_to_distribute, normal_passes_mapped; 545 separations_to_distribute = firstrow / w->rw.separation; 546 spread = (separations_to_distribute + 1) * w->rw.separation; 547 normal_passes_mapped = (spread + w->rw.advancebasis - 1) 548 / w->rw.advancebasis; 549 w->first_normal_pass += normal_passes_mapped; 550 make_passmap(&w->rw, &w->pass_premap, &w->stagger_premap, 551 w->first_premapped_pass, 552 w->first_premapped_pass, w->first_normal_pass, 553 w->first_premapped_pass, 554 w->first_normal_pass - normal_passes_mapped, 555 -1, separations_to_distribute); 556 } else { 557 w->pass_premap = 0; 558 w->stagger_premap = 0; 559 } 560 561 if (w->first_unused_pass >= w->first_postmapped_pass) { 562 int spread, separations_to_distribute, normal_passes_mapped; 563 separations_to_distribute = (pageheight - lastrow - 1) 564 / w->rw.separation; 565 spread = (separations_to_distribute + 1) * w->rw.separation; 566 normal_passes_mapped = (spread + w->rw.advancebasis) 567 / w->rw.advancebasis; 568 w->first_postmapped_pass -= normal_passes_mapped; 569 make_passmap(&w->rw, &w->pass_postmap, &w->stagger_postmap, 570 w->first_premapped_pass, 571 w->first_postmapped_pass, w->first_unused_pass, 572 w->first_postmapped_pass + normal_passes_mapped, 573 w->first_unused_pass, 574 pageheight - 1 575 - w->rw.separation * (w->rw.jets - 1), 576 separations_to_distribute); 577 } else { 578 w->pass_postmap = 0; 579 w->stagger_postmap = 0; 580 } 581} 582 583static void * /* O - weave parameter block */ 584initialize_weave_params(int separation, /* I - jet separation */ 585 int jets, /* I - number of jets */ 586 int oversample, /* I - oversampling factor */ 587 int firstrow, /* I - first row number to print */ 588 int lastrow, /* I - last row number to print */ 589 int pageheight, /* I - number of rows on the whole 590 page, without using any 591 expanded margin facilities */ 592 stp_weave_strategy_t strategy, /* I - weave pattern variant to use */ 593 stp_vars_t *v) 594{ 595 cooked_t *w = stp_malloc(sizeof(cooked_t)); 596 if (w) { 597 initialize_raw_weave(&w->rw, separation, jets, oversample, strategy, v); 598 calculate_pass_map(v, w, pageheight, firstrow, lastrow); 599 } 600 return w; 601} 602 603static void 604stpi_destroy_weave_params(void *vw) 605{ 606 cooked_t *w = (cooked_t *) vw; 607 608 if (w->pass_premap) stp_free(w->pass_premap); 609 if (w->stagger_premap) stp_free(w->stagger_premap); 610 if (w->pass_postmap) stp_free(w->pass_postmap); 611 if (w->stagger_postmap) stp_free(w->stagger_postmap); 612 stp_free(w); 613} 614 615static void 616stpi_calculate_row_parameters(void *vw, /* I - weave parameters */ 617 int row, /* I - row number */ 618 int subpass, /* I - subpass */ 619 int *pass, /* O - pass containing row */ 620 int *jetnum, /* O - jet number of row */ 621 int *startingrow, /* O - phys start of pass */ 622 int *ophantomrows, /* O - missing rows @ start */ 623 int *ojetsused) /* O - jets used by pass */ 624{ 625 cooked_t *w = (cooked_t *) vw; 626 int raw_pass, jet, startrow, phantomrows, jetsused; 627 int stagger = 0; 628 int extra; 629 630 STPI_ASSERT(row >= w->first_row_printed, w->rw.v); 631 STPI_ASSERT(row <= w->last_row_printed, w->rw.v); 632 calculate_raw_row_parameters(&w->rw, 633 row + w->rw.separation * w->rw.jets, 634 subpass, &raw_pass, &jet, &startrow); 635 startrow -= w->rw.separation * w->rw.jets; 636 jetsused = w->rw.jets; 637 phantomrows = 0; 638 639 if (raw_pass < w->first_normal_pass) { 640 STPI_ASSERT(raw_pass >= w->first_premapped_pass, w->rw.v); 641 *pass = w->pass_premap[raw_pass - w->first_premapped_pass]; 642 stagger = w->stagger_premap[raw_pass - w->first_premapped_pass]; 643 } else if (raw_pass >= w->first_postmapped_pass) { 644 STPI_ASSERT(raw_pass >= w->first_postmapped_pass, w->rw.v); 645 *pass = w->pass_postmap[raw_pass - w->first_postmapped_pass]; 646 stagger = w->stagger_postmap[raw_pass 647 - w->first_postmapped_pass]; 648 } else { 649 *pass = raw_pass - w->first_premapped_pass; 650 } 651 652 startrow += stagger * w->rw.separation; 653 *jetnum = jet - stagger; 654 if (stagger < 0) { 655 stagger = -stagger; 656 phantomrows += stagger; 657 } 658 jetsused -= stagger; 659 660 extra = w->first_row_printed 661 - (startrow + w->rw.separation * phantomrows); 662 if (extra > 0) { 663 extra = (extra + w->rw.separation - 1) / w->rw.separation; 664 jetsused -= extra; 665 phantomrows += extra; 666 } 667 668 extra = startrow + w->rw.separation * (phantomrows + jetsused - 1) 669 - w->last_row_printed; 670 if (extra > 0) { 671 extra = (extra + w->rw.separation - 1) / w->rw.separation; 672 jetsused -= extra; 673 } 674 675 *startingrow = startrow; 676 *ophantomrows = phantomrows; 677 *ojetsused = jetsused; 678} 679 680/* 681 * "Soft" weave 682 * 683 * The Epson Stylus Color/Photo printers don't have memory to print 684 * using all of the nozzles in the print head. For example, the Stylus Photo 685 * 700/EX has 32 nozzles. At 720 dpi, with an 8" wide image, a single line 686 * requires (8 * 720 * 6 / 8) bytes, or 4320 bytes (because the Stylus Photo 687 * printers have 6 ink colors). To use 32 nozzles would require 138240 bytes. 688 * It's actually worse than that, though, because the nozzles are spaced 8 689 * rows apart. Therefore, in order to store enough data to permit sending the 690 * page as a simple raster, the printer would require enough memory to store 691 * 256 rows, or 1105920 bytes. Considering that the Photo EX can print 692 * 11" wide, we're looking at more like 1.5 MB. In fact, these printers are 693 * capable of 1440 dpi horizontal resolution. This would require 3 MB. The 694 * printers actually have 64K-256K. 695 * 696 * With the newer (740/750 and later) printers it's even worse, since these 697 * printers support multiple dot sizes. But that's neither here nor there. 698 * 699 * Older Epson printers had a mode called MicroWeave (tm). In this mode, the 700 * host fed the printer individual rows of dots, and the printer bundled them 701 * up and sent them to the print head in the correct order to achieve high 702 * quality. This MicroWeave mode still works in new printers, but the 703 * implementation is very minimal: the printer uses exactly one nozzle of 704 * each color (the first one). This makes printing extremely slow (more than 705 * 30 minutes for one 8.5x11" page), although the quality is extremely high 706 * with no visible banding whatsoever. It's not good for the print head, 707 * though, since no ink is flowing through the other nozzles. This leads to 708 * drying of ink and possible permanent damage to the print head. 709 * 710 * By the way, although the Epson manual says that microweave mode should be 711 * used at 720 dpi, 360 dpi continues to work in much the same way. At 360 712 * dpi, data is fed to the printer one row at a time on all Epson printers. 713 * The pattern that the printer uses to print is very prone to banding. 714 * However, 360 dpi is inherently a low quality mode; if you're using it, 715 * presumably you don't much care about quality. 716 * 717 * Printers from roughly the Stylus Color 600 and later do not have the 718 * capability to do MicroWeave correctly. Instead, the host must arrange 719 * the output in the order that it will be sent to the print head. This 720 * is a very complex process; the jets in the print head are spaced more 721 * than one row (1/720") apart, so we can't simply send consecutive rows 722 * of dots to the printer. Instead, we have to pass e. g. the first, ninth, 723 * 17th, 25th... rows in order for them to print in the correct position on 724 * the paper. This interleaving process is called "soft" weaving. 725 * 726 * This decision was probably made to save money on memory in the printer. 727 * It certainly makes the driver code far more complicated than it would 728 * be if the printer could arrange the output. Is that a bad thing? 729 * Usually this takes far less CPU time than the dithering process, and it 730 * does allow us more control over the printing process, e. g. to reduce 731 * banding. Conceivably, we could even use this ability to map out bad 732 * jets. 733 * 734 * Interestingly, apparently the Windows (and presumably Macintosh) drivers 735 * for most or all Epson printers still list a "microweave" mode. 736 * Experiments have demonstrated that this does not in fact use the 737 * "microweave" mode of the printer. Possibly it does nothing, or it uses 738 * a different weave pattern from what the non-"microweave" mode does. 739 * This is unnecessarily confusing. 740 * 741 * What makes this interesting is that there are many different ways of 742 * of accomplishing this goal. The naive way would be to divide the image 743 * up into groups of 256 rows, and print all the mod8=0 rows in the first pass, 744 * mod8=1 rows in the second, and so forth. The problem with this approach 745 * is that the individual ink jets are not perfectly uniform; some emit 746 * slightly bigger or smaller drops than others. Since each group of 8 747 * adjacent rows is printed with the same nozzle, that means that there will 748 * be distinct streaks of lighter and darker bands within the image (8 rows 749 * is 1/90", which is visible; 1/720" is not). Possibly worse is that these 750 * patterns will repeat every 256 rows. This creates banding patterns that 751 * are about 1/3" wide. 752 * 753 * So we have to do something to break up this patterning. 754 * 755 * Epson does not publish the weaving algorithms that they use in their 756 * bundled drivers. Indeed, their developer web site 757 * (http://www.ercipd.com/isv/edr_docs.htm) does not even describe how to 758 * do this weaving at all; it says that the only way to achieve 720 dpi 759 * is to use MicroWeave. It does note (correctly) that 1440 dpi horizontal 760 * can only be achieved by the driver (i. e. in software). The manual 761 * actually makes it fairly clear how to do this (it requires two passes 762 * with horizontal head movement between passes), and it is presumably 763 * possible to do this with MicroWeave. 764 * 765 * The information about how to do this is apparently available under NDA. 766 * It's actually easy enough to reverse engineer what's inside a print file 767 * with a simple Perl script. There are presumably other printer commands 768 * that are not documented and may not be as easy to reverse engineer. 769 * 770 * I considered a few algorithms to perform the weave. The first one I 771 * devised let me use only (jets - distance_between_jets + 1) nozzles, or 772 * 25. This is OK in principle, but it's slower than using all nozzles. 773 * By playing around with it some more, I came up with an algorithm that 774 * lets me use all of the nozzles, except near the top and bottom of the 775 * page. 776 * 777 * This still produces some banding, though. Even better quality can be 778 * achieved by using multiple nozzles on the same line. How do we do this? 779 * In 1440x720 mode, we're printing two output lines at the same vertical 780 * position. However, if we want four passes, we have to effectively print 781 * each line twice. Actually doing this would increase the density, so 782 * what we do is print half the dots on each pass. This produces near-perfect 783 * output, and it's far faster than using (pseudo) "MicroWeave". 784 * 785 * The current algorithm is not completely general. The number of passes 786 * is limited to (nozzles / gap). On the Photo EX class printers, that limits 787 * it to 4 -- 32 nozzles, an inter-nozzle gap of 8 lines. Furthermore, there 788 * are a number of routines that are only coded up to 8 passes. Fortunately, 789 * this is enough passes to get rid of most banding. What's left is a very 790 * fine pattern that is sometimes described as "corduroy", since the pattern 791 * looks like that kind of fabric. 792 * 793 * Newer printers (those that support variable dot sizes, such as the 740, 794 * 1200, etc.) have an additional complication: when used in softweave mode, 795 * they operate at 360 dpi horizontal resolution. This requires FOUR passes 796 * to achieve 1440x720 dpi. Thus, to enable us to break up each row 797 * into separate sub-rows, we have to actually print each row eight times. 798 * Fortunately, all such printers have 48 nozzles and a gap of 6 rows, 799 * except for the high-speed 900, which uses 96 nozzles and a gap of 2 rows. 800 * 801 * I cannot let this entirely pass without commenting on the Stylus Color 440. 802 * This is a very low-end printer with 21 (!) nozzles and a separation of 8. 803 * The weave routine works correctly with single-pass printing, which is enough 804 * to minimally achieve 720 dpi output (it's physically a 720 dpi printer). 805 * However, the routine does not work correctly at more than one pass per row. 806 * Therefore, this printer bands badly. 807 * 808 * Yet another complication is how to get near the top and bottom of the page. 809 * This algorithm lets us print to within one head width of the top of the 810 * page, and a bit more than one head width from the bottom. That leaves a 811 * lot of blank space. Doing the weave properly outside of this region is 812 * increasingly difficult as we get closer to the edge of the paper; in the 813 * interior region, any nozzle can print any line, but near the top and 814 * bottom edges, only some nozzles can print. We've handled this for now by 815 * using the naive way mentioned above near the borders, and switching over 816 * to the high quality method in the interior. Unfortunately, this means 817 * that the quality is quite visibly degraded near the top and bottom of the 818 * page. Algorithms that degrade more gracefully are more complicated. 819 * Epson does not advertise that the printers can print at the very top of the 820 * page, although in practice most or all of them can. I suspect that the 821 * quality that can be achieved very close to the top is poor enough that 822 * Epson does not want to allow printing there. That is a valid decision, 823 * although we have taken another approach. 824 * 825 * To compute the weave information, we need to start with the following 826 * information: 827 * 828 * 1) The number of jets the print head has for each color; 829 * 830 * 2) The separation in rows between the jets; 831 * 832 * 3) The horizontal resolution of the printer; 833 * 834 * 4) The desired horizontal resolution of the output; 835 * 836 * 5) The desired extra passes to reduce banding. 837 * 838 * As discussed above, each row is actually printed in one or more passes 839 * of the print head; we refer to these as subpasses. For example, if we're 840 * printing at 1440(h)x720(v) on a printer with true horizontal resolution of 841 * 360 dpi, and we wish to print each line twice with different nozzles 842 * to reduce banding, we need to use 8 subpasses. The dither routine 843 * will feed us a complete row of bits for each color; we have to split that 844 * up, first by round robining the bits to ensure that they get printed at 845 * the right micro-position, and then to split up the bits that are actually 846 * turned on into two equal chunks to reduce banding. 847 * 848 * Given the above information, and the desired row index and subpass (which 849 * together form a line number), we can compute: 850 * 851 * 1) Which pass this line belongs to. Passes are numbered consecutively, 852 * and each pass must logically (see #3 below) start at no smaller a row 853 * number than the previous pass, as the printer cannot advance by a 854 * negative amount. 855 * 856 * 2) Which jet will print this line. 857 * 858 * 3) The "logical" first line of this pass. That is, what line would be 859 * printed by jet 0 in this pass. This number may be less than zero. 860 * If it is, there are ghost lines that don't actually contain any data. 861 * The difference between the logical first line of this pass and the 862 * logical first line of the preceding pass tells us how many lines must 863 * be advanced. 864 * 865 * 4) The "physical" first line of this pass. That is, the first line index 866 * that is actually printed in this pass. This information lets us know 867 * when we must prepare this pass. 868 * 869 * 5) The last line of this pass. This lets us know when we must actually 870 * send this pass to the printer. 871 * 872 * 6) The number of ghost rows this pass contains. We must still send the 873 * ghost data to the printer, so this lets us know how much data we must 874 * fill in prior to the start of the pass. 875 * 876 * The bookkeeping to keep track of all this stuff is quite hairy, and needs 877 * to be documented separately. 878 * 879 * The routine initialize_weave calculates the basic parameters, given 880 * the number of jets and separation between jets, in rows. 881 * 882 * -- Robert Krawitz <rlk@alum.mit.edu) November 3, 1999 883 */ 884 885static stp_lineoff_t * 886allocate_lineoff(int count, int ncolors) 887{ 888 int i; 889 stp_lineoff_t *retval = stp_malloc(count * sizeof(stp_lineoff_t)); 890 for (i = 0; i < count; i++) 891 { 892 retval[i].ncolors = ncolors; 893 retval[i].v = stp_zalloc(ncolors * sizeof(unsigned long)); 894 } 895 return (retval); 896} 897 898static stp_lineactive_t * 899allocate_lineactive(int count, int ncolors) 900{ 901 int i; 902 stp_lineactive_t *retval = stp_malloc(count * sizeof(stp_lineactive_t)); 903 for (i = 0; i < count; i++) 904 { 905 retval[i].ncolors = ncolors; 906 retval[i].v = stp_zalloc(ncolors * sizeof(char)); 907 } 908 return (retval); 909} 910 911static stp_linecount_t * 912allocate_linecount(int count, int ncolors) 913{ 914 int i; 915 stp_linecount_t *retval = stp_malloc(count * sizeof(stp_linecount_t)); 916 for (i = 0; i < count; i++) 917 { 918 retval[i].ncolors = ncolors; 919 retval[i].v = stp_zalloc(ncolors * sizeof(int)); 920 } 921 return (retval); 922} 923 924static stp_linebounds_t * 925allocate_linebounds(int count, int ncolors) 926{ 927 int i; 928 stp_linebounds_t *retval = stp_malloc(count * sizeof(stp_linebounds_t)); 929 for (i = 0; i < count; i++) 930 { 931 retval[i].ncolors = ncolors; 932 retval[i].start_pos = stp_zalloc(ncolors * sizeof(int)); 933 retval[i].end_pos = stp_zalloc(ncolors * sizeof(int)); 934 } 935 return (retval); 936} 937 938static stp_linebufs_t * 939allocate_linebuf(int count, int ncolors) 940{ 941 int i; 942 stp_linebufs_t *retval = stp_malloc(count * sizeof(stp_linebufs_t)); 943 for (i = 0; i < count; i++) 944 { 945 retval[i].ncolors = ncolors; 946 retval[i].v = stp_zalloc(ncolors * sizeof(unsigned char *)); 947 } 948 return (retval); 949} 950 951/* 952 * Initialize the weave parameters 953 * 954 * Rules: 955 * 956 * 1) Currently, osample * v_subpasses * v_subsample <= 8, and no one 957 * of these variables may exceed 4. 958 * 959 * 2) first_line >= 0 960 * 961 * 3) line_height < physlines 962 * 963 * 4) page_height >= 2 * jets * sep 964 */ 965 966static void 967stpi_destroy_weave(void *vsw) 968{ 969 int i, j; 970 stpi_softweave_t *sw = (stpi_softweave_t *) vsw; 971 stp_free(sw->passes); 972 if (sw->fold_buf) 973 stp_free(sw->fold_buf); 974 if (sw->comp_buf) 975 stp_free(sw->comp_buf); 976 for (i = 0; i < STP_MAX_WEAVE; i++) 977 if (sw->s[i]) 978 stp_free(sw->s[i]); 979 for (i = 0; i < sw->vmod; i++) 980 { 981 for (j = 0; j < sw->ncolors; j++) 982 { 983 if (sw->linebases[i].v[j]) 984 stp_free(sw->linebases[i].v[j]); 985 } 986 stp_free(sw->linecounts[i].v); 987 stp_free(sw->linebases[i].v); 988 stp_free(sw->lineactive[i].v); 989 stp_free(sw->lineoffsets[i].v); 990 stp_free(sw->linebounds[i].start_pos); 991 stp_free(sw->linebounds[i].end_pos); 992 } 993 stp_free(sw->linecounts); 994 stp_free(sw->lineactive); 995 stp_free(sw->lineoffsets); 996 stp_free(sw->linebases); 997 stp_free(sw->linebounds); 998 stp_free(sw->head_offset); 999 stpi_destroy_weave_params(sw->weaveparm); 1000 stp_free(vsw); 1001} 1002 1003void 1004stp_initialize_weave(stp_vars_t *v, 1005 int jets, /* Width of print head */ 1006 int sep, /* Separation in rows between jets */ 1007 int osample, /* Horizontal oversample */ 1008 int v_subpasses, /* Vertical passes */ 1009 int v_subsample, /* Vertical oversampling */ 1010 int ncolors, 1011 int bitwidth, /* bits/pixel */ 1012 int linewidth, /* Width of a line, in pixels */ 1013 int line_count, /* Lines that will be printed */ 1014 int first_line, /* First line that will be printed */ 1015 int page_height, /* Total height of the page in rows */ 1016 const int *head_offset, 1017 stp_weave_strategy_t weave_strategy, 1018 stp_flushfunc flushfunc, 1019 stp_fillfunc fillfunc, 1020 stp_packfunc pack, 1021 stp_compute_linewidth_func compute_linewidth) 1022{ 1023 int i; 1024 int last_line, maxHeadOffset; 1025 stpi_softweave_t *sw = stp_zalloc(sizeof (stpi_softweave_t)); 1026 1027 if (jets < 1) 1028 jets = 1; 1029 if (jets == 1 || sep < 1) 1030 sep = 1; 1031 if (v_subpasses < 1) 1032 v_subpasses = 1; 1033 if (v_subsample < 1) 1034 v_subsample = 1; 1035 1036 sw->separation = sep; 1037 sw->jets = jets; 1038 sw->horizontal_weave = osample; 1039 sw->oversample = osample * v_subpasses * v_subsample; 1040 if (sw->oversample > jets) 1041 { 1042 int found = 0; 1043 for (i = 2; i <= osample; i++) 1044 { 1045 if ((osample % i == 0) && (sw->oversample / i <= jets)) 1046 { 1047 sw->repeat_count = i; 1048 osample /= i; 1049 found = 1; 1050 break; 1051 } 1052 } 1053 if (!found) 1054 { 1055 stp_eprintf(v, "Weave error: oversample (%d) > jets (%d)\n", 1056 sw->oversample, jets); 1057 stp_free(sw); 1058 return; 1059 } 1060 } 1061 else 1062 sw->repeat_count = 1; 1063 1064 sw->vertical_oversample = v_subsample; 1065 sw->vertical_subpasses = v_subpasses; 1066 sw->oversample = osample * v_subpasses * v_subsample; 1067 sw->firstline = first_line; 1068 sw->lineno = first_line; 1069 sw->flushfunc = flushfunc; 1070 1071 if (sw->oversample > jets) 1072 { 1073 stp_eprintf(v, "Weave error: oversample (%d) > jets (%d)\n", 1074 sw->oversample, jets); 1075 stp_free(sw); 1076 return; 1077 } 1078 1079 /* 1080 * setup printhead offsets. 1081 * for monochrome (bw) printing, the offsets are 0. 1082 */ 1083 sw->head_offset = stp_zalloc(ncolors * sizeof(int)); 1084 if (ncolors > 1) 1085 for(i = 0; i < ncolors; i++) 1086 sw->head_offset[i] = head_offset[i]; 1087 1088 maxHeadOffset = 0; 1089 for (i = 0; i < ncolors; i++) 1090 if (sw->head_offset[i] > maxHeadOffset) 1091 maxHeadOffset = sw->head_offset[i]; 1092 1093 sw->virtual_jets = sw->jets; 1094 if (maxHeadOffset > 0) 1095 sw->virtual_jets += (maxHeadOffset + sw->separation - 1) / sw->separation; 1096 last_line = first_line + line_count - 1 + maxHeadOffset; 1097 1098 sw->weaveparm = initialize_weave_params(sw->separation, sw->jets, 1099 sw->oversample, first_line, last_line, 1100 page_height, weave_strategy, v); 1101 /* 1102 * The value of vmod limits how many passes may be unfinished at a time. 1103 * If pass x is not yet printed, pass x+vmod cannot be started. 1104 * 1105 * The multiplier of 2: 1 for the normal passes, 1 for the special passes 1106 * at the start or end. 1107 */ 1108 sw->vmod = 2 * sw->separation * sw->oversample * sw->repeat_count; 1109 if (sw->virtual_jets > sw->jets) 1110 sw->vmod *= (sw->virtual_jets + sw->jets - 1) / sw->jets; 1111 1112 sw->bitwidth = bitwidth; 1113 sw->last_pass_offset = 0; 1114 sw->last_pass = -1; 1115 sw->current_vertical_subpass = 0; 1116 sw->ncolors = ncolors; 1117 sw->linewidth = linewidth; 1118 sw->vertical_height = line_count; 1119 sw->lineoffsets = allocate_lineoff(sw->vmod, ncolors); 1120 sw->lineactive = allocate_lineactive(sw->vmod, ncolors); 1121 sw->linebases = allocate_linebuf(sw->vmod, ncolors); 1122 sw->linebounds = allocate_linebounds(sw->vmod, ncolors); 1123 sw->passes = stp_zalloc(sw->vmod * sizeof(stp_pass_t)); 1124 sw->linecounts = allocate_linecount(sw->vmod, ncolors); 1125 sw->rcache = -2; 1126 sw->vcache = -2; 1127 sw->fillfunc = fillfunc; 1128 sw->compute_linewidth = compute_linewidth; 1129 sw->pack = pack; 1130 sw->horizontal_width = 1131 (sw->compute_linewidth)(v, ((sw->linewidth + sw->horizontal_weave - 1) / 1132 sw->horizontal_weave)); 1133 stp_dprintf(STP_DBG_WEAVE_PARAMS, v, 1134 "Computing linewidth for linewidth %d weave %d => %d (%d)\n", 1135 sw->linewidth, sw->horizontal_weave, sw->horizontal_width, 1136 ((sw->horizontal_width + 7) / 8)); 1137 sw->horizontal_width = ((sw->horizontal_width + 7) / 8); 1138 1139 for (i = 0; i < sw->vmod; i++) 1140 { 1141 int j; 1142 sw->passes[i].pass = -1; 1143 for (j = 0; j < sw->ncolors; j++) 1144 { 1145 sw->linebases[i].v[j] = NULL; 1146 } 1147 } 1148 stp_dprintf(STP_DBG_WEAVE_PARAMS, v, 1149 "Weave parameters: separation %d jets %d (%d) h %d v %d v_sub %d\n", 1150 sw->separation, sw->jets, sw->virtual_jets, osample, 1151 v_subpasses, v_subsample); 1152 stp_dprintf(STP_DBG_WEAVE_PARAMS, v, 1153 " ncolors %d bpp %d width %d (%d) line_count %d first %d last %d max_offset %d\n", 1154 sw->ncolors, sw->bitwidth, linewidth, sw->horizontal_width, 1155 sw->vertical_height, first_line, last_line, maxHeadOffset); 1156 stp_dprintf(STP_DBG_WEAVE_PARAMS, v, 1157 " oversample %d line buffer count %d total buffer %d, page_height %d\n", 1158 sw->oversample, sw->vmod, 1159 sw->vmod * sw->virtual_jets * sw->bitwidth * 1160 sw->ncolors * sw->horizontal_width, page_height); 1161 stp_dprintf(STP_DBG_WEAVE_PARAMS, v, 1162 " ***Buffer limit %d (vj %d bw %d hw %d)\n", 1163 sw->virtual_jets * sw->bitwidth * sw->horizontal_width, 1164 sw->virtual_jets, sw->bitwidth, sw->horizontal_width); 1165 stp_allocate_component_data(v, "Weave", NULL, stpi_destroy_weave, sw); 1166 return; 1167} 1168 1169static void 1170weave_parameters_by_row(const stp_vars_t *v, stpi_softweave_t *sw, 1171 int row, int vertical_subpass, stp_weave_t *w) 1172{ 1173 int jetsused; 1174 int sub_repeat_count = vertical_subpass % sw->repeat_count; 1175 /* 1176 * Conceptually, this does not modify the softweave state. We cache 1177 * the results, but this cache is considered hidden. 1178 */ 1179 vertical_subpass /= sw->repeat_count; 1180 1181 if (sw->rcache == row && sw->vcache == vertical_subpass) 1182 { 1183 memcpy(w, &sw->wcache, sizeof(stp_weave_t)); 1184 w->pass = (w->pass * sw->repeat_count) + sub_repeat_count; 1185 return; 1186 } 1187 sw->rcache = row; 1188 sw->vcache = vertical_subpass; 1189 1190 w->row = row; 1191 stpi_calculate_row_parameters(sw->weaveparm, row, vertical_subpass, 1192 &w->pass, &w->jet, &w->logicalpassstart, 1193 &w->missingstartrows, &jetsused); 1194 1195 w->physpassstart = w->logicalpassstart + sw->separation * w->missingstartrows; 1196 w->physpassend = w->physpassstart + sw->separation * (jetsused - 1); 1197 1198 memcpy(&(sw->wcache), w, sizeof(stp_weave_t)); 1199 w->pass = (w->pass * sw->repeat_count) + sub_repeat_count; 1200 stp_dprintf(STP_DBG_ROWS, v, "row %d, jet %d of pass %d " 1201 "(pos %d, start %d, end %d, missing rows %d)\n", 1202 w->row, w->jet, w->pass, w->logicalpassstart, w->physpassstart, 1203 w->physpassend, w->missingstartrows); 1204} 1205 1206static stpi_softweave_t * 1207get_sw(const stp_vars_t *v) 1208{ 1209 return (stpi_softweave_t *) stp_get_component_data(v, "Weave"); 1210} 1211 1212void 1213stp_weave_parameters_by_row(const stp_vars_t *v, int row, 1214 int vertical_subpass, stp_weave_t *w) 1215{ 1216 stpi_softweave_t *sw = get_sw(v); 1217 weave_parameters_by_row(v, sw, row, vertical_subpass, w); 1218} 1219 1220 1221static stp_lineoff_t * 1222stpi_get_lineoffsets(const stp_vars_t *v, stpi_softweave_t *sw, 1223 int row, int subpass, int offset) 1224{ 1225 stp_weave_t w; 1226 weave_parameters_by_row(v, sw, row + offset, subpass, &w); 1227 return &(sw->lineoffsets[w.pass % sw->vmod]); 1228} 1229 1230static stp_lineactive_t * 1231stpi_get_lineactive(const stp_vars_t *v, stpi_softweave_t *sw, 1232 int row, int subpass, int offset) 1233{ 1234 stp_weave_t w; 1235 weave_parameters_by_row(v, sw, row + offset, subpass, &w); 1236 return &(sw->lineactive[w.pass % sw->vmod]); 1237} 1238 1239static stp_linecount_t * 1240stpi_get_linecount(const stp_vars_t *v, stpi_softweave_t *sw, 1241 int row, int subpass, int offset) 1242{ 1243 stp_weave_t w; 1244 weave_parameters_by_row(v, sw, row + offset, subpass, &w); 1245 return &(sw->linecounts[w.pass % sw->vmod]); 1246} 1247 1248static stp_linebufs_t * 1249stpi_get_linebases(const stp_vars_t *v, stpi_softweave_t *sw, 1250 int row, int subpass, int offset) 1251{ 1252 stp_weave_t w; 1253 weave_parameters_by_row(v, sw, row + offset, subpass, &w); 1254 return &(sw->linebases[w.pass % sw->vmod]); 1255} 1256 1257static stp_linebounds_t * 1258stpi_get_linebounds(const stp_vars_t *v, stpi_softweave_t *sw, 1259 int row, int subpass, int offset) 1260{ 1261 stp_weave_t w; 1262 weave_parameters_by_row(v, sw, row + offset, subpass, &w); 1263 return &(sw->linebounds[w.pass % sw->vmod]); 1264} 1265 1266static stp_pass_t * 1267stpi_get_pass_by_row(stp_vars_t *v, stpi_softweave_t *sw, 1268 int row, int subpass,int offset) 1269{ 1270 stp_weave_t w; 1271 weave_parameters_by_row(v, sw, row + offset, subpass, &w); 1272 return &(sw->passes[w.pass % sw->vmod]); 1273} 1274 1275stp_lineoff_t * 1276stp_get_lineoffsets_by_pass(const stp_vars_t *v, int pass) 1277{ 1278 const stpi_softweave_t *sw = get_sw(v); 1279 return &(sw->lineoffsets[pass % sw->vmod]); 1280} 1281 1282stp_lineactive_t * 1283stp_get_lineactive_by_pass(const stp_vars_t *v, int pass) 1284{ 1285 const stpi_softweave_t *sw = get_sw(v); 1286 return &(sw->lineactive[pass % sw->vmod]); 1287} 1288 1289stp_linecount_t * 1290stp_get_linecount_by_pass(const stp_vars_t *v, int pass) 1291{ 1292 const stpi_softweave_t *sw = get_sw(v); 1293 return &(sw->linecounts[pass % sw->vmod]); 1294} 1295 1296const stp_linebufs_t * 1297stp_get_linebases_by_pass(const stp_vars_t *v, int pass) 1298{ 1299 const stpi_softweave_t *sw = get_sw(v); 1300 return &(sw->linebases[pass % sw->vmod]); 1301} 1302 1303stp_pass_t * 1304stp_get_pass_by_pass(const stp_vars_t *v, int pass) 1305{ 1306 const stpi_softweave_t *sw = get_sw(v); 1307 return &(sw->passes[pass % sw->vmod]); 1308} 1309 1310static void 1311check_linebases(stp_vars_t *v, stpi_softweave_t *sw, 1312 int row, int cpass, int head_offset, int color) 1313{ 1314 stp_linebufs_t *bufs = 1315 (stp_linebufs_t *) stpi_get_linebases(v, sw, row, cpass, head_offset); 1316 if (!(bufs->v[color])) 1317 bufs->v[color] = 1318 stp_zalloc (sw->virtual_jets * sw->bitwidth * sw->horizontal_width); 1319} 1320 1321/* 1322 * If there are phantom rows at the beginning of a pass, fill them in so 1323 * that the printer knows exactly what it doesn't have to print. We're 1324 * using RLE compression here. Each line must be specified independently, 1325 * so we have to compute how many full blocks (groups of 128 bytes, or 1024 1326 * "off" pixels) and how much leftover is needed. Note that we can only 1327 * RLE-encode groups of 2 or more bytes; single bytes must be specified 1328 * with a count of 1. 1329 */ 1330 1331void 1332stp_fill_tiff(stp_vars_t *v, int row, int subpass, 1333 int width, int missingstartrows, int color) 1334{ 1335 stpi_softweave_t *sw = get_sw(v); 1336 stp_lineoff_t *lineoffs; 1337 stp_linecount_t *linecount; 1338 const stp_linebufs_t *bufs; 1339 int i = 0; 1340 int k = 0; 1341 1342 width = sw->bitwidth * width * 8; 1343 for (k = 0; k < missingstartrows; k++) 1344 { 1345 int bytes_to_fill = width; 1346 int full_blocks = bytes_to_fill / (128 * 8); 1347 int leftover = (7 + (bytes_to_fill % (128 * 8))) / 8; 1348 int l = 0; 1349 bufs = stpi_get_linebases(v, sw, row, subpass, sw->head_offset[color]); 1350 1351 while (l < full_blocks) 1352 { 1353 (bufs->v[color][2 * i]) = 129; 1354 (bufs->v[color][2 * i + 1]) = 0; 1355 i++; 1356 l++; 1357 } 1358 if (leftover == 1) 1359 { 1360 (bufs->v[color][2 * i]) = 1; 1361 (bufs->v[color][2 * i + 1]) = 0; 1362 i++; 1363 } 1364 else if (leftover > 0) 1365 { 1366 (bufs->v[color][2 * i]) = 257 - leftover; 1367 (bufs->v[color][2 * i + 1]) = 0; 1368 i++; 1369 } 1370 } 1371 1372 lineoffs = stpi_get_lineoffsets(v, sw, row, subpass, sw->head_offset[color]); 1373 linecount = stpi_get_linecount(v, sw, row, subpass, sw->head_offset[color]); 1374 lineoffs->v[color] = 2 * i; 1375 linecount->v[color] = missingstartrows; 1376} 1377 1378void 1379stp_fill_uncompressed(stp_vars_t *v, int row, int subpass, 1380 int width, int missingstartrows, int color) 1381{ 1382 stpi_softweave_t *sw = get_sw(v); 1383 stp_lineoff_t *lineoffs; 1384 stp_linecount_t *linecount; 1385 const stp_linebufs_t *bufs; 1386 1387 bufs = stpi_get_linebases(v, sw, row, subpass, sw->head_offset[color]); 1388 lineoffs = stpi_get_lineoffsets(v, sw, row, subpass, sw->head_offset[color]); 1389 linecount = stpi_get_linecount(v, sw, row, subpass, sw->head_offset[color]); 1390 width *= sw->bitwidth * missingstartrows; 1391 memset(bufs->v[color], 0, width); 1392 lineoffs->v[color] = width; 1393 linecount->v[color] = missingstartrows; 1394} 1395 1396int 1397stp_compute_tiff_linewidth(stp_vars_t *v, int n) 1398{ 1399 /* 1400 * It's possible for the "compression" to actually expand the line by 1401 * roughly one part in 128. 1402 */ 1403 return ((n + 128 + 7) * 129 / 128); 1404} 1405 1406int 1407stp_compute_uncompressed_linewidth(stp_vars_t *v, int n) 1408{ 1409 return (8 * ((n + 7) / 8)); 1410} 1411 1412static void 1413initialize_row(stp_vars_t *v, stpi_softweave_t *sw, 1414 int row, int width, unsigned char *const cols[]) 1415{ 1416 stp_weave_t w; 1417 int i, j, jj; 1418 stp_pass_t *pass; 1419 1420 for (i = 0; i < sw->oversample; i++) 1421 { 1422 for (j = 0; j < sw->ncolors; j++) 1423 { 1424 if (cols[j]) 1425 { 1426 stp_lineoff_t *lineoffs = 1427 stpi_get_lineoffsets(v, sw, row, i, sw->head_offset[j]); 1428 stp_lineactive_t *lineactive = 1429 stpi_get_lineactive(v, sw, row, i, sw->head_offset[j]); 1430 stp_linecount_t *linecount = 1431 stpi_get_linecount(v, sw, row, i, sw->head_offset[j]); 1432 stp_linebounds_t *linebounds = 1433 stpi_get_linebounds(v, sw, row, i, sw->head_offset[j]); 1434 check_linebases(v, sw, row, i, sw->head_offset[j], j); 1435 weave_parameters_by_row(v, sw, row+sw->head_offset[j], i, &w); 1436 pass = stpi_get_pass_by_row(v, sw, row, i, sw->head_offset[j]); 1437 1438 /* initialize pass if not initialized yet */ 1439 if (pass->pass < 0) 1440 { 1441 pass->pass = w.pass; 1442 pass->missingstartrows = w.missingstartrows; 1443 pass->logicalpassstart = w.logicalpassstart; 1444 pass->physpassstart = w.physpassstart; 1445 pass->physpassend = w.physpassend; 1446 pass->subpass = i; 1447 1448 for(jj=0; jj<sw->ncolors; jj++) 1449 { 1450 if (lineoffs->v[jj] != 0) 1451 stp_eprintf(v, "WARNING: pass %d subpass %d row %d: " 1452 "lineoffs %ld should be zero!\n", 1453 w.pass, i, row, lineoffs->v[jj]); 1454 lineoffs->v[jj] = 0; 1455 lineactive->v[jj] = 0; 1456 if (linecount->v[jj] != 0) 1457 stp_eprintf(v, "WARNING: pass %d subpass %d row %d: " 1458 "linecount %d should be zero!\n", 1459 w.pass, i, row, linecount->v[jj]); 1460 linecount->v[jj] = 0; 1461 linebounds->start_pos[jj] = INT_MAX; 1462 linebounds->end_pos[jj] = -1; 1463 } 1464 } 1465 1466 if((linecount->v[j] == 0) && (w.jet > 0)) 1467 { 1468 (sw->fillfunc)(v, row, i, width, w.jet, j); 1469 } 1470 } 1471 } 1472 } 1473} 1474 1475static void 1476add_to_row(stp_vars_t *v, stpi_softweave_t *sw, int row, unsigned char *buf, 1477 size_t nbytes, int color, int setactive, int h_pass) 1478{ 1479 const stp_linebufs_t *bufs = 1480 stpi_get_linebases(v, sw, sw->lineno, h_pass, sw->head_offset[color]); 1481 stp_lineoff_t *lineoffs = 1482 stpi_get_lineoffsets(v, sw, sw->lineno, h_pass, sw->head_offset[color]); 1483 stp_lineactive_t *lineactive = 1484 stpi_get_lineactive(v, sw, sw->lineno, h_pass, sw->head_offset[color]); 1485 stp_linecount_t *linecount = 1486 stpi_get_linecount(v, sw, sw->lineno, h_pass, sw->head_offset[color]); 1487 size_t place = lineoffs->v[color]; 1488 size_t count = linecount->v[color]; 1489 if (place + nbytes > sw->virtual_jets * sw->bitwidth * sw->horizontal_width) 1490 { 1491 int i; 1492 stp_eprintf(v, "ERROR: %s\n", _("Fatal error!")); 1493 stp_eprintf(v, "ERROR: Static weave data follows:\n"); 1494 stp_eprintf(v, "ERROR: jets: %d\n", sw->jets); 1495 stp_eprintf(v, "ERROR: virtual_jets: %d\n", sw->virtual_jets); 1496 stp_eprintf(v, "ERROR: separation: %d\n", sw->separation); 1497 stp_eprintf(v, "ERROR: horizontal_weave: %d\n", sw->horizontal_weave); 1498 stp_eprintf(v, "ERROR: vertical_subpasses: %d\n", sw->vertical_subpasses); 1499 stp_eprintf(v, "ERROR: vmod: %d\n", sw->vmod); 1500 stp_eprintf(v, "ERROR: oversample: %d\n", sw->oversample); 1501 stp_eprintf(v, "ERROR: repeat_count: %d\n", sw->repeat_count); 1502 stp_eprintf(v, "ERROR: ncolors: %d\n", sw->ncolors); 1503 stp_eprintf(v, "ERROR: linewidth: %d\n", sw->linewidth); 1504 stp_eprintf(v, "ERROR: vertical_height: %d\n", sw->vertical_height); 1505 stp_eprintf(v, "ERROR: firstline: %d\n", sw->firstline); 1506 stp_eprintf(v, "ERROR: bitwidth: %d\n", sw->bitwidth); 1507 stp_eprintf(v, "ERROR: vertical_oversample: %d\n", sw->vertical_oversample); 1508 stp_eprintf(v, "ERROR: horizontal_width: %d\n", sw->horizontal_width); 1509 if (sw->head_offset) 1510 { 1511 stp_eprintf(v, "ERROR: head_offset:\n"); 1512 for (i = 0; i < sw->ncolors; i++) 1513 stp_eprintf(v, "ERROR: head %d: %d\n", i, sw->head_offset[i]); 1514 } 1515 stp_eprintf(v, "ERROR: Dynamic weave data follows:\n"); 1516 stp_eprintf(v, "ERROR: last_pass_offset: %d\n", sw->last_pass_offset); 1517 stp_eprintf(v, "ERROR: last_pass: %d\n", sw->last_pass); 1518 stp_eprintf(v, "ERROR: lineno: %d\n", sw->lineno); 1519 stp_eprintf(v, "ERROR: current_vertical_subpass: %d\n", sw->current_vertical_subpass); 1520 stp_eprintf(v, "ERROR: rcache: %d\n", sw->rcache); 1521 stp_eprintf(v, "ERROR: vcache: %d\n", sw->vcache); 1522 stp_eprintf(v, "ERROR: Other parameters: row %d color %d setactive %d hpass %d\n", 1523 row, color, setactive, h_pass); 1524 stp_eprintf(v, "ERROR: Buffer overflow: limit %d (jets %d bits %d horizontal %d), actual %ld (current %d added %d), count %ld\n", 1525 sw->virtual_jets * sw->bitwidth * sw->horizontal_width, 1526 sw->virtual_jets, sw->bitwidth, sw->horizontal_width, 1527 (long) (place + nbytes), (int) place, (int) nbytes, (long) count); 1528 stp_eprintf(v, "ERROR: %s\n", _("Please report the above information to gimp-print-devel@lists.sourceforge.net")); 1529 stp_abort(); 1530 } 1531 memcpy(bufs->v[color] + lineoffs->v[color], buf, nbytes); 1532 lineoffs->v[color] += nbytes; 1533 if (setactive) 1534 lineactive->v[color] = 1; 1535} 1536 1537static void 1538stpi_flush_passes(stp_vars_t *v, int flushall) 1539{ 1540 stpi_softweave_t *sw = get_sw(v); 1541 while (1) 1542 { 1543 stp_pass_t *pass = stp_get_pass_by_pass(v, sw->last_pass + 1); 1544 /* 1545 * This ought to be pass->physpassend > sw->lineno 1546 * but that causes rubbish to be output for some reason. 1547 */ 1548 if (pass->pass < 0 || (!flushall && pass->physpassend >= sw->lineno)) 1549 return; 1550 (sw->flushfunc)(v, pass->pass, pass->subpass); 1551 sw->last_pass = pass->pass; 1552 pass->pass = -1; 1553 } 1554} 1555 1556void 1557stp_flush_all(stp_vars_t *v) 1558{ 1559 stpi_flush_passes(v, 1); 1560} 1561 1562static void 1563finalize_row(stp_vars_t *v, int row) 1564{ 1565 stpi_softweave_t *sw = get_sw(v); 1566 int i,j; 1567 stp_dprintf(STP_DBG_ROWS, v, "Finalizing row %d...\n", row); 1568 for (i = 0; i < sw->oversample; i++) 1569 { 1570 stp_weave_t w; 1571 stp_linecount_t *lines; 1572 1573 for(j=0; j<sw->ncolors; j++) 1574 { 1575 lines = stpi_get_linecount(v, sw, row, i, sw->head_offset[j]); 1576 lines->v[j]++; 1577 } 1578 1579 weave_parameters_by_row(v, sw, row, i, &w); 1580 if (w.physpassend == row) 1581 { 1582 stp_dprintf(STP_DBG_ROWS, v, 1583 "Pass=%d, physpassend=%d, row=%d, lineno=%d, flush..\n", 1584 w.pass, w.physpassend, row, sw->lineno); 1585 stpi_flush_passes(v, 0); 1586 } 1587 } 1588} 1589 1590void 1591stp_write_weave(stp_vars_t *v, unsigned char *const cols[]) 1592{ 1593 stpi_softweave_t *sw = get_sw(v); 1594 int length = (sw->linewidth + 7) / 8; 1595 stp_lineoff_t *lineoffs[STP_MAX_WEAVE]; 1596 stp_lineactive_t *lineactives[STP_MAX_WEAVE]; 1597 stp_linecount_t *linecounts[STP_MAX_WEAVE]; 1598 stp_linebounds_t *linebounds[STP_MAX_WEAVE]; 1599 const stp_linebufs_t *bufs[STP_MAX_WEAVE]; 1600 int xlength = (length + sw->horizontal_weave - 1) / sw->horizontal_weave; 1601 int ylength = xlength * sw->horizontal_weave; 1602 unsigned char *comp_ptr; 1603 int i, j; 1604 int setactive; 1605 int h_passes = sw->horizontal_weave * sw->vertical_subpasses; 1606 int cpass = sw->current_vertical_subpass * h_passes; 1607 1608 if (!sw->fold_buf) 1609 { 1610 stp_dprintf(STP_DBG_WEAVE_PARAMS, v, 1611 "fold buffer allocation: length %d lw %d weave %d xlength %d ylength %d\n", 1612 length, sw->linewidth, sw->horizontal_weave, xlength, ylength); 1613 stp_dprintf(STP_DBG_WEAVE_PARAMS, v, 1614 "Allocating fold buf %d * %d (%d)\n", ylength, sw->bitwidth, 1615 sw->bitwidth * ylength); 1616 sw->fold_buf = stp_zalloc(sw->bitwidth * ylength); 1617 } 1618 if (!sw->comp_buf) 1619 { 1620 stp_dprintf(STP_DBG_WEAVE_PARAMS, v, 1621 "Allocating compression buffer based on %d, %d\n", 1622 sw->bitwidth, ylength); 1623 sw->comp_buf = stp_zalloc(sw->bitwidth * 1624 (sw->compute_linewidth)(v,ylength)); 1625 } 1626 if (sw->current_vertical_subpass == 0) 1627 initialize_row(v, sw, sw->lineno, xlength, cols); 1628 1629 for (j = 0; j < sw->ncolors; j++) 1630 { 1631 if (cols[j]) 1632 { 1633 const unsigned char *in; 1634 int idx; 1635 1636 for (i = 0; i < h_passes; i++) 1637 { 1638 int offset = sw->head_offset[j]; 1639 int pass = cpass + i; 1640 if (!sw->s[i]) 1641 sw->s[i] = stp_zalloc(sw->bitwidth * 1642 (sw->compute_linewidth)(v, ylength)); 1643 lineoffs[i] = 1644 stpi_get_lineoffsets(v, sw, sw->lineno, pass, offset); 1645 linecounts[i] = 1646 stpi_get_linecount(v, sw, sw->lineno, pass, offset); 1647 lineactives[i] = 1648 stpi_get_lineactive(v, sw, sw->lineno, pass,offset); 1649 linebounds[i] = 1650 stpi_get_linebounds(v, sw, sw->lineno, pass, offset); 1651 bufs[i] = 1652 stpi_get_linebases(v, sw, sw->lineno, pass, offset); 1653 } 1654 1655 if (sw->bitwidth == 2) 1656 { 1657 stp_fold(cols[j], length, sw->fold_buf); 1658 in = sw->fold_buf; 1659 } 1660 else 1661 in = cols[j]; 1662 if (sw->horizontal_weave == 1) 1663 memcpy(sw->s[0], in, length * sw->bitwidth); 1664 else 1665 stp_unpack(length, sw->bitwidth, sw->horizontal_weave, in, sw->s); 1666 if (sw->vertical_subpasses > 1) 1667 { 1668 for (idx = 0; idx < sw->horizontal_weave; idx++) 1669 stp_split(length, sw->bitwidth, sw->vertical_subpasses, 1670 sw->s[idx], sw->horizontal_weave, &(sw->s[idx])); 1671 } 1672 for (i = 0; i < h_passes; i++) 1673 { 1674 int first, last; 1675 setactive = (sw->pack)(v, sw->s[i], sw->bitwidth * xlength, 1676 sw->comp_buf, &comp_ptr, &first, &last); 1677 if (first < linebounds[i]->start_pos[j]) 1678 linebounds[i]->start_pos[j] = first; 1679 if (last > linebounds[i]->end_pos[j]) 1680 linebounds[i]->end_pos[j] = last; 1681 add_to_row(v, sw, sw->lineno, sw->comp_buf, 1682 comp_ptr - sw->comp_buf, j, setactive, cpass + i); 1683 } 1684 } 1685 } 1686 sw->current_vertical_subpass++; 1687 if (sw->current_vertical_subpass >= sw->vertical_oversample) 1688 { 1689 finalize_row(v, sw->lineno); 1690 sw->lineno++; 1691 sw->current_vertical_subpass = 0; 1692 } 1693} 1694 1695#if 0 1696#define TEST_RAW 1697#endif 1698#if 0 1699#define TEST_COOKED 1700#endif 1701#if 0 1702#define ACCUMULATE 1703#endif 1704 1705#if defined(TEST_RAW) || defined(TEST_COOKED) 1706#define TEST 1707#endif 1708 1709#ifdef TEST 1710#define MAXCOLLECT (1000) 1711#endif 1712 1713#ifdef TEST_COOKED 1714static void 1715calculate_pass_parameters(cooked_t *w, /* I - weave parameters */ 1716 int pass, /* I - pass number ( >= 0) */ 1717 int *startrow, /* O - print head position */ 1718 int *subpass, /* O - subpass number */ 1719 int *phantomrows, /* O - missing rows */ 1720 int *jetsused) /* O - jets used to print */ 1721{ 1722 int raw_pass = pass + w->first_premapped_pass; 1723 int stagger = 0; 1724 int extra; 1725 1726 if (raw_pass < w->first_normal_pass) { 1727 int i = 0; 1728 while (i + w->first_premapped_pass < w->first_normal_pass) { 1729 if (w->pass_premap[i] == pass) { 1730 raw_pass = i + w->first_premapped_pass; 1731 stagger = w->stagger_premap[i]; 1732 break; 1733 } 1734 i++; 1735 } 1736 } else if (raw_pass >= w->first_postmapped_pass) { 1737 int i = 0; 1738 while (i + w->first_postmapped_pass < w->first_unused_pass) { 1739 if (w->pass_postmap[i] == pass) { 1740 raw_pass = i + w->first_postmapped_pass; 1741 stagger = w->stagger_postmap[i]; 1742 break; 1743 } 1744 i++; 1745 } 1746 } 1747 1748 calculate_raw_pass_parameters(&w->rw, raw_pass, startrow, subpass); 1749 *startrow -= w->rw.separation * w->rw.jets; 1750 *jetsused = w->rw.jets; 1751 *phantomrows = 0; 1752 1753 *startrow += stagger * w->rw.separation; 1754 if (stagger < 0) { 1755 stagger = -stagger; 1756 *phantomrows += stagger; 1757 } 1758 *jetsused -= stagger; 1759 1760 extra = w->first_row_printed - (*startrow + w->rw.separation * *phantomrows); 1761 extra = (extra + w->rw.separation - 1) / w->rw.separation; 1762 if (extra > 0) { 1763 *jetsused -= extra; 1764 *phantomrows += extra; 1765 } 1766 1767 extra = *startrow + w->rw.separation * (*phantomrows + *jetsused - 1) 1768 - w->last_row_printed; 1769 extra = (extra + w->rw.separation - 1) / w->rw.separation; 1770 if (extra > 0) { 1771 *jetsused -= extra; 1772 } 1773} 1774#endif /* TEST_COOKED */ 1775 1776#ifdef TEST 1777 1778#ifdef ACCUMULATE 1779#define PUTCHAR(x) /* nothing */ 1780#else 1781#define PUTCHAR(x) putchar(x) 1782#endif 1783 1784static void 1785plotpass(int startrow, int phantomjets, int jetsused, int totaljets, 1786 int separation, int subpass, int *collect, int *prints) 1787{ 1788 int hpos, i; 1789 1790 for (hpos = 0; hpos < startrow; hpos++) 1791 PUTCHAR(' '); 1792 1793 for (i = 0; i < phantomjets; i++) { 1794 int j; 1795 PUTCHAR('X'); 1796 hpos++; 1797 for (j = 1; j < separation; j++) { 1798 PUTCHAR(' '); 1799 hpos++; 1800 } 1801 } 1802 1803 for (; i < phantomjets + jetsused; i++) { 1804 if (i > phantomjets) { 1805 int j; 1806 for (j = 1; j < separation; j++) { 1807 PUTCHAR('-'); 1808 hpos++; 1809 } 1810 } 1811 if (hpos < MAXCOLLECT) { 1812 if (collect[hpos] & 1 << subpass) 1813 PUTCHAR('^'); 1814 else if (subpass < 10) 1815 PUTCHAR('0' + subpass); 1816 else 1817 PUTCHAR('A' + subpass - 10); 1818 collect[hpos] |= 1 << subpass; 1819 prints[hpos]++; 1820 } else { 1821 PUTCHAR('0' + subpass); 1822 } 1823 hpos++; 1824 } 1825 1826 while (i++ < totaljets) { 1827 int j; 1828 for (j = 1; j < separation; j++) { 1829 PUTCHAR(' '); 1830 hpos++; 1831 } 1832 PUTCHAR('X'); 1833 } 1834#ifdef ACCUMULATE 1835 for (i=0; i<=MAXCOLLECT; i++) { 1836 if (collect[i] == 0) 1837 putchar(' '); 1838 else if (collect[i] < 10) 1839 putchar('0'+collect[i]); 1840 else 1841 putchar('A'+collect[i]-10); 1842 } 1843#endif 1844 putchar('\n'); 1845} 1846#endif /* TEST */ 1847 1848#ifdef TEST_COOKED 1849int 1850main(int ac, char *av[]) 1851{ 1852 int S =ac>1 ? atoi(av[1]) : 4; 1853 int J =ac>2 ? atoi(av[2]) : 12; 1854 int H =ac>3 ? atoi(av[3]) : 1; 1855 int firstrow =ac>4 ? atoi(av[4]) : 1; 1856 int lastrow =ac>5 ? atoi(av[5]) : 100; 1857 int pageheight=ac>6 ? atoi(av[6]) : 1000; 1858 stp_weave_strategy_t strategy =ac>7 ? atoi(av[7]) : 1; 1859 cooked_t *weave; 1860 int passes; 1861 1862 int pass, x; 1863 int collect[MAXCOLLECT]; 1864 int prints[MAXCOLLECT]; 1865 1866 memset(collect, 0, MAXCOLLECT*sizeof(int)); 1867 memset(prints, 0, MAXCOLLECT*sizeof(int)); 1868 printf("S=%d J=%d H=%d firstrow=%d lastrow=%d " 1869 "pageheight=%d strategy=%d\n", 1870 S, J, H, firstrow, lastrow, pageheight, strategy); 1871 1872 weave = initialize_weave_params(S, J, H, firstrow, lastrow, 1873 pageheight, strategy); 1874 passes = weave->first_unused_pass - weave->first_premapped_pass; 1875 1876 for (pass = 0; pass < passes; pass++) { 1877 int startrow, subpass, phantomjets, jetsused; 1878 1879 calculate_pass_parameters(weave, pass, &startrow, &subpass, 1880 &phantomjets, &jetsused); 1881 1882 plotpass(startrow, phantomjets, jetsused, J, S, subpass, 1883 collect, prints); 1884 } 1885 1886 for (pass=MAXCOLLECT - 1; prints[pass] == 0; pass--) 1887 ; 1888 1889 for (x=0; x<=pass; x++) { 1890 if (collect[x] < 10) 1891 putchar('0'+collect[x]); 1892 else 1893 putchar('A'+collect[x]-10); 1894 } 1895 putchar('\n'); 1896 1897 for (x=0; x<=pass; x++) { 1898 if (prints[x] < 10) 1899 putchar('0'+prints[x]); 1900 else 1901 putchar('A'+prints[x]-10); 1902 } 1903 putchar('\n'); 1904 1905 return 0; 1906} 1907#endif /* TEST_COOKED */ 1908 1909#ifdef TEST_RAW 1910int 1911main(int ac, char *av[]) 1912{ 1913 int S =ac>1 ? atoi(av[1]) : 4; 1914 int J =ac>2 ? atoi(av[2]) : 12; 1915 int h_pos =ac>3 ? atoi(av[3]) : 1; 1916 int h_over=ac>4 ? atoi(av[4]) : 1; 1917 int v_over=ac>5 ? atoi(av[5]) : 1; 1918 int H = h_pos * h_over * v_over; 1919 1920 int pass, passes, x; 1921 int collect[MAXCOLLECT]; 1922 int prints[MAXCOLLECT]; 1923 raw_t raw; 1924 1925 memset(collect, 0, MAXCOLLECT*sizeof(int)); 1926 memset(prints, 0, MAXCOLLECT*sizeof(int)); 1927 printf("S=%d J=%d H=%d\n", S, J, H); 1928 1929 if (H > J) { 1930 printf("H > J, so this weave will not work!\n"); 1931 } 1932 passes = S * H * 3; 1933 1934 initialize_raw_weave(&raw, S, J, H); 1935 1936 for (pass=0; pass<passes + S * H; pass++) { 1937 int startrow, subpass, phantomjets, jetsused; 1938 1939 calculate_raw_pass_parameters(&raw, pass, &startrow, &subpass); 1940 phantomjets = 0; 1941 jetsused = J; 1942 1943 plotpass(startrow, phantomjets, jetsused, J, S, subpass, 1944 collect, prints); 1945 } 1946 for (pass=MAXCOLLECT - 1; prints[pass] == 0; pass--) 1947 ; 1948 1949 for (x=0; x<=pass; x++) { 1950 if (collect[x] < 10) 1951 putchar('0'+collect[x]); 1952 else 1953 putchar('A'+collect[x]-10); 1954 } 1955 putchar('\n'); 1956 1957 for (x=0; x<=pass; x++) { 1958 if (prints[x] < 10) 1959 putchar('0'+prints[x]); 1960 else 1961 putchar('A'+prints[x]-10); 1962 } 1963 putchar('\n'); 1964 1965 printf(" A first row given by pass lookup doesn't match row lookup\n" 1966 " B jet out of range\n" 1967 " C given jet number of pass doesn't print this row\n" 1968 " D subpass given by reverse lookup doesn't match requested subpass\n"); 1969 1970 for (x = S * J; x < S * J * 20; x++) { 1971 int h; 1972 for (h = 0; h < H; h++) { 1973 int pass, jet, start, first, subpass, z; 1974 int a=0, b=0, c=0, d=0; 1975 calculate_raw_row_parameters(&raw, x, h, &pass, &jet, &start); 1976 for (z=0; z < pass; z++) { 1977 putchar(' '); 1978 } 1979 printf("%d", jet); 1980 calculate_raw_pass_parameters(&raw, pass, &first, &subpass); 1981 if (first != start) 1982 a=1; 1983 if (jet < 0 || jet >= J) 1984 b=1; 1985 if (x != first + jet * S) 1986 c=1; 1987 if (subpass != h) 1988 d=1; 1989 if (a || b || c || d) { 1990 printf(" ("); 1991 if (a) putchar('A'); 1992 if (b) putchar('B'); 1993 if (c) putchar('C'); 1994 if (d) putchar('D'); 1995 putchar(')'); 1996 printf("\npass=%d first=%d start=%d jet=%d subpass=%d", pass, first, start, jet, subpass); 1997 } 1998 putchar('\n'); 1999 } 2000 /* putchar('\n'); */ 2001 } 2002 2003 return 0; 2004} 2005 2006#endif /* TEST_RAW */ 2007