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

                              cimglist_instance,filename);
      return *this;
    }

    CImgList<T>& _load_gif_external(const char *const filename, const bool use_graphicsmagick=false) {
      CImg<charT> command(1024), filename_tmp(256), filename_tmp2(256);
      std::FILE *file = 0;
      do {
        cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s",
                      cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
        if (use_graphicsmagick) cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s.png.0",filename_tmp._data);
        else cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s-0.png",filename_tmp._data);
        if ((file=cimg::std_fopen(filename_tmp2,"rb"))!=0) cimg::fclose(file);
      } while (file);
      if (use_graphicsmagick) cimg_snprintf(command,command._width,"%s convert \"%s\" \"%s.png\"",
                                            cimg::graphicsmagick_path(),
                                            CImg<charT>::string(filename)._system_strescape().data(),
                                            CImg<charT>::string(filename_tmp)._system_strescape().data());
      else cimg_snprintf(command,command._width,"%s \"%s\" \"%s.png\"",
                         cimg::imagemagick_path(),
                         CImg<charT>::string(filename)._system_strescape().data(),
                         CImg<charT>::string(filename_tmp)._system_strescape().data());
      cimg::system(command,0);
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode(0);
      assign();

      // Try to read a single frame gif.
      cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s.png",filename_tmp._data);
      CImg<T> img;
      try { img.load_png(filename_tmp2); }
      catch (CImgException&) { }
      if (img) { img.move_to(*this); std::remove(filename_tmp2); }
      else { // Try to read animated gif
        unsigned int i = 0;
        for (bool stop_flag = false; !stop_flag; ++i) {
          if (use_graphicsmagick) cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s.png.%u",filename_tmp._data,i);
          else cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s-%u.png",filename_tmp._data,i);
          try { img.load_png(filename_tmp2); }
          catch (CImgException&) { stop_flag = true; }
          if (img) { img.move_to(*this); std::remove(filename_tmp2); }
        }

Project: CImg
File: CImg.h


    CImg<ulongT> _label(const unsigned int nb, const int *const dx,
                        const int *const dy, const int *const dz,
                        const Tfloat tolerance) const {
      CImg<ulongT> res(_width,_height,_depth,_spectrum);
      cimg_forC(*this,c) {
        CImg<ulongT> _res = res.get_shared_channel(c);

        // Init label numbers.
        ulongT *ptr = _res.data();
        cimg_foroff(_res,p) *(ptr++) = p;

        // For each neighbour-direction, label.
        for (unsigned int n = 0; n<nb; ++n) {
          const int _dx = dx[n], _dy = dy[n], _dz = dz[n];
          if (_dx || _dy || _dz) {
            const int
              x0 = _dx<0?-_dx:0,
              x1 = _dx<0?width():width() - _dx,
              y0 = _dy<0?-_dy:0,
              y1 = _dy<0?height():height() - _dy,
              z0 = _dz<0?-_dz:0,
              z1 = _dz<0?depth():depth() - _dz;
            const longT
              wh = (longT)width()*height(),
              whd = (longT)width()*height()*depth(),
              offset = _dz*wh + _dy*width() + _dx;
            for (longT z = z0, nz = z0 + _dz, pz = z0*wh; z<z1; ++z, ++nz, pz+=wh) {
              for (longT y = y0, ny = y0 + _dy, py = y0*width() + pz; y<y1; ++y, ++ny, py+=width()) {
                for (longT x = x0, nx = x0 + _dx, p = x0 + py; x<x1; ++x, ++nx, ++p) {
                  if (cimg::abs((Tfloat)(*this)(x,y,z,c,wh,whd) - (Tfloat)(*this)(nx,ny,nz,c,wh,whd))<=tolerance) {
                    const longT q = p + offset;
                    ulongT xk, yk;
                    for (xk = (ulongT)(p<q?q:p), yk = (ulongT)(p<q?p:q); xk!=yk && _res[xk]!=xk; ) {
                      xk = _res[xk]; if (xk<yk) cimg::swap(xk,yk);
                    }
                    if (xk!=yk) _res[xk] = (ulongT)yk;
                    for (ulongT _p = (ulongT)p; _p!=yk; ) {
                      const ulongT h = _res[_p];
                      _res[_p] = (ulongT)yk;
                      _p = h;
                    }
                    for (ulongT _q = (ulongT)q; _q!=yk; ) {
                      const ulongT h = _res[_q];
                      _res[_q] = (ulongT)yk;
                      _q = h;
                    }
                  }
                }
              }
            }
          }
        }

        // Resolve equivalences.
        ulongT counter = 0;
        ptr = _res.data();
        cimg_foroff(_res,p) { *ptr = *ptr==p?counter++:_res[*ptr]; ++ptr; }
      }
      return res;

Project: CImg
File: CImg.h

    }
    inline int abs(const int a) {
      return std::abs(a);

Project: CImg
File: CImg.h

    **/
    CImg<T>& haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) {
      return get_haar(axis,invert,nb_scales).move_to(*this);

Project: CImg
File: CImg.h

    template<typename t>
    static int _isoline3d_index(const unsigned int edge, const CImg<t>& indices1, const CImg<t>& indices2,
                                 const unsigned int x, const unsigned int nx) {
      switch (edge) {
      case 0 : return (int)indices1(x,0);
      case 1 : return (int)indices1(nx,1);
      case 2 : return (int)indices2(x,0);
      case 3 : return (int)indices1(x,1);
      }
      return 0;

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& sort(CImg<t>& permutations, const bool is_increasing=true) {
      permutations.assign(_width,_height,_depth,_spectrum);
      if (is_empty()) return *this;
      cimg_foroff(permutations,off) permutations[off] = (t)off;
      return _quicksort(0,size() - 1,permutations,is_increasing,true);

Project: CImg
File: CImg.h

    **/
    CImg<T>& transpose() {
      if (_width==1) { _width = _height; _height = 1; return *this; }
      if (_height==1) { _height = _width; _width = 1; return *this; }
      if (_width==_height) {
        cimg_forYZC(*this,y,z,c) for (int x = y; x<width(); ++x) cimg::swap((*this)(x,y,z,c),(*this)(y,x,z,c));
        return *this;
      }
      return get_transpose().move_to(*this);

Project: CImg
File: CImg.h

      _functor2d_float(const CImg<T>& pref):ref(pref) {}
      float operator()(const float x, const float y) const {
        return (float)ref._linear_atXY(x,y);

Project: CImg
File: CImg.h

    //! Resize image to double-size, using the Scale2X algorithm \newinstance.
    CImg<T> get_resize_doubleXY() const {
#define _cimg_gs2x_for3(bound,i) \
 for (int i = 0, _p1##i = 0, \
      _n1##i = 1>=(bound)?(int)(bound) - 1:1; \
      _n1##i<(int)(bound) || i==--_n1##i; \
      _p1##i = i++, ++_n1##i, ptrd1+=(res)._width, ptrd2+=(res)._width)

#define _cimg_gs2x_for3x3(img,x,y,z,c,I,T) \
  _cimg_gs2x_for3((img)._height,y) for (int x = 0, \
   _p1##x = 0, \
   _n1##x = (int)( \
   (I[1] = (T)(img)(_p1##x,_p1##y,z,c)), \
   (I[3] = I[4] = (T)(img)(0,y,z,c)), \
   (I[7] = (T)(img)(0,_n1##y,z,c)),	\
   1>=(img)._width?(img).width() - 1:1); \
   (_n1##x<(img).width() && ( \
   (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \
   (I[5] = (T)(img)(_n1##x,y,z,c)), \
   (I[8] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \
   x==--_n1##x; \
   I[1] = I[2], \
   I[3] = I[4], I[4] = I[5], \
   I[7] = I[8], \
   _p1##x = x++, ++_n1##x)

      if (is_empty()) return *this;
      CImg<T> res(_width<<1,_height<<1,_depth,_spectrum);
      CImg_3x3(I,T);
      cimg_forZC(*this,z,c) {
        T
          *ptrd1 = res.data(0,0,z,c),
          *ptrd2 = ptrd1 + res._width;
        _cimg_gs2x_for3x3(*this,x,y,z,c,I,T) {
          if (Icp!=Icn && Ipc!=Inc) {
            *(ptrd1++) = Ipc==Icp?Ipc:Icc;
            *(ptrd1++) = Icp==Inc?Inc:Icc;
            *(ptrd2++) = Ipc==Icn?Ipc:Icc;
            *(ptrd2++) = Icn==Inc?Inc:Icc;
          } else { *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc; }
        }
      }
      return res;

Project: CImg
File: CImg.h


      static double mp_list_set_Ioff_s(_cimg_math_parser& mp) {
        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
        CImg<T> &img = mp.listout[ind];
        const longT
          off = (longT)_mp_arg(3),
          whd = (longT)img.width()*img.height()*img.depth();
        const T val = (T)_mp_arg(1);
        if (off>=0 && off<whd) {
          T *ptrd = &img[off];
          cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }
        }
        return _mp_arg(1);

Project: CImg
File: CImg.h

    **/
    explicit CImgList(const CImgDisplay& disp):_width(0),_allocated_width(0),_data(0) {
      assign(disp);

Project: CImg
File: CImg.h

      // Check a matrix is square.
      void check_matrix_square(const unsigned int arg, const unsigned int n_arg,
                               char *const ss, char *const se, const char saved_char) {
        _cimg_mp_check_type(arg,n_arg,2,0);
        const unsigned int
          siz = _cimg_mp_size(arg),
          n = (unsigned int)cimg::round(std::sqrt((float)siz));
        if (n*n!=siz) {
          const char *s_arg;
          if (*s_op!='F') s_arg = !n_arg?"":n_arg==1?"Left-hand ":"Right-hand ";
          else s_arg = !n_arg?"":n_arg==1?"First ":n_arg==2?"Second ":n_arg==3?"Third ":"One ";
          *se = saved_char;
          char *const s0 = ss - 4>expr._data?ss - 4:expr._data;
          cimg::strellipsize(s0,64);
          throw CImgArgumentException("[" cimg_appname "_math_parser] "
                                      "CImg<%s>::%s: %s%s %s%s (of type '%s') "
                                      "cannot be considered as a square matrix, in expression '%s%s%s'.",
                                      pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"",
                                      s_arg,*s_op=='F'?(*s_arg?"argument":"Argument"):(*s_arg?"operand":"Operand"),
                                      s_type(arg)._data,
                                      s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
        }

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 gunzip binary.
    **/
    inline const char *gunzip_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,".\\gunzip.exe");
          if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(s_path,"gunzip.exe");
#else
        if (!path_found) {
          std::strcpy(s_path,"./gunzip");
          if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(s_path,"gunzip");
#endif
        winformat_string(s_path);

Project: CImg
File: CImg.h


      static double mp_crop(_cimg_math_parser& mp) {
        double *ptrd = &_mp_arg(1) + 1;
        const int x = (int)_mp_arg(3), y = (int)_mp_arg(4), z = (int)_mp_arg(5), c = (int)_mp_arg(6);
        const unsigned int
          dx = (unsigned int)mp.opcode[7],
          dy = (unsigned int)mp.opcode[8],
          dz = (unsigned int)mp.opcode[9],
          dc = (unsigned int)mp.opcode[10];
        const unsigned int boundary_conditions = (unsigned int)_mp_arg(11);
        unsigned int ind = (unsigned int)mp.opcode[2];
        if (ind!=~0U) ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
        const CImg<T> &img = ind==~0U?mp.imgin:mp.listin[ind];
        if (!img) std::memset(ptrd,0,dx*dy*dz*dc*sizeof(double));
        else CImg<doubleT>(ptrd,dx,dy,dz,dc,true) = img.get_crop(x,y,z,c,
                                                                 x + dx - 1,y + dy - 1,
                                                                 z + dz - 1,c + dc - 1,
                                                                 boundary_conditions);
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

    /**
      \param pos0 Starting index of the sublist.
      \param pos1 Ending index of the sublist.

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

      static half max() { return (half)65504; }

Project: CImg
File: CImg.h


      static double mp_string_init(_cimg_math_parser& mp) {
        const char *ptrs = (char*)&mp.opcode[3];
        unsigned int
          ptrd = (unsigned int)mp.opcode[1] + 1,
          siz = (unsigned int)mp.opcode[2];
        while (siz-->0) mp.mem[ptrd++] = (double)*(ptrs++);
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h


      static double mp_complex_conj(_cimg_math_parser& mp) {
        const double *ptrs = &_mp_arg(2) + 1;
        double *ptrd = &_mp_arg(1) + 1;
        *(ptrd++) = *(ptrs++);
        *ptrd = -*(ptrs);
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h


    CImg<T>& _load_rgba(std::FILE *const file, const char *const filename,
                        const unsigned int dimw, const unsigned int dimh) {
      if (!file && !filename)
        throw CImgArgumentException(_cimg_instance
                                    "load_rgba(): Specified filename is (null).",
                                    cimg_instance);

      if (!dimw || !dimh) return assign();
      const longT cimg_iobuffer = (longT)24*1024*1024;
      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
      CImg<ucharT> raw;
      assign(dimw,dimh,1,4);
      T
        *ptr_r = data(0,0,0,0),
        *ptr_g = data(0,0,0,1),
        *ptr_b = data(0,0,0,2),
        *ptr_a = data(0,0,0,3);
      for (longT to_read = (longT)size(); to_read>0; ) {
        raw.assign(std::min(to_read,cimg_iobuffer));
        cimg::fread(raw._data,raw._width,nfile);
        to_read-=raw._width;
        const unsigned char *ptrs = raw._data;
        for (ulongT off = raw._width/4UL; off; --off) {
          *(ptr_r++) = (T)*(ptrs++);
          *(ptr_g++) = (T)*(ptrs++);
          *(ptr_b++) = (T)*(ptrs++);
          *(ptr_a++) = (T)*(ptrs++);
        }
      }
      if (!file) cimg::fclose(nfile);
      return *this;

Project: CImg
File: CImg.h

    template<typename t>
    CImgList<T>& operator,(const CImgList<t>& list) {
      return insert(list);

Project: CImg
File: CImg.h


    const CImg<T> *data(const unsigned int l) const {
      return const_cast<CImgList<T>*>(this)->data(l);

Project: CImg
File: CImg.h

      static signed char inf() { return max(); }
      static signed char cut(const double val) {

Project: CImg
File: CImg.h

    **/
    CImg<T> get_shared_slice(const unsigned int z0, const unsigned int c0=0) {
      return get_shared_slices(z0,z0,c0);

Project: CImg
File: CImg.h

    //! Transfer content of an image instance into another one \specialization.
    CImg<T>& move_to(CImg<T>& img) {
      if (_is_shared || img._is_shared) img.assign(*this);
      else swap(img);
      assign();
      return img;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    **/
    bool is_empty() const {
      return !(_data && _width && _height && _depth && _spectrum);

Project: CImg
File: CImg.h

    **/
    int window_height() const {
      return (int)_window_height;

Project: CImg
File: CImg.h


      static double mp_atan2(_cimg_math_parser& mp) {
        return std::atan2(_mp_arg(2),_mp_arg(3));

Project: CImg
File: CImg.h

      static double cut(const double val) { return val; }

Project: CImg
File: CImg.h

    template<typename t>
    CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c,
         const std::initializer_list<t> values,
	 const bool repeat_values=true):
      _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
#define _cimg_constructor_cpp11(repeat_values) \
  auto it = values.begin(); \
  size_t siz = size(); \
  if (repeat_values) for (T *ptrd = _data; siz--; ) { \
    *(ptrd++) = (T)(*(it++)); if (it==values.end()) it = values.begin(); } \
  else { siz = std::min(siz,values.size()); for (T *ptrd = _data; siz--; ) *(ptrd++) = (T)(*(it++)); }
      assign(size_x,size_y,size_z,size_c);
      _cimg_constructor_cpp11(repeat_values);

Project: CImg
File: CImg.h

    **/
    bool is_inf() const {
      if (cimg::type<T>::is_float()) cimg_for(*this,p,T) if (cimg::type<T>::is_inf((float)*p)) return true;
      return false;

Project: CImg
File: CImg.h


      static double mp_norminf(_cimg_math_parser& mp) {
        const unsigned int i_end = (unsigned int)mp.opcode[2];
        switch (i_end - 3) {
        case 1 : return cimg::abs(_mp_arg(3));
        case 2 : return std::max(cimg::abs(_mp_arg(3)),cimg::abs(_mp_arg(4)));
        }
        double res = 0;
        for (unsigned int i = 3; i<i_end; ++i) {
          const double val = cimg::abs(_mp_arg(i));
          if (val>res) res = val;
        }
        return res;

Project: CImg
File: CImg.h

    **/
    static CImg<T> vector(const T& a0) {
      CImg<T> r(1,1);
      r[0] = a0;
      return r;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    **/
    int wheel() const {
      return _wheel;

Project: CImg
File: CImg.h


      static double mp_self_pow(_cimg_math_parser& mp) {
        double &val = _mp_arg(1);
        return val = std::pow(val,_mp_arg(2));

Project: CImg
File: CImg.h

    //! Fill sequentially pixel values according to a given expression \newinstance.
    CImg<T> get_fill(const char *const expression, const bool repeat_values, const bool allow_formula=true,
                     const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) const {
      return (+*this).fill(expression,repeat_values,allow_formula?1:0,list_inputs,list_outputs);

Project: CImg
File: CImg.h

    //! Return pointer to the first image of the list \const.
    operator const CImg<T>*() const {
      return _data;

Project: CImg
File: CImg.h

    template<typename T>
    inline T hypot(const T x, const T y) {
      return std::sqrt(x*x + y*y);

Project: CImg
File: CImg.h


      static double mp_trace(_cimg_math_parser& mp) {
        const double *ptrs = &_mp_arg(2) + 1;
        const unsigned int k = (unsigned int)mp.opcode[3];
        return CImg<doubleT>(ptrs,k,k,1,1,true).trace();

Project: CImg
File: CImg.h

      static double max() { return DBL_MAX; }
      static double inf() {
#ifdef INFINITY
        return (double)INFINITY;
#else
        return max()*max();
#endif

Project: CImg
File: CImg.h


      static double mp_set_Ixyz_s(_cimg_math_parser& mp) {
        CImg<T> &img = mp.imgout;
        const int
          x = (int)_mp_arg(2),
          y = (int)_mp_arg(3),
          z = (int)_mp_arg(4);
        const T val = (T)_mp_arg(1);
        if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {
          T *ptrd = &img(x,y,z);
          const ulongT whd = (ulongT)img._width*img._height*img._depth;
          cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }
        }
        return _mp_arg(1);

Project: CImg
File: CImg.h

    **/
    double variance_noise(const unsigned int variance_method=2) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "variance_noise(): Empty instance.",
                                    cimg_instance);

      const ulongT siz = size();
      if (!siz || !_data) return 0;
      if (variance_method>1) { // Compute a scaled version of the Laplacian
        CImg<Tdouble> tmp(*this,false);
        if (_depth==1) {
          const double cste = 1./std::sqrt(20.); // Depends on how the Laplacian is computed
          cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height>=(cimg_openmp_sizefactor)*262144 &&
                                                         _spectrum>=2))
          cimg_forC(*this,c) {
            CImg_3x3(I,T);
            cimg_for3x3(*this,x,y,0,c,I,T) {
              tmp(x,y,c) = cste*((double)Inc + (double)Ipc + (double)Icn +
                                 (double)Icp - 4*(double)Icc);
            }
          }
        } else {
          const double cste = 1./std::sqrt(42.); // Depends on how the Laplacian is computed
          cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height*_depth>=(cimg_openmp_sizefactor)*262144 &&
                                                         _spectrum>=2))
          cimg_forC(*this,c) {
            CImg_3x3x3(I,T);
            cimg_for3x3x3(*this,x,y,z,c,I,T) {
              tmp(x,y,z,c) = cste*(
                                   (double)Incc + (double)Ipcc + (double)Icnc + (double)Icpc +
                                   (double)Iccn + (double)Iccp - 6*(double)Iccc);
            }
          }
        }
        return tmp.variance(variance_method);
      }

      // Version that doesn't need intermediate images.
      double variance = 0, S = 0, S2 = 0;
      if (_depth==1) {
        const double cste = 1./std::sqrt(20.);
        CImg_3x3(I,T);
        cimg_forC(*this,c) cimg_for3x3(*this,x,y,0,c,I,T) {
          const double val = cste*((double)Inc + (double)Ipc +
                                   (double)Icn + (double)Icp - 4*(double)Icc);
          S+=val; S2+=val*val;
        }
      } else {
        const double cste = 1./std::sqrt(42.);
        CImg_3x3x3(I,T);
        cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,T) {
          const double val = cste *
            ((double)Incc + (double)Ipcc + (double)Icnc +
             (double)Icpc +
             (double)Iccn + (double)Iccp - 6*(double)Iccc);
          S+=val; S2+=val*val;
        }
      }
      if (variance_method) variance = siz>1?(S2 - S*S/siz)/(siz - 1):0;
      else variance = (S2 - S*S/siz)/siz;
      return variance>0?variance:0;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

                                 CImgDisplay::_fitscreen(dx,dy,dz,128,-85,true)
    static unsigned int _fitscreen(const unsigned int dx, const unsigned int dy, const unsigned int dz,
                                   const int dmin, const int dmax, const bool return_y) {
      const int
        u = CImgDisplay::screen_width(),
        v = CImgDisplay::screen_height();
      const float
        mw = dmin<0?cimg::round(u*-dmin/100.f):(float)dmin,
        mh = dmin<0?cimg::round(v*-dmin/100.f):(float)dmin,
        Mw = dmax<0?cimg::round(u*-dmax/100.f):(float)dmax,
        Mh = dmax<0?cimg::round(v*-dmax/100.f):(float)dmax;
      float
        w = (float)std::max(1U,dx),
        h = (float)std::max(1U,dy);
      if (dz>1) { w+=dz; h+=dz; }
      if (w<mw) { h = h*mw/w; w = mw; }
      if (h<mh) { w = w*mh/h; h = mh; }
      if (w>Mw) { h = h*Mw/w; w = Mw; }
      if (h>Mh) { w = w*Mh/h; h = Mh; }
      if (w<mw) w = mw;
      if (h<mh) h = mh;
      return std::max(1U,(unsigned int)cimg::round(return_y?h:w));

Project: CImg
File: CImg.h

      static char min() { return 0; }

Project: CImg
File: CImg.h

    **/
    inline int strncasecmp(const char *const str1, const char *const str2, const int l) {
      if (!l) return 0;
      if (!str1) return str2?-1:0;
      const char *nstr1 = str1, *nstr2 = str2;
      int k, diff = 0; for (k = 0; k<l && !(diff = lowercase(*nstr1) - lowercase(*nstr2)); ++k) { ++nstr1; ++nstr2; }
      return k!=l?diff:0;

Project: CImg
File: CImg.h

    template<typename tf, typename tfunc>
    static CImg<floatT> isoline3d(CImgList<tf>& primitives, const tfunc& func, const float isovalue,
                                  const float x0, const float y0, const float x1, const float y1,
                                  const int size_x=256, const int size_y=256) {
      static const unsigned int edges[16] = { 0x0, 0x9, 0x3, 0xa, 0x6, 0xf, 0x5, 0xc, 0xc,
                                              0x5, 0xf, 0x6, 0xa, 0x3, 0x9, 0x0 };
      static const int segments[16][4] = { { -1,-1,-1,-1 }, { 0,3,-1,-1 }, { 0,1,-1,-1 }, { 1,3,-1,-1 },
                                           { 1,2,-1,-1 },   { 0,1,2,3 },   { 0,2,-1,-1 }, { 2,3,-1,-1 },
                                           { 2,3,-1,-1 },   { 0,2,-1,-1},  { 0,3,1,2 },   { 1,2,-1,-1 },
                                           { 1,3,-1,-1 },   { 0,1,-1,-1},  { 0,3,-1,-1},  { -1,-1,-1,-1 } };
      const unsigned int
        _nx = (unsigned int)(size_x>=0?size_x:cimg::round((x1-x0)*-size_x/100 + 1)),
        _ny = (unsigned int)(size_y>=0?size_y:cimg::round((y1-y0)*-size_y/100 + 1)),
        nx = _nx?_nx:1,
        ny = _ny?_ny:1,
        nxm1 = nx - 1,
        nym1 = ny - 1;
      primitives.assign();
      if (!nxm1 || !nym1) return CImg<floatT>();
      const float dx = (x1 - x0)/nxm1, dy = (y1 - y0)/nym1;
      CImgList<floatT> vertices;
      CImg<intT> indices1(nx,1,1,2,-1), indices2(nx,1,1,2);
      CImg<floatT> values1(nx), values2(nx);
      float X = x0, Y = y0, nX = X + dx, nY = Y + dy;

      // Fill first line with values
      cimg_forX(values1,x) { values1(x) = (float)func(X,Y); X+=dx; }

      // Run the marching squares algorithm
      for (unsigned int yi = 0, nyi = 1; yi<nym1; ++yi, ++nyi, Y=nY, nY+=dy) {
        X = x0; nX = X + dx;
        indices2.fill(-1);
        for (unsigned int xi = 0, nxi = 1; xi<nxm1; ++xi, ++nxi, X=nX, nX+=dx) {

          // Determine square configuration
          const float
            val0 = values1(xi),
            val1 = values1(nxi),
            val2 = values2(nxi) = (float)func(nX,nY),
            val3 = values2(xi) = (float)func(X,nY);
          const unsigned int
            configuration = (val0<isovalue?1U:0U) | (val1<isovalue?2U:0U) |
            (val2<isovalue?4U:0U) | (val3<isovalue?8U:0U),
            edge = edges[configuration];

          // Compute intersection vertices
          if (edge) {
            if ((edge&1) && indices1(xi,0)<0) {
              const float Xi = X + (isovalue-val0)*dx/(val1-val0);
              indices1(xi,0) = vertices.width();
              CImg<floatT>::vector(Xi,Y,0).move_to(vertices);
            }
            if ((edge&2) && indices1(nxi,1)<0) {
              const float Yi = Y + (isovalue-val1)*dy/(val2-val1);
              indices1(nxi,1) = vertices.width();
              CImg<floatT>::vector(nX,Yi,0).move_to(vertices);
            }
            if ((edge&4) && indices2(xi,0)<0) {
              const float Xi = X + (isovalue-val3)*dx/(val2-val3);
              indices2(xi,0) = vertices.width();
              CImg<floatT>::vector(Xi,nY,0).move_to(vertices);
            }
            if ((edge&8) && indices1(xi,1)<0) {
              const float Yi = Y + (isovalue-val0)*dy/(val3-val0);
              indices1(xi,1) = vertices.width();
              CImg<floatT>::vector(X,Yi,0).move_to(vertices);
            }

            // Create segments
            for (const int *segment = segments[configuration]; *segment!=-1; ) {
              const unsigned int p0 = (unsigned int)*(segment++), p1 = (unsigned int)*(segment++);
              const tf
                i0 = (tf)(_isoline3d_index(p0,indices1,indices2,xi,nxi)),
                i1 = (tf)(_isoline3d_index(p1,indices1,indices2,xi,nxi));
              CImg<tf>::vector(i0,i1).move_to(primitives);
            }
          }
        }
        values1.swap(values2);
        indices1.swap(indices2);
      }
      return vertices>'x';

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


      static double mp_gte(_cimg_math_parser& mp) {
        return (double)(_mp_arg(2)>=_mp_arg(3));

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

      static int max() { return (int)((unsigned int)-1>>1); }

Project: CImg
File: CImg.h

    //! Label connected components \newinstance.
    CImg<ulongT> get_label(const bool is_high_connectivity=false,
                           const Tfloat tolerance=0) const {
      if (is_empty()) return CImg<ulongT>();

      // Create neighborhood tables.
      int dx[13], dy[13], dz[13], nb = 0;
      dx[nb] = 1; dy[nb] = 0; dz[nb++] = 0;
      dx[nb] = 0; dy[nb] = 1; dz[nb++] = 0;
      if (is_high_connectivity) {
        dx[nb] = 1; dy[nb] = 1; dz[nb++] = 0;
        dx[nb] = 1; dy[nb] = -1; dz[nb++] = 0;
      }
      if (_depth>1) { // 3D version
        dx[nb] = 0; dy[nb] = 0; dz[nb++]=1;
        if (is_high_connectivity) {
          dx[nb] = 1; dy[nb] = 1; dz[nb++] = -1;
          dx[nb] = 1; dy[nb] = 0; dz[nb++] = -1;
          dx[nb] = 1; dy[nb] = -1; dz[nb++] = -1;
          dx[nb] = 0; dy[nb] = 1; dz[nb++] = -1;

          dx[nb] = 0; dy[nb] = 1; dz[nb++] = 1;
          dx[nb] = 1; dy[nb] = -1; dz[nb++] = 1;
          dx[nb] = 1; dy[nb] = 0; dz[nb++] = 1;
          dx[nb] = 1; dy[nb] = 1; dz[nb++] = 1;
        }
      }
      return _label(nb,dx,dy,dz,tolerance);

Project: CImg
File: CImg.h


      static double mp_critical(_cimg_math_parser& mp) {
        const double res = _mp_arg(1);
        cimg_pragma_openmp(critical(mp_critical))
        {
          for (const CImg<ulongT> *const p_end = ++mp.p_code + mp.opcode[2];
               mp.p_code<p_end; ++mp.p_code) { // Evaluate body
            mp.opcode._data = mp.p_code->_data;
            const ulongT target = mp.opcode[1];
            mp.mem[target] = _cimg_mp_defunc(mp);
          }
        }
        --mp.p_code;
        return res;

Project: CImg
File: CImg.h


      static double mp_image_stats(_cimg_math_parser& mp) {
        double *ptrd = &_mp_arg(1) + 1;
        unsigned int ind = (unsigned int)mp.opcode[2];
        if (ind==~0U) CImg<doubleT>(ptrd,14,1,1,1,true) = mp.imgout.get_stats();
        else {
          ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
          CImg<doubleT>(ptrd,14,1,1,1,true) = mp.listout[ind].get_stats();
        }
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

    //! Convert pixel values from RGB to YCbCr color spaces.
    CImg<T>& YCbCrtoRGB() {
      if (_spectrum!=3)
        throw CImgInstanceException(_cimg_instance
                                    "YCbCrtoRGB(): Instance is not a YCbCr image.",
                                    cimg_instance);

      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,512))
      for (longT N = 0; N<whd; ++N) {
        const Tfloat
          Y = (Tfloat)p1[N] - 16,
          Cb = (Tfloat)p2[N] - 128,
          Cr = (Tfloat)p3[N] - 128,
          R = (298*Y + 409*Cr + 128)/256,
          G = (298*Y - 100*Cb - 208*Cr + 128)/256,
          B = (298*Y + 516*Cb + 128)/256;
        p1[N] = (T)cimg::cut(R,0,255),
        p2[N] = (T)cimg::cut(G,0,255),
        p3[N] = (T)cimg::cut(B,0,255);
      }
      return *this;

Project: CImg
File: CImg.h


      static double mp_cbrt(_cimg_math_parser& mp) {
        return cimg::cbrt(_mp_arg(2));

Project: CImg
File: CImg.h


    inline void srand() {
      cimg::mutex(4);
      cimg::srand(&cimg::rng());
      cimg::mutex(4,0);

Project: CImg
File: CImg.h

      static T max() { return (T)1<<(8*sizeof(T) - 1); }

Project: CImg
File: CImg.h


    CImgDisplay& move(const int posx, const int posy) {
      if (is_empty()) return *this;
      if (_window_x!=posx || _window_y!=posy) {
        if (!_is_fullscreen) {
          RECT rect;
          rect.left = rect.top = 0; rect.right = (LONG)_window_width - 1; rect.bottom = (LONG)_window_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);
          SetWindowPos(_window,0,posx - border1,posy - border2,0,0,SWP_NOSIZE | SWP_NOZORDER);
        } else SetWindowPos(_window,0,posx,posy,0,0,SWP_NOSIZE | SWP_NOZORDER);
        _window_x = posx;
        _window_y = posy;
        show();
      }
      _is_moved = false;
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    **/
    Tfloat linear_atXY(const float fx, const float fy, const int z, const int c, const T& out_value) const {
      const int
        x = (int)fx - (fx>=0?0:1), nx = x + 1,
        y = (int)fy - (fy>=0?0:1), ny = y + 1;
      const float
        dx = fx - x,
        dy = fy - y;
      const Tfloat
        Icc = (Tfloat)atXY(x,y,z,c,out_value),  Inc = (Tfloat)atXY(nx,y,z,c,out_value),
        Icn = (Tfloat)atXY(x,ny,z,c,out_value), Inn = (Tfloat)atXY(nx,ny,z,c,out_value);
      return Icc + dx*(Inc - Icc + dy*(Icc + Inn - Icn - Inc)) + dy*(Icn - Icc);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& operator>>=(const t value) {
      if (is_empty()) return *this;
      cimg_openmp_for(*this,((longT)*ptr) >> (int)value,65536);
      return *this;

Project: CImg
File: CImg.h

    **/
    const CImg<T>& save_rgb(const char *const filename) const {
      return _save_rgb(0,filename);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& rol(const CImg<t>& img) {
      const ulongT siz = size(), isiz = img.size();
      if (siz && isiz) {
        if (is_overlapped(img)) return rol(+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)cimg::rol(*ptrd,(unsigned int)(*(ptrs++)));
        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)cimg::rol(*ptrd,(unsigned int)(*(ptrs++)));
      }
      return *this;

Project: CImg
File: CImg.h

    template<typename T>
    static void screenshot(CImg<T>& img) {
      return screenshot(0,0,cimg::type<int>::max(),cimg::type<int>::max(),img);

Project: CImg
File: CImg.h

    /**
       \param is_compressed tells if zlib compression must be used for serialization
       (this requires 'cimg_use_zlib' been enabled).
    **/
    CImg<ucharT> get_serialize(const bool is_compressed=false) const {
#ifndef cimg_use_zlib
      if (is_compressed)
        cimg::warn(_cimglist_instance
                   "get_serialize(): Unable to compress data unless zlib is enabled, "
                   "storing them uncompressed.",
                   cimglist_instance);
#endif
      CImgList<ucharT> stream;
      CImg<charT> tmpstr(128);
      const char *const ptype = pixel_type(), *const etype = cimg::endianness()?"big":"little";
      if (std::strstr(ptype,"unsigned")==ptype)
        cimg_snprintf(tmpstr,tmpstr._width,"%u unsigned_%s %s_endian\n",_width,ptype + 9,etype);
      else
        cimg_snprintf(tmpstr,tmpstr._width,"%u %s %s_endian\n",_width,ptype,etype);
      CImg<ucharT>::string(tmpstr,false).move_to(stream);
      cimglist_for(*this,l) {
        const CImg<T>& img = _data[l];
        cimg_snprintf(tmpstr,tmpstr._width,"%u %u %u %u",img._width,img._height,img._depth,img._spectrum);
        CImg<ucharT>::string(tmpstr,false).move_to(stream);
        if (img._data) {
          CImg<T> tmp;
          if (cimg::endianness()) { tmp = img; cimg::invert_endianness(tmp._data,tmp.size()); }
          const CImg<T>& ref = cimg::endianness()?tmp:img;
          bool failed_to_compress = true;
          if (is_compressed) {
#ifdef cimg_use_zlib
            const ulongT siz = sizeof(T)*ref.size();
            uLongf csiz = (ulongT)compressBound(siz);
            Bytef *const cbuf = new Bytef[csiz];
            if (compress(cbuf,&csiz,(Bytef*)ref._data,siz))
              cimg::warn(_cimglist_instance
                         "get_serialize(): Failed to save compressed data, saving them uncompressed.",
                         cimglist_instance);
            else {
              cimg_snprintf(tmpstr,tmpstr._width," #%lu\n",csiz);
              CImg<ucharT>::string(tmpstr,false).move_to(stream);
              CImg<ucharT>(cbuf,csiz).move_to(stream);
              delete[] cbuf;
              failed_to_compress = false;
            }
#endif
          }
          if (failed_to_compress) { // Write in a non-compressed way
            CImg<charT>::string("\n",false).move_to(stream);
            stream.insert(1);
            stream.back().assign((unsigned char*)ref._data,ref.size()*sizeof(T),1,1,1,true);
          }
        } else CImg<charT>::string("\n",false).move_to(stream);

Project: CImg
File: CImg.h


      static double mp_complex_exp(_cimg_math_parser& mp) {
        double *ptrd = &_mp_arg(1) + 1;
        const double *ptrs = &_mp_arg(2) + 1, r = *(ptrs++), i = *(ptrs), er = std::exp(r);
        *(ptrd++) = er*std::cos(i);
        *(ptrd++) = er*std::sin(i);
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h


      static double mp_sqrt(_cimg_math_parser& mp) {
        return std::sqrt(_mp_arg(2));

Project: CImg
File: CImg.h

    //! Return a \c 1x9 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, const T& a6, const T& a7,
			  const T& a8) {
      CImg<T> r(1,9); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
      *(ptr++) = a8;
      return r;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    template<typename t>
    const T& min_max(t& max_val) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "min_max(): Empty instance.",
                                    cimg_instance);
      const T *ptr_min = _data;
      T min_value = *ptr_min, max_value = min_value;
      cimg_for(*this,ptrs,T) {
        const T val = *ptrs;
        if (val<min_value) { min_value = val; ptr_min = ptrs; }
        if (val>max_value) max_value = val;
      }
      max_val = (t)max_value;
      return *ptr_min;

Project: CImg
File: CImg.h

    template<typename tf, typename t>
    static CImg<T> dijkstra(const tf& distance, const unsigned int nb_nodes,
                            const unsigned int starting_node, const unsigned int ending_node,
                            CImg<t>& previous_node) {
      if (starting_node>=nb_nodes)
        throw CImgArgumentException("CImg<%s>::dijkstra(): Specified index of starting node %u is higher "
                                    "than number of nodes %u.",
                                    pixel_type(),starting_node,nb_nodes);
      CImg<T> dist(1,nb_nodes,1,1,cimg::type<T>::max());
      dist(starting_node) = 0;
      previous_node.assign(1,nb_nodes,1,1,(t)-1);
      previous_node(starting_node) = (t)starting_node;
      CImg<uintT> Q(nb_nodes);
      cimg_forX(Q,u) Q(u) = (unsigned int)u;
      cimg::swap(Q(starting_node),Q(0));
      unsigned int sizeQ = nb_nodes;
      while (sizeQ) {
        // Update neighbors from minimal vertex
        const unsigned int umin = Q(0);
        if (umin==ending_node) sizeQ = 0;
        else {
          const T dmin = dist(umin);
          const T infty = cimg::type<T>::max();
          for (unsigned int q = 1; q<sizeQ; ++q) {
            const unsigned int v = Q(q);
            const T d = (T)distance(v,umin);
            if (d<infty) {
              const T alt = dmin + d;
              if (alt<dist(v)) {
                dist(v) = alt;
                previous_node(v) = (t)umin;
                const T distpos = dist(Q(q));
                for (unsigned int pos = q, par = 0; pos && distpos<dist(Q(par=(pos + 1)/2 - 1)); pos=par)
                  cimg::swap(Q(pos),Q(par));
              }
            }
          }
          // Remove minimal vertex from queue
          Q(0) = Q(--sizeQ);
          const T distpos = dist(Q(0));
          for (unsigned int pos = 0, left = 0, right = 0;
               ((right=2*(pos + 1),(left=right - 1))<sizeQ && distpos>dist(Q(left))) ||
                 (right<sizeQ && distpos>dist(Q(right)));) {
            if (right<sizeQ) {
              if (dist(Q(left))<dist(Q(right))) { cimg::swap(Q(pos),Q(left)); pos = left; }
              else { cimg::swap(Q(pos),Q(right)); pos = right; }
            } else { cimg::swap(Q(pos),Q(left)); pos = left; }
          }
        }
      }
      return dist;

Project: CImg
File: CImg.h

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

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

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

    //! Return pixel value, using linear interpolation and periodic boundary conditions for the X,Y and Z-coordinates.
    Tfloat linear_atXYZ_p(const float fx, const float fy=0, const float fz=0, const int c=0) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "linear_atXYZ_p(): Empty instance.",
                                    cimg_instance);

      return _linear_atXYZ_p(fx,fy,fz,c);

Project: CImg
File: CImg.h

    **/
    CImgList<T>& assign(const CImgDisplay &disp) {
      return assign(CImg<T>(disp));

Project: CImg
File: CImg.h


      static double mp_display(_cimg_math_parser& mp) {
        const unsigned int
          _siz = (unsigned int)mp.opcode[3],
          siz = _siz?_siz:1;
        const double *const ptr = &_mp_arg(1) + (_siz?1:0);
        const int
          w = (int)_mp_arg(4),
          h = (int)_mp_arg(5),
          d = (int)_mp_arg(6),
          s = (int)_mp_arg(7);
        CImg<doubleT> img;
        if (w>0 && h>0 && d>0 && s>0) {
          if ((unsigned int)w*h*d*s<=siz) img.assign(ptr,w,h,d,s,true);
          else img.assign(ptr,siz).resize(w,h,d,s,-1);
        } else img.assign(ptr,1,siz,1,1,true);

        CImg<charT> expr(mp.opcode[2] - 8);
        const ulongT *ptrs = mp.opcode._data + 8;
        cimg_for(expr,ptrd,char) *ptrd = (char)*(ptrs++);
        ((CImg<charT>::string("[" cimg_appname "_math_parser] ",false,true),expr)>'x').move_to(expr);
        cimg::strellipsize(expr);
        std::fputc('\n',cimg::output());
        img.display(expr._data);
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h


    Tfloat _cubic_atXY(const float fx, const float fy, const int z=0, const int c=0) const {
      const float
        nfx = cimg::type<float>::is_nan(fx)?0:cimg::cut(fx,0,width() - 1),
        nfy = cimg::type<float>::is_nan(fy)?0:cimg::cut(fy,0,height() - 1);
      const int x = (int)nfx, y = (int)nfy;
      const float dx = nfx - x, dy = nfy - y;
      const int
        px = x - 1<0?0:x - 1, nx = dx<=0?x:x + 1, ax = x + 2>=width()?width() - 1:x + 2,
        py = y - 1<0?0:y - 1, ny = dy<=0?y:y + 1, ay = y + 2>=height()?height() - 1:y + 2;
      const Tfloat
        Ipp = (Tfloat)(*this)(px,py,z,c), Icp = (Tfloat)(*this)(x,py,z,c), Inp = (Tfloat)(*this)(nx,py,z,c),
        Iap = (Tfloat)(*this)(ax,py,z,c),
        Ip = Icp + 0.5f*(dx*(-Ipp + Inp) + dx*dx*(2*Ipp - 5*Icp + 4*Inp - Iap) + dx*dx*dx*(-Ipp + 3*Icp - 3*Inp + Iap)),
        Ipc = (Tfloat)(*this)(px,y,z,c),  Icc = (Tfloat)(*this)(x, y,z,c), Inc = (Tfloat)(*this)(nx,y,z,c),
        Iac = (Tfloat)(*this)(ax,y,z,c),
        Ic = Icc + 0.5f*(dx*(-Ipc + Inc) + dx*dx*(2*Ipc - 5*Icc + 4*Inc - Iac) + dx*dx*dx*(-Ipc + 3*Icc - 3*Inc + Iac)),
        Ipn = (Tfloat)(*this)(px,ny,z,c), Icn = (Tfloat)(*this)(x,ny,z,c), Inn = (Tfloat)(*this)(nx,ny,z,c),
        Ian = (Tfloat)(*this)(ax,ny,z,c),
        In = Icn + 0.5f*(dx*(-Ipn + Inn) + dx*dx*(2*Ipn - 5*Icn + 4*Inn - Ian) + dx*dx*dx*(-Ipn + 3*Icn - 3*Inn + Ian)),
        Ipa = (Tfloat)(*this)(px,ay,z,c), Ica = (Tfloat)(*this)(x,ay,z,c), Ina = (Tfloat)(*this)(nx,ay,z,c),
        Iaa = (Tfloat)(*this)(ax,ay,z,c),
        Ia = Ica + 0.5f*(dx*(-Ipa + Ina) + dx*dx*(2*Ipa - 5*Ica + 4*Ina - Iaa) + dx*dx*dx*(-Ipa + 3*Ica - 3*Ina + Iaa));
      return Ic + 0.5f*(dy*(-Ip + In) + dy*dy*(2*Ip - 5*Ic + 4*In - Ia) + dy*dy*dy*(-Ip + 3*Ic - 3*In + Ia));

Project: CImg
File: CImg.h


      static double mp_sub(_cimg_math_parser& mp) {
        return _mp_arg(2) - _mp_arg(3);

Project: CImg
File: CImg.h

    //! Access to pixel value with Neumann boundary conditions for the 4 coordinates (\c pos, \c x,\c y,\c z) \const.
    T atNXYZ(const int pos, const int x, const int y, const int z, const int c=0) const {
      if (is_empty())
        throw CImgInstanceException(_cimglist_instance
                                    "atNXYZ(): Empty instance.",
                                    cimglist_instance);

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

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_triangle(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 (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(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);
          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,
              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;
          }
        }
      }
      return *this;

Project: CImg
File: CImg.h

    struct Magick_info {
      Magick_info() {
        Magick::InitializeMagick("");

Project: CImg
File: CImg.h

    template<typename T>
    inline T median(T val0, T val1, T val2, T val3, T val4, T val5, T val6,
                    T val7, T val8, T val9, T val10, T val11, T val12, T val13,
                    T val14, T val15, T val16, T val17, T val18, T val19, T val20,
                    T val21, T val22, T val23, T val24, T val25, T val26, T val27,
                    T val28, T val29, T val30, T val31, T val32, T val33, T val34,
                    T val35, T val36, T val37, T val38, T val39, T val40, T val41,
                    T val42, T val43, T val44, T val45, T val46, T val47, T val48) {
      T tmp = std::min(val0,val32);
      val32 = std::max(val0,val32); val0 = tmp; tmp = std::min(val1,val33); val33 = std::max(val1,val33); val1 = tmp;
      tmp = std::min(val2,val34); val34 = std::max(val2,val34); val2 = tmp; tmp = std::min(val3,val35);
      val35 = std::max(val3,val35); val3 = tmp; tmp = std::min(val4,val36); val36 = std::max(val4,val36); val4 = tmp;
      tmp = std::min(val5,val37); val37 = std::max(val5,val37); val5 = tmp; tmp = std::min(val6,val38);
      val38 = std::max(val6,val38); val6 = tmp; tmp = std::min(val7,val39); val39 = std::max(val7,val39); val7 = tmp;
      tmp = std::min(val8,val40); val40 = std::max(val8,val40); val8 = tmp; tmp = std::min(val9,val41);
      val41 = std::max(val9,val41); val9 = tmp; tmp = std::min(val10,val42); val42 = std::max(val10,val42);
      val10 = tmp; tmp = std::min(val11,val43); val43 = std::max(val11,val43); val11 = tmp;
      tmp = std::min(val12,val44); val44 = std::max(val12,val44); val12 = tmp; tmp = std::min(val13,val45);
      val45 = std::max(val13,val45); val13 = tmp; tmp = std::min(val14,val46); val46 = std::max(val14,val46);
      val14 = tmp; tmp = std::min(val15,val47); val47 = std::max(val15,val47); val15 = tmp;
      tmp = std::min(val16,val48); val48 = std::max(val16,val48); val16 = tmp; tmp = std::min(val0,val16);
      val16 = std::max(val0,val16); val0 = tmp; tmp = std::min(val1,val17); val17 = std::max(val1,val17);
      val1 = tmp; tmp = std::min(val2,val18); val18 = std::max(val2,val18); val2 = tmp; tmp = std::min(val3,val19);
      val19 = std::max(val3,val19); val3 = tmp; tmp = std::min(val4,val20); val20 = std::max(val4,val20); val4 = tmp;
      tmp = std::min(val5,val21); val21 = std::max(val5,val21); val5 = tmp; tmp = std::min(val6,val22);
      val22 = std::max(val6,val22); val6 = tmp; tmp = std::min(val7,val23); val23 = std::max(val7,val23); val7 = tmp;
      tmp = std::min(val8,val24); val24 = std::max(val8,val24); val8 = tmp; tmp = std::min(val9,val25);
      val25 = std::max(val9,val25); val9 = tmp; tmp = std::min(val10,val26); val26 = std::max(val10,val26);
      val10 = tmp; tmp = std::min(val11,val27); val27 = std::max(val11,val27); val11 = tmp;
      tmp = std::min(val12,val28); val28 = std::max(val12,val28); val12 = tmp; tmp = std::min(val13,val29);
      val29 = std::max(val13,val29); val13 = tmp; tmp = std::min(val14,val30); val30 = std::max(val14,val30);
      val14 = tmp; tmp = std::min(val15,val31); val31 = std::max(val15,val31); val15 = tmp;
      tmp = std::min(val32,val48); val48 = std::max(val32,val48); val32 = tmp; tmp = std::min(val16,val32);
      val32 = std::max(val16,val32); val16 = tmp; tmp = std::min(val17,val33); val33 = std::max(val17,val33);
      val17 = tmp; tmp = std::min(val18,val34); val34 = std::max(val18,val34); val18 = tmp;
      tmp = std::min(val19,val35); val35 = std::max(val19,val35); val19 = tmp; tmp = std::min(val20,val36);
      val36 = std::max(val20,val36); val20 = tmp; tmp = std::min(val21,val37); val37 = std::max(val21,val37);
      val21 = tmp; tmp = std::min(val22,val38); val38 = std::max(val22,val38); val22 = tmp;
      tmp = std::min(val23,val39); val39 = std::max(val23,val39); val23 = tmp; tmp = std::min(val24,val40);
      val40 = std::max(val24,val40); val24 = tmp; tmp = std::min(val25,val41); val41 = std::max(val25,val41);
      val25 = tmp; tmp = std::min(val26,val42); val42 = std::max(val26,val42); val26 = tmp;
      tmp = std::min(val27,val43); val43 = std::max(val27,val43); val27 = tmp; tmp = std::min(val28,val44);
      val44 = std::max(val28,val44); val28 = tmp; tmp = std::min(val29,val45); val45 = std::max(val29,val45);
      val29 = tmp; tmp = std::min(val30,val46); val46 = std::max(val30,val46); val30 = tmp;
      tmp = std::min(val31,val47); val47 = std::max(val31,val47); val31 = tmp; tmp = std::min(val0,val8);
      val8 = std::max(val0,val8); val0 = tmp; tmp = std::min(val1,val9); val9 = std::max(val1,val9); val1 = tmp;
      tmp = std::min(val2,val10); val10 = std::max(val2,val10); val2 = tmp; tmp = std::min(val3,val11);
      val11 = std::max(val3,val11); val3 = tmp; tmp = std::min(val4,val12); val12 = std::max(val4,val12); val4 = tmp;
      tmp = std::min(val5,val13); val13 = std::max(val5,val13); val5 = tmp; tmp = std::min(val6,val14);
      val14 = std::max(val6,val14); val6 = tmp; tmp = std::min(val7,val15); val15 = std::max(val7,val15); val7 = tmp;
      tmp = std::min(val16,val24); val24 = std::max(val16,val24); val16 = tmp; tmp = std::min(val17,val25);
      val25 = std::max(val17,val25); val17 = tmp; tmp = std::min(val18,val26); val26 = std::max(val18,val26);
      val18 = tmp; tmp = std::min(val19,val27); val27 = std::max(val19,val27); val19 = tmp;
      tmp = std::min(val20,val28); val28 = std::max(val20,val28); val20 = tmp; tmp = std::min(val21,val29);
      val29 = std::max(val21,val29); val21 = tmp; tmp = std::min(val22,val30); val30 = std::max(val22,val30);
      val22 = tmp; tmp = std::min(val23,val31); val31 = std::max(val23,val31); val23 = tmp;
      tmp = std::min(val32,val40); val40 = std::max(val32,val40); val32 = tmp; tmp = std::min(val33,val41);
      val41 = std::max(val33,val41); val33 = tmp; tmp = std::min(val34,val42); val42 = std::max(val34,val42);
      val34 = tmp; tmp = std::min(val35,val43); val43 = std::max(val35,val43); val35 = tmp;
      tmp = std::min(val36,val44); val44 = std::max(val36,val44); val36 = tmp; tmp = std::min(val37,val45);
      val45 = std::max(val37,val45); val37 = tmp; tmp = std::min(val38,val46); val46 = std::max(val38,val46);
      val38 = tmp; tmp = std::min(val39,val47); val47 = std::max(val39,val47); val39 = tmp;
      tmp = std::min(val8,val32); val32 = std::max(val8,val32); val8 = tmp; tmp = std::min(val9,val33);
      val33 = std::max(val9,val33); val9 = tmp; tmp = std::min(val10,val34); val34 = std::max(val10,val34);
      val10 = tmp; tmp = std::min(val11,val35); val35 = std::max(val11,val35); val11 = tmp;
      tmp = std::min(val12,val36); val36 = std::max(val12,val36); val12 = tmp; tmp = std::min(val13,val37);
      val37 = std::max(val13,val37); val13 = tmp; tmp = std::min(val14,val38); val38 = std::max(val14,val38);
      val14 = tmp; tmp = std::min(val15,val39); val39 = std::max(val15,val39); val15 = tmp;
      tmp = std::min(val24,val48); val48 = std::max(val24,val48); val24 = tmp; tmp = std::min(val8,val16);
      val16 = std::max(val8,val16); val8 = tmp; tmp = std::min(val9,val17); val17 = std::max(val9,val17);
      val9 = tmp; tmp = std::min(val10,val18); val18 = std::max(val10,val18); val10 = tmp;
      tmp = std::min(val11,val19); val19 = std::max(val11,val19); val11 = tmp; tmp = std::min(val12,val20);
      val20 = std::max(val12,val20); val12 = tmp; tmp = std::min(val13,val21); val21 = std::max(val13,val21);
      val13 = tmp; tmp = std::min(val14,val22); val22 = std::max(val14,val22); val14 = tmp;
      tmp = std::min(val15,val23); val23 = std::max(val15,val23); val15 = tmp; tmp = std::min(val24,val32);
      val32 = std::max(val24,val32); val24 = tmp; tmp = std::min(val25,val33); val33 = std::max(val25,val33);
      val25 = tmp; tmp = std::min(val26,val34); val34 = std::max(val26,val34); val26 = tmp;
      tmp = std::min(val27,val35); val35 = std::max(val27,val35); val27 = tmp; tmp = std::min(val28,val36);
      val36 = std::max(val28,val36); val28 = tmp; tmp = std::min(val29,val37); val37 = std::max(val29,val37);
      val29 = tmp; tmp = std::min(val30,val38); val38 = std::max(val30,val38); val30 = tmp;
      tmp = std::min(val31,val39); val39 = std::max(val31,val39); val31 = tmp; tmp = std::min(val40,val48);
      val48 = std::max(val40,val48); val40 = tmp; tmp = std::min(val0,val4); val4 = std::max(val0,val4);
      val0 = tmp; tmp = std::min(val1,val5); val5 = std::max(val1,val5); val1 = tmp; tmp = std::min(val2,val6);
      val6 = std::max(val2,val6); val2 = tmp; tmp = std::min(val3,val7); val7 = std::max(val3,val7); val3 = tmp;
      tmp = std::min(val8,val12); val12 = std::max(val8,val12); val8 = tmp; tmp = std::min(val9,val13);
      val13 = std::max(val9,val13); val9 = tmp; tmp = std::min(val10,val14); val14 = std::max(val10,val14);
      val10 = tmp; tmp = std::min(val11,val15); val15 = std::max(val11,val15); val11 = tmp;
      tmp = std::min(val16,val20); val20 = std::max(val16,val20); val16 = tmp; tmp = std::min(val17,val21);
      val21 = std::max(val17,val21); val17 = tmp; tmp = std::min(val18,val22); val22 = std::max(val18,val22);
      val18 = tmp; tmp = std::min(val19,val23); val23 = std::max(val19,val23); val19 = tmp;
      tmp = std::min(val24,val28); val28 = std::max(val24,val28); val24 = tmp; tmp = std::min(val25,val29);
      val29 = std::max(val25,val29); val25 = tmp; tmp = std::min(val26,val30); val30 = std::max(val26,val30);
      val26 = tmp; tmp = std::min(val27,val31); val31 = std::max(val27,val31); val27 = tmp;
      tmp = std::min(val32,val36); val36 = std::max(val32,val36); val32 = tmp; tmp = std::min(val33,val37);
      val37 = std::max(val33,val37); val33 = tmp; tmp = std::min(val34,val38); val38 = std::max(val34,val38);
      val34 = tmp; tmp = std::min(val35,val39); val39 = std::max(val35,val39); val35 = tmp;
      tmp = std::min(val40,val44); val44 = std::max(val40,val44); val40 = tmp; tmp = std::min(val41,val45);
      val45 = std::max(val41,val45); val41 = tmp; tmp = std::min(val42,val46); val46 = std::max(val42,val46);
      val42 = tmp; tmp = std::min(val43,val47); val47 = std::max(val43,val47); val43 = tmp;
      tmp = std::min(val4,val32); val32 = std::max(val4,val32); val4 = tmp; tmp = std::min(val5,val33);
      val33 = std::max(val5,val33); val5 = tmp; tmp = std::min(val6,val34); val34 = std::max(val6,val34);
      val6 = tmp; tmp = std::min(val7,val35); val35 = std::max(val7,val35); val7 = tmp;
      tmp = std::min(val12,val40); val40 = std::max(val12,val40); val12 = tmp; tmp = std::min(val13,val41);
      val41 = std::max(val13,val41); val13 = tmp; tmp = std::min(val14,val42); val42 = std::max(val14,val42);
      val14 = tmp; tmp = std::min(val15,val43); val43 = std::max(val15,val43); val15 = tmp;
      tmp = std::min(val20,val48); val48 = std::max(val20,val48); val20 = tmp; tmp = std::min(val4,val16);
      val16 = std::max(val4,val16); val4 = tmp; tmp = std::min(val5,val17); val17 = std::max(val5,val17);
      val5 = tmp; tmp = std::min(val6,val18); val18 = std::max(val6,val18); val6 = tmp;
      tmp = std::min(val7,val19); val19 = std::max(val7,val19); val7 = tmp; tmp = std::min(val12,val24);
      val24 = std::max(val12,val24); val12 = tmp; tmp = std::min(val13,val25); val25 = std::max(val13,val25);
      val13 = tmp; tmp = std::min(val14,val26); val26 = std::max(val14,val26); val14 = tmp;
      tmp = std::min(val15,val27); val27 = std::max(val15,val27); val15 = tmp; tmp = std::min(val20,val32);
      val32 = std::max(val20,val32); val20 = tmp; tmp = std::min(val21,val33); val33 = std::max(val21,val33);
      val21 = tmp; tmp = std::min(val22,val34); val34 = std::max(val22,val34); val22 = tmp;
      tmp = std::min(val23,val35); val35 = std::max(val23,val35); val23 = tmp; tmp = std::min(val28,val40);
      val40 = std::max(val28,val40); val28 = tmp; tmp = std::min(val29,val41); val41 = std::max(val29,val41);
      val29 = tmp; tmp = std::min(val30,val42); val42 = std::max(val30,val42); val30 = tmp;
      tmp = std::min(val31,val43); val43 = std::max(val31,val43); val31 = tmp; tmp = std::min(val36,val48);
      val48 = std::max(val36,val48); val36 = tmp; tmp = std::min(val4,val8); val8 = std::max(val4,val8);
      val4 = tmp; tmp = std::min(val5,val9); val9 = std::max(val5,val9); val5 = tmp; tmp = std::min(val6,val10);
      val10 = std::max(val6,val10); val6 = tmp; tmp = std::min(val7,val11); val11 = std::max(val7,val11); val7 = tmp;
      tmp = std::min(val12,val16); val16 = std::max(val12,val16); val12 = tmp; tmp = std::min(val13,val17);
      val17 = std::max(val13,val17); val13 = tmp; tmp = std::min(val14,val18); val18 = std::max(val14,val18);
      val14 = tmp; tmp = std::min(val15,val19); val19 = std::max(val15,val19); val15 = tmp;
      tmp = std::min(val20,val24); val24 = std::max(val20,val24); val20 = tmp; tmp = std::min(val21,val25);
      val25 = std::max(val21,val25); val21 = tmp; tmp = std::min(val22,val26); val26 = std::max(val22,val26);
      val22 = tmp; tmp = std::min(val23,val27); val27 = std::max(val23,val27); val23 = tmp;
      tmp = std::min(val28,val32); val32 = std::max(val28,val32); val28 = tmp; tmp = std::min(val29,val33);
      val33 = std::max(val29,val33); val29 = tmp; tmp = std::min(val30,val34); val34 = std::max(val30,val34);
      val30 = tmp; tmp = std::min(val31,val35); val35 = std::max(val31,val35); val31 = tmp;
      tmp = std::min(val36,val40); val40 = std::max(val36,val40); val36 = tmp; tmp = std::min(val37,val41);
      val41 = std::max(val37,val41); val37 = tmp; tmp = std::min(val38,val42); val42 = std::max(val38,val42);
      val38 = tmp; tmp = std::min(val39,val43); val43 = std::max(val39,val43); val39 = tmp;
      tmp = std::min(val44,val48); val48 = std::max(val44,val48); val44 = tmp; tmp = std::min(val0,val2);
      val2 = std::max(val0,val2); val0 = tmp; tmp = std::min(val1,val3); val3 = std::max(val1,val3); val1 = tmp;
      tmp = std::min(val4,val6); val6 = std::max(val4,val6); val4 = tmp; tmp = std::min(val5,val7);
      val7 = std::max(val5,val7); val5 = tmp; tmp = std::min(val8,val10); val10 = std::max(val8,val10); val8 = tmp;
      tmp = std::min(val9,val11); val11 = std::max(val9,val11); val9 = tmp; tmp = std::min(val12,val14);
      val14 = std::max(val12,val14); val12 = tmp; tmp = std::min(val13,val15); val15 = std::max(val13,val15);
      val13 = tmp; tmp = std::min(val16,val18); val18 = std::max(val16,val18); val16 = tmp;
      tmp = std::min(val17,val19); val19 = std::max(val17,val19); val17 = tmp; tmp = std::min(val20,val22);
      val22 = std::max(val20,val22); val20 = tmp; tmp = std::min(val21,val23); val23 = std::max(val21,val23);
      val21 = tmp; tmp = std::min(val24,val26); val26 = std::max(val24,val26); val24 = tmp;
      tmp = std::min(val25,val27); val27 = std::max(val25,val27); val25 = tmp; tmp = std::min(val28,val30);
      val30 = std::max(val28,val30); val28 = tmp; tmp = std::min(val29,val31); val31 = std::max(val29,val31);
      val29 = tmp; tmp = std::min(val32,val34); val34 = std::max(val32,val34); val32 = tmp;
      tmp = std::min(val33,val35); val35 = std::max(val33,val35); val33 = tmp; tmp = std::min(val36,val38);
      val38 = std::max(val36,val38); val36 = tmp; tmp = std::min(val37,val39); val39 = std::max(val37,val39);
      val37 = tmp; tmp = std::min(val40,val42); val42 = std::max(val40,val42); val40 = tmp;
      tmp = std::min(val41,val43); val43 = std::max(val41,val43); val41 = tmp; tmp = std::min(val44,val46);
      val46 = std::max(val44,val46); val44 = tmp; tmp = std::min(val45,val47); val47 = std::max(val45,val47);
      val45 = tmp; tmp = std::min(val2,val32); val32 = std::max(val2,val32); val2 = tmp; tmp = std::min(val3,val33);
      val33 = std::max(val3,val33); val3 = tmp; tmp = std::min(val6,val36); val36 = std::max(val6,val36); val6 = tmp;
      tmp = std::min(val7,val37); val37 = std::max(val7,val37); val7 = tmp; tmp = std::min(val10,val40);
      val40 = std::max(val10,val40); val10 = tmp; tmp = std::min(val11,val41); val41 = std::max(val11,val41);
      val11 = tmp; tmp = std::min(val14,val44); val44 = std::max(val14,val44); val14 = tmp;
      tmp = std::min(val15,val45); val45 = std::max(val15,val45); val15 = tmp; tmp = std::min(val18,val48);
      val48 = std::max(val18,val48); val18 = tmp; tmp = std::min(val2,val16); val16 = std::max(val2,val16);
      val2 = tmp; tmp = std::min(val3,val17); val17 = std::max(val3,val17); val3 = tmp;
      tmp = std::min(val6,val20); val20 = std::max(val6,val20); val6 = tmp; tmp = std::min(val7,val21);
      val21 = std::max(val7,val21); val7 = tmp; tmp = std::min(val10,val24); val24 = std::max(val10,val24);
      val10 = tmp; tmp = std::min(val11,val25); val25 = std::max(val11,val25); val11 = tmp;
      tmp = std::min(val14,val28); val28 = std::max(val14,val28); val14 = tmp; tmp = std::min(val15,val29);
      val29 = std::max(val15,val29); val15 = tmp; tmp = std::min(val18,val32); val32 = std::max(val18,val32);
      val18 = tmp; tmp = std::min(val19,val33); val33 = std::max(val19,val33); val19 = tmp;
      tmp = std::min(val22,val36); val36 = std::max(val22,val36); val22 = tmp; tmp = std::min(val23,val37);
      val37 = std::max(val23,val37); val23 = tmp; tmp = std::min(val26,val40); val40 = std::max(val26,val40);
      val26 = tmp; tmp = std::min(val27,val41); val41 = std::max(val27,val41); val27 = tmp;
      tmp = std::min(val30,val44); val44 = std::max(val30,val44); val30 = tmp; tmp = std::min(val31,val45);
      val45 = std::max(val31,val45); val31 = tmp; tmp = std::min(val34,val48); val48 = std::max(val34,val48);
      val34 = tmp; tmp = std::min(val2,val8); val8 = std::max(val2,val8); val2 = tmp; tmp = std::min(val3,val9);
      val9 = std::max(val3,val9); val3 = tmp; tmp = std::min(val6,val12); val12 = std::max(val6,val12); val6 = tmp;
      tmp = std::min(val7,val13); val13 = std::max(val7,val13); val7 = tmp; tmp = std::min(val10,val16);
      val16 = std::max(val10,val16); val10 = tmp; tmp = std::min(val11,val17); val17 = std::max(val11,val17);
      val11 = tmp; tmp = std::min(val14,val20); val20 = std::max(val14,val20); val14 = tmp;
      tmp = std::min(val15,val21); val21 = std::max(val15,val21); val15 = tmp; tmp = std::min(val18,val24);
      val24 = std::max(val18,val24); val18 = tmp; tmp = std::min(val19,val25); val25 = std::max(val19,val25);
      val19 = tmp; tmp = std::min(val22,val28); val28 = std::max(val22,val28); val22 = tmp;
      tmp = std::min(val23,val29); val29 = std::max(val23,val29); val23 = tmp; tmp = std::min(val26,val32);
      val32 = std::max(val26,val32); val26 = tmp; tmp = std::min(val27,val33); val33 = std::max(val27,val33);
      val27 = tmp; tmp = std::min(val30,val36); val36 = std::max(val30,val36); val30 = tmp;
      tmp = std::min(val31,val37); val37 = std::max(val31,val37); val31 = tmp; tmp = std::min(val34,val40);
      val40 = std::max(val34,val40); val34 = tmp; tmp = std::min(val35,val41); val41 = std::max(val35,val41);
      val35 = tmp; tmp = std::min(val38,val44); val44 = std::max(val38,val44); val38 = tmp;
      tmp = std::min(val39,val45); val45 = std::max(val39,val45); val39 = tmp; tmp = std::min(val42,val48);
      val48 = std::max(val42,val48); val42 = tmp; tmp = std::min(val2,val4); val4 = std::max(val2,val4);
      val2 = tmp; tmp = std::min(val3,val5); val5 = std::max(val3,val5); val3 = tmp; tmp = std::min(val6,val8);
      val8 = std::max(val6,val8); val6 = tmp; tmp = std::min(val7,val9); val9 = std::max(val7,val9); val7 = tmp;
      tmp = std::min(val10,val12); val12 = std::max(val10,val12); val10 = tmp; tmp = std::min(val11,val13);
      val13 = std::max(val11,val13); val11 = tmp; tmp = std::min(val14,val16); val16 = std::max(val14,val16);
      val14 = tmp; tmp = std::min(val15,val17); val17 = std::max(val15,val17); val15 = tmp;
      tmp = std::min(val18,val20); val20 = std::max(val18,val20); val18 = tmp; tmp = std::min(val19,val21);
      val21 = std::max(val19,val21); val19 = tmp; tmp = std::min(val22,val24); val24 = std::max(val22,val24);
      val22 = tmp; tmp = std::min(val23,val25); val25 = std::max(val23,val25); val23 = tmp;
      tmp = std::min(val26,val28); val28 = std::max(val26,val28); val26 = tmp; tmp = std::min(val27,val29);
      val29 = std::max(val27,val29); val27 = tmp; tmp = std::min(val30,val32); val32 = std::max(val30,val32);
      val30 = tmp; tmp = std::min(val31,val33); val33 = std::max(val31,val33); val31 = tmp;
      tmp = std::min(val34,val36); val36 = std::max(val34,val36); val34 = tmp; tmp = std::min(val35,val37);
      val37 = std::max(val35,val37); val35 = tmp; tmp = std::min(val38,val40); val40 = std::max(val38,val40);
      val38 = tmp; tmp = std::min(val39,val41); val41 = std::max(val39,val41); val39 = tmp;
      tmp = std::min(val42,val44); val44 = std::max(val42,val44); val42 = tmp; tmp = std::min(val43,val45);
      val45 = std::max(val43,val45); val43 = tmp; tmp = std::min(val46,val48); val48 = std::max(val46,val48);
      val46 = tmp; val1 = std::max(val0,val1); val3 = std::max(val2,val3); val5 = std::max(val4,val5);
      val7 = std::max(val6,val7); val9 = std::max(val8,val9); val11 = std::max(val10,val11);
      val13 = std::max(val12,val13); val15 = std::max(val14,val15); val17 = std::max(val16,val17);
      val19 = std::max(val18,val19); val21 = std::max(val20,val21); val23 = std::max(val22,val23);
      val24 = std::min(val24,val25); val26 = std::min(val26,val27); val28 = std::min(val28,val29);
      val30 = std::min(val30,val31); val32 = std::min(val32,val33); val34 = std::min(val34,val35);
      val36 = std::min(val36,val37); val38 = std::min(val38,val39); val40 = std::min(val40,val41);
      val42 = std::min(val42,val43); val44 = std::min(val44,val45); val46 = std::min(val46,val47);
      val32 = std::max(val1,val32); val34 = std::max(val3,val34); val36 = std::max(val5,val36);
      val38 = std::max(val7,val38); val9 = std::min(val9,val40); val11 = std::min(val11,val42);
      val13 = std::min(val13,val44); val15 = std::min(val15,val46); val17 = std::min(val17,val48);
      val24 = std::max(val9,val24); val26 = std::max(val11,val26); val28 = std::max(val13,val28);
      val30 = std::max(val15,val30); val17 = std::min(val17,val32); val19 = std::min(val19,val34);
      val21 = std::min(val21,val36); val23 = std::min(val23,val38); val24 = std::max(val17,val24);
      val26 = std::max(val19,val26); val21 = std::min(val21,val28); val23 = std::min(val23,val30);
      val24 = std::max(val21,val24); val23 = std::min(val23,val26);
      return std::max(val23,val24);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    **/
    CImgList<T> get_shared() {
      CImgList<T> res(_width);
      cimglist_for(*this,l) res[l].assign(_data[l],true);
      return res;

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_point(const int x0, const int y0, const int z0,
                        const tc *const color, const float opacity=1) {
      if (is_empty()) return *this;
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_point(): Specified color is (null).",
                                    cimg_instance);
      if (x0>=0 && y0>=0 && z0>=0 && x0<width() && y0<height() && z0<depth()) {
        const ulongT whd = (ulongT)_width*_height*_depth;
        const float nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.f);
        T *ptrd = data(x0,y0,z0,0);
        const tc *col = color;
        if (opacity>=1) cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=whd; }
        else cimg_forC(*this,c) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whd; }
      }
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    **/
    double eval(const char *const expression,
                const double x=0, const double y=0, const double z=0, const double c=0,
                const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) {
      return _eval(this,expression,x,y,z,c,list_inputs,list_outputs);

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_fill(const int x0, const int y0, const int z0,
                       const tc *const color, const float opacity=1,
                       const float tolerance=0, const bool is_high_connexity=false) {
      CImg<ucharT> tmp;
      return draw_fill(x0,y0,z0,color,opacity,tmp,tolerance,is_high_connexity);

Project: CImg
File: CImg.h


      static double mp_image_print(_cimg_math_parser& mp) {
        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listout.width());
        cimg::mutex(6);
        CImg<T> &img = mp.listout[ind];
        CImg<charT> title(256);
        std::fputc('\n',cimg::output());
        cimg_snprintf(title,title._width,"[ Image #%u ]",ind);
        img.print(title);
        cimg::mutex(6,0);
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h


      static double mp_list_set_jxyzc(_cimg_math_parser& mp) {
        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
        CImg<T> &img = mp.listout[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];
        const int
          x = (int)(ox + _mp_arg(3)), y = (int)(oy + _mp_arg(4)),
          z = (int)(oz + _mp_arg(5)), c = (int)(oc + _mp_arg(6));
        const double val = _mp_arg(1);
        if (x>=0 && x<img.width() && y>=0 && y<img.height() &&
            z>=0 && z<img.depth() && c>=0 && c<img.spectrum())
          img(x,y,z,c) = (T)val;
        return val;

Project: CImg
File: CImg.h

    **/
    T& atNXYZC(const int pos, const int x, const int y, const int z, const int c, const T& out_value) {
      return (pos<0 || pos>=width())?(cimg::temporary(out_value)=out_value):_data[pos].atXYZC(x,y,z,c,out_value);

Project: CImg
File: CImg.h

    **/
    CImg<T> *data() {
      return _data;

Project: CImg
File: CImg.h

    template<typename tp, typename tf, typename tc>
    CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
                           const CImg<tp>& vertices, const CImgList<tf>& primitives,
                           const CImgList<tc>& colors,
                           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(x0,y0,z0,vertices,primitives,colors,CImg<floatT>::const_empty(),
                           render_type,is_double_sided,focale,lightx,lighty,lightz,
                           specular_lightness,specular_shininess,g_opacity,CImg<floatT>::empty());

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    //! Return a shared-memory image referencing a range of channels of the image instance \const.
    const CImg<T> get_shared_channels(const unsigned int c0, const unsigned int c1) const {
      const unsigned int
        beg = (unsigned int)offset(0,0,0,c0),
        end = (unsigned int)offset(0,0,0,c1);
      if (beg>end || beg>=size() || end>=size())
        throw CImgArgumentException(_cimg_instance
                                    "get_shared_channels(): Invalid request of a shared-memory subset "
                                    "(0->%u,0->%u,0->%u,%u->%u).",
                                    cimg_instance,
                                    _width - 1,_height - 1,_depth - 1,c0,c1);

      return CImg<T>(_data + beg,_width,_height,_depth,c1 - c0 + 1,true);

Project: CImg
File: CImg.h

    //! Blur image with the median filter \newinstance.
    CImg<T> get_blur_median(const unsigned int n, const float threshold=0) const {
      if (is_empty() || n<=1) return +*this;
      CImg<T> res(_width,_height,_depth,_spectrum);
      T *ptrd = res._data;
      cimg::unused(ptrd);
      const int hr = (int)n/2, hl = n - hr - 1;
      if (res._depth!=1) { // 3D
        if (threshold>0)
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*16 &&
                                                                     _height*_depth*_spectrum>=4))
          cimg_forXYZC(*this,x,y,z,c) { // With threshold
            const int
              x0 = x - hl, y0 = y - hl, z0 = z - hl, x1 = x + hr, y1 = y + hr, z1 = z + hr,
              nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, nz0 = z0<0?0:z0,
              nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1, nz1 = z1>=depth()?depth() - 1:z1;
            const Tfloat val0 = (Tfloat)(*this)(x,y,z,c);
            CImg<T> values(n*n*n);
            unsigned int nb_values = 0;
            T *_ptrd = values.data();
            cimg_for_inXYZ(*this,nx0,ny0,nz0,nx1,ny1,nz1,p,q,r)
              if (cimg::abs((*this)(p,q,r,c) - val0)<=threshold) { *(_ptrd++) = (*this)(p,q,r,c); ++nb_values; }
            res(x,y,z,c) = nb_values?values.get_shared_points(0,nb_values - 1).median():(*this)(x,y,z,c);
          }
        else
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*16 &&
                                                                     _height*_depth*_spectrum>=4))
          cimg_forXYZC(*this,x,y,z,c) { // Without threshold
            const int
              x0 = x - hl, y0 = y - hl, z0 = z - hl, x1 = x + hr, y1 = y + hr, z1 = z + hr,
              nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, nz0 = z0<0?0:z0,
              nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1, nz1 = z1>=depth()?depth() - 1:z1;
            res(x,y,z,c) = get_crop(nx0,ny0,nz0,c,nx1,ny1,nz1,c).median();
          }
      } else {
        if (threshold>0)
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*16 &&
                                                                     _height*_spectrum>=4))
          cimg_forXYC(*this,x,y,c) { // With threshold
            const int
              x0 = x - hl, y0 = y - hl, x1 = x + hr, y1 = y + hr,
              nx0 = x0<0?0:x0, ny0 = y0<0?0:y0,
                                        nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1;
            const Tfloat val0 = (Tfloat)(*this)(x,y,c);
            CImg<T> values(n*n);
            unsigned int nb_values = 0;
            T *_ptrd = values.data();
            cimg_for_inXY(*this,nx0,ny0,nx1,ny1,p,q)
              if (cimg::abs((*this)(p,q,c) - val0)<=threshold) { *(_ptrd++) = (*this)(p,q,c); ++nb_values; }
            res(x,y,c) = nb_values?values.get_shared_points(0,nb_values - 1).median():(*this)(x,y,c);
          }
        else {
          const int
            w1 = width() - 1, h1 = height() - 1,
            w2 = width() - 2, h2 = height() - 2,
            w3 = width() - 3, h3 = height() - 3,
            w4 = width() - 4, h4 = height() - 4;
          switch (n) { // Without threshold
          case 3 : {
            cimg_pragma_openmp(parallel for cimg_openmp_if(_spectrum>=2))
            cimg_forC(*this,c) {
              CImg<T> I(9);
              cimg_for_in3x3(*this,1,1,w2,h2,x,y,0,c,I,T)
                res(x,y,c) = cimg::median(I[0],I[1],I[2],I[3],I[4],I[5],I[6],I[7],I[8]);
              cimg_for_borderXY(*this,x,y,1)
                res(x,y,c) = get_crop(std::max(0,x - 1),std::max(0,y - 1),0,c,
                                      std::min(w1,x + 1),std::min(h1,y + 1),0,c).median();
            }
          } break;
          case 5 : {
            cimg_pragma_openmp(parallel for cimg_openmp_if(_spectrum>=2))
            cimg_forC(*this,c) {
              CImg<T> I(25);
              cimg_for_in5x5(*this,2,2,w3,h3,x,y,0,c,I,T)
                res(x,y,c) = cimg::median(I[0],I[1],I[2],I[3],I[4],
                                          I[5],I[6],I[7],I[8],I[9],
                                          I[10],I[11],I[12],I[13],I[14],
                                          I[15],I[16],I[17],I[18],I[19],
                                          I[20],I[21],I[22],I[23],I[24]);
              cimg_for_borderXY(*this,x,y,2)
                res(x,y,c) = get_crop(std::max(0,x - 2),std::max(0,y - 2),0,c,
                                      std::min(w1,x + 2),std::min(h1,y + 2),0,c).median();
            }
          } break;
          case 7 : {
            cimg_pragma_openmp(parallel for cimg_openmp_if(_spectrum>=2))
            cimg_forC(*this,c) {
              CImg<T> I(49);
              cimg_for_in7x7(*this,3,3,w4,h4,x,y,0,c,I,T)
                res(x,y,c) = cimg::median(I[0],I[1],I[2],I[3],I[4],I[5],I[6],
                                          I[7],I[8],I[9],I[10],I[11],I[12],I[13],
                                          I[14],I[15],I[16],I[17],I[18],I[19],I[20],
                                          I[21],I[22],I[23],I[24],I[25],I[26],I[27],
                                          I[28],I[29],I[30],I[31],I[32],I[33],I[34],
                                          I[35],I[36],I[37],I[38],I[39],I[40],I[41],
                                          I[42],I[43],I[44],I[45],I[46],I[47],I[48]);
              cimg_for_borderXY(*this,x,y,3)
                res(x,y,c) = get_crop(std::max(0,x - 3),std::max(0,y - 3),0,c,
                                      std::min(w1,x + 3),std::min(h1,y + 3),0,c).median();
            }
          } break;
          default : {
            cimg_pragma_openmp(parallel for cimg_openmp_collapse(2)
                               cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*16 && _height*_spectrum>=4))
            cimg_forXYC(*this,x,y,c) {
              const int
                x0 = x - hl, y0 = y - hl, x1 = x + hr, y1 = y + hr,
                nx0 = x0<0?0:x0, ny0 = y0<0?0:y0,
                                          nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1;
              res(x,y,c) = get_crop(nx0,ny0,0,c,nx1,ny1,0,c).median();
            }
          }
          }
        }
      }
      return res;

Project: CImg
File: CImg.h

    template<typename tp, typename tc, typename to>
    unsigned int _size_object3dtoCImg3d(const CImgList<tp>& primitives,
                                        const CImgList<tc>& colors,
                                        const CImgList<to>& opacities) const {
      unsigned int siz = 8U + 3*_width;
      cimglist_for(primitives,p) siz+=primitives[p].size() + 1;
      for (int c = std::min(primitives.width(),colors.width()) - 1; c>=0; --c) {
        if (colors[c].is_shared()) siz+=4;
        else { const unsigned int csiz = colors[c].size(); siz+=(csiz!=3)?4 + csiz:3; }
      }
      if (colors._width<primitives._width) siz+=3*(primitives._width - colors._width);
      cimglist_for(opacities,o) {
        if (opacities[o].is_shared()) siz+=4;
        else { const unsigned int osiz = opacities[o].size(); siz+=(osiz!=1)?4 + osiz:1; }
      }
      siz+=primitives._width - opacities._width;
      return siz;

Project: CImg
File: CImg.h

    // Lock/unlock mutex for CImg multi-thread programming.
    inline int mutex(const unsigned int n, const int lock_mode) {
      switch (lock_mode) {
      case 0 : cimg::Mutex_attr().unlock(n); return 0;
      case 1 : cimg::Mutex_attr().lock(n); return 0;
      default : return cimg::Mutex_attr().trylock(n);
      }

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


      static double mp_ceil(_cimg_math_parser& mp) {
        return std::ceil(_mp_arg(2));

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    //! Save image as a PNM file \overloading.
    const CImg<T>& save_pnm(std::FILE *const file, const unsigned int bytes_per_pixel=0) const {
      return _save_pnm(file,0,bytes_per_pixel);

Project: CImg
File: CImg.h

    **/
    CImg<T>& load_graphicsmagick_external(const char *const filename) {
      if (!filename)
        throw CImgArgumentException(_cimg_instance
                                    "load_graphicsmagick_external(): Specified filename is (null).",
                                    cimg_instance);
      cimg::fclose(cimg::fopen(filename,"rb")); // Check if file exists
      CImg<charT> command(1024), filename_tmp(256);
      std::FILE *file = 0;
      const CImg<charT> s_filename = CImg<charT>::string(filename)._system_strescape();
#if cimg_OS==1
      if (!cimg::system("which gm")) {
        cimg_snprintf(command,command._width,"%s convert \"%s\" pnm:-",
                      cimg::graphicsmagick_path(),s_filename.data());
        file = popen(command,"r");
        if (file) {
          const unsigned int omode = cimg::exception_mode();
          cimg::exception_mode(0);
          try { load_pnm(file); } catch (...) {
            pclose(file);
            cimg::exception_mode(omode);
            throw CImgIOException(_cimg_instance
                                  "load_graphicsmagick_external(): Failed to load file '%s' "
                                  "with external command 'gm'.",
                                  cimg_instance,
                                  filename);
          }
          pclose(file);
          return *this;
        }
      }
#endif
      do {
        cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.pnm",
                      cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
        if ((file=cimg::std_fopen(filename_tmp,"rb"))!=0) cimg::fclose(file);
      } while (file);
      cimg_snprintf(command,command._width,"%s convert \"%s\" \"%s\"",
                    cimg::graphicsmagick_path(),s_filename.data(),
                    CImg<charT>::string(filename_tmp)._system_strescape().data());
      cimg::system(command,cimg::graphicsmagick_path());
      if (!(file=cimg::std_fopen(filename_tmp,"rb"))) {
        cimg::fclose(cimg::fopen(filename,"r"));
        throw CImgIOException(_cimg_instance
                              "load_graphicsmagick_external(): Failed to load file '%s' with external command 'gm'.",
                              cimg_instance,
                              filename);

      } else cimg::fclose(file);
      load_pnm(filename_tmp);
      std::remove(filename_tmp);
      return *this;

Project: CImg
File: CImg.h

    **/
    static const CImg<Tuchar>& hot_LUT256() {
      static CImg<Tuchar> colormap;
      cimg::mutex(8);
      if (!colormap) {
        colormap.assign(1,4,1,3,(T)0);
        colormap[1] = colormap[2] = colormap[3] = colormap[6] = colormap[7] = colormap[11] = 255;
        colormap.resize(1,256,1,3,3);
      }
      cimg::mutex(8,0);
      return colormap;

Project: CImg
File: CImg.h

    //! Test if image width is equal to specified value.
    bool is_sameX(const CImgDisplay& disp) const {
      return is_sameX(disp._width);

Project: CImg
File: CImg.h

      // Insert constant value in memory.
      unsigned int constant(const double val) {

        // Search for built-in constant.
        if (cimg::type<double>::is_nan(val)) return _cimg_mp_slot_nan;
        if (val==(double)(int)val) {
          if (val>=0 && val<=10) return (unsigned int)val;
          if (val<0 && val>=-5) return (unsigned int)(10 - val);
        }
        if (val==0.5) return 16;

        // Search for constant already requested before (in const cache).
        unsigned int ind = ~0U;
        if (constcache_size<1024) {
          if (!constcache_size) {
            constcache_vals.assign(16,1,1,1,0);
            constcache_inds.assign(16,1,1,1,0);
            *constcache_vals = val;
            constcache_size = 1;
            ind = 0;
          } else { // Dichotomic search
            const double val_beg = *constcache_vals, val_end = constcache_vals[constcache_size - 1];
            if (val_beg>=val) ind = 0;
            else if (val_end==val) ind = constcache_size - 1;
            else if (val_end<val) ind = constcache_size;
            else {
              unsigned int i0 = 1, i1 = constcache_size - 2;
              while (i0<=i1) {
                const unsigned int mid = (i0 + i1)/2;
                if (constcache_vals[mid]==val) { i0 = mid; break; }
                else if (constcache_vals[mid]<val) i0 = mid + 1;
                else i1 = mid - 1;
              }
              ind = i0;
            }

            if (ind>=constcache_size || constcache_vals[ind]!=val) {
              ++constcache_size;
              if (constcache_size>constcache_vals._width) {
                constcache_vals.resize(-200,1,1,1,0);
                constcache_inds.resize(-200,1,1,1,0);
              }
              const int l = constcache_size - (int)ind - 1;
              if (l>0) {
                std::memmove(&constcache_vals[ind + 1],&constcache_vals[ind],l*sizeof(double));
                std::memmove(&constcache_inds[ind + 1],&constcache_inds[ind],l*sizeof(unsigned int));
              }
              constcache_vals[ind] = val;
              constcache_inds[ind] = 0;
            }
          }
          if (constcache_inds[ind]) return constcache_inds[ind];
        }

        // Insert new constant in memory if necessary.
        if (mempos>=mem._width) { mem.resize(-200,1,1,1,0); memtype.resize(-200,1,1,1,0); }
        const unsigned int pos = mempos++;
        mem[pos] = val;
        memtype[pos] = 1; // Set constant property
        if (ind!=~0U) constcache_inds[ind] = pos;
        return pos;

Project: CImg
File: CImg.h

      static const char* format_s() { return "%s"; }

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_triangle(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 (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(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);
          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,
              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;
          }
        }
      }
      return *this;

Project: CImg
File: CImg.h

    //! Construct list from another list \specialization.
    CImgList<T>& operator=(const CImgList<T>& list) {
      return assign(list);

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

    template<typename tc, typename t>
    CImg<T>& draw_fill(const int x0, const int y0, const int z0,
                        const tc *const color, const float opacity,
                        CImg<t> &region,
                        const float tolerance = 0,
                        const bool is_high_connectivity = false) {
#define _draw_fill_push(x,y,z) if (N>=stack._width) stack.resize(2*N + 1,1,1,3,0); \
                               stack[N] = x; stack(N,1) = y; stack(N++,2) = z
#define _draw_fill_pop(x,y,z) x = stack[--N]; y = stack(N,1); z = stack(N,2)
#define _draw_fill_is_inside(x,y,z) !_region(x,y,z) && _draw_fill(x,y,z,ref,tolerance2)

      if (!containsXYZC(x0,y0,z0,0)) return *this;
      const float nopacity = cimg::abs((float)opacity), copacity = 1 - std::max((float)opacity,0.f);
      const float tolerance2 = cimg::sqr(tolerance);
      const CImg<T> ref = get_vector_at(x0,y0,z0);
      CImg<uintT> stack(256,1,1,3);
      CImg<ucharT> _region(_width,_height,_depth,1,0);
      unsigned int N = 0;
      int x, y, z;

      _draw_fill_push(x0,y0,z0);
      while (N>0) {
        _draw_fill_pop(x,y,z);
        if (!_region(x,y,z)) {
          const int yp = y - 1, yn = y + 1, zp = z - 1, zn = z + 1;
          int xl = x, xr = x;

          // Using these booleans reduces the number of pushes drastically.
          bool is_yp = false, is_yn = false, is_zp = false, is_zn = false;
          for (int step = -1; step<2; step+=2) {
            while (x>=0 && x<width() && _draw_fill_is_inside(x,y,z)) {
              if (yp>=0 && _draw_fill_is_inside(x,yp,z)) {
                if (!is_yp) { _draw_fill_push(x,yp,z); is_yp = true; }
              } else is_yp = false;
              if (yn<height() && _draw_fill_is_inside(x,yn,z)) {
                if (!is_yn) { _draw_fill_push(x,yn,z); is_yn = true; }
              } else is_yn = false;
              if (depth()>1) {
                if (zp>=0 && _draw_fill_is_inside(x,y,zp)) {
                  if (!is_zp) { _draw_fill_push(x,y,zp); is_zp = true; }
                } else is_zp = false;
                if (zn<depth() && _draw_fill_is_inside(x,y,zn)) {
                  if (!is_zn) { _draw_fill_push(x,y,zn); is_zn = true; }
                } else is_zn = false;
              }
              if (is_high_connectivity) {
                const int xp = x - 1, xn = x + 1;
                if (yp>=0 && !is_yp) {
                  if (xp>=0 && _draw_fill_is_inside(xp,yp,z)) {
                    _draw_fill_push(xp,yp,z); if (step<0) is_yp = true;
                  }
                  if (xn<width() && _draw_fill_is_inside(xn,yp,z)) {
                    _draw_fill_push(xn,yp,z); if (step>0) is_yp = true;
                  }
                }
                if (yn<height() && !is_yn) {
                  if (xp>=0 && _draw_fill_is_inside(xp,yn,z)) {
                    _draw_fill_push(xp,yn,z); if (step<0) is_yn = true;
                  }
                  if (xn<width() && _draw_fill_is_inside(xn,yn,z)) {
                    _draw_fill_push(xn,yn,z); if (step>0) is_yn = true;
                  }
                }
                if (depth()>1) {
                  if (zp>=0 && !is_zp) {
                    if (xp>=0 && _draw_fill_is_inside(xp,y,zp)) {
                      _draw_fill_push(xp,y,zp); if (step<0) is_zp = true;
                    }
                    if (xn<width() && _draw_fill_is_inside(xn,y,zp)) {
                      _draw_fill_push(xn,y,zp); if (step>0) is_zp = true;
                    }

                    if (yp>=0 && !is_yp) {
                      if (_draw_fill_is_inside(x,yp,zp)) { _draw_fill_push(x,yp,zp); }
                      if (xp>=0 && _draw_fill_is_inside(xp,yp,zp)) { _draw_fill_push(xp,yp,zp); }
                      if (xn<width() && _draw_fill_is_inside(xn,yp,zp)) { _draw_fill_push(xn,yp,zp); }
                    }
                    if (yn<height() && !is_yn) {
                      if (_draw_fill_is_inside(x,yn,zp)) { _draw_fill_push(x,yn,zp); }
                      if (xp>=0 && _draw_fill_is_inside(xp,yn,zp)) { _draw_fill_push(xp,yn,zp); }
                      if (xn<width() && _draw_fill_is_inside(xn,yn,zp)) { _draw_fill_push(xn,yn,zp); }
                    }
                  }

                  if (zn<depth() && !is_zn) {
                    if (xp>=0 && _draw_fill_is_inside(xp,y,zn)) {
                      _draw_fill_push(xp,y,zn); if (step<0) is_zn = true;
                    }
                    if (xn<width() && _draw_fill_is_inside(xn,y,zn)) {
                      _draw_fill_push(xn,y,zn); if (step>0) is_zn = true;
                    }

                    if (yp>=0 && !is_yp) {
                      if (_draw_fill_is_inside(x,yp,zn)) { _draw_fill_push(x,yp,zn); }
                      if (xp>=0 && _draw_fill_is_inside(xp,yp,zn)) { _draw_fill_push(xp,yp,zn); }
                      if (xn<width() && _draw_fill_is_inside(xn,yp,zn)) { _draw_fill_push(xn,yp,zn); }
                    }
                    if (yn<height() && !is_yn) {
                      if (_draw_fill_is_inside(x,yn,zn)) { _draw_fill_push(x,yn,zn); }
                      if (xp>=0 && _draw_fill_is_inside(xp,yn,zn)) { _draw_fill_push(xp,yn,zn); }
                      if (xn<width() && _draw_fill_is_inside(xn,yn,zn)) { _draw_fill_push(xn,yn,zn); }
                    }
                  }
                }
              }
              x+=step;
            }
            if (step<0) { xl = ++x; x = xr + 1; is_yp = is_yn = is_zp = is_zn = false; }
            else xr = --x;
          }
          std::memset(_region.data(xl,y,z),1,xr - xl + 1);
          if (opacity==1) {
            if (sizeof(T)==1) {
              const int dx = xr - xl + 1;
              cimg_forC(*this,c) std::memset(data(xl,y,z,c),(int)color[c],dx);
            } else cimg_forC(*this,c) {
                const T val = (T)color[c];
                T *ptri = data(xl,y,z,c); for (int k = xl; k<=xr; ++k) *(ptri++) = val;
              }
          } else cimg_forC(*this,c) {
              const T val = (T)(color[c]*nopacity);
              T *ptri = data(xl,y,z,c); for (int k = xl; k<=xr; ++k) { *ptri = (T)(val + *ptri*copacity); ++ptri; }
            }
        }
      }
      _region.move_to(region);
      return *this;

Project: CImg
File: CImg.h


    static longT _distance_sep_cdt(const longT i, const longT u, const longT *const g) {
      const longT h = (i + u)/2;
      if (g[i]<=g[u]) { return h<i + g[u]?i + g[u]:h; }
      return h<u - g[i]?h:u - g[i];

Project: CImg
File: CImg.h

    **/
    CImg<T>& rol(const unsigned int n=1) {
      if (is_empty()) return *this;
      cimg_openmp_for(*this,cimg::rol(*ptr,n),32768);
      return *this;

Project: CImg
File: CImg.h

    template<typename tx, typename ty, typename tc>
    CImg<T>& draw_axes(const CImg<tx>& values_x, const CImg<ty>& values_y,
                       const tc *const color, const float opacity=1,
                       const unsigned int pattern_x=~0U, const unsigned int pattern_y=~0U,
                       const unsigned int font_height=13, const bool allow_zero=true,
                       const float round_x=0, const float round_y=0) {
      if (is_empty()) return *this;
      const CImg<tx> nvalues_x(values_x._data,values_x.size(),1,1,1,true);
      const int sizx = (int)values_x.size() - 1, wm1 = width() - 1;
      if (sizx>=0) {
        float ox = (float)*nvalues_x;
        for (unsigned int x = sizx?1U:0U; x<_width; ++x) {
          const float nx = (float)nvalues_x._linear_atX((float)x*sizx/wm1);
          if (nx*ox<=0) {
            draw_axis(nx==0?x:x - 1,values_y,color,opacity,pattern_y,font_height,allow_zero,round_y);
            break;
          }
          ox = nx;
        }
      }
      const CImg<ty> nvalues_y(values_y._data,values_y.size(),1,1,1,true);
      const int sizy = (int)values_y.size() - 1, hm1 = height() - 1;
      if (sizy>0) {
        float oy = (float)nvalues_y[0];
        for (unsigned int y = sizy?1U:0U; y<_height; ++y) {
          const float ny = (float)nvalues_y._linear_atX((float)y*sizy/hm1);
          if (ny*oy<=0) {
            draw_axis(values_x,ny==0?y:y - 1,color,opacity,pattern_x,font_height,allow_zero,round_x);
            break;
          }
          oy = ny;
        }
      }
      return *this;

Project: CImg
File: CImg.h

    template<typename T>
    inline T median(T val0, T val1, T val2, T val3, T val4, T val5, T val6) {
      T tmp = std::min(val0,val5);
      val5 = std::max(val0,val5); val0 = tmp; tmp = std::min(val0,val3); val3 = std::max(val0,val3); val0 = tmp;
      tmp = std::min(val1,val6); val6 = std::max(val1,val6); val1 = tmp; tmp = std::min(val2,val4);
      val4 = std::max(val2,val4); val2 = tmp; val1 = std::max(val0,val1); tmp = std::min(val3,val5);
      val5 = std::max(val3,val5); val3 = tmp; tmp = std::min(val2,val6); val6 = std::max(val2,val6);
      val3 = std::max(tmp,val3); val3 = std::min(val3,val6); tmp = std::min(val4,val5); val4 = std::max(val1,tmp);
      tmp = std::min(val1,tmp); val3 = std::max(tmp,val3);
      return std::min(val3,val4);

Project: CImg
File: CImg.h

    template<typename t, typename to>
    static float __draw_object3d(const CImg<t>& opacities, const unsigned int n_primitive, CImg<to>& opacity) {
      opacity.assign();
      return n_primitive>=opacities._width?1.f:(float)opacities[n_primitive];

Project: CImg
File: CImg.h

    //! Wait for any user event occuring on the current display.
    CImgDisplay& wait() {
      wait(*this);
      return *this;

Project: CImg
File: CImg.h


      static double* _mp_memcopy_double(_cimg_math_parser& mp, const unsigned int ind, const ulongT *const p_ref,
                                        const longT siz, const long inc) {
        const longT
          off = *p_ref?p_ref[1] + (longT)mp.mem[(longT)p_ref[2]] + 1:ind,
          eoff = off + (siz - 1)*inc;
        if (off<0 || eoff>=mp.mem.width())
          throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'copy()': "
                                      "Out-of-bounds variable pointer "
                                      "(length: %ld, increment: %ld, offset start: %ld, "
                                      "offset end: %ld, offset max: %u).",
                                      mp.imgin.pixel_type(),siz,inc,off,eoff,mp.mem._width - 1);
        return &mp.mem[off];

Project: CImg
File: CImg.h

      void unlock(const unsigned int n) { pthread_mutex_unlock(&mutex[n]); }

Project: CImg
File: CImg.h


      static double mp_log2(_cimg_math_parser& mp) {
        return cimg::log2(_mp_arg(2));

Project: CImg
File: CImg.h


      static double mp_ror(_cimg_math_parser& mp) {
        return cimg::ror(_mp_arg(2),(unsigned int)_mp_arg(3));

Project: CImg
File: CImg.h

    template<typename tc1, typename tc2>
    CImg<T>& draw_text(const int x0, const int y0,
                       const char *const text,
                       const tc1 *const foreground_color, const tc2 *const background_color,
                       const float opacity=1, const unsigned int font_height=13, ...) {
      if (!font_height) return *this;
      CImg<charT> tmp(2048);
      std::va_list ap; va_start(ap,font_height);
      cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap);
      const CImgList<ucharT>& font = CImgList<ucharT>::font(font_height,true);
      _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font,true);
      return *this;

Project: CImg
File: CImg.h

      // Return type of a memory element as a string.
      CImg<charT> s_type(const unsigned int arg) const {
        CImg<charT> res;
        if (_cimg_mp_is_vector(arg)) { // Vector
          CImg<charT>::string("vectorXXXXXXXXXXXXXXXX").move_to(res);
          cimg_sprintf(res._data + 6,"%u",_cimg_mp_size(arg));
        } else CImg<charT>::string("scalar").move_to(res);
        return res;

Project: CImg
File: CImg.h

    **/
    CImg<T>& resize_doubleXY() {
      return get_resize_doubleXY().move_to(*this);

Project: CImg
File: CImg.h

    **/
    inline int system(const char *const command, const char *const module_name=0, const bool is_verbose=false) {
      cimg::unused(module_name);
#ifdef cimg_no_system_calls
      return -1;
#else
      if (is_verbose) return std::system(command);
#if cimg_OS==1
      const unsigned int l = (unsigned int)std::strlen(command);
      if (l) {
        char *const ncommand = new char[l + 24];
        std::memcpy(ncommand,command,l);
        std::strcpy(ncommand + l," >/dev/null 2>&1"); // Make command silent
        const int out_val = std::system(ncommand);
        delete[] ncommand;
        return out_val;
      } else return -1;
#elif cimg_OS==2
      PROCESS_INFORMATION pi;
      STARTUPINFO si;
      std::memset(&pi,0,sizeof(PROCESS_INFORMATION));
      std::memset(&si,0,sizeof(STARTUPINFO));
      GetStartupInfo(&si);
      si.cb = sizeof(si);
      si.wShowWindow = SW_HIDE;
      si.dwFlags |= SW_HIDE | STARTF_USESHOWWINDOW;
      const BOOL res = CreateProcess((LPCTSTR)module_name,(LPTSTR)command,0,0,FALSE,0,0,0,&si,&pi);
      if (res) {
        WaitForSingleObject(pi.hProcess,INFINITE);
        CloseHandle(pi.hThread);
        CloseHandle(pi.hProcess);
        return 0;
      } else return std::system(command);
#else
      return std::system(command);
#endif
#endif

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& assign(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 size_t siz = (size_t)size_x*size_y*size_z*size_c;
      if (!values || !siz) return assign();
      assign(size_x,size_y,size_z,size_c);
      const t *ptrs = values; cimg_for(*this,ptrd,T) *ptrd = (T)*(ptrs++);
      return *this;

Project: CImg
File: CImg.h

    **/
    Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c=0) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "cubic_atXYZ(): Empty instance.",
                                    cimg_instance);
      return _cubic_atXYZ(fx,fy,fz,c);

Project: CImg
File: CImg.h

    template<typename t, typename tc>
    CImg<T>& draw_polygon(const CImg<t>& points,
                          const tc *const color, const float opacity, const unsigned int pattern) {
      if (is_empty() || !points) return *this;
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_polygon(): Specified color is (null).",
                                    cimg_instance);
      if (points._width==1) return draw_point((int)points(0,0),(int)points(0,1),color,opacity);
      if (points._width==2) return draw_line((int)points(0,0),(int)points(0,1),
                                             (int)points(1,0),(int)points(1,1),color,opacity,pattern);
      bool ninit_hatch = true;
      switch (points._height) {
      case 0 : case 1 :
        throw CImgArgumentException(_cimg_instance
                                    "draw_polygon(): Invalid specified point set (%u,%u,%u,%u).",
                                    cimg_instance,
                                    points._width,points._height,points._depth,points._spectrum);
      default : {
        CImg<intT> npoints(points._width,2);
        int x = npoints(0,0) = (int)points(0,0), y = npoints(0,1) = (int)points(0,1);
        unsigned int nb_points = 1;
        for (unsigned int p = 1; p<points._width; ++p) {
          const int nx = (int)points(p,0), ny = (int)points(p,1);
          if (nx!=x || ny!=y) { npoints(nb_points,0) = nx; npoints(nb_points++,1) = ny; x = nx; y = ny; }
        }
        const int x0 = (int)npoints(0,0), y0 = (int)npoints(0,1);
        int ox = x0, oy = y0;
        for (unsigned int i = 1; i<nb_points; ++i) {
          const int _x = (int)npoints(i,0), _y = (int)npoints(i,1);
          draw_line(ox,oy,_x,_y,color,opacity,pattern,ninit_hatch);
          ninit_hatch = false;
          ox = _x; oy = _y;
        }
        draw_line(ox,oy,x0,y0,color,opacity,pattern,false);
      }
      }
      return *this;

Project: CImg
File: CImg.h

    //! Load image from a PNG file \newinstance.
    static CImg<T> get_load_png(const char *const filename, unsigned int *const bits_per_pixel=0) {
      return CImg<T>().load_png(filename,bits_per_pixel);

Project: CImg
File: CImg.h

    template<typename T>
    const CImgDisplay& snapshot(CImg<T>& img) const {
      if (is_empty()) { img.assign(); return *this; }
      const unsigned char *ptrs = (unsigned char*)_data;
      img.assign(_width,_height,1,3);
      T
        *data1 = img.data(0,0,0,0),
        *data2 = img.data(0,0,0,1),
        *data3 = img.data(0,0,0,2);
      if (cimg::X11_attr().is_blue_first) cimg::swap(data1,data3);
      switch (cimg::X11_attr().nb_bits) {
      case 8 : {
        for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
          const unsigned char val = *(ptrs++);
          *(data1++) = (T)(val&0xe0);
          *(data2++) = (T)((val&0x1c)<<3);
          *(data3++) = (T)(val<<6);
        }
      } break;
      case 16 : {
        if (cimg::X11_attr().byte_order) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
          const unsigned char
            val0 = ptrs[0],
            val1 = ptrs[1];
          ptrs+=2;
          *(data1++) = (T)(val0&0xf8);
          *(data2++) = (T)((val0<<5) | ((val1&0xe0)>>5));
          *(data3++) = (T)(val1<<3);
          } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
          const unsigned short
            val0 = ptrs[0],
            val1 = ptrs[1];
          ptrs+=2;
          *(data1++) = (T)(val1&0xf8);
          *(data2++) = (T)((val1<<5) | ((val0&0xe0)>>5));
          *(data3++) = (T)(val0<<3);
        }
      } break;
      default : {
        if (cimg::X11_attr().byte_order) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
          ++ptrs;
          *(data1++) = (T)ptrs[0];
          *(data2++) = (T)ptrs[1];
          *(data3++) = (T)ptrs[2];
          ptrs+=3;
          } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
            *(data3++) = (T)ptrs[0];
            *(data2++) = (T)ptrs[1];
            *(data1++) = (T)ptrs[2];
            ptrs+=3;
            ++ptrs;
          }
      }
      }
      return *this;

Project: CImg
File: CImg.h

    template<typename T>
    const CImgDisplay& snapshot(CImg<T>& img) const {
      if (is_empty()) { img.assign(); return *this; }
      const unsigned int *ptrs = _data;
      img.assign(_width,_height,1,3);
      T
        *data1 = img.data(0,0,0,0),
        *data2 = img.data(0,0,0,1),
        *data3 = img.data(0,0,0,2);
      for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
        const unsigned int val = *(ptrs++);
        *(data1++) = (T)(unsigned char)(val>>16);
        *(data2++) = (T)(unsigned char)((val>>8)&0xFF);
        *(data3++) = (T)(unsigned char)(val&0xFF);
      }
      return *this;

Project: CImg
File: CImg.h

    **/
    CImg<T>& load_analyze(const char *const filename, float *const voxel_size=0) {
      return _load_analyze(0,filename,voxel_size);

Project: CImg
File: CImg.h

    **/
    bool is_sameXYC(const unsigned int size_x, const unsigned int size_y, const unsigned int size_c) const {
      return is_sameXY(size_x,size_y) && _spectrum==size_c;

Project: CImg
File: CImg.h

    //! Cut pixel values in specified range \newinstance.
    CImg<T> get_cut(const T& min_value, const T& max_value) const {
      return (+*this).cut(min_value,max_value);

Project: CImg
File: CImg.h

    template<typename tc1, typename tc2, typename t>
    CImg<T>& _draw_text(const int x0, const int y0,
                        const char *const text,
                        const tc1 *const foreground_color, const tc2 *const background_color,
                        const float opacity, const CImgList<t>& font,
                        const bool is_native_font) {
      if (!text) return *this;
      if (!font)
        throw CImgArgumentException(_cimg_instance
                                    "draw_text(): Empty specified font.",
                                    cimg_instance);

      const unsigned int text_length = (unsigned int)std::strlen(text);
      if (is_empty()) {
        // If needed, pre-compute necessary size of the image
        int x = 0, y = 0, w = 0;
        unsigned char c = 0;
        for (unsigned int i = 0; i<text_length; ++i) {
          c = (unsigned char)text[i];
          switch (c) {
          case '\n' : y+=font[0]._height; if (x>w) w = x; x = 0; break;
          case '\t' : x+=4*font[(int)' ']._width; break;
          default : if (c<font._width) x+=font[c]._width;
          }
        }
        if (x!=0 || c=='\n') {
          if (x>w) w=x;
          y+=font[0]._height;
        }
        assign(x0 + w,y0 + y,1,is_native_font?1:font[0]._spectrum,(T)0);
      }

      int x = x0, y = y0;
      for (unsigned int i = 0; i<text_length; ++i) {
        const unsigned char ch = (unsigned char)text[i];
        switch (ch) {
        case '\n' : y+=font[0]._height; x = x0; break;
        case '\t' : x+=4*font[(int)' ']._width; break;
        default : if (ch<font._width) {
            CImg<T> letter = font[ch];
            if (letter) {
              if (is_native_font && _spectrum>letter._spectrum) letter.resize(-100,-100,1,_spectrum,0,2);
              const unsigned int cmin = std::min(_spectrum,letter._spectrum);
              if (foreground_color)
                for (unsigned int c = 0; c<cmin; ++c)
                  if (foreground_color[c]!=1) letter.get_shared_channel(c)*=foreground_color[c];
              if (ch + 256<font.width()) { // Letter has mask
                if (background_color)
                  for (unsigned int c = 0; c<cmin; ++c)
                    draw_rectangle(x,y,0,c,x + letter._width - 1,y + letter._height - 1,0,c,
                                   background_color[c],opacity);
                draw_image(x,y,letter,font[ch + 256],opacity,255.f);
              } else draw_image(x,y,letter,opacity); // Letter has no mask
              x+=letter._width;
            }
          }
        }
      }
      return *this;

Project: CImg
File: CImg.h

    //! Return a reference to an empty display \const.
    static const CImgDisplay& const_empty() {
      static const CImgDisplay _empty;
      return _empty;

Project: CImg
File: CImg.h

    template<typename tc, typename t>
    CImg<T>& draw_text(const int x0, const int y0,
                       const char *const text,
                       const tc *const foreground_color, const int,
                       const float opacity, const CImgList<t>& font, ...) {
      if (!font) return *this;
      CImg<charT> tmp(2048);
      std::va_list ap; va_start(ap,font);
      cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap);
      return _draw_text(x0,y0,tmp,foreground_color,(tc*)0,opacity,font,false);

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_triangle(int x0, int y0,
                           int x1, int y1,
                           int x2, int y2,
                           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()) return *this;
      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(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness);

      if (y0>y1) cimg::swap(x0,x1,y0,y1,tx0,tx1,ty0,ty1);
      if (y0>y2) cimg::swap(x0,x2,y0,y2,tx0,tx2,ty0,ty2);
      if (y1>y2) cimg::swap(x1,x2,y1,y2,tx1,ty1,tx2,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,
        dtx01 = tx1 - tx0, dtx02 = tx2 - tx0, dtx12 = tx2 - tx1,
        dty01 = ty1 - ty0, dty02 = ty2 - ty0, dty12 = ty2 - ty1,
        hdy01tx = dy01*cimg::sign(dtx01)/2, hdy02tx = dy02*cimg::sign(dtx02)/2, hdy12tx = dy12*cimg::sign(dtx12)/2,
        hdy01ty = dy01*cimg::sign(dty01)/2, hdy02ty = dy02*cimg::sign(dty02)/2, hdy12ty = dy12*cimg::sign(dty12)/2;
      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,
          txm = y<y1?tx0 + (dtx01*yy0 + hdy01tx)/dy01:tx1 + (dtx12*yy1 + hdy12tx)/dy12,
          txM = tx0 + (dtx02*yy0 + hdy02tx)/dy02,
          tym = y<y1?ty0 + (dty01*yy0 + hdy01ty)/dy01:ty1 + (dty12*yy1 + hdy12ty)/dy12,
          tyM = ty0 + (dty02*yy0 + hdy02ty)/dy02;
        if (xm>xM) cimg::swap(xm,xM,txm,txM,tym,tyM);
        if (xM>=0 || xm<=w1) {
          const int
            cxm = cimg::cut(xm,0,w1),
            cxM = cimg::cut(xM,0,w1);
          T *ptrd = data(cxm,y);
          const int
            dxmM = std::max(1,xM - xm), hdxmM = dxmM/2,
            dtxmM = txM - txm, dtymM = tyM - tym;

          for (int x = cxm; x<=cxM; ++x) {
            const int
              xxm = x - xm,
              tx = (txm*dxmM + dtxmM*xxm + hdxmM)/dxmM,
              ty = (tym*dxmM + dtymM*xxm + hdxmM)/dxmM;
            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;
          }
        }
      }
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


      static double mp_isbool(_cimg_math_parser& mp) {
        const double val = _mp_arg(2);
        return (double)(val==0. || val==1.);

Project: CImg
File: CImg.h

      static half inf() { return max()*max(); }

Project: CImg
File: CImg.h

    //! Compute image Laplacian \newinstance.
    CImg<Tfloat> get_laplacian() const {
      if (is_empty()) return CImg<Tfloat>();
      CImg<Tfloat> res(_width,_height,_depth,_spectrum);
      if (_depth>1) { // 3D
        cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height*_depth>=(cimg_openmp_sizefactor)*1048576 &&
                                                       _spectrum>=2))
        cimg_forC(*this,c) {
          Tfloat *ptrd = res.data(0,0,0,c);
          CImg_3x3x3(I,Tfloat);
          cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = Incc + Ipcc + Icnc + Icpc + Iccn + Iccp - 6*Iccc;
        }
      } else if (_height>1) { // 2D
        cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height>=(cimg_openmp_sizefactor)*1048576 &&
                                                       _depth*_spectrum>=2))
        cimg_forC(*this,c) {
          Tfloat *ptrd = res.data(0,0,0,c);
          CImg_3x3(I,Tfloat);
          cimg_for3x3(*this,x,y,0,c,I,Tfloat) *(ptrd++) = Inc + Ipc + Icn + Icp - 4*Icc;
        }
      } else { // 1D
        cimg_pragma_openmp(parallel for cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*1048576 &&
                                                       _height*_depth*_spectrum>=2))
        cimg_forC(*this,c) {
          Tfloat *ptrd = res.data(0,0,0,c);
          CImg_3x3(I,Tfloat);
          cimg_for3x3(*this,x,y,0,c,I,Tfloat) *(ptrd++) = Inc + Ipc - 2*Icc;
        }
      }
      return res;

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T> get_watershed(const CImg<t>& priority, const bool is_high_connectivity=false) const {
      return (+*this).watershed(priority,is_high_connectivity);

Project: CImg
File: CImg.h

    **/
    CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,
                        const unsigned int depth, const unsigned int spectrum, const int val0, const int val1, ...) {
      _CImgList_stdarg(int);
      return *this;

Project: CImg
File: CImg.h

    }
    inline int mod(const short x, const short m) {
      return x>=0?x%m:(x%m?m + x%m:0);

Project: CImg
File: CImg.h

    **/
    inline int strcasecmp(const char *const str1, const char *const str2) {
      if (!str1) return str2?-1:0;
      const int
        l1 = (int)std::strlen(str1),
        l2 = (int)std::strlen(str2);
      return cimg::strncasecmp(str1,str2,1 + (l1<l2?l1:l2));

Project: CImg
File: CImg.h

      }
      float operator()(const float x, const float y, const float z) const {
        return (float)(*mp)(x,y,z,0);

Project: CImg
File: CImg.h

    **/
    iterator begin() {
      return _data;

Project: CImg
File: CImg.h

    **/
    CImg<T>& blur_box(const float boxsize_x, const float boxsize_y, const float boxsize_z,
                      const bool boundary_conditions=true,
                      const unsigned int nb_iter=1) {
      if (is_empty()) return *this;
      if (_width>1) boxfilter(boxsize_x,0,'x',boundary_conditions,nb_iter);
      if (_height>1) boxfilter(boxsize_y,0,'y',boundary_conditions,nb_iter);
      if (_depth>1) boxfilter(boxsize_z,0,'z',boundary_conditions,nb_iter);
      return *this;

Project: CImg
File: CImg.h

    **/
    bool is_sameXZC(const unsigned int size_x, const unsigned int size_z, const unsigned int size_c) const {
      return is_sameXZ(size_x,size_z) && _spectrum==size_c;

Project: CImg
File: CImg.h


      static double mp_lowercase(_cimg_math_parser& mp) {
        return cimg::lowercase(_mp_arg(2));

Project: CImg
File: CImg.h

    template<typename T>
    inline T sign(const T& x) {
      return (T)(cimg::type<T>::is_nan(x)?0:x<0?-1:x>0);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<Tfloat> get_blur_anisotropic(const CImg<t>& G,
                                      const float amplitude=60, const float dl=0.8f, const float da=30,
                                      const float gauss_prec=2, const unsigned int interpolation_type=0,
                                      const bool is_fast_approx=true) const {
      return CImg<Tfloat>(*this,false).blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,is_fast_approx);

Project: CImg
File: CImg.h

    //! Return a 3x3 symmetric matrix containing specified coefficients.
    static CImg<T> tensor(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5) {
      return matrix(a0,a1,a2,a1,a3,a4,a2,a4,a5);

Project: CImg
File: CImg.h

    //! Convert pixel values from xyY pixels to XYZ color spaces \newinstance.
    CImg<Tfloat> get_xyYtoXYZ() const {
      return CImg<Tfloat>(*this,false).xyYtoXYZ();

Project: CImg
File: CImg.h

    **/
    explicit CImgList(const char *const filename):_width(0),_allocated_width(0),_data(0) {
      assign(filename);

Project: CImg
File: CImg.h

    template<typename T>
    inline void sgels(char & TRANS, int &M, int &N, int &NRHS, T* lapA, int &LDA,
		      T* lapB, int &LDB, T* WORK, int &LWORK, int &INFO){
      dgels_(&TRANS, &M, &N, &NRHS, lapA, &LDA, lapB, &LDB, WORK, &LWORK, &INFO);

Project: CImg
File: CImg.h

     **/
    CImg<T>& invert_endianness() {
      cimg::invert_endianness(_data,size());
      return *this;

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

    template<typename tp, typename tc>
    CImg<T>& object3dtoCImg3d(const CImgList<tp>& primitives,
                              const CImgList<tc>& colors,
                              const bool full_check=true) {
      return get_object3dtoCImg3d(primitives,colors,full_check).move_to(*this);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


    CImgDisplay& assign() {
      if (is_empty()) return flush();
      DestroyWindow(_window);
      TerminateThread(_thread,0);
      delete[] _data;
      delete[] _title;
      _data = 0;
      _title = 0;
      if (_is_fullscreen) _desinit_fullscreen();
      _width = _height = _normalization = _window_width = _window_height = 0;
      _window_x = _window_y = 0;
      _is_fullscreen = false;
      _is_closed = true;
      _min = _max = 0;
      _title = 0;
      flush();
      return *this;

Project: CImg
File: CImg.h

    template<typename t>
    CImg(const unsigned int size_x, const unsigned int size_y,
         std::initializer_list<t> values,
	 const bool repeat_values=true):
      _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
      assign(size_x,size_y);
      _cimg_constructor_cpp11(repeat_values);

Project: CImg
File: CImg.h


    CImgDisplay& toggle_fullscreen(const bool force_redraw=true) {
      if (is_empty()) return *this;
      if (force_redraw) {
        const cimg_ulong buf_size = (cimg_ulong)_width*_height*4;
        void *odata = std::malloc(buf_size);
        if (odata) {
          std::memcpy(odata,_data,buf_size);
          assign(_width,_height,_title,_normalization,!_is_fullscreen,false);
          std::memcpy(_data,odata,buf_size);
          std::free(odata);
        }
        return paint();
      }
      return assign(_width,_height,_title,_normalization,!_is_fullscreen,false);

Project: CImg
File: CImg.h

                       first_frame,last_frame,step_frame,yuv2rgb);
    }

    //! Load a list from a YUV image sequence file \newinstance.
    static CImgList<T> get_load_yuv(const char *const filename,
                                    const unsigned int size_x, const unsigned int size_y=1,
                                    const unsigned int chroma_subsampling=444,
                                    const unsigned int first_frame=0, const unsigned int last_frame=~0U,

Project: CImg
File: CImg.h


    inline void srand(cimg_ulong *const p_rng) {
#if cimg_OS==1
      *p_rng = cimg::time() + (cimg_ulong)getpid();
#elif cimg_OS==2
      *p_rng = cimg::time() + (cimg_ulong)_getpid();
#endif

Project: CImg
File: CImg.h


      static double mp_self_bitwise_or(_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 mp_solve(_cimg_math_parser& mp) {
        double *ptrd = &_mp_arg(1) + 1;
        const double
          *ptr1 = &_mp_arg(2) + 1,
          *ptr2 = &_mp_arg(3) + 1;
        const unsigned int
          k = (unsigned int)mp.opcode[4],
          l = (unsigned int)mp.opcode[5],
          m = (unsigned int)mp.opcode[6];
        CImg<doubleT>(ptrd,m,k,1,1,true) = CImg<doubleT>(ptr2,m,l,1,1,true).get_solve(CImg<doubleT>(ptr1,k,l,1,1,true));
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

    //! Fill sequentially all pixel values with specified values \overloading.
    CImg<T>& 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) {
      if (is_empty()) return *this;
      T *ptrd, *ptre = end() - 7;
      for (ptrd = _data; ptrd<ptre; ) {
        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3;
        *(ptrd++) = val4; *(ptrd++) = val5; *(ptrd++) = val6; *(ptrd++) = val7;
      }
      ptre+=7;
      switch (ptre - ptrd) {
      case 7 : *(--ptre) = val6; // fallthrough
      case 6 : *(--ptre) = val5; // fallthrough
      case 5 : *(--ptre) = val4; // fallthrough
      case 4 : *(--ptre) = val3; // fallthrough
      case 3 : *(--ptre) = val2; // fallthrough
      case 2 : *(--ptre) = val1; // fallthrough
      case 1 : *(--ptre) = val0; // fallthrough
      }
      return *this;

Project: CImg
File: CImg.h

    template<typename t>
    T& min_max(t& max_val) {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "min_max(): Empty instance.",
                                    cimg_instance);
      T *ptr_min = _data;
      T min_value = *ptr_min, max_value = min_value;
      cimg_for(*this,ptrs,T) {
        const T val = *ptrs;
        if (val<min_value) { min_value = val; ptr_min = ptrs; }
        if (val>max_value) max_value = val;
      }
      max_val = (t)max_value;
      return *ptr_min;

Project: CImg
File: CImg.h

    template<typename t1, typename t2, typename t3, typename t4>
    CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
                        const bool is_shared=false) {
      assign(4);
      _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared);
      _data[3].assign(img4,is_shared);
      return *this;

Project: CImg
File: CImg.h

    //! Convert pixel values from HSI to RGB color spaces.
    CImg<T>& HSItoRGB() {
      if (_spectrum!=3)
        throw CImgInstanceException(_cimg_instance
                                    "HSItoRGB(): Instance is not a HSI image.",
                                    cimg_instance);

      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,256))
      for (longT N = 0; N<whd; ++N) {
        const Tfloat
          H = cimg::mod((Tfloat)p1[N]/60,(Tfloat)6),
          S = (Tfloat)p2[N],
          I = (Tfloat)p3[N],
          Z = 1 - cimg::abs(cimg::mod(H,(Tfloat)2) - 1),
          C = I*S/(1 + Z),
          X = C*Z,
          m = I*(1 - S)/3;
        Tfloat R, G, B;
        switch ((int)H) {
        case 0 : R = C; G = X; B = 0; break;
        case 1 : R = X; G = C; B = 0; break;
        case 2 : R = 0; G = C; B = X; break;
        case 3 : R = 0; G = X; B = C; break;
        case 4 : R = X; G = 0; B = C; break;
        default : R = C; G = 0; B = X;
        }
        p1[N] = (T)((R + m)*3*255);
        p2[N] = (T)((G + m)*3*255);
        p3[N] = (T)((B + m)*3*255);
      }
      return *this;

Project: CImg
File: CImg.h

    //! Return a 2x2 symmetric matrix tensor containing specified coefficients.
    static CImg<T> tensor(const T& a0, const T& a1, const T& a2) {
      return matrix(a0,a1,a1,a2);

Project: CImg
File: CImg.h

    **/
    CImg(const unsigned int size_x, const unsigned int size_y,
         const unsigned int size_z, const unsigned int size_c, const T& value):
      _is_shared(false) {
      const size_t siz = (size_t)size_x*size_y*size_z*size_c;
      if (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);
        }
        fill(value);
      } else { _width = _height = _depth = _spectrum = 0; _data = 0; }

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& mul(const CImg<t>& img) {
      const ulongT siz = size(), isiz = img.size();
      if (siz && isiz) {
        if (is_overlapped(img)) return mul(+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

    //! Transpose the image, viewed as a matrix \newinstance.
    CImg<T> get_transpose() const {
      return get_permute_axes("yxzc");

Project: CImg
File: CImg.h

    // [internal] Version used to display text in interactive viewers.
    CImg<T>& __draw_text(const char *const text, const int is_down, ...) {
      CImg<charT> tmp(2048);
      std::va_list ap; va_start(ap,is_down);
      cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap);
      CImg<ucharT> a_label, a_labelmask;
      const unsigned char a_labelcolor = 255;
      const unsigned int fsize = 14;
      a_label.draw_text(0,0,"%s",&a_labelcolor,0,1,fsize,tmp._data).normalize(0,255);
      if (a_label) {
        a_label+=(255 - a_label.get_dilate(3)).normalize(0,80);
        a_label.resize(-100,-100,1,3,1);
        return draw_image(0,is_down?height() - a_label.height():0,a_label,0.85f);
      }
      return *this;

Project: CImg
File: CImg.h

     **/
    CImgList():

Project: CImg
File: CImg.h

    **/
    CImg<T>& load_dcraw_external(const char *const filename) {
      if (!filename)
        throw CImgArgumentException(_cimg_instance
                                    "load_dcraw_external(): Specified filename is (null).",
                                    cimg_instance);
      cimg::fclose(cimg::fopen(filename,"rb")); // Check if file exists
      CImg<charT> command(1024), filename_tmp(256);
      std::FILE *file = 0;
      const CImg<charT> s_filename = CImg<charT>::string(filename)._system_strescape();
#if cimg_OS==1
      cimg_snprintf(command,command._width,"%s -w -4 -c \"%s\"",
                    cimg::dcraw_path(),s_filename.data());
      file = popen(command,"r");
      if (file) {
        const unsigned int omode = cimg::exception_mode();
        cimg::exception_mode(0);
        try { load_pnm(file); } catch (...) {
          pclose(file);
          cimg::exception_mode(omode);
          throw CImgIOException(_cimg_instance
                                "load_dcraw_external(): Failed to load file '%s' with external command 'dcraw'.",
                                cimg_instance,
                                filename);
        }
        pclose(file);
        return *this;
      }
#endif
      do {
        cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.ppm",
                      cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
        if ((file=cimg::std_fopen(filename_tmp,"rb"))!=0) cimg::fclose(file);
      } while (file);
      cimg_snprintf(command,command._width,"%s -w -4 -c \"%s\" > \"%s\"",
                    cimg::dcraw_path(),s_filename.data(),CImg<charT>::string(filename_tmp)._system_strescape().data());
      cimg::system(command,cimg::dcraw_path());
      if (!(file=cimg::std_fopen(filename_tmp,"rb"))) {
        cimg::fclose(cimg::fopen(filename,"r"));
        throw CImgIOException(_cimg_instance
                              "load_dcraw_external(): Failed to load file '%s' with external command 'dcraw'.",
                              cimg_instance,
                              filename);

      } else cimg::fclose(file);
      load_pnm(filename_tmp);
      std::remove(filename_tmp);
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

      static bool is_inf(const T) { return false; }

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 ffmpeg binary.
    **/
    inline const char *ffmpeg_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,".\\ffmpeg.exe");
          if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(s_path,"ffmpeg.exe");
#else
        if (!path_found) {
          std::strcpy(s_path,"./ffmpeg");
          if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(s_path,"ffmpeg");
#endif
        winformat_string(s_path);

Project: CImg
File: CImg.h

    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
    inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6,
                     T7& a7, T7& b7) {
      cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6); cimg::swap(a7,b7);

Project: CImg
File: CImg.h

    **/
    Tfloat linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int c=0) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "linear_atXYZ(): Empty instance.",
                                    cimg_instance);

      return _linear_atXYZ(fx,fy,fz,c);

Project: CImg
File: CImg.h

    //! Crop image region \newinstance.
    CImg<T> get_crop(const int x0, const int y0, const int z0,
                     const int x1, const int y1, const int z1,
                     const unsigned int boundary_conditions=0) const {
      return get_crop(x0,y0,z0,0,x1,y1,z1,_spectrum - 1,boundary_conditions);

Project: CImg
File: CImg.h


    const T& _at(const int offset) const {
      const unsigned int siz = (unsigned int)size();
      return (*this)[offset<0?0:(unsigned int)offset>=siz?siz - 1:offset];

Project: CImg
File: CImg.h

    //! Construct list copy \specialization.
    CImgList(const CImgList<T>& list):_width(0),_allocated_width(0),_data(0) {
      assign(list._width);
      cimglist_for(*this,l) _data[l].assign(list[l],list[l]._is_shared);

Project: CImg
File: CImg.h

    template<typename t>
    void _load_tiff_tiled_separate(TIFF *const tif, const uint16 samplesperpixel,
                                   const uint32 nx, const uint32 ny, const uint32 tw, const uint32 th) {
      t *const buf = (t*)_TIFFmalloc(TIFFTileSize(tif));
      if (buf) {
        for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
          for (unsigned int row = 0; row<ny; row+=th)
            for (unsigned int col = 0; col<nx; col+=tw) {
              if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
                _TIFFfree(buf); TIFFClose(tif);
                throw CImgIOException(_cimg_instance
                                      "load_tiff(): Invalid tile in file '%s'.",
                                      cimg_instance,
                                      TIFFFileName(tif));
              }
              const t *ptr = buf;
              for (unsigned int rr = row; rr<std::min((unsigned int)(row + th),(unsigned int)ny); ++rr)
                for (unsigned int cc = col; cc<std::min((unsigned int)(col + tw),(unsigned int)nx); ++cc)
                  (*this)(cc,rr,vv) = (T)*(ptr++);
            }
        _TIFFfree(buf);
      }

Project: CImg
File: CImg.h

    //! Return pixel value, using cubic interpolation and mirror boundary conditions for the X and Y-coordinates.
    Tfloat cubic_atXY_p(const float fx, const float fy, const int z=0, const int c=0) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "cubic_atXY_p(): Empty instance.",
                                    cimg_instance);
      return _cubic_atXY_p(fx,fy,z,c);

Project: CImg
File: CImg.h

    **/
    CImgDisplay():
      _width(0),_height(0),_normalization(0),
      _min(0),_max(0),
      _is_fullscreen(false),
      _title(0),
      _window_width(0),_window_height(0),_button(0),
      _keys(new unsigned int[128]),_released_keys(new unsigned int[128]),
      _window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0),
      _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) {
      assign();

Project: CImg
File: CImg.h

    //! Save image as a sub-image into an existing .cimg file \overloading.
    const CImg<T>& save_cimg(std::FILE *const file,
			     const unsigned int n0,
			     const unsigned int x0, const unsigned int y0,
			     const unsigned int z0, const unsigned int c0) const {
      CImgList<T>(*this,true).save_cimg(file,n0,x0,y0,z0,c0);
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


      static double mp_sort(_cimg_math_parser& mp) {
        double *const ptrd = &_mp_arg(1) + 1;
        const double *const ptrs = &_mp_arg(2) + 1;
        const unsigned int
          siz = (unsigned int)mp.opcode[3],
          chunk_siz = (unsigned int)mp.opcode[5];
        const bool is_increasing = (bool)_mp_arg(4);
        CImg<doubleT>(ptrd,chunk_siz,siz/chunk_siz,1,1,true) = CImg<doubleT>(ptrs,chunk_siz,siz/chunk_siz,1,1,true).
          get_sort(is_increasing,chunk_siz>1?'y':0);
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

     **/
    CImg<T> operator-() const {
      return CImg<T>(_width,_height,_depth,_spectrum,(T)0)-=*this;

Project: CImg
File: CImg.h

      return *ptr_max;
    }

    //! Return a reference to the maximum pixel value of the instance list \const.
    const T& max() const {
      bool is_all_empty = true;
      T *ptr_max = 0;
      cimglist_for(*this,l) if (!_data[l].is_empty()) {
        ptr_max = _data[l]._data;
        is_all_empty = false;
        break;
      }
      if (is_all_empty)
        throw CImgInstanceException(_cimglist_instance
                                    "max(): %s.",
                                    _data?"List of empty images":"Empty instance",
                                    cimglist_instance);
      T max_value = *ptr_max;
      cimglist_for(*this,l) {
        const CImg<T>& img = _data[l];

Project: CImg
File: CImg.h

    //! Compute image Laplacian.
    CImg<T>& laplacian() {
      return get_laplacian().move_to(*this);

Project: CImg
File: CImg.h

    //! Fill sequentially all pixel values with specified values \overloading.
    CImg<T>& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5) {
      if (is_empty()) return *this;
      T *ptrd, *ptre = end() - 5;
      for (ptrd = _data; ptrd<ptre; ) {
        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5;
      }
      ptre+=5;
      switch (ptre - ptrd) {
      case 5 : *(--ptre) = val4; // fallthrough
      case 4 : *(--ptre) = val3; // fallthrough
      case 3 : *(--ptre) = val2; // fallthrough
      case 2 : *(--ptre) = val1; // fallthrough
      case 1 : *(--ptre) = val0; // fallthrough
      }
      return *this;

Project: CImg
File: CImg.h

    //! Compute the bitwise right rotation of each pixel value \newinstance.
    CImg<T> get_ror(const unsigned int n=1) const {
      return (+*this).ror(n);

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const float sigma,
                           const tc *const color, const float opacity=1) {
      return draw_gaussian(xc,yc,zc,CImg<floatT>::diagonal(sigma,sigma,sigma),color,opacity);

Project: CImg
File: CImg.h


    inline double rand(const double val_min, const double val_max) {
      cimg::mutex(4);
      const double res = cimg::rand(val_min,val_max,&cimg::rng());
      cimg::mutex(4,0);
      return res;

Project: CImg
File: CImg.h

    //! Remove white spaces on the start and/or end of a C-string.
    inline bool strpare(char *const str, const bool is_symmetric, const bool is_iterative) {
      if (!str) return false;
      const int l = (int)std::strlen(str);
      int p, q;
      if (is_symmetric) for (p = 0, q = l - 1; p<q && is_blank(str[p]) && is_blank(str[q]); ) {
          --q; ++p; if (!is_iterative) break;
        } else {
        for (p = 0; p<l && is_blank(str[p]); ) { ++p; if (!is_iterative) break; }
        for (q = l - 1; q>p && is_blank(str[q]); ) { --q; if (!is_iterative) break; }
      }
      const int n = q - p + 1;
      if (n!=l) { std::memmove(str,str + p,(unsigned int)n); str[n] = 0; return true; }
      return false;

Project: CImg
File: CImg.h

    template<typename t, typename tc>
    CImg<T>& draw_line(const CImg<t>& points,
                       const tc *const color, const float opacity=1,
                       const unsigned int pattern=~0U, const bool init_hatch=true) {
      if (is_empty() || !points || points._width<2) return *this;
      bool ninit_hatch = init_hatch;
      switch (points._height) {
      case 0 : case 1 :
        throw CImgArgumentException(_cimg_instance
                                    "draw_line(): Invalid specified point set (%u,%u,%u,%u,%p).",
                                    cimg_instance,
                                    points._width,points._height,points._depth,points._spectrum,points._data);

      default : {
        const int x0 = (int)points(0,0), y0 = (int)points(0,1);
        int ox = x0, oy = y0;
        for (unsigned int i = 1; i<points._width; ++i) {
          const int x = (int)points(i,0), y = (int)points(i,1);
          draw_line(ox,oy,x,y,color,opacity,pattern,ninit_hatch);
          ninit_hatch = false;
          ox = x; oy = y;
        }
      }
      }
      return *this;

Project: CImg
File: CImg.h


      static double mp_list_l(_cimg_math_parser& mp) {
        return (double)mp.listout.width();

Project: CImg
File: CImg.h

    //! Return specified image channel \inplace.
    CImg<T>& channel(const int c0) {
      return channels(c0,c0);

Project: CImg
File: CImg.h


      static double mp_set_Joff_v(_cimg_math_parser& mp) {
        CImg<T> &img = mp.imgout;
        const int
          ox = (int)mp.mem[_cimg_mp_slot_x], oy = (int)mp.mem[_cimg_mp_slot_y],
          oz = (int)mp.mem[_cimg_mp_slot_z], oc = (int)mp.mem[_cimg_mp_slot_c];
        const longT
          off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(2),
          whd = (longT)img.width()*img.height()*img.depth();
        const double *ptrs = &_mp_arg(1) + 1;
        if (off>=0 && off<whd) {
          const unsigned int vsiz = (unsigned int)mp.opcode[3];
          T *ptrd = &img[off];
          cimg_for_inC(img,0,vsiz - 1,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }
        }
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

    **/
    static void FFT(CImg<T>& real, CImg<T>& imag, const char axis, const bool is_inverse=false,
                    const unsigned int nb_threads=0) {
      if (!real)
        throw CImgInstanceException("CImg<%s>::FFT(): Specified real part is empty.",
                                    pixel_type());
      if (!imag) imag.assign(real._width,real._height,real._depth,real._spectrum,(T)0);
      if (!real.is_sameXYZC(imag))
        throw CImgInstanceException("CImg<%s>::FFT(): Specified real part (%u,%u,%u,%u,%p) and "
                                    "imaginary part (%u,%u,%u,%u,%p) have different dimensions.",
                                    pixel_type(),
                                    real._width,real._height,real._depth,real._spectrum,real._data,
                                    imag._width,imag._height,imag._depth,imag._spectrum,imag._data);
      const char _axis = cimg::lowercase(axis);
      if (_axis!='x' && _axis!='y' && _axis!='z')
        throw CImgArgumentException("CImgList<%s>::FFT(): Invalid specified axis '%c' for real and imaginary parts "
                                    "(%u,%u,%u,%u) "
                                    "(should be { x | y | z }).",
                                    pixel_type(),axis,
                                    real._width,real._height,real._depth,real._spectrum);
      cimg::unused(nb_threads);
#ifdef cimg_use_fftw3
      cimg::mutex(12);
#ifndef cimg_use_fftw3_singlethread
      fftw_plan_with_nthreads(nb_threads?nb_threads:cimg::nb_cpus());
#endif
      fftw_complex *data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*real._width*real._height*real._depth);
      if (!data_in)
        throw CImgInstanceException("CImgList<%s>::FFT(): Failed to allocate memory (%s) "
                                    "for computing FFT of image (%u,%u,%u,%u) along the X-axis.",
                                    pixel_type(),
                                    cimg::strbuffersize(sizeof(fftw_complex)*real._width),
                                    real._width,real._height,real._depth,real._spectrum);
      double *const ptrf = (double*)data_in;
      fftw_plan data_plan =
        _axis=='x'?fftw_plan_many_dft(1,(int*)&real._width,real.height()*real.depth(),
                                      data_in,0,1,real.width(),
                                      data_in,0,1,real.width(),
                                      is_inverse?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE):
        _axis=='y'?fftw_plan_many_dft(1,(int*)&real._height,real.width()*real.depth(),
                                      data_in,0,real.width(),1,
                                      data_in,0,real.width(),1,
                                      is_inverse?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE):
        fftw_plan_many_dft(1,(int*)&real._depth,real.width()*real.height(),
                           data_in,0,real.width()*real.height(),1,
                           data_in,0,real.width()*real.height(),1,
                           is_inverse?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
      cimg_forC(real,c) {
        CImg<T> realc = real.get_shared_channel(c), imagc = imag.get_shared_channel(c);
        cimg_pragma_openmp(parallel for cimg_openmp_if_size(real.width()*real.height()*real.depth(),125000))
          cimg_rofoff(realc,i) { const ulongT i2 = 2*i; ptrf[i2] = (double)realc[i]; ptrf[i2 + 1] = (double)imagc[i]; }
        fftw_execute(data_plan);
        if (is_inverse) {
          const double a = 1.0/(_axis=='x'?real.width():_axis=='y'?real.height():real.depth());
          cimg_pragma_openmp(parallel for cimg_openmp_if_size(real.width()*real.height()*real.depth(),125000))
            cimg_rofoff(realc,i) { const ulongT i2 = 2*i; realc[i] = (T)(a*ptrf[i2]); imagc[i] = (T)(a*ptrf[i2 + 1]); }
        } else
          cimg_pragma_openmp(parallel for cimg_openmp_if_size(real.width()*real.height()*real.depth(),125000))
            cimg_rofoff(realc,i) { const ulongT i2 = 2*i; realc[i] = (T)ptrf[i2]; imagc[i] = (T)ptrf[i2 + 1]; }
      }
      fftw_destroy_plan(data_plan);
      fftw_free(data_in);
#ifndef cimg_use_fftw3_singlethread
      fftw_cleanup_threads();
#endif
      cimg::mutex(12,0);
#else
      switch (_axis) {
      case 'x' : { // Fourier along X, using built-in functions
        const unsigned int N = real._width, N2 = N>>1;
        if (((N - 1)&N) && N!=1)
          throw CImgInstanceException("CImgList<%s>::FFT(): Specified real and imaginary parts (%u,%u,%u,%u) "
                                      "have non 2^N dimension along the X-axis.",
                                      pixel_type(),
                                      real._width,real._height,real._depth,real._spectrum);

        for (unsigned int i = 0, j = 0; i<N2; ++i) {
          if (j>i) cimg_forYZC(real,y,z,c) {
              cimg::swap(real(i,y,z,c),real(j,y,z,c));
              cimg::swap(imag(i,y,z,c),imag(j,y,z,c));
              if (j<N2) {
                const unsigned int ri = N - 1 - i, rj = N - 1 - j;
                cimg::swap(real(ri,y,z,c),real(rj,y,z,c));
                cimg::swap(imag(ri,y,z,c),imag(rj,y,z,c));
              }
            }
          for (unsigned int m = N, n = N2; (j+=n)>=m; j-=m, m = n, n>>=1) {}
        }
        for (unsigned int delta = 2; delta<=N; delta<<=1) {
          const unsigned int delta2 = delta>>1;
          for (unsigned int i = 0; i<N; i+=delta) {
            float wr = 1, wi = 0;
            const float
              angle = (float)((is_inverse?+1:-1)*2*cimg::PI/delta),
              ca = (float)std::cos(angle),
              sa = (float)std::sin(angle);
            for (unsigned int k = 0; k<delta2; ++k) {
              const unsigned int j = i + k, nj = j + delta2;
              cimg_forYZC(real,y,z,c) {
                T &ir = real(j,y,z,c), &ii = imag(j,y,z,c), &nir = real(nj,y,z,c), &nii = imag(nj,y,z,c);
                const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
                nir = (T)(ir - tmpr);
                nii = (T)(ii - tmpi);
                ir+=(T)tmpr;
                ii+=(T)tmpi;
              }
              const float nwr = wr*ca-wi*sa;
              wi = wi*ca + wr*sa;
              wr = nwr;
            }
          }
        }
        if (is_inverse) { real/=N; imag/=N; }
      } break;
      case 'y' : { // Fourier along Y, using built-in functions
        const unsigned int N = real._height, N2 = N>>1;
        if (((N - 1)&N) && N!=1)
          throw CImgInstanceException("CImgList<%s>::FFT(): Specified real and imaginary parts (%u,%u,%u,%u) "
                                      "have non 2^N dimension along the Y-axis.",
                                      pixel_type(),
                                      real._width,real._height,real._depth,real._spectrum);

        for (unsigned int i = 0, j = 0; i<N2; ++i) {
          if (j>i) cimg_forXZC(real,x,z,c) {
              cimg::swap(real(x,i,z,c),real(x,j,z,c));
              cimg::swap(imag(x,i,z,c),imag(x,j,z,c));
              if (j<N2) {
                const unsigned int ri = N - 1 - i, rj = N - 1 - j;
                cimg::swap(real(x,ri,z,c),real(x,rj,z,c));
                cimg::swap(imag(x,ri,z,c),imag(x,rj,z,c));
              }
            }
          for (unsigned int m = N, n = N2; (j+=n)>=m; j-=m, m = n, n>>=1) {}
        }
        for (unsigned int delta = 2; delta<=N; delta<<=1) {
          const unsigned int delta2 = (delta>>1);
          for (unsigned int i = 0; i<N; i+=delta) {
            float wr = 1, wi = 0;
            const float
              angle = (float)((is_inverse?+1:-1)*2*cimg::PI/delta),
              ca = (float)std::cos(angle),
              sa = (float)std::sin(angle);
            for (unsigned int k = 0; k<delta2; ++k) {
              const unsigned int j = i + k, nj = j + delta2;
              cimg_forXZC(real,x,z,c) {
                T &ir = real(x,j,z,c), &ii = imag(x,j,z,c), &nir = real(x,nj,z,c), &nii = imag(x,nj,z,c);
                const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
                nir = (T)(ir - tmpr);
                nii = (T)(ii - tmpi);
                ir+=(T)tmpr;
                ii+=(T)tmpi;
              }
              const float nwr = wr*ca-wi*sa;
              wi = wi*ca + wr*sa;
              wr = nwr;
            }
          }
        }
        if (is_inverse) { real/=N; imag/=N; }
      } break;
      default : { // Fourier along Z, using built-in functions
        const unsigned int N = real._depth, N2 = N>>1;
        if (((N - 1)&N) && N!=1)
          throw CImgInstanceException("CImgList<%s>::FFT(): Specified real and imaginary parts (%u,%u,%u,%u) "
                                      "have non 2^N dimension along the Z-axis.",
                                      pixel_type(),
                                      real._width,real._height,real._depth,real._spectrum);

        for (unsigned int i = 0, j = 0; i<N2; ++i) {
          if (j>i) cimg_forXYC(real,x,y,c) {
              cimg::swap(real(x,y,i,c),real(x,y,j,c));
              cimg::swap(imag(x,y,i,c),imag(x,y,j,c));
              if (j<N2) {
                const unsigned int ri = N - 1 - i, rj = N - 1 - j;
                cimg::swap(real(x,y,ri,c),real(x,y,rj,c));
                cimg::swap(imag(x,y,ri,c),imag(x,y,rj,c));
              }
            }
          for (unsigned int m = N, n = N2; (j+=n)>=m; j-=m, m = n, n>>=1) {}
        }
        for (unsigned int delta = 2; delta<=N; delta<<=1) {
          const unsigned int delta2 = (delta>>1);
          for (unsigned int i = 0; i<N; i+=delta) {
            float wr = 1, wi = 0;
            const float
              angle = (float)((is_inverse?+1:-1)*2*cimg::PI/delta),
              ca = (float)std::cos(angle),
              sa = (float)std::sin(angle);
            for (unsigned int k = 0; k<delta2; ++k) {
              const unsigned int j = i + k, nj = j + delta2;
              cimg_forXYC(real,x,y,c) {
                T &ir = real(x,y,j,c), &ii = imag(x,y,j,c), &nir = real(x,y,nj,c), &nii = imag(x,y,nj,c);
                const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
                nir = (T)(ir - tmpr);
                nii = (T)(ii - tmpi);
                ir+=(T)tmpr;
                ii+=(T)tmpi;
              }
              const float nwr = wr*ca-wi*sa;
              wi = wi*ca + wr*sa;
              wr = nwr;
            }
          }
        }
        if (is_inverse) { real/=N; imag/=N; }
      } break;
      }
#endif

Project: CImg
File: CImg.h

    template<typename tp>
    CImg<floatT> get_object3dtoCImg3d(const CImgList<tp>& primitives,
                                      const bool full_check=true) const {
      CImgList<T> colors, opacities;
      return get_object3dtoCImg3d(primitives,colors,opacities,full_check);

Project: CImg
File: CImg.h

    template<typename T>
    inline T round(const T& x) {
      return (T)std::floor((_cimg_Tfloat)x + 0.5f);

Project: CImg
File: CImg.h

    //! Simple interface to select a shape from an image \overloading.
    CImg<T>& select(const char *const title,
		    const unsigned int feature_type=2, unsigned int *const XYZ=0,
                    const bool exit_on_anykey=false,
                    const bool is_deep_selection_default=false) {
      return get_select(title,feature_type,XYZ,exit_on_anykey,is_deep_selection_default).move_to(*this);

Project: CImg
File: CImg.h

    //! Return a shared-memory image referencing one slice of the image instance \const.
    const CImg<T> get_shared_slice(const unsigned int z0, const unsigned int c0=0) const {
      return get_shared_slices(z0,z0,c0);

Project: CImg
File: CImg.h

  template<typename T>
  inline CImg<_cimg_Tfloat> invert(const CImg<T>& instance) {
    return instance.get_invert();

Project: CImg
File: CImg.h


    Tfloat _linear_atXYZC(const float fx, const float fy=0, const float fz=0, const float fc=0) const {
      const float
        nfx = cimg::cut(fx,0,width() - 1),
        nfy = cimg::cut(fy,0,height() - 1),
        nfz = cimg::cut(fz,0,depth() - 1),
        nfc = cimg::cut(fc,0,spectrum() - 1);
      const unsigned int
        x = (unsigned int)nfx,
        y = (unsigned int)nfy,
        z = (unsigned int)nfz,
        c = (unsigned int)nfc;
      const float
        dx = nfx - x,
        dy = nfy - y,
        dz = nfz - z,
        dc = nfc - c;
      const unsigned int
        nx = dx>0?x + 1:x,
        ny = dy>0?y + 1:y,
        nz = dz>0?z + 1:z,
        nc = dc>0?c + 1:c;
      const Tfloat
        Icccc = (Tfloat)(*this)(x,y,z,c), Inccc = (Tfloat)(*this)(nx,y,z,c),
        Icncc = (Tfloat)(*this)(x,ny,z,c), Inncc = (Tfloat)(*this)(nx,ny,z,c),
        Iccnc = (Tfloat)(*this)(x,y,nz,c), Incnc = (Tfloat)(*this)(nx,y,nz,c),
        Icnnc = (Tfloat)(*this)(x,ny,nz,c), Innnc = (Tfloat)(*this)(nx,ny,nz,c),
        Icccn = (Tfloat)(*this)(x,y,z,nc), Inccn = (Tfloat)(*this)(nx,y,z,nc),
        Icncn = (Tfloat)(*this)(x,ny,z,nc), Inncn = (Tfloat)(*this)(nx,ny,z,nc),
        Iccnn = (Tfloat)(*this)(x,y,nz,nc), Incnn = (Tfloat)(*this)(nx,y,nz,nc),
        Icnnn = (Tfloat)(*this)(x,ny,nz,nc), Innnn = (Tfloat)(*this)(nx,ny,nz,nc);
      return Icccc +
        dx*(Inccc - Icccc +
            dy*(Icccc + Inncc - Icncc - Inccc +
                dz*(Iccnc + Innnc + Icncc + Inccc - Icnnc - Incnc - Icccc - Inncc +
                    dc*(Iccnn + Innnn + Icncn + Inccn + Icnnc + Incnc + Icccc + Inncc -
                        Icnnn - Incnn - Icccn - Inncn - Iccnc - Innnc - Icncc - Inccc)) +
                dc*(Icccn + Inncn + Icncc + Inccc - Icncn - Inccn - Icccc - Inncc)) +
            dz*(Icccc + Incnc - Iccnc - Inccc +
                dc*(Icccn + Incnn + Iccnc + Inccc - Iccnn - Inccn - Icccc - Incnc)) +
            dc*(Icccc + Inccn - Inccc - Icccn)) +
        dy*(Icncc - Icccc +
            dz*(Icccc + Icnnc - Iccnc - Icncc +
                dc*(Icccn + Icnnn + Iccnc + Icncc - Iccnn - Icncn - Icccc - Icnnc)) +
            dc*(Icccc + Icncn - Icncc - Icccn)) +
        dz*(Iccnc - Icccc +
            dc*(Icccc + Iccnn - Iccnc - Icccn)) +
        dc*(Icccn - Icccc);

Project: CImg
File: CImg.h


      static double mp_list_set_Jxyz_v(_cimg_math_parser& mp) {
        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
        CImg<T> &img = mp.listout[ind];
        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(3)),
          y = (int)(oy + _mp_arg(4)),
          z = (int)(oz + _mp_arg(5));
        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[6];
          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


      static double mp_complex_mul(_cimg_math_parser& mp) {
        const double
          *ptr1 = &_mp_arg(2) + 1, *ptr2 = &_mp_arg(3) + 1,
          r1 = *(ptr1++), i1 = *ptr1,
          r2 = *(ptr2++), i2 = *ptr2;
        double *ptrd = &_mp_arg(1) + 1;
        *(ptrd++) = r1*r2 - i1*i2;
        *(ptrd++) = r1*i2 + r2*i1;
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

      }
      static double nan() {
#ifdef NAN
        return (double)NAN;
#else
        const double val_nan = -std::sqrt(-1.); return val_nan;
#endif

Project: CImg
File: CImg.h

    //! Load image sequence from a video file, using OpenCV library \newinstance.
    static CImg<T> get_load_video(const char *const filename,
                                  const unsigned int first_frame=0, const unsigned int last_frame=~0U,
                                  const unsigned int step_frame=1,
                                  const char axis='z', const float align=0) {
      return CImgList<T>().load_video(filename,first_frame,last_frame,step_frame).get_append(axis,align);

Project: CImg
File: CImg.h


      static double mp_copy(_cimg_math_parser& mp) {
        return _mp_arg(2);

Project: CImg
File: CImg.h

      // Check that listin or listout are not empty.
      void check_list(const bool is_out,
                      char *const ss, char *const se, const char saved_char) {
        if ((!is_out && !listin) || (is_out && !listout)) {
          *se = saved_char;
          char *const s0 = ss - 4>expr._data?ss - 4:expr._data;
          cimg::strellipsize(s0,64);
          throw CImgArgumentException("[" cimg_appname "_math_parser] "
                                      "CImg<%s>::%s: %s%s Invalid call with an empty image list, "
                                      "in expression '%s%s%s'.",
                                      pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"",
                                      s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
        }

Project: CImg
File: CImg.h

      static unsigned short inf() { return max(); }
      static unsigned short cut(const double val) {

Project: CImg
File: CImg.h

    template<typename t>
    double dot(const CImg<t>& img) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "dot(): Empty instance.",
                                    cimg_instance);
      if (!img)
        throw CImgArgumentException(_cimg_instance
                                    "dot(): Empty specified image.",
                                    cimg_instance);

      const ulongT nb = std::min(size(),img.size());
      double res = 0;
      for (ulongT off = 0; off<nb; ++off) res+=(double)_data[off]*(double)img[off];
      return res;

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& dijkstra(const unsigned int starting_node, const unsigned int ending_node,
                      CImg<t>& previous_node) {
      return get_dijkstra(starting_node,ending_node,previous_node).move_to(*this);

Project: CImg
File: CImg.h


    const CImg<T>& _save_tiff(TIFF *tif, const unsigned int directory, const unsigned int z,
                              const unsigned int compression_type, const float *const voxel_size,
                              const char *const description) const {
      _cimg_save_tiff("bool",unsigned char,compression_type);
      _cimg_save_tiff("unsigned char",unsigned char,compression_type);
      _cimg_save_tiff("char",char,compression_type);
      _cimg_save_tiff("unsigned short",unsigned short,compression_type);
      _cimg_save_tiff("short",short,compression_type);
      _cimg_save_tiff("unsigned int",unsigned int,compression_type);
      _cimg_save_tiff("int",int,compression_type);
      _cimg_save_tiff("unsigned int64",unsigned int,compression_type);
      _cimg_save_tiff("int64",int,compression_type);
      _cimg_save_tiff("float",float,compression_type);
      _cimg_save_tiff("double",float,compression_type);
      const char *const filename = TIFFFileName(tif);
      throw CImgInstanceException(_cimg_instance
                                  "save_tiff(): Unsupported pixel type '%s' for file '%s'.",
                                  cimg_instance,
                                  pixel_type(),filename?filename:"(FILE*)");
      return *this;

Project: CImg
File: CImg.h

    //! Load image sequence using FFMPEG's external tool 'ffmpeg' \newinstance.
    static CImg<T> get_load_ffmpeg_external(const char *const filename, const char axis='z', const float align=0) {
      return CImgList<T>().load_ffmpeg_external(filename).get_append(axis,align);

Project: CImg
File: CImg.h

    //! Fill sequentially all pixel values with specified values \overloading.
    CImg<T>& 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) {
      if (is_empty()) return *this;
      T *ptrd, *ptre = end() - 8;
      for (ptrd = _data; ptrd<ptre; ) {
        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2;
        *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5;
        *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8;
      }
      ptre+=8;
      switch (ptre - ptrd) {
      case 8 : *(--ptre) = val7; // fallthrough
      case 7 : *(--ptre) = val6; // fallthrough
      case 6 : *(--ptre) = val5; // fallthrough
      case 5 : *(--ptre) = val4; // fallthrough
      case 4 : *(--ptre) = val3; // fallthrough
      case 3 : *(--ptre) = val2; // fallthrough
      case 2 : *(--ptre) = val1; // fallthrough
      case 1 : *(--ptre) = val0; // fallthrough
      }
      return *this;

Project: CImg
File: CImg.h

    //! Convert pixel values from CMY to RGB color spaces.
    CImg<T>& CMYtoRGB() {
      if (_spectrum!=3)
        throw CImgInstanceException(_cimg_instance
                                    "CMYtoRGB(): Instance is not a CMY image.",
                                    cimg_instance);

      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,2048))
      for (longT N = 0; N<whd; ++N) {
        const Tfloat
          C = (Tfloat)p1[N],
          M = (Tfloat)p2[N],
          Y = (Tfloat)p3[N],
          R = 255 - C,
          G = 255 - M,
          B = 255 - Y;
        p1[N] = (T)cimg::cut(R,0,255),
        p2[N] = (T)cimg::cut(G,0,255),
        p3[N] = (T)cimg::cut(B,0,255);
      }
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    //! Resize image to dimensions of a display window \newinstance.
    CImg<T> get_resize(const CImgDisplay& disp,
                       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(disp.width(),disp.height(),_depth,_spectrum,interpolation_type,boundary_conditions,
                        centering_x,centering_y,centering_z,centering_c);

Project: CImg
File: CImg.h

    **/
    CImgList<T> operator<(const char axis) const {
      return get_split(axis);

Project: CImg
File: CImg.h

      // { 0=constant | 1=integer constant | 2=positive integer constant | 3=strictly-positive integer constant }
      void check_constant(const unsigned int arg, const unsigned int n_arg,
                          const unsigned int mode,
                          char *const ss, char *const se, const char saved_char) {
        _cimg_mp_check_type(arg,n_arg,1,0);
        if (!(_cimg_mp_is_constant(arg) &&
              (!mode || (double)(int)mem[arg]==mem[arg]) &&
              (mode<2 || mem[arg]>=(mode==3)))) {
          const char *s_arg = !n_arg?"":n_arg==1?"First ":n_arg==2?"Second ":n_arg==3?"Third ":
            n_arg==4?"Fourth ":n_arg==5?"Fifth ":n_arg==6?"Sixth ":n_arg==7?"Seventh ":n_arg==8?"Eighth ":
            n_arg==9?"Ninth ":"One of the ";
          *se = saved_char;
          char *const s0 = ss - 4>expr._data?ss - 4:expr._data;
          cimg::strellipsize(s0,64);
          throw CImgArgumentException("[" cimg_appname "_math_parser] "
                                      "CImg<%s>::%s: %s%s %s%s (of type '%s') is not a%s constant, "
                                      "in expression '%s%s%s'.",
                                      pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"",
                                      s_arg,*s_arg?"argument":"Argument",s_type(arg)._data,
                                      !mode?"":mode==1?"n integer":
                                      mode==2?" positive integer":" strictly positive integer",
                                      s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
        }

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_text(const int x0, const int y0,
                       const char *const text,
                       const int, const tc *const background_color,
                       const float opacity=1, const unsigned int font_height=13, ...) {
      if (!font_height) return *this;
      CImg<charT> tmp(2048);
      std::va_list ap; va_start(ap,font_height);
      cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap);
      return draw_text(x0,y0,"%s",(tc*)0,background_color,opacity,font_height,tmp._data);

Project: CImg
File: CImg.h

      \param last_frame Index of the last frame to read (can be higher than the actual number of frames, e.g. '~0U').
      \param step_frame Step value for frame reading.
      \note If step_frame==0, the current video stream is forced to be released (without any frames read).
    **/
    CImgList<T>& load_video(const char *const filename,
                            const unsigned int first_frame=0, const unsigned int last_frame=~0U,
                            const unsigned int step_frame=1) {
#ifndef cimg_use_opencv
      if (first_frame || last_frame!=~0U || step_frame>1)
        throw CImgArgumentException(_cimglist_instance
                                    "load_video() : File '%s', arguments 'first_frame', 'last_frame' "
                                    "and 'step_frame' can be only set when using OpenCV "
                                    "(-Dcimg_use_opencv must be enabled).",
                                    cimglist_instance,filename);
      return load_ffmpeg_external(filename);
#else
      static cv::VideoCapture *captures[32] = { 0 };
      static CImgList<charT> filenames(32);
      static CImg<uintT> positions(32,1,1,1,0);
      static int last_used_index = -1;

      // Detect if a video capture already exists for the specified filename.
      cimg::mutex(9);
      int index = -1;
      if (filename) {
        if (last_used_index>=0 && !std::strcmp(filename,filenames[last_used_index])) {
          index = last_used_index;
        } else cimglist_for(filenames,l) if (filenames[l] && !std::strcmp(filename,filenames[l])) {
            index = l; break;
          }
      } else index = last_used_index;
      cimg::mutex(9,0);

      // Release stream if needed.
      if (!step_frame || (index>=0 && positions[index]>first_frame)) {
        if (index>=0) {
          cimg::mutex(9);
          captures[index]->release();
          delete captures[index];
          captures[index] = 0;
          positions[index] = 0;
          filenames[index].assign();
          if (last_used_index==index) last_used_index = -1;
          index = -1;
          cimg::mutex(9,0);
        } else
          if (filename)
            cimg::warn(_cimglist_instance
                       "load_video() : File '%s', no opened video stream associated with filename found.",
                       cimglist_instance,filename);
          else
            cimg::warn(_cimglist_instance
                       "load_video() : No opened video stream found.",
                       cimglist_instance,filename);
        if (!step_frame) return *this;
      }

      // Find empty slot for capturing video stream.
      if (index<0) {
        if (!filename)
          throw CImgArgumentException(_cimglist_instance
                                      "load_video(): No already open video reader found. You must specify a "
                                      "non-(null) filename argument for the first call.",
                                      cimglist_instance);
        else { cimg::mutex(9); cimglist_for(filenames,l) if (!filenames[l]) { index = l; break; } cimg::mutex(9,0); }
        if (index<0)
          throw CImgIOException(_cimglist_instance
                                "load_video(): File '%s', no video reader slots available. "
                                "You have to release some of your previously opened videos.",
                                cimglist_instance,filename);
        cimg::mutex(9);
        captures[index] = new cv::VideoCapture(filename);
        positions[index] = 0;
        if (!captures[index]->isOpened()) {
          delete captures[index];
          captures[index] = 0;
          cimg::mutex(9,0);
          cimg::fclose(cimg::fopen(filename,"rb"));  // Check file availability
          throw CImgIOException(_cimglist_instance
                                "load_video(): File '%s', unable to detect format of video file.",
                                cimglist_instance,filename);
        }
        CImg<charT>::string(filename).move_to(filenames[index]);
        cimg::mutex(9,0);
      }

      cimg::mutex(9);
      const unsigned int nb_frames = (unsigned int)std::max(0.,captures[index]->get(_cimg_cap_prop_frame_count));
      cimg::mutex(9,0);
      assign();

      // Skip frames if requested.
      bool go_on = true;
      unsigned int &pos = positions[index];
      while (pos<first_frame) {
        cimg::mutex(9);
        if (!captures[index]->grab()) { cimg::mutex(9,0); go_on = false; break; }
        cimg::mutex(9,0);
        ++pos;
      }

      // Read and convert frames.
      const unsigned int _last_frame = std::min(nb_frames?nb_frames - 1:~0U,last_frame);
      while (go_on && pos<=_last_frame) {
        cv::Mat cvimg;
        cimg::mutex(9);
        if (captures[index]->read(cvimg)) { CImg<T>::_cvmat2cimg(cvimg).move_to(*this); ++pos; }
        else go_on = false;
        cimg::mutex(9,0);
        if (go_on)
          for (unsigned int i = 1; go_on && i<step_frame && pos<=_last_frame; ++i, ++pos) {
            cimg::mutex(9);
            if (!captures[index]->grab()) go_on = false;
            cimg::mutex(9,0);
          }
      }

      if (!go_on || (nb_frames && pos>=nb_frames)) { // Close video stream when necessary
        cimg::mutex(9);
        captures[index]->release();
        delete captures[index];
        captures[index] = 0;
        filenames[index].assign();
        positions[index] = 0;
        index = -1;
        cimg::mutex(9,0);
      }

      cimg::mutex(9);
      last_used_index = index;
      cimg::mutex(9,0);

      if (is_empty())
        throw CImgIOException(_cimglist_instance
                              "load_video(): File '%s', unable to locate frame %u.",

Project: CImg
File: CImg.h

    //! Version of 'fseek()' that supports >=64bits offsets everywhere (for Windows).
    inline int fseek(FILE *stream, cimg_long offset, int origin) {
#if defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
      return _fseeki64(stream,(__int64)offset,origin);
#else
      return std::fseek(stream,offset,origin);
#endif

Project: CImg
File: CImg.h

    template<typename tf>
    CImg<floatT> get_isoline3d(CImgList<tf>& primitives, const float isovalue,
                               const int size_x=-100, const int size_y=-100) const {
      if (_spectrum>1)
        throw CImgInstanceException(_cimg_instance
                                    "get_isoline3d(): Instance is not a scalar image.",
                                    cimg_instance);
      if (_depth>1)
        throw CImgInstanceException(_cimg_instance
                                    "get_isoline3d(): Instance is not a 2D image.",
                                    cimg_instance);
      primitives.assign();
      if (is_empty()) return *this;
      CImg<floatT> vertices;
      if ((size_x==-100 && size_y==-100) || (size_x==width() && size_y==height())) {
        const _functor2d_int func(*this);
        vertices = isoline3d(primitives,func,isovalue,0,0,width() - 1.f,height() - 1.f,width(),height());
      } else {
        const _functor2d_float func(*this);
        vertices = isoline3d(primitives,func,isovalue,0,0,width() - 1.f,height() - 1.f,size_x,size_y);
      }
      return vertices;

Project: CImg
File: CImg.h


      static double mp_isfile(_cimg_math_parser& mp) {
        const double *ptrs = &_mp_arg(2) + 1;
        const ulongT siz = (ulongT)mp.opcode[3];
        CImg<charT> ss(siz + 1);
        cimg_forX(ss,i) ss[i] = (char)ptrs[i];
        ss.back() = 0;
        return (double)cimg::is_file(ss);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


      static double mp_asin(_cimg_math_parser& mp) {
        return std::asin(_mp_arg(2));

Project: CImg
File: CImg.h

    //! Load image from a file, using Magick++ library \newinstance.
    static CImg<T> get_load_magick(const char *const filename) {
      return CImg<T>().load_magick(filename);

Project: CImg
File: CImg.h


    CImgDisplay& show_mouse() {
      if (is_empty()) return *this;
      _is_cursor_visible = true;
      return *this;

Project: CImg
File: CImg.h

    //! Return a shared-memory version of the image instance.
    CImg<T> get_shared() {
      return CImg<T>(_data,_width,_height,_depth,_spectrum,true);

Project: CImg
File: CImg.h

    template<typename tf, typename tc, typename te>
    CImg<floatT> get_elevation3d(CImgList<tf>& primitives, CImgList<tc>& colors, const CImg<te>& elevation) const {
      if (!is_sameXY(elevation) || elevation._depth>1 || elevation._spectrum>1)
        throw CImgArgumentException(_cimg_instance
                                    "get_elevation3d(): Instance and specified elevation (%u,%u,%u,%u,%p) "
                                    "have incompatible dimensions.",
                                    cimg_instance,
                                    elevation._width,elevation._height,elevation._depth,
                                    elevation._spectrum,elevation._data);
      if (is_empty()) return *this;
      float m, M = (float)max_min(m);
      if (M==m) ++M;
      colors.assign();
      const unsigned int size_x1 = _width - 1, size_y1 = _height - 1;
      for (unsigned int y = 0; y<size_y1; ++y)
        for (unsigned int x = 0; x<size_x1; ++x) {
          const unsigned char
            r = (unsigned char)(((*this)(x,y,0) - m)*255/(M-m)),
            g = (unsigned char)(_spectrum>1?((*this)(x,y,1) - m)*255/(M-m):r),
            b = (unsigned char)(_spectrum>2?((*this)(x,y,2) - m)*255/(M-m):_spectrum>1?0:r);
          CImg<tc>::vector((tc)r,(tc)g,(tc)b).move_to(colors);
        }
      const typename CImg<te>::_functor2d_int func(elevation);
      return elevation3d(primitives,func,0,0,_width - 1.f,_height - 1.f,_width,_height);

Project: CImg
File: CImg.h


      static double mp_complex_div_vv(_cimg_math_parser& mp) {
        const double
          *ptr1 = &_mp_arg(2) + 1, *ptr2 = &_mp_arg(3) + 1,
          r1 = *(ptr1++), i1 = *ptr1,
          r2 = *(ptr2++), i2 = *ptr2;
        double *ptrd = &_mp_arg(1) + 1;
        const double denom = r2*r2 + i2*i2;
        *(ptrd++) = (r1*r2 + i1*i2)/denom;
        *ptrd = (r2*i1 - r1*i2)/denom;
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

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

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 T& val9, const T& val10, const T& val11,
                     const T& val12, const T& val13, const T& val14, const T& val15) const {
      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,
                                                           val11,val12,val13,val14,val15);

Project: CImg
File: CImg.h


      static double mp_list_ioff(_cimg_math_parser& mp) {
        const unsigned int
          ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
          boundary_conditions = (unsigned int)_mp_arg(4);
        const CImg<T> &img = mp.listin[ind];
        const longT
          off = (longT)_mp_arg(3),
          whds = (longT)img.size();
        if (off>=0 && off<whds) return (double)img[off];
        if (img._data) switch (boundary_conditions) {
          case 3 : { // Mirror
            const longT whds2 = 2*whds, moff = cimg::mod(off,whds2);
            return (double)img[moff<whds?moff:whds2 - moff - 1];
          }
          case 2 : // Periodic
            return (double)img[cimg::mod(off,whds)];
          case 1 : // Neumann
            return (double)img[off<0?0:whds - 1];
          default : // Dirichlet
            return 0;
          }
        return 0;

Project: CImg
File: CImg.h


      static double mp_i(_cimg_math_parser& mp) {
        return (double)mp.imgin.atXYZC((int)mp.mem[_cimg_mp_slot_x],(int)mp.mem[_cimg_mp_slot_y],
                                       (int)mp.mem[_cimg_mp_slot_z],(int)mp.mem[_cimg_mp_slot_c],(T)0);

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
                            const int x1, const int y1, const int z1,
                            const tc *const color, const float opacity=1) {
      if (is_empty()) return *this;
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_rectangle(): Specified color is (null).",
                                    cimg_instance);
      cimg_forC(*this,c) draw_rectangle(x0,y0,z0,c,x1,y1,z1,c,(T)color[c],opacity);
      return *this;

Project: CImg
File: CImg.h

    //! Apply recursive Deriche filter \newinstance.
    CImg<Tfloat> get_deriche(const float sigma, const unsigned int order=0, const char axis='x',
                             const bool boundary_conditions=true) const {
      return CImg<Tfloat>(*this,false).deriche(sigma,order,axis,boundary_conditions);

Project: CImg
File: CImg.h

       \param align Alignment setting when images have not all the same size.
       \param exit_on_anykey Exit function when any key is pressed.
       \return A one-column vector containing the selected image indexes.
    **/
    CImg<intT> get_select(const char *const title, const bool feature_type=true,
                          const char axis='x', const float align=0,

Project: CImg
File: CImg.h

    **/
    CImg<T>& assign(const unsigned int size_x, const unsigned int size_y,
                    const unsigned int size_z, const unsigned int size_c,
                    const double value0, const double value1, ...) {
      assign(size_x,size_y,size_z,size_c);
      _CImg_stdarg(*this,value0,value1,(size_t)size_x*size_y*size_z*size_c,double);
      return *this;

Project: CImg
File: CImg.h

    template<typename T>
    inline T median(T val0, T val1, T val2, T val3, T val4, T val5, T val6, T val7, T val8) {
      T tmp = std::min(val1,val2);
      val2 = std::max(val1,val2); val1 = tmp; tmp = std::min(val4,val5);
      val5 = std::max(val4,val5); val4 = tmp; tmp = std::min(val7,val8);
      val8 = std::max(val7,val8); val7 = tmp; tmp = std::min(val0,val1);
      val1 = std::max(val0,val1); val0 = tmp; tmp = std::min(val3,val4);
      val4 = std::max(val3,val4); val3 = tmp; tmp = std::min(val6,val7);
      val7 = std::max(val6,val7); val6 = tmp; tmp = std::min(val1,val2);
      val2 = std::max(val1,val2); val1 = tmp; tmp = std::min(val4,val5);
      val5 = std::max(val4,val5); val4 = tmp; tmp = std::min(val7,val8);
      val8 = std::max(val7,val8); val3 = std::max(val0,val3); val5 = std::min(val5,val8);
      val7 = std::max(val4,tmp); tmp = std::min(val4,tmp); val6 = std::max(val3,val6);
      val4 = std::max(val1,tmp); val2 = std::min(val2,val5); val4 = std::min(val4,val7);
      tmp = std::min(val4,val2); val2 = std::max(val4,val2); val4 = std::max(val6,tmp);
      return std::min(val4,val2);

Project: CImg
File: CImg.h

         CImgDisplay window.
       Images of the list are appended in a single temporarly image for visualization purposes.
       The function returns immediately.
    **/

Project: CImg
File: CImg.h


    static longT _distance_dist_cdt(const longT x, const longT i, const longT *const g) {
      const longT d = x<i?i - x:x - i;
      return d<g[i]?g[i]:d;

Project: CImg
File: CImg.h

    **/
    inline const char *split_filename(const char *const filename, char *const body=0) {
      if (!filename) { if (body) *body = 0; return 0; }
      const char *p = 0; for (const char *np = filename; np>=filename && (p=np); np = std::strchr(np,'.') + 1) {}
      if (p==filename || std::strchr(p,'/') || std::strchr(p,'\\')) {
        if (body) std::strcpy(body,filename);
        return filename + std::strlen(filename);
      }
      const unsigned int l = (unsigned int)(p - filename - 1);
      if (body) { if (l) std::memcpy(body,filename,l); body[l] = 0; }
      return p;

Project: CImg
File: CImg.h

    template<typename t1, typename t2, typename t3>
    CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const bool is_shared=false) {
      assign(3);
      _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared);
      return *this;

Project: CImg
File: CImg.h

    **/
    CImg<T> operator>>(const char *const expression) const {
      return (+*this)>>=expression;

Project: CImg
File: CImg.h

    template<typename t>
    CImg<_cimg_Ttfloat> get_convolve(const CImg<t>& kernel, const bool boundary_conditions=true,
                                     const bool is_normalized=false, const int dilation=1) const {
      return _correlate(CImg<t>(kernel._data,kernel.size()/kernel._spectrum,1,1,kernel._spectrum,true).
                        get_mirror('x').resize(kernel,-1),boundary_conditions,is_normalized,dilation,true);

Project: CImg
File: CImg.h

    template<typename T>
    CImgDisplay& display(const CImgList<T>& list, const char axis='x', const float align=0) {
      if (list._width==1) {
        const CImg<T>& img = list[0];
        if (img._depth==1 && (img._spectrum==1 || img._spectrum>=3) && _normalization!=1) return display(img);
      }
      CImgList<typename CImg<T>::ucharT> visu(list._width);
      unsigned int dims = 0;
      cimglist_for(list,l) {
        const CImg<T>& img = list._data[l];
        img._get_select(*this,_normalization,(img._width - 1)/2,(img._height - 1)/2,
                        (img._depth - 1)/2).move_to(visu[l]);
        dims = std::max(dims,visu[l]._spectrum);
      }
      cimglist_for(list,l) if (visu[l]._spectrum<dims) visu[l].resize(-100,-100,-100,dims,1);
      visu.get_append(axis,align).display(*this);
      return *this;

Project: CImg
File: CImg.h

      return _load_cimg(0,filename);
    }