LCOV - code coverage report
Current view: top level - src/IC - PNG.H (source / functions) Hit Total Coverage
Test: coverage_merged.info Lines: 0 157 0.0 %
Date: 2024-11-18 05:28:54 Functions: 0 6 0.0 %

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

Generated by: LCOV version 1.14