about summary refs log tree commit diff
path: root/urt/rle_getrow.c
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2006-08-19 03:12:28 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2006-08-19 03:12:28 +0000
commit1fd361a1ea06e44286c213ca1f814f49306fdc43 (patch)
tree64c8c96cf54d8718847339a403e5e67b922e8c3f /urt/rle_getrow.c
downloadnetpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.gz
netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.xz
netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.zip
Create Subversion repository
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@1 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'urt/rle_getrow.c')
-rw-r--r--urt/rle_getrow.c562
1 files changed, 562 insertions, 0 deletions
diff --git a/urt/rle_getrow.c b/urt/rle_getrow.c
new file mode 100644
index 00000000..fadf5441
--- /dev/null
+++ b/urt/rle_getrow.c
@@ -0,0 +1,562 @@
+/*
+ * This software is copyrighted as noted below.  It may be freely copied,
+ * modified, and redistributed, provided that the copyright notice is 
+ * preserved on all copies.
+ * 
+ * There is no warranty or other guarantee of fitness for this software,
+ * it is provided solely "as is".  Bug reports or fixes may be sent
+ * to the author, who may or may not act on them as he desires.
+ *
+ * You may not include this software in a program or other software product
+ * without supplying the source, or without informing the end-user that the 
+ * source is available for no extra charge.
+ *
+ * If you modify this software, you should include a notice giving the
+ * name of the person performing the modification, the date of modification,
+ * and the reason for such modification.
+ *
+ *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
+ *  to have all "void" functions so declared.
+ */
+/* 
+ * rle_getrow.c - Read an RLE file in.
+ * 
+ * Author:  Spencer W. Thomas
+ *      Computer Science Dept.
+ *      University of Utah
+ * Date:    Wed Apr 10 1985
+ * Copyright (c) 1985 Spencer W. Thomas
+ * 
+ * $Id: rle_getrow.c,v 3.0.1.5 1992/03/04 19:33:08 spencer Exp spencer $
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include "pm.h"
+#include "mallocvar.h"
+
+#include "rle.h"
+#include "rle_code.h"
+#include "vaxshort.h"
+
+/* Read a two-byte "short" that started in VAX (LITTLE_ENDIAN) order */
+#define VAXSHORT( var, fp )\
+    { var = fgetc(fp)&0xFF; var |= (fgetc(fp)) << 8; }
+  
+/* Instruction format -- first byte is opcode, second is datum. */
+
+#define OPCODE(inst) (inst[0] & ~LONG)
+#define LONGP(inst) (inst[0] & LONG)
+#define DATUM(inst) (inst[1] & 0xff)    /* Make sure it's unsigned. */
+
+static int     debug_f;     /* If non-zero, print debug info. */
+
+/*****************************************************************
+ * TAG( rle_get_setup )
+ * 
+ * Read the initialization information from an RLE file.
+ * Inputs:
+ *  the_hdr:    Contains pointer to the input file.
+ * Outputs:
+ *  the_hdr:    Initialized with information from the
+ *          input file.
+ *  Returns 0 on success, -1 if the file is not an RLE file,
+ *  -2 if malloc of the color map failed, -3 if an immediate EOF
+ *  is hit (empty input file), and -4 if an EOF is encountered reading
+ *  the setup information.
+ * Assumptions:
+ *  infile points to the "magic" number in an RLE file (usually
+ * byte 0 in the file).
+ * Algorithm:
+ *  Read in the setup info and fill in the_hdr.
+ */
+int
+rle_get_setup(rle_hdr * const the_hdr) {
+    struct XtndRsetup setup;
+    short magic;
+    FILE * infile = the_hdr->rle_file;
+    int i;
+    char * comment_buf;
+    
+    /* Clear old stuff out of the header. */
+    rle_hdr_clear( the_hdr );
+    if ( the_hdr->is_init != RLE_INIT_MAGIC )
+        rle_names( the_hdr, "Urt", "some file", 0 );
+    the_hdr->img_num++;     /* Count images. */
+
+    VAXSHORT( magic, infile );
+    if ( feof( infile ) )
+        return RLE_EMPTY;
+    if ( magic != RLE_MAGIC )
+        return RLE_NOT_RLE;
+    fread( &setup, 1, SETUPSIZE, infile );  /* assume VAX packing */
+    if ( feof( infile ) )
+        return RLE_EOF;
+
+    /* Extract information from setup */
+    the_hdr->ncolors = setup.h_ncolors;
+    for ( i = 0; i < the_hdr->ncolors; i++ )
+        RLE_SET_BIT( *the_hdr, i );
+
+    if ( !(setup.h_flags & H_NO_BACKGROUND) && setup.h_ncolors > 0 )
+    {
+        rle_pixel * bg_color;
+
+        MALLOCARRAY(the_hdr->bg_color, setup.h_ncolors);
+        MALLOCARRAY(bg_color, 1 + (setup.h_ncolors / 2) * 2);
+        RLE_CHECK_ALLOC( the_hdr->cmd, the_hdr->bg_color && bg_color,
+                         "background color" );
+        fread( (char *)bg_color, 1, 1 + (setup.h_ncolors / 2) * 2, infile );
+        for ( i = 0; i < setup.h_ncolors; i++ )
+            the_hdr->bg_color[i] = bg_color[i];
+        free( bg_color );
+    }
+    else
+    {
+        (void)getc( infile );   /* skip filler byte */
+        the_hdr->bg_color = NULL;
+    }
+
+    if ( setup.h_flags & H_NO_BACKGROUND )
+        the_hdr->background = 0;
+    else if ( setup.h_flags & H_CLEARFIRST )
+        the_hdr->background = 2;
+    else
+        the_hdr->background = 1;
+    if ( setup.h_flags & H_ALPHA )
+    {
+        the_hdr->alpha = 1;
+        RLE_SET_BIT( *the_hdr, RLE_ALPHA );
+    }
+    else
+        the_hdr->alpha = 0;
+
+    the_hdr->xmin = vax_gshort( setup.hc_xpos );
+    the_hdr->ymin = vax_gshort( setup.hc_ypos );
+    the_hdr->xmax = the_hdr->xmin + vax_gshort( setup.hc_xlen ) - 1;
+    the_hdr->ymax = the_hdr->ymin + vax_gshort( setup.hc_ylen ) - 1;
+
+    the_hdr->ncmap = setup.h_ncmap;
+    the_hdr->cmaplen = setup.h_cmaplen;
+    if ( the_hdr->ncmap > 0 )
+    {
+        int const maplen = the_hdr->ncmap * (1 << the_hdr->cmaplen);
+        int i;
+        char *maptemp;
+
+        MALLOCARRAY(the_hdr->cmap, maplen);
+        MALLOCARRAY(maptemp, 2 * maplen);
+        if ( the_hdr->cmap == NULL || maptemp == NULL )
+        {
+            pm_error("Malloc failed for color map of size %d*%d "
+                     "in rle_get_setup, reading '%s'",
+                     the_hdr->ncmap, (1 << the_hdr->cmaplen),
+                     the_hdr->file_name );
+            return RLE_NO_SPACE;
+        }
+        fread( maptemp, 2, maplen, infile );
+        for ( i = 0; i < maplen; i++ )
+            the_hdr->cmap[i] = vax_gshort( &maptemp[i * 2] );
+        free( maptemp );
+    }
+
+    /* Check for comments */
+    if ( setup.h_flags & H_COMMENT )
+    {
+        short comlen, evenlen;
+        register char * cp;
+
+        VAXSHORT( comlen, infile ); /* get comment length */
+        evenlen = (comlen + 1) & ~1;    /* make it even */
+        if ( evenlen )
+        {
+            MALLOCARRAY(comment_buf, evenlen);
+    
+            if ( comment_buf == NULL )
+            {
+                pm_error("Malloc failed for comment buffer of size %d "
+                         "in rle_get_setup, reading '%s'",
+                         comlen, the_hdr->file_name );
+                return RLE_NO_SPACE;
+            }
+            fread( comment_buf, 1, evenlen, infile );
+            /* Count the comments */
+            for ( i = 0, cp = comment_buf; cp < comment_buf + comlen; cp++ )
+                if ( *cp == 0 )
+                    i++;
+            i++;            /* extra for NULL pointer at end */
+            /* Get space to put pointers to comments */
+            MALLOCARRAY(the_hdr->comments, i);
+            if ( the_hdr->comments == NULL )
+            {
+                pm_error("Malloc failed for %d comment pointers "
+                         "in rle_get_setup, reading '%s'",
+                         i, the_hdr->file_name );
+                return RLE_NO_SPACE;
+            }
+            /* Get pointers to the comments */
+            *the_hdr->comments = comment_buf;
+            for ( i = 1, cp = comment_buf + 1;
+                  cp < comment_buf + comlen;
+                  cp++ )
+                if ( *(cp - 1) == 0 )
+                    the_hdr->comments[i++] = cp;
+            the_hdr->comments[i] = NULL;
+        }
+        else
+            the_hdr->comments = NULL;
+    }
+    else
+        the_hdr->comments = NULL;
+
+    /* Initialize state for rle_getrow */
+    the_hdr->priv.get.scan_y = the_hdr->ymin;
+    the_hdr->priv.get.vert_skip = 0;
+    the_hdr->priv.get.is_eof = 0;
+    the_hdr->priv.get.is_seek = ftell( infile ) > 0;
+    debug_f = 0;
+
+    if ( !feof( infile ) )
+        return RLE_SUCCESS; /* success! */
+    else
+    {
+        the_hdr->priv.get.is_eof = 1;
+        return RLE_EOF;
+    }
+}
+
+
+/*****************************************************************
+ * TAG( rle_get_setup_ok )
+ * 
+ * Read the initialization information from an RLE file.
+ * Inputs:
+ *  the_hdr:    Contains pointer to the input file.
+ *  prog_name:  Program name to be printed in the error message.
+ *      file_name:  File name to be printed in the error message.
+ *                  If NULL, the string "stdin" is generated.
+ * Outputs:
+ *  the_hdr:    Initialized with information from the
+ *          input file.
+ *      If reading the header fails, it prints an error message
+ *  and exits with the appropriate status code.
+ * Algorithm:
+ *  rle_get_setup does all the work.
+ */
+void
+rle_get_setup_ok( the_hdr, prog_name, file_name )
+rle_hdr * the_hdr;
+const char *prog_name;
+const char *file_name;
+{
+    int code;
+
+    /* Backwards compatibility: if is_init is not properly set, 
+     * initialize the header.
+     */
+    if ( the_hdr->is_init != RLE_INIT_MAGIC )
+    {
+    FILE *f = the_hdr->rle_file;
+    rle_hdr_init( the_hdr );
+    the_hdr->rle_file = f;
+    rle_names( the_hdr, prog_name, file_name, 0 );
+    }
+
+    code = rle_get_error( rle_get_setup( the_hdr ),
+              the_hdr->cmd, the_hdr->file_name );
+    if (code)
+    exit( code );
+}
+
+
+/*****************************************************************
+ * TAG( rle_debug )
+ * 
+ * Turn RLE debugging on or off.
+ * Inputs:
+ *  on_off:     if 0, stop debugging, else start.
+ * Outputs:
+ *  Sets internal debug flag.
+ * Assumptions:
+ *  [None]
+ * Algorithm:
+ *  [None]
+ */
+void
+rle_debug( on_off )
+int on_off;
+{
+    debug_f = on_off;
+
+    /* Set line buffering on stderr.  Character buffering is the default, and
+     * it is SLOOWWW for large amounts of output.
+     */
+    setvbuf( stderr, NULL, _IOLBF, 0);
+/*
+    setlinebuf( stderr );
+*/
+}
+
+
+/*****************************************************************
+ * TAG( rle_getrow )
+ * 
+ * Get a scanline from the input file.
+ * Inputs:
+ *  the_hdr:    Header structure containing information about 
+ *          the input file.
+ * Outputs:
+ *  scanline:   an array of pointers to the individual color
+ *          scanlines.  Scanline is assumed to have
+ *          the_hdr->ncolors pointers to arrays of rle_pixel,
+ *          each of which is at least the_hdr->xmax+1 long.
+ *  Returns the current scanline number.
+ * Assumptions:
+ *  rle_get_setup has already been called.
+ * Algorithm:
+ *  If a vertical skip is being executed, and clear-to-background is
+ *  specified (the_hdr->background is true), just set the
+ *  scanlines to the background color.  If clear-to-background is
+ *  not set, just increment the scanline number and return.
+ * 
+ *  Otherwise, read input until a vertical skip is encountered,
+ *  decoding the instructions into scanline data.
+ *
+ *  If ymax is reached (or, somehow, passed), continue reading and
+ *  discarding input until end of image.
+ */
+int
+rle_getrow( the_hdr, scanline )
+rle_hdr * the_hdr;
+rle_pixel *scanline[];
+{
+    register rle_pixel * scanc;
+    register int nc;
+    register FILE *infile = the_hdr->rle_file;
+    int scan_x = the_hdr->xmin, /* current X position */
+        max_x = the_hdr->xmax,  /* End of the scanline */
+       channel = 0;         /* current color channel */
+    int ns;         /* Number to skip */
+    short word, long_data;
+    char inst[2];
+
+    /* Clear to background if specified */
+    if ( the_hdr->background != 1 )
+    {
+    if ( the_hdr->alpha && RLE_BIT( *the_hdr, -1 ) )
+        memset( (char *)scanline[-1] + the_hdr->xmin, 0,
+           the_hdr->xmax - the_hdr->xmin + 1 );
+    for ( nc = 0; nc < the_hdr->ncolors; nc++ )
+        if ( RLE_BIT( *the_hdr, nc ) ) {
+        /* Unless bg color given explicitly, use 0. */
+        if ( the_hdr->background != 2 || the_hdr->bg_color[nc] == 0 )
+            memset( (char *)scanline[nc] + the_hdr->xmin, 0,
+               the_hdr->xmax - the_hdr->xmin + 1 );
+        else
+            memset((char *)scanline[nc] + the_hdr->xmin,
+                   the_hdr->bg_color[nc],
+                   the_hdr->xmax - the_hdr->xmin + 1);
+        }
+    }
+
+    /* If skipping, then just return */
+    if ( the_hdr->priv.get.vert_skip > 0 )
+    {
+    the_hdr->priv.get.vert_skip--;
+    the_hdr->priv.get.scan_y++;
+    if ( the_hdr->priv.get.vert_skip > 0 ) {
+        if ( the_hdr->priv.get.scan_y >= the_hdr->ymax )
+        {
+        int y = the_hdr->priv.get.scan_y;
+        while ( rle_getskip( the_hdr ) != 32768 )
+            ;
+        return y;
+        }
+        else
+        return the_hdr->priv.get.scan_y;
+    }
+    }
+
+    /* If EOF has been encountered, return also */
+    if ( the_hdr->priv.get.is_eof )
+    return ++the_hdr->priv.get.scan_y;
+
+    /* Otherwise, read and interpret instructions until a skipLines
+     * instruction is encountered.
+     */
+    if ( RLE_BIT( *the_hdr, channel ) )
+    scanc = scanline[channel] + scan_x;
+    else
+    scanc = NULL;
+    for (;;)
+    {
+    inst[0] = getc( infile );
+    inst[1] = getc( infile );
+    if ( feof(infile) )
+    {
+        the_hdr->priv.get.is_eof = 1;
+        break;      /* <--- one of the exits */
+    }
+
+    switch( OPCODE(inst) )
+    {
+    case RSkipLinesOp:
+        if ( LONGP(inst) )
+        {
+        VAXSHORT( the_hdr->priv.get.vert_skip, infile );
+        }
+        else
+        the_hdr->priv.get.vert_skip = DATUM(inst);
+        if (debug_f)
+        fprintf(stderr, "Skip %d Lines (to %d)\n",
+            the_hdr->priv.get.vert_skip,
+            the_hdr->priv.get.scan_y +
+                the_hdr->priv.get.vert_skip );
+
+        break;          /* need to break for() here, too */
+
+    case RSetColorOp:
+        channel = DATUM(inst);  /* select color channel */
+        if ( channel == 255 )
+        channel = -1;
+        scan_x = the_hdr->xmin;
+        if ( RLE_BIT( *the_hdr, channel ) )
+        scanc = scanline[channel]+scan_x;
+        if ( debug_f )
+        fprintf( stderr, "Set color to %d (reset x to %d)\n",
+             channel, scan_x );
+        break;
+
+    case RSkipPixelsOp:
+        if ( LONGP(inst) )
+        {
+        VAXSHORT( long_data, infile );
+        scan_x += long_data;
+        scanc += long_data;
+        if ( debug_f )
+            fprintf( stderr, "Skip %d pixels (to %d)\n",
+                long_data, scan_x );
+        }
+        else
+        {
+        scan_x += DATUM(inst);
+        scanc += DATUM(inst);
+        if ( debug_f )
+            fprintf( stderr, "Skip %d pixels (to %d)\n",
+                DATUM(inst), scan_x );
+        }
+        break;
+
+    case RByteDataOp:
+        if ( LONGP(inst) )
+        {
+        VAXSHORT( nc, infile );
+        }
+        else
+        nc = DATUM(inst);
+        nc++;
+        if ( debug_f ) {
+        if ( RLE_BIT( *the_hdr, channel ) )
+            fprintf( stderr, "Pixel data %d (to %d):", nc, scan_x+nc );
+        else
+            fprintf( stderr, "Pixel data %d (to %d)\n", nc, scan_x+nc);
+        }
+        if ( RLE_BIT( *the_hdr, channel ) )
+        {
+        /* Don't fill past end of scanline! */
+        if ( scan_x + nc > max_x )
+        {
+            ns = scan_x + nc - max_x - 1;
+            nc -= ns;
+        }
+        else
+            ns = 0;
+        fread( (char *)scanc, 1, nc, infile );
+        while ( ns-- > 0 )
+            (void)getc( infile );
+        if ( nc & 1 )
+            (void)getc( infile );   /* throw away odd byte */
+        }
+        else
+        if ( the_hdr->priv.get.is_seek )
+            fseek( infile, ((nc + 1) / 2) * 2, 1 );
+        else
+        {
+            register int ii;
+            for ( ii = ((nc + 1) / 2) * 2; ii > 0; ii-- )
+            (void) getc( infile );  /* discard it */
+        }
+
+        scanc += nc;
+        scan_x += nc;
+        if ( debug_f && RLE_BIT( *the_hdr, channel ) )
+        {
+        rle_pixel * cp = scanc - nc;
+        for ( ; nc > 0; nc-- )
+            fprintf( stderr, "%02x", *cp++ );
+        putc( '\n', stderr );
+        }
+        break;
+
+    case RRunDataOp:
+        if ( LONGP(inst) )
+        {
+        VAXSHORT( nc, infile );
+        }
+        else
+        nc = DATUM(inst);
+        nc++;
+        scan_x += nc;
+
+        VAXSHORT( word, infile );
+        if ( debug_f )
+        fprintf( stderr, "Run length %d (to %d), data %02x\n",
+                nc, scan_x, word );
+        if ( RLE_BIT( *the_hdr, channel ) )
+        {
+        if ( scan_x > max_x )
+        {
+            ns = scan_x - max_x - 1;
+            nc -= ns;
+        } 
+        else
+            ns = 0;
+        if ( nc >= 10 )     /* break point for 785, anyway */
+        {
+            memset((char *)scanc, word, nc);
+            scanc += nc;
+        }
+        else
+            for ( nc--; nc >= 0; nc--, scanc++ )
+            *scanc = word;
+        }
+        break;
+
+    case REOFOp:
+        the_hdr->priv.get.is_eof = 1;
+        if ( debug_f )
+        fprintf( stderr, "End of Image\n" );
+        break;
+
+    default:
+        fprintf( stderr,
+             "%s: rle_getrow: Unrecognized opcode: %d, reading %s\n",
+             the_hdr->cmd, inst[0], the_hdr->file_name );
+        exit(1);
+    }
+    if ( OPCODE(inst) == RSkipLinesOp || OPCODE(inst) == REOFOp )
+        break;          /* <--- the other loop exit */
+    }
+
+    /* If at end, skip the rest of a malformed image. */
+    if ( the_hdr->priv.get.scan_y >= the_hdr->ymax )
+    {
+    int y = the_hdr->priv.get.scan_y;
+    while ( rle_getskip( the_hdr ) != 32768 )
+        ;
+    return y;
+    }
+
+    return the_hdr->priv.get.scan_y;
+}