home *** CD-ROM | disk | FTP | other *** search
/ Encyclopedia of Graphics File Formats Companion / GFF_CD.ISO / formats / pcx / code / pcx_code.txt
Text File  |  1994-06-01  |  59KB  |  1,462 lines

  1. This file contains examples of PCX header structures and how to
  2. read, write, display, decode, and encode a PCX file and to
  3. manipulate DCX files.
  4.  
  5.  
  6. PCX Header File
  7.  
  8. PCX.H
  9.  
  10.  
  11. /****************************************************************************\
  12. **  Title:       PCX.H                                                      **
  13. **  Purpose:     PCX/DCX Header file                                        **
  14. **  Version:     1.0                                                        **
  15. **  Date:        April 1991                                                 **
  16. **  Author:      James D. Murray, Anaheim, CA, USA                          **
  17. **  C Compilers: Borland C++ v2.0, Microsoft C v6.00a                       **
  18. **                                                                          **
  19. **  This file contains the header structures for the PCX and DCX image file **
  20. **  formats.  Also included are the prototypes for the functions in the     **
  21. **  source files PCXHEAD.C, DCXHEAD.C, PCXCODE.C, PCX2DCX.C, and DCX2PCX.C. **
  22. **                                                                          **
  23. **  Copyright (C) 1991 by Graphics Software Labs.  All rights reserved.     **
  24. \****************************************************************************/
  25. #ifndef _PCX_H
  26. #define _PCX_H   1
  27.  
  28. #include "datatype.h"         /* Include data type definitions */
  29.                                                                
  30. /*
  31. **  The PCX header format.
  32. */
  33. typedef struct _PcxHeader       /* Offset   Description            */
  34. {
  35.     BYTE   Id;                  /*  00h     Manufacturer ID        */
  36.     BYTE   Version;             /*  01h     Version                */
  37.     BYTE   Format;              /*  02h     Encoding Scheme        */
  38.     BYTE   BitsPixelPlane;      /*  03h     Bits/Pixel/Plane       */
  39.     WORD   Xmin;                /*  04h     X Start (upper left)   */
  40.     WORD   Ymin;                /*  06h     Y Start (top)          */
  41.     WORD   Xmax;                /*  08h     X End (lower right)    */
  42.     WORD   Ymax;                /*  0Ah     Y End (bottom)         */
  43.     WORD   Hdpi;                /*  0Ch     Horizontal Resolution  */
  44.     WORD   Vdpi;                /*  0Eh     Vertical Resolution    */
  45.     BYTE   EgaPalette[48];      /*  10h     16-Color EGA Palette   */
  46.     BYTE   Reserved;            /*  40h     Reserved               */
  47.     BYTE   NumberOfPlanes;      /*  41h     Number of Color Planes */
  48.     WORD   BytesLinePlane;      /*  42h     Bytes/Line/Plane       */
  49.     WORD   PaletteInfo;         /*  44h     Palette Interpretation */
  50.     WORD   HScreenSize;         /*  46h     Horizontal Screen Size */
  51.     WORD   VScreenSize;         /*  48h     Vertical Screen Size   */
  52.     BYTE   Filler[54];          /*  4Ah     Reserved               */
  53. } PCXHEADER;
  54.  
  55. /*
  56. **  PCX VGA palette.
  57. */
  58. typedef struct _PcxVgaPalette
  59. {
  60.     BYTE   VgaPalette[768];     /*          256 VGA Color Palette  */
  61. } PCXVGAPALETTE;
  62.  
  63. /*
  64. **  The DCX header format.
  65. */
  66. typedef struct _DcxHeader       /* Offset   Description            */
  67. {
  68.     DWORD   Id;                 /*   0h     File ID                */
  69.     DWORD   PageList[1024];     /*   4h     Page List Array        */
  70. } DCXHEADER;
  71.  
  72.  
  73. /*
  74. **  Function prototypes 
  75. */
  76. SHORT PcxDecodeScanLine(BYTE *, WORD, FILE *);
  77. WORD  PcxEncodeScanLine(BYTE *, BYTE *, WORD);
  78. VOID  ReadPcxHeader(PCXHEADER *, FILE *);
  79. VOID  WritePcxHeader(PCXHEADER *, FILE *);
  80.  
  81. #endif  /* _PCX_H */
  82.  
  83. }
  84.  
  85.  
  86.  
  87.  
  88. PCX File Header Reader
  89.  
  90. PCXREAD.C
  91.  
  92.  
  93. This file header reader uses the ENDIANIO functions to insure that the
  94. PCX header information is always read using the Intel byte format
  95. regardless of the machine the code is running on.  It also insures
  96. that the data read will be stored in the header structure properly
  97. despite any byte-alignment restrictions on the computer hardware.
  98.  
  99.  
  100. /****************************************************************************\
  101. **  Title:        PCXREAD                                                   **
  102. **  Purpose:      Read PCX header information from a file.                  **
  103. **  Version:      1.0                                                       **
  104. **  Date:         May 1991                                                  **
  105. **  Author:       James D. Murray, Anaheim, CA  USA                         **
  106. **  C Compilers:  Borland C++ v2.0, Microsoft C v6.00a                      **
  107. **                                                                          **
  108. **  Read the header information contained within a PCX-format file and      **
  109. **  store it in a PCXHEADER structure.                                      **
  110. **                                                                          **
  111. **  This module contains the following functions:                           **
  112. **                                                                          **
  113. **      ReadPcxHeader - Read a PCX header to a structure                    **
  114. **                                                                          **
  115. **  Copyright (C) 1991 Graphics Software Labs.  All rights reserved.        **
  116. \****************************************************************************/
  117. #include <stdio.h>
  118. #include "endianio.h"
  119. #include "pcx.h"
  120.  
  121. WORD (*GetWord)(FILE *);        /* Pointer to ENDIANIO function */
  122.  
  123. /*
  124. **  Read the information from a PCX image file header.
  125. **
  126. **  PCX header file information is read fromn the supplied FILE
  127. **  stream and written to the supplied PCX header structure.
  128. **  The ENDIANIO I/O finctions are used to insure that the header
  129. **  information is written in little-endian order.
  130. **
  131. **  Returns: Nothing.
  132. */
  133. VOID
  134. ReadPcxHeader(PcxHead, FpPcx)
  135. PCXHEADER *PcxHead;     /* Pointer to PCX header structure  */
  136. FILE      *FpPcx;       /* PCX image file input FILE stream */
  137. {
  138.     register SHORT i;
  139.  
  140.     GetWord = GetLittleWord;    /* Initialize ENDIANIO read function */
  141.  
  142.     PcxHead->Id             = GetByte(FpPcx);
  143.     PcxHead->Version        = GetByte(FpPcx);
  144.     PcxHead->Format         = GetByte(FpPcx);
  145.     PcxHead->BitsPixelPlane = GetByte(FpPcx);
  146.     PcxHead->Xmin           = GetWord(FpPcx);
  147.     PcxHead->Ymin           = GetWord(FpPcx);
  148.     PcxHead->Xmax           = GetWord(FpPcx);
  149.     PcxHead->Ymax           = GetWord(FpPcx);
  150.     PcxHead->Hdpi           = GetWord(FpPcx);
  151.     PcxHead->Vdpi           = GetWord(FpPcx);
  152.  
  153.     /* Read the EGA Palette */
  154.     for (i = 0; i < sizeof(PcxHead->EgaPalette); i++)
  155.         PcxHead->EgaPalette[i] = GetByte(FpPcx);
  156.  
  157.     PcxHead->Reserved       = GetByte(FpPcx);       
  158.     PcxHead->NumberOfPlanes = GetByte(FpPcx);
  159.     PcxHead->BytesLinePlane = GetWord(FpPcx); 
  160.     PcxHead->PaletteInfo    = GetWord(FpPcx);  
  161.     PcxHead->HScreenSize    = GetWord(FpPcx);  
  162.     PcxHead->VScreenSize    = GetWord(FpPcx);
  163.  
  164.     /* Read the reserved area at the end of the header */
  165.     for (i = 0; i < sizeof(PcxHead->Filler); i++)
  166.         PcxHead->Filler[i] = GetByte(FpPcx);
  167. }
  168. }
  169.  
  170.  
  171. PCX File Header Writer
  172.  
  173. PCXWRITE.C
  174.  
  175.  
  176. The header writer is identical to the PCX file header, except that
  177. the corresponding ENDIANIO output functions are used instead.  This
  178. code is necessary for safely writing PCX file header information on
  179. almost any machine.
  180.  
  181.  
  182. /****************************************************************************\
  183. **  Title:       PCXWRITE.C                                                 **
  184. **  Purpose:     Write PCX header information to a file.                    **
  185. **  Version:     1.0                                                        **
  186. **  Date:        May 1991                                                   **
  187. **  Author:      James D. Murray, Anaheim, CA  USA                          **
  188. **  C Compilers: Borland C++ v2.0, Microsoft C v6.00a                       **
  189. **                                                                          **
  190. **  Write the information contained within a PCXHEADER structure to a file. **
  191. **                                                                          **
  192. **  This module contains the following functions:                           **
  193. **                                                                          **
  194. **      WritePcxHeader - Write a PCX header to a file stream                **
  195. **                                                                          **
  196. **  Copyright (C) 1991 by Graphics Software Labs.  All rights reserved.     **
  197. \****************************************************************************/
  198. #include <stdio.h>
  199. #include "endianio.h"
  200. #include "pcx.h"
  201.  
  202. VOID (*PutWord)(WORD, FILE *);      /* Pointer to ENDIANIO function */
  203.  
  204. /*
  205. **  Write the information from a PCX image file structure.
  206. **
  207. **  PCX header file information is read from the supplied PCX
  208. **  header structure and written to the supplied FILE stream.
  209. **  The ENDIANIO I/O finctions are used to insure that the header
  210. **  information is written in little-endian order.
  211. **
  212. **  Returns: Nothing.
  213. */
  214. VOID
  215. WritePcxHeader(PcxHead, FpPcx)
  216. PCXHEADER *PcxHead;     /* Pointer to PCX header structure  */
  217. FILE      *FpPcx;       /* PCX image file output FILE stream */
  218. {
  219.     register SHORT i;
  220.  
  221.     PutWord = PutLittleWord;    /* Initialize ENDIANIO write function */
  222.  
  223.     PutByte(PcxHead->Id,             FpPcx);
  224.     PutByte(PcxHead->Version,        FpPcx);
  225.     PutByte(PcxHead->Format,         FpPcx);
  226.     PutByte(PcxHead->BitsPixelPlane, FpPcx);
  227.     PutWord(PcxHead->Xmin,           FpPcx);
  228.     PutWord(PcxHead->Ymin,           FpPcx);
  229.     PutWord(PcxHead->Xmax,           FpPcx);
  230.     PutWord(PcxHead->Ymax,           FpPcx);
  231.     PutWord(PcxHead->Hdpi,           FpPcx);
  232.     PutWord(PcxHead->Vdpi,           FpPcx);
  233.  
  234.     /* Write the EGA Palette */
  235.     for (i = 0; i < sizeof(PcxHead->EgaPalette); i++)
  236.         PutByte(PcxHead->EgaPalette[i], FpPcx);
  237.  
  238.     PutByte(PcxHead->Reserved,       FpPcx);       
  239.     PutByte(PcxHead->NumberOfPlanes, FpPcx);
  240.     PutWord(PcxHead->BytesLinePlane, FpPcx); 
  241.     PutWord(PcxHead->PaletteInfo,    FpPcx);  
  242.     PutWord(PcxHead->HScreenSize,    FpPcx);  
  243.     PutWord(PcxHead->VScreenSize,    FpPcx);
  244.  
  245.     /* Write the reserved area at the end of the header */
  246.     for (i = 0; i < sizeof(PcxHead->Filler); i++)
  247.         PutByte(PcxHead->Filler[i], FpPcx);
  248. }
  249.  
  250. }
  251.  
  252.  
  253. PCX File Information Lister
  254.  
  255. PCXHEAD.C
  256.  
  257.  
  258. This listing program shows the information contained within a PCX file
  259. header and VGA color palette, if one is present in the image. It
  260. is a useful way of learning how to extract such information from a
  261. PCX file and a darn handy tool is you do a lot of work with PCX
  262. files in general.
  263.  
  264.  
  265. /****************************************************************************\
  266. **  Title:       PCXHEAD.C                                                  **
  267. **  Purpose:     Display the data in a PCX image file header.               **
  268. **  Version:     1.0                                                        **
  269. **  Date:        April 1991                                                 **
  270. **  Author:      James D. Murray, Anaheim, CA, USA                          **
  271. **  C Compilers: Borland C++ v2.0, Microsoft C v6.00a                       **
  272. **                                                                          **
  273. **  PCXHEAD displays all real information contained within the header of a  **
  274. **  PCX image file.  The EGA color palette (map) is always displayed        **
  275. **  because this color palette always exists in the PCX header even if it   **
  276. **  if it is all zeros.  If a VGA color palette exists then it is also      **
  277. **  displayed.                                                              **
  278. **                                                                          **
  279. **  Copyright (C) 1991 by Graphics Software Labs.  All rights reserved.     **
  280. \****************************************************************************/
  281. #include <stdio.h>
  282. #include <stdlib.h>
  283. #include <string.h>
  284. #include <conio.h>
  285. #include <io.h>
  286. #include "endianio.h"
  287. #include "pcx.h"
  288.  
  289. #define VERSION                     "1.00"
  290.  
  291.  
  292. int
  293. main(argc, argv)
  294. int argc;           /* Number of command line arguments */
  295. char *argv[];       /* Array of command line arguments  */
  296. {
  297.     WORD           i, j;            /* Loop Counters                        */
  298.     LONG           imageSize;       /* Size of the PCX image file           */
  299.     CHAR           pcxFileName[81]; /* Holder for the PCX image file name   */
  300.     FILE          *fpPcx;           /* File pointer to the PCX image file   */
  301.     PCXHEADER      pcxHead;         /* PCX image file header structure      */
  302.     PCXVGAPALETTE  pcxVgaPal;       /* PCX image file VGA palette structure */
  303.  
  304.     printf("PCXHEAD - Display the header info within a PCX image file (v%s)\n",
  305.       VERSION);
  306.  
  307.     /* Check for proper number of command line arguments */
  308.     if (argc < 2)
  309.     {
  310.         fputs("Usage: PCXHEAD filename.pcx\n\n", stderr);
  311.         exit(-1);
  312.     }
  313.  
  314.     /* Add the .pcx extension to the file name if no extension exists */
  315.     strncpy(pcxFileName, argv[1], 76);
  316.     if (!strrchr(pcxFileName, '.'))
  317.         strcat(pcxFileName, ".pcx");
  318.  
  319.     /* Open the PCX image file */
  320.     if ((fpPcx = fopen(pcxFileName, "rb")) == (FILE *) NULL)
  321.     {
  322.         fprintf(stderr, "PCXHEAD: Cannot open file %s\n", pcxFileName);
  323.         exit(-2);
  324.     }
  325.  
  326.     /* Read the PCX image file header information */
  327.     ReadPcxHeader(&pcxHead, fpPcx);
  328.  
  329.     /* Check for FILE stream error */
  330.     if (ferror(fpPcx))
  331.     {
  332.         fputs("PCXHEAD: Error reading header information!\n", stderr);
  333.         exit(-3);
  334.     }
  335.  
  336.     /* Check the identification byte value */
  337.     if (pcxHead.Id != 0x0A)
  338.     {
  339.         fprintf(stderr, "PCXHEAD: %s is not a PCX-format file!\n",
  340.           pcxFileName);
  341.         exit(-4);
  342.     }
  343.  
  344.     /* Get the size of the image file */
  345.     imageSize = filelength(fileno(fpPcx));
  346.  
  347.     /*
  348.     ** Display, in an orderly fashion, all the information now contained
  349.     ** within the PCXHEADER structure.  The following code looks like
  350.     ** hell in an attempt to make the information look nice on screen.
  351.     **
  352.     ** Note the Horizontal and Vertical Screen Size field values are not
  353.     ** displayed as they are only present in headers of PCX files created
  354.     ** by PC Paintbrush, PC Paintbrush Plus, PC Paintbrush for Windows,
  355.     ** and compatable programs (Version field values 4 or 5) and are
  356.     ** typically not used.
  357.     */
  358.     puts("                                            EGA Color Palette");
  359.     puts("                                          Color  Red  Green  Blue");
  360.     printf("\n             PCX File: %-16s", pcxFileName);
  361.     printf("     0    %03d   %03d   %03d\n",
  362.       pcxHead.EgaPalette[0], pcxHead.EgaPalette[1], pcxHead.EgaPalette[2]);
  363.     
  364.     printf("   Size of Image File: %-16ld", imageSize);
  365.     printf("     1    %03d   %03d   %03d\n",
  366.       pcxHead.EgaPalette[3], pcxHead.EgaPalette[4], pcxHead.EgaPalette[5]);
  367.     
  368.     printf("              Version: ");
  369.     switch((int) pcxHead.Version) {
  370.         case 0:
  371.             printf("%-16s", "2.5");
  372.             break;
  373.         case 1:
  374.             printf("%-16s", "2.8");
  375.             break;
  376.         case 3:
  377.             printf("%-16s", "2.8 (no palette)");
  378.             break;
  379.         case 5:
  380.             printf("%-16s", "3.0");
  381.             break;
  382.         default:
  383.             printf("%-16s", "Unknown");
  384.             break;
  385.     }
  386.     printf("     2    %03d   %03d   %03d\n",
  387.       pcxHead.EgaPalette[6], pcxHead.EgaPalette[7], pcxHead.EgaPalette[8]);
  388.     
  389.     printf("             Encoding: %-16s", pcxHead.Format == 1 ?
  390.       "RLE" : (pcxHead.Format == 0 ? "None" : "Unknown"));
  391.     printf("     3    %03d   %03d   %03d\n",
  392.       pcxHead.EgaPalette[9], pcxHead.EgaPalette[10], pcxHead.EgaPalette[11]);
  393.  
  394.     printf("       Bits per Pixel: %-16d", pcxHead.BitsPixelPlane);
  395.     printf("     4    %03d   %03d   %03d\n",
  396.       pcxHead.EgaPalette[12], pcxHead.EgaPalette[13], pcxHead.EgaPalette[14]);
  397.     
  398.     printf("              X Start: %-16d", pcxHead.Xmin);
  399.     printf("     5    %03d   %03d   %03d\n",
  400.       pcxHead.EgaPalette[15], pcxHead.EgaPalette[16], pcxHead.EgaPalette[17]);
  401.     
  402.     printf("              Y Start: %-16d", pcxHead.Ymin);
  403.     printf("     6    %03d   %03d   %03d\n",
  404.       pcxHead.EgaPalette[18], pcxHead.EgaPalette[19], pcxHead.EgaPalette[20]);
  405.     
  406.     printf("                X End: %-16d", pcxHead.Xmax);
  407.     printf("     7    %03d   %03d   %03d\n",
  408.       pcxHead.EgaPalette[21], pcxHead.EgaPalette[22], pcxHead.EgaPalette[23]);
  409.     
  410.     printf("                Y End: %-16d", pcxHead.Ymax);
  411.     printf("     8    %03d   %03d   %03d\n",
  412.       pcxHead.EgaPalette[24], pcxHead.EgaPalette[25], pcxHead.EgaPalette[26]);
  413.     
  414.     printf("Horizontal Resolution: %-16d", pcxHead.Hdpi);
  415.     printf("     9    %03d   %03d   %03d\n",
  416.       pcxHead.EgaPalette[27], pcxHead.EgaPalette[28], pcxHead.EgaPalette[29]);
  417.     
  418.     printf("  Vertical Resolution: %-16d", pcxHead.Vdpi);
  419.     printf("    10    %03d   %03d   %03d\n",
  420.       pcxHead.EgaPalette[30], pcxHead.EgaPalette[31], pcxHead.EgaPalette[32]);
  421.     
  422.     printf("        Reserved Byte: %-16d", pcxHead.Reserved);
  423.     printf("    11    %03d   %03d   %03d\n",
  424.       pcxHead.EgaPalette[33], pcxHead.EgaPalette[34], pcxHead.EgaPalette[35]);
  425.     
  426.     printf(" Number of Bit Planes: %-16d", pcxHead.NumberOfPlanes);
  427.     printf("    12    %03d   %03d   %03d\n",
  428.       pcxHead.EgaPalette[36], pcxHead.EgaPalette[37], pcxHead.EgaPalette[38]);
  429.     
  430.     printf("  Bytes per Scan Line: %-16d", pcxHead.BytesLinePlane * pcxHead.Numb
  431. erOfPlanes);
  432.     printf("    13    %03d   %03d   %03d\n",
  433.       pcxHead.EgaPalette[39], pcxHead.EgaPalette[40], pcxHead.EgaPalette[41]);
  434.     
  435.     printf("         Palette Type: %-16s", (pcxHead.PaletteInfo == 1 ?
  436.       "Color or B&W" : (pcxHead.PaletteInfo == 2 ? "Gray Scale" :
  437.       "Unknown")));
  438.     printf("    14    %03d   %03d   %03d\n",
  439.       pcxHead.EgaPalette[42], pcxHead.EgaPalette[43], pcxHead.EgaPalette[44]);
  440.                  
  441.     printf(" Max Number of Colors: %-16ld", 1L << (pcxHead.NumberOfPlanes * pcxH
  442. ead.BitsPixelPlane));
  443.     printf("    15    %03d   %03d   %03d\n",
  444.       pcxHead.EgaPalette[45], pcxHead.EgaPalette[46], pcxHead.EgaPalette[47]);
  445.  
  446.     /* Check for the presence of a VGA color map */
  447.     if (pcxHead.Version == 5)
  448.     {
  449.         fseek(fpPcx, -769L, SEEK_END);  /* Seek to the VGA Id byte */
  450.  
  451.         if (GetByte(fpPcx) == 0x0C)     /* Is it the proper value? */
  452.         {
  453.             fputs("\nHit Enter for VGA palette information...", stdout);
  454.             getch();
  455.  
  456.             /* Read VGA palette information from PCX file */
  457.             for (i = 0; i < sizeof(pcxVgaPal); i++)
  458.                 pcxVgaPal.VgaPalette[i] = GetByte(fpPcx);
  459.  
  460.             if (ferror(fpPcx))
  461.                 fputs("PCXHEAD: Error reading VGA palette information!\n", stder
  462. r);
  463.             else
  464.             {
  465.                 puts("\n\n                                VGA Color Palette\n");
  466.  
  467.                 puts("Color  Red Grn Blu  Color  Red Grn Blu  Color  Red Grn Blu
  468.   Color  Red Grn Blu");
  469.  
  470.                 /* Display the palette values */
  471.                 for (i = 0, j = 0; i < 256; i += 4, j += 12)
  472.                 {
  473.                     printf(" %3d   %03u %03u %03u   %3d   %03u %03u %03u",
  474.                       i,
  475.                       pcxVgaPal.VgaPalette[j],
  476.                       pcxVgaPal.VgaPalette[j+1],
  477.                       pcxVgaPal.VgaPalette[j+2],
  478.                       i+1,
  479.                       pcxVgaPal.VgaPalette[j+3],
  480.                       pcxVgaPal.VgaPalette[j+4],
  481.                       pcxVgaPal.VgaPalette[j+5]);
  482.                       
  483.                     printf("   %3d   %03u %03u %03u   %3d   %03u %03u %03u\n",
  484.                       i+2,
  485.                       pcxVgaPal.VgaPalette[j+6],
  486.                       pcxVgaPal.VgaPalette[j+7],
  487.                       pcxVgaPal.VgaPalette[j+8],
  488.                       i+3,
  489.                       pcxVgaPal.VgaPalette[j+9],
  490.                       pcxVgaPal.VgaPalette[j+10],
  491.                       pcxVgaPal.VgaPalette[j+11]);
  492.  
  493.                     if (i && i % 88 == 0)
  494.                     {
  495.                         fputs("Hit Enter for next page...", stdout);
  496.                         getch();        
  497.                         puts("\n\nColor  Red Grn Blu  Color  Red Grn Blu  \
  498.                               Color  Red Grn Blu  Color  Red Grn Blu");
  499.                     }
  500.                 }
  501.                 putchar('\n');
  502.             }
  503.         }
  504.         else
  505.             puts("\nPCXHEAD: No VGA color palette found.");
  506.     }
  507.     fclose(fpPcx);
  508.  
  509.     return(0);              /* Successful termination */
  510. }
  511. }
  512.                                                                                 
  513.                         
  514.  
  515.  
  516. PCX Run-length Decoder
  517.  
  518. PCXDECOD.C
  519.  
  520.  
  521. PCX decoders need to be aware of image data that contains runs which
  522. start at the end of one scan line and finish at the start of the next
  523. line.  This function decodes one scan line at a time and will keep
  524. track of runs if they extend to the next scan line.
  525.  
  526.  
  527. /****************************************************************************\
  528. **  Title:       PCXDECODE.C                                                **
  529. **  Purpose:     Decode a PCX image file scan line.                         **
  530. **  Version:     1.0                                                        **
  531. **  Date:        May 1991                                                   **
  532. **  Author:      James D. Murray, Anaheim, CA  USA                          **
  533. **  C Compilers: Borland C++ v2.0, Microsoft C v6.00a                       **
  534. **                                                                          **
  535. **  Decode an image scan line using the PCX run-length encoding algorithm   **
  536. **  Decoded data is returned in a buffer.  Useful for algorithms that need  **
  537. **  to work on images one scan line at a time.                              **
  538. **                                                                          **
  539. **  This module contains the following functions:                           **
  540. **                                                                          **
  541. **      PcxDecodeScanLine - Decode a PCX RLE-encoded scan line              **
  542. **                                                                          **
  543. **  Copyright (C) 1991 by Graphics Software Labs.  All rights reserved.     **
  544. \****************************************************************************/
  545. #include <stdio.h>
  546. #include "endianio.h"
  547. #include "pcx.h"
  548.  
  549.  
  550. /*
  551. **  Decode (uncompress) a PCX image file scan line.
  552. **
  553. **  PcxDecodeScanLine() decodes a buffer containing scan line data encoded
  554. **  using the PCX run-length encoding algorithm.  The encoded data is read
  555. **  from a FILE stream, decoded, and then written to a pointer to a buffer
  556. **  passed to this function.
  557. **
  558. **  The PCX specification states (in so many words) that the run-length
  559. **  encoding of a pixel run should stop at the end of each scan line. 
  560. **  However, some PCX encoders may continue the encoding of a pixel run on
  561. **  to the beginning of the next scan line, if possible.  This code,
  562. **  therefore, assumes that any pixel run can span scan lines.
  563. **
  564. **  To check for decoding errors, the value returned by PcxDecodeScanLine()
  565. **  should be the same as the value of BufferSize (the length of an
  566. **  uncompressed scan line).
  567. **
  568. **  Returns: Total number of pixels decoded from compressed scan line,
  569. **           or EOF if a file stream error occured.
  570. */
  571. SHORT
  572. PcxDecodeScanLine(DecodedBuffer, BufferSize, FpPcx)
  573. BYTE *DecodedBuffer;    /* Pointer to buffer to hold decoded data         */
  574. WORD  BufferSize;       /* Size of buffer to hold decoded data            */
  575. FILE *FpPcx;            /* FILE pointer to the open input PCX image file  */
  576. {
  577.     WORD  index = 0;            /* Index into compressed scan line buffer */
  578.     SHORT total = 0;            /* Running total of decoded pixel values  */
  579.     BYTE  byte;                 /* Data byte read from PCX file           */
  580.     static BYTE runcount = 0;   /* Length of decoded pixel run            */
  581.     static BYTE runvalue = 0;   /* Value of decoded pixel run             */
  582.  
  583.     /*
  584.     ** If there is any data left over from the previous scan
  585.     ** line write it to the beginning of this scan line.
  586.     */
  587.     do
  588.     {
  589.         /* Write the pixel run to the buffer */
  590.         for (total += runcount;                 /* Update total             */
  591.              runcount && index < BufferSize;    /* Don't read past buffer   */
  592.              runcount--, index++)
  593.             DecodedBuffer[index] = runvalue;    /* Assign value to buffer   */
  594.  
  595.         if (runcount)           /* Encoded run ran past end of scan line    */
  596.         {
  597.             total -= runcount;  /* Subtract count not written to buffer     */
  598.             return(total);      /* Return number of pixels decoded          */
  599.         }
  600.  
  601.         /*
  602.         ** Get the next encoded run packet.
  603.         **
  604.         ** Read a byte of data.  If the two MBSs are 1 then this byte
  605.         ** holds a count value (0 to 63) and the following byte is the
  606.         ** data value to be repeated.  If the two MSBs are 0 then the
  607.         ** count is one and the byte is the data value itself.
  608.         */
  609.         byte = GetByte(FpPcx);                  /* Get next byte    */
  610.  
  611.         if ((byte & 0xC0) == 0xC0)              /* Two-byte code    */
  612.         {
  613.             runcount = byte & 0x3F;             /* Get run count    */
  614.             runvalue = GetByte(FpPcx);          /* Get pixel value  */
  615.         }
  616.         else                                    /* One byte code    */
  617.         {
  618.             runcount = 1;                       /* Run count is one */
  619.             runvalue = byte;                    /* Pixel value      */
  620.         }
  621.     }
  622.     while (index < BufferSize);     /* Read until the end of the buffer     */
  623.  
  624.     if (ferror(FpPcx))
  625.         return(EOF);    /* File stream error.  Probably a premature EOF     */
  626.  
  627.     return(total);      /* Return number of pixels decoded                  */
  628. }
  629. }
  630.  
  631.  
  632. PCX Run-length Encoder
  633.  
  634. PCXENCOD.C
  635.  
  636.  
  637. Run-length encoding is as easy as decoding.  This function encodes a
  638. single scan line of data at a time and will not encode across scan
  639. lines.
  640.  
  641.  
  642. /****************************************************************************\
  643. **  Title:       PCXENCOD.C                                                 **
  644. **  Purpose:     Encode a PCX image file scan line.                         **
  645. **  Version:     1.0                                                        **
  646. **  Date:        May 1991                                                   **
  647. **  Author:      James D. Murray, Anaheim, CA  USA                          **
  648. **  C Compilers: Borland C++ v2.0, Microsoft C v6.00a                       **
  649. **                                                                          **
  650. **  Compress an image scan line using the PCX run-length encoding           **
  651. **  algorithm.  Useful for algorithms that need to work on images one scan  **
  652. **  line at a time.                                                         **
  653. **                                                                          **
  654. **  This module contains the following functions:                           **
  655. **                                                                          **
  656. **      PcxEncodeScanLine - Encode a raw scan line using PCX RLE.           **
  657. **                                                                          **
  658. **  Copyright (C) 1991 by Graphics Software Labs.  All rights reserved.     **
  659. \****************************************************************************/
  660. #include <stdio.h>
  661. #include "endianio.h"
  662. #include "pcx.h"
  663.  
  664. /*
  665. **  Encode (compress) a PCX image file scan line.
  666. **
  667. **  PcxEncodeScanLine() encodes a buffer containing raw scan line data
  668. **  using the PCX PackBytes run-length encoding algorithm.  The encoded
  669. **  data is written to a second buffer passed to the function.
  670. **
  671. **  The main problem when encoding a scan line is that we never know how
  672. **  long the resulting encoded scan line will be.  Typically it will be
  673. **  shorter than the unencoded line, however, this type of RLE encoding
  674. **  can make the resulting encoded data larger in size than the unencoded
  675. **  data depending upon the data being encoded.
  676. **
  677. **  It is therefore important that the buffer used to hold the encoded
  678. **  scan line be larger than what will typically be needed.  A size of
  679. **  2048 bytes should be more than plenty for typical VGA images.  The
  680. **  size of the buffer can be trimmed down to the size of the encoded
  681. **  data using realloc() and the return value of PcxEncodeScanLine()
  682. **  function, if necessary.
  683. **
  684. **  Returns: Number of bytes in compressed scan line.
  685. */
  686. WORD
  687. PcxEncodeScanLine(DecodedBuffer, EncodedBuffer, BufferSize)
  688. BYTE *DecodedBuffer;    /* Pointer to buffer holding unencoded data         */
  689. BYTE *EncodedBuffer;    /* Pointer to buffer to hold encodeded scan line    */
  690. WORD  BufferSize;       /* Size of buffer holding unencoded data            */
  691. {
  692.     register WORD index = 0;        /* Index into uncompressed data buffer  */
  693.     register WORD scanindex = 0;    /* Index into compressed data buffer    */
  694.     BYTE runcount;                  /* Length of encoded pixel run          */
  695.     BYTE runvalue;                  /* Value of encoded pixel run           */
  696.  
  697.     while (index < BufferSize)
  698.     {
  699.         /*
  700.         ** Get the run count of the next pixel value run.
  701.         **
  702.         ** Pixel value runs are encoded until a different pixel value
  703.         ** is encountered, the end of the scan line is reached, or 63
  704.         ** pixel values have been counted.
  705.         */
  706.         for (runcount = 1, runvalue = DecodedBuffer[index];
  707.              runvalue == DecodedBuffer[index + runcount] &&
  708.              index + runcount < BufferSize &&
  709.              runcount < 63;
  710.              runcount++);
  711.  
  712.         /*
  713.         ** Encode the run into a one or two-byte code.
  714.         **
  715.         ** Multiple pixel runs are stored in two-byte codes.  If a single
  716.         ** pixel run has a value of less than 64 then it is stored in a
  717.         ** one-byte code.  If a single pixel run has a value of 64 to 255
  718.         ** then it is stored in a two-byte code.
  719.         */
  720.         if (runcount > 1)                   /* Multiple pixel run */
  721.         {
  722.             EncodedBuffer[scanindex++] = runcount | 0xC0;
  723.             EncodedBuffer[scanindex++] = runvalue;       
  724.         }
  725.         else                                /* Single pixel run   */
  726.         {
  727.             if (DecodedBuffer[index] < 64)  /* Value is 0 to 63   */
  728.             {
  729.                 EncodedBuffer[scanindex++] = runvalue;
  730.             }
  731.             else                            /* Value is 64 to 255 */
  732.             {
  733.                 EncodedBuffer[scanindex++] = runcount | 0xC0;
  734.                 EncodedBuffer[scanindex++] = runvalue;       
  735.             }
  736.         }
  737.         index += runcount;  /* Jump ahead to next pixel run value */
  738.     }
  739.     return(scanindex);      /* Return the number of bytes written to buffer */
  740. }
  741. }
  742.  
  743.  
  744. PCX File Reader and Writer
  745.  
  746. PCXCODE.C
  747.  
  748.  
  749. This program uses all the functions in the previous listings to create
  750. a program that reads, decodes, encodes, and writes a PCX image file.
  751. This program is only an example of how to implement the PCX functions
  752. in your own code.  However, if you have an PCX files that appear
  753. partly munged when displayed, you might try running them through this
  754. encoder/decoder to see if it can fix them.
  755.  
  756.  
  757. /****************************************************************************\
  758. **  Title:        PCXCODE                                                   **
  759. **  Purpose:      Decode/Encode a PCX image file.                           **
  760. **  Version:      1.0                                                       **
  761. **  Date:         May 1991                                                  **
  762. **  Author:       James D. Murray, Anaheim, CA  USA                         **
  763. **  C Compilers:  Borland C++ v2.0, Microsoft C v6.00a                      **
  764. **                                                                          **
  765. **  This code is an example of several functions that work with PCX image   **
  766. **  files.  PCXCODE reads a PCX image file, decodes the image, data         **
  767. **  re-encodes it, and writes it out to a second PCX file.  While this      **
  768. **  program is only a working example, it can be used to possibly repair    **
  769. **  PCX files that have been previously encoded incorrectly and fail to     **
  770. **  display properly.                                                           
  771.                 **
  772. **                                                                          **
  773. **  Copyright (C) 1991 Graphics Software Labs.  All rights reserved.        **
  774. \****************************************************************************/
  775. #include <stdio.h>
  776. #include <stdlib.h>
  777. #include <string.h>
  778. #include "endianio.h"
  779. #include "pcx.h"
  780.  
  781.  
  782. int
  783. main(argc, argv)
  784. int argc;           /* Number of command line arguments */
  785. char *argv[];       /* Array of command line arguments  */
  786. {
  787.     register WORD i;                /* Loop counter                      */
  788.     FILE         *fpPcxIn;          /* PCX image file input FILE stream  */
  789.     FILE         *fpPcxOut;         /* PCX image file output FILE stream */
  790.     PCXHEADER     pcxHead;          /* PCX image file header structure   */
  791.     WORD          numOfColors;      /* Number of colors in the image     */
  792.     WORD          xSize;            /* Width of image in pixels          */
  793.     WORD          ySize;            /* Height of image in scan lines     */
  794.     SHORT         scanLineLength;       /* Length of uncompressed scan line  */
  795.     BYTE         *decodedBuffer;    /* Buffer holding decoded scan line  */
  796.     BYTE         *encodedBuffer;    /* Buffer holding encoded scan line  */
  797.     WORD          scanLineSize;     /* Size of encoded scan line         */
  798.     SHORT         ret;              /* Return value holder               */
  799.  
  800.     puts("PCXCODE - Decode and recode a PCX image file (v1.00)\n");
  801.  
  802.     /* Check for proper number of command line arguments */
  803.     if (argc < 3)
  804.     {
  805.         fputs("Usage: PCXHEAD input_filename.pcx output_filename.pcx\n\n",
  806.           stderr);
  807.         exit(-1);
  808.     }
  809.  
  810.     /* Open the input PCX image file */
  811.     if ((fpPcxIn = fopen(argv[1], "rb")) == (FILE *) NULL)
  812.     {
  813.         fprintf(stderr, "PCXHEAD: Cannot open input file %s\n", argv[1]);
  814.         exit(-2);
  815.     }
  816.  
  817.     /* Open the output PCX image file */
  818.     if ((fpPcxOut = fopen(argv[2], "wb")) == (FILE *) NULL)
  819.     {
  820.         fprintf(stderr, "PCXHEAD: Cannot open output file %s\n", argv[2]);
  821.         exit(-3);
  822.     }
  823.  
  824.     /* Read the PCX image file header information */
  825.     ReadPcxHeader(&pcxHead, fpPcxIn);
  826.  
  827.     /* Check for FILE stream error */
  828.     if (ferror(fpPcxIn))
  829.     {
  830.         fputs("PCXHEAD: Error reading header information!\n", stderr);
  831.         exit(-4);
  832.     }
  833.  
  834.     /* Check the identification byte value */
  835.     if (pcxHead.Id != 0x0A)
  836.     {
  837.         fprintf(stderr, "PCXHEAD: Not a PCX-format file!\n");
  838.         exit(-5);
  839.     }
  840.  
  841.     /* Calculate size of image in pixels and scan lines */
  842.     xSize = pcxHead.Xmax - pcxHead.Xmin + 1;
  843.     ySize = pcxHead.Ymax - pcxHead.Ymin + 1;
  844.  
  845.     /* Do some more calculations */
  846.     numOfColors = (1 << (pcxHead.BitsPixelPlane * pcxHead.NumberOfPlanes));
  847.     scanLineLength = pcxHead.NumberOfPlanes * pcxHead.BytesLinePlane;
  848.  
  849.     /* Display some PCX image file information */
  850.     printf("Image Width  = %3d\nImage Length = %3d\n", xSize, ySize);
  851.     printf("Number of Colors: %d\n", numOfColors);
  852.     printf("Size of uncompressed scan line: %d\n\n", scanLineLength);
  853.  
  854.     /* Write out the PCX image file header */
  855.     WritePcxHeader(&pcxHead, fpPcxOut);
  856.  
  857.     /* Create an uncompressed scanline buffer */
  858.     if ((decodedBuffer = (BYTE *) malloc(scanLineLength)) == NULL)
  859.     {
  860.         fputs("PCXCODE: Cannot allocate scan line buffer.", stderr);
  861.         exit(-6);
  862.     }
  863.  
  864.     /* Create a compressed scanline buffer */
  865.     if ((encodedBuffer = (BYTE *) malloc(2048)) == NULL)
  866.     {
  867.         fputs("PCXCODE: Cannot allocate scan line buffer.", stderr);
  868.         exit(-7);
  869.     }
  870.  
  871.     /*
  872.     ** Read an encoded scan line, decode it, reencode it, and write it to
  873.     ** the output file stream.  Continue until all scan lines are read.
  874.     */
  875.     for (i = 0; i < ySize; i++)
  876.     {
  877.         printf("Scan Line %03d\r", i);
  878.  
  879.         /* Read scan line and decode it */
  880.         if ((ret = PcxDecodeScanLine(decodedBuffer, scanLineLength, fpPcxIn))
  881.           != scanLineLength)
  882.         {
  883.             printf("PCXCODE: Bad scan line length (was %d should be %d)\n",
  884.               ret, scanLineLength);
  885.         }
  886.  
  887.         /* Encode scan line */
  888.         scanLineSize =
  889.           PcxEncodeScanLine(decodedBuffer, encodedBuffer, scanLineLength);
  890.  
  891.         /* Write scan line to output FILE stream */
  892.         fwrite((BYTE *) encodedBuffer, sizeof(BYTE), scanLineSize, fpPcxOut);
  893.     }
  894.  
  895.     /* If there is a VGA palette then read and append it to the output file */
  896.     if (pcxHead.Version == 5)
  897.     {
  898.         fseek(fpPcxIn, -769L, SEEK_END);  /* Seek backwards from end of file */
  899.  
  900.         if (GetByte(fpPcxIn) == 0x0C)     /* VGA Palette ID value? */ 
  901.         {
  902.             PCXVGAPALETTE  PcxVgaPal;     /* PCX VGA palette structure */
  903.  
  904.             fputc(0x0c, fpPcxOut);
  905.  
  906.             /* Read the VGA palette */
  907.             for (i = 0; i < sizeof(PcxVgaPal); i++)
  908.                 PcxVgaPal.VgaPalette[i] = GetByte(fpPcxIn);
  909.  
  910.             /* Write the VGA palette */
  911.             for (i = 0; i < sizeof(PcxVgaPal); i++)
  912.                 PutByte(PcxVgaPal.VgaPalette[i], fpPcxOut);
  913.         }
  914.     }
  915.     fclose(fpPcxIn);
  916.     fclose(fpPcxOut);
  917.  
  918.     return(0);
  919. }
  920. }
  921.  
  922.  
  923. DCX File Information Lister
  924.  
  925. DCXHEAD.C
  926.  
  927.  
  928. This listing program prints out the number and size of each PCX file
  929. contained within a DCX file.  It is a good example of how to parse
  930. the data in a DCX file header and page list.
  931.  
  932.  
  933. /****************************************************************************\
  934. **  Title:       DCXHEAD.C                                                  **
  935. **  Purpose:     Display the data in a DCX image file header.               **
  936. **  Version:     1.0                                                        **
  937. **  Date:        April 1991                                                 **
  938. **  Author:      James D. Murray, Anaheim, CA, USA                          **
  939. **  C Compilers: Borland C++ v2.0, Microsoft C v6.00a                       **
  940. **                                                                          **
  941. **  DCX2PCX extracts all the PCX images from within a DCX file.  A DCX file **
  942. **  may contain up to 1023 images.  Each PCX image is a complete PCX image  **
  943. **  file, including header, palette, and compressed image data.             **
  944. **                                                                          **
  945. **  Copyright (C) 1991 by Graphics Software Labs.  All rights reserved.     **
  946. \****************************************************************************/
  947. #include <stdio.h>
  948. #include <stdlib.h>
  949. #include <string.h>
  950. #include "endianio.h"
  951. #include "pcx.h"
  952.  
  953. DWORD (*GetDword)(FILE *);      /* Pointer to ENDIANIO function */
  954.  
  955.  
  956. int
  957. main(argc, argv)
  958. int argc;
  959. char *argv[];
  960. {
  961.     WORD       counter;         /* Number of PCX images in DCX file     */
  962.     FILE      *fpDcx;           /* File pointer to the DCX image file   */
  963.     CHAR       dcxFileName[81]; /* Holder for the DCX image file name   */
  964.     DCXHEADER  dcxHead;         /* DCX image file header structure      */
  965.  
  966.     puts("DCXHEAD - Display the header info within a DCX image file (v1.00)\n");
  967.  
  968.  
  969.     /* Check for proper number of command line arguments */
  970.     if (argc < 2)
  971.     {
  972.         fputs("Usage: DCXHEAD filename.dcx\n\n", stderr);
  973.         exit(-1);
  974.     }
  975.  
  976.     /* Add the .dcx extension to the file name if no extension exists */
  977.     strncpy(dcxFileName, argv[1], 80);
  978.     if (!strrchr(argv[1], '.'))
  979.         strcat(dcxFileName, ".dcx");
  980.  
  981.     /* Open the DCX image file */
  982.     if ((fpDcx = fopen(dcxFileName, "rb")) == NULL)
  983.     {
  984.         fprintf(stderr, "DCXHEAD: Cannot open file %s\n", dcxFileName);
  985.         exit(-2);
  986.     }
  987.  
  988.     /* Read using little-endian byte order */
  989.     GetDword = GetLittleDword;
  990.  
  991.     /* Read the ID word */
  992.     dcxHead.Id = GetDword(fpDcx);
  993.  
  994.     /* Check the identification word value */
  995.     if (dcxHead.Id != 987654321L)
  996.     {
  997.         fprintf(stderr, "DCXHEAD: %s is not a DCX-format file!\n", dcxFileName);
  998.  
  999.         exit(-3);
  1000.     }
  1001.     printf("Magic number: %ld\n\n", dcxHead.Id);
  1002.  
  1003.     /* Zero-out the page list */
  1004.     memset(&dcxHead.PageList, 0, sizeof(dcxHead.PageList));
  1005.  
  1006.     /* Read the page list one entry at a time */
  1007.     for (counter = 0; dcxHead.PageList[counter] = GetDword(fpDcx); counter++)
  1008.         printf("PCX Image %d Offset: %ld\n",
  1009.           counter + 1, dcxHead.PageList[counter]);
  1010.  
  1011.     printf("\nTotal Number of PCX images in DCX file %s: %u\n",
  1012.       dcxFileName, counter);
  1013.  
  1014.     /* Check for FILE stream errors */
  1015.     if (ferror(fpDcx))
  1016.     {
  1017.         fputs("DCXHEAD: Error reading header information!\n", stderr);
  1018.         exit(-3);
  1019.     }
  1020.     return(0);              /* Successful termination */
  1021. }
  1022. }
  1023.  
  1024.  
  1025. PCX to DCX Image File Converter
  1026.  
  1027. PCX2DCX.C
  1028.  
  1029.  
  1030. Although this program is called a converter, it is really an archiver, in
  1031. that it takes  a bunch of PCX image files and makes one big DCX image
  1032. file out of them without really changing the PCX files themselves.
  1033. It is included as an example of how to use the PCX and DCX code
  1034. together in a single application.
  1035.  
  1036.  
  1037. /***************************************************************************\
  1038. **  Title:       PCX2DCX.C                                                  **
  1039. **  Purpose:     Append or more PCX image files to a DCX file.              **
  1040. **  Version:     1.0                                                        **
  1041. **  Date:        April 1991                                                 **
  1042. **  Author:      James D. Murray, Anaheim, CA, USA                          **
  1043. **  C Compilers: Borland C++ v2.0, Microsoft C v6.00a                       **
  1044. **                                                                          **
  1045. **  PCX2DCX will append one or more PCX files to an existing DCX image      **
  1046. **  file.  If the DCX file named does not exist it is then created by       **
  1047. **  PCX2DCX. A DCX file may contain no more than 1023 PCX image pages.      **
  1048. **  Wildcards are supported.                                                **
  1049. **                                                                          **
  1050. **  Copyright (C) 1991 by Graphics Software Labs.  All rights reserved.     **
  1051. \****************************************************************************/
  1052. #include <stdio.h>
  1053. #include <stdlib.h>
  1054. #include <string.h>
  1055. #include <dos.h>
  1056. #include <io.h>
  1057. #include "endianio.h"
  1058. #include "pcx.h"
  1059.  
  1060. DWORD (*GetDword)(FILE *);
  1061.  
  1062. #ifdef  __TURBOC__
  1063. #include <dir.h>
  1064. #define FindFirst(p, f, a)  findfirst(p, f, a)
  1065. #define FindNext(f)         findnext(f)
  1066. #define FindStruct          ffblk
  1067. #define FindName            ff_name
  1068. #define FindSize            ff_fsize
  1069. #else   /* MSC */
  1070. #define FindFirst(p, f, a)  _dos_findfirst(p, a, f)
  1071. #define FindNext(f)         _dos_findnext(f)
  1072. #define FindStruct          find_t
  1073. #define FindName            name
  1074. #define FindSize            size
  1075. #endif
  1076.  
  1077. #define BUFFERSIZE      8192            /* Size of the copy buffer */
  1078. #define TEMPFILENAME    "PCX2DCX.TMP"   /* Temporary file name     */
  1079. #define SAVEFILENAME    "SAVEFILE.DCX"  /* DCX save file name      */
  1080.  
  1081. int                           
  1082. main(argc, argv)
  1083. int argc;
  1084. char *argv[];
  1085. {
  1086.     register WORD i;            /* Loop counter                             */
  1087.     FILE *fpDcx;                /* DCX file pointer                         */
  1088.     FILE *fpPcx;                /* PCX file pointer                         */
  1089.     FILE *fpTmp;                /* Temporary file pointer                   */
  1090.     CHAR *ptr;                  /* Pointer used by strrchr()                */
  1091.     
  1092.     WORD pageCount;             /* Count of PCX pages in DCX file           */
  1093.     WORD appendCount = 0;       /* Count of PCX pages appended to DCX file  */
  1094.     WORD retsize;               /* fread() return size value holder         */
  1095.     LONG offsetCount;           /* Current offset in temporary file         */
  1096.     CHAR pcxFileName[20];       /* PCX file name holder                     */
  1097.     CHAR dcxFileName[20];       /* DCX file name holder                     */
  1098.     CHAR buffer[BUFFERSIZE];    /* Copy buffer                              */
  1099.     DCXHEADER dcxHead;          /* DCX header structure                     */
  1100.     struct FindStruct fileinfo; /* File information block structure         */
  1101.  
  1102.     puts("PCX2DCX - Convert PCX image file(s) to DCX image file (v1.00)\n\n");
  1103.     
  1104.     /* Check for proper number of command line arguments */
  1105.     if (argc < 3)
  1106.     {
  1107.         fputs("Usage: PCX2DCX filename.DCX filename.PCX [ ... ]", stderr);
  1108.         exit(-1);
  1109.     }
  1110.  
  1111.     strcpy(dcxFileName, argv[1]);   
  1112.     if (!strrchr(dcxFileName, '.'))     /* Check if the file name has an    */
  1113.         strcat(dcxFileName, ".DCX");    /* extension and append .DCX if not */
  1114.  
  1115.     /* Initialize (zero-out) the page list */
  1116.     memset(dcxHead.PageList, 0, sizeof(dcxHead.PageList));
  1117.  
  1118.     /* Open (create) the temporary file */
  1119.     if ((fpTmp = fopen(TEMPFILENAME, "wb+")) == NULL)
  1120.     {
  1121.         fprintf(stderr, "PCX2DCX: Cannot create file %s\n", TEMPFILENAME);
  1122.         exit(-2);
  1123.     }
  1124.  
  1125.     /* Read using little-endian byte order */
  1126.     GetDword = GetLittleDword;
  1127.  
  1128.     /* Zero-out page list */
  1129.     memset(&dcxHead.PageList, 0, sizeof(dcxHead.PageList));
  1130.  
  1131.     if (!access(dcxFileName, 00)) {     /* If DCX file does exist... */
  1132.         printf("Appending to DCX image file %s\n", dcxFileName);
  1133.  
  1134.         /* Open the DCX image file */
  1135.         if ((fpDcx = fopen(dcxFileName, "rb+")) == NULL)
  1136.         {
  1137.             fprintf(stderr, "PCX2DCX: Cannot open file %s\n", dcxFileName);
  1138.             exit(-2);
  1139.         }
  1140.  
  1141.         /* Read the ID word */
  1142.         dcxHead.Id = GetDword(fpDcx);
  1143.  
  1144.         /* Check the magic number */
  1145.         if (dcxHead.Id != 987654321L)
  1146.         {
  1147.             fprintf(stderr, "PCX2DCX: %s is not a DCX-format file!\n",
  1148.               dcxFileName);
  1149.             exit(-3);
  1150.         }
  1151.  
  1152.         /*
  1153.         ** Load the page table with the offset values in the DCX file and
  1154.         ** count the number of PCX image pages in the DCX file.  In order
  1155.         ** to save space it is possible that some software will create DCX
  1156.         ** files that do not have a full 4096-byte page table.  PCX2DCX,
  1157.         ** therefore, does not assume that all data from bytes 4 to 4099
  1158.         ** in any DCX image file is a PCX image page offset value.
  1159.         */
  1160.         i = 0;
  1161.         do
  1162.         {
  1163.             dcxHead.PageList[i] = GetDword(fpDcx);
  1164.         }
  1165.         while (dcxHead.PageList[i++] != (DWORD) 0);
  1166.  
  1167.         pageCount = --i;
  1168.  
  1169.         /* Seek to first PCX image page */
  1170.         fseek(fpDcx, dcxHead.PageList[0], SEEK_SET);
  1171.  
  1172.         /* Copy all PCX image pages to the temporary file */
  1173.         while ((retsize = fread(&buffer, sizeof(char), BUFFERSIZE, fpDcx))
  1174.           == sizeof(buffer))
  1175.             fwrite(&buffer, sizeof(char), retsize, fpTmp);
  1176.         fwrite(&buffer, sizeof(char), retsize, fpTmp);
  1177.  
  1178.         offsetCount = ftell(fpDcx);   /* Get next offset */
  1179.         
  1180.         fclose(fpDcx);
  1181.  
  1182.         /* Save the original DCX file, just in case... */
  1183.         if (rename(dcxFileName, SAVEFILENAME) == -1)
  1184.             fputs("PCX2DCX: Rename failed.  Continuing...", stderr);
  1185.     }
  1186.     else        /* else, DCX file does not exist... */
  1187.     {
  1188.         printf("Creating DCX image file %s\n", dcxFileName);
  1189.  
  1190.         dcxHead.Id = 987654321L;    /* Set the magic number */
  1191.  
  1192.         offsetCount = 4100L;     /* First PCX page starts at offset 4100  */
  1193.         pageCount   = 0;         /* Number of PCX pages added to DCX file */
  1194.     }
  1195.  
  1196.     /* Open (create) the DCX file */
  1197.     if ((fpDcx = fopen(dcxFileName, "wb")) == NULL)
  1198.     {
  1199.         fprintf(stderr, "PCX2DCX: Cannot create file %s\n", dcxFileName);
  1200.         exit(-4);
  1201.     }
  1202.  
  1203.     /* For each PCX file specification in the argument list... */
  1204.     for (i = 2; argv[i]; i++)
  1205.     {
  1206.         if (FindFirst(argv[i], &fileinfo, 0) == -1)
  1207.             break;
  1208.  
  1209.         do
  1210.         {
  1211.             /* Add the path to the PCX file name if one was given */
  1212.             strcpy(pcxFileName, fileinfo.FindName);
  1213.             if ((ptr = strrchr(argv[i], '\\')) != NULL)
  1214.             {
  1215.                 *ptr = '\0';
  1216.                 strcpy(pcxFileName, argv[i]);
  1217.                 *ptr = '\\';
  1218.                 strcat(pcxFileName, fileinfo.FindName);
  1219.             }
  1220.  
  1221.             /* Open the PCX image file */
  1222.             if ((fpPcx = fopen(pcxFileName, "rb")) == NULL)
  1223.             {
  1224.                 fprintf(stderr, "PCX2DCX: Cannot create file %s\n",
  1225.                   TEMPFILENAME);
  1226.                 exit(-2);
  1227.             }
  1228.  
  1229.             printf("\nCopying file %-13s  Size = %ld", pcxFileName,
  1230.               fileinfo.FindSize);
  1231.  
  1232.             /* Copy the PCX image file to the temporary file */
  1233.             while ((retsize = fread(&buffer, sizeof(char), BUFFERSIZE, fpPcx))
  1234.               == sizeof(buffer))
  1235.                 fwrite(&buffer, sizeof(char), retsize, fpTmp);
  1236.             fwrite(&buffer, sizeof(char), retsize, fpTmp);
  1237.  
  1238.             fclose(fpPcx);    /* Close the PCX image file */
  1239.  
  1240.             /* Write offset of PCX page to the page list */
  1241.             dcxHead.PageList[pageCount] = offsetCount;
  1242.  
  1243.             /* Add PCX page size to DCX offset    */
  1244.             offsetCount += fileinfo.FindSize;
  1245.  
  1246.             /* Increment page and append counters */
  1247.             pageCount++;
  1248.             appendCount++;
  1249.  
  1250.             /* Check if the page table is full    */
  1251.             if (pageCount > 1023)
  1252.                 break;
  1253.         }
  1254.         while(FindNext(&fileinfo) == 0);
  1255.  
  1256.         /* Check if the page table is full */
  1257.         if (pageCount > 1023)
  1258.         {
  1259.             fputs("\nPCX2DCX: Maximum number of PCX files reached.", stderr);
  1260.             break;
  1261.         }
  1262.     }
  1263.     /* Write the DCX header to the DCX image file */
  1264.     fwrite(&dcxHead, sizeof(char), sizeof(dcxHead), fpDcx);
  1265.  
  1266.     fflush(fpTmp);          /* Flush the buffer stream    */
  1267.     rewind(fpTmp);          /* Set file pointer to byte 0 */
  1268.  
  1269.     /* Copy the temporary file if PCX image pages to the DCX image file */
  1270.     while ((retsize = fread(&buffer, sizeof(char), BUFFERSIZE, fpTmp))
  1271.       == sizeof(buffer))
  1272.         fwrite(&buffer, sizeof(char), retsize, fpDcx);
  1273.     fwrite(&buffer, sizeof(char), retsize, fpDcx);
  1274.  
  1275.     fclose(fpDcx);          /* Close the DCX file         */
  1276.     fclose(fpTmp);          /* Close the temporary file   */
  1277.     unlink(TEMPFILENAME);   /* Delete the temporary file  */
  1278.     unlink(SAVEFILENAME);   /* Delete the DCX save file   */
  1279.  
  1280.     printf("\n\n%d PCX image files appended to DCX image file %s \
  1281.       (%d images total).\n\n", appendCount, dcxFileName, pageCount);
  1282.  
  1283.     return(0);              /* Successful termination     */
  1284. }
  1285. }
  1286.  
  1287.  
  1288. DCX to PCX Image File Converter
  1289.  
  1290. DCX2PCX
  1291.  
  1292.  
  1293. Once you have made a DCX file why not split it back up into its PCX
  1294.  
  1295. file components?  Once again, this program is just one example of
  1296.  
  1297. an application that can be written using the information and code
  1298.  
  1299. in this directory and in its corresponding documentation.
  1300.  
  1301.  
  1302.  
  1303.  
  1304. /****************************************************************************\
  1305. **  Title:       DCX2PCX.C                                                  **
  1306. **  Purpose:     Extract PCX image files from a DCX image file.             **
  1307. **  Version:     1.0                                                        **
  1308. **  Date:        April 1991                                                 **
  1309. **  Author:      James D. Murray, Anaheim, CA  USA                          **
  1310. **  C Compilers: Borland C++ v2.0, Microsoft C v6.00a                       **
  1311. **                                                                          **
  1312. **  DCX2PCX extracts all the PCX images from within a DCX file.  A DCX file **
  1313. **  may contain up to 1023 PCX images.  Each PCX image is a complete PCX    **
  1314. **  image file, including header, palette, and compressed image data.       **
  1315. **                                                                          **
  1316. **  Copyright (C) 1991 by Graphics Software Labs.  All rights reserved.     **
  1317. \****************************************************************************/
  1318. #include <stdio.h>
  1319. #include <stdlib.h>
  1320. #include <string.h>
  1321. #include "endianio.h"
  1322. #include "pcx.h"
  1323.  
  1324. DWORD (*GetDword)(FILE *);      /* Pointer to ENDIANIO function */
  1325.  
  1326. #define BUFFERSIZE  8192        /* Size of copy buffer */
  1327.  
  1328.  
  1329. int
  1330. main(argc, argv)
  1331. int argc;
  1332. char *argv[];
  1333. {
  1334.     register WORD i, j;         /* Loop counters                            */
  1335.     FILE *fpDcx;                /* DCX file input file stream               */
  1336.     FILE *fpPcx;                /* PCX file output file stream              */
  1337.     int  counter = 0;           /* Counter used to construct PCX file names */
  1338.     int  retsize;               /* fread() return size value holder         */
  1339.     int  numberOfBlockReads;    /* Number of block to fread() in DCX file   */
  1340.     int  remainder;             /* Remainder of data to fread()             */
  1341.     long lpcxFileSize;          /* Size of a PCX file                       */
  1342.     char pcxFileName[20];       /* PCX file name holder                     */
  1343.     char dcxFileName[20];       /* DCX file name holder                     */
  1344.     char buffer[BUFFERSIZE];    /* Copy buffer                              */
  1345.     DCXHEADER dcxHead;          /* DCX header structure                     */
  1346.  
  1347.     puts("DCX2PCX - Extract PCX image file(s) from a DCX file (v1.00)\n\n");
  1348.  
  1349.     /* Check for proper number of command line arguments */
  1350.     if (argc < 2)
  1351.     {
  1352.         fputs("Usage: DCX2PCX filename.DCX", stderr);
  1353.         exit(-1);
  1354.     }
  1355.  
  1356.     strcpy(dcxFileName, argv[1]);   
  1357.     if (!strrchr(dcxFileName, '.'))     /* Check if the file name has an    */
  1358.         strcat(dcxFileName, ".DCX");    /* extension and append .DCX if not */
  1359.  
  1360.     /* Open the DCX image file */
  1361.     if ((fpDcx = fopen(dcxFileName, "rb")) == NULL)
  1362.     {
  1363.         fprintf(stderr, "DCX2PCX: Cannot open file %s\n", dcxFileName);
  1364.         exit(-2);
  1365.     }
  1366.  
  1367.     /* Read using little-endian byte order */
  1368.     GetDword = GetLittleDword;
  1369.  
  1370.     /* Read the ID word */
  1371.     dcxHead.Id = GetDword(fpDcx);
  1372.  
  1373.     /* Check the magic number */
  1374.     if (dcxHead.Id != 987654321L)
  1375.     {
  1376.         fprintf(stderr, "DCX2PCX: %s is not a DCX-format file!\n",
  1377.           dcxFileName);
  1378.         exit(-3);
  1379.     }
  1380.  
  1381.     /* Zero-out page list */
  1382.     memset(&dcxHead.PageList, 0, sizeof(dcxHead.PageList));
  1383.  
  1384.     /* Read the page list from the DCX file */
  1385.     i = 0;
  1386.     do
  1387.     {
  1388.         dcxHead.PageList[i] = GetDword(fpDcx);
  1389.     }
  1390.     while (dcxHead.PageList[i++] != (DWORD) 0);
  1391.  
  1392.     /* For each PCX image in the DCX file ... */
  1393.     for (i = 0; dcxHead.PageList[i]; i++)
  1394.     {
  1395.         /*
  1396.         ** The DCX format does not allow a way to preserve the orignal
  1397.         ** file names of the PCX images, so we must make new file names.
  1398.         **
  1399.         ** Names may range from PCX0000.PCX to PCX1022.PCX for a total
  1400.         ** of 1023 PCX image files.
  1401.         */
  1402.         sprintf(pcxFileName, "PCX%04d.PCX", counter);
  1403.         if ((fpPcx = fopen(pcxFileName, "wb")) == NULL)
  1404.         {
  1405.             fprintf(stderr, "DCX2PCX: Cannot create PCX file %s\n",
  1406.               pcxFileName);
  1407.             break;
  1408.         }
  1409.         printf("Extracting PCX image file %-13s", pcxFileName);
  1410.  
  1411.         /* Seek to the next PCX image */
  1412.         fseek(fpDcx, dcxHead.PageList[i], SEEK_SET);
  1413.  
  1414.         /* If this next PCX image is not the last PCX image in the file ... */
  1415.         if (dcxHead.PageList[i + 1] != 0)
  1416.         {
  1417.             /*
  1418.             ** Calculate the number of blocks in a PCX image based on
  1419.             ** the value of the BUFFERSIZE identifier.
  1420.             */
  1421.             lpcxFileSize = dcxHead.PageList[i+1] - dcxHead.PageList[i];
  1422.             numberOfBlockReads = (int) (lpcxFileSize / (long) BUFFERSIZE);
  1423.             remainder = (int) (lpcxFileSize % (long) BUFFERSIZE);
  1424.  
  1425.             printf("  Size = %ld\n", lpcxFileSize);
  1426.  
  1427.             /* Read and write blocks of data */
  1428.             for (j = 0; j < numberOfBlockReads; j++)
  1429.             {
  1430.                 if ((retsize = fread(&buffer, sizeof(char), BUFFERSIZE, fpDcx))
  1431.                   == sizeof(buffer))
  1432.                     fwrite(&buffer, sizeof(char), BUFFERSIZE, fpPcx);
  1433.             }
  1434.             fread(&buffer, sizeof(char), remainder, fpDcx);
  1435.             fwrite(&buffer, sizeof(char), remainder, fpPcx);
  1436.  
  1437.             /* Check if file pointer is where its suppose to be */
  1438.             if (ftell(fpDcx) != dcxHead.PageList[i + 1])
  1439.                 fprintf(stderr, "DCX2PCX: File position error!\
  1440.                   (are: %ld should be: %ld)\n",
  1441.                   ftell(fpDcx), dcxHead.PageList[i + 1]);
  1442.  
  1443.         }
  1444.         else    /* Extract last PCX image in the DCX file */
  1445.         {   
  1446.             while ((retsize = fread(buffer, sizeof(char), BUFFERSIZE, fpDcx))
  1447.               == sizeof(buffer))
  1448.                 fwrite(&buffer, sizeof(char), BUFFERSIZE, fpPcx);
  1449.             fwrite(&buffer, sizeof(char), retsize, fpPcx);
  1450.             printf("  Size = %ld\n", ftell(fpDcx) - dcxHead.PageList[i]);
  1451.         }
  1452.         fclose(fpPcx);      /* Close the PCX file             */
  1453.         counter++;          /* Increment the PCX file counter */
  1454.     }
  1455.     fclose(fpDcx);          /* Close the DCX file             */
  1456.  
  1457.     printf("\n%d PCX image files extracted.\n\n", counter);
  1458.  
  1459.     return(0);              /* Successful termination         */
  1460. }
  1461. }
  1462.