Skip to content

Latest commit

 

History

History
301 lines (275 loc) · 7.43 KB

IMG_pcx.c

File metadata and controls

301 lines (275 loc) · 7.43 KB
 
Aug 10, 2000
Aug 10, 2000
1
/*
Dec 31, 2011
Dec 31, 2011
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
SDL_image: An example image loading library for use with SDL
Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Aug 10, 2000
Aug 10, 2000
20
21
*/
Feb 27, 2001
Feb 27, 2001
22
23
24
25
26
27
28
/*
* PCX file reader:
* Supports:
* 1..4 bits/pixel in multiplanar format (1 bit/plane/pixel)
* 8 bits/pixel in single-planar format (8 bits/plane/pixel)
* 24 bits/pixel in 3-plane format (8 bits/plane/pixel)
*
Mar 7, 2001
Mar 7, 2001
29
30
* (The <8bpp formats are expanded to 8bpp surfaces)
*
Feb 27, 2001
Feb 27, 2001
31
32
33
34
* Doesn't support:
* single-planar packed-pixel formats other than 8bpp
* 4-plane 32bpp format with a fourth "intensity" plane
*/
Aug 10, 2000
Aug 10, 2000
35
#include <stdio.h>
Feb 27, 2001
Feb 27, 2001
36
#include <stdlib.h>
Aug 10, 2000
Aug 10, 2000
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include "SDL_endian.h"
#include "SDL_image.h"
#ifdef LOAD_PCX
struct PCXheader {
Uint8 Manufacturer;
Uint8 Version;
Uint8 Encoding;
Uint8 BitsPerPixel;
Sint16 Xmin, Ymin, Xmax, Ymax;
Sint16 HDpi, VDpi;
Uint8 Colormap[48];
Uint8 Reserved;
Uint8 NPlanes;
Sint16 BytesPerLine;
Sint16 PaletteInfo;
Sint16 HscreenSize;
Sint16 VscreenSize;
Uint8 Filler[54];
};
/* See if an image is contained in a data source */
int IMG_isPCX(SDL_RWops *src)
{
Feb 4, 2006
Feb 4, 2006
64
int start;
Aug 10, 2000
Aug 10, 2000
65
66
67
int is_PCX;
const int ZSoft_Manufacturer = 10;
const int PC_Paintbrush_Version = 5;
Oct 4, 2009
Oct 4, 2009
68
const int PCX_Uncompressed_Encoding = 0;
Aug 10, 2000
Aug 10, 2000
69
70
71
const int PCX_RunLength_Encoding = 1;
struct PCXheader pcxh;
Feb 13, 2007
Feb 13, 2007
72
73
if ( !src )
return 0;
Feb 4, 2006
Feb 4, 2006
74
start = SDL_RWtell(src);
Aug 10, 2000
Aug 10, 2000
75
76
77
78
is_PCX = 0;
if ( SDL_RWread(src, &pcxh, sizeof(pcxh), 1) == 1 ) {
if ( (pcxh.Manufacturer == ZSoft_Manufacturer) &&
(pcxh.Version == PC_Paintbrush_Version) &&
Oct 4, 2009
Oct 4, 2009
79
80
(pcxh.Encoding == PCX_RunLength_Encoding ||
pcxh.Encoding == PCX_Uncompressed_Encoding) ) {
Aug 10, 2000
Aug 10, 2000
81
82
83
is_PCX = 1;
}
}
Nov 8, 2009
Nov 8, 2009
84
SDL_RWseek(src, start, RW_SEEK_SET);
Aug 10, 2000
Aug 10, 2000
85
86
87
88
89
90
return(is_PCX);
}
/* Load a PCX type image from an SDL datasource */
SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src)
{
Feb 4, 2006
Feb 4, 2006
91
int start;
Aug 10, 2000
Aug 10, 2000
92
93
94
95
96
struct PCXheader pcxh;
Uint32 Rmask;
Uint32 Gmask;
Uint32 Bmask;
Uint32 Amask;
Feb 27, 2001
Feb 27, 2001
97
SDL_Surface *surface = NULL;
Aug 10, 2000
Aug 10, 2000
98
int width, height;
Feb 27, 2001
Feb 27, 2001
99
100
101
102
int y, bpl;
Uint8 *row, *buf = NULL;
char *error = NULL;
int bits, src_bits;
Jul 10, 2019
Jul 10, 2019
103
104
int count = 0;
Uint8 ch;
Aug 10, 2000
Aug 10, 2000
105
Jan 4, 2004
Jan 4, 2004
106
107
108
109
if ( !src ) {
/* The error message has been set in SDL_RWFromFile */
return NULL;
}
Feb 4, 2006
Feb 4, 2006
110
111
start = SDL_RWtell(src);
Aug 10, 2000
Aug 10, 2000
112
if ( ! SDL_RWread(src, &pcxh, sizeof(pcxh), 1) ) {
Feb 27, 2001
Feb 27, 2001
113
error = "file truncated";
Aug 10, 2000
Aug 10, 2000
114
115
116
117
118
119
120
121
goto done;
}
pcxh.Xmin = SDL_SwapLE16(pcxh.Xmin);
pcxh.Ymin = SDL_SwapLE16(pcxh.Ymin);
pcxh.Xmax = SDL_SwapLE16(pcxh.Xmax);
pcxh.Ymax = SDL_SwapLE16(pcxh.Ymax);
pcxh.BytesPerLine = SDL_SwapLE16(pcxh.BytesPerLine);
Jul 10, 2019
Jul 10, 2019
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#if 0
printf("Manufacturer = %d\n", pcxh.Manufacturer);
printf("Version = %d\n", pcxh.Version);
printf("Encoding = %d\n", pcxh.Encoding);
printf("BitsPerPixel = %d\n", pcxh.BitsPerPixel);
printf("Xmin = %d, Ymin = %d, Xmax = %d, Ymax = %d\n", pcxh.Xmin, pcxh.Ymin, pcxh.Xmax, pcxh.Ymax);
printf("HDpi = %d, VDpi = %d\n", pcxh.HDpi, pcxh.VDpi);
printf("NPlanes = %d\n", pcxh.NPlanes);
printf("BytesPerLine = %d\n", pcxh.BytesPerLine);
printf("PaletteInfo = %d\n", pcxh.PaletteInfo);
printf("HscreenSize = %d\n", pcxh.HscreenSize);
printf("VscreenSize = %d\n", pcxh.VscreenSize);
#endif
Aug 10, 2000
Aug 10, 2000
136
137
138
/* Create the surface of the appropriate type */
width = (pcxh.Xmax - pcxh.Xmin) + 1;
height = (pcxh.Ymax - pcxh.Ymin) + 1;
Feb 27, 2001
Feb 27, 2001
139
140
141
142
143
144
145
Rmask = Gmask = Bmask = Amask = 0;
src_bits = pcxh.BitsPerPixel * pcxh.NPlanes;
if((pcxh.BitsPerPixel == 1 && pcxh.NPlanes >= 1 && pcxh.NPlanes <= 4)
|| (pcxh.BitsPerPixel == 8 && pcxh.NPlanes == 1)) {
bits = 8;
} else if(pcxh.BitsPerPixel == 8 && pcxh.NPlanes == 3) {
bits = 24;
Sep 12, 2019
Sep 12, 2019
146
147
148
149
150
151
152
153
154
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
Rmask = 0x000000FF;
Gmask = 0x0000FF00;
Bmask = 0x00FF0000;
#else
Rmask = 0xFF0000;
Gmask = 0x00FF00;
Bmask = 0x0000FF;
#endif
Feb 27, 2001
Feb 27, 2001
155
156
157
} else {
error = "unsupported PCX format";
goto done;
Aug 10, 2000
Aug 10, 2000
158
159
}
surface = SDL_AllocSurface(SDL_SWSURFACE, width, height,
Feb 27, 2001
Feb 27, 2001
160
bits, Rmask, Gmask, Bmask, Amask);
Jul 10, 2019
Jul 10, 2019
161
if ( surface == NULL ) {
Aug 10, 2000
Aug 10, 2000
162
goto done;
Jul 10, 2019
Jul 10, 2019
163
}
Aug 10, 2000
Aug 10, 2000
164
Feb 27, 2001
Feb 27, 2001
165
bpl = pcxh.NPlanes * pcxh.BytesPerLine;
Jul 10, 2019
Jul 10, 2019
166
167
168
169
buf = (Uint8 *)calloc(bpl, 1);
if (!buf) {
error = "Out of memory";
goto done;
Oct 4, 2009
Oct 4, 2009
170
}
Oct 16, 2018
Oct 16, 2018
171
row = (Uint8 *)surface->pixels;
Aug 10, 2000
Aug 10, 2000
172
for ( y=0; y<surface->h; ++y ) {
Feb 27, 2001
Feb 27, 2001
173
/* decode a scan line to a temporary buffer first */
Jul 10, 2019
Jul 10, 2019
174
int i;
Oct 4, 2009
Oct 4, 2009
175
if ( pcxh.Encoding == 0 ) {
Jul 10, 2019
Jul 10, 2019
176
if(!SDL_RWread(src, buf, bpl, 1)) {
Oct 4, 2009
Oct 4, 2009
177
178
179
180
181
182
error = "file truncated";
goto done;
}
} else {
for(i = 0; i < bpl; i++) {
if(!count) {
Feb 27, 2001
Feb 27, 2001
183
184
185
186
if(!SDL_RWread(src, &ch, 1, 1)) {
error = "file truncated";
goto done;
}
Jul 10, 2019
Jul 10, 2019
187
188
189
190
if (ch < 0xc0) {
count = 1;
} else {
count = ch - 0xc0;
Oct 4, 2009
Oct 4, 2009
191
192
193
194
if(!SDL_RWread(src, &ch, 1, 1)) {
error = "file truncated";
goto done;
}
Jul 10, 2019
Jul 10, 2019
195
}
Oct 4, 2009
Oct 4, 2009
196
}
Jul 10, 2019
Jul 10, 2019
197
buf[i] = ch;
Oct 4, 2009
Oct 4, 2009
198
count--;
Feb 27, 2001
Feb 27, 2001
199
200
201
202
203
}
}
if(src_bits <= 4) {
/* expand planes to 1 byte/pixel */
Oct 16, 2018
Oct 16, 2018
204
Uint8 *innerSrc = buf;
Feb 27, 2001
Feb 27, 2001
205
206
int plane;
for(plane = 0; plane < pcxh.NPlanes; plane++) {
Oct 16, 2018
Oct 16, 2018
207
208
209
210
211
int j, k, x = 0;
for(j = 0; j < pcxh.BytesPerLine; j++) {
Uint8 byte = *innerSrc++;
for(k = 7; k >= 0; k--) {
unsigned bit = (byte >> k) & 1;
Aug 6, 2003
Aug 6, 2003
212
/* skip padding bits */
Oct 16, 2018
Oct 16, 2018
213
if (j * 8 + k >= width)
Aug 6, 2003
Aug 6, 2003
214
continue;
Feb 27, 2001
Feb 27, 2001
215
216
row[x++] |= bit << plane;
}
Aug 10, 2000
Aug 10, 2000
217
}
Feb 27, 2001
Feb 27, 2001
218
}
Jul 10, 2019
Jul 10, 2019
219
220
221
} else if(src_bits == 8) {
/* Copy the row directly */
memcpy(row, buf, SDL_min(width, bpl));
Feb 27, 2001
Feb 27, 2001
222
223
} else if(src_bits == 24) {
/* de-interlace planes */
Oct 16, 2018
Oct 16, 2018
224
Uint8 *innerSrc = buf;
Feb 27, 2001
Feb 27, 2001
225
226
227
int plane;
for(plane = 0; plane < pcxh.NPlanes; plane++) {
int x;
Jul 10, 2019
Jul 10, 2019
228
Uint8 *dst = row + plane;
Feb 27, 2001
Feb 27, 2001
229
for(x = 0; x < width; x++) {
Jul 10, 2019
Jul 10, 2019
230
231
232
233
if (dst >= row+surface->pitch) {
error = "decoding out of bounds (corrupt?)";
goto done;
}
Oct 16, 2018
Oct 16, 2018
234
*dst = *innerSrc++;
Feb 27, 2001
Feb 27, 2001
235
dst += pcxh.NPlanes;
Aug 10, 2000
Aug 10, 2000
236
237
238
239
}
}
}
Feb 27, 2001
Feb 27, 2001
240
241
row += surface->pitch;
}
Aug 10, 2000
Aug 10, 2000
242
Feb 27, 2001
Feb 27, 2001
243
if(bits == 8) {
Aug 10, 2000
Aug 10, 2000
244
SDL_Color *colors = surface->format->palette->colors;
Feb 27, 2001
Feb 27, 2001
245
246
247
248
249
250
251
252
253
int nc = 1 << src_bits;
int i;
surface->format->palette->ncolors = nc;
if(src_bits == 8) {
Uint8 ch;
/* look for a 256-colour palette */
do {
if ( !SDL_RWread(src, &ch, 1, 1)) {
Jul 10, 2019
Jul 10, 2019
254
255
256
/* Couldn't find the palette, try the end of the file */
SDL_RWseek(src, -768, RW_SEEK_END);
break;
Feb 27, 2001
Feb 27, 2001
257
258
}
} while ( ch != 12 );
Aug 10, 2000
Aug 10, 2000
259
Feb 27, 2001
Feb 27, 2001
260
261
262
263
264
265
266
267
268
269
for(i = 0; i < 256; i++) {
SDL_RWread(src, &colors[i].r, 1, 1);
SDL_RWread(src, &colors[i].g, 1, 1);
SDL_RWread(src, &colors[i].b, 1, 1);
}
} else {
for(i = 0; i < nc; i++) {
colors[i].r = pcxh.Colormap[i * 3];
colors[i].g = pcxh.Colormap[i * 3 + 1];
colors[i].b = pcxh.Colormap[i * 3 + 2];
Aug 10, 2000
Aug 10, 2000
270
271
272
273
274
}
}
}
done:
Feb 27, 2001
Feb 27, 2001
275
276
free(buf);
if ( error ) {
Nov 8, 2009
Nov 8, 2009
277
SDL_RWseek(src, start, RW_SEEK_SET);
Feb 4, 2006
Feb 4, 2006
278
279
280
281
if ( surface ) {
SDL_FreeSurface(surface);
surface = NULL;
}
Feb 27, 2001
Feb 27, 2001
282
IMG_SetError(error);
Aug 10, 2000
Aug 10, 2000
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
}
return(surface);
}
#else
/* See if an image is contained in a data source */
int IMG_isPCX(SDL_RWops *src)
{
return(0);
}
/* Load a PCX type image from an SDL datasource */
SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src)
{
return(NULL);
}
#endif /* LOAD_PCX */