]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/libsdl-image/contrib/IMG_pcx.c
3a4cb1885429b57112fee385b96fd485266f5e63
[l4.git] / l4 / pkg / libsdl-image / contrib / IMG_pcx.c
1 /*
2     SDL_image:  An example image loading library for use with SDL
3     Copyright (C) 1997-2009 Sam Lantinga
4
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 of the License, or (at your option) any later version.
9
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     Lesser General Public License for more details.
14
15     You should have received a copy of the GNU Lesser General Public
16     License along with this library; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19     Sam Lantinga
20     slouken@libsdl.org
21 */
22
23 /*
24  * PCX file reader:
25  * Supports:
26  *  1..4 bits/pixel in multiplanar format (1 bit/plane/pixel)
27  *  8 bits/pixel in single-planar format (8 bits/plane/pixel)
28  *  24 bits/pixel in 3-plane format (8 bits/plane/pixel)
29  *
30  * (The <8bpp formats are expanded to 8bpp surfaces)
31  *
32  * Doesn't support:
33  *  single-planar packed-pixel formats other than 8bpp
34  *  4-plane 32bpp format with a fourth "intensity" plane
35  */
36 #include <stdio.h>
37 #include <stdlib.h>
38
39 #include "SDL_endian.h"
40
41 #include "SDL_image.h"
42
43 #ifdef LOAD_PCX
44
45 struct PCXheader {
46         Uint8 Manufacturer;
47         Uint8 Version;
48         Uint8 Encoding;
49         Uint8 BitsPerPixel;
50         Sint16 Xmin, Ymin, Xmax, Ymax;
51         Sint16 HDpi, VDpi;
52         Uint8 Colormap[48];
53         Uint8 Reserved;
54         Uint8 NPlanes;
55         Sint16 BytesPerLine;
56         Sint16 PaletteInfo;
57         Sint16 HscreenSize;
58         Sint16 VscreenSize;
59         Uint8 Filler[54];
60 };
61
62 /* See if an image is contained in a data source */
63 int IMG_isPCX(SDL_RWops *src)
64 {
65         int start;
66         int is_PCX;
67         const int ZSoft_Manufacturer = 10;
68         const int PC_Paintbrush_Version = 5;
69         const int PCX_Uncompressed_Encoding = 0;
70         const int PCX_RunLength_Encoding = 1;
71         struct PCXheader pcxh;
72
73         if ( !src )
74                 return 0;
75         start = SDL_RWtell(src);
76         is_PCX = 0;
77         if ( SDL_RWread(src, &pcxh, sizeof(pcxh), 1) == 1 ) {
78                 if ( (pcxh.Manufacturer == ZSoft_Manufacturer) &&
79                      (pcxh.Version == PC_Paintbrush_Version) &&
80                      (pcxh.Encoding == PCX_RunLength_Encoding ||
81                       pcxh.Encoding == PCX_Uncompressed_Encoding) ) {
82                         is_PCX = 1;
83                 }
84         }
85         SDL_RWseek(src, start, SEEK_SET);
86         return(is_PCX);
87 }
88
89 /* Load a PCX type image from an SDL datasource */
90 SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src)
91 {
92         int start;
93         struct PCXheader pcxh;
94         Uint32 Rmask;
95         Uint32 Gmask;
96         Uint32 Bmask;
97         Uint32 Amask;
98         SDL_Surface *surface = NULL;
99         int width, height;
100         int y, bpl;
101         Uint8 *row, *buf = NULL;
102         char *error = NULL;
103         int bits, src_bits;
104
105         if ( !src ) {
106                 /* The error message has been set in SDL_RWFromFile */
107                 return NULL;
108         }
109         start = SDL_RWtell(src);
110
111         if ( ! SDL_RWread(src, &pcxh, sizeof(pcxh), 1) ) {
112                 error = "file truncated";
113                 goto done;
114         }
115         pcxh.Xmin = SDL_SwapLE16(pcxh.Xmin);
116         pcxh.Ymin = SDL_SwapLE16(pcxh.Ymin);
117         pcxh.Xmax = SDL_SwapLE16(pcxh.Xmax);
118         pcxh.Ymax = SDL_SwapLE16(pcxh.Ymax);
119         pcxh.BytesPerLine = SDL_SwapLE16(pcxh.BytesPerLine);
120
121         /* Create the surface of the appropriate type */
122         width = (pcxh.Xmax - pcxh.Xmin) + 1;
123         height = (pcxh.Ymax - pcxh.Ymin) + 1;
124         Rmask = Gmask = Bmask = Amask = 0;
125         src_bits = pcxh.BitsPerPixel * pcxh.NPlanes;
126         if((pcxh.BitsPerPixel == 1 && pcxh.NPlanes >= 1 && pcxh.NPlanes <= 4)
127            || (pcxh.BitsPerPixel == 8 && pcxh.NPlanes == 1)) {
128                 bits = 8;
129         } else if(pcxh.BitsPerPixel == 8 && pcxh.NPlanes == 3) {
130                 bits = 24;
131                 if ( SDL_BYTEORDER == SDL_LIL_ENDIAN ) {
132                         Rmask = 0x000000FF;
133                         Gmask = 0x0000FF00;
134                         Bmask = 0x00FF0000;
135                 } else {
136                         Rmask = 0xFF0000;
137                         Gmask = 0x00FF00;
138                         Bmask = 0x0000FF;
139                 }
140         } else {
141                 error = "unsupported PCX format";
142                 goto done;
143         }
144         surface = SDL_AllocSurface(SDL_SWSURFACE, width, height,
145                                    bits, Rmask, Gmask, Bmask, Amask);
146         if ( surface == NULL )
147                 goto done;
148
149         bpl = pcxh.NPlanes * pcxh.BytesPerLine;
150         if (bpl > surface->pitch) {
151                 error = "bytes per line is too large (corrupt?)";
152         }
153         buf = malloc(bpl);
154         row = surface->pixels;
155         for ( y=0; y<surface->h; ++y ) {
156                 /* decode a scan line to a temporary buffer first */
157                 int i, count = 0;
158                 Uint8 ch;
159                 Uint8 *dst = (src_bits == 8) ? row : buf;
160                 if ( pcxh.Encoding == 0 ) {
161                         if(!SDL_RWread(src, dst, bpl, 1)) {
162                                 error = "file truncated";
163                                 goto done;
164                         }
165                 } else {
166                         for(i = 0; i < bpl; i++) {
167                                 if(!count) {
168                                         if(!SDL_RWread(src, &ch, 1, 1)) {
169                                                 error = "file truncated";
170                                                 goto done;
171                                         }
172                                         if( (ch & 0xc0) == 0xc0) {
173                                                 count = ch & 0x3f;
174                                                 if(!SDL_RWread(src, &ch, 1, 1)) {
175                                                         error = "file truncated";
176                                                         goto done;
177                                                 }
178                                         } else
179                                                 count = 1;
180                                 }
181                                 dst[i] = ch;
182                                 count--;
183                         }
184                 }
185
186                 if(src_bits <= 4) {
187                         /* expand planes to 1 byte/pixel */
188                         Uint8 *src = buf;
189                         int plane;
190                         for(plane = 0; plane < pcxh.NPlanes; plane++) {
191                                 int i, j, x = 0;
192                                 for(i = 0; i < pcxh.BytesPerLine; i++) {
193                                         Uint8 byte = *src++;
194                                         for(j = 7; j >= 0; j--) {
195                                                 unsigned bit = (byte >> j) & 1;
196                                                 /* skip padding bits */
197                                                 if (i * 8 + j >= width)
198                                                         continue;
199                                                 row[x++] |= bit << plane;
200                                         }
201                                 }
202                         }
203                 } else if(src_bits == 24) {
204                         /* de-interlace planes */
205                         Uint8 *src = buf;
206                         int plane;
207                         for(plane = 0; plane < pcxh.NPlanes; plane++) {
208                                 int x;
209                                 dst = row + plane;
210                                 for(x = 0; x < width; x++) {
211                                         *dst = *src++;
212                                         dst += pcxh.NPlanes;
213                                 }
214                         }
215                 }
216
217                 row += surface->pitch;
218         }
219
220         if(bits == 8) {
221                 SDL_Color *colors = surface->format->palette->colors;
222                 int nc = 1 << src_bits;
223                 int i;
224
225                 surface->format->palette->ncolors = nc;
226                 if(src_bits == 8) {
227                         Uint8 ch;
228                         /* look for a 256-colour palette */
229                         do {
230                                 if ( !SDL_RWread(src, &ch, 1, 1)) {
231                                         error = "file truncated";
232                                         goto done;
233                                 }
234                         } while ( ch != 12 );
235
236                         for(i = 0; i < 256; i++) {
237                                 SDL_RWread(src, &colors[i].r, 1, 1);
238                                 SDL_RWread(src, &colors[i].g, 1, 1);
239                                 SDL_RWread(src, &colors[i].b, 1, 1);
240                         }
241                 } else {
242                         for(i = 0; i < nc; i++) {
243                                 colors[i].r = pcxh.Colormap[i * 3];
244                                 colors[i].g = pcxh.Colormap[i * 3 + 1];
245                                 colors[i].b = pcxh.Colormap[i * 3 + 2];
246                         }
247                 }
248         }
249
250 done:
251         free(buf);
252         if ( error ) {
253                 SDL_RWseek(src, start, SEEK_SET);
254                 if ( surface ) {
255                         SDL_FreeSurface(surface);
256                         surface = NULL;
257                 }
258                 IMG_SetError(error);
259         }
260         return(surface);
261 }
262
263 #else
264
265 /* See if an image is contained in a data source */
266 int IMG_isPCX(SDL_RWops *src)
267 {
268         return(0);
269 }
270
271 /* Load a PCX type image from an SDL datasource */
272 SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src)
273 {
274         return(NULL);
275 }
276
277 #endif /* LOAD_PCX */