LCOV - code coverage report
Current view: top level - src/Util - PNG.H (source / functions) Coverage Total Hit
Test: coverage_merged.info Lines: 0.0 % 134 0
Test Date: 2025-08-05 17:56:56 Functions: 0.0 % 7 0

            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              : }
        

Generated by: LCOV version 2.0-1