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