-
Notifications
You must be signed in to change notification settings - Fork 41
Expand file tree
/
Copy pathimage_codec.cpp
More file actions
125 lines (107 loc) · 3.17 KB
/
Copy pathimage_codec.cpp
File metadata and controls
125 lines (107 loc) · 3.17 KB
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
// This file is part of SmallBASIC
//
// Image handling
//
// This program is distributed under the terms of the GPL v2.0 or later
// Download the GNU Public License (GPL) from www.gnu.org
//
// Copyright(C) 2002-2025 Chris Warren-Smith.
#include "config.h"
#include <cstdio>
#include <malloc.h>
#include "image_codec.h"
#include "lib/lodepng/lodepng.h"
static char g_last_error[256] = {0};
static float lerp(float a, float b, float t) {
return a + t * (b - a);
}
static void to_argb(unsigned char *image, unsigned w, unsigned h) {
#if defined(_SDL)
// convert from LCT_RGBA to ARGB
for (unsigned y = 0; y < h; y++) {
unsigned yoffs = (y * w * 4);
for (unsigned x = 0; x < w; x++) {
unsigned offs = yoffs + (x * 4);
uint8_t r = image[offs + 2];
uint8_t b = image[offs + 0];
image[offs + 2] = b;
image[offs + 0] = r;
}
}
#endif
}
ImageCodec::ImageCodec() :
_width(0),
_height(0),
_pixels(nullptr) {
}
bool ImageCodec::decode(const uint8_t *data, size_t size) {
auto error = lodepng_decode32(&_pixels, &_width, &_height, data, size);
if (error) {
snprintf(g_last_error, sizeof(g_last_error), "%s", lodepng_error_text(error));
} else {
to_argb(_pixels, _width, _height);
}
return !error;
}
ImageCodec::~ImageCodec() {
free(_pixels);
_pixels = nullptr;
}
const char *ImageCodec::getLastError() {
return g_last_error;
}
bool ImageCodec::encode(uint8_t **data, size_t *size) const {
bool result;
if (!data || !size) {
sprintf(g_last_error, "Invalid args");
result = false;
} else {
uint8_t *img = nullptr;
size_t img_size = 0;
auto error = lodepng_encode32(&img, &img_size, _pixels, _width, _height);
if (error) {
snprintf(g_last_error, sizeof(g_last_error), "%s", lodepng_error_text(error));
} else {
*data = img;
*size = img_size;
}
result = !error;
}
return result;
}
void ImageCodec::resize(unsigned width, unsigned height) {
auto *pixels = new uint8_t[width * height * 4];
for (unsigned y = 0; y < height; y++) {
float gy = ((float)y + 0.5f) * _height / height - 0.5f;
unsigned y0 = (unsigned)gy;
unsigned y1 = y0 + 1;
float fy = gy - y0;
y0 = y0 < 0 ? 0 : (y0 >= _height ? _height - 1 : y0);
y1 = y1 < 0 ? 0 : (y1 >= _height ? _height - 1 : y1);
for (unsigned x = 0; x < width; x++) {
float gx = ((float)x + 0.5f) * _width / width - 0.5f;
unsigned x0 = (unsigned)gx;
unsigned x1 = x0 + 1;
float fx = gx - x0;
x0 = x0 < 0 ? 0 : (x0 >= _width ? _width - 1 : x0);
x1 = x1 < 0 ? 0 : (x1 >= _width ? _width - 1 : x1);
int offset = 4 * (y * width + x);
for (unsigned c = 0; c < 4; c++) {
// A, R, G, B
float tl = _pixels[4 * (y0 * _width + x0) + c];
float tr = _pixels[4 * (y0 * _width + x1) + c];
float bl = _pixels[4 * (y1 * _width + x0) + c];
float br = _pixels[4 * (y1 * _width + x1) + c];
float top = lerp(tl, tr, fx);
float bottom = lerp(bl, br, fx);
float value = lerp(top, bottom, fy);
pixels[offset + c] = (uint8_t)(value + 0.5f);
}
}
}
free(_pixels);
_pixels = pixels;
_width = width;
_height = height;
}