home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / ddjmag / ddj8908.zip / QUIRK.LST < prev    next >
File List  |  1989-07-06  |  15KB  |  502 lines

  1. TRANSLATING PCX FILES
  2. by Kent Quirk
  3.  
  4.  
  5. [LISTING ONE]
  6.  
  7. /*+
  8.     Name:       pcx.c
  9.     Author:     Kent J. Quirk
  10.     Abstract:   This file contains subroutines to read PCX files.
  11. -*/
  12.  
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <malloc.h>
  16. #include <memory.h>
  17. #include "pcx.h"
  18.  
  19. /**** p c x _ r e a d _ h e a d e r ****
  20.     Abstract:   Reads the header of a PCX file.
  21.     Parameters: A data storage area for the header, an open file.
  22.     Returns:    The pointer to the data storage area passed, or NULL if error.
  23.     Comments:   The file should be opened in binary mode.
  24. ****************************/
  25. PCX_HDR *pcx_read_header(PCX_HDR *hdr, FILE *f)
  26. {
  27.     fseek(f, 0L, SEEK_SET);     /* header is at top of file */
  28.     if (fread(hdr, 1, sizeof(PCX_HDR), f) != sizeof(PCX_HDR))
  29.         return(NULL);
  30.     else
  31.         return(hdr);
  32. }
  33.  
  34. /**** p c x _ p r i n t _ h e a d e r ****
  35.     Abstract:   Printf's a PCX file header data to a given file.
  36.     Parameters: The PCX file header, the file to write the data to.
  37.     Returns:    Nothing
  38. ****************************/
  39. void pcx_print_header(PCX_HDR *hdr, FILE *f)
  40. {
  41.     char *t;
  42.     if (hdr->pcx_id != 0x0A)
  43.     {    
  44.         fprintf(f, "Not a PCX file.\n");
  45.         return;
  46.     }
  47.     switch (hdr->version) {
  48.     case 0: t="2.5"; break;
  49.     case 2: t="2.8 with palette info."; break;
  50.     case 3: t="2.8 without palette info."; break;
  51.     case 5: t="3.0"; break;
  52.     default: t="unknown."; break;
  53.     }
  54.     fprintf(f, "PCX Version %s\n", t);
  55.     fprintf(f, "Compression: %s\n", 
  56.                 hdr->encoding==1 ? "Run length" : "Unknown");
  57.     fprintf(f, "%d bits per pixel\n", hdr->bpp);
  58.     fprintf(f, "Image from (%d, %d) to (%d, %d) pixels.\n", 
  59.             hdr->upleftx, hdr->uplefty, hdr->lorightx, hdr->lorighty);
  60.     fprintf(f, "Created on a device with %d x %d dpi resolution.\n", 
  61.             hdr->display_xres, hdr->display_yres);
  62.     fprintf(f, "The image contains %d image planes.\n", hdr->nplanes);
  63.     fprintf(f, "There are %d bytes per line of data after decompression.\n",
  64.                 hdr->bytesperline);
  65.     fprintf(f, "There are %ld total bytes in the image.\n", 
  66.                 ((long)hdr->lorighty - (long)hdr->uplefty + 1) * 
  67.                  (long)hdr->bytesperline);
  68.     return;
  69. }
  70.  
  71. /**** p c x _ a l l o c _ l i n e ****
  72.     Abstract:   Allocates enough space to store a complete scan line from the
  73.                 current PCX file.
  74.     Parameters: The header pointer.
  75.     Returns:    A pointer to a "big enough" block of allocated space, or
  76.                 null if not enough space or an error occurred.
  77. ****************************/
  78. BYTE *pcx_alloc_line(PCX_HDR *hdr)
  79. {
  80.     return(calloc(hdr->nplanes, hdr->bytesperline));
  81. }
  82.  
  83. /**** p c x _ n e x t _ l i n e ****
  84.     Abstract:   Reads the next line from the PCX file.
  85.     Parameters: Pointer to the header, a pointer to the line area (or NULL
  86.                 for automatic allocation), and the open data file.
  87.     Returns:    A pointer to the line area, or NULL if there was a problem.
  88.     Comments:   To read the first line, call pcx_read_header() first.
  89.                 This sets the file position to the beginning of the data.
  90. ****************************/
  91. BYTE *pcx_next_line(PCX_HDR *hdr, BYTE *line, FILE *f)
  92. {
  93.     int c, len;
  94.     BYTE *dp;
  95.     WORD linesize = hdr->nplanes * hdr->bytesperline;
  96.     WORD i;
  97.     if (line == NULL)
  98.         if ((line = pcx_alloc_line(hdr)) == NULL)
  99.             return(line);
  100.     dp = line;                  /* point to data */
  101.     for (i=0; i<linesize; )
  102.     {    
  103.         if ((c = fgetc(f)) == EOF)
  104.             return(NULL);
  105.         if ((c & PCX_COMPRESSED) == PCX_COMPRESSED)
  106.         {
  107.             len = (c & PCX_MASK);
  108.             if ((c = fgetc(f)) == EOF)
  109.                 return(NULL);
  110.             memset(dp, (BYTE)c, len);
  111.             dp += len;
  112.             i += len;
  113.         }
  114.         else
  115.         {
  116.             *dp++ = (BYTE)c;
  117.             i++;
  118.         }
  119.     }
  120.     return(line);
  121. }
  122.  
  123.  
  124. [LISTING TWO]
  125.  
  126. /*+
  127.     Name:       pcx.h
  128.     Author:     Kent J. Quirk
  129.     Abstract:   This file contains information required when handling
  130.                 PCX files.
  131. -*/
  132.  
  133. /********************
  134.     Need these to handle the PCX data below.
  135. *********************/
  136. typedef unsigned char BYTE;
  137. typedef unsigned int  WORD;
  138.  
  139. /********************
  140.     This is the definition of the PCX header.
  141. *********************/
  142. typedef struct {
  143.     BYTE pcx_id;                        /* Always 0x0A for PCX files */
  144.     BYTE version;                       /* Version of the PCX format */
  145.     BYTE encoding;                      /* 1 = RLE (RLL) compression */
  146.     BYTE bpp;                           /* Number of bits per pixel */
  147.     WORD upleftx, uplefty;              /* position of upper left corner */
  148.     WORD lorightx, lorighty;            /* lower right corner (inclusive) */
  149.     WORD display_xres, display_yres;    /* resolution in dpi of display */
  150.     BYTE palette[48];                   /* palette data if it fits */
  151.     BYTE reserved;
  152.     BYTE nplanes;                       /* number of bit planes of data */
  153.     WORD bytesperline;                  /* # bytes in an uncompressed line */
  154.     WORD palletteinfo;
  155.     BYTE reserved2[58];
  156. } PCX_HDR;
  157.  
  158. /********************
  159.    These two definitions are used to decompress data in the PCX file.
  160.    (The compressed count byte has the top two bits set).
  161. *********************/
  162. #define PCX_COMPRESSED 0xC0
  163. #define PCX_MASK 0x3F
  164.  
  165. /********************
  166.     These prototypes declare the PCX read subroutines.
  167. *********************/
  168. PCX_HDR *pcx_read_header(PCX_HDR *hdr, FILE *f);
  169. BYTE *pcx_alloc_line(PCX_HDR *hdr);
  170. BYTE *pcx_next_line(PCX_HDR *hdr, BYTE *line, FILE *f);
  171. void pcx_print_header(PCX_HDR *hdr, FILE *f);
  172.  
  173.  
  174. [LISTING THREE]
  175.  
  176. /*+
  177.     Name:       prpcx.c
  178.     Author:     Kent J. Quirk
  179.     Abstract:   This program prints .PCX files (as created by PC Paintbrush
  180.                 and other software) on a PostScript printer by converting
  181.                 them to a PS-compatible image.  The user can scale and
  182.                 position the image.
  183. -*/
  184.  
  185. #include <stdio.h>
  186. #include <stdlib.h>
  187. #include <memory.h>
  188. #include <string.h>
  189.  
  190. #define BUFSIZE 100
  191.  
  192. #include "pcx.h"
  193.  
  194. typedef struct {
  195.     int xpos;
  196.     int ypos;
  197.     int width;
  198.     int height;
  199.     int scale;
  200.     int invert;
  201.     int prt_res;
  202.     int dumphdr;
  203. } MAPPING;
  204.  
  205. /**** c o p y _ p s _ h e a d e r ****
  206.     Abstract:   Opens the PS header file and copies it to the output.
  207.     Parameters: Filename of the current file (the .PS extension is added
  208.                 here) and the output file pointer.
  209.     Returns:    0 if successful, 1 if failure.
  210. ****************************/
  211. char *copy_ps_header(char *name, FILE *outfile, char *stop)
  212. {
  213.     static char buf[BUFSIZE];
  214.     char *bp;
  215.     static FILE *f = NULL;
  216.     if (f == NULL)
  217.     {    
  218.         strcpy(buf, name);
  219.         if ((bp = strchr(buf, '.')) != NULL)
  220.             *bp = 0;
  221.         strcat(buf, ".ps");             /* open file with this name but .ps ext */
  222.         if ((f = fopen(buf, "r")) == NULL)
  223.         {
  224.             fprintf(stderr, "Unable to open PostScript header file '%s'\n",
  225.                 buf);
  226.             return(NULL);
  227.         }
  228.     }
  229.     else
  230.     {
  231.         fputs(buf, outfile);
  232.     }
  233.     while (fgets(buf, BUFSIZE, f) != NULL)
  234.     {
  235.         if ((stop != NULL) && (strncmp(buf, stop, strlen(stop)) == 0))
  236.             return(buf);                /* bail out right now */
  237.         fputs(buf, outfile);
  238.     }
  239.     fclose(f);
  240.     f = NULL;
  241.     return(NULL);
  242. }
  243.  
  244. /**** d o f i l e ****
  245.     Abstract:   Processes a single PCX file.
  246.     Parameters: char *filename - the input PCX filename (.PCX optional)
  247.                 MAPPING *map - the structure containing page position info
  248.                 char *psname - the PostScript prologue (.PS will be forced)
  249.                 FILE *outfile - the open output file
  250.     Returns:    0 if successful, 1 if no file generated
  251. ****************************/
  252. int dofile(char *filename, MAPPING *map, char *psname, FILE *outfile)
  253. {
  254.     FILE *f;
  255.     PCX_HDR hdr;
  256.     WORD i, j, xsize, ysize;
  257.     BYTE *lineptr = NULL;
  258.     char *t;
  259.     char buf[BUFSIZE];
  260.     long bbox_x, bbox_y;
  261.     strcpy(buf, filename);
  262.     if (strchr(buf, '.') == NULL)
  263.         strcat(buf, ".pcx");     /* add .PCX if needed */
  264.     if ((f = fopen(buf, "rb")) == NULL)
  265.     {
  266.         fprintf(stderr, "Unable to open '%s'\n", buf);
  267.         return(1);
  268.     }
  269.     if (pcx_read_header(&hdr, f) == NULL)
  270.     {
  271.         fprintf(stderr, "Unable to read header for file '%s'.\n", buf);
  272.         fclose(f);
  273.         return(1);
  274.     }
  275.     if (map->dumphdr)
  276.     {
  277.         pcx_print_header(&hdr, stdout);
  278.         return(1);
  279.     }
  280.     if (hdr.nplanes != 1)
  281.     {
  282.         fprintf(stderr, "Only able to read monochrome .PCX files.\n");
  283.         fclose(f);
  284.         return(1);
  285.     }
  286.     xsize = hdr.lorightx - hdr.upleftx + 1;
  287.     ysize = hdr.lorighty - hdr.uplefty + 1;
  288.     
  289.     t = copy_ps_header(psname, outfile, "%%BoundingBox");
  290.     bbox_x = (long)xsize * (long)map->width  * (long)map->scale / 10000L;
  291.     bbox_y = (long)ysize * (long)map->height * (long)map->scale / 10000L;
  292.     bbox_x += map->xpos;
  293.     bbox_y += map->ypos;
  294.     sprintf(t, "%%%%BoundingBox: %d %d %ld %ld\n", map->xpos, map->ypos,
  295.             bbox_x, bbox_y);
  296.     t = copy_ps_header(psname, outfile, NULL);
  297.         
  298.     fprintf(outfile, "/bmap_wid %d def\n", xsize);
  299.     fprintf(outfile, "/bmap_hgt %d def\n", ysize);
  300.     fprintf(outfile, "/bpp %d def\n", hdr.bpp);
  301.     fprintf(outfile, "/res %d def\n\n", map->prt_res);
  302.     fprintf(outfile, "/x %d def\n", map->xpos);
  303.     fprintf(outfile, "/y %d def\n\n", map->ypos);
  304.     fprintf(outfile, "/scy %d 100 div def\n", map->height);
  305.     fprintf(outfile, "/scx %d 100 div def\n", map->width);
  306.     fprintf(outfile, "/scg %d 100 div def\n\n", map->scale);
  307.     fprintf(outfile, "scaleit\n");
  308.     fprintf(outfile, "imagedata\n\n");
  309.  
  310.     for (i=0; i<ysize; i++)
  311.     {
  312.         lineptr = pcx_next_line(&hdr, lineptr, f);
  313.         if (map->invert)                 /* invert if necessary */
  314.             for (j=0; j < xsize/8; j++)
  315.                 lineptr[j] = ~lineptr[j];
  316.         for (j=0; j < xsize/8; j++)
  317.             fprintf(outfile, "%02X", lineptr[j]);
  318.         fprintf(outfile, "\n");
  319.     }
  320.     fprintf(outfile, "\nshowit\n");
  321.     free(lineptr);
  322.     fclose(f);
  323.     return(0);
  324. }
  325.  
  326. /**** u s a g e ****
  327.     Abstract:   Prints a usage message and dies.
  328.     Parameters: None
  329.     Returns:    Never returns.
  330. ****************************/
  331. void usage()
  332. {
  333.     printf("PRPCX:  by Kent Quirk\n");
  334.     printf("   Given a .PCX file, this program creates a PostScript file \n");
  335.     printf("    which will print the image.\n");
  336.     printf(" PRPCX [-wW] [-hH] [-xX] [-yY] [-sS] [-rR] [-d] [-i] filename\n");
  337.     printf("   Options include:         (units) [default]\n");
  338.     printf("   -sSCA  set overall scale factor (percent) [100]\n");
  339.     printf("   -wWID  set horizontal scale factor (percent) [100]\n");
  340.     printf("   -hHGT  set vertical scale factor (percent) [100]\n");
  341.     printf("   -xPOS  set horizontal position (points from left) [0]\n");
  342.     printf("   -yPOS  set vertical position (points from bottom) [0]\n");
  343.     printf("   -rRES  set printer resolution (dpi) [300]\n");
  344.     printf("   -d     dump PCX file info to stdout [off]\n");
  345.     printf("   -i     invert image [off]\n");
  346.     printf("   -oFIL  set output filename, or use SET PRPCX=filename\n");
  347.     printf("   The defaults print the image at one pixel per device pixel\n");
  348.     printf("   at the lower left corner of the page.\n");
  349.     printf("   PRPCX.PS must be in the same directory as PRPCX.EXE.\n");
  350.     exit(1);
  351. }
  352.  
  353. /**** m a i n ****
  354.     The main routine for PRPCX.  Sets defaults, parses command line,
  355.     and calls dofile().
  356. ****************************/
  357. int main(int argc, char *argv[])
  358. {
  359.     int i;
  360.     MAPPING map;
  361.     FILE *outfile = stdout;
  362.     char *outfname = NULL;
  363.     char *filename = NULL;
  364.     map.xpos = map.ypos = 0;
  365.     map.width = map.height = map.scale = 100;
  366.     map.invert = 0;
  367.     map.prt_res = 300;
  368.     map.dumphdr = 0;
  369.     if (argc < 2)
  370.         usage();
  371.     for (i=1; i<argc; i++)
  372.     {
  373.         if (argv[i][0] == '-' || argv[i][0] == '/')
  374.         {
  375.             switch (argv[i][1]) 
  376.             {
  377.             case 'x':  case 'X':
  378.                 map.xpos = atoi(argv[i]+2);
  379.                 break;
  380.             case 'y':  case 'Y':
  381.                 map.ypos = atoi(argv[i]+2);
  382.                 break;
  383.             case 'h':  case 'H':
  384.                 map.height = atoi(argv[i]+2);
  385.                 break;
  386.             case 'w':  case 'W':
  387.                 map.width = atoi(argv[i]+2);
  388.                 break;
  389.             case 's':  case 'S':
  390.                 map.scale = atoi(argv[i]+2);
  391.                 break;
  392.             case 'r': case 'R':
  393.                 map.prt_res = atoi(argv[i]+2);
  394.                 break;
  395.             case 'i': case 'I':
  396.                 map.invert = !map.invert;
  397.                 break;
  398.             case 'd': case 'D':
  399.                 map.dumphdr = 1;
  400.                 break;
  401.             case 'o': case 'O':
  402.                 outfname = argv[i]+2;
  403.                 break;
  404.             case '?':
  405.                 usage();
  406.                 break;
  407.             default:
  408.                 fprintf(stderr, "Unknown option %s\n", argv[i]);
  409.                 usage();
  410.                 break;
  411.             }
  412.         }
  413.         else                    /* process a file */
  414.         {
  415.             filename = argv[i];
  416.         }
  417.     }
  418.     if ((outfname != NULL) || ((outfname = getenv("PRPCX")) != NULL))
  419.     {
  420.         if ((outfile = fopen(outfname, "w")) == NULL)
  421.         {
  422.             fprintf(stderr,"Unable to open output file %s", outfname);
  423.             exit(1);
  424.         }
  425.     }
  426.     i = dofile(filename, &map, argv[0], outfile);
  427.     fclose(outfile);
  428.     return(i);
  429. }
  430.  
  431.  
  432. [LISTING FOUR]
  433.  
  434. #
  435. # Program: PRPCX
  436. #
  437.  
  438. .c.obj:
  439.         cl -c  -W2 -Zid -Od -AS $*.c
  440.  
  441. pcx.obj : pcx.c pcx.h
  442.  
  443. prpcx.obj : prpcx.c pcx.h
  444.  
  445. prpcx.exe : prpcx.obj pcx.obj
  446.         echo prpcx.obj+ >prpcx.lnk
  447.         echo pcx.obj >>prpcx.lnk
  448.         echo prpcx.exe >>prpcx.lnk
  449.         echo nul >>prpcx.lnk
  450.         link /NOI $(LDFLAGS) @prpcx.lnk;
  451.  
  452.  
  453. [LISTING FIVE]
  454.  
  455. %!PS-Adobe 1.0
  456. %%Title:
  457. %%Creator:
  458. %%Pages: 1
  459. %%BoundingBox:
  460. %%EndComments
  461.  
  462. gsave
  463.             
  464.         % the next item translates the image from
  465.         % top-to-bottom .PCX format to PS bottom-to-top
  466. /xform 
  467. {
  468.     [ bmap_wid 0 0 bmap_hgt neg 0 bmap_hgt ]
  469. } def
  470.  
  471. /readproc
  472. {
  473.     { currentfile picstr readhexstring pop }
  474. } def
  475.  
  476. /scaleit
  477. {
  478.     x y translate
  479.     bmap_wid bmap_hgt scale
  480.     72 res div 72 res div scale
  481.     scx scg mul scy scg mul scale
  482.  
  483.     /picstr bmap_wid 8 idiv string def
  484.  
  485. } def
  486.  
  487. /imagedata
  488. {
  489.     bmap_wid bmap_hgt bpp xform readproc image
  490. } def
  491.  
  492. /showit
  493. {
  494.     grestore
  495.     showpage
  496. } def
  497.  
  498. % Will generate <bmap_hgt> lines of image data, 
  499. % each with <bmap_wid>/8 bytes of data (in hex).
  500. %%EndProlog
  501.  
  502.