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