This repository has been archived by the owner on Apr 17, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathImage.hpp
337 lines (282 loc) · 9.02 KB
/
Image.hpp
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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
#if !defined(__IMAGE_H_)
#define __IMAGE_H_
#include "Bitmap.h"
#include "ImpBrush.h"
#include "gl_helper.h"
#include <cmath>
#include <functional>
#include <tuple>
#include <vector>
using namespace std;
typedef tuple<GLubyte, GLubyte, GLubyte, GLubyte> RGBA;
static RGBA operator+(RGBA c1, RGBA c2) {
return {get<0>(c1) + get<0>(c2), get<1>(c1) + get<1>(c2),
get<2>(c1) + get<2>(c2), get<3>(c1) + get<3>(c2)};
}
static RGBA operator/(RGBA c1, double d) {
return {(int)(get<0>(c1) / d), (int)(get<1>(c1) / d), int(get<2>(c1) / d),
int(get<3>(c1) / d)};
}
static RGBA operator*(RGBA c1, double d) {
return {(int)(get<0>(c1) * d), (int)(get<1>(c1) * d), int(get<2>(c1) * d),
int(get<3>(c1) * d)};
}
class Image {
static const int NUM_CHANNEL = 4;
public:
vector<GLubyte> bytes;
vector<GLubyte> exportable;
int width;
int height;
Image() : Image{nullptr, 0, 0} {}
Image(GLubyte *buf, int w, int h) { set(buf, w, h); }
static Image from(const char *path) {
unsigned char *data;
int width, height;
data = readBMP(path, width, height);
return Image(data, width, height);
}
static Image colored_image(GLubyte r, GLubyte g, GLubyte b, GLubyte a, int w,
int h) {
Image tmp;
tmp.width = w;
tmp.height = h;
tmp.bytes.resize(w * h * 4);
for (auto p = tmp.bytes.begin(); p != tmp.bytes.end(); p += 4) {
p[0] = r;
p[1] = g;
p[2] = b;
p[3] = a;
}
return tmp;
}
void operator=(Image &img) {
this->bytes = img.bytes;
this->width = img.width;
this->height = img.height;
}
void set(GLubyte *buf, int w, int h) {
width = w, height = h;
bytes = {};
const int length = w * h * 3;
short count = 0;
for (int i = 0; i < length; i++) {
bytes.push_back(buf[i]);
if (++count == 3) {
count = 0;
bytes.push_back(255);
}
}
}
void set_alpha_image(GLubyte *buf, int w, int h) {
width = w, height = h;
bytes = {};
const int length = w * h;
short count = 0;
for (int i = 0; i < length; i++) {
GLubyte grayscale =
0.3 * buf[count++] + 0.6 * buf[count++] + 0.1 * buf[count++];
bytes.push_back(grayscale);
}
printf("size is %d x %d and length of bytes is %d\n", width, height,
bytes.size());
}
bool valid_point(int y, int x) const {
if (x < 0)
return false;
if (y < 0)
return false;
if (x >= width)
return false;
if (y >= height)
return false;
return true;
}
Point clip(const Point &p) { return clip(p.x, p.y); }
Point clip(int x, int y) {
if (x < 0)
x = 0;
if (y < 0)
y = 0;
if (x >= width)
x = width - 1;
if (y >= height)
y = height - 1;
return Point{x, y};
}
const tuple<GLubyte &, GLubyte &, GLubyte &, GLubyte &> operator()(int y,
int x) {
int i = convert_to_index(y, x);
return {bytes[i], bytes[i + 1], bytes[i + 2], bytes[i + 3]};
}
const GLubyte get_alpha(int y, int x) {
int i = y * width + x;
return bytes[i];
}
int convert_to_index(int y, int x) { return NUM_CHANNEL * (y * width + x); }
GLubyte *raw_fmt() { return bytes.data(); }
GLubyte *paint_byte() { return bytes.data() + height * NUM_CHANNEL; }
void set_pixel(int y, int x, const RGBA &rgb) {
auto color = (*this)(y, x);
get<0>(color) = get<0>(rgb);
get<1>(color) = get<1>(rgb);
get<2>(color) = get<2>(rgb);
}
void set_pixel(const Point &p, const RGBA &rgb) { set_pixel(p.y, p.x, rgb); }
void for_range_pixel(const Point &s, const Point &e,
function<void(int, int)> handler) {
for (int y = s.y; y <= e.y; y++) {
for (int x = s.x; x <= e.x; x++) {
handler(y, x);
}
}
}
void for_each_pixel(function<void(int, int)> handler) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
handler(y, x);
}
}
}
void for_each_alpha(function<void(GLubyte &)> handler) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int i = convert_to_index(y, x) + 3;
handler(bytes[i]);
}
}
}
void set_alpha(float a) {
for_each_pixel(
[&](int y, int x) { get<3>((*this)(y, x)) = (GLubyte)(255 * a); });
}
void crop(size_t sx, size_t sy) {
vector<GLubyte> buf{};
for_each_pixel([&](int y, int x) {
if (y >= sy || x >= sx)
return;
auto color = (*this)(y, x);
buf.push_back(get<0>(color));
buf.push_back(get<1>(color));
buf.push_back(get<2>(color));
buf.push_back(get<3>(color));
});
bytes = buf;
width = width > sx ? sx : width;
height = height > sy ? sy : height;
}
bool contain_content() const { return width != 0 && height != 0; }
void clear() {
this->bytes = {};
this->width = this->height = 0;
}
bool has_color(int y, int x) {
int i = convert_to_index(y, x);
return bytes[i] || bytes[i + 1] || bytes[i + 2];
}
void resize(int w, int h) {
// to be implemented
int completed_col = 0;
int completed_row = 0;
float hratio = (float)w / width;
float vratio = (float)h / height;
float hcur = 1.0f;
float vcur = 1.0f;
}
unsigned char *exportable_fmt() {
exportable = {};
int c = 0;
for (GLubyte ch : bytes) {
if (++c == 4) {
c = 0;
continue;
}
exportable.push_back(ch);
}
return exportable.data();
}
void paint(Image &img, const Point &at) {
img.for_each_pixel([&](int y, int x) {
Point p{y, x};
p = p + at;
if (valid_point(p.y, p.x)) {
auto src_color = img(y, x);
auto tar_color = (*this)(p.y, p.x);
tar_color = src_color;
}
});
}
Image crop(const Point &from, const Point &to) {
vector<GLubyte> buf{};
for_range_pixel(from, to, [&](int y, int x) {
auto color = (*this)(y, x);
buf.push_back(get<0>(color));
buf.push_back(get<1>(color));
buf.push_back(get<2>(color));
buf.push_back(get<3>(color));
});
const Point diff = to - from;
Image tmp;
tmp.set(buf.data(), diff.x + 1, diff.y + 1);
return tmp;
}
// void ImageManipulator::reduce(Image *source, Image *result, int
// targetWidth,
// int targetHeight) {
// int copiedColumns = 0;
// int copiedLines = 0;
// // Calculate the ration between the target and source image
// // We'll use this value later to determine how many lines/columns we need
// to
// // skip before copying another line/column to the target buffer
// float horizontalRatio = (float)targetWidth / (float)source->getWidth();
// float verticalRatio = (float)targetHeight / (float)source->getHeight();
// // 'current' values = arbitrary number that tells the program when to
// copy a
// // pixel to the target image. The program copies a pixel whenever one of
// // these values is at least 1. We start with both values set to 1 so that
// we
// // keep the first column and line of the source image.
// float horizontalCurrent = 1.0f;
// float verticalCurrent = 1.0f;
// // Set the bitmap data so that other programs can read the resulting
// *.bmp
// // file
// result->setWidth(targetWidth);
// result->setHeight(targetHeight);
// result->recalculateBuffers();
// // Iterate over all columns of the source image
// for (int x = 0; x < source->getWidth(); x++) {
// // If we reached the target width, abort
// if (copiedColumns == targetWidth)
// break;
// // Copy the current column to the resulting image if the current value
// is
// // at least 1
// if (horizontalCurrent >= 1.0f) {
// // Iterate over each pixel in the current column (from the top of the
// // image to the bottom)
// for (int y = 0; y < source->getHeight(); y++) {
// if (copiedLines == targetHeight)
// break;
// // But make sure to only copy the needed pixels of the current
// column if (verticalCurrent >= 1.0f) {
// unsigned char pixel[3];
// source->getPixel(x, y, &pixel[0]);
// result->setPixel(copiedColumns, copiedLines, pixel[0], pixel[1],
// pixel[2]);
// copiedLines += 1;
// verticalCurrent -= 1.0f;
// }
// verticalCurrent += verticalRatio;
// }
// copiedLines = 0;
// copiedColumns += 1;
// horizontalCurrent -= 1.0f;
// verticalCurrent = 1.0f;
// }
// horizontalCurrent += horizontalRatio;
// }
// }
};
#endif // __IMAGE_H_