/* writeres.c
*
* Module: writeres
* Owner: knox
* stdin: image internal format
* args:
* -i (if present, a request to write the internal file on stdout)
* name (name of the output res file)
* resolution (if present, the resolution of the image in spots/inch)
*
* Description:
* This program reads internal format images and puts them
* into RES files. The input internal memory image is read
* from standard input. If the flag, -i, is the first argument
* then the internal file is written onto the standard output.
* If this flag is absent then the name of the output RES file is
* the first argument of the command line.
*
* The image raster will be stored in the file "name.res",
* where name is read from the command line. The ".res"
* extension will not be added if it is already present in the
* name. The mask raster present in the internal image will
* be recorded with the image data in the file. Both the image
* and mask rasters may be either 1 or 8 bits/pixel.
*
* If an argument follows the name on the command line, then
* it is the resolution at which the image was originally created.
* If this argument is not present, then a resolution of 300 spi
* is assumed. The resolution parameter must be an integer.
*
*/
#include <time.h>
#include <fcntl.h>
#include <internal.h>
#include <iptokens.h>
extern unsigned char *malloc();
extern struct header *getheader();
extern long timezone;
#define err0 "writeres: No output RES file name!\n"
#define err1 "writeres: Needs one resolution parameter, got %d!\n"
#define err2 "writeres: Resolution cannot be zero!"
#define err3 "writeres: Output RES file could not be created, %s!\n"
#define RES←header "Interpress/Xerox/2.1/RasterEncoding/1.0 "
#define BUFFSIZE 65536
#define BLOCKSIZE 16777215 /* 16*1024*1024-1 */
#define len←longOP 2
#define len←shortNUM 2
#define len←shortSEQ 2
#define len←longSEQ 4
#define max(a, b) (a > b ? a : b)
struct header *input;
char * program;
int resolution = 300;
int fdin, fdout, fdint;
int internal = 0;
int index = 2;
char *filename;
int masklen;
int imagelen;
long startmask;
long startimage;
struct blocks
{
int depth;
long *bytelength;
int current;
int bytesused;
};
struct blocks maskblocks;
struct blocks imageblocks;
main(argc, argv)
int argc;
char *argv[];
{
program = argv[0];
getargs(argc, argv);
input = getheader(fdin);
checkheader(argc, argv);
if (internal) putheader(fdint, input);
writedata();
writecodes();
exit(0);
}
getargs(argc, argv)
int argc;
char *argv[];
{
int n;
fdin = 0;
fdint = 1;
if (argc < 2) error(err0);
if (strcmp(argv[1], "-i") == 0)
{
internal = 1;
index = 3;
}
if (argc < index) error(err0);
if (argc > index)
{
n = sscanf(argv[index], "%d", &resolution);
if (n != 1) error(err1, n);
if (resolution == 0) error(err2);
}
}
checkheader(argc, argv)
int argc;
char *argv[];
{
/* variables */
int size;
char *temp;
/* Check for errors in the input header using library routines. */
check(input, program);
restrict(input, program, "bitsperPixel", "1 8");
restrict(input, program, "maskbitsperPixel", "1 8");
restrict(input, program, "signed", "0");
restrict(input, program, "trcLength", "0");
/* Make output RES file. */
fdout = 0;
filename = (char *) malloc(strlen(argv[index-1])+1+strlen(".res"));
strcpy(filename, argv[index-1]);
if (strcmp(".res", strrchr(filename, '.')) != 0) strcat(filename, ".res");
ImageSize();
size = RESfilesize();
fdout = open(filename, O←WRONLY | O←CREAT | O←CTG, 0666, size);
if (fdout == -1) fdout = open(filename, O←WRONLY | O←CREAT, 0666);
if (fdout == -1) error(err3, filename);
}
writedata()
{
/* allocate buffer space for scanlines */
int n, firstwrite;
int imagecount, imagebuffersize, imageroom;
int maskcount, maskbuffersize, maskroom;
long imagefp, maskfp;
unsigned char *mask, *image;
firstwrite = 1;
if (input->imageExists)
{
imageroom = max(imagelen, input->bytesperSL); /* room for either input or output */
imagebuffersize = max(imageroom, BUFFSIZE); /* make sure one line can fit */
image = malloc(imagebuffersize);
}
if (input->maskExists)
{
maskroom = max(masklen, input->maskbytesperSL);
maskbuffersize = max(maskroom, BUFFSIZE);
mask = malloc(maskbuffersize);
}
imagefp = startimage;
maskfp = startmask;
/* read and send the raster data */
imagecount = maskcount = 0;
for (n=0; n < input->scanlines; n++)
{
if (input->imageExists)
{
readbytes(fdin, image+imagecount, input->bytesperSL);
if (internal) writebytes(fdint, image+imagecount, input->bytesperSL);
imagecount += imagelen;
if (((imagebuffersize-imagecount) < imageroom) || (n == (input->scanlines-1)))
{
if (input->maskExists != 0 || firstwrite != 0) lseek(fdout, imagefp, 0);
imagefp += writescanlines(fdout, image, imagecount, &imageblocks);
imagecount = 0;
firstwrite = 0;
}
}
if (input->maskExists)
{
readbytes(fdin, mask+maskcount, input->maskbytesperSL);
if (internal) writebytes(fdint, mask+maskcount, input->maskbytesperSL);
maskcount += masklen;
if (((maskbuffersize-maskcount) < maskroom) || (n == (input->scanlines-1)))
{
if (input->imageExists != 0 || firstwrite != 0) lseek(fdout, maskfp, 0);
maskfp += writescanlines(fdout, mask, maskcount, &maskblocks);
maskcount = 0;
firstwrite = 0;
}
}
}
if (input->imageExists) free(image);
if (input->maskExists) free(mask);
}
writescanlines(fd, buffer, count, ptrblocks)
int fd;
unsigned char *buffer;
int count;
struct blocks *ptrblocks;
{
/* It fits completely in this block. */
int bytesleft, padding, current;
bytesleft = ptrblocks->bytelength[ptrblocks->current]-ptrblocks->bytesused;
if (count < bytesleft)
{
write(fd, buffer, count);
ptrblocks->bytesused += count;
return(count);
}
/* It goes into the next block, too. */
write(fd, buffer, bytesleft);
ptrblocks->current++;
ptrblocks->bytesused = 0;
current = ptrblocks->current;
padding = 0;
if (current < ptrblocks->depth)
{
padding = (ptrblocks->bytelength[current] > 255) ? len←longSEQ : len←shortSEQ;
}
if (padding) lseek(fd, padding, 1);
buffer += bytesleft;
count -= bytesleft;
if (count) count = writescanlines(fd, buffer, count, ptrblocks);
return(bytesleft+padding+count);
}
extern char *RESdate();
writecodes()
{
/* start RES file */
int n;
char *date;
lseek(fdout, (long) 0, 0);
AppendHeader(fdout, RES←header); /* "Interpress/Xerox/2.1/RasterEncoding/1.0 " */
AppendOp(OP←beginBlock); /* BEGIN */
AppendRational(254, 3000000); /* scale in x */
AppendOp(OP←dup); /* scale in y */
AppendInteger(2);
AppendOp(OP←makevec); /* imageScale */
AppendInteger(input->pixels); /* xDimension */
AppendInteger(input->scanlines); /* yDimension */
/* Do the mask pixel array. */
if (input->maskExists)
{
AppendInteger(input->scanlines); /* xPixels */
AppendInteger(input->pixels); /* yPixels */
AppendInteger(1); /* samples/pixel */
AppendInteger((1 << input->maskbitsperPixel)-1); /* max sample value */
AppendInteger(0); /* samples interleaved */
AppendInteger(-90);
AppendOp(OP←rotate);
AppendInteger(0);
AppendInteger(input->scanlines); /* xPixels */
AppendOp(OP←translate);
AppendOp(OP←concat); /* transformation */
AppendPPV(maskblocks.bytelength[0],
input->maskbitsperPixel, input->pixels); /* packed pixel vector */
lseek(fdout, maskblocks.bytelength[0]-4, 1);
for (n=1; n < maskblocks.depth; n++)
{
AppendSeqContinued(maskblocks.bytelength[n]);
lseek(fdout, maskblocks.bytelength[n], 1);
}
AppendOp(OP←makepixelarray);
}
else AppendInteger(0); /* null maskImage */
/* Do the image pixel array. */
if (input->imageExists)
{
AppendInteger(input->scanlines); /* xPixels */
AppendInteger(input->pixels); /* yPixels */
AppendInteger(1); /* samples/pixel */
AppendInteger((1 << input->bitsperPixel)-1); /* max sample value */
AppendInteger(0); /* samples interleaved */
AppendInteger(-90);
AppendOp(OP←rotate);
AppendInteger(0);
AppendInteger(input->scanlines); /* xPixels */
AppendOp(OP←translate);
AppendOp(OP←concat); /* transformation */
AppendPPV(imageblocks.bytelength[0],
input->bitsperPixel, input->pixels); /* packed pixel vector */
lseek(fdout, imageblocks.bytelength[0]-4, 1);
for (n=1; n < imageblocks.depth; n++)
{
AppendSeqContinued(imageblocks.bytelength[n]);
lseek(fdout, imageblocks.bytelength[n], 1);
}
AppendOp(OP←makepixelarray);
}
else AppendInteger(0); /* null colorImage */
/* Write out the color operator. */
if (input->imageExists)
{
AppendInteger((1 << input->bitsperPixel)-1); /* swhite */
AppendInteger(0); /* sblack */
AppendInteger(0); /* pixelMap */
AppendInteger(3); /* 3 */
AppendOp(OP←makevec); /* MAKEVEC */
AppendIdentifier("xerox"); /* xerox */
AppendIdentifier("GrayLinear"); /* GrayLinear */
AppendInteger(2); /* 2 */
AppendOp(OP←makevec); /* MAKEVEC */
AppendOp(OP←findcolormodeloperator); /* FINDCOLORMODELOP */
AppendOp(OP←do); /* DO */
}
/* Append image properties. */
AppendIdentifier("name"); /* name */
AppendString(filename); /* filename */
AppendIdentifier("creationTime"); /* creationTime */
AppendString((date = RESdate())); /* date */
AppendInteger(4); /* 4 */
AppendOp(OP←makevec); /* MAKEVEC */
/* Wrap up the RES file. */
AppendInteger(13086); /* signature */
AppendOp(OP←endBlock); /* END */
free(date);
}
ImageSize()
{
/* How big is the mask. */
int n, depth;
long total;
if (input->maskExists)
{
masklen = 4*((input->pixels*input->maskbitsperPixel+31)/32);
total = 4+input->scanlines*masklen;
depth = (total+BLOCKSIZE-1)/BLOCKSIZE;
maskblocks.depth = depth;
maskblocks.bytelength = (long *) malloc(depth*sizeof(long *));
for (n=0; n < depth-1; n++)
{
maskblocks.bytelength[n] = BLOCKSIZE;
total -= BLOCKSIZE;
}
maskblocks.bytelength[depth-1] = total;
maskblocks.current = 0;
maskblocks.bytesused = 4;
}
/* How big is the image. */
if (input->imageExists)
{
imagelen = 4*((input->pixels*input->bitsperPixel+31)/32);
total = 4+input->scanlines*imagelen;
depth = (total+BLOCKSIZE-1)/BLOCKSIZE;
imageblocks.depth = depth;
imageblocks.bytelength = (long *) malloc(depth*sizeof(long *));
for (n=0; n < depth-1; n++)
{
imageblocks.bytelength[n] = BLOCKSIZE;
total -= BLOCKSIZE;
}
imageblocks.bytelength[depth-1] = total;
imageblocks.current = 0;
imageblocks.bytesused = 4;
}
}
RESfilesize()
{
int n, size;
size = 0;
/* RES header */ size += strlen(RES←header);
/* BEGIN */ size += len←longOP;
/* rational */ size += len←shortSEQ+2*bytes←in←int(resolution*10000);
/* DUP */ size += len←longOP;
/* 2 */ size += len←shortNUM;
/* MAKEVEC */ size += len←longOP;
/* xDimension */ size += len←shortNUM;
/* yDimension */ size += len←shortNUM;
/* maskImage */ if (input->maskExists == 0) size += 2;
else
{
/* xPixels */ size += len←shortNUM;
/* yPixels */ size += len←shortNUM;
/* samplesPerPixel */ size += len←shortNUM;
/* maxSampleValues */ size += len←shortNUM;
/* samplesInterleaved */ size += len←shortNUM;
/* -90 */ size += len←shortNUM;
/* ROTATE */ size += len←longOP;
/* 0 */ size += len←shortNUM;
/* xPixels */ size += len←shortNUM;
/* TRANSLATE */ size += len←longOP;
/* CONCAT */ size += len←longOP;
/* sequencePPV */ size += (maskblocks.bytelength[0] > 255) ? len←longSEQ : len←shortSEQ;
/* BitsPerSample */ size += 2;
/* ScanLength */ size += 2;
startmask = size;
/* compressed data */ size += input->scanlines*masklen;
/* sequenceContinued */ for (n=1; n < maskblocks.depth; n++)
{
size += (maskblocks.bytelength[n] > 255) ? len←longSEQ : len←shortSEQ;
}
/* MAKEPIXELARRAY */ size += len←longOP;
}
/* colorImage */ if (input->imageExists == 0) size += 2;
else
{
/* xPixels */ size += len←shortNUM;
/* yPixels */ size += len←shortNUM;
/* samplesPerPixel */ size += len←shortNUM;
/* maxSampleValues */ size += len←shortNUM;
/* samplesInterleaved */ size += len←shortNUM;
/* -90 */ size += len←shortNUM;
/* ROTATE */ size += len←longOP;
/* 0 */ size += len←shortNUM;
/* xPixels */ size += len←shortNUM;
/* TRANSLATE */ size += len←longOP;
/* CONCAT */ size += len←longOP;
/* sequencePPV */ size += (imageblocks.bytelength[0] > 255) ? len←longSEQ : len←shortSEQ;
/* BitsPerSample */ size += 2;
/* ScanLength */ size += 2;
startimage = size;
/* compressed data */ size += input->scanlines*imagelen;
/* sequenceContinued */ for (n=1; n < imageblocks.depth; n++)
{
size += (imageblocks.bytelength[n] > 255) ? len←longSEQ : len←shortSEQ;
}
/* MAKEPIXELARRAY */ size += len←longOP;
/* swhite */ size += len←shortNUM;
/* sblack */ size += len←shortNUM;
/* pixelMap */ size += len←shortNUM;
/* 3 */ size += len←shortNUM;
/* MAKEVEC */ size += len←longOP;
/* xerox */ size += len←shortSEQ+strlen("xerox");
/* GrayLinear */ size += len←shortSEQ+strlen("GrayLinear");
/* 2 */ size += len←shortNUM;
/* MAKEVEC */ size += len←longOP;
/* FINDCOLORMODELOP */ size += len←longOP;
/* DO */ size += len←longOP;
}
/* name */ size += len←shortSEQ+strlen("name");
/* filename */ size += len←shortSEQ+strlen(filename);
/* creationTime */ size += len←shortSEQ+strlen("creationTime");
/* date */ size += len←shortSEQ+strlen("1983 10 12 13:22:15-05:00");
/* 4 */ size += len←shortNUM;
/* MAKEVEC */ size += len←longOP;
/* 13086 */ size += len←shortNUM;
/* END */ size += len←longOP;
return(size);
}
extern struct tm *localtime();
char *RESdate()
{
int tz;
char *date, *op;
struct tm *ptm;
long tloc;
tz = (timezone < 0) ? (-timezone)/3600 : timezone/3600;
op = (timezone < 0) ? "+" : "-";
date = (char *) malloc(26);
tloc = time((long *) 0);
ptm = localtime(&tloc);
sprintf(date, "%4d %02d %02d %02d:%02d:%02d%s%02d:00",
ptm->tm←year+1900, ptm->tm←mon+1, ptm->tm←mday, ptm->tm←hour,
ptm->tm←min, ptm->tm←sec, op, tz);
return(date);
}
/* Change Log
*
* K. Knox, 1-Apr-85 14:25:59, Created first version.
* K. Knox, 10-May-85 18:03:10, Changed transformation from landscape to portrait.
* K. Knox, 20-May-85 10:17:48, Added "-i" flag for outputting internal image.
* K. Knox, 22-Aug-85 18:16:00, Changed buffer size to 64K bytes.
* K. Knox, 23-Sep-85 14:48:39, Put xDim and yDim in proper order (were reversed).
*
*
*/