~ubuntu-branches/ubuntu/lucid/xli/lucid

« back to all changes in this revision

Viewing changes to bmp.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Schulze
  • Date: 2005-03-18 12:46:39 UTC
  • Revision ID: james.westby@ubuntu.com-20050318124639-sbi2ud4ee08pqjer
Tags: upstream-1.17.0
ImportĀ upstreamĀ versionĀ 1.17.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Read a Microsoft/IBM BMP file.
 
3
 *
 
4
 * Created for xli by Graeme Gill,
 
5
 *
 
6
 * Based on tga.c, and guided by the Microsoft file format
 
7
 * description, and bmptoppm.c by David W. Sanderson.
 
8
 *
 
9
 */
 
10
 
 
11
#include "xli.h"
 
12
#include "imagetypes.h"
 
13
#include "bmp.h"
 
14
 
 
15
#define GULONG4(bp) ((unsigned long)(bp)[0] + 256 * (unsigned long)(bp)[1] \
 
16
        + 65536 * (unsigned long)(bp)[2] + 16777216 * (unsigned long)(bp)[3])
 
17
#define GULONG2(bp) ((unsigned long)(bp)[0] + 256 * (unsigned long)(bp)[1])
 
18
#define GUINT2(bp) ((unsigned int)(bp)[0] + 256 * (unsigned int)(bp)[1])
 
19
 
 
20
/* Read the header of the file, and */
 
21
/* Return TRUE if this looks like a bmp file */
 
22
static boolean read_bmpHeader(ZFILE * zf, bmpHeader * hp, char *name)
 
23
{
 
24
        unsigned char buf[WIN_INFOHEADER_LEN];  /* largest we'll need */
 
25
 
 
26
        if (zread(zf, buf, BMP_FILEHEADER_LEN) != BMP_FILEHEADER_LEN)
 
27
                return FALSE;
 
28
 
 
29
        if (buf[0] != 'B' || buf[1] != 'M')
 
30
                return FALSE;   /* bad magic number */
 
31
 
 
32
        hp->bfSize = GULONG4(&buf[2]);
 
33
        hp->bfxHotSpot = GUINT2(&buf[6]);
 
34
        hp->bfyHotSpot = GUINT2(&buf[8]);
 
35
        hp->bfOffBits = GULONG4(&buf[10]);
 
36
 
 
37
        /* Read enough of the file info to figure the type out */
 
38
        if (zread(zf, buf, 4) != 4)
 
39
                return FALSE;
 
40
 
 
41
        hp->biSize = GULONG4(&buf[0]);
 
42
        if (hp->biSize == WIN_INFOHEADER_LEN)
 
43
                hp->class = C_WIN;
 
44
        else if (hp->biSize == OS2_INFOHEADER_LEN)
 
45
                hp->class = C_OS2;
 
46
        else
 
47
                return FALSE;
 
48
 
 
49
        if (hp->class == C_WIN) {
 
50
                /* read in the rest of the info header */
 
51
                if (zread(zf, buf + 4, WIN_INFOHEADER_LEN - 4)
 
52
                                != WIN_INFOHEADER_LEN - 4)
 
53
                        return FALSE;
 
54
 
 
55
                hp->biWidth = GULONG4(&buf[4]);
 
56
                hp->biHeight = GULONG4(&buf[8]);
 
57
                hp->biPlanes = GUINT2(&buf[12]);;
 
58
                hp->biBitCount = GUINT2(&buf[14]);;
 
59
                hp->biCompression = GULONG4(&buf[16]);;
 
60
                hp->biSizeImage = GULONG4(&buf[20]);;
 
61
                hp->biXPelsPerMeter = GULONG4(&buf[24]);;
 
62
                hp->biYPelsPerMeter = GULONG4(&buf[28]);;
 
63
                hp->biClrUsed = GULONG4(&buf[32]);
 
64
                hp->biClrImportant = GULONG4(&buf[36]);
 
65
        } else {                /* C_OS2 */
 
66
                /* read in the rest of the info header */
 
67
                if (zread(zf, buf + 4, OS2_INFOHEADER_LEN - 4)
 
68
                                != OS2_INFOHEADER_LEN - 4)
 
69
                        return FALSE;
 
70
 
 
71
                hp->biWidth = GULONG2(&buf[4]);
 
72
                hp->biHeight = GULONG2(&buf[6]);
 
73
                hp->biPlanes = GUINT2(&buf[8]);;
 
74
                hp->biBitCount = GUINT2(&buf[10]);;
 
75
                hp->biCompression = BI_RGB;
 
76
                hp->biSizeImage = 0;
 
77
                hp->biXPelsPerMeter = 0;
 
78
                hp->biYPelsPerMeter = 0;
 
79
                hp->biClrUsed = 0;
 
80
                hp->biClrImportant = 0;
 
81
        }
 
82
 
 
83
        /* Check for file corruption */
 
84
 
 
85
        if (hp->biBitCount != 1
 
86
            && hp->biBitCount != 4
 
87
            && hp->biBitCount != 8
 
88
            && hp->biBitCount != 24) {
 
89
                fprintf(stderr, "bmpLoad: %s - Illegal image BitCount\n",
 
90
                        hp->name);
 
91
                return FALSE;
 
92
        }
 
93
        if ((hp->biCompression != BI_RGB
 
94
             && hp->biCompression != BI_RLE8
 
95
             && hp->biCompression != BI_RLE4)
 
96
            || (hp->biCompression == BI_RLE8 && hp->biBitCount != 8)
 
97
            || (hp->biCompression == BI_RLE4 && hp->biBitCount != 4)) {
 
98
                fprintf(stderr,
 
99
                        "bmpLoad: %s - Illegal image compression type\n",
 
100
                        hp->name);
 
101
                return FALSE;
 
102
        }
 
103
        if (hp->biPlanes != 1) {
 
104
                fprintf(stderr, "bmpLoad: %s - Illegal image Planes value\n",
 
105
                        hp->name);
 
106
                return FALSE;
 
107
        }
 
108
        /* Fix up a few things */
 
109
        if (hp->biBitCount < 24) {
 
110
                if (hp->biClrUsed == 0
 
111
                    || hp->biClrUsed > (1 << hp->biBitCount))
 
112
                        hp->biClrUsed = (1 << hp->biBitCount);
 
113
        } else
 
114
                hp->biClrUsed = 0;
 
115
 
 
116
        hp->name = name;
 
117
        return TRUE;
 
118
}
 
119
 
 
120
/* Print a brief description of the image */
 
121
static void tell_about_bmp(bmpHeader * hp)
 
122
{
 
123
        printf("%s is a %lux%lu %d bit deep, %s%s BMP image\n", hp->name,
 
124
                hp->biWidth, hp->biHeight, hp->biBitCount,
 
125
                hp->biCompression == BI_RGB ? "" : "Run length compressed, ",
 
126
                hp->class == C_WIN ? "Windows" : "OS/2");
 
127
}
 
128
 
 
129
int bmpIdent(char *fullname, char *name)
 
130
{
 
131
        ZFILE *zf;
 
132
        bmpHeader hdr;
 
133
 
 
134
        if (!(zf = zopen(fullname))) {
 
135
                perror("bmpIdent");
 
136
                return (0);
 
137
        }
 
138
        if (!read_bmpHeader(zf, &hdr, name)) {
 
139
                zclose(zf);
 
140
                return 0;       /* Nope, not a BMP file */
 
141
        }
 
142
        tell_about_bmp(&hdr);
 
143
        zclose(zf);
 
144
        return 1;
 
145
}
 
146
 
 
147
Image *bmpLoad(char *fullname, ImageOptions * image_ops, boolean verbose)
 
148
{
 
149
        ZFILE *zf;
 
150
        bmpHeader hdr;
 
151
        Image *image;
 
152
        boolean data_bounds = FALSE;
 
153
        int skip;
 
154
 
 
155
        if (!(zf = zopen(fullname))) {
 
156
                perror("bmpIdent");
 
157
                return (0);
 
158
        }
 
159
        if (!read_bmpHeader(zf, &hdr, image_ops->name)) {
 
160
                zclose(zf);
 
161
                return NULL;    /* Nope, not a BMP file */
 
162
        }
 
163
        if (verbose)
 
164
                tell_about_bmp(&hdr);
 
165
        znocache(zf);
 
166
 
 
167
        /* Create the appropriate image and colormap */
 
168
        if (hdr.biBitCount < 24) {
 
169
                /* must be 1, 4 or 8 bit mapped type */
 
170
                int i, n = 3;
 
171
                byte buf[4];
 
172
                /* maximum number of colors */
 
173
                int used = (1 << hdr.biBitCount);
 
174
 
 
175
                if (hdr.biBitCount == 1)        /* bitmap */
 
176
                        image = newBitImage(hdr.biWidth, hdr.biHeight);
 
177
                else
 
178
                        image = newRGBImage(hdr.biWidth, hdr.biHeight,
 
179
                                hdr.biBitCount);
 
180
                image->title = dupString(hdr.name);
 
181
 
 
182
                if (hdr.class == C_WIN)
 
183
                        n++;
 
184
                for (i = 0; i < hdr.biClrUsed; i++) {
 
185
                        if (zread(zf, buf, n) != n) {
 
186
                                fprintf(stderr, "bmpLoad: %s - Short read within Colormap\n", hdr.name);
 
187
                                freeImage(image);
 
188
                                zclose(zf);
 
189
                                return NULL;
 
190
                        }
 
191
                        image->rgb.red[i] = buf[2] << 8;
 
192
                        image->rgb.green[i] = buf[1] << 8;
 
193
                        image->rgb.blue[i] = buf[0] << 8;
 
194
                }
 
195
 
 
196
                /* init rest of colormap (if any) */
 
197
                for (; i < used; i++) {
 
198
                        image->rgb.red[i] =
 
199
                            image->rgb.green[i] =
 
200
                            image->rgb.blue[i] = 0;
 
201
                }
 
202
                /* Don't know how many colors are actually used. */
 
203
                /* (believing the header caould cause a fault) */
 
204
                /* compress() will figure it out. */
 
205
                image->rgb.used = used;         /* so use max possible */
 
206
        } else {                /* else must be a true color image */
 
207
                image = newTrueImage(hdr.biWidth, hdr.biHeight);
 
208
                image->title = dupString(hdr.name);
 
209
        }
 
210
 
 
211
        /* Skip to offset specified in file header for image data */
 
212
        if (hdr.class == C_WIN)
 
213
                skip = hdr.bfOffBits - (BMP_FILEHEADER_LEN
 
214
                        + WIN_INFOHEADER_LEN + 4 * hdr.biClrUsed);
 
215
        else
 
216
                skip = hdr.bfOffBits - (BMP_FILEHEADER_LEN
 
217
                        + OS2_INFOHEADER_LEN + 3 * hdr.biClrUsed);
 
218
 
 
219
        while (skip > 0) {
 
220
                if (zgetc(zf) == EOF)
 
221
                        goto data_short;
 
222
                skip--;
 
223
        }
 
224
 
 
225
        /* Read the pixel data */
 
226
        if (hdr.biBitCount == 1) {
 
227
                byte *data, pad[4];
 
228
                int illen, padlen, y;
 
229
 
 
230
                /* round bits up to byte */
 
231
                illen = (image->width + 7) / 8;
 
232
                /* extra bytes to word boundary */      
 
233
                padlen = (((image->width + 31) / 32) * 4) - illen;
 
234
                /* start at bottom */
 
235
                data = image->data + (image->height - 1) * illen;
 
236
                for (y = image->height; y > 0; y--, data -= illen) {
 
237
                        /* BMP files are left bit == ms bit,
 
238
                         * so read straight in.
 
239
                         */
 
240
                        if (zread(zf, data, illen) != illen
 
241
                            || zread(zf, pad, padlen) != padlen)
 
242
                                goto data_short;
 
243
                }
 
244
        } else if (hdr.biBitCount == 4) {
 
245
                byte *data;
 
246
                int illen, x, y;
 
247
 
 
248
                illen = image->width;
 
249
                /* start at bottom */
 
250
                data = image->data + (image->height - 1) * illen;
 
251
 
 
252
                if (hdr.biCompression == BI_RLE4) {
 
253
                        int d, e;
 
254
                        bzero((char *) image->data,
 
255
                                image->width * image->height);
 
256
                        for (x = y = 0;;) {
 
257
                                int i, f;
 
258
                                if ((d = zgetc(zf)) == EOF)
 
259
                                        goto data_short;
 
260
                                if (d != 0) {   /* run of pixels */
 
261
                                        x += d;
 
262
                                        if (x > image->width ||
 
263
                                                        y > image->height) {
 
264
                                                /* don't run off buffer */
 
265
                                                data_bounds = TRUE;
 
266
                                                /* ignore this run */
 
267
                                                x -= d; 
 
268
                                                if ((e = zgetc(zf)) == EOF)
 
269
                                                        goto data_short;
 
270
                                                continue;
 
271
                                        }
 
272
                                        if ((e = zgetc(zf)) == EOF)
 
273
                                                goto data_short;
 
274
                                        f = e & 0xf;
 
275
                                        e >>= 4;
 
276
                                        for (i = d / 2; i > 0; i--) {
 
277
                                                *(data++) = e;
 
278
                                                *(data++) = f;
 
279
                                        }
 
280
                                        if (d & 1)
 
281
                                                *(data++) = e;
 
282
                                        continue;
 
283
                                }
 
284
                                /* else code */
 
285
                                if ((d = zgetc(zf)) == EOF)
 
286
                                        goto data_short;
 
287
                                if (d == 0) {   /* end of line */
 
288
                                        data -= (x + illen);
 
289
                                        x = 0;
 
290
                                        y++;
 
291
                                        continue;
 
292
                                }
 
293
                                /* else */
 
294
                                if (d == 1)     /* end of bitmap */
 
295
                                        break;
 
296
                                /* else */
 
297
                                if (d == 2) {   /* delta */
 
298
                                        if ((d = zgetc(zf)) == EOF ||
 
299
                                                        (e = zgetc(zf)) == EOF)
 
300
                                                goto data_short;
 
301
                                        x += d;
 
302
                                        data += d;
 
303
                                        y += e;
 
304
                                        data -= (e * illen);
 
305
                                        continue;
 
306
                                }
 
307
                                /* else run of literals */
 
308
                                x += d;
 
309
                                if (x > image->width || y > image->height) {
 
310
                                        int btr;
 
311
                                        /* don't run off buffer */
 
312
                                        data_bounds = TRUE;
 
313
                                        x -= d;         /* ignore this run */
 
314
                                        btr = d / 2 + (d & 1)
 
315
                                                + (((d + 1) & 2) >> 1);
 
316
                                        for (; btr > 0; btr--) {
 
317
                                                if ((e = zgetc(zf)) == EOF)
 
318
                                                        goto data_short;
 
319
                                        }
 
320
                                        continue;
 
321
                                }
 
322
                                for (i = d / 2; i > 0; i--) {
 
323
                                        if ((e = zgetc(zf)) == EOF)
 
324
                                                goto data_short;
 
325
                                        *(data++) = e >> 4;
 
326
                                        *(data++) = e & 0xf;
 
327
                                }
 
328
                                if (d & 1) {
 
329
                                        if ((e = zgetc(zf)) == EOF)
 
330
                                                goto data_short;
 
331
                                        *(data++) = e >> 4;
 
332
                                }
 
333
                                if ((d + 1) & 2)        /* read pad byte */
 
334
                                        if (zgetc(zf) == EOF)
 
335
                                                goto data_short;
 
336
                        }
 
337
                } else {        /* No 4 bit rle compression */
 
338
                        int d, s, p;
 
339
                        int i, e;
 
340
                        d = image->width / 2;   /* double pixel count */
 
341
                        s = image->width & 1;   /* single pixel */
 
342
                        p = (4 - (d + s)) & 0x3;        /* byte pad */
 
343
                        for (y = image->height; y > 0; y--, data -= (2 * illen)) {
 
344
                                for (i = d; i > 0; i--) {
 
345
                                        if ((e = zgetc(zf)) == EOF)
 
346
                                                goto data_short;
 
347
                                        *(data++) = e >> 4;
 
348
                                        *(data++) = e & 0xf;
 
349
                                }
 
350
                                if (s) {
 
351
                                        if ((e = zgetc(zf)) == EOF)
 
352
                                                goto data_short;
 
353
                                        *(data++) = e >> 4;
 
354
                                }
 
355
                                for (i = p; i > 0; i--)
 
356
                                        if (zgetc(zf) == EOF)
 
357
                                                goto data_short;
 
358
                        }
 
359
                }
 
360
        } else if (hdr.biBitCount == 8) {
 
361
                byte *data;
 
362
                int illen, x, y;
 
363
 
 
364
                illen = image->width;
 
365
                /* start at bottom */
 
366
                data = image->data + (image->height - 1) * illen;
 
367
 
 
368
                if (hdr.biCompression == BI_RLE8) {
 
369
                        int d, e;
 
370
                        bzero((char *) image->data,
 
371
                                image->width * image->height);
 
372
                        for (x = y = 0;;) {
 
373
                                if ((d = zgetc(zf)) == EOF)
 
374
                                        goto data_short;
 
375
                                if (d != 0) {   /* run of pixels */
 
376
                                        x += d;
 
377
                                        if (x > image->width ||
 
378
                                                        y > image->height) {
 
379
                                                /* don't run off buffer */
 
380
                                                data_bounds = TRUE;
 
381
                                                /* ignore this run */
 
382
                                                x -= d;
 
383
                                                if ((e = zgetc(zf)) == EOF)
 
384
                                                        goto data_short;
 
385
                                                continue;
 
386
                                        }
 
387
                                        if ((e = zgetc(zf)) == EOF)
 
388
                                                goto data_short;
 
389
                                        bfill(data, d, e);
 
390
                                        data += d;
 
391
                                        continue;
 
392
                                }
 
393
                                /* else code */
 
394
                                if ((d = zgetc(zf)) == EOF)
 
395
                                        goto data_short;
 
396
                                if (d == 0) {   /* end of line */
 
397
                                        data -= (x + illen);
 
398
                                        x = 0;
 
399
                                        y++;
 
400
                                        continue;
 
401
                                }
 
402
                                /* else */
 
403
                                if (d == 1)     /* end of bitmap */
 
404
                                        break;
 
405
                                /* else */
 
406
                                if (d == 2) {   /* delta */
 
407
                                        if ((d = zgetc(zf)) == EOF ||
 
408
                                                        (e = zgetc(zf)) == EOF)
 
409
                                                goto data_short;
 
410
                                        x += d;
 
411
                                        data += d;
 
412
                                        y += e;
 
413
                                        data -= (e * illen);
 
414
                                        continue;
 
415
                                }
 
416
                                /* else run of literals */
 
417
                                x += d;
 
418
                                if (x > image->width || y > image->height) {
 
419
                                        int btr;
 
420
                                        /* don't run off buffer */
 
421
                                        data_bounds = TRUE;
 
422
                                        /* ignore this run */
 
423
                                        x -= d; 
 
424
                                        btr = d + (d & 1);
 
425
                                        for (; btr > 0; btr--) {
 
426
                                                if ((e = zgetc(zf)) == EOF)
 
427
                                                        goto data_short;
 
428
                                        }
 
429
                                        continue;
 
430
                                }
 
431
                                if (zread(zf, data, d) != d)
 
432
                                        goto data_short;
 
433
                                data += d;
 
434
                                if (d & 1)      /* read pad byte */
 
435
                                        if (zgetc(zf) == EOF)
 
436
                                                goto data_short;
 
437
                        }
 
438
                } else {        /* No 8 bit rle compression */
 
439
                        byte pad[4];
 
440
                        int padlen;
 
441
 
 
442
                        /* extra bytes to word boundary */
 
443
                        padlen = ((image->width + 3) & ~3) - illen;
 
444
                        for (y = image->height; y > 0; y--, data -= illen) {
 
445
                                if (zread(zf, data, illen) != illen
 
446
                                    || zread(zf, pad, padlen) != padlen)
 
447
                                        goto data_short;
 
448
                        }
 
449
                }
 
450
        } else {                /* hdr.biBitCount == 24 */
 
451
                byte *data, pad[4];
 
452
                int illen, padlen, y;
 
453
                illen = image->width * image->pixlen;
 
454
                /* extra bytes to word boundary */
 
455
                padlen = (((image->width * 3) + 3) & ~3) - illen;
 
456
                /* start at bottom */   
 
457
                data = image->data + (image->height - 1) * illen;       
 
458
                for (y = image->height; y > 0; y--, data -= illen) {
 
459
                        int i;
 
460
 
 
461
                        /* BMP files are RGB, so read straight in. */
 
462
                        if (zread(zf, data, illen) != illen
 
463
                            || zread(zf, pad, padlen) != padlen)
 
464
                                goto data_short;
 
465
                        /* Oh, no they're not */
 
466
                        for (i = 3 * image->width - 1; i > 0; i -= 3) {
 
467
                                int t = data[i];
 
468
                                data[i] = data[i - 2];
 
469
                                data[i - 2] = t;
 
470
                        }
 
471
                }
 
472
 
 
473
        }
 
474
        if (data_bounds)
 
475
                fprintf(stderr, "bmpLoad: %s - Data outside image area\n",
 
476
                        hdr.name);
 
477
        zclose(zf);
 
478
        return image;
 
479
 
 
480
      data_short:
 
481
        fprintf(stderr, "bmpLoad: %s - Short read within Data\n", hdr.name);
 
482
        zclose(zf);
 
483
        return image;
 
484
}