libgimpprint API Reference: src/main/print-weave.c Source File

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

# src/main/print-weave.c

Go to the documentation of this file.

    00001 /*
    00002  * "$Id: print-weave_8c-source.html,v 1.1.1.2 2004/12/22 23:49:11 jlovell Exp $"
    00003  *
    00004  *   Softweave calculator for gimp-print.
    00005  *
    00006  *   Copyright 2000 Charles Briscoe-Smith <cpbs@debian.org>
    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
    00023 /*
    00024  * This file must include only standard C header files.  The core code must
    00025  * compile on generic platforms that don't support glib, gimp, gtk, etc.
    00026  */
    00027
    00028 #ifdef HAVE_CONFIG_H
    00029 #include <config.h>
    00030 #endif
    00031 #include <string.h>
    00032 #include <gimp-print/gimp-print.h>
    00033 #include "gimp-print-internal.h"
    00034 #include <gimp-print/gimp-print-intl-internal.h>
    00035 #ifdef HAVE_LIMITS_H
    00036 #include <limits.h>
    00037 #endif
    00038
    00039 #if 1
    00040 #define ASSERTIONS
    00041 #endif
    00042
    00043 #ifdef ASSERTIONS
    00044 #define assert(x,v)                                                     \
    00045 do                                                                      \
    00046 {                                                                       \
    00047   if (!(x))                                                             \
    00048     {                                                                   \
    00049       stp_eprintf(v, "Assertion %s failed! file %s, line %d.\n",        \
    00050                   #x, __FILE__, __LINE__);                              \
    00051       stp_abort();                                                      \
    00052     }                                                                   \
    00053 } while (0)
    00054 #else
    00055 #define assert(x,v) do {} while (0)
    00056 #endif
    00057
    00058 static int
    00059 gcd(int x, int y)
    00060 {
    00061         if (y == 0)
    00062                 return x;
    00063         while (x != 0) {
    00064                 if (y > x) {
    00065                         int t = x;
    00066                         x = y;
    00067                         y = t;
    00068                 }
    00069                 x %= y;
    00070         }
    00071         return y;
    00072 }
    00073
    00074 typedef struct stpi_softweave
    00075 {
    00076   stp_linebufs_t *linebases;    /* Base address of each row buffer */
    00077   stp_lineoff_t *lineoffsets;   /* Offsets within each row buffer */
    00078   stp_lineactive_t *lineactive; /* Does this line have anything printed? */
    00079   stp_linecount_t *linecounts;  /* How many rows we've printed this pass */
    00080   stp_linebounds_t *linebounds; /* Starting and ending print column */
    00081   stp_pass_t *passes;           /* Circular list of pass numbers */
    00082   int last_pass_offset;         /* Starting row (offset from the start of */
    00083                                 /* the page) of the most recently printed */
    00084                                 /* pass (so we can determine how far to */
    00085                                 /* advance the paper) */
    00086   int last_pass;                /* Number of the most recently printed pass */
    00087
    00088   int jets;                     /* Number of jets per color */
    00089   int virtual_jets;             /* Number of jets per color, taking into */
    00090                                 /* account the head offset */
    00091   int separation;               /* Offset from one jet to the next in rows */
    00092   void *weaveparm;              /* Weave calculation parameter block */
    00093
    00094   int horizontal_weave;         /* Number of horizontal passes required */
    00095                                 /* This is > 1 for some of the ultra-high */
    00096                                 /* resolution modes */
    00097   int vertical_subpasses;       /* Number of passes per line (for better */
    00098                                 /* quality) */
    00099   int vmod;                     /* Number of banks of passes */
    00100   int oversample;               /* Excess precision per row */
    00101   int repeat_count;             /* How many times a pass is repeated */
    00102   int ncolors;                  /* How many colors */
    00103   int linewidth;                /* Line width in input pixels */
    00104   int vertical_height;          /* Image height in output pixels */
    00105   int firstline;                /* Actual first line (referenced to paper) */
    00106
    00107   int bitwidth;                 /* Bits per pixel */
    00108   int lineno;
    00109   int vertical_oversample;      /* Vertical oversampling */
    00110   int current_vertical_subpass;
    00111   int horizontal_width;         /* Horizontal width, in bits */
    00112   int *head_offset;             /* offset of printheads */
    00113   unsigned char *s[STP_MAX_WEAVE];
    00114   unsigned char *fold_buf;
    00115   unsigned char *comp_buf;
    00116   stp_weave_t wcache;
    00117   int rcache;
    00118   int vcache;
    00119   stp_flushfunc *flushfunc;
    00120   stp_fillfunc *fillfunc;
    00121   stp_packfunc *pack;
    00122   stp_compute_linewidth_func *compute_linewidth;
    00123 } stpi_softweave_t;
    00124
    00125 /* RAW WEAVE */
    00126
    00127 typedef struct raw {
    00128         int separation;
    00129         int jets;
    00130         int oversampling;
    00131         int advancebasis;
    00132         int subblocksperpassblock;
    00133         int passespersubblock;
    00134         stp_weave_strategy_t strategy;
    00135         stp_vars_t *v;
    00136 } raw_t;
    00137
    00138 /*
    00139  * Strategy types currently defined:
    00140  *
    00141  *  0: zig-zag type pass block filling
    00142  *  1: ascending pass block filling
    00143  *  2: descending pass block filling
    00144  *  3: ascending fill with 2x expansion
    00145  *  4: staggered zig-zag neighbour-avoidance fill
    00146  *  5: ascending fill with 3x expansion
    00147  *
    00148  * In theory, strategy 0 should be optimal; in practice, it can lead
    00149  * to visible areas of banding.  If it's necessary to avoid filling
    00150  * neighbouring rows in neighbouring passes, strategy 4 should be optimal,
    00151  * at least for some weaves.
    00152  */
    00153
    00154 static void
    00155 initialize_raw_weave(raw_t *w,  /* I - weave struct to be filled in */
    00156                      int separation,    /* I - jet separation */
    00157                      int jets,  /* I - number of jets */
    00158                      int oversample,    /* I - oversampling factor */
    00159                      stp_weave_strategy_t strat,        /* I - weave pattern variation to use */
    00160                      stp_vars_t *v)
    00161 {
    00162         w->separation = separation;
    00163         w->jets = jets;
    00164         w->oversampling = oversample;
    00165         w->advancebasis = jets / oversample;
    00166         if (w->advancebasis == 0)
    00167           w->advancebasis++;
    00168         w->subblocksperpassblock = gcd(separation, w->advancebasis);
    00169         w->passespersubblock = separation / w->subblocksperpassblock;
    00170         w->strategy = strat;
    00171         w->v = v;
    00172 }
    00173
    00174 static void
    00175 calculate_raw_pass_parameters(raw_t *w,         /* I - weave parameters */
    00176                               int pass,         /* I - pass number ( >= 0) */
    00177                               int *startrow,    /* O - print head position */
    00178                               int *subpass)     /* O - subpass number */
    00179 {
    00180         int band, passinband, subpassblock, subpassoffset;
    00181
    00182         band = pass / (w->separation * w->oversampling);
    00183         passinband = pass % (w->separation * w->oversampling);
    00184         subpassblock = pass % w->separation
    00185                          * w->subblocksperpassblock / w->separation;
    00186
    00187         switch (w->strategy) {
    00188         case STP_WEAVE_ZIGZAG:
    00189                 if (subpassblock * 2 < w->subblocksperpassblock)
    00190                         subpassoffset = 2 * subpassblock;
    00191                 else
    00192                         subpassoffset = 2 * (w->subblocksperpassblock
    00193                                               - subpassblock) - 1;
    00194                 break;
    00195         case STP_WEAVE_ASCENDING:
    00196                 subpassoffset = subpassblock;
    00197                 break;
    00198         case STP_WEAVE_DESCENDING:
    00199                 subpassoffset = w->subblocksperpassblock - 1 - subpassblock;
    00200                 break;
    00201         case STP_WEAVE_ASCENDING_2X:
    00202                 if (subpassblock * 2 < w->subblocksperpassblock)
    00203                         subpassoffset = 2 * subpassblock;
    00204                 else
    00205                         subpassoffset = 1 + 2 * (subpassblock
    00206                                                   - (w->subblocksperpassblock
    00207                                                       + 1) / 2);
    00208                 break;
    00209         case STP_WEAVE_ASCENDING_3X:
    00210                 if (subpassblock * 3 < w->subblocksperpassblock)
    00211                         subpassoffset = 3 * subpassblock;
    00212                 else if (3 * (subpassblock - (w->subblocksperpassblock + 2) / 3)
    00213                           < w->subblocksperpassblock - 2)
    00214                         subpassoffset = 2 + 3 * (subpassblock
    00215                                                   - (w->subblocksperpassblock
    00216                                                       + 2) / 3);
    00217                 else
    00218                         subpassoffset = 1 + 3 * (subpassblock
    00219                                                   - (w->subblocksperpassblock
    00220                                                       + 2) / 3
    00221                                                   - w->subblocksperpassblock
    00222                                                       / 3);
    00223                 break;
    00224         case STP_WEAVE_STAGGERED:
    00225                 if (subpassblock * 2 < w->subblocksperpassblock)
    00226                         subpassoffset = 2 * subpassblock;
    00227                 else if (subpassblock * 2 < w->subblocksperpassblock + 2)
    00228                         subpassoffset = 1;
    00229                 else
    00230                         subpassoffset = 2 * (w->subblocksperpassblock
    00231                                               - subpassblock) + 1;
    00232                 break;
    00233         default:
    00234                 subpassoffset = subpassblock;
    00235                 break;
    00236         }
    00237
    00238         *startrow = w->separation * w->jets * band
    00239                       + w->advancebasis * passinband + subpassoffset;
    00240         *subpass = passinband / w->separation;
    00241 }
    00242
    00243 static void
    00244 calculate_raw_row_parameters(raw_t *w,          /* I - weave parameters */
    00245                              int row,           /* I - row number */
    00246                              int subpass,       /* I - subpass number */
    00247                              int *pass,         /* O - pass number */
    00248                              int *jet,          /* O - jet number in pass */
    00249                              int *startrow)     /* O - starting row of pass */
    00250 {
    00251         int subblockoffset, subpassblock, band, baserow, passinband, offset;
    00252         int pass_div_separation;
    00253         int pass_mod_separation;
    00254         int off_mod_separation;
    00255
    00256         subblockoffset = row % w->subblocksperpassblock;
    00257         switch (w->strategy) {
    00258         case STP_WEAVE_ZIGZAG:
    00259                 if (subblockoffset % 2 == 0)
    00260                         subpassblock = subblockoffset / 2;
    00261                 else
    00262                         subpassblock = w->subblocksperpassblock
    00263                                          - (subblockoffset + 1) / 2;
    00264                 break;
    00265         case STP_WEAVE_ASCENDING:
    00266                 subpassblock = subblockoffset;
    00267                 break;
    00268         case STP_WEAVE_DESCENDING:
    00269                 subpassblock = w->subblocksperpassblock - 1 - subblockoffset;
    00270                 break;
    00271         case STP_WEAVE_ASCENDING_2X:
    00272                 if (subblockoffset % 2 == 0)
    00273                         subpassblock = subblockoffset / 2;
    00274                 else
    00275                         subpassblock = (subblockoffset - 1) / 2
    00276                                        + (w->subblocksperpassblock + 1) / 2;
    00277                 break;
    00278         case STP_WEAVE_ASCENDING_3X:
    00279                 if (subblockoffset % 3 == 0)
    00280                         subpassblock = subblockoffset / 3;
    00281                 else if (subblockoffset % 3 == 1)
    00282                         subpassblock = (subblockoffset - 1) / 3
    00283                                          + (w->subblocksperpassblock + 2) / 3;
    00284                 else
    00285                         subpassblock = (subblockoffset - 2) / 3
    00286                                          + (w->subblocksperpassblock + 2) / 3
    00287                                          + (w->subblocksperpassblock + 1) / 3;
    00288                 break;
    00289         case STP_WEAVE_STAGGERED:
    00290                 if (subblockoffset % 2 == 0)
    00291                         subpassblock = subblockoffset / 2;
    00292                 else if (subblockoffset == 1)
    00293                         subpassblock = (w->subblocksperpassblock + 1) / 2;
    00294                 else
    00295                         subpassblock = w->subblocksperpassblock
    00296                                          - (subblockoffset - 1) / 2;
    00297                 break;
    00298         default:
    00299                 subpassblock = subblockoffset;
    00300                 break;
    00301         }
    00302
    00303         band = row / (w->separation * w->jets);
    00304         baserow = row - subblockoffset - band * w->separation * w->jets;
    00305         passinband = baserow / w->advancebasis;
    00306         offset = baserow % w->advancebasis;
    00307         pass_div_separation = passinband / w->separation;
    00308         pass_mod_separation = passinband % w->separation;
    00309         off_mod_separation = offset % w->separation;
    00310
    00311         while (off_mod_separation != 0
    00312                || pass_div_separation != subpass
    00313                || pass_mod_separation / w->passespersubblock
    00314                     != subpassblock)
    00315           {
    00316             offset += w->advancebasis;
    00317             passinband--;
    00318             if (passinband >= 0)
    00319               {
    00320                 pass_mod_separation--;
    00321                 if (pass_mod_separation < 0)
    00322                   {
    00323                     pass_mod_separation += w->separation;
    00324                     pass_div_separation--;
    00325                   }
    00326                 if (w->advancebasis < w->separation)
    00327                   {
    00328                     off_mod_separation += w->advancebasis;
    00329                     if (off_mod_separation >= w->separation)
    00330                       off_mod_separation -= w->separation;
    00331                   }
    00332                 else if (w->advancebasis > w->separation)
    00333                   off_mod_separation = offset % w->separation;
    00334               }
    00335             else
    00336               {
    00337                 const int roundedjets =
    00338                   (w->advancebasis * w->oversampling) % w->jets;
    00339                 band--;
    00340                 passinband += w->separation * w->oversampling;
    00341                 offset += w->separation * (w->jets - roundedjets);
    00342                 pass_div_separation = passinband / w->separation;
    00343                 pass_mod_separation = passinband % w->separation;
    00344                 off_mod_separation = offset % w->separation;
    00345               }
    00346           }
    00347
    00348         *pass = band * w->oversampling * w->separation + passinband;
    00349         *jet = (offset / w->separation) % w->jets;
    00350         *startrow = row - (*jet * w->separation);
    00351 }
    00352
    00353 /* COOKED WEAVE */
    00354
    00355 typedef struct cooked {
    00356         raw_t rw;
    00357         int first_row_printed;
    00358         int last_row_printed;
    00359
    00360         int first_premapped_pass;       /* First raw pass used by this page */
    00361         int first_normal_pass;
    00362         int first_postmapped_pass;
    00363         int first_unused_pass;
    00364
    00365         int *pass_premap;
    00366         int *stagger_premap;
    00367         int *pass_postmap;
    00368         int *stagger_postmap;
    00369 } cooked_t;
    00370
    00371 static void
    00372 sort_by_start_row(int *map, int *startrows, int count)
    00373 {
    00374         /*
    00375          * Yes, it's a bubble sort, but we do it no more than 4 times
    00376          * per page, and we are only sorting a small number of items.
    00377          */
    00378
    00379         int dirty;
    00380
    00381         do {
    00382                 int x;
    00383                 dirty = 0;
    00384                 for (x = 1; x < count; x++) {
    00385                         if (startrows[x - 1] > startrows[x]) {
    00386                                 int temp = startrows[x - 1];
    00387                                 startrows[x - 1] = startrows[x];
    00388                                 startrows[x] = temp;
    00389                                 temp = map[x - 1];
    00390                                 map[x - 1] = map[x];
    00391                                 map[x] = temp;
    00392                                 dirty = 1;
    00393                         }
    00394                 }
    00395         } while (dirty);
    00396 }
    00397
    00398 static void
    00399 calculate_stagger(raw_t *w, int *map, int *startrows_stagger, int count)
    00400 {
    00401         int i;
    00402
    00403         for (i = 0; i < count; i++) {
    00404                 int startrow, subpass;
    00405                 calculate_raw_pass_parameters(w, map[i], &startrow, &subpass);
    00406                 startrow -= w->separation * w->jets;
    00407                 startrows_stagger[i] = (startrows_stagger[i] - startrow)
    00408                                          / w->separation;
    00409         }
    00410 }
    00411
    00412 static void
    00413 invert_map(int *map, int *stagger, int count, int oldfirstpass,
    00414            int newfirstpass)
    00415 {
    00416         int i;
    00417         int *newmap, *newstagger;
    00418         newmap = stp_malloc(count * sizeof(int));
    00419         newstagger = stp_malloc(count * sizeof(int));
    00420
    00421         for (i = 0; i < count; i++) {
    00422                 newmap[map[i] - oldfirstpass] = i + newfirstpass;
    00423                 newstagger[map[i] - oldfirstpass] = stagger[i];
    00424         }
    00425
    00426         memcpy(map, newmap, count * sizeof(int));
    00427         memcpy(stagger, newstagger, count * sizeof(int));
    00428         stp_free(newstagger);
    00429         stp_free(newmap);
    00430 }
    00431
    00432 static void
    00433 make_passmap(raw_t *w, int **map, int **starts, int first_pass_number,
    00434              int first_pass_to_map, int first_pass_after_map,
    00435              int first_pass_to_stagger, int first_pass_after_stagger,
    00436              int first_row_of_maximal_pass, int separations_to_distribute)
    00437 {
    00438         int *passmap, *startrows;
    00439         int passes_to_map = first_pass_after_map - first_pass_to_map;
    00440         int i;
    00441
    00442         assert(first_pass_to_map <= first_pass_after_map, w->v);
    00443         assert(first_pass_to_stagger <= first_pass_after_stagger, w->v);
    00444
    00445         *map = passmap = stp_malloc(passes_to_map * sizeof(int));
    00446         *starts = startrows = stp_malloc(passes_to_map * sizeof(int));
    00447
    00448         for (i = 0; i < passes_to_map; i++) {
    00449                 int startrow, subpass;
    00450                 int pass = i + first_pass_to_map;
    00451                 calculate_raw_pass_parameters(w, pass, &startrow, &subpass);
    00452                 passmap[i] = pass;
    00453                 if (first_row_of_maximal_pass >= 0)
    00454                         startrow = first_row_of_maximal_pass - startrow
    00455                                      + w->separation * w->jets;
    00456                 else
    00457                         startrow -= w->separation * w->jets;
    00458                 while (startrow < 0)
    00459                         startrow += w->separation;
    00460                 startrows[i] = startrow;
    00461         }
    00462
    00463         sort_by_start_row(passmap, startrows, passes_to_map);
    00464
    00465         separations_to_distribute++;
    00466
    00467         for (i = 0; i < first_pass_after_stagger - first_pass_to_stagger; i++) {
    00468                 int offset = first_pass_to_stagger - first_pass_to_map;
    00469                 if (startrows[i + offset] / w->separation
    00470                       < i % separations_to_distribute)
    00471                 {
    00472                         startrows[i + offset]
    00473                           = startrows[i + offset] % w->separation
    00474                              + w->separation * (i % separations_to_distribute);
    00475                 }
    00476         }
    00477
    00478         if (first_row_of_maximal_pass >= 0) {
    00479                 for (i = 0; i < passes_to_map; i++) {
    00480                         startrows[i] = first_row_of_maximal_pass - startrows[i];
    00481                 }
    00482         }
    00483
    00484         sort_by_start_row(passmap, startrows, passes_to_map);
    00485         calculate_stagger(w, passmap, startrows, passes_to_map);
    00486
    00487         invert_map(passmap, startrows, passes_to_map, first_pass_to_map,
    00488                    first_pass_to_map - first_pass_number);
    00489 }
    00490
    00491 static void
    00492 calculate_pass_map(stp_vars_t *v,
    00493                    cooked_t *w,         /* I - weave parameters */
    00494                    int pageheight,      /* I - number of rows on page */
    00495                    int firstrow,        /* I - first printed row */
    00496                    int lastrow)         /* I - last printed row */
    00497 {
    00498         int startrow, subpass;
    00499         int pass = -1;
    00500
    00501         w->first_row_printed = firstrow;
    00502         w->last_row_printed = lastrow;
    00503
    00504         if (pageheight <= lastrow)
    00505                 pageheight = lastrow + 1;
    00506
    00507         do {
    00508                 calculate_raw_pass_parameters(&w->rw, ++pass,
    00509                                               &startrow, &subpass);
    00510         } while (startrow - w->rw.separation < firstrow);
    00511
    00512         w->first_premapped_pass = pass;
    00513
    00514         while (startrow < w->rw.separation * w->rw.jets
    00515                && startrow - w->rw.separation < pageheight
    00516                && startrow <= lastrow + w->rw.separation * w->rw.jets)
    00517         {
    00518                 calculate_raw_pass_parameters(&w->rw, ++pass,
    00519                                               &startrow, &subpass);
    00520         }
    00521         w->first_normal_pass = pass;
    00522
    00523         while (startrow - w->rw.separation < pageheight
    00524                && startrow <= lastrow + w->rw.separation * w->rw.jets)
    00525         {
    00526                 calculate_raw_pass_parameters(&w->rw, ++pass,
    00527                                               &startrow, &subpass);
    00528         }
    00529         w->first_postmapped_pass = pass;
    00530
    00531         while (startrow <= lastrow + w->rw.separation * w->rw.jets) {
    00532                 calculate_raw_pass_parameters(&w->rw, ++pass,
    00533                                               &startrow, &subpass);
    00534         }
    00535         w->first_unused_pass = pass;
    00536
    00537         stp_dprintf(STP_DBG_WEAVE_PARAMS, v,
    00538                     "first premapped %d first normal %d first postmapped %d "
    00539                     "first unused %d\n",
    00540                     w->first_premapped_pass, w->first_normal_pass,
    00541                     w->first_postmapped_pass, w->first_unused_pass);
    00542         /*
    00543          * FIXME: make sure first_normal_pass doesn't advance beyond
    00544          * first_postmapped_pass, or first_postmapped_pass doesn't
    00545          * retreat before first_normal_pass.
    00546          */
    00547
    00548         if (w->first_normal_pass > w->first_premapped_pass) {
    00549                 int spread, separations_to_distribute, normal_passes_mapped;
    00550                 separations_to_distribute = firstrow / w->rw.separation;
    00551                 spread = (separations_to_distribute + 1) * w->rw.separation;
    00552                 normal_passes_mapped = (spread + w->rw.advancebasis - 1)
    00553                                             / w->rw.advancebasis;
    00554                 w->first_normal_pass += normal_passes_mapped;
    00555                 make_passmap(&w->rw, &w->pass_premap, &w->stagger_premap,
    00556                              w->first_premapped_pass,
    00557                              w->first_premapped_pass, w->first_normal_pass,
    00558                              w->first_premapped_pass,
    00559                              w->first_normal_pass - normal_passes_mapped,
    00560                              -1, separations_to_distribute);
    00561         } else {
    00562                 w->pass_premap = 0;
    00563                 w->stagger_premap = 0;
    00564         }
    00565
    00566         if (w->first_unused_pass >= w->first_postmapped_pass) {
    00567                 int spread, separations_to_distribute, normal_passes_mapped;
    00568                 separations_to_distribute = (pageheight - lastrow - 1)
    00569                                                      / w->rw.separation;
    00570                 spread = (separations_to_distribute + 1) * w->rw.separation;
    00571                 normal_passes_mapped = (spread + w->rw.advancebasis)
    00572                                              / w->rw.advancebasis;
    00573                 w->first_postmapped_pass -= normal_passes_mapped;
    00574                 make_passmap(&w->rw, &w->pass_postmap, &w->stagger_postmap,
    00575                              w->first_premapped_pass,
    00576                              w->first_postmapped_pass, w->first_unused_pass,
    00577                              w->first_postmapped_pass + normal_passes_mapped,
    00578                              w->first_unused_pass,
    00579                              pageheight - 1
    00580                                  - w->rw.separation * (w->rw.jets - 1),
    00581                              separations_to_distribute);
    00582         } else {
    00583                 w->pass_postmap = 0;
    00584                 w->stagger_postmap = 0;
    00585         }
    00586 }
    00587
    00588 static void *                           /* O - weave parameter block */
    00589 initialize_weave_params(int separation,         /* I - jet separation */
    00590                         int jets,               /* I - number of jets */
    00591                         int oversample,         /* I - oversampling factor */
    00592                         int firstrow,   /* I - first row number to print */
    00593                         int lastrow,    /* I - last row number to print */
    00594                         int pageheight, /* I - number of rows on the whole
    00595                                                page, without using any
    00596                                                expanded margin facilities */
    00597                         stp_weave_strategy_t strategy,  /* I - weave pattern variant to use */
    00598                         stp_vars_t *v)
    00599 {
    00600         cooked_t *w = stp_malloc(sizeof(cooked_t));
    00601         if (w) {
    00602                 initialize_raw_weave(&w->rw, separation, jets, oversample, strategy, v);
    00603                 calculate_pass_map(v, w, pageheight, firstrow, lastrow);
    00604         }
    00605         return w;
    00606 }
    00607
    00608 static void
    00609 stpi_destroy_weave_params(void *vw)
    00610 {
    00611         cooked_t *w = (cooked_t *) vw;
    00612
    00613         if (w->pass_premap) stp_free(w->pass_premap);
    00614         if (w->stagger_premap) stp_free(w->stagger_premap);
    00615         if (w->pass_postmap) stp_free(w->pass_postmap);
    00616         if (w->stagger_postmap) stp_free(w->stagger_postmap);
    00617         stp_free(w);
    00618 }
    00619
    00620 static void
    00621 stpi_calculate_row_parameters(void *vw,         /* I - weave parameters */
    00622                               int row,          /* I - row number */
    00623                               int subpass,      /* I - subpass */
    00624                               int *pass,        /* O - pass containing row */
    00625                               int *jetnum,      /* O - jet number of row */
    00626                               int *startingrow, /* O - phys start of pass */
    00627                               int *ophantomrows, /* O - missing rows @ start */
    00628                               int *ojetsused)   /* O - jets used by pass */
    00629 {
    00630         cooked_t *w = (cooked_t *) vw;
    00631         int raw_pass, jet, startrow, phantomrows, jetsused;
    00632         int stagger = 0;
    00633         int extra;
    00634
    00635         assert(row >= w->first_row_printed, w->rw.v);
    00636         assert(row <= w->last_row_printed, w->rw.v);
    00637         calculate_raw_row_parameters(&w->rw,
    00638                                      row + w->rw.separation * w->rw.jets,
    00639                                      subpass, &raw_pass, &jet, &startrow);
    00640         startrow -= w->rw.separation * w->rw.jets;
    00641         jetsused = w->rw.jets;
    00642         phantomrows = 0;
    00643
    00644         if (raw_pass < w->first_normal_pass) {
    00645                 assert(raw_pass >= w->first_premapped_pass, w->rw.v);
    00646                 *pass = w->pass_premap[raw_pass - w->first_premapped_pass];
    00647                 stagger = w->stagger_premap[raw_pass - w->first_premapped_pass];
    00648         } else if (raw_pass >= w->first_postmapped_pass) {
    00649                 assert(raw_pass >= w->first_postmapped_pass, w->rw.v);
    00650                 *pass = w->pass_postmap[raw_pass - w->first_postmapped_pass];
    00651                 stagger = w->stagger_postmap[raw_pass
    00652                                              - w->first_postmapped_pass];
    00653         } else {
    00654                 *pass = raw_pass - w->first_premapped_pass;
    00655         }
    00656
    00657         startrow += stagger * w->rw.separation;
    00658         *jetnum = jet - stagger;
    00659         if (stagger < 0) {
    00660                 stagger = -stagger;
    00661                 phantomrows += stagger;
    00662         }
    00663         jetsused -= stagger;
    00664
    00665         extra = w->first_row_printed
    00666                      - (startrow + w->rw.separation * phantomrows);
    00667         if (extra > 0) {
    00668                 extra = (extra + w->rw.separation - 1) / w->rw.separation;
    00669                 jetsused -= extra;
    00670                 phantomrows += extra;
    00671         }
    00672
    00673         extra = startrow + w->rw.separation * (phantomrows + jetsused - 1)
    00674                   - w->last_row_printed;
    00675         if (extra > 0) {
    00676                 extra = (extra + w->rw.separation - 1) / w->rw.separation;
    00677                 jetsused -= extra;
    00678         }
    00679
    00680         *startingrow = startrow;
    00681         *ophantomrows = phantomrows;
    00682         *ojetsused = jetsused;
    00683 }
    00684
    00685 /*
    00686  * "Soft" weave
    00687  *
    00688  * The Epson Stylus Color/Photo printers don't have memory to print
    00689  * using all of the nozzles in the print head.  For example, the Stylus Photo
    00690  * 700/EX has 32 nozzles.  At 720 dpi, with an 8" wide image, a single line
    00691  * requires (8 * 720 * 6 / 8) bytes, or 4320 bytes (because the Stylus Photo
    00692  * printers have 6 ink colors).  To use 32 nozzles would require 138240 bytes.
    00693  * It's actually worse than that, though, because the nozzles are spaced 8
    00694  * rows apart.  Therefore, in order to store enough data to permit sending the
    00695  * page as a simple raster, the printer would require enough memory to store
    00696  * 256 rows, or 1105920 bytes.  Considering that the Photo EX can print
    00697  * 11" wide, we're looking at more like 1.5 MB.  In fact, these printers are
    00698  * capable of 1440 dpi horizontal resolution.  This would require 3 MB.  The
    00699  * printers actually have 64K-256K.
    00700  *
    00701  * With the newer (740/750 and later) printers it's even worse, since these
    00702  * printers support multiple dot sizes.  But that's neither here nor there.
    00703  *
    00704  * Older Epson printers had a mode called MicroWeave (tm).  In this mode, the
    00705  * host fed the printer individual rows of dots, and the printer bundled them
    00706  * up and sent them to the print head in the correct order to achieve high
    00707  * quality.  This MicroWeave mode still works in new printers, but the
    00708  * implementation is very minimal: the printer uses exactly one nozzle of
    00709  * each color (the first one).  This makes printing extremely slow (more than
    00710  * 30 minutes for one 8.5x11" page), although the quality is extremely high
    00711  * with no visible banding whatsoever.  It's not good for the print head,
    00712  * though, since no ink is flowing through the other nozzles.  This leads to
    00713  * drying of ink and possible permanent damage to the print head.
    00714  *
    00715  * By the way, although the Epson manual says that microweave mode should be
    00716  * used at 720 dpi, 360 dpi continues to work in much the same way.  At 360
    00717  * dpi, data is fed to the printer one row at a time on all Epson printers.
    00718  * The pattern that the printer uses to print is very prone to banding.
    00719  * However, 360 dpi is inherently a low quality mode; if you're using it,
    00720  * presumably you don't much care about quality.
    00721  *
    00722  * Printers from roughly the Stylus Color 600 and later do not have the
    00723  * capability to do MicroWeave correctly.  Instead, the host must arrange
    00724  * the output in the order that it will be sent to the print head.  This
    00725  * is a very complex process; the jets in the print head are spaced more
    00726  * than one row (1/720") apart, so we can't simply send consecutive rows
    00727  * of dots to the printer.  Instead, we have to pass e. g. the first, ninth,
    00728  * 17th, 25th... rows in order for them to print in the correct position on
    00729  * the paper.  This interleaving process is called "soft" weaving.
    00730  *
    00731  * This decision was probably made to save money on memory in the printer.
    00732  * It certainly makes the driver code far more complicated than it would
    00733  * be if the printer could arrange the output.  Is that a bad thing?
    00734  * Usually this takes far less CPU time than the dithering process, and it
    00735  * does allow us more control over the printing process, e. g. to reduce
    00736  * banding.  Conceivably, we could even use this ability to map out bad
    00737  * jets.
    00738  *
    00739  * Interestingly, apparently the Windows (and presumably Macintosh) drivers
    00740  * for most or all Epson printers still list a "microweave" mode.
    00741  * Experiments have demonstrated that this does not in fact use the
    00742  * "microweave" mode of the printer.  Possibly it does nothing, or it uses
    00743  * a different weave pattern from what the non-"microweave" mode does.
    00744  * This is unnecessarily confusing.
    00745  *
    00746  * What makes this interesting is that there are many different ways of
    00747  * of accomplishing this goal.  The naive way would be to divide the image
    00748  * up into groups of 256 rows, and print all the mod8=0 rows in the first pass,
    00749  * mod8=1 rows in the second, and so forth.  The problem with this approach
    00750  * is that the individual ink jets are not perfectly uniform; some emit
    00751  * slightly bigger or smaller drops than others.  Since each group of 8
    00752  * adjacent rows is printed with the same nozzle, that means that there will
    00753  * be distinct streaks of lighter and darker bands within the image (8 rows
    00754  * is 1/90", which is visible; 1/720" is not).  Possibly worse is that these
    00755  * patterns will repeat every 256 rows.  This creates banding patterns that
    00756  * are about 1/3" wide.
    00757  *
    00758  * So we have to do something to break up this patterning.
    00759  *
    00760  * Epson does not publish the weaving algorithms that they use in their
    00761  * bundled drivers.  Indeed, their developer web site
    00762  * (http://www.ercipd.com/isv/edr_docs.htm) does not even describe how to
    00763  * do this weaving at all; it says that the only way to achieve 720 dpi
    00764  * is to use MicroWeave.  It does note (correctly) that 1440 dpi horizontal
    00765  * can only be achieved by the driver (i. e. in software).  The manual
    00766  * actually makes it fairly clear how to do this (it requires two passes
    00767  * with horizontal head movement between passes), and it is presumably
    00768  * possible to do this with MicroWeave.
    00769  *
    00770  * The information about how to do this is apparently available under NDA.
    00771  * It's actually easy enough to reverse engineer what's inside a print file
    00772  * with a simple Perl script.  There are presumably other printer commands
    00773  * that are not documented and may not be as easy to reverse engineer.
    00774  *
    00775  * I considered a few algorithms to perform the weave.  The first one I
    00776  * devised let me use only (jets - distance_between_jets + 1) nozzles, or
    00777  * 25.  This is OK in principle, but it's slower than using all nozzles.
    00778  * By playing around with it some more, I came up with an algorithm that
    00779  * lets me use all of the nozzles, except near the top and bottom of the
    00780  * page.
    00781  *
    00782  * This still produces some banding, though.  Even better quality can be
    00783  * achieved by using multiple nozzles on the same line.  How do we do this?
    00784  * In 1440x720 mode, we're printing two output lines at the same vertical
    00785  * position.  However, if we want four passes, we have to effectively print
    00786  * each line twice.  Actually doing this would increase the density, so
    00787  * what we do is print half the dots on each pass.  This produces near-perfect
    00788  * output, and it's far faster than using (pseudo) "MicroWeave".
    00789  *
    00790  * The current algorithm is not completely general.  The number of passes
    00791  * is limited to (nozzles / gap).  On the Photo EX class printers, that limits
    00792  * it to 4 -- 32 nozzles, an inter-nozzle gap of 8 lines.  Furthermore, there
    00793  * are a number of routines that are only coded up to 8 passes.  Fortunately,
    00794  * this is enough passes to get rid of most banding.  What's left is a very
    00795  * fine pattern that is sometimes described as "corduroy", since the pattern
    00796  * looks like that kind of fabric.
    00797  *
    00798  * Newer printers (those that support variable dot sizes, such as the 740,
    00799  * 1200, etc.) have an additional complication: when used in softweave mode,
    00800  * they operate at 360 dpi horizontal resolution.  This requires FOUR passes
    00801  * to achieve 1440x720 dpi.  Thus, to enable us to break up each row
    00802  * into separate sub-rows, we have to actually print each row eight times.
    00803  * Fortunately, all such printers have 48 nozzles and a gap of 6 rows,
    00804  * except for the high-speed 900, which uses 96 nozzles and a gap of 2 rows.
    00805  *
    00806  * I cannot let this entirely pass without commenting on the Stylus Color 440.
    00807  * This is a very low-end printer with 21 (!) nozzles and a separation of 8.
    00808  * The weave routine works correctly with single-pass printing, which is enough
    00809  * to minimally achieve 720 dpi output (it's physically a 720 dpi printer).
    00810  * However, the routine does not work correctly at more than one pass per row.
    00811  * Therefore, this printer bands badly.
    00812  *
    00813  * Yet another complication is how to get near the top and bottom of the page.
    00814  * This algorithm lets us print to within one head width of the top of the
    00815  * page, and a bit more than one head width from the bottom.  That leaves a
    00816  * lot of blank space.  Doing the weave properly outside of this region is
    00817  * increasingly difficult as we get closer to the edge of the paper; in the
    00818  * interior region, any nozzle can print any line, but near the top and
    00819  * bottom edges, only some nozzles can print.  We've handled this for now by
    00820  * using the naive way mentioned above near the borders, and switching over
    00821  * to the high quality method in the interior.  Unfortunately, this means
    00822  * that the quality is quite visibly degraded near the top and bottom of the
    00823  * page.  Algorithms that degrade more gracefully are more complicated.
    00824  * Epson does not advertise that the printers can print at the very top of the
    00825  * page, although in practice most or all of them can.  I suspect that the
    00826  * quality that can be achieved very close to the top is poor enough that
    00827  * Epson does not want to allow printing there.  That is a valid decision,
    00828  * although we have taken another approach.
    00829  *
    00830  * To compute the weave information, we need to start with the following
    00831  * information:
    00832  *
    00833  * 1) The number of jets the print head has for each color;
    00834  *
    00835  * 2) The separation in rows between the jets;
    00836  *
    00837  * 3) The horizontal resolution of the printer;
    00838  *
    00839  * 4) The desired horizontal resolution of the output;
    00840  *
    00841  * 5) The desired extra passes to reduce banding.
    00842  *
    00843  * As discussed above, each row is actually printed in one or more passes
    00844  * of the print head; we refer to these as subpasses.  For example, if we're
    00845  * printing at 1440(h)x720(v) on a printer with true horizontal resolution of
    00846  * 360 dpi, and we wish to print each line twice with different nozzles
    00847  * to reduce banding, we need to use 8 subpasses.  The dither routine
    00848  * will feed us a complete row of bits for each color; we have to split that
    00849  * up, first by round robining the bits to ensure that they get printed at
    00850  * the right micro-position, and then to split up the bits that are actually
    00851  * turned on into two equal chunks to reduce banding.
    00852  *
    00853  * Given the above information, and the desired row index and subpass (which
    00854  * together form a line number), we can compute:
    00855  *
    00856  * 1) Which pass this line belongs to.  Passes are numbered consecutively,
    00857  *    and each pass must logically (see #3 below) start at no smaller a row
    00858  *    number than the previous pass, as the printer cannot advance by a
    00859  *    negative amount.
    00860  *
    00861  * 2) Which jet will print this line.
    00862  *
    00863  * 3) The "logical" first line of this pass.  That is, what line would be
    00864  *    printed by jet 0 in this pass.  This number may be less than zero.
    00865  *    If it is, there are ghost lines that don't actually contain any data.
    00866  *    The difference between the logical first line of this pass and the
    00867  *    logical first line of the preceding pass tells us how many lines must
    00868  *    be advanced.
    00869  *
    00870  * 4) The "physical" first line of this pass.  That is, the first line index
    00871  *    that is actually printed in this pass.  This information lets us know
    00872  *    when we must prepare this pass.
    00873  *
    00874  * 5) The last line of this pass.  This lets us know when we must actually
    00875  *    send this pass to the printer.
    00876  *
    00877  * 6) The number of ghost rows this pass contains.  We must still send the
    00878  *    ghost data to the printer, so this lets us know how much data we must
    00879  *    fill in prior to the start of the pass.
    00880  *
    00881  * The bookkeeping to keep track of all this stuff is quite hairy, and needs
    00882  * to be documented separately.
    00883  *
    00884  * The routine initialize_weave calculates the basic parameters, given
    00885  * the number of jets and separation between jets, in rows.
    00886  *
    00887  * -- Robert Krawitz <rlk@alum.mit.edu) November 3, 1999
    00888  */
    00889
    00890 static stp_lineoff_t *
    00891 allocate_lineoff(int count, int ncolors)
    00892 {
    00893   int i;
    00894   stp_lineoff_t *retval = stp_malloc(count * sizeof(stp_lineoff_t));
    00895   for (i = 0; i < count; i++)
    00896     {
    00897       retval[i].ncolors = ncolors;
    00898       retval[i].v = stp_zalloc(ncolors * sizeof(unsigned long));
    00899     }
    00900   return (retval);
    00901 }
    00902
    00903 static stp_lineactive_t *
    00904 allocate_lineactive(int count, int ncolors)
    00905 {
    00906   int i;
    00907   stp_lineactive_t *retval = stp_malloc(count * sizeof(stp_lineactive_t));
    00908   for (i = 0; i < count; i++)
    00909     {
    00910       retval[i].ncolors = ncolors;
    00911       retval[i].v = stp_zalloc(ncolors * sizeof(char));
    00912     }
    00913   return (retval);
    00914 }
    00915
    00916 static stp_linecount_t *
    00917 allocate_linecount(int count, int ncolors)
    00918 {
    00919   int i;
    00920   stp_linecount_t *retval = stp_malloc(count * sizeof(stp_linecount_t));
    00921   for (i = 0; i < count; i++)
    00922     {
    00923       retval[i].ncolors = ncolors;
    00924       retval[i].v = stp_zalloc(ncolors * sizeof(int));
    00925     }
    00926   return (retval);
    00927 }
    00928
    00929 static stp_linebounds_t *
    00930 allocate_linebounds(int count, int ncolors)
    00931 {
    00932   int i;
    00933   stp_linebounds_t *retval = stp_malloc(count * sizeof(stp_linebounds_t));
    00934   for (i = 0; i < count; i++)
    00935     {
    00936       retval[i].ncolors = ncolors;
    00937       retval[i].start_pos = stp_zalloc(ncolors * sizeof(int));
    00938       retval[i].end_pos = stp_zalloc(ncolors * sizeof(int));
    00939     }
    00940   return (retval);
    00941 }
    00942
    00943 static stp_linebufs_t *
    00944 allocate_linebuf(int count, int ncolors)
    00945 {
    00946   int i;
    00947   stp_linebufs_t *retval = stp_malloc(count * sizeof(stp_linebufs_t));
    00948   for (i = 0; i < count; i++)
    00949     {
    00950       retval[i].ncolors = ncolors;
    00951       retval[i].v = stp_zalloc(ncolors * sizeof(unsigned char *));
    00952     }
    00953   return (retval);
    00954 }
    00955
    00956 /*
    00957  * Initialize the weave parameters
    00958  *
    00959  * Rules:
    00960  *
    00961  * 1) Currently, osample * v_subpasses * v_subsample <= 8, and no one
    00962  *    of these variables may exceed 4.
    00963  *
    00964  * 2) first_line >= 0
    00965  *
    00966  * 3) line_height < physlines
    00967  *
    00968  * 4) page_height >= 2 * jets * sep
    00969  */
    00970
    00971 static void
    00972 stpi_destroy_weave(void *vsw)
    00973 {
    00974   int i, j;
    00975   stpi_softweave_t *sw = (stpi_softweave_t *) vsw;
    00976   stp_free(sw->passes);
    00977   if (sw->fold_buf)
    00978     stp_free(sw->fold_buf);
    00979   if (sw->comp_buf)
    00980     stp_free(sw->comp_buf);
    00981   for (i = 0; i < STP_MAX_WEAVE; i++)
    00982     if (sw->s[i])
    00983       stp_free(sw->s[i]);
    00984   for (i = 0; i < sw->vmod; i++)
    00985     {
    00986       for (j = 0; j < sw->ncolors; j++)
    00987         {
    00988           if (sw->linebases[i].v[j])
    00989             stp_free(sw->linebases[i].v[j]);
    00990         }
    00991       stp_free(sw->linecounts[i].v);
    00992       stp_free(sw->linebases[i].v);
    00993       stp_free(sw->lineactive[i].v);
    00994       stp_free(sw->lineoffsets[i].v);
    00995       stp_free(sw->linebounds[i].start_pos);
    00996       stp_free(sw->linebounds[i].end_pos);
    00997     }
    00998   stp_free(sw->linecounts);
    00999   stp_free(sw->lineactive);
    01000   stp_free(sw->lineoffsets);
    01001   stp_free(sw->linebases);
    01002   stp_free(sw->linebounds);
    01003   stp_free(sw->head_offset);
    01004   stpi_destroy_weave_params(sw->weaveparm);
    01005   stp_free(vsw);
    01006 }
    01007
    01008 void
    01009 stp_initialize_weave(stp_vars_t *v,
    01010                      int jets,  /* Width of print head */
    01011                      int sep,   /* Separation in rows between jets */
    01012                      int osample,       /* Horizontal oversample */
    01013                      int v_subpasses, /* Vertical passes */
    01014                      int v_subsample, /* Vertical oversampling */
    01015                      int ncolors,
    01016                      int bitwidth,      /* bits/pixel */
    01017                      int linewidth,     /* Width of a line, in pixels */
    01018                      int line_count, /* Lines that will be printed */
    01019                      int first_line, /* First line that will be printed */
    01020                      int page_height, /* Total height of the page in rows */
    01021                      const int *head_offset,
    01022                      stp_weave_strategy_t weave_strategy,
    01023                      stp_flushfunc flushfunc,
    01024                      stp_fillfunc fillfunc,
    01025                      stp_packfunc pack,
    01026                      stp_compute_linewidth_func compute_linewidth)
    01027 {
    01028   int i;
    01029   int last_line, maxHeadOffset;
    01030   stpi_softweave_t *sw = stp_zalloc(sizeof (stpi_softweave_t));
    01031
    01032   if (jets < 1)
    01033     jets = 1;
    01034   if (jets == 1 || sep < 1)
    01035     sep = 1;
    01036   if (v_subpasses < 1)
    01037     v_subpasses = 1;
    01038   if (v_subsample < 1)
    01039     v_subsample = 1;
    01040
    01041   sw->separation = sep;
    01042   sw->jets = jets;
    01043   sw->horizontal_weave = osample;
    01044   sw->oversample = osample * v_subpasses * v_subsample;
    01045   if (sw->oversample > jets)
    01046     {
    01047       int found = 0;
    01048       for (i = 2; i <= osample; i++)
    01049         {
    01050           if ((osample % i == 0) && (sw->oversample / i <= jets))
    01051             {
    01052               sw->repeat_count = i;
    01053               osample /= i;
    01054               found = 1;
    01055               break;
    01056             }
    01057         }
    01058       if (!found)
    01059         {
    01060           stp_eprintf(v, "Weave error: oversample (%d) > jets (%d)\n",
    01061                       sw->oversample, jets);
    01062           stp_free(sw);
    01063           return;
    01064         }
    01065     }
    01066   else
    01067     sw->repeat_count = 1;
    01068
    01069   sw->vertical_oversample = v_subsample;
    01070   sw->vertical_subpasses = v_subpasses;
    01071   sw->oversample = osample * v_subpasses * v_subsample;
    01072   sw->firstline = first_line;
    01073   sw->lineno = first_line;
    01074   sw->flushfunc = flushfunc;
    01075
    01076   if (sw->oversample > jets)
    01077     {
    01078       stp_eprintf(v, "Weave error: oversample (%d) > jets (%d)\n",
    01079                   sw->oversample, jets);
    01080       stp_free(sw);
    01081       return;
    01082     }
    01083
    01084   /*
    01085    * setup printhead offsets.
    01086    * for monochrome (bw) printing, the offsets are 0.
    01087    */
    01088   sw->head_offset = stp_zalloc(ncolors * sizeof(int));
    01089   if (ncolors > 1)
    01090     for(i = 0; i < ncolors; i++)
    01091       sw->head_offset[i] = head_offset[i];
    01092
    01093   maxHeadOffset = 0;
    01094   for (i = 0; i < ncolors; i++)
    01095     if (sw->head_offset[i] > maxHeadOffset)
    01096       maxHeadOffset = sw->head_offset[i];
    01097
    01098   sw->virtual_jets = sw->jets;
    01099   if (maxHeadOffset > 0)
    01100     sw->virtual_jets += (maxHeadOffset + sw->separation - 1) / sw->separation;
    01101   last_line = first_line + line_count - 1 + maxHeadOffset;
    01102
    01103   sw->weaveparm = initialize_weave_params(sw->separation, sw->jets,
    01104                                           sw->oversample, first_line, last_line,
    01105                                           page_height, weave_strategy, v);
    01106   /*
    01107    * The value of vmod limits how many passes may be unfinished at a time.
    01108    * If pass x is not yet printed, pass x+vmod cannot be started.
    01109    *
    01110    * The multiplier of 2: 1 for the normal passes, 1 for the special passes
    01111    * at the start or end.
    01112    */
    01113   sw->vmod = 2 * sw->separation * sw->oversample * sw->repeat_count;
    01114   if (sw->virtual_jets > sw->jets)
    01115     sw->vmod *= (sw->virtual_jets + sw->jets - 1) / sw->jets;
    01116
    01117   sw->bitwidth = bitwidth;
    01118   sw->last_pass_offset = 0;
    01119   sw->last_pass = -1;
    01120   sw->current_vertical_subpass = 0;
    01121   sw->ncolors = ncolors;
    01122   sw->linewidth = linewidth;
    01123   sw->vertical_height = line_count;
    01124   sw->lineoffsets = allocate_lineoff(sw->vmod, ncolors);
    01125   sw->lineactive = allocate_lineactive(sw->vmod, ncolors);
    01126   sw->linebases = allocate_linebuf(sw->vmod, ncolors);
    01127   sw->linebounds = allocate_linebounds(sw->vmod, ncolors);
    01128   sw->passes = stp_zalloc(sw->vmod * sizeof(stp_pass_t));
    01129   sw->linecounts = allocate_linecount(sw->vmod, ncolors);
    01130   sw->rcache = -2;
    01131   sw->vcache = -2;
    01132   sw->fillfunc = fillfunc;
    01133   sw->compute_linewidth = compute_linewidth;
    01134   sw->pack = pack;
    01135   sw->horizontal_width =
    01136     (sw->compute_linewidth)(v, ((sw->linewidth + sw->horizontal_weave - 1) /
    01137                                  sw->horizontal_weave));
    01138   sw->horizontal_width = ((sw->horizontal_width + 7) / 8);
    01139
    01140   for (i = 0; i < sw->vmod; i++)
    01141     {
    01142       int j;
    01143       sw->passes[i].pass = -1;
    01144       for (j = 0; j < sw->ncolors; j++)
    01145         {
    01146           sw->linebases[i].v[j] = NULL;
    01147         }
    01148     }
    01149   stp_allocate_component_data(v, "Weave", NULL, stpi_destroy_weave, sw);
    01150   return;
    01151 }
    01152
    01153 static void
    01154 weave_parameters_by_row(const stp_vars_t *v, const stpi_softweave_t *sw,
    01155                         int row, int vertical_subpass, stp_weave_t *w)
    01156 {
    01157   int jetsused;
    01158   int sub_repeat_count = vertical_subpass % sw->repeat_count;
    01159   /*
    01160    * Conceptually, this does not modify the softweave state.  We cache
    01161    * the results, but this cache is considered hidden.
    01162    */
    01163   stpi_softweave_t *wsw = (stpi_softweave_t *) sw;
    01164   vertical_subpass /= sw->repeat_count;
    01165
    01166   if (sw->rcache == row && sw->vcache == vertical_subpass)
    01167     {
    01168       memcpy(w, &sw->wcache, sizeof(stp_weave_t));
    01169       w->pass = (w->pass * sw->repeat_count) + sub_repeat_count;
    01170       return;
    01171     }
    01172   wsw->rcache = row;
    01173   wsw->vcache = vertical_subpass;
    01174
    01175   w->row = row;
    01176   stpi_calculate_row_parameters(sw->weaveparm, row, vertical_subpass,
    01177                                 &w->pass, &w->jet, &w->logicalpassstart,
    01178                                 &w->missingstartrows, &jetsused);
    01179
    01180   w->physpassstart = w->logicalpassstart + sw->separation * w->missingstartrows;
    01181   w->physpassend = w->physpassstart + sw->separation * (jetsused - 1);
    01182
    01183   memcpy(&(((stpi_softweave_t *) wsw)->wcache), w, sizeof(stp_weave_t));
    01184   w->pass = (w->pass * sw->repeat_count) + sub_repeat_count;
    01185   stp_dprintf(STP_DBG_WEAVE_PARAMS, v, "row %d, jet %d of pass %d "
    01186               "(pos %d, start %d, end %d, missing rows %d)\n",
    01187               w->row, w->jet, w->pass, w->logicalpassstart, w->physpassstart,
    01188               w->physpassend, w->missingstartrows);
    01189 }
    01190
    01191 void
    01192 stp_weave_parameters_by_row(const stp_vars_t *v, int row,
    01193                             int vertical_subpass, stp_weave_t *w)
    01194 {
    01195   const stpi_softweave_t *sw =
    01196     (stpi_softweave_t *) stp_get_component_data(v, "Weave");
    01197   weave_parameters_by_row(v, sw, row, vertical_subpass, w);
    01198 }
    01199
    01200
    01201 static stp_lineoff_t *
    01202 stpi_get_lineoffsets(const stp_vars_t *v, const stpi_softweave_t *sw,
    01203                      int row, int subpass, int offset)
    01204 {
    01205   stp_weave_t w;
    01206   weave_parameters_by_row(v, sw, row + offset, subpass, &w);
    01207   return &(sw->lineoffsets[w.pass % sw->vmod]);
    01208 }
    01209
    01210 static stp_lineactive_t *
    01211 stpi_get_lineactive(const stp_vars_t *v, const stpi_softweave_t *sw,
    01212                     int row, int subpass, int offset)
    01213 {
    01214   stp_weave_t w;
    01215   weave_parameters_by_row(v, sw, row + offset, subpass, &w);
    01216   return &(sw->lineactive[w.pass % sw->vmod]);
    01217 }
    01218
    01219 static stp_linecount_t *
    01220 stpi_get_linecount(const stp_vars_t *v, const stpi_softweave_t *sw,
    01221                    int row, int subpass, int offset)
    01222 {
    01223   stp_weave_t w;
    01224   weave_parameters_by_row(v, sw, row + offset, subpass, &w);
    01225   return &(sw->linecounts[w.pass % sw->vmod]);
    01226 }
    01227
    01228 static stp_linebufs_t *
    01229 stpi_get_linebases(const stp_vars_t *v, const stpi_softweave_t *sw,
    01230                    int row, int subpass, int offset)
    01231 {
    01232   stp_weave_t w;
    01233   weave_parameters_by_row(v, sw, row + offset, subpass, &w);
    01234   return &(sw->linebases[w.pass % sw->vmod]);
    01235 }
    01236
    01237 static stp_linebounds_t *
    01238 stpi_get_linebounds(const stp_vars_t *v, const stpi_softweave_t *sw,
    01239                     int row, int subpass, int offset)
    01240 {
    01241   stp_weave_t w;
    01242   weave_parameters_by_row(v, sw, row + offset, subpass, &w);
    01243   return &(sw->linebounds[w.pass % sw->vmod]);
    01244 }
    01245
    01246 static stp_pass_t *
    01247 stpi_get_pass_by_row(stp_vars_t *v, const stpi_softweave_t *sw,
    01248                      int row, int subpass,int offset)
    01249 {
    01250   stp_weave_t w;
    01251   weave_parameters_by_row(v, sw, row + offset, subpass, &w);
    01252   return &(sw->passes[w.pass % sw->vmod]);
    01253 }
    01254
    01255 stp_lineoff_t *
    01256 stp_get_lineoffsets_by_pass(const stp_vars_t *v, int pass)
    01257 {
    01258   const stpi_softweave_t *sw =
    01259     (stpi_softweave_t *) stp_get_component_data(v, "Weave");
    01260   return &(sw->lineoffsets[pass % sw->vmod]);
    01261 }
    01262
    01263 stp_lineactive_t *
    01264 stp_get_lineactive_by_pass(const stp_vars_t *v, int pass)
    01265 {
    01266   const stpi_softweave_t *sw =
    01267     (stpi_softweave_t *) stp_get_component_data(v, "Weave");
    01268   return &(sw->lineactive[pass % sw->vmod]);
    01269 }
    01270
    01271 stp_linecount_t *
    01272 stp_get_linecount_by_pass(const stp_vars_t *v, int pass)
    01273 {
    01274   const stpi_softweave_t *sw =
    01275     (stpi_softweave_t *) stp_get_component_data(v, "Weave");
    01276   return &(sw->linecounts[pass % sw->vmod]);
    01277 }
    01278
    01279 const stp_linebufs_t *
    01280 stp_get_linebases_by_pass(const stp_vars_t *v, int pass)
    01281 {
    01282   const stpi_softweave_t *sw =
    01283     (stpi_softweave_t *) stp_get_component_data(v, "Weave");
    01284   return &(sw->linebases[pass % sw->vmod]);
    01285 }
    01286
    01287 stp_pass_t *
    01288 stp_get_pass_by_pass(const stp_vars_t *v, int pass)
    01289 {
    01290   const stpi_softweave_t *sw =
    01291     (stpi_softweave_t *) stp_get_component_data(v, "Weave");
    01292   return &(sw->passes[pass % sw->vmod]);
    01293 }
    01294
    01295 static void
    01296 check_linebases(stp_vars_t *v, const stpi_softweave_t *sw,
    01297                 int row, int cpass, int head_offset, int color)
    01298 {
    01299   stp_linebufs_t *bufs =
    01300     (stp_linebufs_t *) stpi_get_linebases(v, sw, row, cpass, head_offset);
    01301   if (!(bufs[0].v[color]))
    01302     bufs[0].v[color] =
    01303       stp_zalloc (sw->virtual_jets * sw->bitwidth * sw->horizontal_width);
    01304 }
    01305
    01306 /*
    01307  * If there are phantom rows at the beginning of a pass, fill them in so
    01308  * that the printer knows exactly what it doesn't have to print.  We're
    01309  * using RLE compression here.  Each line must be specified independently,
    01310  * so we have to compute how many full blocks (groups of 128 bytes, or 1024
    01311  * "off" pixels) and how much leftover is needed.  Note that we can only
    01312  * RLE-encode groups of 2 or more bytes; single bytes must be specified
    01313  * with a count of 1.
    01314  */
    01315
    01316 void
    01317 stp_fill_tiff(stp_vars_t *v, int row, int subpass,
    01318               int width, int missingstartrows, int color)
    01319 {
    01320   stpi_softweave_t *sw =
    01321     (stpi_softweave_t *) stp_get_component_data(v, "Weave");
    01322   stp_lineoff_t *lineoffs;
    01323   stp_linecount_t *linecount;
    01324   const stp_linebufs_t *bufs;
    01325   int i = 0;
    01326   int k = 0;
    01327
    01328   width = sw->bitwidth * width * 8;
    01329   for (k = 0; k < missingstartrows; k++)
    01330     {
    01331       int bytes_to_fill = width;
    01332       int full_blocks = bytes_to_fill / (128 * 8);
    01333       int leftover = (7 + (bytes_to_fill % (128 * 8))) / 8;
    01334       int l = 0;
    01335       bufs = stpi_get_linebases(v, sw, row, subpass, sw->head_offset[color]);
    01336
    01337       while (l < full_blocks)
    01338         {
    01339           (bufs[0].v[color][2 * i]) = 129;
    01340           (bufs[0].v[color][2 * i + 1]) = 0;
    01341           i++;
    01342           l++;
    01343         }
    01344       if (leftover == 1)
    01345         {
    01346           (bufs[0].v[color][2 * i]) = 1;
    01347           (bufs[0].v[color][2 * i + 1]) = 0;
    01348           i++;
    01349         }
    01350       else if (leftover > 0)
    01351         {
    01352           (bufs[0].v[color][2 * i]) = 257 - leftover;
    01353           (bufs[0].v[color][2 * i + 1]) = 0;
    01354           i++;
    01355         }
    01356     }
    01357
    01358   lineoffs = stpi_get_lineoffsets(v, sw, row, subpass, sw->head_offset[color]);
    01359   linecount = stpi_get_linecount(v, sw, row, subpass, sw->head_offset[color]);
    01360   lineoffs[0].v[color] = 2 * i;
    01361   linecount[0].v[color] = missingstartrows;
    01362 }
    01363
    01364 void
    01365 stp_fill_uncompressed(stp_vars_t *v, int row, int subpass,
    01366                       int width, int missingstartrows, int color)
    01367 {
    01368   stpi_softweave_t *sw =
    01369     (stpi_softweave_t *) stp_get_component_data(v, "Weave");
    01370   stp_lineoff_t *lineoffs;
    01371   stp_linecount_t *linecount;
    01372   const stp_linebufs_t *bufs;
    01373
    01374   bufs = stpi_get_linebases(v, sw, row, subpass, sw->head_offset[color]);
    01375   lineoffs = stpi_get_lineoffsets(v, sw, row, subpass, sw->head_offset[color]);
    01376   linecount = stpi_get_linecount(v, sw, row, subpass, sw->head_offset[color]);
    01377   width *= sw->bitwidth * missingstartrows;
    01378   memset(bufs[0].v[color], 0, width);
    01379   lineoffs[0].v[color] = width;
    01380   linecount[0].v[color] = missingstartrows;
    01381 }
    01382
    01383 int
    01384 stp_compute_tiff_linewidth(stp_vars_t *v, int n)
    01385 {
    01386   /*
    01387    * It's possible for the "compression" to actually expand the line by
    01388    * roughly one part in 128.
    01389    */
    01390   return ((n + 128 + 7) * 129 / 128);
    01391 }
    01392
    01393 int
    01394 stp_compute_uncompressed_linewidth(stp_vars_t *v, int n)
    01395 {
    01396   return (8 * ((n + 7) / 8));
    01397 }
    01398
    01399 static void
    01400 initialize_row(stp_vars_t *v, stpi_softweave_t *sw,
    01401                int row, int width, unsigned char *const cols[])
    01402 {
    01403   stp_weave_t w;
    01404   int i, j, jj;
    01405   stp_pass_t *pass;
    01406
    01407   for (i = 0; i < sw->oversample; i++)
    01408     {
    01409       for (j = 0; j < sw->ncolors; j++)
    01410         {
    01411           if (cols[j])
    01412             {
    01413               stp_lineoff_t *lineoffs =
    01414                 stpi_get_lineoffsets(v, sw, row, i, sw->head_offset[j]);
    01415               stp_lineactive_t *lineactive =
    01416                 stpi_get_lineactive(v, sw, row, i, sw->head_offset[j]);
    01417               stp_linecount_t *linecount =
    01418                 stpi_get_linecount(v, sw, row, i, sw->head_offset[j]);
    01419               stp_linebounds_t *linebounds =
    01420                 stpi_get_linebounds(v, sw, row, i, sw->head_offset[j]);
    01421               check_linebases(v, sw, row, i, sw->head_offset[j], j);
    01422               weave_parameters_by_row(v, sw, row+sw->head_offset[j], i, &w);
    01423               pass = stpi_get_pass_by_row(v, sw, row, i, sw->head_offset[j]);
    01424
    01425               /* initialize pass if not initialized yet */
    01426               if (pass->pass < 0)
    01427                 {
    01428                   pass->pass = w.pass;
    01429                   pass->missingstartrows = w.missingstartrows;
    01430                   pass->logicalpassstart = w.logicalpassstart;
    01431                   pass->physpassstart = w.physpassstart;
    01432                   pass->physpassend = w.physpassend;
    01433                   pass->subpass = i;
    01434
    01435                   for(jj=0; jj<sw->ncolors; jj++)
    01436                     {
    01437                       if (lineoffs[0].v[jj] != 0)
    01438                         stp_eprintf(v, "WARNING: pass %d subpass %d row %d: "
    01439                                     "lineoffs %ld should be zero!\n",
    01440                                     w.pass, i, row, lineoffs[0].v[jj]);
    01441                       lineoffs[0].v[jj] = 0;
    01442                       lineactive[0].v[jj] = 0;
    01443                       if (linecount[0].v[jj] != 0)
    01444                         stp_eprintf(v, "WARNING: pass %d subpass %d row %d: "
    01445                                     "linecount %d should be zero!\n",
    01446                                     w.pass, i, row, linecount[0].v[jj]);
    01447                       linecount[0].v[jj] = 0;
    01448                       linebounds[0].start_pos[jj] = INT_MAX;
    01449                       linebounds[0].end_pos[jj] = -1;
    01450                     }
    01451                 }
    01452
    01453               if((linecount[0].v[j] == 0) && (w.jet > 0))
    01454                 {
    01455                   (sw->fillfunc)(v, row, i, width, w.jet, j);
    01456                 }
    01457             }
    01458         }
    01459     }
    01460 }
    01461
    01462 static void
    01463 add_to_row(stp_vars_t *v, stpi_softweave_t *sw, int row, unsigned char *buf,
    01464            size_t nbytes, int color, int setactive, int h_pass)
    01465 {
    01466   const stp_linebufs_t *bufs =
    01467     stpi_get_linebases(v, sw, sw->lineno, h_pass, sw->head_offset[color]);
    01468   stp_lineoff_t *lineoffs =
    01469     stpi_get_lineoffsets(v, sw, sw->lineno, h_pass, sw->head_offset[color]);
    01470   stp_lineactive_t *lineactive =
    01471     stpi_get_lineactive(v, sw, sw->lineno, h_pass, sw->head_offset[color]);
    01472   stp_linecount_t *linecount =
    01473     stpi_get_linecount(v, sw, sw->lineno, h_pass, sw->head_offset[color]);
    01474   size_t place = lineoffs[0].v[color];
    01475   size_t count = linecount[0].v[color];
    01476   if (place + nbytes > sw->virtual_jets * sw->bitwidth * sw->horizontal_width)
    01477     {
    01478       stp_eprintf(v, "Buffer overflow: limit %d, actual %d, count %d\n",
    01479                   sw->virtual_jets * sw->bitwidth * sw->horizontal_width,
    01480                   place + nbytes, count);
    01481       stp_abort();
    01482     }
    01483   memcpy(bufs[0].v[color] + lineoffs[0].v[color], buf, nbytes);
    01484   lineoffs[0].v[color] += nbytes;
    01485   if (setactive)
    01486     lineactive[0].v[color] = 1;
    01487 }
    01488
    01489 static void
    01490 stpi_flush_passes(stp_vars_t *v, int flushall)
    01491 {
    01492   stpi_softweave_t *sw =
    01493     (stpi_softweave_t *) stp_get_component_data(v, "Weave");
    01494   while (1)
    01495     {
    01496       stp_pass_t *pass = stp_get_pass_by_pass(v, sw->last_pass + 1);
    01497       /*
    01498        * This ought to be   pass->physpassend >  sw->lineno
    01499        * but that causes rubbish to be output for some reason.
    01500        */
    01501       if (pass->pass < 0 || (!flushall && pass->physpassend >= sw->lineno))
    01502         return;
    01503       (sw->flushfunc)(v, pass->pass, pass->subpass);
    01504       sw->last_pass = pass->pass;
    01505       pass->pass = -1;
    01506     }
    01507 }
    01508
    01509 void
    01510 stp_flush_all(stp_vars_t *v)
    01511 {
    01512   stpi_flush_passes(v, 1);
    01513 }
    01514
    01515 static void
    01516 finalize_row(stp_vars_t *v, int row)
    01517 {
    01518   stpi_softweave_t *sw =
    01519     (stpi_softweave_t *) stp_get_component_data(v, "Weave");
    01520   int i,j;
    01521   stp_dprintf(STP_DBG_ROWS, v, "Finalizing row %d...\n", row);
    01522   for (i = 0; i < sw->oversample; i++)
    01523     {
    01524       stp_weave_t w;
    01525       stp_linecount_t *lines;
    01526
    01527       for(j=0; j<sw->ncolors; j++)
    01528         {
    01529           lines = stpi_get_linecount(v, sw, row, i, sw->head_offset[j]);
    01530           lines[0].v[j]++;
    01531         }
    01532
    01533       weave_parameters_by_row(v, sw, row, i, &w);
    01534       if (w.physpassend == row)
    01535         {
    01536           stp_dprintf(STP_DBG_ROWS, v,
    01537                       "Pass=%d, physpassend=%d, row=%d, lineno=%d, flush..\n",
    01538                       w.pass, w.physpassend, row, sw->lineno);
    01539           stpi_flush_passes(v, 0);
    01540         }
    01541     }
    01542 }
    01543
    01544 void
    01545 stp_write_weave(stp_vars_t *v, unsigned char *const cols[])
    01546 {
    01547   stpi_softweave_t *sw =
    01548     (stpi_softweave_t *) stp_get_component_data(v, "Weave");
    01549   int length = (sw->linewidth + 7) / 8;
    01550   stp_lineoff_t *lineoffs[STP_MAX_WEAVE];
    01551   stp_lineactive_t *lineactives[STP_MAX_WEAVE];
    01552   stp_linecount_t *linecounts[STP_MAX_WEAVE];
    01553   stp_linebounds_t *linebounds[STP_MAX_WEAVE];
    01554   const stp_linebufs_t *bufs[STP_MAX_WEAVE];
    01555   int xlength = (length + sw->horizontal_weave - 1) / sw->horizontal_weave;
    01556   int ylength = xlength * sw->horizontal_weave;
    01557   unsigned char *comp_ptr;
    01558   int i, j;
    01559   int setactive;
    01560   int h_passes = sw->horizontal_weave * sw->vertical_subpasses;
    01561   int cpass = sw->current_vertical_subpass * h_passes;
    01562
    01563   if (!sw->fold_buf)
    01564     sw->fold_buf = stp_zalloc(sw->bitwidth * ylength);
    01565   if (!sw->comp_buf)
    01566     sw->comp_buf = stp_zalloc(sw->bitwidth *
    01567                                (sw->compute_linewidth)(v,ylength));
    01568   if (sw->current_vertical_subpass == 0)
    01569     initialize_row(v, sw, sw->lineno, xlength, cols);
    01570
    01571   for (j = 0; j < sw->ncolors; j++)
    01572     {
    01573       if (cols[j])
    01574         {
    01575           const unsigned char *in;
    01576           int idx;
    01577
    01578           for (i = 0; i < h_passes; i++)
    01579             {
    01580               int offset = sw->head_offset[j];
    01581               int pass = cpass + i;
    01582               if (!sw->s[i])
    01583                 sw->s[i] = stp_zalloc(sw->bitwidth *
    01584                                       (sw->compute_linewidth)(v, ylength));
    01585               lineoffs[i] =
    01586                 stpi_get_lineoffsets(v, sw, sw->lineno, pass, offset);
    01587               linecounts[i] =
    01588                 stpi_get_linecount(v, sw, sw->lineno, pass, offset);
    01589               lineactives[i] =
    01590                 stpi_get_lineactive(v, sw, sw->lineno, pass,offset);
    01591               linebounds[i] =
    01592                 stpi_get_linebounds(v, sw, sw->lineno, pass, offset);
    01593               bufs[i] =
    01594                 stpi_get_linebases(v, sw, sw->lineno, pass, offset);
    01595             }
    01596
    01597           if (sw->bitwidth == 2)
    01598             {
    01599               stp_fold(cols[j], length, sw->fold_buf);
    01600               in = sw->fold_buf;
    01601             }
    01602           else
    01603             in = cols[j];
    01604           switch (sw->horizontal_weave)
    01605             {
    01606             case 1:
    01607               memcpy(sw->s[0], in, length * sw->bitwidth);
    01608               break;
    01609             case 2:
    01610               stp_unpack_2(length, sw->bitwidth, in, sw->s[0], sw->s[1]);
    01611               break;
    01612             case 4:
    01613               stp_unpack_4(length, sw->bitwidth, in,
    01614                            sw->s[0], sw->s[1], sw->s[2], sw->s[3]);
    01615               break;
    01616             case 8:
    01617               stp_unpack_8(length, sw->bitwidth, in,
    01618                            sw->s[0], sw->s[1], sw->s[2], sw->s[3],
    01619                            sw->s[4], sw->s[5], sw->s[6], sw->s[7]);
    01620               break;
    01621             }
    01622           switch (sw->vertical_subpasses)
    01623             {
    01624             case 4:
    01625               for (idx = 0; idx < sw->horizontal_weave; idx++)
    01626                 stp_split_4(length, sw->bitwidth, sw->s[idx], sw->s[idx],
    01627                             sw->s[idx + sw->horizontal_weave],
    01628                             sw->s[idx + sw->horizontal_weave * 2],
    01629                             sw->s[idx + sw->horizontal_weave * 3]);
    01630               break;
    01631             case 2:
    01632               for (idx = 0; idx < sw->horizontal_weave; idx++)
    01633                 stp_split_2(length, sw->bitwidth, sw->s[idx], sw->s[idx],
    01634                             sw->s[idx + sw->horizontal_weave]);
    01635               break;
    01636               /* case 1 is taken care of because the various unpack */
    01637               /* functions will do the trick themselves */
    01638             }
    01639           for (i = 0; i < h_passes; i++)
    01640             {
    01641               int first, last;
    01642               setactive = (sw->pack)(v, sw->s[i], sw->bitwidth * xlength,
    01643                                      sw->comp_buf, &comp_ptr, &first, &last);
    01644               if (first < linebounds[i]->start_pos[j])
    01645                 linebounds[i]->start_pos[j] = first;
    01646               if (last > linebounds[i]->end_pos[j])
    01647                 linebounds[i]->end_pos[j] = last;
    01648               add_to_row(v, sw, sw->lineno, sw->comp_buf,
    01649                          comp_ptr - sw->comp_buf, j, setactive, cpass + i);
    01650             }
    01651         }
    01652     }
    01653   sw->current_vertical_subpass++;
    01654   if (sw->current_vertical_subpass >= sw->vertical_oversample)
    01655     {
    01656       finalize_row(v, sw->lineno);
    01657       sw->lineno++;
    01658       sw->current_vertical_subpass = 0;
    01659     }
    01660 }
    01661
    01662 #if 0
    01663 #define TEST_RAW
    01664 #endif
    01665 #if 0
    01666 #define TEST_COOKED
    01667 #endif
    01668 #if 0
    01669 #define ACCUMULATE
    01670 #endif
    01671
    01672 #if defined(TEST_RAW) || defined(TEST_COOKED)
    01673 #define TEST
    01674 #endif
    01675
    01676 #ifdef TEST
    01677 #define MAXCOLLECT (1000)
    01678 #endif
    01679
    01680 #ifdef TEST_COOKED
    01681 static void
    01682 calculate_pass_parameters(cooked_t *w,          /* I - weave parameters */
    01683                           int pass,             /* I - pass number ( >= 0) */
    01684                           int *startrow,        /* O - print head position */
    01685                           int *subpass,         /* O - subpass number */
    01686                           int *phantomrows,     /* O - missing rows */
    01687                           int *jetsused)        /* O - jets used to print */
    01688 {
    01689         int raw_pass = pass + w->first_premapped_pass;
    01690         int stagger = 0;
    01691         int extra;
    01692
    01693         if (raw_pass < w->first_normal_pass) {
    01694                 int i = 0;
    01695                 while (i + w->first_premapped_pass < w->first_normal_pass) {
    01696                         if (w->pass_premap[i] == pass) {
    01697                                 raw_pass = i + w->first_premapped_pass;
    01698                                 stagger = w->stagger_premap[i];
    01699                                 break;
    01700                         }
    01701                         i++;
    01702                 }
    01703         } else if (raw_pass >= w->first_postmapped_pass) {
    01704                 int i = 0;
    01705                 while (i + w->first_postmapped_pass < w->first_unused_pass) {
    01706                         if (w->pass_postmap[i] == pass) {
    01707                                 raw_pass = i + w->first_postmapped_pass;
    01708                                 stagger = w->stagger_postmap[i];
    01709                                 break;
    01710                         }
    01711                         i++;
    01712                 }
    01713         }
    01714
    01715         calculate_raw_pass_parameters(&w->rw, raw_pass, startrow, subpass);
    01716         *startrow -= w->rw.separation * w->rw.jets;
    01717         *jetsused = w->rw.jets;
    01718         *phantomrows = 0;
    01719
    01720         *startrow += stagger * w->rw.separation;
    01721         if (stagger < 0) {
    01722                 stagger = -stagger;
    01723                 *phantomrows += stagger;
    01724         }
    01725         *jetsused -= stagger;
    01726
    01727         extra = w->first_row_printed - (*startrow + w->rw.separation * *phantomrows);
    01728         extra = (extra + w->rw.separation - 1) / w->rw.separation;
    01729         if (extra > 0) {
    01730                 *jetsused -= extra;
    01731                 *phantomrows += extra;
    01732         }
    01733
    01734         extra = *startrow + w->rw.separation * (*phantomrows + *jetsused - 1)
    01735                   - w->last_row_printed;
    01736         extra = (extra + w->rw.separation - 1) / w->rw.separation;
    01737         if (extra > 0) {
    01738                 *jetsused -= extra;
    01739         }
    01740 }
    01741 #endif /* TEST_COOKED */
    01742
    01743 #ifdef TEST
    01744
    01745 #ifdef ACCUMULATE
    01746 #define PUTCHAR(x) /* nothing */
    01747 #else
    01748 #define PUTCHAR(x) putchar(x)
    01749 #endif
    01750
    01751 static void
    01752 plotpass(int startrow, int phantomjets, int jetsused, int totaljets,
    01753          int separation, int subpass, int *collect, int *prints)
    01754 {
    01755         int hpos, i;
    01756
    01757         for (hpos = 0; hpos < startrow; hpos++)
    01758                 PUTCHAR(' ');
    01759
    01760         for (i = 0; i < phantomjets; i++) {
    01761                 int j;
    01762                 PUTCHAR('X');
    01763                 hpos++;
    01764                 for (j = 1; j < separation; j++) {
    01765                         PUTCHAR(' ');
    01766                         hpos++;
    01767                 }
    01768         }
    01769
    01770         for (; i < phantomjets + jetsused; i++) {
    01771                 if (i > phantomjets) {
    01772                         int j;
    01773                         for (j = 1; j < separation; j++) {
    01774                                 PUTCHAR('-');
    01775                                 hpos++;
    01776                         }
    01777                 }
    01778                 if (hpos < MAXCOLLECT) {
    01779                         if (collect[hpos] & 1 << subpass)
    01780                                 PUTCHAR('^');
    01781                         else if (subpass < 10)
    01782                                 PUTCHAR('0' + subpass);
    01783                         else
    01784                                 PUTCHAR('A' + subpass - 10);
    01785                         collect[hpos] |= 1 << subpass;
    01786                         prints[hpos]++;
    01787                 } else {
    01788                         PUTCHAR('0' + subpass);
    01789                 }
    01790                 hpos++;
    01791         }
    01792
    01793         while (i++ < totaljets) {
    01794                 int j;
    01795                 for (j = 1; j < separation; j++) {
    01796                         PUTCHAR(' ');
    01797                         hpos++;
    01798                 }
    01799                 PUTCHAR('X');
    01800         }
    01801 #ifdef ACCUMULATE
    01802         for (i=0; i<=MAXCOLLECT; i++) {
    01803                 if (collect[i] == 0)
    01804                         putchar(' ');
    01805                 else if (collect[i] < 10)
    01806                         putchar('0'+collect[i]);
    01807                 else
    01808                         putchar('A'+collect[i]-10);
    01809         }
    01810 #endif
    01811         putchar('\n');
    01812 }
    01813 #endif /* TEST */
    01814
    01815 #ifdef TEST_COOKED
    01816 int
    01817 main(int ac, char *av[])
    01818 {
    01819         int S         =ac>1 ? atoi(av[1]) : 4;
    01820         int J         =ac>2 ? atoi(av[2]) : 12;
    01821         int H         =ac>3 ? atoi(av[3]) : 1;
    01822         int firstrow  =ac>4 ? atoi(av[4]) : 1;
    01823         int lastrow   =ac>5 ? atoi(av[5]) : 100;
    01824         int pageheight=ac>6 ? atoi(av[6]) : 1000;
    01825         stp_weave_strategy_t strategy  =ac>7 ? atoi(av[7]) : 1;
    01826         cooked_t *weave;
    01827         int passes;
    01828
    01829         int pass, x;
    01830         int collect[MAXCOLLECT];
    01831         int prints[MAXCOLLECT];
    01832
    01833         memset(collect, 0, MAXCOLLECT*sizeof(int));
    01834         memset(prints, 0, MAXCOLLECT*sizeof(int));
    01835         printf("S=%d  J=%d  H=%d  firstrow=%d  lastrow=%d  "
    01836                "pageheight=%d  strategy=%d\n",
    01837                S, J, H, firstrow, lastrow, pageheight, strategy);
    01838
    01839         weave = initialize_weave_params(S, J, H, firstrow, lastrow,
    01840                                         pageheight, strategy);
    01841         passes = weave->first_unused_pass - weave->first_premapped_pass;
    01842
    01843         for (pass = 0; pass < passes; pass++) {
    01844                 int startrow, subpass, phantomjets, jetsused;
    01845
    01846                 calculate_pass_parameters(weave, pass, &startrow, &subpass,
    01847                                           &phantomjets, &jetsused);
    01848
    01849                 plotpass(startrow, phantomjets, jetsused, J, S, subpass,
    01850                          collect, prints);
    01851         }
    01852
    01853         for (pass=MAXCOLLECT - 1; prints[pass] == 0; pass--)
    01854                 ;
    01855
    01856         for (x=0; x<=pass; x++) {
    01857                 if (collect[x] < 10)
    01858                         putchar('0'+collect[x]);
    01859                 else
    01860                         putchar('A'+collect[x]-10);
    01861         }
    01862         putchar('\n');
    01863
    01864         for (x=0; x<=pass; x++) {
    01865                 if (prints[x] < 10)
    01866                         putchar('0'+prints[x]);
    01867                 else
    01868                         putchar('A'+prints[x]-10);
    01869         }
    01870         putchar('\n');
    01871
    01872         return 0;
    01873 }
    01874 #endif /* TEST_COOKED */
    01875
    01876 #ifdef TEST_RAW
    01877 int
    01878 main(int ac, char *av[])
    01879 {
    01880         int S     =ac>1 ? atoi(av[1]) : 4;
    01881         int J     =ac>2 ? atoi(av[2]) : 12;
    01882         int h_pos =ac>3 ? atoi(av[3]) : 1;
    01883         int h_over=ac>4 ? atoi(av[4]) : 1;
    01884         int v_over=ac>5 ? atoi(av[5]) : 1;
    01885         int H = h_pos * h_over * v_over;
    01886
    01887         int pass, passes, x;
    01888         int collect[MAXCOLLECT];
    01889         int prints[MAXCOLLECT];
    01890         raw_t raw;
    01891
    01892         memset(collect, 0, MAXCOLLECT*sizeof(int));
    01893         memset(prints, 0, MAXCOLLECT*sizeof(int));
    01894         printf("S=%d  J=%d  H=%d\n", S, J, H);
    01895
    01896         if (H > J) {
    01897                 printf("H > J, so this weave will not work!\n");
    01898         }
    01899         passes = S * H * 3;
    01900
    01901         initialize_raw_weave(&raw, S, J, H);
    01902
    01903         for (pass=0; pass<passes + S * H; pass++) {
    01904                 int startrow, subpass, phantomjets, jetsused;
    01905
    01906                 calculate_raw_pass_parameters(&raw, pass, &startrow, &subpass);
    01907                 phantomjets = 0;
    01908                 jetsused = J;
    01909
    01910                 plotpass(startrow, phantomjets, jetsused, J, S, subpass,
    01911                          collect, prints);
    01912         }
    01913         for (pass=MAXCOLLECT - 1; prints[pass] == 0; pass--)
    01914                 ;
    01915
    01916         for (x=0; x<=pass; x++) {
    01917                 if (collect[x] < 10)
    01918                         putchar('0'+collect[x]);
    01919                 else
    01920                         putchar('A'+collect[x]-10);
    01921         }
    01922         putchar('\n');
    01923
    01924         for (x=0; x<=pass; x++) {
    01925                 if (prints[x] < 10)
    01926                         putchar('0'+prints[x]);
    01927                 else
    01928                         putchar('A'+prints[x]-10);
    01929         }
    01930         putchar('\n');
    01931
    01932         printf("  A  first row given by pass lookup doesn't match row lookup\n"
    01933                "  B  jet out of range\n"
    01934                "  C  given jet number of pass doesn't print this row\n"
    01935                "  D  subpass given by reverse lookup doesn't match requested subpass\n");
    01936
    01937         for (x = S * J; x < S * J * 20; x++) {
    01938                 int h;
    01939                 for (h = 0; h < H; h++) {
    01940                         int pass, jet, start, first, subpass, z;
    01941                         int a=0, b=0, c=0, d=0;
    01942                         calculate_raw_row_parameters(&raw, x, h, &pass, &jet, &start);
    01943                         for (z=0; z < pass; z++) {
    01944                                 putchar(' ');
    01945                         }
    01946                         printf("%d", jet);
    01947                         calculate_raw_pass_parameters(&raw, pass, &first, &subpass);
    01948                         if (first != start)
    01949                                 a=1;
    01950                         if (jet < 0 || jet >= J)
    01951                                 b=1;
    01952                         if (x != first + jet * S)
    01953                                 c=1;
    01954                         if (subpass != h)
    01955                                 d=1;
    01956                         if (a || b || c || d) {
    01957                                 printf("    (");
    01958                                 if (a) putchar('A');
    01959                                 if (b) putchar('B');
    01960                                 if (c) putchar('C');
    01961                                 if (d) putchar('D');
    01962                                 putchar(')');
    01963                                 printf("\npass=%d first=%d start=%d jet=%d subpass=%d", pass, first, start, jet, subpass);
    01964                         }
    01965                         putchar('\n');
    01966                 }
    01967                 /* putchar('\n'); */
    01968         }
    01969
    01970         return 0;
    01971 }
    01972
    01973 #endif /* TEST_RAW */