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