/* * 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. */ /* * Runput.c - General purpose Run Length Encoding. * * Author: Spencer W. Thomas * Computer Science Dept. * University of Utah * Date: Mon Aug 9 1982 * Copyright (c) 1982,1986 Spencer W. Thomas * * $Id: Runput.c,v 3.0.1.1 1992/01/28 18:17:40 spencer Exp $ * * Modified by: Todd W. Fuqua * Date: Jul 22 1984 * convert to new RLE format to make room for larger frame buffers */ /* THIS IS WAY OUT OF DATE. See rle.5. * The output file format is: * * Word 0: A "magic" number. The top byte of the word contains * the letter 'R' or the letter 'W'. 'W' indicates that * only black and white information was saved. The bottom * byte is one of the following: * ' ': Means a straight "box" save, -S flag was given. * 'B': Image saved with background color, clear screen to * background before restoring image. * 'O': Image saved in overlay mode. * * Words 1-6: The structure * { short xpos, Lower left corner * ypos, * xsize, Size of saved box * ysize; * char rgb[3]; Background color * char map; flag for map presence * } * * If the map flag is non-zero, then the color map will follow as * 3*256 16 bit words, first the red map, then the green map, and * finally the blue map. * * Following the setup information is the Run Length Encoded image. * Each instruction consists of a 4-bit opcode, a 12-bit datum and * possibly one or more following words (all words are 16 bits). The * instruction opcodes are: * * SkipLines (1): The bottom 10 bits are an unsigned number to be added to * current Y position. * * SetColor (2): The datum indicates which color is to be loaded with * the data described by the following ByteData and * RunData instructions. 0->red, 1->green, 2->blue. The * operation also resets the X position to the initial * X (i.e. a carriage return operation is performed). * * SkipPixels (3): The bottom 10 bits are an unsigned number to be * added to the current X position. * * ByteData (5): The datum is one less than the number of bytes of * color data following. If the number of bytes is * odd, a filler byte will be appended to the end of * the byte string to make an integral number of 16-bit * words. The bytes are in PDP-11 order. The X * position is incremented to follow the last byte of * data. * * RunData (6): The datum is one less than the run length. The * following word contains (in its lower 8 bits) the * color of the run. The X position is incremented to * follow the last byte in the run. */ #include #include #include #include "mallocvar.h" #include "pm.h" #include "rle_put.h" #include "rle.h" #include "rle_code.h" #include "vaxshort.h" #include "Runput.h" #define UPPER 255 /* anything bigger ain't a byte */ /* * Macros to make writing instructions with correct byte order easier. */ /* Write a two-byte value in little_endian order. */ #define put16(a) (putc((a)&0xff,rle_fd),putc((char)(((a)>>8)&0xff),rle_fd)) /* short instructions */ #define mk_short_1(oper,a1) /* one argument short */ \ putc(oper,rle_fd), putc((char)a1,rle_fd) #define mk_short_2(oper,a1,a2) /* two argument short */ \ putc(oper,rle_fd), putc((char)a1,rle_fd), put16(a2) /* long instructions */ #define mk_long_1(oper,a1) /* one argument long */ \ putc((char)(LONG|oper),rle_fd), putc('\0', rle_fd), put16(a1) #define mk_long_2(oper,a1,a2) /* two argument long */ \ putc((char)(LONG|oper),rle_fd), putc('\0', rle_fd), \ put16(a1), put16(a2) /* choose between long and short format instructions */ /* NOTE: these macros can only be used where a STATEMENT is legal */ #define mk_inst_1(oper,a1) /* one argument inst */ \ if (a1>UPPER) (mk_long_1(oper,a1)); else (mk_short_1(oper,a1)) #define mk_inst_2(oper,a1,a2) /* two argument inst */ \ if (a1>UPPER) (mk_long_2(oper,a1,a2)); else (mk_short_2(oper,a1,a2)) /* * Opcode definitions */ #define RSkipLines(n) mk_inst_1(RSkipLinesOp,(n)) #define RSetColor(c) mk_short_1(RSetColorOp,(c)) /* has side effect of performing */ /* "carriage return" action */ #define RSkipPixels(n) mk_inst_1(RSkipPixelsOp,(n)) #define RNewLine RSkipLines(1) #define RByteData(n) mk_inst_1(RByteDataOp,n) /* followed by ((n+1)/2)*2 bytes */ /* of data. If n is odd, last */ /* byte will be ignored */ /* "cursor" is left at pixel */ /* following last pixel written */ #define RRunData(n,c) mk_inst_2(RRunDataOp,(n),(c)) /* next word contains color data */ /* "cursor" is left at pixel after */ /* end of run */ #define REOF mk_inst_1(REOFOp,0) /* Really opcode only */ void RunSetup(rle_hdr * const hdrP) { /*---------------------------------------------------------------------------- Put out initial setup data for RLE files. -----------------------------------------------------------------------------*/ FILE * const rle_fd = hdrP->rle_file; struct XtndRsetup setup; put16(RLE_MAGIC); if (hdrP->background == 2) setup.h_flags = H_CLEARFIRST; else if (hdrP->background == 0) setup.h_flags = H_NO_BACKGROUND; else setup.h_flags = 0; if (hdrP->alpha) setup.h_flags |= H_ALPHA; if (hdrP->comments != NULL && *hdrP->comments != NULL) setup.h_flags |= H_COMMENT; if (hdrP->ncolors > 255) pm_error("Too many colors (%u) for RLE format. Maximum is 255", hdrP->ncolors); setup.h_ncolors = (unsigned char)hdrP->ncolors; setup.h_pixelbits = 8; /* Grinnell dependent */ if ((hdrP->cmaplen) > sizeof(UINT_MAX) * 8 - 1) { pm_error("Color map size logarithm (%u) " "is too large for computation. Maximum is %lu", hdrP->cmaplen, sizeof(UINT_MAX) * 8 - 2); } /* We need to be able to count 2 bytes for each channel of each entry in the color map: */ if (hdrP->ncmap > 0 && 1 << hdrP->cmaplen > UINT_MAX/2/hdrP->ncmap) { pm_error("Color map length %u and number of color channels in the " "color map %u are too large for computation", 1 << hdrP->cmaplen, hdrP->ncmap); } if (hdrP->ncmap > 255) pm_error("Too many color channels in the color map (%u) " "for the RLE format. Maximum is 255", hdrP->ncmap); setup.h_ncmap = hdrP->ncmap; /* no of color channels */ if (hdrP->ncmap > 0 && hdrP->cmap == NULL) { pm_message("Warning: " "Color map of size %d*%d specified, but not supplied, " "writing '%s'", hdrP->ncmap, (1 << hdrP->cmaplen), hdrP->file_name); hdrP->ncmap = 0; } setup.h_cmaplen = (unsigned char)hdrP->cmaplen; vax_pshort(setup.hc_xpos,hdrP->xmin); vax_pshort(setup.hc_ypos,hdrP->ymin); vax_pshort(setup.hc_xlen,hdrP->xmax - hdrP->xmin + 1); vax_pshort(setup.hc_ylen,hdrP->ymax - hdrP->ymin + 1); fwrite((char *)&setup, SETUPSIZE, 1, rle_fd); if (hdrP->background != 0) { unsigned int i; rle_pixel * background; int * bg_color; assert(hdrP->ncolors < UINT_MAX); MALLOCARRAY_NOFAIL(background, hdrP->ncolors + 1); /* If even number of bg color bytes, put out one more to get to 16 bit boundary. */ for (i = 0, bg_color = hdrP->bg_color; i < hdrP->ncolors; ++i) background[i] = *bg_color++; /* Extra byte; if written, should be 0. */ background[i] = 0; fwrite(background, (hdrP->ncolors / 2) * 2 + 1, 1, rle_fd); free(background); } else putc('\0', rle_fd); if (hdrP->ncmap > 0) { /* Big-endian machines are harder */ unsigned int const nmap = (1 << hdrP->cmaplen) * hdrP->ncmap; unsigned char * h_cmap; unsigned int i; MALLOCARRAY(h_cmap, nmap * 2); if (!h_cmap) { pm_error("Failed to allocate memory for color map of size %u, " "writing '%s'", nmap, hdrP->file_name); } for (i = 0; i < nmap; ++i) vax_pshort(&h_cmap[i*2], hdrP->cmap[i]); fwrite(h_cmap, nmap, 2, rle_fd); free(h_cmap); } /* Now write out comments if given */ if (setup.h_flags & H_COMMENT) { unsigned int comlen; const char ** comP; /* Get the total length of comments */ for (comP = hdrP->comments, comlen = 0; *comP != NULL; ++comP) comlen += 1 + strlen(*comP); put16(comlen); for (comP = hdrP->comments; *comP != NULL; ++comP) fwrite(*comP, 1, strlen(*comP) + 1, rle_fd); if (comlen & 0x1) /* if odd length, round up */ putc('\0', rle_fd); } } void RunSkipBlankLines(unsigned int const nblank, rle_hdr * const hdrP) { /*---------------------------------------------------------------------------- Skip one or more blank lines in the RLE file. -----------------------------------------------------------------------------*/ FILE * const rle_fd = hdrP->rle_file; RSkipLines(nblank); } void RunSetColor(int const c, rle_hdr * const hdrP) { /*---------------------------------------------------------------------------- Select a color and do carriage return. color: 0 = Red, 1 = Green, 2 = Blue. -----------------------------------------------------------------------------*/ FILE * const rle_fd = hdrP->rle_file; RSetColor(c); } void RunSkipPixels(unsigned int const nskip, int const last, int const wasrun, rle_hdr * const hdrP) { /*---------------------------------------------------------------------------- Skip a run of background. -----------------------------------------------------------------------------*/ FILE * const rle_fd = hdrP->rle_file; if (!last && nskip > 0) { RSkipPixels(nskip); } } void RunNewScanLine(int const flag, rle_hdr * const hdrP) { /*---------------------------------------------------------------------------- Perform a newline action. Since CR is implied by the Set Color operation, only generate code if the newline flag is true. -----------------------------------------------------------------------------*/ FILE * const rle_fd = hdrP->rle_file; if (flag) { RNewLine; } } void Runputdata(rle_pixel * const buf, unsigned int const n, rle_hdr * const hdrP) { /*---------------------------------------------------------------------------- Put one or more pixels of byte data into the output file. -----------------------------------------------------------------------------*/ FILE * const rle_fd = hdrP->rle_file; if (n != 0) { RByteData(n - 1); fwrite(buf, n, 1, rle_fd); if (n & 0x1) putc(0, rle_fd); } } void Runputrun(int const color, unsigned int const n, int const last, rle_hdr * const hdrP) { /*---------------------------------------------------------------------------- Output a single color run. -----------------------------------------------------------------------------*/ FILE * const rle_fd = hdrP->rle_file; RRunData(n - 1, color); } void RunputEof(rle_hdr * const hdrP) { /*---------------------------------------------------------------------------- Output an EOF opcode -----------------------------------------------------------------------------*/ FILE * const rle_fd = hdrP->rle_file; REOF; }