Initial revision
[blender.git] / source / blender / imbuf / intern / bmp_decode.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #ifdef _WIN32
34 #include "BLI_winstuff.h"
35 #endif
36 #include "BLI_blenlib.h"
37
38 #include "imbuf.h"
39 #include "imbuf_patch.h"
40
41 #include "IMB_imbuf_types.h"
42 #include "IMB_imbuf.h"
43
44 #include "IMB_allocimbuf.h"
45 #include "IMB_cmap.h"
46 #include "IMB_bmp.h"
47
48
49 // some code copied from article on microsoft.com, copied
50 // here for enhanced BMP support in the future
51 // http://www.microsoft.com/msj/defaultframe.asp?page=/msj/0197/mfcp1/mfcp1.htm&nav=/msj/0197/newnav.htm
52
53 /*
54 LPBYTE CDib::GetBits()
55  {
56    return (LPBYTE)m_pbmih + // start of bitmap +
57      m_pbmih->biSize +      // size of header +
58      GetNumPaletteColors()  // (num colors *
59        *sizeof(RGBQUAD);    // size each entry)
60  }
61
62 UINT CDib::GetNumPaletteColors()
63  {
64     UINT nColors=m_pbmih->biClrUsed;
65     if (nColors==0 && m_pbmih->biBitCount<=8)
66        nColors = 1<<m_pbmih->biBitCount;
67     return nColors;
68  }
69
70 */
71
72 typedef struct BMPINFOHEADER{
73         unsigned int    biSize;
74         int                             biWidth;
75         int                             biHeight;
76         unsigned short  biPlanes;
77         unsigned short  biBitCount;
78         unsigned int    biCompression;
79         unsigned int    biSizeImage;
80         int                             biXPelsPerMeter;
81         int                             biYPelsPerMeter;
82         unsigned int    biClrUsed;
83         unsigned int    biClrImportant;
84 } BMPINFOHEADER;
85
86 #define BMP_FILEHEADER_SIZE 14
87
88 static int checkbmp(unsigned char *mem)
89 {
90         int ret_val = 0;
91         BMPINFOHEADER bmi;
92         unsigned int u;
93
94         if (mem) {
95                 if ((mem[0] == 'B') && (mem[1] == 'M')) {
96                         // skip fileheader
97                         mem += BMP_FILEHEADER_SIZE;
98                 }
99
100                 // for systems where an int needs to be 4 bytes aligned
101                 memcpy(&bmi, mem, sizeof(bmi));
102
103                 u = LITTLE_LONG(bmi.biSize);
104                 // we only support uncompressed 24 or 32 bits images for now
105                 if (u >= sizeof(BMPINFOHEADER)) {
106                         if ((bmi.biCompression == 0) && (bmi.biClrUsed == 0)) {
107                                 u = LITTLE_SHORT(bmi.biBitCount);
108                                 if (u >= 16) {
109                                         ret_val = 1;
110                                 }
111                         }
112                 }
113         }
114
115         return(ret_val);
116 }
117
118 int imb_is_a_bmp(void *buf) {
119         
120         return checkbmp(buf);
121 }
122
123 struct ImBuf *imb_bmp_decode(unsigned char *mem, int size, int flags)
124 {
125         struct ImBuf *ibuf = 0;
126         BMPINFOHEADER bmi;
127         int x, y, depth, skip, i;
128         unsigned char *bmp, *rect;
129         unsigned short col;
130
131         if (checkbmp(mem) == 0) return(0);
132
133         if ((mem[0] == 'B') && (mem[1] == 'M')) {
134                 // skip fileheader
135                 mem += BMP_FILEHEADER_SIZE;
136         }
137
138         // for systems where an int needs to be 4 bytes aligned
139         memcpy(&bmi, mem, sizeof(bmi));
140
141         skip = LITTLE_LONG(bmi.biSize);
142         x = LITTLE_LONG(bmi.biWidth);
143         y = LITTLE_LONG(bmi.biHeight);
144         depth = LITTLE_SHORT(bmi.biBitCount);
145
146         // printf("skip: %d, x: %d y: %d, depth: %d (%x)\n", skip, x, y, depth, bmi.biBitCount);
147         if (flags & IB_test) {
148                 ibuf = IMB_allocImBuf(x, y, depth, 0, 0);
149         } else {
150                 ibuf = IMB_allocImBuf(x, y, depth, IB_rect, 0);
151                 bmp = mem + skip;
152                 rect = (unsigned char *) ibuf->rect;
153
154                 if (depth == 16) {
155                         for (i = x * y; i > 0; i--) {
156                                 col = bmp[0] + (bmp[1] << 8);
157                                 rect[0] = ((col >> 10) & 0x1f) << 3;
158                                 rect[1] = ((col >>  5) & 0x1f) << 3;
159                                 rect[2] = ((col >>  0) & 0x1f) << 3;
160                                 
161                                 rect[3] = 255;
162                                 rect += 4; bmp += 2;
163                         }
164
165                 } else if (depth == 24) {
166                         for (i = x * y; i > 0; i--) {
167                                 rect[0] = bmp[2];
168                                 rect[1] = bmp[1];
169                                 rect[2] = bmp[0];
170                                 
171                                 rect[3] = 255;
172                                 rect += 4; bmp += 3;
173                         }
174                 } else if (depth == 32) {
175                         for (i = x * y; i > 0; i--) {
176                                 rect[0] = bmp[0];
177                                 rect[1] = bmp[1];
178                                 rect[2] = bmp[2];
179                                 rect[3] = bmp[3];
180                                 rect += 4; bmp += 4;
181                         }
182                 }
183         }
184
185         if (ibuf) {
186                 ibuf->ftype = BMP;
187         }
188         
189         return(ibuf);
190 }
191