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