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

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

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_line(const int x0, const int y0, const float z0,
                       const int x1, const int y1, const float z1,
                       const CImg<tc>& texture,
                       const int tx0, const int ty0,
                       const int tx1, const int ty1,
                       const float opacity=1,
                       const unsigned int pattern=~0U, const bool init_hatch=true) {
      if (is_empty() && z0<=0 && z1<=0) return *this;
      if (texture._depth>1 || texture._spectrum<_spectrum)
        throw CImgArgumentException(_cimg_instance
                                    "draw_line(): Invalid specified texture (%u,%u,%u,%u,%p).",
                                    cimg_instance,
                                    texture._width,texture._height,texture._depth,texture._spectrum,texture._data);
      if (is_overlapped(texture))
        return draw_line(x0,y0,z0,x1,y1,z1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);
      static unsigned int hatch = ~0U - (~0U>>1);
      if (init_hatch) hatch = ~0U - (~0U>>1);
      const bool xdir = x0<x1, ydir = y0<y1;
      int
        nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
        &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
        &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
        &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
        &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
      float
        Tx0 = tx0/z0, Tx1 = tx1/z1,
        Ty0 = ty0/z0, Ty1 = ty1/z1,
        Z0 = 1/z0, Z1 = 1/z1,
        dz = Z1 - Z0, dtx = Tx1 - Tx0, dty = Ty1 - Ty0,
        tnx0 = Tx0, tnx1 = Tx1, tny0 = Ty0, tny1 = Ty1, nz0 = Z0, nz1 = Z1,
        &zleft = xdir?nz0:nz1, &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1,
        &zright = xdir?nz1:nz0, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0,
        &zup = ydir?nz0:nz1, &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1,
        &zdown = ydir?nz1:nz0, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0;
      if (xright<0 || xleft>=width()) return *this;
      if (xleft<0) {
        const float D = (float)xright - xleft;
        yleft-=(int)((float)xleft*((float)yright - yleft)/D);
        zleft-=(float)xleft*(zright - zleft)/D;
        txleft-=(float)xleft*(txright - txleft)/D;
        tyleft-=(float)xleft*(tyright - tyleft)/D;
        xleft = 0;
      }
      if (xright>=width()) {
        const float d = (float)xright - width(), D = (float)xright - xleft;
        yright-=(int)(d*((float)yright - yleft)/D);
        zright-=d*(zright - zleft)/D;
        txright-=d*(txright - txleft)/D;
        tyright-=d*(tyright - tyleft)/D;
        xright = width() - 1;
      }
      if (ydown<0 || yup>=height()) return *this;
      if (yup<0) {
        const float D = (float)ydown - yup;
        xup-=(int)((float)yup*((float)xdown - xup)/D);
        zup-=(float)yup*(zdown - zup)/D;
        txup-=(float)yup*(txdown - txup)/D;
        tyup-=(float)yup*(tydown - tyup)/D;
        yup = 0;
      }
      if (ydown>=height()) {
        const float d = (float)ydown - height(), D = (float)ydown - yup;
        xdown-=(int)(d*((float)xdown - xup)/D);
        zdown-=d*(zdown - zup)/D;
        txdown-=d*(txdown - txup)/D;
        tydown-=d*(tydown - tyup)/D;
        ydown = height() - 1;
      }
      T *ptrd0 = data(nx0,ny0);
      int dx = xright - xleft, dy = ydown - yup;
      const bool steep = dy>dx;
      if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
      const longT
        offx = (longT)(nx0<nx1?1:-1)*(steep?width():1),
        offy = (longT)(ny0<ny1?1:-1)*(steep?1:width()),
        ndx = (longT)(dx>0?dx:1);
      const ulongT
        whd = (ulongT)_width*_height*_depth,
        twh = (ulongT)texture._width*texture._height;

      if (opacity>=1) {
        if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
          if (pattern&hatch) {
            const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
            const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z));
            T *ptrd = ptrd0;
            cimg_forC(*this,c) { *ptrd = (T)*col; ptrd+=whd; col+=twh; }
          }
          hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
          ptrd0+=offx;
          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
        } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
          const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
          const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z));
          T *ptrd = ptrd0;
          cimg_forC(*this,c) { *ptrd = (T)*col; ptrd+=whd; col+=twh; }
          ptrd0+=offx;
          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
        }
      } else {
        const float nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.0f);
        if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
          if (pattern&hatch) {
            const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
            const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z));
            T *ptrd = ptrd0;
            cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; }
          }
          hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
          ptrd0+=offx;
          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
        } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
          const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
          const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z));
          T *ptrd = ptrd0;
          cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; }
          ptrd0+=offx;
          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
        }
      }
      return *this;

Project: CImg
File: CImg.h

    **/
    CImgList<T> get_split(const char axis, const int nb=-1) const {
      CImgList<T> res;
      if (is_empty()) return res;
      const char _axis = cimg::lowercase(axis);

      if (nb<0) { // Split by bloc size.
        const unsigned int dp = (unsigned int)(nb?-nb:1);
        switch (_axis) {
        case 'x': {
          if (_width>dp) {
            res.assign(_width/dp + (_width%dp?1:0),1,1);
            const unsigned int pe = _width - dp;
            cimg_pragma_openmp(parallel for cimg_openmp_if(res._width>=128 && _height*_depth*_spectrum>=128))
            for (unsigned int p = 0; p<pe; p+=dp)
              get_crop(p,0,0,0,p + dp - 1,_height - 1,_depth - 1,_spectrum - 1).move_to(res[p/dp]);
            get_crop((res._width - 1)*dp,0,0,0,_width - 1,_height - 1,_depth - 1,_spectrum - 1).move_to(res.back());
          } else res.assign(*this);
        } break;
        case 'y': {
          if (_height>dp) {
            res.assign(_height/dp + (_height%dp?1:0),1,1);
            const unsigned int pe = _height - dp;
            cimg_pragma_openmp(parallel for cimg_openmp_if(res._width>=128 && _width*_depth*_spectrum>=128))
            for (unsigned int p = 0; p<pe; p+=dp)
              get_crop(0,p,0,0,_width - 1,p + dp - 1,_depth - 1,_spectrum - 1).move_to(res[p/dp]);
            get_crop(0,(res._width - 1)*dp,0,0,_width - 1,_height - 1,_depth - 1,_spectrum - 1).move_to(res.back());
          } else res.assign(*this);
        } break;
        case 'z': {
          if (_depth>dp) {
            res.assign(_depth/dp + (_depth%dp?1:0),1,1);
            const unsigned int pe = _depth - dp;
            cimg_pragma_openmp(parallel for cimg_openmp_if(res._width>=128 && _width*_height*_spectrum>=128))
            for (unsigned int p = 0; p<pe; p+=dp)
              get_crop(0,0,p,0,_width - 1,_height - 1,p + dp - 1,_spectrum - 1).move_to(res[p/dp]);
            get_crop(0,0,(res._width - 1)*dp,0,_width - 1,_height - 1,_depth - 1,_spectrum - 1).move_to(res.back());
          } else res.assign(*this);
        } break;
        case 'c' : {
          if (_spectrum>dp) {
            res.assign(_spectrum/dp + (_spectrum%dp?1:0),1,1);
            const unsigned int pe = _spectrum - dp;
            cimg_pragma_openmp(parallel for cimg_openmp_if(res._width>=128 && _width*_height*_depth>=128))
            for (unsigned int p = 0; p<pe; p+=dp)
              get_crop(0,0,0,p,_width - 1,_height - 1,_depth - 1,p + dp - 1).move_to(res[p/dp]);
            get_crop(0,0,0,(res._width - 1)*dp,_width - 1,_height - 1,_depth - 1,_spectrum - 1).move_to(res.back());
          } else res.assign(*this);
        }
        }
      } else if (nb>0) { // Split by number of (non-homogeneous) blocs.
        const unsigned int siz = _axis=='x'?_width:_axis=='y'?_height:_axis=='z'?_depth:_axis=='c'?_spectrum:0;
        if ((unsigned int)nb>siz)
          throw CImgArgumentException(_cimg_instance
                                      "get_split(): Instance cannot be split along %c-axis into %u blocs.",
                                      cimg_instance,
                                      axis,nb);
        if (nb==1) res.assign(*this);
        else {
          int err = (int)siz;
          unsigned int _p = 0;
          switch (_axis) {
          case 'x' : {
            cimg_forX(*this,p) if ((err-=nb)<=0) {
              get_crop(_p,0,0,0,p,_height - 1,_depth - 1,_spectrum - 1).move_to(res);
              err+=(int)siz;
              _p = p + 1U;
            }
          } break;
          case 'y' : {
            cimg_forY(*this,p) if ((err-=nb)<=0) {
              get_crop(0,_p,0,0,_width - 1,p,_depth - 1,_spectrum - 1).move_to(res);
              err+=(int)siz;
              _p = p + 1U;
            }
          } break;
          case 'z' : {
            cimg_forZ(*this,p) if ((err-=nb)<=0) {
              get_crop(0,0,_p,0,_width - 1,_height - 1,p,_spectrum - 1).move_to(res);
              err+=(int)siz;
              _p = p + 1U;
            }
          } break;
          case 'c' : {
            cimg_forC(*this,p) if ((err-=nb)<=0) {
              get_crop(0,0,0,_p,_width - 1,_height - 1,_depth - 1,p).move_to(res);
              err+=(int)siz;
              _p = p + 1U;
            }
          }
          }
        }
      } else { // Split by egal values according to specified axis.
        T current = *_data;
        switch (_axis) {
        case 'x' : {
          int i0 = 0;
          cimg_forX(*this,i)
            if ((*this)(i)!=current) { get_columns(i0,i - 1).move_to(res); i0 = i; current = (*this)(i); }
          get_columns(i0,width() - 1).move_to(res);
        } break;
        case 'y' : {
          int i0 = 0;
          cimg_forY(*this,i)
            if ((*this)(0,i)!=current) { get_rows(i0,i - 1).move_to(res); i0 = i; current = (*this)(0,i); }
          get_rows(i0,height() - 1).move_to(res);
        } break;
        case 'z' : {
          int i0 = 0;
          cimg_forZ(*this,i)
            if ((*this)(0,0,i)!=current) { get_slices(i0,i - 1).move_to(res); i0 = i; current = (*this)(0,0,i); }
          get_slices(i0,depth() - 1).move_to(res);
        } break;
        case 'c' : {
          int i0 = 0;
          cimg_forC(*this,i)
            if ((*this)(0,0,0,i)!=current) { get_channels(i0,i - 1).move_to(res); i0 = i; current = (*this)(0,0,0,i); }
          get_channels(i0,spectrum() - 1).move_to(res);
        } break;
        default : {
          longT i0 = 0;
          cimg_foroff(*this,i)
            if ((*this)[i]!=current) {
              CImg<T>(_data + i0,1,(unsigned int)(i - i0)).move_to(res);
              i0 = (longT)i; current = (*this)[i];
            }
          CImg<T>(_data + i0,1,(unsigned int)(size() - i0)).move_to(res);
        }
        }
      }
      return res;

Project: CImg
File: CImg.h

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

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

Project: CImg
File: CImg.h

    template<typename t, typename tc>
    CImg<T>& draw_axis(const int x, const CImg<t>& values_y,
                       const tc *const color, const float opacity=1,
                       const unsigned int pattern=~0U, const unsigned int font_height=13,
                       const bool allow_zero=true) {
      if (is_empty()) return *this;
      int siz = (int)values_y.size() - 1;
      CImg<charT> txt(32);
      CImg<T> label;
      if (siz<=0) { // Degenerated case.
        draw_line(x,0,x,_height - 1,color,opacity,pattern);
        if (!siz) {
          cimg_snprintf(txt,txt._width,"%g",(double)*values_y);
          label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height);
          const int
            _yt = (height() - label.height())/2,
            yt = _yt<0?0:_yt + label.height()>=height()?height() - 1-label.height():_yt,
            _xt = x - 2 - label.width(),
            xt = _xt>=0?_xt:x + 3;
          draw_point(x - 1,height()/2,color,opacity).draw_point(x + 1,height()/2,color,opacity);
          if (allow_zero || *txt!='0' || txt[1]!=0)
            draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height);
        }
      } else { // Regular case.
        if (values_y[0]<values_y[siz]) draw_arrow(x,0,x,_height - 1,color,opacity,30,5,pattern);
        else draw_arrow(x,_height - 1,x,0,color,opacity,30,5,pattern);
        cimg_foroff(values_y,y) {
          cimg_snprintf(txt,txt._width,"%g",(double)values_y(y));
          label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height);
          const int
            yi = (int)(y*(_height - 1)/siz),
            _yt = yi - label.height()/2,
            yt = _yt<0?0:_yt + label.height()>=height()?height() - 1-label.height():_yt,
            _xt = x - 2 - label.width(),
            xt = _xt>=0?_xt:x + 3;
          draw_point(x - 1,yi,color,opacity).draw_point(x + 1,yi,color,opacity);
          if (allow_zero || *txt!='0' || txt[1]!=0)
            draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height);
        }
      }
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


      unsigned int scalar6(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 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:scalar();
        CImg<ulongT>::vector((ulongT)op,pos,arg1,arg2,arg3,arg4,arg5,arg6).move_to(code);
        return pos;

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()>=32768))
      cimg_rof(*this,ptrd,T) *ptrd = (T)((ulongT)*ptrd ^ (ulongT)value);
      return *this;

Project: CImg
File: CImg.h

    template<typename tz, typename tc, typename tl>
    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 CImg<tl>& light,
                           const int lx0, const int ly0,
                           const int lx1, const int ly1,
                           const int lx2, const int ly2,
                           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 (light._depth>1 || light._spectrum<_spectrum)
        throw CImgArgumentException(_cimg_instance
                                    "draw_triangle(): Invalid specified light texture (%u,%u,%u,%u,%p).",
                                    cimg_instance,light._width,light._height,light._depth,light._spectrum,light._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,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
      if (is_overlapped(light))
        return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,
                             texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,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,
        lwh = (ulongT)light._width*light._height,
        offx = _spectrum*whd;
      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
        nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
      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,nlx0,nlx1,nly0,nly1,nz0,nz1);
      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2,nz0,nz2);
      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2,nz1,nz2);
      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)));
      const bool is_bump = texture._spectrum>=_spectrum + 2;
      const ulongT obx = twh*_spectrum, oby = twh*(_spectrum + 1);

      _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
                          nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
        if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
        int
          xleft = xleft0, xright = xright0,
          lxleft = lxleft0, lxright = lxright0,
          lyleft = lyleft0, lyright = lyright0;
        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,lxleft,lxright,lyleft,lyright);
        const int
          dx = xright - xleft,
          dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
          dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
          rlx = dx?(lxright - lxleft)/dx:0,
          rly = dx?(lyright - lyleft)/dx:0,
          slx = lxright>lxleft?1:-1,
          sly = lyright>lyleft?1:-1,
          ndlx = dlx - (dx?dx*(dlx/dx):0),
          ndly = dly - (dx?dx*(dly/dx):0);
        float pentetx = (txright - txleft)/dx, pentety = (tyright - tyleft)/dx;
        const tzfloat pentez = (zright - zleft)/dx;
        int errlx = dx>>1, errly = errlx;
        if (xleft<0 && dx) {
          zleft-=xleft*(zright - zleft)/dx;
          lxleft-=xleft*(lxright - lxleft)/dx;
          lyleft-=xleft*(lyright - lyleft)/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, ++ptrz, ++ptrd) {
            if (zleft>=(tzfloat)*ptrz) {
              *ptrz = (tz)zleft;
              const tzfloat invz = 1/zleft;
              const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));
              const int bx = is_bump?128 - (int)col[obx]:0, by = is_bump?128 - (int)col[oby]:0;
              const tl *lig = &light._atXY(lxleft + bx,lyleft + by);
              cimg_forC(*this,c) {
                const tl l = *lig;
                *ptrd = (T)(l<1?l**col:(2 - l)**col + (l - 1)*maxval);
                ptrd+=whd; col+=twh; lig+=lwh;
              }
              ptrd-=offx;
            }
            zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
            lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
            lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
          } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
            if (zleft>=(tzfloat)*ptrz) {
              *ptrz = (tz)zleft;
              const tzfloat invz = 1/zleft;
              const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));
              const int bx = is_bump?128 - (int)col[obx]:0, by = is_bump?128 - (int)col[oby]:0;
              const tl *lig = &light._atXY(lxleft + bx,lyleft + by);
              cimg_forC(*this,c) {
                const tl l = *lig;
                const T val = (T)(l<1?l**col:(2 - l)**col + (l - 1)*maxval);
                *ptrd = (T)(nopacity*val + *ptrd*copacity);
                ptrd+=whd; col+=twh; lig+=lwh;
              }
              ptrd-=offx;
            }
            zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
            lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
            lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
          }
        zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
      }
      return *this;

Project: CImg
File: CImg.h

    //! Load a gzipped list, using external tool 'gunzip'.
    /**
      \param filename Filename to read data from.
    **/
    CImgList<T>& load_gzip_external(const char *const filename) {
      if (!filename)
        throw CImgIOException(_cimglist_instance
                              "load_gzip_external(): Specified filename is (null).",
                              cimglist_instance);
      std::fclose(cimg::fopen(filename,"rb"));            // Check if file exists.
      CImg<charT> command(1024), filename_tmp(256), body(256);
      const char
        *ext = cimg::split_filename(filename,body),
        *ext2 = cimg::split_filename(body,0);
      std::FILE *file = 0;
      do {
        if (!cimg::strcasecmp(ext,"gz")) {
          if (*ext2) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s",
                                   cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2);
          else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s",
                             cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
        } else {
          if (*ext) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s",
                                  cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext);
          else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s",
                             cimg::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 -c \"%s\" > \"%s\"",
                    cimg::gunzip_path(),
                    CImg<charT>::string(filename)._system_strescape().data(),
                    CImg<charT>::string(filename_tmp)._system_strescape().data());
      cimg::system(command);
      if (!(file = std_fopen(filename_tmp,"rb"))) {
        cimg::fclose(cimg::fopen(filename,"r"));
        throw CImgIOException(_cimglist_instance
                              "load_gzip_external(): Failed to open file '%s'.",
                              cimglist_instance,
                              filename);

      } else cimg::fclose(file);

Project: CImg
File: CImg.h


    inline double _fibonacci(int exp) {
      double
        base = (1 + std::sqrt(5.0))/2,
        result = 1/std::sqrt(5.0);
      while (exp) {
        if (exp&1) result*=base;
        exp>>=1;
        base*=base;
      }
      return result;

Project: CImg
File: CImg.h

      return *this;
    }

    //! Insert a copy of the image \c img into the current image list, at position \c pos \specialization.
    CImgList<T>& insert(const CImg<T>& img, const unsigned int pos=~0U, const bool is_shared=false) {
      const unsigned int npos = pos==~0U?_width:pos;
      if (npos>_width)
        throw CImgArgumentException(_cimglist_instance
                                    "insert(): Invalid insertion request of specified image (%u,%u,%u,%u,%p) "
                                    "at position %u.",
                                    cimglist_instance,
                                    img._width,img._height,img._depth,img._spectrum,img._data,npos);
      CImg<T> *const new_data = (++_width>_allocated_width)?new CImg<T>[_allocated_width?(_allocated_width<<=1):
                                                                        (_allocated_width=16)]:0;
      if (!_data) { // Insert new element into empty list.
        _data = new_data;
        if (is_shared && img) {
          _data->_width = img._width;
          _data->_height = img._height;
          _data->_depth = img._depth;
          _data->_spectrum = img._spectrum;
          _data->_is_shared = true;
          _data->_data = img._data;
        } else *_data = img;
      }
      else {
        if (new_data) { // Insert with re-allocation.
          if (npos) std::memcpy(new_data,_data,sizeof(CImg<T>)*npos);
          if (npos!=_width - 1) std::memcpy(new_data + npos + 1,_data + npos,sizeof(CImg<T>)*(_width - 1 - npos));
          if (is_shared && img) {
            new_data[npos]._width = img._width;
            new_data[npos]._height = img._height;
            new_data[npos]._depth = img._depth;
            new_data[npos]._spectrum = img._spectrum;
            new_data[npos]._is_shared = true;
            new_data[npos]._data = img._data;
          } else {
            new_data[npos]._width = new_data[npos]._height = new_data[npos]._depth = new_data[npos]._spectrum = 0;
            new_data[npos]._data = 0;
            new_data[npos] = img;
          }
          std::memset(_data,0,sizeof(CImg<T>)*(_width - 1));
          delete[] _data;
          _data = new_data;
        } else { // Insert without re-allocation.
          if (npos!=_width - 1) std::memmove(_data + npos + 1,_data + npos,sizeof(CImg<T>)*(_width - 1 - npos));
          if (is_shared && img) {
            _data[npos]._width = img._width;
            _data[npos]._height = img._height;
            _data[npos]._depth = img._depth;
            _data[npos]._spectrum = img._spectrum;
            _data[npos]._is_shared = true;
            _data[npos]._data = img._data;
          } else {
            _data[npos]._width = _data[npos]._height = _data[npos]._depth = _data[npos]._spectrum = 0;
            _data[npos]._data = 0;
            _data[npos] = img;
          }

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    template<typename tp, typename tf, typename tc, typename to>
    const CImg<T>& _display_object3d(CImgDisplay& disp, const char *const title,
				     const CImg<tp>& vertices,
				     const CImgList<tf>& primitives,
				     const CImgList<tc>& colors,
                                     const to& opacities,
				     const bool centering,
				     const int render_static, const int render_motion,
				     const bool is_double_sided, const float focale,
                                     const float light_x, const float light_y, const float light_z,
				     const float specular_lightness, const float specular_shininess,
				     const bool display_axes, float *const pose_matrix,
                                     const bool exit_on_anykey) const {
      typedef typename cimg::superset<tp,float>::type tpfloat;

      // Check input arguments
      if (is_empty()) {
	if (disp) return CImg<T>(disp.width(),disp.height(),1,(colors && colors[0].size()==1)?1:3,0).
		    _display_object3d(disp,title,vertices,primitives,colors,opacities,centering,
                                      render_static,render_motion,is_double_sided,focale,
                                      light_x,light_y,light_z,specular_lightness,specular_shininess,
                                      display_axes,pose_matrix,exit_on_anykey);
	else return CImg<T>(1,2,1,1,64,128).resize(cimg_fitscreen(CImgDisplay::screen_width()/2,
                                                                  CImgDisplay::screen_height()/2,1),
                                                   1,(colors && colors[0].size()==1)?1:3,3).
               _display_object3d(disp,title,vertices,primitives,colors,opacities,centering,
				 render_static,render_motion,is_double_sided,focale,
                                 light_x,light_y,light_z,specular_lightness,specular_shininess,
				 display_axes,pose_matrix,exit_on_anykey);
      } else { if (disp) disp.resize(*this,false); }
      CImg<charT> error_message(1024);
      if (!vertices.is_object3d(primitives,colors,opacities,true,error_message))
        throw CImgArgumentException(_cimg_instance
                                    "display_object3d(): Invalid specified 3d object (%u,%u) (%s).",
                                    cimg_instance,vertices._width,primitives._width,error_message.data());
      if (vertices._width && !primitives) {
        CImgList<tf> nprimitives(vertices._width,1,1,1,1);
        cimglist_for(nprimitives,l) nprimitives(l,0) = (tf)l;
        return _display_object3d(disp,title,vertices,nprimitives,colors,opacities,centering,
				 render_static,render_motion,is_double_sided,focale,
                                 light_x,light_y,light_z,specular_lightness,specular_shininess,
				 display_axes,pose_matrix,exit_on_anykey);
      }
      if (!disp) {
	disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,3);
        if (!title) disp.set_title("CImg<%s> (%u vertices, %u primitives)",
                                   pixel_type(),vertices._width,primitives._width);
      } else if (title) disp.set_title("%s",title);

      // Init 3d objects and compute object statistics
      CImg<floatT>
        pose,
        rotated_vertices(vertices._width,3),
        bbox_vertices, rotated_bbox_vertices,
        axes_vertices, rotated_axes_vertices,
        bbox_opacities, axes_opacities;
      CImgList<uintT> bbox_primitives, axes_primitives;
      CImgList<tf> reverse_primitives;
      CImgList<T> bbox_colors, bbox_colors2, axes_colors;
      unsigned int ns_width = 0, ns_height = 0;
      int _is_double_sided = (int)is_double_sided;
      bool ndisplay_axes = display_axes;
      const CImg<T>
        background_color(1,1,1,_spectrum,0),
        foreground_color(1,1,1,_spectrum,255);
      float
        Xoff = 0, Yoff = 0, Zoff = 0, sprite_scale = 1,
        xm = 0, xM = vertices?vertices.get_shared_row(0).max_min(xm):0,
        ym = 0, yM = vertices?vertices.get_shared_row(1).max_min(ym):0,
        zm = 0, zM = vertices?vertices.get_shared_row(2).max_min(zm):0;
      const float delta = cimg::max(xM - xm,yM - ym,zM - zm);

      rotated_bbox_vertices = bbox_vertices.assign(8,3,1,1,
                                                   xm,xM,xM,xm,xm,xM,xM,xm,
                                                   ym,ym,yM,yM,ym,ym,yM,yM,
                                                   zm,zm,zm,zm,zM,zM,zM,zM);
      bbox_primitives.assign(6,1,4,1,1, 0,3,2,1, 4,5,6,7, 1,2,6,5, 0,4,7,3, 0,1,5,4, 2,3,7,6);
      bbox_colors.assign(6,_spectrum,1,1,1,background_color[0]);
      bbox_colors2.assign(6,_spectrum,1,1,1,foreground_color[0]);
      bbox_opacities.assign(bbox_colors._width,1,1,1,0.3f);

      rotated_axes_vertices = axes_vertices.assign(7,3,1,1,
                                                   0,20,0,0,22,-6,-6,
                                                   0,0,20,0,-6,22,-6,
                                                   0,0,0,20,0,0,22);
      axes_opacities.assign(3,1,1,1,1);
      axes_colors.assign(3,_spectrum,1,1,1,foreground_color[0]);
      axes_primitives.assign(3,1,2,1,1, 0,1, 0,2, 0,3);

      // Begin user interaction loop
      CImg<T> visu0(*this,false), visu;
      CImg<tpfloat> zbuffer(visu0.width(),visu0.height(),1,1,0);
      bool init_pose = true, clicked = false, redraw = true;
      unsigned int key = 0;
      int
        x0 = 0, y0 = 0, x1 = 0, y1 = 0,
        nrender_static = render_static,
        nrender_motion = render_motion;
      disp.show().flush();

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

        // Init object pose
        if (init_pose) {
          const float
            ratio = delta>0?(2.0f*std::min(disp.width(),disp.height())/(3.0f*delta)):1,
            dx = (xM + xm)/2, dy = (yM + ym)/2, dz = (zM + zm)/2;
          if (centering)
            CImg<floatT>(4,3,1,1, ratio,0.,0.,-ratio*dx, 0.,ratio,0.,-ratio*dy, 0.,0.,ratio,-ratio*dz).move_to(pose);
          else CImg<floatT>(4,3,1,1, 1,0,0,0, 0,1,0,0, 0,0,1,0).move_to(pose);
          if (pose_matrix) {
            CImg<floatT> pose0(pose_matrix,4,3,1,1,false);
            pose0.resize(4,4,1,1,0); pose.resize(4,4,1,1,0);
            pose0(3,3) = pose(3,3) = 1;
            (pose0*pose).get_crop(0,0,3,2).move_to(pose);
            Xoff = pose_matrix[12]; Yoff = pose_matrix[13]; Zoff = pose_matrix[14]; sprite_scale = pose_matrix[15];
          } else { Xoff = Yoff = Zoff = 0; sprite_scale = 1; }
          init_pose = false;
          redraw = true;
        }

        // Rotate and draw 3d object
        if (redraw) {
          const float
            r00 = pose(0,0), r10 = pose(1,0), r20 = pose(2,0), r30 = pose(3,0),
            r01 = pose(0,1), r11 = pose(1,1), r21 = pose(2,1), r31 = pose(3,1),
            r02 = pose(0,2), r12 = pose(1,2), r22 = pose(2,2), r32 = pose(3,2);
          if ((clicked && nrender_motion>=0) || (!clicked && nrender_static>=0))
            cimg_forX(vertices,l) {
              const float x = (float)vertices(l,0), y = (float)vertices(l,1), z = (float)vertices(l,2);
              rotated_vertices(l,0) = r00*x + r10*y + r20*z + r30;
              rotated_vertices(l,1) = r01*x + r11*y + r21*z + r31;
              rotated_vertices(l,2) = r02*x + r12*y + r22*z + r32;
            }
          else cimg_forX(bbox_vertices,l) {
              const float x = bbox_vertices(l,0), y = bbox_vertices(l,1), z = bbox_vertices(l,2);
              rotated_bbox_vertices(l,0) = r00*x + r10*y + r20*z + r30;
              rotated_bbox_vertices(l,1) = r01*x + r11*y + r21*z + r31;
              rotated_bbox_vertices(l,2) = r02*x + r12*y + r22*z + r32;
            }

          // Draw objects
          const bool render_with_zbuffer = !clicked && nrender_static>0;
          visu = visu0;
          if ((clicked && nrender_motion<0) || (!clicked && nrender_static<0))
            visu.draw_object3d(Xoff + visu._width/2.0f,Yoff + visu._height/2.0f,Zoff,
                               rotated_bbox_vertices,bbox_primitives,bbox_colors,bbox_opacities,2,false,focale).
              draw_object3d(Xoff + visu._width/2.0f,Yoff + visu._height/2.0f,Zoff,
                            rotated_bbox_vertices,bbox_primitives,bbox_colors2,1,false,focale);
          else visu._draw_object3d((void*)0,render_with_zbuffer?zbuffer.fill(0):CImg<tpfloat>::empty(),
                                   Xoff + visu._width/2.0f,Yoff + visu._height/2.0f,Zoff,
                                   rotated_vertices,reverse_primitives?reverse_primitives:primitives,
                                   colors,opacities,clicked?nrender_motion:nrender_static,_is_double_sided==1,focale,
                                   width()/2.0f + light_x,height()/2.0f + light_y,light_z + Zoff,
                                   specular_lightness,specular_shininess,sprite_scale);
          // Draw axes
          if (ndisplay_axes) {
            const float
              n = 1e-8f + cimg::hypot(r00,r01,r02),
              _r00 = r00/n, _r10 = r10/n, _r20 = r20/n,
              _r01 = r01/n, _r11 = r11/n, _r21 = r21/n,
              _r02 = r01/n, _r12 = r12/n, _r22 = r22/n,
              Xaxes = 25, Yaxes = visu._height - 38.0f;
            cimg_forX(axes_vertices,l) {
              const float
                x = axes_vertices(l,0),
                y = axes_vertices(l,1),
                z = axes_vertices(l,2);
              rotated_axes_vertices(l,0) = _r00*x + _r10*y + _r20*z;
              rotated_axes_vertices(l,1) = _r01*x + _r11*y + _r21*z;
              rotated_axes_vertices(l,2) = _r02*x + _r12*y + _r22*z;
            }
            axes_opacities(0,0) = (rotated_axes_vertices(1,2)>0)?0.5f:1.0f;
            axes_opacities(1,0) = (rotated_axes_vertices(2,2)>0)?0.5f:1.0f;
            axes_opacities(2,0) = (rotated_axes_vertices(3,2)>0)?0.5f:1.0f;
            visu.draw_object3d(Xaxes,Yaxes,0,rotated_axes_vertices,axes_primitives,
                               axes_colors,axes_opacities,1,false,focale).
              draw_text((int)(Xaxes + rotated_axes_vertices(4,0)),
                        (int)(Yaxes + rotated_axes_vertices(4,1)),
                        "X",axes_colors[0]._data,0,axes_opacities(0,0),13).
              draw_text((int)(Xaxes + rotated_axes_vertices(5,0)),
                        (int)(Yaxes + rotated_axes_vertices(5,1)),
                        "Y",axes_colors[1]._data,0,axes_opacities(1,0),13).
              draw_text((int)(Xaxes + rotated_axes_vertices(6,0)),
                        (int)(Yaxes + rotated_axes_vertices(6,1)),
                        "Z",axes_colors[2]._data,0,axes_opacities(2,0),13);
          }
          visu.display(disp);
          if (!clicked || nrender_motion==nrender_static) redraw = false;
        }

        // Handle user interaction
        disp.wait();
        if ((disp.button() || disp.wheel()) && disp.mouse_x()>=0 && disp.mouse_y()>=0) {
          redraw = true;
          if (!clicked) { x0 = x1 = disp.mouse_x(); y0 = y1 = disp.mouse_y(); if (!disp.wheel()) clicked = true; }
          else { x1 = disp.mouse_x(); y1 = disp.mouse_y(); }
          if (disp.button()&1) {
            const float
              R = 0.45f*std::min(disp.width(),disp.height()),
              R2 = R*R,
              u0 = (float)(x0 - disp.width()/2),
              v0 = (float)(y0 - disp.height()/2),
              u1 = (float)(x1 - disp.width()/2),
              v1 = (float)(y1 - disp.height()/2),
              n0 = cimg::hypot(u0,v0),
              n1 = cimg::hypot(u1,v1),
              nu0 = n0>R?(u0*R/n0):u0,
              nv0 = n0>R?(v0*R/n0):v0,
              nw0 = (float)std::sqrt(std::max(0.0f,R2 - nu0*nu0 - nv0*nv0)),
              nu1 = n1>R?(u1*R/n1):u1,
              nv1 = n1>R?(v1*R/n1):v1,
              nw1 = (float)std::sqrt(std::max(0.0f,R2 - nu1*nu1 - nv1*nv1)),
              u = nv0*nw1 - nw0*nv1,
              v = nw0*nu1 - nu0*nw1,
              w = nv0*nu1 - nu0*nv1,
              n = cimg::hypot(u,v,w),
              alpha = (float)std::asin(n/R2)*180/cimg::PI;
            (CImg<floatT>::rotation_matrix(u,v,w,-alpha)*pose).move_to(pose);
            x0 = x1; y0 = y1;
          }
          if (disp.button()&2) {
            if (focale>0) Zoff-=(y0 - y1)*focale/400;
            else { const float s = std::exp((y0 - y1)/400.0f); pose*=s; sprite_scale*=s; }
            x0 = x1; y0 = y1;
          }
          if (disp.wheel()) {
            if (focale>0) Zoff-=disp.wheel()*focale/20;
            else { const float s = std::exp(disp.wheel()/20.0f); pose*=s; sprite_scale*=s; }
            disp.set_wheel();
          }
          if (disp.button()&4) { Xoff+=(x1 - x0); Yoff+=(y1 - y0); x0 = x1; y0 = y1; }
          if ((disp.button()&1) && (disp.button()&2)) {
            init_pose = true; disp.set_button(); x0 = x1; y0 = y1;
            pose = CImg<floatT>(4,3,1,1, 1,0,0,0, 0,1,0,0, 0,0,1,0);
          }
        } else if (clicked) { x0 = x1; y0 = y1; clicked = false; redraw = true; }

        CImg<charT> filename(32);
        switch (key = disp.key()) {
#if cimg_OS!=2
        case cimg::keyCTRLRIGHT :
#endif
        case 0 : case cimg::keyCTRLLEFT : key = 0; break;
        case cimg::keyD: if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
            disp.set_fullscreen(false).
              resize(CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,false),
                     CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,true),false).
              _is_resized = true;
            disp.set_key(key,false); key = 0;
          } break;
        case cimg::keyC : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
            disp.set_fullscreen(false).
              resize(cimg_fitscreen(2*disp.width()/3,2*disp.height()/3,1),false)._is_resized = true;
            disp.set_key(key,false); key = 0;
          } break;
        case cimg::keyR : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
            disp.set_fullscreen(false).resize(cimg_fitscreen(_width,_height,_depth),false)._is_resized = true;
            disp.set_key(key,false); key = 0;
          } break;
        case cimg::keyF : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
            if (!ns_width || !ns_height ||
                ns_width>(unsigned int)disp.screen_width() || ns_height>(unsigned int)disp.screen_height()) {
              ns_width = disp.screen_width()*3U/4;
              ns_height = disp.screen_height()*3U/4;
            }
            if (disp.is_fullscreen()) disp.resize(ns_width,ns_height,false);
            else {
              ns_width = disp._width; ns_height = disp._height;
              disp.resize(disp.screen_width(),disp.screen_height(),false);
            }
            disp.toggle_fullscreen()._is_resized = true;
            disp.set_key(key,false); key = 0;
          } break;
        case cimg::keyT : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
            // Switch single/double-sided primitives.
            if (--_is_double_sided==-2) _is_double_sided = 1;
            if (_is_double_sided>=0) reverse_primitives.assign();
            else primitives.get_reverse_object3d().move_to(reverse_primitives);
            disp.set_key(key,false); key = 0; redraw = true;
          } break;
        case cimg::keyZ : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Enable/disable Z-buffer
            if (zbuffer) zbuffer.assign();
            else zbuffer.assign(visu0.width(),visu0.height(),1,1,0);
            disp.set_key(key,false); key = 0; redraw = true;
          } break;
        case cimg::keyA : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Show/hide 3d axes.
            ndisplay_axes = !ndisplay_axes;
            disp.set_key(key,false); key = 0; redraw = true;
          } break;
        case cimg::keyF1 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to points.
            nrender_motion = (nrender_static==0 && nrender_motion!=0)?0:-1; nrender_static = 0;
            disp.set_key(key,false); key = 0; redraw = true;
          } break;
        case cimg::keyF2 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to lines.
            nrender_motion = (nrender_static==1 && nrender_motion!=1)?1:-1; nrender_static = 1;
            disp.set_key(key,false); key = 0; redraw = true;
          } break;
        case cimg::keyF3 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to flat.
            nrender_motion = (nrender_static==2 && nrender_motion!=2)?2:-1; nrender_static = 2;
            disp.set_key(key,false); key = 0; redraw = true;
          } break;
        case cimg::keyF4 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to flat-shaded.
            nrender_motion = (nrender_static==3 && nrender_motion!=3)?3:-1; nrender_static = 3;
            disp.set_key(key,false); key = 0; redraw = true;
          } break;
        case cimg::keyF5 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
            // Set rendering mode to gouraud-shaded.
            nrender_motion = (nrender_static==4 && nrender_motion!=4)?4:-1; nrender_static = 4;
            disp.set_key(key,false); key = 0; redraw = true;
          } break;
        case cimg::keyF6 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to phong-shaded.
            nrender_motion = (nrender_static==5 && nrender_motion!=5)?5:-1; nrender_static = 5;
            disp.set_key(key,false); key = 0; redraw = true;
          } break;
        case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save snapshot
            static unsigned int snap_number = 0;
            std::FILE *file;
            do {
              cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.bmp",snap_number++);
              if ((file=std_fopen(filename,"r"))!=0) cimg::fclose(file);
            } while (file);
            (+visu).draw_text(0,0," Saving snapshot... ",
                              foreground_color._data,background_color._data,0.7f,13).display(disp);
            visu.save(filename);
            (+visu).draw_text(0,0," Snapshot '%s' saved. ",
                              foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp);
            disp.set_key(key,false); key = 0;
          } break;
        case cimg::keyG : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .off file
            static unsigned int snap_number = 0;
            std::FILE *file;
            do {
              cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.off",snap_number++);
              if ((file=std_fopen(filename,"r"))!=0) cimg::fclose(file);
            } while (file);
            (+visu).draw_text(0,0," Saving object... ",
                              foreground_color._data,background_color._data,0.7f,13).display(disp);
            vertices.save_off(reverse_primitives?reverse_primitives:primitives,colors,filename);
            (+visu).draw_text(0,0," Object '%s' saved. ",
                              foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp);
            disp.set_key(key,false); key = 0;
          } break;
        case cimg::keyO : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .cimg file
            static unsigned int snap_number = 0;
            std::FILE *file;
            do {
#ifdef cimg_use_zlib
              cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimgz",snap_number++);
#else
              cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimg",snap_number++);
#endif
              if ((file=std_fopen(filename,"r"))!=0) cimg::fclose(file);
            } while (file);
            (+visu).draw_text(0,0," Saving object... ",
                              foreground_color._data,background_color._data,0.7f,13).display(disp);
            vertices.get_object3dtoCImg3d(reverse_primitives?reverse_primitives:primitives,colors,opacities).
              save(filename);
            (+visu).draw_text(0,0," Object '%s' saved. ",
                              foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp);
            disp.set_key(key,false); key = 0;
          } break;
#ifdef cimg_use_board
        case cimg::keyP : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .EPS file
            static unsigned int snap_number = 0;
            std::FILE *file;
            do {
              cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.eps",snap_number++);
              if ((file=std_fopen(filename,"r"))!=0) cimg::fclose(file);
            } while (file);
            (+visu).draw_text(0,0," Saving EPS snapshot... ",
                              foreground_color._data,background_color._data,0.7f,13).display(disp);
            LibBoard::Board board;
            (+visu)._draw_object3d(&board,zbuffer.fill(0),
                                   Xoff + visu._width/2.0f,Yoff + visu._height/2.0f,Zoff,
                                   rotated_vertices,reverse_primitives?reverse_primitives:primitives,
                                   colors,opacities,clicked?nrender_motion:nrender_static,
                                   _is_double_sided==1,focale,
                                   visu.width()/2.0f + light_x,visu.height()/2.0f + light_y,light_z + Zoff,
                                   specular_lightness,specular_shininess,
                                   sprite_scale);
            board.saveEPS(filename);
            (+visu).draw_text(0,0," Object '%s' saved. ",
                              foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp);
            disp.set_key(key,false); key = 0;
          } break;
        case cimg::keyV : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .SVG file
            static unsigned int snap_number = 0;
            std::FILE *file;
            do {
              cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.svg",snap_number++);
              if ((file=std_fopen(filename,"r"))!=0) cimg::fclose(file);
            } while (file);
            (+visu).draw_text(0,0," Saving SVG snapshot... ",
                              foreground_color._data,background_color._data,0.7f,13).display(disp);
            LibBoard::Board board;
            (+visu)._draw_object3d(&board,zbuffer.fill(0),
                                   Xoff + visu._width/2.0f,Yoff + visu._height/2.0f,Zoff,
                                   rotated_vertices,reverse_primitives?reverse_primitives:primitives,
                                   colors,opacities,clicked?nrender_motion:nrender_static,
                                   _is_double_sided==1,focale,
                                   visu.width()/2.0f + light_x,visu.height()/2.0f + light_y,light_z + Zoff,
                                   specular_lightness,specular_shininess,
                                   sprite_scale);
            board.saveSVG(filename);
            (+visu).draw_text(0,0," Object '%s' saved. ",
                              foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp);
            disp.set_key(key,false); key = 0;
          } break;
#endif
        }
        if (disp.is_resized()) {
          disp.resize(false); visu0 = get_resize(disp,1);
          if (zbuffer) zbuffer.assign(disp.width(),disp.height());
          redraw = true;
        }
        if (!exit_on_anykey && key && key!=cimg::keyESC &&
            (key!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) {
          key = 0;
        }
      }
      if (pose_matrix) {
        std::memcpy(pose_matrix,pose._data,12*sizeof(float));
        pose_matrix[12] = Xoff; pose_matrix[13] = Yoff; pose_matrix[14] = Zoff; pose_matrix[15] = sprite_scale;
      }
      disp.set_button().set_key(key);
      return *this;

Project: CImg
File: CImg.h

    **/
    inline cimg_int64 fsize(const char *const filename) {
      std::FILE *const file = std::fopen(filename,"rb");
      if (!file) return (cimg_int64)-1;
      std::fseek(file,0,SEEK_END);
      const cimg_int64 siz = (cimg_int64)std::ftell(file);
      std::fclose(file);
      return siz;

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()>=32768))
      cimg_rof(*this,ptrd,T) *ptrd = (T)((ulongT)*ptrd | (ulongT)value);
      return *this;

Project: CImg
File: CImg.h


      static double mp_permutations(_cimg_math_parser& mp) {
        return cimg::permutations(_mp_arg(2),_mp_arg(3),(bool)_mp_arg(4));

Project: CImg
File: CImg.h

    template<typename T>
    inline T round(const T& x, const double y, const int rounding_type=0) {
      if (y<=0) return x;
      if (y==1) switch (rounding_type) {
        case 0 : return round(x);
        case 1 : return (T)std::ceil((_cimg_Tfloat)x);
        default : return (T)std::floor((_cimg_Tfloat)x);
        }
      const double sx = (double)x/y, floor = std::floor(sx), delta =  sx - floor;
      return (T)(y*(rounding_type<0?floor:rounding_type>0?std::ceil(sx):delta<0.5?floor:std::ceil(sx)));

Project: CImg
File: CImg.h

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

      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);
      const ulongT whd = (ulongT)_width*_height*_depth;
      cimg_pragma_openmp(parallel for cimg_openmp_if(whd>=256))
      for (ulongT N = 0; N<whd; ++N) {
        Tfloat
          H = cimg::mod((Tfloat)p1[N],(Tfloat)360),
          S = (Tfloat)p2[N],
          I = (Tfloat)p3[N],
          a = I*(1 - S),
          R = 0, G = 0, B = 0;
        if (H<120) {
          B = a;
          R = (Tfloat)(I*(1 + S*std::cos(H*cimg::PI/180)/std::cos((60 - H)*cimg::PI/180)));
          G = 3*I - (R + B);
        } else if (H<240) {
          H-=120;
          R = a;
          G = (Tfloat)(I*(1 + S*std::cos(H*cimg::PI/180)/std::cos((60 - H)*cimg::PI/180)));
          B = 3*I - (R + G);
        } else {
          H-=240;
          G = a;
          B = (Tfloat)(I*(1 + S*std::cos(H*cimg::PI/180)/std::cos((60 - H)*cimg::PI/180)));
          R = 3*I - (G + B);
        }
        p1[N] = (T)cimg::cut(R*255,0,255);
        p2[N] = (T)cimg::cut(G*255,0,255);
        p3[N] = (T)cimg::cut(B*255,0,255);
      }
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

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

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

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& correlate(const CImg<t>& kernel, const bool boundary_conditions=true,
                       const bool is_normalized=false) {
      if (is_empty() || !kernel) return *this;
      return get_correlate(kernel,boundary_conditions,is_normalized).move_to(*this);

Project: CImg
File: CImg.h


      static double mp_find_seq(_cimg_math_parser& mp) {
        const bool is_forward = (bool)_mp_arg(6);
        const ulongT
          siz1 = (ulongT)mp.opcode[3],
          siz2 = (ulongT)mp.opcode[5];
        longT ind = (longT)(mp.opcode[7]!=_cimg_mp_slot_nan?_mp_arg(7):is_forward?0:siz1 - 1);
        if (ind<0 || ind>=(longT)siz1) return -1.;
        const double
          *const ptr1b = &_mp_arg(2) + 1,
          *const ptr1e = ptr1b + siz1,
          *const ptr2b = &_mp_arg(4) + 1,
          *const ptr2e = ptr2b + siz2,
          *ptr1 = ptr1b + ind,
          *p1 = 0,
          *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

    //! Shift 3d object's vertices \newinstance.
    CImg<Tfloat> get_shift_object3d(const float tx, const float ty=0, const float tz=0) const {
      return CImg<Tfloat>(*this,false).shift_object3d(tx,ty,tz);

Project: CImg
File: CImg.h

      return *ptr_max;
    }

    //! Return a reference to the maximum pixel value of the instance list \const.
    const T& max() const {
      if (is_empty())
        throw CImgInstanceException(_cimglist_instance
                                    "max(): Empty instance.",
                                    cimglist_instance);
      const T *ptr_max = _data->_data;
      T max_value = *ptr_max;
      cimglist_for(*this,l) {
        const CImg<T>& img = _data[l];

Project: CImg
File: CImg.h

    template<typename tf>
    static CImg<floatT> sphere3d(CImgList<tf>& primitives,
                                 const float radius=50, const unsigned int subdivisions=3) {

      // Create initial icosahedron
      primitives.assign();
      const double tmp = (1 + std::sqrt(5.0f))/2, a = 1.0/std::sqrt(1 + tmp*tmp), b = tmp*a;
      CImgList<floatT> vertices(12,1,3,1,1, b,a,0.0, -b,a,0.0, -b,-a,0.0, b,-a,0.0, a,0.0,b, a,0.0,-b,
                                -a,0.0,-b, -a,0.0,b, 0.0,b,a, 0.0,-b,a, 0.0,-b,-a, 0.0,b,-a);
      primitives.assign(20,1,3,1,1, 4,8,7, 4,7,9, 5,6,11, 5,10,6, 0,4,3, 0,3,5, 2,7,1, 2,1,6,
                        8,0,11, 8,11,1, 9,10,3, 9,2,10, 8,4,0, 11,0,5, 4,9,3,
                        5,3,10, 7,8,1, 6,1,11, 7,2,9, 6,10,2);
      // edge - length/2
      float he = (float)a;

      // Recurse subdivisions
      for (unsigned int i = 0; i<subdivisions; ++i) {
        const unsigned int L = primitives._width;
	he/=2;
	const float he2 = he*he;
        for (unsigned int l = 0; l<L; ++l) {
          const unsigned int
            p0 = (unsigned int)primitives(0,0), p1 = (unsigned int)primitives(0,1), p2 = (unsigned int)primitives(0,2);
          const float
            x0 = vertices(p0,0), y0 = vertices(p0,1), z0 = vertices(p0,2),
            x1 = vertices(p1,0), y1 = vertices(p1,1), z1 = vertices(p1,2),
            x2 = vertices(p2,0), y2 = vertices(p2,1), z2 = vertices(p2,2),
            tnx0 = (x0 + x1)/2, tny0 = (y0 + y1)/2, tnz0 = (z0 + z1)/2,
            nn0 = cimg::hypot(tnx0,tny0,tnz0),
            tnx1 = (x0 + x2)/2, tny1 = (y0 + y2)/2, tnz1 = (z0 + z2)/2,
            nn1 = cimg::hypot(tnx1,tny1,tnz1),
            tnx2 = (x1 + x2)/2, tny2 = (y1 + y2)/2, tnz2 = (z1 + z2)/2,
            nn2 = cimg::hypot(tnx2,tny2,tnz2),
            nx0 = tnx0/nn0, ny0 = tny0/nn0, nz0 = tnz0/nn0,
            nx1 = tnx1/nn1, ny1 = tny1/nn1, nz1 = tnz1/nn1,
            nx2 = tnx2/nn2, ny2 = tny2/nn2, nz2 = tnz2/nn2;
          int i0 = -1, i1 = -1, i2 = -1;
          cimglist_for(vertices,p) {
            const float x = (float)vertices(p,0), y = (float)vertices(p,1), z = (float)vertices(p,2);
            if (cimg::sqr(x-nx0) + cimg::sqr(y-ny0) + cimg::sqr(z-nz0)<he2) i0 = p;
            if (cimg::sqr(x-nx1) + cimg::sqr(y-ny1) + cimg::sqr(z-nz1)<he2) i1 = p;
            if (cimg::sqr(x-nx2) + cimg::sqr(y-ny2) + cimg::sqr(z-nz2)<he2) i2 = p;
          }
          if (i0<0) { CImg<floatT>::vector(nx0,ny0,nz0).move_to(vertices); i0 = vertices.width() - 1; }
          if (i1<0) { CImg<floatT>::vector(nx1,ny1,nz1).move_to(vertices); i1 = vertices.width() - 1; }
          if (i2<0) { CImg<floatT>::vector(nx2,ny2,nz2).move_to(vertices); i2 = vertices.width() - 1; }
          primitives.remove(0);
          CImg<tf>::vector(p0,i0,i1).move_to(primitives);
          CImg<tf>::vector((tf)i0,(tf)p1,(tf)i2).move_to(primitives);
          CImg<tf>::vector((tf)i1,(tf)i2,(tf)p2).move_to(primitives);
          CImg<tf>::vector((tf)i1,(tf)i0,(tf)i2).move_to(primitives);
        }
      }
      return (vertices>'x')*=radius;

Project: CImg
File: CImg.h

    **/
    CImg<T>& diffusion_tensors(const float sharpness=0.7f, const float anisotropy=0.6f,
                               const float alpha=0.6f, const float sigma=1.1f, const bool is_sqrt=false) {
      CImg<Tfloat> res;
      const float
        nsharpness = std::max(sharpness,1e-5f),
        power1 = (is_sqrt?0.5f:1)*nsharpness,
        power2 = power1/(1e-7f + 1 - anisotropy);
      blur(alpha).normalize(0,(T)255);

      if (_depth>1) { // 3d
        get_structure_tensors().move_to(res).blur(sigma);
        cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if(_width>=256 && _height*_depth>=256))
        cimg_forYZ(*this,y,z) {
          Tfloat
            *ptrd0 = res.data(0,y,z,0), *ptrd1 = res.data(0,y,z,1), *ptrd2 = res.data(0,y,z,2),
            *ptrd3 = res.data(0,y,z,3), *ptrd4 = res.data(0,y,z,4), *ptrd5 = res.data(0,y,z,5);
          CImg<floatT> val(3), vec(3,3);
          cimg_forX(*this,x) {
            res.get_tensor_at(x,y,z).symmetric_eigen(val,vec);
            const float
              _l1 = val[2], _l2 = val[1], _l3 = val[0],
              l1 = _l1>0?_l1:0, l2 = _l2>0?_l2:0, l3 = _l3>0?_l3:0,
              ux = vec(0,0), uy = vec(0,1), uz = vec(0,2),
              vx = vec(1,0), vy = vec(1,1), vz = vec(1,2),
              wx = vec(2,0), wy = vec(2,1), wz = vec(2,2),
              n1 = (float)std::pow(1 + l1 + l2 + l3,-power1),
              n2 = (float)std::pow(1 + l1 + l2 + l3,-power2);
            *(ptrd0++) = n1*(ux*ux + vx*vx) + n2*wx*wx;
            *(ptrd1++) = n1*(ux*uy + vx*vy) + n2*wx*wy;
            *(ptrd2++) = n1*(ux*uz + vx*vz) + n2*wx*wz;
            *(ptrd3++) = n1*(uy*uy + vy*vy) + n2*wy*wy;
            *(ptrd4++) = n1*(uy*uz + vy*vz) + n2*wy*wz;
            *(ptrd5++) = n1*(uz*uz + vz*vz) + n2*wz*wz;
          }
        }
      } else { // for 2d images
        get_structure_tensors().move_to(res).blur(sigma);
        cimg_pragma_openmp(parallel for cimg_openmp_if(_width>=256 && _height>=256))
        cimg_forY(*this,y) {
          Tfloat *ptrd0 = res.data(0,y,0,0), *ptrd1 = res.data(0,y,0,1), *ptrd2 = res.data(0,y,0,2);
          CImg<floatT> val(2), vec(2,2);
          cimg_forX(*this,x) {
            res.get_tensor_at(x,y).symmetric_eigen(val,vec);
            const float
              _l1 = val[1], _l2 = val[0],
              l1 = _l1>0?_l1:0, l2 = _l2>0?_l2:0,
              ux = vec(1,0), uy = vec(1,1),
              vx = vec(0,0), vy = vec(0,1),
              n1 = (float)std::pow(1 + l1 + l2,-power1),
              n2 = (float)std::pow(1 + l1 + l2,-power2);
            *(ptrd0++) = n1*ux*ux + n2*vx*vx;
            *(ptrd1++) = n1*ux*uy + n2*vx*vy;
            *(ptrd2++) = n1*uy*uy + n2*vy*vy;
          }
        }
      }
      return res.move_to(*this);

Project: CImg
File: CImg.h


      unsigned int scalar2(const mp_func op, const unsigned int arg1, const unsigned int arg2) {
        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:scalar();
        CImg<ulongT>::vector((ulongT)op,pos,arg1,arg2).move_to(code);
        return pos;

Project: CImg
File: CImg.h

    //! Autocrop image region, regarding the specified background color \newinstance.
    template<typename t> CImg<T> get_autocrop(const CImg<t>& color, const char *const axes="zyx") const {
      return get_autocrop(color._data,axes);

Project: CImg
File: CImg.h

    //! Compute the base-10 logarithm of each pixel value \newinstance.
    CImg<Tfloat> get_log2() const {
      return CImg<Tfloat>(*this,false).log2();

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    **/
    CImg<T>& sqr() {
      if (is_empty()) return *this;
      cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=524288))
      cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(val*val); };
      return *this;

Project: CImg
File: CImg.h

    // [internal] Perform box filter with dirichlet boundary conditions.
    CImg<T>& _blur_guided(const unsigned int psize) {
      const int p1 = (int)psize/2, p2 = (int)psize - p1;
      if (_depth!=1) {
        CImg<floatT> cumul = get_cumulate('z'), cumul2 = cumul.get_shift(0,0,p2,0,1);
        (cumul.shift(0,0,-p1,0,1)-=cumul2).move_to(*this);
      }
      if (_height!=1) {
        CImg<floatT> cumul = get_cumulate('y'), cumul2 = cumul.get_shift(0,p2,0,0,1);
        (cumul.shift(0,-p1,0,0,1)-=cumul2).move_to(*this);
      }
      if (_width!=1) {
        CImg<floatT> cumul = get_cumulate('x'), cumul2 = cumul.get_shift(p2,0,0,0,1);
        (cumul.shift(-p1,0,0,0,1)-=cumul2).move_to(*this);
      }
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    template<typename tp, typename tc>
    CImg<T>& draw_spline(const CImg<tp>& points,
                         const tc *const color, const float opacity=1,
                         const bool is_closed_set=false, const float precision=4,
                         const unsigned int pattern=~0U, const bool init_hatch=true) {
      if (is_empty() || !points || points._width<2) return *this;
      CImg<Tfloat> tangents;
      switch (points._height) {
      case 0 : case 1 :
        throw CImgArgumentException(_cimg_instance
                                    "draw_spline(): Invalid specified point set (%u,%u,%u,%u,%p).",
                                    cimg_instance,
                                    points._width,points._height,points._depth,points._spectrum,points._data);
      case 2 : {
        tangents.assign(points._width,points._height);
        cimg_forX(points,p) {
          const unsigned int
            p0 = is_closed_set?(p + points._width - 1)%points._width:(p?p - 1:0),
            p1 = is_closed_set?(p + 1)%points._width:(p + 1<points._width?p + 1:p);
          const float
            x = (float)points(p,0),
            y = (float)points(p,1),
            x0 = (float)points(p0,0),
            y0 = (float)points(p0,1),
            x1 = (float)points(p1,0),
            y1 = (float)points(p1,1),
            u0 = x - x0,
            v0 = y - y0,
            n0 = 1e-8f + cimg::hypot(u0,v0),
            u1 = x1 - x,
            v1 = y1 - y,
            n1 = 1e-8f + cimg::hypot(u1,v1),
            u = u0/n0 + u1/n1,
            v = v0/n0 + v1/n1,
            n = 1e-8f + cimg::hypot(u,v),
            fact = 0.5f*(n0 + n1);
          tangents(p,0) = (Tfloat)(fact*u/n);
          tangents(p,1) = (Tfloat)(fact*v/n);
        }
      } break;
      default : {
        tangents.assign(points._width,points._height);
        cimg_forX(points,p) {
          const unsigned int
            p0 = is_closed_set?(p + points._width - 1)%points._width:(p?p - 1:0),
            p1 = is_closed_set?(p + 1)%points._width:(p + 1<points._width?p + 1:p);
          const float
            x = (float)points(p,0),
            y = (float)points(p,1),
            z = (float)points(p,2),
            x0 = (float)points(p0,0),
            y0 = (float)points(p0,1),
            z0 = (float)points(p0,2),
            x1 = (float)points(p1,0),
            y1 = (float)points(p1,1),
            z1 = (float)points(p1,2),
            u0 = x - x0,
            v0 = y - y0,
            w0 = z - z0,
            n0 = 1e-8f + cimg::hypot(u0,v0,w0),
            u1 = x1 - x,
            v1 = y1 - y,
            w1 = z1 - z,
            n1 = 1e-8f + cimg::hypot(u1,v1,w1),
            u = u0/n0 + u1/n1,
            v = v0/n0 + v1/n1,
            w = w0/n0 + w1/n1,
            n = 1e-8f + cimg::hypot(u,v,w),
            fact = 0.5f*(n0 + n1);
          tangents(p,0) = (Tfloat)(fact*u/n);
          tangents(p,1) = (Tfloat)(fact*v/n);
          tangents(p,2) = (Tfloat)(fact*w/n);
        }
      }
      }
      return draw_spline(points,tangents,color,opacity,is_closed_set,precision,pattern,init_hatch);

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

Project: CImg
File: CImg.h

    **/
    const CImg<T>& save(const char *const filename, const int number=-1, const unsigned int digits=6) const {
      if (!filename)
        throw CImgArgumentException(_cimg_instance
                                    "save(): Specified filename is (null).",
                                    cimg_instance);
      // Do not test for empty instances, since .cimg format is able to manage empty instances.
      const bool is_stdout = *filename=='-' && (!filename[1] || filename[1]=='.');
      const char *const ext = cimg::split_filename(filename);
      CImg<charT> nfilename(1024);
      const char *const fn = is_stdout?filename:(number>=0)?cimg::number_filename(filename,number,digits,nfilename):
        filename;

#ifdef cimg_save_plugin
      cimg_save_plugin(fn);
#endif
#ifdef cimg_save_plugin1
      cimg_save_plugin1(fn);
#endif
#ifdef cimg_save_plugin2
      cimg_save_plugin2(fn);
#endif
#ifdef cimg_save_plugin3
      cimg_save_plugin3(fn);
#endif
#ifdef cimg_save_plugin4
      cimg_save_plugin4(fn);
#endif
#ifdef cimg_save_plugin5
      cimg_save_plugin5(fn);
#endif
#ifdef cimg_save_plugin6
      cimg_save_plugin6(fn);
#endif
#ifdef cimg_save_plugin7
      cimg_save_plugin7(fn);
#endif
#ifdef cimg_save_plugin8
      cimg_save_plugin8(fn);
#endif
      // Ascii formats
      if (!cimg::strcasecmp(ext,"asc")) return save_ascii(fn);
      else if (!cimg::strcasecmp(ext,"dlm") ||
               !cimg::strcasecmp(ext,"txt")) return save_dlm(fn);
      else if (!cimg::strcasecmp(ext,"cpp") ||
               !cimg::strcasecmp(ext,"hpp") ||
               !cimg::strcasecmp(ext,"h") ||
               !cimg::strcasecmp(ext,"c")) return save_cpp(fn);

      // 2d binary formats
      else if (!cimg::strcasecmp(ext,"bmp")) return save_bmp(fn);
      else if (!cimg::strcasecmp(ext,"jpg") ||
               !cimg::strcasecmp(ext,"jpeg") ||
               !cimg::strcasecmp(ext,"jpe") ||
               !cimg::strcasecmp(ext,"jfif") ||
               !cimg::strcasecmp(ext,"jif")) return save_jpeg(fn);
      else if (!cimg::strcasecmp(ext,"rgb")) return save_rgb(fn);
      else if (!cimg::strcasecmp(ext,"rgba")) return save_rgba(fn);
      else if (!cimg::strcasecmp(ext,"png")) return save_png(fn);
      else if (!cimg::strcasecmp(ext,"pgm") ||
               !cimg::strcasecmp(ext,"ppm") ||
               !cimg::strcasecmp(ext,"pnm")) return save_pnm(fn);
      else if (!cimg::strcasecmp(ext,"pnk")) return save_pnk(fn);
      else if (!cimg::strcasecmp(ext,"pfm")) return save_pfm(fn);
      else if (!cimg::strcasecmp(ext,"exr")) return save_exr(fn);
      else if (!cimg::strcasecmp(ext,"tif") ||
               !cimg::strcasecmp(ext,"tiff")) return save_tiff(fn);

      // 3d binary formats
      else if (!cimg::strcasecmp(ext,"cimgz")) return save_cimg(fn,true);
      else if (!cimg::strcasecmp(ext,"cimg") || !*ext) return save_cimg(fn,false);
      else if (!cimg::strcasecmp(ext,"dcm")) return save_medcon_external(fn);
      else if (!cimg::strcasecmp(ext,"hdr") ||
               !cimg::strcasecmp(ext,"nii")) return save_analyze(fn);
      else if (!cimg::strcasecmp(ext,"inr")) return save_inr(fn);
      else if (!cimg::strcasecmp(ext,"mnc")) return save_minc2(fn);
      else if (!cimg::strcasecmp(ext,"pan")) return save_pandore(fn);
      else if (!cimg::strcasecmp(ext,"raw")) return save_raw(fn);

      // Archive files
      else if (!cimg::strcasecmp(ext,"gz")) return save_gzip_external(fn);

      // Image sequences
      else if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(fn,444,true);
      else if (!cimg::strcasecmp(ext,"avi") ||
               !cimg::strcasecmp(ext,"mov") ||
               !cimg::strcasecmp(ext,"asf") ||
               !cimg::strcasecmp(ext,"divx") ||
               !cimg::strcasecmp(ext,"flv") ||
               !cimg::strcasecmp(ext,"mpg") ||
               !cimg::strcasecmp(ext,"m1v") ||
               !cimg::strcasecmp(ext,"m2v") ||
               !cimg::strcasecmp(ext,"m4v") ||
               !cimg::strcasecmp(ext,"mjp") ||
               !cimg::strcasecmp(ext,"mp4") ||
               !cimg::strcasecmp(ext,"mkv") ||
               !cimg::strcasecmp(ext,"mpe") ||
               !cimg::strcasecmp(ext,"movie") ||
               !cimg::strcasecmp(ext,"ogm") ||
               !cimg::strcasecmp(ext,"ogg") ||
               !cimg::strcasecmp(ext,"ogv") ||
               !cimg::strcasecmp(ext,"qt") ||
               !cimg::strcasecmp(ext,"rm") ||
               !cimg::strcasecmp(ext,"vob") ||
               !cimg::strcasecmp(ext,"wmv") ||
               !cimg::strcasecmp(ext,"xvid") ||
               !cimg::strcasecmp(ext,"mpeg")) return save_video(fn);
      return save_other(fn);

Project: CImg
File: CImg.h


      static double mp_Ixyz(_cimg_math_parser& mp) {
        double *ptrd = &_mp_arg(1) + 1;
        const unsigned int
          interpolation = (unsigned int)_mp_arg(5),
          boundary_conditions = (unsigned int)_mp_arg(6),
          vsiz = (unsigned int)mp.opcode[7];
        const CImg<T> &img = mp.imgin;
        const double x = _mp_arg(2), y = _mp_arg(3), z = _mp_arg(4);
        const ulongT whd = (ulongT)img._width*img._height*img._depth;
        const T *ptrs;
        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


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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


    Tfloat _cubic_atXYZ(const float fx, const float fy, const float fz, const int c=0) const {
      const float
        nfx = cimg::cut(fx,0,width() - 1),
        nfy = cimg::cut(fy,0,height() - 1),
        nfz = cimg::cut(fz,0,depth() - 1);
      const int x = (int)nfx, y = (int)nfy, z = (int)nfz;
      const float dx = nfx - x, dy = nfy - y, dz = nfz - z;
      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,
        pz = z - 1<0?0:z - 1, nz = dz>0?z + 1:z, az = z + 2>=depth()?depth() - 1:z + 2;
      const Tfloat
        Ippp = (Tfloat)(*this)(px,py,pz,c), Icpp = (Tfloat)(*this)(x,py,pz,c),
        Inpp = (Tfloat)(*this)(nx,py,pz,c), Iapp = (Tfloat)(*this)(ax,py,pz,c),
        Ipp = Icpp + 0.5f*(dx*(-Ippp + Inpp) + dx*dx*(2*Ippp - 5*Icpp + 4*Inpp - Iapp) +
                           dx*dx*dx*(-Ippp + 3*Icpp - 3*Inpp + Iapp)),
        Ipcp = (Tfloat)(*this)(px,y,pz,c),  Iccp = (Tfloat)(*this)(x, y,pz,c),
        Incp = (Tfloat)(*this)(nx,y,pz,c),  Iacp = (Tfloat)(*this)(ax,y,pz,c),
        Icp = Iccp + 0.5f*(dx*(-Ipcp + Incp) + dx*dx*(2*Ipcp - 5*Iccp + 4*Incp - Iacp) +
                           dx*dx*dx*(-Ipcp + 3*Iccp - 3*Incp + Iacp)),
        Ipnp = (Tfloat)(*this)(px,ny,pz,c), Icnp = (Tfloat)(*this)(x,ny,pz,c),
        Innp = (Tfloat)(*this)(nx,ny,pz,c), Ianp = (Tfloat)(*this)(ax,ny,pz,c),
        Inp = Icnp + 0.5f*(dx*(-Ipnp + Innp) + dx*dx*(2*Ipnp - 5*Icnp + 4*Innp - Ianp) +
                           dx*dx*dx*(-Ipnp + 3*Icnp - 3*Innp + Ianp)),
        Ipap = (Tfloat)(*this)(px,ay,pz,c), Icap = (Tfloat)(*this)(x,ay,pz,c),
        Inap = (Tfloat)(*this)(nx,ay,pz,c), Iaap = (Tfloat)(*this)(ax,ay,pz,c),
        Iap = Icap + 0.5f*(dx*(-Ipap + Inap) + dx*dx*(2*Ipap - 5*Icap + 4*Inap - Iaap) +
                           dx*dx*dx*(-Ipap + 3*Icap - 3*Inap + Iaap)),
        Ip = Icp + 0.5f*(dy*(-Ipp + Inp) + dy*dy*(2*Ipp - 5*Icp + 4*Inp - Iap) +
                         dy*dy*dy*(-Ipp + 3*Icp - 3*Inp + Iap)),
        Ippc = (Tfloat)(*this)(px,py,z,c), Icpc = (Tfloat)(*this)(x,py,z,c),
        Inpc = (Tfloat)(*this)(nx,py,z,c), Iapc = (Tfloat)(*this)(ax,py,z,c),
        Ipc = Icpc + 0.5f*(dx*(-Ippc + Inpc) + dx*dx*(2*Ippc - 5*Icpc + 4*Inpc - Iapc) +
                           dx*dx*dx*(-Ippc + 3*Icpc - 3*Inpc + Iapc)),
        Ipcc = (Tfloat)(*this)(px,y,z,c),  Iccc = (Tfloat)(*this)(x, y,z,c),
        Incc = (Tfloat)(*this)(nx,y,z,c),  Iacc = (Tfloat)(*this)(ax,y,z,c),
        Icc = Iccc + 0.5f*(dx*(-Ipcc + Incc) + dx*dx*(2*Ipcc - 5*Iccc + 4*Incc - Iacc) +
                           dx*dx*dx*(-Ipcc + 3*Iccc - 3*Incc + Iacc)),
        Ipnc = (Tfloat)(*this)(px,ny,z,c), Icnc = (Tfloat)(*this)(x,ny,z,c),
        Innc = (Tfloat)(*this)(nx,ny,z,c), Ianc = (Tfloat)(*this)(ax,ny,z,c),
        Inc = Icnc + 0.5f*(dx*(-Ipnc + Innc) + dx*dx*(2*Ipnc - 5*Icnc + 4*Innc - Ianc) +
                           dx*dx*dx*(-Ipnc + 3*Icnc - 3*Innc + Ianc)),
        Ipac = (Tfloat)(*this)(px,ay,z,c), Icac = (Tfloat)(*this)(x,ay,z,c),
        Inac = (Tfloat)(*this)(nx,ay,z,c), Iaac = (Tfloat)(*this)(ax,ay,z,c),
        Iac = Icac + 0.5f*(dx*(-Ipac + Inac) + dx*dx*(2*Ipac - 5*Icac + 4*Inac - Iaac) +
                           dx*dx*dx*(-Ipac + 3*Icac - 3*Inac + Iaac)),
        Ic = Icc + 0.5f*(dy*(-Ipc + Inc) + dy*dy*(2*Ipc - 5*Icc + 4*Inc - Iac) +
                         dy*dy*dy*(-Ipc + 3*Icc - 3*Inc + Iac)),
        Ippn = (Tfloat)(*this)(px,py,nz,c), Icpn = (Tfloat)(*this)(x,py,nz,c),
        Inpn = (Tfloat)(*this)(nx,py,nz,c), Iapn = (Tfloat)(*this)(ax,py,nz,c),
        Ipn = Icpn + 0.5f*(dx*(-Ippn + Inpn) + dx*dx*(2*Ippn - 5*Icpn + 4*Inpn - Iapn) +
                           dx*dx*dx*(-Ippn + 3*Icpn - 3*Inpn + Iapn)),
        Ipcn = (Tfloat)(*this)(px,y,nz,c),  Iccn = (Tfloat)(*this)(x, y,nz,c),
        Incn = (Tfloat)(*this)(nx,y,nz,c),  Iacn = (Tfloat)(*this)(ax,y,nz,c),
        Icn = Iccn + 0.5f*(dx*(-Ipcn + Incn) + dx*dx*(2*Ipcn - 5*Iccn + 4*Incn - Iacn) +
                           dx*dx*dx*(-Ipcn + 3*Iccn - 3*Incn + Iacn)),
        Ipnn = (Tfloat)(*this)(px,ny,nz,c), Icnn = (Tfloat)(*this)(x,ny,nz,c),
        Innn = (Tfloat)(*this)(nx,ny,nz,c), Iann = (Tfloat)(*this)(ax,ny,nz,c),
        Inn = Icnn + 0.5f*(dx*(-Ipnn + Innn) + dx*dx*(2*Ipnn - 5*Icnn + 4*Innn - Iann) +
                           dx*dx*dx*(-Ipnn + 3*Icnn - 3*Innn + Iann)),
        Ipan = (Tfloat)(*this)(px,ay,nz,c), Ican = (Tfloat)(*this)(x,ay,nz,c),
        Inan = (Tfloat)(*this)(nx,ay,nz,c), Iaan = (Tfloat)(*this)(ax,ay,nz,c),
        Ian = Ican + 0.5f*(dx*(-Ipan + Inan) + dx*dx*(2*Ipan - 5*Ican + 4*Inan - Iaan) +
                           dx*dx*dx*(-Ipan + 3*Ican - 3*Inan + Iaan)),
        In = Icn + 0.5f*(dy*(-Ipn + Inn) + dy*dy*(2*Ipn - 5*Icn + 4*Inn - Ian) +
                         dy*dy*dy*(-Ipn + 3*Icn - 3*Inn + Ian)),
        Ippa = (Tfloat)(*this)(px,py,az,c), Icpa = (Tfloat)(*this)(x,py,az,c),
        Inpa = (Tfloat)(*this)(nx,py,az,c), Iapa = (Tfloat)(*this)(ax,py,az,c),
        Ipa = Icpa + 0.5f*(dx*(-Ippa + Inpa) + dx*dx*(2*Ippa - 5*Icpa + 4*Inpa - Iapa) +
                           dx*dx*dx*(-Ippa + 3*Icpa - 3*Inpa + Iapa)),
        Ipca = (Tfloat)(*this)(px,y,az,c),  Icca = (Tfloat)(*this)(x, y,az,c),
        Inca = (Tfloat)(*this)(nx,y,az,c),  Iaca = (Tfloat)(*this)(ax,y,az,c),
        Ica = Icca + 0.5f*(dx*(-Ipca + Inca) + dx*dx*(2*Ipca - 5*Icca + 4*Inca - Iaca) +
                           dx*dx*dx*(-Ipca + 3*Icca - 3*Inca + Iaca)),
        Ipna = (Tfloat)(*this)(px,ny,az,c), Icna = (Tfloat)(*this)(x,ny,az,c),
        Inna = (Tfloat)(*this)(nx,ny,az,c), Iana = (Tfloat)(*this)(ax,ny,az,c),
        Ina = Icna + 0.5f*(dx*(-Ipna + Inna) + dx*dx*(2*Ipna - 5*Icna + 4*Inna - Iana) +
                           dx*dx*dx*(-Ipna + 3*Icna - 3*Inna + Iana)),
        Ipaa = (Tfloat)(*this)(px,ay,az,c), Icaa = (Tfloat)(*this)(x,ay,az,c),
        Inaa = (Tfloat)(*this)(nx,ay,az,c), Iaaa = (Tfloat)(*this)(ax,ay,az,c),
        Iaa = Icaa + 0.5f*(dx*(-Ipaa + Inaa) + dx*dx*(2*Ipaa - 5*Icaa + 4*Inaa - Iaaa) +
                           dx*dx*dx*(-Ipaa + 3*Icaa - 3*Inaa + Iaaa)),
        Ia = Ica + 0.5f*(dy*(-Ipa + Ina) + dy*dy*(2*Ipa - 5*Ica + 4*Ina - Iaa) +
                         dy*dy*dy*(-Ipa + 3*Ica - 3*Ina + Iaa));
      return Ic + 0.5f*(dz*(-Ip + In) + dz*dz*(2*Ip - 5*Ic + 4*In - Ia) + dz*dz*dz*(-Ip + 3*Ic - 3*In + Ia));

Project: CImg
File: CImg.h


    //! Crop font along the X-axis.
    /**

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 convert binary.
  **/
  inline const char* imagemagick_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
      const char *const pf_path = programfiles_path();
      for (int l = 0; l<2 && !path_found; ++l) {
        const char *const s_exe = l?"convert":"magick";
        cimg_snprintf(s_path,s_path._width,".\\%s.exe",s_exe);
        if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        for (int k = 32; k>=10 && !path_found; --k) {
          cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%.2d-\\%s.exe",pf_path,k,s_exe);
          if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 9; k>=0 && !path_found; --k) {
          cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%d-Q\\%s.exe",pf_path,k,s_exe);
          if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=0 && !path_found; --k) {
          cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%d\\%s.exe",pf_path,k,s_exe);
          if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=10 && !path_found; --k) {
          cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\%s.exe",pf_path,k,s_exe);
          if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 9; k>=0 && !path_found; --k) {
          cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\%s.exe",pf_path,k,s_exe);
          if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=0 && !path_found; --k) {
          cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%d\\VISUA~1\\BIN\\%s.exe",pf_path,k,s_exe);
          if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=10 && !path_found; --k) {
          cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%.2d-\\%s.exe",k,s_exe);
          if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 9; k>=0 && !path_found; --k) {
          cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%d-Q\\%s.exe",k,s_exe);
          if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=0 && !path_found; --k) {
          cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%d\\%s.exe",k,s_exe);
          if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=10 && !path_found; --k) {
          cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\%s.exe",k,s_exe);
          if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 9; k>=0 && !path_found; --k) {
          cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\%s.exe",k,s_exe);
          if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=0 && !path_found; --k) {
          cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%d\\VISUA~1\\BIN\\%s.exe",k,s_exe);
          if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=10 && !path_found; --k) {
          cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%.2d-\\%s.exe",k,s_exe);
          if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 9; k>=0 && !path_found; --k) {
          cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%d-Q\\%s.exe",k,s_exe);
          if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=0 && !path_found; --k) {
          cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%d\\%s.exe",k,s_exe);
          if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=10 && !path_found; --k) {
          cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\%s.exe",k,s_exe);
          if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 9; k>=0 && !path_found; --k) {
          cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\%s.exe",k,s_exe);
          if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=0 && !path_found; --k) {
          cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%d\\VISUA~1\\BIN\\%s.exe",k,s_exe);
          if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) cimg_snprintf(s_path,s_path._width,"%s.exe",s_exe);
      }
#else
      std::strcpy(s_path,"./magick");
      if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
      if (!path_found) {
        std::strcpy(s_path,"./convert");
        if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
      }
      if (!path_found) std::strcpy(s_path,"convert");
#endif
      winformat_string(s_path);

Project: CImg
File: CImg.h

    //! Convert pixel values from xyY pixels to XYZ color spaces.
    CImg<T>& xyYtoXYZ() {
      if (_spectrum!=3)
        throw CImgInstanceException(_cimg_instance
                                    "xyYtoXYZ(): Instance is not a xyY 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>=4096))
      for (ulongT N = 0; N<whd; ++N) {
        const Tfloat
         px = (Tfloat)p1[N],
         py = (Tfloat)p2[N],
         Y = (Tfloat)p3[N],
         ny = py>0?py:1;
        p1[N] = (T)(px*Y/ny);
        p2[N] = (T)Y;
        p3[N] = (T)((1 - px - py)*Y/ny);
      }
      return *this;

Project: CImg
File: CImg.h

    **/
    CImg<T>& load_other(const char *const filename) {
      if (!filename)
        throw CImgArgumentException(_cimg_instance
                                    "load_other(): Specified filename is (null).",
                                    cimg_instance);

      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode(0);
      try { load_magick(filename); }
      catch (CImgException&) {
        try { load_imagemagick_external(filename); }
        catch (CImgException&) {
          try { load_graphicsmagick_external(filename); }
          catch (CImgException&) {
            try { load_cimg(filename); }
            catch (CImgException&) {
              try {
                std::fclose(cimg::fopen(filename,"rb"));
              } catch (CImgException&) {
                cimg::exception_mode(omode);
                throw CImgIOException(_cimg_instance
                                      "load_other(): Failed to open file '%s'.",
                                      cimg_instance,
                                      filename);
              }
              cimg::exception_mode(omode);
              throw CImgIOException(_cimg_instance
                                    "load_other(): Failed to recognize format of file '%s'.",
                                    cimg_instance,
                                    filename);
            }
          }
        }
      }
      cimg::exception_mode(omode);
      return *this;

Project: CImg
File: CImg.h

      return CImgList<T>().load_yuv(file,size_x,size_y,chroma_subsampling,
                                    first_frame,last_frame,step_frame,yuv2rgb);
    }

    CImgList<T>& _load_yuv(std::FILE *const file, const char *const filename,
			   const unsigned int size_x, const unsigned int size_y,
                           const unsigned int chroma_subsampling,
			   const unsigned int first_frame, const unsigned int last_frame,
			   const unsigned int step_frame, const bool yuv2rgb) {
      if (!filename && !file)
        throw CImgArgumentException(_cimglist_instance
                                    "load_yuv(): Specified filename is (null).",
                                    cimglist_instance);
      if (chroma_subsampling!=420 && chroma_subsampling!=422 && chroma_subsampling!=444)
        throw CImgArgumentException(_cimglist_instance
                                    "load_yuv(): Specified chroma subsampling '%u' is invalid, for file '%s'.",
                                    cimglist_instance,
                                    chroma_subsampling,filename?filename:"(FILE*)");
      const unsigned int
        cfx = chroma_subsampling==420 || chroma_subsampling==422?2:1,
        cfy = chroma_subsampling==420?2:1,
	nfirst_frame = first_frame<last_frame?first_frame:last_frame,
	nlast_frame = first_frame<last_frame?last_frame:first_frame,
	nstep_frame = step_frame?step_frame:1;

      if (!size_x || !size_y || size_x%cfx || size_y%cfy)
        throw CImgArgumentException(_cimglist_instance
                                    "load_yuv(): Specified dimensions (%u,%u) are invalid, for file '%s'.",
                                    cimglist_instance,
                                    size_x,size_y,filename?filename:"(FILE*)");

      CImg<ucharT> YUV(size_x,size_y,1,3), UV(size_x/cfx,size_y/cfy,1,2);
      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
      bool stop_flag = false;
      int err;
      if (nfirst_frame) {
        err = cimg::fseek(nfile,(uint64T)nfirst_frame*(YUV._width*YUV._height + 2*UV._width*UV._height),SEEK_CUR);
        if (err) {
          if (!file) cimg::fclose(nfile);
          throw CImgIOException(_cimglist_instance
                                "load_yuv(): File '%s' doesn't contain frame number %u.",
                                cimglist_instance,
                                filename?filename:"(FILE*)",nfirst_frame);
        }
      }
      unsigned int frame;
      for (frame = nfirst_frame; !stop_flag && frame<=nlast_frame; frame+=nstep_frame) {
        YUV.get_shared_channel(0).fill(0);
        // *TRY* to read the luminance part, do not replace by cimg::fread!
        err = (int)std::fread((void*)(YUV._data),1,(size_t)YUV._width*YUV._height,nfile);
        if (err!=(int)(YUV._width*YUV._height)) {
          stop_flag = true;
          if (err>0)
            cimg::warn(_cimglist_instance
                       "load_yuv(): File '%s' contains incomplete data or given image dimensions "
                       "(%u,%u) are incorrect.",
                       cimglist_instance,
                       filename?filename:"(FILE*)",size_x,size_y);
        } else {
          UV.fill(0);
          // *TRY* to read the luminance part, do not replace by cimg::fread!
          err = (int)std::fread((void*)(UV._data),1,(size_t)UV.size(),nfile);
          if (err!=(int)(UV.size())) {
            stop_flag = true;
            if (err>0)
              cimg::warn(_cimglist_instance
                         "load_yuv(): File '%s' contains incomplete data or given image dimensions "
                         "(%u,%u) are incorrect.",
                         cimglist_instance,
                         filename?filename:"(FILE*)",size_x,size_y);
          } else {
            const ucharT *ptrs1 = UV._data, *ptrs2 = UV.data(0,0,0,1);
            ucharT *ptrd1 = YUV.data(0,0,0,1), *ptrd2 = YUV.data(0,0,0,2);
            const unsigned int wd = YUV._width;
            switch (chroma_subsampling) {
            case 420 :
              cimg_forY(UV,y) {
                cimg_forX(UV,x) {
                  const ucharT U = *(ptrs1++), V = *(ptrs2++);
                  ptrd1[wd] = U; *(ptrd1)++ = U;
                  ptrd1[wd] = U; *(ptrd1)++ = U;
                  ptrd2[wd] = V; *(ptrd2)++ = V;
                  ptrd2[wd] = V; *(ptrd2)++ = V;
                }
                ptrd1+=wd; ptrd2+=wd;
              }
              break;
            case 422 :
              cimg_forXY(UV,x,y) {
                const ucharT U = *(ptrs1++), V = *(ptrs2++);
                *(ptrd1++) = U; *(ptrd1++) = U;
                *(ptrd2++) = V; *(ptrd2++) = V;
              }
              break;
            default :
              YUV.draw_image(0,0,0,1,UV);
            }
            if (yuv2rgb) YUV.YCbCrtoRGB();
            insert(YUV);
            if (nstep_frame>1) cimg::fseek(nfile,(uint64T)(nstep_frame - 1)*(size_x*size_y + size_x*size_y/2),SEEK_CUR);
          }
        }
      }
      if (stop_flag && nlast_frame!=~0U && frame!=nlast_frame)
        cimg::warn(_cimglist_instance
                   "load_yuv(): Frame %d not reached since only %u frames were found in file '%s'.",
                   cimglist_instance,
                   nlast_frame,frame - 1,filename?filename:"(FILE*)");

Project: CImg
File: CImg.h

    return filename_local;
  }

  // Implement a tic/toc mechanism to display elapsed time of algorithms.
  inline cimg_ulong tictoc(const bool is_tic) {
    cimg::mutex(2);
    static CImg<cimg_ulong> times(64);
    static unsigned int pos = 0;
    const cimg_ulong t1 = cimg::time();
    if (is_tic) {
      // Tic
      times[pos++] = t1;
      if (pos>=times._width)
        throw CImgArgumentException("cimg::tic(): Too much calls to 'cimg::tic()' without calls to 'cimg::toc()'.");
      cimg::mutex(2,0);
      return t1;
    }

    // Toc
    if (!pos)
      throw CImgArgumentException("cimg::toc(): No previous call to 'cimg::tic()' has been made.");
    const cimg_ulong
      t0 = times[--pos],
      dt = t1>=t0?(t1 - t0):cimg::type<cimg_ulong>::max();
    const unsigned int
      edays = (unsigned int)(dt/86400000.0),
      ehours = (unsigned int)((dt - edays*86400000.0)/3600000.0),
      emin = (unsigned int)((dt - edays*86400000.0 - ehours*3600000.0)/60000.0),
      esec = (unsigned int)((dt - edays*86400000.0 - ehours*3600000.0 - emin*60000.0)/1000.0),
      ems = (unsigned int)(dt - edays*86400000.0 - ehours*3600000.0 - emin*60000.0 - esec*1000.0);
    if (!edays && !ehours && !emin && !esec)
      std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u ms%s\n",
                   cimg::t_red,1 + 2*pos,"",ems,cimg::t_normal);
    else {
      if (!edays && !ehours && !emin)
        std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u sec %u ms%s\n",
                     cimg::t_red,1 + 2*pos,"",esec,ems,cimg::t_normal);
      else {
        if (!edays && !ehours)
          std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u min %u sec %u ms%s\n",
                       cimg::t_red,1 + 2*pos,"",emin,esec,ems,cimg::t_normal);
        else{
          if (!edays)
            std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u hours %u min %u sec %u ms%s\n",
                         cimg::t_red,1 + 2*pos,"",ehours,emin,esec,ems,cimg::t_normal);
          else{
            std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u days %u hours %u min %u sec %u ms%s\n",
                         cimg::t_red,1 + 2*pos,"",edays,ehours,emin,esec,ems,cimg::t_normal);
          }
        }
      }

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    CImg<typename cimg::superset<t,long>::type>
    get_distance_dijkstra(const T& value, const CImg<t>& metric, const bool is_high_connectivity,
                          CImg<to>& return_path) const {
      if (is_empty()) return return_path.assign();
      if (!is_sameXYZ(metric))
        throw CImgArgumentException(_cimg_instance
                                    "distance_dijkstra(): image instance and metric map (%u,%u,%u,%u) "
                                    "have incompatible dimensions.",
                                    cimg_instance,
                                    metric._width,metric._height,metric._depth,metric._spectrum);
      typedef typename cimg::superset<t,long>::type td;  // Type used for computing cumulative distances.
      CImg<td> result(_width,_height,_depth,_spectrum), Q;
      CImg<boolT> is_queued(_width,_height,_depth,1);
      if (return_path) return_path.assign(_width,_height,_depth,_spectrum);

      cimg_forC(*this,c) {
        const CImg<T> img = get_shared_channel(c);
        const CImg<t> met = metric.get_shared_channel(c%metric._spectrum);
        CImg<td> res = result.get_shared_channel(c);
        CImg<to> path = return_path?return_path.get_shared_channel(c):CImg<to>();
        unsigned int sizeQ = 0;

        // Detect initial seeds.
        is_queued.fill(0);
        cimg_forXYZ(img,x,y,z) if (img(x,y,z)==value) {
          Q._priority_queue_insert(is_queued,sizeQ,0,x,y,z);
          res(x,y,z) = 0;
          if (path) path(x,y,z) = (to)0;
        }

        // Start distance propagation.
        while (sizeQ) {

          // Get and remove point with minimal potential from the queue.
          const int x = (int)Q(0,1), y = (int)Q(0,2), z = (int)Q(0,3);
          const td P = (td)-Q(0,0);
          Q._priority_queue_remove(sizeQ);

          // Update neighbors.
          td npot = 0;
          if (x - 1>=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x - 1,y,z) + P),x - 1,y,z)) {
            res(x - 1,y,z) = npot; if (path) path(x - 1,y,z) = (to)2;
          }
          if (x + 1<width() && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x + 1,y,z) + P),x + 1,y,z)) {
            res(x + 1,y,z) = npot; if (path) path(x + 1,y,z) = (to)1;
          }
          if (y - 1>=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x,y - 1,z) + P),x,y - 1,z)) {
            res(x,y - 1,z) = npot; if (path) path(x,y - 1,z) = (to)8;
          }
          if (y + 1<height() && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x,y + 1,z) + P),x,y + 1,z)) {
            res(x,y + 1,z) = npot; if (path) path(x,y + 1,z) = (to)4;
          }
          if (z - 1>=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x,y,z - 1) + P),x,y,z - 1)) {
            res(x,y,z - 1) = npot; if (path) path(x,y,z - 1) = (to)32;
          }
          if (z + 1<depth() && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x,y,z + 1) + P),x,y,z + 1)) {
            res(x,y,z + 1) = npot; if (path) path(x,y,z + 1) = (to)16;
          }

          if (is_high_connectivity) {
            const float sqrt2 = std::sqrt(2.0f), sqrt3 = std::sqrt(3.0f);

            // Diagonal neighbors on slice z.
            if (x - 1>=0 && y - 1>=0 &&
                Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x - 1,y - 1,z) + P)),x - 1,y - 1,z)) {
              res(x - 1,y - 1,z) = npot; if (path) path(x - 1,y - 1,z) = (to)10;
            }
            if (x + 1<width() && y - 1>=0 &&
                Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x + 1,y - 1,z) + P)),x + 1,y - 1,z)) {
              res(x + 1,y - 1,z) = npot; if (path) path(x + 1,y - 1,z) = (to)9;
            }
            if (x - 1>=0 && y + 1<height() &&
                Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x - 1,y + 1,z) + P)),x - 1,y + 1,z)) {
              res(x - 1,y + 1,z) = npot; if (path) path(x - 1,y + 1,z) = (to)6;
            }
            if (x + 1<width() && y + 1<height() &&
                Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x + 1,y + 1,z) + P)),x + 1,y + 1,z)) {
              res(x + 1,y + 1,z) = npot; if (path) path(x + 1,y + 1,z) = (to)5;
            }

            if (z - 1>=0) { // Diagonal neighbors on slice z - 1.
              if (x - 1>=0 &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x - 1,y,z - 1) + P)),x - 1,y,z - 1)) {
                res(x - 1,y,z - 1) = npot; if (path) path(x - 1,y,z - 1) = (to)34;
              }
              if (x + 1<width() &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x + 1,y,z - 1) + P)),x + 1,y,z - 1)) {
                res(x + 1,y,z - 1) = npot; if (path) path(x + 1,y,z - 1) = (to)33;
              }
              if (y - 1>=0 &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x,y - 1,z - 1) + P)),x,y - 1,z - 1)) {
                res(x,y - 1,z - 1) = npot; if (path) path(x,y - 1,z - 1) = (to)40;
              }
              if (y + 1<height() &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x,y + 1,z - 1) + P)),x,y + 1,z - 1)) {
                res(x,y + 1,z - 1) = npot; if (path) path(x,y + 1,z - 1) = (to)36;
              }
              if (x - 1>=0 && y - 1>=0 &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x - 1,y - 1,z - 1) + P)),
                                           x - 1,y - 1,z - 1)) {
                res(x - 1,y - 1,z - 1) = npot; if (path) path(x - 1,y - 1,z - 1) = (to)42;
              }
              if (x + 1<width() && y - 1>=0 &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x + 1,y - 1,z - 1) + P)),
                                           x + 1,y - 1,z - 1)) {
                res(x + 1,y - 1,z - 1) = npot; if (path) path(x + 1,y - 1,z - 1) = (to)41;
              }
              if (x - 1>=0 && y + 1<height() &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x - 1,y + 1,z - 1) + P)),
                                           x - 1,y + 1,z - 1)) {
                res(x - 1,y + 1,z - 1) = npot; if (path) path(x - 1,y + 1,z - 1) = (to)38;
              }
              if (x + 1<width() && y + 1<height() &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x + 1,y + 1,z - 1) + P)),
                                           x + 1,y + 1,z - 1)) {
                res(x + 1,y + 1,z - 1) = npot; if (path) path(x + 1,y + 1,z - 1) = (to)37;
              }
            }

            if (z + 1<depth()) { // Diagonal neighbors on slice z + 1.
              if (x - 1>=0 &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x - 1,y,z + 1) + P)),x - 1,y,z + 1)) {
                res(x - 1,y,z + 1) = npot; if (path) path(x - 1,y,z + 1) = (to)18;
              }
              if (x + 1<width() &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x + 1,y,z + 1) + P)),x + 1,y,z + 1)) {
                res(x + 1,y,z + 1) = npot; if (path) path(x + 1,y,z + 1) = (to)17;
              }
              if (y - 1>=0 &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x,y - 1,z + 1) + P)),x,y - 1,z + 1)) {
                res(x,y - 1,z + 1) = npot; if (path) path(x,y - 1,z + 1) = (to)24;
              }
              if (y + 1<height() &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x,y + 1,z + 1) + P)),x,y + 1,z + 1)) {
                res(x,y + 1,z + 1) = npot; if (path) path(x,y + 1,z + 1) = (to)20;
              }
              if (x - 1>=0 && y - 1>=0 &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x - 1,y - 1,z + 1) + P)),
                                           x - 1,y - 1,z + 1)) {
                res(x - 1,y - 1,z + 1) = npot; if (path) path(x - 1,y - 1,z + 1) = (to)26;
              }
              if (x + 1<width() && y - 1>=0 &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x + 1,y - 1,z + 1) + P)),
                                           x + 1,y - 1,z + 1)) {
                res(x + 1,y - 1,z + 1) = npot; if (path) path(x + 1,y - 1,z + 1) = (to)25;
              }
              if (x - 1>=0 && y + 1<height() &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x - 1,y + 1,z + 1) + P)),
                                           x - 1,y + 1,z + 1)) {
                res(x - 1,y + 1,z + 1) = npot; if (path) path(x - 1,y + 1,z + 1) = (to)22;
              }
              if (x + 1<width() && y + 1<height() &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x + 1,y + 1,z + 1) + P)),
                                           x + 1,y + 1,z + 1)) {
                res(x + 1,y + 1,z + 1) = npot; if (path) path(x + 1,y + 1,z + 1) = (to)21;
              }
            }
          }
        }
      }
      return result;

Project: CImg
File: CImg.h


      static double mp_stov(_cimg_math_parser& mp) {
        const double *ptrs = &_mp_arg(2);
        const ulongT siz = (ulongT)mp.opcode[3];
        longT ind = (longT)_mp_arg(4);
        const bool is_strict = (bool)_mp_arg(5);
        double val = cimg::type<double>::nan();
        if (ind<0 || ind>=(longT)siz) return val;
        if (!siz) return *ptrs>='0' && *ptrs<='9'?*ptrs - '0':val;

        CImg<charT> ss(siz + 1 - ind);
        char sep;
        ptrs+=1 + ind; cimg_forX(ss,i) ss[i] = (char)*(ptrs++); ss.back() = 0;

        int err = std::sscanf(ss,"%lf%c",&val,&sep);
#if cimg_OS==2
        // Check for +/-NaN and +/-inf as Microsoft's sscanf() version is not able
        // to read those particular values.
        if (!err && (*ss=='+' || *ss=='-' || *ss=='i' || *ss=='I' || *ss=='n' || *ss=='N')) {
          bool is_positive = true;
          const char *s = ss;
          if (*s=='+') ++s; else if (*s=='-') { ++s; is_positive = false; }
          if (!cimg::strcasecmp(s,"inf")) { val = cimg::type<double>::inf(); err = 1; }
          else if (!cimg::strcasecmp(s,"nan")) { val = cimg::type<double>::nan(); err = 1; }
          if (err==1 && !is_positive) val = -val;
        }
#endif
        if (is_strict && err!=1) return cimg::type<double>::nan();
        return val;

Project: CImg
File: CImg.h


      static float* _mp_memcopy_float(_cimg_math_parser& mp, const ulongT *const p_ref,
                                      const longT siz, const long inc) {
        const unsigned ind = (unsigned int)p_ref[1];
        const CImg<T> &img = ind==~0U?mp.imgin:mp.listin[cimg::mod((int)mp.mem[ind],mp.listin.width())];
        const bool is_relative = (bool)p_ref[2];
        int ox, oy, oz, oc;
        longT off = 0;
        if (is_relative) {
          ox = (int)mp.mem[_cimg_mp_slot_x];
          oy = (int)mp.mem[_cimg_mp_slot_y];
          oz = (int)mp.mem[_cimg_mp_slot_z];
          oc = (int)mp.mem[_cimg_mp_slot_c];
          off = img.offset(ox,oy,oz,oc);
        }
        if ((*p_ref)%2) {
          const int
            x = (int)mp.mem[p_ref[3]],
            y = (int)mp.mem[p_ref[4]],
            z = (int)mp.mem[p_ref[5]],
            c = *p_ref==5?0:(int)mp.mem[p_ref[6]];
          off+=img.offset(x,y,z,c);
        } else off+=(longT)mp.mem[p_ref[3]];
        const longT eoff = off + (siz - 1)*inc;
        if (off<0 || eoff>=(longT)img.size())
          throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'copy()': "
                                      "Out-of-bounds image pointer "
                                      "(length: %ld, increment: %ld, offset start: %ld, "
                                      "offset end: %ld, offset max: %lu).",
                                      mp.imgin.pixel_type(),siz,inc,off,eoff,img.size() - 1);
        return (float*)&img[off];

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    **/
    CImg<T>& cut(const T& min_value, const T& max_value) {
      if (is_empty()) return *this;
      const T a = min_value<max_value?min_value:max_value, b = min_value<max_value?max_value:min_value;
      cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=32768))
      cimg_rof(*this,ptrd,T) *ptrd = (*ptrd<a)?a:((*ptrd>b)?b:*ptrd);
      return *this;

Project: CImg
File: CImg.h


    CImgDisplay& resize(const int nwidth, const int nheight, const bool force_redraw=true) {
      if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
      if (is_empty()) return assign(nwidth,nheight);
      Display *const dpy = cimg::X11_attr().display;
      const unsigned int
        tmpdimx = (nwidth>0)?nwidth:(-nwidth*width()/100),
        tmpdimy = (nheight>0)?nheight:(-nheight*height()/100),
        dimx = tmpdimx?tmpdimx:1,
        dimy = tmpdimy?tmpdimy:1;
      if (_width!=dimx || _height!=dimy || _window_width!=dimx || _window_height!=dimy) {
        show();
        cimg_lock_display();
        if (_window_width!=dimx || _window_height!=dimy) {
          XWindowAttributes attr;
          for (unsigned int i = 0; i<10; ++i) {
            XResizeWindow(dpy,_window,dimx,dimy);
            XGetWindowAttributes(dpy,_window,&attr);
            if (attr.width==(int)dimx && attr.height==(int)dimy) break;
            cimg::wait(5);
          }
        }
        if (_width!=dimx || _height!=dimy) switch (cimg::X11_attr().nb_bits) {
          case 8 :  { unsigned char pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } break;
          case 16 : { unsigned short pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } break;
          default : { unsigned int pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); }
          }
        _window_width = _width = dimx; _window_height = _height = dimy;
        cimg_unlock_display();
      }
      _is_resized = false;
      if (_is_fullscreen) move((screen_width() - _width)/2,(screen_height() - _height)/2);
      if (force_redraw) return paint();
      return *this;

Project: CImg
File: CImg.h

    }

    //! Load a 3d object from a .OFF file \newinstance.
    template<typename tf, typename tc>

Project: CImg
File: CImg.h

    //! Return base-2 logarithm of a value.
    inline double log2(const double x) {
      const double base = std::log(2.0);
      return std::log(x)/base;

Project: CImg
File: CImg.h

    **/
    CImg<T>& fill(const char *const expression, const bool repeat_values, const bool allow_formula=true,
                  const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) {
      return _fill(expression,repeat_values,allow_formula,list_inputs,list_outputs,"fill",0);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T> get_warp(const CImg<t>& warp, const unsigned int mode=0,
                     const unsigned int interpolation=1, const unsigned int boundary_conditions=0) const {
      if (is_empty() || !warp) return *this;
      if (mode && !is_sameXYZ(warp))
        throw CImgArgumentException(_cimg_instance
                                    "warp(): Instance and specified relative warping field (%u,%u,%u,%u,%p) "
                                    "have different XYZ dimensions.",
                                    cimg_instance,
                                    warp._width,warp._height,warp._depth,warp._spectrum,warp._data);

      CImg<T> res(warp._width,warp._height,warp._depth,_spectrum);

      if (warp._spectrum==1) { // 1d warping
        if (mode>=3) { // Forward-relative warp
          res.fill((T)0);
          if (interpolation>=1) // Linear interpolation
            cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
            cimg_forYZC(res,y,z,c) {
              const t *ptrs0 = warp.data(0,y,z); const T *ptrs = data(0,y,z,c);
              cimg_forX(res,x) res.set_linear_atX(*(ptrs++),x + (float)*(ptrs0++),y,z,c);
            }
          else // Nearest-neighbor interpolation
            cimg_forYZC(res,y,z,c) {
              const t *ptrs0 = warp.data(0,y,z); const T *ptrs = data(0,y,z,c);
              cimg_forX(res,x) {
                const int X = x + (int)cimg::round(*(ptrs0++));
                if (X>=0 && X<width()) res(X,y,z,c) = *(ptrs++);
              }
            }
        } else if (mode==2) { // Forward-absolute warp
          res.fill((T)0);
          if (interpolation>=1) // Linear interpolation
            cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
            cimg_forYZC(res,y,z,c) {
              const t *ptrs0 = warp.data(0,y,z); const T *ptrs = data(0,y,z,c);
              cimg_forX(res,x) res.set_linear_atX(*(ptrs++),(float)*(ptrs0++),y,z,c);
            }
          else // Nearest-neighbor interpolation
            cimg_forYZC(res,y,z,c) {
              const t *ptrs0 = warp.data(0,y,z); const T *ptrs = data(0,y,z,c);
              cimg_forX(res,x) {
                const int X = (int)cimg::round(*(ptrs0++));
                if (X>=0 && X<width()) res(X,y,z,c) = *(ptrs++);
              }
            }
        } else if (mode==1) { // Backward-relative warp
          if (interpolation==2) // Cubic interpolation
            switch (boundary_conditions) {
            case 3 : { // Mirror
              const float w2 = 2.0f*width();
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) {
                  const float mx = cimg::mod(x - (float)*(ptrs0++),w2);
                  *(ptrd++) = _cubic_cut_atX(mx<width()?mx:w2 - mx - 1,y,z,c);
                }
              }
            } break;
            case 2 : // Periodic
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = _cubic_cut_atX(cimg::mod(x - (float)*(ptrs0++),(float)_width),y,z,c);
              }
              break;
            case 1 : // Neumann
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = _cubic_cut_atX(x - (float)*(ptrs0++),y,z,c);
              }
              break;
            default : // Dirichlet
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = cubic_cut_atX(x - (float)*(ptrs0++),y,z,c,(T)0);
              }
            }
          else if (interpolation==1) // Linear interpolation
            switch (boundary_conditions) {
            case 3 : { // Mirror
              const float w2 = 2.0f*width();
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) {
                  const float mx = cimg::mod(x - (float)*(ptrs0++),w2);
                  *(ptrd++) = (T)_linear_atX(mx<width()?mx:w2 - mx - 1,y,z,c);
                }
              }
            } break;
            case 2 : // Periodic
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=1048576))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = (T)_linear_atX(cimg::mod(x - (float)*(ptrs0++),(float)_width),y,z,c);
              }
              break;
            case 1 : // Neumann
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=1048576))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = (T)_linear_atX(x - (float)*(ptrs0++),y,z,c);
              }
              break;
            default : // Dirichlet
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=1048576))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = (T)linear_atX(x - (float)*(ptrs0++),y,z,c,(T)0);
              }
            }
          else // Nearest-neighbor interpolation
            switch (boundary_conditions) {
            case 3 : { // Mirror
              const int w2 = 2*width();
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) {
                  const int mx = cimg::mod(x - (int)cimg::round(*(ptrs0++)),w2);
                  *(ptrd++) = (*this)(mx<width()?mx:w2 - mx - 1,y,z,c);
                }
              }
            } break;
            case 2 : // Periodic
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = (*this)(cimg::mod(x - (int)cimg::round(*(ptrs0++)),(int)_width),y,z,c);
              }
              break;
            case 1 : // Neumann
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = _atX(x - (int)*(ptrs0++),y,z,c);
              }
              break;
            default : // Dirichlet
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = atX(x - (int)*(ptrs0++),y,z,c,(T)0);
              }
            }
        }
        else { // Backward-absolute warp
          if (interpolation==2) // Cubic interpolation
            switch (boundary_conditions) {
            case 3 : { // Mirror
              const float w2 = 2.0f*width();
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
                cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) {
                  const float mx = cimg::mod((float)*(ptrs0++),w2);
                  *(ptrd++) = _cubic_cut_atX(mx<width()?mx:w2 - mx - 1,0,0,c);
                }
              }
            } break;
            case 2 : // Periodic
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = _cubic_cut_atX(cimg::mod((float)*(ptrs0++),(float)_width),0,0,c);
              }
              break;
            case 1 : // Neumann
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = _cubic_cut_atX((float)*(ptrs0++),0,0,c);
              }
              break;
            default : // Dirichlet
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = cubic_cut_atX((float)*(ptrs0++),0,0,c,(T)0);
              }
            }
          else if (interpolation==1) // Linear interpolation
            switch (boundary_conditions) {
            case 3 : { // Mirror
              const float w2 = 2.0f*width();
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
                cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) {
                  const float mx = cimg::mod((float)*(ptrs0++),w2);
                  *(ptrd++) = (T)_linear_atX(mx<width()?mx:w2 - mx - 1,0,0,c);
                }
              }
            } break;
            case 2 : // Periodic
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=1048576))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = (T)_linear_atX(cimg::mod((float)*(ptrs0++),(float)_width),0,0,c);
              }
              break;
            case 1 : // Neumann
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=1048576))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = (T)_linear_atX((float)*(ptrs0++),0,0,c);
              }
              break;
            default : // Dirichlet
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=1048576))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = (T)linear_atX((float)*(ptrs0++),0,0,c,(T)0);
              }
            }
          else // Nearest-neighbor interpolation
            switch (boundary_conditions) {
            case 3 : { // Mirror
              const int w2 = 2*width();
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
                cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) {
                  const int mx = cimg::mod((int)cimg::round(*(ptrs0++)),w2);
                  *(ptrd++) = (*this)(mx<width()?mx:w2 - mx - 1,0,0,c);
                }
              }
            } break;
            case 2 : // Periodic
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = (*this)(cimg::mod((int)cimg::round(*(ptrs0++)),(int)_width),0,0,c);
              }
              break;
            case 1 : // Neumann
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = _atX((int)*(ptrs0++),0,0,c);
              }
              break;
            default : // Dirichlet
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = atX((int)*(ptrs0++),0,0,c,(T)0);
              }
            }
        }

      } else if (warp._spectrum==2) { // 2d warping
        if (mode>=3) { // Forward-relative warp
          res.fill((T)0);
          if (interpolation>=1) // Linear interpolation
            cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
            cimg_forYZC(res,y,z,c) {
              const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); const T *ptrs = data(0,y,z,c);
              cimg_forX(res,x) res.set_linear_atXY(*(ptrs++),x + (float)*(ptrs0++),y + (float)*(ptrs1++),z,c);
            }
          else // Nearest-neighbor interpolation
            cimg_forYZC(res,y,z,c) {
              const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); const T *ptrs = data(0,y,z,c);
              cimg_forX(res,x) {
                const int X = x + (int)cimg::round(*(ptrs0++)), Y = y + (int)cimg::round(*(ptrs1++));
                if (X>=0 && X<width() && Y>=0 && Y<height()) res(X,Y,z,c) = *(ptrs++);
              }
            }
        } else if (mode==2) { // Forward-absolute warp
          res.fill((T)0);
          if (interpolation>=1) // Linear interpolation
            cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
            cimg_forYZC(res,y,z,c) {
              const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); const T *ptrs = data(0,y,z,c);
              cimg_forX(res,x) res.set_linear_atXY(*(ptrs++),(float)*(ptrs0++),(float)*(ptrs1++),z,c);
            }
          else // Nearest-neighbor interpolation
            cimg_forYZC(res,y,z,c) {
              const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); const T *ptrs = data(0,y,z,c);
              cimg_forX(res,x) {
                const int X = (int)cimg::round(*(ptrs0++)), Y = (int)cimg::round(*(ptrs1++));
                if (X>=0 && X<width() && Y>=0 && Y<height()) res(X,Y,z,c) = *(ptrs++);
              }
            }
        } else if (mode==1) { // Backward-relative warp
          if (interpolation==2) // Cubic interpolation
            switch (boundary_conditions) {
            case 3 : { // Mirror
              const float w2 = 2.0f*width(), h2 = 2.0f*height();
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) {
                  const float
                    mx = cimg::mod(x - (float)*(ptrs0++),w2),
                    my = cimg::mod(y - (float)*(ptrs1++),h2);
                  *(ptrd++) = _cubic_cut_atXY(mx<width()?mx:w2 - mx - 1,my<height()?my:h2 - my - 1,z,c);
                }
              }
            } break;
            case 2 : // Periodic
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = _cubic_cut_atXY(cimg::mod(x - (float)*(ptrs0++),(float)_width),
                                                             cimg::mod(y - (float)*(ptrs1++),(float)_height),z,c);
              }
              break;
            case 1 : // Neumann
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = _cubic_cut_atXY(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z,c);
              }
              break;
            default : // Dirichlet
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = cubic_cut_atXY(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z,c,(T)0);
              }
            }
          else if (interpolation==1) // Linear interpolation
            switch (boundary_conditions) {
            case 3 : { // Mirror
              const float w2 = 2.0f*width(), h2 = 2.0f*height();
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) {
                  const float
                    mx = cimg::mod(x - (float)*(ptrs0++),w2),
                    my = cimg::mod(y - (float)*(ptrs1++),h2);
                  *(ptrd++) = (T)_linear_atXY(mx<width()?mx:w2 - mx - 1,my<height()?my:h2 - my - 1,z,c);
                }
              }
            } break;
            case 2 : // Periodic
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=1048576))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = (T)_linear_atXY(cimg::mod(x - (float)*(ptrs0++),(float)_width),
                                                             cimg::mod(y - (float)*(ptrs1++),(float)_height),z,c);
              }
              break;
            case 1 : // Neumann
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=1048576))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = (T)_linear_atXY(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z,c);
              }
              break;
            default : // Dirichlet
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=1048576))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = (T)linear_atXY(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z,c,(T)0);
              }
            }
          else // Nearest-neighbor interpolation
            switch (boundary_conditions) {
            case 3 : { // Mirror
              const int w2 = 2*width(), h2 = 2*height();
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) {
                  const int
                    mx = cimg::mod(x - (int)cimg::round(*(ptrs0++)),w2),
                    my = cimg::mod(y - (int)cimg::round(*(ptrs1++)),h2);
                  *(ptrd++) = (*this)(mx<width()?mx:w2 - mx - 1,my<height()?my:h2 - my - 1,z,c);
                }
              }
            } break;
            case 2 : // Periodic
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = (*this)(cimg::mod(x - (int)cimg::round(*(ptrs0++)),(int)_width),
                                                     cimg::mod(y - (int)cimg::round(*(ptrs1++)),(int)_height),z,c);
              }
              break;
            case 1 : // Neumann
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = _atXY(x - (int)*(ptrs0++),y - (int)*(ptrs1++),z,c);
              }
              break;
            default : // Dirichlet
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = atXY(x - (int)*(ptrs0++),y - (int)*(ptrs1++),z,c,(T)0);
              }
            }
        } else { // Backward-absolute warp
          if (interpolation==2) // Cubic interpolation
            switch (boundary_conditions) {
            case 3 : { // Mirror
              const float w2 = 2.0f*width(), h2 = 2.0f*height();
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) {
                  const float
                    mx = cimg::mod((float)*(ptrs0++),w2),
                    my = cimg::mod((float)*(ptrs1++),h2);
                  *(ptrd++) = _cubic_cut_atXY(mx<width()?mx:w2 - mx - 1,my<height()?my:h2 - my - 1,0,c);
                }
              }
            } break;
            case 2 : // Periodic
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = _cubic_cut_atXY(cimg::mod((float)*(ptrs0++),(float)_width),
                                                             cimg::mod((float)*(ptrs1++),(float)_height),0,c);
              }
              break;
            case 1 : // Neumann
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = _cubic_cut_atXY((float)*(ptrs0++),(float)*(ptrs1++),0,c);
              }
              break;
            default : // Dirichlet
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = cubic_cut_atXY((float)*(ptrs0++),(float)*(ptrs1++),0,c,(T)0);
              }
            }
          else if (interpolation==1) // Linear interpolation
            switch (boundary_conditions) {
            case 3 : { // Mirror
              const float w2 = 2.0f*width(), h2 = 2.0f*height();
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) {
                  const float
                    mx = cimg::mod((float)*(ptrs0++),w2),
                    my = cimg::mod((float)*(ptrs1++),h2);
                  *(ptrd++) = (T)_linear_atXY(mx<width()?mx:w2 - mx - 1,my<height()?my:h2 - my - 1,0,c);
                }
              }
            } break;
            case 2 : // Periodic
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=1048576))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = (T)_linear_atXY(cimg::mod((float)*(ptrs0++),(float)_width),
                                                             cimg::mod((float)*(ptrs1++),(float)_height),0,c);
              }
              break;
            case 1 : // Neumann
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=1048576))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = (T)_linear_atXY((float)*(ptrs0++),(float)*(ptrs1++),0,c);
              }
              break;
            default : // Dirichlet
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=1048576))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = (T)linear_atXY((float)*(ptrs0++),(float)*(ptrs1++),0,c,(T)0);
              }
            }
          else // Nearest-neighbor interpolation
            switch (boundary_conditions) {
            case 3 : { // Mirror
              const int w2 = 2*width(), h2 = 2*height();
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) {
                  const int
                    mx = cimg::mod((int)cimg::round(*(ptrs0++)),w2),
                    my = cimg::mod((int)cimg::round(*(ptrs1++)),h2);
                  *(ptrd++) = (*this)(mx<width()?mx:w2 - mx - 1,my<height()?my:h2 - my - 1,0,c);
                }
              }
            } break;
            case 2 : // Periodic
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = (*this)(cimg::mod((int)cimg::round(*(ptrs0++)),(int)_width),
                                                     cimg::mod((int)cimg::round(*(ptrs1++)),(int)_height),0,c);
              }
              break;
            case 1 : // Neumann
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = _atXY((int)*(ptrs0++),(int)*(ptrs1++),0,c);
              }
              break;
            default : // Dirichlet
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = atXY((int)*(ptrs0++),(int)*(ptrs1++),0,c,(T)0);
              }
            }
        }

      } else { // 3d warping
        if (mode>=3) { // Forward-relative warp
          res.fill((T)0);
          if (interpolation>=1) // Linear interpolation
            cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
            cimg_forYZC(res,y,z,c) {
              const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
              const T *ptrs = data(0,y,z,c);
              cimg_forX(res,x) res.set_linear_atXYZ(*(ptrs++),x + (float)*(ptrs0++),y + (float)*(ptrs1++),
                                                    z + (float)*(ptrs2++),c);
            }
          else // Nearest-neighbor interpolation
            cimg_forYZC(res,y,z,c) {
              const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
              const T *ptrs = data(0,y,z,c);
              cimg_forX(res,x) {
                const int
                  X = x + (int)cimg::round(*(ptrs0++)),
                  Y = y + (int)cimg::round(*(ptrs1++)),
                  Z = z + (int)cimg::round(*(ptrs2++));
                if (X>=0 && X<width() && Y>=0 && Y<height() && Z>=0 && Z<depth()) res(X,Y,Z,c) = *(ptrs++);
              }
            }
        } else if (mode==2) { // Forward-absolute warp
          res.fill((T)0);
          if (interpolation>=1) // Linear interpolation
            cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
            cimg_forYZC(res,y,z,c) {
              const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
              const T *ptrs = data(0,y,z,c);
              cimg_forX(res,x) res.set_linear_atXYZ(*(ptrs++),(float)*(ptrs0++),(float)*(ptrs1++),(float)*(ptrs2++),c);
            }
          else // Nearest-neighbor interpolation
            cimg_forYZC(res,y,z,c) {
              const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
              const T *ptrs = data(0,y,z,c);
              cimg_forX(res,x) {
                const int
                  X = (int)cimg::round(*(ptrs0++)),
                  Y = (int)cimg::round(*(ptrs1++)),
                  Z = (int)cimg::round(*(ptrs2++));
                if (X>=0 && X<width() && Y>=0 && Y<height() && Z>=0 && Z<depth()) res(X,Y,Z,c) = *(ptrs++);
              }
            }
        } else if (mode==1) { // Backward-relative warp
          if (interpolation==2) // Cubic interpolation
            switch (boundary_conditions) {
            case 3 : { // Mirror
              const float w2 = 2.0f*width(), h2 = 2.0f*height(), d2 = 2.0f*depth();
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) {
                  const float
                    mx = cimg::mod(x - (float)*(ptrs0++),w2),
                    my = cimg::mod(y - (float)*(ptrs1++),h2),
                    mz = cimg::mod(z - (float)*(ptrs2++),d2);
                  *(ptrd++) = _cubic_cut_atXYZ(mx<width()?mx:w2 - mx - 1,
                                               my<height()?my:h2 - my - 1,
                                               mz<depth()?mz:d2 - mz - 1,c);
                }
              }
            } break;
            case 2 : // Periodic
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = _cubic_cut_atXYZ(cimg::mod(x - (float)*(ptrs0++),(float)_width),
                                                              cimg::mod(y - (float)*(ptrs1++),(float)_height),
                                                              cimg::mod(z - (float)*(ptrs2++),(float)_depth),c);
              }
              break;
            case 1 : // Neumann
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x)
                  *(ptrd++) = _cubic_cut_atXYZ(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z - (float)*(ptrs2++),c);
              }
              break;
            default : // Dirichlet
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x)
                  *(ptrd++) = cubic_cut_atXYZ(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z - (float)*(ptrs2++),c,(T)0);
              }
            }
          else if (interpolation==1) // Linear interpolation
            switch (boundary_conditions) {
            case 3 : { // Mirror
              const float w2 = 2.0f*width(), h2 = 2.0f*height(), d2 = 2.0f*depth();
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) {
                  const float
                    mx = cimg::mod(x - (float)*(ptrs0++),w2),
                    my = cimg::mod(y - (float)*(ptrs1++),h2),
                    mz = cimg::mod(z - (float)*(ptrs2++),d2);
                  *(ptrd++) = (T)_linear_atXYZ(mx<width()?mx:w2 - mx - 1,
                                               my<height()?my:h2 - my - 1,
                                               mz<depth()?mz:d2 - mz - 1,c);
                }
              }
            } break;
            case 2 : // Periodic
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=1048576))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = (T)_linear_atXYZ(cimg::mod(x - (float)*(ptrs0++),(float)_width),
                                                              cimg::mod(y - (float)*(ptrs1++),(float)_height),
                                                              cimg::mod(z - (float)*(ptrs2++),(float)_depth),c);
              }
              break;
            case 1 : // Neumann
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=1048576))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x)
                  *(ptrd++) = (T)_linear_atXYZ(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z - (float)*(ptrs2++),c);
              }
              break;
            default : // Dirichlet
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=1048576))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x)
                  *(ptrd++) = (T)linear_atXYZ(x - (float)*(ptrs0++),y - (float)*(ptrs1++),z - (float)*(ptrs2++),c,(T)0);
              }
            }
          else // Nearest neighbor interpolation
            switch (boundary_conditions) {
            case 3 : { // Mirror
              const int w2 = 2*width(), h2 = 2*height(), d2 = 2*depth();
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) {
                  const int
                    mx = cimg::mod(x - (int)cimg::round(*(ptrs0++)),w2),
                    my = cimg::mod(y - (int)cimg::round(*(ptrs1++)),h2),
                    mz = cimg::mod(z - (int)cimg::round(*(ptrs2++)),d2);
                  *(ptrd++) = (*this)(mx<width()?mx:w2 - mx - 1,
                                      my<height()?my:h2 - my - 1,
                                      mz<depth()?mz:d2 - mz - 1,c);
                }
              }
            } break;
            case 2 : // Periodic
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = (*this)(cimg::mod(x - (int)cimg::round(*(ptrs0++)),(int)_width),
                                                     cimg::mod(y - (int)cimg::round(*(ptrs1++)),(int)_height),
                                                     cimg::mod(z - (int)cimg::round(*(ptrs2++)),(int)_depth),c);
              }
              break;
            case 1 : // Neumann
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = _atXYZ(x - (int)*(ptrs0++),y - (int)*(ptrs1++),z - (int)*(ptrs2++),c);
              }
              break;
            default : // Dirichlet
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = atXYZ(x - (int)*(ptrs0++),y - (int)*(ptrs1++),z - (int)*(ptrs2++),c,(T)0);
              }
            }
        } else { // Backward-absolute warp
          if (interpolation==2) // Cubic interpolation
            switch (boundary_conditions) {
            case 3 : { // Mirror
              const float w2 = 2.0f*width(), h2 = 2.0f*height(), d2 = 2.0f*depth();
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) {
                  const float
                    mx = cimg::mod((float)*(ptrs0++),w2),
                    my = cimg::mod((float)*(ptrs1++),h2),
                    mz = cimg::mod((float)*(ptrs2++),d2);
                  *(ptrd++) = _cubic_cut_atXYZ(mx<width()?mx:w2 - mx - 1,
                                               my<height()?my:h2 - my - 1,
                                               mz<depth()?mz:d2 - mz - 1,c);
                }
              }
            } break;
            case 2 : // Periodic
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = _cubic_cut_atXYZ(cimg::mod((float)*(ptrs0++),(float)_width),
                                                              cimg::mod((float)*(ptrs1++),(float)_height),
                                                              cimg::mod((float)*(ptrs2++),(float)_depth),c);
              }
              break;
            case 1 : // Neumann
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = _cubic_cut_atXYZ((float)*(ptrs0++),(float)*(ptrs1++),(float)*(ptrs2++),c);
              }
              break;
            default : // Dirichlet
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = cubic_cut_atXYZ((float)*(ptrs0++),(float)*(ptrs1++),(float)*(ptrs2++),
                                                             c,(T)0);
              }
            }
          else if (interpolation==1) // Linear interpolation
            switch (boundary_conditions) {
            case 3 : { // Mirror
              const float w2 = 2.0f*width(), h2 = 2.0f*height(), d2 = 2.0f*depth();
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) {
                  const float
                    mx = cimg::mod((float)*(ptrs0++),w2),
                    my = cimg::mod((float)*(ptrs1++),h2),
                    mz = cimg::mod((float)*(ptrs2++),d2);
                  *(ptrd++) = (T)_linear_atXYZ(mx<width()?mx:w2 - mx - 1,
                                               my<height()?my:h2 - my - 1,
                                               mz<depth()?mz:d2 - mz - 1,c);
                }
              }
            } break;
            case 2 :// Periodic
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=1048576))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = (T)_linear_atXYZ(cimg::mod((float)*(ptrs0++),(float)_width),
                                                              cimg::mod((float)*(ptrs1++),(float)_height),
                                                              cimg::mod((float)*(ptrs2++),(float)_depth),c);
              }
              break;
            case 1 : // Neumann
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=1048576))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = (T)_linear_atXYZ((float)*(ptrs0++),(float)*(ptrs1++),(float)*(ptrs2++),c);
              }
              break;
            default : // Dirichlet
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=1048576))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = (T)linear_atXYZ((float)*(ptrs0++),(float)*(ptrs1++),(float)*(ptrs2++),
                                                             c,(T)0);
              }
            }
          else // Nearest-neighbor interpolation
            switch (boundary_conditions) {
            case 3 : { // Mirror
              const int w2 = 2*width(), h2 = 2*height(), d2 = 2*depth();
              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(res.size()>=4096))
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) {
                  const int
                    mx = cimg::mod((int)cimg::round(*(ptrs0++)),w2),
                    my = cimg::mod((int)cimg::round(*(ptrs1++)),h2),
                    mz = cimg::mod((int)cimg::round(*(ptrs2++)),d2);
                  *(ptrd++) = (*this)(mx<width()?mx:w2 - mx - 1,
                                      my<height()?my:h2 - my - 1,
                                      mz<depth()?mz:d2 - mz - 1,c);
                }
              }
            } break;
            case 2 : // Periodic
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = (*this)(cimg::mod((int)cimg::round(*(ptrs0++)),(int)_width),
                                                     cimg::mod((int)cimg::round(*(ptrs1++)),(int)_height),
                                                     cimg::mod((int)cimg::round(*(ptrs2++)),(int)_depth),c);
              }
              break;
            case 1 : // Neumann
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = _atXYZ((int)*(ptrs0++),(int)*(ptrs1++),(int)*(ptrs2++),c);
              }
              break;
            default : // Dirichlet
              cimg_forYZC(res,y,z,c) {
                const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2);
                T *ptrd = res.data(0,y,z,c);
                cimg_forX(res,x) *(ptrd++) = atXYZ((int)*(ptrs0++),(int)*(ptrs1++),(int)*(ptrs2++),c,(T)0);
              }
            }
        }
      }
      return res;

Project: CImg
File: CImg.h

    **/
    inline double rand(const double val_min, const double val_max) {
      const double val = (double)std::rand()/RAND_MAX;
      return val_min + (val_max - val_min)*val;

Project: CImg
File: CImg.h

    template<typename t>
    CImg<_cimg_Tt> operator*(const CImg<t>& img) const {
      if (_width!=img._height || _depth!=1 || _spectrum!=1)
        throw CImgArgumentException(_cimg_instance
                                    "operator*(): Invalid multiplication of instance by specified "
                                    "matrix (%u,%u,%u,%u,%p)",
                                    cimg_instance,
                                    img._width,img._height,img._depth,img._spectrum,img._data);
      CImg<_cimg_Tt> res(img._width,_height);
#ifdef cimg_use_openmp
      cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if(size()>1024 && img.size()>1024))
      cimg_forXY(res,i,j) {
        _cimg_Ttdouble value = 0; cimg_forX(*this,k) value+=(*this)(k,j)*img(i,k); res(i,j) = (_cimg_Tt)value;
      }
#else
      _cimg_Tt *ptrd = res._data;
      cimg_forXY(res,i,j) {
        _cimg_Ttdouble value = 0; cimg_forX(*this,k) value+=(*this)(k,j)*img(i,k); *(ptrd++) = (_cimg_Tt)value;
      }
#endif
      return res;

Project: CImg
File: CImg.h


      static double mp_Jxyz(_cimg_math_parser& mp) {
        double *ptrd = &_mp_arg(1) + 1;
        const unsigned int
          interpolation = (unsigned int)_mp_arg(5),
          boundary_conditions = (unsigned int)_mp_arg(6),
          vsiz = (unsigned int)mp.opcode[7];
        const CImg<T> &img = mp.imgin;
        const double
          ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y], oz = mp.mem[_cimg_mp_slot_z],
          x = ox + _mp_arg(2), y = oy + _mp_arg(3), z = oz + _mp_arg(4);
        const ulongT whd = (ulongT)img._width*img._height*img._depth;
        const T *ptrs;
        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

    //! Pointwise max operator between instance image and a value \newinstance.
    CImg<T> get_max(const T& val) const {
      return (+*this).max(val);

Project: CImg
File: CImg.h

    // Conversion functions to get more precision when trying to store unsigned ints values as floats.
    inline unsigned int float2uint(const float f) {
      int tmp = 0;
      std::memcpy(&tmp,&f,sizeof(float));
      if (tmp>=0) return (unsigned int)f;
      unsigned int u;
      // use memcpy instead of assignment to avoid undesired optimizations by C++-compiler.
      std::memcpy(&u,&f,sizeof(float));
      return ((u)<<1)>>1; // set sign bit to 0.

Project: CImg
File: CImg.h

    //! Compute the square value of each pixel value \newinstance.
    CImg<Tfloat> get_sqr() const {
      return CImg<Tfloat>(*this,false).sqr();

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

    template<typename tp, typename tc>
    CImg<T>& draw_polygon(const CImg<tp>& points,
                          const tc *const color, const float opacity=1) {
      if (is_empty() || !points) return *this;
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_polygon(): Specified color is (null).",
                                    cimg_instance);
      if (points._width==1) return draw_point((int)points(0,0),(int)points(0,1),color,opacity);
      if (points._width==2) return draw_line((int)points(0,0),(int)points(0,1),
                                             (int)points(1,0),(int)points(1,1),color,opacity);
      if (points._width==3) return draw_triangle((int)points(0,0),(int)points(0,1),
                                                 (int)points(1,0),(int)points(1,1),
                                                 (int)points(2,0),(int)points(2,1),color,opacity);
      cimg_init_scanline(color,opacity);
      int
        xmin = 0, ymin = 0,
        xmax = points.get_shared_row(0).max_min(xmin),
        ymax = points.get_shared_row(1).max_min(ymin);
      if (xmax<0 || xmin>=width() || ymax<0 || ymin>=height()) return *this;
      if (ymin==ymax) return draw_line(xmin,ymin,xmax,ymax,color,opacity);

      ymin = std::max(0,ymin);
      ymax = std::min(height() - 1,ymax);
      CImg<intT> Xs(points._width,ymax - ymin + 1);
      CImg<uintT> count(Xs._height,1,1,1,0);
      unsigned int n = 0, nn = 1;
      bool go_on = true;

      while (go_on) {
        unsigned int an = (nn + 1)%points._width;
        const int
          x0 = (int)points(n,0),
          y0 = (int)points(n,1);
        if (points(nn,1)==y0) while (points(an,1)==y0) { nn = an; (an+=1)%=points._width; }
        const int
          x1 = (int)points(nn,0),
          y1 = (int)points(nn,1);
        unsigned int tn = an;
        while (points(tn,1)==y1) (tn+=1)%=points._width;

        if (y0!=y1) {
          const int
            y2 = (int)points(tn,1),
            x01 = x1 - x0, y01 = y1 - y0, y12 = y2 - y1,
            dy = cimg::sign(y01),
            tmax = std::max(1,cimg::abs(y01)),
            tend = tmax - (dy==cimg::sign(y12));
          unsigned int y = (unsigned int)y0 - ymin;
          for (int t = 0; t<=tend; ++t, y+=dy)
            if (y<Xs._height) Xs(count[y]++,y) = x0 + t*x01/tmax;
        }

        go_on = nn>n;
        n = nn;
        nn = an;
      }

      cimg_pragma_openmp(parallel for cimg_openmp_if(Xs._height>32))
      cimg_forY(Xs,y) {
        const CImg<intT> Xsy = Xs.get_shared_points(0,count[y] - 1,y).sort();
        int px = width();
        for (unsigned int n = 0; n<Xsy._width; n+=2) {
          int x0 = Xsy[n];
          const int x1 = Xsy[n + 1];
          x0+=x0==px;
          cimg_draw_scanline(x0,x1,y + ymin,color,opacity,1);
          px = x1;
        }
      }
      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 medcon binary.
  **/
  inline const char* medcon_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
      const char *const pf_path = programfiles_path();
      if (!path_found) {
        std::strcpy(s_path,".\\medcon.exe");
        if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
      }
      if (!path_found) {
        cimg_snprintf(s_path,s_path._width,"%s\\XMedCon\\bin\\medcon.bat",pf_path);
        if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
      }
      if (!path_found) {
        cimg_snprintf(s_path,s_path._width,"%s\\XMedCon\\bin\\medcon.exe",pf_path);
        if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
      }
      if (!path_found) {
        std::strcpy(s_path,"C:\\XMedCon\\bin\\medcon.exe");
        if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
      }
      if (!path_found) std::strcpy(s_path,"medcon.exe");
#else
      if (!path_found) {
        std::strcpy(s_path,"./medcon");
        if ((file=std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
      }
      if (!path_found) std::strcpy(s_path,"medcon");
#endif
      winformat_string(s_path);

Project: CImg
File: CImg.h

    //! Compute the base-10 logarithm of each pixel value \newinstance.
    CImg<Tfloat> get_log10() const {
      return CImg<Tfloat>(*this,false).log10();

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& _draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float angle,
                           const tc *const color, const float opacity,
                           const unsigned int pattern) {
      if (is_empty()) return *this;
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_ellipse(): Specified color is (null).",
                                    cimg_instance);
      if (r1<=0 || r2<=0) return draw_point(x0,y0,color,opacity);
      if (r1==r2 && (float)(int)r1==r1) {
        if (pattern) return draw_circle(x0,y0,r1,color,opacity,pattern);
        else return draw_circle(x0,y0,r1,color,opacity);
      }
      cimg_init_scanline(color,opacity);
      const float
        nr1 = cimg::abs(r1) - 0.5, nr2 = cimg::abs(r2) - 0.5,
        nangle = (float)(angle*cimg::PI/180),
        u = (float)std::cos(nangle),
        v = (float)std::sin(nangle),
        rmax = std::max(nr1,nr2),
        l1 = (float)std::pow(rmax/(nr1>0?nr1:1e-6),2),
        l2 = (float)std::pow(rmax/(nr2>0?nr2:1e-6),2),
        a = l1*u*u + l2*v*v,
        b = u*v*(l1 - l2),
        c = l1*v*v + l2*u*u;
      const int
        yb = (int)std::sqrt(a*rmax*rmax/(a*c - b*b)),
        tymin = y0 - yb - 1,
        tymax = y0 + yb + 1,
        ymin = tymin<0?0:tymin,
        ymax = tymax>=height()?height() - 1:tymax;
      int oxmin = 0, oxmax = 0;
      bool first_line = true;
      for (int y = ymin; y<=ymax; ++y) {
        const float
          Y = y - y0 + (y<y0?0.5f:-0.5f),
          delta = b*b*Y*Y - a*(c*Y*Y - rmax*rmax),
          sdelta = delta>0?(float)std::sqrt(delta)/a:0.0f,
          bY = b*Y/a,
          fxmin = x0 - 0.5f - bY - sdelta,
          fxmax = x0 + 0.5f - bY + sdelta;
        const int xmin = (int)cimg::round(fxmin), xmax = (int)cimg::round(fxmax);
        if (!pattern) cimg_draw_scanline(xmin,xmax,y,color,opacity,1);
        else {
          if (first_line) {
            if (y0 - yb>=0) cimg_draw_scanline(xmin,xmax,y,color,opacity,1);
            else draw_point(xmin,y,color,opacity).draw_point(xmax,y,color,opacity);
            first_line = false;
          } else {
            if (xmin<oxmin) cimg_draw_scanline(xmin,oxmin - 1,y,color,opacity,1);
            else cimg_draw_scanline(oxmin + (oxmin==xmin?0:1),xmin,y,color,opacity,1);
            if (xmax<oxmax) cimg_draw_scanline(xmax,oxmax - 1,y,color,opacity,1);
            else cimg_draw_scanline(oxmax + (oxmax==xmax?0:1),xmax,y,color,opacity,1);
            if (y==tymax) cimg_draw_scanline(xmin + 1,xmax - 1,y,color,opacity,1);
          }
        }
        oxmin = xmin; oxmax = xmax;
      }
      return *this;

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_mandelbrot(const int x0, const int y0, const int x1, const int y1,
                             const CImg<tc>& colormap, const float opacity=1,
                             const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2,
                             const unsigned int iteration_max=255,
                             const bool is_normalized_iteration=false,
                             const bool is_julia_set=false,
                             const double param_r=0, const double param_i=0) {
      if (is_empty()) return *this;
      CImg<tc> palette;
      if (colormap) palette.assign(colormap._data,colormap.size()/colormap._spectrum,1,1,colormap._spectrum,true);
      if (palette && palette._spectrum!=_spectrum)
        throw CImgArgumentException(_cimg_instance
                                    "draw_mandelbrot(): Instance and specified colormap (%u,%u,%u,%u,%p) have "
                                    "incompatible dimensions.",
                                    cimg_instance,
                                    colormap._width,colormap._height,colormap._depth,colormap._spectrum,colormap._data);

      const float nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.0f), ln2 = (float)std::log(2.0);
      const int
        _x0 = cimg::cut(x0,0,width() - 1),
        _y0 = cimg::cut(y0,0,height() - 1),
        _x1 = cimg::cut(x1,0,width() - 1),
        _y1 = cimg::cut(y1,0,height() - 1);

      cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if((1 + _x1 - _x0)*(1 + _y1 - _y0)>=2048))
      for (int q = _y0; q<=_y1; ++q)
        for (int p = _x0; p<=_x1; ++p) {
          unsigned int iteration = 0;
          const double x = z0r + p*(z1r-z0r)/_width, y = z0i + q*(z1i-z0i)/_height;
          double zr, zi, cr, ci;
          if (is_julia_set) { zr = x; zi = y; cr = param_r; ci = param_i; }
          else { zr = param_r; zi = param_i; cr = x; ci = y; }
          for (iteration=1; zr*zr + zi*zi<=4 && iteration<=iteration_max; ++iteration) {
            const double temp = zr*zr - zi*zi + cr;
            zi = 2*zr*zi + ci;
            zr = temp;
          }
          if (iteration>iteration_max) {
            if (palette) {
              if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)palette(0,c);
              else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)(palette(0,c)*nopacity + (*this)(p,q,0,c)*copacity);
            } else {
              if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)0;
              else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)((*this)(p,q,0,c)*copacity);
            }
          } else if (is_normalized_iteration) {
            const float
              normz = (float)cimg::abs(zr*zr + zi*zi),
              niteration = (float)(iteration + 1 - std::log(std::log(normz))/ln2);
            if (palette) {
              if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)palette._linear_atX(niteration,c);
              else cimg_forC(*this,c)
                     (*this)(p,q,0,c) = (T)(palette._linear_atX(niteration,c)*nopacity + (*this)(p,q,0,c)*copacity);
            } else {
              if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)niteration;
              else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)(niteration*nopacity + (*this)(p,q,0,c)*copacity);
            }
          } else {
            if (palette) {
              if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)palette._atX(iteration,c);
              else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)(palette(iteration,c)*nopacity + (*this)(p,q,0,c)*copacity);
            } else {
              if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)iteration;
              else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)(iteration*nopacity + (*this)(p,q,0,c)*copacity);
            }
          }
        }
      return *this;

Project: CImg
File: CImg.h

    //! Convert pixel values from XYZ to Lab color spaces.
    CImg<T>& XYZtoLab(const bool use_D65=true) {
#define _cimg_Labf(x) (24389*(x)>216?cimg::cbrt(x):(24389*(x)/27 + 16)/116)

      if (_spectrum!=3)
        throw CImgInstanceException(_cimg_instance
                                    "XYZtoLab(): Instance is not a XYZ image.",
                                    cimg_instance);
      const CImg<Tfloat> white = CImg<Tfloat>(1,1,1,3,255).RGBtoXYZ(use_D65);
      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);
      const ulongT whd = (ulongT)_width*_height*_depth;
      cimg_pragma_openmp(parallel for cimg_openmp_if(whd>=128))
      for (ulongT N = 0; N<whd; ++N) {
        const Tfloat
          X = (Tfloat)(p1[N]/white[0]),
          Y = (Tfloat)(p2[N]/white[1]),
          Z = (Tfloat)(p3[N]/white[2]),
          fX = (Tfloat)_cimg_Labf(X),
          fY = (Tfloat)_cimg_Labf(Y),
          fZ = (Tfloat)_cimg_Labf(Z);
        p1[N] = (T)cimg::cut(116*fY - 16,0,100);
        p2[N] = (T)(500*(fX - fY));
        p3[N] = (T)(200*(fY - fZ));
      }
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

      }
      static bool is_nan(const float val) {
#ifdef isnan
        return (bool)isnan(val);
#else
        return !(val==val);
#endif

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


      static double mp_date(_cimg_math_parser& mp) {
        const unsigned int
          _arg = (unsigned int)mp.opcode[3],
          _siz = (unsigned int)mp.opcode[4],
          siz = _siz?_siz:1;
        const double *const arg_in = _arg==~0U?0:&_mp_arg(3) + (_siz?1:0);
        double *const arg_out = &_mp_arg(1) + (_siz?1:0);
        if (arg_in) std::memcpy(arg_out,arg_in,siz*sizeof(double));
        else for (unsigned int i = 0; i<siz; ++i) arg_out[i] = i;

        CImg<charT> filename(mp.opcode[2] - 5);
        if (filename) {
          const ulongT *ptrs = mp.opcode._data + 5;
          cimg_for(filename,ptrd,char) *ptrd = (char)*(ptrs++);
          cimg::fdate(filename,arg_out,siz);
        } else cimg::date(arg_out,siz);
        return _siz?cimg::type<double>::nan():*arg_out;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    //! Compute the arctangent of each pixel value \newinstance.
    CImg<Tfloat> get_atan() const {
      return CImg<Tfloat>(*this,false).atan();