]> git.sur5r.net Git - cc65/blob - src/sp65/pcx.c
Some more work on reading pcx files.
[cc65] / src / sp65 / pcx.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                   pcx.c                                   */
4 /*                                                                           */
5 /*                              Read PCX files                               */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2012,      Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <errno.h>
37 #include <stdio.h>
38 #include <string.h>
39
40 /* common */
41 #include "print.h"
42 #include "xmalloc.h"
43
44 /* sp65 */
45 #include "error.h"
46 #include "fileio.h"
47 #include "pcx.h"
48
49
50
51 /*****************************************************************************/
52 /*                                  Macros                                   */
53 /*****************************************************************************/
54
55
56
57 /* Some PCX constants */
58 #define PCX_MAGIC_ID            0x0A
59
60 /* A raw PCX header is just a block of bytes */
61 typedef unsigned char           RawPCXHeader[128];
62
63 /* Structured PCX header */
64 typedef struct PCXHeader PCXHeader;
65 struct PCXHeader {
66     unsigned    Id;
67     unsigned    FileVersion;
68     unsigned    Compressed;
69     unsigned    BPP;
70     unsigned    XMin;
71     unsigned    YMin;
72     unsigned    XMax;
73     unsigned    YMax;
74     unsigned    XDPI;
75     unsigned    YDPI;
76     unsigned    Planes;
77     unsigned    BytesPerPlane;
78     unsigned    PalInfo;
79     unsigned    ScreenWidth;
80     unsigned    ScreenHeight;
81
82     /* Calculated data */
83     unsigned    Width;
84     unsigned    Height;
85 };
86
87 /* Read a little endian word from a byte array at offset O */
88 #define WORD(H, O)              ((H)[O] | ((H)[O+1] << 8))
89
90
91
92 /*****************************************************************************/
93 /*                                   Code                                    */
94 /*****************************************************************************/
95
96
97
98 static PCXHeader* NewPCXHeader (void)
99 /* Allocate a new PCX header and return it */
100 {
101     /* No initialization here */
102     return xmalloc (sizeof (PCXHeader));
103 }
104
105
106
107 static PCXHeader* ReadPCXHeader (FILE* F, const char* Name)
108 /* Read a structured PCX header from the given file and return it */
109 {
110     RawPCXHeader H;
111
112     /* Allocate a new PCXHeader structure */
113     PCXHeader* P = NewPCXHeader ();
114
115     /* Read the raw header */
116     ReadData (F, H, sizeof (H));
117
118     /* Convert the data into structured form */
119     P->Id               = H[0];
120     P->FileVersion      = H[1];
121     P->Compressed       = H[2];
122     P->BPP              = H[3];
123     P->XMin             = WORD (H, 4);
124     P->YMin             = WORD (H, 6);
125     P->XMax             = WORD (H, 8);
126     P->YMax             = WORD (H, 10);
127     P->XDPI             = WORD (H, 12);
128     P->YDPI             = WORD (H, 14);
129     P->Planes           = H[65];
130     P->BytesPerPlane    = WORD (H, 66);
131     P->PalInfo          = WORD (H, 68);
132     P->ScreenWidth      = WORD (H, 70);
133     P->ScreenHeight     = WORD (H, 72);
134     P->Width            = P->XMax - P->XMin + 1;
135     P->Height           = P->YMax - P->YMin + 1;
136
137     /* Check the header data */
138     if (P->Id != PCX_MAGIC_ID || P->FileVersion == 1 || P->FileVersion > 5) {
139         Error ("`%s' is not a PCX file", Name);
140     }
141     if (P->Compressed > 1) {
142         Error ("Unsupported compression (%d) in PCX file `%s'",
143                P->Compressed, Name);
144     }
145     if (P->BPP != 1 && P->BPP != 4 && P->BPP != 8) {
146         Error ("Unsupported bit depth (%u) in PCX file `%s'",
147                P->BPP, Name);
148     }
149     if (P->PalInfo != 1 && P->PalInfo != 2) {
150         Error ("Unsupported palette info (%u) in PCX file `%s'",
151                P->PalInfo, Name);
152     }
153     if (!ValidBitmapSize (P->Width, P->Height)) {
154         Error ("PCX file `%s' has an unsupported size (w=%u, h=%d)",
155                Name, P->Width, P->Height);
156     }
157
158     /* Return the structured header */
159     return P;
160 }
161
162
163
164 static void DumpPCXHeader (const PCXHeader* P, const char* Name)
165 /* Dump the header of the PCX file in readable form to stdout */
166 {
167     printf ("File name:      %s\n", Name);
168     printf ("PCX Version:    ");
169     switch (P->FileVersion) {
170         case 0: puts ("2.5");                             break;
171         case 2: puts ("2.8 with palette");                break;
172         case 3: puts ("2.8 without palette");             break;
173         case 4: puts ("PCX for Windows without palette"); break;
174         case 5: puts ("3.0");                             break;
175     }
176     printf ("Image type:     %s\n", P->PalInfo? "color" : "grayscale");
177     printf ("Compression:    %s\n", P->Compressed? "RLE" : "None");
178     printf ("Structure:      %u planes of %u bits\n", P->Planes, P->BPP);
179     printf ("Bounding box:   [%u/%u - %u/%u]\n", P->XMin, P->YMin, P->XMax, P->YMax);
180     printf ("Resolution:     %u/%u DPI\n", P->XDPI, P->YDPI);
181     printf ("Screen size:    %u/%u\n", P->ScreenWidth, P->ScreenHeight);
182 }
183
184
185
186 Bitmap* ReadPCXFile (const char* Name)
187 /* Read a bitmap from a PCX file */
188 {
189     PCXHeader* P;
190     Bitmap* B;
191
192     /* Open the file */
193     FILE* F = fopen (Name, "rb");
194     if (F == 0) {
195         Error ("Cannot open PCX file `%s': %s", Name, strerror (errno));
196     }
197
198     /* Read the PCX header */
199     P = ReadPCXHeader (F, Name);
200
201     /* Dump the header if requested */
202     if (Verbosity > 0) {
203         DumpPCXHeader (P, Name);
204     }
205
206     /* Close the file */
207     fclose (F);
208
209     /* Return the bitmap */
210     return B;
211 }
212
213
214