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

    //! Resize image to new dimensions \newinstance.
    CImg<T> get_resize(const int size_x, const int size_y = -100,
                       const int size_z = -100, const int size_c = -100,
                       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 {
      if (centering_x<0 || centering_x>1 || centering_y<0 || centering_y>1 ||
          centering_z<0 || centering_z>1 || centering_c<0 || centering_c>1)
        throw CImgArgumentException(_cimg_instance
                                    "resize(): Specified centering arguments (%g,%g,%g,%g) are outside range [0,1].",
                                    cimg_instance,
                                    centering_x,centering_y,centering_z,centering_c);

      if (!size_x || !size_y || !size_z || !size_c) return CImg<T>();
      const unsigned int
        sx = std::max(1U,(unsigned int)(size_x>=0?size_x:-size_x*width()/100)),
        sy = std::max(1U,(unsigned int)(size_y>=0?size_y:-size_y*height()/100)),
        sz = std::max(1U,(unsigned int)(size_z>=0?size_z:-size_z*depth()/100)),
        sc = std::max(1U,(unsigned int)(size_c>=0?size_c:-size_c*spectrum()/100));
      if (sx==_width && sy==_height && sz==_depth && sc==_spectrum) return +*this;
      if (is_empty()) return CImg<T>(sx,sy,sz,sc,(T)0);
      CImg<T> res;
      switch (interpolation_type) {

        // Raw resizing.
        //
      case -1 :
        std::memcpy(res.assign(sx,sy,sz,sc,(T)0)._data,_data,sizeof(T)*std::min(size(),(ulongT)sx*sy*sz*sc));
        break;

        // No interpolation.
        //
      case 0 : {
        const int
          xc = (int)(centering_x*((int)sx - width())),
          yc = (int)(centering_y*((int)sy - height())),
          zc = (int)(centering_z*((int)sz - depth())),
          cc = (int)(centering_c*((int)sc - spectrum()));

        switch (boundary_conditions) {
        case 3 : { // Mirror
          res.assign(sx,sy,sz,sc);
          const int w2 = 2*width(), h2 = 2*height(), d2 = 2*depth(), s2 = 2*spectrum();
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(res.size(),65536))
          cimg_forXYZC(res,x,y,z,c) {
            const int
              mx = cimg::mod(x - xc,w2), my = cimg::mod(y - yc,h2),
              mz = cimg::mod(z - zc,d2), mc = cimg::mod(c - cc,s2);
            res(x,y,z,c) = (*this)(mx<width()?mx:w2 - mx - 1,
                                   my<height()?my:h2 - my - 1,
                                   mz<depth()?mz:d2 - mz - 1,
                                   mc<spectrum()?mc:s2 - mc - 1);
          }
        } break;
        case 2 : { // Periodic
          res.assign(sx,sy,sz,sc);
          const int
            x0 = ((int)xc%width()) - width(),
            y0 = ((int)yc%height()) - height(),
            z0 = ((int)zc%depth()) - depth(),
            c0 = ((int)cc%spectrum()) - spectrum(),
            dx = width(), dy = height(), dz = depth(), dc = spectrum();
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(res.size(),65536))
          for (int c = c0; c<(int)sc; c+=dc)
            for (int z = z0; z<(int)sz; z+=dz)
              for (int y = y0; y<(int)sy; y+=dy)
                for (int x = x0; x<(int)sx; x+=dx)
                  res.draw_image(x,y,z,c,*this);
        } break;
        case 1 : { // Neumann
          res.assign(sx,sy,sz,sc).draw_image(xc,yc,zc,cc,*this);
          CImg<T> sprite;
          if (xc>0) {  // X-backward
            res.get_crop(xc,yc,zc,cc,xc,yc + height() - 1,zc + depth() - 1,cc + spectrum() - 1).move_to(sprite);
            for (int x = xc - 1; x>=0; --x) res.draw_image(x,yc,zc,cc,sprite);
          }
          if (xc + width()<(int)sx) { // X-forward
            res.get_crop(xc + width() - 1,yc,zc,cc,xc + width() - 1,yc + height() - 1,
                         zc + depth() - 1,cc + spectrum() - 1).move_to(sprite);
            for (int x = xc + width(); x<(int)sx; ++x) res.draw_image(x,yc,zc,cc,sprite);
          }
          if (yc>0) {  // Y-backward
            res.get_crop(0,yc,zc,cc,sx - 1,yc,zc + depth() - 1,cc + spectrum() - 1).move_to(sprite);
            for (int y = yc - 1; y>=0; --y) res.draw_image(0,y,zc,cc,sprite);
          }
          if (yc + height()<(int)sy) { // Y-forward
            res.get_crop(0,yc + height() - 1,zc,cc,sx - 1,yc + height() - 1,
                         zc + depth() - 1,cc + spectrum() - 1).move_to(sprite);
            for (int y = yc + height(); y<(int)sy; ++y) res.draw_image(0,y,zc,cc,sprite);
          }
          if (zc>0) {  // Z-backward
            res.get_crop(0,0,zc,cc,sx - 1,sy - 1,zc,cc + spectrum() - 1).move_to(sprite);
            for (int z = zc - 1; z>=0; --z) res.draw_image(0,0,z,cc,sprite);
          }
          if (zc + depth()<(int)sz) { // Z-forward
            res.get_crop(0,0,zc  +depth() - 1,cc,sx - 1,sy - 1,zc + depth() - 1,cc + spectrum() - 1).move_to(sprite);
            for (int z = zc + depth(); z<(int)sz; ++z) res.draw_image(0,0,z,cc,sprite);
          }
          if (cc>0) {  // C-backward
            res.get_crop(0,0,0,cc,sx - 1,sy - 1,sz - 1,cc).move_to(sprite);
            for (int c = cc - 1; c>=0; --c) res.draw_image(0,0,0,c,sprite);
          }
          if (cc + spectrum()<(int)sc) { // C-forward
            res.get_crop(0,0,0,cc + spectrum() - 1,sx - 1,sy - 1,sz - 1,cc + spectrum() - 1).move_to(sprite);
            for (int c = cc + spectrum(); c<(int)sc; ++c) res.draw_image(0,0,0,c,sprite);
          }
        } break;
        default : // Dirichlet
          res.assign(sx,sy,sz,sc,(T)0).draw_image(xc,yc,zc,cc,*this);
        }
        break;
      } break;

        // Nearest neighbor interpolation.
        //
      case 1 : {
        res.assign(sx,sy,sz,sc);
        CImg<ulongT> off_x(sx), off_y(sy + 1), off_z(sz + 1), off_c(sc + 1);
        const ulongT
          wh = (ulongT)_width*_height,
          whd = (ulongT)_width*_height*_depth,
          sxy = (ulongT)sx*sy,
          sxyz = (ulongT)sx*sy*sz,
          one = (ulongT)1;
        if (sx==_width) off_x.fill(1);
        else {
          ulongT *poff_x = off_x._data, curr = 0;
          cimg_forX(res,x) {
            const ulongT old = curr;
            curr = (x + one)*_width/sx;
            *(poff_x++) = curr - old;
          }
        }
        if (sy==_height) off_y.fill(_width);
        else {
          ulongT *poff_y = off_y._data, curr = 0;
          cimg_forY(res,y) {
            const ulongT old = curr;
            curr = (y + one)*_height/sy;
            *(poff_y++) = _width*(curr - old);
          }
          *poff_y = 0;
        }
        if (sz==_depth) off_z.fill(wh);
        else {
          ulongT *poff_z = off_z._data, curr = 0;
          cimg_forZ(res,z) {
            const ulongT old = curr;
            curr = (z + one)*_depth/sz;
            *(poff_z++) = wh*(curr - old);
          }
          *poff_z = 0;
        }
        if (sc==_spectrum) off_c.fill(whd);
        else {
          ulongT *poff_c = off_c._data, curr = 0;
          cimg_forC(res,c) {
            const ulongT old = curr;
            curr = (c + one)*_spectrum/sc;
            *(poff_c++) = whd*(curr - old);
          }
          *poff_c = 0;
        }

        T *ptrd = res._data;
        const T* ptrc = _data;
        const ulongT *poff_c = off_c._data;
        for (unsigned int c = 0; c<sc; ) {
          const T *ptrz = ptrc;
          const ulongT *poff_z = off_z._data;
          for (unsigned int z = 0; z<sz; ) {
            const T *ptry = ptrz;
            const ulongT *poff_y = off_y._data;
            for (unsigned int y = 0; y<sy; ) {
              const T *ptrx = ptry;
              const ulongT *poff_x = off_x._data;
              cimg_forX(res,x) { *(ptrd++) = *ptrx; ptrx+=*(poff_x++); }
              ++y;
              ulongT dy = *(poff_y++);
              for ( ; !dy && y<dy; std::memcpy(ptrd,ptrd - sx,sizeof(T)*sx), ++y, ptrd+=sx, dy = *(poff_y++)) {}
              ptry+=dy;
            }
            ++z;
            ulongT dz = *(poff_z++);
            for ( ; !dz && z<dz; std::memcpy(ptrd,ptrd - sxy,sizeof(T)*sxy), ++z, ptrd+=sxy, dz = *(poff_z++)) {}
            ptrz+=dz;
          }
          ++c;
          ulongT dc = *(poff_c++);
          for ( ; !dc && c<dc; std::memcpy(ptrd,ptrd - sxyz,sizeof(T)*sxyz), ++c, ptrd+=sxyz, dc = *(poff_c++)) {}
          ptrc+=dc;
        }
      } break;

        // Moving average.
        //
      case 2 : {
        bool instance_first = true;
        if (sx!=_width) {
          CImg<Tfloat> tmp(sx,_height,_depth,_spectrum,0);
          for (unsigned int a = _width*sx, b = _width, c = sx, s = 0, t = 0; a; ) {
            const unsigned int d = std::min(b,c);
            a-=d; b-=d; c-=d;
            cimg_forYZC(tmp,y,z,v) tmp(t,y,z,v)+=(Tfloat)(*this)(s,y,z,v)*d;
            if (!b) {
              cimg_forYZC(tmp,y,z,v) tmp(t,y,z,v)/=_width;
              ++t;
              b = _width;
            }
            if (!c) { ++s; c = sx; }
          }
          tmp.move_to(res);
          instance_first = false;
        }
        if (sy!=_height) {
          CImg<Tfloat> tmp(sx,sy,_depth,_spectrum,0);
          for (unsigned int a = _height*sy, b = _height, c = sy, s = 0, t = 0; a; ) {
            const unsigned int d = std::min(b,c);
            a-=d; b-=d; c-=d;
            if (instance_first)
              cimg_forXZC(tmp,x,z,v) tmp(x,t,z,v)+=(Tfloat)(*this)(x,s,z,v)*d;
            else
              cimg_forXZC(tmp,x,z,v) tmp(x,t,z,v)+=(Tfloat)res(x,s,z,v)*d;
            if (!b) {
              cimg_forXZC(tmp,x,z,v) tmp(x,t,z,v)/=_height;
              ++t;
              b = _height;
            }
            if (!c) { ++s; c = sy; }
          }
          tmp.move_to(res);
          instance_first = false;
        }
        if (sz!=_depth) {
          CImg<Tfloat> tmp(sx,sy,sz,_spectrum,0);
          for (unsigned int a = _depth*sz, b = _depth, c = sz, s = 0, t = 0; a; ) {
            const unsigned int d = std::min(b,c);
            a-=d; b-=d; c-=d;
            if (instance_first)
              cimg_forXYC(tmp,x,y,v) tmp(x,y,t,v)+=(Tfloat)(*this)(x,y,s,v)*d;
            else
              cimg_forXYC(tmp,x,y,v) tmp(x,y,t,v)+=(Tfloat)res(x,y,s,v)*d;
            if (!b) {
              cimg_forXYC(tmp,x,y,v) tmp(x,y,t,v)/=_depth;
              ++t;
              b = _depth;
            }
            if (!c) { ++s; c = sz; }
          }
          tmp.move_to(res);
          instance_first = false;
        }
        if (sc!=_spectrum) {
          CImg<Tfloat> tmp(sx,sy,sz,sc,0);
          for (unsigned int a = _spectrum*sc, b = _spectrum, c = sc, s = 0, t = 0; a; ) {
            const unsigned int d = std::min(b,c);
            a-=d; b-=d; c-=d;
            if (instance_first)
              cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)+=(Tfloat)(*this)(x,y,z,s)*d;
            else
              cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)+=(Tfloat)res(x,y,z,s)*d;
            if (!b) {
              cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)/=_spectrum;
              ++t;
              b = _spectrum;
            }
            if (!c) { ++s; c = sc; }
          }
          tmp.move_to(res);
          instance_first = false;
        }
      } break;

        // Linear interpolation.
        //
      case 3 : {
        CImg<uintT> off(cimg::max(sx,sy,sz,sc));
        CImg<doubleT> foff(off._width);
        CImg<T> resx, resy, resz, resc;
        double curr, old;

        if (sx!=_width) {
          if (_width==1) get_resize(sx,_height,_depth,_spectrum,1).move_to(resx);
          else if (_width>sx) get_resize(sx,_height,_depth,_spectrum,2).move_to(resx);
          else {
            const double fx = (!boundary_conditions && sx>_width)?(sx>1?(_width - 1.)/(sx - 1):0):
              (double)_width/sx;
            resx.assign(sx,_height,_depth,_spectrum);
            curr = old = 0;
            {
              unsigned int *poff = off._data;
              double *pfoff = foff._data;
              cimg_forX(resx,x) {
                *(pfoff++) = curr - (unsigned int)curr;
                old = curr;
                curr = std::min(width() - 1.,curr + fx);
                *(poff++) = (unsigned int)curr - (unsigned int)old;
              }
            }
            cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(resx.size(),65536))
              cimg_forYZC(resx,y,z,c) {
              const T *ptrs = data(0,y,z,c), *const ptrsmax = ptrs + _width - 1;
              T *ptrd = resx.data(0,y,z,c);
              const unsigned int *poff = off._data;
              const double *pfoff = foff._data;
              cimg_forX(resx,x) {
                const double alpha = *(pfoff++);
                const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs + 1):val1;
                *(ptrd++) = (T)((1 - alpha)*val1 + alpha*val2);
                ptrs+=*(poff++);
              }
            }
          }
        } else resx.assign(*this,true);

        if (sy!=_height) {
          if (_height==1) resx.get_resize(sx,sy,_depth,_spectrum,1).move_to(resy);
          else {
            if (_height>sy) resx.get_resize(sx,sy,_depth,_spectrum,2).move_to(resy);
            else {
              const double fy = (!boundary_conditions && sy>_height)?(sy>1?(_height - 1.)/(sy - 1):0):
                (double)_height/sy;
              resy.assign(sx,sy,_depth,_spectrum);
              curr = old = 0;
              {
                unsigned int *poff = off._data;
                double *pfoff = foff._data;
                cimg_forY(resy,y) {
                  *(pfoff++) = curr - (unsigned int)curr;
                  old = curr;
                  curr = std::min(height() - 1.,curr + fy);
                  *(poff++) = sx*((unsigned int)curr - (unsigned int)old);
                }
              }
              cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(resy.size(),65536))
              cimg_forXZC(resy,x,z,c) {
                const T *ptrs = resx.data(x,0,z,c), *const ptrsmax = ptrs + (_height - 1)*sx;
                T *ptrd = resy.data(x,0,z,c);
                const unsigned int *poff = off._data;
                const double *pfoff = foff._data;
                cimg_forY(resy,y) {
                  const double alpha = *(pfoff++);
                  const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs + sx):val1;
                  *ptrd = (T)((1 - alpha)*val1 + alpha*val2);
                  ptrd+=sx;
                  ptrs+=*(poff++);
                }
              }
            }
          }
          resx.assign();
        } else resy.assign(resx,true);

        if (sz!=_depth) {
          if (_depth==1) resy.get_resize(sx,sy,sz,_spectrum,1).move_to(resz);
          else {
            if (_depth>sz) resy.get_resize(sx,sy,sz,_spectrum,2).move_to(resz);
            else {
              const double fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth - 1.)/(sz - 1):0):
                (double)_depth/sz;
              const unsigned int sxy = sx*sy;
              resz.assign(sx,sy,sz,_spectrum);
              curr = old = 0;
              {
                unsigned int *poff = off._data;
                double *pfoff = foff._data;
                cimg_forZ(resz,z) {
                  *(pfoff++) = curr - (unsigned int)curr;
                  old = curr;
                  curr = std::min(depth() - 1.,curr + fz);
                  *(poff++) = sxy*((unsigned int)curr - (unsigned int)old);
                }
              }
              cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(resz.size(),65536))
              cimg_forXYC(resz,x,y,c) {
                const T *ptrs = resy.data(x,y,0,c), *const ptrsmax = ptrs + (_depth - 1)*sxy;
                T *ptrd = resz.data(x,y,0,c);
                const unsigned int *poff = off._data;
                const double *pfoff = foff._data;
                cimg_forZ(resz,z) {
                  const double alpha = *(pfoff++);
                  const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs + sxy):val1;
                  *ptrd = (T)((1 - alpha)*val1 + alpha*val2);
                  ptrd+=sxy;
                  ptrs+=*(poff++);
                }
              }
            }
          }
          resy.assign();
        } else resz.assign(resy,true);

        if (sc!=_spectrum) {
          if (_spectrum==1) resz.get_resize(sx,sy,sz,sc,1).move_to(resc);
          else {
            if (_spectrum>sc) resz.get_resize(sx,sy,sz,sc,2).move_to(resc);
            else {
              const double fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum - 1.)/(sc - 1):0):
                (double)_spectrum/sc;
              const unsigned int sxyz = sx*sy*sz;
              resc.assign(sx,sy,sz,sc);
              curr = old = 0;
              {
                unsigned int *poff = off._data;
                double *pfoff = foff._data;
                cimg_forC(resc,c) {
                  *(pfoff++) = curr - (unsigned int)curr;
                  old = curr;
                  curr = std::min(spectrum() - 1.,curr + fc);
                  *(poff++) = sxyz*((unsigned int)curr - (unsigned int)old);
                }
              }
              cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(resc.size(),65536))
              cimg_forXYZ(resc,x,y,z) {
                const T *ptrs = resz.data(x,y,z,0), *const ptrsmax = ptrs + (_spectrum - 1)*sxyz;
                T *ptrd = resc.data(x,y,z,0);
                const unsigned int *poff = off._data;
                const double *pfoff = foff._data;
                cimg_forC(resc,c) {
                  const double alpha = *(pfoff++);
                  const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs + sxyz):val1;
                  *ptrd = (T)((1 - alpha)*val1 + alpha*val2);
                  ptrd+=sxyz;
                  ptrs+=*(poff++);
                }
              }
            }
          }
          resz.assign();
        } else resc.assign(resz,true);
        return resc._is_shared?(resz._is_shared?(resy._is_shared?(resx._is_shared?(+(*this)):resx):resy):resz):resc;
      } break;

        // Grid interpolation.
        //
      case 4 : {
        CImg<T> resx, resy, resz, resc;
        if (sx!=_width) {
          if (sx<_width) get_resize(sx,_height,_depth,_spectrum,1).move_to(resx);
          else {
            resx.assign(sx,_height,_depth,_spectrum,(T)0);
            const int dx = (int)(2*sx), dy = 2*width();
            int err = (int)(dy + centering_x*(sx*dy/width() - dy)), xs = 0;
            cimg_forX(resx,x) if ((err-=dy)<=0) {
              cimg_forYZC(resx,y,z,c) resx(x,y,z,c) = (*this)(xs,y,z,c);
              ++xs;
              err+=dx;
            }
          }
        } else resx.assign(*this,true);

        if (sy!=_height) {
          if (sy<_height) resx.get_resize(sx,sy,_depth,_spectrum,1).move_to(resy);
          else {
            resy.assign(sx,sy,_depth,_spectrum,(T)0);
            const int dx = (int)(2*sy), dy = 2*height();
            int err = (int)(dy + centering_y*(sy*dy/height() - dy)), ys = 0;
            cimg_forY(resy,y) if ((err-=dy)<=0) {
              cimg_forXZC(resy,x,z,c) resy(x,y,z,c) = resx(x,ys,z,c);
              ++ys;
              err+=dx;
            }
          }
          resx.assign();
        } else resy.assign(resx,true);

        if (sz!=_depth) {
          if (sz<_depth) resy.get_resize(sx,sy,sz,_spectrum,1).move_to(resz);
          else {
            resz.assign(sx,sy,sz,_spectrum,(T)0);
            const int dx = (int)(2*sz), dy = 2*depth();
            int err = (int)(dy + centering_z*(sz*dy/depth() - dy)), zs = 0;
            cimg_forZ(resz,z) if ((err-=dy)<=0) {
              cimg_forXYC(resz,x,y,c) resz(x,y,z,c) = resy(x,y,zs,c);
              ++zs;
              err+=dx;
            }
          }
          resy.assign();
        } else resz.assign(resy,true);

        if (sc!=_spectrum) {
          if (sc<_spectrum) resz.get_resize(sx,sy,sz,sc,1).move_to(resc);
          else {
            resc.assign(sx,sy,sz,sc,(T)0);
            const int dx = (int)(2*sc), dy = 2*spectrum();
            int err = (int)(dy + centering_c*(sc*dy/spectrum() - dy)), cs = 0;
            cimg_forC(resc,c) if ((err-=dy)<=0) {
              cimg_forXYZ(resc,x,y,z) resc(x,y,z,c) = resz(x,y,z,cs);
              ++cs;
              err+=dx;
            }
          }
          resz.assign();
        } else resc.assign(resz,true);

        return resc._is_shared?(resz._is_shared?(resy._is_shared?(resx._is_shared?(+(*this)):resx):resy):resz):resc;
      } break;

        // Cubic interpolation.
        //
      case 5 : {
        const Tfloat vmin = (Tfloat)cimg::type<T>::min(), vmax = (Tfloat)cimg::type<T>::max();
        CImg<uintT> off(cimg::max(sx,sy,sz,sc));
        CImg<doubleT> foff(off._width);
        CImg<T> resx, resy, resz, resc;
        double curr, old;

        if (sx!=_width) {
          if (_width==1) get_resize(sx,_height,_depth,_spectrum,1).move_to(resx);
          else {
            if (_width>sx) get_resize(sx,_height,_depth,_spectrum,2).move_to(resx);
            else {
              const double fx = (!boundary_conditions && sx>_width)?(sx>1?(_width - 1.)/(sx - 1):0):
                (double)_width/sx;
              resx.assign(sx,_height,_depth,_spectrum);
              curr = old = 0;
              {
                unsigned int *poff = off._data;
                double *pfoff = foff._data;
                cimg_forX(resx,x) {
                  *(pfoff++) = curr - (unsigned int)curr;
                  old = curr;
                  curr = std::min(width() - 1.,curr + fx);
                  *(poff++) = (unsigned int)curr - (unsigned int)old;
                }
              }
              cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(resx.size(),65536))
              cimg_forYZC(resx,y,z,c) {
                const T *const ptrs0 = data(0,y,z,c), *ptrs = ptrs0, *const ptrsmax = ptrs + (_width - 2);
                T *ptrd = resx.data(0,y,z,c);
                const unsigned int *poff = off._data;
                const double *pfoff = foff._data;
                cimg_forX(resx,x) {
                  const double
                    t = *(pfoff++),
                    val1 = (double)*ptrs,
                    val0 = ptrs>ptrs0?(double)*(ptrs - 1):val1,
                    val2 = ptrs<=ptrsmax?(double)*(ptrs + 1):val1,
                    val3 = ptrs<ptrsmax?(double)*(ptrs + 2):val2,
                    val = val1 + 0.5f*(t*(-val0 + val2) + t*t*(2*val0 - 5*val1 + 4*val2 - val3) +
                                       t*t*t*(-val0 + 3*val1 - 3*val2 + val3));
                  *(ptrd++) = (T)(val<vmin?vmin:val>vmax?vmax:val);
                  ptrs+=*(poff++);
                }
              }
            }
          }
        } else resx.assign(*this,true);

        if (sy!=_height) {
          if (_height==1) resx.get_resize(sx,sy,_depth,_spectrum,1).move_to(resy);
          else {
            if (_height>sy) resx.get_resize(sx,sy,_depth,_spectrum,2).move_to(resy);
            else {
              const double fy = (!boundary_conditions && sy>_height)?(sy>1?(_height - 1.)/(sy - 1):0):
                (double)_height/sy;
              resy.assign(sx,sy,_depth,_spectrum);
              curr = old = 0;
              {
                unsigned int *poff = off._data;
                double *pfoff = foff._data;
                cimg_forY(resy,y) {
                  *(pfoff++) = curr - (unsigned int)curr;
                  old = curr;
                  curr = std::min(height() - 1.,curr + fy);
                  *(poff++) = sx*((unsigned int)curr - (unsigned int)old);
                }
              }
              cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(resy.size(),65536))
              cimg_forXZC(resy,x,z,c) {
                const T *const ptrs0 = resx.data(x,0,z,c), *ptrs = ptrs0, *const ptrsmax = ptrs + (_height - 2)*sx;
                T *ptrd = resy.data(x,0,z,c);
                const unsigned int *poff = off._data;
                const double *pfoff = foff._data;
                cimg_forY(resy,y) {
                  const double
                    t = *(pfoff++),
                    val1 = (double)*ptrs,
                    val0 = ptrs>ptrs0?(double)*(ptrs - sx):val1,
                    val2 = ptrs<=ptrsmax?(double)*(ptrs + sx):val1,
                    val3 = ptrs<ptrsmax?(double)*(ptrs + 2*sx):val2,
                    val = val1 + 0.5f*(t*(-val0 + val2) + t*t*(2*val0 - 5*val1 + 4*val2 - val3) +
                                       t*t*t*(-val0 + 3*val1 - 3*val2 + val3));
                  *ptrd = (T)(val<vmin?vmin:val>vmax?vmax:val);
                  ptrd+=sx;
                  ptrs+=*(poff++);
                }
              }
            }
          }
          resx.assign();
        } else resy.assign(resx,true);

        if (sz!=_depth) {
          if (_depth==1) resy.get_resize(sx,sy,sz,_spectrum,1).move_to(resz);
          else {
            if (_depth>sz) resy.get_resize(sx,sy,sz,_spectrum,2).move_to(resz);
            else {
              const double fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth - 1.)/(sz - 1):0):
                (double)_depth/sz;
              const unsigned int sxy = sx*sy;
              resz.assign(sx,sy,sz,_spectrum);
              curr = old = 0;
              {
                unsigned int *poff = off._data;
                double *pfoff = foff._data;
                cimg_forZ(resz,z) {
                  *(pfoff++) = curr - (unsigned int)curr;
                  old = curr;
                  curr = std::min(depth() - 1.,curr + fz);
                  *(poff++) = sxy*((unsigned int)curr - (unsigned int)old);
                }
              }
              cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(resz.size(),65536))
              cimg_forXYC(resz,x,y,c) {
                const T *const ptrs0 = resy.data(x,y,0,c), *ptrs = ptrs0, *const ptrsmax = ptrs + (_depth - 2)*sxy;
                T *ptrd = resz.data(x,y,0,c);
                const unsigned int *poff = off._data;
                const double *pfoff = foff._data;
                cimg_forZ(resz,z) {
                  const double
                    t = *(pfoff++),
                    val1 = (double)*ptrs,
                    val0 = ptrs>ptrs0?(double)*(ptrs - sxy):val1,
                    val2 = ptrs<=ptrsmax?(double)*(ptrs + sxy):val1,
                    val3 = ptrs<ptrsmax?(double)*(ptrs + 2*sxy):val2,
                    val = val1 + 0.5f*(t*(-val0 + val2) + t*t*(2*val0 - 5*val1 + 4*val2 - val3) +
                                       t*t*t*(-val0 + 3*val1 - 3*val2 + val3));
                  *ptrd = (T)(val<vmin?vmin:val>vmax?vmax:val);
                  ptrd+=sxy;
                  ptrs+=*(poff++);
                }
              }
            }
          }
          resy.assign();
        } else resz.assign(resy,true);

        if (sc!=_spectrum) {
          if (_spectrum==1) resz.get_resize(sx,sy,sz,sc,1).move_to(resc);
          else {
            if (_spectrum>sc) resz.get_resize(sx,sy,sz,sc,2).move_to(resc);
            else {
              const double fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum - 1.)/(sc - 1):0):
                (double)_spectrum/sc;
              const unsigned int sxyz = sx*sy*sz;
              resc.assign(sx,sy,sz,sc);
              curr = old = 0;
              {
                unsigned int *poff = off._data;
                double *pfoff = foff._data;
                cimg_forC(resc,c) {
                  *(pfoff++) = curr - (unsigned int)curr;
                  old = curr;
                  curr = std::min(spectrum() - 1.,curr + fc);
                  *(poff++) = sxyz*((unsigned int)curr - (unsigned int)old);
                }
              }
              cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(resc.size(),65536))
              cimg_forXYZ(resc,x,y,z) {
                const T *const ptrs0 = resz.data(x,y,z,0), *ptrs = ptrs0, *const ptrsmax = ptrs + (_spectrum - 2)*sxyz;
                T *ptrd = resc.data(x,y,z,0);
                const unsigned int *poff = off._data;
                const double *pfoff = foff._data;
                cimg_forC(resc,c) {
                  const double
                    t = *(pfoff++),
                    val1 = (double)*ptrs,
                    val0 = ptrs>ptrs0?(double)*(ptrs - sxyz):val1,
                    val2 = ptrs<=ptrsmax?(double)*(ptrs + sxyz):val1,
                    val3 = ptrs<ptrsmax?(double)*(ptrs + 2*sxyz):val2,
                    val = val1 + 0.5f*(t*(-val0 + val2) + t*t*(2*val0 - 5*val1 + 4*val2 - val3) +
                                       t*t*t*(-val0 + 3*val1 - 3*val2 + val3));
                  *ptrd = (T)(val<vmin?vmin:val>vmax?vmax:val);
                  ptrd+=sxyz;
                  ptrs+=*(poff++);
                }
              }
            }
          }
          resz.assign();
        } else resc.assign(resz,true);

        return resc._is_shared?(resz._is_shared?(resy._is_shared?(resx._is_shared?(+(*this)):resx):resy):resz):resc;
      } break;

        // Lanczos interpolation.
        //
      case 6 : {
        const double vmin = (double)cimg::type<T>::min(), vmax = (double)cimg::type<T>::max();
        CImg<uintT> off(cimg::max(sx,sy,sz,sc));
        CImg<doubleT> foff(off._width);
        CImg<T> resx, resy, resz, resc;
        double curr, old;

        if (sx!=_width) {
          if (_width==1) get_resize(sx,_height,_depth,_spectrum,1).move_to(resx);
          else {
            if (_width>sx) get_resize(sx,_height,_depth,_spectrum,2).move_to(resx);
            else {
              const double fx = (!boundary_conditions && sx>_width)?(sx>1?(_width - 1.)/(sx - 1):0):
                (double)_width/sx;
              resx.assign(sx,_height,_depth,_spectrum);
              curr = old = 0;
              {
                unsigned int *poff = off._data;
                double *pfoff = foff._data;
                cimg_forX(resx,x) {
                  *(pfoff++) = curr - (unsigned int)curr;
                  old = curr;
                  curr = std::min(width() - 1.,curr + fx);
                  *(poff++) = (unsigned int)curr - (unsigned int)old;
                }
              }
              cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(resx.size(),65536))
              cimg_forYZC(resx,y,z,c) {
                const T *const ptrs0 = data(0,y,z,c), *ptrs = ptrs0, *const ptrsmin = ptrs0 + 1,
                  *const ptrsmax = ptrs0 + (_width - 2);
                T *ptrd = resx.data(0,y,z,c);
                const unsigned int *poff = off._data;
                const double *pfoff = foff._data;
                cimg_forX(resx,x) {
                  const double
                    t = *(pfoff++),
                    w0 = _cimg_lanczos(t + 2),
                    w1 = _cimg_lanczos(t + 1),
                    w2 = _cimg_lanczos(t),
                    w3 = _cimg_lanczos(t - 1),
                    w4 = _cimg_lanczos(t - 2),
                    val2 = (double)*ptrs,
                    val1 = ptrs>=ptrsmin?(double)*(ptrs - 1):val2,
                    val0 = ptrs>ptrsmin?(double)*(ptrs - 2):val1,
                    val3 = ptrs<=ptrsmax?(double)*(ptrs + 1):val2,
                    val4 = ptrs<ptrsmax?(double)*(ptrs + 2):val3,
                    val = (val0*w0 + val1*w1 + val2*w2 + val3*w3 + val4*w4)/(w1 + w2 + w3 + w4);
                  *(ptrd++) = (T)(val<vmin?vmin:val>vmax?vmax:val);
                  ptrs+=*(poff++);
                }
              }
            }
          }
        } else resx.assign(*this,true);

        if (sy!=_height) {
          if (_height==1) resx.get_resize(sx,sy,_depth,_spectrum,1).move_to(resy);
          else {
            if (_height>sy) resx.get_resize(sx,sy,_depth,_spectrum,2).move_to(resy);
            else {
              const double fy = (!boundary_conditions && sy>_height)?(sy>1?(_height - 1.)/(sy - 1):0):
                (double)_height/sy;
              resy.assign(sx,sy,_depth,_spectrum);
              curr = old = 0;
              {
                unsigned int *poff = off._data;
                double *pfoff = foff._data;
                cimg_forY(resy,y) {
                  *(pfoff++) = curr - (unsigned int)curr;
                  old = curr;
                  curr = std::min(height() - 1.,curr + fy);
                  *(poff++) = sx*((unsigned int)curr - (unsigned int)old);
                }
              }
              cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(resy.size(),65536))
              cimg_forXZC(resy,x,z,c) {
                const T *const ptrs0 = resx.data(x,0,z,c), *ptrs = ptrs0, *const ptrsmin = ptrs0 + sx,
                  *const ptrsmax = ptrs0 + (_height - 2)*sx;
                T *ptrd = resy.data(x,0,z,c);
                const unsigned int *poff = off._data;
                const double *pfoff = foff._data;
                cimg_forY(resy,y) {
                  const double
                    t = *(pfoff++),
                    w0 = _cimg_lanczos(t + 2),
                    w1 = _cimg_lanczos(t + 1),
                    w2 = _cimg_lanczos(t),
                    w3 = _cimg_lanczos(t - 1),
                    w4 = _cimg_lanczos(t - 2),
                    val2 = (double)*ptrs,
                    val1 = ptrs>=ptrsmin?(double)*(ptrs - sx):val2,
                    val0 = ptrs>ptrsmin?(double)*(ptrs - 2*sx):val1,
                    val3 = ptrs<=ptrsmax?(double)*(ptrs + sx):val2,
                    val4 = ptrs<ptrsmax?(double)*(ptrs + 2*sx):val3,
                    val = (val0*w0 + val1*w1 + val2*w2 + val3*w3 + val4*w4)/(w1 + w2 + w3 + w4);
                  *ptrd = (T)(val<vmin?vmin:val>vmax?vmax:val);
                  ptrd+=sx;
                  ptrs+=*(poff++);
                }
              }
            }
          }
          resx.assign();
        } else resy.assign(resx,true);

        if (sz!=_depth) {
          if (_depth==1) resy.get_resize(sx,sy,sz,_spectrum,1).move_to(resz);
          else {
            if (_depth>sz) resy.get_resize(sx,sy,sz,_spectrum,2).move_to(resz);
            else {
              const double fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth - 1.)/(sz - 1):0):
                (double)_depth/sz;
              const unsigned int sxy = sx*sy;
              resz.assign(sx,sy,sz,_spectrum);
              curr = old = 0;
              {
                unsigned int *poff = off._data;
                double *pfoff = foff._data;
                cimg_forZ(resz,z) {
                  *(pfoff++) = curr - (unsigned int)curr;
                  old = curr;
                  curr = std::min(depth() - 1.,curr + fz);
                  *(poff++) = sxy*((unsigned int)curr - (unsigned int)old);
                }
              }
              cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(resz.size(),65536))
              cimg_forXYC(resz,x,y,c) {
                const T *const ptrs0 = resy.data(x,y,0,c), *ptrs = ptrs0, *const ptrsmin = ptrs0 + sxy,
                  *const ptrsmax = ptrs0 + (_depth - 2)*sxy;
                T *ptrd = resz.data(x,y,0,c);
                const unsigned int *poff = off._data;
                const double *pfoff = foff._data;
                cimg_forZ(resz,z) {
                  const double
                    t = *(pfoff++),
                    w0 = _cimg_lanczos(t + 2),
                    w1 = _cimg_lanczos(t + 1),
                    w2 = _cimg_lanczos(t),
                    w3 = _cimg_lanczos(t - 1),
                    w4 = _cimg_lanczos(t - 2),
                    val2 = (double)*ptrs,
                    val1 = ptrs>=ptrsmin?(double)*(ptrs - sxy):val2,
                    val0 = ptrs>ptrsmin?(double)*(ptrs - 2*sxy):val1,
                    val3 = ptrs<=ptrsmax?(double)*(ptrs + sxy):val2,
                    val4 = ptrs<ptrsmax?(double)*(ptrs + 2*sxy):val3,
                    val = (val0*w0 + val1*w1 + val2*w2 + val3*w3 + val4*w4)/(w1 + w2 + w3 + w4);
                  *ptrd = (T)(val<vmin?vmin:val>vmax?vmax:val);
                  ptrd+=sxy;
                  ptrs+=*(poff++);
                }
              }
            }
          }
          resy.assign();
        } else resz.assign(resy,true);

        if (sc!=_spectrum) {
          if (_spectrum==1) resz.get_resize(sx,sy,sz,sc,1).move_to(resc);
          else {
            if (_spectrum>sc) resz.get_resize(sx,sy,sz,sc,2).move_to(resc);
            else {
              const double fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum - 1.)/(sc - 1):0):
                (double)_spectrum/sc;
              const unsigned int sxyz = sx*sy*sz;
              resc.assign(sx,sy,sz,sc);
              curr = old = 0;
              {
                unsigned int *poff = off._data;
                double *pfoff = foff._data;
                cimg_forC(resc,c) {
                  *(pfoff++) = curr - (unsigned int)curr;
                  old = curr;
                  curr = std::min(spectrum() - 1.,curr + fc);
                  *(poff++) = sxyz*((unsigned int)curr - (unsigned int)old);
                }
              }
              cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(resc.size(),65536))
              cimg_forXYZ(resc,x,y,z) {
                const T *const ptrs0 = resz.data(x,y,z,0), *ptrs = ptrs0, *const ptrsmin = ptrs0 + sxyz,
                  *const ptrsmax = ptrs + (_spectrum - 2)*sxyz;
                T *ptrd = resc.data(x,y,z,0);
                const unsigned int *poff = off._data;
                const double *pfoff = foff._data;
                cimg_forC(resc,c) {
                  const double
                    t = *(pfoff++),
                    w0 = _cimg_lanczos(t + 2),
                    w1 = _cimg_lanczos(t + 1),
                    w2 = _cimg_lanczos(t),
                    w3 = _cimg_lanczos(t - 1),
                    w4 = _cimg_lanczos(t - 2),
                    val2 = (double)*ptrs,
                    val1 = ptrs>=ptrsmin?(double)*(ptrs - sxyz):val2,
                    val0 = ptrs>ptrsmin?(double)*(ptrs - 2*sxyz):val1,
                    val3 = ptrs<=ptrsmax?(double)*(ptrs + sxyz):val2,
                    val4 = ptrs<ptrsmax?(double)*(ptrs + 2*sxyz):val3,
                    val = (val0*w0 + val1*w1 + val2*w2 + val3*w3 + val4*w4)/(w1 + w2 + w3 + w4);
                  *ptrd = (T)(val<vmin?vmin:val>vmax?vmax:val);
                  ptrd+=sxyz;
                  ptrs+=*(poff++);
                }
              }
            }
          }
          resz.assign();
        } else resc.assign(resz,true);

        return resc._is_shared?(resz._is_shared?(resy._is_shared?(resx._is_shared?(+(*this)):resx):resy):resz):resc;
      } break;

        // Unknow interpolation.
        //
      default :
        throw CImgArgumentException(_cimg_instance
                                    "resize(): Invalid specified interpolation %d "
                                    "(should be { -1=raw | 0=none | 1=nearest | 2=average | 3=linear | 4=grid | "
                                    "5=cubic | 6=lanczos }).",
                                    cimg_instance,
                                    interpolation_type);
      }
      return res;

Project: CImg
File: CImg.h

    template<> struct type<double> {

Project: CImg
File: CImg.h

    /**
       \param axis Appending axis. Can be <tt>{ 'x' | 'y' | 'z' | 'c' }</tt>.
       \param align Appending alignment.
    **/
    CImg<T> get_append(const char axis, const float align=0) const {
      if (is_empty()) return CImg<T>();
      if (_width==1) return +((*this)[0]);
      unsigned int dx = 0, dy = 0, dz = 0, dc = 0, pos = 0;
      CImg<T> res;
      switch (cimg::lowercase(axis)) {
      case 'x' : { // Along the X-axis
        cimglist_for(*this,l) {
          const CImg<T>& img = (*this)[l];
          if (img) {
            dx+=img._width;
            dy = std::max(dy,img._height);
            dz = std::max(dz,img._depth);
            dc = std::max(dc,img._spectrum);
          }
        }
        res.assign(dx,dy,dz,dc,(T)0);
        if (res) cimglist_for(*this,l) {
            const CImg<T>& img = (*this)[l];
            if (img) res.draw_image(pos,
                                    (int)(align*(dy - img._height)),
                                    (int)(align*(dz - img._depth)),
                                    (int)(align*(dc - img._spectrum)),
                                    img);
            pos+=img._width;
          }
      } break;
      case 'y' : { // Along the Y-axis
        cimglist_for(*this,l) {
          const CImg<T>& img = (*this)[l];
          if (img) {
            dx = std::max(dx,img._width);
            dy+=img._height;
            dz = std::max(dz,img._depth);
            dc = std::max(dc,img._spectrum);
          }
        }
        res.assign(dx,dy,dz,dc,(T)0);
        if (res) cimglist_for(*this,l) {
            const CImg<T>& img = (*this)[l];
            if (img) res.draw_image((int)(align*(dx - img._width)),
                                    pos,
                                    (int)(align*(dz - img._depth)),
                                    (int)(align*(dc - img._spectrum)),
                                    img);
            pos+=img._height;
          }
      } break;
      case 'z' : { // Along the Z-axis
        cimglist_for(*this,l) {
          const CImg<T>& img = (*this)[l];
          if (img) {
            dx = std::max(dx,img._width);
            dy = std::max(dy,img._height);
            dz+=img._depth;
            dc = std::max(dc,img._spectrum);
          }
        }
        res.assign(dx,dy,dz,dc,(T)0);
        if (res) cimglist_for(*this,l) {
            const CImg<T>& img = (*this)[l];
            if (img) res.draw_image((int)(align*(dx - img._width)),
                                    (int)(align*(dy - img._height)),
                                    pos,
                                    (int)(align*(dc - img._spectrum)),
                                    img);
            pos+=img._depth;
          }
      } break;
      default : { // Along the C-axis
        cimglist_for(*this,l) {
          const CImg<T>& img = (*this)[l];
          if (img) {
            dx = std::max(dx,img._width);
            dy = std::max(dy,img._height);
            dz = std::max(dz,img._depth);
            dc+=img._spectrum;
          }
        }
        res.assign(dx,dy,dz,dc,(T)0);
        if (res) cimglist_for(*this,l) {
            const CImg<T>& img = (*this)[l];
            if (img) res.draw_image((int)(align*(dx - img._width)),
                                    (int)(align*(dy - img._height)),
                                    (int)(align*(dz - img._depth)),
                                    pos,
                                    img);
            pos+=img._spectrum;
          }

Project: CImg
File: CImg.h


      static double mp_list_set_Joff_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 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(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

    }

    //! Insert a copy of the image \c img into the current image list, at position \c pos \newinstance.

Project: CImg
File: CImg.h

      // Evaluation procedure.
      double operator()(const double x, const double y, const double z, const double c) {
        mem[_cimg_mp_slot_x] = x; mem[_cimg_mp_slot_y] = y; mem[_cimg_mp_slot_z] = z; mem[_cimg_mp_slot_c] = c;
        for (p_code = code; p_code<p_code_end; ++p_code) {
          opcode._data = p_code->_data;
          const ulongT target = opcode[1];
          mem[target] = _cimg_mp_defunc(*this);
        }
        return *result;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    **/
    CImg<T>& sharpen(const float amplitude, const bool sharpen_type=false, const float edge=1,
                     const float alpha=0, const float sigma=0) {
      if (is_empty()) return *this;
      T val_min, val_max = max_min(val_min);
      const float nedge = edge/2;
      CImg<Tfloat> velocity(_width,_height,_depth,_spectrum), _veloc_max(_spectrum);

      if (_depth>1) { // 3D
        if (sharpen_type) { // Shock filters
          CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensors():get_structure_tensors());
          if (sigma>0) G.blur(sigma);
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*32 &&
                                                                     _height*_depth>=16))
          cimg_forYZ(G,y,z) {
            Tfloat *ptrG0 = G.data(0,y,z,0), *ptrG1 = G.data(0,y,z,1),
              *ptrG2 = G.data(0,y,z,2), *ptrG3 = G.data(0,y,z,3);
            CImg<Tfloat> val, vec;
            cimg_forX(G,x) {
              G.get_tensor_at(x,y,z).symmetric_eigen(val,vec);
              if (val[0]<0) val[0] = 0;
              if (val[1]<0) val[1] = 0;
              if (val[2]<0) val[2] = 0;
              *(ptrG0++) = vec(0,0);
              *(ptrG1++) = vec(0,1);
              *(ptrG2++) = vec(0,2);
              *(ptrG3++) = 1 - (Tfloat)std::pow(1 + val[0] + val[1] + val[2],-(Tfloat)nedge);
            }
          }
          cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height*_depth>=(cimg_openmp_sizefactor)*512 &&
                                                         _spectrum>=2))
          cimg_forC(*this,c) {
            Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0;
            CImg_3x3x3(I,Tfloat);
            cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) {
              const Tfloat
                u = G(x,y,z,0),
                v = G(x,y,z,1),
                w = G(x,y,z,2),
                amp = G(x,y,z,3),
                ixx = Incc + Ipcc - 2*Iccc,
                ixy = (Innc + Ippc - Inpc - Ipnc)/4,
                ixz = (Incn + Ipcp - Incp - Ipcn)/4,
                iyy = Icnc + Icpc - 2*Iccc,
                iyz = (Icnn + Icpp - Icnp - Icpn)/4,
                izz = Iccn + Iccp - 2*Iccc,
                ixf = Incc - Iccc,
                ixb = Iccc - Ipcc,
                iyf = Icnc - Iccc,
                iyb = Iccc - Icpc,
                izf = Iccn - Iccc,
                izb = Iccc - Iccp,
                itt = u*u*ixx + v*v*iyy + w*w*izz + 2*u*v*ixy + 2*u*w*ixz + 2*v*w*iyz,
                it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb) + w*cimg::minmod(izf,izb),
                veloc = -amp*cimg::sign(itt)*cimg::abs(it);
              *(ptrd++) = veloc;
              if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc;
            }
            _veloc_max[c] = veloc_max;
          }
        } else  // Inverse diffusion
          cimg_forC(*this,c) {
            Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0;
            CImg_3x3x3(I,Tfloat);
            cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) {
              const Tfloat veloc = -Ipcc - Incc - Icpc - Icnc - Iccp - Iccn + 6*Iccc;
              *(ptrd++) = veloc;
              if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc;
            }
            _veloc_max[c] = veloc_max;
          }
      } else { // 2D
        if (sharpen_type) { // Shock filters
          CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensors():get_structure_tensors());
          if (sigma>0) G.blur(sigma);
          cimg_pragma_openmp(parallel for cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*32 &&
                                                         _height>=(cimg_openmp_sizefactor)*16))
          cimg_forY(G,y) {
            CImg<Tfloat> val, vec;
            Tfloat *ptrG0 = G.data(0,y,0,0), *ptrG1 = G.data(0,y,0,1), *ptrG2 = G.data(0,y,0,2);
            cimg_forX(G,x) {
              G.get_tensor_at(x,y).symmetric_eigen(val,vec);
              if (val[0]<0) val[0] = 0;
              if (val[1]<0) val[1] = 0;
              *(ptrG0++) = vec(0,0);
              *(ptrG1++) = vec(0,1);
              *(ptrG2++) = 1 - (Tfloat)std::pow(1 + val[0] + val[1],-(Tfloat)nedge);
            }
          }
          cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height>=(cimg_openmp_sizefactor)*512 &&
                                                         _spectrum>=2))
          cimg_forC(*this,c) {
            Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0;
            CImg_3x3(I,Tfloat);
            cimg_for3x3(*this,x,y,0,c,I,Tfloat) {
              const Tfloat
                u = G(x,y,0),
                v = G(x,y,1),
                amp = G(x,y,2),
                ixx = Inc + Ipc - 2*Icc,
                ixy = (Inn + Ipp - Inp - Ipn)/4,
                iyy = Icn + Icp - 2*Icc,
                ixf = Inc - Icc,
                ixb = Icc - Ipc,
                iyf = Icn - Icc,
                iyb = Icc - Icp,
                itt = u*u*ixx + v*v*iyy + 2*u*v*ixy,
                it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb),
                veloc = -amp*cimg::sign(itt)*cimg::abs(it);
              *(ptrd++) = veloc;
              if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc;
            }
            _veloc_max[c] = veloc_max;
          }
        } else // Inverse diffusion
          cimg_forC(*this,c) {
            Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0;
            CImg_3x3(I,Tfloat);
            cimg_for3x3(*this,x,y,0,c,I,Tfloat) {
              const Tfloat veloc = -Ipc - Inc - Icp - Icn + 4*Icc;
              *(ptrd++) = veloc;
              if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc;
            }
            _veloc_max[c] = veloc_max;
          }
      }
      const Tfloat veloc_max = _veloc_max.max();
      if (veloc_max<=0) return *this;
      return ((velocity*=amplitude/veloc_max)+=*this).cut(val_min,val_max).move_to(*this);

Project: CImg
File: CImg.h

    template<typename tf>
    static CImg<floatT> cylinder3d(CImgList<tf>& primitives,
                                   const float radius=50, const float size_z=100, const unsigned int subdivisions=24) {
      primitives.assign();
      if (!subdivisions) return CImg<floatT>();
      CImgList<floatT> vertices(2,1,3,1,1,
                                0.,0.,0.,
                                0.,0.,size_z);
      for (float delta = 360.f/subdivisions, angle = 0; angle<360; angle+=delta) {
	const float a = (float)(angle*cimg::PI/180);
        CImg<floatT>::vector((float)(radius*std::cos(a)),(float)(radius*std::sin(a)),0.f).move_to(vertices);
        CImg<floatT>::vector((float)(radius*std::cos(a)),(float)(radius*std::sin(a)),size_z).move_to(vertices);
      }
      const unsigned int nbr = (vertices._width - 2)/2;
      for (unsigned int p = 0; p<nbr; ++p) {
	const unsigned int curr = 2 + 2*p, next = 2 + (2*((p + 1)%nbr));
        CImg<tf>::vector(0,next,curr).move_to(primitives);
        CImg<tf>::vector(1,curr + 1,next + 1).move_to(primitives);
        CImg<tf>::vector(curr,next,next + 1,curr + 1).move_to(primitives);
      }
      return vertices>'x';

Project: CImg
File: CImg.h


      static double mp_argkth(_cimg_math_parser& mp) {
        const unsigned int i_end = (unsigned int)mp.opcode[2];
        const double val = mp_kth(mp);
        for (unsigned int i = 4; i<i_end; ++i) if (val==_mp_arg(i)) return i - 3.;
        return 1;

Project: CImg
File: CImg.h


    Tfloat _linear_atX(const float fx, const int y=0, const int z=0, const int c=0) const {
      const float
        nfx = cimg::cut(fx,0,width() - 1);
      const unsigned int
        x = (unsigned int)nfx;
      const float
        dx = nfx - x;
      const unsigned int
        nx = dx>0?x + 1:x;
      const Tfloat
        Ic = (Tfloat)(*this)(x,y,z,c), In = (Tfloat)(*this)(nx,y,z,c);
      return Ic + dx*(In - Ic);

Project: CImg
File: CImg.h

    **/
    T cubic_atXYZ_c(const float fx, const float fy, const float fz, const int c) const {
      return cimg::type<T>::cut(cubic_atXYZ(fx,fy,fz,c));

Project: CImg
File: CImg.h

    template<typename t>
    CImg<Tfloat> get_pow(const CImg<t>& img) const {
      return CImg<Tfloat>(*this,false).pow(img);

Project: CImg
File: CImg.h

    }
    CImg<T>& operator=(CImg<T>&& img) {
      if (_is_shared) return assign(img);
      return img.swap(*this);

Project: CImg
File: CImg.h

    **/
    T& atN(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):(*this)(pos,x,y,z,c);

Project: CImg
File: CImg.h

    const CImgList<T>& save_cimg(std::FILE *file, const bool is_compressed=false) const {
      return _save_cimg(file,0,is_compressed);
    }

    const CImgList<T>& _save_cimg(std::FILE *const file, const char *const filename,
                                 const unsigned int n0,
                                 const unsigned int x0, const unsigned int y0,
                                 const unsigned int z0, const unsigned int c0) const {
#define _cimg_save_cimg_case(Ts,Tss) \
      if (!saved && !cimg::strcasecmp(Ts,str_pixeltype)) { \
        for (unsigned int l = 0; l<lmax; ++l) { \
          j = 0; while ((i=std::fgetc(nfile))!='\n') tmp[j++]=(char)i; tmp[j] = 0; \
          W = H = D = C = 0; \
          if (cimg_sscanf(tmp,"%u %u %u %u",&W,&H,&D,&C)!=4) \
            throw CImgIOException(_cimglist_instance \
                                  "save_cimg(): Invalid size (%u,%u,%u,%u) of image[%u], for file '%s'.", \
                                  cimglist_instance, \
                                  W,H,D,C,l,filename?filename:"(FILE*)"); \
          if (W*H*D*C>0) { \
            if (l<n0 || x0>=W || y0>=H || z0>=D || c0>=D) cimg::fseek(nfile,W*H*D*C*sizeof(Tss),SEEK_CUR); \
            else { \
              const CImg<T>& img = (*this)[l - n0]; \
              const T *ptrs = img._data; \
              const unsigned int \
                x1 = x0 + img._width - 1, \
                y1 = y0 + img._height - 1, \
                z1 = z0 + img._depth - 1, \
                c1 = c0 + img._spectrum - 1, \
                nx1 = x1>=W?W - 1:x1, \
                ny1 = y1>=H?H - 1:y1, \
                nz1 = z1>=D?D - 1:z1, \
                nc1 = c1>=C?C - 1:c1; \
              CImg<Tss> raw(1 + nx1 - x0); \
              const unsigned int skipvb = c0*W*H*D*sizeof(Tss); \
              if (skipvb) cimg::fseek(nfile,skipvb,SEEK_CUR); \
              for (unsigned int v = 1 + nc1 - c0; v; --v) { \
                const unsigned int skipzb = z0*W*H*sizeof(Tss); \
                if (skipzb) cimg::fseek(nfile,skipzb,SEEK_CUR); \
                for (unsigned int z = 1 + nz1 - z0; z; --z) { \
                  const unsigned int skipyb = y0*W*sizeof(Tss); \
                  if (skipyb) cimg::fseek(nfile,skipyb,SEEK_CUR); \
                  for (unsigned int y = 1 + ny1 - y0; y; --y) { \
                    const unsigned int skipxb = x0*sizeof(Tss); \
                    if (skipxb) cimg::fseek(nfile,skipxb,SEEK_CUR); \
                    raw.assign(ptrs, raw._width); \
                    ptrs+=img._width; \
                    if (endian) cimg::invert_endianness(raw._data,raw._width); \
                    cimg::fwrite(raw._data,raw._width,nfile); \
                    const unsigned int skipxe = (W - 1 - nx1)*sizeof(Tss); \
                    if (skipxe) cimg::fseek(nfile,skipxe,SEEK_CUR); \
                  } \
                  const unsigned int skipye = (H - 1 - ny1)*W*sizeof(Tss); \
                  if (skipye) cimg::fseek(nfile,skipye,SEEK_CUR); \
                } \
                const unsigned int skipze = (D - 1 - nz1)*W*H*sizeof(Tss); \
                if (skipze) cimg::fseek(nfile,skipze,SEEK_CUR); \
              } \
              const unsigned int skipve = (C - 1 - nc1)*W*H*D*sizeof(Tss); \
              if (skipve) cimg::fseek(nfile,skipve,SEEK_CUR); \
            } \
          } \
        } \
        saved = true; \
      }

      if (!file && !filename)
        throw CImgArgumentException(_cimglist_instance
                                    "save_cimg(): Specified filename is (null).",
                                    cimglist_instance);
      if (is_empty())
        throw CImgInstanceException(_cimglist_instance
                                    "save_cimg(): Empty instance, for file '%s'.",
                                    cimglist_instance,
                                    filename?filename:"(FILE*)");

      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb+");
      bool saved = false, endian = cimg::endianness();
      CImg<charT> tmp(256), str_pixeltype(256), str_endian(256);
      *tmp = *str_pixeltype = *str_endian = 0;
      unsigned int j, N, W, H, D, C;
      int i, err;
      j = 0; while ((i=std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = 0;
      err = cimg_sscanf(tmp,"%u%*c%255[A-Za-z64_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype._data,str_endian._data);
      if (err<2) {
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimglist_instance
                              "save_cimg(): CImg header not found in file '%s'.",
                              cimglist_instance,
                              filename?filename:"(FILE*)");
      }
      if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
      else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
      const unsigned int lmax = std::min(N,n0 + _width);
      _cimg_save_cimg_case("bool",bool);
      _cimg_save_cimg_case("unsigned_char",unsigned char);
      _cimg_save_cimg_case("uchar",unsigned char);
      _cimg_save_cimg_case("char",char);
      _cimg_save_cimg_case("unsigned_short",unsigned short);
      _cimg_save_cimg_case("ushort",unsigned short);
      _cimg_save_cimg_case("short",short);
      _cimg_save_cimg_case("unsigned_int",unsigned int);
      _cimg_save_cimg_case("uint",unsigned int);
      _cimg_save_cimg_case("int",int);
      _cimg_save_cimg_case("unsigned_int64",uint64T);
      _cimg_save_cimg_case("uint64",uint64T);
      _cimg_save_cimg_case("int64",int64T);
      _cimg_save_cimg_case("float",float);
      _cimg_save_cimg_case("double",double);
      if (!saved) {
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimglist_instance
                              "save_cimg(): Unsupported data type '%s' for file '%s'.",
                              cimglist_instance,
                              filename?filename:"(FILE*)",str_pixeltype._data);

Project: CImg
File: CImg.h

    **/
    CImg<T>& set_linear_atXY(const T& value, const float fx, const float fy=0, const int z=0, const int c=0,
                             const bool is_added=false) {
      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;
      if (z>=0 && z<depth() && c>=0 && c<spectrum()) {
        if (y>=0 && y<height()) {
          if (x>=0 && x<width()) {
            const float w1 = (1 - dx)*(1 - dy), w2 = is_added?1:(1 - w1);
            (*this)(x,y,z,c) = (T)(w1*value + w2*(*this)(x,y,z,c));
          }
          if (nx>=0 && nx<width()) {
            const float w1 = dx*(1 - dy), w2 = is_added?1:(1 - w1);
            (*this)(nx,y,z,c) = (T)(w1*value + w2*(*this)(nx,y,z,c));
          }
        }
        if (ny>=0 && ny<height()) {
          if (x>=0 && x<width()) {
            const float w1 = (1 - dx)*dy, w2 = is_added?1:(1 - w1);
            (*this)(x,ny,z,c) = (T)(w1*value + w2*(*this)(x,ny,z,c));
          }
          if (nx>=0 && nx<width()) {
            const float w1 = dx*dy, w2 = is_added?1:(1 - w1);
            (*this)(nx,ny,z,c) = (T)(w1*value + w2*(*this)(nx,ny,z,c));
          }
        }
      }
      return *this;

Project: CImg
File: CImg.h

      \param filename Filename to write data to.
      \param chroma_subsampling Type of chroma subsampling. Can be <tt>{ 420 | 422 | 444 }</tt>.
      \param is_rgb Tells if the RGB to YUV conversion must be done for saving.
    **/
    const CImgList<T>& save_yuv(const char *const filename=0,

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

    }

    //! Unserialize a CImg<unsigned char> serialized buffer into a CImgList<T> list.
    template<typename t>
    static CImgList<T> get_unserialize(const CImg<t>& buffer) {
#ifdef cimg_use_zlib
#define _cimgz_unserialize_case(Tss) { \
        Bytef *cbuf = 0; \
        if (sizeof(t)!=1 || cimg::type<t>::string()==cimg::type<bool>::string()) { \
          cbuf = new Bytef[csiz]; Bytef *_cbuf = cbuf; \
          for (ulongT k = 0; k<csiz; ++k) *(_cbuf++) = (Bytef)*(stream++); \
          is_bytef = false; \
        } else { cbuf = (Bytef*)stream; stream+=csiz; is_bytef = true; } \
        raw.assign(W,H,D,C); \
        uLongf destlen = raw.size()*sizeof(Tss); \
        uncompress((Bytef*)raw._data,&destlen,cbuf,csiz); \
        if (!is_bytef) delete[] cbuf; \
      }
#else
#define _cimgz_unserialize_case(Tss) \
      throw CImgArgumentException("CImgList<%s>::get_unserialize(): Unable to unserialize compressed data " \
                                  "unless zlib is enabled.", \
                                  pixel_type());
#endif

#define _cimg_unserialize_case(Ts,Tss) \
      if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \
        for (unsigned int l = 0; l<N; ++l) { \
          j = 0; while ((i=(int)*stream)!='\n' && stream<estream && j<255) { ++stream; tmp[j++] = (char)i; } \
          ++stream; tmp[j] = 0; \
          W = H = D = C = 0; csiz = 0; \
          if ((err = cimg_sscanf(tmp,"%u %u %u %u #" cimg_fuint64,&W,&H,&D,&C,&csiz))<4) \
            throw CImgArgumentException("CImgList<%s>::unserialize(): Invalid specified size (%u,%u,%u,%u) for " \
                                        "image #%u in serialized buffer.", \
                                        pixel_type(),W,H,D,C,l); \
          if (W*H*D*C>0) { \
            CImg<Tss> raw; \
            CImg<T> &img = res._data[l]; \
            if (err==5) _cimgz_unserialize_case(Tss) \
            else if (sizeof(Tss)==sizeof(t) && cimg::type<Tss>::is_float()==cimg::type<t>::is_float()) { \
              raw.assign((Tss*)stream,W,H,D,C,true); \
              stream+=raw.size(); \
            } else { \
              raw.assign(W,H,D,C); \
              CImg<ucharT> _raw((unsigned char*)raw._data,W*sizeof(Tss),H,D,C,true); \
              cimg_for(_raw,p,unsigned char) *p = (unsigned char)*(stream++); \
            } \
            if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw.size()); \
            raw.move_to(img); \
          } \
        } \
        loaded = true; \
      }

      if (buffer.is_empty())
        throw CImgArgumentException("CImgList<%s>::get_unserialize(): Specified serialized buffer is (null).",
                                    pixel_type());
      CImgList<T> res;
      const t *stream = buffer._data, *const estream = buffer._data + buffer.size();
      bool loaded = false, endian = cimg::endianness(), is_bytef = false;
      CImg<charT> tmp(256), str_pixeltype(256), str_endian(256);
      *tmp = *str_pixeltype = *str_endian = 0;
      unsigned int j, N = 0, W, H, D, C;
      uint64T csiz;
      int i, err;
      cimg::unused(is_bytef);
      do {
        j = 0; while ((i=(int)*stream)!='\n' && stream<estream && j<255) { ++stream; tmp[j++] = (char)i; }
        ++stream; tmp[j] = 0;
      } while (*tmp=='#' && stream<estream);
      err = cimg_sscanf(tmp,"%u%*c%255[A-Za-z64_]%*c%255[sA-Za-z_ ]",
                        &N,str_pixeltype._data,str_endian._data);
      if (err<2)
        throw CImgArgumentException("CImgList<%s>::get_unserialize(): CImg header not found in serialized buffer.",
                                    pixel_type());
      if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
      else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
      res.assign(N);
      _cimg_unserialize_case("bool",bool);
      _cimg_unserialize_case("unsigned_char",unsigned char);
      _cimg_unserialize_case("uchar",unsigned char);
      _cimg_unserialize_case("char",char);
      _cimg_unserialize_case("unsigned_short",unsigned short);
      _cimg_unserialize_case("ushort",unsigned short);
      _cimg_unserialize_case("short",short);
      _cimg_unserialize_case("unsigned_int",unsigned int);
      _cimg_unserialize_case("uint",unsigned int);
      _cimg_unserialize_case("int",int);
      _cimg_unserialize_case("unsigned_int64",uint64T);
      _cimg_unserialize_case("uint64",uint64T);
      _cimg_unserialize_case("int64",int64T);
      _cimg_unserialize_case("float",float);
      _cimg_unserialize_case("double",double);
      if (!loaded)
        throw CImgArgumentException("CImgList<%s>::get_unserialize(): Unsupported pixel type '%s' defined "

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_line(int x0, int y0, const float z0,
                       int x1, int y1, const float z1,
                       const CImg<tc>& texture,
                       const int tx0, const int ty0,
                       const int tx1, const int ty1,
                       const float opacity=1,
                       const unsigned int pattern=~0U, const bool init_hatch=true) {
      if (is_empty() || z0<=0 || z1<=0 || !opacity || !pattern) return *this;
      if (texture._depth>1 || texture._spectrum<_spectrum)
        throw CImgArgumentException(_cimg_instance
                                    "draw_line(): 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_line(x0,y0,z0,x1,y1,z1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);

      if (std::min(y0,y1)>=height() || std::max(y0,y1)<0 || std::min(x0,x1)>=width() || std::max(x0,x1)<0) return *this;

      float iz0 = 1/z0, iz1 = 1/z1;
      int
        w1 = width() - 1, h1 = height() - 1,
        dx01 = x1 - x0, dy01 = y1 - y0;
      float
        diz01 = iz1 - iz0,
        txz0 = tx0*iz0, txz1 = tx1*iz1,
        tyz0 = ty0*iz0, tyz1 = ty1*iz1,
        dtxz01 = txz1 - txz0, dtyz01 = tyz1 - tyz0;

      const bool is_horizontal = cimg::abs(dx01)>cimg::abs(dy01);
      if (is_horizontal) cimg::swap(x0,y0,x1,y1,w1,h1,dx01,dy01);
      if (pattern==~0U && y0>y1) {
        cimg::swap(x0,x1,y0,y1,iz0,iz1,txz0,txz1,tyz0,tyz1);
        dx01*=-1; dy01*=-1; diz01*=-1; dtxz01*=-1; dtyz01*=-1;
      }

      const ulongT twhd = (ulongT)texture._width*texture._height*texture._depth;
      static unsigned int hatch = ~0U - (~0U>>1);
      if (init_hatch) hatch = ~0U - (~0U>>1);
      cimg_init_scanline(opacity);

      const int
        step = y0<=y1?1:-1, hdy01 = dy01*cimg::sign(dx01)/2,
        cy0 = cimg::cut(y0,0,h1), cy1 = cimg::cut(y1,0,h1) + step;
      dy01+=dy01?0:1;

      for (int y = cy0; y!=cy1; y+=step) {
        const int
          yy0 = y - y0,
          x = x0 + (dx01*yy0 + hdy01)/dy01;
        const float
          iz = iz0 + diz01*yy0/dy01,
          txz = txz0 + dtxz01*yy0/dy01,
          tyz = tyz0 + dtyz01*yy0/dy01;
        if (x>=0 && x<=w1 && pattern&hatch) {
          const int
            tx = (int)cimg::round(txz/iz),
            ty = (int)cimg::round(tyz/iz);
          T *const ptrd = is_horizontal?data(y,x):data(x,y);
          const tc *const color = &texture._atXY(tx,ty);
          cimg_forC(*this,c) {
            const T val = color[c*twhd];
            ptrd[c*_sc_whd] = (T)(opacity>=1?val:val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity);
          }
        }
        if (!(hatch>>=1)) hatch = ~0U - (~0U>>1);
      }
      return *this;

Project: CImg
File: CImg.h

    template<typename t>
    bool is_sameXYC(const CImg<t>& img) const {
      return is_sameXYC(img._width,img._height,img._spectrum);

Project: CImg
File: CImg.h

    template<typename t>
    static float ___draw_object3d(const CImgList<t>& opacities, const unsigned int n_primitive) {
      return n_primitive<opacities._width && opacities[n_primitive].size()==1?(float)opacities(n_primitive,0):1.f;

Project: CImg
File: CImg.h

    **/
    CImg<T>& deriche(const float sigma, const unsigned int order=0, const char axis='x',
                     const bool boundary_conditions=true) {
#define _cimg_deriche_apply \
  CImg<Tfloat> Y(N); \
  Tfloat *ptrY = Y._data, yb = 0, yp = 0; \
  T xp = (T)0; \
  if (boundary_conditions) { xp = *ptrX; yb = yp = (Tfloat)(coefp*xp); } \
  for (int m = 0; m<N; ++m) { \
    const T xc = *ptrX; ptrX+=off; \
    const Tfloat yc = *(ptrY++) = (Tfloat)(a0*xc + a1*xp - b1*yp - b2*yb); \
    xp = xc; yb = yp; yp = yc; \
  } \
  T xn = (T)0, xa = (T)0; \
  Tfloat yn = 0, ya = 0; \
  if (boundary_conditions) { xn = xa = *(ptrX-off); yn = ya = (Tfloat)coefn*xn; } \
  for (int n = N - 1; n>=0; --n) { \
    const T xc = *(ptrX-=off); \
    const Tfloat yc = (Tfloat)(a2*xn + a3*xa - b1*yn - b2*ya); \
    xa = xn; xn = xc; ya = yn; yn = yc; \
    *ptrX = (T)(*(--ptrY)+yc); \
  }
      const char naxis = cimg::lowercase(axis);
      const float nsigma = sigma>=0?sigma:-sigma*(naxis=='x'?_width:naxis=='y'?_height:naxis=='z'?_depth:_spectrum)/100;
      if (is_empty() || (nsigma<0.1f && !order)) return *this;
      const float
        nnsigma = nsigma<0.1f?0.1f:nsigma,
        alpha = 1.695f/nnsigma,
        ema = (float)std::exp(-alpha),
        ema2 = (float)std::exp(-2*alpha),
        b1 = -2*ema,
        b2 = ema2;
      float a0 = 0, a1 = 0, a2 = 0, a3 = 0, coefp = 0, coefn = 0;
      switch (order) {
      case 0 : {
        const float k = (1-ema)*(1-ema)/(1 + 2*alpha*ema-ema2);
        a0 = k;
        a1 = k*(alpha - 1)*ema;
        a2 = k*(alpha + 1)*ema;
        a3 = -k*ema2;
      } break;
      case 1 : {
        const float k = -(1-ema)*(1-ema)*(1-ema)/(2*(ema + 1)*ema);
	a0 = a3 = 0;
	a1 = k*ema;
        a2 = -a1;
      } break;
      case 2 : {
        const float
          ea = (float)std::exp(-alpha),
          k = -(ema2 - 1)/(2*alpha*ema),
          kn = (-2*(-1 + 3*ea - 3*ea*ea + ea*ea*ea)/(3*ea + 1 + 3*ea*ea + ea*ea*ea));
        a0 = kn;
        a1 = -kn*(1 + k*alpha)*ema;
        a2 = kn*(1 - k*alpha)*ema;
        a3 = -kn*ema2;
      } break;
      default :
        throw CImgArgumentException(_cimg_instance
                                    "deriche(): Invalid specified filter order %u "
                                    "(should be { 0=smoothing | 1=1st-derivative | 2=2nd-derivative }).",
                                    cimg_instance,
                                    order);
      }
      coefp = (a0 + a1)/(1 + b1 + b2);
      coefn = (a2 + a3)/(1 + b1 + b2);
      switch (naxis) {
      case 'x' : {
        const int N = width();
        const ulongT off = 1U;
        cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*256 &&
                                                                   _height*_depth*_spectrum>=16))
        cimg_forYZC(*this,y,z,c) { T *ptrX = data(0,y,z,c); _cimg_deriche_apply; }
      } break;
      case 'y' : {
        const int N = height();
        const ulongT off = (ulongT)_width;
        cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*256 &&
                                                                   _height*_depth*_spectrum>=16))
        cimg_forXZC(*this,x,z,c) { T *ptrX = data(x,0,z,c); _cimg_deriche_apply; }
      } break;
      case 'z' : {
        const int N = depth();
        const ulongT off = (ulongT)_width*_height;
        cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*256 &&
                                                                   _height*_depth*_spectrum>=16))
        cimg_forXYC(*this,x,y,c) { T *ptrX = data(x,y,0,c); _cimg_deriche_apply; }
      } break;
      default : {
        const int N = spectrum();
        const ulongT off = (ulongT)_width*_height*_depth;
        cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*256 &&
                                                                   _height*_depth*_spectrum>=16))
        cimg_forXYZ(*this,x,y,z) { T *ptrX = data(x,y,z,0); _cimg_deriche_apply; }
      }
      }
      return *this;

Project: CImg
File: CImg.h


      static double mp_u(_cimg_math_parser& mp) {
        return cimg::rand(_mp_arg(2),_mp_arg(3),&mp.rng);

Project: CImg
File: CImg.h

    template<typename tq, typename tv>
    bool _priority_queue_insert(CImg<tq>& is_queued, unsigned int& siz, const tv value,
                                const unsigned int x, const unsigned int y, const unsigned int z,
                                const unsigned int n=1) {
      if (is_queued(x,y,z)) return false;
      is_queued(x,y,z) = (tq)n;
      if (++siz>=_width) { if (!is_empty()) resize(_width*2,4,1,1,0); else assign(64,4); }
      (*this)(siz - 1,0) = (T)value;
      (*this)(siz - 1,1) = (T)x;
      (*this)(siz - 1,2) = (T)y;
      (*this)(siz - 1,3) = (T)z;
      for (unsigned int pos = siz - 1, par = 0; pos && value>(tv)(*this)(par=(pos + 1)/2 - 1,0); pos = par) {
        cimg::swap((*this)(pos,0),(*this)(par,0));
        cimg::swap((*this)(pos,1),(*this)(par,1));
        cimg::swap((*this)(pos,2),(*this)(par,2));
        cimg::swap((*this)(pos,3),(*this)(par,3));
      }
      return true;

Project: CImg
File: CImg.h

    **/
    explicit CImg(const unsigned int size_x, const unsigned int size_y=1,
                  const unsigned int size_z=1, const unsigned int size_c=1):
      _is_shared(false) {
      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);
        }
      } else { _width = _height = _depth = _spectrum = 0; _data = 0; }

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& matchpatch(const CImg<T>& patch_image,
                        const unsigned int patch_width,
                        const unsigned int patch_height,
                        const unsigned int patch_depth,
                        const unsigned int nb_iterations=5,
                        const unsigned int nb_randoms=5,
                        const float occ_penalization=0,
                        const CImg<t> &guide=CImg<t>::const_empty()) {
      return get_matchpatch(patch_image,patch_width,patch_height,patch_depth,
                            nb_iterations,nb_randoms,occ_penalization,guide).move_to(*this);

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=0) {
      cimg::unused(wh,whd);
      return (*this)(x,y,z,c);

Project: CImg
File: CImg.h

    template<typename T>
    CImgDisplay& assign(const CImgList<T>& list,
                        const char *const title=0, const unsigned int normalization=3,
                        const bool is_fullscreen=false, const bool is_closed=false) {
      _no_display_exception();
      return assign(list._width,list._width,title,normalization,is_fullscreen,is_closed);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    //! Load an image from a video file using the external tool 'ffmpeg'.
    /**
      \param filename Filename to read data from.
    **/
    CImgList<T>& load_ffmpeg_external(const char *const filename) {
      if (!filename)
        throw CImgArgumentException(_cimglist_instance
                                    "load_ffmpeg_external(): Specified filename is (null).",
                                    cimglist_instance);
      cimg::fclose(cimg::fopen(filename,"rb")); // Check if file exists
      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());
        cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_000001.ppm",filename_tmp._data);
        if ((file=cimg::std_fopen(filename_tmp2,"rb"))!=0) cimg::fclose(file);
      } while (file);
      cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_%%6d.ppm",filename_tmp._data);
      cimg_snprintf(command,command._width,"%s -i \"%s\" \"%s\"",
                    cimg::ffmpeg_path(),
                    CImg<charT>::string(filename)._system_strescape().data(),
                    CImg<charT>::string(filename_tmp2)._system_strescape().data());
      cimg::system(command,0);
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode(0);
      assign();
      unsigned int i = 1;
      for (bool stop_flag = false; !stop_flag; ++i) {
        cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_%.6u.ppm",filename_tmp._data,i);
        CImg<T> img;
        try { img.load_pnm(filename_tmp2); }
        catch (CImgException&) { stop_flag = true; }
        if (img) { img.move_to(*this); std::remove(filename_tmp2); }
      }
      cimg::exception_mode(omode);
      if (is_empty())
        throw CImgIOException(_cimglist_instance
                              "load_ffmpeg_external(): Failed to open file '%s' with external command 'ffmpeg'.",

Project: CImg
File: CImg.h

      HANDLE mutex[32];

Project: CImg
File: CImg.h

    //! Cumulate image values, along specified axes \newinstance.
    CImg<Tlong> get_cumulate(const char *const axes) const {
      return CImg<Tlong>(*this,false).cumulate(axes);

Project: CImg
File: CImg.h

      \param filename Filename to write data to.
      \param number When positive, represents an index added to the filename. Otherwise, no number is added.
      \param digits Number of digits used for adding the number to the filename.
    **/
    const CImgList<T>& save(const char *const filename, const int number=-1, const unsigned int digits=6) const {
      if (!filename)
        throw CImgArgumentException(_cimglist_instance
                                    "save(): Specified filename is (null).",
                                    cimglist_instance);
      // Do not test for empty instances, since .cimg format is able to manage empty instances.
      const bool is_stdout = *filename=='-' && (!filename[1] || filename[1]=='.');
      const char *const ext = cimg::split_filename(filename);
      CImg<charT> nfilename(1024);
      const char *const fn = is_stdout?filename:number>=0?cimg::number_filename(filename,number,digits,nfilename):
        filename;

#ifdef cimglist_save_plugin
      cimglist_save_plugin(fn);
#endif
#ifdef cimglist_save_plugin1
      cimglist_save_plugin1(fn);
#endif
#ifdef cimglist_save_plugin2
      cimglist_save_plugin2(fn);
#endif
#ifdef cimglist_save_plugin3
      cimglist_save_plugin3(fn);
#endif
#ifdef cimglist_save_plugin4
      cimglist_save_plugin4(fn);
#endif
#ifdef cimglist_save_plugin5
      cimglist_save_plugin5(fn);
#endif
#ifdef cimglist_save_plugin6
      cimglist_save_plugin6(fn);
#endif
#ifdef cimglist_save_plugin7
      cimglist_save_plugin7(fn);
#endif
#ifdef cimglist_save_plugin8
      cimglist_save_plugin8(fn);
#endif
      if (!cimg::strcasecmp(ext,"cimgz")) return save_cimg(fn,true);
      else if (!cimg::strcasecmp(ext,"cimg") || !*ext) return save_cimg(fn,false);
      else if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(fn,444,true);
      else if (!cimg::strcasecmp(ext,"avi") ||
               !cimg::strcasecmp(ext,"mov") ||
               !cimg::strcasecmp(ext,"asf") ||
               !cimg::strcasecmp(ext,"divx") ||
               !cimg::strcasecmp(ext,"flv") ||
               !cimg::strcasecmp(ext,"mpg") ||
               !cimg::strcasecmp(ext,"m1v") ||
               !cimg::strcasecmp(ext,"m2v") ||
               !cimg::strcasecmp(ext,"m4v") ||
               !cimg::strcasecmp(ext,"mjp") ||
               !cimg::strcasecmp(ext,"mp4") ||
               !cimg::strcasecmp(ext,"mkv") ||
               !cimg::strcasecmp(ext,"mpe") ||
               !cimg::strcasecmp(ext,"movie") ||
               !cimg::strcasecmp(ext,"ogm") ||
               !cimg::strcasecmp(ext,"ogg") ||
               !cimg::strcasecmp(ext,"ogv") ||
               !cimg::strcasecmp(ext,"qt") ||
               !cimg::strcasecmp(ext,"rm") ||
               !cimg::strcasecmp(ext,"vob") ||
               !cimg::strcasecmp(ext,"wmv") ||
               !cimg::strcasecmp(ext,"xvid") ||
               !cimg::strcasecmp(ext,"mpeg")) return save_video(fn);
#ifdef cimg_use_tiff
      else if (!cimg::strcasecmp(ext,"tif") ||
          !cimg::strcasecmp(ext,"tiff")) return save_tiff(fn);
#endif
      else if (!cimg::strcasecmp(ext,"gz")) return save_gzip_external(fn);
      else {
        if (_width==1) _data[0].save(fn,-1);

Project: CImg
File: CImg.h

    **/
    CImgDisplay& wait(const unsigned int milliseconds) {
      cimg::wait(milliseconds,&_timer);
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


      static double mp_cats(_cimg_math_parser& mp) {
        const double *ptrd = &_mp_arg(1) + 1;
        const unsigned int
          sizd = (unsigned int)mp.opcode[2],
          nb_args = (unsigned int)(mp.opcode[3] - 4)/2;
        CImgList<charT> _str;
        for (unsigned int n = 0; n<nb_args; ++n) {
          const unsigned int siz = (unsigned int)mp.opcode[5 + 2*n];
          if (siz) { // Vector argument
            const double *ptrs = &_mp_arg(4 + 2*n) + 1;
            unsigned int l = 0;
            while (l<siz && ptrs[l]) ++l;
            CImg<doubleT>(ptrs,l,1,1,1,true).move_to(_str);
          } else CImg<charT>::vector((char)_mp_arg(4 + 2*n)).move_to(_str); // Scalar argument
        }
        CImg(1,1,1,1,0).move_to(_str);
        const CImg<charT> str = _str>'x';
        const unsigned int l = std::min(str._width,sizd);
        CImg<doubleT>(ptrd,l,1,1,1,true) = str.get_shared_points(0,l - 1);
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h


      static double mp_for(_cimg_math_parser& mp) {
        const ulongT
          mem_body = mp.opcode[1],
          mem_cond = mp.opcode[3];
        const CImg<ulongT>
          *const p_init = ++mp.p_code,
          *const p_cond = p_init + mp.opcode[4],
          *const p_body = p_cond + mp.opcode[5],
          *const p_post = p_body + mp.opcode[6],
          *const p_end = p_post + mp.opcode[7];
        const unsigned int vsiz = (unsigned int)mp.opcode[2];
        bool is_cond = false;
        if (mp.opcode[8]) { // Set default value for result and condition if necessary
          if (vsiz) CImg<doubleT>(&mp.mem[mem_body] + 1,vsiz,1,1,1,true).fill(cimg::type<double>::nan());
          else mp.mem[mem_body] = cimg::type<double>::nan();
        }
        if (mp.opcode[9]) mp.mem[mem_cond] = 0;
        const unsigned int _break_type = mp.break_type;
        mp.break_type = 0;

        for (mp.p_code = p_init; mp.p_code<p_cond; ++mp.p_code) { // Evaluate init
          mp.opcode._data = mp.p_code->_data;
          const ulongT target = mp.opcode[1];
          mp.mem[target] = _cimg_mp_defunc(mp);
        }

        if (!mp.break_type) do {
            for (mp.p_code = p_cond; mp.p_code<p_body; ++mp.p_code) { // Evaluate condition
              mp.opcode._data = mp.p_code->_data;
              const ulongT target = mp.opcode[1];
              mp.mem[target] = _cimg_mp_defunc(mp);
            }
            if (mp.break_type==1) break;

            is_cond = (bool)mp.mem[mem_cond];
            if (is_cond && !mp.break_type) {
              for (mp.p_code = p_body; mp.p_code<p_post; ++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);
              }
              if (mp.break_type==1) break; else if (mp.break_type==2) mp.break_type = 0;

              for (mp.p_code = p_post; mp.p_code<p_end; ++mp.p_code) { // Evaluate post-code
                mp.opcode._data = mp.p_code->_data;
                const ulongT target = mp.opcode[1];
                mp.mem[target] = _cimg_mp_defunc(mp);
              }
              if (mp.break_type==1) break; else if (mp.break_type==2) mp.break_type = 0;
            }
          } while (is_cond);

        mp.break_type = _break_type;
        mp.p_code = p_end - 1;
        return mp.mem[mem_body];

Project: CImg
File: CImg.h

    template<typename tf>
    static CImg<floatT> isosurface3d(CImgList<tf>& primitives, const char *const expression, const float isovalue,
                                     const float x0, const float y0, const float z0,
                                     const float x1, const float y1, const float z1,
                                     const int dx=32, const int dy=32, const int dz=32) {
      const _functor3d_expr func(expression);
      return isosurface3d(primitives,func,isovalue,x0,y0,z0,x1,y1,z1,dx,dy,dz);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<doubleT> eval(const char *const expression, const CImg<t>& xyzc,
                       const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) const {
      return _eval(0,expression,xyzc,list_inputs,list_outputs);

Project: CImg
File: CImg.h

      ~_functor4d_streamline3d_oriented() { delete pI; }
      float operator()(const float x, const float y, const float z, const unsigned int c) const {
#define _cimg_vecalign3d(i,j,k) if (I(i,j,k,0)*I(0,0,0,0) + I(i,j,k,1)*I(0,0,0,1) + I(i,j,k,2)*I(0,0,0,2)<0) { \
  I(i,j,k,0) = -I(i,j,k,0); I(i,j,k,1) = -I(i,j,k,1); I(i,j,k,2) = -I(i,j,k,2); }
        int
          xi = (int)x - (x>=0?0:1), nxi = xi + 1,
          yi = (int)y - (y>=0?0:1), nyi = yi + 1,
          zi = (int)z - (z>=0?0:1), nzi = zi + 1;
        const float
          dx = x - xi,
          dy = y - yi,
          dz = z - zi;
        if (c==0) {
          CImg<floatT>& I = *pI;
          if (xi<0) xi = 0;
          if (nxi<0) nxi = 0;
          if (xi>=ref.width()) xi = ref.width() - 1;
          if (nxi>=ref.width()) nxi = ref.width() - 1;
          if (yi<0) yi = 0;
          if (nyi<0) nyi = 0;
          if (yi>=ref.height()) yi = ref.height() - 1;
          if (nyi>=ref.height()) nyi = ref.height() - 1;
          if (zi<0) zi = 0;
          if (nzi<0) nzi = 0;
          if (zi>=ref.depth()) zi = ref.depth() - 1;
          if (nzi>=ref.depth()) nzi = ref.depth() - 1;
          I(0,0,0,0) = (float)ref(xi,yi,zi,0); I(0,0,0,1) = (float)ref(xi,yi,zi,1);
          I(0,0,0,2) = (float)ref(xi,yi,zi,2); I(1,0,0,0) = (float)ref(nxi,yi,zi,0);
          I(1,0,0,1) = (float)ref(nxi,yi,zi,1); I(1,0,0,2) = (float)ref(nxi,yi,zi,2);
          I(1,1,0,0) = (float)ref(nxi,nyi,zi,0); I(1,1,0,1) = (float)ref(nxi,nyi,zi,1);
          I(1,1,0,2) = (float)ref(nxi,nyi,zi,2); I(0,1,0,0) = (float)ref(xi,nyi,zi,0);
          I(0,1,0,1) = (float)ref(xi,nyi,zi,1); I(0,1,0,2) = (float)ref(xi,nyi,zi,2);
          I(0,0,1,0) = (float)ref(xi,yi,nzi,0); I(0,0,1,1) = (float)ref(xi,yi,nzi,1);
          I(0,0,1,2) = (float)ref(xi,yi,nzi,2); I(1,0,1,0) = (float)ref(nxi,yi,nzi,0);
          I(1,0,1,1) = (float)ref(nxi,yi,nzi,1);  I(1,0,1,2) = (float)ref(nxi,yi,nzi,2);
          I(1,1,1,0) = (float)ref(nxi,nyi,nzi,0); I(1,1,1,1) = (float)ref(nxi,nyi,nzi,1);
          I(1,1,1,2) = (float)ref(nxi,nyi,nzi,2); I(0,1,1,0) = (float)ref(xi,nyi,nzi,0);
          I(0,1,1,1) = (float)ref(xi,nyi,nzi,1);  I(0,1,1,2) = (float)ref(xi,nyi,nzi,2);
          _cimg_vecalign3d(1,0,0); _cimg_vecalign3d(1,1,0); _cimg_vecalign3d(0,1,0);
          _cimg_vecalign3d(0,0,1); _cimg_vecalign3d(1,0,1); _cimg_vecalign3d(1,1,1); _cimg_vecalign3d(0,1,1);
        }
        return (float)pI->_linear_atXYZ(dx,dy,dz,c);

Project: CImg
File: CImg.h

    //! Construct list as a copy of an existing list and force shared state of elements \inplace \specialization.
    CImgList<T>& assign(const CImgList<T>& list, const bool is_shared=false) {
      if (this==&list) return *this;
      CImgList<T> res(list._width);
      cimglist_for(res,l) res[l].assign(list[l],is_shared);
      return res.move_to(*this);

Project: CImg
File: CImg.h


    T& _atXYZ(const int x, const int y, const int z, const int c=0) {
      return (*this)(cimg::cut(x,0,width() - 1),
                     cimg::cut(y,0,height() - 1),
                     cimg::cut(z,0,depth() - 1),c);

Project: CImg
File: CImg.h

    //! Return a pointer to the first pixel value \const.
    const T* data() const {
      return _data;

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

    //! Pointwise max operator between an image and an expression \newinstance.
    CImg<Tfloat> get_max(const char *const expression) const {
      return CImg<Tfloat>(*this,false).max(expression);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<Tfloat> get_blur_bilateral(const CImg<t>& guide,
                                    const float sigma_s, const float sigma_r,
                                    const float sampling_s=0, const float sampling_r=0) const {
      return CImg<Tfloat>(*this,false).blur_bilateral(guide,sigma_s,sigma_r,sampling_s,sampling_r);

Project: CImg
File: CImg.h

    //! Return a CImg<T>::iterator pointing to the first value of the pixel buffer \const.
    const_iterator begin() const {
      return _data;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


      static double mp_Jxyz(_cimg_math_parser& mp) {
        double *ptrd = &_mp_arg(1) + 1;
        const unsigned int
          interpolation = (unsigned int)_mp_arg(5),
          boundary_conditions = (unsigned int)_mp_arg(6),
          vsiz = (unsigned int)mp.opcode[7];
        const CImg<T> &img = mp.imgin;
        const double
          ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y], oz = mp.mem[_cimg_mp_slot_z],
          x = ox + _mp_arg(2), y = oy + _mp_arg(3), z = oz + _mp_arg(4);
        const ulongT whd = (ulongT)img._width*img._height*img._depth;
        const T *ptrs;
        switch (interpolation) {
        case 2 : // Cubic interpolation
          switch (boundary_conditions) {
          case 3 : { // Mirror
            const float
              w2 = 2.f*img.width(), h2 = 2.f*img.height(), d2 = 2.f*img.depth(),
              mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2), mz = cimg::mod((float)z,d2),
              cx = mx<img.width()?mx:w2 - mx - 1,
              cy = my<img.height()?my:h2 - my - 1,
              cz = mz<img.depth()?mz:d2 - mz - 1;
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._cubic_atXYZ(cx,cy,cz,c);
          } break;
          case 2 : // Periodic
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._cubic_atXYZ_p((float)x,(float)y,(float)z,c);
            break;
          case 1 : // Neumann
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._cubic_atXYZ((float)x,(float)y,(float)z,c);
            break;
          default : // Dirichlet
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img.cubic_atXYZ((float)x,(float)y,(float)z,c,(T)0);
          } break;
        case 1 : // Linear interpolation
          switch (boundary_conditions) {
          case 3 : { // Mirror
            const float
              w2 = 2.f*img.width(), h2 = 2.f*img.height(), d2 = 2.f*img.depth(),
              mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2), mz = cimg::mod((float)z,d2),
              cx = mx<img.width()?mx:w2 - mx - 1,
              cy = my<img.height()?my:h2 - my - 1,
              cz = mz<img.depth()?mz:d2 - mz - 1;
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._linear_atXYZ(cx,cy,cz,c);
          } break;
          case 2 : // Periodic
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._linear_atXYZ_p((float)x,(float)y,(float)z,c);
            break;
          case 1 : // Neumann
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._linear_atXYZ((float)x,(float)y,(float)z,c);
            break;
          default : // Dirichlet
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c,(T)0);
          } break;
        default : // Nearest neighbor interpolation
          switch (boundary_conditions) {
          case 3 : { // Mirror
            const int
              w2 = 2*img.width(), h2 = 2*img.height(), d2 = 2*img.depth(),
              mx = cimg::mod((int)x,w2), my = cimg::mod((int)y,h2), mz = cimg::mod((int)z,d2),
              cx = mx<img.width()?mx:w2 - mx - 1,
              cy = my<img.height()?my:h2 - my - 1,
              cz = mz<img.depth()?mz:d2 - mz - 1;
            ptrs = &img(cx,cy,cz);
            cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
          } break;
          case 2 : { // Periodic
            const int
              cx = (int)cimg::mod(x,(double)img._width),
              cy = (int)cimg::mod(y,(double)img._height),
              cz = (int)cimg::mod(z,(double)img._depth);
            ptrs = &img(cx,cy,cz);
            cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
          } break;
          case 1 : { // Neumann
            ptrs = &img._atXYZ((int)x,(int)y,(int)z);
            cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
          } break;
          default : // Dirichlet
            if (img.containsXYZC((int)x,(int)y,(int)z)) {
              ptrs = &img((int)x,(int)y,(int)z);
              cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
            } else std::memset(ptrd,0,vsiz*sizeof(double));
          }
        }
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

    **/
    CImg<T>& blur_median(const unsigned int n, const float threshold=0) {
      if (!n) return *this;
      return get_blur_median(n,threshold).move_to(*this);

Project: CImg
File: CImg.h

    template<> struct type<unsigned short> {

Project: CImg
File: CImg.h

    **/
    CImg<T> operator>(const char axis) const {
      return get_append(axis,0);

Project: CImg
File: CImg.h

    //! Convert pixel values from sRGB to RGB color spaces.
    CImg<T>& sRGBtoRGB() {
      if (is_empty()) return *this;
      cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),32))
      cimg_rofoff(*this,off) {
        const Tfloat
          sval = (Tfloat)_data[off]/255,
          val = (Tfloat)(sval<=0.04045f?sval/12.92f:std::pow((sval + 0.055f)/(1.055f),2.4f));
        _data[off] = (T)cimg::cut(val*255,0,255);
      }
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


    Tfloat _linear_atXYZC_p(const float fx, const float fy=0, const float fz=0, const float fc=0) const {
      const float
        nfx = cimg::mod(fx,(float)_width),
        nfy = cimg::mod(fy,(float)_height),
        nfz = cimg::mod(fz,(float)_depth),
        nfc = cimg::mod(fc,(float)_spectrum);
      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 = cimg::mod(x + 1,_width),
        ny = cimg::mod(y + 1,_height),
        nz = cimg::mod(z + 1,_depth),
        nc = cimg::mod(c + 1,_spectrum);
      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

    //! Resize image to half-size along XY axes, using an optimized filter.
    CImg<T>& resize_halfXY() {
      return get_resize_halfXY().move_to(*this);

Project: CImg
File: CImg.h


      static double mp_div(_cimg_math_parser& mp) {
        return _mp_arg(2)/_mp_arg(3);

Project: CImg
File: CImg.h


      static double mp_lte(_cimg_math_parser& mp) {
        return (double)(_mp_arg(2)<=_mp_arg(3));

Project: CImg
File: CImg.h


    const T& _atXY(const int x, const int y, const int z=0, const int c=0) const {
      return (*this)(cimg::cut(x,0,width() - 1),
                     cimg::cut(y,0,height() - 1),z,c);

Project: CImg
File: CImg.h

    **/
    static CImg<T> matrix(const T& a0, const T& a1,
			  const T& a2, const T& a3) {
      CImg<T> r(2,2); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1;
      *(ptr++) = a2; *(ptr++) = a3;
      return r;

Project: CImg
File: CImg.h


      static double mp_matrix_eig(_cimg_math_parser& mp) {
        double *ptrd = &_mp_arg(1) + 1;
        const double *ptr1 = &_mp_arg(2) + 1;
        const unsigned int k = (unsigned int)mp.opcode[3];
        CImg<doubleT> val, vec;
        CImg<doubleT>(ptr1,k,k,1,1,true).symmetric_eigen(val,vec);
        CImg<doubleT>(ptrd,1,k,1,1,true) = val;
        CImg<doubleT>(ptrd + k,k,k,1,1,true) = vec.get_transpose();
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

    inline int _snprintf(char *const s, const size_t n, const char *const format, ...) {
      cimg::mutex(6);
      va_list args;
      va_start(args,format);
      const int result = std::vsnprintf(s,n,format,args);
      va_end(args);
      cimg::mutex(6,0);
      return result;
    }

Project: CImg
File: CImg.h

      // Insert code instructions for processing vectors.
      bool is_comp_vector(const unsigned int arg) const {
        unsigned int siz = _cimg_mp_size(arg);
        if (siz>8) return false;
        const int *ptr = memtype.data(arg + 1);
        bool is_tmp = true;
        while (siz-->0) if (*(ptr++)) { is_tmp = false; break; }
        return is_tmp;

Project: CImg
File: CImg.h


      static double mp_display_memory(_cimg_math_parser& mp) {
        cimg::unused(mp);
        std::fputc('\n',cimg::output());
        mp.mem.display("[" cimg_appname "_math_parser] Memory snapshot");
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h


      static double mp_neq(_cimg_math_parser& mp) {
        return (double)(_mp_arg(2)!=_mp_arg(3));

Project: CImg
File: CImg.h

      static unsigned char max() { return (unsigned char)-1; }

Project: CImg
File: CImg.h

    template<typename t, typename tc>
    CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
                          const tc *const color, const float opacity,
                          const unsigned int pattern) {
      CImgList<t> eig = tensor.get_symmetric_eigen();
      const CImg<t> &val = eig[0], &vec = eig[1];
      return draw_ellipse(x0,y0,std::sqrt(val(0)),std::sqrt(val(1)),
                          std::atan2(vec(0,1),vec(0,0))*180/cimg::PI,
                          color,opacity,pattern);

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 tc *const color,
                           float bs0,
                           float bs1,
                           float bs2,
                           const float opacity=1) {
      if (is_empty()) return *this;
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_triangle(): Specified color is (null).",
                                    cimg_instance);

      if (y0>y1) cimg::swap(x0,x1,y0,y1,bs0,bs1);
      if (y0>y2) cimg::swap(x0,x2,y0,y2,bs0,bs2);
      if (y1>y2) cimg::swap(x1,x2,y1,y2,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 dbs01 = bs1 - bs0, dbs02 = bs2 - bs0, dbs12 = bs2 - bs1;

      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
          bsm = y<y1?(bs0 + dbs01*yy0/dy01):(bs1 + dbs12*yy1/dy12),
          bsM = bs0 + dbs02*yy0/dy02;
        if (xm>xM) cimg::swap(xm,xM,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 dbsmM = bsM - bsm;

          for (int x = cxm; x<=cxM; ++x) {
            const int xxm = x - xm;
            const float cbs = cimg::cut(bsm + dbsmM*xxm/dxmM,0,2);
            cimg_forC(*this,c) {
              const Tfloat val = cbs<=1?color[c]*cbs:(2 - cbs)*color[c] + (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 t>
    CImg(const std::initializer_list<t> values):
      _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
      assign(values.size(),1,1,1);
      auto it = values.begin();
      unsigned int siz = _width;
      for (T *ptrd = _data; siz--; ) *(ptrd++) = (T)(*(it++));

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


      static double mp_set_ioff(_cimg_math_parser& mp) {
        CImg<T> &img = mp.imgout;
        const longT
          off = (longT)_mp_arg(2),
          whds = (longT)img.size();
        const double val = _mp_arg(1);
        if (off>=0 && off<whds) img[off] = (T)val;
        return val;

Project: CImg
File: CImg.h

    **/
    CImgList(const unsigned int n, const unsigned int width, const unsigned int height=1,
             const unsigned int depth=1, const unsigned int spectrum=1):
      _width(0),_allocated_width(0),_data(0) {
      assign(n);
      cimglist_apply(*this,assign)(width,height,depth,spectrum);

Project: CImg
File: CImg.h

    **/
    CImg<T>& histogram(const unsigned int nb_levels, const T& min_value, const T& max_value) {
      return get_histogram(nb_levels,min_value,max_value).move_to(*this);

Project: CImg
File: CImg.h

      return 0;
#endif
    }

    inline FILE* _stdout(const bool throw_exception) {
#ifndef cimg_use_r
      cimg::unused(throw_exception);
      return stdout;
#else
      if (throw_exception) {
        cimg::exception_mode(0);
        throw CImgIOException("cimg::stdout(): Reference to 'stdout' stream not allowed in R mode "
                              "('cimg_use_r' is defined).");

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    /**
       \param axis Axis along which the Fourier transform is computed.
       \param invert Tells if the direct (\c false) or inverse transform (\c true) is computed.
    **/
    CImgList<T>& FFT(const char axis, const bool invert=false) {
      if (is_empty()) return *this;
      if (_width==1) insert(1);
      if (_width>2)
        cimg::warn(_cimglist_instance
                   "FFT(): Instance has more than 2 images",
                   cimglist_instance);

Project: CImg
File: CImg.h


      static double mp_det(_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).det();

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


      static double mp_image_whd(_cimg_math_parser& mp) {
        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.imgout:mp.listout[ind];
        return (double)img.width()*img.height()*img.depth();

Project: CImg
File: CImg.h


      static double mp_cross(_cimg_math_parser& mp) {
        CImg<doubleT>
          vout(&_mp_arg(1) + 1,1,3,1,1,true),
          v1(&_mp_arg(2) + 1,1,3,1,1,true),
          v2(&_mp_arg(3) + 1,1,3,1,1,true);
        (vout = v1).cross(v2);
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

    **/
    operator T*() {
      return _data;

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

#elif defined(cimg_main)

Project: CImg
File: CImg.h

    template<typename t>
    bool is_sameZC(const CImg<t>& img) const {
      return is_sameZC(img._depth,img._spectrum);

Project: CImg
File: CImg.h

      \param dy Checked image height.
      \param dz Checked image depth.
      \param dc Checked image spectrum.
    **/
    bool is_sameXYZC(const unsigned int dx, const unsigned int dy,
                     const unsigned int dz, const unsigned int dc) const {

Project: CImg
File: CImg.h


      static double mp_image_s(_cimg_math_parser& mp) {
        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.imgout:mp.listout[ind];
        return (double)img.spectrum();

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    template<> struct type<short> {

Project: CImg
File: CImg.h

    **/
    Tfloat cubic_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), px = x - 1, nx = x + 1, ax = x + 2,
        y = (int)fy - (fy>=0?0:1), py = y - 1, ny = y + 1, ay = y + 2;
      const float dx = fx - x, dy = fy - y;
      const Tfloat
        Ipp = (Tfloat)atXY(px,py,z,c,out_value), Icp = (Tfloat)atXY(x,py,z,c,out_value),
        Inp = (Tfloat)atXY(nx,py,z,c,out_value), Iap = (Tfloat)atXY(ax,py,z,c,out_value),
        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)atXY(px,y,z,c,out_value),  Icc = (Tfloat)atXY(x, y,z,c,out_value),
        Inc = (Tfloat)atXY(nx,y,z,c,out_value),  Iac = (Tfloat)atXY(ax,y,z,c,out_value),
        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)atXY(px,ny,z,c,out_value), Icn = (Tfloat)atXY(x,ny,z,c,out_value),
        Inn = (Tfloat)atXY(nx,ny,z,c,out_value), Ian = (Tfloat)atXY(ax,ny,z,c,out_value),
        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)atXY(px,ay,z,c,out_value), Ica = (Tfloat)atXY(x,ay,z,c,out_value),
        Ina = (Tfloat)atXY(nx,ay,z,c,out_value), Iaa = (Tfloat)atXY(ax,ay,z,c,out_value),
        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_logical_and(_cimg_math_parser& mp) {
        const bool val_left = (bool)_mp_arg(2);
        const CImg<ulongT> *const p_end = ++mp.p_code + mp.opcode[4];
        if (!val_left) { mp.p_code = p_end - 1; return 0; }
        const ulongT mem_right = mp.opcode[3];
        for ( ; mp.p_code<p_end; ++mp.p_code) {
          mp.opcode._data = mp.p_code->_data;
          const ulongT target = mp.opcode[1];
          mp.mem[target] = _cimg_mp_defunc(mp);
        }
        --mp.p_code;
        return (double)(bool)mp.mem[mem_right];

Project: CImg
File: CImg.h


      static double mp_Ixyz(_cimg_math_parser& mp) {
        double *ptrd = &_mp_arg(1) + 1;
        const unsigned int
          interpolation = (unsigned int)_mp_arg(5),
          boundary_conditions = (unsigned int)_mp_arg(6),
          vsiz = (unsigned int)mp.opcode[7];
        const CImg<T> &img = mp.imgin;
        const double x = _mp_arg(2), y = _mp_arg(3), z = _mp_arg(4);
        const ulongT whd = (ulongT)img._width*img._height*img._depth;
        const T *ptrs;
        switch (interpolation) {
        case 2 : // Cubic interpolation
          switch (boundary_conditions) {
          case 3 : { // Mirror
            const float
              w2 = 2.f*img.width(), h2 = 2.f*img.height(), d2 = 2.f*img.depth(),
              mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2), mz = cimg::mod((float)z,d2),
              cx = mx<img.width()?mx:w2 - mx - 1,
              cy = my<img.height()?my:h2 - my - 1,
              cz = mz<img.depth()?mz:d2 - mz - 1;
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._cubic_atXYZ(cx,cy,cz,c);
          } break;
          case 2 : // Periodic
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._cubic_atXYZ_p((float)x,(float)y,(float)z,c);
            break;
          case 1 : // Neumann
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._cubic_atXYZ((float)x,(float)y,(float)z,c);
            break;
          default : // Dirichlet
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img.cubic_atXYZ((float)x,(float)y,(float)z,c,(T)0);
          } break;
        case 1 : // Linear interpolation
          switch (boundary_conditions) {
          case 3 : { // Mirror
            const float
              w2 = 2.f*img.width(), h2 = 2.f*img.height(), d2 = 2.f*img.depth(),
              mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2), mz = cimg::mod((float)z,d2),
              cx = mx<img.width()?mx:w2 - mx - 1,
              cy = my<img.height()?my:h2 - my - 1,
              cz = mz<img.depth()?mz:d2 - mz - 1;
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._linear_atXYZ(cx,cy,cz,c);
          } break;
          case 2 : // Periodic
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._linear_atXYZ_p((float)x,(float)y,(float)z,c);
            break;
          case 1 : // Neumann
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._linear_atXYZ((float)x,(float)y,(float)z,c);
            break;
          default : // Dirichlet
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c,(T)0);
          } break;
        default : // Nearest neighbor interpolation
          switch (boundary_conditions) {
          case 3 : { // Mirror
            const int
              w2 = 2*img.width(), h2 = 2*img.height(), d2 = 2*img.depth(),
              mx = cimg::mod((int)x,w2), my = cimg::mod((int)y,h2), mz = cimg::mod((int)z,d2),
              cx = mx<img.width()?mx:w2 - mx - 1,
              cy = my<img.height()?my:h2 - my - 1,
              cz = mz<img.depth()?mz:d2 - mz - 1;
            ptrs = &img(cx,cy,cz);
            cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
          } break;
          case 2 : { // Periodic
            const int
              cx = (int)cimg::mod(x,(double)img._width),
              cy = (int)cimg::mod(y,(double)img._height),
              cz = (int)cimg::mod(z,(double)img._depth);
            ptrs = &img(cx,cy,cz);
            cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
          } break;
          case 1 : { // Neumann
            ptrs = &img._atXYZ((int)x,(int)y,(int)z);
            cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
          } break;
          default : // Dirichlet
            if (img.containsXYZC((int)x,(int)y,(int)z)) {
              ptrs = &img((int)x,(int)y,(int)z);
              cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
            } else std::memset(ptrd,0,vsiz*sizeof(double));
          }
        }
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

    //! Return pixel value, using cubic interpolation and periodic boundary conditions for the X-coordinate.
    Tfloat cubic_atX_p(const float fx, const int y=0, const int z=0, const int c=0) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "cubic_atX_p(): Empty instance.",
                                    cimg_instance);
      return _cubic_atX_p(fx,y,z,c);

Project: CImg
File: CImg.h

      static const char* format() { return "%.17g"; }

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& distance(const T& value, const CImg<t>& metric_mask) {
      if (is_empty()) return *this;
      bool is_value = false;
      cimg_for(*this,ptr,T) *ptr = *ptr==value?is_value=true,0:(T)999999999;
      if (!is_value) return fill(cimg::type<T>::max());
      const ulongT wh = (ulongT)_width*_height;
      cimg_pragma_openmp(parallel for cimg_openmp_if(_spectrum>=2))
      cimg_forC(*this,c) {
        CImg<T> img = get_shared_channel(c);
        cimg_pragma_openmp(parallel for cimg_openmp_collapse(3)
                           cimg_openmp_if(_width*_height*_depth>=(cimg_openmp_sizefactor)*1024))
        cimg_forXYZ(metric_mask,dx,dy,dz) {
          const t weight = metric_mask(dx,dy,dz);
          if (weight) {
            for (int z = dz, nz = 0; z<depth(); ++z,++nz) { // Forward scan
              for (int y = dy , ny = 0; y<height(); ++y,++ny) {
                for (int x = dx, nx = 0; x<width(); ++x,++nx) {
                  const T dd = img(nx,ny,nz,0,wh) + weight;
                  if (dd<img(x,y,z,0,wh)) img(x,y,z,0,wh) = dd;
                }
              }
            }
            for (int z = depth() - 1 - dz, nz = depth() - 1; z>=0; --z,--nz) { // Backward scan
              for (int y = height() - 1 - dy, ny = height() - 1; y>=0; --y,--ny) {
                for (int x = width() - 1 - dx, nx = width() - 1; x>=0; --x,--nx) {
                  const T dd = img(nx,ny,nz,0,wh) + weight;
                  if (dd<img(x,y,z,0,wh)) img(x,y,z,0,wh) = dd;
                }
              }
            }
          }
        }
      }
      return *this;

Project: CImg
File: CImg.h

    //! Convert pixel values from RGB to HSV color spaces.
    CImg<T>& RGBtoHSV() {
      if (_spectrum!=3)
        throw CImgInstanceException(_cimg_instance
                                    "RGBtoHSV(): Instance is not a RGB 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
          R = (Tfloat)p1[N],
          G = (Tfloat)p2[N],
          B = (Tfloat)p3[N],
          M = cimg::max(R,G,B),
          C = M - cimg::min(R,G,B),
          H = 60*(C==0?0:M==R?cimg::mod((G-B)/C,(Tfloat)6):M==G?(B - R)/C + 2:(R - G)/C + 4),
          S = M<=0?0:C/M;
        p1[N] = (T)H;
        p2[N] = (T)S;
        p3[N] = (T)(M/255);
      }
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    //! Test if the list contains the image img.
    /**
       \param img Reference to image to test.
    **/

Project: CImg
File: CImg.h

    //! Convert pixel values from RGB to CMYK color spaces.
    CImg<T>& RGBtoCMYK() {
      return RGBtoCMY().CMYtoCMYK();

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    template<> struct type<long double> {

Project: CImg
File: CImg.h

    **/
    const CImg<T>& save_ffmpeg_external(const char *const filename, const unsigned int fps=25,
                                        const char *const codec=0, const unsigned int bitrate=2048) const {
      if (!filename)
        throw CImgArgumentException(_cimg_instance
                                    "save_ffmpeg_external(): Specified filename is (null).",
                                    cimg_instance);
      if (is_empty()) { cimg::fempty(0,filename); return *this; }

      CImgList<T> list;
      get_split('z').move_to(list);
      list.save_ffmpeg_external(filename,fps,codec,bitrate);
      return *this;

Project: CImg
File: CImg.h

    inline unsigned int openmp_mode(const unsigned int value, const bool is_set) {
      static unsigned int mode = 2;
      if (is_set)  { cimg::mutex(0); mode = value<2?value:2; cimg::mutex(0,0); }
      return mode;
    }

Project: CImg
File: CImg.h

    **/
    T kth_smallest(const ulongT k) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "kth_smallest(): Empty instance.",
                                    cimg_instance);
      CImg<T> arr(*this,false);
      ulongT l = 0, ir = size() - 1;
      for ( ; ; ) {
        if (ir<=l + 1) {
          if (ir==l + 1 && arr[ir]<arr[l]) cimg::swap(arr[l],arr[ir]);
          return arr[k];
        } else {
          const ulongT mid = (l + ir)>>1;
          cimg::swap(arr[mid],arr[l + 1]);
          if (arr[l]>arr[ir]) cimg::swap(arr[l],arr[ir]);
          if (arr[l + 1]>arr[ir]) cimg::swap(arr[l + 1],arr[ir]);
          if (arr[l]>arr[l + 1]) cimg::swap(arr[l],arr[l + 1]);
          ulongT i = l + 1, j = ir;
          const T pivot = arr[l + 1];
          for ( ; ; ) {
            do ++i; while (arr[i]<pivot);
            do --j; while (arr[j]>pivot);
            if (j<i) break;
            cimg::swap(arr[i],arr[j]);
          }
          arr[l + 1] = arr[j];
          arr[j] = pivot;
          if (j>=k) ir = j - 1;
          if (j<=k) l = i;
        }
      }

Project: CImg
File: CImg.h


    inline unsigned int _rand(cimg_ulong *const p_rng) {
      *p_rng = *p_rng*1103515245 + 12345U;
      return (unsigned int)*p_rng;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    //! Convert pixel values from XYZ to RGB color spaces \newinstance.
    CImg<Tuchar> get_XYZtoRGB(const bool use_D65=true) const {
      return CImg<Tuchar>(*this,false).XYZtoRGB(use_D65);

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h


    T cubic_atX_pc(const float fx, const int y, const int z, const int c) const {
      return cimg::type<T>::cut(cubic_atX_p(fx,y,z,c));

Project: CImg
File: CImg.h

    **/
    CImgList<T>& assign(const unsigned int n) {
      if (!n) return assign();
      if (_allocated_width<n || _allocated_width>(n<<2)) {
        delete[] _data;
        _data = new CImg<T>[_allocated_width = std::max(16U,(unsigned int)cimg::nearest_pow2(n))];
      }
      _width = n;
      return *this;

Project: CImg
File: CImg.h

    template<typename T>
    inline T pow3(const T& val) {
      return val*val*val;

Project: CImg
File: CImg.h

    //   This is experimental code, not much tested, use with care.
    CImg<T>& load_magick(const char *const filename) {
      if (!filename)
        throw CImgArgumentException(_cimg_instance
                                    "load_magick(): Specified filename is (null).",
                                    cimg_instance);

#ifdef cimg_use_magick
      Magick::Image image(filename);
      const unsigned int W = image.size().width(), H = image.size().height();
      switch (image.type()) {
      case Magick::PaletteMatteType :
      case Magick::TrueColorMatteType :
      case Magick::ColorSeparationType : {
        assign(W,H,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);
        Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
        for (ulongT off = (ulongT)W*H; off; --off) {
          *(ptr_r++) = (T)(pixels->red);
          *(ptr_g++) = (T)(pixels->green);
          *(ptr_b++) = (T)(pixels->blue);
          *(ptr_a++) = (T)(pixels->opacity);
          ++pixels;
        }
      } break;
      case Magick::PaletteType :
      case Magick::TrueColorType : {
        assign(W,H,1,3);
        T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2);
        Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
        for (ulongT off = (ulongT)W*H; off; --off) {
          *(ptr_r++) = (T)(pixels->red);
          *(ptr_g++) = (T)(pixels->green);
          *(ptr_b++) = (T)(pixels->blue);
          ++pixels;
        }
      } break;
      case Magick::GrayscaleMatteType : {
        assign(W,H,1,2);
        T *ptr_r = data(0,0,0,0), *ptr_a = data(0,0,0,1);
        Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
        for (ulongT off = (ulongT)W*H; off; --off) {
          *(ptr_r++) = (T)(pixels->red);
          *(ptr_a++) = (T)(pixels->opacity);
          ++pixels;
        }
      } break;
      default : {
        assign(W,H,1,1);
        T *ptr_r = data(0,0,0,0);
        Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
        for (ulongT off = (ulongT)W*H; off; --off) {
          *(ptr_r++) = (T)(pixels->red);
          ++pixels;
        }
      }
      }
      return *this;
#else
      throw CImgIOException(_cimg_instance
                            "load_magick(): Unable to load file '%s' unless libMagick++ is enabled.",
                            cimg_instance,
                            filename);
#endif

Project: CImg
File: CImg.h

    **/
    const CImg<T>& display(const char *const title=0, const bool display_info=true, unsigned int *const XYZ=0,
                           const bool exit_on_anykey=false) const {
      CImgDisplay disp;
      return _display(disp,title,display_info,XYZ,exit_on_anykey,false);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    template<typename T>
    inline void gesvd(char &JOB, int &M, int &N, T *lapA, int &MN,
                      T *lapS, T *lapU, T *lapV, T *WORK, int &LWORK, int &INFO) {
      dgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO);

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_line(int x0, int y0,
                       int x1, int y1,
                       const CImg<tc>& texture,
                       int tx0, int ty0,
                       int tx1, int ty1,
                       const float opacity=1,
                       const unsigned int pattern=~0U, const bool init_hatch=true) {

      if (is_empty() || !opacity || !pattern) return *this;
      if (texture._depth>1 || texture._spectrum<_spectrum)
        throw CImgArgumentException(_cimg_instance
                                    "draw_line(): 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_line(x0,y0,x1,y1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);

      if (std::min(y0,y1)>=height() || std::max(y0,y1)<0 || std::min(x0,x1)>=width() || std::max(x0,x1)<0) return *this;

      int
        w1 = width() - 1, h1 = height() - 1,
        dx01 = x1 - x0, dy01 = y1 - y0;
      int
        dtx01 = tx1 - tx0, dty01 = ty1 - ty0;

      const bool is_horizontal = cimg::abs(dx01)>cimg::abs(dy01);
      if (is_horizontal) cimg::swap(x0,y0,x1,y1,w1,h1,dx01,dy01);
      if (pattern==~0U && y0>y1) {
        cimg::swap(x0,x1,y0,y1,tx0,tx1,ty0,ty1);
        dx01*=-1; dy01*=-1; dtx01*=-1; dty01*=-1;
      }

      const ulongT twhd = (ulongT)texture._width*texture._height*texture._depth;
      static unsigned int hatch = ~0U - (~0U>>1);
      if (init_hatch) hatch = ~0U - (~0U>>1);
      cimg_init_scanline(opacity);

      const int
        step = y0<=y1?1:-1, hdy01 = dy01*cimg::sign(dx01)/2,
        hdy01tx = dy01*cimg::sign(dtx01)/2, hdy01ty = dy01*cimg::sign(dty01)/2,
        cy0 = cimg::cut(y0,0,h1), cy1 = cimg::cut(y1,0,h1) + step;
      dy01+=dy01?0:1;

      for (int y = cy0; y!=cy1; y+=step) {
        const int
          yy0 = y - y0,
          x = x0 + (dx01*yy0 + hdy01)/dy01,
          tx = tx0 + (dtx01*yy0 + hdy01tx)/dy01,
          ty = ty0 + (dty01*yy0 + hdy01ty)/dy01;
        if (x>=0 && x<=w1 && pattern&hatch) {
          T *const ptrd = is_horizontal?data(y,x):data(x,y);
          const tc *const color = &texture._atXY(tx,ty);
          cimg_forC(*this,c) {
            const T val = color[c*twhd];
            ptrd[c*_sc_whd] = (T)(opacity>=1?val:val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity);
          }
        }
        if (!(hatch>>=1)) hatch = ~0U - (~0U>>1);
      }
      return *this;

Project: CImg
File: CImg.h

    **/
    inline int fclose(std::FILE *file) {
      if (!file) { warn("cimg::fclose(): Specified file is (null)."); return 0; }
      if (file==cimg::_stdin(false) || file==cimg::_stdout(false)) return 0;
      const int errn = std::fclose(file);
      if (errn!=0) warn("cimg::fclose(): Error code %d returned during file closing.",
                        errn);
      return errn;

Project: CImg
File: CImg.h

    //! Convert pixel values from RGB to Lab color spaces \newinstance.
    CImg<Tfloat> get_RGBtoLab(const bool use_D65=true) const {
      return CImg<Tfloat>(*this,false).RGBtoLab(use_D65);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


      static double mp_joff(_cimg_math_parser& mp) {
        const unsigned int
          boundary_conditions = (unsigned int)_mp_arg(3);
        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 CImg<T> &img = mp.imgin;
        const longT
          off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(2),
          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

    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=~0U) {
      CImg<uintT> foo;
      return dijkstra(distance,nb_nodes,starting_node,ending_node,foo);

Project: CImg
File: CImg.h

    // [internal] Replace possibly malicious characters for commands to be called by system() by their escaped version.
    CImg<T>& _system_strescape() {
#define cimg_system_strescape(c,s) case c : if (p!=ptrs) CImg<T>(ptrs,(unsigned int)(p-ptrs),1,1,1,false).\
      move_to(list); \
      CImg<T>(s,(unsigned int)std::strlen(s),1,1,1,false).move_to(list); ptrs = p + 1; break
      CImgList<T> list;
      const T *ptrs = _data;
      cimg_for(*this,p,T) switch ((int)*p) {
        cimg_system_strescape('\\',"\\\\");
        cimg_system_strescape('\"',"\\\"");
        cimg_system_strescape('!',"\"\\!\"");
        cimg_system_strescape('`',"\\`");
        cimg_system_strescape('$',"\\$");
      }
      if (ptrs<end()) CImg<T>(ptrs,(unsigned int)(end()-ptrs),1,1,1,false).move_to(list);
      return (list>'x').move_to(*this);

Project: CImg
File: CImg.h

    template<typename T>
    void _resize(T pixel_type, const unsigned int ndimx, const unsigned int ndimy, const bool force_redraw) {
      Display *const dpy = cimg::X11_attr().display;
      cimg::unused(pixel_type);

#ifdef cimg_use_xshm
      if (_shminfo) {
        XShmSegmentInfo *const nshminfo = new XShmSegmentInfo;
        XImage *const nimage = XShmCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),
                                               cimg::X11_attr().nb_bits,ZPixmap,0,nshminfo,ndimx,ndimy);
        if (!nimage) { delete nshminfo; return; }
        else {
          nshminfo->shmid = shmget(IPC_PRIVATE,ndimx*ndimy*sizeof(T),IPC_CREAT | 0777);
          if (nshminfo->shmid==-1) { XDestroyImage(nimage); delete nshminfo; return; }
          else {
            nshminfo->shmaddr = nimage->data = (char*)shmat(nshminfo->shmid,0,0);
            if (nshminfo->shmaddr==(char*)-1) {
              shmctl(nshminfo->shmid,IPC_RMID,0); XDestroyImage(nimage); delete nshminfo; return;
            } else {
              nshminfo->readOnly = 0;
              cimg::X11_attr().is_shm_enabled = true;
              XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm);
              XShmAttach(dpy,nshminfo);
              XFlush(dpy);
              XSetErrorHandler(oldXErrorHandler);
              if (!cimg::X11_attr().is_shm_enabled) {
                shmdt(nshminfo->shmaddr);
                shmctl(nshminfo->shmid,IPC_RMID,0);
                XDestroyImage(nimage);
                delete nshminfo;
                return;
              } else {
                T *const ndata = (T*)nimage->data;
                if (force_redraw) _render_resize((T*)_data,_width,_height,ndata,ndimx,ndimy);
                else std::memset(ndata,0,sizeof(T)*ndimx*ndimy);
                XShmDetach(dpy,_shminfo);
                XDestroyImage(_image);
                shmdt(_shminfo->shmaddr);
                shmctl(_shminfo->shmid,IPC_RMID,0);
                delete _shminfo;
                _shminfo = nshminfo;
                _image = nimage;
                _data = (void*)ndata;
              }
            }
          }
        }
      } else
#endif
        {
          T *ndata = (T*)std::malloc(ndimx*ndimy*sizeof(T));
          if (force_redraw) _render_resize((T*)_data,_width,_height,ndata,ndimx,ndimy);
          else std::memset(ndata,0,sizeof(T)*ndimx*ndimy);
          _data = (void*)ndata;
          XDestroyImage(_image);
          _image = XCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),
                                cimg::X11_attr().nb_bits,ZPixmap,0,(char*)_data,ndimx,ndimy,8,0);
        }

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& label(const CImg<t>& connectivity_mask, const Tfloat tolerance=0) {
      return get_label(connectivity_mask,tolerance).move_to(*this);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    template<typename T>
    inline cimg_ulong nearest_pow2(const T& x) {
      cimg_ulong i = 1;
      while (x>i) i<<=1;
      return i;

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) {
      if (is_empty()) return *this;
      T *ptrd, *ptre = end() - 4;
      for (ptrd = _data; ptrd<ptre; ) {
        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4;
      }
      ptre+=4;
      switch (ptre - ptrd) {
      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

    **/
    CImg<T>& norm(const int norm_type=2) {
      if (_spectrum==1 && norm_type) return abs();
      return get_norm(norm_type).move_to(*this);

Project: CImg
File: CImg.h

    **/
    CImg<T>& set_linear_atXYZ(const T& value, const float fx, const float fy=0, const float fz=0, const int c=0,
                              const bool is_added=false) {
      const int
        x = (int)fx - (fx>=0?0:1), nx = x + 1,
        y = (int)fy - (fy>=0?0:1), ny = y + 1,
        z = (int)fz - (fz>=0?0:1), nz = z + 1;
      const float
        dx = fx - x,
        dy = fy - y,
        dz = fz - z;
      if (c>=0 && c<spectrum()) {
        if (z>=0 && z<depth()) {
          if (y>=0 && y<height()) {
            if (x>=0 && x<width()) {
              const float w1 = (1 - dx)*(1 - dy)*(1 - dz), w2 = is_added?1:(1 - w1);
              (*this)(x,y,z,c) = (T)(w1*value + w2*(*this)(x,y,z,c));
            }
            if (nx>=0 && nx<width()) {
              const float w1 = dx*(1 - dy)*(1 - dz), w2 = is_added?1:(1 - w1);
              (*this)(nx,y,z,c) = (T)(w1*value + w2*(*this)(nx,y,z,c));
            }
          }
          if (ny>=0 && ny<height()) {
            if (x>=0 && x<width()) {
              const float w1 = (1 - dx)*dy*(1 - dz), w2 = is_added?1:(1 - w1);
              (*this)(x,ny,z,c) = (T)(w1*value + w2*(*this)(x,ny,z,c));
            }
            if (nx>=0 && nx<width()) {
              const float w1 = dx*dy*(1 - dz), w2 = is_added?1:(1 - w1);
              (*this)(nx,ny,z,c) = (T)(w1*value + w2*(*this)(nx,ny,z,c));
            }
          }
        }
        if (nz>=0 && nz<depth()) {
          if (y>=0 && y<height()) {
            if (x>=0 && x<width()) {
              const float w1 = (1 - dx)*(1 - dy)*dz, w2 = is_added?1:(1 - w1);
              (*this)(x,y,nz,c) = (T)(w1*value + w2*(*this)(x,y,nz,c));
            }
            if (nx>=0 && nx<width()) {
              const float w1 = dx*(1 - dy)*dz, w2 = is_added?1:(1 - w1);
              (*this)(nx,y,nz,c) = (T)(w1*value + w2*(*this)(nx,y,nz,c));
            }
          }
          if (ny>=0 && ny<height()) {
            if (x>=0 && x<width()) {
              const float w1 = (1 - dx)*dy*dz, w2 = is_added?1:(1 - w1);
              (*this)(x,ny,nz,c) = (T)(w1*value + w2*(*this)(x,ny,nz,c));
            }
            if (nx>=0 && nx<width()) {
              const float w1 = dx*dy*dz, w2 = is_added?1:(1 - w1);
              (*this)(nx,ny,nz,c) = (T)(w1*value + w2*(*this)(nx,ny,nz,c));
            }
          }
        }
      }
      return *this;

Project: CImg
File: CImg.h

    //! Return a shared-memory image referencing a range of pixels of the image instance \const.
    const CImg<T> get_shared_points(const unsigned int x0, const unsigned int x1,
                                    const unsigned int y0=0, const unsigned int z0=0, const unsigned int c0=0) const {
      const unsigned int
        beg = (unsigned int)offset(x0,y0,z0,c0),
        end = (unsigned int)offset(x1,y0,z0,c0);
      if (beg>end || beg>=size() || end>=size())
        throw CImgArgumentException(_cimg_instance
                                    "get_shared_points(): Invalid request of a shared-memory subset (%u->%u,%u,%u,%u).",
                                    cimg_instance,
                                    x0,x1,y0,z0,c0);

      return CImg<T>(_data + beg,x1 - x0 + 1,1,1,1,true);

Project: CImg
File: CImg.h

     **/
    CImg<T>& rand(const T& val_min, const T& val_max) {
      const float delta = (float)val_max - (float)val_min + (cimg::type<T>::is_float()?0:1);
      if (cimg::type<T>::is_float()) cimg_pragma_openmp(parallel cimg_openmp_if_size(size(),524288)) {
          ulongT rng = (cimg::_rand(),cimg::rng());

#if cimg_use_openmp!=0
          rng+=omp_get_thread_num();
#endif
          cimg_pragma_openmp(for)
            cimg_rofoff(*this,off) _data[off] = (T)(val_min + delta*cimg::rand(1,&rng));
          cimg::srand(rng);
        } else cimg_pragma_openmp(parallel cimg_openmp_if_size(size(),524288)) {
          ulongT rng = (cimg::_rand(),cimg::rng());

#if cimg_use_openmp!=0
          rng+=omp_get_thread_num();
#endif
          cimg_pragma_openmp(for)
            cimg_rofoff(*this,off) _data[off] = std::min(val_max,(T)(val_min + delta*cimg::rand(1,&rng)));
          cimg::srand(rng);
        }
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


    const CImg<T>& _save_jpeg(std::FILE *const file, const char *const filename, const unsigned int quality) const {
      if (!file && !filename)
        throw CImgArgumentException(_cimg_instance
                                    "save_jpeg(): Specified filename is (null).",
                                    cimg_instance);
      if (is_empty()) { cimg::fempty(file,filename); return *this; }
      if (_depth>1)
        cimg::warn(_cimg_instance
                   "save_jpeg(): Instance is volumetric, only the first slice will be saved in file '%s'.",
                   cimg_instance,
                   filename?filename:"(FILE*)");

#ifndef cimg_use_jpeg
      if (!file) return save_other(filename,quality);
      else throw CImgIOException(_cimg_instance
                                 "save_jpeg(): Unable to save data in '(*FILE)' unless libjpeg is enabled.",
                                 cimg_instance);
#else
      unsigned int dimbuf = 0;
      J_COLOR_SPACE colortype = JCS_RGB;

      switch (_spectrum) {
      case 1 : dimbuf = 1; colortype = JCS_GRAYSCALE; break;
      case 2 : dimbuf = 3; colortype = JCS_RGB; break;
      case 3 : dimbuf = 3; colortype = JCS_RGB; break;
      default : dimbuf = 4; colortype = JCS_CMYK; break;
      }

      // Call libjpeg functions
      struct jpeg_compress_struct cinfo;
      struct jpeg_error_mgr jerr;
      cinfo.err = jpeg_std_error(&jerr);
      jpeg_create_compress(&cinfo);
      std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
      jpeg_stdio_dest(&cinfo,nfile);
      cinfo.image_width = _width;
      cinfo.image_height = _height;
      cinfo.input_components = dimbuf;
      cinfo.in_color_space = colortype;
      jpeg_set_defaults(&cinfo);
      jpeg_set_quality(&cinfo,quality<100?quality:100,TRUE);
      jpeg_start_compress(&cinfo,TRUE);

      JSAMPROW row_pointer[1];
      CImg<ucharT> buffer(_width*dimbuf);

      while (cinfo.next_scanline<cinfo.image_height) {
        unsigned char *ptrd = buffer._data;

        // Fill pixel buffer
        switch (_spectrum) {
        case 1 : { // Greyscale images
          const T *ptr_g = data(0, cinfo.next_scanline);
          for (unsigned int b = 0; b<cinfo.image_width; b++)
            *(ptrd++) = (unsigned char)*(ptr_g++);
        } break;
        case 2 : { // RG images
          const T *ptr_r = data(0,cinfo.next_scanline,0,0),
            *ptr_g = data(0,cinfo.next_scanline,0,1);
          for (unsigned int b = 0; b<cinfo.image_width; ++b) {
            *(ptrd++) = (unsigned char)*(ptr_r++);
            *(ptrd++) = (unsigned char)*(ptr_g++);
            *(ptrd++) = 0;
          }
        } break;
        case 3 : { // RGB images
          const T *ptr_r = data(0,cinfo.next_scanline,0,0),
            *ptr_g = data(0,cinfo.next_scanline,0,1),
            *ptr_b = data(0,cinfo.next_scanline,0,2);
          for (unsigned int b = 0; b<cinfo.image_width; ++b) {
            *(ptrd++) = (unsigned char)*(ptr_r++);
            *(ptrd++) = (unsigned char)*(ptr_g++);
            *(ptrd++) = (unsigned char)*(ptr_b++);
          }
        } break;
        default : { // CMYK images
          const T *ptr_r = data(0,cinfo.next_scanline,0,0),
            *ptr_g = data(0,cinfo.next_scanline,0,1),
            *ptr_b = data(0,cinfo.next_scanline,0,2),
            *ptr_a = data(0,cinfo.next_scanline,0,3);
          for (unsigned int b = 0; b<cinfo.image_width; ++b) {
            *(ptrd++) = (unsigned char)*(ptr_r++);
            *(ptrd++) = (unsigned char)*(ptr_g++);
            *(ptrd++) = (unsigned char)*(ptr_b++);
            *(ptrd++) = (unsigned char)*(ptr_a++);
          }
        }
        }
        *row_pointer = buffer._data;
        jpeg_write_scanlines(&cinfo,row_pointer,1);
      }
      jpeg_finish_compress(&cinfo);
      if (!file) cimg::fclose(nfile);
      jpeg_destroy_compress(&cinfo);
      return *this;
#endif

Project: CImg
File: CImg.h

    **/
    bool is_moved() const {
      return _is_moved;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

      _functor4d_streamline2d_oriented(const CImg<T>& pref):ref(pref),pI(0) { pI = new CImg<floatT>(2,2,1,2); }

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


    inline unsigned int _rand() {
      cimg::mutex(4);
      const unsigned int res = cimg::_rand(&cimg::rng());
      cimg::mutex(4,0);
      return res;

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

    //! Return iterator to one position after the last image of the list \const.
    const_iterator end() const {
      return _data + _width;

Project: CImg
File: CImg.h

      static long double inf() { return max()*max(); }

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

      return _linear_atXYZC(fx,fy,fz,fc);

Project: CImg
File: CImg.h

    //! Convert pixel values from RGB to CMY color spaces \newinstance.
    CImg<Tuchar> get_RGBtoCMY() const {
      return CImg<Tfloat>(*this,false).RGBtoCMY();

Project: CImg
File: CImg.h

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

      CImg<charT> command(1024), filename_tmp(256), body(256);
      const char
        *ext = cimg::split_filename(filename,body),
        *ext2 = cimg::split_filename(body,0);
      std::FILE *file;
      do {
        if (!cimg::strcasecmp(ext,"gz")) {
          if (*ext2) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s",
                                   cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2);
          else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.cimg",
                             cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
        } else {
          if (*ext) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s",
                                  cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext);
          else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.cimg",
                             cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
        }
        if ((file=cimg::std_fopen(filename_tmp,"rb"))!=0) cimg::fclose(file);
      } while (file);
      save(filename_tmp);
      cimg_snprintf(command,command._width,"%s -c \"%s\" > \"%s\"",
                    cimg::gzip_path(),
                    CImg<charT>::string(filename_tmp)._system_strescape().data(),
                    CImg<charT>::string(filename)._system_strescape().data());
      cimg::system(command);
      file = cimg::std_fopen(filename,"rb");
      if (!file)
        throw CImgIOException(_cimg_instance
                              "save_gzip_external(): Failed to save file '%s' with external command 'gzip'.",
                              cimg_instance,
                              filename);

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

Project: CImg
File: CImg.h


      static double mp_complex_abs(_cimg_math_parser& mp) {
        return cimg::_hypot(_mp_arg(2),_mp_arg(3));

Project: CImg
File: CImg.h

    }

    //! Insert \c n copies of the image \c img into the current image list, at position \c pos \newinstance.
    template<typename t>

Project: CImg
File: CImg.h

      return s_path;
    }

    // [internal] Sorting function, used by cimg::files().

Project: CImg
File: CImg.h

    **/
    unsigned int button() const {
      return _button;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

      static const char* format() { return "%d"; }

Project: CImg
File: CImg.h


    const CImg<T>& _save_cpp(std::FILE *const file, const char *const filename) const {
      if (!file && !filename)
        throw CImgArgumentException(_cimg_instance
                                    "save_cpp(): Specified filename is (null).",
                                    cimg_instance);
      std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
      CImg<charT> varname(1024); *varname = 0;
      if (filename) cimg_sscanf(cimg::basename(filename),"%1023[a-zA-Z0-9_]",varname._data);
      if (!*varname) cimg_snprintf(varname,varname._width,"unnamed");
      std::fprintf(nfile,
                   "/* Define image '%s' of size %ux%ux%ux%u and type '%s' */\n"
                   "%s data_%s[] = { %s\n  ",
                   varname._data,_width,_height,_depth,_spectrum,pixel_type(),pixel_type(),varname._data,
                   is_empty()?"};":"");
      if (!is_empty()) for (ulongT off = 0, siz = size() - 1; off<=siz; ++off) {
        std::fprintf(nfile,cimg::type<T>::format(),cimg::type<T>::format((*this)[off]));
        if (off==siz) std::fprintf(nfile," };\n");
        else if (!((off + 1)%16)) std::fprintf(nfile,",\n  ");
        else std::fprintf(nfile,", ");
      }
      if (!file) cimg::fclose(nfile);
      return *this;

Project: CImg
File: CImg.h

    **/
    CImgDisplay& set_key(const unsigned int keycode, const bool is_pressed=true) {
#define _cimg_set_key(k) if (keycode==cimg::key##k) _is_key##k = is_pressed;
      _cimg_set_key(ESC); _cimg_set_key(F1); _cimg_set_key(F2); _cimg_set_key(F3);
      _cimg_set_key(F4); _cimg_set_key(F5); _cimg_set_key(F6); _cimg_set_key(F7);
      _cimg_set_key(F8); _cimg_set_key(F9); _cimg_set_key(F10); _cimg_set_key(F11);
      _cimg_set_key(F12); _cimg_set_key(PAUSE); _cimg_set_key(1); _cimg_set_key(2);
      _cimg_set_key(3); _cimg_set_key(4); _cimg_set_key(5); _cimg_set_key(6);
      _cimg_set_key(7); _cimg_set_key(8); _cimg_set_key(9); _cimg_set_key(0);
      _cimg_set_key(BACKSPACE); _cimg_set_key(INSERT); _cimg_set_key(HOME);
      _cimg_set_key(PAGEUP); _cimg_set_key(TAB); _cimg_set_key(Q); _cimg_set_key(W);
      _cimg_set_key(E); _cimg_set_key(R); _cimg_set_key(T); _cimg_set_key(Y);
      _cimg_set_key(U); _cimg_set_key(I); _cimg_set_key(O); _cimg_set_key(P);
      _cimg_set_key(DELETE); _cimg_set_key(END); _cimg_set_key(PAGEDOWN);
      _cimg_set_key(CAPSLOCK); _cimg_set_key(A); _cimg_set_key(S); _cimg_set_key(D);
      _cimg_set_key(F); _cimg_set_key(G); _cimg_set_key(H); _cimg_set_key(J);
      _cimg_set_key(K); _cimg_set_key(L); _cimg_set_key(ENTER);
      _cimg_set_key(SHIFTLEFT); _cimg_set_key(Z); _cimg_set_key(X); _cimg_set_key(C);
      _cimg_set_key(V); _cimg_set_key(B); _cimg_set_key(N); _cimg_set_key(M);
      _cimg_set_key(SHIFTRIGHT); _cimg_set_key(ARROWUP); _cimg_set_key(CTRLLEFT);
      _cimg_set_key(APPLEFT); _cimg_set_key(ALT); _cimg_set_key(SPACE); _cimg_set_key(ALTGR);
      _cimg_set_key(APPRIGHT); _cimg_set_key(MENU); _cimg_set_key(CTRLRIGHT);
      _cimg_set_key(ARROWLEFT); _cimg_set_key(ARROWDOWN); _cimg_set_key(ARROWRIGHT);
      _cimg_set_key(PAD0); _cimg_set_key(PAD1); _cimg_set_key(PAD2);
      _cimg_set_key(PAD3); _cimg_set_key(PAD4); _cimg_set_key(PAD5);
      _cimg_set_key(PAD6); _cimg_set_key(PAD7); _cimg_set_key(PAD8);
      _cimg_set_key(PAD9); _cimg_set_key(PADADD); _cimg_set_key(PADSUB);
      _cimg_set_key(PADMUL); _cimg_set_key(PADDIV);
      if (is_pressed) {
        if (*_keys)
          std::memmove((void*)(_keys + 1),(void*)_keys,127*sizeof(unsigned int));
        *_keys = keycode;
        if (*_released_keys) {
          std::memmove((void*)(_released_keys + 1),(void*)_released_keys,127*sizeof(unsigned int));
          *_released_keys = 0;
        }
      } else {
        if (*_keys) {
          std::memmove((void*)(_keys + 1),(void*)_keys,127*sizeof(unsigned int));
          *_keys = 0;
        }
        if (*_released_keys)
          std::memmove((void*)(_released_keys + 1),(void*)_released_keys,127*sizeof(unsigned int));
        *_released_keys = keycode;
      }
      _is_event = keycode?true:false;
      if (keycode) {
#if cimg_display==1
        pthread_cond_broadcast(&cimg::X11_attr().wait_event);
#elif cimg_display==2
        SetEvent(cimg::Win32_attr().wait_event);
#endif
      }
      return *this;

Project: CImg
File: CImg.h

    **/
    CImgList<Tfloat> get_eigen() const {
      CImgList<Tfloat> res(2);
      eigen(res[0],res[1]);
      return res;

Project: CImg
File: CImg.h

    //! Fill pixel values along the Y-axis at a specified pixel position \overloading.
    CImg<T>& fillY(const unsigned int x, const unsigned int z, const unsigned int c, const double a0, ...) {
      if (x<_width && z<_depth && c<_spectrum) _cimg_fill1(x,0,z,c,_width,_height,double);
      return *this;

Project: CImg
File: CImg.h

    //! Test if image depth is equal to specified value.
    bool is_sameZ(const unsigned int size_z) const {
      return _depth==size_z;

Project: CImg
File: CImg.h

    //! Compute Haar multiscale wavelet transform \newinstance.
    CImg<Tfloat> get_haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) const {
      if (is_empty() || !nb_scales) return +*this;
      CImg<Tfloat> res;
      const Tfloat sqrt2 = std::sqrt(2.f);
      if (nb_scales==1) {
        switch (cimg::lowercase(axis)) { // Single scale transform
        case 'x' : {
          const unsigned int w = _width/2;
          if (w) {
            if ((w%2) && w!=1)
              throw CImgInstanceException(_cimg_instance
                                          "haar(): Sub-image width %u is not even.",
                                          cimg_instance,
                                          w);

            res.assign(_width,_height,_depth,_spectrum);
            if (invert) cimg_forYZC(*this,y,z,c) { // Inverse transform along X
              for (unsigned int x = 0, xw = w, x2 = 0; x<w; ++x, ++xw) {
                const Tfloat val0 = (Tfloat)(*this)(x,y,z,c), val1 = (Tfloat)(*this)(xw,y,z,c);
                res(x2++,y,z,c) = (val0 - val1)/sqrt2;
                res(x2++,y,z,c) = (val0 + val1)/sqrt2;
              }
            } else cimg_forYZC(*this,y,z,c) { // Direct transform along X
              for (unsigned int x = 0, xw = w, x2 = 0; x<w; ++x, ++xw) {
                const Tfloat val0 = (Tfloat)(*this)(x2++,y,z,c), val1 = (Tfloat)(*this)(x2++,y,z,c);
                res(x,y,z,c) = (val0 + val1)/sqrt2;
                res(xw,y,z,c) = (val1 - val0)/sqrt2;
              }
            }
          } else return *this;
        } break;
        case 'y' : {
          const unsigned int h = _height/2;
          if (h) {
            if ((h%2) && h!=1)
              throw CImgInstanceException(_cimg_instance
                                          "haar(): Sub-image height %u is not even.",
                                          cimg_instance,
                                          h);

            res.assign(_width,_height,_depth,_spectrum);
            if (invert) cimg_forXZC(*this,x,z,c) { // Inverse transform along Y
              for (unsigned int y = 0, yh = h, y2 = 0; y<h; ++y, ++yh) {
                const Tfloat val0 = (Tfloat)(*this)(x,y,z,c), val1 = (Tfloat)(*this)(x,yh,z,c);
                res(x,y2++,z,c) = (val0 - val1)/sqrt2;
                res(x,y2++,z,c) = (val0 + val1)/sqrt2;
              }
            } else cimg_forXZC(*this,x,z,c) {
              for (unsigned int y = 0, yh = h, y2 = 0; y<h; ++y, ++yh) { // Direct transform along Y
                const Tfloat val0 = (Tfloat)(*this)(x,y2++,z,c), val1 = (Tfloat)(*this)(x,y2++,z,c);
                res(x,y,z,c)  = (val0 + val1)/sqrt2;
                res(x,yh,z,c) = (val1 - val0)/sqrt2;
              }
            }
          } else return *this;
        } break;
        case 'z' : {
          const unsigned int d = _depth/2;
          if (d) {
            if ((d%2) && d!=1)
              throw CImgInstanceException(_cimg_instance
                                          "haar(): Sub-image depth %u is not even.",
                                          cimg_instance,
                                          d);

            res.assign(_width,_height,_depth,_spectrum);
            if (invert) cimg_forXYC(*this,x,y,c) { // Inverse transform along Z
              for (unsigned int z = 0, zd = d, z2 = 0; z<d; ++z, ++zd) {
                const Tfloat val0 = (Tfloat)(*this)(x,y,z,c), val1 = (Tfloat)(*this)(x,y,zd,c);
                res(x,y,z2++,c) = (val0 - val1)/sqrt2;
                res(x,y,z2++,c) = (val0 + val1)/sqrt2;
              }
            } else cimg_forXYC(*this,x,y,c) {
              for (unsigned int z = 0, zd = d, z2 = 0; z<d; ++z, ++zd) { // Direct transform along Z
                const Tfloat val0 = (Tfloat)(*this)(x,y,z2++,c), val1 = (Tfloat)(*this)(x,y,z2++,c);
                res(x,y,z,c)  = (val0 + val1)/sqrt2;
                res(x,y,zd,c) = (val1 - val0)/sqrt2;
              }
            }
          } else return *this;
        } break;
        default :
          throw CImgArgumentException(_cimg_instance
                                      "haar(): Invalid specified axis '%c' "
                                      "(should be { x | y | z }).",
                                      cimg_instance,
                                      axis);
        }
      } else { // Multi-scale version
        if (invert) {
          res.assign(*this,false);
          switch (cimg::lowercase(axis)) {
          case 'x' : {
            unsigned int w = _width;
            for (unsigned int s = 1; w && s<nb_scales; ++s) w/=2;
            for (w = w?w:1; w<=_width; w*=2) res.draw_image(res.get_crop(0,w - 1).get_haar('x',true,1));
          } break;
          case 'y' : {
            unsigned int h = _width;
            for (unsigned int s = 1; h && s<nb_scales; ++s) h/=2;
            for (h = h?h:1; h<=_height; h*=2) res.draw_image(res.get_crop(0,0,_width - 1,h - 1).get_haar('y',true,1));
          } break;
          case 'z' : {
            unsigned int d = _depth;
            for (unsigned int s = 1; d && s<nb_scales; ++s) d/=2;
            for (d = d?d:1; d<=_depth; d*=2)
              res.draw_image(res.get_crop(0,0,0,_width - 1,_height - 1,d - 1).get_haar('z',true,1));
          } break;
          default :
            throw CImgArgumentException(_cimg_instance
                                        "haar(): Invalid specified axis '%c' "
                                        "(should be { x | y | z }).",
                                        cimg_instance,
                                        axis);
          }
        } else { // Direct transform
          res = get_haar(axis,false,1);
          switch (cimg::lowercase(axis)) {
          case 'x' : {
            for (unsigned int s = 1, w = _width/2; w && s<nb_scales; ++s, w/=2)
              res.draw_image(res.get_crop(0,w - 1).get_haar('x',false,1));
          } break;
          case 'y' : {
            for (unsigned int s = 1, h = _height/2; h && s<nb_scales; ++s, h/=2)
              res.draw_image(res.get_crop(0,0,_width - 1,h - 1).get_haar('y',false,1));
          } break;
          case 'z' : {
            for (unsigned int s = 1, d = _depth/2; d && s<nb_scales; ++s, d/=2)
              res.draw_image(res.get_crop(0,0,0,_width - 1,_height - 1,d - 1).get_haar('z',false,1));
          } break;
          default :
            throw CImgArgumentException(_cimg_instance
                                        "haar(): Invalid specified axis '%c' "
                                        "(should be { x | y | z }).",
                                        cimg_instance,
                                        axis);
          }
        }
      }
      return res;

Project: CImg
File: CImg.h

      return (+*this).remove();
    }

    //! Reverse list order.

Project: CImg
File: CImg.h


    METHODDEF(void) _cimg_jpeg_error_exit(j_common_ptr cinfo) {
      _cimg_error_ptr c_err = (_cimg_error_ptr) cinfo->err;  // Return control to the setjmp point
      (*cinfo->err->format_message)(cinfo,c_err->message);
      jpeg_destroy(cinfo);  // Clean memory and temp files
      longjmp(c_err->setjmp_buffer,1);

Project: CImg
File: CImg.h

    }
    inline cimg_int64 abs(const cimg_uint64 a) {
      return (cimg_int64)a;

Project: CImg
File: CImg.h

    template<typename to>
    float* _object3dtoCImg3d(const CImgList<to>& opacities, float *ptrd) const {
      cimglist_for(opacities,o) {
        const CImg<to>& opacity = opacities[o];
        const to *ptro = opacity._data;
        if (opacity.size()==1) *(ptrd++) = (float)*ptro;
        else {
          *(ptrd++) = -128.f;
          int shared_ind = -1;
          if (opacity.is_shared()) for (int i = 0; i<o; ++i) if (ptro==opacities[i]._data) { shared_ind = i; break; }
          if (shared_ind<0) {
            *(ptrd++) = (float)opacity._width;
            *(ptrd++) = (float)opacity._height;
            *(ptrd++) = (float)opacity._spectrum;
            cimg_foroff(opacity,l) *(ptrd++) = (float)*(ptro++);
          } else {
            *(ptrd++) = (float)shared_ind;
            *(ptrd++) = 0;
            *(ptrd++) = 0;
          }
        }
      }
      return ptrd;

Project: CImg
File: CImg.h

    //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3, \c disp4, ... \c disp9.
    static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5,
                     CImgDisplay& disp6, CImgDisplay& disp7, CImgDisplay& disp8, CImgDisplay& disp9) {
      disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event =
        disp6._is_event = disp7._is_event = disp8._is_event = disp9._is_event = false;
      while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed ||
              !disp6._is_closed || !disp7._is_closed || !disp8._is_closed || !disp9._is_closed) &&
             !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event &&
             !disp6._is_event && !disp7._is_event && !disp8._is_event && !disp9._is_event) wait_all();

Project: CImg
File: CImg.h

      Mutex_info() { for (unsigned int i = 0; i<32; ++i) mutex[i] = CreateMutex(0,FALSE,0); }

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

   **/
    inline bool strpare(char *const str, const char delimiter,
                        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 && str[p]==delimiter && str[q]==delimiter; ) {
          --q; ++p; if (!is_iterative) break;
        } else {
        for (p = 0; p<l && str[p]==delimiter; ) { ++p; if (!is_iterative) break; }
        for (q = l - 1; q>p && str[q]==delimiter; ) { --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


      static double mp_image_d(_cimg_math_parser& mp) {
        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.imgout:mp.listout[ind];
        return (double)img.depth();

Project: CImg
File: CImg.h


      static double mp_set_Ioff_v(_cimg_math_parser& mp) {
        CImg<T> &img = mp.imgout;
        const longT
          off = (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

       \param referer Referer used, as a C-string.
       \return Value of \c filename_local.
       \note Use the \c libcurl library, or the external binaries \c wget or \c curl to perform the download.
    **/
    inline char *load_network(const char *const url, char *const filename_local,
                              const unsigned int timeout, const bool try_fallback,
                              const char *const referer) {
      if (!url)
        throw CImgArgumentException("cimg::load_network(): Specified URL is (null).");
      if (!filename_local)
        throw CImgArgumentException("cimg::load_network(): Specified destination string is (null).");

      const char *const __ext = cimg::split_filename(url), *const _ext = (*__ext && __ext>url)?__ext - 1:__ext;
      CImg<char> ext = CImg<char>::string(_ext);
      std::FILE *file = 0;
      *filename_local = 0;
      if (ext._width>16 || !cimg::strncasecmp(ext,"cgi",3)) *ext = 0;
      else cimg::strwindows_reserved(ext);
      do {
        cimg_snprintf(filename_local,256,"%s%c%s%s",
                      cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext._data);
        if ((file=cimg::std_fopen(filename_local,"rb"))!=0) cimg::fclose(file);
      } while (file);

#ifdef cimg_use_curl
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode(0);
      try {
        CURL *curl = 0;
        CURLcode res;
        curl = curl_easy_init();
        if (curl) {
          file = cimg::fopen(filename_local,"wb");
          curl_easy_setopt(curl,CURLOPT_URL,url);
          curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,0);
          curl_easy_setopt(curl,CURLOPT_WRITEDATA,file);
          curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,0L);
          curl_easy_setopt(curl,CURLOPT_SSL_VERIFYHOST,0L);
          curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,1L);
          if (timeout) curl_easy_setopt(curl,CURLOPT_TIMEOUT,(long)timeout);
          if (std::strchr(url,'?')) curl_easy_setopt(curl,CURLOPT_HTTPGET,1L);
          if (referer) curl_easy_setopt(curl,CURLOPT_REFERER,referer);
          res = curl_easy_perform(curl);
          curl_easy_cleanup(curl);
          cimg::fseek(file,0,SEEK_END); // Check if file size is 0
          const cimg_ulong siz = cimg::ftell(file);
          cimg::fclose(file);
          if (siz>0 && res==CURLE_OK) {
            cimg::exception_mode(omode);
            return filename_local;
          } else std::remove(filename_local);
        }
      } catch (...) { }
      cimg::exception_mode(omode);
      if (!try_fallback) throw CImgIOException("cimg::load_network(): Failed to load file '%s' with libcurl.",url);
#endif

      CImg<char> command((unsigned int)std::strlen(url) + 64);
      cimg::unused(try_fallback);

      // Try with 'curl' first.
      if (timeout) {
        if (referer)
          cimg_snprintf(command,command._width,"%s -e %s -m %u -f --silent --compressed -o \"%s\" \"%s\"",
                        cimg::curl_path(),referer,timeout,filename_local,
                        CImg<char>::string(url)._system_strescape().data());
        else
          cimg_snprintf(command,command._width,"%s -m %u -f --silent --compressed -o \"%s\" \"%s\"",
                        cimg::curl_path(),timeout,filename_local,
                        CImg<char>::string(url)._system_strescape().data());
      } else {
        if (referer)
          cimg_snprintf(command,command._width,"%s -e %s -f --silent --compressed -o \"%s\" \"%s\"",
                        cimg::curl_path(),referer,filename_local,
                        CImg<char>::string(url)._system_strescape().data());
        else
          cimg_snprintf(command,command._width,"%s -f --silent --compressed -o \"%s\" \"%s\"",
                        cimg::curl_path(),filename_local,
                        CImg<char>::string(url)._system_strescape().data());
      }
      cimg::system(command);

      if (!(file=cimg::std_fopen(filename_local,"rb"))) {

        // Try with 'wget' otherwise.
        if (timeout) {
          if (referer)
            cimg_snprintf(command,command._width,"%s --referer=%s -T %u -q -r -l 0 --no-cache -O \"%s\" \"%s\"",
                          cimg::wget_path(),referer,timeout,filename_local,
                          CImg<char>::string(url)._system_strescape().data());
          else
            cimg_snprintf(command,command._width,"%s -T %u -q -r -l 0 --no-cache -O \"%s\" \"%s\"",
                          cimg::wget_path(),timeout,filename_local,
                          CImg<char>::string(url)._system_strescape().data());
        } else {
          if (referer)
            cimg_snprintf(command,command._width,"%s --referer=%s -q -r -l 0 --no-cache -O \"%s\" \"%s\"",
                          cimg::wget_path(),referer,filename_local,
                          CImg<char>::string(url)._system_strescape().data());
          else
            cimg_snprintf(command,command._width,"%s -q -r -l 0 --no-cache -O \"%s\" \"%s\"",
                          cimg::wget_path(),filename_local,
                          CImg<char>::string(url)._system_strescape().data());
        }
        cimg::system(command);

        if (!(file=cimg::std_fopen(filename_local,"rb")))
          throw CImgIOException("cimg::load_network(): Failed to load file '%s' with external commands "
                                "'wget' or 'curl'.",url);
        cimg::fclose(file);

        // Try gunzip it.
        cimg_snprintf(command,command._width,"%s.gz",filename_local);
        std::rename(filename_local,command);
        cimg_snprintf(command,command._width,"%s --quiet \"%s.gz\"",
                      gunzip_path(),filename_local);
        cimg::system(command);
        file = cimg::std_fopen(filename_local,"rb");
        if (!file) {
          cimg_snprintf(command,command._width,"%s.gz",filename_local);
          std::rename(command,filename_local);
          file = cimg::std_fopen(filename_local,"rb");
        }
      }
      cimg::fseek(file,0,SEEK_END); // Check if file size is 0
      if (std::ftell(file)<=0)
        throw CImgIOException("cimg::load_network(): Failed to load URL '%s' with external commands "

Project: CImg
File: CImg.h

    //! Return the number of permutations of k objects in a set of n objects.
    inline double permutations(const int k, const int n, const bool with_order) {
      if (n<0 || k<0) return cimg::type<double>::nan();
      if (k>n) return 0;
      double res = 1;
      for (int i = n; i>=n - k + 1; --i) res*=i;
      return with_order?res:res/cimg::factorial(k);

Project: CImg
File: CImg.h

    template<typename T>
    inline T& temporary(const T&) {
      static T temp;
      return temp;

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

    //! Return iterator to the first image of the list \const.
    const_iterator begin() const {
      return _data;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    //! Load image from a PAR-REC (Philips) file \newinstance.
    static CImg<T> get_load_parrec(const char *const filename, const char axis='c', const float align=0) {
      return CImg<T>().load_parrec(filename,axis,align);

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
    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, T8& a8, T8& b8) {
      cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6,a7,b7); cimg::swap(a8,b8);

Project: CImg
File: CImg.h

    // Convert a CImg<T> to a cv::Mat.
    cv::Mat _cimg2cvmat() const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "_cimg2cvmat() : Instance image is empty.",
                                    cimg_instance);
      if (_spectrum==2)
        throw CImgInstanceException(_cimg_instance
                                    "_cimg2cvmat() : Invalid number of channels (should be '1' or '3+').",
                                    cimg_instance);
      if (_depth!=1)
        throw CImgInstanceException(_cimg_instance
                                    "_cimg2cvmat() : Invalid number of slices (should be '1').",
                                    cimg_instance);
      int mat_type = -1;
      if (cimg::type<T>::string()==cimg::type<unsigned char>::string()) mat_type = CV_8UC1;
      if (cimg::type<T>::string()==cimg::type<char>::string()) mat_type = CV_8SC1;
      if (cimg::type<T>::string()==cimg::type<unsigned short>::string()) mat_type = CV_16UC1;
      if (cimg::type<T>::string()==cimg::type<short>::string()) mat_type = CV_16SC1;
      if (cimg::type<T>::string()==cimg::type<int>::string()) mat_type = CV_32SC1;
      if (cimg::type<T>::string()==cimg::type<float>::string()) mat_type = CV_32FC1;
      if (cimg::type<T>::string()==cimg::type<double>::string()) mat_type = CV_64FC1;
      if (mat_type<0)
        throw CImgInstanceException(_cimg_instance
                                    "_cvmat2cimg() : pixel type '%s' is not supported.",
                                    cimg_instance,pixel_type());
      cv::Mat res;
      std::vector<cv::Mat> channels(_spectrum);
      if (_spectrum>1) {
        cimg_forC(*this,c)
          channels[c] = cv::Mat(_height,_width,mat_type,_data + _width*_height*(_spectrum - 1 - c));
        cv::merge(channels,res);
      } else res = cv::Mat(_height,_width,mat_type,_data).clone();
      return res;

Project: CImg
File: CImg.h

    //! Return a list with elements being shared copies of images in the list instance \const.
    const CImgList<T> get_shared() const {
      CImgList<T> res(_width);
      cimglist_for(*this,l) res[l].assign(_data[l],true);
      return res;

Project: CImg
File: CImg.h

    **/
    CImg<T>& displacement(const CImg<T>& source, const float smoothness=0.1f, const float precision=5.f,
                          const unsigned int nb_scales=0, const unsigned int iteration_max=10000,
                          const bool is_backward=false,
                          const CImg<floatT>& guide=CImg<floatT>::const_empty()) {
      return get_displacement(source,smoothness,precision,nb_scales,iteration_max,is_backward,guide).
        move_to(*this);

Project: CImg
File: CImg.h


      static double mp_matrix_pseudoinv(_cimg_math_parser& mp) {
        double *ptrd = &_mp_arg(1) + 1;
        const double *ptr1 = &_mp_arg(2) + 1;
        const unsigned int
          k = (unsigned int)mp.opcode[3],
          l = (unsigned int)mp.opcode[4];
        CImg<doubleT>(ptrd,l,k,1,1,true) = CImg<doubleT>(ptr1,k,l,1,1,true).get_pseudoinvert();
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

    CImgAbortException() { _message = new char[1]; *_message = 0; }

Project: CImg
File: CImg.h

    //! Return stream line of a 2D or 3D vector field.
    CImg<floatT> get_streamline(const float x, const float y, const float z,
                                const float L=256, const float dl=0.1f,
                                const unsigned int interpolation_type=2, const bool is_backward_tracking=false,
                                const bool is_oriented_only=false) const {
      if (_spectrum!=2 && _spectrum!=3)
        throw CImgInstanceException(_cimg_instance
                                    "streamline(): Instance is not a 2D or 3D vector field.",
                                    cimg_instance);
      if (_spectrum==2) {
        if (is_oriented_only) {
          typename CImg<T>::_functor4d_streamline2d_oriented func(*this);
          return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,true,
                            0,0,0,_width - 1.f,_height - 1.f,0.f);
        } else {
          typename CImg<T>::_functor4d_streamline2d_directed func(*this);
          return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,false,
                            0,0,0,_width - 1.f,_height - 1.f,0.f);
        }
      }
      if (is_oriented_only) {
        typename CImg<T>::_functor4d_streamline3d_oriented func(*this);
        return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,true,
                          0,0,0,_width - 1.f,_height - 1.f,_depth - 1.f);
      }
      typename CImg<T>::_functor4d_streamline3d_directed func(*this);
      return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,false,
                        0,0,0,_width - 1.f,_height - 1.f,_depth - 1.f);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    **/
    int width() const {
      return (int)_width;

Project: CImg
File: CImg.h


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

      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
      unsigned int ppm_type, W, H, D = 1, colormax = 255;
      CImg<charT> item(16384,1,1,1,0);
      int err, rval, gval, bval;
      const longT cimg_iobuffer = (longT)24*1024*1024;
      while ((err=std::fscanf(nfile,"%16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile);
      if (cimg_sscanf(item," P%u",&ppm_type)!=1) {
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "load_pnm(): PNM header not found in file '%s'.",
                              cimg_instance,
                              filename?filename:"(FILE*)");
      }
      while ((err=std::fscanf(nfile," %16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile);
      if ((err=cimg_sscanf(item," %u %u %u %u",&W,&H,&D,&colormax))<2) {
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "load_pnm(): WIDTH and HEIGHT fields undefined in file '%s'.",
                              cimg_instance,
                              filename?filename:"(FILE*)");
      }
      if (ppm_type!=1 && ppm_type!=4) {
        if (err==2 || (err==3 && (ppm_type==5 || ppm_type==7 || ppm_type==8 || ppm_type==9))) {
          while ((err=std::fscanf(nfile," %16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile);
          if (cimg_sscanf(item,"%u",&colormax)!=1)
            cimg::warn(_cimg_instance
                       "load_pnm(): COLORMAX field is undefined in file '%s'.",
                       cimg_instance,
                       filename?filename:"(FILE*)");
        } else { colormax = D; D = 1; }
      }
      std::fgetc(nfile);

      switch (ppm_type) {
      case 1 : { // 2D b&w Ascii
        assign(W,H,1,1);
        T* ptrd = _data;
        cimg_foroff(*this,off) { if (std::fscanf(nfile,"%d",&rval)>0) *(ptrd++) = (T)(rval?0:255); else break; }
      } break;
      case 2 : { // 2D grey Ascii
        assign(W,H,1,1);
        T* ptrd = _data;
        cimg_foroff(*this,off) { if (std::fscanf(nfile,"%d",&rval)>0) *(ptrd++) = (T)rval; else break; }
      } break;
      case 3 : { // 2D color Ascii
        assign(W,H,1,3);
        T *ptrd = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2);
        cimg_forXY(*this,x,y) {
          if (std::fscanf(nfile,"%d %d %d",&rval,&gval,&bval)==3) {
            *(ptrd++) = (T)rval; *(ptr_g++) = (T)gval; *(ptr_b++) = (T)bval;
          } else break;
        }
      } break;
      case 4 : { // 2D b&w binary (support 3D PINK extension)
        CImg<ucharT> raw;
        assign(W,H,D,1);
        T *ptrd = data(0,0,0,0);
        unsigned int w = 0, h = 0, d = 0;
        for (longT to_read = (longT)((W/8 + (W%8?1:0))*H*D); 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;
          unsigned char mask = 0, val = 0;
          for (ulongT off = (ulongT)raw._width; off || mask; mask>>=1) {
            if (!mask) { if (off--) val = *(ptrs++); mask = 128; }
            *(ptrd++) = (T)((val&mask)?0:255);
            if (++w==W) { w = 0; mask = 0; if (++h==H) { h = 0; if (++d==D) break; }}
          }
        }
      } break;
      case 5 : case 7 : { // 2D/3D grey binary (support 3D PINK extension)
        if (colormax<256) { // 8 bits
          CImg<ucharT> raw;
          assign(W,H,D,1);
          T *ptrd = data(0,0,0,0);
          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 = (ulongT)raw._width; off; --off) *(ptrd++) = (T)*(ptrs++);
          }
        } else { // 16 bits
          CImg<ushortT> raw;
          assign(W,H,D,1);
          T *ptrd = data(0,0,0,0);
          for (longT to_read = (longT)size(); to_read>0; ) {
            raw.assign(std::min(to_read,cimg_iobuffer/2));
            cimg::fread(raw._data,raw._width,nfile);
	    if (!cimg::endianness()) cimg::invert_endianness(raw._data,raw._width);
            to_read-=raw._width;
            const unsigned short *ptrs = raw._data;
            for (ulongT off = (ulongT)raw._width; off; --off) *(ptrd++) = (T)*(ptrs++);
          }
        }
      } break;
      case 6 : { // 2D color binary
        if (colormax<256) { // 8 bits
          CImg<ucharT> raw;
          assign(W,H,1,3);
          T
            *ptr_r = data(0,0,0,0),
            *ptr_g = data(0,0,0,1),
            *ptr_b = data(0,0,0,2);
          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 = (ulongT)raw._width/3; off; --off) {
              *(ptr_r++) = (T)*(ptrs++);
              *(ptr_g++) = (T)*(ptrs++);
              *(ptr_b++) = (T)*(ptrs++);
            }
          }
        } else { // 16 bits
          CImg<ushortT> raw;
          assign(W,H,1,3);
          T
            *ptr_r = data(0,0,0,0),
            *ptr_g = data(0,0,0,1),
            *ptr_b = data(0,0,0,2);
          for (longT to_read = (longT)size(); to_read>0; ) {
            raw.assign(std::min(to_read,cimg_iobuffer/2));
            cimg::fread(raw._data,raw._width,nfile);
            if (!cimg::endianness()) cimg::invert_endianness(raw._data,raw._width);
            to_read-=raw._width;
            const unsigned short *ptrs = raw._data;
            for (ulongT off = (ulongT)raw._width/3; off; --off) {
              *(ptr_r++) = (T)*(ptrs++);
              *(ptr_g++) = (T)*(ptrs++);
              *(ptr_b++) = (T)*(ptrs++);
            }
          }
        }
      } break;
      case 8 : { // 2D/3D grey binary with int32 integers (PINK extension)
        CImg<intT> raw;
        assign(W,H,D,1);
        T *ptrd = data(0,0,0,0);
        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 int *ptrs = raw._data;
          for (ulongT off = (ulongT)raw._width; off; --off) *(ptrd++) = (T)*(ptrs++);
        }
      } break;
      case 9 : { // 2D/3D grey binary with float values (PINK extension)
        CImg<floatT> raw;
        assign(W,H,D,1);
        T *ptrd = data(0,0,0,0);
        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 float *ptrs = raw._data;
          for (ulongT off = (ulongT)raw._width; off; --off) *(ptrd++) = (T)*(ptrs++);
        }
      } break;
      default :
        assign();
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "load_pnm(): PNM type 'P%d' found, but type is not supported.",
                              cimg_instance,
                              filename?filename:"(FILE*)",ppm_type);
      }
      if (!file) cimg::fclose(nfile);
      return *this;

Project: CImg
File: CImg.h


    const T& _atX(const int x, const int y=0, const int z=0, const int c=0) const {
      return (*this)(x<0?0:(x>=width()?width() - 1:x),y,z,c);

Project: CImg
File: CImg.h

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

      return CImg<T>(_data + beg,_width,_height,z1 - z0 + 1,1,true);

Project: CImg
File: CImg.h

    **/
    ulongT size() const {
      return (ulongT)_width*_height*_depth*_spectrum;

Project: CImg
File: CImg.h


      static double mp_image_h(_cimg_math_parser& mp) {
        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.imgout:mp.listout[ind];
        return (double)img.height();

Project: CImg
File: CImg.h

    template<typename T>
    inline T mod(const T& x, const T& m) {
      const double dx = (double)x, dm = (double)m;
      return (T)(dx - dm * std::floor(dx / dm));

Project: CImg
File: CImg.h


    //! Return a reference to the maximum pixel value of the instance list.
    /**
    **/
    T& max() {
      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


      static double mp_matrix_inv(_cimg_math_parser& mp) {
        double *ptrd = &_mp_arg(1) + 1;
        const double *ptr1 = &_mp_arg(2) + 1;
        const unsigned int k = (unsigned int)mp.opcode[3];
        CImg<doubleT>(ptrd,k,k,1,1,true) = CImg<doubleT>(ptr1,k,k,1,1,true).get_invert();
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    **/
    CImg<T>& swap(CImg<T>& img) {
      cimg::swap(_width,img._width,_height,img._height,_depth,img._depth,_spectrum,img._spectrum);
      cimg::swap(_data,img._data);
      cimg::swap(_is_shared,img._is_shared);
      return img;

Project: CImg
File: CImg.h


      static double mp_norm0(_cimg_math_parser& mp) {
        const unsigned int i_end = (unsigned int)mp.opcode[2];
        switch (i_end - 3) {
        case 1 : return _mp_arg(3)!=0;
        case 2 : return (_mp_arg(3)!=0) + (_mp_arg(4)!=0);
        }
        double res = 0;
        for (unsigned int i = 3; i<i_end; ++i)
          res+=_mp_arg(i)==0?0:1;
        return res;