/* pbmtolj.c - read a portable bitmap and produce a LaserJet bitmap file ** ** based on pbmtops.c ** ** Michael Haberler HP Vienna mah@hpuviea.uucp ** mcvax!tuvie!mah ** misfeatures: ** no positioning ** ** Bug fix Dec 12, 1988 : ** lines in putbit() reshuffled ** now runs OK on HP-UX 6.0 with X10R4 and HP Laserjet II ** Bo Thide', Swedish Institute of Space Physics, Uppsala ** ** Flags added December, 1993: ** -noreset to suppress printer reset code ** -float to suppress positioning code (such as it is) ** Wim Lewis, Seattle ** ** Copyright (C) 1988 by Jef Poskanzer and Michael Haberler. ** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, provided ** that the above copyright notice appear in all copies and that both that ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. */ #include "pbm.h" #include #include static int dpi = 75; static int floating = 0; /* suppress the ``ESC & l 0 E'' ? */ static int pack = 0; /* use TIFF packbits compression */ static int delta = 0; /* use row-delta compression */ static int resets = 3; /* bit mask for when to emit printer reset seq */ static int copies = 1; /* number of copies */ static char *rowBuffer, *prevRowBuffer, *packBuffer, *deltaBuffer; static int rowBufferSize, rowBufferIndex; static int packBufferSize, packBufferIndex; static int deltaBufferSize, deltaBufferIndex; static void putinit ARGS(( void )); static void putbit ARGS(( bit b )); static void putflush ARGS(( void )); static void putrest ARGS(( void )); static void putitem ARGS(( void )); static void packbits ARGS(( void )); static void deltarow ARGS(( void )); int main( argc, argv ) int argc; char* argv[]; { FILE* ifp; bit* bitrow; register bit* bP; int argn, rows, cols, format, rucols, padright, row, mode, blankRows; int prevRowBufferIndex; int savedRowBufferIndex; register int nzcol, col; const char* const usage = "[-noreset|-float|-packbits|-delta|-compress|-resolution N|-copies N] [pbmfile]\n\tresolution = [75|100|150|300|600] (dpi)"; pbm_init( &argc, argv ); argn = 1; /* Check for flags. */ while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) { if ( pm_keymatch( argv[argn], "-resolution", 2 ) ) { ++argn; if ( argn == argc || sscanf( argv[argn], "%d", &dpi ) != 1 ) pm_usage( usage ); } else if ( pm_keymatch( argv[argn], "-copies", 2 ) ) { ++argn; if ( argn == argc || sscanf( argv[argn], "%d", &copies ) != 1 ) pm_usage( usage ); } else if ( pm_keymatch( argv[argn], "-float", 2 ) ) { floating = 1; } else if ( pm_keymatch( argv[argn], "-noreset", 2 ) ) { resets = 0; } else if ( pm_keymatch( argv[argn], "-packbits", 2 ) ) { pack = 1; } else if ( pm_keymatch( argv[argn], "-delta", 2 ) ) { delta = 1; } else if ( pm_keymatch( argv[argn], "-compress", 2 ) ) { pack = 1; delta = 1; } else pm_usage( usage ); ++argn; } if ( argn != argc ) { ifp = pm_openr( argv[argn] ); ++argn; } else ifp = stdin; if ( argn != argc ) pm_usage( usage ); pbm_readpbminit( ifp, &cols, &rows, &format ); bitrow = pbm_allocrow( cols ); rowBufferSize = (cols + 7) / 8; packBufferSize = rowBufferSize + (rowBufferSize + 127) / 128 + 1; deltaBufferSize = rowBufferSize + rowBufferSize / 8 + 10; prevRowBuffer = (char *) malloc(rowBufferSize); rowBuffer = (char *) malloc(rowBufferSize); packBuffer = (char *) malloc(packBufferSize); deltaBuffer = (char *) malloc(deltaBufferSize); if (!rowBuffer || !prevRowBuffer || !packBuffer || !deltaBuffer) { fprintf(stderr, "Can't allocate row buffer\n"); return 1; } putinit( ); blankRows = 0; prevRowBufferIndex = 0; memset(prevRowBuffer, 0, rowBufferSize); mode = -1; for ( row = 0; row < rows; ++row ) { pbm_readpbmrow( ifp, bitrow, cols, format ); /* Find rightmost black pixel. */ for ( nzcol = cols - 1; nzcol >= 0 && bitrow[nzcol] == PBM_WHITE; --nzcol ) continue; if (nzcol < 0) { blankRows ++; continue; } if (blankRows > 0) { int x; /* The code used to be this, but Charles Howes reports that this escape sequence does not exist on his HP Laserjet IIP plus, so we use the following less elegant code instead. printf("\033*b%dY", blankRows); */ for (x=0;x 1) { /* number of copies */ printf("\033&l%dX", copies); } if(!floating) { /* Ensure top margin is zero */ printf("\033&l0E"); } /* Set raster graphics resolution */ printf("\033*t%dR",dpi); /* Start raster graphics, relative adressing */ printf("\033*r1A"); itemsperline = 0; bitsperitem = 1; item = 0; bitshift = 7; firstitem = 1; } #if __STDC__ static void putbit( bit b ) #else /*__STDC__*/ static void putbit( b ) bit b; #endif /*__STDC__*/ { if ( b == PBM_BLACK ) item += 1 << bitshift; bitshift--; if ( bitsperitem == 8 ) { putitem( ); bitshift = 7; } bitsperitem++; } static void putflush( ) { if ( bitsperitem > 1 ) putitem( ); } static void putrest( ) { /* end raster graphics */ printf( "\033*rB" ); if(resets & 2) { /* Printer reset. */ printf("\033E"); } } static void putitem( ) { assert (rowBufferIndex < rowBufferSize); rowBuffer[rowBufferIndex++] = item; bitsperitem = 0; item = 0; } static void packbits() { int ptr, litStart, runStart, thisByte, startByte, chew, spit; packBufferIndex = 0; ptr = 0; while (ptr < rowBufferIndex) { litStart = ptr; runStart = ptr; startByte = rowBuffer[ptr]; ptr++; while (ptr < rowBufferIndex) { thisByte = rowBuffer[ptr]; if (thisByte != startByte) { if (ptr - runStart > 3) { /* found literal after nontrivial run */ break; } startByte = thisByte; runStart = ptr; } ptr ++; } /* We drop out here after having found a [possibly empty] literal, followed by a [possibly degenerate] run of repeated bytes. Degenerate runs can occur at the end of the scan line... there may be a "repeat" of 1 byte (which can't actually be represented as a repeat) so we simply fold it into the previous literal. */ if (runStart == rowBufferIndex - 1) { runStart = rowBufferIndex; } /* Spit out the leading literal if it isn't empty */ chew = runStart - litStart; while (chew > 0) { spit = (chew > 127) ? 127 : chew; packBuffer[packBufferIndex++] = (char) (spit - 1); memcpy(packBuffer+packBufferIndex, rowBuffer+litStart, spit); packBufferIndex += spit; litStart += spit; chew -= spit; } /* Spit out the repeat, if it isn't empty */ chew = ptr - runStart; while (chew > 0) { spit = (chew > 128) ? 128 : chew; if (chew == spit + 1) { spit--; /* don't leave a degenerate run at the end */ } if (spit == 1) { fprintf(stderr, "packbits created a degenerate run!\n"); } packBuffer[packBufferIndex++] = (char) -(spit - 1); packBuffer[packBufferIndex++] = startByte; chew -= spit; } } } static void deltarow() { int burstStart, burstEnd, burstCode, mustBurst, ptr, skip, skipped, code; deltaBufferIndex = 0; if (memcmp(rowBuffer, prevRowBuffer, rowBufferIndex) == 0) { return; /* exact match, no deltas required */ } ptr = 0; skipped = 0; burstStart = -1; burstEnd = -1; mustBurst = 0; while (ptr < rowBufferIndex) { skip = 0; if (ptr == 0 || skipped == 30 || rowBuffer[ptr] != prevRowBuffer[ptr] || (burstStart != -1 && ptr == rowBufferIndex - 1)) { /* we want to output this byte... */ if (burstStart == -1) { burstStart = ptr; } if (ptr - burstStart == 7 || ptr == rowBufferIndex - 1) { /* we have to output it now... */ burstEnd = ptr; mustBurst = 1; } } else { /* duplicate byte, we can skip it */ if (burstStart != -1) { burstEnd = ptr - 1; mustBurst = 1; } skip = 1; } if (mustBurst) { burstCode = burstEnd - burstStart; /* 0-7, means 1-8 bytes follow */ code = (burstCode << 5) | skipped; deltaBuffer[deltaBufferIndex++] = (char) code; memcpy(deltaBuffer+deltaBufferIndex, rowBuffer+burstStart, burstCode + 1); deltaBufferIndex += burstCode + 1; burstStart = -1; burstEnd = -1; mustBurst = 0; skipped = 0; } if (skip) { skipped ++; } ptr ++; } }