cnv/rletoraw.c
/*
* 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.
*/
/*
* rletoraw.c - Convert the RLE format to the kitchen sink.
*
* Author: Martin R. Friedmann
* Vision and Modeling Group/Media Lab
* Massachusetts Institute of Technology
* Date: Thu Sep 13 1990
* Copyright (c) 1990, Martin R. Friedmann
*
* usage : rletoraw [-{Ns}] [-r] [-w width] [-h height] [-f header-size]
* [-t tailer-size] [-n nchannels] [-a]
* [-p scanline-pad] [-l left-scanline-pad] [-o outfile]
* [infile]
*
* -a dont strip the alpha channel from the rle file
* -s output data in scanline interleaved order
* -N output data in non-interleaved order (eg. | split -Wid*Height -)
* -r reverse the channel order (e.g. write data as ABGR instead of
* the default RGBA order)
*
*/
#include <stdio.h>
#include "rle.h"
/* hey.. why spin normally! */
#define duff(counter, block) {\
while (counter >= 4) {\
{ block; } \
{ block; } \
{ block; } \
{ block; } \
counter -= 4;\
} \
switch (counter & 3) { \
case 3: { block; } \
case 2: { block; } \
case 1: { block; } \
case 0: counter = 0;\
}\
}
#define WRITE_DATA() \
if (fwrite( outrows, 1, fwrite_len, outfile ) != fwrite_len) {\
perror( "write error" );\
exit(-2);\
}\
void
main(argc,argv)
int argc;
char *argv[];
{
int i, rle_err;
char *nullbytes = NULL;
char *infname = NULL, *outfname = NULL, *progname;
FILE *infile, *outfile;
rle_hdr hdr;
int oflag = 0;
int fflag = 0, tflag = 0, Nflag = 0, rflag = 0;
int header = 0, trailer = 0;
int pflag= 0, right_pad = 0, lflag = 0, left_pad = 0;
int aflag = 0, output_alpha = 0, sflag = 0;
int height, width, nochan;
int red_pos, alpha_pos, green_pos = 0, blue_pos = 0;
int img_size;
/* Default color values */
unsigned char *outrows;
rle_pixel **inrows;
int outrows_size;
int y;
int line_pos;
int fwrite_len;
unsigned char *fwrite_pos;
progname = cmd_name( argv );
if ( scanargs( argc, argv,
"% Ns%- r%- a%- f%-header-size!d t%-trailer-size!d \n\
\t\tp%-scanline-pad!d l%-left-scanline-pad!d o%-outfile!s \n\
\t\tinfile%s\n(\
\t-a\tDon't strip the alpha channel from the rle file.\n\
\t-f,-t\tEach output image is preceded (followed) by so many bytes.\n\
\t-l,-p\tScanlines are padded on left (right) end with so many bytes.\n\
\t\tAll padding is with null (0) bytes.\n\
\t-s\tOutput data in scanline interleaved order\n\
\t-N\tOutput data in non-interleaved order (eg. | split -Wid*Height -)\n\
\t-r\treverse the channel order (e.g. write data as ABGR instead of\n\
\t\tthe default RGBA order).)",
&Nflag, &rflag, &aflag, &fflag, &header,
&tflag, &trailer, &pflag, &right_pad, &lflag, &left_pad,
&oflag, &outfname, &infname ) == 0)
exit( 1 );
/* Initialize header. */
hdr = *rle_hdr_init( (rle_hdr *)NULL );
rle_names( &hdr, cmd_name( argv ), infname, 0 );
if (Nflag) {
if (Nflag & 1) {
Nflag = 0;
sflag = 1;
} else {
Nflag = 1;
sflag = 0;
}
}
/* Open Raw file */
infile = rle_open_f( progname, infname, "r" );
outfile = rle_open_f( progname, outfname, "w" );
rle_dflt_hdr.rle_file = infile;
if ( (rle_err = rle_get_setup(&rle_dflt_hdr)) < 0) {
rle_get_error( rle_err, progname, infname );
exit ( rle_err );
}
rle_dflt_hdr.xmax -= rle_dflt_hdr.xmin;
rle_dflt_hdr.xmin = 0;
rle_dflt_hdr.ymax -= rle_dflt_hdr.ymin;
rle_dflt_hdr.ymin = 0;
width = rle_dflt_hdr.xmax + 1;
height = rle_dflt_hdr.ymax + 1;
nochan = rle_dflt_hdr.ncolors;
fprintf(stderr, "width %d, height %d, channels %d\n", width, height, nochan);
if (! aflag)
RLE_CLR_BIT(rle_dflt_hdr, RLE_ALPHA);
output_alpha = (aflag && RLE_BIT(rle_dflt_hdr, RLE_ALPHA)) ? 1 : 0;
/* for -Non-interleaved case, we need nochan-1 whole channels of buffer */
/* HACK: we allocate more memory; we jack the size for the first fread */
outrows_size = width * (nochan + output_alpha);
if ( Nflag )
outrows_size *= height;
if ((outrows = (unsigned char *) malloc ( outrows_size )) == NULL ) {
fprintf(stderr, "%s: No memory available for rows malloc\n", progname);
exit(-2);
}
img_size = width * height;
/* Were only interested in R, G, & B */
for (i = 3; i < rle_dflt_hdr.ncolors; i++)
RLE_CLR_BIT(rle_dflt_hdr, i);
if (rle_row_alloc( &rle_dflt_hdr, &inrows )) {
fprintf(stderr, "%s: No memory available for rle_row_alloc\n", progname);
exit(-2);
}
/* maybe faster to malloc and fwrite than to do lots of GETCs, Idunno */
if (fflag || tflag) {
nullbytes = (char *) malloc ( (header > trailer) ? header : trailer );
if (! nullbytes)
fprintf(stderr, "%s: No memory for nullbytes\n", progname);
else
for( i = (header > trailer) ? header : trailer; i > 0; )
nullbytes[--i] = 0;
}
/* setup byte positions for reversed colors or otherwise */
if ( rflag ) {
alpha_pos = 0;
/* alpha comes first if it's there */
if (nochan > 2) {
red_pos = 2 + output_alpha;
green_pos = 1 + output_alpha;
blue_pos = 0 + output_alpha;
} else
red_pos = 0 + output_alpha;
}
else {
alpha_pos = nochan;
red_pos = 0;
if (nochan > 2) {
green_pos = 1;
blue_pos = 2;
}
}
if ( Nflag ) {
red_pos *= img_size;
green_pos *= img_size;
blue_pos *= img_size;
alpha_pos *= img_size;
} else if ( sflag ) {
red_pos *= width;
green_pos *= width;
blue_pos *= width;
alpha_pos *= width;
}
y = height;
line_pos = 0;
fwrite_len = outrows_size;
fwrite_pos = outrows;
/* write the header */
if (fflag)
fwrite( nullbytes, 1, header, outfile );
while (--y >= 0) {
register rle_pixel *p, *o;
register int stride = nochan + output_alpha, count;
rle_getrow(&rle_dflt_hdr, inrows);
/* non-interleaved data is easier to compute than interleaved */
if ( Nflag ) {
/*
* This is a wierd case... We had to read in all of the
* scanlines for all but one of the channels... Then we can
* handle things scanline by scanline... We have to jack
* the fread parameters for all of the remaining scanlines
*/
if ( output_alpha )
bcopy(inrows[RLE_ALPHA], outrows + alpha_pos + line_pos,width);
bcopy(inrows[RLE_RED], outrows + red_pos + line_pos, width);
if (nochan > 2) {
bcopy(inrows[RLE_GREEN], outrows + green_pos + line_pos,width);
bcopy(inrows[RLE_BLUE], outrows + blue_pos + line_pos,width);
}
line_pos += width;
} else if (sflag) {
/* scanline interleaved: we only need to copy the data */
if ( output_alpha )
bcopy (inrows[RLE_ALPHA], outrows + alpha_pos, width);
bcopy (inrows[RLE_RED], outrows + red_pos, width);
if (nochan > 2) {
bcopy(inrows[RLE_GREEN], outrows + green_pos, width);
bcopy(inrows[RLE_BLUE], outrows + blue_pos, width);
}
}
else
{
#define COPY_LINE() duff(count, *o = *p++; o += stride);
/* ahhh... the default. interleaved data */
if ( output_alpha ) {
o = outrows + alpha_pos;
p = inrows[RLE_ALPHA];
count = width;
COPY_LINE();
}
o = outrows + red_pos;
p = inrows[RLE_RED];
count = width;
COPY_LINE();
if (nochan > 2) {
o = outrows + green_pos;
p = inrows[RLE_GREEN];
count = width;
COPY_LINE();
o = outrows + blue_pos;
p = inrows[RLE_BLUE];
count = width;
COPY_LINE();
}
}
/* LEFT_PAD */
for (count = 0; count < left_pad; count++)
putc('\0', outfile);
/* WRITE_SCANLINE */
if (! Nflag)
WRITE_DATA();
/* RIGHT_PAD */
for (count = 0; count < right_pad; count++)
putc('\0', outfile);
}
if ( Nflag )
WRITE_DATA();
/* write the trailer */
if (tflag)
fwrite( nullbytes, 1, trailer, outfile );
exit(0);
}