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

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_circle(const int x0, const int y0, int radius,
                         const tc *const color, const float opacity,
                         const unsigned int pattern) {
      if (pattern!=~0U) return draw_ellipse(x0,y0,radius,radius,0,color,opacity,pattern);
      if (is_empty()) return *this;
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_circle(): Specified color is (null).",
                                    cimg_instance);
      if (radius<0 || x0 - radius>=width() || y0 + radius<0 || y0 - radius>=height()) return *this;
      if (!radius) return draw_point(x0,y0,color,opacity);

      draw_point(x0 - radius,y0,color,opacity).draw_point(x0 + radius,y0,color,opacity).
        draw_point(x0,y0 - radius,color,opacity).draw_point(x0,y0 + radius,color,opacity);
      if (radius==1) return *this;
      for (int f = 1 - radius, ddFx = 0, ddFy = -(radius<<1), x = 0, y = radius; x<y; ) {
        if (f>=0) { f+=(ddFy+=2); --y; }
        ++x; ++(f+=(ddFx+=2));
        if (x!=y + 1) {
          const int x1 = x0 - y, x2 = x0 + y, y1 = y0 - x, y2 = y0 + x,
            x3 = x0 - x, x4 = x0 + x, y3 = y0 - y, y4 = y0 + y;
          draw_point(x1,y1,color,opacity).draw_point(x1,y2,color,opacity).
            draw_point(x2,y1,color,opacity).draw_point(x2,y2,color,opacity);
          if (x!=y)
            draw_point(x3,y3,color,opacity).draw_point(x4,y4,color,opacity).
              draw_point(x4,y3,color,opacity).draw_point(x3,y4,color,opacity);
        }
      }
      return *this;

Project: CImg
File: CImg.h

    //! Equalize histogram of pixel values \newinstance.
    CImg<T> get_equalize(const unsigned int nblevels, const T& val_min, const T& val_max) const {
      return (+*this).equalize(nblevels,val_min,val_max);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    //! Fill sequentially all pixel values with specified values \overloading.
    CImg<T>& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,
                  const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11,
                  const T& val12, const T& val13, const T& val14) {
      if (is_empty()) return *this;
      T *ptrd, *ptre = end() - 14;
      for (ptrd = _data; ptrd<ptre; ) {
        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5;
        *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9; *(ptrd++) = val10; *(ptrd++) = val11;
        *(ptrd++) = val12; *(ptrd++) = val13; *(ptrd++) = val14;
      }
      ptre+=14;
      switch (ptre - ptrd) {
      case 14 : *(--ptre) = val13; // fallthrough
      case 13 : *(--ptre) = val12; // fallthrough
      case 12 : *(--ptre) = val11; // fallthrough
      case 11 : *(--ptre) = val10; // fallthrough
      case 10 : *(--ptre) = val9; // fallthrough
      case 9 : *(--ptre) = val8; // fallthrough
      case 8 : *(--ptre) = val7; // fallthrough
      case 7 : *(--ptre) = val6; // fallthrough
      case 6 : *(--ptre) = val5; // fallthrough
      case 5 : *(--ptre) = val4; // fallthrough
      case 4 : *(--ptre) = val3; // fallthrough
      case 3 : *(--ptre) = val2; // fallthrough
      case 2 : *(--ptre) = val1; // fallthrough
      case 1 : *(--ptre) = val0; // fallthrough
      }
      return *this;

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

    //! Crop image region \overloading.
    CImg<T>& crop(const int x0, const int y0,
                  const int x1, const int y1,
                  const unsigned int boundary_conditions=0) {
      return crop(x0,y0,0,0,x1,y1,_depth - 1,_spectrum - 1,boundary_conditions);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    template<typename t1, typename t2>
    CImg<intT> get_matchpatch(const CImg<T>& patch_image,
                              const unsigned int patch_width,
                              const unsigned int patch_height,
                              const unsigned int patch_depth,
                              const unsigned int nb_iterations,
                              const unsigned int nb_randoms,
                              const float occ_penalization,
                              const CImg<t1> &guide,
                              CImg<t2> &matching_score) const {
      return _matchpatch(patch_image,patch_width,patch_height,patch_depth,
                         nb_iterations,nb_randoms,occ_penalization,
                         guide,true,matching_score);

Project: CImg
File: CImg.h

    template<typename t, typename tc>
    CImg<T>& draw_point(const CImg<t>& points,
                        const tc *const color, const float opacity=1) {
      if (is_empty() || !points) return *this;
      switch (points._height) {
      case 0 : case 1 :
        throw CImgArgumentException(_cimg_instance
                                    "draw_point(): Invalid specified point set (%u,%u,%u,%u,%p).",
                                    cimg_instance,
                                    points._width,points._height,points._depth,points._spectrum,points._data);
      case 2 : {
        cimg_forX(points,i) draw_point((int)points(i,0),(int)points(i,1),color,opacity);
      } break;
      default : {
        cimg_forX(points,i) draw_point((int)points(i,0),(int)points(i,1),(int)points(i,2),color,opacity);
      }
      }
      return *this;

Project: CImg
File: CImg.h

    **/
    int height() const {
      return (int)_height;

Project: CImg
File: CImg.h

    template<typename t>
    CImg<_cimg_Tt> get_append(const CImg<T>& img, const char axis='x', const float align=0) const {
      if (is_empty()) return +img;
      if (!img) return +*this;
      return CImgList<_cimg_Tt>(*this,true).insert(img).get_append(axis,align);

Project: CImg
File: CImg.h

    **/
    CImg<T>& blur_patch(const float sigma_s, const float sigma_p, const unsigned int patch_size=3,
                        const unsigned int lookup_size=4, const float smoothness=0, const bool is_fast_approx=true) {
      if (is_empty() || !patch_size || !lookup_size) return *this;
      return get_blur_patch(sigma_s,sigma_p,patch_size,lookup_size,smoothness,is_fast_approx).move_to(*this);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    **/
    bool is_sameXY(const CImgDisplay& disp) const {
      return is_sameXY(disp._width,disp._height);

Project: CImg
File: CImg.h


    const CImg<T>& _save_pandore(std::FILE *const file, const char *const filename,
                                 const unsigned int colorspace) const {

#define __cimg_save_pandore_case(dtype) \
       dtype *buffer = new dtype[size()]; \
       const T *ptrs = _data; \
       cimg_foroff(*this,off) *(buffer++) = (dtype)(*(ptrs++)); \
       buffer-=size(); \
       cimg::fwrite(buffer,size(),nfile); \
       delete[] buffer

#define _cimg_save_pandore_case(sy,sz,sv,stype,id) \
      if (!saved && (sy?(sy==_height):true) && (sz?(sz==_depth):true) && \
          (sv?(sv==_spectrum):true) && !std::strcmp(stype,pixel_type())) { \
	unsigned int *iheader = (unsigned int*)(header + 12); \
	nbdims = _save_pandore_header_length((*iheader=id),dims,colorspace); \
	cimg::fwrite(header,36,nfile); \
        if (sizeof(unsigned long)==4) { CImg<ulongT> ndims(5); \
          for (int d = 0; d<5; ++d) ndims[d] = (unsigned long)dims[d]; cimg::fwrite(ndims._data,nbdims,nfile); } \
        else if (sizeof(unsigned int)==4) { CImg<uintT> ndims(5); \
          for (int d = 0; d<5; ++d) ndims[d] = (unsigned int)dims[d]; cimg::fwrite(ndims._data,nbdims,nfile); } \
        else if (sizeof(unsigned short)==4) { CImg<ushortT> ndims(5); \
          for (int d = 0; d<5; ++d) ndims[d] = (unsigned short)dims[d]; cimg::fwrite(ndims._data,nbdims,nfile); } \
        else throw CImgIOException(_cimg_instance \
                                   "save_pandore(): Unsupported datatype for file '%s'.",\
                                   cimg_instance, \
                                   filename?filename:"(FILE*)"); \
	if (id==2 || id==5 || id==8 || id==16 || id==19 || id==22 || id==26 || id==30) { \
          __cimg_save_pandore_case(unsigned char); \
	} else if (id==3 || id==6 || id==9 || id==17 || id==20 || id==23 || id==27 || id==31) { \
          if (sizeof(unsigned long)==4) { __cimg_save_pandore_case(unsigned long); } \
          else if (sizeof(unsigned int)==4) { __cimg_save_pandore_case(unsigned int); } \
          else if (sizeof(unsigned short)==4) { __cimg_save_pandore_case(unsigned short); } \
          else throw CImgIOException(_cimg_instance \
                                     "save_pandore(): Unsupported datatype for file '%s'.",\
                                     cimg_instance, \
                                     filename?filename:"(FILE*)"); \
	} else if (id==4 || id==7 || id==10 || id==18 || id==21 || id==25 || id==29 || id==33) { \
          if (sizeof(double)==4) { __cimg_save_pandore_case(double); } \
          else if (sizeof(float)==4) { __cimg_save_pandore_case(float); } \
          else throw CImgIOException(_cimg_instance \
                                     "save_pandore(): Unsupported datatype for file '%s'.",\
                                     cimg_instance, \
                                     filename?filename:"(FILE*)"); \
        } \
	saved = true; \
      }

      if (!file && !filename)
        throw CImgArgumentException(_cimg_instance
                                    "save_pandore(): Specified filename is (null).",
                                    cimg_instance);
      if (is_empty()) { cimg::fempty(file,filename); return *this; }

      std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
      unsigned char header[36] = { 'P','A','N','D','O','R','E','0','4',0,0,0,
                                   0,0,0,0,'C','I','m','g',0,0,0,0,0,
                                   'N','o',' ','d','a','t','e',0,0,0,0 };
      unsigned int nbdims, dims[5] = { 0 };
      bool saved = false;
      _cimg_save_pandore_case(1,1,1,"unsigned char",2);
      _cimg_save_pandore_case(1,1,1,"char",3);
      _cimg_save_pandore_case(1,1,1,"unsigned short",3);
      _cimg_save_pandore_case(1,1,1,"short",3);
      _cimg_save_pandore_case(1,1,1,"unsigned int",3);
      _cimg_save_pandore_case(1,1,1,"int",3);
      _cimg_save_pandore_case(1,1,1,"unsigned int64",3);
      _cimg_save_pandore_case(1,1,1,"int64",3);
      _cimg_save_pandore_case(1,1,1,"float",4);
      _cimg_save_pandore_case(1,1,1,"double",4);

      _cimg_save_pandore_case(0,1,1,"unsigned char",5);
      _cimg_save_pandore_case(0,1,1,"char",6);
      _cimg_save_pandore_case(0,1,1,"unsigned short",6);
      _cimg_save_pandore_case(0,1,1,"short",6);
      _cimg_save_pandore_case(0,1,1,"unsigned int",6);
      _cimg_save_pandore_case(0,1,1,"int",6);
      _cimg_save_pandore_case(0,1,1,"unsigned int64",6);
      _cimg_save_pandore_case(0,1,1,"int64",6);
      _cimg_save_pandore_case(0,1,1,"float",7);
      _cimg_save_pandore_case(0,1,1,"double",7);

      _cimg_save_pandore_case(0,0,1,"unsigned char",8);
      _cimg_save_pandore_case(0,0,1,"char",9);
      _cimg_save_pandore_case(0,0,1,"unsigned short",9);
      _cimg_save_pandore_case(0,0,1,"short",9);
      _cimg_save_pandore_case(0,0,1,"unsigned int",9);
      _cimg_save_pandore_case(0,0,1,"int",9);
      _cimg_save_pandore_case(0,0,1,"unsigned int64",9);
      _cimg_save_pandore_case(0,0,1,"int64",9);
      _cimg_save_pandore_case(0,0,1,"float",10);
      _cimg_save_pandore_case(0,0,1,"double",10);

      _cimg_save_pandore_case(0,1,3,"unsigned char",16);
      _cimg_save_pandore_case(0,1,3,"char",17);
      _cimg_save_pandore_case(0,1,3,"unsigned short",17);
      _cimg_save_pandore_case(0,1,3,"short",17);
      _cimg_save_pandore_case(0,1,3,"unsigned int",17);
      _cimg_save_pandore_case(0,1,3,"int",17);
      _cimg_save_pandore_case(0,1,3,"unsigned int64",17);
      _cimg_save_pandore_case(0,1,3,"int64",17);
      _cimg_save_pandore_case(0,1,3,"float",18);
      _cimg_save_pandore_case(0,1,3,"double",18);

      _cimg_save_pandore_case(0,0,3,"unsigned char",19);
      _cimg_save_pandore_case(0,0,3,"char",20);
      _cimg_save_pandore_case(0,0,3,"unsigned short",20);
      _cimg_save_pandore_case(0,0,3,"short",20);
      _cimg_save_pandore_case(0,0,3,"unsigned int",20);
      _cimg_save_pandore_case(0,0,3,"int",20);
      _cimg_save_pandore_case(0,0,3,"unsigned int64",20);
      _cimg_save_pandore_case(0,0,3,"int64",20);
      _cimg_save_pandore_case(0,0,3,"float",21);
      _cimg_save_pandore_case(0,0,3,"double",21);

      _cimg_save_pandore_case(1,1,0,"unsigned char",22);
      _cimg_save_pandore_case(1,1,0,"char",23);
      _cimg_save_pandore_case(1,1,0,"unsigned short",23);
      _cimg_save_pandore_case(1,1,0,"short",23);
      _cimg_save_pandore_case(1,1,0,"unsigned int",23);
      _cimg_save_pandore_case(1,1,0,"int",23);
      _cimg_save_pandore_case(1,1,0,"unsigned int64",23);
      _cimg_save_pandore_case(1,1,0,"int64",23);
      _cimg_save_pandore_case(1,1,0,"float",25);
      _cimg_save_pandore_case(1,1,0,"double",25);

      _cimg_save_pandore_case(0,1,0,"unsigned char",26);
      _cimg_save_pandore_case(0,1,0,"char",27);
      _cimg_save_pandore_case(0,1,0,"unsigned short",27);
      _cimg_save_pandore_case(0,1,0,"short",27);
      _cimg_save_pandore_case(0,1,0,"unsigned int",27);
      _cimg_save_pandore_case(0,1,0,"int",27);
      _cimg_save_pandore_case(0,1,0,"unsigned int64",27);
      _cimg_save_pandore_case(0,1,0,"int64",27);
      _cimg_save_pandore_case(0,1,0,"float",29);
      _cimg_save_pandore_case(0,1,0,"double",29);

      _cimg_save_pandore_case(0,0,0,"unsigned char",30);
      _cimg_save_pandore_case(0,0,0,"char",31);
      _cimg_save_pandore_case(0,0,0,"unsigned short",31);
      _cimg_save_pandore_case(0,0,0,"short",31);
      _cimg_save_pandore_case(0,0,0,"unsigned int",31);
      _cimg_save_pandore_case(0,0,0,"int",31);
      _cimg_save_pandore_case(0,0,0,"unsigned int64",31);
      _cimg_save_pandore_case(0,0,0,"int64",31);
      _cimg_save_pandore_case(0,0,0,"float",33);
      _cimg_save_pandore_case(0,0,0,"double",33);

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

Project: CImg
File: CImg.h

    CImgException(const char *const format, ...):_message(0) { _cimg_exception_err("CImgException",true); }
    CImgException(const CImgException& e):std::exception(e) {
      const size_t size = std::strlen(e._message);
      _message = new char[size + 1];
      std::strncpy(_message,e._message,size);
      _message[size] = 0;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    **/
    CImgDisplay& toggle_fullscreen(const bool force_redraw=true) {
      return assign(_width,_height,0,3,force_redraw);

Project: CImg
File: CImg.h

      static half min() { return (half)-65504; }

Project: CImg
File: CImg.h

    **/
    inline cimg_ulong time() {
#if cimg_OS==1
      struct timeval st_time;
      gettimeofday(&st_time,0);
      return (cimg_ulong)(st_time.tv_usec/1000 + st_time.tv_sec*1000);
#elif cimg_OS==2
      SYSTEMTIME st_time;
      GetLocalTime(&st_time);
      return (cimg_ulong)(st_time.wMilliseconds + 1000*(st_time.wSecond + 60*(st_time.wMinute + 60*st_time.wHour)));
#else
      return 0;
#endif

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

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

      return _linear_atX(fx,y,z,c);

Project: CImg
File: CImg.h

      _functor4d_streamline2d_directed(const CImg<T>& pref):ref(pref) {}
      float operator()(const float x, const float y, const float z, const unsigned int c) const {
        return c<2?(float)ref._linear_atXY(x,y,(int)z,c):0;

Project: CImg
File: CImg.h

    template<typename tf>
    static CImg<floatT> elevation3d(CImgList<tf>& primitives, const char *const expression,
                                    const float x0, const float y0, const float x1, const float y1,
                                    const int size_x=256, const int size_y=256) {
      const _functor2d_expr func(expression);
      return elevation3d(primitives,func,x0,y0,x1,y1,size_x,size_y);

Project: CImg
File: CImg.h

    **/
    CImgDisplay& set_wheel(const int amplitude) {
      _wheel+=amplitude;
      _is_event = amplitude?true:false;
      if (amplitude) {
#if cimg_display==1
        pthread_cond_broadcast(&cimg::X11_attr().wait_event);
#elif cimg_display==2
        SetEvent(cimg::Win32_attr().wait_event);
#endif
      }
      return *this;

Project: CImg
File: CImg.h

     **/
    T& atX(const int x, const int y=0, const int z=0, const int c=0) {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "atX(): Empty instance.",
                                    cimg_instance);
      return _atX(x,y,z,c);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<Tfloat> get_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) const {
      return CImg<Tfloat>(*this,false).blur_bilateral(guide,sigma_x,sigma_y,sigma_z,sigma_r,
                                                      sampling_x,sampling_y,sampling_z,sampling_r);

Project: CImg
File: CImg.h

    template<typename t>
    void eval(CImg<t>& output, const char *const expression,
              const double x=0, const double y=0, const double z=0, const double c=0,
              const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) const {
      _eval(output,0,expression,x,y,z,c,list_inputs,list_outputs);

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 longT whd = (longT)width()*height()*depth();
      cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,4096))
      for (longT 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

    template<typename tf, typename tfunc>
    static CImg<floatT> elevation3d(CImgList<tf>& primitives, const tfunc& func,
                                    const float x0, const float y0, const float x1, const float y1,
                                    const int size_x=256, const int size_y=256) {
      const float
        nx0 = x0<x1?x0:x1, ny0 = y0<y1?y0:y1,
        nx1 = x0<x1?x1:x0, ny1 = y0<y1?y1:y0;
      const unsigned int
        _nsize_x = (unsigned int)(size_x>=0?size_x:(nx1-nx0)*-size_x/100),
        nsize_x = _nsize_x?_nsize_x:1, nsize_x1 = nsize_x - 1,
        _nsize_y = (unsigned int)(size_y>=0?size_y:(ny1-ny0)*-size_y/100),
        nsize_y = _nsize_y?_nsize_y:1, nsize_y1 = nsize_y - 1;
      if (nsize_x<2 || nsize_y<2)
        throw CImgArgumentException("CImg<%s>::elevation3d(): Invalid specified size (%d,%d).",
                                    pixel_type(),
                                    nsize_x,nsize_y);

      CImg<floatT> vertices(nsize_x*nsize_y,3);
      floatT *ptr_x = vertices.data(0,0), *ptr_y = vertices.data(0,1), *ptr_z = vertices.data(0,2);
      for (unsigned int y = 0; y<nsize_y; ++y) {
        const float Y = ny0 + y*(ny1-ny0)/nsize_y1;
        for (unsigned int x = 0; x<nsize_x; ++x) {
          const float X = nx0 + x*(nx1-nx0)/nsize_x1;
          *(ptr_x++) = (float)x;
          *(ptr_y++) = (float)y;
          *(ptr_z++) = (float)func(X,Y);
        }
      }
      primitives.assign(nsize_x1*nsize_y1,1,4);
      for (unsigned int p = 0, y = 0; y<nsize_y1; ++y) {
        const unsigned int yw = y*nsize_x;
        for (unsigned int x = 0; x<nsize_x1; ++x) {
          const unsigned int xpyw = x + yw, xpyww = xpyw + nsize_x;
          primitives[p++].fill(xpyw,xpyww,xpyww + 1,xpyw + 1);
        }
      }
      return vertices;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    //! Access to a pixel value, using Dirichlet boundary conditions for the X-coordinate \const.
    T atX(const int x, const int y, const int z, const int c, const T& out_value) const {
      return (x<0 || x>=width())?out_value:(*this)(x,y,z,c);

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

    template<typename ti, typename tm>
    CImg<T>& draw_image(const int x0, const int y0, const int z0, const int c0,
                        const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
                        const float mask_max_value=1) {
      if (is_empty() || !sprite || !mask) return *this;
      if (is_overlapped(sprite)) return draw_image(x0,y0,z0,c0,+sprite,mask,opacity,mask_max_value);
      if (is_overlapped(mask)) return draw_image(x0,y0,z0,c0,sprite,+mask,opacity,mask_max_value);
      if (mask._width!=sprite._width || mask._height!=sprite._height || mask._depth!=sprite._depth)
        throw CImgArgumentException(_cimg_instance
                                    "draw_image(): Sprite (%u,%u,%u,%u,%p) and mask (%u,%u,%u,%u,%p) have "
                                    "incompatible dimensions.",
                                    cimg_instance,
                                    sprite._width,sprite._height,sprite._depth,sprite._spectrum,sprite._data,
                                    mask._width,mask._height,mask._depth,mask._spectrum,mask._data);

      const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bc = (c0<0);
      const int
        lX = sprite.width() - (x0 + sprite.width()>width()?x0 + sprite.width() - width():0) + (bx?x0:0),
        lY = sprite.height() - (y0 + sprite.height()>height()?y0 + sprite.height() - height():0) + (by?y0:0),
        lZ = sprite.depth() - (z0 + sprite.depth()>depth()?z0 + sprite.depth() - depth():0) + (bz?z0:0),
        lC = sprite.spectrum() - (c0 + sprite.spectrum()>spectrum()?c0 + sprite.spectrum() - spectrum():0) + (bc?c0:0);
      const ulongT
        coff = (bx?-x0:0) +
        (by?-y0*(ulongT)mask.width():0) +
        (bz?-z0*(ulongT)mask.width()*mask.height():0) +
        (bc?-c0*(ulongT)mask.width()*mask.height()*mask.depth():0),
        ssize = (ulongT)mask.width()*mask.height()*mask.depth()*mask.spectrum();
      const ti *ptrs = sprite._data + coff;
      const tm *ptrm = mask._data + coff;
      const ulongT
        offX = (ulongT)_width - lX,
        soffX = (ulongT)sprite._width - lX,
        offY = (ulongT)_width*(_height - lY),
        soffY = (ulongT)sprite._width*(sprite._height - lY),
        offZ = (ulongT)_width*_height*(_depth - lZ),
        soffZ = (ulongT)sprite._width*sprite._height*(sprite._depth - lZ);
      if (lX>0 && lY>0 && lZ>0 && lC>0) {
	T *ptrd = data(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,c0<0?0:c0);
        for (int c = 0; c<lC; ++c) {
          ptrm = mask._data + (ptrm - mask._data)%ssize;
          for (int z = 0; z<lZ; ++z) {
            for (int y = 0; y<lY; ++y) {
              for (int x = 0; x<lX; ++x) {
                const float mopacity = (float)(*(ptrm++)*opacity),
                  nopacity = cimg::abs(mopacity), copacity = mask_max_value - std::max(mopacity,0.f);
                *ptrd = (T)((nopacity*(*(ptrs++)) + *ptrd*copacity)/mask_max_value);
                ++ptrd;
              }
              ptrd+=offX; ptrs+=soffX; ptrm+=soffX;
            }
            ptrd+=offY; ptrs+=soffY; ptrm+=soffY;
          }
          ptrd+=offZ; ptrs+=soffZ; ptrm+=soffZ;
        }
      }
      return *this;

Project: CImg
File: CImg.h

     **/
    T& max() {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "max(): Empty instance.",
                                    cimg_instance);
      T *ptr_max = _data;
      T max_value = *ptr_max;
      cimg_for(*this,ptrs,T) if (*ptrs>max_value) max_value = *(ptr_max=ptrs);
      return *ptr_max;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    template<typename tp, typename tf, typename tc, typename tz>
    CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
                           const CImg<tp>& vertices, const CImgList<tf>& primitives,
                           const CImgList<tc>& colors,
                           const unsigned int render_type,
                           const bool is_double_sided, const float focale,
                           const float lightx, const float lighty, const float lightz,
                           const float specular_lightness, const float specular_shininess,
                           const float g_opacity, CImg<tz>& zbuffer) {
      return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg<floatT>::const_empty(),
                           render_type,is_double_sided,focale,lightx,lighty,lightz,
                           specular_lightness,specular_shininess,g_opacity,zbuffer);

Project: CImg
File: CImg.h

    template<typename T>
    inline void getri(int &N, T *lapA, int *IPIV, T* WORK, int &LWORK, int &INFO) {
      dgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO);

Project: CImg
File: CImg.h

    //! Linearly normalize pixel values \newinstance.
    CImg<Tfloat> get_normalize(const T& min_value, const T& max_value) const {
      return CImg<Tfloat>(*this,false).normalize((Tfloat)min_value,(Tfloat)max_value);

Project: CImg
File: CImg.h

    //! Advanced copy constructor \specialization.
    CImg(const CImg<T>& img, const bool is_shared) {
      const size_t siz = (size_t)img.size();
      if (img._data && siz) {
        _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum;
        _is_shared = is_shared;
        if (_is_shared) _data = const_cast<T*>(img._data);
        else {
          try { _data = new T[siz]; } catch (...) {
            _width = _height = _depth = _spectrum = 0; _data = 0;
            throw CImgInstanceException(_cimg_instance
                                        "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
                                        cimg_instance,
                                        cimg::strbuffersize(sizeof(T)*img._width*img._height*img._depth*img._spectrum),
                                        img._width,img._height,img._depth,img._spectrum);
          }
          std::memcpy(_data,img._data,siz*sizeof(T));
        }
      } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; }

Project: CImg
File: CImg.h

    **/
    CImg<T> get_slice(const int z0) const {
      return get_slices(z0,z0);

Project: CImg
File: CImg.h


      static double mp_shift(_cimg_math_parser& mp) {
        double *const ptrd = &_mp_arg(1) + 1;
        const double *const ptrs = &_mp_arg(2) + 1;
        const unsigned int siz = (unsigned int)mp.opcode[3];
        const int
          shift = (int)_mp_arg(4),
          boundary_conditions = (int)_mp_arg(5);
        CImg<doubleT>(ptrd,siz,1,1,1,true) = CImg<doubleT>(ptrs,siz,1,1,1,true).shift(shift,0,0,0,boundary_conditions);
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

    **/
    CImg<T>& load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
      return _load_rgb(0,filename,dimw,dimh);

Project: CImg
File: CImg.h

    //! Rotate volumetric image with arbitrary angle and axis \newinstance.
    CImg<T> get_rotate(const float u, const float v, const float w, const float angle,
                       const unsigned int interpolation, const unsigned int boundary_conditions) const {
      if (is_empty()) return *this;
      CImg<T> res;
      const float
        w1 = _width - 1, h1 = _height - 1, d1 = _depth -1,
        w2 = 0.5f*w1, h2 = 0.5f*h1, d2 = 0.5f*d1;
      CImg<floatT> R = CImg<floatT>::rotation_matrix(u,v,w,angle);
      const CImg<Tfloat>
        X = R*CImg<Tfloat>(8,3,1,1,
                           0.f,w1,w1,0.f,0.f,w1,w1,0.f,
                           0.f,0.f,h1,h1,0.f,0.f,h1,h1,
                           0.f,0.f,0.f,0.f,d1,d1,d1,d1);
      float
        xm, xM = X.get_shared_row(0).max_min(xm),
        ym, yM = X.get_shared_row(1).max_min(ym),
        zm, zM = X.get_shared_row(2).max_min(zm);
      const int
        dx = (int)cimg::round(xM - xm),
        dy = (int)cimg::round(yM - ym),
        dz = (int)cimg::round(zM - zm);
      R.transpose();
      res.assign(1 + dx,1 + dy,1 + dz,_spectrum);
      const float rw2 = 0.5f*dx, rh2 = 0.5f*dy, rd2 = 0.5f*dz;
      _rotate(res,R,interpolation,boundary_conditions,w2,h2,d2,rw2,rh2,rd2);
      return res;

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>=(cimg_openmp_sizefactor)*128 &&
                                                           _height*_depth*_spectrum>=128))
            for (int p = 0; p<(int)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>=(cimg_openmp_sizefactor)*128 &&
                                                           _width*_depth*_spectrum>=128))
            for (int p = 0; p<(int)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>=(cimg_openmp_sizefactor)*128 &&
                                                           _width*_height*_spectrum>=128))
            for (int p = 0; p<(int)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>=(cimg_openmp_sizefactor)*128 &&
                                                           _width*_height*_depth>=128))
            for (int p = 0; p<(int)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

    //! Raise each pixel value to a power, specified from an expression \newinstance.
    CImg<Tfloat> get_pow(const char *const expression) const {
      return CImg<Tfloat>(*this,false).pow(expression);

Project: CImg
File: CImg.h


      static double mp_image_sort(_cimg_math_parser& mp) {
        const bool is_increasing = (bool)_mp_arg(3);
        const unsigned int
          ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listout.width()),
          axis = (unsigned int)_mp_arg(4);
        cimg::mutex(6);
        CImg<T> &img = mp.listout[ind];
        img.sort(is_increasing,
                 axis==0 || axis=='x'?'x':
                 axis==1 || axis=='y'?'y':
                 axis==2 || axis=='z'?'z':
                 axis==3 || axis=='c'?'c':0);
        cimg::mutex(6,0);
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

    **/
    CImgList<Tfloat> get_SVD(const bool sorting=true,
                             const unsigned int max_iteration=40, const float lambda=0) const {
      CImgList<Tfloat> res(3);
      SVD(res[0],res[1],res[2],sorting,max_iteration,lambda);
      return res;

Project: CImg
File: CImg.h

      }
      static bool is_nan(const double val) { // Custom version that works with '-ffast-math'
        if (sizeof(double)==8) {
          cimg_uint64 u;
          std::memcpy(&u,&val,sizeof(double));
          return ((unsigned int)(u>>32)&0x7fffffff) + ((unsigned int)u!=0)>0x7ff00000;
        }
#ifdef isnan
        return (bool)isnan(val);
#else
        return !(val==val);
#endif

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);
      cimg::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=cimg::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=cimg::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

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

Project: CImg
File: CImg.h

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

#ifndef cimg_use_minc2
     cimg::unused(imitate_file);
     return save_other(filename);
#else
     minc::minc_1_writer wtr;
     if (imitate_file)
       wtr.open(filename, imitate_file);
     else {
       minc::minc_info di;
       if (width()) di.push_back(minc::dim_info(width(),width()*0.5,-1,minc::dim_info::DIM_X));
       if (height()) di.push_back(minc::dim_info(height(),height()*0.5,-1,minc::dim_info::DIM_Y));
       if (depth()) di.push_back(minc::dim_info(depth(),depth()*0.5,-1,minc::dim_info::DIM_Z));
       if (spectrum()) di.push_back(minc::dim_info(spectrum(),spectrum()*0.5,-1,minc::dim_info::DIM_TIME));
       wtr.open(filename,di,1,NC_FLOAT,0);
     }
     if (cimg::type<T>::string()==cimg::type<unsigned char>::string())
       wtr.setup_write_byte();
     else if (cimg::type<T>::string()==cimg::type<int>::string())
       wtr.setup_write_int();
     else if (cimg::type<T>::string()==cimg::type<double>::string())
       wtr.setup_write_double();
     else
       wtr.setup_write_float();
     minc::save_standard_volume(wtr, this->_data);
     return *this;
#endif

Project: CImg
File: CImg.h

    template<typename T>
    inline T median(T val0, T val1) {
      return (val0 + val1)/2;

Project: CImg
File: CImg.h

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

      return CImg<T>(_data + beg,_width,y1 - y0 + 1,1,1,true);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    //! Convert pixel values from Lab to RGB color spaces.
    CImg<T>& LabtoRGB(const bool use_D65=true) {
      return LabtoXYZ().XYZtoRGB(use_D65);

Project: CImg
File: CImg.h

       \param[out] n Index of image containing the pixel value, if test succeeds.
       \note If true, set coordinates (n).
    **/
    template<typename t>

Project: CImg
File: CImg.h

      return _load_cimg(file,0,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1);
    }

    //! Load a sub-image list from a (non compressed) .cimg file \newinstance.
    static CImgList<T> get_load_cimg(std::FILE *const file,
                                     const unsigned int n0, const unsigned int n1,
                                     const unsigned int x0, const unsigned int y0,
                                     const unsigned int z0, const unsigned int c0,

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);
      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) {
        if (_window_width!=dimx || _window_height!=dimy) {
          RECT rect; rect.left = rect.top = 0; rect.right = (LONG)dimx - 1; rect.bottom = (LONG)dimy - 1;
          AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
          const int cwidth = rect.right - rect.left + 1, cheight = rect.bottom - rect.top + 1;
          SetWindowPos(_window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS);
        }
        if (_width!=dimx || _height!=dimy) {
          unsigned int *const ndata = new unsigned int[dimx*dimy];
          if (force_redraw) _render_resize(_data,_width,_height,ndata,dimx,dimy);
          else std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);
          delete[] _data;
          _data = ndata;
          _bmi.bmiHeader.biWidth = (LONG)dimx;
          _bmi.bmiHeader.biHeight = -(int)dimy;
          _width = dimx;
          _height = dimy;
        }
        _window_width = dimx; _window_height = dimy;
        show();
      }
      _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


      static double mp_set_Ioff_s(_cimg_math_parser& mp) {
        CImg<T> &img = mp.imgout;
        const longT
          off = (longT)_mp_arg(2),
          whd = (longT)img.width()*img.height()*img.depth();
        const T val = (T)_mp_arg(1);
        if (off>=0 && off<whd) {
          T *ptrd = &img[off];
          cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }
        }
        return _mp_arg(1);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h


    CImg<T>& _load_raw(std::FILE *const file, const char *const filename,
		       const unsigned int size_x, const unsigned int size_y,
		       const unsigned int size_z, const unsigned int size_c,
		       const bool is_multiplexed, const bool invert_endianness,
                       const ulongT offset) {
      if (!file && !filename)
        throw CImgArgumentException(_cimg_instance
                                    "load_raw(): Specified filename is (null).",
                                    cimg_instance);
      if (cimg::is_directory(filename))
        throw CImgArgumentException(_cimg_instance
                                    "load_raw(): Specified filename '%s' is a directory.",
                                    cimg_instance,filename);

      ulongT siz = (ulongT)size_x*size_y*size_z*size_c;
      unsigned int
        _size_x = size_x,
        _size_y = size_y,
        _size_z = size_z,
        _size_c = size_c;
      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
      if (!siz) {  // Retrieve file size
        const longT fpos = cimg::ftell(nfile);
        if (fpos<0) throw CImgArgumentException(_cimg_instance
                                                "load_raw(): Cannot determine size of input file '%s'.",
                                                cimg_instance,filename?filename:"(FILE*)");
        cimg::fseek(nfile,0,SEEK_END);
        siz = cimg::ftell(nfile)/sizeof(T);
		_size_y = (unsigned int)siz;
        _size_x = _size_z = _size_c = 1;
        cimg::fseek(nfile,fpos,SEEK_SET);
      }
      cimg::fseek(nfile,offset,SEEK_SET);
      assign(_size_x,_size_y,_size_z,_size_c,0);
      if (siz && (!is_multiplexed || size_c==1)) {
        cimg::fread(_data,siz,nfile);
        if (invert_endianness) cimg::invert_endianness(_data,siz);
      } else if (siz) {
        CImg<T> buf(1,1,1,_size_c);
        cimg_forXYZ(*this,x,y,z) {
          cimg::fread(buf._data,_size_c,nfile);
          if (invert_endianness) cimg::invert_endianness(buf._data,_size_c);
          set_vector_at(buf,x,y,z);
        }
      }
      if (!file) cimg::fclose(nfile);
      return *this;

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

    /**
       \param file File to write data to.
       \param is_compressed Tells if data compression must be enabled.

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    //! Return a pointer to a located pixel value \const.
    const T* data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) const {
      return const_cast<CImg<T>*>(this)->data(x,y,z,c);

Project: CImg
File: CImg.h

    **/
    CImg<T>& load_parrec(const char *const filename, const char axis='c', const float align=0) {
      CImgList<T> list;
      list.load_parrec(filename);
      if (list._width==1) return list[0].move_to(*this);
      return assign(list.get_append(axis,align));

Project: CImg
File: CImg.h

    **/
    const CImg<T>& save_cimg(const char *const filename, const bool is_compressed=false) const {
      CImgList<T>(*this,true).save_cimg(filename,is_compressed);
      return *this;

Project: CImg
File: CImg.h

    **/
    CImg<T>& autocrop(const T *const color=0, const char *const axes="zyx") {
      if (is_empty()) return *this;
      if (!color) { // Guess color
        const CImg<T> col1 = get_vector_at(0,0,0);
        const unsigned int w = _width, h = _height, d = _depth, s = _spectrum;
        autocrop(col1,axes);
        if (_width==w && _height==h && _depth==d && _spectrum==s) {
          const CImg<T> col2 = get_vector_at(w - 1,h - 1,d - 1);
          autocrop(col2,axes);
        }
        return *this;
      }
      for (const char *s = axes; *s; ++s) {
        const char axis = cimg::lowercase(*s);
        switch (axis) {
        case 'x' : {
	  int x0 = width(), x1 = -1;
	  cimg_forC(*this,c) {
	    const CImg<intT> coords = get_shared_channel(c)._autocrop(color[c],'x');
	    const int nx0 = coords[0], nx1 = coords[1];
	    if (nx0>=0 && nx1>=0) { x0 = std::min(x0,nx0); x1 = std::max(x1,nx1); }
	  }
          if (x0==width() && x1==-1) return assign(); else crop(x0,x1);
	} break;
        case 'y' : {
	  int y0 = height(), y1 = -1;
	  cimg_forC(*this,c) {
	    const CImg<intT> coords = get_shared_channel(c)._autocrop(color[c],'y');
	    const int ny0 = coords[0], ny1 = coords[1];
	    if (ny0>=0 && ny1>=0) { y0 = std::min(y0,ny0); y1 = std::max(y1,ny1); }
	  }
          if (y0==height() && y1==-1) return assign(); else crop(0,y0,_width - 1,y1);
	} break;
        default : {
	  int z0 = depth(), z1 = -1;
	  cimg_forC(*this,c) {
	    const CImg<intT> coords = get_shared_channel(c)._autocrop(color[c],'z');
	    const int nz0 = coords[0], nz1 = coords[1];
	    if (nz0>=0 && nz1>=0) { z0 = std::min(z0,nz0); z1 = std::max(z1,nz1); }
	  }
	  if (z0==depth() && z1==-1) return assign(); else crop(0,0,z0,_width - 1,_height - 1,z1);
	}
        }
      }
      return *this;

Project: CImg
File: CImg.h

    // Convert filename as a Windows-style filename (short path name).
    inline void winformat_string(char *const str) {
      if (str && *str) {
#if cimg_OS==2
        char *const nstr = new char[MAX_PATH];
        if (GetShortPathNameA(str,nstr,MAX_PATH)) std::strcpy(str,nstr);
        delete[] nstr;
#endif
      }

Project: CImg
File: CImg.h


    inline double option(const char *const name, const int argc, const char *const *const argv,
                         const double defaut, const char *const usage=0) {
      const char *const s = cimg::option(name,argc,argv,(char*)0);
      const double res = s?cimg::atof(s):defaut;
      char *const tmp = new char[256];
      cimg_snprintf(tmp,256,"%g",res);
      cimg::option(name,0,0,tmp,usage);
      delete[] tmp;
      return res;

Project: CImg
File: CImg.h

    **/
    CImg<T>& shift(const int delta_x, const int delta_y=0, const int delta_z=0, const int delta_c=0,
                   const unsigned int boundary_conditions=0) {
      if (is_empty()) return *this;
      if (boundary_conditions==3)
        return get_crop(-delta_x,-delta_y,-delta_z,-delta_c,
                        width() - delta_x - 1,
                        height() - delta_y - 1,
                        depth() - delta_z - 1,
                        spectrum() - delta_c - 1,3).move_to(*this);
      if (delta_x) // Shift along X-axis
        switch (boundary_conditions) {
        case 2 : { // Periodic
          const int ml = cimg::mod(-delta_x,width()), ndelta_x = (ml<=width()/2)?ml:(ml-width());
          if (!ndelta_x) return *this;
          CImg<T> buf(cimg::abs(ndelta_x));
          if (ndelta_x>0) cimg_forYZC(*this,y,z,c) {
              std::memcpy(buf,data(0,y,z,c),ndelta_x*sizeof(T));
              std::memmove(data(0,y,z,c),data(ndelta_x,y,z,c),(_width-ndelta_x)*sizeof(T));
              std::memcpy(data(_width-ndelta_x,y,z,c),buf,ndelta_x*sizeof(T));
            } else cimg_forYZC(*this,y,z,c) {
              std::memcpy(buf,data(_width + ndelta_x,y,z,c),-ndelta_x*sizeof(T));
              std::memmove(data(-ndelta_x,y,z,c),data(0,y,z,c),(_width + ndelta_x)*sizeof(T));
              std::memcpy(data(0,y,z,c),buf,-ndelta_x*sizeof(T));
            }
        } break;
        case 1 : // Neumann
          if (delta_x<0) {
            const int ndelta_x = (-delta_x>=width())?width() - 1:-delta_x;
            if (!ndelta_x) return *this;
            cimg_forYZC(*this,y,z,c) {
              std::memmove(data(0,y,z,c),data(ndelta_x,y,z,c),(_width-ndelta_x)*sizeof(T));
              T *ptrd = data(_width - 1,y,z,c);
              const T val = *ptrd;
              for (int l = 0; l<ndelta_x - 1; ++l) *(--ptrd) = val;
            }
          } else {
            const int ndelta_x = (delta_x>=width())?width() - 1:delta_x;
            if (!ndelta_x) return *this;
            cimg_forYZC(*this,y,z,c) {
              std::memmove(data(ndelta_x,y,z,c),data(0,y,z,c),(_width-ndelta_x)*sizeof(T));
              T *ptrd = data(0,y,z,c);
              const T val = *ptrd;
              for (int l = 0; l<ndelta_x - 1; ++l) *(++ptrd) = val;
            }
          }
          break;
        default : // Dirichlet
          if (delta_x<=-width() || delta_x>=width()) return fill((T)0);
          if (delta_x<0) cimg_forYZC(*this,y,z,c) {
              std::memmove(data(0,y,z,c),data(-delta_x,y,z,c),(_width + delta_x)*sizeof(T));
              std::memset(data(_width + delta_x,y,z,c),0,-delta_x*sizeof(T));
            } else cimg_forYZC(*this,y,z,c) {
              std::memmove(data(delta_x,y,z,c),data(0,y,z,c),(_width-delta_x)*sizeof(T));
              std::memset(data(0,y,z,c),0,delta_x*sizeof(T));
            }
        }

      if (delta_y) // Shift along Y-axis
        switch (boundary_conditions) {
        case 2 : { // Periodic
          const int ml = cimg::mod(-delta_y,height()), ndelta_y = (ml<=height()/2)?ml:(ml-height());
          if (!ndelta_y) return *this;
          CImg<T> buf(width(),cimg::abs(ndelta_y));
          if (ndelta_y>0) cimg_forZC(*this,z,c) {
              std::memcpy(buf,data(0,0,z,c),_width*ndelta_y*sizeof(T));
              std::memmove(data(0,0,z,c),data(0,ndelta_y,z,c),_width*(_height-ndelta_y)*sizeof(T));
              std::memcpy(data(0,_height-ndelta_y,z,c),buf,_width*ndelta_y*sizeof(T));
            } else cimg_forZC(*this,z,c) {
              std::memcpy(buf,data(0,_height + ndelta_y,z,c),-ndelta_y*_width*sizeof(T));
              std::memmove(data(0,-ndelta_y,z,c),data(0,0,z,c),_width*(_height + ndelta_y)*sizeof(T));
              std::memcpy(data(0,0,z,c),buf,-ndelta_y*_width*sizeof(T));
            }
        } break;
        case 1 : // Neumann
          if (delta_y<0) {
            const int ndelta_y = (-delta_y>=height())?height() - 1:-delta_y;
            if (!ndelta_y) return *this;
            cimg_forZC(*this,z,c) {
              std::memmove(data(0,0,z,c),data(0,ndelta_y,z,c),_width*(_height-ndelta_y)*sizeof(T));
              T *ptrd = data(0,_height-ndelta_y,z,c), *ptrs = data(0,_height - 1,z,c);
              for (int l = 0; l<ndelta_y - 1; ++l) { std::memcpy(ptrd,ptrs,_width*sizeof(T)); ptrd+=_width; }
            }
          } else {
            const int ndelta_y = (delta_y>=height())?height() - 1:delta_y;
            if (!ndelta_y) return *this;
            cimg_forZC(*this,z,c) {
              std::memmove(data(0,ndelta_y,z,c),data(0,0,z,c),_width*(_height-ndelta_y)*sizeof(T));
              T *ptrd = data(0,1,z,c), *ptrs = data(0,0,z,c);
              for (int l = 0; l<ndelta_y - 1; ++l) { std::memcpy(ptrd,ptrs,_width*sizeof(T)); ptrd+=_width; }
            }
          }
          break;
        default : // Dirichlet
          if (delta_y<=-height() || delta_y>=height()) return fill((T)0);
          if (delta_y<0) cimg_forZC(*this,z,c) {
              std::memmove(data(0,0,z,c),data(0,-delta_y,z,c),_width*(_height + delta_y)*sizeof(T));
              std::memset(data(0,_height + delta_y,z,c),0,-delta_y*_width*sizeof(T));
            } else cimg_forZC(*this,z,c) {
              std::memmove(data(0,delta_y,z,c),data(0,0,z,c),_width*(_height-delta_y)*sizeof(T));
              std::memset(data(0,0,z,c),0,delta_y*_width*sizeof(T));
            }
        }

      if (delta_z) // Shift along Z-axis
        switch (boundary_conditions) {
        case 2 : { // Periodic
          const int ml = cimg::mod(-delta_z,depth()), ndelta_z = (ml<=depth()/2)?ml:(ml-depth());
          if (!ndelta_z) return *this;
          CImg<T> buf(width(),height(),cimg::abs(ndelta_z));
          if (ndelta_z>0) cimg_forC(*this,c) {
              std::memcpy(buf,data(0,0,0,c),_width*_height*ndelta_z*sizeof(T));
              std::memmove(data(0,0,0,c),data(0,0,ndelta_z,c),_width*_height*(_depth-ndelta_z)*sizeof(T));
              std::memcpy(data(0,0,_depth-ndelta_z,c),buf,_width*_height*ndelta_z*sizeof(T));
            } else cimg_forC(*this,c) {
              std::memcpy(buf,data(0,0,_depth + ndelta_z,c),-ndelta_z*_width*_height*sizeof(T));
              std::memmove(data(0,0,-ndelta_z,c),data(0,0,0,c),_width*_height*(_depth + ndelta_z)*sizeof(T));
              std::memcpy(data(0,0,0,c),buf,-ndelta_z*_width*_height*sizeof(T));
            }
        } break;
        case 1 : // Neumann
          if (delta_z<0) {
            const int ndelta_z = (-delta_z>=depth())?depth() - 1:-delta_z;
            if (!ndelta_z) return *this;
            cimg_forC(*this,c) {
              std::memmove(data(0,0,0,c),data(0,0,ndelta_z,c),_width*_height*(_depth-ndelta_z)*sizeof(T));
              T *ptrd = data(0,0,_depth-ndelta_z,c), *ptrs = data(0,0,_depth - 1,c);
              for (int l = 0; l<ndelta_z - 1; ++l) {
                std::memcpy(ptrd,ptrs,_width*_height*sizeof(T)); ptrd+=(ulongT)_width*_height;
              }
            }
          } else {
            const int ndelta_z = (delta_z>=depth())?depth() - 1:delta_z;
            if (!ndelta_z) return *this;
            cimg_forC(*this,c) {
              std::memmove(data(0,0,ndelta_z,c),data(0,0,0,c),_width*_height*(_depth-ndelta_z)*sizeof(T));
              T *ptrd = data(0,0,1,c), *ptrs = data(0,0,0,c);
              for (int l = 0; l<ndelta_z - 1; ++l) {
                std::memcpy(ptrd,ptrs,_width*_height*sizeof(T)); ptrd+=(ulongT)_width*_height;
              }
            }
          }
          break;
        default : // Dirichlet
          if (delta_z<=-depth() || delta_z>=depth()) return fill((T)0);
          if (delta_z<0) cimg_forC(*this,c) {
              std::memmove(data(0,0,0,c),data(0,0,-delta_z,c),_width*_height*(_depth + delta_z)*sizeof(T));
              std::memset(data(0,0,_depth + delta_z,c),0,_width*_height*(-delta_z)*sizeof(T));
            } else cimg_forC(*this,c) {
              std::memmove(data(0,0,delta_z,c),data(0,0,0,c),_width*_height*(_depth-delta_z)*sizeof(T));
              std::memset(data(0,0,0,c),0,delta_z*_width*_height*sizeof(T));
            }
        }

      if (delta_c) // Shift along C-axis
        switch (boundary_conditions) {
        case 2 : { // Periodic
          const int ml = cimg::mod(-delta_c,spectrum()), ndelta_c = (ml<=spectrum()/2)?ml:(ml-spectrum());
          if (!ndelta_c) return *this;
          CImg<T> buf(width(),height(),depth(),cimg::abs(ndelta_c));
          if (ndelta_c>0) {
            std::memcpy(buf,_data,_width*_height*_depth*ndelta_c*sizeof(T));
            std::memmove(_data,data(0,0,0,ndelta_c),_width*_height*_depth*(_spectrum-ndelta_c)*sizeof(T));
            std::memcpy(data(0,0,0,_spectrum-ndelta_c),buf,_width*_height*_depth*ndelta_c*sizeof(T));
          } else {
            std::memcpy(buf,data(0,0,0,_spectrum + ndelta_c),-ndelta_c*_width*_height*_depth*sizeof(T));
            std::memmove(data(0,0,0,-ndelta_c),_data,_width*_height*_depth*(_spectrum + ndelta_c)*sizeof(T));
            std::memcpy(_data,buf,-ndelta_c*_width*_height*_depth*sizeof(T));
          }
        } break;
        case 1 : // Neumann
          if (delta_c<0) {
            const int ndelta_c = (-delta_c>=spectrum())?spectrum() - 1:-delta_c;
            if (!ndelta_c) return *this;
            std::memmove(_data,data(0,0,0,ndelta_c),_width*_height*_depth*(_spectrum-ndelta_c)*sizeof(T));
            T *ptrd = data(0,0,0,_spectrum-ndelta_c), *ptrs = data(0,0,0,_spectrum - 1);
            for (int l = 0; l<ndelta_c - 1; ++l) {
              std::memcpy(ptrd,ptrs,_width*_height*_depth*sizeof(T)); ptrd+=(ulongT)_width*_height*_depth;
            }
          } else {
            const int ndelta_c = (delta_c>=spectrum())?spectrum() - 1:delta_c;
            if (!ndelta_c) return *this;
            std::memmove(data(0,0,0,ndelta_c),_data,_width*_height*_depth*(_spectrum-ndelta_c)*sizeof(T));
            T *ptrd = data(0,0,0,1);
            for (int l = 0; l<ndelta_c - 1; ++l) {
              std::memcpy(ptrd,_data,_width*_height*_depth*sizeof(T)); ptrd+=(ulongT)_width*_height*_depth;
            }
          }
          break;
        default : // Dirichlet
          if (delta_c<=-spectrum() || delta_c>=spectrum()) return fill((T)0);
          if (delta_c<0) {
            std::memmove(_data,data(0,0,0,-delta_c),_width*_height*_depth*(_spectrum + delta_c)*sizeof(T));
            std::memset(data(0,0,0,_spectrum + delta_c),0,_width*_height*_depth*(-delta_c)*sizeof(T));
          } else {
            std::memmove(data(0,0,0,delta_c),_data,_width*_height*_depth*(_spectrum-delta_c)*sizeof(T));
            std::memset(_data,0,delta_c*_width*_height*_depth*sizeof(T));
          }
        }
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    template<typename T>
    inline void invert_endianness(T* const buffer, const cimg_ulong size) {
      if (size) switch (sizeof(T)) {
        case 1 : break;
        case 2 : {
          for (unsigned short *ptr = (unsigned short*)buffer + size; ptr>(unsigned short*)buffer; ) {
            const unsigned short val = *(--ptr);
            *ptr = (unsigned short)((val>>8) | ((val<<8)));
          }
        } break;
        case 4 : {
          for (unsigned int *ptr = (unsigned int*)buffer + size; ptr>(unsigned int*)buffer; ) {
            const unsigned int val = *(--ptr);
            *ptr = (val>>24) | ((val>>8)&0xff00) | ((val<<8)&0xff0000) | (val<<24);
          }
        } break;
        case 8 : {
          const cimg_uint64
            m0 = (cimg_uint64)0xff, m1 = m0<<8, m2 = m0<<16, m3 = m0<<24,
            m4 = m0<<32, m5 = m0<<40, m6 = m0<<48, m7 = m0<<56;
          for (cimg_uint64 *ptr = (cimg_uint64*)buffer + size; ptr>(cimg_uint64*)buffer; ) {
            const cimg_uint64 val = *(--ptr);
            *ptr =  (((val&m7)>>56) | ((val&m6)>>40) | ((val&m5)>>24) | ((val&m4)>>8) |
                     ((val&m3)<<8) |((val&m2)<<24) | ((val&m1)<<40) | ((val&m0)<<56));
          }
        } break;
        default : {
          for (T* ptr = buffer + size; ptr>buffer; ) {
            unsigned char *pb = (unsigned char*)(--ptr), *pe = pb + sizeof(T);
            for (int i = 0; i<(int)sizeof(T)/2; ++i) swap(*(pb++),*(--pe));
          }
        }
        }

Project: CImg
File: CImg.h

    **/
    inline cimg_ulong tic() {
      return cimg::tictoc(true);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

#if cimg_verbosity>=3
    T& operator()(const unsigned int x, const unsigned int y=0,
                  const unsigned int z=0, const unsigned int c=0) {
      const ulongT off = (ulongT)offset(x,y,z,c);
      if (!_data || off>=size()) {
        cimg::warn(_cimg_instance
                   "operator(): Invalid pixel request, at coordinates (%d,%d,%d,%d) [offset=%u].",
                   cimg_instance,
                   (int)x,(int)y,(int)z,(int)c,off);
        return *_data;
      }
      else return _data[off];

Project: CImg
File: CImg.h

    **/
    bool is_sameYZ(const unsigned int size_y, const unsigned int size_z) const {
      return _height==size_y && _depth==size_z;

Project: CImg
File: CImg.h

    **/
    T& atXYZ(const int x, const int y, const int z, const int c=0) {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "atXYZ(): Empty instance.",
                                    cimg_instance);
      return _atXYZ(x,y,z,c);

Project: CImg
File: CImg.h

    // Return a visualizable uchar8 image for display routines.
    CImg<ucharT> _get_select(const CImgDisplay& disp, const int normalization,
                             const int x, const int y, const int z) const {
      if (is_empty()) return CImg<ucharT>(1,1,1,1,0);
      const CImg<T> crop = get_shared_channels(0,std::min(2,spectrum() - 1));
      CImg<Tuchar> img2d;
      if (_depth>1) {
        const int mdisp = std::min(disp.screen_width(),disp.screen_height());
        if (depth()>mdisp) {
          crop.get_resize(-100,-100,mdisp,-100,0).move_to(img2d);
          img2d.projections2d(x,y,z*img2d._depth/_depth);
        } else crop.get_projections2d(x,y,z).move_to(img2d);
      } else CImg<Tuchar>(crop,false).move_to(img2d);

      // Check for inf and NaN values.
      if (cimg::type<T>::is_float() && normalization) {
        bool is_inf = false, is_nan = false;
        cimg_for(img2d,ptr,Tuchar)
          if (cimg::type<T>::is_inf(*ptr)) { is_inf = true; break; }
          else if (cimg::type<T>::is_nan(*ptr)) { is_nan = true; break; }
        if (is_inf || is_nan) {
          Tint m0 = (Tint)cimg::type<T>::max(), M0 = (Tint)cimg::type<T>::min();
          if (!normalization) { m0 = 0; M0 = 255; }
          else if (normalization==2) { m0 = (Tint)disp._min; M0 = (Tint)disp._max; }
          else
            cimg_for(img2d,ptr,Tuchar)
              if (!cimg::type<T>::is_inf(*ptr) && !cimg::type<T>::is_nan(*ptr)) {
                if (*ptr<(Tuchar)m0) m0 = *ptr;
                if (*ptr>(Tuchar)M0) M0 = *ptr;
              }
          const T
            val_minf = (T)(normalization==1 || normalization==3?m0 - (M0 - m0)*20 - 1:m0),
            val_pinf = (T)(normalization==1 || normalization==3?M0 + (M0 - m0)*20 + 1:M0);
          if (is_nan)
            cimg_for(img2d,ptr,Tuchar)
              if (cimg::type<T>::is_nan(*ptr)) *ptr = val_minf; // Replace NaN values
          if (is_inf)
            cimg_for(img2d,ptr,Tuchar)
              if (cimg::type<T>::is_inf(*ptr)) *ptr = (float)*ptr<0?val_minf:val_pinf; // Replace +-inf values
        }
      }

      switch (normalization) {
      case 1 : img2d.normalize((ucharT)0,(ucharT)255); break;
      case 2 : {
        const float m = disp._min, M = disp._max;
        (img2d-=m)*=255.f/(M - m>0?M - m:1);
      } break;
      case 3 :
        if (cimg::type<T>::is_float()) img2d.normalize((ucharT)0,(ucharT)255);
        else {
          const float m = (float)cimg::type<T>::min(), M = (float)cimg::type<T>::max();
          (img2d-=m)*=255.f/(M - m>0?M - m:1);
        } break;
      }
      if (img2d.spectrum()==2) img2d.channels(0,2);
      return img2d;

Project: CImg
File: CImg.h


    CImgDisplay& set_title(const char *const format, ...) {
      if (is_empty()) return *this;
      char *const tmp = new char[1024];
      va_list ap;
      va_start(ap, format);
      cimg_vsnprintf(tmp,1024,format,ap);
      va_end(ap);
      if (!std::strcmp(_title,tmp)) { delete[] tmp; return *this; }
      delete[] _title;
      const unsigned int s = (unsigned int)std::strlen(tmp) + 1;
      _title = new char[s];
      std::memcpy(_title,tmp,s*sizeof(char));
      Display *const dpy = cimg::X11_attr().display;
      cimg_lock_display();
      XStoreName(dpy,_window,tmp);
      cimg_unlock_display();
      delete[] tmp;
      return *this;

Project: CImg
File: CImg.h

    template<> struct type<cimg_uint64> {

Project: CImg
File: CImg.h

    //! Return a 5x5 diagonal matrix containing specified coefficients.
    static CImg<T> diagonal(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) {
      return matrix(a0,0,0,0,0,0,a1,0,0,0,0,0,a2,0,0,0,0,0,a3,0,0,0,0,0,a4);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& assign(const t *const values, const unsigned int size_x, const unsigned int size_y,
                    const unsigned int size_z, const unsigned int size_c, const bool is_shared) {
      if (is_shared)
        throw CImgArgumentException(_cimg_instance
                                    "assign(): Invalid assignment request of shared instance from (%s*) buffer"
                                    "(pixel types are different).",
                                    cimg_instance,
                                    CImg<t>::pixel_type());
      return assign(values,size_x,size_y,size_z,size_c);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& map(const CImg<t>& colormap, const unsigned int boundary_conditions=0) {
      return get_map(colormap,boundary_conditions).move_to(*this);

Project: CImg
File: CImg.h

    **/
    CImg<T>& columns(const int x0, const int x1) {
      return get_columns(x0,x1).move_to(*this);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T> get_sort(CImg<t>& permutations, const bool is_increasing=true) const {
      return (+*this).sort(permutations,is_increasing);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


      static double mp_sinh(_cimg_math_parser& mp) {
        return std::sinh(_mp_arg(2));

Project: CImg
File: CImg.h

    template<> struct type<int> {

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

    //! Load image from a PNG file \overloading.
    CImg<T>& load_png(std::FILE *const file, unsigned int *const bits_per_pixel=0) {
      return _load_png(file,0,bits_per_pixel);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    template<typename T>
    inline T median(T val0, T val1, T val2) {
      return std::max(std::min(val0,val1),std::min(val2,std::max(val0,val1)));

Project: CImg
File: CImg.h

      static cimg_int64 inf() { return max(); }
      static cimg_int64 cut(const double val) {
        return val<(double)min()?min():val>(double)max()?max():(cimg_int64)val;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


      static double mp_sinc(_cimg_math_parser& mp) {
        return cimg::sinc(_mp_arg(2));

Project: CImg
File: CImg.h


      static double mp_isnan(_cimg_math_parser& mp) {
        return (double)cimg::type<double>::is_nan(_mp_arg(2));

Project: CImg
File: CImg.h

    template<typename t>
    void _load_tiff_separate(TIFF *const tif, const uint16 samplesperpixel, const uint32 nx, const uint32 ny) {
      t *buf = (t*)_TIFFmalloc(TIFFStripSize(tif));
      if (buf) {
        uint32 row, rowsperstrip = (uint32)-1;
        TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
        for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
          for (row = 0; row<ny; row+= rowsperstrip) {
            uint32 nrow = (row + rowsperstrip>ny?ny - row:rowsperstrip);
            tstrip_t strip = TIFFComputeStrip(tif, row, vv);
            if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
              _TIFFfree(buf); TIFFClose(tif);
              throw CImgIOException(_cimg_instance
                                    "load_tiff(): Invalid strip in file '%s'.",
                                    cimg_instance,
                                    TIFFFileName(tif));
            }
            const t *ptr = buf;
            for (unsigned int rr = 0;rr<nrow; ++rr)
              for (unsigned int cc = 0; cc<nx; ++cc)
                (*this)(cc,row + rr,vv) = (T)*(ptr++);
          }
        _TIFFfree(buf);
      }

Project: CImg
File: CImg.h

       \param[out] x X-coordinate of the pixel value, if test succeeds.
       \note If true, set coordinates (n,x).
    **/
    template<typename t>

Project: CImg
File: CImg.h

    // Custom random number generator (allow re-entrance).
    inline cimg_ulong& rng() { // Used as a shared global number for rng
      static cimg_ulong rng = 0xB16B00B5U;
      return rng;

Project: CImg
File: CImg.h

     **/
    CImg<T>& matrix() {
      const ulongT siz = size();
      switch (siz) {
      case 1 : break;
      case 4 : _width = _height = 2; break;
      case 9 : _width = _height = 3; break;
      case 16 : _width = _height = 4; break;
      case 25 : _width = _height = 5; break;
      case 36 : _width = _height = 6; break;
      case 49 : _width = _height = 7; break;
      case 64 : _width = _height = 8; break;
      case 81 : _width = _height = 9; break;
      case 100 : _width = _height = 10; break;
      default : {
        ulongT i = 11, i2 = i*i;
        while (i2<siz) { i2+=2*i + 1; ++i; }
        if (i2==siz) _width = _height = i;
        else throw CImgInstanceException(_cimg_instance
                                         "matrix(): Invalid instance size %u (should be a square integer).",
                                         cimg_instance,
                                         siz);
      }
      }
      return *this;

Project: CImg
File: CImg.h

    //! Construct a 2D representation of a 3D image, with XY,XZ and YZ views \inplace.
    CImg<T>& projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0) {
      if (_depth<2) return *this;
      return get_projections2d(x0,y0,z0).move_to(*this);

Project: CImg
File: CImg.h

    //! Return pointer to the pos-th image of the list \const.
    const CImg<T> *data(const unsigned int l) const {
      return _data + l;

Project: CImg
File: CImg.h


      static double mp_list_set_ixyzc(_cimg_math_parser& mp) {
        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
        CImg<T> &img = mp.listout[ind];
        const int
          x = (int)_mp_arg(3), y = (int)_mp_arg(4),
          z = (int)_mp_arg(5), c = (int)_mp_arg(6);
        const double val = _mp_arg(1);
        if (x>=0 && x<img.width() && y>=0 && y<img.height() &&
            z>=0 && z<img.depth() && c>=0 && c<img.spectrum())
          img(x,y,z,c) = (T)val;
        return val;

Project: CImg
File: CImg.h

    template<typename t, typename tc>
    CImg<T>& draw_graph(const CImg<t>& data,
                        const tc *const color, const float opacity=1,
                        const unsigned int plot_type=1, const int vertex_type=1,
                        const double ymin=0, const double ymax=0, const unsigned int pattern=~0U) {
      if (is_empty() || _height<=1) return *this;
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_graph(): Specified color is (null).",
                                    cimg_instance);

      // Create shaded colors for displaying bar plots.
      CImg<tc> color1, color2;
      if (plot_type==3) {
        color1.assign(_spectrum); color2.assign(_spectrum);
        cimg_forC(*this,c) {
          color1[c] = (tc)std::min((float)cimg::type<tc>::max(),(float)color[c]*1.2f);
          color2[c] = (tc)(color[c]*0.4f);
        }
      }

      // Compute min/max and normalization factors.
      const ulongT
        siz = data.size(),
        _siz1 = siz - (plot_type!=3),
        siz1 = _siz1?_siz1:1;
      const unsigned int
        _width1 = _width - (plot_type!=3),
        width1 = _width1?_width1:1;
      double m = ymin, M = ymax;
      if (ymin==ymax) m = (double)data.max_min(M);
      if (m==M) { --m; ++M; }
      const float ca = (float)(M-m)/(_height - 1);
      bool init_hatch = true;

      // Draw graph edges
      switch (plot_type%4) {
      case 1 : { // Segments
        int oX = 0, oY = (int)((data[0] - m)/ca);
        if (siz==1) {
          const int Y = (int)((*data - m)/ca);
          draw_line(0,Y,width() - 1,Y,color,opacity,pattern);
        } else {
          const float fx = (float)_width/siz1;
          for (ulongT off = 1; off<siz; ++off) {
            const int
              X = (int)(off*fx) - 1,
              Y = (int)((data[off]-m)/ca);
            draw_line(oX,oY,X,Y,color,opacity,pattern,init_hatch);
            oX = X; oY = Y;
            init_hatch = false;
          }
        }
      } break;
      case 2 : { // Spline
        const CImg<t> ndata(data._data,siz,1,1,1,true);
        int oY = (int)((data[0] - m)/ca);
        cimg_forX(*this,x) {
          const int Y = (int)((ndata._cubic_atX((float)x*siz1/width1)-m)/ca);
          if (x>0) draw_line(x,oY,x + 1,Y,color,opacity,pattern,init_hatch);
          init_hatch = false;
          oY = Y;
        }
      } break;
      case 3 : { // Bars
        const int Y0 = (int)(-m/ca);
        const float fx = (float)_width/siz1;
        int oX = 0;
        cimg_foroff(data,off) {
          const int
            X = (int)((off + 1)*fx) - 1,
            Y = (int)((data[off] - m)/ca);
          draw_rectangle(oX,Y0,X,Y,color,opacity).
            draw_line(oX,Y,oX,Y0,color2.data(),opacity).
            draw_line(oX,Y0,X,Y0,Y<=Y0?color2.data():color1.data(),opacity).
            draw_line(X,Y,X,Y0,color1.data(),opacity).
            draw_line(oX,Y,X,Y,Y<=Y0?color1.data():color2.data(),opacity);
          oX = X + 1;
        }
      } break;
      default : break; // No edges
      }

      // Draw graph points
      const unsigned int wb2 = plot_type==3?_width1/(2*siz):0;
      const float fx = (float)_width1/siz1;
      switch (vertex_type%8) {
      case 1 : { // Point
        cimg_foroff(data,off) {
          const int
            X = (int)(off*fx + wb2),
            Y = (int)((data[off]-m)/ca);
          draw_point(X,Y,color,opacity);
        }
      } break;
      case 2 : { // Straight Cross
        cimg_foroff(data,off) {
          const int
            X = (int)(off*fx + wb2),
            Y = (int)((data[off]-m)/ca);
          draw_line(X - 3,Y,X + 3,Y,color,opacity).draw_line(X,Y - 3,X,Y + 3,color,opacity);
        }
      } break;
      case 3 : { // Diagonal Cross
        cimg_foroff(data,off) {
          const int
            X = (int)(off*fx + wb2),
            Y = (int)((data[off]-m)/ca);
          draw_line(X - 3,Y - 3,X + 3,Y + 3,color,opacity).draw_line(X - 3,Y + 3,X + 3,Y - 3,color,opacity);
        }
      } break;
      case 4 : { // Filled Circle
        cimg_foroff(data,off) {
          const int
            X = (int)(off*fx + wb2),
            Y = (int)((data[off]-m)/ca);
          draw_circle(X,Y,3,color,opacity);
        }
      } break;
      case 5 : { // Outlined circle
        cimg_foroff(data,off) {
          const int
            X = (int)(off*fx + wb2),
            Y = (int)((data[off]-m)/ca);
          draw_circle(X,Y,3,color,opacity,~0U);
        }
      } break;
      case 6 : { // Square
        cimg_foroff(data,off) {
          const int
            X = (int)(off*fx + wb2),
            Y = (int)((data[off]-m)/ca);
          draw_rectangle(X - 3,Y - 3,X + 3,Y + 3,color,opacity,~0U);
        }
      } break;
      case 7 : { // Diamond
        cimg_foroff(data,off) {
          const int
            X = (int)(off*fx + wb2),
            Y = (int)((data[off]-m)/ca);
          draw_line(X,Y - 4,X + 4,Y,color,opacity).
            draw_line(X + 4,Y,X,Y + 4,color,opacity).
            draw_line(X,Y + 4,X - 4,Y,color,opacity).
            draw_line(X - 4,Y,X,Y - 4,color,opacity);
        }
      } break;
      default : break; // No points
      }
      return *this;

Project: CImg
File: CImg.h

    template<typename tz, typename tc>
    CImg<T>& draw_triangle(CImg<tz>& zbuffer,
                           int x0, int y0, const float z0,
                           int x1, int y1, const float z1,
                           int x2, int y2, const float z2,
                           const tc *const color, const float opacity=1,
                           const float brightness=1) {
      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_triangle(): Specified color is (null).",
                                    cimg_instance);
      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);

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

      const int
        w1 = width() - 1, h1 = height() - 1,
        dx01 = x1 - x0, dx02 = x2 - x0, dx12 = x2 - x1,
        dy01 = std::max(1,y1 - y0), dy02 = std::max(1,y2 - y0), dy12 = std::max(1,y2 - y1),
        cy0 = cimg::cut(y0,0,h1), cy2 = cimg::cut(y2,0,h1),
        hdy01 = dy01*cimg::sign(dx01)/2, hdy02 = dy02*cimg::sign(dx02)/2, hdy12 = dy12*cimg::sign(dx12)/2;
      const float diz01 = iz1 - iz0, diz02 = iz2 - iz0, diz12 = iz2 - iz1;

      const float cbs = cimg::cut(brightness,0,2);
      cimg_init_scanline(opacity);

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

          for (int x = cxm; x<cxM; ++x) {
            const int xxm = x - xm;
            const float iz = izm + dizmM*xxm/dxmM;
            if (iz>=*ptrz) {
              *ptrz = (tz)iz;
              cimg_forC(*this,c) {
                const Tfloat val = cbs<=1?color[c]*cbs:(2 - cbs)*color[c] + (cbs - 1)*_sc_maxval;
                ptrd[c*_sc_whd] = (T)(opacity>=1?val:val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity);
              }
            }
            ++ptrd; ++ptrz;
          }
        }
      }
      return *this;

Project: CImg
File: CImg.h

    //! Convert pixel values from YUV to RGB color spaces \newinstance.
    CImg<Tuchar> get_YUVtoRGB() const {
      return CImg< Tuchar>(*this,false).YUVtoRGB();

Project: CImg
File: CImg.h

       \param y Y-coordinate of the checked pixel value.
       \param z Z-coordinate of the checked pixel value.
       \param c C-coordinate of the checked pixel value.
    **/
    bool containsNXYZC(const int n, const int x=0, const int y=0, const int z=0, const int c=0) const {

Project: CImg
File: CImg.h


      static double mp_bitwise_right_shift(_cimg_math_parser& mp) {
        return (double)((longT)_mp_arg(2)>>(unsigned int)_mp_arg(3));

Project: CImg
File: CImg.h

    template<typename t>
    void eval(CImg<t> &output, const char *const expression,
              const double x=0, const double y=0, const double z=0, const double c=0,
              const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) {
      _eval(output,this,expression,x,y,z,c,list_inputs,list_outputs);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    template<typename t1, typename t2>
    CImg<T>& draw_quiver(const CImg<t1>& flow,
                         const CImg<t2>& color, const float opacity=1,
                         const unsigned int sampling=25, const float factor=-20,
                         const bool is_arrow=true, const unsigned int pattern=~0U) {
      if (is_empty()) return *this;
      if (!flow || flow._spectrum!=2)
        throw CImgArgumentException(_cimg_instance
                                    "draw_quiver(): Invalid dimensions of specified flow (%u,%u,%u,%u,%p).",
                                    cimg_instance,
                                    flow._width,flow._height,flow._depth,flow._spectrum,flow._data);
      if (sampling<=0)
        throw CImgArgumentException(_cimg_instance
                                    "draw_quiver(): Invalid sampling value %g "
                                    "(should be >0)",
                                    cimg_instance,
                                    sampling);
      const bool colorfield = (color._width==flow._width && color._height==flow._height &&
                               color._depth==1 && color._spectrum==_spectrum);
      if (is_overlapped(flow)) return draw_quiver(+flow,color,opacity,sampling,factor,is_arrow,pattern);
      float vmax,fact;
      if (factor<=0) {
        float m, M = (float)flow.get_norm(2).max_min(m);
        vmax = (float)std::max(cimg::abs(m),cimg::abs(M));
        if (!vmax) vmax = 1;
        fact = -factor;
      } else { fact = factor; vmax = 1; }

      for (unsigned int y = sampling/2; y<_height; y+=sampling)
        for (unsigned int x = sampling/2; x<_width; x+=sampling) {
          const unsigned int X = x*flow._width/_width, Y = y*flow._height/_height;
          float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax;
          if (is_arrow) {
            const int xx = (int)(x + u), yy = (int)(y + v);
            if (colorfield) draw_arrow(x,y,xx,yy,color.get_vector_at(X,Y)._data,opacity,45,sampling/5.f,pattern);
            else draw_arrow(x,y,xx,yy,color._data,opacity,45,sampling/5.f,pattern);
          } else {
            if (colorfield)
              draw_line((int)(x - 0.5*u),(int)(y - 0.5*v),(int)(x + 0.5*u),(int)(y + 0.5*v),
                        color.get_vector_at(X,Y)._data,opacity,pattern);
            else draw_line((int)(x - 0.5*u),(int)(y - 0.5*v),(int)(x + 0.5*u),(int)(y + 0.5*v),
                           color._data,opacity,pattern);
          }
        }
      return *this;

Project: CImg
File: CImg.h

    //! Return a shared-memory image referencing one channel of the image instance \const.
    const CImg<T> get_shared_channel(const unsigned int c0) const {
      return get_shared_channels(c0,c0);

Project: CImg
File: CImg.h


    void _map_window() {
      Display *const dpy = cimg::X11_attr().display;
      bool is_exposed = false, is_mapped = false;
      XWindowAttributes attr;
      XEvent event;
      XMapRaised(dpy,_window);
      do { // Wait for the window to be mapped
        XWindowEvent(dpy,_window,StructureNotifyMask | ExposureMask,&event);
        switch (event.type) {
        case MapNotify : is_mapped = true; break;
        case Expose : is_exposed = true; break;
        }
      } while (!is_exposed || !is_mapped);
      do { // Wait for the window to be visible
        XGetWindowAttributes(dpy,_window,&attr);
        if (attr.map_state!=IsViewable) { XSync(dpy,0); cimg::sleep(10); }
      } while (attr.map_state!=IsViewable);
      _window_x = attr.x;
      _window_y = attr.y;

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h


      static double mp_cos(_cimg_math_parser& mp) {
        return std::cos(_mp_arg(2));

Project: CImg
File: CImg.h


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

      std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
      if (!is_multiplexed) cimg::fwrite(_data,size(),nfile);
      else {
        CImg<T> buf(_spectrum);
        cimg_forXYZ(*this,x,y,z) {
          cimg_forC(*this,c) buf[c] = (*this)(x,y,z,c);
          cimg::fwrite(buf._data,_spectrum,nfile);
        }
      }
      if (!file) cimg::fclose(nfile);
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    /**
       \param font_height Height of the desired font (exact match for 13,23,53,103).
       \param is_variable_width Decide if the font has a variable (\c true) or fixed (\c false) width.
    **/
    static const CImgList<ucharT>& font(const unsigned int requested_height, const bool is_variable_width=true) {
      if (!requested_height) return CImgList<ucharT>::const_empty();
      cimg::mutex(11);
      static const unsigned char font_resizemap[] = {
        0, 4, 7, 9, 11, 13, 15, 17, 19, 21, 22, 24, 26, 27, 29, 30,
        32, 33, 35, 36, 38, 39, 41, 42, 43, 45, 46, 47, 49, 50, 51, 52,
        54, 55, 56, 58, 59, 60, 61, 62, 64, 65, 66, 67, 68, 69, 71, 72,
        73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
        90, 91, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106,
        107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
        123, 124, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137,
        138, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 148, 149, 150, 151,
        152, 153, 154, 155, 156, 157, 157, 158, 159, 160, 161, 162, 163, 164, 164, 165,
        166, 167, 168, 169, 170, 170, 171, 172, 173, 174, 175, 176, 176, 177, 178, 179,
        180, 181, 181, 182, 183, 184, 185, 186, 186, 187, 188, 189, 190, 191, 191, 192,
        193, 194, 195, 196, 196, 197, 198, 199, 200, 200, 201, 202, 203, 204, 205, 205,
        206, 207, 208, 209, 209, 210, 211, 212, 213, 213, 214, 215, 216, 216, 217, 218,
        219, 220, 220, 221, 222, 223, 224, 224, 225, 226, 227, 227, 228, 229, 230, 231,
        231, 232, 233, 234, 234, 235, 236, 237, 238, 238, 239, 240, 241, 241, 242, 243,
        244, 244, 245, 246, 247, 247, 248, 249, 250, 250, 251, 252, 253, 253, 254, 255 };
      static const char *const *font_data[] = {
        cimg::data_font_small,
        cimg::data_font_normal,
        cimg::data_font_large,
        cimg::data_font_huge };
      static const unsigned int
        font_width[] = { 10,26,52,104 },
        font_height[] = { 13,32,64,128 },
        font_M[] = { 86,91,91,47 },
        font_chunk[] = { sizeof(cimg::data_font_small)/sizeof(char*),
                         sizeof(cimg::data_font_normal)/sizeof(char*),
                         sizeof(cimg::data_font_large)/sizeof(char*),
                         sizeof(cimg::data_font_huge)/sizeof(char*) };
      static const unsigned char font_is_binary[] = { 1,0,0,1 };
      static CImg<ucharT> font_base[4];

      unsigned int ind =
        requested_height<=font_height[0]?0U:
        requested_height<=font_height[1]?1U:
        requested_height<=font_height[2]?2U:3U;

      // Decompress nearest base font data if needed.
      CImg<ucharT> &basef = font_base[ind];
      if (!basef) {
        basef.assign(256*font_width[ind],font_height[ind]);

        unsigned char *ptrd = basef;
        const unsigned char *const ptrde = basef.end();

        // Recompose font data from several chunks, to deal with MS compiler limit with big strings (64 Kb).
        CImg<char> dataf;
        for (unsigned int k = 0; k<font_chunk[ind]; ++k)
          dataf.append(CImg<char>::string(font_data[ind][k],k==font_chunk[ind] - 1,true),'x');

        // Uncompress font data (decode RLE).
        const unsigned int M = font_M[ind];
        if (font_is_binary[ind])
          for (const char *ptrs = dataf; *ptrs; ++ptrs) {
            const int _n = (int)(*ptrs - M - 32), v = _n>=0?255:0, n = _n>=0?_n:-_n;
            if (ptrd + n<=ptrde) { std::memset(ptrd,v,n); ptrd+=n; }
            else { std::memset(ptrd,v,ptrde - ptrd); break; }
          }
        else
          for (const char *ptrs = dataf; *ptrs; ++ptrs) {
            int n = (int)*ptrs - M - 32, v = 0;
            if (n>=0) { v = 85*n; n = 1; }
            else {
              n = -n;
              v = (int)*(++ptrs) - M - 32;
              if (v<0) { v = 0; --ptrs; } else v*=85;
            }
            if (ptrd + n<=ptrde) { std::memset(ptrd,v,n); ptrd+=n; }
            else { std::memset(ptrd,v,ptrde - ptrd); break; }
          }
      }

      // Find optimal font cache location to return.
      static CImgList<ucharT> fonts[16];
      static bool is_variable_widths[16] = { 0 };
      ind = ~0U;
      for (int i = 0; i<16; ++i)
        if (!fonts[i] || (is_variable_widths[i]==is_variable_width && requested_height==fonts[i][0]._height)) {
          ind = (unsigned int)i; break; // Found empty slot or cached font
        }
      if (ind==~0U) { // No empty slots nor existing font in cache
        fonts->assign();
        std::memmove(fonts,fonts + 1,15*sizeof(CImgList<ucharT>));
        std::memmove(is_variable_widths,is_variable_widths + 1,15*sizeof(bool));
        std::memset((void*)(fonts + (ind=15)),0,sizeof(CImgList<ucharT>)); // Free a slot in cache for new font
      }
      CImgList<ucharT> &font = fonts[ind];

      // Render requested font.
      if (!font) {
        const unsigned int padding_x = requested_height<=64?1U:requested_height<=128?2U:3U;
        is_variable_widths[ind] = is_variable_width;
        font = basef.get_split('x',256);
        if (requested_height!=font[0]._height)
          cimglist_for(font,l) {
            font[l].resize(std::max(1U,font[l]._width*requested_height/font[l]._height),requested_height,-100,-100,
                           font[0]._height>requested_height?2:5);
            cimg_for(font[l],ptr,ucharT) *ptr = font_resizemap[*ptr];
          }
        if (is_variable_width) { // Crop font
          cimglist_for(font,l) {
            CImg<ucharT>& letter = font[l];
            int xmin = letter.width(), xmax = 0;
            cimg_forXY(letter,x,y) if (letter(x,y)) { if (x<xmin) xmin = x; if (x>xmax) xmax = x; }
            if (xmin<=xmax) letter.crop(xmin,0,xmax,letter._height - 1);
          }
          font[(int)' '].resize(font[(int)'f']._width,-100,-100,-100,0);
          if (' ' + 256<font.size()) font[' ' + 256].resize(font[(int)'f']._width,-100,-100,-100,0);
          cimglist_for(font,l)
            font[l].resize(std::max(font[(int)';']._width,font[l]._width) + padding_x,
                           -100,1,1,0,0,0.55f);
        } else cimglist_for(font,l) font[l].resize(font[l]._width + padding_x,-100,1,1,0,0,0.55f);
        font.insert(256,0);
        cimglist_for_in(font,0,255,l) font[l].assign(font[l + 256]._width,font[l + 256]._height,1,3,1);

Project: CImg
File: CImg.h


      _cimg_math_parser(const _cimg_math_parser& mp):
        mem(mp.mem),code(mp.code),p_code_end(mp.p_code_end),p_break(mp.p_break),
        imgin(mp.imgin),listin(mp.listin),imgout(mp.imgout),listout(mp.listout),img_stats(mp.img_stats),
        list_stats(mp.list_stats),list_median(mp.list_median),debug_indent(0),result_dim(mp.result_dim),
        break_type(0),constcache_size(0),is_parallelizable(mp.is_parallelizable),is_fill(mp.is_fill),
        need_input_copy(mp.need_input_copy), result(mem._data + (mp.result - mp.mem._data)),
        rng((cimg::_rand(),cimg::rng())),calling_function(0) {

#if cimg_use_openmp!=0
        mem[17] = omp_get_thread_num();
        rng+=omp_get_thread_num();
#endif
        opcode.assign();
        opcode._is_shared = true;

Project: CImg
File: CImg.h

    struct FFTW3_info {
      FFTW3_info() {
        fftw_init_threads();

Project: CImg
File: CImg.h

    **/
    ~CImgDisplay() {
      assign();
      delete[] _keys;
      delete[] _released_keys;

Project: CImg
File: CImg.h


      static double mp_ext(_cimg_math_parser& mp) {
        const unsigned int nb_args = (unsigned int)(mp.opcode[2] - 3)/2;
        CImgList<charT> _str;
        CImg<charT> it;
        for (unsigned int n = 0; n<nb_args; ++n) {
          const unsigned int siz = (unsigned int)mp.opcode[4 + 2*n];
          if (siz) { // Vector argument -> string
            const double *ptr = &_mp_arg(3 + 2*n) + 1;
            unsigned int l = 0;
            while (l<siz && ptr[l]) ++l;
            CImg<doubleT>(ptr,l,1,1,1,true).move_to(_str);
          } else { // Scalar argument -> number
            it.assign(256);
            cimg_snprintf(it,it._width,"%.17g",_mp_arg(3 + 2*n));
            CImg<charT>::string(it,false,true).move_to(_str);
          }
        }
        CImg(1,1,1,1,0).move_to(_str);
        CImg<charT> str = _str>'x';
#ifdef cimg_mp_ext_function
        cimg_mp_ext_function(str);
#endif
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


      static double mp_logical_or(_cimg_math_parser& mp) {
        const bool val_left = (bool)_mp_arg(2);
        const CImg<ulongT> *const p_end = ++mp.p_code + mp.opcode[4];
        if (val_left) { mp.p_code = p_end - 1; return 1; }
        const ulongT mem_right = mp.opcode[3];
        for ( ; mp.p_code<p_end; ++mp.p_code) {
          mp.opcode._data = mp.p_code->_data;
          const ulongT target = mp.opcode[1];
          mp.mem[target] = _cimg_mp_defunc(mp);
        }
        --mp.p_code;
        return (double)(bool)mp.mem[mem_right];

Project: CImg
File: CImg.h

    //! Compute field of diffusion tensors for edge-preserving smoothing \newinstance.
    CImg<Tfloat> get_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) const {
      return CImg<Tfloat>(*this,false).diffusion_tensors(sharpness,anisotropy,alpha,sigma,is_sqrt);

Project: CImg
File: CImg.h

     **/
    CImg<T> operator++(int) {
      const CImg<T> copy(*this,false);
      ++*this;
      return copy;

Project: CImg
File: CImg.h

    //! Compute the histogram of pixel values \newinstance.
    CImg<ulongT> get_histogram(const unsigned int nb_levels, const T& min_value, const T& max_value) const {
      if (!nb_levels || is_empty()) return CImg<ulongT>();
      const double
        vmin = (double)(min_value<max_value?min_value:max_value),
        vmax = (double)(min_value<max_value?max_value:min_value);
      CImg<ulongT> res(nb_levels,1,1,1,0);
      cimg_rof(*this,ptrs,T) {
        const T val = *ptrs;
        if (val>=vmin && val<=vmax) ++res[val==vmax?nb_levels - 1:(unsigned int)((val - vmin)*nb_levels/(vmax - vmin))];
      }
      return res;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    **/
    CImgDisplay& paint() {
      return assign();

Project: CImg
File: CImg.h

    //! Load image sequence from a YUV file \overloading.
    CImg<T>& load_yuv(std::FILE *const file,
                      const unsigned int size_x, const unsigned int size_y=1,
                      const unsigned int chroma_subsampling=444,
                      const unsigned int first_frame=0, const unsigned int last_frame=~0U,
		      const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z') {
      return get_load_yuv(file,size_x,size_y,chroma_subsampling,
                          first_frame,last_frame,step_frame,yuv2rgb,axis).move_to(*this);

Project: CImg
File: CImg.h

    **/
    bool is_sameXYZC(const unsigned int size_x, const unsigned int size_y,
                     const unsigned int size_z, const unsigned int size_c) const {
      return is_sameXYZ(size_x,size_y,size_z) && _spectrum==size_c;

Project: CImg
File: CImg.h

    **/
    bool is_key() const {
      return _is_keyESC || _is_keyF1 || _is_keyF2 || _is_keyF3 ||
        _is_keyF4 || _is_keyF5 || _is_keyF6 || _is_keyF7 ||
        _is_keyF8 || _is_keyF9 || _is_keyF10 || _is_keyF11 ||
        _is_keyF12 || _is_keyPAUSE || _is_key1 || _is_key2 ||
        _is_key3 || _is_key4 || _is_key5 || _is_key6 ||
        _is_key7 || _is_key8 || _is_key9 || _is_key0 ||
        _is_keyBACKSPACE || _is_keyINSERT || _is_keyHOME ||
        _is_keyPAGEUP || _is_keyTAB || _is_keyQ || _is_keyW ||
        _is_keyE || _is_keyR || _is_keyT || _is_keyY ||
        _is_keyU || _is_keyI || _is_keyO || _is_keyP ||
        _is_keyDELETE || _is_keyEND || _is_keyPAGEDOWN ||
        _is_keyCAPSLOCK || _is_keyA || _is_keyS || _is_keyD ||
        _is_keyF || _is_keyG || _is_keyH || _is_keyJ ||
        _is_keyK || _is_keyL || _is_keyENTER ||
        _is_keySHIFTLEFT || _is_keyZ || _is_keyX || _is_keyC ||
        _is_keyV || _is_keyB || _is_keyN || _is_keyM ||
        _is_keySHIFTRIGHT || _is_keyARROWUP || _is_keyCTRLLEFT ||
        _is_keyAPPLEFT || _is_keyALT || _is_keySPACE || _is_keyALTGR ||
        _is_keyAPPRIGHT || _is_keyMENU || _is_keyCTRLRIGHT ||
        _is_keyARROWLEFT || _is_keyARROWDOWN || _is_keyARROWRIGHT ||
        _is_keyPAD0 || _is_keyPAD1 || _is_keyPAD2 ||
        _is_keyPAD3 || _is_keyPAD4 || _is_keyPAD5 ||
        _is_keyPAD6 || _is_keyPAD7 || _is_keyPAD8 ||
        _is_keyPAD9 || _is_keyPADADD || _is_keyPADSUB ||
        _is_keyPADMUL || _is_keyPADDIV;

Project: CImg
File: CImg.h

    **/
    CImg<T>& load_raw(const char *const filename,
                      const unsigned int size_x=0, const unsigned int size_y=1,
                      const unsigned int size_z=1, const unsigned int size_c=1,
                      const bool is_multiplexed=false, const bool invert_endianness=false,
                      const ulongT offset=0) {
      return _load_raw(0,filename,size_x,size_y,size_z,size_c,is_multiplexed,invert_endianness,offset);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    template<typename tc1, typename tc2, typename tc3>
    CImg<T>& draw_triangle(const int x0, const int y0,
                           const int x1, const int y1,
                           const int x2, const int y2,
                           const tc1 *const color1,
                           const tc2 *const color2,
                           const tc3 *const color3,
                           const float opacity=1) {
      const unsigned char one = 1;
      cimg_forC(*this,c)
        get_shared_channel(c).draw_triangle(x0,y0,x1,y1,x2,y2,&one,color1[c],color2[c],color3[c],opacity);
      return *this;

Project: CImg
File: CImg.h

    template<typename t>
    CImg<_cimg_Tt> get_erode(const CImg<t>& kernel, const bool boundary_conditions=true,
                             const bool is_real=false) const {
      if (is_empty() || !kernel) return *this;
      if (!is_real && kernel==0) return CImg<T>(width(),height(),depth(),spectrum(),0);
      typedef _cimg_Tt Tt;
      CImg<Tt> res(_width,_height,_depth,std::max(_spectrum,kernel._spectrum));
      const int
        mx2 = kernel.width()/2, my2 = kernel.height()/2, mz2 = kernel.depth()/2,
        mx1 = kernel.width() - mx2 - 1, my1 = kernel.height() - my2 - 1, mz1 = kernel.depth() - mz2 - 1,
        mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2;
      const bool
        is_inner_parallel = _width*_height*_depth>=(cimg_openmp_sizefactor)*32768,
        is_outer_parallel = res.size()>=(cimg_openmp_sizefactor)*32768;
      cimg::unused(is_inner_parallel,is_outer_parallel);
      _cimg_abort_init_omp;
      cimg_abort_init;
      cimg_pragma_openmp(parallel for cimg_openmp_if(!is_inner_parallel && is_outer_parallel))
      cimg_forC(res,c) _cimg_abort_try_omp {
        cimg_abort_test;
        const CImg<T> img = get_shared_channel(c%_spectrum);
        const CImg<t> K = kernel.get_shared_channel(c%kernel._spectrum);
        if (is_real) { // Real erosion
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(is_inner_parallel))
          for (int z = mz1; z<mze; ++z)
            for (int y = my1; y<mye; ++y)
              for (int x = mx1; x<mxe; ++x) _cimg_abort_try_omp2 {
                cimg_abort_test2;
                Tt min_val = cimg::type<Tt>::max();
                for (int zm = -mz1; zm<=mz2; ++zm)
                  for (int ym = -my1; ym<=my2; ++ym)
                    for (int xm = -mx1; xm<=mx2; ++xm) {
                      const t mval = K(mx1 + xm,my1 + ym,mz1 + zm);
                      const Tt cval = (Tt)(img(x + xm,y + ym,z + zm) - mval);
                      if (cval<min_val) min_val = cval;
                    }
                res(x,y,z,c) = min_val;
              } _cimg_abort_catch_omp2
          if (boundary_conditions)
            cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(is_inner_parallel))
            cimg_forYZ(res,y,z) _cimg_abort_try_omp2 {
              cimg_abort_test2;
              for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {
                Tt min_val = cimg::type<Tt>::max();
                for (int zm = -mz1; zm<=mz2; ++zm)
                  for (int ym = -my1; ym<=my2; ++ym)
                    for (int xm = -mx1; xm<=mx2; ++xm) {
                      const t mval = K(mx1 + xm,my1 + ym,mz1 + zm);
                      const Tt cval = (Tt)(img._atXYZ(x + xm,y + ym,z + zm) - mval);
                      if (cval<min_val) min_val = cval;
                    }
                res(x,y,z,c) = min_val;
              }
            } _cimg_abort_catch_omp2
          else
            cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(is_inner_parallel))
            cimg_forYZ(res,y,z) _cimg_abort_try_omp2 {
              cimg_abort_test2;
              for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {
                Tt min_val = cimg::type<Tt>::max();
                for (int zm = -mz1; zm<=mz2; ++zm)
                  for (int ym = -my1; ym<=my2; ++ym)
                    for (int xm = -mx1; xm<=mx2; ++xm) {
                      const t mval = K(mx1 + xm,my1 + ym,mz1 + zm);
                      const Tt cval = (Tt)(img.atXYZ(x + xm,y + ym,z + zm,0,(T)0) - mval);
                      if (cval<min_val) min_val = cval;
                    }
                res(x,y,z,c) = min_val;
              }
            } _cimg_abort_catch_omp2

        } else { // Binary erosion
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(is_inner_parallel))
          for (int z = mz1; z<mze; ++z)
            for (int y = my1; y<mye; ++y)
              for (int x = mx1; x<mxe; ++x) _cimg_abort_try_omp2 {
                cimg_abort_test2;
                Tt min_val = cimg::type<Tt>::max();
                for (int zm = -mz1; zm<=mz2; ++zm)
                  for (int ym = -my1; ym<=my2; ++ym)
                    for (int xm = -mx1; xm<=mx2; ++xm)
                      if (K(mx1 + xm,my1 + ym,mz1 + zm)) {
                        const Tt cval = (Tt)img(x + xm,y + ym,z + zm);
                        if (cval<min_val) min_val = cval;
                      }
                res(x,y,z,c) = min_val;
              } _cimg_abort_catch_omp2
          if (boundary_conditions)
            cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(is_inner_parallel))
            cimg_forYZ(res,y,z) _cimg_abort_try_omp2 {
              cimg_abort_test2;
              for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {
                Tt min_val = cimg::type<Tt>::max();
                for (int zm = -mz1; zm<=mz2; ++zm)
                  for (int ym = -my1; ym<=my2; ++ym)
                    for (int xm = -mx1; xm<=mx2; ++xm)
                      if (K(mx1 + xm,my1 + ym,mz1 + zm)) {
                        const Tt cval = (Tt)img._atXYZ(x + xm,y + ym,z + zm);
                        if (cval<min_val) min_val = cval;
                      }
                res(x,y,z,c) = min_val;
              }
            } _cimg_abort_catch_omp2
          else
            cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(is_inner_parallel))
            cimg_forYZ(res,y,z) _cimg_abort_try_omp2 {
              cimg_abort_test2;
              for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {
                Tt min_val = cimg::type<Tt>::max();
                for (int zm = -mz1; zm<=mz2; ++zm)
                  for (int ym = -my1; ym<=my2; ++ym)
                    for (int xm = -mx1; xm<=mx2; ++xm)
                      if (K(mx1 + xm,my1 + ym,mz1 + zm)) {
                        const Tt cval = (Tt)img.atXYZ(x + xm,y + ym,z + zm,0,(T)0);
                        if (cval<min_val) min_val = cval;
                      }
                res(x,y,z,c) = min_val;
              }
            } _cimg_abort_catch_omp2
        }
      } _cimg_abort_catch_omp
      cimg_abort_test;
      return res;

Project: CImg
File: CImg.h

                                    first_frame,last_frame,step_frame,yuv2rgb);
    }

    //! Load a list from an image sequence YUV file \overloading.
    CImgList<T>& load_yuv(std::FILE *const file,
                          const unsigned int size_x, const unsigned int size_y,
                          const unsigned int chroma_subsampling=444,
                          const unsigned int first_frame=0, const unsigned int last_frame=~0U,

Project: CImg
File: CImg.h

    **/
    bool operator==(const char *const expression) const {
      return *this==(+*this)._fill(expression,true,1,0,0,"operator==",this);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    **/
    CImg<T>& threshold(const T& value, const bool soft_threshold=false, const bool strict_threshold=false) {
      if (is_empty()) return *this;
      if (strict_threshold) {
        if (soft_threshold)
          cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),32768))
          cimg_rofoff(*this,off) {
            const T v = _data[off];
            _data[off] = v>value?(T)(v-value):v<-(float)value?(T)(v + value):(T)0;
          }
        else
          cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),65536))
          cimg_rofoff(*this,off) _data[off] = _data[off]>value?(T)1:(T)0;
      } else {
        if (soft_threshold)
          cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),32768))
          cimg_rofoff(*this,off) {
            const T v = _data[off];
            _data[off] = v>=value?(T)(v-value):v<=-(float)value?(T)(v + value):(T)0;
          }
        else
          cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),65536))
          cimg_rofoff(*this,off) _data[off] = _data[off]>=value?(T)1:(T)0;
      }
      return *this;

Project: CImg
File: CImg.h


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

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!=~0U && arg1>_cimg_mp_slot_c && _cimg_mp_is_comp(arg1)?arg1:
          arg2!=~0U && 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

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

Project: CImg
File: CImg.h

    // [internal] Perform 2D rotation with arbitrary angle.
    void _rotate(CImg<T>& res, const float angle,
                 const unsigned int interpolation, const unsigned int boundary_conditions,
                 const float w2, const float h2,
                 const float rw2, const float rh2) const {
      const float
        rad = (float)(angle*cimg::PI/180.),
        ca = (float)std::cos(rad), sa = (float)std::sin(rad);

      switch (boundary_conditions) {
      case 3 : { // Mirror

        switch (interpolation) {
        case 2 : { // Cubic interpolation
          const float ww = 2.f*width(), hh = 2.f*height();
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(res.size(),2048))
            cimg_forXYZC(res,x,y,z,c) {
            const float xc = x - rw2, yc = y - rh2,
              mx = cimg::mod(w2 + xc*ca + yc*sa,ww),
              my = cimg::mod(h2 - xc*sa + yc*ca,hh);
            res(x,y,z,c) = _cubic_atXY_c(mx<width()?mx:ww - mx - 1,my<height()?my:hh - my - 1,z,c);
          }
        } break;
        case 1 : { // Linear interpolation
          const float ww = 2.f*width(), hh = 2.f*height();
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(res.size(),2048))
            cimg_forXYZC(res,x,y,z,c) {
            const float xc = x - rw2, yc = y - rh2,
              mx = cimg::mod(w2 + xc*ca + yc*sa,ww),
              my = cimg::mod(h2 - xc*sa + yc*ca,hh);
            res(x,y,z,c) = (T)_linear_atXY(mx<width()?mx:ww - mx - 1,my<height()?my:hh - my - 1,z,c);
          }
        } break;
        default : { // Nearest-neighbor interpolation
          const int ww = 2*width(), hh = 2*height();
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(res.size(),2048))
            cimg_forXYZC(res,x,y,z,c) {
            const float xc = x - rw2, yc = y - rh2,
              mx = cimg::mod((int)cimg::round(w2 + xc*ca + yc*sa),ww),
              my = cimg::mod((int)cimg::round(h2 - xc*sa + yc*ca),hh);
            res(x,y,z,c) = (*this)(mx<width()?mx:ww - mx - 1,my<height()?my:hh - my - 1,z,c);
          }
        }
        }
      } break;

      case 2 : // Periodic
        switch (interpolation) {
        case 2 : { // Cubic interpolation
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(res.size(),2048))
            cimg_forXYZC(res,x,y,z,c) {
            const float xc = x - rw2, yc = y - rh2;
            res(x,y,z,c) = _cubic_atXY_pc(w2 + xc*ca + yc*sa,h2 - xc*sa + yc*ca,z,c);
          }
        } break;
        case 1 : { // Linear interpolation
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(res.size(),2048))
            cimg_forXYZC(res,x,y,z,c) {
            const float xc = x - rw2, yc = y - rh2;
            res(x,y,z,c) = (T)_linear_atXY_p(w2 + xc*ca + yc*sa,h2 - xc*sa + yc*ca,z,c);
          }
        } break;
        default : { // Nearest-neighbor interpolation
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(res.size(),2048))
            cimg_forXYZC(res,x,y,z,c) {
            const float xc = x - rw2, yc = y - rh2;
            res(x,y,z,c) = (*this)(cimg::mod((int)cimg::round(w2 + xc*ca + yc*sa),(float)width()),
                                   cimg::mod((int)cimg::round(h2 - xc*sa + yc*ca),(float)height()),z,c);
          }
        }
        } break;

      case 1 : // Neumann
        switch (interpolation) {
        case 2 : { // Cubic interpolation
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(res.size(),2048))
          cimg_forXYZC(res,x,y,z,c) {
            const float xc = x - rw2, yc = y - rh2;
            res(x,y,z,c) = _cubic_atXY_c(w2 + xc*ca + yc*sa,h2 - xc*sa + yc*ca,z,c);
          }
        } break;
        case 1 : { // Linear interpolation
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(res.size(),2048))
          cimg_forXYZC(res,x,y,z,c) {
            const float xc = x - rw2, yc = y - rh2;
            res(x,y,z,c) = (T)_linear_atXY(w2 + xc*ca + yc*sa,h2 - xc*sa + yc*ca,z,c);
          }
        } break;
        default : { // Nearest-neighbor interpolation
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(res.size(),2048))
          cimg_forXYZC(res,x,y,z,c) {
            const float xc = x - rw2, yc = y - rh2;
            res(x,y,z,c) = _atXY((int)cimg::round(w2 + xc*ca + yc*sa),
                                 (int)cimg::round(h2 - xc*sa + yc*ca),z,c);
          }
        }
        } break;

      default : // Dirichlet
        switch (interpolation) {
        case 2 : { // Cubic interpolation
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(res.size(),2048))
          cimg_forXYZC(res,x,y,z,c) {
            const float xc = x - rw2, yc = y - rh2;
            res(x,y,z,c) = cubic_atXY_c(w2 + xc*ca + yc*sa,h2 - xc*sa + yc*ca,z,c,(T)0);
          }
        } break;
        case 1 : { // Linear interpolation
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(res.size(),2048))
          cimg_forXYZC(res,x,y,z,c) {
            const float xc = x - rw2, yc = y - rh2;
            res(x,y,z,c) = (T)linear_atXY(w2 + xc*ca + yc*sa,h2 - xc*sa + yc*ca,z,c,(T)0);
          }
        } break;
        default : { // Nearest-neighbor interpolation
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(res.size(),2048))
          cimg_forXYZC(res,x,y,z,c) {
            const float xc = x - rw2, yc = y - rh2;
            res(x,y,z,c) = atXY((int)cimg::round(w2 + xc*ca + yc*sa),
                                (int)cimg::round(h2 - xc*sa + yc*ca),z,c,(T)0);
          }
        }
        }
      }

Project: CImg
File: CImg.h


      static double mp_argmax(_cimg_math_parser& mp) {
        const unsigned int i_end = (unsigned int)mp.opcode[2];
        double val = _mp_arg(3);
        unsigned int argval = 0;
        for (unsigned int i = 4; i<i_end; ++i) {
          const double _val = _mp_arg(i);
          if (_val>val) { val = _val; argval = i - 3; }
        }
        return (double)argval;

Project: CImg
File: CImg.h


      static double mp_uppercase(_cimg_math_parser& mp) {
        return cimg::uppercase(_mp_arg(2));

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

  template<typename T>
  inline CImg<T> transpose(const CImg<T>& instance) {
    return instance.get_transpose();

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h


      static double mp_atanh(_cimg_math_parser& mp) {
        return cimg::atanh(_mp_arg(2));

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=1) {
      return _draw_ellipse(x0,y0,r1,r2,angle,color,opacity,0U,true);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


    static void _distance_scan(const unsigned int len,
                               const longT *const g,
                               longT (*const sep)(const longT, const longT, const longT *const),
                               longT (*const f)(const longT, const longT, const longT *const),
                               longT *const s,
                               longT *const t,
                               longT *const dt) {
      longT q = s[0] = t[0] = 0;
      for (int u = 1; u<(int)len; ++u) { // Forward scan
        while ((q>=0) && f(t[q],s[q],g)>f(t[q],u,g)) { --q; }
        if (q<0) { q = 0; s[0] = u; }
        else { const longT w = 1 + sep(s[q], u, g); if (w<(longT)len) { ++q; s[q] = u; t[q] = w; }}
      }
      for (int u = (int)len - 1; u>=0; --u) { dt[u] = f(u,s[q],g); if (u==t[q]) --q; } // Backward scan

Project: CImg
File: CImg.h

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

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    template<typename t>
    bool contains(const T& pixel, t& x, t& y, t& z) const {
      const ulongT wh = (ulongT)_width*_height, whd = wh*_depth, siz = whd*_spectrum;
      const T *const ppixel = &pixel;
      if (is_empty() || ppixel<_data || ppixel>=_data + siz) return false;
      ulongT off = ((ulongT)(ppixel - _data))%whd;
      const ulongT nz = off/wh;
      off%=wh;
      const ulongT ny = off/_width, nx = off%_width;
      x = (t)nx; y = (t)ny; z = (t)nz;
      return true;

Project: CImg
File: CImg.h


      static double mp_image_wh(_cimg_math_parser& mp) {
        unsigned int ind = (unsigned int)mp.opcode[2];
        if (ind!=~0U) ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
        const CImg<T> &img = ind==~0U?mp.imgout:mp.listout[ind];
        return (double)img.width()*img.height();

Project: CImg
File: CImg.h

    //! Construct image with specified size and initialize pixel values from a memory buffer \specialization.
    CImg(const T *const values, const unsigned int size_x, const unsigned int size_y=1,
         const unsigned int size_z=1, const unsigned int size_c=1, const bool is_shared=false) {
      const size_t siz = (size_t)size_x*size_y*size_z*size_c;
      if (values && siz) {
        _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; _is_shared = is_shared;
        if (_is_shared) _data = const_cast<T*>(values);
        else {
          try { _data = new T[siz]; } catch (...) {
            _width = _height = _depth = _spectrum = 0; _data = 0;
            throw CImgInstanceException(_cimg_instance
                                        "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
                                        cimg_instance,
                                        cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c),
                                        size_x,size_y,size_z,size_c);
          }
          std::memcpy(_data,values,siz*sizeof(T));
        }
      } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; }

Project: CImg
File: CImg.h

    template<> struct type<char> {

Project: CImg
File: CImg.h

      // Tell for each character of an expression if it is inside a string or not.
      CImg<boolT> is_inside_string(CImg<charT>& _expr) const {
        bool is_escaped = false, next_is_escaped = false;
        unsigned int mode = 0, next_mode = 0; // { 0=normal | 1=char-string | 2=vector-string
        CImg<boolT> res = CImg<charT>::string(_expr);
        bool *pd = res._data;
        for (const char *ps = _expr._data; *ps; ++ps) {
          if (!next_is_escaped && *ps=='\\') next_is_escaped = true;
          if (!is_escaped && *ps=='\'') { // Non-escaped character
            if (!mode && ps>_expr._data && *(ps - 1)=='[') next_mode = mode = 2; // Start vector-string
            else if (mode==2 && *(ps + 1)==']') next_mode = !mode; // End vector-string
            else if (mode<2) next_mode = mode?(mode = 0):1; // Start/end char-string
          }
          *(pd++) = mode>=1 || is_escaped;
          mode = next_mode;
          is_escaped = next_is_escaped;
          next_is_escaped = false;
        }
        return res;

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h


    const CImg<T>& _save_png(std::FILE *const file, const char *const filename,
                             const unsigned int bytes_per_pixel=0) const {
      if (!file && !filename)
        throw CImgArgumentException(_cimg_instance
                                    "save_png(): Specified filename is (null).",
                                    cimg_instance);
      if (is_empty()) { cimg::fempty(file,filename); return *this; }

#ifndef cimg_use_png
      cimg::unused(bytes_per_pixel);
      if (!file) return save_other(filename);
      else throw CImgIOException(_cimg_instance
                                 "save_png(): Unable to save data in '(*FILE)' unless libpng is enabled.",
                                 cimg_instance);
#else

#if defined __GNUC__
      const char *volatile nfilename = filename; // Use 'volatile' to avoid (wrong) g++ warning
      std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"wb");
      volatile double stmin, stmax = (double)max_min(stmin);
#else
      const char *nfilename = filename;
      std::FILE *nfile = file?file:cimg::fopen(nfilename,"wb");
      double stmin, stmax = (double)max_min(stmin);
#endif

      if (_depth>1)
        cimg::warn(_cimg_instance
                   "save_png(): Instance is volumetric, only the first slice will be saved in file '%s'.",
                   cimg_instance,
                   filename);

      if (_spectrum>4)
        cimg::warn(_cimg_instance
                   "save_png(): Instance is multispectral, only the three first channels will be saved in file '%s'.",
                   cimg_instance,
                   filename);

      if (stmin<0 || (bytes_per_pixel==1 && stmax>=256) || stmax>=65536)
        cimg::warn(_cimg_instance
                   "save_png(): Instance has pixel values in [%g,%g], probable type overflow in file '%s'.",
                   cimg_instance,
                   filename,stmin,stmax);

      // Setup PNG structures for write
      png_voidp user_error_ptr = 0;
      png_error_ptr user_error_fn = 0, user_warning_fn = 0;
      png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,user_error_ptr, user_error_fn,
                                                    user_warning_fn);
      if (!png_ptr){
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "save_png(): Failed to initialize 'png_ptr' structure when saving file '%s'.",
                              cimg_instance,
                              nfilename?nfilename:"(FILE*)");
      }
      png_infop info_ptr = png_create_info_struct(png_ptr);
      if (!info_ptr) {
        png_destroy_write_struct(&png_ptr,(png_infopp)0);
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "save_png(): Failed to initialize 'info_ptr' structure when saving file '%s'.",
                              cimg_instance,
                              nfilename?nfilename:"(FILE*)");
      }
      if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "save_png(): Encountered unknown fatal error in libpng when saving file '%s'.",
                              cimg_instance,
                              nfilename?nfilename:"(FILE*)");
      }
      png_init_io(png_ptr, nfile);

      const int bit_depth = bytes_per_pixel?(bytes_per_pixel*8):(stmax>=256?16:8);

      int color_type;
      switch (spectrum()) {
      case 1 : color_type = PNG_COLOR_TYPE_GRAY; break;
      case 2 : color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break;
      case 3 : color_type = PNG_COLOR_TYPE_RGB; break;
      default : color_type = PNG_COLOR_TYPE_RGB_ALPHA;
      }
      const int interlace_type = PNG_INTERLACE_NONE;
      const int compression_type = PNG_COMPRESSION_TYPE_DEFAULT;
      const int filter_method = PNG_FILTER_TYPE_DEFAULT;
      png_set_IHDR(png_ptr,info_ptr,_width,_height,bit_depth,color_type,interlace_type,compression_type,filter_method);
      png_write_info(png_ptr,info_ptr);
      const int byte_depth = bit_depth>>3;
      const int numChan = spectrum()>4?4:spectrum();
      const int pixel_bit_depth_flag = numChan * (bit_depth - 1);

      // Allocate Memory for Image Save and Fill pixel data
      png_bytep *const imgData = new png_byte*[_height];
      for (unsigned int row = 0; row<_height; ++row) imgData[row] = new png_byte[byte_depth*numChan*_width];
      const T *pC0 = data(0,0,0,0);
      switch (pixel_bit_depth_flag) {
      case 7 :  { // Gray 8-bit
        cimg_forY(*this,y) {
          unsigned char *ptrd = imgData[y];
          cimg_forX(*this,x) *(ptrd++) = (unsigned char)*(pC0++);
        }
      } break;
      case 14 : { // Gray w/ Alpha 8-bit
        const T *pC1 = data(0,0,0,1);
        cimg_forY(*this,y) {
          unsigned char *ptrd = imgData[y];
          cimg_forX(*this,x) {
            *(ptrd++) = (unsigned char)*(pC0++);
            *(ptrd++) = (unsigned char)*(pC1++);
          }
        }
      } break;
      case 21 :  { // RGB 8-bit
        const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2);
        cimg_forY(*this,y) {
          unsigned char *ptrd = imgData[y];
          cimg_forX(*this,x) {
            *(ptrd++) = (unsigned char)*(pC0++);
            *(ptrd++) = (unsigned char)*(pC1++);
            *(ptrd++) = (unsigned char)*(pC2++);
          }
        }
      } break;
      case 28 : { // RGB x/ Alpha 8-bit
        const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2), *pC3 = data(0,0,0,3);
        cimg_forY(*this,y){
          unsigned char *ptrd = imgData[y];
          cimg_forX(*this,x){
            *(ptrd++) = (unsigned char)*(pC0++);
            *(ptrd++) = (unsigned char)*(pC1++);
            *(ptrd++) = (unsigned char)*(pC2++);
            *(ptrd++) = (unsigned char)*(pC3++);
          }
        }
      } break;
      case 15 : { // Gray 16-bit
        cimg_forY(*this,y){
          unsigned short *ptrd = (unsigned short*)(imgData[y]);
          cimg_forX(*this,x) *(ptrd++) = (unsigned short)*(pC0++);
          if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],_width);
        }
      } break;
      case 30 : { // Gray w/ Alpha 16-bit
        const T *pC1 = data(0,0,0,1);
        cimg_forY(*this,y){
          unsigned short *ptrd = (unsigned short*)(imgData[y]);
          cimg_forX(*this,x) {
            *(ptrd++) = (unsigned short)*(pC0++);
            *(ptrd++) = (unsigned short)*(pC1++);
          }
          if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],2*_width);
        }
      } break;
      case 45 : { // RGB 16-bit
        const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2);
        cimg_forY(*this,y) {
          unsigned short *ptrd = (unsigned short*)(imgData[y]);
          cimg_forX(*this,x) {
            *(ptrd++) = (unsigned short)*(pC0++);
            *(ptrd++) = (unsigned short)*(pC1++);
            *(ptrd++) = (unsigned short)*(pC2++);
          }
          if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],3*_width);
        }
      } break;
      case 60 : { // RGB w/ Alpha 16-bit
        const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2), *pC3 = data(0,0,0,3);
        cimg_forY(*this,y) {
          unsigned short *ptrd = (unsigned short*)(imgData[y]);
          cimg_forX(*this,x) {
            *(ptrd++) = (unsigned short)*(pC0++);
            *(ptrd++) = (unsigned short)*(pC1++);
            *(ptrd++) = (unsigned short)*(pC2++);
            *(ptrd++) = (unsigned short)*(pC3++);
          }
          if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],4*_width);
        }
      } break;
      default :
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "save_png(): Encountered unknown fatal error in libpng when saving file '%s'.",
                              cimg_instance,
                              nfilename?nfilename:"(FILE*)");
      }
      png_write_image(png_ptr,imgData);
      png_write_end(png_ptr,info_ptr);
      png_destroy_write_struct(&png_ptr, &info_ptr);

      // Deallocate Image Write Memory
      cimg_forY(*this,n) delete[] imgData[n];
      delete[] imgData;

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

Project: CImg
File: CImg.h


      static double mp_list_set_Jxyz_s(_cimg_math_parser& mp) {
        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
        CImg<T> &img = mp.listout[ind];
        const double ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y], oz = mp.mem[_cimg_mp_slot_z];
        const int
          x = (int)(ox + _mp_arg(3)),
          y = (int)(oy + _mp_arg(4)),
          z = (int)(oz + _mp_arg(5));
        const T val = (T)_mp_arg(1);
        if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {
          T *ptrd = &img(x,y,z);
          const ulongT whd = (ulongT)img._width*img._height*img._depth;
          cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }
        }
        return _mp_arg(1);

Project: CImg
File: CImg.h

    template<typename T>
    inline T& invert_endianness(T& a) {
      invert_endianness(&a,1);
      return a;

Project: CImg
File: CImg.h

      return CImgList<T>().load_cimg(filename,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1);
    }

    //! Load a sub-image list from a (non compressed) .cimg file \overloading.
    CImgList<T>& load_cimg(std::FILE *const file,
                           const unsigned int n0, const unsigned int n1,
                           const unsigned int x0, const unsigned int y0,
                           const unsigned int z0, const unsigned int c0,

Project: CImg
File: CImg.h

    **/
    CImg<T> get_rows(const int y0, const int y1) const {
      return get_crop(0,y0,0,0,width() - 1,y1,depth() - 1,spectrum() - 1);

Project: CImg
File: CImg.h

    **/
    CImgDisplay& set_mouse(const int pos_x, const int pos_y) {
      return assign(pos_x,pos_y);

Project: CImg
File: CImg.h

    **/
    static const char* pixel_type() {
      return cimg::type<T>::string();

Project: CImg
File: CImg.h


    inline unsigned int wait(const unsigned int milliseconds, cimg_ulong *const p_timer) {
      if (!*p_timer) *p_timer = cimg::time();
      const cimg_ulong current_time = cimg::time();
      if (current_time>=*p_timer + milliseconds) { *p_timer = current_time; return 0; }
      const unsigned int time_diff = (unsigned int)(*p_timer + milliseconds - current_time);
      *p_timer = current_time + time_diff;
      cimg::sleep(time_diff);
      return time_diff;

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_arrow(const int x0, const int y0,
                        const int x1, const int y1,
                        const tc *const color, const float opacity=1,
                        const float angle=30, const float length=-10,
                        const unsigned int pattern=~0U) {
      if (is_empty()) return *this;
      const float u = (float)(x0 - x1), v = (float)(y0 - y1), sq = u*u + v*v,
        deg = (float)(angle*cimg::PI/180), ang = (sq>0)?(float)std::atan2(v,u):0.f,
        l = (length>=0)?length:-length*(float)std::sqrt(sq)/100;
      if (sq>0) {
        const float
            cl = (float)std::cos(ang - deg), sl = (float)std::sin(ang - deg),
            cr = (float)std::cos(ang + deg), sr = (float)std::sin(ang + deg);
        const int
          xl = x1 + (int)(l*cl), yl = y1 + (int)(l*sl),
          xr = x1 + (int)(l*cr), yr = y1 + (int)(l*sr),
          xc = x1 + (int)((l + 1)*(cl + cr))/2, yc = y1 + (int)((l + 1)*(sl + sr))/2;
        draw_line(x0,y0,xc,yc,color,opacity,pattern).draw_triangle(x1,y1,xl,yl,xr,yr,color,opacity);
      } else draw_point(x0,y0,color,opacity);
      return *this;

Project: CImg
File: CImg.h

    **/
    const CImg<T>& back() const {
      return *(_data + _width - 1);

Project: CImg
File: CImg.h

    template<typename tf, typename t>
    static CImg<floatT> ellipsoid3d(CImgList<tf>& primitives,
                                    const CImg<t>& tensor, const unsigned int subdivisions=3) {
      primitives.assign();
      if (!subdivisions) return CImg<floatT>();
      CImg<floatT> S, V;
      tensor.symmetric_eigen(S,V);
      const float orient =
        (V(0,1)*V(1,2) - V(0,2)*V(1,1))*V(2,0) +
        (V(0,2)*V(1,0) - V(0,0)*V(1,2))*V(2,1) +
        (V(0,0)*V(1,1) - V(0,1)*V(1,0))*V(2,2);
      if (orient<0) { V(2,0) = -V(2,0); V(2,1) = -V(2,1); V(2,2) = -V(2,2); }
      const float l0 = S[0], l1 = S[1], l2 = S[2];
      CImg<floatT> vertices = sphere3d(primitives,1.,subdivisions);
      vertices.get_shared_row(0)*=l0;
      vertices.get_shared_row(1)*=l1;
      vertices.get_shared_row(2)*=l2;
      return V*vertices;

Project: CImg
File: CImg.h

    //! Return a 5x5 matrix containing specified coefficients.
    static CImg<T> matrix(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4,
                          const T& a5, const T& a6, const T& a7, const T& a8, const T& a9,
                          const T& a10, const T& a11, const T& a12, const T& a13, const T& a14,
                          const T& a15, const T& a16, const T& a17, const T& a18, const T& a19,
                          const T& a20, const T& a21, const T& a22, const T& a23, const T& a24) {
      CImg<T> r(5,5); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4;
      *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; *(ptr++) = a9;
      *(ptr++) = a10; *(ptr++) = a11; *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14;
      *(ptr++) = a15; *(ptr++) = a16; *(ptr++) = a17; *(ptr++) = a18; *(ptr++) = a19;
      *(ptr++) = a20; *(ptr++) = a21; *(ptr++) = a22; *(ptr++) = a23; *(ptr++) = a24;
      return r;

Project: CImg
File: CImg.h

    **/
    CImg<T>& clear() {
      return assign();

Project: CImg
File: CImg.h

       \param[out] n Index of image in the list, if test succeeds.
       \note If true, returns the position (n) of the image in the list.
    **/
    template<typename t>
    bool contains(const CImg<T>& img, t& n) const {
      if (is_empty()) return false;

Project: CImg
File: CImg.h

    //! Save image as an INRIMAGE-4 file \overloading.
    const CImg<T>& save_inr(std::FILE *const file, const float *const voxel_size=0) const {
      return _save_inr(file,0,voxel_size);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<_cimg_Tt> get_dilate(const CImg<t>& kernel, const bool boundary_conditions=true,
                              const bool is_real=false) const {
      if (is_empty() || !kernel || (!is_real && kernel==0)) return *this;
      typedef _cimg_Tt Tt;
      CImg<Tt> res(_width,_height,_depth,std::max(_spectrum,kernel._spectrum));
      const int
        mx1 = kernel.width()/2, my1 = kernel.height()/2, mz1 = kernel.depth()/2,
        mx2 = kernel.width() - mx1 - 1, my2 = kernel.height() - my1 - 1, mz2 = kernel.depth() - mz1 - 1,
        mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2;
      const bool
        is_inner_parallel = _width*_height*_depth>=(cimg_openmp_sizefactor)*32768,
        is_outer_parallel = res.size()>=(cimg_openmp_sizefactor)*32768;
      cimg::unused(is_inner_parallel,is_outer_parallel);
      _cimg_abort_init_omp;
      cimg_abort_init;
      cimg_pragma_openmp(parallel for cimg_openmp_if(!is_inner_parallel && is_outer_parallel))
      cimg_forC(res,c) _cimg_abort_try_omp {
        cimg_abort_test;
        const CImg<T> img = get_shared_channel(c%_spectrum);
        const CImg<t> K = kernel.get_shared_channel(c%kernel._spectrum);
        if (is_real) { // Real dilation
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(is_inner_parallel))
          for (int z = mz1; z<mze; ++z)
            for (int y = my1; y<mye; ++y)
              for (int x = mx1; x<mxe; ++x) _cimg_abort_try_omp2 {
                cimg_abort_test2;
                Tt max_val = cimg::type<Tt>::min();
                for (int zm = -mz1; zm<=mz2; ++zm)
                  for (int ym = -my1; ym<=my2; ++ym)
                    for (int xm = -mx1; xm<=mx2; ++xm) {
                      const t mval = K(mx2 - xm,my2 - ym,mz2 - zm);
                      const Tt cval = (Tt)(img(x + xm,y + ym,z + zm) + mval);
                      if (cval>max_val) max_val = cval;
                    }
                res(x,y,z,c) = max_val;
              } _cimg_abort_catch_omp2
          if (boundary_conditions)
            cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(is_inner_parallel))
            cimg_forYZ(res,y,z) _cimg_abort_try_omp2 {
              cimg_abort_test2;
              for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {
                Tt max_val = cimg::type<Tt>::min();
                for (int zm = -mz1; zm<=mz2; ++zm)
                  for (int ym = -my1; ym<=my2; ++ym)
                    for (int xm = -mx1; xm<=mx2; ++xm) {
                      const t mval = K(mx2 - xm,my2 - ym,mz2 - zm);
                      const Tt cval = (Tt)(img._atXYZ(x + xm,y + ym,z + zm) + mval);
                      if (cval>max_val) max_val = cval;
                    }
                res(x,y,z,c) = max_val;
              }
            } _cimg_abort_catch_omp2
          else
            cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(is_inner_parallel))
            cimg_forYZ(*this,y,z) _cimg_abort_try_omp2 {
              cimg_abort_test2;
              for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {
                Tt max_val = cimg::type<Tt>::min();
                for (int zm = -mz1; zm<=mz2; ++zm)
                  for (int ym = -my1; ym<=my2; ++ym)
                    for (int xm = -mx1; xm<=mx2; ++xm) {
                      const t mval = K(mx2 - xm,my2 - ym,mz2 - zm);
                      const Tt cval = (Tt)(img.atXYZ(x + xm,y + ym,z + zm,0,(T)0) + mval);
                      if (cval>max_val) max_val = cval;
                    }
                res(x,y,z,c) = max_val;
              }
            } _cimg_abort_catch_omp2
        } else { // Binary dilation
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(is_inner_parallel))
          for (int z = mz1; z<mze; ++z)
            for (int y = my1; y<mye; ++y)
              for (int x = mx1; x<mxe; ++x) _cimg_abort_try_omp2 {
                cimg_abort_test2;
                Tt max_val = cimg::type<Tt>::min();
                for (int zm = -mz1; zm<=mz2; ++zm)
                  for (int ym = -my1; ym<=my2; ++ym)
                    for (int xm = -mx1; xm<=mx2; ++xm)
                      if (K(mx2 - xm,my2 - ym,mz2 - zm)) {
                        const Tt cval = (Tt)img(x + xm,y + ym,z + zm);
                        if (cval>max_val) max_val = cval;
                      }
                res(x,y,z,c) = max_val;
              } _cimg_abort_catch_omp2
          if (boundary_conditions)
            cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(is_inner_parallel))
            cimg_forYZ(res,y,z) _cimg_abort_try_omp2 {
              cimg_abort_test2;
              for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {
                Tt max_val = cimg::type<Tt>::min();
                for (int zm = -mz1; zm<=mz2; ++zm)
                  for (int ym = -my1; ym<=my2; ++ym)
                    for (int xm = -mx1; xm<=mx2; ++xm)
                      if (K(mx2 - xm,my2 - ym,mz2 - zm)) {
                        const Tt cval = (Tt)img._atXYZ(x + xm,y + ym,z + zm);
                        if (cval>max_val) max_val = cval;
                      }
                res(x,y,z,c) = max_val;
              }
            } _cimg_abort_catch_omp2
          else
            cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(is_inner_parallel))
            cimg_forYZ(res,y,z) _cimg_abort_try_omp2 {
              cimg_abort_test2;
              for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {
                Tt max_val = cimg::type<Tt>::min();
                for (int zm = -mz1; zm<=mz2; ++zm)
                  for (int ym = -my1; ym<=my2; ++ym)
                    for (int xm = -mx1; xm<=mx2; ++xm)
                      if (K(mx2 - xm,my2 - ym,mz2 - zm)) {
                        const Tt cval = (Tt)img.atXYZ(x + xm,y + ym,z + zm,0,(T)0);
                        if (cval>max_val) max_val = cval;
                      }
                res(x,y,z,c) = max_val;
              }
            } _cimg_abort_catch_omp2
        }
      } _cimg_abort_catch_omp
      cimg_abort_test;
      return res;

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& watershed(const CImg<t>& priority, const bool is_high_connectivity=false) {
#define _cimg_watershed_init(cond,X,Y,Z) \
      if (cond && !(*this)(X,Y,Z)) Q._priority_queue_insert(labels,sizeQ,priority(X,Y,Z),X,Y,Z,nb_seeds)

#define _cimg_watershed_propagate(cond,X,Y,Z) \
      if (cond) { \
        if ((*this)(X,Y,Z)) { \
          ns = labels(X,Y,Z) - 1; xs = seeds(ns,0); ys = seeds(ns,1); zs = seeds(ns,2); \
          d = cimg::sqr((float)x - xs) + cimg::sqr((float)y - ys) + cimg::sqr((float)z - zs); \
          if (d<dmin) { dmin = d; nmin = ns; nlabel = (*this)(xs,ys,zs); } \
        } else Q._priority_queue_insert(labels,sizeQ,priority(X,Y,Z),X,Y,Z,n); \
      }

      if (is_empty()) return *this;
      if (!is_sameXYZ(priority))
        throw CImgArgumentException(_cimg_instance
                                    "watershed(): image instance and specified priority (%u,%u,%u,%u,%p) "
                                    "have different dimensions.",
                                    cimg_instance,
                                    priority._width,priority._height,priority._depth,priority._spectrum,priority._data);
      if (_spectrum!=1) {
        cimg_forC(*this,c)
          get_shared_channel(c).watershed(priority.get_shared_channel(c%priority._spectrum));
        return *this;
      }

      CImg<uintT> labels(_width,_height,_depth,1,0), seeds(64,3);
      CImg<typename cimg::superset2<T,t,int>::type> Q;
      unsigned int sizeQ = 0;
      int px, nx, py, ny, pz, nz;
      bool is_px, is_nx, is_py, is_ny, is_pz, is_nz;
      const bool is_3d = _depth>1;

      // Find seed points and insert them in priority queue.
      unsigned int nb_seeds = 0;
      const T *ptrs = _data;
      cimg_forXYZ(*this,x,y,z) if (*(ptrs++)) { // 3D version
        if (nb_seeds>=seeds._width) seeds.resize(2*seeds._width,3,1,1,0);
        seeds(nb_seeds,0) = x; seeds(nb_seeds,1) = y; seeds(nb_seeds++,2) = z;
        px = x - 1; nx = x + 1;
        py = y - 1; ny = y + 1;
        pz = z - 1; nz = z + 1;
        is_px = px>=0; is_nx = nx<width();
        is_py = py>=0; is_ny = ny<height();
        is_pz = pz>=0; is_nz = nz<depth();
        _cimg_watershed_init(is_px,px,y,z);
        _cimg_watershed_init(is_nx,nx,y,z);
        _cimg_watershed_init(is_py,x,py,z);
        _cimg_watershed_init(is_ny,x,ny,z);
        if (is_3d) {
          _cimg_watershed_init(is_pz,x,y,pz);
          _cimg_watershed_init(is_nz,x,y,nz);
        }
        if (is_high_connectivity) {
          _cimg_watershed_init(is_px && is_py,px,py,z);
          _cimg_watershed_init(is_nx && is_py,nx,py,z);
          _cimg_watershed_init(is_px && is_ny,px,ny,z);
          _cimg_watershed_init(is_nx && is_ny,nx,ny,z);
          if (is_3d) {
            _cimg_watershed_init(is_px && is_pz,px,y,pz);
            _cimg_watershed_init(is_nx && is_pz,nx,y,pz);
            _cimg_watershed_init(is_px && is_nz,px,y,nz);
            _cimg_watershed_init(is_nx && is_nz,nx,y,nz);
            _cimg_watershed_init(is_py && is_pz,x,py,pz);
            _cimg_watershed_init(is_ny && is_pz,x,ny,pz);
            _cimg_watershed_init(is_py && is_nz,x,py,nz);
            _cimg_watershed_init(is_ny && is_nz,x,ny,nz);
            _cimg_watershed_init(is_px && is_py && is_pz,px,py,pz);
            _cimg_watershed_init(is_nx && is_py && is_pz,nx,py,pz);
            _cimg_watershed_init(is_px && is_ny && is_pz,px,ny,pz);
            _cimg_watershed_init(is_nx && is_ny && is_pz,nx,ny,pz);
            _cimg_watershed_init(is_px && is_py && is_nz,px,py,nz);
            _cimg_watershed_init(is_nx && is_py && is_nz,nx,py,nz);
            _cimg_watershed_init(is_px && is_ny && is_nz,px,ny,nz);
            _cimg_watershed_init(is_nx && is_ny && is_nz,nx,ny,nz);
          }
        }
        labels(x,y,z) = nb_seeds;
      }

      // Start watershed computation.
      while (sizeQ) {

        // Get and remove point with maximal priority from the queue.
        const int x = (int)Q(0,1), y = (int)Q(0,2), z = (int)Q(0,3);
        const unsigned int n = labels(x,y,z);
        px = x - 1; nx = x + 1;
        py = y - 1; ny = y + 1;
        pz = z - 1; nz = z + 1;
        is_px = px>=0; is_nx = nx<width();
        is_py = py>=0; is_ny = ny<height();
        is_pz = pz>=0; is_nz = nz<depth();

        // Check labels of the neighbors.
        Q._priority_queue_remove(sizeQ);

        unsigned int xs, ys, zs, ns, nmin = 0;
        float d, dmin = cimg::type<float>::inf();
        T nlabel = (T)0;
        _cimg_watershed_propagate(is_px,px,y,z);
        _cimg_watershed_propagate(is_nx,nx,y,z);
        _cimg_watershed_propagate(is_py,x,py,z);
        _cimg_watershed_propagate(is_ny,x,ny,z);
        if (is_3d) {
          _cimg_watershed_propagate(is_pz,x,y,pz);
          _cimg_watershed_propagate(is_nz,x,y,nz);
        }
        if (is_high_connectivity) {
          _cimg_watershed_propagate(is_px && is_py,px,py,z);
          _cimg_watershed_propagate(is_nx && is_py,nx,py,z);
          _cimg_watershed_propagate(is_px && is_ny,px,ny,z);
          _cimg_watershed_propagate(is_nx && is_ny,nx,ny,z);
          if (is_3d) {
            _cimg_watershed_propagate(is_px && is_pz,px,y,pz);
            _cimg_watershed_propagate(is_nx && is_pz,nx,y,pz);
            _cimg_watershed_propagate(is_px && is_nz,px,y,nz);
            _cimg_watershed_propagate(is_nx && is_nz,nx,y,nz);
            _cimg_watershed_propagate(is_py && is_pz,x,py,pz);
            _cimg_watershed_propagate(is_ny && is_pz,x,ny,pz);
            _cimg_watershed_propagate(is_py && is_nz,x,py,nz);
            _cimg_watershed_propagate(is_ny && is_nz,x,ny,nz);
            _cimg_watershed_propagate(is_px && is_py && is_pz,px,py,pz);
            _cimg_watershed_propagate(is_nx && is_py && is_pz,nx,py,pz);
            _cimg_watershed_propagate(is_px && is_ny && is_pz,px,ny,pz);
            _cimg_watershed_propagate(is_nx && is_ny && is_pz,nx,ny,pz);
            _cimg_watershed_propagate(is_px && is_py && is_nz,px,py,nz);
            _cimg_watershed_propagate(is_nx && is_py && is_nz,nx,py,nz);
            _cimg_watershed_propagate(is_px && is_ny && is_nz,px,ny,nz);
            _cimg_watershed_propagate(is_nx && is_ny && is_nz,nx,ny,nz);
          }
        }
        (*this)(x,y,z) = nlabel;
        labels(x,y,z) = ++nmin;
      }
      return *this;

Project: CImg
File: CImg.h

      static cimg_uint64 max() { return (cimg_uint64)-1; }

Project: CImg
File: CImg.h

      // Count parentheses/brackets level of each character of the expression.
      CImg<uintT> get_level(CImg<charT>& _expr) const {
        bool is_escaped = false, next_is_escaped = false;
        unsigned int mode = 0, next_mode = 0; // { 0=normal | 1=char-string | 2=vector-string
        CImg<uintT> res(_expr._width - 1);
        unsigned int *pd = res._data;
        int _level = 0;
        for (const char *ps = _expr._data; *ps && _level>=0; ++ps) {
          if (!is_escaped && !next_is_escaped && *ps=='\\') next_is_escaped = true;
          if (!is_escaped && *ps=='\'') { // Non-escaped character
            if (!mode && ps>_expr._data && *(ps - 1)=='[') next_mode = mode = 2; // Start vector-string
            else if (mode==2 && *(ps + 1)==']') next_mode = !mode; // End vector-string
            else if (mode<2) next_mode = mode?(mode = 0):1; // Start/end char-string
          }
          *(pd++) = (unsigned int)(mode>=1 || is_escaped?_level + (mode==1):
                                   *ps=='(' || *ps=='['?_level++:
                                   *ps==')' || *ps==']'?--_level:
                                   _level);
          mode = next_mode;
          is_escaped = next_is_escaped;
          next_is_escaped = false;
        }
        if (mode) {
          cimg::strellipsize(_expr,64);
          throw CImgArgumentException("[" cimg_appname "_math_parser] "
                                      "CImg<%s>::%s: Unterminated string literal, in expression '%s'.",
                                      pixel_type(),_cimg_mp_calling_function,
                                      _expr._data);
        }
        if (_level) {
          cimg::strellipsize(_expr,64);
          throw CImgArgumentException("[" cimg_appname "_math_parser] "
                                      "CImg<%s>::%s: Unbalanced parentheses/brackets, in expression '%s'.",
                                      pixel_type(),_cimg_mp_calling_function,
                                      _expr._data);
        }
        return res;

Project: CImg
File: CImg.h


      static double mp_list_Joff(_cimg_math_parser& mp) {
        double *ptrd = &_mp_arg(1) + 1;
        const unsigned int
          ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
          boundary_conditions = (unsigned int)_mp_arg(4),
          vsiz = (unsigned int)mp.opcode[5];
        const int
          ox = (int)mp.mem[_cimg_mp_slot_x], oy = (int)mp.mem[_cimg_mp_slot_y], oz = (int)mp.mem[_cimg_mp_slot_z];
        const CImg<T> &img = mp.listin[ind];
        const longT
          off = img.offset(ox,oy,oz) + (longT)_mp_arg(3),
          whd = (longT)img.width()*img.height()*img.depth();
        const T *ptrs;
        if (off>=0 && off<whd) {
          ptrs = &img[off];
          cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
          return cimg::type<double>::nan();
        }
        if (img._data) switch (boundary_conditions) {
          case 3 : { // Mirror
            const longT whd2 = 2*whd, moff = cimg::mod(off,whd2);
            ptrs = &img[moff<whd?moff:whd2 - moff - 1];
            cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
            return cimg::type<double>::nan();
          }
          case 2 : // Periodic
            ptrs = &img[cimg::mod(off,whd)];
            cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
            return cimg::type<double>::nan();
          case 1 : // Neumann
            ptrs = off<0?&img[0]:&img[whd - 1];
            cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
            return cimg::type<double>::nan();
          default : // Dirichlet
            std::memset(ptrd,0,vsiz*sizeof(double));
            return cimg::type<double>::nan();
          }
        std::memset(ptrd,0,vsiz*sizeof(double));
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    //! Blur image with a box filter \newinstance.
    CImg<Tfloat> get_blur_box(const float boxsize_x, const float boxsize_y, const float boxsize_z,
                              const bool boundary_conditions=true) const {
      return CImg<Tfloat>(*this,false).blur_box(boxsize_x,boxsize_y,boxsize_z,boundary_conditions);

Project: CImg
File: CImg.h

    template<typename t>
    CImg(const CImg<t>& img, const char *const dimensions, const T& value):
      _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
      assign(img,dimensions).fill(value);

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h


    static longT _distance_dist_mdt(const longT x, const longT i, const longT *const g) {
      return (x<i?i - x:x - i) + g[i];

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


    Tfloat _linear_atXYZ(const float fx, const float fy=0, const float fz=0, 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 unsigned int
        x = (unsigned int)nfx,
        y = (unsigned int)nfy,
        z = (unsigned int)nfz;
      const float
        dx = nfx - x,
        dy = nfy - y,
        dz = nfz - z;
      const unsigned int
        nx = dx>0?x + 1:x,
        ny = dy>0?y + 1:y,
        nz = dz>0?z + 1:z;
      const Tfloat
        Iccc = (Tfloat)(*this)(x,y,z,c), Incc = (Tfloat)(*this)(nx,y,z,c),
        Icnc = (Tfloat)(*this)(x,ny,z,c), Innc = (Tfloat)(*this)(nx,ny,z,c),
        Iccn = (Tfloat)(*this)(x,y,nz,c), Incn = (Tfloat)(*this)(nx,y,nz,c),
        Icnn = (Tfloat)(*this)(x,ny,nz,c), Innn = (Tfloat)(*this)(nx,ny,nz,c);
      return Iccc +
        dx*(Incc - Iccc +
            dy*(Iccc + Innc - Icnc - Incc +
                dz*(Iccn + Innn + Icnc + Incc - Icnn - Incn - Iccc - Innc)) +
            dz*(Iccc + Incn - Iccn - Incc)) +
        dy*(Icnc - Iccc +
            dz*(Iccc + Icnn - Iccn - Icnc)) +
        dz*(Iccn - Iccc);

Project: CImg
File: CImg.h


      static double mp_g(_cimg_math_parser& mp) {
        cimg::unused(mp);
        return cimg::grand(&mp.rng);

Project: CImg
File: CImg.h

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

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);
        ptrs+=1 + ind;
        cimg_forX(ss,i) ss[i] = (char)ptrs[i];
        ss.back() = 0;

        const char *s = ss._data;
        while (*s && *s<=32) ++s;
        const bool is_negative = *s=='-';
        if (is_negative || *s=='+') ++s;
        int err = 0;
        char sep;

        if (*s=='0' && (s[1]=='x' || s[1]=='X') && s[2]>32) { // Hexadecimal number
          unsigned int ival;
          err = cimg_sscanf(s + 2,"%x%c",&ival,&sep);
          if (err>0) val = (double)ival;
        } else if (*s>32) { // Decimal number
          err = cimg_sscanf(s,"%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 && (*s=='i' || *s=='I' || *s=='n' || *s=='N')) {
            if (!cimg::strncasecmp(s,"inf",3)) { val = cimg::type<double>::inf(); err = 1 + (s[3]!=0); }
            else if (!cimg::strncasecmp(s,"nan",3)) { val = cimg::type<double>::nan(); err = 1 + (s[3]!=0); }
          }
#endif
        }
        if (err<=0 || (is_strict && err!=1)) return cimg::type<double>::nan();
        if (is_negative) val = -val;
        return val;

Project: CImg
File: CImg.h

                                     const unsigned int z1, const unsigned int c1) {
      return CImgList<T>().load_cimg(file,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1);
    }

    CImgList<T>& _load_cimg(std::FILE *const file, const char *const filename,
			    const unsigned int n0, const unsigned int n1,
			    const unsigned int x0, const unsigned int y0,
                            const unsigned int z0, const unsigned int c0,
			    const unsigned int x1, const unsigned int y1,
                            const unsigned int z1, const unsigned int c1) {
#define _cimg_load_cimg_case2(Ts,Tss) \
      if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \
        for (unsigned int l = 0; l<=nn1; ++l) { \
          j = 0; while ((i=std::fgetc(nfile))!='\n' && i>=0) tmp[j++] = (char)i; tmp[j] = 0; \
          W = H = D = C = 0; \
          if (cimg_sscanf(tmp,"%u %u %u %u",&W,&H,&D,&C)!=4) \
            throw CImgIOException(_cimglist_instance \
                                  "load_cimg(): Invalid specified size (%u,%u,%u,%u) of image %u in file '%s'", \
                                  cimglist_instance, \
                                  W,H,D,C,l,filename?filename:"(FILE*)"); \
          if (W*H*D*C>0) { \
            if (l<nn0 || nx0>=W || ny0>=H || nz0>=D || nc0>=C) cimg::fseek(nfile,W*H*D*C*sizeof(Tss),SEEK_CUR); \
            else { \
              const unsigned int \
                _nx1 = nx1==~0U?W - 1:nx1, \
                _ny1 = ny1==~0U?H - 1:ny1, \
                _nz1 = nz1==~0U?D - 1:nz1, \
                _nc1 = nc1==~0U?C - 1:nc1; \
              if (_nx1>=W || _ny1>=H || _nz1>=D || _nc1>=C) \
                throw CImgArgumentException(_cimglist_instance \
                                            "load_cimg(): Invalid specified coordinates " \
                                            "[%u](%u,%u,%u,%u) -> [%u](%u,%u,%u,%u) " \
                                            "because image [%u] in file '%s' has size (%u,%u,%u,%u).", \
                                            cimglist_instance, \
                                            n0,x0,y0,z0,c0,n1,x1,y1,z1,c1,l,filename?filename:"(FILE*)",W,H,D,C); \
              CImg<Tss> raw(1 + _nx1 - nx0); \
              CImg<T> &img = _data[l - nn0]; \
              img.assign(1 + _nx1 - nx0,1 + _ny1 - ny0,1 + _nz1 - nz0,1 + _nc1 - nc0); \
              T *ptrd = img._data; \
              ulongT skipvb = nc0*W*H*D*sizeof(Tss); \
              if (skipvb) cimg::fseek(nfile,skipvb,SEEK_CUR); \
              for (unsigned int c = 1 + _nc1 - nc0; c; --c) { \
                const ulongT skipzb = nz0*W*H*sizeof(Tss); \
                if (skipzb) cimg::fseek(nfile,skipzb,SEEK_CUR); \
                for (unsigned int z = 1 + _nz1 - nz0; z; --z) { \
                  const ulongT skipyb = ny0*W*sizeof(Tss); \
                  if (skipyb) cimg::fseek(nfile,skipyb,SEEK_CUR); \
                  for (unsigned int y = 1 + _ny1 - ny0; y; --y) { \
                    const ulongT skipxb = nx0*sizeof(Tss); \
                    if (skipxb) cimg::fseek(nfile,skipxb,SEEK_CUR); \
                    cimg::fread(raw._data,raw._width,nfile); \
                    if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw._width); \
                    const Tss *ptrs = raw._data; \
                    for (unsigned int off = raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); \
                    const ulongT skipxe = (W - 1 - _nx1)*sizeof(Tss); \
                    if (skipxe) cimg::fseek(nfile,skipxe,SEEK_CUR); \
                  } \
                  const ulongT skipye = (H - 1 - _ny1)*W*sizeof(Tss); \
                  if (skipye) cimg::fseek(nfile,skipye,SEEK_CUR); \
                } \
                const ulongT skipze = (D - 1 - _nz1)*W*H*sizeof(Tss); \
                if (skipze) cimg::fseek(nfile,skipze,SEEK_CUR); \
              } \
              const ulongT skipve = (C - 1 - _nc1)*W*H*D*sizeof(Tss); \
              if (skipve) cimg::fseek(nfile,skipve,SEEK_CUR); \
            } \
          } \
        } \
        loaded = true; \
      }

      if (!filename && !file)
        throw CImgArgumentException(_cimglist_instance
                                    "load_cimg(): Specified filename is (null).",
                                    cimglist_instance);
      unsigned int
        nn0 = std::min(n0,n1), nn1 = std::max(n0,n1),
        nx0 = std::min(x0,x1), nx1 = std::max(x0,x1),
        ny0 = std::min(y0,y1), ny1 = std::max(y0,y1),
        nz0 = std::min(z0,z1), nz1 = std::max(z0,z1),
        nc0 = std::min(c0,c1), nc1 = std::max(c0,c1);

      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
      bool loaded = false, endian = cimg::endianness();
      CImg<charT> tmp(256), str_pixeltype(256), str_endian(256);
      *tmp = *str_pixeltype = *str_endian = 0;
      unsigned int j, N, W, H, D, C;
      int i, err;
      j = 0; while ((i=std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = 0;
      err = cimg_sscanf(tmp,"%u%*c%255[A-Za-z64_]%*c%255[sA-Za-z_ ]",
                        &N,str_pixeltype._data,str_endian._data);
      if (err<2) {
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimglist_instance
                              "load_cimg(): CImg header not found in file '%s'.",
                              cimglist_instance,
                              filename?filename:"(FILE*)");
      }
      if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
      else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
      nn1 = n1==~0U?N - 1:n1;
      if (nn1>=N)
        throw CImgArgumentException(_cimglist_instance
                                    "load_cimg(): Invalid specified coordinates [%u](%u,%u,%u,%u) -> [%u](%u,%u,%u,%u) "
                                    "because file '%s' contains only %u images.",
                                    cimglist_instance,
                                    n0,x0,y0,z0,c0,n1,x1,y1,z1,c1,filename?filename:"(FILE*)",N);
      assign(1 + nn1 - n0);
      _cimg_load_cimg_case2("bool",bool);
      _cimg_load_cimg_case2("unsigned_char",unsigned char);
      _cimg_load_cimg_case2("uchar",unsigned char);
      _cimg_load_cimg_case2("char",char);
      _cimg_load_cimg_case2("unsigned_short",unsigned short);
      _cimg_load_cimg_case2("ushort",unsigned short);
      _cimg_load_cimg_case2("short",short);
      _cimg_load_cimg_case2("unsigned_int",unsigned int);
      _cimg_load_cimg_case2("uint",unsigned int);
      _cimg_load_cimg_case2("int",int);
      _cimg_load_cimg_case2("unsigned_long",ulongT);
      _cimg_load_cimg_case2("ulong",ulongT);
      _cimg_load_cimg_case2("long",longT);
      _cimg_load_cimg_case2("unsigned_int64",uint64T);
      _cimg_load_cimg_case2("uint64",uint64T);
      _cimg_load_cimg_case2("int64",int64T);
      _cimg_load_cimg_case2("float",float);
      _cimg_load_cimg_case2("double",double);
      if (!loaded) {
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimglist_instance
                              "load_cimg(): Unsupported pixel type '%s' for file '%s'.",
                              cimglist_instance,
                              str_pixeltype._data,filename?filename:"(FILE*)");

Project: CImg
File: CImg.h

    template<typename t>
    CImg<_cimg_Tt> operator*(const CImg<t>& img) const {
      typedef _cimg_Ttdouble Ttdouble;
      typedef _cimg_Tt Tt;
      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<Tt> res(img._width,_height);

      // Check for common cases to optimize.
      if (img._width==1) { // Matrix * Vector
        if (_height==1) switch (_width) { // Vector^T * Vector
          case 1 :
            res[0] = (Tt)((Ttdouble)_data[0]*img[0]);
            return res;
          case 2 :
            res[0] = (Tt)((Ttdouble)_data[0]*img[0] + (Ttdouble)_data[1]*img[1]);
            return res;
          case 3 :
            res[0] = (Tt)((Ttdouble)_data[0]*img[0] + (Ttdouble)_data[1]*img[1] +
                          (Ttdouble)_data[2]*img[2]);
            return res;
          case 4 :
            res[0] = (Tt)((Ttdouble)_data[0]*img[0] + (Ttdouble)_data[1]*img[1] +
                          (Ttdouble)_data[2]*img[2] + (Ttdouble)_data[3]*img[3]);
            return res;
          default : {
            Ttdouble val = 0;
            cimg_forX(*this,i) val+=(Ttdouble)_data[i]*img[i];
            res[0] = val;
            return res;
          }
          } else if (_height==_width) switch (_width) { // Square_matrix * Vector
          case 2 : // 2x2_matrix * Vector
            res[0] = (Tt)((Ttdouble)_data[0]*img[0] + (Ttdouble)_data[1]*img[1]);
            res[1] = (Tt)((Ttdouble)_data[2]*img[0] + (Ttdouble)_data[3]*img[1]);
            return res;
          case 3 : // 3x3_matrix * Vector
            res[0] = (Tt)((Ttdouble)_data[0]*img[0] + (Ttdouble)_data[1]*img[1] +
                          (Ttdouble)_data[2]*img[2]);
            res[1] = (Tt)((Ttdouble)_data[3]*img[0] + (Ttdouble)_data[4]*img[1] +
                          (Ttdouble)_data[5]*img[2]);
            res[2] = (Tt)((Ttdouble)_data[6]*img[0] + (Ttdouble)_data[7]*img[1] +
                          (Ttdouble)_data[8]*img[2]);
            return res;
          case 4 : // 4x4_matrix * Vector
            res[0] = (Tt)((Ttdouble)_data[0]*img[0] + (Ttdouble)_data[1]*img[1] +
                          (Ttdouble)_data[2]*img[2] + (Ttdouble)_data[3]*img[3]);
            res[1] = (Tt)((Ttdouble)_data[4]*img[0] + (Ttdouble)_data[5]*img[1] +
                          (Ttdouble)_data[6]*img[2] + (Ttdouble)_data[7]*img[3]);
            res[2] = (Tt)((Ttdouble)_data[8]*img[0] + (Ttdouble)_data[9]*img[1] +
                          (Ttdouble)_data[10]*img[2] + (Ttdouble)_data[11]*img[3]);
            res[3] = (Tt)((Ttdouble)_data[12]*img[0] + (Ttdouble)_data[13]*img[1] +
                          (Ttdouble)_data[14]*img[2] + (Ttdouble)_data[15]*img[3]);
            return res;
          }
      } else if (_height==_width) {
        if (img._height==img._width) switch (_width) { // Square_matrix * Square_matrix
          case 2 : // 2x2_matrix * 2x2_matrix
            res[0] = (Tt)((Ttdouble)_data[0]*img[0] + (Ttdouble)_data[1]*img[2]);
            res[1] = (Tt)((Ttdouble)_data[0]*img[1] + (Ttdouble)_data[1]*img[3]);
            res[2] = (Tt)((Ttdouble)_data[2]*img[0] + (Ttdouble)_data[3]*img[2]);
            res[3] = (Tt)((Ttdouble)_data[2]*img[1] + (Ttdouble)_data[3]*img[3]);
            return res;
          case 3 : // 3x3_matrix * 3x3_matrix
            res[0] = (Tt)((Ttdouble)_data[0]*img[0] + (Ttdouble)_data[1]*img[3] +
                          (Ttdouble)_data[2]*img[6]);
            res[1] = (Tt)((Ttdouble)_data[0]*img[1] + (Ttdouble)_data[1]*img[4] +
                          (Ttdouble)_data[2]*img[7]);
            res[2] = (Tt)((Ttdouble)_data[0]*img[2] + (Ttdouble)_data[1]*img[5] +
                          (Ttdouble)_data[2]*img[8]);
            res[3] = (Tt)((Ttdouble)_data[3]*img[0] + (Ttdouble)_data[4]*img[3] +
                          (Ttdouble)_data[5]*img[6]);
            res[4] = (Tt)((Ttdouble)_data[3]*img[1] + (Ttdouble)_data[4]*img[4] +
                          (Ttdouble)_data[5]*img[7]);
            res[5] = (Tt)((Ttdouble)_data[3]*img[2] + (Ttdouble)_data[4]*img[5] +
                          (Ttdouble)_data[5]*img[8]);
            res[6] = (Tt)((Ttdouble)_data[6]*img[0] + (Ttdouble)_data[7]*img[3] +
                          (Ttdouble)_data[8]*img[6]);
            res[7] = (Tt)((Ttdouble)_data[6]*img[1] + (Ttdouble)_data[7]*img[4] +
                          (Ttdouble)_data[8]*img[7]);
            res[8] = (Tt)((Ttdouble)_data[6]*img[2] + (Ttdouble)_data[7]*img[5] +
                          (Ttdouble)_data[8]*img[8]);
            return res;
          case 4 : // 4x4_matrix * 4x4_matrix
            res[0] = (Tt)((Ttdouble)_data[0]*img[0] + (Ttdouble)_data[1]*img[4] +
                          (Ttdouble)_data[2]*img[8] + (Ttdouble)_data[3]*img[12]);
            res[1] = (Tt)((Ttdouble)_data[0]*img[1] + (Ttdouble)_data[1]*img[5] +
                          (Ttdouble)_data[2]*img[9] + (Ttdouble)_data[3]*img[13]);
            res[2] = (Tt)((Ttdouble)_data[0]*img[2] + (Ttdouble)_data[1]*img[6] +
                          (Ttdouble)_data[2]*img[10] + (Ttdouble)_data[3]*img[14]);
            res[3] = (Tt)((Ttdouble)_data[0]*img[3] + (Ttdouble)_data[1]*img[7] +
                          (Ttdouble)_data[2]*img[11] + (Ttdouble)_data[3]*img[15]);
            res[4] = (Tt)((Ttdouble)_data[4]*img[0] + (Ttdouble)_data[5]*img[4] +
                          (Ttdouble)_data[6]*img[8] + (Ttdouble)_data[7]*img[12]);
            res[5] = (Tt)((Ttdouble)_data[4]*img[1] + (Ttdouble)_data[5]*img[5] +
                          (Ttdouble)_data[6]*img[9] + (Ttdouble)_data[7]*img[13]);
            res[6] = (Tt)((Ttdouble)_data[4]*img[2] + (Ttdouble)_data[5]*img[6] +
                          (Ttdouble)_data[6]*img[10] + (Ttdouble)_data[7]*img[14]);
            res[7] = (Tt)((Ttdouble)_data[4]*img[3] + (Ttdouble)_data[5]*img[7] +
                          (Ttdouble)_data[6]*img[11] + (Ttdouble)_data[7]*img[15]);
            res[8] = (Tt)((Ttdouble)_data[8]*img[0] + (Ttdouble)_data[9]*img[4] +
                          (Ttdouble)_data[10]*img[8] + (Ttdouble)_data[11]*img[12]);
            res[9] = (Tt)((Ttdouble)_data[8]*img[1] + (Ttdouble)_data[9]*img[5] +
                          (Ttdouble)_data[10]*img[9] + (Ttdouble)_data[11]*img[13]);
            res[10] = (Tt)((Ttdouble)_data[8]*img[2] + (Ttdouble)_data[9]*img[6] +
                           (Ttdouble)_data[10]*img[10] + (Ttdouble)_data[11]*img[14]);
            res[11] = (Tt)((Ttdouble)_data[8]*img[3] + (Ttdouble)_data[9]*img[7] +
                           (Ttdouble)_data[10]*img[11] + (Ttdouble)_data[11]*img[15]);
            res[12] = (Tt)((Ttdouble)_data[12]*img[0] + (Ttdouble)_data[13]*img[4] +
                           (Ttdouble)_data[14]*img[8] + (Ttdouble)_data[15]*img[12]);
            res[13] = (Tt)((Ttdouble)_data[12]*img[1] + (Ttdouble)_data[13]*img[5] +
                           (Ttdouble)_data[14]*img[9] + (Ttdouble)_data[15]*img[13]);
            res[14] = (Tt)((Ttdouble)_data[12]*img[2] + (Ttdouble)_data[13]*img[6] +
                           (Ttdouble)_data[14]*img[10] + (Ttdouble)_data[15]*img[14]);
            res[15] = (Tt)((Ttdouble)_data[12]*img[3] + (Ttdouble)_data[13]*img[7] +
                           (Ttdouble)_data[14]*img[11] + (Ttdouble)_data[15]*img[15]);
            return res;
          } else switch (_width) { // Square_matrix * Matrix
          case 2 : { // 2x2_matrix * Matrix
            const t *ps0 = img.data(), *ps1 = img.data(0,1);
            Tt *pd0 = res.data(), *pd1 = res.data(0,1);
            const Ttdouble
              a0 = (Ttdouble)_data[0], a1 = (Ttdouble)_data[1],
              a2 = (Ttdouble)_data[2], a3 = (Ttdouble)_data[3];
            cimg_forX(img,i) {
              const Ttdouble x = (Ttdouble)*(ps0++), y = (Ttdouble)*(ps1++);
              *(pd0++) = (Tt)(a0*x + a1*y);
              *(pd1++) = (Tt)(a2*x + a3*y);
            }
            return res;
          }
          case 3 : { // 3x3_matrix * Matrix
            const t *ps0 = img.data(), *ps1 = img.data(0,1), *ps2 = img.data(0,2);
            Tt *pd0 = res.data(), *pd1 = res.data(0,1), *pd2 = res.data(0,2);
            const Ttdouble
              a0 = (Ttdouble)_data[0], a1 = (Ttdouble)_data[1], a2 = (Ttdouble)_data[2],
              a3 = (Ttdouble)_data[3], a4 = (Ttdouble)_data[4], a5 = (Ttdouble)_data[5],
              a6 = (Ttdouble)_data[6], a7 = (Ttdouble)_data[7], a8 = (Ttdouble)_data[8];
            cimg_forX(img,i) {
              const Ttdouble x = (Ttdouble)*(ps0++), y = (Ttdouble)*(ps1++), z = (Ttdouble)*(ps2++);
              *(pd0++) = (Tt)(a0*x + a1*y + a2*z);
              *(pd1++) = (Tt)(a3*x + a4*y + a5*z);
              *(pd2++) = (Tt)(a6*x + a7*y + a8*z);
            }
            return res;
          }
          case 4 : { // 4x4_matrix * Matrix
            const t *ps0 = img.data(), *ps1 = img.data(0,1), *ps2 = img.data(0,2), *ps3 = img.data(0,3);
            Tt *pd0 = res.data(), *pd1 = res.data(0,1), *pd2 = res.data(0,2), *pd3 = res.data(0,3);
            const Ttdouble
              a0 = (Ttdouble)_data[0], a1 = (Ttdouble)_data[1], a2 = (Ttdouble)_data[2], a3 = (Ttdouble)_data[3],
              a4 = (Ttdouble)_data[4], a5 = (Ttdouble)_data[5], a6 = (Ttdouble)_data[6], a7 = (Ttdouble)_data[7],
              a8 = (Ttdouble)_data[8], a9 = (Ttdouble)_data[9], a10 = (Ttdouble)_data[10], a11 = (Ttdouble)_data[11],
              a12 = (Ttdouble)_data[12], a13 = (Ttdouble)_data[13], a14 = (Ttdouble)_data[14],
              a15 = (Ttdouble)_data[15];
            cimg_forX(img,col) {
              const Ttdouble x = (Ttdouble)*(ps0++), y = (Ttdouble)*(ps1++), z = (Ttdouble)*(ps2++),
                c = (Ttdouble)*(ps3++);
              *(pd0++) = (Tt)(a0*x + a1*y + a2*z + a3*c);
              *(pd1++) = (Tt)(a4*x + a5*y + a6*z + a7*c);
              *(pd2++) = (Tt)(a8*x + a9*y + a10*z + a11*c);
              *(pd3++) = (Tt)(a12*x + a13*y + a14*z + a15*c);
            }
            return res;
          }
          }
      }

      // Fallback to generic version.
#if cimg_use_openmp!=0
      cimg_pragma_openmp(parallel for cimg_openmp_collapse(2)
                         cimg_openmp_if(size()>(cimg_openmp_sizefactor)*1024 &&
                                        img.size()>(cimg_openmp_sizefactor)*1024))
        cimg_forXY(res,i,j) {
          Ttdouble value = 0; cimg_forX(*this,k) value+=(*this)(k,j)*img(i,k); res(i,j) = (Tt)value;
      }
#else
      Tt *ptrd = res._data;
      cimg_forXY(res,i,j) {
        Ttdouble value = 0; cimg_forX(*this,k) value+=(*this)(k,j)*img(i,k); *(ptrd++) = (Tt)value;
      }
#endif
      return res;