Blame converter/pbm/pbmtogo.c

Packit 78deda
/* pbmtogo.c - read a PBM image and produce a GraphOn terminal raster file
Packit 78deda
**      
Packit 78deda
**      Rev 1.1 was based on pbmtolj.c
Packit 78deda
**
Packit 78deda
**      Bo Thide', Swedish Institute of Space Physics, bt@irfu.se
Packit 78deda
**                                 
Packit 78deda
**
Packit 78deda
** $Log:        pbmtogo.c,v $
Packit 78deda
 * Revision 1.5  89/11/25  00:24:12  00:24:12  root (Bo Thide)
Packit 78deda
 * Bug found: The byte after 64 repeated bytes sometimes lost. Fixed.
Packit 78deda
 * 
Packit 78deda
 * Revision 1.4  89/11/24  14:56:04  14:56:04  root (Bo Thide)
Packit 78deda
 * Fixed the command line parsing since pbmtogo now always uses 2D
Packit 78deda
 * compression.  Added a few comments to the source.
Packit 78deda
 * 
Packit 78deda
 * Revision 1.3  89/11/24  13:43:43  13:43:43  root (Bo Thide)
Packit 78deda
 * Added capability for > 63 repeated bytes and > 62 repeated lines in
Packit 78deda
 * the 2D compression scheme.
Packit 78deda
 * 
Packit 78deda
 * Revision 1.2  89/11/15  01:04:47  01:04:47  root (Bo Thide)
Packit 78deda
 * First version that works reasonably well with GraphOn 2D runlength
Packit 78deda
 * encoding/compression.
Packit 78deda
 * 
Packit 78deda
 * Revision 1.1  89/11/02  23:25:25  23:25:25  root (Bo Thide)
Packit 78deda
 * Initial revision
Packit 78deda
 * 
Packit 78deda
**
Packit 78deda
** Copyright (C) 1988, 1989 by Jef Poskanzer, Michael Haberler, and Bo Thide'.
Packit 78deda
**
Packit 78deda
** Permission to use, copy, modify, and distribute this software and its
Packit 78deda
** documentation for any purpose and without fee is hereby granted, provided
Packit 78deda
** that the above copyright notice appear in all copies and that both that
Packit 78deda
** copyright notice and this permission notice appear in supporting
Packit 78deda
** documentation.  This software is provided "as is" without express or
Packit 78deda
** implied warranty.
Packit 78deda
*/
Packit 78deda
Packit 78deda
#include <assert.h>
Packit 78deda
#include <stdio.h>
Packit 78deda
#include <string.h>
Packit 78deda
Packit 78deda
#include "pm_c_util.h"
Packit 78deda
#include "pbm.h"
Packit 78deda
Packit 78deda
#define GRAPHON_WIDTH 1056 /* GraphOn has 1056 bit wide raster lines */
Packit 78deda
#define GRAPHON_WIDTH_BYTES (GRAPHON_WIDTH / 8)
Packit 78deda
#define REPEAT_CURRENT_LINE_MASK        0x00 
Packit 78deda
#define SKIP_AND_PLOT_MASK              0x40 
Packit 78deda
#define REPEAT_PLOT_MASK                0x80 
Packit 78deda
#define PLOT_ARBITRARY_DATA_MASK        0xc0 
Packit 78deda
#define MAX_REPEAT 64
Packit 78deda
Packit 78deda
static unsigned char * scanlineptr;
Packit 78deda
    /* Pointer to current scan line byte */
Packit 78deda
Packit 78deda
static int item, bitsperitem, bitshift;
Packit 78deda
Packit 78deda
static void
Packit 78deda
putinit(void) {
Packit 78deda
Packit 78deda
    /* Enter graphics window */
Packit 78deda
    printf("\0331");
Packit 78deda
Packit 78deda
    /* Erase graphics window */
Packit 78deda
    printf("\033\014");
Packit 78deda
Packit 78deda
    /* Set graphics window in raster mode */
Packit 78deda
    printf("\033r");
Packit 78deda
Packit 78deda
    /* Select standard Tek coding **/
Packit 78deda
    printf("\033[=11l");
Packit 78deda
Packit 78deda
    bitsperitem = 1;
Packit 78deda
    item = 0;
Packit 78deda
    bitshift = 7;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
putitem(void) {
Packit 78deda
Packit 78deda
    *scanlineptr++ = item;
Packit 78deda
    bitsperitem = 0;
Packit 78deda
    item = 0;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
putbit(bit const b) {
Packit 78deda
Packit 78deda
    if (b == PBM_BLACK)
Packit 78deda
        item += 1 << bitshift;
Packit 78deda
Packit 78deda
    bitshift--;
Packit 78deda
Packit 78deda
    if (bitsperitem == 8)
Packit 78deda
    {
Packit 78deda
        putitem();
Packit 78deda
        bitshift = 7;
Packit 78deda
    }
Packit 78deda
    bitsperitem++;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
putrest(void) {
Packit 78deda
Packit 78deda
    if (bitsperitem > 1)
Packit 78deda
        putitem();
Packit 78deda
Packit 78deda
    /* end raster downloading */
Packit 78deda
    printf("\033\134");
Packit 78deda
Packit 78deda
    /* Exit raster mode */
Packit 78deda
    printf("\033t");
Packit 78deda
Packit 78deda
    /* Exit graphics window
Packit 78deda
       printf("\0332"); */
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
int
Packit 78deda
main(int           argc,
Packit 78deda
     const char ** argv) {
Packit 78deda
Packit 78deda
    FILE * ifP;
Packit 78deda
    bit * bitrow;
Packit 78deda
    bit * bP;
Packit 78deda
    int rows, cols, format, rucols, padright, row, col;
Packit 78deda
    int nbyte, bytesperrow, ecount, ucount, nout, i, linerepeat;
Packit 78deda
    int olditem;
Packit 78deda
    unsigned char oldscanline[GRAPHON_WIDTH_BYTES];
Packit 78deda
    unsigned char newscanline[GRAPHON_WIDTH_BYTES];
Packit 78deda
    unsigned char diff[GRAPHON_WIDTH_BYTES];
Packit 78deda
    unsigned char buffer[GRAPHON_WIDTH_BYTES];
Packit 78deda
    unsigned char outbuffer[2*(GRAPHON_WIDTH_BYTES+1)];     /* Worst case. */
Packit 78deda
Packit 78deda
    pm_proginit(&argc, argv);
Packit 78deda
Packit 78deda
    if (argc-1 == 0)
Packit 78deda
      ifP = stdin;
Packit 78deda
    else if (argc-1 == 1)
Packit 78deda
      ifP = pm_openr(argv[1]);
Packit 78deda
    else
Packit 78deda
        pm_error("There is at most one argument: input file name.  "
Packit 78deda
                 "You specified %u", argc-1);
Packit 78deda
Packit 78deda
    pbm_readpbminit(ifP, &cols, &rows, &format);
Packit 78deda
Packit 78deda
    if (cols > GRAPHON_WIDTH)
Packit 78deda
        pm_error("Image is wider (%u pixels) than a Graphon terminal "
Packit 78deda
                 "(%u pixels)", cols, GRAPHON_WIDTH);
Packit 78deda
Packit 78deda
    bitrow = pbm_allocrow(cols);
Packit 78deda
Packit 78deda
    /* Round cols up to the nearest multiple of 8. */
Packit 78deda
    rucols = ( cols + 7 ) / 8;
Packit 78deda
    bytesperrow = rucols;       /* GraphOn uses bytes */
Packit 78deda
    rucols = rucols * 8;
Packit 78deda
    padright = rucols - cols;
Packit 78deda
Packit 78deda
    for (i = 0; i < GRAPHON_WIDTH_BYTES; ++i )
Packit 78deda
      buffer[i] = oldscanline[i] = 0;
Packit 78deda
    putinit();
Packit 78deda
Packit 78deda
    /* Start donwloading screen raster */
Packit 78deda
    printf("\033P0;1;0;4;1;%d;%d;1!R1/", rows, rucols);
Packit 78deda
Packit 78deda
    linerepeat = 63; /*  63 means "Start new picture" */
Packit 78deda
    nout = 0;  /* To prevent compiler warning */
Packit 78deda
    for (row = 0; row < rows; row++) {
Packit 78deda
        /* Store scan line data in the new scan line vector */
Packit 78deda
        scanlineptr = newscanline;
Packit 78deda
        pbm_readpbmrow(ifP, bitrow, cols, format);
Packit 78deda
        /* Transfer raster graphics */
Packit 78deda
        for (col = 0, bP = bitrow; col < cols; col++, bP++)
Packit 78deda
          putbit(*bP);
Packit 78deda
        for (col = 0; col < padright; col++)
Packit 78deda
          putbit(0);
Packit 78deda
Packit 78deda
        assert(bytesperrow <= GRAPHON_WIDTH_BYTES);
Packit 78deda
        
Packit 78deda
        /* XOR data from the new scan line with data from old scan line */
Packit 78deda
        for (i = 0; i < bytesperrow; i++)
Packit 78deda
          diff[i] = oldscanline[i]^newscanline[i];
Packit 78deda
        
Packit 78deda
        /*
Packit 78deda
         ** If the difference map is different from current internal buffer,
Packit 78deda
         ** encode the difference and put it in the output buffer. 
Packit 78deda
         ** Else, increase the counter for the current buffer by one.
Packit 78deda
         */
Packit 78deda
        
Packit 78deda
        if ((memcmp(buffer, diff, bytesperrow) != 0) || (row == 0)) {
Packit 78deda
            /*    
Packit 78deda
             **Since the data in the buffer has changed, send the
Packit 78deda
             **scan line repeat count to cause the old line(s) to
Packit 78deda
             **be plotted on the screen, copy the new data into
Packit 78deda
             **the internal buffer, and reset the counters.  
Packit 78deda
             */
Packit 78deda
              
Packit 78deda
            putchar(linerepeat);
Packit 78deda
            for (i = 0; i < bytesperrow; ++i)
Packit 78deda
              buffer[i] = diff[i];
Packit 78deda
            nbyte = 0;          /* Internal buffer byte counter */
Packit 78deda
            nout = 0;           /* Output buffer byte counter */
Packit 78deda
              
Packit 78deda
            /* Run length encode the new internal buffr (= difference map) */
Packit 78deda
            while (TRUE) {
Packit 78deda
                ucount = 0;     /* Unique items counter */
Packit 78deda
                do              /* Find unique patterns */
Packit 78deda
                  {
Packit 78deda
                      olditem = buffer[nbyte++];
Packit 78deda
                      ucount++;
Packit 78deda
                  } while (nbyte < bytesperrow && (olditem != buffer[nbyte])
Packit 78deda
                           && (ucount < MIN(bytesperrow, MAX_REPEAT)));
Packit 78deda
                  
Packit 78deda
                if ((ucount != MAX_REPEAT) && (nbyte != bytesperrow)) {
Packit 78deda
                    /* Back up to the last truly unique pattern */
Packit 78deda
                    ucount--;
Packit 78deda
                    nbyte--;
Packit 78deda
                }
Packit 78deda
Packit 78deda
                if (ucount > 0) { 
Packit 78deda
                    /* Output the unique patterns */
Packit 78deda
                    outbuffer[nout++] = 
Packit 78deda
                      (ucount-1) | PLOT_ARBITRARY_DATA_MASK;
Packit 78deda
                    for (i = nbyte-ucount; i < nbyte; i++)
Packit 78deda
                      outbuffer[nout++] = buffer[i];
Packit 78deda
                }
Packit 78deda
Packit 78deda
                /*
Packit 78deda
                 ** If we already are at the end of the current scan
Packit 78deda
                 ** line, skip the rest of the encoding and start
Packit 78deda
                 ** with a new scan line.  
Packit 78deda
                 */
Packit 78deda
Packit 78deda
                if (nbyte >= bytesperrow)
Packit 78deda
                  goto nextrow;
Packit 78deda
                  
Packit 78deda
                ecount = 0;     /* Equal items counter */
Packit 78deda
                do              /* Find equal patterns */
Packit 78deda
                  {
Packit 78deda
                      olditem = buffer[nbyte++];
Packit 78deda
                      ecount++;
Packit 78deda
                  } while (nbyte < bytesperrow && (olditem == buffer[nbyte])
Packit 78deda
                           && (ecount < MIN(bytesperrow, MAX_REPEAT)));
Packit 78deda
                  
Packit 78deda
                if (ecount > 1) {
Packit 78deda
                    /* More than 1 equal pattern */
Packit 78deda
                    if (olditem == '\0') {
Packit 78deda
                        /* White patterns */
Packit 78deda
                        if (nbyte >= bytesperrow-1) {
Packit 78deda
                            /* No more valid data ahead */
Packit 78deda
                            outbuffer[nout++] = 
Packit 78deda
                              (ecount-2) | SKIP_AND_PLOT_MASK;
Packit 78deda
                            outbuffer[nout++] = buffer[nbyte-1];
Packit 78deda
                        } 
Packit 78deda
                        else { 
Packit 78deda
                            /* More valid data ahead */
Packit 78deda
                            outbuffer[nout++] = 
Packit 78deda
                              (ecount-1) | SKIP_AND_PLOT_MASK;
Packit 78deda
                            outbuffer[nout++] = buffer[nbyte++];
Packit 78deda
                        } 
Packit 78deda
                    }
Packit 78deda
                    else { 
Packit 78deda
                        /* Non-white patterns */
Packit 78deda
                        outbuffer[nout++] = (ecount-1) | REPEAT_PLOT_MASK;
Packit 78deda
                        outbuffer[nout++] = olditem;
Packit 78deda
                    } /* if (olditem == '\0') */
Packit 78deda
                } /* if (ecount > 1) */
Packit 78deda
                else
Packit 78deda
                  nbyte--;      /* No equal items found */
Packit 78deda
                  
Packit 78deda
                if (nbyte >= bytesperrow)
Packit 78deda
                  goto nextrow;
Packit 78deda
            } /* while (TRUE) */
Packit 78deda
              
Packit 78deda
          nextrow: printf("%d/", nout+1); /* Total bytes to xfer = nout+1 */
Packit 78deda
            fflush(stdout);
Packit 78deda
Packit 78deda
            /* Output the plot data */
Packit 78deda
            fwrite(outbuffer, 1, nout, stdout);
Packit 78deda
Packit 78deda
            /* Reset the counters */
Packit 78deda
            linerepeat = 0;
Packit 78deda
        } else {
Packit 78deda
            linerepeat++;
Packit 78deda
            if (linerepeat == 62) /* 62 lines max, then restart */
Packit 78deda
              {
Packit 78deda
                  putchar(linerepeat);
Packit 78deda
                  printf("%d/", nout+1);
Packit 78deda
                  fflush(stdout);
Packit 78deda
                  fwrite(outbuffer, 1, nout, stdout);
Packit 78deda
                  linerepeat = 0;
Packit 78deda
              }
Packit 78deda
        }
Packit 78deda
        
Packit 78deda
        /* Now we are ready for a new scan line */
Packit 78deda
        for (i = 0; i < bytesperrow; ++i)
Packit 78deda
          oldscanline[i] = newscanline[i];
Packit 78deda
    }
Packit 78deda
    putchar(linerepeat);        /* For the last line(s) to be plotted */
Packit 78deda
    pm_close(ifP);
Packit 78deda
    putrest();
Packit 78deda
Packit 78deda
    return 0;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda