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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
|
/**
* @module cbitmap
* @author Manuel Mausz, 0728348
* @brief Implementation of CFile handling Windows Bitmaps.
* @date 17.04.2009
*/
#include <boost/lexical_cast.hpp>
#include <boost/numeric/conversion/cast.hpp>
#ifdef DEBUG
# include <iostream>
#endif
#include "cbitmap.h"
#include "cpixelformat_24.h"
using namespace std;
CBitmap::~CBitmap()
{
if (m_pixeldata != NULL)
delete[] m_pixeldata;
m_pixeldata = NULL;
if (m_pixelformat != NULL)
delete m_pixelformat;
m_pixelformat = NULL;
}
/*----------------------------------------------------------------------------*/
void CBitmap::read(std::ifstream& in)
{
/* read and check file header */
in.read(reinterpret_cast<char *>(&m_fileheader), sizeof(m_fileheader));
if (m_fileheader.bfType[0] != 'B' || m_fileheader.bfType[1] != 'M')
throw FileError("Imagefile has invalid Bitmap header.");
/* bfSize is unreliable (http://de.wikipedia.org/wiki/Windows_Bitmap) */
if (m_fileheader.bfSize < 0)
throw FileError("Bitmap filesize is less than zero?");
/* read and check info header */
in.read(reinterpret_cast<char *>(&m_infoheader), sizeof(m_infoheader));
if (m_infoheader.biSize != 40)
throw FileError("Bitmap info header size is invalid.");
if (m_infoheader.biPlanes != 1)
throw FileError("Bitmap color planes is not set to 1.");
if (m_infoheader.biCompression != 0)
throw FileError("Bitmap compression is set but not supported.");
if (m_infoheader.biSizeImage < 0)
throw FileError("Bitmap image size is less than zero?");
if (m_infoheader.biClrUsed != 0 || m_infoheader.biClrImportant != 0)
throw FileError("Bitmap colortable is used but not supported.");
/* currently only 24bit */
if (m_infoheader.biBitCount != 24)
throw FileError("Bitmap bitcount is not supported.");
/* read pixel data using separate class */
if (m_infoheader.biSizeImage > 0)
{
if (m_pixeldata != NULL)
delete[] m_pixeldata;
m_pixeldata = new uint8_t[m_infoheader.biSizeImage];
in.read(reinterpret_cast<char *>(m_pixeldata), m_infoheader.biSizeImage);
}
/* create pixelformat instance */
if (m_pixelformat != NULL)
delete m_pixelformat;
m_pixelformat = NULL;
if (m_infoheader.biBitCount == 24)
m_pixelformat = new CPixelFormat_24(this);
}
/*----------------------------------------------------------------------------*/
void CBitmap::write(std::ofstream& out)
{
/* set header values */
m_fileheader.bfSize = m_infoheader.biSizeImage + sizeof(m_infoheader) + sizeof(m_fileheader);
/* write file header */
out.write(reinterpret_cast<char *>(&m_fileheader), sizeof(m_fileheader));
/* write info header */
out.write(reinterpret_cast<char *>(&m_infoheader), sizeof(m_infoheader));
/* write pixel data */
if (m_pixeldata != NULL)
out.write(reinterpret_cast<char *>(m_pixeldata), m_infoheader.biSizeImage);
}
/*----------------------------------------------------------------------------*/
void CBitmap::callFunc(const std::string& func, const std::list<std::string>& params)
{
if (func.empty())
throw FileError("Function name is empty.");
if (func == "fillrect")
fillrect(params);
else
throw FileError("Unknown function '" + func + "'.");
}
/*----------------------------------------------------------------------------*/
void CBitmap::fillrect(std::list<std::string> params)
{
/* check prerequirements */
if (params.size() != 7)
throw FileError("Invalid number of function parameters (must be 7).");
/* convert parameters */
uint32_t pparams[7];
int i = 0;
try
{
for(i = 0; i < 7; i++)
{
pparams[i] = boost::lexical_cast<uint32_t>(params.front());
params.pop_front();
}
}
catch(boost::bad_lexical_cast& ex)
{
throw FileError("Invalid parameter (" + params.front() + ").");
}
/* width and height can be negativ */
uint32_t width = static_cast<uint32_t>(abs(m_infoheader.biWidth));
uint32_t height = static_cast<uint32_t>(abs(m_infoheader.biHeight));
/* check parameter values are in range */
if (pparams[0] < 0 || pparams[0] > width
|| pparams[1] < 0 || pparams[1] > height)
throw FileError("At least one x/y-parameter is out of range.");
if (pparams[2] < 0 || pparams[2] + pparams[0] > width
|| pparams[3] < 0 || pparams[3] + pparams[1] > height)
throw FileError("At least one w/h-parameter is out of range.");
if (pparams[4] < 0 || pparams[4] > 255
|| pparams[5] < 0 || pparams[5] > 255
|| pparams[6] < 0 || pparams[6] > 255)
throw FileError("At least one pixel color parameter is out of range.");
/* call setPixel for every pixel in the rectangel */
if (m_pixeldata != NULL && m_pixelformat != NULL)
{
for(uint32_t i = pparams[0]; i < pparams[2] + pparams[0]; i++)
{
for(uint32_t j = pparams[1]; j < pparams[3] + pparams[1]; j++)
{
try
{
m_pixelformat->setPixel(&pparams[4], i, j);
}
catch(CPixelFormat::PixelFormatError& ex)
{
stringstream errstr;
errstr << "Can't set pixel (pos=" << i << "," << j << " col="
<< pparams[4] << "," << pparams[5] << "," << pparams[6] << "): "
<< ex.what();
throw FileError(errstr.str());
}
}
}
}
}
/*----------------------------------------------------------------------------*/
#ifdef DEBUG
void CBitmap::dump(std::ostream& out)
{
out
<< "Bitmap File Header:" << endl
<< " bfType=" << m_fileheader.bfType[0] << m_fileheader.bfType[1]
<< ", bfSize=" << m_fileheader.bfSize
<< ", bfReserved=" << m_fileheader.bfReserved
<< ", bfOffBits=" << m_fileheader.bfOffBits
<< endl;
out
<< "Bitmap Info Header:" << endl
<< " biSize=" << m_infoheader.biSize
<< ", biWidth=" << m_infoheader.biWidth
<< ", biHeight=" << m_infoheader.biHeight
<< ", biPlanes=" << m_infoheader.biPlanes
<< endl
<< " biBitCount=" << m_infoheader.biBitCount
<< ", biCompression=" << m_infoheader.biCompression
<< ", biSizeImage=" << m_infoheader.biSizeImage
<< endl
<< " biXPelsPerMeter=" << m_infoheader.biXPelsPerMeter
<< ", biYPelsPerMeter=" << m_infoheader.biYPelsPerMeter
<< ", biClrUsed=" << m_infoheader.biClrUsed
<< ", biClrImportant=" << m_infoheader.biClrImportant
<< endl;
}
#endif
/* vim: set et sw=2 ts=2: */
|