Alamo
PNG.H
Go to the documentation of this file.
1
2#include <string.h>
3
4#include "Set/Set.H"
5#include "IO/ParmParse.H"
6
7#ifndef ALAMO_NOPNG
8#include <png.h>
9#endif
10
11namespace Util
12{
13class PNG
14{
15public:
16 PNG() {}
17 PNG(IO::ParmParse &pp,std::string name)
18 {pp.queryclass(name, *this);}
20 {
21 for (int y = 0; y < png_height; y++) {
22 free(row_pointers[y]);
23 }
24 free(row_pointers);
25 }
26
27 //enum Type {XYZ, XY, YZ, XZ};
29 enum Channel { R = 0, G = 1, B = 2, A = 3 };
30
31 static void Parse(PNG &value, IO::ParmParse &pp)
32 {
33#ifndef ALAMO_NOPNG
34
35 std::string filename;
36 pp_query_file("filename", filename); // BMP filename.
37
38 std::string fit = "stretch";
39 // how to position the image
40 pp_query_validate("fit", fit, {"stretch","fitheight","fitwidth","coord"});
41 if (fit == "stretch") value.fit = Fit::Stretch;
42 else if (fit == "fitheight") value.fit = Fit::FitHeight;
43 else if (fit == "fitwidth") value.fit = Fit::FitWidth;
44 else if (fit == "coord")
45 {
46 value.fit = Fit::Coord;
47 pp_queryarr("coord.lo", value.coord_lo); // Lower-left coordinates of image in domain
48 pp_queryarr("coord.hi", value.coord_hi); // Upper-right coordinates of image in domain
49 }
50 else Util::Abort(INFO);
51
52 // Desired minimum value to scale pixels by
53 pp_query_default("min", value.min, 0.0 );
54 // Desired maximum value to scale pixels by
55 pp_query_default("max", value.max, 255.0);
56
57 //
58 //
59 // Now, read in the PNG
60 //
61 //
62
63
64 FILE* fp = std::fopen(filename.c_str(), "rb");
65
66 if (fp == NULL) Util::Abort(INFO, "Cannot find file", filename);
67
68 png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
69 if (!png) Util::Abort(INFO);
70
71 png_infop info = png_create_info_struct(png);
72 if (!info) Util::Abort(INFO);
73
74 if (setjmp(png_jmpbuf(png))) Util::Abort(INFO);
75
76
77 png_init_io(png, fp);
78
79 png_read_info(png, info);
80
81 value.png_width = png_get_image_width(png, info);
82 value.png_height = png_get_image_height(png, info);
83 value.color_type = png_get_color_type(png, info);
84 value.bit_depth = png_get_bit_depth(png, info);
85
86 if (value.bit_depth == 16)
87 png_set_strip_16(png);
88
89 if (value.color_type == PNG_COLOR_TYPE_PALETTE)
90 png_set_palette_to_rgb(png);
91
92 if (value.color_type == PNG_COLOR_TYPE_GRAY && value.bit_depth < 8)
93 png_set_expand_gray_1_2_4_to_8(png);
94
95 if (png_get_valid(png, info, PNG_INFO_tRNS))
96 png_set_tRNS_to_alpha(png);
97
98 if (value.color_type == PNG_COLOR_TYPE_RGB ||
99 value.color_type == PNG_COLOR_TYPE_GRAY ||
100 value.color_type == PNG_COLOR_TYPE_PALETTE)
101 png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
102
103 if (value.color_type == PNG_COLOR_TYPE_GRAY ||
104 value.color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
105 png_set_gray_to_rgb(png);
106
107 png_read_update_info(png, info);
108
109 if (value.row_pointers) Util::Abort(INFO);
110
111 value.row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * value.png_height);
112 for (int y = 0; y < value.png_height; y++) {
113 value.row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png, info));
114 }
115
116 png_read_image(png, value.row_pointers);
117
118 fclose(fp);
119
120 png_destroy_read_struct(&png, &info, NULL);
121#else
122 Util::Abort(INFO,"PNG is disabled");
123#endif
124
125 }
127 {
128#ifndef ALAMO_NOPNG
129 domain_lo = _lo;
130 domain_hi = _hi;
131 domain_defined = false;
132#endif
133 }
134
135 [[nodiscard]]
136 std::array<int, 4> operator() (int I, int J)
137 {
138#ifndef ALAMO_NOPNG
139 std::array<int, 4> ret;
140 png_bytep px = &row_pointers[J][I * 4];
141 ret = { px[0], px[1], px[2], px[3] };
142 return ret;
143#endif
144 }
145
146 [[nodiscard]]
147 std::array<Set::Scalar, 4> operator()(Set::Vector &x)
148 {
149#ifndef ALAMO_NOPNG
150 Util::Assert(INFO, TEST(row_pointers), "Running IC without initialization...");
151
152 std::array<Set::Scalar, 4> ret;
153
154 Set::Scalar img_width = (Set::Scalar)(png_width - 1);
155 Set::Scalar img_height = (Set::Scalar)(png_height - 1);
156 Set::Scalar img_dx = 1.0;
157 Set::Scalar img_dy = 1.0;
158
159 //Set::Scalar x, y;
160 Set::Vector ximg;
161
162 if (fit == Fit::Stretch)
163 {
164 ximg(0) = (x(0) - domain_lo(0)) / (domain_hi(0) - domain_lo(0));
165 ximg(1) = (x(1) - domain_lo(1)) / (domain_hi(1) - domain_lo(1));
166 }
167 else if (fit == Fit::FitWidth)
168 {
169 Set::Scalar aspect_ratio = img_width / img_height;
170 ximg(0) = (x(0) - domain_lo(0)) / (domain_hi(0) - domain_lo(0));
171 ximg(1) = (x(1) - domain_lo(1)) / (domain_hi(1) - domain_lo(1));
172 ximg(1) -= 0.5 - 0.5 / aspect_ratio;
173 ximg(1) *= aspect_ratio;
174 }
175 else if (fit == Fit::FitHeight)
176 {
177 Set::Scalar aspect_ratio = img_height / img_width;
178 ximg(0) = (x(0) - domain_lo(0)) / (domain_hi(0) - domain_lo(0));
179 ximg(1) = (x(1) - domain_lo(1)) / (domain_hi(1) - domain_lo(1));
180 ximg(0) -= 0.5 - 0.5 / aspect_ratio;
181 ximg(0) *= aspect_ratio;
182 }
183 else if (fit == Fit::Coord)
184 {
185 ximg(0) = (x(0) - coord_lo(0)) / (coord_hi(0) - coord_lo(0));
186 ximg(1) = (x(1) - coord_lo(1)) / (coord_hi(1) - coord_lo(1));
187 }
188
189
190
191 ximg(0) = std::min(ximg(0), 1.0); ximg(1) = std::min(ximg(1), 1.0);
192 ximg(0) = std::max(ximg(0), 0.0); ximg(1) = std::max(ximg(1), 0.0);
193
194 ximg(0) *= img_width;
195 ximg(1) *= img_height;
196
197 int I = (int)(ximg(0));
198 int J = (int)(ximg(1));
199
200 Set::Scalar x1 = I * img_dx, x2 = (I + 1) * img_dx;
201 Set::Scalar y1 = J * img_dy, y2 = (J + 1) * img_dy;
202
203
204 for (int channel = 0; channel < 4; channel++)
205 {
206
207 if (I > 0 && I < png_width - 1 &&
208 J>0 && J < png_height - 1)
209 {
210 png_bytep px_sw = &(row_pointers[J][I * 4]);
211 png_bytep px_se = &(row_pointers[J][(I + 1) * 4]);
212 png_bytep px_nw = &(row_pointers[J + 1][I * 4]);
213 png_bytep px_ne = &(row_pointers[J + 1][(I + 1) * 4]);
214
215
216 Set::Scalar fQ11 = ((Set::Scalar)(px_sw[channel]) - min) / (max - min);
217 Set::Scalar fQ12 = ((Set::Scalar)(px_nw[channel]) - min) / (max - min);
218 Set::Scalar fQ21 = ((Set::Scalar)(px_se[channel]) - min) / (max - min);
219 Set::Scalar fQ22 = ((Set::Scalar)(px_ne[channel]) - min) / (max - min);
220
221 ret[channel] = (
222 fQ11 * (x2 - ximg(0)) * (y2 - ximg(1)) +
223 fQ21 * (ximg(0) - x1) * (y2 - ximg(1)) +
224 fQ12 * (x2 - ximg(0)) * (ximg(1) - y1) +
225 fQ22 * (ximg(0) - x1) * (ximg(1) - y1)) / (img_dx * img_dy);
226
227 }
228 else if ((I == 0 || I == png_width - 1) && J < png_height - 1)
229 {
230 png_bytep px_sw = &(row_pointers[J][I * 4]);
231 png_bytep px_nw = &(row_pointers[J + 1][I * 4]);
232
233 Set::Scalar fQ11 = ((Set::Scalar)(px_sw[channel]) - min) / (max - min);
234 Set::Scalar fQ12 = ((Set::Scalar)(px_nw[channel]) - min) / (max - min);
235 ret[channel] = fQ11 + (fQ12 - fQ11) * (ximg(1) - y1);
236 }
237 else if (I < png_width - 1 && (J == 0 || J == png_height - 1))
238 {
239 png_bytep px_sw = &(row_pointers[J][I * 4]);
240 png_bytep px_se = &(row_pointers[J][(I + 1) * 4]);
241
242 Set::Scalar fQ11 = ((Set::Scalar)(px_sw[channel]) - min) / (max - min);
243 Set::Scalar fQ21 = ((Set::Scalar)(px_se[channel]) - min) / (max - min);
244 ret[channel] = fQ11 + (fQ21 - fQ11) * (ximg(0) - x1);
245 }
246 else if (I == png_width - 1 && J == png_height - 1)
247 {
248 png_bytep px_sw = &(row_pointers[J][I * 4]);
249
250 Set::Scalar fQ11 = ((Set::Scalar)(px_sw[channel]) - min) / (max - min);
251 ret[channel] = fQ11;
252 }
253 else
254 {
255 ret[channel] = 0.0;
256 }
257 }
258 return ret;
259#endif
260 }
261
262private:
263
264#ifndef ALAMO_NOPNG
266 png_byte color_type;
267 png_byte bit_depth;
268 png_bytep* row_pointers = NULL;
269 Set::Vector coord_lo = Set::Vector::Zero();
270 Set::Vector coord_hi = Set::Vector::Zero();
271
272 //Util::BMP bmp;
274 Set::Scalar min = NAN, max = NAN;
275
276 bool domain_defined = false;
277 Set::Vector domain_lo = Set::Vector::Zero();
278 Set::Vector domain_hi = Set::Vector::Zero();
279#endif
280
281};
282
283}
#define pp_query_validate(...)
Definition ParmParse.H:101
#define pp_queryarr(...)
Definition ParmParse.H:103
#define pp_query_file(...)
Definition ParmParse.H:102
#define pp_query_default(...)
Definition ParmParse.H:100
#define TEST(x)
Definition Util.H:21
#define INFO
Definition Util.H:20
void queryclass(std::string name, T *value, std::string file="", std::string func="", int line=-1)
Definition ParmParse.H:604
Set::Vector domain_lo
Definition PNG.H:277
PNG(IO::ParmParse &pp, std::string name)
Definition PNG.H:17
~PNG()
Definition PNG.H:19
std::array< Set::Scalar, 4 > operator()(Set::Vector &x)
Definition PNG.H:147
@ Coord
Definition PNG.H:28
@ FitWidth
Definition PNG.H:28
@ Stretch
Definition PNG.H:28
@ FitHeight
Definition PNG.H:28
Fit fit
Definition PNG.H:273
int png_height
Definition PNG.H:265
bool domain_defined
Definition PNG.H:276
Set::Scalar min
Definition PNG.H:274
PNG()
Definition PNG.H:16
int png_width
Definition PNG.H:265
Set::Vector coord_hi
Definition PNG.H:270
Set::Scalar max
Definition PNG.H:274
Channel
Definition PNG.H:29
@ A
Definition PNG.H:29
@ G
Definition PNG.H:29
@ R
Definition PNG.H:29
@ B
Definition PNG.H:29
Set::Vector coord_lo
Definition PNG.H:269
png_byte bit_depth
Definition PNG.H:267
Set::Vector domain_hi
Definition PNG.H:278
void setDomain(Set::Vector &_lo, Set::Vector &_hi)
Definition PNG.H:126
static void Parse(PNG &value, IO::ParmParse &pp)
Definition PNG.H:31
std::array< int, 4 > operator()(int I, int J)
Definition PNG.H:136
png_byte color_type
Definition PNG.H:266
png_bytep * row_pointers
Definition PNG.H:268
amrex::Real Scalar
Definition Base.H:19
Eigen::Matrix< amrex::Real, AMREX_SPACEDIM, 1 > Vector
Definition Base.H:20
A collection of utility routines.
Definition Set.cpp:8
void Abort(const char *msg)
Definition Util.cpp:170
std::string filename
Definition Util.cpp:19
AMREX_FORCE_INLINE void Assert(std::string file, std::string func, int line, std::string smt, bool pass, Args const &... args)
Definition Util.H:70