~ubuntu-branches/ubuntu/lucid/libsdl1.2/lucid-proposed

« back to all changes in this revision

Viewing changes to src/video/SDL_bmp.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthew Danish
  • Date: 2004-06-11 22:30:47 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040611223047-smb1s91z497k92o5
Tags: 1.2.7-7
* Updates from CVS:
  - joystick ioctl error checking, and "logical joystick" enhancement.
  - Don't crash if SoftStretch used on hardware surface.
  - Fix DirectFB crash on exit.
  - Free X11 mouse cursor pixmaps properly in FreeWMCursor.
  - Fix for gcc-3.4.0 / PIC; and cpuinfo detects more extensions now.
  - Don't allow video modes larger than maximum size.
  - Properly set error when OpenGL init fails.
* De-multilined Build-Depends and Uploaders field.
* Converted changelog to UTF-8.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
    SDL - Simple DirectMedia Layer
3
 
    Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  Sam Lantinga
4
 
 
5
 
    This library is free software; you can redistribute it and/or
6
 
    modify it under the terms of the GNU Library General Public
7
 
    License as published by the Free Software Foundation; either
8
 
    version 2 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
 
    Library General Public License for more details.
14
 
 
15
 
    You should have received a copy of the GNU Library General Public
16
 
    License along with this library; if not, write to the Free
17
 
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 
 
19
 
    Sam Lantinga
20
 
    slouken@libsdl.org
21
 
*/
22
 
 
23
 
#ifdef SAVE_RCSID
24
 
static char rcsid =
25
 
 "@(#) $Id: SDL_bmp.c,v 1.4 2002/03/06 11:23:03 slouken Exp $";
26
 
#endif
27
 
 
28
 
#ifndef DISABLE_FILE
29
 
 
30
 
/* 
31
 
   Code to load and save surfaces in Windows BMP format.
32
 
 
33
 
   Why support BMP format?  Well, it's a native format for Windows, and
34
 
   most image processing programs can read and write it.  It would be nice
35
 
   to be able to have at least one image format that we can natively load
36
 
   and save, and since PNG is so complex that it would bloat the library,
37
 
   BMP is a good alternative. 
38
 
 
39
 
   This code currently supports Win32 DIBs in uncompressed 8 and 24 bpp.
40
 
*/
41
 
 
42
 
#include <string.h>
43
 
 
44
 
#include "SDL_error.h"
45
 
#include "SDL_video.h"
46
 
#include "SDL_endian.h"
47
 
 
48
 
/* Compression encodings for BMP files */
49
 
#ifndef BI_RGB
50
 
#define BI_RGB          0
51
 
#define BI_RLE8         1
52
 
#define BI_RLE4         2
53
 
#define BI_BITFIELDS    3
54
 
#endif
55
 
 
56
 
 
57
 
SDL_Surface * SDL_LoadBMP_RW (SDL_RWops *src, int freesrc)
58
 
{
59
 
        int was_error;
60
 
        long fp_offset;
61
 
        int bmpPitch;
62
 
        int i, pad;
63
 
        SDL_Surface *surface;
64
 
        Uint32 Rmask;
65
 
        Uint32 Gmask;
66
 
        Uint32 Bmask;
67
 
        SDL_Palette *palette;
68
 
        Uint8 *bits;
69
 
        int ExpandBMP;
70
 
 
71
 
        /* The Win32 BMP file header (14 bytes) */
72
 
        char   magic[2];
73
 
        Uint32 bfSize;
74
 
        Uint16 bfReserved1;
75
 
        Uint16 bfReserved2;
76
 
        Uint32 bfOffBits;
77
 
 
78
 
        /* The Win32 BITMAPINFOHEADER struct (40 bytes) */
79
 
        Uint32 biSize;
80
 
        Sint32 biWidth;
81
 
        Sint32 biHeight;
82
 
        Uint16 biPlanes;
83
 
        Uint16 biBitCount;
84
 
        Uint32 biCompression;
85
 
        Uint32 biSizeImage;
86
 
        Sint32 biXPelsPerMeter;
87
 
        Sint32 biYPelsPerMeter;
88
 
        Uint32 biClrUsed;
89
 
        Uint32 biClrImportant;
90
 
 
91
 
        /* Make sure we are passed a valid data source */
92
 
        surface = NULL;
93
 
        was_error = 0;
94
 
        if ( src == NULL ) {
95
 
                was_error = 1;
96
 
                goto done;
97
 
        }
98
 
 
99
 
        /* Read in the BMP file header */
100
 
        fp_offset = SDL_RWtell(src);
101
 
        SDL_ClearError();
102
 
        if ( SDL_RWread(src, magic, 1, 2) != 2 ) {
103
 
                SDL_Error(SDL_EFREAD);
104
 
                was_error = 1;
105
 
                goto done;
106
 
        }
107
 
        if ( strncmp(magic, "BM", 2) != 0 ) {
108
 
                SDL_SetError("File is not a Windows BMP file");
109
 
                was_error = 1;
110
 
                goto done;
111
 
        }
112
 
        bfSize          = SDL_ReadLE32(src);
113
 
        bfReserved1     = SDL_ReadLE16(src);
114
 
        bfReserved2     = SDL_ReadLE16(src);
115
 
        bfOffBits       = SDL_ReadLE32(src);
116
 
 
117
 
        /* Read the Win32 BITMAPINFOHEADER */
118
 
        biSize          = SDL_ReadLE32(src);
119
 
        if ( biSize == 12 ) {
120
 
                biWidth         = (Uint32)SDL_ReadLE16(src);
121
 
                biHeight        = (Uint32)SDL_ReadLE16(src);
122
 
                biPlanes        = SDL_ReadLE16(src);
123
 
                biBitCount      = SDL_ReadLE16(src);
124
 
                biCompression   = BI_RGB;
125
 
                biSizeImage     = 0;
126
 
                biXPelsPerMeter = 0;
127
 
                biYPelsPerMeter = 0;
128
 
                biClrUsed       = 0;
129
 
                biClrImportant  = 0;
130
 
        } else {
131
 
                biWidth         = SDL_ReadLE32(src);
132
 
                biHeight        = SDL_ReadLE32(src);
133
 
                biPlanes        = SDL_ReadLE16(src);
134
 
                biBitCount      = SDL_ReadLE16(src);
135
 
                biCompression   = SDL_ReadLE32(src);
136
 
                biSizeImage     = SDL_ReadLE32(src);
137
 
                biXPelsPerMeter = SDL_ReadLE32(src);
138
 
                biYPelsPerMeter = SDL_ReadLE32(src);
139
 
                biClrUsed       = SDL_ReadLE32(src);
140
 
                biClrImportant  = SDL_ReadLE32(src);
141
 
        }
142
 
 
143
 
        /* Check for read error */
144
 
        if ( strcmp(SDL_GetError(), "") != 0 ) {
145
 
                was_error = 1;
146
 
                goto done;
147
 
        }
148
 
 
149
 
        /* Expand 1 and 4 bit bitmaps to 8 bits per pixel */
150
 
        switch (biBitCount) {
151
 
                case 1:
152
 
                case 4:
153
 
                        ExpandBMP = biBitCount;
154
 
                        biBitCount = 8;
155
 
                        break;
156
 
                default:
157
 
                        ExpandBMP = 0;
158
 
                        break;
159
 
        }
160
 
 
161
 
        /* We don't support any BMP compression right now */
162
 
        Rmask = Gmask = Bmask = 0;
163
 
        switch (biCompression) {
164
 
                case BI_RGB:
165
 
                        /* If there are no masks, use the defaults */
166
 
                        if ( bfOffBits == (14+biSize) ) {
167
 
                                /* Default values for the BMP format */
168
 
                                switch (biBitCount) {
169
 
                                        case 15:
170
 
                                        case 16:
171
 
                                                Rmask = 0x7C00;
172
 
                                                Gmask = 0x03E0;
173
 
                                                Bmask = 0x001F;
174
 
                                                break;
175
 
                                        case 24:
176
 
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
177
 
                                                Rmask = 0x000000FF;
178
 
                                                Gmask = 0x0000FF00;
179
 
                                                Bmask = 0x00FF0000;
180
 
                                                break;
181
 
#endif
182
 
                                        case 32:
183
 
                                                Rmask = 0x00FF0000;
184
 
                                                Gmask = 0x0000FF00;
185
 
                                                Bmask = 0x000000FF;
186
 
                                                break;
187
 
                                        default:
188
 
                                                break;
189
 
                                }
190
 
                                break;
191
 
                        }
192
 
                        /* Fall through -- read the RGB masks */
193
 
 
194
 
                case BI_BITFIELDS:
195
 
                        switch (biBitCount) {
196
 
                                case 15:
197
 
                                case 16:
198
 
                                case 32:
199
 
                                        Rmask = SDL_ReadLE32(src);
200
 
                                        Gmask = SDL_ReadLE32(src);
201
 
                                        Bmask = SDL_ReadLE32(src);
202
 
                                        break;
203
 
                                default:
204
 
                                        break;
205
 
                        }
206
 
                        break;
207
 
                default:
208
 
                        SDL_SetError("Compressed BMP files not supported");
209
 
                        was_error = 1;
210
 
                        goto done;
211
 
        }
212
 
 
213
 
        /* Create a compatible surface, note that the colors are RGB ordered */
214
 
        surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
215
 
                        biWidth, biHeight, biBitCount, Rmask, Gmask, Bmask, 0);
216
 
        if ( surface == NULL ) {
217
 
                was_error = 1;
218
 
                goto done;
219
 
        }
220
 
 
221
 
        /* Load the palette, if any */
222
 
        palette = (surface->format)->palette;
223
 
        if ( palette ) {
224
 
                if ( biClrUsed == 0 ) {
225
 
                        biClrUsed = 1 << biBitCount;
226
 
                }
227
 
                if ( biSize == 12 ) {
228
 
                        for ( i = 0; i < (int)biClrUsed; ++i ) {
229
 
                                SDL_RWread(src, &palette->colors[i].b, 1, 1);
230
 
                                SDL_RWread(src, &palette->colors[i].g, 1, 1);
231
 
                                SDL_RWread(src, &palette->colors[i].r, 1, 1);
232
 
                                palette->colors[i].unused = 0;
233
 
                        }       
234
 
                } else {
235
 
                        for ( i = 0; i < (int)biClrUsed; ++i ) {
236
 
                                SDL_RWread(src, &palette->colors[i].b, 1, 1);
237
 
                                SDL_RWread(src, &palette->colors[i].g, 1, 1);
238
 
                                SDL_RWread(src, &palette->colors[i].r, 1, 1);
239
 
                                SDL_RWread(src, &palette->colors[i].unused, 1, 1);
240
 
                        }       
241
 
                }
242
 
                palette->ncolors = biClrUsed;
243
 
        }
244
 
 
245
 
        /* Read the surface pixels.  Note that the bmp image is upside down */
246
 
        if ( SDL_RWseek(src, fp_offset+bfOffBits, SEEK_SET) < 0 ) {
247
 
                SDL_Error(SDL_EFSEEK);
248
 
                was_error = 1;
249
 
                goto done;
250
 
        }
251
 
        bits = (Uint8 *)surface->pixels+(surface->h*surface->pitch);
252
 
        switch (ExpandBMP) {
253
 
                case 1:
254
 
                        bmpPitch = (biWidth + 7) >> 3;
255
 
                        pad  = (((bmpPitch)%4) ? (4-((bmpPitch)%4)) : 0);
256
 
                        break;
257
 
                case 4:
258
 
                        bmpPitch = (biWidth + 1) >> 1;
259
 
                        pad  = (((bmpPitch)%4) ? (4-((bmpPitch)%4)) : 0);
260
 
                        break;
261
 
                default:
262
 
                        pad  = ((surface->pitch%4) ?
263
 
                                        (4-(surface->pitch%4)) : 0);
264
 
                        break;
265
 
        }
266
 
        while ( bits > (Uint8 *)surface->pixels ) {
267
 
                bits -= surface->pitch;
268
 
                switch (ExpandBMP) {
269
 
                        case 1:
270
 
                        case 4: {
271
 
                        Uint8 pixel = 0;
272
 
                        int   shift = (8-ExpandBMP);
273
 
                        for ( i=0; i<surface->w; ++i ) {
274
 
                                if ( i%(8/ExpandBMP) == 0 ) {
275
 
                                        if ( !SDL_RWread(src, &pixel, 1, 1) ) {
276
 
                                                SDL_SetError(
277
 
                                        "Error reading from BMP");
278
 
                                                was_error = 1;
279
 
                                                goto done;
280
 
                                        }
281
 
                                }
282
 
                                *(bits+i) = (pixel>>shift);
283
 
                                pixel <<= ExpandBMP;
284
 
                        } }
285
 
                        break;
286
 
 
287
 
                        default:
288
 
                        if ( SDL_RWread(src, bits, 1, surface->pitch)
289
 
                                                         != surface->pitch ) {
290
 
                                SDL_Error(SDL_EFREAD);
291
 
                                was_error = 1;
292
 
                                goto done;
293
 
                        }
294
 
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
295
 
                        /* Byte-swap the pixels if needed. Note that the 24bpp
296
 
                           case has already been taken care of above. */
297
 
                        switch(biBitCount) {
298
 
                                case 15:
299
 
                                case 16: {
300
 
                                        Uint16 *pix = (Uint16 *)bits;
301
 
                                        for(i = 0; i < surface->w; i++)
302
 
                                                pix[i] = SDL_Swap16(pix[i]);
303
 
                                        break;
304
 
                                }
305
 
 
306
 
                                case 32: {
307
 
                                        Uint32 *pix = (Uint32 *)bits;
308
 
                                        for(i = 0; i < surface->w; i++)
309
 
                                                pix[i] = SDL_Swap32(pix[i]);
310
 
                                        break;
311
 
                                }
312
 
                        }
313
 
#endif
314
 
                        break;
315
 
                }
316
 
                /* Skip padding bytes, ugh */
317
 
                if ( pad ) {
318
 
                        Uint8 padbyte;
319
 
                        for ( i=0; i<pad; ++i ) {
320
 
                                SDL_RWread(src, &padbyte, 1, 1);
321
 
                        }
322
 
                }
323
 
        }
324
 
done:
325
 
        if ( was_error ) {
326
 
                if ( surface ) {
327
 
                        SDL_FreeSurface(surface);
328
 
                }
329
 
                surface = NULL;
330
 
        }
331
 
        if ( freesrc && src ) {
332
 
                SDL_RWclose(src);
333
 
        }
334
 
        return(surface);
335
 
}
336
 
 
337
 
int SDL_SaveBMP_RW (SDL_Surface *saveme, SDL_RWops *dst, int freedst)
338
 
{
339
 
        long fp_offset;
340
 
        int i, pad;
341
 
        SDL_Surface *surface;
342
 
        Uint8 *bits;
343
 
 
344
 
        /* The Win32 BMP file header (14 bytes) */
345
 
        char   magic[2] = { 'B', 'M' };
346
 
        Uint32 bfSize;
347
 
        Uint16 bfReserved1;
348
 
        Uint16 bfReserved2;
349
 
        Uint32 bfOffBits;
350
 
 
351
 
        /* The Win32 BITMAPINFOHEADER struct (40 bytes) */
352
 
        Uint32 biSize;
353
 
        Sint32 biWidth;
354
 
        Sint32 biHeight;
355
 
        Uint16 biPlanes;
356
 
        Uint16 biBitCount;
357
 
        Uint32 biCompression;
358
 
        Uint32 biSizeImage;
359
 
        Sint32 biXPelsPerMeter;
360
 
        Sint32 biYPelsPerMeter;
361
 
        Uint32 biClrUsed;
362
 
        Uint32 biClrImportant;
363
 
 
364
 
        /* Make sure we have somewhere to save */
365
 
        surface = NULL;
366
 
        if ( dst ) {
367
 
                if ( saveme->format->palette ) {
368
 
                        if ( saveme->format->BitsPerPixel == 8 ) {
369
 
                                surface = saveme;
370
 
                        } else {
371
 
                                SDL_SetError("%d bpp BMP files not supported",
372
 
                                                saveme->format->BitsPerPixel);
373
 
                        }
374
 
                }
375
 
                else if ( (saveme->format->BitsPerPixel == 24) &&
376
 
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
377
 
                                (saveme->format->Rmask == 0x00FF0000) &&
378
 
                                (saveme->format->Gmask == 0x0000FF00) &&
379
 
                                (saveme->format->Bmask == 0x000000FF)
380
 
#else
381
 
                                (saveme->format->Rmask == 0x000000FF) &&
382
 
                                (saveme->format->Gmask == 0x0000FF00) &&
383
 
                                (saveme->format->Bmask == 0x00FF0000)
384
 
#endif
385
 
                          ) {
386
 
                        surface = saveme;
387
 
                } else {
388
 
                        SDL_Rect bounds;
389
 
 
390
 
                        /* Convert to 24 bits per pixel */
391
 
                        surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
392
 
                                        saveme->w, saveme->h, 24,
393
 
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
394
 
                                        0x00FF0000, 0x0000FF00, 0x000000FF,
395
 
#else
396
 
                                        0x000000FF, 0x0000FF00, 0x00FF0000,
397
 
#endif
398
 
                                        0);
399
 
                        if ( surface != NULL ) {
400
 
                                bounds.x = 0;
401
 
                                bounds.y = 0;
402
 
                                bounds.w = saveme->w;
403
 
                                bounds.h = saveme->h;
404
 
                                if ( SDL_LowerBlit(saveme, &bounds, surface,
405
 
                                                        &bounds) < 0 ) {
406
 
                                        SDL_FreeSurface(surface);
407
 
                                        SDL_SetError(
408
 
                                        "Couldn't convert image to 24 bpp");
409
 
                                        surface = NULL;
410
 
                                }
411
 
                        }
412
 
                }
413
 
        }
414
 
 
415
 
        if ( surface && (SDL_LockSurface(surface) == 0) ) {
416
 
                /* Set the BMP file header values */
417
 
                bfSize = 0;              /* We'll write this when we're done */
418
 
                bfReserved1 = 0;
419
 
                bfReserved2 = 0;
420
 
                bfOffBits = 0;          /* We'll write this when we're done */
421
 
 
422
 
                /* Write the BMP file header values */
423
 
                fp_offset = SDL_RWtell(dst);
424
 
                SDL_ClearError();
425
 
                SDL_RWwrite(dst, magic, 2, 1);
426
 
                SDL_WriteLE32(dst, bfSize);
427
 
                SDL_WriteLE16(dst, bfReserved1);
428
 
                SDL_WriteLE16(dst, bfReserved2);
429
 
                SDL_WriteLE32(dst, bfOffBits);
430
 
 
431
 
                /* Set the BMP info values */
432
 
                biSize = 40;
433
 
                biWidth = surface->w;
434
 
                biHeight = surface->h;
435
 
                biPlanes = 1;
436
 
                biBitCount = surface->format->BitsPerPixel;
437
 
                biCompression = BI_RGB;
438
 
                biSizeImage = surface->h*surface->pitch;
439
 
                biXPelsPerMeter = 0;
440
 
                biYPelsPerMeter = 0;
441
 
                if ( surface->format->palette ) {
442
 
                        biClrUsed = surface->format->palette->ncolors;
443
 
                } else {
444
 
                        biClrUsed = 0;
445
 
                }
446
 
                biClrImportant = 0;
447
 
 
448
 
                /* Write the BMP info values */
449
 
                SDL_WriteLE32(dst, biSize);
450
 
                SDL_WriteLE32(dst, biWidth);
451
 
                SDL_WriteLE32(dst, biHeight);
452
 
                SDL_WriteLE16(dst, biPlanes);
453
 
                SDL_WriteLE16(dst, biBitCount);
454
 
                SDL_WriteLE32(dst, biCompression);
455
 
                SDL_WriteLE32(dst, biSizeImage);
456
 
                SDL_WriteLE32(dst, biXPelsPerMeter);
457
 
                SDL_WriteLE32(dst, biYPelsPerMeter);
458
 
                SDL_WriteLE32(dst, biClrUsed);
459
 
                SDL_WriteLE32(dst, biClrImportant);
460
 
 
461
 
                /* Write the palette (in BGR color order) */
462
 
                if ( surface->format->palette ) {
463
 
                        SDL_Color *colors;
464
 
                        int       ncolors;
465
 
 
466
 
                        colors = surface->format->palette->colors;
467
 
                        ncolors = surface->format->palette->ncolors;
468
 
                        for ( i=0; i<ncolors; ++i ) {
469
 
                                SDL_RWwrite(dst, &colors[i].b, 1, 1);
470
 
                                SDL_RWwrite(dst, &colors[i].g, 1, 1);
471
 
                                SDL_RWwrite(dst, &colors[i].r, 1, 1);
472
 
                                SDL_RWwrite(dst, &colors[i].unused, 1, 1);
473
 
                        }
474
 
                }
475
 
 
476
 
                /* Write the bitmap offset */
477
 
                bfOffBits = SDL_RWtell(dst)-fp_offset;
478
 
                if ( SDL_RWseek(dst, fp_offset+10, SEEK_SET) < 0 ) {
479
 
                        SDL_Error(SDL_EFSEEK);
480
 
                }
481
 
                SDL_WriteLE32(dst, bfOffBits);
482
 
                if ( SDL_RWseek(dst, fp_offset+bfOffBits, SEEK_SET) < 0 ) {
483
 
                        SDL_Error(SDL_EFSEEK);
484
 
                }
485
 
 
486
 
                /* Write the bitmap image upside down */
487
 
                bits = (Uint8 *)surface->pixels+(surface->h*surface->pitch);
488
 
                pad  = ((surface->pitch%4) ? (4-(surface->pitch%4)) : 0);
489
 
                while ( bits > (Uint8 *)surface->pixels ) {
490
 
                        bits -= surface->pitch;
491
 
                        if ( SDL_RWwrite(dst, bits, 1, surface->pitch)
492
 
                                                        != surface->pitch) {
493
 
                                SDL_Error(SDL_EFWRITE);
494
 
                                break;
495
 
                        }
496
 
                        if ( pad ) {
497
 
                                const Uint8 padbyte = 0;
498
 
                                for ( i=0; i<pad; ++i ) {
499
 
                                        SDL_RWwrite(dst, &padbyte, 1, 1);
500
 
                                }
501
 
                        }
502
 
                }
503
 
 
504
 
                /* Write the BMP file size */
505
 
                bfSize = SDL_RWtell(dst)-fp_offset;
506
 
                if ( SDL_RWseek(dst, fp_offset+2, SEEK_SET) < 0 ) {
507
 
                        SDL_Error(SDL_EFSEEK);
508
 
                }
509
 
                SDL_WriteLE32(dst, bfSize);
510
 
                if ( SDL_RWseek(dst, fp_offset+bfSize, SEEK_SET) < 0 ) {
511
 
                        SDL_Error(SDL_EFSEEK);
512
 
                }
513
 
 
514
 
                /* Close it up.. */
515
 
                SDL_UnlockSurface(surface);
516
 
                if ( surface != saveme ) {
517
 
                        SDL_FreeSurface(surface);
518
 
                }
519
 
        }
520
 
 
521
 
        if ( freedst && dst ) {
522
 
                SDL_RWclose(dst);
523
 
        }
524
 
        return((strcmp(SDL_GetError(), "") == 0) ? 0 : -1);
525
 
}
526
 
 
527
 
#endif /* ENABLE_FILE */