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

src/main/print-weave.c

Go to the documentation of this file.
00001 /*
00002  * "$Id: print-weave.c,v 1.61 2004/05/07 19:20:34 rleigh 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 */

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