Commit message: Fix other issues in 'CImg<T>::load_bmp()'.
CVE: CVE-2018-7641
CWE: CWE-125
Vulnerability description: An issue was discovered in CImg v.220. A heap-based buffer over-read in load_bmp in CImg.h occurs when loading a crafted bmp image, a different vulnerability than CVE-2018-7588. This is in a "32 bits colors" case, aka case 32.

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 collapse(3) cimg_openmp_if(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 collapse(3) cimg_openmp_if(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;
        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 = (ulongT)((x + 1.0)*_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 = (ulongT)((y + 1.0)*_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 = (ulongT)((z + 1.0)*_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 = (ulongT)((c + 1.0)*_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.0)/(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.0,curr + fx);
              *(poff++) = (unsigned int)curr - (unsigned int)old;
            }
            cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(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.0)/(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.0,curr + fy);
                *(poff++) = sx*((unsigned int)curr - (unsigned int)old);
              }
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(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.0)/(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.0,curr + fz);
                *(poff++) = sxy*((unsigned int)curr - (unsigned int)old);
              }
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(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.0)/(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.0,curr + fc);
                *(poff++) = sxyz*((unsigned int)curr - (unsigned int)old);
              }
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(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.0)/(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.0,curr + fx);
                *(poff++) = (unsigned int)curr - (unsigned int)old;
              }
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(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.0)/(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.0,curr + fy);
                *(poff++) = sx*((unsigned int)curr - (unsigned int)old);
              }
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(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.0)/(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.0,curr + fz);
                *(poff++) = sxy*((unsigned int)curr - (unsigned int)old);
              }
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(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.0)/(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.0,curr + fc);
                *(poff++) = sxyz*((unsigned int)curr - (unsigned int)old);
              }
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(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.0)/(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.0,curr + fx);
                *(poff++) = (unsigned int)curr - (unsigned int)old;
              }
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(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.0)/(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.0,curr + fy);
                *(poff++) = sx*((unsigned int)curr - (unsigned int)old);
              }
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(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.0)/(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.0,curr + fz);
                *(poff++) = sxy*((unsigned int)curr - (unsigned int)old);
              }
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(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.0)/(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.0,curr + fc);
                *(poff++) = sxyz*((unsigned int)curr - (unsigned int)old);
              }
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(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<typename tc>
    CImg<T>& draw_circle(const int x0, const int y0, int radius,
                         const tc *const color, const float opacity,
                         const unsigned int pattern) {
      cimg::unused(pattern);
      if (is_empty()) return *this;
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_circle(): Specified color is (null).",
                                    cimg_instance);
      if (radius<0 || x0 - radius>=width() || y0 + radius<0 || y0 - radius>=height()) return *this;
      if (!radius) return draw_point(x0,y0,color,opacity);
      draw_point(x0 - radius,y0,color,opacity).draw_point(x0 + radius,y0,color,opacity).
        draw_point(x0,y0 - radius,color,opacity).draw_point(x0,y0 + radius,color,opacity);
      if (radius==1) return *this;
      for (int f = 1 - radius, ddFx = 0, ddFy = -(radius<<1), x = 0, y = radius; x<y; ) {
        if (f>=0) { f+=(ddFy+=2); --y; }
        ++x; ++(f+=(ddFx+=2));
        if (x!=y + 1) {
          const int x1 = x0 - y, x2 = x0 + y, y1 = y0 - x, y2 = y0 + x,
            x3 = x0 - x, x4 = x0 + x, y3 = y0 - y, y4 = y0 + y;
          draw_point(x1,y1,color,opacity).draw_point(x1,y2,color,opacity).
            draw_point(x2,y1,color,opacity).draw_point(x2,y2,color,opacity);
          if (x!=y)
            draw_point(x3,y3,color,opacity).draw_point(x4,y4,color,opacity).
              draw_point(x4,y3,color,opacity).draw_point(x3,y4,color,opacity);
        }
      }
      return *this;

Project: CImg
File: CImg.h

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

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

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

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

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

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

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& operator%=(const t value) {
      if (is_empty()) return *this;
      cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=16384))
      cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::mod(*ptrd,(T)value);
      return *this;

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

    **/
    CImg<T>& noise(const double sigma, const unsigned int noise_type=0) {
      if (is_empty()) return *this;
      const Tfloat vmin = (Tfloat)cimg::type<T>::min(), vmax = (Tfloat)cimg::type<T>::max();
      Tfloat nsigma = (Tfloat)sigma, m = 0, M = 0;
      if (nsigma==0 && noise_type!=3) return *this;
      if (nsigma<0 || noise_type==2) m = (Tfloat)min_max(M);
      if (nsigma<0) nsigma = (Tfloat)(-nsigma*(M-m)/100.0);
      switch (noise_type) {
      case 0 : { // Gaussian noise
        cimg_rof(*this,ptrd,T) {
          Tfloat val = (Tfloat)(*ptrd + nsigma*cimg::grand());
          if (val>vmax) val = vmax;
          if (val<vmin) val = vmin;
          *ptrd = (T)val;
        }
      } break;
      case 1 : { // Uniform noise
        cimg_rof(*this,ptrd,T) {
          Tfloat val = (Tfloat)(*ptrd + nsigma*cimg::rand(-1,1));
          if (val>vmax) val = vmax;
          if (val<vmin) val = vmin;
          *ptrd = (T)val;
        }
      } break;
      case 2 : { // Salt & Pepper noise
        if (nsigma<0) nsigma = -nsigma;
        if (M==m) { m = 0; M = cimg::type<T>::is_float()?(Tfloat)1:(Tfloat)cimg::type<T>::max(); }
        cimg_rof(*this,ptrd,T) if (cimg::rand(100)<nsigma) *ptrd = (T)(cimg::rand()<0.5?M:m);
      } break;
      case 3 : { // Poisson Noise
        cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::prand(*ptrd);
      } break;
      case 4 : { // Rice noise
        const Tfloat sqrt2 = (Tfloat)std::sqrt(2.0);
        cimg_rof(*this,ptrd,T) {
          const Tfloat
            val0 = (Tfloat)*ptrd/sqrt2,
            re = (Tfloat)(val0 + nsigma*cimg::grand()),
            im = (Tfloat)(val0 + nsigma*cimg::grand());
          Tfloat val = cimg::hypot(re,im);
          if (val>vmax) val = vmax;
          if (val<vmin) val = vmin;
          *ptrd = (T)val;
        }
      } break;
      default :
        throw CImgArgumentException(_cimg_instance
                                    "noise(): Invalid specified noise type %d "
                                    "(should be { 0=gaussian | 1=uniform | 2=salt&Pepper | 3=poisson }).",
                                    cimg_instance,
                                    noise_type);
      }
      return *this;

Project: CImg
File: CImg.h

    //! Convert pixel values from RGB to HSL color spaces.
    CImg<T>& RGBtoHSL() {
      if (_spectrum!=3)
        throw CImgInstanceException(_cimg_instance
                                    "RGBtoHSL(): 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 ulongT whd = (ulongT)_width*_height*_depth;
      cimg_pragma_openmp(parallel for cimg_openmp_if(whd>=256))
      for (ulongT N = 0; N<whd; ++N) {
        const Tfloat
          R = (Tfloat)p1[N],
          G = (Tfloat)p2[N],
          B = (Tfloat)p3[N],
          m = cimg::min(R,G,B),
          M = cimg::max(R,G,B),
          L = (m + M)/(2*255);
        Tfloat H = 0, S = 0;
        if (M!=m) {
          const Tfloat
            f = R==m?G - B:G==m?B - R:R - G,
            i = R==m?3:G==m?5:1;
          H = i - f/(M - m);
          if (H>=6) H-=6;
          H*=60;
          S = 2*L<=1?(M - m)/(M + m):(M - m)/(2*255 - M - m);
        }
        p1[N] = (T)cimg::cut(H,0,360);
        p2[N] = (T)cimg::cut(S,0,1);
        p3[N] = (T)cimg::cut(L,0,1);
      }
      return *this;

Project: CImg
File: CImg.h

     **/
    inline double rand(const double val_max=1) {
      return cimg::rand(0,val_max);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

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

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

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

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

Project: CImg
File: CImg.h


      static double mp_print(_cimg_math_parser& mp) {
          const double val = _mp_arg(1);
          const bool print_char = (bool)mp.opcode[3];
          cimg_pragma_openmp(critical(mp_print))
          {
            CImg<charT> expr(mp.opcode[2] - 4);
            const ulongT *ptrs = mp.opcode._data + 4;
            cimg_for(expr,ptrd,char) *ptrd = (char)*(ptrs++);
            cimg::strellipsize(expr);
            cimg::mutex(6);
            if (print_char)
              std::fprintf(cimg::output(),"\n[" cimg_appname "_math_parser] %s = %g = '%c'",expr._data,val,(int)val);
            else
              std::fprintf(cimg::output(),"\n[" cimg_appname "_math_parser] %s = %g",expr._data,val);
            std::fflush(cimg::output());
            cimg::mutex(6,0);
          }
          return val;

Project: CImg
File: CImg.h

     **/
    const CImg<T>& save_tiff(const char *const filename, const unsigned int compression_type=0,
                             const float *const voxel_size=0, const char *const description=0,
                             const bool use_bigtiff=true) const {
      if (!filename)
        throw CImgArgumentException(_cimg_instance
                                    "save_tiff(): Specified filename is (null).",
                                    cimg_instance);
      if (is_empty()) { cimg::fempty(0,filename); return *this; }

#ifdef cimg_use_tiff
      const bool
        _use_bigtiff = use_bigtiff && sizeof(ulongT)>=8 && size()*sizeof(T)>=1UL<<31; // No bigtiff for small images.
      TIFF *tif = TIFFOpen(filename,_use_bigtiff?"w8":"w4");
      if (tif) {
        cimg_forZ(*this,z) _save_tiff(tif,z,z,compression_type,voxel_size,description);
        TIFFClose(tif);
      } else throw CImgIOException(_cimg_instance
                                   "save_tiff(): Failed to open file '%s' for writing.",
                                   cimg_instance,
                                   filename);
      return *this;
#else
      cimg::unused(compression_type,voxel_size,description,use_bigtiff);
      return save_other(filename);
#endif

Project: CImg
File: CImg.h

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

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

Project: CImg
File: CImg.h

    //! Load gif file, using ImageMagick or GraphicsMagick's external tools.
    /**
      \param filename Filename to read data from.
    **/
    CImgList<T>& load_gif_external(const char *const filename) {
      if (!filename)
        throw CImgArgumentException(_cimglist_instance
                                    "load_gif_external(): Specified filename is (null).",
                                    cimglist_instance);
      std::fclose(cimg::fopen(filename,"rb"));            // Check if file exists.
      if (!_load_gif_external(filename,false))
        if (!_load_gif_external(filename,true))
          try { assign(CImg<T>().load_other(filename)); } catch (CImgException&) { assign(); }
      if (is_empty())
        throw CImgIOException(_cimglist_instance

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_for(*this,ptrd,T) *ptrd = (T)(val_min + cimg::rand()*delta);
      else cimg_for(*this,ptrd,T) *ptrd = std::min(val_max,(T)(val_min + cimg::rand()*delta));
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_triangle(const int x0, const int y0, const float z0,
                           const int x1, const int y1, const float z1,
                           const int x2, const int y2, const float z2,
                           const CImg<tc>& texture,
                           const int tx0, const int ty0,
                           const int tx1, const int ty1,
                           const int tx2, const int ty2,
                           const float brightness0,
                           const float brightness1,
                           const float brightness2,
                           const float opacity=1) {
      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
      if (texture._depth>1 || texture._spectrum<_spectrum)
        throw CImgArgumentException(_cimg_instance
                                    "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).",
                                    cimg_instance,
                                    texture._width,texture._height,texture._depth,texture._spectrum,texture._data);
      if (is_overlapped(texture)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,
                                                       brightness0,brightness1,brightness2,opacity);
      static const T maxval = (T)std::min(cimg::type<T>::max(),(T)cimg::type<tc>::max());
      const float nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.0f);
      const ulongT
        whd = (ulongT)_width*_height*_depth,
        twh = (ulongT)texture._width*texture._height,
        offx = _spectrum*whd - 1;
      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
        nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f),
        nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f),
        nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f);
      float
        ntx0 = tx0/z0, nty0 = ty0/z0,
        ntx1 = tx1/z1, nty1 = ty1/z1,
        ntx2 = tx2/z2, nty2 = ty2/z2,
        nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1,nc0,nc1);
      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2,nc0,nc2);
      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2,nc1,nc2);
      if (ny0>=height() || ny2<0) return *this;
      float
        ptxl = (ntx1 - ntx0)/(ny1 - ny0),
        ptxr = (ntx2 - ntx0)/(ny2 - ny0),
        ptxn = (ntx2 - ntx1)/(ny2 - ny1),
        ptyl = (nty1 - nty0)/(ny1 - ny0),
        ptyr = (nty2 - nty0)/(ny2 - ny0),
        ptyn = (nty2 - nty1)/(ny2 - ny1),
        pzl = (nz1 - nz0)/(ny1 - ny0),
        pzr = (nz2 - nz0)/(ny2 - ny0),
        pzn = (nz2 - nz1)/(ny2 - ny1),
        zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
        txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
        tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
        zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
        txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):
          (ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
        tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):
          (ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
      _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
        if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
        int
          xleft = xleft0, xright = xright0,
          cleft = cleft0, cright = cright0;
        float
          zleft = zl, zright = zr,
          txleft = txl, txright = txr,
          tyleft = tyl, tyright = tyr;
        if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,cleft,cright);
        const int
          dx = xright - xleft,
          dc = cright>cleft?cright - cleft:cleft - cright,
          rc = dx?(cright - cleft)/dx:0,
          sc = cright>cleft?1:-1,
          ndc = dc - (dx?dx*(dc/dx):0);
        const float
          pentez = (zright - zleft)/dx,
          pentetx = (txright - txleft)/dx,
          pentety = (tyright - tyleft)/dx;
        int errc = dx>>1;
        if (xleft<0 && dx) {
          cleft-=xleft*(cright - cleft)/dx;
          zleft-=xleft*(zright - zleft)/dx;
          txleft-=xleft*(txright - txleft)/dx;
          tyleft-=xleft*(tyright - tyleft)/dx;
        }
        if (xleft<0) xleft = 0;
        if (xright>=width() - 1) xright = width() - 1;
        T* ptrd = data(xleft,y,0,0);
        if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
          const float invz = 1/zleft;
          const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));
          cimg_forC(*this,c) {
            *ptrd = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256);
            ptrd+=whd; col+=twh;
          }
          ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
          cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
        } else for (int x = xleft; x<=xright; ++x) {
          const float invz = 1/zleft;
          const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));
          cimg_forC(*this,c) {
            const T val = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256);
            *ptrd = (T)(nopacity*val + *ptrd*copacity);
            ptrd+=whd; col+=twh;
          }
          ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
          cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
        }
        zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
      }
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    **/
    CImgList<Tfloat> get_FFT(const bool is_invert=false) const {
      CImgList<Tfloat> res(*this,CImg<Tfloat>());
      CImg<Tfloat>::FFT(res[0],res[1],is_invert);
      return res;

Project: CImg
File: CImg.h

    **/
    static const CImg<Tuchar>& lines_LUT256() {
      static const unsigned char pal[] = {
        217,62,88,75,1,237,240,12,56,160,165,116,1,1,204,2,15,248,148,185,133,141,46,246,222,116,16,5,207,226,
        17,114,247,1,214,53,238,0,95,55,233,235,109,0,17,54,33,0,90,30,3,0,94,27,19,0,68,212,166,130,0,15,7,119,
        238,2,246,198,0,3,16,10,13,2,25,28,12,6,2,99,18,141,30,4,3,140,12,4,30,233,7,10,0,136,35,160,168,184,20,
        233,0,1,242,83,90,56,180,44,41,0,6,19,207,5,31,214,4,35,153,180,75,21,76,16,202,218,22,17,2,136,71,74,
        81,251,244,148,222,17,0,234,24,0,200,16,239,15,225,102,230,186,58,230,110,12,0,7,129,249,22,241,37,219,
        1,3,254,210,3,212,113,131,197,162,123,252,90,96,209,60,0,17,0,180,249,12,112,165,43,27,229,77,40,195,12,
        87,1,210,148,47,80,5,9,1,137,2,40,57,205,244,40,8,252,98,0,40,43,206,31,187,0,180,1,69,70,227,131,108,0,
        223,94,228,35,248,243,4,16,0,34,24,2,9,35,73,91,12,199,51,1,249,12,103,131,20,224,2,70,32,
        233,1,165,3,8,154,246,233,196,5,0,6,183,227,247,195,208,36,0,0,226,160,210,198,69,153,210,1,23,8,192,2,4,
        137,1,0,52,2,249,241,129,0,0,234,7,238,71,7,32,15,157,157,252,158,2,250,6,13,30,11,162,0,199,21,11,27,224,
        4,157,20,181,111,187,218,3,0,11,158,230,196,34,223,22,248,135,254,210,157,219,0,117,239,3,255,4,227,5,247,
        11,4,3,188,111,11,105,195,2,0,14,1,21,219,192,0,183,191,113,241,1,12,17,248,0,48,7,19,1,254,212,0,239,246,
        0,23,0,250,165,194,194,17,3,253,0,24,6,0,141,167,221,24,212,2,235,243,0,0,205,1,251,133,204,28,4,6,1,10,
        141,21,74,12,236,254,228,19,1,0,214,1,186,13,13,6,13,16,27,209,6,216,11,207,251,59,32,9,155,23,19,235,143,
        116,6,213,6,75,159,23,6,0,228,4,10,245,249,1,7,44,234,4,102,174,0,19,239,103,16,15,18,8,214,22,4,47,244,
        255,8,0,251,173,1,212,252,250,251,252,6,0,29,29,222,233,246,5,149,0,182,180,13,151,0,203,183,0,35,149,0,
        235,246,254,78,9,17,203,73,11,195,0,3,5,44,0,0,237,5,106,6,130,16,214,20,168,247,168,4,207,11,5,1,232,251,
        129,210,116,231,217,223,214,27,45,38,4,177,186,249,7,215,172,16,214,27,249,230,236,2,34,216,217,0,175,30,
        243,225,244,182,20,212,2,226,21,255,20,0,2,13,62,13,191,14,76,64,20,121,4,118,0,216,1,147,0,2,210,1,215,
        95,210,236,225,184,46,0,248,24,11,1,9,141,250,243,9,221,233,160,11,147,2,55,8,23,12,253,9,0,54,0,231,6,3,
        141,8,2,246,9,180,5,11,8,227,8,43,110,242,1,130,5,97,36,10,6,219,86,133,11,108,6,1,5,244,67,19,28,0,174,
        154,16,127,149,252,188,196,196,228,244,9,249,0,0,0,37,170,32,250,0,73,255,23,3,224,234,38,195,198,0,255,87,
        33,221,174,31,3,0,189,228,6,153,14,144,14,108,197,0,9,206,245,254,3,16,253,178,248,0,95,125,8,0,3,168,21,
        23,168,19,50,240,244,185,0,1,144,10,168,31,82,1,13 };
      static const CImg<Tuchar> colormap(pal,1,256,1,3,false);
      return colormap;

Project: CImg
File: CImg.h


    CImg<T>& _load_tiff(TIFF *const tif, const unsigned int directory,
                        float *const voxel_size, CImg<charT> *const description) {
      if (!TIFFSetDirectory(tif,directory)) return assign();
      uint16 samplesperpixel = 1, bitspersample = 8, photo = 0;
      uint16 sampleformat = 1;
      uint32 nx = 1, ny = 1;
      const char *const filename = TIFFFileName(tif);
      const bool is_spp = (bool)TIFFGetField(tif,TIFFTAG_SAMPLESPERPIXEL,&samplesperpixel);
      TIFFGetField(tif,TIFFTAG_IMAGEWIDTH,&nx);
      TIFFGetField(tif,TIFFTAG_IMAGELENGTH,&ny);
      TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &sampleformat);
      TIFFGetFieldDefaulted(tif,TIFFTAG_BITSPERSAMPLE,&bitspersample);
      TIFFGetField(tif,TIFFTAG_PHOTOMETRIC,&photo);
      if (voxel_size) {
        const char *s_description = 0;
        float vx = 0, vy = 0, vz = 0;
        if (TIFFGetField(tif,TIFFTAG_IMAGEDESCRIPTION,&s_description) && s_description) {
          const char *s_desc = std::strstr(s_description,"VX=");
          if (s_desc && cimg_sscanf(s_desc,"VX=%f VY=%f VZ=%f",&vx,&vy,&vz)==3) { // CImg format.
            voxel_size[0] = vx; voxel_size[1] = vy; voxel_size[2] = vz;
          }
          s_desc = std::strstr(s_description,"spacing=");
          if (s_desc && cimg_sscanf(s_desc,"spacing=%f",&vz)==1) { // fiji format.
            voxel_size[2] = vz;
          }
        }
        TIFFGetField(tif,TIFFTAG_XRESOLUTION,voxel_size);
        TIFFGetField(tif,TIFFTAG_YRESOLUTION,voxel_size + 1);
        voxel_size[0] = 1.0f/voxel_size[0];
        voxel_size[1] = 1.0f/voxel_size[1];
      }
      if (description) {
        const char *s_description = 0;
        if (TIFFGetField(tif,TIFFTAG_IMAGEDESCRIPTION,&s_description) && s_description)
          CImg<charT>::string(s_description).move_to(*description);
      }
      const unsigned int spectrum = !is_spp || photo>=3?(photo>1?3:1):samplesperpixel;
      assign(nx,ny,1,spectrum);

      if ((photo>=3 && sampleformat==1 &&
           (bitspersample==4 || bitspersample==8) &&
           (samplesperpixel==1 || samplesperpixel==3 || samplesperpixel==4)) ||
          (bitspersample==1 && samplesperpixel==1)) {
        // Special case for unsigned color images.
        uint32 *const raster = (uint32*)_TIFFmalloc(nx*ny*sizeof(uint32));
        if (!raster) {
          _TIFFfree(raster); TIFFClose(tif);
          throw CImgException(_cimg_instance
                              "load_tiff(): Failed to allocate memory (%s) for file '%s'.",
                              cimg_instance,
                              cimg::strbuffersize(nx*ny*sizeof(uint32)),filename);
        }
        TIFFReadRGBAImage(tif,nx,ny,raster,0);
        switch (spectrum) {
        case 1 :
          cimg_forXY(*this,x,y)
            (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 -y) + x]);
          break;
        case 3 :
          cimg_forXY(*this,x,y) {
            (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 -y) + x]);
            (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny - 1 -y) + x]);
            (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny - 1 -y) + x]);
          }
          break;
        case 4 :
          cimg_forXY(*this,x,y) {
            (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 - y) + x]);
            (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny - 1 - y) + x]);
            (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny - 1 - y) + x]);
            (*this)(x,y,3) = (T)(float)TIFFGetA(raster[nx*(ny - 1 - y) + x]);
          }
          break;
        }
        _TIFFfree(raster);
      } else { // Other cases.
        uint16 config;
        TIFFGetField(tif,TIFFTAG_PLANARCONFIG,&config);
        if (TIFFIsTiled(tif)) {
          uint32 tw = 1, th = 1;
          TIFFGetField(tif,TIFFTAG_TILEWIDTH,&tw);
          TIFFGetField(tif,TIFFTAG_TILELENGTH,&th);
          if (config==PLANARCONFIG_CONTIG) switch (bitspersample) {
            case 8 :
              if (sampleformat==SAMPLEFORMAT_UINT)
                _load_tiff_tiled_contig<unsigned char>(tif,samplesperpixel,nx,ny,tw,th);
              else _load_tiff_tiled_contig<signed char>(tif,samplesperpixel,nx,ny,tw,th);
              break;
            case 16 :
              if (sampleformat==SAMPLEFORMAT_UINT)
                _load_tiff_tiled_contig<unsigned short>(tif,samplesperpixel,nx,ny,tw,th);
              else _load_tiff_tiled_contig<short>(tif,samplesperpixel,nx,ny,tw,th);
              break;
            case 32 :
              if (sampleformat==SAMPLEFORMAT_UINT)
                _load_tiff_tiled_contig<unsigned int>(tif,samplesperpixel,nx,ny,tw,th);
              else if (sampleformat==SAMPLEFORMAT_INT)
                _load_tiff_tiled_contig<int>(tif,samplesperpixel,nx,ny,tw,th);
              else _load_tiff_tiled_contig<float>(tif,samplesperpixel,nx,ny,tw,th);
              break;
            case 64 :
              if (sampleformat==SAMPLEFORMAT_UINT)
                _load_tiff_tiled_contig<uint64T>(tif,samplesperpixel,nx,ny,tw,th);
              else if (sampleformat==SAMPLEFORMAT_INT)
                _load_tiff_tiled_contig<int64T>(tif,samplesperpixel,nx,ny,tw,th);
              else _load_tiff_tiled_contig<double>(tif,samplesperpixel,nx,ny,tw,th);
              break;
            } else switch (bitspersample) {
            case 8 :
              if (sampleformat==SAMPLEFORMAT_UINT)
                _load_tiff_tiled_separate<unsigned char>(tif,samplesperpixel,nx,ny,tw,th);
              else _load_tiff_tiled_separate<signed char>(tif,samplesperpixel,nx,ny,tw,th);
              break;
            case 16 :
              if (sampleformat==SAMPLEFORMAT_UINT)
                _load_tiff_tiled_separate<unsigned short>(tif,samplesperpixel,nx,ny,tw,th);
              else _load_tiff_tiled_separate<short>(tif,samplesperpixel,nx,ny,tw,th);
              break;
            case 32 :
              if (sampleformat==SAMPLEFORMAT_UINT)
                _load_tiff_tiled_separate<unsigned int>(tif,samplesperpixel,nx,ny,tw,th);
              else if (sampleformat==SAMPLEFORMAT_INT)
                _load_tiff_tiled_separate<int>(tif,samplesperpixel,nx,ny,tw,th);
              else _load_tiff_tiled_separate<float>(tif,samplesperpixel,nx,ny,tw,th);
              break;
            case 64 :
              if (sampleformat==SAMPLEFORMAT_UINT)
                _load_tiff_tiled_separate<uint64T>(tif,samplesperpixel,nx,ny,tw,th);
              else if (sampleformat==SAMPLEFORMAT_INT)
                _load_tiff_tiled_separate<int64T>(tif,samplesperpixel,nx,ny,tw,th);
              else _load_tiff_tiled_separate<double>(tif,samplesperpixel,nx,ny,tw,th);
              break;
            }
        } else {
          if (config==PLANARCONFIG_CONTIG) switch (bitspersample) {
            case 8 :
              if (sampleformat==SAMPLEFORMAT_UINT)
                _load_tiff_contig<unsigned char>(tif,samplesperpixel,nx,ny);
              else _load_tiff_contig<signed char>(tif,samplesperpixel,nx,ny);
              break;
            case 16 :
              if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_contig<unsigned short>(tif,samplesperpixel,nx,ny);
              else _load_tiff_contig<short>(tif,samplesperpixel,nx,ny);
              break;
            case 32 :
              if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_contig<unsigned int>(tif,samplesperpixel,nx,ny);
              else if (sampleformat==SAMPLEFORMAT_INT) _load_tiff_contig<int>(tif,samplesperpixel,nx,ny);
              else _load_tiff_contig<float>(tif,samplesperpixel,nx,ny);
              break;
            case 64 :
              if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_contig<uint64T>(tif,samplesperpixel,nx,ny);
              else if (sampleformat==SAMPLEFORMAT_INT) _load_tiff_contig<int64T>(tif,samplesperpixel,nx,ny);
              else _load_tiff_contig<double>(tif,samplesperpixel,nx,ny);
              break;
            } else switch (bitspersample) {
            case 8 :
              if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_separate<unsigned char>(tif,samplesperpixel,nx,ny);
              else _load_tiff_separate<signed char>(tif,samplesperpixel,nx,ny);
              break;
            case 16 :
              if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_separate<unsigned short>(tif,samplesperpixel,nx,ny);
              else _load_tiff_separate<short>(tif,samplesperpixel,nx,ny);
              break;
            case 32 :
              if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_separate<unsigned int>(tif,samplesperpixel,nx,ny);
              else if (sampleformat==SAMPLEFORMAT_INT) _load_tiff_separate<int>(tif,samplesperpixel,nx,ny);
              else _load_tiff_separate<float>(tif,samplesperpixel,nx,ny);
              break;
            case 64 :
              if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_separate<uint64T>(tif,samplesperpixel,nx,ny);
              else if (sampleformat==SAMPLEFORMAT_INT) _load_tiff_separate<int64T>(tif,samplesperpixel,nx,ny);
              else _load_tiff_separate<double>(tif,samplesperpixel,nx,ny);
              break;
            }
        }
      }
      return *this;

Project: CImg
File: CImg.h

    template<typename tf>
    CImg<floatT> get_isosurface3d(CImgList<tf>& primitives, const float isovalue,
                                  const int size_x=-100, const int size_y=-100, const int size_z=-100) const {
      if (_spectrum>1)
        throw CImgInstanceException(_cimg_instance
                                    "get_isosurface3d(): Instance is not a scalar image.",
                                    cimg_instance);
      primitives.assign();
      if (is_empty()) return *this;
      CImg<floatT> vertices;
      if ((size_x==-100 && size_y==-100 && size_z==-100) || (size_x==width() && size_y==height() && size_z==depth())) {
        const _functor3d_int func(*this);
        vertices = isosurface3d(primitives,func,isovalue,0,0,0,width() - 1.0f,height() - 1.0f,depth() - 1.0f,
                                width(),height(),depth());
      } else {
        const _functor3d_float func(*this);
        vertices = isosurface3d(primitives,func,isovalue,0,0,0,width() - 1.0f,height() - 1.0f,depth() - 1.0f,
                                size_x,size_y,size_z);
      }
      return vertices;

Project: CImg
File: CImg.h


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

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

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

Project: CImg
File: CImg.h

    **/
    CImg<T>& operator=(const char *const expression) {
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode(0);
      try {
        _fill(expression,true,true,0,0,"operator=",0);
      } catch (CImgException&) {
        cimg::exception_mode(omode);
        load(expression);
      }
      cimg::exception_mode(omode);
      return *this;

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_line(const int x0, const int y0, const int z0,
                       const int x1, const int y1, const int z1,
                       const tc *const color, const float opacity=1,
                       const unsigned int pattern=~0U, const bool init_hatch=true) {
      if (is_empty()) return *this;
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_line(): Specified color is (null).",
                                    cimg_instance);
      static unsigned int hatch = ~0U - (~0U>>1);
      if (init_hatch) hatch = ~0U - (~0U>>1);
      int nx0 = x0, ny0 = y0, nz0 = z0, nx1 = x1, ny1 = y1, nz1 = z1;
      if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
      if (nx1<0 || nx0>=width()) return *this;
      if (nx0<0) {
        const float D = 1.0f + nx1 - nx0;
        ny0-=(int)((float)nx0*(1.0f + ny1 - ny0)/D);
        nz0-=(int)((float)nx0*(1.0f + nz1 - nz0)/D);
        nx0 = 0;
      }
      if (nx1>=width()) {
        const float d = (float)nx1 - width(), D = 1.0f + nx1 - nx0;
        ny1+=(int)(d*(1.0f + ny0 - ny1)/D);
        nz1+=(int)(d*(1.0f + nz0 - nz1)/D);
        nx1 = width() - 1;
      }
      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
      if (ny1<0 || ny0>=height()) return *this;
      if (ny0<0) {
        const float D = 1.0f + ny1 - ny0;
        nx0-=(int)((float)ny0*(1.0f + nx1 - nx0)/D);
        nz0-=(int)((float)ny0*(1.0f + nz1 - nz0)/D);
        ny0 = 0;
      }
      if (ny1>=height()) {
        const float d = (float)ny1 - height(), D = 1.0f + ny1 - ny0;
        nx1+=(int)(d*(1.0f + nx0 - nx1)/D);
        nz1+=(int)(d*(1.0f + nz0 - nz1)/D);
        ny1 = height() - 1;
      }
      if (nz0>nz1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
      if (nz1<0 || nz0>=depth()) return *this;
      if (nz0<0) {
        const float D = 1.0f + nz1 - nz0;
        nx0-=(int)((float)nz0*(1.0f + nx1 - nx0)/D);
        ny0-=(int)((float)nz0*(1.0f + ny1 - ny0)/D);
        nz0 = 0;
      }
      if (nz1>=depth()) {
        const float d = (float)nz1 - depth(), D = 1.0f + nz1 - nz0;
        nx1+=(int)(d*(1.0f + nx0 - nx1)/D);
        ny1+=(int)(d*(1.0f + ny0 - ny1)/D);
        nz1 = depth() - 1;
      }
      const unsigned int dmax = (unsigned int)cimg::max(cimg::abs(nx1 - nx0),cimg::abs(ny1 - ny0),nz1 - nz0);
      const ulongT whd = (ulongT)_width*_height*_depth;
      const float px = (nx1 - nx0)/(float)dmax, py = (ny1 - ny0)/(float)dmax, pz = (nz1 - nz0)/(float)dmax;
      float x = (float)nx0, y = (float)ny0, z = (float)nz0;
      if (opacity>=1) for (unsigned int t = 0; t<=dmax; ++t) {
        if (!(~pattern) || (~pattern && pattern&hatch)) {
          T* ptrd = data((unsigned int)x,(unsigned int)y,(unsigned int)z);
          const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=whd; }
        }
        x+=px; y+=py; z+=pz; if (pattern) { hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); }
      } else {
        const float nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.0f);
        for (unsigned int t = 0; t<=dmax; ++t) {
          if (!(~pattern) || (~pattern && pattern&hatch)) {
            T* ptrd = data((unsigned int)x,(unsigned int)y,(unsigned int)z);
            const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whd; }
          }
          x+=px; y+=py; z+=pz; if (pattern) { hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); }
        }
      }
      return *this;

Project: CImg
File: CImg.h

    template<typename t1, typename t2>
    CImg<T>& patchmatch(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,
                        const unsigned int nb_randoms,
                        const CImg<t1> &guide,
                        CImg<t2> &matching_score) {
      return get_patchmatch(patch_image,patch_width,patch_height,patch_depth,
                            nb_iterations,nb_randoms,guide,matching_score).move_to(*this);

Project: CImg
File: CImg.h

      bool is_exit = false;
      return _display(disp,title,0,display_info,axis,align,XYZ,exit_on_anykey,0,true,is_exit);
    }

    const CImgList<T>& _display(CImgDisplay &disp, const char *const title, const CImgList<charT> *const titles,
                                const bool display_info, const char axis, const float align, unsigned int *const XYZ,
                                const bool exit_on_anykey, const unsigned int orig, const bool is_first_call,
                                bool &is_exit) const {
      if (is_empty())
        throw CImgInstanceException(_cimglist_instance
                                    "display(): Empty instance.",
                                    cimglist_instance);
      if (!disp) {
        if (axis=='x') {
          unsigned int sum_width = 0, max_height = 0;
          cimglist_for(*this,l) {
            const CImg<T> &img = _data[l];
            const unsigned int
              w = CImgDisplay::_fitscreen(img._width,img._height,img._depth,128,-85,false),
              h = CImgDisplay::_fitscreen(img._width,img._height,img._depth,128,-85,true);
            sum_width+=w;
            if (h>max_height) max_height = h;
          }
          disp.assign(cimg_fitscreen(sum_width,max_height,1),title?title:titles?titles->__display()._data:0,1);
        } else {
          unsigned int max_width = 0, sum_height = 0;
          cimglist_for(*this,l) {
            const CImg<T> &img = _data[l];
            const unsigned int
              w = CImgDisplay::_fitscreen(img._width,img._height,img._depth,128,-85,false),
              h = CImgDisplay::_fitscreen(img._width,img._height,img._depth,128,-85,true);
            if (w>max_width) max_width = w;
            sum_height+=h;
          }
          disp.assign(cimg_fitscreen(max_width,sum_height,1),title?title:titles?titles->__display()._data:0,1);
        }
        if (!title && !titles) disp.set_title("CImgList<%s> (%u)",pixel_type(),_width);
      } else if (title) disp.set_title("%s",title);
      else if (titles) disp.set_title("%s",titles->__display()._data);
      const CImg<char> dtitle = CImg<char>::string(disp.title());
      if (display_info) print(disp.title());
      disp.show().flush();

      if (_width==1) {
        const unsigned int dw = disp._width, dh = disp._height;
        if (!is_first_call)
          disp.resize(cimg_fitscreen(_data[0]._width,_data[0]._height,_data[0]._depth),false);
        disp.set_title("%s (%ux%ux%ux%u)",
                       dtitle.data(),_data[0]._width,_data[0]._height,_data[0]._depth,_data[0]._spectrum);
        _data[0]._display(disp,0,false,XYZ,exit_on_anykey,!is_first_call);
        if (disp.key()) is_exit = true;
        disp.resize(cimg_fitscreen(dw,dh,1),false).set_title("%s",dtitle.data());
      } else {
        bool disp_resize = !is_first_call;
        while (!disp.is_closed() && !is_exit) {
          const CImg<intT> s = _select(disp,0,true,axis,align,exit_on_anykey,orig,disp_resize,!is_first_call,true);
          disp_resize = true;
          if (s[0]<0 && !disp.wheel()) { // No selections done.
            if (disp.button()&2) { disp.flush(); break; }
            is_exit = true;
          } else if (disp.wheel()) { // Zoom in/out.
            const int wheel = disp.wheel();
            disp.set_wheel();
            if (!is_first_call && wheel<0) break;
            if (wheel>0 && _width>=4) {
              const unsigned int
                delta = std::max(1U,(unsigned int)cimg::round(0.3*_width)),
                ind0 = (unsigned int)std::max(0,s[0] - (int)delta),
                ind1 = (unsigned int)std::min(width() - 1,s[0] + (int)delta);
              if ((ind0!=0 || ind1!=_width - 1) && ind1 - ind0>=3) {
                const CImgList<T> sublist = get_shared_images(ind0,ind1);
                CImgList<charT> t_sublist;
                if (titles) t_sublist = titles->get_shared_images(ind0,ind1);
                sublist._display(disp,0,titles?&t_sublist:0,false,axis,align,XYZ,exit_on_anykey,
                                 orig + ind0,false,is_exit);
              }
            }
          } else if (s[0]!=0 || s[1]!=width() - 1) {
            const CImgList<T> sublist = get_shared_images(s[0],s[1]);
            CImgList<charT> t_sublist;
            if (titles) t_sublist = titles->get_shared_images(s[0],s[1]);
            sublist._display(disp,0,titles?&t_sublist:0,false,axis,align,XYZ,exit_on_anykey,
                             orig + s[0],false,is_exit);
          }
          disp.set_title("%s",dtitle.data());

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    //! Simple interface to select a shape from an image \newinstance.
    CImg<intT> get_select(CImgDisplay &disp,
		          const unsigned int feature_type=2, unsigned int *const XYZ=0,
                          const bool exit_on_anykey=false) const {
      return _select(disp,0,feature_type,XYZ,0,0,0,exit_on_anykey,true,false);

Project: CImg
File: CImg.h


      unsigned int scalar7(const mp_func op,
                           const unsigned int arg1, const unsigned int arg2, const unsigned int arg3,
                           const unsigned int arg4, const unsigned int arg5, const unsigned int arg6,
                           const unsigned int arg7) {
        const unsigned int pos =
          arg1>_cimg_mp_slot_c && _cimg_mp_is_comp(arg1)?arg1:
          arg2>_cimg_mp_slot_c && _cimg_mp_is_comp(arg2)?arg2:
          arg3>_cimg_mp_slot_c && _cimg_mp_is_comp(arg3)?arg3:
          arg4>_cimg_mp_slot_c && _cimg_mp_is_comp(arg4)?arg4:
          arg5>_cimg_mp_slot_c && _cimg_mp_is_comp(arg5)?arg5:
          arg6>_cimg_mp_slot_c && _cimg_mp_is_comp(arg6)?arg6:
          arg7>_cimg_mp_slot_c && _cimg_mp_is_comp(arg7)?arg7:scalar();
        CImg<ulongT>::vector((ulongT)op,pos,arg1,arg2,arg3,arg4,arg5,arg6,arg7).move_to(code);
        return pos;

Project: CImg
File: CImg.h

    **/
    CImgList<Tfloat> get_FFT(const char axis, const bool is_invert=false) const {
      CImgList<Tfloat> res(*this,CImg<Tfloat>());
      CImg<Tfloat>::FFT(res[0],res[1],axis,is_invert);
      return res;

Project: CImg
File: CImg.h

    // Compute SSD between two patches in different images.
    static float _patchmatch(const CImg<T>& img1, const CImg<T>& img2,
                             const unsigned int psizew, const unsigned int psizeh,
                             const int x1, const int y1,
                             const int x2, const int y2,
                             const float max_ssd) { // 2d version.
      const T *p1 = img1.data(x1,y1), *p2 = img2.data(x2,y2);
      const ulongT
        offx1 = (ulongT)img1._width - psizew,
        offx2 = (ulongT)img2._width - psizew,
        offy1 = (ulongT)img1._width*img1._height - psizeh*img1._width,
        offy2 = (ulongT)img2._width*img2._height - psizeh*img2._width;
      float ssd = 0;
      cimg_forC(img1,c) {
        for (unsigned int j = 0; j<psizeh; ++j) {
          for (unsigned int i = 0; i<psizew; ++i)
            ssd += cimg::sqr(*(p1++) - *(p2++));
          if (ssd>max_ssd) return max_ssd;
          p1+=offx1; p2+=offx2;
        }
        p1+=offy1; p2+=offy2;
      }
      return ssd;

Project: CImg
File: CImg.h

    **/
    CImg<T>& tan() {
      if (is_empty()) return *this;
      cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=2048))
      cimg_rof(*this,ptrd,T) *ptrd = (T)std::tan((double)*ptrd);
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    template<typename t, typename T>
    static void _render_resize(const T *ptrs, const unsigned int ws, const unsigned int hs,
                               t *ptrd, const unsigned int wd, const unsigned int hd) {
      unsigned int *const offx = new unsigned int[wd], *const offy = new unsigned int[hd + 1], *poffx, *poffy;
      float s, curr, old;
      s = (float)ws/wd;
      poffx = offx; curr = 0; for (unsigned int x = 0; x<wd; ++x) {
        old = curr; curr+=s; *(poffx++) = (unsigned int)curr - (unsigned int)old;
      }
      s = (float)hs/hd;
      poffy = offy; curr = 0; for (unsigned int y = 0; y<hd; ++y) {
        old = curr; curr+=s; *(poffy++) = ws*((unsigned int)curr - (unsigned int)old);
      }
      *poffy = 0;
      poffy = offy;
      for (unsigned int y = 0; y<hd; ) {
        const T *ptr = ptrs;
        poffx = offx;
        for (unsigned int x = 0; x<wd; ++x) { *(ptrd++) = *ptr; ptr+=*(poffx++); }
        ++y;
        unsigned int dy = *(poffy++);
        for ( ; !dy && y<hd; std::memcpy(ptrd,ptrd - wd,sizeof(t)*wd), ++y, ptrd+=wd, dy = *(poffy++)) {}
        ptrs+=dy;
      }
      delete[] offx; delete[] offy;

Project: CImg
File: CImg.h


      static double mp_list_Jxyz(_cimg_math_parser& mp) {
        double *ptrd = &_mp_arg(1) + 1;
        const unsigned int
          ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
          interpolation = (unsigned int)_mp_arg(6),
          boundary_conditions = (unsigned int)_mp_arg(7),
          vsiz = (unsigned int)mp.opcode[8];
        const CImg<T> &img = mp.listin[ind];
        const double
          ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y], oz = mp.mem[_cimg_mp_slot_z],
          x = ox + _mp_arg(3), y = oy + _mp_arg(4), z = oz + _mp_arg(5);
        const ulongT whd = (ulongT)img._width*img._height*img._depth;
        const T *ptrs;
        if (interpolation==0) switch (boundary_conditions) { // Nearest neighbor interpolation
          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 = cimg::mod((int)x,img.width()),
              cy = cimg::mod((int)y,img.height()),
              cz = cimg::mod((int)z,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(x,y,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));
          } else switch (boundary_conditions) { // Linear interpolation
          case 3 : { // Mirror
            const float
              w2 = 2.0f*img.width(), h2 = 2.0f*img.height(), d2 = 2.0f*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
            const float
              cx = cimg::mod((float)x,(float)img.width()),
              cy = cimg::mod((float)y,(float)img.height()),
              cz = cimg::mod((float)z,(float)img.depth());
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._linear_atXYZ(cx,cy,cz,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);
          }
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

    //! Compute the structure tensor field of an image \newinstance.
    CImg<Tfloat> get_structure_tensors(const bool is_fwbw_scheme=false) const {
      if (is_empty()) return *this;
      CImg<Tfloat> res;
      if (_depth>1) { // 3d
        res.assign(_width,_height,_depth,6,0);
        if (!is_fwbw_scheme) { // Classical central finite differences
          cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2))
          cimg_forC(*this,c) {
            Tfloat
              *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2),
              *ptrd3 = res.data(0,0,0,3), *ptrd4 = res.data(0,0,0,4), *ptrd5 = res.data(0,0,0,5);
            CImg_3x3x3(I,Tfloat);
            cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) {
              const Tfloat
                ix = (Incc - Ipcc)/2,
                iy = (Icnc - Icpc)/2,
                iz = (Iccn - Iccp)/2;
              *(ptrd0++)+=ix*ix;
              *(ptrd1++)+=ix*iy;
              *(ptrd2++)+=ix*iz;
              *(ptrd3++)+=iy*iy;
              *(ptrd4++)+=iy*iz;
              *(ptrd5++)+=iz*iz;
            }
          }
        } else { // Forward/backward finite differences.
          cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2))
          cimg_forC(*this,c) {
            Tfloat
              *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2),
              *ptrd3 = res.data(0,0,0,3), *ptrd4 = res.data(0,0,0,4), *ptrd5 = res.data(0,0,0,5);
            CImg_3x3x3(I,Tfloat);
            cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) {
              const Tfloat
                ixf = Incc - Iccc, ixb = Iccc - Ipcc,
                iyf = Icnc - Iccc, iyb = Iccc - Icpc,
                izf = Iccn - Iccc, izb = Iccc - Iccp;
              *(ptrd0++)+=(ixf*ixf + ixb*ixb)/2;
              *(ptrd1++)+=(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb)/4;
              *(ptrd2++)+=(ixf*izf + ixf*izb + ixb*izf + ixb*izb)/4;
              *(ptrd3++)+=(iyf*iyf + iyb*iyb)/2;
              *(ptrd4++)+=(iyf*izf + iyf*izb + iyb*izf + iyb*izb)/4;
              *(ptrd5++)+=(izf*izf + izb*izb)/2;
            }
          }
        }
      } else { // 2d
        res.assign(_width,_height,_depth,3,0);
        if (!is_fwbw_scheme) { // Classical central finite differences
          cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height>=1048576 && _depth*_spectrum>=2))
          cimg_forC(*this,c) {
            Tfloat *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2);
            CImg_3x3(I,Tfloat);
            cimg_for3x3(*this,x,y,0,c,I,Tfloat) {
              const Tfloat
                ix = (Inc - Ipc)/2,
                iy = (Icn - Icp)/2;
              *(ptrd0++)+=ix*ix;
              *(ptrd1++)+=ix*iy;
              *(ptrd2++)+=iy*iy;
            }
          }
        } else { // Forward/backward finite differences (version 2).
          cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height>=1048576 && _depth*_spectrum>=2))
          cimg_forC(*this,c) {
            Tfloat *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2);
            CImg_3x3(I,Tfloat);
            cimg_for3x3(*this,x,y,0,c,I,Tfloat) {
              const Tfloat
                ixf = Inc - Icc, ixb = Icc - Ipc,
                iyf = Icn - Icc, iyb = Icc - Icp;
              *(ptrd0++)+=(ixf*ixf + ixb*ixb)/2;
              *(ptrd1++)+=(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb)/4;
              *(ptrd2++)+=(iyf*iyf + iyb*iyb)/2;
            }
          }
        }
      }
      return res;

Project: CImg
File: CImg.h

                                 CImgDisplay::_fitscreen(dx,dy,dz,128,-85,true)
    static unsigned int _fitscreen(const unsigned int dx, const unsigned int dy, const unsigned int dz,
                                   const int dmin, const int dmax,const bool return_y) {
      const unsigned int _nw = dx + (dz>1?dz:0), _nh = dy + (dz>1?dz:0);
      unsigned int nw = _nw?_nw:1, nh = _nh?_nh:1;
      const unsigned int
        sw = (unsigned int)CImgDisplay::screen_width(),
        sh = (unsigned int)CImgDisplay::screen_height(),
        mw = dmin<0?(unsigned int)(sw*-dmin/100):(unsigned int)dmin,
        mh = dmin<0?(unsigned int)(sh*-dmin/100):(unsigned int)dmin,
        Mw = dmax<0?(unsigned int)(sw*-dmax/100):(unsigned int)dmax,
        Mh = dmax<0?(unsigned int)(sh*-dmax/100):(unsigned int)dmax;
      if (nw<mw) { nh = nh*mw/nw; nh+=(nh==0); nw = mw; }
      if (nh<mh) { nw = nw*mh/nh; nw+=(nw==0); nh = mh; }
      if (nw>Mw) { nh = nh*Mw/nw; nh+=(nh==0); nw = Mw; }
      if (nh>Mh) { nw = nw*Mh/nh; nw+=(nw==0); nh = Mh; }
      if (nw<mw) nw = mw;
      if (nh<mh) nh = mh;
      return return_y?nh:nw;

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
                            const int x1, const int y1, const int z1,
                            const tc *const color, const float opacity,
                            const unsigned int pattern) {
      return draw_line(x0,y0,z0,x1,y0,z0,color,opacity,pattern,true).
	draw_line(x1,y0,z0,x1,y1,z0,color,opacity,pattern,false).
	draw_line(x1,y1,z0,x0,y1,z0,color,opacity,pattern,false).
	draw_line(x0,y1,z0,x0,y0,z0,color,opacity,pattern,false).
	draw_line(x0,y0,z1,x1,y0,z1,color,opacity,pattern,true).
	draw_line(x1,y0,z1,x1,y1,z1,color,opacity,pattern,false).
	draw_line(x1,y1,z1,x0,y1,z1,color,opacity,pattern,false).
	draw_line(x0,y1,z1,x0,y0,z1,color,opacity,pattern,false).
	draw_line(x0,y0,z0,x0,y0,z1,color,opacity,pattern,true).
	draw_line(x1,y0,z0,x1,y0,z1,color,opacity,pattern,true).
	draw_line(x1,y1,z0,x1,y1,z1,color,opacity,pattern,true).
	draw_line(x0,y1,z0,x0,y1,z1,color,opacity,pattern,true);

Project: CImg
File: CImg.h

    const CImgList<T>& save_cimg(const char *const filename, const bool is_compressed=false) const {
      return _save_cimg(0,filename,is_compressed);
    }

    const CImgList<T>& _save_cimg(std::FILE *const file, const char *const filename, const bool is_compressed) const {
      if (!file && !filename)
        throw CImgArgumentException(_cimglist_instance
                                    "save_cimg(): Specified filename is (null).",
                                    cimglist_instance);
#ifndef cimg_use_zlib
      if (is_compressed)
        cimg::warn(_cimglist_instance
                   "save_cimg(): Unable to save compressed data in file '%s' unless zlib is enabled, "
                   "saving them uncompressed.",
                   cimglist_instance,
                   filename?filename:"(FILE*)");
#endif
      std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
      const char *const ptype = pixel_type(), *const etype = cimg::endianness()?"big":"little";
      if (std::strstr(ptype,"unsigned")==ptype) std::fprintf(nfile,"%u unsigned_%s %s_endian\n",_width,ptype + 9,etype);
      else std::fprintf(nfile,"%u %s %s_endian\n",_width,ptype,etype);
      cimglist_for(*this,l) {
        const CImg<T>& img = _data[l];
        std::fprintf(nfile,"%u %u %u %u",img._width,img._height,img._depth,img._spectrum);
        if (img._data) {
          CImg<T> tmp;
          if (cimg::endianness()) { tmp = img; cimg::invert_endianness(tmp._data,tmp.size()); }
          const CImg<T>& ref = cimg::endianness()?tmp:img;
          bool failed_to_compress = true;
          if (is_compressed) {
#ifdef cimg_use_zlib
            const ulongT siz = sizeof(T)*ref.size();
            uLongf csiz = siz + siz/100 + 16;
            Bytef *const cbuf = new Bytef[csiz];
            if (compress(cbuf,&csiz,(Bytef*)ref._data,siz))
              cimg::warn(_cimglist_instance
                         "save_cimg(): Failed to save compressed data for file '%s', saving them uncompressed.",
                         cimglist_instance,
                         filename?filename:"(FILE*)");
            else {
              std::fprintf(nfile," #%lu\n",csiz);
              cimg::fwrite(cbuf,csiz,nfile);
              delete[] cbuf;
              failed_to_compress = false;
            }
#endif
          }
          if (failed_to_compress) { // Write in a non-compressed way.
            std::fputc('\n',nfile);
            cimg::fwrite(ref._data,ref.size(),nfile);
          }
        } else std::fputc('\n',nfile);

Project: CImg
File: CImg.h

    template<typename tz, typename tc>
    CImg<T>& draw_triangle(CImg<tz>& zbuffer,
                           const int x0, const int y0, const float z0,
                           const int x1, const int y1, const float z1,
                           const int x2, const int y2, const float z2,
                           const CImg<tc>& texture,
                           const int tx0, const int ty0,
                           const int tx1, const int ty1,
                           const int tx2, const int ty2,
                           const float brightness0,
                           const float brightness1,
                           const float brightness2,
                           const float opacity=1) {
      typedef typename cimg::superset<tz,float>::type tzfloat;
      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
      if (!is_sameXY(zbuffer))
        throw CImgArgumentException(_cimg_instance
                                    "draw_triangle(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have "
                                    "different dimensions.",
                                    cimg_instance,
                                    zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data);
      if (texture._depth>1 || texture._spectrum<_spectrum)
        throw CImgArgumentException(_cimg_instance
                                    "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).",
                                    cimg_instance,
                                    texture._width,texture._height,texture._depth,texture._spectrum,texture._data);
      if (is_overlapped(texture))
        return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,
                                                       brightness0,brightness1,brightness2,opacity);
      static const T maxval = (T)std::min(cimg::type<T>::max(),(T)cimg::type<tc>::max());
      const float nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.0f);
      const ulongT
        whd = (ulongT)_width*_height*_depth,
        twh = (ulongT)texture._width*texture._height,
        offx = _spectrum*whd;
      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
        nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f),
        nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f),
        nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f);
      float
        ntx0 = tx0/z0, nty0 = ty0/z0,
        ntx1 = tx1/z1, nty1 = ty1/z1,
        ntx2 = tx2/z2, nty2 = ty2/z2;
      tzfloat nz0 = 1/(tzfloat)z0, nz1 = 1/(tzfloat)z1, nz2 = 1/(tzfloat)z2;
      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1,nc0,nc1);
      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2,nc0,nc2);
      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2,nc1,nc2);
      if (ny0>=height() || ny2<0) return *this;
      float
        ptxl = (ntx1 - ntx0)/(ny1 - ny0),
        ptxr = (ntx2 - ntx0)/(ny2 - ny0),
        ptxn = (ntx2 - ntx1)/(ny2 - ny1),
        ptyl = (nty1 - nty0)/(ny1 - ny0),
        ptyr = (nty2 - nty0)/(ny2 - ny0),
        ptyn = (nty2 - nty1)/(ny2 - ny1),
        txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
        tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
        txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):
          (ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
        tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):
          (ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
      tzfloat
        pzl = (nz1 - nz0)/(ny1 - ny0),
        pzr = (nz2 - nz0)/(ny2 - ny0),
        pzn = (nz2 - nz1)/(ny2 - ny1),
        zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
        zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));
      _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
        if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
        int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0;
        float txleft = txl, txright = txr, tyleft = tyl, tyright = tyr;
        tzfloat zleft = zl, zright = zr;
        if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,cleft,cright);
        const int
          dx = xright - xleft,
          dc = cright>cleft?cright - cleft:cleft - cright,
          rc = dx?(cright - cleft)/dx:0,
          sc = cright>cleft?1:-1,
          ndc = dc - (dx?dx*(dc/dx):0);
        float pentetx = (txright - txleft)/dx, pentety = (tyright - tyleft)/dx;
        const tzfloat pentez = (zright - zleft)/dx;
        int errc = dx>>1;
        if (xleft<0 && dx) {
          cleft-=xleft*(cright - cleft)/dx;
          zleft-=xleft*(zright - zleft)/dx;
          txleft-=xleft*(txright - txleft)/dx;
          tyleft-=xleft*(tyright - tyleft)/dx;
        }
        if (xleft<0) xleft = 0;
        if (xright>=width() - 1) xright = width() - 1;
        T* ptrd = data(xleft,y);
        tz *ptrz = zbuffer.data(xleft,y);
        if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
            if (zleft>=(tzfloat)*ptrz) {
              *ptrz = (tz)zleft;
              const tzfloat invz = 1/zleft;
              const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));
              cimg_forC(*this,c) {
                *ptrd = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256);
                ptrd+=whd; col+=twh;
              }
              ptrd-=offx;
            }
            zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
            cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
          } else for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
            if (zleft>=(tzfloat)*ptrz) {
              *ptrz = (tz)zleft;
              const tzfloat invz = 1/zleft;
              const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));
              cimg_forC(*this,c) {
                const T val = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256);
                *ptrd = (T)(nopacity*val + *ptrd*copacity);
                ptrd+=whd; col+=twh;
              }
              ptrd-=offx;
            }
            zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
            cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
          }
        zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
      }
      return *this;

Project: CImg
File: CImg.h

    template<typename t>
    void _eval(CImg<t>& output, CImg<T> *const img_output, const char *const expression,
               const double x, const double y, const double z, const double c,
               const CImgList<T> *const list_inputs, CImgList<T> *const list_outputs) const {
      if (!expression || !*expression) { output.assign(1); *output = 0; }
      if (!expression[1]) switch (*expression) { // Single-char optimization.
        case 'w' : output.assign(1); *output = (t)_width; break;
        case 'h' : output.assign(1); *output = (t)_height; break;
        case 'd' : output.assign(1); *output = (t)_depth; break;
        case 's' : output.assign(1); *output = (t)_spectrum; break;
        case 'r' : output.assign(1); *output = (t)_is_shared; break;
        }
      _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' ||
                                         *expression=='*' || *expression==':'),"eval",
                           *this,img_output,list_inputs,list_outputs,false);
      output.assign(1,std::max(1U,mp.result_dim));
      mp(x,y,z,c,output._data);
      mp.end();

Project: CImg
File: CImg.h

    **/
    CImg<T>& invert(const bool use_LU=true) {
      if (_width!=_height || _depth!=1 || _spectrum!=1)
        throw CImgInstanceException(_cimg_instance
                                    "invert(): Instance is not a square matrix.",
                                    cimg_instance);
#ifdef cimg_use_lapack
      int INFO = (int)use_LU, N = _width, LWORK = 4*N, *const IPIV = new int[N];
      Tfloat
        *const lapA = new Tfloat[N*N],
        *const WORK = new Tfloat[LWORK];
      cimg_forXY(*this,k,l) lapA[k*N + l] = (Tfloat)((*this)(k,l));
      cimg::getrf(N,lapA,IPIV,INFO);
      if (INFO)
        cimg::warn(_cimg_instance
                   "invert(): LAPACK function dgetrf_() returned error code %d.",
                   cimg_instance,
                   INFO);
      else {
        cimg::getri(N,lapA,IPIV,WORK,LWORK,INFO);
        if (INFO)
          cimg::warn(_cimg_instance
                     "invert(): LAPACK function dgetri_() returned error code %d.",
                     cimg_instance,
                     INFO);
      }
      if (!INFO) cimg_forXY(*this,k,l) (*this)(k,l) = (T)(lapA[k*N + l]); else fill(0);
      delete[] IPIV; delete[] lapA; delete[] WORK;
#else
      const double dete = _width>3?-1.0:det();
      if (dete!=0.0 && _width==2) {
        const double
          a = _data[0], c = _data[1],
          b = _data[2], d = _data[3];
        _data[0] = (T)(d/dete); _data[1] = (T)(-c/dete);
        _data[2] = (T)(-b/dete); _data[3] = (T)(a/dete);
      } else if (dete!=0.0 && _width==3) {
        const double
          a = _data[0], d = _data[1], g = _data[2],
          b = _data[3], e = _data[4], h = _data[5],
          c = _data[6], f = _data[7], i = _data[8];
        _data[0] = (T)((i*e - f*h)/dete), _data[1] = (T)((g*f - i*d)/dete), _data[2] = (T)((d*h - g*e)/dete);
        _data[3] = (T)((h*c - i*b)/dete), _data[4] = (T)((i*a - c*g)/dete), _data[5] = (T)((g*b - a*h)/dete);
        _data[6] = (T)((b*f - e*c)/dete), _data[7] = (T)((d*c - a*f)/dete), _data[8] = (T)((a*e - d*b)/dete);
      } else {
        if (use_LU) { // LU-based inverse computation
          CImg<Tfloat> A(*this,false), indx, col(1,_width);
          bool d;
          A._LU(indx,d);
          cimg_forX(*this,j) {
            col.fill(0);
            col(j) = 1;
            col._solve(A,indx);
            cimg_forX(*this,i) (*this)(j,i) = (T)col(i);
          }
        } else { // SVD-based inverse computation
          CImg<Tfloat> U(_width,_width), S(1,_width), V(_width,_width);
          SVD(U,S,V,false);
          U.transpose();
          cimg_forY(S,k) if (S[k]!=0) S[k]=1/S[k];
          S.diagonal();
          *this = V*S*U;
        }
      }
#endif
      return *this;

Project: CImg
File: CImg.h

    //! Load a list from a file.
    /**
     \param filename Filename to read data from.
    **/
    CImgList<T>& load(const char *const filename) {
      if (!filename)
        throw CImgArgumentException(_cimglist_instance
                                    "load(): Specified filename is (null).",
                                    cimglist_instance);

      if (!cimg::strncasecmp(filename,"http://",7) || !cimg::strncasecmp(filename,"https://",8)) {
        CImg<charT> filename_local(256);
        load(cimg::load_network(filename,filename_local));
        std::remove(filename_local);
        return *this;
      }

      const bool is_stdin = *filename=='-' && (!filename[1] || filename[1]=='.');
      const char *const ext = cimg::split_filename(filename);
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode(0);
      bool is_loaded = true;
      try {
#ifdef cimglist_load_plugin
        cimglist_load_plugin(filename);
#endif
#ifdef cimglist_load_plugin1
        cimglist_load_plugin1(filename);
#endif
#ifdef cimglist_load_plugin2
        cimglist_load_plugin2(filename);
#endif
#ifdef cimglist_load_plugin3
        cimglist_load_plugin3(filename);
#endif
#ifdef cimglist_load_plugin4
        cimglist_load_plugin4(filename);
#endif
#ifdef cimglist_load_plugin5
        cimglist_load_plugin5(filename);
#endif
#ifdef cimglist_load_plugin6
        cimglist_load_plugin6(filename);
#endif
#ifdef cimglist_load_plugin7
        cimglist_load_plugin7(filename);
#endif
#ifdef cimglist_load_plugin8
        cimglist_load_plugin8(filename);
#endif
        if (!cimg::strcasecmp(ext,"tif") ||
            !cimg::strcasecmp(ext,"tiff")) load_tiff(filename);
        else if (!cimg::strcasecmp(ext,"gif")) load_gif_external(filename);
        else if (!cimg::strcasecmp(ext,"cimg") ||
                 !cimg::strcasecmp(ext,"cimgz") ||
                 !*ext) load_cimg(filename);
        else if (!cimg::strcasecmp(ext,"rec") ||
                 !cimg::strcasecmp(ext,"par")) load_parrec(filename);
        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")) load_video(filename);
        else if (!cimg::strcasecmp(ext,"gz")) load_gzip_external(filename);
        else is_loaded = false;
      } catch (CImgIOException&) { is_loaded = false; }

      // If nothing loaded, try to guess file format from magic number in file.
      if (!is_loaded && !is_stdin) {
        std::FILE *const file = std_fopen(filename,"rb");
        if (!file) {
          cimg::exception_mode(omode);
          throw CImgIOException(_cimglist_instance
                                "load(): Failed to open file '%s'.",
                                cimglist_instance,
                                filename);
        }

        const char *const f_type = cimg::ftype(file,filename);
        std::fclose(file);
        is_loaded = true;
        try {
          if (!cimg::strcasecmp(f_type,"gif")) load_gif_external(filename);
          else if (!cimg::strcasecmp(f_type,"tif")) load_tiff(filename);
          else is_loaded = false;
        } catch (CImgIOException&) { is_loaded = false; }
      }

      // If nothing loaded, try to load file as a single image.
      if (!is_loaded) {
        assign(1);
        try {
          _data->load(filename);
        } catch (CImgIOException&) {
          cimg::exception_mode(omode);
          throw CImgIOException(_cimglist_instance
                                "load(): Failed to recognize format of file '%s'.",
                                cimglist_instance,
                                filename);
        }

Project: CImg
File: CImg.h

    **/
    inline std::FILE *fopen(const char *const path, const char *const mode) {
      if (!path)
        throw CImgArgumentException("cimg::fopen(): Specified file path is (null).");
      if (!mode)
        throw CImgArgumentException("cimg::fopen(): File '%s', specified mode is (null).",
                                    path);
      std::FILE *res = 0;
      if (*path=='-' && (!path[1] || path[1]=='.')) {
        res = (*mode=='r')?cimg::_stdin():cimg::_stdout();
#if cimg_OS==2
        if (*mode && mode[1]=='b') { // Force stdin/stdout to be in binary mode.
#ifdef __BORLANDC__
          if (setmode(_fileno(res),0x8000)==-1) res = 0;
#else
          if (_setmode(_fileno(res),0x8000)==-1) res = 0;
#endif
        }
#endif
      } else res = std_fopen(path,mode);
      if (!res) throw CImgIOException("cimg::fopen(): Failed to open file '%s' with mode '%s'.",
                                      path,mode);
      return res;

Project: CImg
File: CImg.h

    /**
       \param[out] max_val Value of the maximum value found.
    **/
    template<typename t>
    const T& min_max(t& max_val) const {
      if (is_empty())
        throw CImgInstanceException(_cimglist_instance
                                    "min_max(): Empty instance.",
                                    cimglist_instance);
      const T *ptr_min = _data->_data;
      T min_value = *ptr_min, max_value = min_value;
      cimglist_for(*this,l) {
        const CImg<T>& img = _data[l];
        cimg_for(img,ptrs,T) {
          const T val = *ptrs;
          if (val<min_value) { min_value = val; ptr_min = ptrs; }
          if (val>max_value) max_value = val;
        }

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& operator-=(const t value) {
      if (is_empty()) return *this;
      cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=524288))
      cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd - value);
      return *this;

Project: CImg
File: CImg.h

    **/
    CImg<T>& ror(const unsigned int n=1) {
      if (is_empty()) return *this;
      cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=32768))
      cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::ror(*ptrd,n);
      return *this;

Project: CImg
File: CImg.h

    **/
    CImg<T>& acos() {
      if (is_empty()) return *this;
      cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=8192))
      cimg_rof(*this,ptrd,T) *ptrd = (T)std::acos((double)*ptrd);
      return *this;

Project: CImg
File: CImg.h

    **/
    CImg<T>& erode(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) {
      if (is_empty() || (sx==1 && sy==1 && sz==1)) return *this;
      if (sx>1 && _width>1) { // Along X-axis.
        const int L = width(), off = 1, s = (int)sx, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1, s2 = _s2>L?L:_s2;
        CImg<T> buf(L);
        cimg_pragma_openmp(parallel for collapse(3) firstprivate(buf) if (size()>524288))
        cimg_forYZC(*this,y,z,c) {
          T *const ptrdb = buf._data, *ptrd = buf._data, *const ptrde = buf._data + L - 1;
          const T *const ptrsb = data(0,y,z,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off;
          T cur = *ptrs; ptrs+=off; bool is_first = true;
          for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) {
            const T val = *ptrs; ptrs+=off; if (val<=cur) { cur = val; is_first = false; }}
          *(ptrd++) = cur;
          if (ptrs>=ptrse) {
            T *pd = data(0,y,z,c); cur = std::min(cur,*ptrse); cimg_forX(buf,x) { *pd = cur; pd+=off; }
          } else {
            for (int p = s1; p>0 && ptrd<=ptrde; --p) {
              const T val = *ptrs; if (ptrs<ptrse) ptrs+=off; if (val<=cur) { cur = val; is_first = false; }
              *(ptrd++) = cur;
            }
            for (int p = L - s - 1; p>0; --p) {
              const T val = *ptrs; ptrs+=off;
              if (is_first) {
                const T *nptrs = ptrs - off; cur = val;
                for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval<cur) cur = nval; }
                nptrs-=off; const T nval = *nptrs; if (nval<cur) { cur = nval; is_first = true; } else is_first = false;
              } else { if (val<=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; }
              *(ptrd++) = cur;
            }
            ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off;
            for (int p = s1; p>0 && ptrs>=ptrsb; --p) {
              const T val = *ptrs; ptrs-=off; if (val<cur) cur = val;
            }
            *(ptrd--) = cur;
            for (int p = s2 - 1; p>0 && ptrd>=ptrdb; --p) {
              const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val<cur) cur = val; *(ptrd--) = cur;
            }
            T *pd = data(0,y,z,c); cimg_for(buf,ps,T) { *pd = *ps; pd+=off; }
          }
        }
      }

      if (sy>1 && _height>1) { // Along Y-axis.
        const int L = height(), off = width(), s = (int)sy, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1,
          s2 = _s2>L?L:_s2;
        CImg<T> buf(L);
        cimg_pragma_openmp(parallel for collapse(3) firstprivate(buf) if (size()>524288))
        cimg_forXZC(*this,x,z,c) {
          T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1;
          const T *const ptrsb = data(x,0,z,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off;
          T cur = *ptrs; ptrs+=off; bool is_first = true;
          for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) {
            const T val = *ptrs; ptrs+=off; if (val<=cur) { cur = val; is_first = false; }
          }
          *(ptrd++) = cur;
          if (ptrs>=ptrse) {
            T *pd = data(x,0,z,c); cur = std::min(cur,*ptrse); cimg_forX(buf,x) { *pd = cur; pd+=off; }
          } else {
            for (int p = s1; p>0 && ptrd<=ptrde; --p) {
              const T val = *ptrs; if (ptrs<ptrse) ptrs+=off; if (val<=cur) { cur = val; is_first = false; }
              *(ptrd++) = cur;
            }
            for (int p = L - s - 1; p>0; --p) {
              const T val = *ptrs; ptrs+=off;
              if (is_first) {
                const T *nptrs = ptrs - off; cur = val;
                for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval<cur) cur = nval; }
                nptrs-=off; const T nval = *nptrs; if (nval<cur) { cur = nval; is_first = true; } else is_first = false;
              } else { if (val<=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; }
              *(ptrd++) = cur;
            }
            ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off;
            for (int p = s1; p>0 && ptrs>=ptrsb; --p) {
              const T val = *ptrs; ptrs-=off; if (val<cur) cur = val;
            }
            *(ptrd--) = cur;
            for (int p = s2 - 1; p>0 && ptrd>=ptrdb; --p) {
              const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val<cur) cur = val; *(ptrd--) = cur;
            }
            T *pd = data(x,0,z,c); cimg_for(buf,ps,T) { *pd = *ps; pd+=off; }
          }
        }
      }

      if (sz>1 && _depth>1) { // Along Z-axis.
        const int L = depth(), off = width()*height(), s = (int)sz, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1,
          s2 = _s2>L?L:_s2;
        CImg<T> buf(L);
        cimg_pragma_openmp(parallel for collapse(3) firstprivate(buf) if (size()>524288))
        cimg_forXYC(*this,x,y,c) {
          T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1;
          const T *const ptrsb = data(x,y,0,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off;
          T cur = *ptrs; ptrs+=off; bool is_first = true;
          for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) {
            const T val = *ptrs; ptrs+=off; if (val<=cur) { cur = val; is_first = false; }
          }
          *(ptrd++) = cur;
          if (ptrs>=ptrse) {
            T *pd = data(x,y,0,c); cur = std::min(cur,*ptrse); cimg_forX(buf,x) { *pd = cur; pd+=off; }
          } else {
            for (int p = s1; p>0 && ptrd<=ptrde; --p) {
              const T val = *ptrs; if (ptrs<ptrse) ptrs+=off; if (val<=cur) { cur = val; is_first = false; }
              *(ptrd++) = cur;
            }
            for (int p = L - s - 1; p>0; --p) {
              const T val = *ptrs; ptrs+=off;
              if (is_first) {
                const T *nptrs = ptrs - off; cur = val;
                for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval<cur) cur = nval; }
                nptrs-=off; const T nval = *nptrs; if (nval<cur) { cur = nval; is_first = true; } else is_first = false;
              } else { if (val<=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; }
              *(ptrd++) = cur;
            }
            ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off;
            for (int p = s1; p>0 && ptrs>=ptrsb; --p) {
              const T val = *ptrs; ptrs-=off; if (val<cur) cur = val;
            }
            *(ptrd--) = cur;
            for (int p = s2 - 1; p>0 && ptrd>=ptrdb; --p) {
              const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val<cur) cur = val; *(ptrd--) = cur;
            }
            T *pd = data(x,y,0,c); cimg_for(buf,ps,T) { *pd = *ps; pd+=off; }
          }
        }
      }
      return *this;

Project: CImg
File: CImg.h

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

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

Project: CImg
File: CImg.h

    **/
    CImg<T>& abs() {
      if (is_empty()) return *this;
      cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=524288))
      cimg_rof(*this,ptrd,T) *ptrd = cimg::abs(*ptrd);
      return *this;

Project: CImg
File: CImg.h

    **/
    CImg<T>& load_medcon_external(const char *const filename) {
      if (!filename)
        throw CImgArgumentException(_cimg_instance
                                    "load_medcon_external(): Specified filename is (null).",
                                    cimg_instance);
      std::fclose(cimg::fopen(filename,"rb"));            // Check if file exists.
      CImg<charT> command(1024), filename_tmp(256), body(256);
      cimg::fclose(cimg::fopen(filename,"r"));
      std::FILE *file = 0;
      do {
        cimg_snprintf(filename_tmp,filename_tmp._width,"%s.hdr",cimg::filenamerand());
        if ((file=std_fopen(filename_tmp,"rb"))!=0) cimg::fclose(file);
      } while (file);
      cimg_snprintf(command,command._width,"%s -w -c anlz -o \"%s\" -f \"%s\"",
                    cimg::medcon_path(),
                    CImg<charT>::string(filename_tmp)._system_strescape().data(),
                    CImg<charT>::string(filename)._system_strescape().data());
      cimg::system(command);
      cimg::split_filename(filename_tmp,body);

      cimg_snprintf(command,command._width,"%s.hdr",body._data);
      file = std_fopen(command,"rb");
      if (!file) {
        cimg_snprintf(command,command._width,"m000-%s.hdr",body._data);
        file = std_fopen(command,"rb");
        if (!file) {
          throw CImgIOException(_cimg_instance
                                "load_medcon_external(): Failed to load file '%s' with external command 'medcon'.",
                                cimg_instance,
                                filename);
        }
      }
      cimg::fclose(file);
      load_analyze(command);
      std::remove(command);
      cimg::split_filename(command,body);
      cimg_snprintf(command,command._width,"%s.img",body._data);
      std::remove(command);
      return *this;

Project: CImg
File: CImg.h

    template<typename t, typename tc>
    CImg<T>& draw_polygon(const CImg<t>& points,
                          const tc *const color, const float opacity, const unsigned int pattern) {
      if (is_empty() || !points || points._width<3) return *this;
      bool ninit_hatch = true;
      switch (points._height) {
      case 0 : case 1 :
        throw CImgArgumentException(_cimg_instance
                                    "draw_polygon(): Invalid specified point set.",
                                    cimg_instance);
      case 2 : { // 2d version.
        CImg<intT> npoints(points._width,2);
        int x = npoints(0,0) = (int)points(0,0), y = npoints(0,1) = (int)points(0,1);
        unsigned int nb_points = 1;
        for (unsigned int p = 1; p<points._width; ++p) {
          const int nx = (int)points(p,0), ny = (int)points(p,1);
          if (nx!=x || ny!=y) { npoints(nb_points,0) = nx; npoints(nb_points++,1) = ny; x = nx; y = ny; }
        }
        const int x0 = (int)npoints(0,0), y0 = (int)npoints(0,1);
        int ox = x0, oy = y0;
        for (unsigned int i = 1; i<nb_points; ++i) {
          const int x = (int)npoints(i,0), y = (int)npoints(i,1);
          draw_line(ox,oy,x,y,color,opacity,pattern,ninit_hatch);
          ninit_hatch = false;
          ox = x; oy = y;
        }
        draw_line(ox,oy,x0,y0,color,opacity,pattern,false);
      } break;
      default : { // 3d version.
        CImg<intT> npoints(points._width,3);
        int
          x = npoints(0,0) = (int)points(0,0),
          y = npoints(0,1) = (int)points(0,1),
          z = npoints(0,2) = (int)points(0,2);
        unsigned int nb_points = 1;
        for (unsigned int p = 1; p<points._width; ++p) {
          const int nx = (int)points(p,0), ny = (int)points(p,1), nz = (int)points(p,2);
          if (nx!=x || ny!=y || nz!=z) {
            npoints(nb_points,0) = nx; npoints(nb_points,1) = ny; npoints(nb_points++,2) = nz;
            x = nx; y = ny; z = nz;
          }
        }
        const int x0 = (int)npoints(0,0), y0 = (int)npoints(0,1), z0 = (int)npoints(0,2);
        int ox = x0, oy = y0, oz = z0;
        for (unsigned int i = 1; i<nb_points; ++i) {
          const int x = (int)npoints(i,0), y = (int)npoints(i,1), z = (int)npoints(i,2);
          draw_line(ox,oy,oz,x,y,z,color,opacity,pattern,ninit_hatch);
          ninit_hatch = false;
          ox = x; oy = y; oz = z;
        }
        draw_line(ox,oy,oz,x0,y0,z0,color,opacity,pattern,false);
      }
      }
      return *this;

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_axes(const float x0, const float x1, const float y0, const float y1,
                       const tc *const color, const float opacity=1,
                       const int subdivisionx=-60, const int subdivisiony=-60,
                       const float precisionx=0, const float precisiony=0,
                       const unsigned int pattern_x=~0U, const unsigned int pattern_y=~0U,
                       const unsigned int font_height=13) {
      if (is_empty()) return *this;
      const bool allow_zero = (x0*x1>0) || (y0*y1>0);
      const float
        dx = cimg::abs(x1 - x0), dy = cimg::abs(y1 - y0),
        px = dx<=0?1:precisionx==0?(float)std::pow(10.0,(int)std::log10(dx) - 2.0):precisionx,
        py = dy<=0?1:precisiony==0?(float)std::pow(10.0,(int)std::log10(dy) - 2.0):precisiony;
      if (x0!=x1 && y0!=y1)
        draw_axes(CImg<floatT>::sequence(subdivisionx>0?subdivisionx:1-width()/subdivisionx,x0,x1).round(px),
                  CImg<floatT>::sequence(subdivisiony>0?subdivisiony:1-height()/subdivisiony,y0,y1).round(py),
                  color,opacity,pattern_x,pattern_y,font_height,allow_zero);
      else if (x0==x1 && y0!=y1)
        draw_axis((int)x0,CImg<floatT>::sequence(subdivisiony>0?subdivisiony:1-height()/subdivisiony,y0,y1).round(py),
                  color,opacity,pattern_y,font_height);
      else if (x0!=x1 && y0==y1)
        draw_axis(CImg<floatT>::sequence(subdivisionx>0?subdivisionx:1-width()/subdivisionx,x0,x1).round(px),(int)y0,
                  color,opacity,pattern_x,font_height);
      return *this;

Project: CImg
File: CImg.h

    template<typename tp, typename tc, typename to>
    bool is_object3d(const CImgList<tp>& primitives,
                     const CImgList<tc>& colors,
                     const to& opacities,
                     const bool full_check=true,
                     char *const error_message=0) const {
      if (error_message) *error_message = 0;

      // Check consistency for the particular case of an empty 3d object.
      if (is_empty()) {
        if (primitives || colors || opacities) {
          if (error_message) cimg_sprintf(error_message,
                                          "3d object (%u,%u) defines no vertices but %u primitives, "
                                          "%u colors and %lu opacities",
                                          _width,primitives._width,primitives._width,
                                          colors._width,(unsigned long)opacities.size());
          return false;
        }
        return true;
      }

      // Check consistency of vertices.
      if (_height!=3 || _depth>1 || _spectrum>1) { // Check vertices dimensions.
        if (error_message) cimg_sprintf(error_message,
                                        "3d object (%u,%u) has invalid vertex dimensions (%u,%u,%u,%u)",
                                        _width,primitives._width,_width,_height,_depth,_spectrum);
        return false;
      }
      if (colors._width>primitives._width + 1) {
        if (error_message) cimg_sprintf(error_message,
                                        "3d object (%u,%u) defines %u colors",
                                        _width,primitives._width,colors._width);
        return false;
      }
      if (opacities.size()>primitives._width) {
        if (error_message) cimg_sprintf(error_message,
                                        "3d object (%u,%u) defines %lu opacities",
                                        _width,primitives._width,(unsigned long)opacities.size());
        return false;
      }
      if (!full_check) return true;

      // Check consistency of primitives.
      cimglist_for(primitives,l) {
        const CImg<tp>& primitive = primitives[l];
        const unsigned int psiz = (unsigned int)primitive.size();
        switch (psiz) {
        case 1 : { // Point.
          const unsigned int i0 = (unsigned int)primitive(0);
          if (i0>=_width) {
            if (error_message) cimg_sprintf(error_message,
                                            "3d object (%u,%u) refers to invalid vertex indice %u in "
                                            "point primitive [%u]",
                                            _width,primitives._width,i0,l);
            return false;
          }
        } break;
        case 5 : { // Sphere.
          const unsigned int
            i0 = (unsigned int)primitive(0),
            i1 = (unsigned int)primitive(1);
          if (i0>=_width || i1>=_width) {
            if (error_message) cimg_sprintf(error_message,
                                            "3d object (%u,%u) refers to invalid vertex indices (%u,%u) in "
                                            "sphere primitive [%u]",
                                            _width,primitives._width,i0,i1,l);
            return false;
          }
        } break;
        case 2 : // Segment.
        case 6 : {
          const unsigned int
            i0 = (unsigned int)primitive(0),
            i1 = (unsigned int)primitive(1);
          if (i0>=_width || i1>=_width) {
            if (error_message) cimg_sprintf(error_message,
                                            "3d object (%u,%u) refers to invalid vertex indices (%u,%u) in "
                                            "segment primitive [%u]",
                                            _width,primitives._width,i0,i1,l);
            return false;
          }
        } break;
        case 3 : // Triangle.
        case 9 : {
          const unsigned int
            i0 = (unsigned int)primitive(0),
            i1 = (unsigned int)primitive(1),
            i2 = (unsigned int)primitive(2);
          if (i0>=_width || i1>=_width || i2>=_width) {
            if (error_message) cimg_sprintf(error_message,
                                            "3d object (%u,%u) refers to invalid vertex indices (%u,%u,%u) in "
                                            "triangle primitive [%u]",
                                            _width,primitives._width,i0,i1,i2,l);
            return false;
          }
        } break;
        case 4 : // Quadrangle.
        case 12 : {
          const unsigned int
            i0 = (unsigned int)primitive(0),
            i1 = (unsigned int)primitive(1),
            i2 = (unsigned int)primitive(2),
            i3 = (unsigned int)primitive(3);
          if (i0>=_width || i1>=_width || i2>=_width || i3>=_width) {
            if (error_message) cimg_sprintf(error_message,
                                            "3d object (%u,%u) refers to invalid vertex indices (%u,%u,%u,%u) in "
                                            "quadrangle primitive [%u]",
                                            _width,primitives._width,i0,i1,i2,i3,l);
            return false;
          }
        } break;
        default :
          if (error_message) cimg_sprintf(error_message,
                                          "3d object (%u,%u) defines an invalid primitive [%u] of size %u",
                                          _width,primitives._width,l,(unsigned int)psiz);
          return false;
        }
      }

      // Check consistency of colors.
      cimglist_for(colors,c) {
        const CImg<tc>& color = colors[c];
        if (!color) {
          if (error_message) cimg_sprintf(error_message,
                                          "3d object (%u,%u) defines no color for primitive [%u]",
                                          _width,primitives._width,c);
          return false;
        }
      }

      // Check consistency of light texture.
      if (colors._width>primitives._width) {
        const CImg<tc> &light = colors.back();
        if (!light || light._depth>1) {
          if (error_message) cimg_sprintf(error_message,
                                          "3d object (%u,%u) defines an invalid light texture (%u,%u,%u,%u)",
                                          _width,primitives._width,light._width,
                                          light._height,light._depth,light._spectrum);
          return false;
        }
      }

      return true;

Project: CImg
File: CImg.h

    **/
    const CImg<T>& save_graphicsmagick_external(const char *const filename, const unsigned int quality=100) const {
      if (!filename)
        throw CImgArgumentException(_cimg_instance
                                    "save_graphicsmagick_external(): Specified filename is (null).",
                                    cimg_instance);
      if (is_empty()) { cimg::fempty(0,filename); return *this; }
      if (_depth>1)
        cimg::warn(_cimg_instance
                   "save_other(): File '%s', saving a volumetric image with an external call to "
                   "GraphicsMagick only writes the first image slice.",
                   cimg_instance,filename);

#ifdef cimg_use_png
#define _cimg_sge_ext1 "png"
#define _cimg_sge_ext2 "png"
#else
#define _cimg_sge_ext1 "pgm"
#define _cimg_sge_ext2 "ppm"
#endif
      CImg<charT> command(1024), filename_tmp(256);
      std::FILE *file;
      do {
        cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s",
                      cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),
                      _spectrum==1?_cimg_sge_ext1:_cimg_sge_ext2);
        if ((file=std_fopen(filename_tmp,"rb"))!=0) cimg::fclose(file);
      } while (file);
#ifdef cimg_use_png
      save_png(filename_tmp);
#else
      save_pnm(filename_tmp);
#endif
      cimg_snprintf(command,command._width,"%s convert -quality %u \"%s\" \"%s\"",
                    cimg::graphicsmagick_path(),quality,
                    CImg<charT>::string(filename_tmp)._system_strescape().data(),
                    CImg<charT>::string(filename)._system_strescape().data());
      cimg::system(command);
      file = std_fopen(filename,"rb");
      if (!file)
        throw CImgIOException(_cimg_instance
                              "save_graphicsmagick_external(): Failed to save file '%s' with external command 'gm'.",
                              cimg_instance,
                              filename);

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

Project: CImg
File: CImg.h


    static void* _events_thread(void *arg) { // Thread to manage events for all opened display windows.
      Display *const dpy = cimg::X11_attr().display;
      XEvent event;
      pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0);
      pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);
      if (!arg) for ( ; ; ) {
        cimg_lock_display();
        bool event_flag = XCheckTypedEvent(dpy,ClientMessage,&event);
        if (!event_flag) event_flag = XCheckMaskEvent(dpy,
                                                      ExposureMask | StructureNotifyMask | ButtonPressMask |
                                                      KeyPressMask | PointerMotionMask | EnterWindowMask |
                                                      LeaveWindowMask | ButtonReleaseMask | KeyReleaseMask,&event);
        if (event_flag)
          for (unsigned int i = 0; i<cimg::X11_attr().nb_wins; ++i)
            if (!cimg::X11_attr().wins[i]->_is_closed && event.xany.window==cimg::X11_attr().wins[i]->_window)
              cimg::X11_attr().wins[i]->_handle_events(&event);
        cimg_unlock_display();
        pthread_testcancel();
        cimg::sleep(8);
      }
      return 0;

Project: CImg
File: CImg.h

    // Use a custom RNG.
    inline unsigned int _rand(const unsigned int seed=0, const bool set_seed=false) {
      static cimg_ulong next = 0xB16B00B5;
      cimg::mutex(4);
      if (set_seed) next = (cimg_ulong)seed;
      else next = next*1103515245 + 12345U;
      cimg::mutex(4,0);
      return (unsigned int)(next&0xFFFFFFU);

Project: CImg
File: CImg.h

    **/
    static void FFT(CImg<T>& real, CImg<T>& imag, const bool is_invert=false, const unsigned int nb_threads=0) {
      if (!real)
        throw CImgInstanceException("CImgList<%s>::FFT(): Empty specified real part.",
                                    pixel_type());

      if (!imag) imag.assign(real._width,real._height,real._depth,real._spectrum,(T)0);
      if (!real.is_sameXYZC(imag))
        throw CImgInstanceException("CImgList<%s>::FFT(): Specified real part (%u,%u,%u,%u,%p) and "
                                    "imaginary part (%u,%u,%u,%u,%p) have different dimensions.",
                                    pixel_type(),
                                    real._width,real._height,real._depth,real._spectrum,real._data,
                                    imag._width,imag._height,imag._depth,imag._spectrum,imag._data);

#ifdef cimg_use_fftw3
      cimg::mutex(12);
#ifndef cimg_use_fftw3_singlethread
      const unsigned int _nb_threads = nb_threads?nb_threads:cimg::nb_cpus();
      static int fftw_st = fftw_init_threads();
      cimg::unused(fftw_st);
      fftw_plan_with_nthreads(_nb_threads);
#else
      cimg::unused(nb_threads);
#endif
      fftw_complex *data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*real._width*real._height*real._depth);
      if (!data_in) throw CImgInstanceException("CImgList<%s>::FFT(): Failed to allocate memory (%s) "
                                                "for computing FFT of image (%u,%u,%u,%u).",
                                                pixel_type(),
                                                cimg::strbuffersize(sizeof(fftw_complex)*real._width*
                                                                    real._height*real._depth*real._spectrum),
                                                real._width,real._height,real._depth,real._spectrum);

      fftw_plan data_plan;
      const ulongT w = (ulongT)real._width, wh = w*real._height, whd = wh*real._depth;
      data_plan = fftw_plan_dft_3d(real._width,real._height,real._depth,data_in,data_in,
                                   is_invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
      cimg_forC(real,c) {
        T *ptrr = real.data(0,0,0,c), *ptri = imag.data(0,0,0,c);
        double *ptrd = (double*)data_in;
        for (unsigned int x = 0; x<real._width; ++x, ptrr-=wh - 1, ptri-=wh - 1)
          for (unsigned int y = 0; y<real._height; ++y, ptrr-=whd-w, ptri-=whd-w)
            for (unsigned int z = 0; z<real._depth; ++z, ptrr+=wh, ptri+=wh) {
              *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri;
            }
        fftw_execute(data_plan);
        ptrd = (double*)data_in;
        ptrr = real.data(0,0,0,c);
        ptri = imag.data(0,0,0,c);
        if (!is_invert) for (unsigned int x = 0; x<real._width; ++x, ptrr-=wh - 1, ptri-=wh - 1)
          for (unsigned int y = 0; y<real._height; ++y, ptrr-=whd-w, ptri-=whd-w)
            for (unsigned int z = 0; z<real._depth; ++z, ptrr+=wh, ptri+=wh) {
              *ptrr = (T)*(ptrd++); *ptri = (T)*(ptrd++);
            }
        else for (unsigned int x = 0; x<real._width; ++x, ptrr-=wh - 1, ptri-=wh - 1)
          for (unsigned int y = 0; y<real._height; ++y, ptrr-=whd-w, ptri-=whd-w)
            for (unsigned int z = 0; z<real._depth; ++z, ptrr+=wh, ptri+=wh) {
              *ptrr = (T)(*(ptrd++)/whd); *ptri = (T)(*(ptrd++)/whd);
            }
      }
      fftw_destroy_plan(data_plan);
      fftw_free(data_in);
#ifndef cimg_use_fftw3_singlethread
      fftw_cleanup_threads();
#endif
      cimg::mutex(12,0);
#else
      cimg::unused(nb_threads);
      if (real._depth>1) FFT(real,imag,'z',is_invert);
      if (real._height>1) FFT(real,imag,'y',is_invert);
      if (real._width>1) FFT(real,imag,'x',is_invert);
#endif

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


    CImg<T>& _fill(const char *const expression, const bool repeat_values, bool allow_formula,
                   const CImgList<T> *const list_inputs, CImgList<T> *const list_outputs,
                   const char *const calling_function, const CImg<T> *provides_copy) {
      if (is_empty() || !expression || !*expression) return *this;
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode(0);
      CImg<charT> is_error;
      bool is_value_sequence = false;
      cimg_abort_init;

      if (allow_formula) {

        // Try to pre-detect regular value sequence to avoid exception thrown by _cimg_math_parser.
        double value;
        char sep;
        const int err = cimg_sscanf(expression,"%lf %c",&value,&sep);
        if (err==1 || (err==2 && sep==',')) {
          if (err==1) return fill((T)value);
          else is_value_sequence = true;
        }

        // Try to fill values according to a formula.
        _cimg_abort_init_omp;
        if (!is_value_sequence) try {
            CImg<T> base = provides_copy?provides_copy->get_shared():get_shared();
            _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' ||
                                               *expression=='*' || *expression==':'),
                                 calling_function,base,this,list_inputs,list_outputs,true);
            if (!provides_copy && expression && *expression!='>' && *expression!='<' && *expression!=':' &&
                mp.need_input_copy)
              base.assign().assign(*this,false); // Needs input copy

            bool do_in_parallel = false;
#ifdef cimg_use_openmp
            cimg_openmp_if(*expression=='*' || *expression==':' ||
                           (mp.is_parallelizable && _width>=320 && _height*_depth*_spectrum>=2))
              do_in_parallel = true;
#endif
            if (mp.result_dim) { // Vector-valued expression
              const unsigned int N = std::min(mp.result_dim,_spectrum);
              const ulongT whd = (ulongT)_width*_height*_depth;
              T *ptrd = *expression=='<'?_data + _width*_height*_depth - 1:_data;
              if (*expression=='<') {
                CImg<doubleT> res(1,mp.result_dim);
                cimg_rofYZ(*this,y,z) {
                  cimg_abort_test;
                  cimg_rofX(*this,x) {
                    mp(x,y,z,0,res._data);
                    const double *ptrs = res._data;
                    T *_ptrd = ptrd--; for (unsigned int n = N; n>0; --n) { *_ptrd = (T)(*ptrs++); _ptrd+=whd; }
                  }
                }
              } else if (*expression=='>' || !do_in_parallel) {
                CImg<doubleT> res(1,mp.result_dim);
                cimg_forYZ(*this,y,z) {
                  cimg_abort_test;
                  cimg_forX(*this,x) {
                    mp(x,y,z,0,res._data);
                    const double *ptrs = res._data;
                    T *_ptrd = ptrd++; for (unsigned int n = N; n>0; --n) { *_ptrd = (T)(*ptrs++); _ptrd+=whd; }
                  }
                }
             } else {
#ifdef cimg_use_openmp
                cimg_pragma_openmp(parallel)
                {
                  _cimg_math_parser
                    _mp = omp_get_thread_num()?mp:_cimg_math_parser(),
                    &lmp = omp_get_thread_num()?_mp:mp;
                  lmp.is_fill = true;
                  cimg_pragma_openmp(for collapse(2))
                    cimg_forYZ(*this,y,z) _cimg_abort_try_omp {
                    cimg_abort_test;
                    CImg<doubleT> res(1,lmp.result_dim);
                    T *ptrd = data(0,y,z,0);
                    cimg_forX(*this,x) {
                      lmp(x,y,z,0,res._data);
                      const double *ptrs = res._data;
                      T *_ptrd = ptrd++; for (unsigned int n = N; n>0; --n) { *_ptrd = (T)(*ptrs++); _ptrd+=whd; }
                    }
                  } _cimg_abort_catch_omp _cimg_abort_catch_fill_omp
                }
#endif
              }

            } else { // Scalar-valued expression
              T *ptrd = *expression=='<'?end() - 1:_data;
              if (*expression=='<')
                cimg_rofYZC(*this,y,z,c) { cimg_abort_test; cimg_rofX(*this,x) *(ptrd--) = (T)mp(x,y,z,c); }
              else if (*expression=='>' || !do_in_parallel)
                cimg_forYZC(*this,y,z,c) { cimg_abort_test; cimg_forX(*this,x) *(ptrd++) = (T)mp(x,y,z,c); }
              else {
#ifdef cimg_use_openmp
                cimg_pragma_openmp(parallel)
                {
                  _cimg_math_parser
                    _mp = omp_get_thread_num()?mp:_cimg_math_parser(),
                    &lmp = omp_get_thread_num()?_mp:mp;
                  lmp.is_fill = true;
                  cimg_pragma_openmp(for collapse(3))
                    cimg_forYZC(*this,y,z,c) _cimg_abort_try_omp {
                    cimg_abort_test;
                    T *ptrd = data(0,y,z,c);
                    cimg_forX(*this,x) *ptrd++ = (T)lmp(x,y,z,c);
                  } _cimg_abort_catch_omp _cimg_abort_catch_fill_omp
                }
#endif
              }
            }
            mp.end();
          } catch (CImgException& e) { CImg<charT>::string(e._message).move_to(is_error); }
      }

      // Try to fill values according to a value sequence.
      if (!allow_formula || is_value_sequence || is_error) {
        CImg<charT> item(256);
        char sep = 0;
        const char *nexpression = expression;
        ulongT nb = 0;
        const ulongT siz = size();
        T *ptrd = _data;
        for (double val = 0; *nexpression && nb<siz; ++nb) {
          sep = 0;
          const int err = cimg_sscanf(nexpression,"%255[ \n\t0-9.eEinfa+-]%c",item._data,&sep);
          if (err>0 && cimg_sscanf(item,"%lf",&val)==1 && (sep==',' || sep==';' || err==1)) {
            nexpression+=std::strlen(item) + (err>1);
            *(ptrd++) = (T)val;
          } else break;
        }
        cimg::exception_mode(omode);
        if (nb<siz && (sep || *nexpression)) {
          if (is_error) throw CImgArgumentException("%s",is_error._data);
          else throw CImgArgumentException(_cimg_instance
                                           "%s(): Invalid sequence of filling values '%s'.",
                                           cimg_instance,calling_function,expression);
        }
        if (repeat_values && nb && nb<siz)
          for (T *ptrs = _data, *const ptre = _data + siz; ptrd<ptre; ++ptrs) *(ptrd++) = *ptrs;
      }

      cimg::exception_mode(omode);
      cimg_abort_test;
      return *this;

Project: CImg
File: CImg.h

    //! Compute the hyperbolic tangent of each pixel value \newinstance.
    CImg<Tfloat> get_tanh() const {
      return CImg<Tfloat>(*this,false).tanh();

Project: CImg
File: CImg.h


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