/* 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). * * */