-
Notifications
You must be signed in to change notification settings - Fork 4
/
BMPLoader.cpp
executable file
·190 lines (158 loc) · 5.37 KB
/
BMPLoader.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/*BMPLoader - loads Microsoft .bmp format
Copyright (C) 2006 Chris Backhouse
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
[email protected] www.backhouse.tk
I would appreciate it if anyone using this in something cool would tell me
so I can see where it ends up.
Takes a filename, returns an array of RGB pixel data
Loads:
24bit bitmaps
256 colour bitmaps
16 colour bitmaps
2 colour bitmaps (Thanks to Charles Rabier)
This code is designed for use in openGL programs, so bitmaps not correctly padded will not
load properly, I believe this only applies to:
256cols if width is not a multiple of 4
16cols if width is not a multiple of 8
2cols if width is not a multiple of 32
Sample code:
BMPClass bmp;
BMPLoad(fname,bmp);
glTexImage2D(GL_TEXTURE_2D,0,3,bmp.width,bmp.height,0,GL_RGB,GL_UNSIGNED_BYTE,bmp.bytes);
*/
#include "BMPLoader.h"
BMPClass::BMPClass(){bytes=0;}
BMPClass::~BMPClass(){delete[] bytes;}
BYTE& BMPClass::pixel(int x,int y,int c){return bytes[(y*width+x)*3+c];}
void BMPClass::allocateMem(){delete[] bytes;bytes=new BYTE[width*height*3];}
std::string TranslateBMPError(BMPError err)
{
switch(err)
{
case(BMPNOTABITMAP):
return "This file is not a bitmap, specifically it doesn't start 'BM'";
case(BMPNOOPEN):
return "Failed to open the file, suspect it doesn't exist";
case(BMPFILEERROR):
return "ferror said we had an error. This error seems to not always mean anything, try ignoring it";
case(BMPBADINT):
return "sizeof(int)!=4 quite a lot of rewriting probably needs to be done on the code";
case(BMPNOERROR):
return "No errors detected";
case(BMPUNKNOWNFORMAT):
return "Unknown bmp format, ie not 24bit, 256,16 or 2 colour";
default:
return "Not a valid error code";
}
}
BMPError BMPLoad(std::string fname,BMPClass& bmp)
{
if(sizeof(int)!=4) return BMPBADINT;
FILE* f=fopen(fname.c_str(),"rb"); //open for reading in binary mode
if(!f) return BMPNOOPEN;
char header[54];
fread(header,54,1,f); //read the 54bit main header
if(header[0]!='B' || header[1]!='M')
{
fclose(f);
return BMPNOTABITMAP; //all bitmaps should start "BM"
}
//it seems gimp sometimes makes its headers small, so we have to do this. hence all the fseeks
int offset=*(unsigned int*)(header+10);
bmp.width=*(int*)(header+18);
bmp.height=*(int*)(header+22);
//now the bitmap knows how big it is it can allocate its memory
bmp.allocateMem();
int bits=int(header[28]); //colourdepth
int x,y,c;
BYTE cols[256*4]; //colourtable
switch(bits)
{
case(24):
fseek(f,offset,SEEK_SET);
fread(bmp.bytes,bmp.width*bmp.height*3,1,f); //24bit is easy
for(x=0;x<bmp.width*bmp.height*3;x+=3) //except the format is BGR, grr
{
BYTE temp=bmp.bytes[x];
bmp.bytes[x]=bmp.bytes[x+2];
bmp.bytes[x+2]=temp;
}
break;
case(8):
fread(cols,256*4,1,f); //read colortable
fseek(f,offset,SEEK_SET);
for(y=0;y<bmp.height;++y) //(Notice 4bytes/col for some reason)
for(x=0;x<bmp.width;++x)
{
BYTE byte;
fread(&byte,1,1,f); //just read byte
for(int c=0;c<3;++c)
bmp.pixel(x,y,c)=cols[byte*4+2-c]; //and look up in the table
}
break;
case(4):
fread(cols,16*4,1,f);
fseek(f,offset,SEEK_SET);
for(y=0;y<256;++y)
for(x=0;x<256;x+=2)
{
BYTE byte;
fread(&byte,1,1,f); //as above, but need to exract two
for(c=0;c<3;++c) //pixels from each byte
bmp.pixel(x,y,c)=cols[byte/16*4+2-c];
for(c=0;c<3;++c)
bmp.pixel(x+1,y,c)=cols[byte%16*4+2-c];
}
break;
case(1):
fread(cols,8,1,f);
fseek(f,offset,SEEK_SET);
for(y=0;y<bmp.height;++y)
for(x=0;x<bmp.width;x+=8)
{
BYTE byte;
fread(&byte,1,1,f);
//Every byte is eight pixels
//so I'm shifting the byte to the relevant position, then masking out
//all but the lowest bit in order to get the index into the colourtable.
for(int x2=0;x2<8;++x2)
for(int c=0;c<3;++c)
bmp.pixel(x+x2,y,c)=cols[((byte>>(7-x2))&1)*4+2-c];
}
break;
default:
fclose(f);
return BMPUNKNOWNFORMAT;
}
if(ferror(f))
{
fclose(f);
return BMPFILEERROR;
}
fclose(f);
return BMPNOERROR;
}
BMPError BMPLoad(std::string fname){BMPClass bmp;return BMPLoad(fname,bmp);}
#ifdef __gl_h
BMPError BMPLoadGL(std::string fname)
{
BMPClass bmp;
BMPError e=BMPLoad(fname,bmp);
if(e!=BMPNOERROR) return e;
glEnable(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D,0,3,bmp.width,bmp.height,0,GL_RGB,GL_UNSIGNED_BYTE,bmp.bytes);
return BMPNOERROR;
}
#endif