Blame converter/ppm/ppmtolj.c

Packit 78deda
/* ppmtolj.c - convert a portable pixmap to an HP PCL 5 color image
Packit 78deda
**
Packit 78deda
** Copyright (C) 2000 by Jonathan Melvin (jonathan.melvin@heywood.co.uk)
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 <string.h>
Packit 78deda
Packit 78deda
#include "ppm.h"
Packit 78deda
Packit 78deda
static int compress_row_delta (unsigned char *op, unsigned char *prev_op, 
Packit 78deda
                               unsigned char *cp, int bufsize);
Packit 78deda
Packit 78deda
#define C_RESET                 "\033E"
Packit 78deda
#define C_PRESENTATION          "\033*r%dF"
Packit 78deda
#define C_PRESENTATION_LOGICAL  0
Packit 78deda
#define C_PRESENTATION_PHYSICAL 3
Packit 78deda
#define C_GAMMA                 "\033*t%dI"
Packit 78deda
#define C_IMAGE_WIDTH           "\033*r%dS"
Packit 78deda
#define C_IMAGE_HEIGHT          "\033*r%dT"
Packit 78deda
#define C_DATA_PLANES           "\033*r%dU"
Packit 78deda
#define C_TRANS_MODE            "\033*b%dM"
Packit 78deda
#define C_TRANS_MODE_STD        0 /*compression modes*/
Packit 78deda
#define C_TRANS_MODE_RLE        1 /*no good for rgb*/
Packit 78deda
#define C_TRANS_MODE_TIFF       2 /*no good for rgb*/
Packit 78deda
#define C_TRANS_MODE_DELTA      3 /*only on to use for rgb values*/
Packit 78deda
#define C_CONFIG_IMAGE_DATA     "\033*v6W"
Packit 78deda
#define C_SEND_ROW              "\033*b%dW"
Packit 78deda
#define C_BEGIN_RASTER          "\033*r%dA"
Packit 78deda
#define C_BEGIN_RASTER_CUR      1
Packit 78deda
#define C_END_RASTER            "\033*r%dC"
Packit 78deda
#define C_END_RASTER_UNUSED     0
Packit 78deda
#define C_RESOLUTION            "\033*t%dR"
Packit 78deda
#define C_RESOLUTION_300DPI     300
Packit 78deda
#define C_MOVE_X                "\033*p+%dX"
Packit 78deda
#define C_MOVE_Y                "\033*p+%dY"
Packit 78deda
#define C_LEFT_MARGIN           "\033*r%dA"
Packit 78deda
#define C_Y_OFFSET              "\033*b%dY"
Packit 78deda
Packit 78deda
Packit 78deda
/*
Packit 78deda
 * delta encoding. 
Packit 78deda
 */
Packit 78deda
/*
Packit 78deda
op row buffer
Packit 78deda
prev_op     previous row buffer
Packit 78deda
bufsize     length of row
Packit 78deda
cp          buffer for compressed data
Packit 78deda
*/
Packit 78deda
static int
Packit 78deda
compress_row_delta(op, prev_op, cp, bufsize)
Packit 78deda
unsigned char *op, *prev_op, *cp;
Packit 78deda
int bufsize;
Packit 78deda
{
Packit 78deda
    int burstStart, burstEnd, burstCode, mustBurst, ptr, skip, skipped, code;
Packit 78deda
    int deltaBufferIndex = 0;
Packit 78deda
    if (memcmp(op, prev_op , bufsize/*rowBufferIndex*/) == 0) 
Packit 78deda
        return 0; /* exact match, no deltas required */
Packit 78deda
Packit 78deda
    ptr = 0;
Packit 78deda
    skipped = 0;
Packit 78deda
    burstStart = -1;
Packit 78deda
    burstEnd = -1;
Packit 78deda
    mustBurst = 0;
Packit 78deda
    while (ptr < bufsize/*rowBufferIndex*/) 
Packit 78deda
    {
Packit 78deda
        skip = 0;
Packit 78deda
        if (ptr == 0 || skipped == 30 || op[ptr] != prev_op[ptr] ||
Packit 78deda
            (burstStart != -1 && ptr == bufsize - 1)) 
Packit 78deda
        {
Packit 78deda
            /* we want to output this byte... */
Packit 78deda
            if (burstStart == -1) 
Packit 78deda
            {
Packit 78deda
                burstStart = ptr;
Packit 78deda
            }
Packit 78deda
            if (ptr - burstStart == 7 || ptr == bufsize - 1) 
Packit 78deda
            {
Packit 78deda
                /* we have to output it now... */
Packit 78deda
                burstEnd = ptr;
Packit 78deda
                mustBurst = 1;
Packit 78deda
            }
Packit 78deda
        } 
Packit 78deda
        else 
Packit 78deda
        {
Packit 78deda
            /* duplicate byte, we can skip it */
Packit 78deda
            if (burstStart != -1) 
Packit 78deda
            {
Packit 78deda
                burstEnd = ptr - 1;
Packit 78deda
                mustBurst = 1;
Packit 78deda
            }
Packit 78deda
            skip = 1;
Packit 78deda
        }
Packit 78deda
        if (mustBurst) 
Packit 78deda
        {
Packit 78deda
            burstCode = burstEnd - burstStart; /* 0-7 means 1-8 bytes follow */
Packit 78deda
            code = (burstCode << 5) | skipped;
Packit 78deda
            cp[deltaBufferIndex++] = (char) code;
Packit 78deda
            memcpy(cp+deltaBufferIndex, op+burstStart, burstCode + 1);
Packit 78deda
            deltaBufferIndex += burstCode + 1;
Packit 78deda
            burstStart = -1;
Packit 78deda
            burstEnd = -1;
Packit 78deda
            mustBurst = 0;
Packit 78deda
            skipped = 0;
Packit 78deda
        }
Packit 78deda
        if (skip) 
Packit 78deda
        {
Packit 78deda
            skipped ++;
Packit 78deda
        }
Packit 78deda
        ptr ++;
Packit 78deda
    }
Packit 78deda
    return deltaBufferIndex;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
int main(int argc, char *argv[]) {
Packit 78deda
    pixel * pixelrow;
Packit 78deda
    FILE *ifp;
Packit 78deda
    int argn, rows, cols, r, c, k;
Packit 78deda
    pixval maxval;
Packit 78deda
    unsigned char *obuf, *op, *cbuf, *previous_obuf;
Packit 78deda
    int format;
Packit 78deda
    int gamma = 0;
Packit 78deda
    int mode = C_TRANS_MODE_STD;
Packit 78deda
    int currentmode = 0;
Packit 78deda
    int floating = 0;  /* suppress the ``ESC & l 0 E'' ? */
Packit 78deda
    int resets = 3;    /* bit mask for when to emit printer reset seq */
Packit 78deda
Packit 78deda
    int resolution = C_RESOLUTION_300DPI;
Packit 78deda
Packit 78deda
    char CID[6] =  { 0, 3, 0, 8, 8, 8 }; 
Packit 78deda
        /*data for the configure image data command*/
Packit 78deda
Packit 78deda
    const char * const usage = "[-noreset][-float][-delta][-gamma <val>] [-resolution N] "
Packit 78deda
        "[ppmfile]\n\tresolution = [75|100|150|300|600] (dpi)";
Packit 78deda
Packit 78deda
    ppm_init( &argc, argv );
Packit 78deda
Packit 78deda
    argn = 1;
Packit 78deda
    while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
Packit 78deda
    {
Packit 78deda
        if( pm_keymatch( argv[argn], "-resolution", 2 ) && argn + 1 < argc )
Packit 78deda
        {
Packit 78deda
            ++argn;
Packit 78deda
            if ( argn == argc || sscanf( argv[argn], "%d", &resolution ) != 1 )
Packit 78deda
                pm_usage( usage );
Packit 78deda
        }
Packit 78deda
        else if ( pm_keymatch(argv[argn],"-gamma",2) && argn + 1 < argc )
Packit 78deda
        {
Packit 78deda
            ++argn;
Packit 78deda
            if ( sscanf( argv[argn], "%d",&gamma ) != 1 )
Packit 78deda
                pm_usage( usage );
Packit 78deda
        }
Packit 78deda
        else if (pm_keymatch(argv[argn],"-delta",2))
Packit 78deda
            mode = C_TRANS_MODE_DELTA;
Packit 78deda
        else if (pm_keymatch(argv[argn],"-float",2))
Packit 78deda
            floating = 1;
Packit 78deda
        else if (pm_keymatch(argv[argn],"-noreset",2))
Packit 78deda
            resets = 0;
Packit 78deda
Packit 78deda
        else
Packit 78deda
            pm_usage( usage );
Packit 78deda
        ++argn;
Packit 78deda
    }
Packit 78deda
Packit 78deda
    if ( argn < argc )
Packit 78deda
    {
Packit 78deda
        ifp = pm_openr( argv[argn] );
Packit 78deda
        ++argn;
Packit 78deda
    }
Packit 78deda
    else
Packit 78deda
        ifp = stdin;
Packit 78deda
Packit 78deda
    if ( argn != argc )
Packit 78deda
        pm_usage( usage );
Packit 78deda
Packit 78deda
    ppm_readppminit( ifp, &cols, &rows, &maxval, &format );
Packit 78deda
    pixelrow = ppm_allocrow( cols );
Packit 78deda
Packit 78deda
    obuf = (unsigned char *) pm_allocrow(cols * 3, sizeof(unsigned char));
Packit 78deda
    cbuf = (unsigned char *) pm_allocrow(cols * 6, sizeof(unsigned char));
Packit 78deda
    if (mode == C_TRANS_MODE_DELTA)
Packit 78deda
    {
Packit 78deda
        previous_obuf = 
Packit 78deda
            (unsigned char *) pm_allocrow(cols * 3, sizeof(unsigned char));
Packit 78deda
        memset(previous_obuf, 0, cols * 3);
Packit 78deda
    }
Packit 78deda
Packit 78deda
    if(resets & 1)
Packit 78deda
    {
Packit 78deda
        /* Printer reset. */
Packit 78deda
        printf(C_RESET);
Packit 78deda
    }
Packit 78deda
Packit 78deda
    if(!floating)
Packit 78deda
    {
Packit 78deda
        /* Ensure top margin is zero */
Packit 78deda
        printf("\033&l0E");
Packit 78deda
    }
Packit 78deda
Packit 78deda
    /*Set Presentation mode*/
Packit 78deda
    (void) printf(C_PRESENTATION, C_PRESENTATION_PHYSICAL);
Packit 78deda
    /* Set the resolution */
Packit 78deda
    (void) printf(C_RESOLUTION, resolution);
Packit 78deda
    /* Set raster height*/
Packit 78deda
    (void) printf(C_IMAGE_HEIGHT, rows);
Packit 78deda
    /* Set raster width*/
Packit 78deda
    (void) printf(C_IMAGE_WIDTH, cols);
Packit 78deda
    /* set left margin to current x pos*/
Packit 78deda
    /*(void) printf(C_LEFT_MARGIN, 1);*/
Packit 78deda
    /* set the correct color mode */
Packit 78deda
    (void) printf(C_CONFIG_IMAGE_DATA);
Packit 78deda
    (void) fwrite(CID, 1, 6, stdout);
Packit 78deda
    /* Start raster graphics */
Packit 78deda
    (void) printf(C_BEGIN_RASTER, C_BEGIN_RASTER_CUR);  /*posscale);*/
Packit 78deda
    /* set Y offset to 0 */
Packit 78deda
    (void) printf(C_Y_OFFSET, 0);
Packit 78deda
/*  
Packit 78deda
    if (xoff)
Packit 78deda
        (void) printf(C_MOVE_X, xoff);
Packit 78deda
    if (yoff)
Packit 78deda
        (void) printf(C_MOVE_Y, yoff);
Packit 78deda
*/
Packit 78deda
    /* Set raster compression */
Packit 78deda
    (void) printf(C_TRANS_MODE, mode);
Packit 78deda
    currentmode = mode;
Packit 78deda
    
Packit 78deda
    if(gamma)
Packit 78deda
        (void) printf(C_GAMMA,   gamma);
Packit 78deda
    
Packit 78deda
    for (r = 0; r < rows; r++)
Packit 78deda
    {
Packit 78deda
        ppm_readppmrow(ifp, pixelrow, cols, maxval, format);
Packit 78deda
Packit 78deda
        /* get a row of data with 3 bytes per pixel */
Packit 78deda
        for (c = 0, op = &obuf[-1]; c < cols; c++)
Packit 78deda
        {
Packit 78deda
            ++op;
Packit 78deda
            *op = (PPM_GETR(pixelrow[c])*255)/maxval;
Packit 78deda
            ++op;
Packit 78deda
            *op = (PPM_GETG(pixelrow[c])*255)/maxval;
Packit 78deda
            ++op;
Packit 78deda
            *op = (PPM_GETB(pixelrow[c])*255)/maxval;
Packit 78deda
        }
Packit 78deda
        ++op;
Packit 78deda
        k = op - obuf; /*size of row*/
Packit 78deda
        /*compress the row if required*/
Packit 78deda
        if(mode == C_TRANS_MODE_STD)
Packit 78deda
        {/*no compression*/
Packit 78deda
            op = obuf;
Packit 78deda
        }
Packit 78deda
Packit 78deda
        if(mode ==  C_TRANS_MODE_DELTA)
Packit 78deda
        {/*delta compression*/
Packit 78deda
            int newmode = 0;
Packit 78deda
            int deltasize = 
Packit 78deda
                compress_row_delta(obuf, previous_obuf, cbuf, cols*3);
Packit 78deda
            if(deltasize >= k)/*normal is best?*/
Packit 78deda
            {
Packit 78deda
                op = obuf;
Packit 78deda
            }
Packit 78deda
            else /*delta is best*/
Packit 78deda
            {
Packit 78deda
                k = deltasize;
Packit 78deda
                op = cbuf;
Packit 78deda
                newmode = C_TRANS_MODE_DELTA;
Packit 78deda
            }
Packit 78deda
            memcpy(previous_obuf, obuf, cols*3);
Packit 78deda
Packit 78deda
            if(currentmode != newmode)
Packit 78deda
            {
Packit 78deda
                (void) printf(C_TRANS_MODE, newmode);
Packit 78deda
                currentmode = newmode;
Packit 78deda
            }
Packit 78deda
        }
Packit 78deda
Packit 78deda
        (void) printf(C_SEND_ROW, k);
Packit 78deda
        (void) fwrite(op, 1, k, stdout);
Packit 78deda
        
Packit 78deda
    }
Packit 78deda
Packit 78deda
    (void) printf(C_END_RASTER, C_END_RASTER_UNUSED);
Packit 78deda
    if(resets & 2)
Packit 78deda
    {
Packit 78deda
        /* Printer reset. */
Packit 78deda
        printf(C_RESET);
Packit 78deda
    }
Packit 78deda
    pm_close( ifp );
Packit 78deda
    ppm_freerow(pixelrow);
Packit 78deda
Packit 78deda
    return 0;
Packit 78deda
}