Commit message: .
CVE: CVE-2019-13568
CWE: CWE-787
Vulnerability description: CImg through 2.6.7 has a heap-based buffer overflow in _load_bmp in CImg.h because of erroneous memory allocation for a malformed BMP image.

Project: CImg
File: CImg.h


    CImg<intT> _select(CImgDisplay &disp, const char *const title,
                       const unsigned int feature_type, unsigned int *const XYZ,
                       const int origX, const int origY, const int origZ,
                       const bool exit_on_anykey,
                       const bool reset_view3d,
                       const bool force_display_z_coord,
                       const bool is_deep_selection_default) const {
      if (is_empty()) return CImg<intT>(1,feature_type==0?3:6,1,1,-1);
      if (!disp) {
        disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,1);
        if (!title) disp.set_title("CImg<%s> (%ux%ux%ux%u)",pixel_type(),_width,_height,_depth,_spectrum);
      } else {
        if (title) disp.set_title("%s",title);
        disp.move_inside_screen();
      }

      CImg<T> thumb;
      if (width()>disp.screen_width() || height()>disp.screen_height())
        get_resize(cimg_fitscreen(width(),height(),depth()),depth(),-100).move_to(thumb);

      const unsigned int old_normalization = disp.normalization();
      bool old_is_resized = disp.is_resized();
      disp._normalization = 0;
      disp.show().set_key(0).set_wheel().show_mouse();

      static const unsigned char foreground_color[] = { 255,255,255 }, background_color[] = { 0,0,0 };

      int area = 0, area_started = 0, area_clicked = 0, phase = 0,
        X0 = (int)((XYZ?XYZ[0]:_width/2)%_width),
        Y0 = (int)((XYZ?XYZ[1]:_height/2)%_height),
        Z0 = (int)((XYZ?XYZ[2]:_depth/2)%_depth),
        X1 =-1, Y1 = -1, Z1 = -1,
        X3d = -1, Y3d = -1,
        oX3d = X3d, oY3d = -1,
        omx = -1, omy = -1;
      float X = -1, Y = -1, Z = -1;
      unsigned int key = 0;

      bool is_deep_selection = is_deep_selection_default,
        shape_selected = false, text_down = false, visible_cursor = true;
      static CImg<floatT> pose3d;
      static bool is_view3d = false, is_axes = true;
      if (reset_view3d) { pose3d.assign(); is_view3d = false; }
      CImg<floatT> points3d, opacities3d, sel_opacities3d;
      CImgList<uintT> primitives3d, sel_primitives3d;
      CImgList<ucharT> colors3d, sel_colors3d;
      CImg<ucharT> visu, visu0, view3d;
      CImg<charT> text(1024); *text = 0;

      while (!key && !disp.is_closed() && !shape_selected) {

        // Handle mouse motion and selection
        int
          mx = disp.mouse_x(),
          my = disp.mouse_y();

        const float
          mX = mx<0?-1.f:(float)mx*(width() + (depth()>1?depth():0))/disp.width(),
          mY = my<0?-1.f:(float)my*(height() + (depth()>1?depth():0))/disp.height();

        area = 0;
        if (mX>=0 && mY>=0 && mX<width() && mY<height())  { area = 1; X = mX; Y = mY; Z = (float)(phase?Z1:Z0); }
        if (mX>=0 && mX<width() && mY>=height()) { area = 2; X = mX; Z = mY - _height; Y = (float)(phase?Y1:Y0); }
        if (mY>=0 && mX>=width() && mY<height()) { area = 3; Y = mY; Z = mX - _width; X = (float)(phase?X1:X0); }
        if (mX>=width() && mY>=height()) area = 4;
        if (disp.button()) { if (!area_clicked) area_clicked = area; } else area_clicked = 0;

        CImg<charT> filename(32);

        switch (key = disp.key()) {
#if cimg_OS!=2
        case cimg::keyCTRLRIGHT :
#endif
        case 0 : case cimg::keyCTRLLEFT : key = 0; break;
        case cimg::keyPAGEUP :
          if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_wheel(1); key = 0; } break;
        case cimg::keyPAGEDOWN :
          if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_wheel(-1); key = 0; } break;
        case cimg::keyX : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
            is_axes = !is_axes; disp.set_key(key,false); key = 0; visu0.assign();
          } break;
        case cimg::keyD : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
            disp.set_fullscreen(false).
              resize(CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,false),
                     CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,true),false).
              _is_resized = true;
            disp.set_key(key,false); key = 0; visu0.assign();
          } break;
        case cimg::keyC : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
            disp.set_fullscreen(false).
              resize(cimg_fitscreen(2*disp.width()/3,2*disp.height()/3,1),false)._is_resized = true;
            disp.set_key(key,false); key = 0; visu0.assign();
          } break;
        case cimg::keyR : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
            disp.set_fullscreen(false).resize(cimg_fitscreen(_width,_height,_depth),false)._is_resized = true;
            disp.set_key(key,false); key = 0; visu0.assign();
          } break;
        case cimg::keyF : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
            disp.resize(disp.screen_width(),disp.screen_height(),false).toggle_fullscreen()._is_resized = true;
            disp.set_key(key,false); key = 0; visu0.assign();
          } break;
        case cimg::keyV : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
            is_view3d = !is_view3d; disp.set_key(key,false); key = 0; visu0.assign();
          } break;
        case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
            static unsigned int snap_number = 0;
            std::FILE *file;
            do {
              cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.bmp",snap_number++);
              if ((file=cimg::std_fopen(filename,"r"))!=0) cimg::fclose(file);
            } while (file);
            if (visu0) {
              (+visu0).__draw_text(" Saving snapshot...",(int)text_down).display(disp);
              visu0.save(filename);
              (+visu0).__draw_text(" Snapshot '%s' saved. ",(int)text_down,filename._data).display(disp);
            }
            disp.set_key(key,false); key = 0;
          } break;
        case cimg::keyO : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
            static unsigned int snap_number = 0;
            std::FILE *file;
            do {

#ifdef cimg_use_zlib
              cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimgz",snap_number++);
#else
              cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimg",snap_number++);
#endif
              if ((file=cimg::std_fopen(filename,"r"))!=0) cimg::fclose(file);
            } while (file);
            (+visu0).__draw_text(" Saving instance... ",(int)text_down).display(disp);
            save(filename);
            (+visu0).__draw_text(" Instance '%s' saved. ",(int)text_down,filename._data).display(disp);
            disp.set_key(key,false); key = 0;
          } break;
        }

        switch (area) {

        case 0 : // When mouse is out of image range
          mx = my = -1; X = Y = Z = -1;
          break;

        case 1 : case 2 : case 3 : { // When mouse is over the XY,XZ or YZ projections
          const unsigned int but = disp.button();
          const bool b1 = (bool)(but&1), b2 = (bool)(but&2), b3 = (bool)(but&4);

          if (b1 && phase==1 && area_clicked==area) { // When selection has been started (1st step)
            if (_depth>1 && (X1!=(int)X || Y1!=(int)Y || Z1!=(int)Z)) visu0.assign();
            X1 = (int)X; Y1 = (int)Y; Z1 = (int)Z;
          }
          if (!b1 && phase==2 && area_clicked!=area) { // When selection is at 2nd step (for volumes)
            switch (area_started) {
            case 1 : if (Z1!=(int)Z) visu0.assign(); Z1 = (int)Z; break;
            case 2 : if (Y1!=(int)Y) visu0.assign(); Y1 = (int)Y; break;
            case 3 : if (X1!=(int)X) visu0.assign(); X1 = (int)X; break;
            }
          }
          if (b2 && area_clicked==area) { // When moving through the image/volume
            if (phase) {
              if (_depth>1 && (X1!=(int)X || Y1!=(int)Y || Z1!=(int)Z)) visu0.assign();
              X1 = (int)X; Y1 = (int)Y; Z1 = (int)Z;
            } else {
              if (_depth>1 && (X0!=(int)X || Y0!=(int)Y || Z0!=(int)Z)) visu0.assign();
              X0 = (int)X; Y0 = (int)Y; Z0 = (int)Z;
            }
          }
          if (b3) { // Reset selection
            X = (float)X0; Y = (float)Y0; Z = (float)Z0; phase = area = area_clicked = area_started = 0;
            visu0.assign();
          }
          if (disp.wheel()) { // When moving through the slices of the volume (with mouse wheel)
            if (_depth>1 && !disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT() &&
                !disp.is_keySHIFTLEFT() && !disp.is_keySHIFTRIGHT()) {
              switch (area) {
              case 1 :
                if (phase) Z = (float)(Z1+=disp.wheel()); else Z = (float)(Z0+=disp.wheel());
                visu0.assign(); break;
              case 2 :
                if (phase) Y = (float)(Y1+=disp.wheel()); else Y = (float)(Y0+=disp.wheel());
                visu0.assign(); break;
              case 3 :
                if (phase) X = (float)(X1+=disp.wheel()); else X = (float)(X0+=disp.wheel());
                visu0.assign(); break;
              }
              disp.set_wheel();
            } else key = ~0U;
          }

          if ((phase==0 && b1) ||
              (phase==1 && !b1) ||
              (phase==2 && b1)) switch (phase) { // Detect change of phase
            case 0 :
              if (area==area_clicked) {
                X0 = X1 = (int)X; Y0 = Y1 = (int)Y; Z0 = Z1 = (int)Z; area_started = area; ++phase;
              } break;
            case 1 :
              if (area==area_started) {
                X1 = (int)X; Y1 = (int)Y; Z1 = (int)Z; ++phase;
                if (_depth>1) {
                  if (disp.is_keyCTRLLEFT()) is_deep_selection = !is_deep_selection_default;
                  if (is_deep_selection) ++phase;
                }
              } else if (!b1) { X = (float)X0; Y = (float)Y0; Z = (float)Z0; phase = 0; visu0.assign(); }
              break;
            case 2 : ++phase; break;
            }
        } break;

        case 4 : // When mouse is over the 3D view
          if (is_view3d && points3d) {
            X3d = mx - width()*disp.width()/(width() + (depth()>1?depth():0));
            Y3d = my - height()*disp.height()/(height() + (depth()>1?depth():0));
            if (oX3d<0) { oX3d = X3d; oY3d = Y3d; }
            // Left + right buttons: reset.
            if ((disp.button()&3)==3) { pose3d.assign(); view3d.assign(); oX3d = oY3d = X3d = Y3d = -1; }
            else if (disp.button()&1 && pose3d && (oX3d!=X3d || oY3d!=Y3d)) { // Left button: rotate
              const float
                R = 0.45f*std::min(view3d._width,view3d._height),
                R2 = R*R,
                u0 = (float)(oX3d - view3d.width()/2),
                v0 = (float)(oY3d - view3d.height()/2),
                u1 = (float)(X3d - view3d.width()/2),
                v1 = (float)(Y3d - view3d.height()/2),
                n0 = cimg::hypot(u0,v0),
                n1 = cimg::hypot(u1,v1),
                nu0 = n0>R?(u0*R/n0):u0,
                nv0 = n0>R?(v0*R/n0):v0,
                nw0 = (float)std::sqrt(std::max(0.f,R2 - nu0*nu0 - nv0*nv0)),
                nu1 = n1>R?(u1*R/n1):u1,
                nv1 = n1>R?(v1*R/n1):v1,
                nw1 = (float)std::sqrt(std::max(0.f,R2 - nu1*nu1 - nv1*nv1)),
                u = nv0*nw1 - nw0*nv1,
                v = nw0*nu1 - nu0*nw1,
                w = nv0*nu1 - nu0*nv1,
                n = cimg::hypot(u,v,w),
                alpha = (float)std::asin(n/R2)*180/cimg::PI;
              pose3d.draw_image(CImg<floatT>::rotation_matrix(u,v,w,-alpha)*pose3d.get_crop(0,0,2,2));
              view3d.assign();
            } else if (disp.button()&2 && pose3d && oY3d!=Y3d) {  // Right button: zoom
              pose3d(3,2)+=(Y3d - oY3d)*1.5f; view3d.assign();
            }
            if (disp.wheel()) { // Wheel: zoom
              pose3d(3,2)-=disp.wheel()*15; view3d.assign(); disp.set_wheel();
            }
            if (disp.button()&4 && pose3d && (oX3d!=X3d || oY3d!=Y3d)) { // Middle button: shift
              pose3d(3,0)-=oX3d - X3d; pose3d(3,1)-=oY3d - Y3d; view3d.assign();
            }
            oX3d = X3d; oY3d = Y3d;
          }
          mx = my = -1; X = Y = Z = -1;
          break;
        }

        if (phase) {
          if (!feature_type) shape_selected = phase?true:false;
          else {
            if (_depth>1) shape_selected = (phase==3)?true:false;
            else shape_selected = (phase==2)?true:false;
          }
        }

        if (X0<0) X0 = 0;
        if (X0>=width()) X0 = width() - 1;
        if (Y0<0) Y0 = 0;
        if (Y0>=height()) Y0 = height() - 1;
        if (Z0<0) Z0 = 0;
        if (Z0>=depth()) Z0 = depth() - 1;
        if (X1<1) X1 = 0;
        if (X1>=width()) X1 = width() - 1;
        if (Y1<0) Y1 = 0;
        if (Y1>=height()) Y1 = height() - 1;
        if (Z1<0) Z1 = 0;
        if (Z1>=depth()) Z1 = depth() - 1;

        // Draw visualization image on the display
        if (mx!=omx || my!=omy || !visu0 || (_depth>1 && !view3d)) {

          if (!visu0) { // Create image of projected planes
            if (thumb) thumb._get_select(disp,old_normalization,phase?X1:X0,phase?Y1:Y0,phase?Z1:Z0).move_to(visu0);
            else _get_select(disp,old_normalization,phase?X1:X0,phase?Y1:Y0,phase?Z1:Z0).move_to(visu0);
            visu0.resize(disp);
            view3d.assign();
            points3d.assign();
          }

          if (is_view3d && _depth>1 && !view3d) { // Create 3D view for volumetric images
            const unsigned int
              _x3d = (unsigned int)cimg::round((float)_width*visu0._width/(_width + _depth),1,1),
              _y3d = (unsigned int)cimg::round((float)_height*visu0._height/(_height + _depth),1,1),
              x3d = _x3d>=visu0._width?visu0._width - 1:_x3d,
              y3d = _y3d>=visu0._height?visu0._height - 1:_y3d;
            CImg<ucharT>(1,2,1,1,64,128).resize(visu0._width - x3d,visu0._height - y3d,1,visu0._spectrum,3).
              move_to(view3d);
            if (!points3d) {
              get_projections3d(primitives3d,colors3d,phase?X1:X0,phase?Y1:Y0,phase?Z1:Z0,true).move_to(points3d);
              points3d.append(CImg<floatT>(8,3,1,1,
                                           0,_width - 1,_width - 1,0,0,_width - 1,_width - 1,0,
                                           0,0,_height - 1,_height - 1,0,0,_height - 1,_height - 1,
                                           0,0,0,0,_depth - 1,_depth - 1,_depth - 1,_depth - 1),'x');
              CImg<uintT>::vector(12,13).move_to(primitives3d); CImg<uintT>::vector(13,14).move_to(primitives3d);
              CImg<uintT>::vector(14,15).move_to(primitives3d); CImg<uintT>::vector(15,12).move_to(primitives3d);
              CImg<uintT>::vector(16,17).move_to(primitives3d); CImg<uintT>::vector(17,18).move_to(primitives3d);
              CImg<uintT>::vector(18,19).move_to(primitives3d); CImg<uintT>::vector(19,16).move_to(primitives3d);
              CImg<uintT>::vector(12,16).move_to(primitives3d); CImg<uintT>::vector(13,17).move_to(primitives3d);
              CImg<uintT>::vector(14,18).move_to(primitives3d); CImg<uintT>::vector(15,19).move_to(primitives3d);
              colors3d.insert(12,CImg<ucharT>::vector(255,255,255));
              opacities3d.assign(primitives3d.width(),1,1,1,0.5f);
              if (!phase) {
                opacities3d[0] = opacities3d[1] = opacities3d[2] = 0.8f;
                sel_primitives3d.assign();
                sel_colors3d.assign();
                sel_opacities3d.assign();
              } else {
                if (feature_type==2) {
                  points3d.append(CImg<floatT>(8,3,1,1,
                                               X0,X1,X1,X0,X0,X1,X1,X0,
                                               Y0,Y0,Y1,Y1,Y0,Y0,Y1,Y1,
                                               Z0,Z0,Z0,Z0,Z1,Z1,Z1,Z1),'x');
                  sel_primitives3d.assign();
                  CImg<uintT>::vector(20,21).move_to(sel_primitives3d);
                  CImg<uintT>::vector(21,22).move_to(sel_primitives3d);
                  CImg<uintT>::vector(22,23).move_to(sel_primitives3d);
                  CImg<uintT>::vector(23,20).move_to(sel_primitives3d);
                  CImg<uintT>::vector(24,25).move_to(sel_primitives3d);
                  CImg<uintT>::vector(25,26).move_to(sel_primitives3d);
                  CImg<uintT>::vector(26,27).move_to(sel_primitives3d);
                  CImg<uintT>::vector(27,24).move_to(sel_primitives3d);
                  CImg<uintT>::vector(20,24).move_to(sel_primitives3d);
                  CImg<uintT>::vector(21,25).move_to(sel_primitives3d);
                  CImg<uintT>::vector(22,26).move_to(sel_primitives3d);
                  CImg<uintT>::vector(23,27).move_to(sel_primitives3d);
                } else {
                  points3d.append(CImg<floatT>(2,3,1,1,
                                               X0,X1,
                                               Y0,Y1,
                                               Z0,Z1),'x');
                  sel_primitives3d.assign(CImg<uintT>::vector(20,21));
                }
                sel_colors3d.assign(sel_primitives3d._width,CImg<ucharT>::vector(255,255,255));
                sel_opacities3d.assign(sel_primitives3d._width,1,1,1,0.8f);
              }
              points3d.shift_object3d(-0.5f*(_width - 1),-0.5f*(_height - 1),-0.5f*(_depth - 1)).resize_object3d();
              points3d*=0.75f*std::min(view3d._width,view3d._height);
            }

            if (!pose3d) CImg<floatT>(4,3,1,1, 1,0,0,0, 0,1,0,0, 0,0,1,0).move_to(pose3d);
            CImg<floatT> zbuffer3d(view3d._width,view3d._height,1,1,0);
            const CImg<floatT> rotated_points3d = pose3d.get_crop(0,0,2,2)*points3d;
            if (sel_primitives3d)
              view3d.draw_object3d(pose3d(3,0) + 0.5f*view3d._width,
                                   pose3d(3,1) + 0.5f*view3d._height,
                                   pose3d(3,2),
                                   rotated_points3d,sel_primitives3d,sel_colors3d,sel_opacities3d,
                                   2,true,500,0,0,0,0,0,1,zbuffer3d);
            view3d.draw_object3d(pose3d(3,0) + 0.5f*view3d._width,
                                 pose3d(3,1) + 0.5f*view3d._height,
                                 pose3d(3,2),
                                 rotated_points3d,primitives3d,colors3d,opacities3d,
                                 2,true,500,0,0,0,0,0,1,zbuffer3d);
            visu0.draw_image(x3d,y3d,view3d);
          }
          visu = visu0;

          if (X<0 || Y<0 || Z<0) { if (!visible_cursor) { disp.show_mouse(); visible_cursor = true; }}
          else {
            if (is_axes) { if (visible_cursor) { disp.hide_mouse(); visible_cursor = false; }}
            else { if (!visible_cursor) { disp.show_mouse(); visible_cursor = true; }}
            const int d = (depth()>1)?depth():0;
            int _vX = (int)X, _vY = (int)Y, _vZ = (int)Z;
            if (phase>=2) { _vX = X1; _vY = Y1; _vZ = Z1; }
            int
              w = disp.width(), W = width() + d,
              h = disp.height(), H = height() + d,
              _xp = (int)(_vX*(float)w/W), xp = _xp + ((int)(_xp*(float)W/w)!=_vX),
              _yp = (int)(_vY*(float)h/H), yp = _yp + ((int)(_yp*(float)H/h)!=_vY),
              _xn = (int)((_vX + 1.f)*w/W - 1), xn = _xn + ((int)((_xn + 1.f)*W/w)!=_vX + 1),
              _yn = (int)((_vY + 1.f)*h/H - 1), yn = _yn + ((int)((_yn + 1.f)*H/h)!=_vY + 1),
              _zxp = (int)((_vZ + width())*(float)w/W), zxp = _zxp + ((int)(_zxp*(float)W/w)!=_vZ + width()),
              _zyp = (int)((_vZ + height())*(float)h/H), zyp = _zyp + ((int)(_zyp*(float)H/h)!=_vZ + height()),
              _zxn = (int)((_vZ + width() + 1.f)*w/W - 1),
                       zxn = _zxn + ((int)((_zxn + 1.f)*W/w)!=_vZ + width() + 1),
              _zyn = (int)((_vZ + height() + 1.f)*h/H - 1),
                       zyn = _zyn + ((int)((_zyn + 1.f)*H/h)!=_vZ + height() + 1),
              _xM = (int)(width()*(float)w/W - 1), xM = _xM + ((int)((_xM + 1.f)*W/w)!=width()),
              _yM = (int)(height()*(float)h/H - 1), yM = _yM + ((int)((_yM + 1.f)*H/h)!=height()),
              xc = (xp + xn)/2,
              yc = (yp + yn)/2,
              zxc = (zxp + zxn)/2,
              zyc = (zyp + zyn)/2,
              xf = (int)(X*w/W),
              yf = (int)(Y*h/H),
              zxf = (int)((Z + width())*w/W),
              zyf = (int)((Z + height())*h/H);

            if (is_axes) { // Draw axes
              visu.draw_line(0,yf,visu.width() - 1,yf,foreground_color,0.7f,0xFF00FF00).
                draw_line(0,yf,visu.width() - 1,yf,background_color,0.7f,0x00FF00FF).
                draw_line(xf,0,xf,visu.height() - 1,foreground_color,0.7f,0xFF00FF00).
                draw_line(xf,0,xf,visu.height() - 1,background_color,0.7f,0x00FF00FF);
              if (_depth>1)
                visu.draw_line(zxf,0,zxf,yM,foreground_color,0.7f,0xFF00FF00).
                  draw_line(zxf,0,zxf,yM,background_color,0.7f,0x00FF00FF).
                  draw_line(0,zyf,xM,zyf,foreground_color,0.7f,0xFF00FF00).
                  draw_line(0,zyf,xM,zyf,background_color,0.7f,0x00FF00FF);
            }

            // Draw box cursor.
            if (xn - xp>=4 && yn - yp>=4)
              visu.draw_rectangle(xp,yp,xn,yn,foreground_color,0.2f).
                draw_rectangle(xp,yp,xn,yn,foreground_color,1,0xAAAAAAAA).
                draw_rectangle(xp,yp,xn,yn,background_color,1,0x55555555);
            if (_depth>1) {
              if (yn - yp>=4 && zxn - zxp>=4)
                visu.draw_rectangle(zxp,yp,zxn,yn,background_color,0.2f).
                                              draw_rectangle(zxp,yp,zxn,yn,foreground_color,1,0xAAAAAAAA).
                                              draw_rectangle(zxp,yp,zxn,yn,background_color,1,0x55555555);
              if (xn - xp>=4 && zyn - zyp>=4)
                visu.draw_rectangle(xp,zyp,xn,zyn,background_color,0.2f).
                          draw_rectangle(xp,zyp,xn,zyn,foreground_color,1,0xAAAAAAAA).
                          draw_rectangle(xp,zyp,xn,zyn,background_color,1,0x55555555);
            }

            // Draw selection.
            if (phase && (phase!=1 || area_started==area)) {
              const int
                _xp0 = (int)(X0*(float)w/W), xp0 = _xp0 + ((int)(_xp0*(float)W/w)!=X0),
                _yp0 = (int)(Y0*(float)h/H), yp0 = _yp0 + ((int)(_yp0*(float)H/h)!=Y0),
                _xn0 = (int)((X0 + 1.f)*w/W - 1), xn0 = _xn0 + ((int)((_xn0 + 1.f)*W/w)!=X0 + 1),
                _yn0 = (int)((Y0 + 1.f)*h/H - 1), yn0 = _yn0 + ((int)((_yn0 + 1.f)*H/h)!=Y0 + 1),
                _zxp0 = (int)((Z0 + width())*(float)w/W), zxp0 = _zxp0 + ((int)(_zxp0*(float)W/w)!=Z0 + width()),
                _zyp0 = (int)((Z0 + height())*(float)h/H), zyp0 = _zyp0 + ((int)(_zyp0*(float)H/h)!=Z0 + height()),
                _zxn0 = (int)((Z0 + width() + 1.f)*w/W - 1),
                zxn0 = _zxn0 + ((int)((_zxn0 + 1.f)*W/w)!=Z0 + width() + 1),
                _zyn0 = (int)((Z0 + height() + 1.f)*h/H - 1),
                zyn0 = _zyn0 + ((int)((_zyn0 + 1.f)*H/h)!=Z0 + height() + 1),
                xc0 = (xp0 + xn0)/2,
                yc0 = (yp0 + yn0)/2,
                zxc0 = (zxp0 + zxn0)/2,
                zyc0 = (zyp0 + zyn0)/2;

              switch (feature_type) {
              case 1 : { // Vector
                visu.draw_arrow(xc0,yc0,xc,yc,background_color,0.9f,30,5,0x33333333).
                  draw_arrow(xc0,yc0,xc,yc,foreground_color,0.9f,30,5,0xCCCCCCCC);
                if (d) {
                  visu.draw_arrow(zxc0,yc0,zxc,yc,background_color,0.9f,30,5,0x33333333).
                    draw_arrow(zxc0,yc0,zxc,yc,foreground_color,0.9f,30,5,0xCCCCCCCC).
                    draw_arrow(xc0,zyc0,xc,zyc,background_color,0.9f,30,5,0x33333333).
                    draw_arrow(xc0,zyc0,xc,zyc,foreground_color,0.9f,30,5,0xCCCCCCCC);
                }
              } break;
              case 2 : { // Box
                visu.draw_rectangle(X0<X1?xp0:xp,Y0<Y1?yp0:yp,X0<X1?xn:xn0,Y0<Y1?yn:yn0,background_color,0.2f).
                  draw_rectangle(X0<X1?xp0:xp,Y0<Y1?yp0:yp,X0<X1?xn:xn0,Y0<Y1?yn:yn0,background_color,0.9f,0x55555555).
                  draw_rectangle(X0<X1?xp0:xp,Y0<Y1?yp0:yp,X0<X1?xn:xn0,Y0<Y1?yn:yn0,foreground_color,0.9f,0xAAAAAAAA);
                if (xc0!=xc && yc0!=yc)
                  visu.draw_line(xc0,yc0,xc,yc,background_color,0.9f,0x33333333).
                    draw_line(xc0,yc0,xc,yc,foreground_color,0.9f,0xCCCCCCCC);
                if (d) {
                  visu.draw_rectangle(Z0<Z1?zxp0:zxp,Y0<Y1?yp0:yp,Z0<Z1?zxn:zxn0,Y0<Y1?yn:yn0,background_color,0.2f).
                    draw_rectangle(Z0<Z1?zxp0:zxp,Y0<Y1?yp0:yp,Z0<Z1?zxn:zxn0,Y0<Y1?yn:yn0,
                                   background_color,0.9f,0x55555555).
                    draw_rectangle(Z0<Z1?zxp0:zxp,Y0<Y1?yp0:yp,Z0<Z1?zxn:zxn0,Y0<Y1?yn:yn0,
                                   foreground_color,0.9f,0xAAAAAAAA);
                  if (zxc0!=zxc && yc0!=yc)
                    visu.draw_line(zxc0,yc0,zxc,yc,background_color,0.9f,0x33333333).
                      draw_line(zxc0,yc0,zxc,yc,foreground_color,0.9f,0xCCCCCCCC);
                  visu.draw_rectangle(X0<X1?xp0:xp,Z0<Z1?zyp0:zyp,X0<X1?xn:xn0,Z0<Z1?zyn:zyn0,
                                      background_color,0.2f).
                    draw_rectangle(X0<X1?xp0:xp,Z0<Z1?zyp0:zyp,X0<X1?xn:xn0,Z0<Z1?zyn:zyn0,
                                   background_color,0.9f,0x55555555).
                    draw_rectangle(X0<X1?xp0:xp,Z0<Z1?zyp0:zyp,X0<X1?xn:xn0,Z0<Z1?zyn:zyn0,
                                   foreground_color,0.9f,0xAAAAAAAA);
                  if (xp0!=xn && zyp0!=zyn)
                    visu.draw_line(xp0,zyp0,xn,zyn,background_color,0.9f,0x33333333).
                      draw_line(xp0,zyp0,xn,zyn,foreground_color,0.9f,0xCCCCCCCC);
                }
              } break;
              case 3 : { // Ellipse
                visu.draw_ellipse(xc0,yc0,
                                  (float)cimg::abs(xc - xc0),
                                  (float)cimg::abs(yc - yc0),0,background_color,0.2f).
                  draw_ellipse(xc0,yc0,
                               (float)cimg::abs(xc - xc0),
                               (float)cimg::abs(yc - yc0),0,foreground_color,0.9f,~0U).
                  draw_point(xc0,yc0,foreground_color,0.9f);
                if (d) {
                  visu.draw_ellipse(zxc0,yc0,(float)cimg::abs(zxc - zxc0),(float)cimg::abs(yc - yc0),0,
                                    background_color,0.2f).
                    draw_ellipse(zxc0,yc0,(float)cimg::abs(zxc - zxc0),(float)cimg::abs(yc - yc0),0,
                                 foreground_color,0.9f,~0U).
                    draw_point(zxc0,yc0,foreground_color,0.9f).
                    draw_ellipse(xc0,zyc0,(float)cimg::abs(xc - xc0),(float)cimg::abs(zyc - zyc0),0,
                                 background_color,0.2f).
                    draw_ellipse(xc0,zyc0,(float)cimg::abs(xc - xc0),(float)cimg::abs(zyc - zyc0),0,
                                 foreground_color,0.9f,~0U).
                    draw_point(xc0,zyc0,foreground_color,0.9f);
                }
              } break;
              }
            }

            // Draw text info.
            if (my>=0 && my<13) text_down = true; else if (my>=visu.height() - 13) text_down = false;
            if (!feature_type || !phase) {
              if (X>=0 && Y>=0 && Z>=0 && X<width() && Y<height() && Z<depth()) {
                if (_depth>1 || force_display_z_coord)
                  cimg_snprintf(text,text._width," Point (%d,%d,%d) = [ ",origX + (int)X,origY + (int)Y,origZ + (int)Z);
                else cimg_snprintf(text,text._width," Point (%d,%d) = [ ",origX + (int)X,origY + (int)Y);
                CImg<T> values = get_vector_at((int)X,(int)Y,(int)Z);
                const bool is_large_spectrum = values._height>8;
                if (is_large_spectrum)
                  values.draw_image(0,4,values.get_rows(values._height - 4,values._height - 1)).resize(1,8,1,1,0);
                char *ctext = text._data + std::strlen(text), *const ltext = text._data + 512;
                for (unsigned int c = 0; c<values._height && ctext<ltext; ++c) {
                  cimg_snprintf(ctext,24,cimg::type<T>::format_s(),
                                cimg::type<T>::format(values[c]));
                  ctext += std::strlen(ctext);
                  if (c==3 && is_large_spectrum) {
                    cimg_snprintf(ctext,24," ...");
                    ctext += std::strlen(ctext);
                  }
                  *(ctext++) = ' '; *ctext = 0;
                }
                std::strcpy(text._data + std::strlen(text),"] ");
              }
            } else switch (feature_type) {
              case 1 : {
                const double dX = (double)(X0 - X1), dY = (double)(Y0 - Y1), dZ = (double)(Z0 - Z1),
                  length = cimg::round(cimg::hypot(dX,dY,dZ),0.1);
                if (_depth>1 || force_display_z_coord)
                  cimg_snprintf(text,text._width," Vect (%d,%d,%d)-(%d,%d,%d), Length = %g ",
                                origX + X0,origY + Y0,origZ + Z0,origX + X1,origY + Y1,origZ + Z1,length);
                else if (_width!=1 && _height!=1)
                  cimg_snprintf(text,text._width," Vect (%d,%d)-(%d,%d), Length = %g, Angle = %g\260 ",
                                origX + X0,origY + Y0,origX + X1,origY + Y1,length,
                                cimg::round(cimg::mod(180*std::atan2(-dY,-dX)/cimg::PI,360.),0.1));
                else
                  cimg_snprintf(text,text._width," Vect (%d,%d)-(%d,%d), Length = %g ",
                                origX + X0,origY + Y0,origX + X1,origY + Y1,length);
              } break;
              case 2 : {
                const double dX = (double)(X0 - X1), dY = (double)(Y0 - Y1), dZ = (double)(Z0 - Z1),
                  length = cimg::round(cimg::hypot(dX,dY,dZ),0.1);
                if (_depth>1 || force_display_z_coord)
                  cimg_snprintf(text,text._width,
                                " Box ( %d,%d,%d ) - ( %d,%d,%d )\n Size = ( %d,%d,%d ), Length = %g ",
                                origX + (X0<X1?X0:X1),origY + (Y0<Y1?Y0:Y1),origZ + (Z0<Z1?Z0:Z1),
                                origX + (X0<X1?X1:X0),origY + (Y0<Y1?Y1:Y0),origZ + (Z0<Z1?Z1:Z0),
                                1 + cimg::abs(X0 - X1),1 + cimg::abs(Y0 - Y1),1 + cimg::abs(Z0 - Z1),length);
                else if (_width!=1 && _height!=1)
                  cimg_snprintf(text,text._width,
                                " Box ( %d,%d ) - ( %d,%d )\n Size = ( %d,%d ), Length = %g \n Angle = %g\260 ",
                                origX + (X0<X1?X0:X1),origY + (Y0<Y1?Y0:Y1),
                                origX + (X0<X1?X1:X0),origY + (Y0<Y1?Y1:Y0),
                                1 + cimg::abs(X0 - X1),1 + cimg::abs(Y0 - Y1),length,
                                cimg::round(cimg::mod(180*std::atan2(-dY,-dX)/cimg::PI,360.),0.1));
                else
                  cimg_snprintf(text,text._width,
                                " Box ( %d,%d ) - ( %d,%d )\n Size = (%d,%d), Length = %g ",
                                origX + (X0<X1?X0:X1),origY + (Y0<Y1?Y0:Y1),
                                origX + (X0<X1?X1:X0),origY + (Y0<Y1?Y1:Y0),
                                1 + cimg::abs(X0 - X1),1 + cimg::abs(Y0 - Y1),length);
              } break;
              default :
                if (_depth>1 || force_display_z_coord)
                  cimg_snprintf(text,text._width," Ellipse ( %d,%d,%d ) - ( %d,%d,%d ), Radii = ( %d,%d,%d ) ",
                                origX + X0,origY + Y0,origZ + Z0,origX + X1,origY + Y1,origZ + Z1,
                                1 + cimg::abs(X0 - X1),1 + cimg::abs(Y0 - Y1),1 + cimg::abs(Z0 - Z1));
                else cimg_snprintf(text,text._width," Ellipse ( %d,%d ) - ( %d,%d ), Radii = ( %d,%d ) ",
                                   origX + X0,origY + Y0,origX + X1,origY + Y1,
                                   1 + cimg::abs(X0 - X1),1 + cimg::abs(Y0 - Y1));
              }
            if (phase || (mx>=0 && my>=0)) visu.__draw_text("%s",(int)text_down,text._data);
          }

          disp.display(visu);
        }
        if (!shape_selected) disp.wait();
        if (disp.is_resized()) { disp.resize(false)._is_resized = false; old_is_resized = true; visu0.assign(); }
        omx = mx; omy = my;
        if (!exit_on_anykey && key && key!=cimg::keyESC &&
            (key!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) {
          key = 0;
        }
      }

      // Return result.
      CImg<intT> res(1,feature_type==0?3:6,1,1,-1);
      if (XYZ) { XYZ[0] = (unsigned int)X0; XYZ[1] = (unsigned int)Y0; XYZ[2] = (unsigned int)Z0; }
      if (shape_selected) {
        if (feature_type==2) {
          if (is_deep_selection) switch (area_started) {
            case 1 : Z0 = 0; Z1 = _depth - 1; break;
            case 2 : Y0 = 0; Y1 = _height - 1; break;
            case 3 : X0 = 0; X1 = _width - 1; break;
          }
          if (X0>X1) cimg::swap(X0,X1);
          if (Y0>Y1) cimg::swap(Y0,Y1);
          if (Z0>Z1) cimg::swap(Z0,Z1);
        }
	if (X1<0 || Y1<0 || Z1<0) X0 = Y0 = Z0 = X1 = Y1 = Z1 = -1;
	switch (feature_type) {
	case 1 : case 2 : res[0] = X0; res[1] = Y0; res[2] = Z0; res[3] = X1; res[4] = Y1; res[5] = Z1; break;
        case 3 :
          res[3] = cimg::abs(X1 - X0); res[4] = cimg::abs(Y1 - Y0); res[5] = cimg::abs(Z1 - Z0);
          res[0] = X0; res[1] = Y0; res[2] = Z0;
          break;
	default : res[0] = X0; res[1] = Y0; res[2] = Z0;
	}
      }
      if (!exit_on_anykey || !(disp.button()&4)) disp.set_button();
      if (!visible_cursor) disp.show_mouse();
      disp._normalization = old_normalization;
      disp._is_resized = old_is_resized;
      if (key!=~0U) disp.set_key(key);
      return res;

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& distance_eikonal(const T& value, const CImg<t>& metric) {
      return get_distance_eikonal(value,metric).move_to(*this);

Project: CImg
File: CImg.h


      static double mp_vector_map_vv(_cimg_math_parser& mp) { // Operator(vector,vector)
        unsigned int
          siz = (unsigned int)mp.opcode[2],
          ptrs1 = (unsigned int)mp.opcode[4] + 1,
          ptrs2 = (unsigned int)mp.opcode[5] + 1;
        double *ptrd = &_mp_arg(1) + 1;
        mp_func op = (mp_func)mp.opcode[3];
        CImg<ulongT> l_opcode(1,4);
        l_opcode.swap(mp.opcode);
        ulongT &argument1 = mp.opcode[2], &argument2 = mp.opcode[3];
        while (siz-->0) { argument1 = ptrs1++; argument2 = ptrs2++; *(ptrd++) = (*op)(mp); }
        l_opcode.swap(mp.opcode);
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& set_tensor_at(const CImg<t>& ten, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
      T *ptrd = data(x,y,z,0);
      const ulongT siz = (ulongT)_width*_height*_depth;
      if (ten._height==2) {
        *ptrd = (T)ten[0]; ptrd+=siz;
        *ptrd = (T)ten[1]; ptrd+=siz;
        *ptrd = (T)ten[3];
      }
      else {
        *ptrd = (T)ten[0]; ptrd+=siz;
        *ptrd = (T)ten[1]; ptrd+=siz;
        *ptrd = (T)ten[2]; ptrd+=siz;
        *ptrd = (T)ten[4]; ptrd+=siz;
        *ptrd = (T)ten[5]; ptrd+=siz;
        *ptrd = (T)ten[8];
      }
      return *this;

Project: CImg
File: CImg.h

    template<typename t>
    CImg(const t *const values, const unsigned int size_x, const unsigned int size_y=1,
         const unsigned int size_z=1, const unsigned int size_c=1, const bool is_shared=false):_is_shared(false) {
      if (is_shared) {
        _width = _height = _depth = _spectrum = 0; _data = 0;
        throw CImgArgumentException(_cimg_instance
                                    "CImg(): Invalid construction request of a (%u,%u,%u,%u) shared instance "
                                    "from a (%s*) buffer (pixel types are different).",
                                    cimg_instance,
                                    size_x,size_y,size_z,size_c,CImg<t>::pixel_type());
      }
      const size_t siz = (size_t)size_x*size_y*size_z*size_c;
      if (values && siz) {
        _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c;
        try { _data = new T[siz]; } catch (...) {
          _width = _height = _depth = _spectrum = 0; _data = 0;
          throw CImgInstanceException(_cimg_instance
                                      "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
                                      cimg_instance,
                                      cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c),
                                      size_x,size_y,size_z,size_c);

        }
        const t *ptrs = values; cimg_for(*this,ptrd,T) *ptrd = (T)*(ptrs++);
      } else { _width = _height = _depth = _spectrum = 0; _data = 0; }

Project: CImg
File: CImg.h

    **/
    bool is_shared() const {
      return _is_shared;

Project: CImg
File: CImg.h


      static double mp_draw(_cimg_math_parser& mp) {
        const int x = (int)_mp_arg(4), y = (int)_mp_arg(5), z = (int)_mp_arg(6), c = (int)_mp_arg(7);
        unsigned int ind = (unsigned int)mp.opcode[3];

        if (ind!=~0U) ind = (unsigned int)cimg::mod((int)_mp_arg(3),mp.listin.width());
        CImg<T> &img = ind==~0U?mp.imgout:mp.listout[ind];
        unsigned int
          dx = (unsigned int)mp.opcode[8],
          dy = (unsigned int)mp.opcode[9],
          dz = (unsigned int)mp.opcode[10],
          dc = (unsigned int)mp.opcode[11];
        dx = dx==~0U?img._width:(unsigned int)_mp_arg(8);
        dy = dy==~0U?img._height:(unsigned int)_mp_arg(9);
        dz = dz==~0U?img._depth:(unsigned int)_mp_arg(10);
        dc = dc==~0U?img._spectrum:(unsigned int)_mp_arg(11);

        const ulongT sizS = mp.opcode[2];
        if (sizS<(ulongT)dx*dy*dz*dc)
          throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'draw()': "
                                      "Sprite dimension (%lu values) and specified sprite geometry (%u,%u,%u,%u) "
                                      "(%lu values) do not match.",
                                      mp.imgin.pixel_type(),sizS,dx,dy,dz,dc,(ulongT)dx*dy*dz*dc);
        CImg<doubleT> S(&_mp_arg(1) + 1,dx,dy,dz,dc,true);
        const float opacity = (float)_mp_arg(12);

        if (img._data) {
          if (mp.opcode[13]!=~0U) { // Opacity mask specified
            const ulongT sizM = mp.opcode[14];
            if (sizM<(ulongT)dx*dy*dz)
              throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'draw()': "
                                          "Mask dimension (%lu values) and specified sprite geometry (%u,%u,%u,%u) "
                                          "(%lu values) do not match.",
                                          mp.imgin.pixel_type(),sizS,dx,dy,dz,dc,(ulongT)dx*dy*dz*dc);
            const CImg<doubleT> M(&_mp_arg(13) + 1,dx,dy,dz,(unsigned int)(sizM/(dx*dy*dz)),true);
            img.draw_image(x,y,z,c,S,M,opacity,(float)_mp_arg(15));
          } else img.draw_image(x,y,z,c,S,opacity);
        }
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

    //! Access to pixel value with Dirichlet boundary conditions for the 2 coordinates (\c pos,\c x) \const.
    T atNX(const int pos, const int x, const int y, const int z, const int c, const T& out_value) const {
      return (pos<0 || pos>=width())?out_value:_data[pos].atX(x,y,z,c,out_value);

Project: CImg
File: CImg.h


      static double mp_set_Jxyz_v(_cimg_math_parser& mp) {
        CImg<T> &img = mp.imgout;
        const double ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y], oz = mp.mem[_cimg_mp_slot_z];
        const int
          x = (int)(ox + _mp_arg(2)),
          y = (int)(oy + _mp_arg(3)),
          z = (int)(oz + _mp_arg(4));
        const double *ptrs = &_mp_arg(1) + 1;
        if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {
          const unsigned int vsiz = (unsigned int)mp.opcode[5];
          T *ptrd = &img(x,y,z);
          const ulongT whd = (ulongT)img._width*img._height*img._depth;
          cimg_for_inC(img,0,vsiz - 1,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }
        }
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

    template<typename T>
    inline size_t fwrite(const T *ptr, const size_t nmemb, std::FILE *stream) {
      if (!ptr || !stream)
        throw CImgArgumentException("cimg::fwrite(): Invalid writing request of %u %s%s from buffer %p to file %p.",
                                    nmemb,cimg::type<T>::string(),nmemb>1?"s":"",ptr,stream);
      if (!nmemb) return 0;
      const size_t wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T);
      size_t to_write = nmemb, al_write = 0, l_to_write = 0, l_al_write = 0;
      do {
        l_to_write = (to_write*sizeof(T))<wlimitT?to_write:wlimit;
        l_al_write = std::fwrite((void*)(ptr + al_write),sizeof(T),l_to_write,stream);
        al_write+=l_al_write;
        to_write-=l_al_write;
      } while (l_to_write==l_al_write && to_write>0);
      if (to_write>0)
        warn("cimg::fwrite(): Only %lu/%lu elements could be written in file.",
             (unsigned long)al_write,(unsigned long)nmemb);
      return al_write;

Project: CImg
File: CImg.h


    static int screen_height() {
      DEVMODE mode;
      mode.dmSize = sizeof(DEVMODE);
      mode.dmDriverExtra = 0;
      EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode);
      return (int)mode.dmPelsHeight;

Project: CImg
File: CImg.h


    CImg<T>& _load_analyze(std::FILE *const file, const char *const filename, float *const voxel_size=0) {
      if (!file && !filename)
        throw CImgArgumentException(_cimg_instance
                                    "load_analyze(): Specified filename is (null).",
                                    cimg_instance);

      std::FILE *nfile_header = 0, *nfile = 0;
      if (!file) {
        CImg<charT> body(1024);
        const char *const ext = cimg::split_filename(filename,body);
        if (!cimg::strcasecmp(ext,"hdr")) { // File is an Analyze header file
          nfile_header = cimg::fopen(filename,"rb");
          cimg_sprintf(body._data + std::strlen(body),".img");
          nfile = cimg::fopen(body,"rb");
        } else if (!cimg::strcasecmp(ext,"img")) { // File is an Analyze data file
          nfile = cimg::fopen(filename,"rb");
          cimg_sprintf(body._data + std::strlen(body),".hdr");
          nfile_header = cimg::fopen(body,"rb");
        } else nfile_header = nfile = cimg::fopen(filename,"rb"); // File is a Niftii file
      } else nfile_header = nfile = file; // File is a Niftii file
      if (!nfile || !nfile_header)
        throw CImgIOException(_cimg_instance
                              "load_analyze(): Invalid Analyze7.5 or NIFTI header in file '%s'.",
                              cimg_instance,
                              filename?filename:"(FILE*)");

      // Read header.
      bool endian = false;
      unsigned int header_size;
      cimg::fread(&header_size,1,nfile_header);
      if (!header_size)
        throw CImgIOException(_cimg_instance
                              "load_analyze(): Invalid zero-size header in file '%s'.",
                              cimg_instance,
                              filename?filename:"(FILE*)");
      if (header_size>=4096) { endian = true; cimg::invert_endianness(header_size); }

      unsigned char *const header = new unsigned char[header_size];
      cimg::fread(header + 4,header_size - 4,nfile_header);
      if (!file && nfile_header!=nfile) cimg::fclose(nfile_header);
      if (endian) {
        cimg::invert_endianness((short*)(header + 40),5);
        cimg::invert_endianness((short*)(header + 70),1);
        cimg::invert_endianness((short*)(header + 72),1);
        cimg::invert_endianness((float*)(header + 76),4);
        cimg::invert_endianness((float*)(header + 108),1);
        cimg::invert_endianness((float*)(header + 112),1);
      }

      if (nfile_header==nfile) {
        const unsigned int vox_offset = (unsigned int)*(float*)(header + 108);
        std::fseek(nfile,vox_offset,SEEK_SET);
      }

      unsigned short *dim = (unsigned short*)(header + 40), dimx = 1, dimy = 1, dimz = 1, dimv = 1;
      if (!dim[0])
        cimg::warn(_cimg_instance
                   "load_analyze(): File '%s' defines an image with zero dimensions.",
                   cimg_instance,
                   filename?filename:"(FILE*)");

      if (dim[0]>4)
        cimg::warn(_cimg_instance
                   "load_analyze(): File '%s' defines an image with %u dimensions, reading only the 4 first.",
                   cimg_instance,
                   filename?filename:"(FILE*)",dim[0]);

      if (dim[0]>=1) dimx = dim[1];
      if (dim[0]>=2) dimy = dim[2];
      if (dim[0]>=3) dimz = dim[3];
      if (dim[0]>=4) dimv = dim[4];
      float scalefactor = *(float*)(header + 112); if (scalefactor==0) scalefactor = 1;
      const unsigned short datatype = *(unsigned short*)(header + 70);
      if (voxel_size) {
        const float *vsize = (float*)(header + 76);
        voxel_size[0] = vsize[1]; voxel_size[1] = vsize[2]; voxel_size[2] = vsize[3];
      }
      delete[] header;

      // Read pixel data.
      assign(dimx,dimy,dimz,dimv);
      const size_t pdim = (size_t)dimx*dimy*dimz*dimv;
      switch (datatype) {
      case 2 : {
        unsigned char *const buffer = new unsigned char[pdim];
        cimg::fread(buffer,pdim,nfile);
        cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor);
        delete[] buffer;
      } break;
      case 4 : {
        short *const buffer = new short[pdim];
        cimg::fread(buffer,pdim,nfile);
        if (endian) cimg::invert_endianness(buffer,pdim);
        cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor);
        delete[] buffer;
      } break;
      case 8 : {
        int *const buffer = new int[pdim];
        cimg::fread(buffer,pdim,nfile);
        if (endian) cimg::invert_endianness(buffer,pdim);
        cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor);
        delete[] buffer;
      } break;
      case 16 : {
        float *const buffer = new float[pdim];
        cimg::fread(buffer,pdim,nfile);
        if (endian) cimg::invert_endianness(buffer,pdim);
        cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor);
        delete[] buffer;
      } break;
      case 64 : {
        double *const buffer = new double[pdim];
        cimg::fread(buffer,pdim,nfile);
        if (endian) cimg::invert_endianness(buffer,pdim);
        cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor);
        delete[] buffer;
      } break;
      default :
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "load_analyze(): Unable to load datatype %d in file '%s'",
                              cimg_instance,
                              datatype,filename?filename:"(FILE*)");
      }
      if (!file) cimg::fclose(nfile);
      return *this;

Project: CImg
File: CImg.h

    **/
    static int screen_width() {
      _no_display_exception();
      return 0;

Project: CImg
File: CImg.h

    //! Load image using ImageMagick's external tool 'convert' \newinstance.
    static CImg<T> get_load_imagemagick_external(const char *const filename) {
      return CImg<T>().load_imagemagick_external(filename);

Project: CImg
File: CImg.h


      static double mp_self_bitwise_and(_cimg_math_parser& mp) {
        double &val = _mp_arg(1);
        return val = (double)((longT)val & (longT)_mp_arg(2));

Project: CImg
File: CImg.h

      static double min() { return -DBL_MAX; }

Project: CImg
File: CImg.h

    **/
    CImg<T> get_shared_channel(const unsigned int c0) {
      return get_shared_channels(c0,c0);

Project: CImg
File: CImg.h

    //! Load image from a raw binary file \newinstance.
    static CImg<T> get_load_raw(std::FILE *const file,
                                const unsigned int size_x=0, const unsigned int size_y=1,
                                const unsigned int size_z=1, const unsigned int size_c=1,
                                const bool is_multiplexed=false, const bool invert_endianness=false,
                                const ulongT offset=0) {
      return CImg<T>().load_raw(file,size_x,size_y,size_z,size_c,is_multiplexed,invert_endianness,offset);

Project: CImg
File: CImg.h

    //! Return a \c 1x6 image containing specified values.
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5) {
      CImg<T> r(1,6); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5;
      return r;

Project: CImg
File: CImg.h

    /**
        \param axis Axis to split images along.
        \param nb Number of spliting parts for each image.

Project: CImg
File: CImg.h

    **/
    inline char *strellipsize(const char *const str, char *const res, const unsigned int l=64,
                              const bool is_ending=true) {
      const unsigned int nl = l<5?5:l, ls = (unsigned int)std::strlen(str);
      if (ls<=nl) { std::strcpy(res,str); return res; }
      if (is_ending) {
        std::strncpy(res,str,nl - 5);
        std::strcpy(res + nl -5,"(...)");
      } else {
        const unsigned int ll = (nl - 5)/2 + 1 - (nl%2), lr = nl - ll - 5;
        std::strncpy(res,str,ll);
        std::strcpy(res + ll,"(...)");
        std::strncpy(res + ll + 5,str + ls - lr,lr);
      }
      res[nl] = 0;
      return res;

Project: CImg
File: CImg.h

    **/
    CImg<T>& operator()(const unsigned int pos) {
#if cimg_verbosity>=3
      if (pos>=_width) {
        cimg::warn(_cimglist_instance
                   "operator(): Invalid image request, at position [%u].",
                   cimglist_instance,
                   pos);
        return *_data;
      }
#endif
      return _data[pos];

Project: CImg
File: CImg.h

    template<typename tp, typename tf, typename tc, typename to>
    CImg<T>& draw_object3d(LibBoard::Board& board,
                           const float x0, const float y0, const float z0,
                           const CImg<tp>& vertices, const CImgList<tf>& primitives,
                           const CImgList<tc>& colors, const CImg<to>& opacities,
                           const unsigned int render_type=4,
                           const bool is_double_sided=false, const float focale=700,
                           const float lightx=0, const float lighty=0, const float lightz=-5e8,
                           const float specular_lightness=0.2f, const float specular_shininess=0.1f,
                           const float g_opacity=1) {
      return draw_object3d(board,x0,y0,z0,vertices,primitives,colors,opacities,render_type,
                           is_double_sided,focale,lightx,lighty,lightz,
                           specular_lightness,specular_shininess,g_opacity,CImg<floatT>::empty());

Project: CImg
File: CImg.h

    //! Convert pixel values from RGB to sRGB color spaces \newinstance.
    CImg<Tfloat> get_RGBtosRGB() const {
      return CImg<Tfloat>(*this,false).RGBtosRGB();

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_circle(const int x0, const int y0, int radius,
                         const tc *const color, const float opacity=1) {
      if (is_empty()) return *this;
      if (radius<0 || x0 - radius>=width() || y0 + radius<0 || y0 - radius>=height()) return *this;
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_circle(): Specified color is (null).",
                                    cimg_instance);
      if (!radius) return draw_point(x0,y0,color,opacity);
      cimg_init_scanline(opacity);
      if (y0>=0 && y0<height()) cimg_draw_scanline(x0 - radius,x0 + radius,y0,color,opacity,1);
      for (int f = 1 - radius, ddFx = 0, ddFy = -(radius<<1), x = 0, y = radius; x<y; ) {
        if (f>=0) {
          const int x1 = x0 - x, x2 = x0 + x, y1 = y0 - y, y2 = y0 + y;
          if (y1>=0 && y1<height()) cimg_draw_scanline(x1,x2,y1,color,opacity,1);
          if (y2>=0 && y2<height()) cimg_draw_scanline(x1,x2,y2,color,opacity,1);
          f+=(ddFy+=2); --y;
        }
        const bool no_diag = y!=(x++);
        ++(f+=(ddFx+=2));
        const int x1 = x0 - y, x2 = x0 + y, y1 = y0 - x, y2 = y0 + x;
        if (no_diag) {
          if (y1>=0 && y1<height()) cimg_draw_scanline(x1,x2,y1,color,opacity,1);
          if (y2>=0 && y2<height()) cimg_draw_scanline(x1,x2,y2,color,opacity,1);
        }
      }
      return *this;

Project: CImg
File: CImg.h


      static double mp_complex_pow_ss(_cimg_math_parser& mp) {
        const double val1 = _mp_arg(2), val2 = _mp_arg(3);
        double *ptrd = &_mp_arg(1) + 1;
        _mp_complex_pow(val1,0,val2,0,ptrd);
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

    //! Resize 3D object to unit size \newinstance.
    CImg<Tfloat> get_resize_object3d() const {
      return CImg<Tfloat>(*this,false).resize_object3d();

Project: CImg
File: CImg.h

      static short inf() { return max(); }

Project: CImg
File: CImg.h

    //! Convert Ascii character to lower case.
    inline char lowercase(const char x) {
      return (char)((x<'A'||x>'Z')?x:x - 'A' + 'a');

Project: CImg
File: CImg.h

    template<typename t>
    CImg<_cimg_Tt> operator*(const t value) const {
      return CImg<_cimg_Tt>(*this,false)*=value;

Project: CImg
File: CImg.h


      static double mp_bitwise_not(_cimg_math_parser& mp) {
        // Limit result to 32bits such that it can be entirely represented as a 'double'.
        return (double)~(unsigned int)_mp_arg(2);

Project: CImg
File: CImg.h


      static double mp_min(_cimg_math_parser& mp) {
        const unsigned int i_end = (unsigned int)mp.opcode[2];
        double val = _mp_arg(3);
        for (unsigned int i = 4; i<i_end; ++i) val = std::min(val,_mp_arg(i));
        return val;

Project: CImg
File: CImg.h

     **/
    CImg<T>& operator-=(const char *const expression) {
      return *this-=(+*this)._fill(expression,true,1,0,0,"operator-=",this);

Project: CImg
File: CImg.h

    //! Display 1D graph in an interactive window \overloading.
    const CImg<T>& display_graph(const char *const title=0,
                                 const unsigned int plot_type=1, const unsigned int vertex_type=1,
                                 const char *const labelx=0, const double xmin=0, const double xmax=0,
                                 const char *const labely=0, const double ymin=0, const double ymax=0,
                                 const bool exit_on_anykey=false) const {
      CImgDisplay disp;
      return _display_graph(disp,title,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax,exit_on_anykey);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& operator>>=(const CImg<t>& img) {
      const ulongT siz = size(), isiz = img.size();
      if (siz && isiz) {
        if (is_overlapped(img)) return *this^=+img;
        T *ptrd = _data, *const ptre = _data + siz;
        if (siz>isiz) for (ulongT n = siz/isiz; n; --n)
          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)
            *ptrd = (T)((longT)*ptrd >> (int)*(ptrs++));
        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)((longT)*ptrd >> (int)*(ptrs++));
      }
      return *this;

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& assign(const CImg<t>& img) {
      return assign(img._data,img._width,img._height,img._depth,img._spectrum);

Project: CImg
File: CImg.h

    template<typename T>
    inline void getrs(char &TRANS, int &N, T *lapA, int *IPIV, T *lapB, int &INFO) {
      int one = 1;
      dgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO);

Project: CImg
File: CImg.h

       \param pos Index of the insertion.
       \param is_shared Tells if inserted images are shared copies of \c img or not.
    **/
    template<typename t>
    CImgList<T>& insert(const unsigned int n, const CImg<t>& img, const unsigned int pos=~0U,
                        const bool is_shared=false) {
      if (!n) return *this;
      const unsigned int npos = pos==~0U?_width:pos;

Project: CImg
File: CImg.h

      static bool is_nan(const int) { return false; }

Project: CImg
File: CImg.h


      static double mp_self_map_vector_v(_cimg_math_parser& mp) { // Vector += vector
        unsigned int
          ptrd = (unsigned int)mp.opcode[1] + 1,
          siz = (unsigned int)mp.opcode[2],
          ptrs = (unsigned int)mp.opcode[4] + 1;
        mp_func op = (mp_func)mp.opcode[3];
        CImg<ulongT> l_opcode(1,4);
        l_opcode.swap(mp.opcode);
        ulongT &target = mp.opcode[1], &argument = mp.opcode[2];
        while (siz-->0) { target = ptrd++; argument = ptrs++; (*op)(mp); }
        l_opcode.swap(mp.opcode);
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h


      static double mp_dot(_cimg_math_parser& mp) {
        const unsigned int siz = (unsigned int)mp.opcode[4];
        return CImg<doubleT>(&_mp_arg(2) + 1,1,siz,1,1,true).
          dot(CImg<doubleT>(&_mp_arg(3) + 1,1,siz,1,1,true));

Project: CImg
File: CImg.h


    const CImg<T>& _save_inr(std::FILE *const file, const char *const filename, const float *const voxel_size) const {
      if (!file && !filename)
        throw CImgArgumentException(_cimg_instance
                                    "save_inr(): Specified filename is (null).",
                                    cimg_instance);
      if (is_empty()) { cimg::fempty(file,filename); return *this; }

      int inrpixsize = -1;
      const char *inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0";
      if (!cimg::strcasecmp(pixel_type(),"unsigned char")) {
        inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1;
      }
      if (!cimg::strcasecmp(pixel_type(),"char")) {
        inrtype = "fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1;
      }
      if (!cimg::strcasecmp(pixel_type(),"unsigned short")) {
        inrtype = "unsigned fixed\nPIXSIZE=16 bits\nSCALE=2**0";inrpixsize = 2;
      }
      if (!cimg::strcasecmp(pixel_type(),"short")) {
        inrtype = "fixed\nPIXSIZE=16 bits\nSCALE=2**0"; inrpixsize = 2;
      }
      if (!cimg::strcasecmp(pixel_type(),"unsigned int")) {
        inrtype = "unsigned fixed\nPIXSIZE=32 bits\nSCALE=2**0";inrpixsize = 4;
      }
      if (!cimg::strcasecmp(pixel_type(),"int")) {
        inrtype = "fixed\nPIXSIZE=32 bits\nSCALE=2**0"; inrpixsize = 4;
      }
      if (!cimg::strcasecmp(pixel_type(),"float")) {
        inrtype = "float\nPIXSIZE=32 bits"; inrpixsize = 4;
      }
      if (!cimg::strcasecmp(pixel_type(),"double")) {
        inrtype = "float\nPIXSIZE=64 bits"; inrpixsize = 8;
      }
      if (inrpixsize<=0)
        throw CImgIOException(_cimg_instance
                              "save_inr(): Unsupported pixel type '%s' for file '%s'",
                              cimg_instance,
                              pixel_type(),filename?filename:"(FILE*)");

      std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
      CImg<charT> header(257);
      int err = cimg_snprintf(header,header._width,"#INRIMAGE-4#{\nXDIM=%u\nYDIM=%u\nZDIM=%u\nVDIM=%u\n",
                              _width,_height,_depth,_spectrum);
      if (voxel_size) err+=cimg_sprintf(header._data + err,"VX=%g\nVY=%g\nVZ=%g\n",
                                        voxel_size[0],voxel_size[1],voxel_size[2]);
      err+=cimg_sprintf(header._data + err,"TYPE=%s\nCPU=%s\n",inrtype,cimg::endianness()?"sun":"decm");
      std::memset(header._data + err,'\n',252 - err);
      std::memcpy(header._data + 252,"##}\n",4);
      cimg::fwrite(header._data,256,nfile);
      cimg_forXYZ(*this,x,y,z) cimg_forC(*this,c) cimg::fwrite(&((*this)(x,y,z,c)),1,nfile);
      if (!file) cimg::fclose(nfile);
      return *this;

Project: CImg
File: CImg.h

    **/
    CImg<T>& fillX(const unsigned int y, const unsigned int z, const unsigned int c, const int a0, ...) {
#define _cimg_fill1(x,y,z,c,off,siz,t) { \
    va_list ap; va_start(ap,a0); T *ptrd = data(x,y,z,c); *ptrd = (T)a0; \
    for (unsigned int k = 1; k<siz; ++k) { ptrd+=off; *ptrd = (T)va_arg(ap,t); } \
    va_end(ap); }
      if (y<_height && z<_depth && c<_spectrum) _cimg_fill1(0,y,z,c,1,_width,int);
      return *this;

Project: CImg
File: CImg.h


    T _atNXYZC(const int pos, const int x, const int y, const int z, const int c) const {
      return _data[cimg::cut(pos,0,width() - 1)].atXYZC(x,y,z,c);

Project: CImg
File: CImg.h


    CImgDisplay& _update_window_pos() {
      if (_is_closed) _window_x = _window_y = -1;
      else {
        RECT rect;
        rect.left = rect.top = 0; rect.right = (LONG)_width - 1; rect.bottom = (LONG)_height - 1;
        AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
        const int
          border1 = (int)((rect.right - rect.left + 1 - _width)/2),
          border2 = (int)(rect.bottom - rect.top + 1 - _height - border1);
        GetWindowRect(_window,&rect);
        _window_x = rect.left + border1;
        _window_y = rect.top + border2;
      }
      return *this;

Project: CImg
File: CImg.h

      const T *ptrs = _data;

Project: CImg
File: CImg.h

    //! Load image from a BMP file \newinstance.
    static CImg<T> get_load_bmp(const char *const filename) {
      return CImg<T>().load_bmp(filename);

Project: CImg
File: CImg.h

    //! Load image from a PFM file \newinstance.
    static CImg<T> get_load_pfm(std::FILE *const file) {
      return CImg<T>().load_pfm(file);

Project: CImg
File: CImg.h

    //! Remove image at index \c pos from the image list.
    /**
      \param pos Index of the image to remove.

Project: CImg
File: CImg.h

    **/
    CImg<T>& mirror(const char *const axes) {
      for (const char *s = axes; *s; ++s) mirror(*s);
      return *this;

Project: CImg
File: CImg.h


      static double mp_list_find_seq(_cimg_math_parser& mp) {
        const unsigned int
          indi = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
        const CImg<T> &img = mp.listin[indi];
        const bool is_forward = (bool)_mp_arg(5);
        const ulongT
          siz1 = (ulongT)img.size(),
          siz2 = (ulongT)mp.opcode[4];
        longT ind = (longT)(mp.opcode[6]!=_cimg_mp_slot_nan?_mp_arg(6):is_forward?0:siz1 - 1);
        if (ind<0 || ind>=(longT)siz1) return -1.;
        const T
          *const ptr1b = img.data(),
          *const ptr1e = ptr1b + siz1,
          *ptr1 = ptr1b + ind,
          *p1 = 0;
        const double
          *const ptr2b = &_mp_arg(3) + 1,
          *const ptr2e = ptr2b + siz2,
          *p2 = 0;

        // Forward search.
        if (is_forward) {
          do {
            while (ptr1<ptr1e && *ptr1!=*ptr2b) ++ptr1;
            if (ptr1>=ptr1e) return -1.;
            p1 = ptr1 + 1;
            p2 = ptr2b + 1;
            while (p1<ptr1e && p2<ptr2e && *p1==*p2) { ++p1; ++p2; }
          } while (p2<ptr2e && ++ptr1<ptr1e);
          return p2<ptr2e?-1.:(double)(ptr1 - ptr1b);
        }

        // Backward search.
        do {
          while (ptr1>=ptr1b && *ptr1!=*ptr2b) --ptr1;
          if (ptr1<ptr1b) return -1.;
          p1 = ptr1 + 1;
          p2 = ptr2b + 1;
          while (p1<ptr1e && p2<ptr2e && *p1==*p2) { ++p1; ++p2; }
        } while (p2<ptr2e && --ptr1>=ptr1b);
        return p2<ptr2e?-1.:(double)(ptr1 - ptr1b);

Project: CImg
File: CImg.h

      ~_functor3d_expr() { mp->end(); delete mp; }
      _functor3d_expr(const char *const expr):mp(0) {
        mp = new _cimg_math_parser(expr,0,CImg<T>::const_empty(),0);

Project: CImg
File: CImg.h

    template<typename T>
    inline T rol(const T& a, const unsigned int n=1) {
      return n?(T)((a<<n)|(a>>((sizeof(T)<<3) - n))):a;

Project: CImg
File: CImg.h

    **/
    const CImg<T>& save_pandore(const char *const filename, const unsigned int colorspace=0) const {
      return _save_pandore(0,filename,colorspace);

Project: CImg
File: CImg.h


    //! Remove last image.
    /**

Project: CImg
File: CImg.h

    **/
    CImg<T>& diagonal() {
      return get_diagonal().move_to(*this);

Project: CImg
File: CImg.h

    template<typename t>
    bool is_sameX(const CImg<t>& img) const {
      return is_sameX(img._width);

Project: CImg
File: CImg.h

    template<typename ti, typename tm>
    CImg<T>& draw_image(const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
                        const float mask_max_value=1) {
      return draw_image(0,sprite,mask,opacity,mask_max_value);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T> operator|(const CImg<t>& img) const {
      return (+*this)|=img;

Project: CImg
File: CImg.h

    **/
    CImg<T>& operator<<=(const char *const expression) {
      return *this<<=(+*this)._fill(expression,true,1,0,0,"operator<<=",this);

Project: CImg
File: CImg.h

    template<typename t>
    bool operator!=(const CImg<t>& img) const {
      return !((*this)==img);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& solve(const CImg<t>& A) {
      if (_depth!=1 || _spectrum!=1 || _height!=A._height || A._depth!=1 || A._spectrum!=1)
        throw CImgArgumentException(_cimg_instance
                                    "solve(): Instance and specified matrix (%u,%u,%u,%u,%p) have "
                                    "incompatible dimensions.",
                                    cimg_instance,
                                    A._width,A._height,A._depth,A._spectrum,A._data);
      typedef _cimg_Ttfloat Ttfloat;

      if (A.size()==1) return (*this)/=A[0];
      if (A._width==2 && A._height==2 && _height==2) {
        const double a = (double)A[0], b = (double)A[1], c = (double)A[2], d = (double)A[3],
          fa = std::fabs(a), fb = std::fabs(b), fc = std::fabs(c), fd = std::fabs(d),
          det = a*d - b*c, fM = cimg::max(fa,fb,fc,fd);
        if (fM==fa) cimg_forX(*this,k) {
            const double u = (double)(*this)(k,0), v = (double)(*this)(k,1), y = (a*v - c*u)/det;
            (*this)(k,0) = (T)((u - b*y)/a); (*this)(k,1) = (T)y;
          } else if (fM==fc) cimg_forX(*this,k) {
            const double u = (double)(*this)(k,0), v = (double)(*this)(k,1), y = (a*v - c*u)/det;
            (*this)(k,0) = (T)((v - d*y)/c); (*this)(k,1) = (T)y;
          } else if (fM==fb) cimg_forX(*this,k) {
            const double u = (double)(*this)(k,0), v = (double)(*this)(k,1), x = (d*u - b*v)/det;
            (*this)(k,0) = (T)x; (*this)(k,1) = (T)((u - a*x)/b);
          } else cimg_forX(*this,k) {
            const double u = (double)(*this)(k,0), v = (double)(*this)(k,1), x = (d*u - b*v)/det;
            (*this)(k,0) = (T)x; (*this)(k,1) = (T)((v - c*x)/d);
          }
        return *this;
      }
      if (_width!=1) { // Process column-by-column
        CImg<T> res(_width,A._width);
        cimg_forX(*this,i) res.draw_image(i,get_column(i).solve(A));
        return res.move_to(*this);
      }

      if (A._width==A._height) { // Square linear system

#ifdef cimg_use_lapack
        char TRANS = 'N';
        int INFO, N = _height, LWORK = 4*N, *const IPIV = new int[N];
        Ttfloat
          *const lapA = new Ttfloat[N*N],
          *const lapB = new Ttfloat[N],
          *const WORK = new Ttfloat[LWORK];
        cimg_forXY(A,k,l) lapA[k*N + l] = (Ttfloat)(A(k,l));
        cimg_forY(*this,i) lapB[i] = (Ttfloat)((*this)(i));
        cimg::getrf(N,lapA,IPIV,INFO);
        if (INFO)
          cimg::warn(_cimg_instance
                     "solve(): LAPACK library function dgetrf_() returned error code %d.",
                     cimg_instance,
                     INFO);

        if (!INFO) {
          cimg::getrs(TRANS,N,lapA,IPIV,lapB,INFO);
          if (INFO)
            cimg::warn(_cimg_instance
                       "solve(): LAPACK library function dgetrs_() returned error code %d.",
                       cimg_instance,
                       INFO);
        }
        if (!INFO) cimg_forY(*this,i) (*this)(i) = (T)(lapB[i]); else fill(0);
        delete[] IPIV; delete[] lapA; delete[] lapB; delete[] WORK;
#else
        CImg<Ttfloat> lu(A,false);
        CImg<Ttfloat> indx;
        bool d;
        lu._LU(indx,d);
        _solve(lu,indx);
#endif
      } else { // Least-square solution for non-square systems

#ifdef cimg_use_lapack
	char TRANS = 'N';
        int INFO, N = A._width, M = A._height, LWORK = -1, LDA = M, LDB = M, NRHS = _width;
	Ttfloat WORK_QUERY;
	Ttfloat
	  * const lapA = new Ttfloat[M*N],
	  * const lapB = new Ttfloat[M*NRHS];
	cimg::sgels(TRANS, M, N, NRHS, lapA, LDA, lapB, LDB, &WORK_QUERY, LWORK, INFO);
	LWORK = (int) WORK_QUERY;
	Ttfloat *const WORK = new Ttfloat[LWORK];
        cimg_forXY(A,k,l) lapA[k*M + l] = (Ttfloat)(A(k,l));
        cimg_forXY(*this,k,l) lapB[k*M + l] = (Ttfloat)((*this)(k,l));
	cimg::sgels(TRANS, M, N, NRHS, lapA, LDA, lapB, LDB, WORK, LWORK, INFO);
        if (INFO != 0)
          cimg::warn(_cimg_instance
                     "solve(): LAPACK library function sgels() returned error code %d.",
                     cimg_instance,
                     INFO);
	assign(NRHS, N);
        if (!INFO)
          cimg_forXY(*this,k,l) (*this)(k,l) = (T)lapB[k*M + l];
        else
          assign(A.get_pseudoinvert()*(*this));
        delete[] lapA; delete[] lapB; delete[] WORK;
#else
	assign(A.get_pseudoinvert()*(*this));
#endif
      }
      return *this;

Project: CImg
File: CImg.h

      \param voxel_size Voxel size, to be stored in the filename.
      \param description Description, to be stored in the filename.
      \param use_bigtiff Allow to save big tiff files (>4Gb).
    **/
    const CImgList<T>& save_tiff(const char *const filename, const unsigned int compression_type=0,
                                 const float *const voxel_size=0, const char *const description=0,
                                 const bool use_bigtiff=true) const {
      if (!filename)
        throw CImgArgumentException(_cimglist_instance
                                    "save_tiff(): Specified filename is (null).",
                                    cimglist_instance);
      if (is_empty()) { cimg::fempty(0,filename); return *this; }

#ifndef cimg_use_tiff
      if (_width==1) _data[0].save_tiff(filename,compression_type,voxel_size,description,use_bigtiff);
      else cimglist_for(*this,l) {
          CImg<charT> nfilename(1024);
          cimg::number_filename(filename,l,6,nfilename);
          _data[l].save_tiff(nfilename,compression_type,voxel_size,description,use_bigtiff);
        }
#else
      ulongT siz = 0;
      cimglist_for(*this,l) siz+=_data[l].size();
      const bool _use_bigtiff = use_bigtiff && sizeof(siz)>=8 && siz*sizeof(T)>=1UL<<31; // No bigtiff for small images
      TIFF *tif = TIFFOpen(filename,_use_bigtiff?"w8":"w4");
      if (tif) {
        for (unsigned int dir = 0, l = 0; l<_width; ++l) {
          const CImg<T>& img = (*this)[l];
          cimg_forZ(img,z) img._save_tiff(tif,dir++,z,compression_type,voxel_size,description);
        }
        TIFFClose(tif);
      } else
        throw CImgIOException(_cimglist_instance
                              "save_tiff(): Failed to open stream for file '%s'.",
                              cimglist_instance,

Project: CImg
File: CImg.h

      // Evaluation procedure for the end() blocks.
      void end() {
        if (code_end.is_empty()) return;
        if (imgin) {
          mem[_cimg_mp_slot_x] = imgin._width - 1.;
          mem[_cimg_mp_slot_y] = imgin._height - 1.;
          mem[_cimg_mp_slot_z] = imgin._depth - 1.;
          mem[_cimg_mp_slot_c] = imgin._spectrum - 1.;
        } else mem[_cimg_mp_slot_x] = mem[_cimg_mp_slot_y] = mem[_cimg_mp_slot_z] = mem[_cimg_mp_slot_c] = 0;
        p_code_end = code_end.end();
        for (p_code = code_end; p_code<p_code_end; ++p_code) {
          opcode._data = p_code->_data;
          const ulongT target = opcode[1];
          mem[target] = _cimg_mp_defunc(*this);
        }

Project: CImg
File: CImg.h

    // Return number of available CPU cores.
    inline unsigned int nb_cpus() {
      unsigned int res = 1;
#if cimg_OS==2
      SYSTEM_INFO sysinfo;
      GetSystemInfo(&sysinfo);
      res = (unsigned int)sysinfo.dwNumberOfProcessors;
#elif cimg_OS == 1
      res = (unsigned int)sysconf(_SC_NPROCESSORS_ONLN);
#endif
      return res?res:1U;

Project: CImg
File: CImg.h

       - If a button text is set to 0, the corresponding button (and the followings) will not appear in the dialog box.
       At least one button must be specified.
    **/
    template<typename t>
    inline int dialog(const char *const title, const char *const msg,
                      const char *const button1_label, const char *const button2_label,
                      const char *const button3_label, const char *const button4_label,
                      const char *const button5_label, const char *const button6_label,
                      const CImg<t>& logo, const bool is_centered=false) {
#if cimg_display==0
      cimg::unused(title,msg,button1_label,button2_label,button3_label,button4_label,button5_label,button6_label,
                   logo._data,is_centered);
      throw CImgIOException("cimg::dialog(): No display available.");
#else
      static const unsigned char
        black[] = { 0,0,0 }, white[] = { 255,255,255 }, gray[] = { 200,200,200 }, gray2[] = { 150,150,150 };

      // Create buttons and canvas graphics
      CImgList<unsigned char> buttons, cbuttons, sbuttons;
      if (button1_label) {
        CImg<unsigned char>().draw_text(0,0,button1_label,black,gray,1,13).move_to(buttons);
        if (button2_label) {
          CImg<unsigned char>().draw_text(0,0,button2_label,black,gray,1,13).move_to(buttons);
          if (button3_label) {
            CImg<unsigned char>().draw_text(0,0,button3_label,black,gray,1,13).move_to(buttons);
            if (button4_label) {
              CImg<unsigned char>().draw_text(0,0,button4_label,black,gray,1,13).move_to(buttons);
              if (button5_label) {
                CImg<unsigned char>().draw_text(0,0,button5_label,black,gray,1,13).move_to(buttons);
                if (button6_label) {
                  CImg<unsigned char>().draw_text(0,0,button6_label,black,gray,1,13).move_to(buttons);
                }}}}}}
      if (!buttons._width)
        throw CImgArgumentException("cimg::dialog(): No buttons have been defined.");
      cimglist_for(buttons,l) buttons[l].resize(-100,-100,1,3);

      unsigned int bw = 0, bh = 0;
      cimglist_for(buttons,l) { bw = std::max(bw,buttons[l]._width); bh = std::max(bh,buttons[l]._height); }
      bw+=8; bh+=8;
      if (bw<64) bw = 64;
      if (bw>128) bw = 128;
      if (bh<24) bh = 24;
      if (bh>48) bh = 48;

      CImg<unsigned char> button(bw,bh,1,3);
      button.draw_rectangle(0,0,bw - 1,bh - 1,gray);
      button.draw_line(0,0,bw - 1,0,white).draw_line(0,bh - 1,0,0,white);
      button.draw_line(bw - 1,0,bw - 1,bh - 1,black).draw_line(bw - 1,bh - 1,0,bh - 1,black);
      button.draw_line(1,bh - 2,bw - 2,bh - 2,gray2).draw_line(bw - 2,bh - 2,bw - 2,1,gray2);
      CImg<unsigned char> sbutton(bw,bh,1,3);
      sbutton.draw_rectangle(0,0,bw - 1,bh - 1,gray);
      sbutton.draw_line(0,0,bw - 1,0,black).draw_line(bw - 1,0,bw - 1,bh - 1,black);
      sbutton.draw_line(bw - 1,bh - 1,0,bh - 1,black).draw_line(0,bh - 1,0,0,black);
      sbutton.draw_line(1,1,bw - 2,1,white).draw_line(1,bh - 2,1,1,white);
      sbutton.draw_line(bw - 2,1,bw - 2,bh - 2,black).draw_line(bw - 2,bh - 2,1,bh - 2,black);
      sbutton.draw_line(2,bh - 3,bw - 3,bh - 3,gray2).draw_line(bw - 3,bh - 3,bw - 3,2,gray2);
      sbutton.draw_line(4,4,bw - 5,4,black,1,0xAAAAAAAA,true).
        draw_line(bw - 5,4,bw - 5,bh - 5,black,1,0xAAAAAAAA,false);
      sbutton.draw_line(bw - 5,bh - 5,4,bh - 5,black,1,0xAAAAAAAA,false).
        draw_line(4,bh - 5,4,4,black,1,0xAAAAAAAA,false);
      CImg<unsigned char> cbutton(bw,bh,1,3);
      cbutton.draw_rectangle(0,0,bw - 1,bh - 1,black).draw_rectangle(1,1,bw - 2,bh - 2,gray2).
        draw_rectangle(2,2,bw - 3,bh - 3,gray);
      cbutton.draw_line(4,4,bw - 5,4,black,1,0xAAAAAAAA,true).
        draw_line(bw - 5,4,bw - 5,bh - 5,black,1,0xAAAAAAAA,false);
      cbutton.draw_line(bw - 5,bh - 5,4,bh - 5,black,1,0xAAAAAAAA,false).
        draw_line(4,bh - 5,4,4,black,1,0xAAAAAAAA,false);

      cimglist_for(buttons,ll) {
        CImg<unsigned char>(cbutton).
          draw_image(1 + (bw  -buttons[ll].width())/2,1 + (bh - buttons[ll].height())/2,buttons[ll]).
          move_to(cbuttons);
        CImg<unsigned char>(sbutton).
          draw_image((bw - buttons[ll].width())/2,(bh - buttons[ll].height())/2,buttons[ll]).
          move_to(sbuttons);
        CImg<unsigned char>(button).
          draw_image((bw - buttons[ll].width())/2,(bh - buttons[ll].height())/2,buttons[ll]).
          move_to(buttons[ll]);
      }

      CImg<unsigned char> canvas;
      if (msg)
        ((CImg<unsigned char>().draw_text(0,0,"%s",gray,0,1,13,msg)*=-1)+=200).resize(-100,-100,1,3).move_to(canvas);

      const unsigned int
        bwall = (buttons._width - 1)*(12 + bw) + bw,
        w = cimg::max(196U,36 + logo._width + canvas._width,24 + bwall),
        h = cimg::max(96U,36 + canvas._height + bh,36 + logo._height + bh),
        lx = 12 + (canvas._data?0:((w - 24 - logo._width)/2)),
        ly = (h - 12 - bh - logo._height)/2,
        tx = lx + logo._width + 12,
        ty = (h - 12 - bh - canvas._height)/2,
        bx = (w - bwall)/2,
        by = h - 12 - bh;

      if (canvas._data)
        canvas = CImg<unsigned char>(w,h,1,3).
          draw_rectangle(0,0,w - 1,h - 1,gray).
          draw_line(0,0,w - 1,0,white).draw_line(0,h - 1,0,0,white).
          draw_line(w - 1,0,w - 1,h - 1,black).draw_line(w - 1,h - 1,0,h - 1,black).
          draw_image(tx,ty,canvas);
      else
        canvas = CImg<unsigned char>(w,h,1,3).
          draw_rectangle(0,0,w - 1,h - 1,gray).
          draw_line(0,0,w - 1,0,white).draw_line(0,h - 1,0,0,white).
          draw_line(w - 1,0,w - 1,h - 1,black).draw_line(w - 1,h - 1,0,h - 1,black);
      if (logo._data) canvas.draw_image(lx,ly,logo);

      unsigned int xbuttons[6] = { 0 };
      cimglist_for(buttons,lll) {
        xbuttons[lll] = bx + (bw + 12)*lll;
        canvas.draw_image(xbuttons[lll],by,buttons[lll]);
      }

      // Open window and enter events loop
      CImgDisplay disp(canvas,title?title:" ",0,false,is_centered?true:false);
      if (is_centered) disp.move((CImgDisplay::screen_width() - disp.width())/2,
                                 (CImgDisplay::screen_height() - disp.height())/2);
      bool stop_flag = false, refresh = false;
      int oselected = -1, oclicked = -1, selected = -1, clicked = -1;
      while (!disp.is_closed() && !stop_flag) {
        if (refresh) {
          if (clicked>=0)
            CImg<unsigned char>(canvas).draw_image(xbuttons[clicked],by,cbuttons[clicked]).display(disp);
          else {
            if (selected>=0)
              CImg<unsigned char>(canvas).draw_image(xbuttons[selected],by,sbuttons[selected]).display(disp);
            else canvas.display(disp);
          }
          refresh = false;
        }
        disp.wait(15);
        if (disp.is_resized()) disp.resize(disp,false);

        if (disp.button()&1)  {
          oclicked = clicked;
          clicked = -1;
          cimglist_for(buttons,l)
            if (disp.mouse_y()>=(int)by && disp.mouse_y()<(int)(by + bh) &&
                disp.mouse_x()>=(int)xbuttons[l] && disp.mouse_x()<(int)(xbuttons[l] + bw)) {
              clicked = selected = l;
              refresh = true;
            }
          if (clicked!=oclicked) refresh = true;
        } else if (clicked>=0) stop_flag = true;

        if (disp.key()) {
          oselected = selected;
          switch (disp.key()) {
          case cimg::keyESC : selected = -1; stop_flag = true; break;
          case cimg::keyENTER : if (selected<0) selected = 0; stop_flag = true; break;
          case cimg::keyTAB :
          case cimg::keyARROWRIGHT :
          case cimg::keyARROWDOWN : selected = (selected + 1)%buttons.width(); break;
          case cimg::keyARROWLEFT :
          case cimg::keyARROWUP : selected = (selected + buttons.width() - 1)%buttons.width(); break;
          }
          disp.set_key();
          if (selected!=oselected) refresh = true;
        }
      }

Project: CImg
File: CImg.h

    template<> struct type<unsigned char> {

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& draw_image(const int x0, const int y0,
                        const CImg<t>& sprite, const float opacity=1) {
      return draw_image(x0,y0,0,sprite,opacity);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<Tfloat> get_distance_dijkstra(const T& value, const CImg<t>& metric,
                                       const bool is_high_connectivity=false) const {
      CImg<T> return_path;
      return get_distance_dijkstra(value,metric,is_high_connectivity,return_path);

Project: CImg
File: CImg.h

     **/
    double det() const {
      if (is_empty() || _width!=_height || _depth!=1 || _spectrum!=1)
        throw CImgInstanceException(_cimg_instance
                                    "det(): Instance is not a square matrix.",
                                    cimg_instance);

      switch (_width) {
      case 1 : return (double)((*this)(0,0));
      case 2 : return (double)((*this)(0,0))*(double)((*this)(1,1)) - (double)((*this)(0,1))*(double)((*this)(1,0));
      case 3 : {
        const double
          a = (double)_data[0], d = (double)_data[1], g = (double)_data[2],
          b = (double)_data[3], e = (double)_data[4], h = (double)_data[5],
          c = (double)_data[6], f = (double)_data[7], i = (double)_data[8];
        return i*a*e - a*h*f - i*b*d + b*g*f + c*d*h - c*g*e;
      }
      default : {
        CImg<Tfloat> lu(*this,false);
        CImg<uintT> indx;
        bool d;
        lu._LU(indx,d);
        double res = d?(double)1:(double)-1;
        cimg_forX(lu,i) res*=lu(i,i);
        return res;
      }
      }

Project: CImg
File: CImg.h

    **/
    CImg<T> get_tensor_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const {
      const T *ptrs = data(x,y,z,0);
      const ulongT whd = (ulongT)_width*_height*_depth;
      if (_spectrum==6)
        return tensor(*ptrs,*(ptrs + whd),*(ptrs + 2*whd),*(ptrs + 3*whd),*(ptrs + 4*whd),*(ptrs + 5*whd));
      if (_spectrum==3)
        return tensor(*ptrs,*(ptrs + whd),*(ptrs + 2*whd));
      return tensor(*ptrs);

Project: CImg
File: CImg.h

        return val<(double)min()?min():val>(double)max()?max():(signed char)val; }

Project: CImg
File: CImg.h


    const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c,
                        const ulongT wh, const ulongT whd) const {
      return _data[x + y*_width + z*wh + c*whd];

Project: CImg
File: CImg.h

       \param user_path Specified path, or \c 0 to get the path currently used.
       \param reinit_path Force path to be recalculated (may take some time).
       \return Path containing the \c dcraw binary.
    **/
    inline const char *dcraw_path(const char *const user_path, const bool reinit_path) {
      static CImg<char> s_path;
      cimg::mutex(7);
      if (reinit_path) s_path.assign();
      if (user_path) {
        if (!s_path) s_path.assign(1024);
        std::strncpy(s_path,user_path,1023);
      } else if (!s_path) {
        s_path.assign(1024);
        bool path_found = false;
        std::FILE *file = 0;
#if cimg_OS==2
        if (!path_found) {
          std::strcpy(s_path,".\\dcraw.exe");
          if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(s_path,"dcraw.exe");
#else
        if (!path_found) {
          std::strcpy(s_path,"./dcraw");
          if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(s_path,"dcraw");
#endif
        winformat_string(s_path);

Project: CImg
File: CImg.h

    //! Load image from a RGB file \newinstance.
    static CImg<T> get_load_rgb(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
      return CImg<T>().load_rgb(file,dimw,dimh);

Project: CImg
File: CImg.h

      static const char* string() { static const char *const s = "float"; return s; }

Project: CImg
File: CImg.h

      static bool is_nan(const cimg_int64) { return false; }

Project: CImg
File: CImg.h

    **/
    CImg<T>& load_png(const char *const filename, unsigned int *const bits_per_pixel=0) {
      return _load_png(0,filename,bits_per_pixel);

Project: CImg
File: CImg.h

    template<typename tp, typename tf, typename tc, typename to>
    const CImg<T>& display_object3d(CImgDisplay& disp,
                                    const CImg<tp>& vertices,
                                    const CImgList<tf>& primitives,
                                    const CImgList<tc>& colors,
                                    const to& opacities,
                                    const bool centering=true,
                                    const int render_static=4, const int render_motion=1,
                                    const bool is_double_sided=true, const float focale=700,
                                    const float light_x=0, const float light_y=0, const float light_z=-5e8f,
                                    const float specular_lightness=0.2f, const float specular_shininess=0.1f,
                                    const bool display_axes=true, float *const pose_matrix=0,
                                    const bool exit_on_anykey=false) const {
      return _display_object3d(disp,0,vertices,primitives,colors,opacities,centering,render_static,
			       render_motion,is_double_sided,focale,
                               light_x,light_y,light_z,specular_lightness,specular_shininess,
			       display_axes,pose_matrix,exit_on_anykey);

Project: CImg
File: CImg.h

      static const char* string() { static const char *const s = "unsigned char"; return s; }

Project: CImg
File: CImg.h

    **/
    CImg<T>& operator=(const CImgDisplay& disp) {
      disp.snapshot(*this);
      return *this;

Project: CImg
File: CImg.h

    }
    inline int abs(const unsigned short a) {
      return (int)a;

Project: CImg
File: CImg.h


    static void wait_all() {
      if (!cimg::X11_attr().display) return;
      pthread_mutex_lock(&cimg::X11_attr().wait_event_mutex);
      pthread_cond_wait(&cimg::X11_attr().wait_event,&cimg::X11_attr().wait_event_mutex);
      pthread_mutex_unlock(&cimg::X11_attr().wait_event_mutex);

Project: CImg
File: CImg.h

    template<typename t, typename tc>
    CImg<T>& draw_gaussian(const float xc, const float yc, const CImg<t>& tensor,
                           const tc *const color, const float opacity=1) {
      if (is_empty()) return *this;
      if (tensor._width!=2 || tensor._height!=2 || tensor._depth!=1 || tensor._spectrum!=1)
        throw CImgArgumentException(_cimg_instance
                                    "draw_gaussian(): Specified tensor (%u,%u,%u,%u,%p) is not a 2x2 matrix.",
                                    cimg_instance,
                                    tensor._width,tensor._height,tensor._depth,tensor._spectrum,tensor._data);
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_gaussian(): Specified color is (null).",
                                    cimg_instance);
      typedef typename CImg<t>::Tfloat tfloat;
      const CImg<tfloat> invT = tensor.get_invert(), invT2 = (invT*invT)/=-2.;
      const tfloat a = invT2(0,0), b = 2*invT2(1,0), c = invT2(1,1);
      const float nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.f);
      const ulongT whd = (ulongT)_width*_height*_depth;
      const tc *col = color;
      float dy = -yc;
      cimg_forY(*this,y) {
        float dx = -xc;
        cimg_forX(*this,x) {
          const float val = (float)std::exp(a*dx*dx + b*dx*dy + c*dy*dy);
          T *ptrd = data(x,y,0,0);
          if (opacity>=1) cimg_forC(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whd; }
          else cimg_forC(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whd; }
          col-=_spectrum;
          ++dx;
        }
        ++dy;
      }
      return *this;

Project: CImg
File: CImg.h

    **/
    CImg<T>& resize_object3d(const float sx, const float sy=-100, const float sz=-100) {
      if (_height!=3 || _depth>1 || _spectrum>1)
        throw CImgInstanceException(_cimg_instance
                                    "resize_object3d(): Instance is not a set of 3D vertices.",
                                    cimg_instance);

      CImg<T> xcoords = get_shared_row(0), ycoords = get_shared_row(1), zcoords = get_shared_row(2);
      float
        xm, xM = (float)xcoords.max_min(xm),
        ym, yM = (float)ycoords.max_min(ym),
        zm, zM = (float)zcoords.max_min(zm);
      if (xm<xM) { if (sx>0) xcoords*=sx/(xM-xm); else xcoords*=-sx/100; }
      if (ym<yM) { if (sy>0) ycoords*=sy/(yM-ym); else ycoords*=-sy/100; }
      if (zm<zM) { if (sz>0) zcoords*=sz/(zM-zm); else zcoords*=-sz/100; }
      return *this;

Project: CImg
File: CImg.h

    template<typename tp, typename tf, typename tc>
    const CImg<T>& display_object3d(CImgDisplay &disp,
                                    const CImg<tp>& vertices,
                                    const CImgList<tf>& primitives,
                                    const CImgList<tc>& colors,
                                    const bool centering=true,
                                    const int render_static=4, const int render_motion=1,
                                    const bool is_double_sided=true, const float focale=700,
                                    const float light_x=0, const float light_y=0, const float light_z=-5e8f,
                                    const float specular_lightness=0.2f, const float specular_shininess=0.1f,
                                    const bool display_axes=true, float *const pose_matrix=0,
                                    const bool exit_on_anykey=false) const {
      return display_object3d(disp,vertices,primitives,colors,CImgList<floatT>(),centering,
			      render_static,render_motion,is_double_sided,focale,
                              light_x,light_y,light_z,specular_lightness,specular_shininess,
			      display_axes,pose_matrix,exit_on_anykey);

Project: CImg
File: CImg.h

#if cimg_verbosity>=3
    CImg<T> *data(const unsigned int pos) {
      if (pos>=size())
        cimg::warn(_cimglist_instance
                   "data(): Invalid pointer request, at position [%u].",
                   cimglist_instance,
                   pos);
      return _data + pos;

Project: CImg
File: CImg.h

    template<typename T>
    const CImgDisplay& snapshot(CImg<T>& img) const {
      cimg::unused(img);
      _no_display_exception();
      return *this;

Project: CImg
File: CImg.h

    inline void unused(const T&, ...) {}

Project: CImg
File: CImg.h

      \param y0 Starting Y-coordinates of image regions to write.
      \param z0 Starting Z-coordinates of image regions to write.
      \param c0 Starting C-coordinates of image regions to write.
    **/
    const CImgList<T>& save_cimg(const char *const filename,
                                 const unsigned int n0,

Project: CImg
File: CImg.h


      static double mp_list_whds(_cimg_math_parser& mp) {
        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
        return (double)mp.listin[ind]._width*mp.listin[ind]._height*mp.listin[ind]._depth*mp.listin[ind]._spectrum;

Project: CImg
File: CImg.h

    template<typename T>
    CImgDisplay& render(const CImg<T>& img) {
      if (!img)
        throw CImgArgumentException(_cimgdisplay_instance
                                    "render(): Empty specified image.",
                                    cimgdisplay_instance);

      if (is_empty()) return *this;
      if (img._depth!=1) return render(img.get_projections2d((img._width - 1)/2,(img._height - 1)/2,
                                                             (img._depth - 1)/2));

      const T
        *data1 = img._data,
        *data2 = (img._spectrum>=2)?img.data(0,0,0,1):data1,
        *data3 = (img._spectrum>=3)?img.data(0,0,0,2):data1;

      WaitForSingleObject(_mutex,INFINITE);
      unsigned int
        *const ndata = (img._width==_width && img._height==_height)?_data:
        new unsigned int[(size_t)img._width*img._height],
        *ptrd = ndata;

      if (!_normalization || (_normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
        _min = _max = 0;
        switch (img._spectrum) {
        case 1 : {
          for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
            const unsigned char val = (unsigned char)*(data1++);
            *(ptrd++) = (unsigned int)((val<<16) | (val<<8) | val);
          }
        } break;
        case 2 : {
          for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
            const unsigned char
              R = (unsigned char)*(data1++),
              G = (unsigned char)*(data2++);
            *(ptrd++) = (unsigned int)((R<<16) | (G<<8));
          }
        } break;
        default : {
          for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
            const unsigned char
              R = (unsigned char)*(data1++),
              G = (unsigned char)*(data2++),
              B = (unsigned char)*(data3++);
            *(ptrd++) = (unsigned int)((R<<16) | (G<<8) | B);
          }
        }
        }
      } else {
        if (_normalization==3) {
          if (cimg::type<T>::is_float()) _min = (float)img.min_max(_max);
          else { _min = (float)cimg::type<T>::min(); _max = (float)cimg::type<T>::max(); }
        } else if ((_min>_max) || _normalization==1) _min = (float)img.min_max(_max);
        const float delta = _max - _min, mm = 255/(delta?delta:1.f);
        switch (img._spectrum) {
        case 1 : {
          for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
            const unsigned char val = (unsigned char)((*(data1++) - _min)*mm);
            *(ptrd++) = (unsigned int)((val<<16) | (val<<8) | val);
          }
        } break;
        case 2 : {
          for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
            const unsigned char
              R = (unsigned char)((*(data1++) - _min)*mm),
              G = (unsigned char)((*(data2++) - _min)*mm);
            *(ptrd++) = (unsigned int)((R<<16) | (G<<8));
          }
        } break;
        default : {
          for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
            const unsigned char
              R = (unsigned char)((*(data1++) - _min)*mm),
              G = (unsigned char)((*(data2++) - _min)*mm),
              B = (unsigned char)((*(data3++) - _min)*mm);
            *(ptrd++) = (unsigned int)((R<<16) | (G<<8) | B);
          }
        }
        }
      }
      if (ndata!=_data) { _render_resize(ndata,img._width,img._height,_data,_width,_height); delete[] ndata; }
      ReleaseMutex(_mutex);
      return *this;

Project: CImg
File: CImg.h

    **/
    CImg<T>& pow(const double p) {
      if (is_empty()) return *this;
      if (p==-4) { cimg_openmp_for(*this,1/(Tfloat)cimg::pow4(*ptr),32768); return *this; }
      if (p==-3) { cimg_openmp_for(*this,1/(Tfloat)cimg::pow3(*ptr),32768); return *this; }
      if (p==-2) { cimg_openmp_for(*this,1/(Tfloat)cimg::sqr(*ptr),32768); return *this; }
      if (p==-1) { cimg_openmp_for(*this,1/(Tfloat)*ptr,32768); return *this; }
      if (p==-0.5) { cimg_openmp_for(*this,1/std::sqrt((Tfloat)*ptr),8192); return *this; }
      if (p==0) return fill((T)1);
      if (p==0.5) return sqrt();
      if (p==1) return *this;
      if (p==2) return sqr();
      if (p==3) { cimg_openmp_for(*this,cimg::pow3(*ptr),262144); return *this; }
      if (p==4) { cimg_openmp_for(*this,cimg::pow4(*ptr),131072); return *this; }
      cimg_openmp_for(*this,std::pow((Tfloat)*ptr,(Tfloat)p),1024);
      return *this;

Project: CImg
File: CImg.h

    template<typename t>
    bool operator==(const CImg<t>& img) const {
      typedef _cimg_Tt Tt;
      const ulongT siz = size();
      bool is_equal = true;
      if (siz!=img.size()) return false;
      t *ptrs = img._data + siz;
      for (T *ptrd = _data + siz; is_equal && ptrd>_data; is_equal = ((Tt)*(--ptrd)==(Tt)*(--ptrs))) {}
      return is_equal;

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& blur_bilateral(const CImg<t>& guide,
                            const float sigma_x, const float sigma_y,
                            const float sigma_z, const float sigma_r,
                            const float sampling_x, const float sampling_y,
                            const float sampling_z, const float sampling_r) {
      if (!is_sameXYZ(guide))
        throw CImgArgumentException(_cimg_instance
                                    "blur_bilateral(): Invalid size for specified guide image (%u,%u,%u,%u,%p).",
                                    cimg_instance,
                                    guide._width,guide._height,guide._depth,guide._spectrum,guide._data);
      if (is_empty() || (!sigma_x && !sigma_y && !sigma_z)) return *this;
      T edge_min, edge_max = guide.max_min(edge_min);
      if (edge_min==edge_max) return blur(sigma_x,sigma_y,sigma_z);
      const float
        edge_delta = (float)(edge_max - edge_min),
        _sigma_x = sigma_x>=0?sigma_x:-sigma_x*_width/100,
        _sigma_y = sigma_y>=0?sigma_y:-sigma_y*_height/100,
        _sigma_z = sigma_z>=0?sigma_z:-sigma_z*_depth/100,
        _sigma_r = sigma_r>=0?sigma_r:-sigma_r*(edge_max - edge_min)/100,
        _sampling_x = sampling_x?sampling_x:std::max(_sigma_x,1.f),
        _sampling_y = sampling_y?sampling_y:std::max(_sigma_y,1.f),
        _sampling_z = sampling_z?sampling_z:std::max(_sigma_z,1.f),
        _sampling_r = sampling_r?sampling_r:std::max(_sigma_r,edge_delta/256),
        derived_sigma_x = _sigma_x / _sampling_x,
        derived_sigma_y = _sigma_y / _sampling_y,
        derived_sigma_z = _sigma_z / _sampling_z,
        derived_sigma_r = _sigma_r / _sampling_r;
      const int
        padding_x = (int)(2*derived_sigma_x) + 1,
        padding_y = (int)(2*derived_sigma_y) + 1,
        padding_z = (int)(2*derived_sigma_z) + 1,
        padding_r = (int)(2*derived_sigma_r) + 1;
      const unsigned int
        bx = (unsigned int)((_width  - 1)/_sampling_x + 1 + 2*padding_x),
        by = (unsigned int)((_height - 1)/_sampling_y + 1 + 2*padding_y),
        bz = (unsigned int)((_depth  - 1)/_sampling_z + 1 + 2*padding_z),
        br = (unsigned int)(edge_delta/_sampling_r + 1 + 2*padding_r);
      if (bx>0 || by>0 || bz>0 || br>0) {
        const bool is_3d = (_depth>1);
        if (is_3d) { // 3D version of the algorithm
          CImg<floatT> bgrid(bx,by,bz,br), bgridw(bx,by,bz,br);
          cimg_forC(*this,c) {
            const CImg<t> _guide = guide.get_shared_channel(c%guide._spectrum);
            bgrid.fill(0); bgridw.fill(0);
            cimg_forXYZ(*this,x,y,z) {
              const T val = (*this)(x,y,z,c);
              const float edge = (float)_guide(x,y,z);
              const int
                X = (int)cimg::round(x/_sampling_x) + padding_x,
                Y = (int)cimg::round(y/_sampling_y) + padding_y,
                Z = (int)cimg::round(z/_sampling_z) + padding_z,
                R = (int)cimg::round((edge - edge_min)/_sampling_r) + padding_r;
              bgrid(X,Y,Z,R)+=(float)val;
              bgridw(X,Y,Z,R)+=1;
            }
            bgrid.blur(derived_sigma_x,derived_sigma_y,derived_sigma_z,true).deriche(derived_sigma_r,0,'c',false);
            bgridw.blur(derived_sigma_x,derived_sigma_y,derived_sigma_z,true).deriche(derived_sigma_r,0,'c',false);

            cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(size(),4096))
            cimg_forXYZ(*this,x,y,z) {
              const float edge = (float)_guide(x,y,z);
              const float
                X = x/_sampling_x + padding_x,
                Y = y/_sampling_y + padding_y,
                Z = z/_sampling_z + padding_z,
                R = (edge - edge_min)/_sampling_r + padding_r;
              const float bval0 = bgrid._linear_atXYZC(X,Y,Z,R), bval1 = bgridw._linear_atXYZC(X,Y,Z,R);
              (*this)(x,y,z,c) = (T)(bval0/bval1);
            }
          }
        } else { // 2D version of the algorithm
          CImg<floatT> bgrid(bx,by,br,2);
          cimg_forC(*this,c) {
            const CImg<t> _guide = guide.get_shared_channel(c%guide._spectrum);
            bgrid.fill(0);
            cimg_forXY(*this,x,y) {
              const T val = (*this)(x,y,c);
              const float edge = (float)_guide(x,y);
              const int
                X = (int)cimg::round(x/_sampling_x) + padding_x,
                Y = (int)cimg::round(y/_sampling_y) + padding_y,
                R = (int)cimg::round((edge - edge_min)/_sampling_r) + padding_r;
              bgrid(X,Y,R,0)+=(float)val;
              bgrid(X,Y,R,1)+=1;
            }
            bgrid.blur(derived_sigma_x,derived_sigma_y,0,true).blur(0,0,derived_sigma_r,false);

            cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if_size(size(),4096))
            cimg_forXY(*this,x,y) {
              const float edge = (float)_guide(x,y);
              const float
                X = x/_sampling_x + padding_x,
                Y = y/_sampling_y + padding_y,
                R = (edge - edge_min)/_sampling_r + padding_r;
              const float bval0 = bgrid._linear_atXYZ(X,Y,R,0), bval1 = bgrid._linear_atXYZ(X,Y,R,1);
              (*this)(x,y,c) = (T)(bval0/bval1);
            }
          }
        }
      }
      return *this;

Project: CImg
File: CImg.h

    **/
    CImg<T>& rotate(const float angle, const float cx, const float cy,
                    const unsigned int interpolation, const unsigned int boundary_conditions=0) {
      return get_rotate(angle,cx,cy,interpolation,boundary_conditions).move_to(*this);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<Tfloat> get_distance_eikonal(const T& value, const CImg<t>& metric) const {
      if (is_empty()) return *this;
      if (!is_sameXYZ(metric))
        throw CImgArgumentException(_cimg_instance
                                    "distance_eikonal(): image instance and metric map (%u,%u,%u,%u) have "
                                    "incompatible dimensions.",
                                    cimg_instance,
                                    metric._width,metric._height,metric._depth,metric._spectrum);
      CImg<Tfloat> result(_width,_height,_depth,_spectrum,cimg::type<Tfloat>::max()), Q;
      CImg<charT> state(_width,_height,_depth); // -1=far away, 0=narrow, 1=frozen

      cimg_pragma_openmp(parallel for cimg_openmp_if(_spectrum>=2) firstprivate(Q,state))
      cimg_forC(*this,c) {
        const CImg<T> img = get_shared_channel(c);
        const CImg<t> met = metric.get_shared_channel(c%metric._spectrum);
        CImg<Tfloat> res = result.get_shared_channel(c);
        unsigned int sizeQ = 0;
        state.fill(-1);

        // Detect initial seeds.
        Tfloat *ptr1 = res._data; char *ptr2 = state._data;
        cimg_for(img,ptr0,T) { if (*ptr0==value) { *ptr1 = 0; *ptr2 = 1; } ++ptr1; ++ptr2; }

        // Initialize seeds neighbors.
        ptr2 = state._data;
        cimg_forXYZ(img,x,y,z) if (*(ptr2++)==1) {
          if (x - 1>=0 && state(x - 1,y,z)==-1) {
            const Tfloat dist = res(x - 1,y,z) = __distance_eikonal(res,met(x - 1,y,z),x - 1,y,z);
            Q._eik_priority_queue_insert(state,sizeQ,-dist,x - 1,y,z);
          }
          if (x + 1<width() && state(x + 1,y,z)==-1) {
            const Tfloat dist = res(x + 1,y,z) = __distance_eikonal(res,met(x + 1,y,z),x + 1,y,z);
            Q._eik_priority_queue_insert(state,sizeQ,-dist,x + 1,y,z);
          }
          if (y - 1>=0 && state(x,y - 1,z)==-1) {
            const Tfloat dist = res(x,y - 1,z) = __distance_eikonal(res,met(x,y - 1,z),x,y - 1,z);
            Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y - 1,z);
          }
          if (y + 1<height() && state(x,y + 1,z)==-1) {
            const Tfloat dist = res(x,y + 1,z) = __distance_eikonal(res,met(x,y + 1,z),x,y + 1,z);
            Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y + 1,z);
          }
          if (z - 1>=0 && state(x,y,z - 1)==-1) {
            const Tfloat dist = res(x,y,z - 1) = __distance_eikonal(res,met(x,y,z - 1),x,y,z - 1);
            Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y,z - 1);
          }
          if (z + 1<depth() && state(x,y,z + 1)==-1) {
            const Tfloat dist = res(x,y,z + 1) = __distance_eikonal(res,met(x,y,z + 1),x,y,z + 1);
            Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y,z + 1);
          }
        }

        // Propagate front.
        while (sizeQ) {
          int x = -1, y = -1, z = -1;
          while (sizeQ && x<0) {
            x = (int)Q(0,1); y = (int)Q(0,2); z = (int)Q(0,3);
            Q._priority_queue_remove(sizeQ);
            if (state(x,y,z)==1) x = -1; else state(x,y,z) = 1;
          }
          if (x>=0) {
            if (x - 1>=0 && state(x - 1,y,z)!=1) {
              const Tfloat dist = __distance_eikonal(res,met(x - 1,y,z),x - 1,y,z);
              if (dist<res(x - 1,y,z)) {
                res(x - 1,y,z) = dist; Q._eik_priority_queue_insert(state,sizeQ,-dist,x - 1,y,z);
              }
            }
            if (x + 1<width() && state(x + 1,y,z)!=1) {
              const Tfloat dist = __distance_eikonal(res,met(x + 1,y,z),x + 1,y,z);
              if (dist<res(x + 1,y,z)) {
                res(x + 1,y,z) = dist; Q._eik_priority_queue_insert(state,sizeQ,-dist,x + 1,y,z);
              }
            }
            if (y - 1>=0 && state(x,y - 1,z)!=1) {
              const Tfloat dist = __distance_eikonal(res,met(x,y - 1,z),x,y - 1,z);
              if (dist<res(x,y - 1,z)) {
                res(x,y - 1,z) = dist; Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y - 1,z);
              }
            }
            if (y + 1<height() && state(x,y + 1,z)!=1) {
              const Tfloat dist = __distance_eikonal(res,met(x,y + 1,z),x,y + 1,z);
              if (dist<res(x,y + 1,z)) {
                res(x,y + 1,z) = dist; Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y + 1,z);
              }
            }
            if (z - 1>=0 && state(x,y,z - 1)!=1) {
              const Tfloat dist = __distance_eikonal(res,met(x,y,z - 1),x,y,z - 1);
              if (dist<res(x,y,z - 1)) {
                res(x,y,z - 1) = dist; Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y,z - 1);
              }
            }
            if (z + 1<depth() && state(x,y,z + 1)!=1) {
              const Tfloat dist = __distance_eikonal(res,met(x,y,z + 1),x,y,z + 1);
              if (dist<res(x,y,z + 1)) {
                res(x,y,z + 1) = dist; Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y,z + 1);
              }
            }
          }
        }
      }
      return result;

Project: CImg
File: CImg.h

    //! Load image from a DICOM file, using XMedcon's external tool 'medcon' \newinstance.
    static CImg<T> get_load_medcon_external(const char *const filename) {
      return CImg<T>().load_medcon_external(filename);

Project: CImg
File: CImg.h

      static float nan() { return (float)cimg::type<double>::nan(); }

Project: CImg
File: CImg.h

    **/
    bool is_sameXY(const unsigned int size_x, const unsigned int size_y) const {
      return _width==size_x && _height==size_y;

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& _draw_ellipse(const int x0, const int y0, const float radius1, const float radius2, const float angle,
                           const tc *const color, const float opacity,
                           const unsigned int pattern, const bool is_filled) {
      if (is_empty() || (!is_filled && !pattern)) return *this;
      const float radiusM = std::max(radius1,radius2);
      if (radius1<0 || radius2<0 || x0 - radiusM>=width() || y0 + radiusM<0 || y0 - radiusM>=height()) return *this;
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_ellipse(): Specified color is (null).",
                                    cimg_instance);
      const int iradius1 = (int)cimg::round(radius1), iradius2 = (int)cimg::round(radius2);
      if (!iradius1 && !iradius2) return draw_point(x0,y0,color,opacity);
      if (iradius1==iradius2) {
        if (is_filled) return draw_circle(x0,y0,iradius1,color,opacity);
        else return draw_circle(x0,y0,iradius1,color,opacity,pattern);
      }
      const float ang = (float)(angle*cimg::PI/180);

      if (!is_filled) { // Outlined
        const float ca = std::cos(ang), sa = std::sin(ang);
        CImg<int> points((unsigned int)cimg::round(6*radiusM),2);
        cimg_forX(points,k) {
          const float
            _ang = (float)(2*cimg::PI*k/points._width),
            X = (float)(radius1*std::cos(_ang)),
            Y = (float)(radius2*std::sin(_ang));
          points(k,0) = (int)cimg::round(x0 + (X*ca - Y*sa));
          points(k,1) = (int)cimg::round(y0 + (X*sa + Y*ca));
        }
        draw_polygon(points,color,opacity,pattern);
      } else { // Filled
        cimg_init_scanline(opacity);
        const float
          ca = std::cos(ang),
          sa = -std::sin(ang),
          ca2 = ca*ca,
          sa2 = sa*sa,
          casa = ca*sa,
          i1 = 1/cimg::sqr(radius1),
          i2 = 1/cimg::sqr(radius2),
          t1 = i1*ca2 + i2*sa2,
          t2 = (i2 - i1)*casa,
          t3 = i2*ca2 + i1*sa2,
          t12 = t1*2;
        const int
          _ymin = (int)std::floor(y0 - radiusM),
          _ymax = (int)std::ceil(y0 + radiusM),
          ymin = _ymin<0?0:_ymin,
          ymax = _ymax>=height()?height() - 1:_ymax;
        for (int y = ymin; y<=ymax; ++y) {
          const float
            Y = y - y0 + 0.5f,
            B = 2*t2*Y,
            C = t3*Y*Y - 1,
            D = B*B - 4*t1*C;
          if (D>=0) {
            const float sD = std::sqrt(D);
            const int
              xmin = (int)(x0 + cimg::round((-B - sD)/t12)),
              xmax = (int)(x0 + cimg::round((-B + sD)/t12));
            cimg_draw_scanline(xmin,xmax,y,color,opacity,1);
          }
        }
      }
      return *this;

Project: CImg
File: CImg.h

    //! Convert pixel values from Lab to XYZ color spaces.
    CImg<T>& LabtoXYZ(const bool use_D65=true) {
      if (_spectrum!=3)
        throw CImgInstanceException(_cimg_instance
                                    "LabtoXYZ(): Instance is not a Lab image.",
                                    cimg_instance);
      const CImg<Tfloat> white = CImg<Tfloat>(1,1,1,3,255).RGBtoXYZ(use_D65);
      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);
      const longT whd = (longT)width()*height()*depth();
      cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,128))
      for (longT N = 0; N<whd; ++N) {
        const Tfloat
          L = (Tfloat)p1[N],
          a = (Tfloat)p2[N],
          b = (Tfloat)p3[N],
          cY = (L + 16)/116,
          cZ = cY - b/200,
          cX = a/500 + cY,
          X = (Tfloat)(24389*cX>216?cX*cX*cX:(116*cX - 16)*27/24389),
          Y = (Tfloat)(27*L>216?cY*cY*cY:27*L/24389),
          Z = (Tfloat)(24389*cZ>216?cZ*cZ*cZ:(116*cZ - 16)*27/24389);
        p1[N] = (T)(X*white[0]);
        p2[N] = (T)(Y*white[1]);
        p3[N] = (T)(Z*white[2]);
      }
      return *this;

Project: CImg
File: CImg.h

    // Find max root of a 2nd-order polynomial.
    static bool ___distance_eikonal(const Tfloat a, const Tfloat b, const Tfloat c, Tfloat &root) {
      const Tfloat delta = b*b - 4*a*c;
      if (delta<0) return false;
      root = 0.5f*(-b + std::sqrt(delta))/a;
      return true;

Project: CImg
File: CImg.h


    unsigned int _save_pandore_header_length(unsigned int id, unsigned int *dims, const unsigned int colorspace) const {
      unsigned int nbdims = 0;
      if (id==2 || id==3 || id==4) {
        dims[0] = 1; dims[1] = _width; nbdims = 2;
      }
      if (id==5 || id==6 || id==7) {
        dims[0] = 1; dims[1] = _height; dims[2] = _width; nbdims=3;
      }
      if (id==8 || id==9 || id==10) {
        dims[0] = _spectrum; dims[1] = _depth; dims[2] = _height; dims[3] = _width; nbdims = 4;
      }
      if (id==16 || id==17 || id==18) {
        dims[0] = 3; dims[1] = _height; dims[2] = _width; dims[3] = colorspace; nbdims = 4;
      }
      if (id==19 || id==20 || id==21) {
        dims[0] = 3; dims[1] = _depth; dims[2] = _height; dims[3] = _width; dims[4] = colorspace; nbdims = 5;
      }
      if (id==22 || id==23 || id==25) {
        dims[0] = _spectrum; dims[1] = _width; nbdims = 2;
      }
      if (id==26 || id==27 || id==29) {
        dims[0] = _spectrum; dims[1] = _height; dims[2] = _width; nbdims=3;
      }
      if (id==30 || id==31 || id==33) {
        dims[0] = _spectrum; dims[1] = _depth; dims[2] = _height; dims[3] = _width; nbdims = 4;
      }
      return nbdims;

Project: CImg
File: CImg.h


      static double mp_self_add(_cimg_math_parser& mp) {
        return _mp_arg(1)+=_mp_arg(2);

Project: CImg
File: CImg.h

       \param user_path Specified path, or \c 0 to get the path currently used.
       \param reinit_path Force path to be recalculated (may take some time).
       \return Path containing the \c curl binary.
    **/
    inline const char *curl_path(const char *const user_path, const bool reinit_path) {
      static CImg<char> s_path;
      cimg::mutex(7);
      if (reinit_path) s_path.assign();
      if (user_path) {
        if (!s_path) s_path.assign(1024);
        std::strncpy(s_path,user_path,1023);
      } else if (!s_path) {
        s_path.assign(1024);
        bool path_found = false;
        std::FILE *file = 0;
#if cimg_OS==2
        if (!path_found) {
          std::strcpy(s_path,".\\curl.exe");
          if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(s_path,"curl.exe");
#else
        if (!path_found) {
          std::strcpy(s_path,"./curl");
          if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(s_path,"curl");
#endif
        winformat_string(s_path);

Project: CImg
File: CImg.h

    }
    inline float abs(const float a) {
      return (float)std::fabs((double)a);

Project: CImg
File: CImg.h

    **/
    CImg<T>& row(const int y0) {
      return rows(y0,y0);

Project: CImg
File: CImg.h

    **/
    const CImg<T>& save_medcon_external(const char *const filename) const {
      if (!filename)
        throw CImgArgumentException(_cimg_instance
                                    "save_medcon_external(): Specified filename is (null).",
                                    cimg_instance);
      if (is_empty()) { cimg::fempty(0,filename); return *this; }

      CImg<charT> command(1024), filename_tmp(256), body(256);
      std::FILE *file;
      do {
        cimg_snprintf(filename_tmp,filename_tmp._width,"%s.hdr",cimg::filenamerand());
        if ((file=cimg::std_fopen(filename_tmp,"rb"))!=0) cimg::fclose(file);
      } while (file);
      save_analyze(filename_tmp);
      cimg_snprintf(command,command._width,"%s -w -c dicom -o \"%s\" -f \"%s\"",
                    cimg::medcon_path(),
                    CImg<charT>::string(filename)._system_strescape().data(),
                    CImg<charT>::string(filename_tmp)._system_strescape().data());
      cimg::system(command);
      std::remove(filename_tmp);
      cimg::split_filename(filename_tmp,body);
      cimg_snprintf(filename_tmp,filename_tmp._width,"%s.img",body._data);
      std::remove(filename_tmp);

      file = cimg::std_fopen(filename,"rb");
      if (!file) {
        cimg_snprintf(command,command._width,"m000-%s",filename);
        file = cimg::std_fopen(command,"rb");
        if (!file) {
          cimg::fclose(cimg::fopen(filename,"r"));
          throw CImgIOException(_cimg_instance
                                "save_medcon_external(): Failed to save file '%s' with external command 'medcon'.",
                                cimg_instance,
                                filename);
        }
      }
      cimg::fclose(file);
      std::rename(command,filename);
      return *this;

Project: CImg
File: CImg.h

      return get_images(pos0,pos1).move_to(*this);
    }

    //! Return a sublist \newinstance.
    CImgList<T> get_images(const unsigned int pos0, const unsigned int pos1) const {
      if (pos0>pos1 || pos1>=_width)
        throw CImgArgumentException(_cimglist_instance
                                    "images(): Specified sub-list indices (%u->%u) are out of bounds.",
                                    cimglist_instance,
                                    pos0,pos1);

Project: CImg
File: CImg.h


    CImg<T>& _distance_core(longT (*const sep)(const longT, const longT, const longT *const),
                            longT (*const f)(const longT, const longT, const longT *const)) {
 // Check for g++ 4.9.X, as OpenMP seems to crash for this particular function. I have no clues why.
#define cimg_is_gcc49x (__GNUC__==4 && __GNUC_MINOR__==9)

      const ulongT wh = (ulongT)_width*_height;
#if cimg_use_openmp!=0 && !cimg_is_gcc49x
      cimg_pragma_openmp(parallel for cimg_openmp_if(_spectrum>=2))
#endif
      cimg_forC(*this,c) {
        CImg<longT> g(_width), dt(_width), s(_width), t(_width);
        CImg<T> img = get_shared_channel(c);
#if cimg_use_openmp!=0 && !cimg_is_gcc49x
        cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*512 &&
                                                                   _height*_depth>=16)
                           firstprivate(g,dt,s,t))
#endif
        cimg_forYZ(*this,y,z) { // Over X-direction
          cimg_forX(*this,x) g[x] = (longT)img(x,y,z,0,wh);
          _distance_scan(_width,g,sep,f,s,t,dt);
          cimg_forX(*this,x) img(x,y,z,0,wh) = (T)dt[x];
        }
        if (_height>1) {
          g.assign(_height); dt.assign(_height); s.assign(_height); t.assign(_height);
#if cimg_use_openmp!=0 && !cimg_is_gcc49x
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(2)
                             cimg_openmp_if(_height>=(cimg_openmp_sizefactor)*512 && _width*_depth>=16)
                             firstprivate(g,dt,s,t))
#endif
          cimg_forXZ(*this,x,z) { // Over Y-direction
            cimg_forY(*this,y) g[y] = (longT)img(x,y,z,0,wh);
            _distance_scan(_height,g,sep,f,s,t,dt);
            cimg_forY(*this,y) img(x,y,z,0,wh) = (T)dt[y];
          }
        }
        if (_depth>1) {
          g.assign(_depth); dt.assign(_depth); s.assign(_depth); t.assign(_depth);
#if cimg_use_openmp!=0 && !cimg_is_gcc49x
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(2)
                             cimg_openmp_if(_depth>=(cimg_openmp_sizefactor)*512 && _width*_height>=16)
                             firstprivate(g,dt,s,t))
#endif
          cimg_forXY(*this,x,y) { // Over Z-direction
            cimg_forZ(*this,z) g[z] = (longT)img(x,y,z,0,wh);
            _distance_scan(_depth,g,sep,f,s,t,dt);
            cimg_forZ(*this,z) img(x,y,z,0,wh) = (T)dt[z];
          }
        }
      }
      return *this;

Project: CImg
File: CImg.h

  template<typename T>
  inline CImg<_cimg_Tfloat> operator-(const char *const expression, const CImg<T>& img) {
    return CImg<_cimg_Tfloat>(img,false).fill(expression,true)-=img;

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& pow(const CImg<t>& img) {
      const ulongT siz = size(), isiz = img.size();
      if (siz && isiz) {
        if (is_overlapped(img)) return pow(+img);
        T *ptrd = _data, *const ptre = _data + siz;
        if (siz>isiz) for (ulongT n = siz/isiz; n; --n)
          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)
            *ptrd = (T)std::pow((double)*ptrd,(double)(*(ptrs++)));
        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)std::pow((double)*ptrd,(double)(*(ptrs++)));
      }
      return *this;

Project: CImg
File: CImg.h

    **/
    T& atNXY(const int pos, const int x, const int y, const int z=0, const int c=0) {
      if (is_empty())
        throw CImgInstanceException(_cimglist_instance
                                    "atNXY(): Empty instance.",
                                    cimglist_instance);

      return _atNXY(pos,x,y,z,c);

Project: CImg
File: CImg.h

    //! Compute statistics vector from the pixel values \inplace.
    CImg<T>& stats(const unsigned int variance_method=1) {
      return get_stats(variance_method).move_to(*this);

Project: CImg
File: CImg.h

    //! Fill image with a linear sequence of values \newinstance.
    CImg<T> get_sequence(const T& a0, const T& a1) const {
      return (+*this).sequence(a0,a1);

Project: CImg
File: CImg.h

    **/
    CImg<T>& normalize(const T& min_value, const T& max_value) {
      if (is_empty()) return *this;
      const T a = min_value<max_value?min_value:max_value, b = min_value<max_value?max_value:min_value;
      T m, M = max_min(m);
      const Tfloat fm = (Tfloat)m, fM = (Tfloat)M;
      if (m==M) return fill(min_value);
      if (m!=a || M!=b) cimg_rof(*this,ptrd,T) *ptrd = (T)((*ptrd - fm)/(fM - fm)*(b - a) + a);
      return *this;

Project: CImg
File: CImg.h

    template<typename t>
    CImgList(const CImgList<t>& list, const bool is_shared):_width(0),_allocated_width(0),_data(0) {
      assign(list._width);
      cimglist_for(*this,l) _data[l].assign(list[l],is_shared);

Project: CImg
File: CImg.h

    **/
    explicit CImgList(const unsigned int n):_width(n) {
      if (n) _data = new CImg<T>[_allocated_width = std::max(16U,(unsigned int)cimg::nearest_pow2(n))];
      else { _allocated_width = 0; _data = 0; }

Project: CImg
File: CImg.h

    **/
    CImgList<T>& assign(const char *const filename) {
      return load(filename);

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_rectangle(const int x0, const int y0,
                            const int x1, const int y1,
                            const tc *const color, const float opacity,
                            const unsigned int pattern) {
      if (is_empty()) return *this;
      if (y0==y1) return draw_line(x0,y0,x1,y0,color,opacity,pattern,true);
      if (x0==x1) return draw_line(x0,y0,x0,y1,color,opacity,pattern,true);
      const int
        nx0 = x0<x1?x0:x1, nx1 = x0^x1^nx0,
        ny0 = y0<y1?y0:y1, ny1 = y0^y1^ny0;
      if (ny1==ny0 + 1) return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true).
                      draw_line(nx1,ny1,nx0,ny1,color,opacity,pattern,false);
      return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true).
        draw_line(nx1,ny0 + 1,nx1,ny1 - 1,color,opacity,pattern,false).
        draw_line(nx1,ny1,nx0,ny1,color,opacity,pattern,false).
        draw_line(nx0,ny1 - 1,nx0,ny0 + 1,color,opacity,pattern,false);

Project: CImg
File: CImg.h


    static int screen_width() {
      DEVMODE mode;
      mode.dmSize = sizeof(DEVMODE);
      mode.dmDriverExtra = 0;
      EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode);
      return (int)mode.dmPelsWidth;

Project: CImg
File: CImg.h


      static double mp_vector_map_vss(_cimg_math_parser& mp) { // Operator(vector,scalar,scalar)
        unsigned int
          siz = (unsigned int)mp.opcode[2],
          ptrs = (unsigned int)mp.opcode[4] + 1;
        double *ptrd = &_mp_arg(1) + 1;
        mp_func op = (mp_func)mp.opcode[3];
        CImg<ulongT> l_opcode(1,5);
        l_opcode[3] = mp.opcode[5]; // Scalar argument2
        l_opcode[4] = mp.opcode[6]; // Scalar argument3
        l_opcode.swap(mp.opcode);
        ulongT &argument1 = mp.opcode[2];
        while (siz-->0) { argument1 = ptrs++; *(ptrd++) = (*op)(mp); }
        l_opcode.swap(mp.opcode);
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h


    CImg<T>& _load_dlm(std::FILE *const file, const char *const filename) {
      if (!file && !filename)
        throw CImgArgumentException(_cimg_instance
                                    "load_dlm(): Specified filename is (null).",
                                    cimg_instance);

      std::FILE *const nfile = file?file:cimg::fopen(filename,"r");
      CImg<charT> delimiter(256), tmp(256); *delimiter = *tmp = 0;
      unsigned int cdx = 0, dx = 0, dy = 0;
      int err = 0;
      double val;
      assign(256,256,1,1,(T)0);
      while ((err = std::fscanf(nfile,"%lf%255[^0-9eEinfa.+-]",&val,delimiter._data))>0) {
        if (err>0) (*this)(cdx++,dy) = (T)val;
        if (cdx>=_width) resize(3*_width/2,_height,1,1,0);
        char c = 0;
        if (!cimg_sscanf(delimiter,"%255[^\n]%c",tmp._data,&c) || c=='\n') {
          dx = std::max(cdx,dx);
          if (++dy>=_height) resize(_width,3*_height/2,1,1,0);
          cdx = 0;
        }
      }
      if (cdx && err==1) { dx = cdx; ++dy; }
      if (!dx || !dy) {
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "load_dlm(): Invalid DLM file '%s'.",
                              cimg_instance,
                              filename?filename:"(FILE*)");
      }
      resize(dx,dy,1,1,0);
      if (!file) cimg::fclose(nfile);
      return *this;

Project: CImg
File: CImg.h


    inline double rol(const long double a, const unsigned int n=1) {
      return (double)rol((cimg_long)a,n);

Project: CImg
File: CImg.h

    //! Load image from a .cimg[z] file \newinstance
    static CImg<T> get_load_cimg(std::FILE *const file, const char axis='z', const float align=0) {
      return CImg<T>().load_cimg(file,axis,align);

Project: CImg
File: CImg.h


      static double mp_list_is_shared(_cimg_math_parser& mp) {
        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
        return (double)mp.listin[ind]._is_shared;

Project: CImg
File: CImg.h

    template<typename t>
    inline t min(const t& a, const t& b, const t& c) {
      return std::min(std::min(a,b),c);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T> get_resize(const CImg<t>& src,
                       const int interpolation_type=1, const unsigned int boundary_conditions=0,
                       const float centering_x = 0, const float centering_y = 0,
                       const float centering_z = 0, const float centering_c = 0) const {
      return get_resize(src._width,src._height,src._depth,src._spectrum,interpolation_type,boundary_conditions,
                        centering_x,centering_y,centering_z,centering_c);

Project: CImg
File: CImg.h


    const CImg<T>& _save_pnk(std::FILE *const file, const char *const filename) const {
      if (!file && !filename)
        throw CImgArgumentException(_cimg_instance
                                    "save_pnk(): Specified filename is (null).",
                                    cimg_instance);
      if (is_empty()) { cimg::fempty(file,filename); return *this; }
      if (_spectrum>1)
        cimg::warn(_cimg_instance
                   "save_pnk(): Instance is multispectral, only the first channel will be saved in file '%s'.",
                   cimg_instance,
                   filename?filename:"(FILE*)");

      const ulongT buf_size = std::min((ulongT)1024*1024,(ulongT)_width*_height*_depth);
      std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
      const T *ptr = data(0,0,0,0);

      if (!cimg::type<T>::is_float() && sizeof(T)==1 && _depth<2) // Can be saved as regular PNM file
        _save_pnm(file,filename,0);
      else if (!cimg::type<T>::is_float() && sizeof(T)==1) { // Save as extended P5 file: Binary byte-valued 3D
        std::fprintf(nfile,"P5\n%u %u %u\n255\n",_width,_height,_depth);
        CImg<ucharT> buf((unsigned int)buf_size);
        for (longT to_write = (longT)width()*height()*depth(); to_write>0; ) {
          const ulongT N = std::min((ulongT)to_write,buf_size);
          unsigned char *ptrd = buf._data;
          for (ulongT i = N; i>0; --i) *(ptrd++) = (unsigned char)*(ptr++);
          cimg::fwrite(buf._data,N,nfile);
          to_write-=N;
        }
      } else if (!cimg::type<T>::is_float()) { // Save as P8: Binary int32-valued 3D
        if (_depth>1) std::fprintf(nfile,"P8\n%u %u %u\n%d\n",_width,_height,_depth,(int)max());
        else std::fprintf(nfile,"P8\n%u %u\n%d\n",_width,_height,(int)max());
        CImg<intT> buf((unsigned int)buf_size);
        for (longT to_write = (longT)width()*height()*depth(); to_write>0; ) {
          const ulongT N = std::min((ulongT)to_write,buf_size);
          int *ptrd = buf._data;
          for (ulongT i = N; i>0; --i) *(ptrd++) = (int)*(ptr++);
          cimg::fwrite(buf._data,N,nfile);
          to_write-=N;
        }
      } else { // Save as P9: Binary float-valued 3D
        if (_depth>1) std::fprintf(nfile,"P9\n%u %u %u\n%g\n",_width,_height,_depth,(double)max());
        else std::fprintf(nfile,"P9\n%u %u\n%g\n",_width,_height,(double)max());
        CImg<floatT> buf((unsigned int)buf_size);
        for (longT to_write = (longT)width()*height()*depth(); to_write>0; ) {
          const ulongT N = std::min((ulongT)to_write,buf_size);
          float *ptrd = buf._data;
          for (ulongT i = N; i>0; --i) *(ptrd++) = (float)*(ptr++);
          cimg::fwrite(buf._data,N,nfile);
          to_write-=N;
        }
      }

      if (!file) cimg::fclose(nfile);
      return *this;

Project: CImg
File: CImg.h

    **/
    CImg<Tfloat> operator-(const char *const expression) const {
      return CImg<Tfloat>(*this,false)-=expression;

Project: CImg
File: CImg.h

    //! Access to a pixel value, using Dirichlet boundary conditions \const.
    T atXYZC(const int x, const int y, const int z, const int c, const T& out_value) const {
      return (x<0 || y<0 || z<0 || c<0 || x>=width() || y>=height() || z>=depth() || c>=spectrum())?out_value:
        (*this)(x,y,z,c);

Project: CImg
File: CImg.h

    **/
    const CImg<T>& save_yuv(std::FILE *const file,
                            const unsigned int chroma_subsampling=444,
                            const bool is_rgb=true) const {
      CImgList<T>(*this,true).save_yuv(file,chroma_subsampling,is_rgb);
      return *this;

Project: CImg
File: CImg.h


    CImgDisplay& set_mouse(const int posx, const int posy) {
      if (is_empty() || _is_closed) return *this;
      Display *const dpy = cimg::X11_attr().display;
      cimg_lock_display();
      XWarpPointer(dpy,0L,_window,0,0,0,0,posx,posy);
      _mouse_x = posx; _mouse_y = posy;
      _is_moved = false;
      XSync(dpy,0);
      cimg_unlock_display();
      return *this;

Project: CImg
File: CImg.h

    **/
    const CImg<T>& save_raw(const char *const filename, const bool is_multiplexed=false) const {
      return _save_raw(0,filename,is_multiplexed);

Project: CImg
File: CImg.h


      static double mp_list_jxyzc(_cimg_math_parser& mp) {
        const unsigned int
          ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
          interpolation = (unsigned int)_mp_arg(7),
          boundary_conditions = (unsigned int)_mp_arg(8);
        const CImg<T> &img = mp.listin[ind];
        const double
          ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y],
          oz = mp.mem[_cimg_mp_slot_z], oc = mp.mem[_cimg_mp_slot_c],
          x = ox + _mp_arg(3), y = oy + _mp_arg(4),
          z = oz + _mp_arg(5), c = oc + _mp_arg(6);
        switch (interpolation) {
        case 2 : // Cubic interpolation
          switch (boundary_conditions) {
          case 3 : { // Mirror
            const float
              w2 = 2.f*img.width(), h2 = 2.f*img.height(), d2 = 2.f*img.depth(), s2 = 2.f*img.spectrum(),
              mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2),
              mz = cimg::mod((float)z,d2), mc = cimg::mod((float)c,s2);
            return (double)img._cubic_atXYZ(mx<img.width()?mx:w2 - mx - 1,
                                            my<img.height()?my:h2 - my - 1,
                                            mz<img.depth()?mz:d2 - mz - 1,
                                            (int)(mc<img.spectrum()?mc:s2 - mc - 1));
          }
          case 2 : // Periodic
            return (double)img._cubic_atXYZ_p((float)x,(float)y,(float)z,
                                              (int)cimg::mod(c,(double)img._spectrum));
          case 1 : // Neumann
            return (double)img._cubic_atXYZ((float)x,(float)y,(float)z,
                                            (int)(c<0?0:c>=img._spectrum?img._spectrum - 1:c));
          default : // Dirichlet
            if (c<0 || c>=img._spectrum) return (T)0;
            return (double)img.cubic_atXYZ((float)x,(float)y,(float)z,(int)c,(T)0);
          }
        case 1 : // Linear interpolation
          switch (boundary_conditions) {
          case 3 : { // Mirror
            const float
              w2 = 2.f*img.width(), h2 = 2.f*img.height(), d2 = 2.f*img.depth(), s2 = 2.f*img.spectrum(),
              mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2),
              mz = cimg::mod((float)z,d2), mc = cimg::mod((float)c,s2);
            return (double)img._linear_atXYZ(mx<img.width()?mx:w2 - mx - 1,
                                             my<img.height()?my:h2 - my - 1,
                                             mz<img.depth()?mz:d2 - mz - 1,
                                             (int)(mc<img.spectrum()?mc:s2 - mc - 1));
          }
          case 2 : // Periodic
            return (double)img._linear_atXYZ_p((float)x,(float)y,(float)z,
                                               (int)cimg::mod(c,(double)img._spectrum));
          case 1 : // Neumann
            return (double)img._linear_atXYZ((float)x,(float)y,(float)z,
                                             (int)(c<0?0:c>=img._spectrum?img._spectrum - 1:c));
          default : // Dirichlet
            if (c<0 || c>=img._spectrum) return (T)0;
            return (double)img.linear_atXYZ((float)x,(float)y,(float)z,(int)c,(T)0);
          }
        default : // Nearest neighbor interpolation
          switch (boundary_conditions) {
          case 3 : { // Mirror
            const int
              w2 = 2*img.width(), h2 = 2*img.height(), d2 = 2*img.depth(), s2 = 2*img.spectrum(),
              mx = cimg::mod((int)x,w2), my = cimg::mod((int)y,h2),
              mz = cimg::mod((int)z,d2), mc = cimg::mod((int)c,s2);
            return (double)img(mx<img.width()?mx:w2 - mx - 1,
                               my<img.height()?my:h2 - my - 1,
                               mz<img.depth()?mz:d2 - mz - 1,
                               mc<img.spectrum()?mc:s2 - mc - 1);
          }
          case 2 : // Periodic
            return (double)img((int)cimg::mod(x,(double)img._width),
                               (int)cimg::mod(y,(double)img._height),
                               (int)cimg::mod(z,(double)img._depth),
                               (int)cimg::mod(c,(double)img._spectrum));
          case 1 : // Neumann
            return (double)img._atXYZC((int)x,(int)y,(int)z,(int)c);
          default : // Dirichlet
            return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c,(T)0);
          }
        }

Project: CImg
File: CImg.h

      static bool is_inf(const signed char) { return false; }

Project: CImg
File: CImg.h

    template<typename T1, typename T2, typename T3, typename T4>
    inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4) {
      cimg::swap(a1,b1,a2,b2,a3,b3); cimg::swap(a4,b4);

Project: CImg
File: CImg.h


    const CImg<T>& _display(CImgDisplay &disp, const char *const title, const bool display_info,
                            unsigned int *const XYZ, const bool exit_on_anykey,
                            const bool exit_on_singleclick) const {
      unsigned int oldw = 0, oldh = 0, _XYZ[3] = { 0 }, key = 0;
      int x0 = 0, y0 = 0, z0 = 0, x1 = width() - 1, y1 = height() - 1, z1 = depth() - 1,
        old_mouse_x = -1, old_mouse_y = -1;

      if (!disp) {
        disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,1);
        if (!title) disp.set_title("CImg<%s> (%ux%ux%ux%u)",pixel_type(),_width,_height,_depth,_spectrum);
        else disp.set_title("%s",title);
      } else if (title) disp.set_title("%s",title);
      disp.show().flush();

      const CImg<char> dtitle = CImg<char>::string(disp.title());
      if (display_info) print(dtitle);

      CImg<T> zoom;
      for (bool reset_view = true, resize_disp = false, is_first_select = true; !key && !disp.is_closed(); ) {
        if (reset_view) {
          if (XYZ) { _XYZ[0] = XYZ[0]; _XYZ[1] = XYZ[1]; _XYZ[2] = XYZ[2]; }
          else {
            _XYZ[0] = (unsigned int)(x0 + x1 + 1)/2;
            _XYZ[1] = (unsigned int)(y0 + y1 + 1)/2;
            _XYZ[2] = (unsigned int)(z0 + z1 + 1)/2;
          }
          x0 = 0; y0 = 0; z0 = 0; x1 = width() - 1; y1 = height() - 1; z1 = depth() - 1;
          disp.resize(cimg_fitscreen(_width,_height,_depth),false);
          oldw = disp._width; oldh = disp._height;
          resize_disp = true;
          reset_view = false;
        }
        if (!x0 && !y0 && !z0 && x1==width() - 1 && y1==height() - 1 && z1==depth() - 1) {
          if (is_empty()) zoom.assign(1,1,1,1,(T)0); else zoom.assign();
        } else zoom = get_crop(x0,y0,z0,x1,y1,z1);

        const CImg<T>& visu = zoom?zoom:*this;
        const unsigned int
          dx = 1U + x1 - x0, dy = 1U + y1 - y0, dz = 1U + z1 - z0,
          tw = dx + (dz>1?dz:0U), th = dy + (dz>1?dz:0U);
        if (!is_empty() && !disp.is_fullscreen() && resize_disp) {
          const float
            ttw = (float)tw*disp.width()/oldw, tth = (float)th*disp.height()/oldh,
            dM = std::max(ttw,tth), diM = (float)std::max(disp.width(),disp.height());
          const unsigned int
            imgw = (unsigned int)(ttw*diM/dM), imgh = (unsigned int)(tth*diM/dM);
          disp.set_fullscreen(false).resize(cimg_fitscreen(imgw,imgh,1),false);
          resize_disp = false;
        }
        oldw = tw; oldh = th;

        bool
          go_up = false, go_down = false, go_left = false, go_right = false,
          go_inc = false, go_dec = false, go_in = false, go_out = false,
          go_in_center = false;

        disp.set_title("%s",dtitle._data);
        if (_width>1 && visu._width==1) disp.set_title("%s | x=%u",disp._title,x0);
        if (_height>1 && visu._height==1) disp.set_title("%s | y=%u",disp._title,y0);
        if (_depth>1 && visu._depth==1) disp.set_title("%s | z=%u",disp._title,z0);

        disp._mouse_x = old_mouse_x; disp._mouse_y = old_mouse_y;
        CImg<intT> selection = visu._select(disp,0,2,_XYZ,x0,y0,z0,true,is_first_select,_depth>1,true);
        old_mouse_x = disp._mouse_x; old_mouse_y = disp._mouse_y;
        is_first_select = false;

        if (disp.wheel()) {
          if ((disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) &&
              (disp.is_keySHIFTLEFT() || disp.is_keySHIFTRIGHT())) {
            go_left = !(go_right = disp.wheel()>0);
          } else if (disp.is_keySHIFTLEFT() || disp.is_keySHIFTRIGHT()) {
            go_down = !(go_up = disp.wheel()>0);
          } else if (depth()==1 || disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
            go_out = !(go_in = disp.wheel()>0); go_in_center = false;
          }
          disp.set_wheel();
        }

        const int
          sx0 = selection(0), sy0 = selection(1), sz0 = selection(2),
          sx1 = selection(3), sy1 = selection(4), sz1 = selection(5);
        if (sx0>=0 && sy0>=0 && sz0>=0 && sx1>=0 && sy1>=0 && sz1>=0) {
          x1 = x0 + sx1; y1 = y0 + sy1; z1 = z0 + sz1;
          x0+=sx0; y0+=sy0; z0+=sz0;
          if ((sx0==sx1 && sy0==sy1) || (_depth>1 && sx0==sx1 && sz0==sz1) || (_depth>1 && sy0==sy1 && sz0==sz1)) {
            if (exit_on_singleclick && (!zoom || is_empty())) break; else reset_view = true;
          }
          resize_disp = true;
        } else switch (key = disp.key()) {
#if cimg_OS!=2
          case cimg::keyCTRLRIGHT : case cimg::keySHIFTRIGHT :
#endif
          case 0 : case cimg::keyCTRLLEFT : case cimg::keySHIFTLEFT : key = 0; break;
          case cimg::keyP : if (visu._depth>1 && (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT())) {
              // Special mode: play stack of frames
              const unsigned int
                w1 = visu._width*disp.width()/(visu._width + (visu._depth>1?visu._depth:0)),
                h1 = visu._height*disp.height()/(visu._height + (visu._depth>1?visu._depth:0));
              float frame_timing = 5;
              bool is_stopped = false;
              disp.set_key(key,false).set_wheel().resize(cimg_fitscreen(w1,h1,1),false); key = 0;
              for (unsigned int timer = 0; !key && !disp.is_closed() && !disp.button(); ) {
                if (disp.is_resized()) disp.resize(false);
                if (!timer) {
                  visu.get_slice((int)_XYZ[2]).display(disp.set_title("%s | z=%d",dtitle.data(),_XYZ[2]));
                  (++_XYZ[2])%=visu._depth;
                }
                if (!is_stopped) { if (++timer>(unsigned int)frame_timing) timer = 0; } else timer = ~0U;
                if (disp.wheel()) { frame_timing-=disp.wheel()/3.f; disp.set_wheel(); }
                switch (key = disp.key()) {
#if cimg_OS!=2
                case cimg::keyCTRLRIGHT :
#endif
                case cimg::keyCTRLLEFT : key = 0; break;
                case cimg::keyPAGEUP : frame_timing-=0.3f; key = 0; break;
                case cimg::keyPAGEDOWN : frame_timing+=0.3f; key = 0; break;
                case cimg::keySPACE : is_stopped = !is_stopped; disp.set_key(key,false); key = 0; break;
                case cimg::keyARROWLEFT : case cimg::keyARROWUP : is_stopped = true; timer = 0; key = 0; break;
                case cimg::keyARROWRIGHT : case cimg::keyARROWDOWN : is_stopped = true;
                  (_XYZ[2]+=visu._depth - 2)%=visu._depth; timer = 0; key = 0; break;
                case cimg::keyD : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
                    disp.set_fullscreen(false).
                      resize(CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,false),
                             CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,true),false);
                    disp.set_key(key,false); key = 0;
                  } break;
                case cimg::keyC : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
                    disp.set_fullscreen(false).
                      resize(cimg_fitscreen(2*disp.width()/3,2*disp.height()/3,1),false).set_key(key,false); key = 0;
                  } break;
                case cimg::keyR : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
                    disp.set_fullscreen(false).
                      resize(cimg_fitscreen(_width,_height,_depth),false).set_key(key,false); key = 0;
                  } break;
                case cimg::keyF : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
                    disp.resize(disp.screen_width(),disp.screen_height(),false).
                      toggle_fullscreen().set_key(key,false); key = 0;
                  } break;
                }
                frame_timing = frame_timing<1?1:(frame_timing>39?39:frame_timing);
                disp.wait(20);
              }
              const unsigned int
                w2 = (visu._width + (visu._depth>1?visu._depth:0))*disp.width()/visu._width,
                h2 = (visu._height + (visu._depth>1?visu._depth:0))*disp.height()/visu._height;
              disp.resize(cimg_fitscreen(w2,h2,1),false).set_title(dtitle.data()).set_key().set_button().set_wheel();
              key = 0;
            } break;
          case cimg::keyHOME : reset_view = resize_disp = true; key = 0; break;
          case cimg::keyPADADD : go_in = true; go_in_center = true; key = 0; break;
          case cimg::keyPADSUB : go_out = true; key = 0; break;
          case cimg::keyARROWLEFT : case cimg::keyPAD4: go_left = true; key = 0; break;
          case cimg::keyARROWRIGHT : case cimg::keyPAD6: go_right = true; key = 0; break;
          case cimg::keyARROWUP : case cimg::keyPAD8: go_up = true; key = 0; break;
          case cimg::keyARROWDOWN : case cimg::keyPAD2: go_down = true; key = 0; break;
          case cimg::keyPAD7 : go_up = go_left = true; key = 0; break;
          case cimg::keyPAD9 : go_up = go_right = true; key = 0; break;
          case cimg::keyPAD1 : go_down = go_left = true; key = 0; break;
          case cimg::keyPAD3 : go_down = go_right = true; key = 0; break;
          case cimg::keyPAGEUP : go_inc = true; key = 0; break;
          case cimg::keyPAGEDOWN : go_dec = true; key = 0; break;
          }
        if (go_in) {
          const int
            mx = go_in_center?disp.width()/2:disp.mouse_x(),
            my = go_in_center?disp.height()/2:disp.mouse_y(),
            mX = mx*(width() + (depth()>1?depth():0))/disp.width(),
            mY = my*(height() + (depth()>1?depth():0))/disp.height();
          int X = (int)_XYZ[0], Y = (int)_XYZ[1], Z = (int)_XYZ[2];
          if (mX<width() && mY<height())  {
            X = x0 + mX*(1 + x1 - x0)/width(); Y = y0 + mY*(1 + y1 - y0)/height();
          }
          if (mX<width() && mY>=height()) {
            X = x0 + mX*(1 + x1 - x0)/width(); Z = z0 + (mY - height())*(1 + z1 - z0)/depth();
          }
          if (mX>=width() && mY<height()) {
            Y = y0 + mY*(1 + y1 - y0)/height(); Z = z0 + (mX - width())*(1 + z1 - z0)/depth();
          }
          if (x1 - x0>4) { x0 = X - 3*(X - x0)/4; x1 = X + 3*(x1 - X)/4; }
          if (y1 - y0>4) { y0 = Y - 3*(Y - y0)/4; y1 = Y + 3*(y1 - Y)/4; }
          if (z1 - z0>4) { z0 = Z - 3*(Z - z0)/4; z1 = Z + 3*(z1 - Z)/4; }
        }
        if (go_out) {
          const int
            delta_x = (x1 - x0)/8, delta_y = (y1 - y0)/8, delta_z = (z1 - z0)/8,
            ndelta_x = delta_x?delta_x:(_width>1),
            ndelta_y = delta_y?delta_y:(_height>1),
            ndelta_z = delta_z?delta_z:(_depth>1);
          x0-=ndelta_x; y0-=ndelta_y; z0-=ndelta_z;
          x1+=ndelta_x; y1+=ndelta_y; z1+=ndelta_z;
          if (x0<0) { x1-=x0; x0 = 0; if (x1>=width()) x1 = width() - 1; }
          if (y0<0) { y1-=y0; y0 = 0; if (y1>=height()) y1 = height() - 1; }
          if (z0<0) { z1-=z0; z0 = 0; if (z1>=depth()) z1 = depth() - 1; }
          if (x1>=width()) { x0-=(x1 - width() + 1); x1 = width() - 1; if (x0<0) x0 = 0; }
          if (y1>=height()) { y0-=(y1 - height() + 1); y1 = height() - 1; if (y0<0) y0 = 0; }
          if (z1>=depth()) { z0-=(z1 - depth() + 1); z1 = depth() - 1; if (z0<0) z0 = 0; }
          const float
            ratio = (float)(x1-x0)/(y1-y0),
            ratiow = (float)disp._width/disp._height,
            sub = std::min(cimg::abs(ratio - ratiow),cimg::abs(1/ratio-1/ratiow));
          if (sub>0.01) resize_disp = true;
        }
        if (go_left) {
          const int delta = (x1 - x0)/4, ndelta = delta?delta:(_width>1);
          if (x0 - ndelta>=0) { x0-=ndelta; x1-=ndelta; }
          else { x1-=x0; x0 = 0; }
        }
        if (go_right) {
          const int delta = (x1 - x0)/4, ndelta = delta?delta:(_width>1);
          if (x1+ndelta<width()) { x0+=ndelta; x1+=ndelta; }
          else { x0+=(width() - 1 - x1); x1 = width() - 1; }
        }
        if (go_up) {
          const int delta = (y1 - y0)/4, ndelta = delta?delta:(_height>1);
          if (y0 - ndelta>=0) { y0-=ndelta; y1-=ndelta; }
          else { y1-=y0; y0 = 0; }
        }
        if (go_down) {
          const int delta = (y1 - y0)/4, ndelta = delta?delta:(_height>1);
          if (y1+ndelta<height()) { y0+=ndelta; y1+=ndelta; }
          else { y0+=(height() - 1 - y1); y1 = height() - 1; }
        }
        if (go_inc) {
          const int delta = (z1 - z0)/4, ndelta = delta?delta:(_depth>1);
          if (z0 - ndelta>=0) { z0-=ndelta; z1-=ndelta; }
          else { z1-=z0; z0 = 0; }
        }
        if (go_dec) {
          const int delta = (z1 - z0)/4, ndelta = delta?delta:(_depth>1);
          if (z1+ndelta<depth()) { z0+=ndelta; z1+=ndelta; }
          else { z0+=(depth() - 1 - z1); z1 = depth() - 1; }
        }
        disp.wait(100);
        if (!exit_on_anykey && key && key!=cimg::keyESC &&
            (key!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) {
          key = 0;
        }
      }
      disp.set_key(key);
      if (XYZ) { XYZ[0] = _XYZ[0]; XYZ[1] = _XYZ[1]; XYZ[2] = _XYZ[2]; }
      return *this;

Project: CImg
File: CImg.h

    template<typename tz, typename tc>
    CImg<T>& draw_triangle(CImg<tz>& zbuffer,
                           int x0, int y0, const float z0,
                           int x1, int y1, const float z1,
                           int x2, int y2, const float z2,
                           const CImg<tc>& texture,
                           int tx0, int ty0,
                           int tx1, int ty1,
                           int tx2, int ty2,
                           const float opacity=1,
                           const float brightness=1) {
      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
      if (!is_sameXY(zbuffer))
        throw CImgArgumentException(_cimg_instance
                                    "draw_triangle(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have "
                                    "different dimensions.",
                                    cimg_instance,
                                    zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data);

      if (texture._depth>1 || texture._spectrum<_spectrum)
        throw CImgArgumentException(_cimg_instance
                                    "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).",
                                    cimg_instance,
                                    texture._width,texture._height,texture._depth,texture._spectrum,texture._data);
      if (is_overlapped(texture))
        return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness);

      float iz0 = 1/z0, iz1 = 1/z1, iz2 = 1/z2;
      if (y0>y1) cimg::swap(x0,x1,y0,y1,iz0,iz1,tx0,tx1,ty0,ty1);
      if (y0>y2) cimg::swap(x0,x2,y0,y2,iz0,iz2,tx0,tx2,ty0,ty2);
      if (y1>y2) cimg::swap(x1,x2,y1,y2,iz1,iz2,tx1,tx2,ty1,ty2);
      if (y2<0 || y0>=height() || cimg::min(x0,x1,x2)>=width() || cimg::max(x0,x1,x2)<0 || !opacity) return *this;

      const int
        w1 = width() - 1, h1 = height() - 1,
        dx01 = x1 - x0, dx02 = x2 - x0, dx12 = x2 - x1,
        dy01 = std::max(1,y1 - y0), dy02 = std::max(1,y2 - y0), dy12 = std::max(1,y2 - y1),
        cy0 = cimg::cut(y0,0,h1), cy2 = cimg::cut(y2,0,h1),
        hdy01 = dy01*cimg::sign(dx01)/2, hdy02 = dy02*cimg::sign(dx02)/2, hdy12 = dy12*cimg::sign(dx12)/2;
      const float
        diz01 = iz1 - iz0, diz02 = iz2 - iz0, diz12 = iz2 - iz1,
        txz0 = tx0*iz0, txz1 = tx1*iz1, txz2 = tx2*iz2,
        tyz0 = ty0*iz0, tyz1 = ty1*iz1, tyz2 = ty2*iz2,
        dtxz01 = txz1 - txz0, dtxz02 = txz2 - txz0, dtxz12 = txz2 - txz1,
        dtyz01 = tyz1 - tyz0, dtyz02 = tyz2 - tyz0, dtyz12 = tyz2 - tyz1;

      const ulongT twhd = (ulongT)texture._width*texture._height*texture._depth;
      const float cbs = cimg::cut(brightness,0,2);
      cimg_init_scanline(opacity);

      for (int y = cy0; y<=cy2; ++y) {
        const int yy0 = y - y0, yy1 = y - y1;
        int
          xm = y<y1?x0 + (dx01*yy0 + hdy01)/dy01:x1 + (dx12*yy1 + hdy12)/dy12,
          xM = x0 + (dx02*yy0 + hdy02)/dy02;
        float
          izm = y<y1?(iz0 + diz01*yy0/dy01):(iz1 + diz12*yy1/dy12),
          izM = iz0 + diz02*yy0/dy02,
          txzm = y<y1?(txz0 + dtxz01*yy0/dy01):(txz1 + dtxz12*yy1/dy12),
          txzM = txz0 + dtxz02*yy0/dy02,
          tyzm = y<y1?(tyz0 + dtyz01*yy0/dy01):(tyz1 + dtyz12*yy1/dy12),
          tyzM = tyz0 + dtyz02*yy0/dy02;
        if (xm>xM) cimg::swap(xm,xM,txzm,txzM,tyzm,tyzM,izm,izM);
        if (xM>=0 || xm<=w1) {
          const int
            cxm = cimg::cut(xm,0,w1),
            cxM = cimg::cut(xM,0,w1);
          T *ptrd = data(cxm,y);
          tz *ptrz = zbuffer.data(cxm,y);
          const int dxmM = std::max(1,xM - xm);
          const float dizmM = izM - izm, dtxzmM = txzM - txzm, dtyzmM = tyzM - tyzm;

          for (int x = cxm; x<cxM; ++x) {
            const int xxm = x - xm;
            const float iz = izm + dizmM*xxm/dxmM;
            if (iz>=*ptrz) {
              *ptrz = (tz)iz;
              const float
                txz = txzm + dtxzmM*xxm/dxmM,
                tyz = tyzm + dtyzmM*xxm/dxmM;
              const int
                tx = (int)cimg::round(txz/iz),
                ty = (int)cimg::round(tyz/iz);
              const tc *const color = &texture._atXY(tx,ty);
              cimg_forC(*this,c) {
                const Tfloat val = cbs<=1?color[c*twhd]*cbs:(2 - cbs)*color[c*twhd] + (cbs - 1)*_sc_maxval;
                ptrd[c*_sc_whd] = (T)(opacity>=1?val:val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity);
              }
            }
            ++ptrd; ++ptrz;
          }
        }
      }
      return *this;

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T> get_dijkstra(const unsigned int starting_node, const unsigned int ending_node,
                         CImg<t>& previous_node) const {
      if (_width!=_height || _depth!=1 || _spectrum!=1)
        throw CImgInstanceException(_cimg_instance
                                    "dijkstra(): Instance is not a graph adjacency matrix.",
                                    cimg_instance);

      return dijkstra(*this,_width,starting_node,ending_node,previous_node);

Project: CImg
File: CImg.h


      static double mp_sin(_cimg_math_parser& mp) {
        return std::sin(_mp_arg(2));

Project: CImg
File: CImg.h

        return val<(double)min()?min():val>(double)max()?max():(unsigned int)val; }

Project: CImg
File: CImg.h

    **/

Project: CImg
File: CImg.h

    //! Sort pixel values \newinstance.
    CImg<T> get_sort(const bool is_increasing=true, const char axis=0) const {
      return (+*this).sort(is_increasing,axis);

Project: CImg
File: CImg.h

  template<typename T>
  inline bool operator==(const char *const expression, const CImg<T>& img) {
    return img==expression;

Project: CImg
File: CImg.h

    **/
    T& back() {
      return *(_data + size() - 1);

Project: CImg
File: CImg.h

        \param last_frame Index of last image frame to read.
        \param step_frame Step applied between each frame.
        \param yuv2rgb Apply YUV to RGB transformation during reading.
    **/
    CImgList<T>& load_yuv(const char *const filename,
                          const unsigned int size_x, const unsigned int size_y,
                          const unsigned int chroma_subsampling=444,
                          const unsigned int first_frame=0, const unsigned int last_frame=~0U,

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& operator+=(const CImg<t>& img) {
      const ulongT siz = size(), isiz = img.size();
      if (siz && isiz) {
        if (is_overlapped(img)) return *this+=+img;
        T *ptrd = _data, *const ptre = _data + siz;
        if (siz>isiz) for (ulongT n = siz/isiz; n; --n)
          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)
            *ptrd = (T)(*ptrd + *(ptrs++));
        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)(*ptrd + *(ptrs++));
      }
      return *this;

Project: CImg
File: CImg.h

    template<typename tz, typename tc>
    CImg<T>& draw_triangle(CImg<tz>& zbuffer,
                           int x0, int y0, const float z0,
                           int x1, int y1, const float z1,
                           int x2, int y2, const float z2,
                           const CImg<tc>& texture,
                           int tx0, int ty0,
                           int tx1, int ty1,
                           int tx2, int ty2,
                           float bs0,
                           float bs1,
                           float bs2,
                           const float opacity=1) {
      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
      if (!is_sameXY(zbuffer))
        throw CImgArgumentException(_cimg_instance
                                    "draw_triangle(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have "
                                    "different dimensions.",
                                    cimg_instance,
                                    zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data);
      if (texture._depth>1 || texture._spectrum<_spectrum)
        throw CImgArgumentException(_cimg_instance
                                    "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).",
                                    cimg_instance,
                                    texture._width,texture._height,texture._depth,texture._spectrum,texture._data);
      if (is_overlapped(texture))
        return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,bs0,bs1,bs2,opacity);

      float iz0 = 1/z0, iz1 = 1/z1, iz2 = 1/z2;
      if (y0>y1) cimg::swap(x0,x1,y0,y1,iz0,iz1,tx0,tx1,ty0,ty1,bs0,bs1);
      if (y0>y2) cimg::swap(x0,x2,y0,y2,iz0,iz2,tx0,tx2,ty0,ty2,bs0,bs2);
      if (y1>y2) cimg::swap(x1,x2,y1,y2,iz1,iz2,tx1,tx2,ty1,ty2,bs1,bs2);
      if (y2<0 || y0>=height() || cimg::min(x0,x1,x2)>=width() || cimg::max(x0,x1,x2)<0 || !opacity) return *this;

      const int
        w1 = width() - 1, h1 = height() - 1,
        dx01 = x1 - x0, dx02 = x2 - x0, dx12 = x2 - x1,
        dy01 = std::max(1,y1 - y0), dy02 = std::max(1,y2 - y0), dy12 = std::max(1,y2 - y1),
        cy0 = cimg::cut(y0,0,h1), cy2 = cimg::cut(y2,0,h1),
        hdy01 = dy01*cimg::sign(dx01)/2, hdy02 = dy02*cimg::sign(dx02)/2, hdy12 = dy12*cimg::sign(dx12)/2;
      const float
        diz01 = iz1 - iz0, diz02 = iz2 - iz0, diz12 = iz2 - iz1,
        txz0 = tx0*iz0, txz1 = tx1*iz1, txz2 = tx2*iz2,
        tyz0 = ty0*iz0, tyz1 = ty1*iz1, tyz2 = ty2*iz2,
        dtxz01 = txz1 - txz0, dtxz02 = txz2 - txz0, dtxz12 = txz2 - txz1,
        dtyz01 = tyz1 - tyz0, dtyz02 = tyz2 - tyz0, dtyz12 = tyz2 - tyz1,
        dbs01 = bs1 - bs0, dbs02 = bs2 - bs0, dbs12 = bs2 - bs1;

      const ulongT twhd = (ulongT)texture._width*texture._height*texture._depth;
      cimg_init_scanline(opacity);

      for (int y = cy0; y<=cy2; ++y) {
        const int yy0 = y - y0, yy1 = y - y1;
        int
          xm = y<y1?x0 + (dx01*yy0 + hdy01)/dy01:x1 + (dx12*yy1 + hdy12)/dy12,
          xM = x0 + (dx02*yy0 + hdy02)/dy02;
        float
          izm = y<y1?(iz0 + diz01*yy0/dy01):(iz1 + diz12*yy1/dy12),
          izM = iz0 + diz02*yy0/dy02,
          txzm = y<y1?(txz0 + dtxz01*yy0/dy01):(txz1 + dtxz12*yy1/dy12),
          txzM = txz0 + dtxz02*yy0/dy02,
          tyzm = y<y1?(tyz0 + dtyz01*yy0/dy01):(tyz1 + dtyz12*yy1/dy12),
          tyzM = tyz0 + dtyz02*yy0/dy02,
          bsm = y<y1?(bs0 + dbs01*yy0/dy01):(bs1 + dbs12*yy1/dy12),
          bsM = bs0 + dbs02*yy0/dy02;
        if (xm>xM) cimg::swap(xm,xM,txzm,txzM,tyzm,tyzM,izm,izM,bsm,bsM);
        if (xM>=0 || xm<=w1) {
          const int
            cxm = cimg::cut(xm,0,w1),
            cxM = cimg::cut(xM,0,w1);
          T *ptrd = data(cxm,y);
          tz *ptrz = zbuffer.data(cxm,y);
          const int dxmM = std::max(1,xM - xm);
          const float dizmM = izM - izm, dtxzmM = txzM - txzm, dtyzmM = tyzM - tyzm, dbsmM = bsM - bsm;

          for (int x = cxm; x<cxM; ++x) {
            const int xxm = x - xm;
            const float iz = izm + dizmM*xxm/dxmM;
            if (iz>=*ptrz) {
              *ptrz = (tz)iz;
              const float
                txz = txzm + dtxzmM*xxm/dxmM,
                tyz = tyzm + dtyzmM*xxm/dxmM,
                cbs = cimg::cut(bsm + dbsmM*xxm/dxmM,0,2);
              const int
                tx = (int)cimg::round(txz/iz),
                ty = (int)cimg::round(tyz/iz);
              const tc *const color = &texture._atXY(tx,ty);
              cimg_forC(*this,c) {
                const tc col = color[c*twhd];
                const Tfloat val = cbs<=1?cbs*col:(2 - cbs)*col + (cbs - 1)*_sc_maxval;
                ptrd[c*_sc_whd] = (T)(opacity>=1?val:val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity);
              }
            }
            ++ptrd; ++ptrz;
          }
        }
      }
      return *this;

Project: CImg
File: CImg.h

      _functor3d_int(const CImg<T>& pref):ref(pref) {}
      float operator()(const float x, const float y, const float z) const {
        return (float)ref((int)x,(int)y,(int)z);

Project: CImg
File: CImg.h

      \param pos Index of the insertion.
      \param is_shared Tells if inserted images are shared copies of images of \c list or not.
    **/
    template<typename t>
    CImgList<T>& insert(const CImgList<t>& list, const unsigned int pos=~0U, const bool is_shared=false) {
      const unsigned int npos = pos==~0U?_width:pos;

Project: CImg
File: CImg.h

    template<typename t, typename T>
    static void _render_resize(const T *ptrs, const unsigned int ws, const unsigned int hs,
                               t *ptrd, const unsigned int wd, const unsigned int hd) {
      typedef typename cimg::last<T,cimg_ulong>::type ulongT;
      const ulongT one = (ulongT)1;
      CImg<ulongT> off_x(wd), off_y(hd + 1);
      if (wd==ws) off_x.fill(1);
      else {
        ulongT *poff_x = off_x._data, curr = 0;
        for (unsigned int x = 0; x<wd; ++x) {
          const ulongT old = curr;
          curr = (x + one)*ws/wd;
          *(poff_x++) = curr - old;
        }
      }
      if (hd==hs) off_y.fill(ws);
      else {
        ulongT *poff_y = off_y._data, curr = 0;
        for (unsigned int y = 0; y<hd; ++y) {
          const ulongT old = curr;
          curr = (y + one)*hs/hd;
          *(poff_y++) = ws*(curr - old);
        }
        *poff_y = 0;
      }
      ulongT *poff_y = off_y._data;
      for (unsigned int y = 0; y<hd; ) {
        const T *ptr = ptrs;
        ulongT *poff_x = off_x._data;
        for (unsigned int x = 0; x<wd; ++x) { *(ptrd++) = *ptr; ptr+=*(poff_x++); }
        ++y;
        ulongT dy = *(poff_y++);
        for ( ; !dy && y<hd; std::memcpy(ptrd,ptrd - wd,sizeof(t)*wd), ++y, ptrd+=wd, dy = *(poff_y++)) {}
        ptrs+=dy;
      }

Project: CImg
File: CImg.h

    template<typename tp, typename tf, typename tc, typename to, typename tz>
    CImg<T>& draw_object3d(LibBoard::Board& board,
                           const float x0, const float y0, const float z0,
                           const CImg<tp>& vertices, const CImgList<tf>& primitives,
                           const CImgList<tc>& colors, const CImgList<to>& opacities,
                           const unsigned int render_type,
                           const bool is_double_sided, const float focale,
                           const float lightx, const float lighty, const float lightz,
                           const float specular_lightness, const float specular_shininess,
                           const float g_opacity, CImg<tz>& zbuffer) {
      return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities,
                            render_type,is_double_sided,focale,lightx,lighty,lightz,
                            specular_lightness,specular_shininess,g_opacity,1);

Project: CImg
File: CImg.h

    //! Fill sequentially all pixel values with specified values \newinstance.
    CImg<T> get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,
                     const T& val6, const T& val7, const T& val8) const {
      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8);

Project: CImg
File: CImg.h


    CImgDisplay& paint(const bool wait_expose=true) {
      if (is_empty()) return *this;
      cimg_lock_display();
      _paint(wait_expose);
      cimg_unlock_display();
      return *this;

Project: CImg
File: CImg.h

    /**
       \param filename Filename to write data to.
       \param is_compressed Tells if data compression must be enabled.

Project: CImg
File: CImg.h

    //! Convert 3D object into a CImg3d representation \overloading.
    CImg<floatT> get_object3dtoCImg3d(const bool full_check=true) const {
      CImgList<T> opacities, colors;
      CImgList<uintT> primitives(width(),1,1,1,1);
      cimglist_for(primitives,p) primitives(p,0) = p;
      return get_object3dtoCImg3d(primitives,colors,opacities,full_check);

Project: CImg
File: CImg.h

    **/
    CImg<T>& shift_object3d(const float tx, const float ty=0, const float tz=0) {
      if (_height!=3 || _depth>1 || _spectrum>1)
        throw CImgInstanceException(_cimg_instance
                                    "shift_object3d(): Instance is not a set of 3D vertices.",
                                    cimg_instance);

      get_shared_row(0)+=tx; get_shared_row(1)+=ty; get_shared_row(2)+=tz;
      return *this;

Project: CImg
File: CImg.h

    //! Return a 1x1 diagonal matrix containing specified coefficients.
    static CImg<T> diagonal(const T& a0) {
      return matrix(a0);

Project: CImg
File: CImg.h

    template<typename T>
    CImgDisplay& assign(const CImg<T>& img, const char *const title=0,
                        const unsigned int normalization_type=3,
                        const bool fullscreen_flag=false, const bool closed_flag=false) {
      if (!img) return assign();
      CImg<T> tmp;
      const CImg<T>& nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width - 1)/2,
                                                                           (img._height - 1)/2,
                                                                           (img._depth - 1)/2));
      _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag);
      if (_normalization==2) _min = (float)nimg.min_max(_max);
      return display(nimg);

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_triangle(const int x0, const int y0,
                           const int x1, const int y1,
                           const int x2, const int y2,
                           const tc *const color, const float opacity,
                           const unsigned int pattern) {
      if (is_empty()) return *this;
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_triangle(): Specified color is (null).",
                                    cimg_instance);
      draw_line(x0,y0,x1,y1,color,opacity,pattern,true).
        draw_line(x1,y1,x2,y2,color,opacity,pattern,false).
        draw_line(x2,y2,x0,y0,color,opacity,pattern,false);
      return *this;

Project: CImg
File: CImg.h

    //! Save list as a gzipped file, using external tool 'gzip'.
    /**
      \param filename Filename to write data to.
    **/
    const CImgList<T>& save_gzip_external(const char *const filename) const {
      if (!filename)
        throw CImgIOException(_cimglist_instance
                              "save_gzip_external(): Specified filename is (null).",
                              cimglist_instance);
      CImg<charT> command(1024), filename_tmp(256), body(256);
      const char
        *ext = cimg::split_filename(filename,body),
        *ext2 = cimg::split_filename(body,0);
      std::FILE *file;
      do {
        if (!cimg::strcasecmp(ext,"gz")) {
          if (*ext2) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s",
                                   cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2);
          else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.cimg",
                             cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
        } else {
          if (*ext) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s",
                                  cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext);
          else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.cimg",
                             cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
        }
        if ((file=cimg::std_fopen(filename_tmp,"rb"))!=0) cimg::fclose(file);
      } while (file);

      if (is_saveable(body)) {
        save(filename_tmp);
        cimg_snprintf(command,command._width,"%s -c \"%s\" > \"%s\"",
                      cimg::gzip_path(),
                      CImg<charT>::string(filename_tmp)._system_strescape().data(),
                      CImg<charT>::string(filename)._system_strescape().data());
        cimg::system(command);
        file = cimg::std_fopen(filename,"rb");
        if (!file)
          throw CImgIOException(_cimglist_instance
                                "save_gzip_external(): Failed to save file '%s' with external command 'gzip'.",
                                cimglist_instance,
                                filename);
        else cimg::fclose(file);
        std::remove(filename_tmp);
      } else {
        CImg<charT> nfilename(1024);
        cimglist_for(*this,l) {
          cimg::number_filename(body,l,6,nfilename);
          if (*ext) cimg_sprintf(nfilename._data + std::strlen(nfilename),".%s",ext);
          _data[l].save_gzip_external(nfilename);

Project: CImg
File: CImg.h

    template<typename T>
    inline T minmod(const T& a, const T& b) {
      return a*b<=0?0:(a>0?(a<b?a:b):(a<b?b:a));

Project: CImg
File: CImg.h

    template<typename t>
    CImg<_cimg_Tt> get_mul(const CImg<t>& img) const {
      return CImg<_cimg_Tt>(*this,false).mul(img);

Project: CImg
File: CImg.h

       \param mode Output type, can be primary { 0=files only | 1=folders only | 2=files + folders }.
       \param include_path Tell if \c path must be included in resulting filenames.
       \return A list of filenames.
    **/
    inline CImgList<char> files(const char *const path, const bool is_pattern=false,
                                const unsigned int mode=2, const bool include_path=false) {
      if (!path || !*path) return files("*",true,mode,include_path);
      CImgList<char> res;

      // If path is a valid folder name, ignore argument 'is_pattern'.
      const bool _is_pattern = is_pattern && !cimg::is_directory(path);
      bool is_root = false, is_current = false;
      cimg::unused(is_root,is_current);

      // Clean format of input path.
      CImg<char> pattern, _path = CImg<char>::string(path);
#if cimg_OS==2
      for (char *ps = _path; *ps; ++ps) if (*ps=='\\') *ps='/';
#endif
      char *pd = _path;
      for (char *ps = pd; *ps; ++ps) { if (*ps!='/' || *ps!=*(ps+1)) *(pd++) = *ps; }
      *pd = 0;
      unsigned int lp = (unsigned int)std::strlen(_path);
      if (!_is_pattern && lp && _path[lp - 1]=='/') {
        _path[lp - 1] = 0; --lp;
#if cimg_OS!=2
        is_root = !*_path;
#endif
      }

      // Separate folder path and matching pattern.
      if (_is_pattern) {
        const unsigned int bpos = (unsigned int)(cimg::basename(_path,'/') - _path.data());
        CImg<char>::string(_path).move_to(pattern);
        if (bpos) {
          _path[bpos - 1] = 0; // End 'path' at last slash
#if cimg_OS!=2
          is_root = !*_path;
#endif
        } else { // No path to folder specified, assuming current folder
          is_current = true; *_path = 0;
        }
        lp = (unsigned int)std::strlen(_path);
      }

      // Windows version.
#if cimg_OS==2
      if (!_is_pattern) {
        pattern.assign(lp + 3);
        std::memcpy(pattern,_path,lp);
        pattern[lp] = '/'; pattern[lp + 1] = '*'; pattern[lp + 2] = 0;
      }
      WIN32_FIND_DATAA file_data;
      const HANDLE dir = FindFirstFileA(pattern.data(),&file_data);
      if (dir==INVALID_HANDLE_VALUE) return CImgList<char>::const_empty();
      do {
        const char *const filename = file_data.cFileName;
        if (*filename!='.' || (filename[1] && (filename[1]!='.' || filename[2]))) {
          const unsigned int lf = (unsigned int)std::strlen(filename);
          const bool is_directory = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)!=0;
          if ((!mode && !is_directory) || (mode==1 && is_directory) || mode>=2) {
            if (include_path) {
              CImg<char> full_filename((lp?lp+1:0) + lf + 1);
              if (lp) { std::memcpy(full_filename,_path,lp); full_filename[lp] = '/'; }
              std::memcpy(full_filename._data + (lp?lp + 1:0),filename,lf + 1);
              full_filename.move_to(res);
            } else CImg<char>(filename,lf + 1).move_to(res);
          }
        }
      } while (FindNextFileA(dir,&file_data));
      FindClose(dir);

      // Unix version (posix).
#elif cimg_OS == 1
      DIR *const dir = opendir(is_root?"/":is_current?".":_path.data());
      if (!dir) return CImgList<char>::const_empty();
      struct dirent *ent;
      while ((ent=readdir(dir))!=0) {
        const char *const filename = ent->d_name;
        if (*filename!='.' || (filename[1] && (filename[1]!='.' || filename[2]))) {
          const unsigned int lf = (unsigned int)std::strlen(filename);
          CImg<char> full_filename(lp + lf + 2);

          if (!is_current) {
            full_filename.assign(lp + lf + 2);
            if (lp) std::memcpy(full_filename,_path,lp);
            full_filename[lp] = '/';
            std::memcpy(full_filename._data + lp + 1,filename,lf + 1);
          } else full_filename.assign(filename,lf + 1);

          struct stat st;
          if (stat(full_filename,&st)==-1) continue;
          const bool is_directory = (st.st_mode & S_IFDIR)!=0;
          if ((!mode && !is_directory) || (mode==1 && is_directory) || mode==2) {
            if (include_path) {
              if (!_is_pattern || (_is_pattern && !fnmatch(pattern,full_filename,0)))
                full_filename.move_to(res);
            } else {
              if (!_is_pattern || (_is_pattern && !fnmatch(pattern,full_filename,0)))
                CImg<char>(filename,lf + 1).move_to(res);
            }
          }
        }
      }
      closedir(dir);
#endif

      // Sort resulting list by lexicographic order.

Project: CImg
File: CImg.h

    // Locally solve eikonal equation.
    Tfloat __distance_eikonal(const CImg<Tfloat>& res, const Tfloat P,
                              const int x=0, const int y=0, const int z=0) const {
      const Tfloat M = (Tfloat)cimg::type<T>::max();
      T T1 = (T)std::min(x - 1>=0?res(x - 1,y,z):M,x + 1<width()?res(x + 1,y,z):M);
      Tfloat root = 0;
      if (_depth>1) { // 3D
        T
          T2 = (T)std::min(y - 1>=0?res(x,y - 1,z):M,y + 1<height()?res(x,y + 1,z):M),
          T3 = (T)std::min(z - 1>=0?res(x,y,z - 1):M,z + 1<depth()?res(x,y,z + 1):M);
        if (T1>T2) cimg::swap(T1,T2);
        if (T2>T3) cimg::swap(T2,T3);
        if (T1>T2) cimg::swap(T1,T2);
        if (P<=0) return (Tfloat)T1;
        if (T3<M && ___distance_eikonal(3,-2*(T1 + T2 + T3),T1*T1 + T2*T2 + T3*T3 - P*P,root))
          return std::max((Tfloat)T3,root);
        if (T2<M && ___distance_eikonal(2,-2*(T1 + T2),T1*T1 + T2*T2 - P*P,root))
          return std::max((Tfloat)T2,root);
        return P + T1;
      } else if (_height>1) { // 2D
        T T2 = (T)std::min(y - 1>=0?res(x,y - 1,z):M,y + 1<height()?res(x,y + 1,z):M);
        if (T1>T2) cimg::swap(T1,T2);
        if (P<=0) return (Tfloat)T1;
        if (T2<M && ___distance_eikonal(2,-2*(T1 + T2),T1*T1 + T2*T2 - P*P,root))
          return std::max((Tfloat)T2,root);
        return P + T1;
      } else { // 1D
        if (P<=0) return (Tfloat)T1;
        return P + T1;
      }
      return 0;

Project: CImg
File: CImg.h


    void _init_fullscreen() {
      _background_window = 0;
      if (!_is_fullscreen || _is_closed) _curr_mode.dmSize = 0;
      else {
        DEVMODE mode;
        unsigned int imode = 0, ibest = 0, bestbpp = 0, bw = ~0U, bh = ~0U;
        for (mode.dmSize = sizeof(DEVMODE), mode.dmDriverExtra = 0; EnumDisplaySettings(0,imode,&mode); ++imode) {
          const unsigned int nw = mode.dmPelsWidth, nh = mode.dmPelsHeight;
          if (nw>=_width && nh>=_height && mode.dmBitsPerPel>=bestbpp && nw<=bw && nh<=bh) {
            bestbpp = mode.dmBitsPerPel;
            ibest = imode;
            bw = nw; bh = nh;
          }
        }
        if (bestbpp) {
          _curr_mode.dmSize = sizeof(DEVMODE); _curr_mode.dmDriverExtra = 0;
          EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&_curr_mode);
          EnumDisplaySettings(0,ibest,&mode);
          ChangeDisplaySettings(&mode,0);
        } else _curr_mode.dmSize = 0;

        const unsigned int
          sx = (unsigned int)screen_width(),
          sy = (unsigned int)screen_height();
        if (sx!=_width || sy!=_height) {
          CLIENTCREATESTRUCT background_ccs;
          _background_window = CreateWindowA("MDICLIENT","",WS_POPUP | WS_VISIBLE, 0,0,sx,sy,0,0,0,&background_ccs);
          SetForegroundWindow(_background_window);
        }
      }

Project: CImg
File: CImg.h


      static double mp_self_increment(_cimg_math_parser& mp) {
        return ++_mp_arg(1);

Project: CImg
File: CImg.h

  template<typename T>
  inline CImg<_cimg_Tfloat> operator/(const char *const expression, const CImg<T>& img) {
    return expression*img.get_invert();

Project: CImg
File: CImg.h

    **/
    CImg<T>& assign(const unsigned int size_x, const unsigned int size_y=1,
                    const unsigned int size_z=1, const unsigned int size_c=1) {
      const size_t siz = (size_t)size_x*size_y*size_z*size_c;
      if (!siz) return assign();
      const size_t curr_siz = (size_t)size();
      if (siz!=curr_siz) {
	if (_is_shared)
          throw CImgArgumentException(_cimg_instance
                                      "assign(): Invalid assignement request of shared instance from specified "
                                      "image (%u,%u,%u,%u).",
                                      cimg_instance,
                                      size_x,size_y,size_z,size_c);
	else {
          delete[] _data;
          try { _data = new T[siz]; } catch (...) {
            _width = _height = _depth = _spectrum = 0; _data = 0;
            throw CImgInstanceException(_cimg_instance
                                        "assign(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
                                        cimg_instance,
                                        cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c),
                                        size_x,size_y,size_z,size_c);
          }
        }
      }
      _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c;
      return *this;

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_triangle(const int x0, const int y0,
                           const int x1, const int y1,
                           const int x2, const int y2,
                           const tc *const color, const float opacity=1) {
      if (is_empty()) return *this;
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_triangle(): Specified color is (null).",
                                    cimg_instance);
      _draw_triangle(x0,y0,x1,y1,x2,y2,color,opacity,1);
      return *this;

Project: CImg
File: CImg.h

    template<typename tf, typename tc>
    static CImg<T> get_load_off(CImgList<tf>& primitives, CImgList<tc>& colors, const char *const filename) {
      return CImg<T>().load_off(primitives,colors,filename);

Project: CImg
File: CImg.h


    inline double rand(const double val_max, cimg_ulong *const p_rng) {
      const double val = cimg::_rand(p_rng)/(double)~0U;
      return val_max*val;

Project: CImg
File: CImg.h


      unsigned int vector3_vss(const mp_func op, const unsigned int arg1, const unsigned int arg2,
                               const unsigned int arg3) {
        const unsigned int
          siz = _cimg_mp_size(arg1),
          pos = is_comp_vector(arg1)?arg1:vector(siz);
        if (siz>24) CImg<ulongT>::vector((ulongT)mp_vector_map_vss,pos,siz,(ulongT)op,arg1,arg2,arg3).move_to(code);
        else {
          code.insert(siz);
          for (unsigned int k = 1; k<=siz; ++k)
            CImg<ulongT>::vector((ulongT)op,pos + k,arg1 + k,arg2,arg3).move_to(code[code._width - 1 - siz + k]);
        }
        return pos;

Project: CImg
File: CImg.h

    template<typename T>
    CImgDisplay& assign(const CImgList<T>& list, const char *const title=0,
                        const unsigned int normalization_type=3,
                        const bool fullscreen_flag=false, const bool closed_flag=false) {
      if (!list) return assign();
      CImg<T> tmp;
      const CImg<T> img = list>'x', &nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width - 1)/2,
                                                                                           (img._height - 1)/2,
                                                                                           (img._depth - 1)/2));
      _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag);
      if (_normalization==2) _min = (float)nimg.min_max(_max);
      return display(nimg);

Project: CImg
File: CImg.h


    static DWORD WINAPI _events_thread(void* arg) {
      CImgDisplay *const disp = (CImgDisplay*)(((void**)arg)[0]);
      const char *const title = (const char*)(((void**)arg)[1]);
      MSG msg;
      delete[] (void**)arg;
      disp->_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
      disp->_bmi.bmiHeader.biWidth = disp->width();
      disp->_bmi.bmiHeader.biHeight = -disp->height();
      disp->_bmi.bmiHeader.biPlanes = 1;
      disp->_bmi.bmiHeader.biBitCount = 32;
      disp->_bmi.bmiHeader.biCompression = BI_RGB;
      disp->_bmi.bmiHeader.biSizeImage = 0;
      disp->_bmi.bmiHeader.biXPelsPerMeter = 1;
      disp->_bmi.bmiHeader.biYPelsPerMeter = 1;
      disp->_bmi.bmiHeader.biClrUsed = 0;
      disp->_bmi.bmiHeader.biClrImportant = 0;
      disp->_data = new unsigned int[(size_t)disp->_width*disp->_height];
      if (!disp->_is_fullscreen) { // Normal window
        RECT rect;
        rect.left = rect.top = 0; rect.right = (LONG)disp->_width - 1; rect.bottom = (LONG)disp->_height - 1;
        AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
        const int
          border1 = (int)((rect.right - rect.left + 1 - disp->_width)/2),
          border2 = (int)(rect.bottom - rect.top + 1 - disp->_height - border1),
          ww = disp->_width + 2*border1,
          wh = disp->_height + border1 + border2,
          sw = CImgDisplay::screen_width(),
          sh = CImgDisplay::screen_height();
        int
          wx = (int)cimg::round(cimg::rand(0,sw - ww -1)),
          wy = (int)cimg::round(cimg::rand(64,sh - wh - 65));
        if (wx + ww>=sw) wx = sw - ww;
        if (wy + wh>=sh) wy = sh - wh;
        if (wx<0) wx = 0;
        if (wy<0) wy = 0;
        disp->_window = CreateWindowA("MDICLIENT",title?title:" ",
                                      WS_OVERLAPPEDWINDOW | (disp->_is_closed?0:WS_VISIBLE),
                                      wx,wy,ww,wh,0,0,0,&(disp->_ccs));
        if (!disp->_is_closed) {
          GetWindowRect(disp->_window,&rect);
          disp->_window_x = rect.left + border1;
          disp->_window_y = rect.top + border2;
        } else disp->_window_x = disp->_window_y = 0;
      } else { // Fullscreen window
        const unsigned int
          sx = (unsigned int)screen_width(),
          sy = (unsigned int)screen_height();
        disp->_window = CreateWindowA("MDICLIENT",title?title:" ",
                                     WS_POPUP | (disp->_is_closed?0:WS_VISIBLE),
                                      (sx - disp->_width)/2,
                                      (sy - disp->_height)/2,
                                     disp->_width,disp->_height,0,0,0,&(disp->_ccs));
        disp->_window_x = disp->_window_y = 0;
      }
      SetForegroundWindow(disp->_window);
      disp->_hdc = GetDC(disp->_window);
      disp->_window_width = disp->_width;
      disp->_window_height = disp->_height;
      disp->flush();
#ifdef _WIN64
      SetWindowLongPtr(disp->_window,GWLP_USERDATA,(LONG_PTR)disp);
      SetWindowLongPtr(disp->_window,GWLP_WNDPROC,(LONG_PTR)_handle_events);
#else
      SetWindowLong(disp->_window,GWL_USERDATA,(LONG)disp);
      SetWindowLong(disp->_window,GWL_WNDPROC,(LONG)_handle_events);
#endif
      SetEvent(disp->_is_created);
      while (GetMessage(&msg,0,0,0)) DispatchMessage(&msg);
      return 0;

Project: CImg
File: CImg.h

    //! Return specified range of image rows \inplace.
    CImg<T>& rows(const int y0, const int y1) {
      return get_rows(y0,y1).move_to(*this);

Project: CImg
File: CImg.h

    template<typename t1, typename t2, typename t3, typename t4, typename t5>
    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
             const CImg<t5>& img5, const bool is_shared=false):
      _width(0),_allocated_width(0),_data(0) {
      assign(5);
      _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared);
      _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared);

Project: CImg
File: CImg.h


      void self_vector_s(const unsigned int pos, const mp_func op, const unsigned int arg1) {
        const unsigned int siz = _cimg_mp_size(pos);
        if (siz>24) CImg<ulongT>::vector((ulongT)mp_self_map_vector_s,pos,siz,(ulongT)op,arg1).move_to(code);
        else {
          code.insert(siz);
          for (unsigned int k = 1; k<=siz; ++k)
            CImg<ulongT>::vector((ulongT)op,pos + k,arg1).move_to(code[code._width - 1 - siz + k]);
        }

Project: CImg
File: CImg.h

    **/
    bool is_sameYC(const unsigned int size_y, const unsigned int size_c) const {
      return _height==size_y && _spectrum==size_c;

Project: CImg
File: CImg.h

    template<typename tf, typename tc>
    CImg<T>& load_off(CImgList<tf>& primitives, CImgList<tc>& colors, const char *const filename) {
      return _load_off(primitives,colors,0,filename);

Project: CImg
File: CImg.h

    template<typename T>
    inline int date(T *attr, const unsigned int nb_attr) {
      int res = -1;
      cimg::mutex(6);
#if cimg_OS==2
      SYSTEMTIME st;
      GetLocalTime(&st);
      for (unsigned int i = 0; i<nb_attr; ++i) {
        res = (int)(attr[i]==0?st.wYear:attr[i]==1?st.wMonth:attr[i]==2?st.wDay:
                    attr[i]==3?st.wDayOfWeek:attr[i]==4?st.wHour:attr[i]==5?st.wMinute:
                    attr[i]==6?st.wSecond:-1);
        attr[i] = (T)res;
      }
#else
      time_t _st;
      std::time(&_st);
      struct tm *st = std::localtime(&_st);
      for (unsigned int i = 0; i<nb_attr; ++i) {
        res = (int)(attr[i]==0?st->tm_year + 1900:attr[i]==1?st->tm_mon + 1:attr[i]==2?st->tm_mday:
                    attr[i]==3?st->tm_wday:attr[i]==4?st->tm_hour:attr[i]==5?st->tm_min:
                    attr[i]==6?st->tm_sec:-1);
        attr[i] = (T)res;
      }
#endif
      cimg::mutex(6,0);
      return res;

Project: CImg
File: CImg.h


    CImg<T>& _load_pfm(std::FILE *const file, const char *const filename) {
      if (!file && !filename)
        throw CImgArgumentException(_cimg_instance
                                    "load_pfm(): Specified filename is (null).",
                                    cimg_instance);

      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
      char pfm_type;
      CImg<charT> item(16384,1,1,1,0);
      int W = 0, H = 0, err = 0;
      double scale = 0;
      while ((err=std::fscanf(nfile,"%16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile);
      if (cimg_sscanf(item," P%c",&pfm_type)!=1) {
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "load_pfm(): PFM header not found in file '%s'.",
                              cimg_instance,
                              filename?filename:"(FILE*)");
      }
      while ((err=std::fscanf(nfile," %16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile);
      if ((err=cimg_sscanf(item," %d %d",&W,&H))<2) {
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "load_pfm(): WIDTH and HEIGHT fields are undefined in file '%s'.",
                              cimg_instance,
                              filename?filename:"(FILE*)");
      } else if (W<=0 || H<=0) {
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "load_pfm(): WIDTH (%d) and HEIGHT (%d) fields are invalid in file '%s'.",
                              cimg_instance,W,H,
                              filename?filename:"(FILE*)");
      }
      if (err==2) {
        while ((err=std::fscanf(nfile," %16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile);
        if (cimg_sscanf(item,"%lf",&scale)!=1)
          cimg::warn(_cimg_instance
                     "load_pfm(): SCALE field is undefined in file '%s'.",
                     cimg_instance,
                     filename?filename:"(FILE*)");
      }
      std::fgetc(nfile);
      const bool is_color = (pfm_type=='F'), is_inverted = (scale>0)!=cimg::endianness();
      if (is_color) {
        assign(W,H,1,3,(T)0);
        CImg<floatT> buf(3*W);
        T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2);
        cimg_forY(*this,y) {
          cimg::fread(buf._data,3*W,nfile);
          if (is_inverted) cimg::invert_endianness(buf._data,3*W);
          const float *ptrs = buf._data;
          cimg_forX(*this,x) {
            *(ptr_r++) = (T)*(ptrs++);
            *(ptr_g++) = (T)*(ptrs++);
            *(ptr_b++) = (T)*(ptrs++);
          }
        }
      } else {
        assign(W,H,1,1,(T)0);
        CImg<floatT> buf(W);
        T *ptrd = data(0,0,0,0);
        cimg_forY(*this,y) {
          cimg::fread(buf._data,W,nfile);
          if (is_inverted) cimg::invert_endianness(buf._data,W);
          const float *ptrs = buf._data;
          cimg_forX(*this,x) *(ptrd++) = (T)*(ptrs++);
        }
      }
      if (!file) cimg::fclose(nfile);
      return mirror('y');  // Most of the .pfm files are flipped along the y-axis

Project: CImg
File: CImg.h

    **/
    CImg<T>& sequence(const T& a0, const T& a1) {
      if (is_empty()) return *this;
      const ulongT siz = size() - 1;
      T* ptr = _data;
      if (siz) {
        const double delta = (double)a1 - (double)a0;
        cimg_foroff(*this,l) *(ptr++) = (T)(a0 + delta*l/siz);
      } else *ptr = a0;
      return *this;

Project: CImg
File: CImg.h


    inline double rand(const double val_min, const double val_max, cimg_ulong *const p_rng) {
      const double val = cimg::_rand(p_rng)/(double)~0U;
      return val_min + (val_max - val_min)*val;

Project: CImg
File: CImg.h


      static double mp_bitwise_and(_cimg_math_parser& mp) {
        return (double)((longT)_mp_arg(2) & (longT)_mp_arg(3));

Project: CImg
File: CImg.h

      static half nan() { const half val_nan = (half)-std::sqrt(-1.); return val_nan; }

Project: CImg
File: CImg.h


    const CImg<T>& _display_graph(CImgDisplay &disp, const char *const title=0,
                                  const unsigned int plot_type=1, const unsigned int vertex_type=1,
                                  const char *const labelx=0, const double xmin=0, const double xmax=0,
                                  const char *const labely=0, const double ymin=0, const double ymax=0,
                                  const bool exit_on_anykey=false) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "display_graph(): Empty instance.",
                                    cimg_instance);
      if (!disp) disp.assign(cimg_fitscreen(CImgDisplay::screen_width()/2,CImgDisplay::screen_height()/2,1),0,0).
                   set_title(title?"%s":"CImg<%s>",title?title:pixel_type());
      const ulongT siz = (ulongT)_width*_height*_depth, siz1 = std::max((ulongT)1,siz - 1);
      const unsigned int old_normalization = disp.normalization();
      disp.show().flush()._normalization = 0;

      double y0 = ymin, y1 = ymax, nxmin = xmin, nxmax = xmax;
      if (nxmin==nxmax) { nxmin = 0; nxmax = siz1; }
      int x0 = 0, x1 = width()*height()*depth() - 1, key = 0;

      for (bool reset_view = true; !key && !disp.is_closed(); ) {
        if (reset_view) { x0 = 0; x1 = width()*height()*depth() - 1; y0 = ymin; y1 = ymax; reset_view = false; }
        CImg<T> zoom(x1 - x0 + 1,1,1,spectrum());
        cimg_forC(*this,c) zoom.get_shared_channel(c) = CImg<T>(data(x0,0,0,c),x1 - x0 + 1,1,1,1,true);
        if (y0==y1) { y0 = zoom.min_max(y1); const double dy = y1 - y0; y0-=dy/20; y1+=dy/20; }
        if (y0==y1) { --y0; ++y1; }

        const CImg<intT> selection = zoom.get_select_graph(disp,plot_type,vertex_type,
        					           labelx,
                                                           nxmin + x0*(nxmax - nxmin)/siz1,
                                                           nxmin + x1*(nxmax - nxmin)/siz1,
                                                           labely,y0,y1,true);
	const int mouse_x = disp.mouse_x(), mouse_y = disp.mouse_y();
        if (selection[0]>=0) {
          if (selection[2]<0) reset_view = true;
          else {
            x1 = x0 + selection[2]; x0+=selection[0];
            if (selection[1]>=0 && selection[3]>=0) {
              y0 = y1 - selection[3]*(y1 - y0)/(disp.height() - 32);
              y1-=selection[1]*(y1 - y0)/(disp.height() - 32);
            }
          }
        } else {
          bool go_in = false, go_out = false, go_left = false, go_right = false, go_up = false, go_down = false;
          switch (key = (int)disp.key()) {
          case cimg::keyHOME : reset_view = true; key = 0; disp.set_key(); break;
          case cimg::keyPADADD : go_in = true; go_out = false; key = 0; disp.set_key(); break;
          case cimg::keyPADSUB : go_out = true; go_in = false; key = 0; disp.set_key(); break;
          case cimg::keyARROWLEFT : case cimg::keyPAD4 : go_left = true; go_right = false; key = 0; disp.set_key();
            break;
          case cimg::keyARROWRIGHT : case cimg::keyPAD6 : go_right = true; go_left = false; key = 0; disp.set_key();
            break;
          case cimg::keyARROWUP : case cimg::keyPAD8 : go_up = true; go_down = false; key = 0; disp.set_key(); break;
          case cimg::keyARROWDOWN : case cimg::keyPAD2 : go_down = true; go_up = false; key = 0; disp.set_key(); break;
          case cimg::keyPAD7 : go_left = true; go_up = true; key = 0; disp.set_key(); break;
          case cimg::keyPAD9 : go_right = true; go_up = true; key = 0; disp.set_key(); break;
          case cimg::keyPAD1 : go_left = true; go_down = true; key = 0; disp.set_key(); break;
          case cimg::keyPAD3 : go_right = true; go_down = true; key = 0; disp.set_key(); break;
          }
          if (disp.wheel()) {
            if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) go_up = !(go_down = disp.wheel()<0);
            else if (disp.is_keySHIFTLEFT() || disp.is_keySHIFTRIGHT()) go_left = !(go_right = disp.wheel()>0);
            else go_out = !(go_in = disp.wheel()>0);
            key = 0;
          }

          if (go_in) {
            const int
              xsiz = x1 - x0,
              mx = (mouse_x - 16)*xsiz/(disp.width() - 32),
              cx = x0 + cimg::cut(mx,0,xsiz);
            if (x1 - x0>4) {
              x0 = cx - 7*(cx - x0)/8; x1 = cx + 7*(x1 - cx)/8;
              if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
                const double
                  ysiz = y1 - y0,
                  my = (mouse_y - 16)*ysiz/(disp.height() - 32),
                  cy = y1 - cimg::cut(my,0.,ysiz);
                y0 = cy - 7*(cy - y0)/8; y1 = cy + 7*(y1 - cy)/8;
              } else y0 = y1 = 0;
            }
          }
          if (go_out) {
            if (x0>0 || x1<(int)siz1) {
              const int delta_x = (x1 - x0)/8, ndelta_x = delta_x?delta_x:(siz>1);
              const double ndelta_y = (y1 - y0)/8;
              x0-=ndelta_x; x1+=ndelta_x;
              y0-=ndelta_y; y1+=ndelta_y;
              if (x0<0) { x1-=x0; x0 = 0; if (x1>=(int)siz) x1 = (int)siz1; }
              if (x1>=(int)siz) { x0-=(x1 - siz1); x1 = (int)siz1; if (x0<0) x0 = 0; }
            }
          }
          if (go_left) {
            const int delta = (x1 - x0)/5, ndelta = delta?delta:1;
            if (x0 - ndelta>=0) { x0-=ndelta; x1-=ndelta; }
            else { x1-=x0; x0 = 0; }
            go_left = false;
          }
          if (go_right) {
            const int delta = (x1 - x0)/5, ndelta = delta?delta:1;
            if (x1 + ndelta<(int)siz) { x0+=ndelta; x1+=ndelta; }
            else { x0+=(siz1 - x1); x1 = (int)siz1; }
            go_right = false;
          }
          if (go_up) {
            const double delta = (y1 - y0)/10, ndelta = delta?delta:1;
            y0+=ndelta; y1+=ndelta;
            go_up = false;
          }
          if (go_down) {
            const double delta = (y1 - y0)/10, ndelta = delta?delta:1;
            y0-=ndelta; y1-=ndelta;
            go_down = false;
          }
        }
        if (!exit_on_anykey && key && key!=(int)cimg::keyESC &&
            (key!=(int)cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) {
          disp.set_key(key,false);
          key = 0;
        }
      }
      disp._normalization = old_normalization;
      return *this;

Project: CImg
File: CImg.h

    template<> struct type<unsigned int> {

Project: CImg
File: CImg.h


    T cubic_atXY_pc(const float fx, const float fy, const int z, const int c) const {
      return cimg::type<T>::cut(cubic_atXY_p(fx,fy,z,c));

Project: CImg
File: CImg.h

      static const char* format() { return cimg_fint64; }