-
Notifications
You must be signed in to change notification settings - Fork 0
/
BMP.cpp
200 lines (171 loc) · 4.91 KB
/
BMP.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
191
192
193
194
195
196
197
198
199
200
#include "BMP.h"
#include <exception>
#include <iostream>
/**
* @brief Construct a new BMP::BMP object
*
* @param width
* @param height
*/
BMP::BMP(uint32_t width, uint32_t height)
: m_width(width), m_height(height), m_pixels(new Color *[width]) {
for (int i = 0; 0 < width; ++i) {
m_pixels[i] = new Color[height];
}
};
/**
* @brief Construct a new BMP::BMP object with loading from file initiated
*
* @param name File name
*/
BMP::BMP(std::string name) { loadFromFile(name); }
/**
* @brief Construct a new BMP::BMP object copying from Pizza object
*
* @param pizza
*/
BMP::BMP(Pizza &pizza) {
m_width = pizza.getWidth();
m_height = pizza.getHeight();
m_pixels = new Color *[m_width];
for (int i = 0; i < m_width; ++i) {
m_pixels[i] = new Color[m_height];
for (int j = 0; j < m_height; ++j) {
m_pixels[i][j] = pizza.getPixel(i, j);
}
}
}
/**
* @brief loads image from file
*
* @param name File Name
*/
void BMP::loadFromFile(std::string name) {
std::fstream file;
file.open(name, std::ios::in | std::ios::binary);
// Read file info
file.read((char *)&m_fileHeader, 14);
if (m_fileHeader.signature != 0x4D42) {
throw std::runtime_error("Error! Unrecognized file format.");
}
file.read((char *)&m_DIBHeader, sizeof(m_DIBHeader));
m_width = m_DIBHeader.width;
m_height = m_DIBHeader.height;
// skip to start of pixer array
file.seekg(m_fileHeader.dataPosition, file.beg);
// Declaring pixels array
m_pixels = new Color *[m_width];
for (int i = 0; i < m_width; i++) {
m_pixels[i] = new Color[m_height];
}
// Getting pixels from file
int size = m_DIBHeader.bitsPerPixel / 8 * m_width;
unsigned char *data = new unsigned char[size];
uint8_t r, g, b;
// Copying pixel data from file to Pixels array
for (int i = m_height - 1; i >= 0; --i) {
// BMP saves pixels from the bottom left, so do i
file.read((char *)data, size); // read data every line, reading whole file
// would couse problems with largers images
for (int j = 0; j < m_width; ++j) {
// BMP saves in order: blue, green, red
b = *(data++);
g = *(data++);
r = *(data++);
if (m_DIBHeader.bitsPerPixel == 32) // If alpha channel exists, skip it
data++;
m_pixels[j][i] = {r, g, b};
}
data -= size; // resets pointer to point on the start of the array
if (m_DIBHeader.bitsPerPixel != 32 &&
(m_width * m_DIBHeader.bitsPerPixel / 8) % 4 != 0)
file.read((char *)data, 4 - (m_width * m_DIBHeader.bitsPerPixel / 8) % 4);
}
delete[] data;
file.close();
}
/**
* @brief Saving int to char, little endian safe
*
* @param a
* @param number
*/
void saveIntToChar(unsigned char *a, int number) {
a[0] = number & 0xff;
a[1] = (number >> 8) & 0xff;
a[2] = (number >> 16) & 0xff;
a[3] = (number >> 24) & 0xff;
}
/**
* @brief Saves image to file
*
* @param name File name
*/
void BMP::saveToFile(std::string name) {
std::fstream file;
file.open(name, std::ios::out | std::ios::binary);
m_DIBHeader.headerSize = 40; // Setting basic DIB header size
m_fileHeader.dataPosition =
14 + m_DIBHeader.headerSize; // File header always takes 14 bytes
if ((m_width * 3) % 4 == 0)
m_fileHeader.fileSize = (m_width)*m_height * 3 + m_fileHeader.dataPosition;
else
m_fileHeader.fileSize = (m_width)*m_height * 3 + m_fileHeader.dataPosition +
(4 - (m_width * 3) % 4) * m_height;
m_DIBHeader.width = m_width;
m_DIBHeader.height = m_height;
m_DIBHeader.bitsPerPixel = 24; // Saving with aplha channel not supported
m_DIBHeader.imageSize = m_height * m_width * 3;
file.write((char *)&m_fileHeader, 14); // Saving file header to file
file.write((char *)&m_DIBHeader,
m_DIBHeader.headerSize); // saving DIB header to file
int size = 3 * m_width;
unsigned char *data = new unsigned char[size];
int zero[4]{0};
// Saving rom bottom row to the first
for (int i = m_height - 1; i >= 0; --i) {
for (int j = 0; j < m_width; ++j) {
// save in reverse order, little endian
data[j * 3] = (char)m_pixels[j][i].b;
data[j * 3 + 1] = (char)m_pixels[j][i].g;
data[j * 3 + 2] = (char)m_pixels[j][i].r;
}
file.write((char *)data, size);
if ((m_width * 3) % 4 != 0)
file.write((char *)&zero, 4 - (m_width * 3) % 4);
}
delete[] data;
file.close();
}
/**
* @brief return Color from given pixel
*
* @param x
* @param y
* @return Color
*/
Color BMP::getPixel(int x, int y) {
if (x < m_width && y < m_height)
return m_pixels[x][y];
}
/**
* @brief Sets pixel for given Color
*
* @param x
* @param y
* @param kolor
*/
void BMP::setPixel(int x, int y, Color color) {
if (x >= 0 && x < m_width && y >= 0 && y < m_height)
m_pixels[x][y] = color;
}
/**
* @brief Destroy the BMP::BMP object
*
*/
BMP::~BMP() {
for (int i = 0; i < m_width; ++i) {
delete[] m_pixels[i];
}
delete m_pixels;
}