1 #include "allegro5/allegro.h"
2 #include "allegro5/allegro_image.h"
3 #include "allegro5/internal/aintern_image.h"
4 
5 #include "iio.h"
6 
7 ALLEGRO_DEBUG_CHANNEL("image")
8 
9 /* Do NOT simplify this to just (x), it doesn't work in MSVC. */
10 #define INT_TO_BOOL(x)   ((x) != 0)
11 
_al_load_pcx_f(ALLEGRO_FILE * f,int flags)12 ALLEGRO_BITMAP *_al_load_pcx_f(ALLEGRO_FILE *f, int flags)
13 {
14    ALLEGRO_BITMAP *b;
15    int c;
16    int width, height;
17    int bpp, bytes_per_line;
18    int x, xx, y;
19    char ch;
20    ALLEGRO_LOCKED_REGION *lr;
21    unsigned char *buf;
22    PalEntry pal[256];
23    bool keep_index;
24    ASSERT(f);
25 
26    al_fgetc(f);                    /* skip manufacturer ID */
27    al_fgetc(f);                    /* skip version flag */
28    al_fgetc(f);                    /* skip encoding flag */
29 
30    char color_plane = al_fgetc(f);
31    if (color_plane != 8) {         /* we like 8 bit color planes */
32       ALLEGRO_ERROR("Invalid color plane %d.\n", color_plane);
33       return NULL;
34    }
35 
36    width = -(al_fread16le(f));        /* xmin */
37    height = -(al_fread16le(f));       /* ymin */
38    width += al_fread16le(f) + 1;      /* xmax */
39    height += al_fread16le(f) + 1;     /* ymax */
40 
41    al_fread32le(f);		   /* skip DPI values */
42 
43    for (c = 0; c < 16 * 3; c++) {          /* skip the 16 color palette */
44       al_fgetc(f);
45    }
46 
47    al_fgetc(f);
48 
49    bpp = al_fgetc(f) * 8;          /* how many color planes? */
50 
51    if ((bpp != 8) && (bpp != 24)) {
52       ALLEGRO_ERROR("Invalid bpp %d.\n", color_plane);
53       return NULL;
54    }
55 
56    bytes_per_line = al_fread16le(f);
57 
58    for (c = 0; c < 60; c++)                /* skip some more junk */
59       al_fgetc(f);
60 
61    if (al_feof(f) || al_ferror(f)) {
62       ALLEGRO_ERROR("Unexpected EOF/error.\n");
63       return NULL;
64    }
65 
66    b = al_create_bitmap(width, height);
67    if (!b) {
68       ALLEGRO_ERROR("Failed to create bitmap.\n");
69       return NULL;
70    }
71 
72    keep_index = INT_TO_BOOL(flags & ALLEGRO_KEEP_INDEX);
73 
74    al_set_errno(0);
75 
76    if (bpp == 8) {
77       /* The palette comes after the image data.  We need to to keep the
78        * whole image in a temporary buffer before mapping the final colours.
79        */
80       buf = (unsigned char *)al_malloc(bytes_per_line * height);
81    }
82    else {
83       /* We can read one line at a time. */
84       buf = (unsigned char *)al_malloc(bytes_per_line * 3);
85    }
86 
87    if (bpp == 8 && keep_index) {
88       lr = al_lock_bitmap(b, ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8, ALLEGRO_LOCK_WRITEONLY);
89    }
90    else {
91       lr = al_lock_bitmap(b, ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, ALLEGRO_LOCK_WRITEONLY);
92    }
93    if (!lr) {
94       ALLEGRO_ERROR("Failed to lock bitmap.\n");
95       al_free(buf);
96       return NULL;
97    }
98 
99    xx = 0;                      /* index into buf, only for bpp = 8 */
100 
101    for (y = 0; y < height; y++) {       /* read RLE encoded PCX data */
102 
103       x = 0;
104 
105       while (x < bytes_per_line * bpp / 8) {
106          ch = al_fgetc(f);
107          if ((ch & 0xC0) == 0xC0) { /* a run */
108             c = (ch & 0x3F);
109             ch = al_fgetc(f);
110          }
111          else {
112             c = 1;                  /* single pixel */
113          }
114 
115          if (bpp == 8) {
116             while (c--) {
117                if (x < width)       /* ignore padding */
118                   buf[xx++] = ch;
119                x++;
120             }
121          }
122          else {
123             while (c--) {
124                if (x < width * 3)   /* ignore padding */
125                   buf[x] = ch;
126                x++;
127             }
128          }
129       }
130       if (bpp == 24) {
131          char *dest = (char*)lr->data + y*lr->pitch;
132          for (x = 0; x < width; x++) {
133             dest[x*4    ] = buf[x];
134             dest[x*4 + 1] = buf[x + width];
135             dest[x*4 + 2] = buf[x + width * 2];
136             dest[x*4 + 3] = 255;
137          }
138       }
139    }
140 
141    if (bpp == 8) {               /* look for a 256 color palette */
142       while ((c = al_fgetc(f)) != EOF) {
143          if (c == 12) {
144             for (c = 0; c < 256; c++) {
145                pal[c].r = al_fgetc(f);
146                pal[c].g = al_fgetc(f);
147                pal[c].b = al_fgetc(f);
148             }
149             break;
150          }
151       }
152       for (y = 0; y < height; y++) {
153          char *dest = (char*)lr->data + y*lr->pitch;
154          for (x = 0; x < width; x++) {
155             int index = buf[y * width + x];
156             if (keep_index) {
157                dest[x] = index;
158             }
159             else {
160                dest[x*4    ] = pal[index].r;
161                dest[x*4 + 1] = pal[index].g;
162                dest[x*4 + 2] = pal[index].b;
163                dest[x*4 + 3] = 255;
164             }
165          }
166       }
167    }
168 
169    al_unlock_bitmap(b);
170 
171    al_free(buf);
172 
173    if (al_get_errno()) {
174       ALLEGRO_ERROR("Error detected: %d.\n", al_get_errno());
175       al_destroy_bitmap(b);
176       return NULL;
177    }
178 
179    return b;
180 }
181 
_al_save_pcx_f(ALLEGRO_FILE * f,ALLEGRO_BITMAP * bmp)182 bool _al_save_pcx_f(ALLEGRO_FILE *f, ALLEGRO_BITMAP *bmp)
183 {
184    int c;
185    int x, y;
186    int i;
187    int w, h;
188    unsigned char *buf;
189    ASSERT(f);
190    ASSERT(bmp);
191 
192    al_set_errno(0);
193 
194    w = al_get_bitmap_width(bmp);
195    h = al_get_bitmap_height(bmp);
196 
197    al_fputc(f, 10);     /* manufacturer */
198    al_fputc(f, 5);      /* version */
199    al_fputc(f, 1);      /* run length encoding  */
200    al_fputc(f, 8);      /* 8 bits per pixel */
201    al_fwrite16le(f, 0);     /* xmin */
202    al_fwrite16le(f, 0);     /* ymin */
203    al_fwrite16le(f, w - 1); /* xmax */
204    al_fwrite16le(f, h - 1); /* ymax */
205    al_fwrite16le(f, 320);   /* HDpi */
206    al_fwrite16le(f, 200);   /* VDpi */
207 
208    for (c = 0; c < 16 * 3; c++) {
209       al_fputc(f, 0);
210    }
211 
212    al_fputc(f, 0);      /* reserved */
213    al_fputc(f, 3);      /* color planes */
214    al_fwrite16le(f, w);     /* number of bytes per scanline */
215    al_fwrite16le(f, 1);     /* color palette */
216    al_fwrite16le(f, w);     /* hscreen size */
217    al_fwrite16le(f, h);     /* vscreen size */
218    for (c = 0; c < 54; c++)     /* filler */
219       al_fputc(f, 0);
220 
221    buf = al_malloc(w * 3);
222 
223    al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY);
224 
225    for (y = 0; y < h; y++) {    /* for each scanline... */
226       for (x = 0; x < w; x++) {
227          ALLEGRO_COLOR c = al_get_pixel(bmp, x, y);
228          unsigned char r, g, b;
229          al_unmap_rgb(c, &r, &g, &b);
230          buf[x] = r;
231          buf[x + w] = g;
232          buf[x + w * 2] = b;
233       }
234 
235       for (i = 0; i < 3; i++) {
236          int color;
237          int count;
238          x = 0;
239          for (;;) {
240             count = 0;
241             color = buf[x + w * i];
242             do {
243                count++;
244                x++;
245             } while ((count < 63) && (x < w) && (color == buf[x + w * i]));
246             al_fputc(f, count | 0xC0);
247             al_fputc(f, color);
248             if (x >= w)
249                break;
250          }
251       }
252    }
253 
254    al_free(buf);
255 
256    al_unlock_bitmap(bmp);
257 
258    if (al_get_errno()) {
259       ALLEGRO_ERROR("Error detected: %d.\n", al_get_errno());
260       return false;
261    }
262    else
263       return true;
264 }
265 
_al_load_pcx(const char * filename,int flags)266 ALLEGRO_BITMAP *_al_load_pcx(const char *filename, int flags)
267 {
268    ALLEGRO_FILE *f;
269    ALLEGRO_BITMAP *bmp;
270    ASSERT(filename);
271 
272    f = al_fopen(filename, "rb");
273    if (!f) {
274       ALLEGRO_ERROR("Unable to open %s for reading.\n", filename);
275       return NULL;
276    }
277 
278    bmp = _al_load_pcx_f(f, flags);
279 
280    al_fclose(f);
281 
282    return bmp;
283 }
284 
_al_save_pcx(const char * filename,ALLEGRO_BITMAP * bmp)285 bool _al_save_pcx(const char *filename, ALLEGRO_BITMAP *bmp)
286 {
287    ALLEGRO_FILE *f;
288    bool retsave;
289    bool retclose;
290    ASSERT(filename);
291 
292    f = al_fopen(filename, "wb");
293    if (!f) {
294       ALLEGRO_ERROR("Unable to open %s for writing.\n", filename);
295       return false;
296    }
297 
298    retsave = _al_save_pcx_f(f, bmp);
299 
300    retclose = al_fclose(f);
301 
302    return retsave && retclose;
303 }
304 
_al_identify_pcx(ALLEGRO_FILE * f)305 bool _al_identify_pcx(ALLEGRO_FILE *f)
306 {
307    uint8_t x[4];
308    al_fread(f, x, 4);
309 
310    if (x[0] != 0x0a) // PCX must start with 0x0a
311       return false;
312    if (x[1] == 1 || x[1] > 5) // version must be 0, 2, 3, 4, 5
313       return false;
314    if (x[2] > 1) // compression must be 0 or 1
315       return false;
316    if (x[3] != 8) // only 8-bit PCX files supported by Allegro!
317       return false;
318    return true;
319 }
320 
321 
322 /* vim: set sts=3 sw=3 et: */
323