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

Project: CImg
File: CImg.h

    **/
    CImg<T>& RGBtoXYZ(const bool use_D65=true) {
      if (_spectrum!=3)
        throw CImgInstanceException(_cimg_instance
                                    "RGBtoXYZ(): Instance is not a RGB image.",
                                    cimg_instance);

      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);
      const ulongT whd = (ulongT)_width*_height*_depth;
      cimg_pragma_openmp(parallel for cimg_openmp_if(whd>=2048))
      for (ulongT N = 0; N<whd; ++N) {
        const Tfloat
          R = (Tfloat)p1[N]/255,
          G = (Tfloat)p2[N]/255,
          B = (Tfloat)p3[N]/255;
        if (use_D65) { // D65
          p1[N] = (T)(0.4124564*R + 0.3575761*G + 0.1804375*B);
          p2[N] = (T)(0.2126729*R + 0.7151522*G + 0.0721750*B);
          p3[N] = (T)(0.0193339*R + 0.1191920*G + 0.9503041*B);
        } else { // D50
          p1[N] = (T)(0.43603516*R + 0.38511658*G + 0.14305115*B);
          p2[N] = (T)(0.22248840*R + 0.71690369*G + 0.06060791*B);
          p3[N] = (T)(0.01391602*R + 0.09706116*G + 0.71392822*B);
        }
      }
      return *this;

Project: CImg
File: CImg.h


      static double mp_normp(_cimg_math_parser& mp) {
        const unsigned int i_end = (unsigned int)mp.opcode[2];
        if (i_end==4) return cimg::abs(_mp_arg(3));
        const double p = (double)mp.opcode[3];
        double res = 0;
        for (unsigned int i = 4; i<i_end; ++i)
          res+=std::pow(cimg::abs(_mp_arg(i)),p);
        res = std::pow(res,1/p);
        return res>0?res:0.0;

Project: CImg
File: CImg.h


    static LRESULT APIENTRY _handle_events(HWND window, UINT msg, WPARAM wParam, LPARAM lParam) {
#ifdef _WIN64
      CImgDisplay *const disp = (CImgDisplay*)GetWindowLongPtr(window,GWLP_USERDATA);
#else
      CImgDisplay *const disp = (CImgDisplay*)GetWindowLong(window,GWL_USERDATA);
#endif
      MSG st_msg;
      switch (msg) {
      case WM_CLOSE :
        disp->_mouse_x = disp->_mouse_y = -1;
        disp->_window_x = disp->_window_y = 0;
        disp->set_button().set_key(0).set_key(0,false)._is_closed = true;
        ReleaseMutex(disp->_mutex);
        ShowWindow(disp->_window,SW_HIDE);
        disp->_is_event = true;
        SetEvent(cimg::Win32_attr().wait_event);
        return 0;
      case WM_SIZE : {
        while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {}
        WaitForSingleObject(disp->_mutex,INFINITE);
        const unsigned int nw = LOWORD(lParam),nh = HIWORD(lParam);
        if (nw && nh && (nw!=disp->_width || nh!=disp->_height)) {
          disp->_window_width = nw;
          disp->_window_height = nh;
          disp->_mouse_x = disp->_mouse_y = -1;
          disp->_is_resized = disp->_is_event = true;
          SetEvent(cimg::Win32_attr().wait_event);
        }
        ReleaseMutex(disp->_mutex);
      } break;
      case WM_MOVE : {
        while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {}
        WaitForSingleObject(disp->_mutex,INFINITE);
        const int nx = (int)(short)(LOWORD(lParam)), ny = (int)(short)(HIWORD(lParam));
        if (nx!=disp->_window_x || ny!=disp->_window_y) {
          disp->_window_x = nx;
          disp->_window_y = ny;
          disp->_is_moved = disp->_is_event = true;
          SetEvent(cimg::Win32_attr().wait_event);
        }
        ReleaseMutex(disp->_mutex);
      } break;
      case WM_PAINT :
        disp->paint();
        cimg::mutex(15);
        if (disp->_is_cursor_visible) while (ShowCursor(TRUE)<0); else while (ShowCursor(FALSE)>=0);
        cimg::mutex(15,0);
        break;
      case WM_ERASEBKGND :
        //        return 0;
        break;
      case WM_KEYDOWN :
        disp->set_key((unsigned int)wParam);
        SetEvent(cimg::Win32_attr().wait_event);
        break;
      case WM_KEYUP :
        disp->set_key((unsigned int)wParam,false);
        SetEvent(cimg::Win32_attr().wait_event);
        break;
      case WM_MOUSEMOVE : {
        while (PeekMessage(&st_msg,window,WM_MOUSEMOVE,WM_MOUSEMOVE,PM_REMOVE)) {}
        disp->_mouse_x = LOWORD(lParam);
        disp->_mouse_y = HIWORD(lParam);
#if (_WIN32_WINNT>=0x0400) && !defined(NOTRACKMOUSEEVENT)
        if (!disp->_is_mouse_tracked) {
          TRACKMOUSEEVENT tme;
          tme.cbSize = sizeof(TRACKMOUSEEVENT);
          tme.dwFlags = TME_LEAVE;
          tme.hwndTrack = disp->_window;
          if (TrackMouseEvent(&tme)) disp->_is_mouse_tracked = true;
        }
#endif
        if (disp->_mouse_x<0 || disp->_mouse_y<0 || disp->_mouse_x>=disp->width() || disp->_mouse_y>=disp->height())
          disp->_mouse_x = disp->_mouse_y = -1;
        disp->_is_event = true;
        SetEvent(cimg::Win32_attr().wait_event);
        cimg::mutex(15);
	if (disp->_is_cursor_visible) while (ShowCursor(TRUE)<0); else while (ShowCursor(FALSE)>=0);
        cimg::mutex(15,0);
      }	break;
      case WM_MOUSELEAVE : {
        disp->_mouse_x = disp->_mouse_y = -1;
        disp->_is_mouse_tracked = false;
        cimg::mutex(15);
	while (ShowCursor(TRUE)<0) {}
        cimg::mutex(15,0);
      } break;
      case WM_LBUTTONDOWN :
        disp->set_button(1);
        SetEvent(cimg::Win32_attr().wait_event);
        break;
      case WM_RBUTTONDOWN :
        disp->set_button(2);
        SetEvent(cimg::Win32_attr().wait_event);
        break;
      case WM_MBUTTONDOWN :
        disp->set_button(3);
        SetEvent(cimg::Win32_attr().wait_event);
        break;
      case WM_LBUTTONUP :
        disp->set_button(1,false);
        SetEvent(cimg::Win32_attr().wait_event);
        break;
      case WM_RBUTTONUP :
        disp->set_button(2,false);
        SetEvent(cimg::Win32_attr().wait_event);
        break;
      case WM_MBUTTONUP :
        disp->set_button(3,false);
        SetEvent(cimg::Win32_attr().wait_event);
        break;
      case 0x020A : // WM_MOUSEWHEEL:
        disp->set_wheel((int)((short)HIWORD(wParam))/120);
        SetEvent(cimg::Win32_attr().wait_event);
      }
      return DefWindowProc(window,msg,wParam,lParam);

Project: CImg
File: CImg.h

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

      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);
      const ulongT whd = (ulongT)_width*_height*_depth;
      cimg_pragma_openmp(parallel for cimg_openmp_if(whd>=256))
      for (ulongT N = 0; N<whd; ++N) {
        Tfloat
          H = cimg::mod((Tfloat)p1[N],(Tfloat)360),
          S = (Tfloat)p2[N],
          V = (Tfloat)p3[N],
          R = 0, G = 0, B = 0;
        if (H==0 && S==0) R = G = B = V;
        else {
          H/=60;
          const int i = (int)std::floor(H);
          const Tfloat
            f = (i&1)?H - i:1 - H + i,
            m = V*(1 - S),
            n = V*(1 - S*f);
          switch (i) {
          case 6 :
          case 0 : R = V; G = n; B = m; break;
          case 1 : R = n; G = V; B = m; break;
          case 2 : R = m; G = V; B = n; break;
          case 3 : R = m; G = n; B = V; break;
          case 4 : R = n; G = m; B = V; break;
          case 5 : R = V; G = m; B = n; break;
          }
        }
        p1[N] = (T)cimg::cut(R*255,0,255);
        p2[N] = (T)cimg::cut(G*255,0,255);
        p3[N] = (T)cimg::cut(B*255,0,255);
      }
      return *this;

Project: CImg
File: CImg.h

    //! Access to pixel value with Dirichlet boundary conditions for the coordinate (\c pos) \const.
    T atN(const int pos, const int x, const int y, const int z, const int c, const T& out_value) const {
      return (pos<0 || pos>=(int)_width)?out_value:(*this)(pos,x,y,z,c);

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

    **/
    CImg<T>& pow(const double p) {
      if (is_empty()) return *this;
      if (p==-4) {
        cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=32768))
        cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val*val*val)); }
        return *this;
      }
      if (p==-3) {
        cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=32768))
        cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val*val)); }
        return *this;
      }
      if (p==-2) {
        cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=32768))
        cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val)); }
        return *this;
      }
      if (p==-1) {
        cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=32768))
        cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/val); }
        return *this;
      }
      if (p==-0.5) {
        cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=8192))
        cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1/std::sqrt((double)val)); }
        return *this;
      }
      if (p==0) return fill((T)1);
      if (p==0.25) return sqrt().sqrt();
      if (p==0.5) return sqrt();
      if (p==1) return *this;
      if (p==2) return sqr();
      if (p==3) {
        cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=262144))
        cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = val*val*val; }
        return *this;
      }
      if (p==4) {
        cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=131072))
        cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = val*val*val*val; }
        return *this;
      }
      cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=1024))
      cimg_rof(*this,ptrd,T) *ptrd = (T)std::pow((double)*ptrd,p);
      return *this;

Project: CImg
File: CImg.h

    **/
    T cubic_cut_atX(const float fx, const int y, const int z, const int c, const T& out_value) const {
      return cimg::type<T>::cut(cubic_atX(fx,y,z,c,out_value));

Project: CImg
File: CImg.h

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

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

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

Project: CImg
File: CImg.h

     **/
    CImg<T> get_matrix_at(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) const {
      const int n = (int)std::sqrt((double)_spectrum);
      const T *ptrs = data(x,y,z,0);
      const ulongT whd = (ulongT)_width*_height*_depth;
      CImg<T> res(n,n);
      T *ptrd = res._data;
      cimg_forC(*this,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
      return res;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


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

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

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

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    //! Resize 3d object to unit size.
    CImg<T> resize_object3d() {
      if (_height!=3 || _depth>1 || _spectrum>1)
        throw CImgInstanceException(_cimg_instance
                                    "resize_object3d(): Instance is not a set of 3d vertices.",
                                    cimg_instance);

      CImg<T> xcoords = get_shared_row(0), ycoords = get_shared_row(1), zcoords = get_shared_row(2);
      float
        xm, xM = (float)xcoords.max_min(xm),
        ym, yM = (float)ycoords.max_min(ym),
        zm, zM = (float)zcoords.max_min(zm);
      const float dx = xM - xm, dy = yM - ym, dz = zM - zm, dmax = cimg::max(dx,dy,dz);
      if (dmax>0) { xcoords/=dmax; ycoords/=dmax; zcoords/=dmax; }
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    **/
    CImg<T>& select(CImgDisplay &disp,
		    const unsigned int feature_type=2, unsigned int *const XYZ=0,
                    const bool exit_on_anykey=false) {
      return get_select(disp,feature_type,XYZ,exit_on_anykey).move_to(*this);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    */
    static void _cimg_blur_box_apply(T *ptr, const float boxsize, const int N, const ulongT off,
                                     const int order, const bool boundary_conditions,
                                     const unsigned int nb_iter) {
      // Smooth.
      if (boxsize>1 && nb_iter) {
        const int w2 = (int)(boxsize - 1)/2;
        const unsigned int winsize = 2*w2 + 1U;
        const double frac = (boxsize - winsize)/2.;
        CImg<T> win(winsize);
        for (unsigned int iter = 0; iter<nb_iter; ++iter) {
          Tdouble sum = 0; // window sum
          for (int x = -w2; x<=w2; ++x) {
            win[x + w2] = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,x);
            sum+=win[x + w2];
          }
          int ifirst = 0, ilast = 2*w2;
          T
            prev = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,-w2 - 1),
            next = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,w2 + 1);
          for (int x = 0; x < N - 1; ++x) {
            const double sum2 = sum + frac * (prev + next);
            ptr[x*off] = (T)(sum2/boxsize);
            prev = win[ifirst];
            sum-=prev;
            ifirst = (int)((ifirst + 1)%winsize);
            ilast = (int)((ilast + 1)%winsize);
            win[ilast] = next;
            sum+=next;
            next = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,x + w2 + 2);
          }
          const double sum2 = sum + frac * (prev + next);
          ptr[(N - 1)*off] = (T)(sum2/boxsize);
        }
      }

      // Derive.
      switch (order) {
      case 0 :
        break;
      case 1 : {
        Tfloat
          p = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,-1),
          c = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,0),
          n = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,1);
        for (int x = 0; x<N - 1; ++x) {
          ptr[x*off] = (T)((n-p)/2.0);
          p = c;
          c = n;
          n = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,x + 2);
        }
        ptr[(N - 1)*off] = (T)((n-p)/2.0);
      } break;
      case 2: {
        Tfloat
          p = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,-1),
          c = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,0),
          n = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,1);
        for (int x = 0; x<N - 1; ++x) {
          ptr[x*off] = (T)(n - 2*c + p);
          p = c;
          c = n;
          n = __cimg_blur_box_apply(ptr,N,off,boundary_conditions,x + 2);
        }
        ptr[(N - 1)*off] = (T)(n - 2*c + p);
      } break;
      }

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.0),
        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.0f*width(), hh = 2.0f*height();
          cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(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_cut_atXY(mx<width()?mx:ww - mx - 1,my<height()?my:hh - my - 1,z,c);
          }
        } break;
        case 1 : { // Linear interpolation
          const float ww = 2.0f*width(), hh = 2.0f*height();
          cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(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 collapse(3) cimg_openmp_if(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 collapse(3) cimg_openmp_if(res.size()>=2048))
            cimg_forXYZC(res,x,y,z,c) {
            const float xc = x - rw2, yc = y - rh2;
            res(x,y,z,c) = _cubic_cut_atXY(cimg::mod(w2 + xc*ca + yc*sa,(float)width()),
                                           cimg::mod(h2 - xc*sa + yc*ca,(float)height()),z,c);
          }
        } break;
        case 1 : { // Linear interpolation
          cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(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(cimg::mod(w2 + xc*ca + yc*sa,(float)width()),
                                           cimg::mod(h2 - xc*sa + yc*ca,(float)height()),z,c);
          }
        } break;
        default : { // Nearest-neighbor interpolation
          cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(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 collapse(3) cimg_openmp_if(res.size()>=2048))
          cimg_forXYZC(res,x,y,z,c) {
            const float xc = x - rw2, yc = y - rh2;
            res(x,y,z,c) = _cubic_cut_atXY(w2 + xc*ca + yc*sa,h2 - xc*sa + yc*ca,z,c);
          }
        } break;
        case 1 : { // Linear interpolation
          cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(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 collapse(3) cimg_openmp_if(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 collapse(3) cimg_openmp_if(res.size()>=2048))
          cimg_forXYZC(res,x,y,z,c) {
            const float xc = x - rw2, yc = y - rh2;
            res(x,y,z,c) = cubic_cut_atXY(w2 + xc*ca + yc*sa,h2 - xc*sa + yc*ca,z,c,(T)0);
          }
        } break;
        case 1 : { // Linear interpolation
          cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(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 collapse(3) cimg_openmp_if(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_list_jxyzc(_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
          ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y],
          oz = mp.mem[_cimg_mp_slot_z], oc = mp.mem[_cimg_mp_slot_c],
          x = ox + _mp_arg(3), y = oy + _mp_arg(4),
          z = oz + _mp_arg(5), c = oc + _mp_arg(6);
        if (interpolation==0) switch (boundary_conditions) { // Nearest neighbor interpolation
          case 3 : { // Mirror
            const int
              w2 = 2*img.width(), h2 = 2*img.height(), d2 = 2*img.depth(), 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(cimg::mod((int)x,img.width()),
                               cimg::mod((int)y,img.height()),
                               cimg::mod((int)z,img.depth()),
                               cimg::mod((int)c,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);
          } else switch (boundary_conditions) { // Linear interpolation
          case 3 : { // Mirror
            const float
              w2 = 2.0f*img.width(), h2 = 2.0f*img.height(), d2 = 2.0f*img.depth(), s2 = 2.0f*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_atXYZC(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._linear_atXYZC(cimg::mod((float)x,(float)img.width()),
                                              cimg::mod((float)y,(float)img.height()),
                                              cimg::mod((float)z,(float)img.depth()),
                                              cimg::mod((float)c,(float)img.spectrum()));
          case 1 : // Neumann
            return (double)img._linear_atXYZC((float)x,(float)y,(float)z,(float)c);
          default : // Dirichlet
            return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,(T)0);
          }

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>=32768,
        is_outer_parallel = res.size()>=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 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 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 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 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 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 T 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 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 T 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

     \param user_path Specified path, or \c 0 to get the path currently used.
     \param reinit_path Force path to be recalculated (may take some time).
     \return Path where temporary files can be saved.
  **/
  inline const char* temporary_path(const char *const user_path, const bool reinit_path) {
#define _cimg_test_temporary_path(p)                                    \
    if (!path_found) {                                                  \
      cimg_snprintf(s_path,s_path.width(),"%s",p);                      \
      cimg_snprintf(tmp,tmp._width,"%s%c%s",s_path.data(),cimg_file_separator,filename_tmp._data); \
      if ((file=std_fopen(tmp,"wb"))!=0) { cimg::fclose(file); std::remove(tmp); path_found = true; } \
    }
    static CImg<char> s_path;
    cimg::mutex(7);
    if (reinit_path) s_path.assign();
    if (user_path) {
      if (!s_path) s_path.assign(1024);
      std::strncpy(s_path,user_path,1023);
    } else if (!s_path) {
      s_path.assign(1024);
      bool path_found = false;
      CImg<char> tmp(1024), filename_tmp(256);
      std::FILE *file = 0;
      cimg_snprintf(filename_tmp,filename_tmp._width,"%s.tmp",cimg::filenamerand());
      char *tmpPath = std::getenv("TMP");
      if (!tmpPath) { tmpPath = std::getenv("TEMP"); winformat_string(tmpPath); }
      if (tmpPath) _cimg_test_temporary_path(tmpPath);
#if cimg_OS==2
      _cimg_test_temporary_path("C:\\WINNT\\Temp");
      _cimg_test_temporary_path("C:\\WINDOWS\\Temp");
      _cimg_test_temporary_path("C:\\Temp");
      _cimg_test_temporary_path("C:");
      _cimg_test_temporary_path("D:\\WINNT\\Temp");
      _cimg_test_temporary_path("D:\\WINDOWS\\Temp");
      _cimg_test_temporary_path("D:\\Temp");
      _cimg_test_temporary_path("D:");
#else
      _cimg_test_temporary_path("/tmp");
      _cimg_test_temporary_path("/var/tmp");
#endif
      if (!path_found) {
        *s_path = 0;
        std::strncpy(tmp,filename_tmp,tmp._width - 1);
        if ((file=std_fopen(tmp,"wb"))!=0) { cimg::fclose(file); std::remove(tmp); path_found = true; }
      }
      if (!path_found) {
        cimg::mutex(7,0);
        throw CImgIOException("cimg::temporary_path(): Failed to locate path for writing temporary files.\n");
      }

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

    //! Resize 3d object to unit size \newinstance.
    CImg<Tfloat> get_resize_object3d() const {
      return CImg<Tfloat>(*this,false).resize_object3d();

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.0f);
                *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

    **/
    CImg<T>& distance_eikonal(const unsigned int nb_iterations, const float band_size=0, const float time_step=0.5f) {
      if (is_empty()) return *this;
      CImg<Tfloat> velocity(*this,false);
      for (unsigned int iteration = 0; iteration<nb_iterations; ++iteration) {
        Tfloat *ptrd = velocity._data, veloc_max = 0;
        if (_depth>1) { // 3d
          CImg_3x3x3(I,Tfloat);
          cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) if (band_size<=0 || cimg::abs(Iccc)<band_size) {
            const Tfloat
              gx = (Incc - Ipcc)/2,
              gy = (Icnc - Icpc)/2,
              gz = (Iccn - Iccp)/2,
              sgn = -cimg::sign(Iccc),
              ix = gx*sgn>0?(Incc - Iccc):(Iccc - Ipcc),
              iy = gy*sgn>0?(Icnc - Iccc):(Iccc - Icpc),
              iz = gz*sgn>0?(Iccn - Iccc):(Iccc - Iccp),
              ng = 1e-5f + cimg::hypot(gx,gy,gz),
              ngx = gx/ng,
              ngy = gy/ng,
              ngz = gz/ng,
              veloc = sgn*(ngx*ix + ngy*iy + ngz*iz - 1);
            *(ptrd++) = veloc;
            if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc;
          } else *(ptrd++) = 0;
        } else { // 2d version
          CImg_3x3(I,Tfloat);
          cimg_forC(*this,c) cimg_for3x3(*this,x,y,0,c,I,Tfloat) if (band_size<=0 || cimg::abs(Icc)<band_size) {
            const Tfloat
              gx = (Inc - Ipc)/2,
              gy = (Icn - Icp)/2,
              sgn = -cimg::sign(Icc),
              ix = gx*sgn>0?(Inc - Icc):(Icc - Ipc),
              iy = gy*sgn>0?(Icn - Icc):(Icc - Icp),
              ng = std::max((Tfloat)1e-5,cimg::hypot(gx,gy)),
              ngx = gx/ng,
              ngy = gy/ng,
              veloc = sgn*(ngx*ix + ngy*iy - 1);
            *(ptrd++) = veloc;
            if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc;
          } else *(ptrd++) = 0;
        }
        if (veloc_max>0) *this+=(velocity*=time_step/veloc_max);
      }
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& cross(const CImg<t>& img) {
      if (_width!=1 || _height<3 || img._width!=1 || img._height<3)
        throw CImgInstanceException(_cimg_instance
                                    "cross(): Instance and/or specified image (%u,%u,%u,%u,%p) are not 3d vectors.",
                                    cimg_instance,
                                    img._width,img._height,img._depth,img._spectrum,img._data);

      const T x = (*this)[0], y = (*this)[1], z = (*this)[2];
      (*this)[0] = (T)(y*img[2] - z*img[1]);
      (*this)[1] = (T)(z*img[0] - x*img[2]);
      (*this)[2] = (T)(x*img[1] - y*img[0]);
      return *this;

Project: CImg
File: CImg.h

    // Locally solve eikonal equation.
    Tfloat __distance_eikonal(const CImg<Tfloat>& res, const Tfloat P,
                              const int x=0, const int y=0, const int z=0) const {
      const Tfloat M = (Tfloat)cimg::type<T>::max();
      T T1 = (T)std::min(x - 1>=0?res(x - 1,y,z):M,x + 1<width()?res(x + 1,y,z):M);
      Tfloat root = 0;
      if (_depth>1) { // 3d.
        T
          T2 = (T)std::min(y - 1>=0?res(x,y - 1,z):M,y + 1<height()?res(x,y + 1,z):M),
          T3 = (T)std::min(z - 1>=0?res(x,y,z - 1):M,z + 1<depth()?res(x,y,z + 1):M);
        if (T1>T2) cimg::swap(T1,T2);
        if (T2>T3) cimg::swap(T2,T3);
        if (T1>T2) cimg::swap(T1,T2);
        if (P<=0) return (Tfloat)T1;
        if (T3<M && ___distance_eikonal(3,-2*(T1 + T2 + T3),T1*T1 + T2*T2 + T3*T3 - P*P,root))
          return std::max((Tfloat)T3,root);
        if (T2<M && ___distance_eikonal(2,-2*(T1 + T2),T1*T1 + T2*T2 - P*P,root))
          return std::max((Tfloat)T2,root);
        return P + T1;
      } else if (_height>1) { // 2d.
        T T2 = (T)std::min(y - 1>=0?res(x,y - 1,z):M,y + 1<height()?res(x,y + 1,z):M);
        if (T1>T2) cimg::swap(T1,T2);
        if (P<=0) return (Tfloat)T1;
        if (T2<M && ___distance_eikonal(2,-2*(T1 + T2),T1*T1 + T2*T2 - P*P,root))
          return std::max((Tfloat)T2,root);
        return P + T1;
      } else { // 1d.
        if (P<=0) return (Tfloat)T1;
        return P + T1;
      }
      return 0;

Project: CImg
File: CImg.h


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

      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
      CImg<charT> line(256); *line = 0;
      int err = std::fscanf(nfile,"%255[^\n]",line._data);
      unsigned int dx = 0, dy = 1, dz = 1, dc = 1;
      cimg_sscanf(line,"%u%*c%u%*c%u%*c%u",&dx,&dy,&dz,&dc);
      err = std::fscanf(nfile,"%*[^0-9.eEinfa+-]");
      if (!dx || !dy || !dz || !dc) {
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "load_ascii(): Invalid ascii header in file '%s', image dimensions are set "
                              "to (%u,%u,%u,%u).",
                              cimg_instance,
                              filename?filename:"(FILE*)",dx,dy,dz,dc);
      }
      assign(dx,dy,dz,dc);
      const ulongT siz = size();
      ulongT off = 0;
      double val;
      T *ptr = _data;
      for (err = 1, off = 0; off<siz && err==1; ++off) {
        err = std::fscanf(nfile,"%lf%*[^0-9.eEinfa+-]",&val);
        *(ptr++) = (T)val;
      }
      if (err!=1)
        cimg::warn(_cimg_instance
                   "load_ascii(): Only %lu/%lu values read from file '%s'.",
                   cimg_instance,
                   off - 1,siz,filename?filename:"(FILE*)");

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

Project: CImg
File: CImg.h

    //! Crop image region \newinstance.
    CImg<T> get_crop(const int x0, const int y0, const int z0, const int c0,
                     const int x1, const int y1, const int z1, const int c1,
                     const unsigned int boundary_conditions=0) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "crop(): Empty instance.",
                                    cimg_instance);
      const int
        nx0 = x0<x1?x0:x1, nx1 = x0^x1^nx0,
        ny0 = y0<y1?y0:y1, ny1 = y0^y1^ny0,
        nz0 = z0<z1?z0:z1, nz1 = z0^z1^nz0,
        nc0 = c0<c1?c0:c1, nc1 = c0^c1^nc0;
      CImg<T> res(1U + nx1 - nx0,1U + ny1 - ny0,1U + nz1 - nz0,1U + nc1 - nc0);
      if (nx0<0 || nx1>=width() || ny0<0 || ny1>=height() || nz0<0 || nz1>=depth() || nc0<0 || nc1>=spectrum())
        switch (boundary_conditions) {
        case 3 : { // Mirror
          const int w2 = 2*width(), h2 = 2*height(), d2 = 2*depth(), s2 = 2*spectrum();
          cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(_width>=16 && _height*_depth*_spectrum>=4))
          cimg_forXYZC(res,x,y,z,c) {
            const int
              mx = cimg::mod(nx0 + x,w2),
              my = cimg::mod(ny0 + y,h2),
              mz = cimg::mod(nz0 + z,d2),
              mc = cimg::mod(nc0 + c,s2);
            res(x,y,z,c) = (*this)(mx<width()?mx:w2 - mx - 1,
                                   my<height()?my:h2 - my - 1,
                                   mz<depth()?mz:d2 - mz - 1,
                                   mc<spectrum()?mc:s2 - mc - 1);
          }
        } break;
        case 2 : { // Periodic
          cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(_width>=16 && _height*_depth*_spectrum>=4))
          cimg_forXYZC(res,x,y,z,c) {
            res(x,y,z,c) = (*this)(cimg::mod(nx0 + x,width()),cimg::mod(ny0 + y,height()),
                                   cimg::mod(nz0 + z,depth()),cimg::mod(nc0 + c,spectrum()));
          }
        } break;
        case 1 : // Neumann
          cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(_width>=16 && _height*_depth*_spectrum>=4))
          cimg_forXYZC(res,x,y,z,c) res(x,y,z,c) = _atXYZC(nx0 + x,ny0 + y,nz0 + z,nc0 + c);
          break;
        default : // Dirichlet
          res.fill((T)0).draw_image(-nx0,-ny0,-nz0,-nc0,*this);
        }
      else res.draw_image(-nx0,-ny0,-nz0,-nc0,*this);
      return res;

Project: CImg
File: CImg.h


    //! Crop font along the X-axis \newinstance.
    /**
    **/
    CImgList<T> get_crop_font() const {
      CImgList<T> res;
      cimglist_for(*this,l) {
        const CImg<T>& letter = (*this)[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) CImg<T>(letter._width,letter._height,1,letter._spectrum,0).move_to(res);
        else letter.get_crop(xmin,0,xmax,letter._height - 1).move_to(res);
      }

Project: CImg
File: CImg.h

    template<typename tp, typename tc, typename to>
    CImg<floatT> get_object3dtoCImg3d(const CImgList<tp>& primitives,
                                      const CImgList<tc>& colors,
                                      const to& opacities,
                                      const bool full_check=true) const {
      CImg<charT> error_message(1024);
      if (!is_object3d(primitives,colors,opacities,full_check,error_message))
        throw CImgInstanceException(_cimg_instance
                                    "object3dtoCImg3d(): Invalid specified 3d object (%u,%u) (%s).",
                                    cimg_instance,_width,primitives._width,error_message.data());
      CImg<floatT> res(1,_size_object3dtoCImg3d(primitives,colors,opacities));
      float *ptrd = res._data;

      // Put magick number.
      *(ptrd++) = 'C' + 0.5f; *(ptrd++) = 'I' + 0.5f; *(ptrd++) = 'm' + 0.5f;
      *(ptrd++) = 'g' + 0.5f; *(ptrd++) = '3' + 0.5f; *(ptrd++) = 'd' + 0.5f;

      // Put number of vertices and primitives.
      *(ptrd++) = cimg::uint2float(_width);
      *(ptrd++) = cimg::uint2float(primitives._width);

      // Put vertex data.
      if (is_empty() || !primitives) return res;
      const T *ptrx = data(0,0), *ptry = data(0,1), *ptrz = data(0,2);
      cimg_forX(*this,p) {
        *(ptrd++) = (float)*(ptrx++);
        *(ptrd++) = (float)*(ptry++);
        *(ptrd++) = (float)*(ptrz++);
      }

      // Put primitive data.
      cimglist_for(primitives,p) {
        *(ptrd++) = (float)primitives[p].size();
        const tp *ptrp = primitives[p]._data;
        cimg_foroff(primitives[p],i) *(ptrd++) = cimg::uint2float((unsigned int)*(ptrp++));
      }

      // Put color/texture data.
      const unsigned int csiz = std::min(colors._width,primitives._width);
      for (int c = 0; c<(int)csiz; ++c) {
        const CImg<tc>& color = colors[c];
        const tc *ptrc = color._data;
        if (color.size()==3) { *(ptrd++) = (float)*(ptrc++); *(ptrd++) = (float)*(ptrc++); *(ptrd++) = (float)*ptrc; }
        else {
          *(ptrd++) = -128.0f;
          int shared_ind = -1;
          if (color.is_shared()) for (int i = 0; i<c; ++i) if (ptrc==colors[i]._data) { shared_ind = i; break; }
          if (shared_ind<0) {
            *(ptrd++) = (float)color._width;
            *(ptrd++) = (float)color._height;
            *(ptrd++) = (float)color._spectrum;
            cimg_foroff(color,l) *(ptrd++) = (float)*(ptrc++);
          } else {
            *(ptrd++) = (float)shared_ind;
            *(ptrd++) = 0;
            *(ptrd++) = 0;
          }
        }
      }
      const int csiz2 = primitives.width() - colors.width();
      for (int c = 0; c<csiz2; ++c) { *(ptrd++) = 200.0f; *(ptrd++) = 200.0f; *(ptrd++) = 200.0f; }

      // Put opacity data.
      ptrd = _object3dtoCImg3d(opacities,ptrd);
      const float *ptre = res.end();
      while (ptrd<ptre) *(ptrd++) = 1.0f;
      return res;

Project: CImg
File: CImg.h

    template<typename tp, typename tf, typename tc, typename to, 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 CImg<to>& opacities,
                           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,
                           CImg<tz>& zbuffer) {
      return _draw_object3d(0,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities,
                            render_type,is_double_sided,focale,lightx,lighty,lightz,
                            specular_lightness,specular_shininess,1);

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& _draw_scanline(const int x0, const int x1, const int y,
                            const tc *const color, const float opacity,
                            const float brightness,
                            const float nopacity, const float copacity, const ulongT whd) {
      static const T maxval = (T)std::min(cimg::type<T>::max(),(T)cimg::type<tc>::max());
      const int nx0 = x0>0?x0:0, nx1 = x1<width()?x1:width() - 1, dx = nx1 - nx0;
      if (dx>=0) {
        const tc *col = color;
        const ulongT off = whd - dx - 1;
        T *ptrd = data(nx0,y);
        if (opacity>=1) { // ** Opaque drawing **
          if (brightness==1) { // Brightness==1
            if (sizeof(T)!=1) cimg_forC(*this,c) {
                const T val = (T)*(col++);
                for (int x = dx; x>=0; --x) *(ptrd++) = val;
                ptrd+=off;
              } else cimg_forC(*this,c) {
                const T val = (T)*(col++);
                std::memset(ptrd,(int)val,dx + 1);
                ptrd+=whd;
              }
          } else if (brightness<1) { // Brightness<1
            if (sizeof(T)!=1) cimg_forC(*this,c) {
                const T val = (T)(*(col++)*brightness);
                for (int x = dx; x>=0; --x) *(ptrd++) = val;
                ptrd+=off;
              } else cimg_forC(*this,c) {
                const T val = (T)(*(col++)*brightness);
                std::memset(ptrd,(int)val,dx + 1);
                ptrd+=whd;
              }
          } else { // Brightness>1
            if (sizeof(T)!=1) cimg_forC(*this,c) {
                const T val = (T)((2-brightness)**(col++) + (brightness - 1)*maxval);
                for (int x = dx; x>=0; --x) *(ptrd++) = val;
                ptrd+=off;
              } else cimg_forC(*this,c) {
                const T val = (T)((2-brightness)**(col++) + (brightness - 1)*maxval);
                std::memset(ptrd,(int)val,dx + 1);
                ptrd+=whd;
              }
          }
        } else { // ** Transparent drawing **
          if (brightness==1) { // Brightness==1
            cimg_forC(*this,c) {
              const Tfloat val = *(col++)*nopacity;
              for (int x = dx; x>=0; --x) { *ptrd = (T)(val + *ptrd*copacity); ++ptrd; }
              ptrd+=off;
            }
          } else if (brightness<=1) { // Brightness<1
            cimg_forC(*this,c) {
              const Tfloat val = *(col++)*brightness*nopacity;
              for (int x = dx; x>=0; --x) { *ptrd = (T)(val + *ptrd*copacity); ++ptrd; }
              ptrd+=off;
            }
          } else { // Brightness>1
            cimg_forC(*this,c) {
              const Tfloat val = ((2-brightness)**(col++) + (brightness - 1)*maxval)*nopacity;
              for (int x = dx; x>=0; --x) { *ptrd = (T)(val + *ptrd*copacity); ++ptrd; }
              ptrd+=off;
            }
          }
        }
      }
      return *this;

Project: CImg
File: CImg.h

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

      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);
      const ulongT whd = (ulongT)_width*_height*_depth;
      cimg_pragma_openmp(parallel for cimg_openmp_if(whd>=4096))
      for (ulongT N = 0; N<whd; ++N) {
        const Tfloat
          X = (Tfloat)p1[N],
          Y = (Tfloat)p2[N],
          Z = (Tfloat)p3[N],
          sum = X + Y + Z,
          nsum = sum>0?sum:1;
        p1[N] = (T)(X/nsum);
        p2[N] = (T)(Y/nsum);
        p3[N] = (T)Y;
      }
      return *this;

Project: CImg
File: CImg.h

    //! Access to pixel value with Dirichlet 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, const int c, const T& out_value) const {
      return (pos<0 || pos>=(int)_width)?out_value:_data[pos].atXY(x,y,z,c,out_value);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

       \param codec Type of compression (See http://www.fourcc.org/codecs.php to see available codecs).
       \param keep_open Tells if the video writer associated to the specified filename
       must be kept open or not (to allow frames to be added in the same file afterwards).
    **/
    const CImgList<T>& save_video(const char *const filename, const unsigned int fps=25,
                                  const char *codec=0, const bool keep_open=false) const {
#ifndef cimg_use_opencv
      cimg::unused(codec,keep_open);
      return save_ffmpeg_external(filename,fps);
#else
      static CvVideoWriter *writers[32] = { 0 };
      static CImgList<charT> filenames(32);
      static CImg<intT> sizes(32,2,1,1,0);
      static int last_used_index = -1;

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

      // Find empty slot for capturing video stream.
      if (index<0) {
        if (!filename)
          throw CImgArgumentException(_cimglist_instance
                                      "save_video(): No already open video writer found. You must specify a "
                                      "non-(null) filename argument for the first call.",
                                      cimglist_instance);
        else { cimg::mutex(9); cimglist_for(filenames,l) if (!filenames[l]) { index = l; break; } cimg::mutex(9,0); }
        if (index<0)
          throw CImgIOException(_cimglist_instance
                                "save_video(): File '%s', no video writer slots available. "
                                "You have to release some of your previously opened videos.",
                                cimglist_instance,filename);
        if (is_empty())
          throw CImgInstanceException(_cimglist_instance
                                      "save_video(): Instance list is empty.",
                                      cimglist_instance);
        const unsigned int W = _data?_data[0]._width:0, H = _data?_data[0]._height:0;
        if (!W || !H)
          throw CImgInstanceException(_cimglist_instance
                                      "save_video(): Frame [0] is an empty image.",
                                      cimglist_instance);

#define _cimg_docase(x) ((x)>='a'&&(x)<='z'?(x) + 'A' - 'a':(x))

        const char
          *const _codec = codec && *codec?codec:cimg_OS==2?"mpeg":"mp4v",
          codec0 = _cimg_docase(_codec[0]),
          codec1 = _codec[0]?_cimg_docase(_codec[1]):0,
          codec2 = _codec[1]?_cimg_docase(_codec[2]):0,
          codec3 = _codec[2]?_cimg_docase(_codec[3]):0;
        cimg::mutex(9);
        writers[index] = cvCreateVideoWriter(filename,CV_FOURCC(codec0,codec1,codec2,codec3),
                                             fps,cvSize(W,H));
        CImg<charT>::string(filename).move_to(filenames[index]);
        sizes(index,0) = W; sizes(index,1) = H;
        cimg::mutex(9,0);
        if (!writers[index])
          throw CImgIOException(_cimglist_instance
                                "save_video(): File '%s', unable to initialize video writer with codec '%c%c%c%c'.",
                                cimglist_instance,filename,
                                codec0,codec1,codec2,codec3);
      }

      if (!is_empty()) {
        const unsigned int W = sizes(index,0), H = sizes(index,1);
        cimg::mutex(9);
        IplImage *ipl = cvCreateImage(cvSize(W,H),8,3);
        cimglist_for(*this,l) {
          CImg<T> &src = _data[l];
          if (src.is_empty())
            cimg::warn(_cimglist_instance
                       "save_video(): Skip empty frame %d for file '%s'.",
                       cimglist_instance,l,filename);
          if (src._depth>1 || src._spectrum>3)
            cimg::warn(_cimglist_instance
                       "save_video(): Frame %u has incompatible dimension (%u,%u,%u,%u). "
                       "Some image data may be ignored when writing frame into video file '%s'.",
                       cimglist_instance,l,src._width,src._height,src._depth,src._spectrum,filename);
          if (src._width==W && src._height==H && src._spectrum==3) {
            const T *ptr_r = src.data(0,0,0,0), *ptr_g = src.data(0,0,0,1), *ptr_b = src.data(0,0,0,2);
            char *ptrd = ipl->imageData;
            cimg_forXY(src,x,y) {
              *(ptrd++) = (char)*(ptr_b++); *(ptrd++) = (char)*(ptr_g++); *(ptrd++) = (char)*(ptr_r++);
            }
          } else {
            CImg<unsigned char> _src(src,false);
            _src.channels(0,std::min(_src._spectrum - 1,2U)).resize(W,H);
            _src.resize(W,H,1,3,_src._spectrum==1);
            const unsigned char *ptr_r = _src.data(0,0,0,0), *ptr_g = _src.data(0,0,0,1), *ptr_b = _src.data(0,0,0,2);
            char *ptrd = ipl->imageData;
            cimg_forXY(_src,x,y) {
              *(ptrd++) = (char)*(ptr_b++); *(ptrd++) = (char)*(ptr_g++); *(ptrd++) = (char)*(ptr_r++);
            }
          }
          cvWriteFrame(writers[index],ipl);
        }
        cvReleaseImage(&ipl);
        cimg::mutex(9,0);
      }

      cimg::mutex(9);
      if (!keep_open) {
        cvReleaseVideoWriter(&writers[index]);
        writers[index] = 0;
        filenames[index].assign();
        sizes(index,0) = sizes(index,1) = 0;
        last_used_index = -1;
      } else last_used_index = index;
      cimg::mutex(9,0);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& _LU(CImg<t>& indx, bool& d) {
      const int N = width();
      int imax = 0;
      CImg<Tfloat> vv(N);
      indx.assign(N);
      d = true;
      cimg_forX(*this,i) {
        Tfloat vmax = 0;
        cimg_forX(*this,j) {
          const Tfloat tmp = cimg::abs((*this)(j,i));
          if (tmp>vmax) vmax = tmp;
        }
        if (vmax==0) { indx.fill(0); return fill(0); }
        vv[i] = 1/vmax;
      }
      cimg_forX(*this,j) {
        for (int i = 0; i<j; ++i) {
          Tfloat sum=(*this)(j,i);
          for (int k = 0; k<i; ++k) sum-=(*this)(k,i)*(*this)(j,k);
          (*this)(j,i) = (T)sum;
        }
        Tfloat vmax = 0;
        for (int i = j; i<width(); ++i) {
          Tfloat sum=(*this)(j,i);
          for (int k = 0; k<j; ++k) sum-=(*this)(k,i)*(*this)(j,k);
          (*this)(j,i) = (T)sum;
          const Tfloat tmp = vv[i]*cimg::abs(sum);
          if (tmp>=vmax) { vmax=tmp; imax=i; }
        }
        if (j!=imax) {
          cimg_forX(*this,k) cimg::swap((*this)(k,imax),(*this)(k,j));
          d =!d;
          vv[imax] = vv[j];
        }
        indx[j] = (t)imax;
        if ((*this)(j,j)==0) (*this)(j,j) = (T)1e-20;
        if (j<N) {
          const Tfloat tmp = 1/(Tfloat)(*this)(j,j);
          for (int i = j + 1; i<N; ++i) (*this)(j,i) = (T)((*this)(j,i)*tmp);
        }
      }
      return *this;

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_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);
        if (interpolation==0) switch (boundary_conditions) { // Nearest neighbor interpolation
          case 3 : { // Mirror
            const int
              w2 = 2*img.width(), h2 = 2*img.height(), d2 = 2*img.depth(), 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(cimg::mod((int)x,img.width()),
                               cimg::mod((int)y,img.height()),
                               cimg::mod((int)z,img.depth()),
                               cimg::mod((int)c,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);
          } else switch (boundary_conditions) { // Linear interpolation
          case 3 : { // Mirror
            const float
              w2 = 2.0f*img.width(), h2 = 2.0f*img.height(), d2 = 2.0f*img.depth(), s2 = 2.0f*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_atXYZC(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._linear_atXYZC(cimg::mod((float)x,(float)img.width()),
                                              cimg::mod((float)y,(float)img.height()),
                                              cimg::mod((float)z,(float)img.depth()),
                                              cimg::mod((float)c,(float)img.spectrum()));
          case 1 : // Neumann
            return (double)img._linear_atXYZC((float)x,(float)y,(float)z,(float)c);
          default : // Dirichlet
            return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,(T)0);
          }

Project: CImg
File: CImg.h

      return *ptr_min;
    }

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

Project: CImg
File: CImg.h

    **/
    CImgList<Tfloat> get_hessian(const char *const axes=0) const {
      CImgList<Tfloat> res;
      const char *naxes = axes, *const def_axes2d = "xxxyyy", *const def_axes3d = "xxxyxzyyyzzz";
      if (!axes) naxes = _depth>1?def_axes3d:def_axes2d;
      const unsigned int lmax = (unsigned int)std::strlen(naxes);
      if (lmax%2)
        throw CImgArgumentException(_cimg_instance
                                    "get_hessian(): Invalid specified axes '%s'.",
                                    cimg_instance,
                                    naxes);

      res.assign(lmax/2,_width,_height,_depth,_spectrum);
      if (!cimg::strcasecmp(naxes,def_axes3d)) { // 3d

        cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2))
        cimg_forC(*this,c) {
          const ulongT off = (ulongT)c*_width*_height*_depth;
          Tfloat
            *ptrd0 = res[0]._data + off, *ptrd1 = res[1]._data + off, *ptrd2 = res[2]._data + off,
            *ptrd3 = res[3]._data + off, *ptrd4 = res[4]._data + off, *ptrd5 = res[5]._data + off;
          CImg_3x3x3(I,Tfloat);
          cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) {
            *(ptrd0++) = Ipcc + Incc - 2*Iccc;          // Ixx
            *(ptrd1++) = (Ippc + Innc - Ipnc - Inpc)/4; // Ixy
            *(ptrd2++) = (Ipcp + Incn - Ipcn - Incp)/4; // Ixz
            *(ptrd3++) = Icpc + Icnc - 2*Iccc;          // Iyy
            *(ptrd4++) = (Icpp + Icnn - Icpn - Icnp)/4; // Iyz
            *(ptrd5++) = Iccn + Iccp - 2*Iccc;          // Izz
          }
        }
      } else if (!cimg::strcasecmp(naxes,def_axes2d)) { // 2d
        cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if(_width*_height>=1048576 && _depth*_spectrum>=2))
        cimg_forZC(*this,z,c) {
          const ulongT off = (ulongT)c*_width*_height*_depth + z*_width*_height;
          Tfloat *ptrd0 = res[0]._data + off, *ptrd1 = res[1]._data + off, *ptrd2 = res[2]._data + off;
          CImg_3x3(I,Tfloat);
          cimg_for3x3(*this,x,y,z,c,I,Tfloat) {
            *(ptrd0++) = Ipc + Inc - 2*Icc;         // Ixx
            *(ptrd1++) = (Ipp + Inn - Ipn - Inp)/4; // Ixy
            *(ptrd2++) = Icp + Icn - 2*Icc;         // Iyy
          }
        }
      } else for (unsigned int l = 0; l<lmax; ) { // Version with custom axes.
          const unsigned int l2 = l/2;
          char axis1 = naxes[l++], axis2 = naxes[l++];
          if (axis1>axis2) cimg::swap(axis1,axis2);
          bool valid_axis = false;
          if (axis1=='x' && axis2=='x') { // Ixx
            valid_axis = true;
            cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if(_width*_height>=1048576 && _depth*_spectrum>=2))
            cimg_forZC(*this,z,c) {
              Tfloat *ptrd = res[l2].data(0,0,z,c);
              CImg_3x3(I,Tfloat);
              cimg_for3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = Ipc + Inc - 2*Icc;
            }
          }
          else if (axis1=='x' && axis2=='y') { // Ixy
            valid_axis = true;
            cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if(_width*_height>=1048576 && _depth*_spectrum>=2))
            cimg_forZC(*this,z,c) {
              Tfloat *ptrd = res[l2].data(0,0,z,c);
              CImg_3x3(I,Tfloat);
              cimg_for3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = (Ipp + Inn - Ipn - Inp)/4;
            }
          }
          else if (axis1=='x' && axis2=='z') { // Ixz
            valid_axis = true;
            cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2))
            cimg_forC(*this,c) {
              Tfloat *ptrd = res[l2].data(0,0,0,c);
              CImg_3x3x3(I,Tfloat);
              cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = (Ipcp + Incn - Ipcn - Incp)/4;
            }
          }
          else if (axis1=='y' && axis2=='y') { // Iyy
            valid_axis = true;
            cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if(_width*_height>=1048576 && _depth*_spectrum>=2))
            cimg_forZC(*this,z,c) {
              Tfloat *ptrd = res[l2].data(0,0,z,c);
              CImg_3x3(I,Tfloat);
              cimg_for3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = Icp + Icn - 2*Icc;
            }
          }
          else if (axis1=='y' && axis2=='z') { // Iyz
            valid_axis = true;
            cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2))
            cimg_forC(*this,c) {
              Tfloat *ptrd = res[l2].data(0,0,0,c);
              CImg_3x3x3(I,Tfloat);
              cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = (Icpp + Icnn - Icpn - Icnp)/4;
            }
          }
          else if (axis1=='z' && axis2=='z') { // Izz
            valid_axis = true;
            cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2))
            cimg_forC(*this,c) {
              Tfloat *ptrd = res[l2].data(0,0,0,c);
              CImg_3x3x3(I,Tfloat);
              cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = Iccn + Iccp - 2*Iccc;
            }
          }
          else if (!valid_axis)
            throw CImgArgumentException(_cimg_instance
                                        "get_hessian(): Invalid specified axes '%s'.",
                                        cimg_instance,
                                        naxes);
        }
      return res;

Project: CImg
File: CImg.h

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

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

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

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>=(int)_width)?out_value:_data[pos].atXYZC(x,y,z,c,out_value);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& warp(const CImg<t>& warp, const unsigned int mode=0,
                  const unsigned int interpolation=1, const unsigned int boundary_conditions=0) {
      return get_warp(warp,mode,interpolation,boundary_conditions).move_to(*this);

Project: CImg
File: CImg.h


      static double mp_gauss(_cimg_math_parser& mp) {
        const double x = _mp_arg(2), s = _mp_arg(3);
        return std::exp(-x*x/(2*s*s))/std::sqrt(2*s*s*cimg::PI);

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    template<typename tp, typename tf, typename tc, typename to, typename tz>
    CImg<T>& draw_object3d(LibBoard::Board& board,
                           const float x0, const float y0, const float z0,
                           const CImg<tp>& vertices, const CImgList<tf>& primitives,
                           const CImgList<tc>& colors,
                           const 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,
                           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,zbuffer);

Project: CImg
File: CImg.h

    template<typename tz, typename tc>
    CImg<T>& draw_triangle(CImg<tz>& zbuffer,
                           const int x0, const int y0, const float z0,
                           const int x1, const int y1, const float z1,
                           const int x2, const int y2, const float z2,
                           const tc *const color,
                           const float brightness0,
                           const float brightness1,
                           const float brightness2,
                           const float opacity=1) {
      typedef typename cimg::superset<tz,float>::type tzfloat;
      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
      if (!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);
      static const T maxval = (T)std::min(cimg::type<T>::max(),(T)cimg::type<tc>::max());
      const float nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.0f);
      const longT whd = (longT)width()*height()*depth(), offx = spectrum()*whd;
      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
        nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f),
        nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f),
        nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f);
      tzfloat nz0 = 1/(tzfloat)z0, nz1 = 1/(tzfloat)z1, nz2 = 1/(tzfloat)z2;
      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1,nc0,nc1);
      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nz0,nz2,nc0,nc2);
      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nz1,nz2,nc1,nc2);
      if (ny0>=height() || ny2<0) return *this;
      tzfloat
        pzl = (nz1 - nz0)/(ny1 - ny0),
        pzr = (nz2 - nz0)/(ny2 - ny0),
        pzn = (nz2 - nz1)/(ny2 - ny1),
        zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
        zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));
      _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
        if (y==ny1) { zl = nz1; pzl = pzn; }
        int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0;
        tzfloat zleft = zl, zright = zr;
        if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,cleft,cright);
        const int
          dx = xright - xleft,
          dc = cright>cleft?cright - cleft:cleft - cright,
          rc = dx?(cright - cleft)/dx:0,
          sc = cright>cleft?1:-1,
          ndc = dc - (dx?dx*(dc/dx):0);
        const tzfloat pentez = (zright - zleft)/dx;
        int errc = dx>>1;
        if (xleft<0 && dx) {
          cleft-=xleft*(cright - cleft)/dx;
          zleft-=xleft*(zright - zleft)/dx;
        }
        if (xleft<0) xleft = 0;
        if (xright>=width() - 1) xright = width() - 1;
        T *ptrd = data(xleft,y);
        tz *ptrz = xleft<=xright?zbuffer.data(xleft,y):0;
        if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
            if (zleft>=(tzfloat)*ptrz) {
              *ptrz = (tz)zleft;
              const tc *col = color;
              cimg_forC(*this,c) {
                *ptrd = (T)(cleft<256?cleft**(col++)/256:((512 - cleft)**(col++)+(cleft - 256)*maxval)/256);
                ptrd+=whd;
              }
              ptrd-=offx;
            }
            zleft+=pentez;
            cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
          } else for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
            if (zleft>=(tzfloat)*ptrz) {
              *ptrz = (tz)zleft;
              const tc *col = color;
              cimg_forC(*this,c) {
                const T val = (T)(cleft<256?cleft**(col++)/256:((512 - cleft)**(col++)+(cleft - 256)*maxval)/256);
                *ptrd = (T)(nopacity*val + *ptrd*copacity);
                ptrd+=whd;
              }
              ptrd-=offx;
            }
            zleft+=pentez;
            cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
          }
        zr+=pzr; zl+=pzl;
      }
      return *this;

Project: CImg
File: CImg.h

    //! Loadimage from an ascii file \newinstance.
    static CImg<T> get_load_ascii(std::FILE *const file) {
      return CImg<T>().load_ascii(file);

Project: CImg
File: CImg.h

#endif
  }

  // Open a file (with wide character support on Windows).
  inline std::FILE *win_fopen(const char *const path, const char *const mode) {
#if cimg_OS==2
    // Convert 'path' to a wide-character string.
    int err = MultiByteToWideChar(CP_UTF8,0,path,-1,0,0);
    if (!err) return std_fopen(path,mode);
    CImg<wchar_t> wpath(err);
    err = MultiByteToWideChar(CP_UTF8,0,path,-1,wpath,err);
    if (!err) return std_fopen(path,mode);

    // Convert 'mode' to a wide-character string.
    err = MultiByteToWideChar(CP_UTF8,0,mode,-1,0,0);
    if (!err) return std_fopen(path,mode);
    CImg<wchar_t> wmode(err);
    err = MultiByteToWideChar(CP_UTF8,0,mode,-1,wmode,err);
    if (!err) return std_fopen(path,mode);
    return _wfopen(wpath,wmode);

Project: CImg
File: CImg.h

    //! Save list as a gzipped file, using external tool 'gzip'.
    /**
      \param filename Filename to write data to.
    **/
    const CImgList<T>& save_gzip_external(const char *const filename) const {
      if (!filename)
        throw CImgIOException(_cimglist_instance
                              "save_gzip_external(): Specified filename is (null).",
                              cimglist_instance);
      CImg<charT> command(1024), filename_tmp(256), body(256);
      const char
        *ext = cimg::split_filename(filename,body),
        *ext2 = cimg::split_filename(body,0);
      std::FILE *file;
      do {
        if (!cimg::strcasecmp(ext,"gz")) {
          if (*ext2) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s",
                                   cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2);
          else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.cimg",
                             cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
        } else {
          if (*ext) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s",
                                  cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext);
          else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.cimg",
                             cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
        }
        if ((file=std_fopen(filename_tmp,"rb"))!=0) cimg::fclose(file);
      } while (file);

      if (is_saveable(body)) {
        save(filename_tmp);
        cimg_snprintf(command,command._width,"%s -c \"%s\" > \"%s\"",
                      cimg::gzip_path(),
                      CImg<charT>::string(filename_tmp)._system_strescape().data(),
                      CImg<charT>::string(filename)._system_strescape().data());
        cimg::system(command);
        file = std_fopen(filename,"rb");
        if (!file)
          throw CImgIOException(_cimglist_instance
                                "save_gzip_external(): Failed to save file '%s' with external command 'gzip'.",
                                cimglist_instance,
                                filename);
        else cimg::fclose(file);
        std::remove(filename_tmp);
      } else {
        CImg<charT> nfilename(1024);
        cimglist_for(*this,l) {
          cimg::number_filename(body,l,6,nfilename);
          if (*ext) cimg_sprintf(nfilename._data + std::strlen(nfilename),".%s",ext);
          _data[l].save_gzip_external(nfilename);

Project: CImg
File: CImg.h

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

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    //! Return stream line of a 3d vector field \overloading.
    static CImg<floatT> streamline(const char *const expression,
                                   const float x, const float y, const float z,
                                   const float L=256, const float dl=0.1f,
                                   const unsigned int interpolation_type=2, const bool is_backward_tracking=true,
                                   const bool is_oriented_only=false,
                                   const float x0=0, const float y0=0, const float z0=0,
                                   const float x1=0, const float y1=0, const float z1=0) {
      _functor4d_streamline_expr func(expression);
      return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,is_oriented_only,x0,y0,z0,x1,y1,z1);

Project: CImg
File: CImg.h


    const CImg<T>& _display_graph(CImgDisplay &disp, const char *const title=0,
                                  const unsigned int plot_type=1, const unsigned int vertex_type=1,
                                  const char *const labelx=0, const double xmin=0, const double xmax=0,
                                  const char *const labely=0, const double ymin=0, const double ymax=0,
                                  const bool exit_on_anykey=false) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "display_graph(): Empty instance.",
                                    cimg_instance);
      if (!disp) disp.assign(cimg_fitscreen(CImgDisplay::screen_width()/2,CImgDisplay::screen_height()/2,1),0,0).
                   set_title(title?"%s":"CImg<%s>",title?title:pixel_type());
      const ulongT siz = (ulongT)_width*_height*_depth, siz1 = std::max((ulongT)1,siz - 1);
      const unsigned int old_normalization = disp.normalization();
      disp.show().flush()._normalization = 0;

      double y0 = ymin, y1 = ymax, nxmin = xmin, nxmax = xmax;
      if (nxmin==nxmax) { nxmin = 0; nxmax = siz1; }
      int x0 = 0, x1 = width()*height()*depth() - 1, key = 0;

      for (bool reset_view = true; !key && !disp.is_closed(); ) {
        if (reset_view) { x0 = 0; x1 = width()*height()*depth() - 1; y0 = ymin; y1 = ymax; reset_view = false; }
        CImg<T> zoom(x1 - x0 + 1,1,1,spectrum());
        cimg_forC(*this,c) zoom.get_shared_channel(c) = CImg<T>(data(x0,0,0,c),x1 - x0 + 1,1,1,1,true);
        if (y0==y1) { y0 = zoom.min_max(y1); const double dy = y1 - y0; y0-=dy/20; y1+=dy/20; }
        if (y0==y1) { --y0; ++y1; }

        const CImg<intT> selection = zoom.get_select_graph(disp,plot_type,vertex_type,
        					           labelx,
                                                           nxmin + x0*(nxmax - nxmin)/siz1,
                                                           nxmin + x1*(nxmax - nxmin)/siz1,
                                                           labely,y0,y1,true);
	const int mouse_x = disp.mouse_x(), mouse_y = disp.mouse_y();
        if (selection[0]>=0) {
          if (selection[2]<0) reset_view = true;
          else {
            x1 = x0 + selection[2]; x0+=selection[0];
            if (selection[1]>=0 && selection[3]>=0) {
              y0 = y1 - selection[3]*(y1 - y0)/(disp.height() - 32);
              y1-=selection[1]*(y1 - y0)/(disp.height() - 32);
            }
          }
        } else {
          bool go_in = false, go_out = false, go_left = false, go_right = false, go_up = false, go_down = false;
          switch (key = (int)disp.key()) {
          case cimg::keyHOME : reset_view = true; key = 0; disp.set_key(); break;
          case cimg::keyPADADD : go_in = true; go_out = false; key = 0; disp.set_key(); break;
          case cimg::keyPADSUB : go_out = true; go_in = false; key = 0; disp.set_key(); break;
          case cimg::keyARROWLEFT : case cimg::keyPAD4 : go_left = true; go_right = false; key = 0; disp.set_key();
            break;
          case cimg::keyARROWRIGHT : case cimg::keyPAD6 : go_right = true; go_left = false; key = 0; disp.set_key();
            break;
          case cimg::keyARROWUP : case cimg::keyPAD8 : go_up = true; go_down = false; key = 0; disp.set_key(); break;
          case cimg::keyARROWDOWN : case cimg::keyPAD2 : go_down = true; go_up = false; key = 0; disp.set_key(); break;
          case cimg::keyPAD7 : go_left = true; go_up = true; key = 0; disp.set_key(); break;
          case cimg::keyPAD9 : go_right = true; go_up = true; key = 0; disp.set_key(); break;
          case cimg::keyPAD1 : go_left = true; go_down = true; key = 0; disp.set_key(); break;
          case cimg::keyPAD3 : go_right = true; go_down = true; key = 0; disp.set_key(); break;
          }
          if (disp.wheel()) {
            if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) go_up = !(go_down = disp.wheel()<0);
            else if (disp.is_keySHIFTLEFT() || disp.is_keySHIFTRIGHT()) go_left = !(go_right = disp.wheel()>0);
            else go_out = !(go_in = disp.wheel()>0);
            key = 0;
          }

          if (go_in) {
            const int
              xsiz = x1 - x0,
              mx = (mouse_x - 16)*xsiz/(disp.width() - 32),
              cx = x0 + cimg::cut(mx,0,xsiz);
            if (x1 - x0>4) {
              x0 = cx - 7*(cx - x0)/8; x1 = cx + 7*(x1 - cx)/8;
              if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
                const double
                  ysiz = y1 - y0,
                  my = (mouse_y - 16)*ysiz/(disp.height() - 32),
                  cy = y1 - cimg::cut(my,0.0,ysiz);
                y0 = cy - 7*(cy - y0)/8; y1 = cy + 7*(y1 - cy)/8;
              } else y0 = y1 = 0;
            }
          }
          if (go_out) {
            if (x0>0 || x1<(int)siz1) {
              const int delta_x = (x1 - x0)/8, ndelta_x = delta_x?delta_x:(siz>1);
              const double ndelta_y = (y1 - y0)/8;
              x0-=ndelta_x; x1+=ndelta_x;
              y0-=ndelta_y; y1+=ndelta_y;
              if (x0<0) { x1-=x0; x0 = 0; if (x1>=(int)siz) x1 = (int)siz1; }
              if (x1>=(int)siz) { x0-=(x1 - siz1); x1 = (int)siz1; if (x0<0) x0 = 0; }
            }
          }
          if (go_left) {
            const int delta = (x1 - x0)/5, ndelta = delta?delta:1;
            if (x0 - ndelta>=0) { x0-=ndelta; x1-=ndelta; }
            else { x1-=x0; x0 = 0; }
            go_left = false;
          }
          if (go_right) {
            const int delta = (x1 - x0)/5, ndelta = delta?delta:1;
            if (x1 + ndelta<(int)siz) { x0+=ndelta; x1+=ndelta; }
            else { x0+=(siz1 - x1); x1 = (int)siz1; }
            go_right = false;
          }
          if (go_up) {
            const double delta = (y1 - y0)/10, ndelta = delta?delta:1;
            y0+=ndelta; y1+=ndelta;
            go_up = false;
          }
          if (go_down) {
            const double delta = (y1 - y0)/10, ndelta = delta?delta:1;
            y0-=ndelta; y1-=ndelta;
            go_down = false;
          }
        }
        if (!exit_on_anykey && key && key!=(int)cimg::keyESC &&
            (key!=(int)cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) {
          disp.set_key(key,false);
          key = 0;
        }
      }
      disp._normalization = old_normalization;
      return *this;

Project: CImg
File: CImg.h

    //! Convert pixel values from CMYK to CMY color spaces \newinstance.
    CImg<Tfloat> get_CMYKtoCMY() const {
      if (_spectrum!=4)
        throw CImgInstanceException(_cimg_instance
                                    "CMYKtoCMY(): Instance is not a CMYK image.",
                                    cimg_instance);

      CImg<Tfloat> res(_width,_height,_depth,3);
      const T *ps1 = data(0,0,0,0), *ps2 = data(0,0,0,1), *ps3 = data(0,0,0,2), *ps4 = data(0,0,0,3);
      Tfloat *pd1 = res.data(0,0,0,0), *pd2 = res.data(0,0,0,1), *pd3 = res.data(0,0,0,2);
      const ulongT whd = (ulongT)_width*_height*_depth;
      cimg_pragma_openmp(parallel for cimg_openmp_if(whd>=1024))
      for (ulongT N = 0; N<whd; ++N) {
        const Tfloat
	  C = (Tfloat)ps1[N],
	  M = (Tfloat)ps2[N],
	  Y = (Tfloat)ps3[N],
	  K = (Tfloat)ps4[N],
	  K1 = 1 - K/255,
          nC = C*K1 + K,
          nM = M*K1 + K,
          nY = Y*K1 + K;
        pd1[N] = (Tfloat)cimg::cut(nC,0,255),
        pd2[N] = (Tfloat)cimg::cut(nM,0,255),
        pd3[N] = (Tfloat)cimg::cut(nY,0,255);
      }
      return res;

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_gaussian(const float xc, const float sigma,
                           const tc *const color, const float opacity=1) {
      if (is_empty()) return *this;
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_gaussian(): Specified color is (null).",
                                    cimg_instance);
      const float sigma2 = 2*sigma*sigma, nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.0f);
      const ulongT whd = (ulongT)_width*_height*_depth;
      const tc *col = color;
      cimg_forX(*this,x) {
        const float dx = (x - xc), val = (float)std::exp(-dx*dx/sigma2);
        T *ptrd = data(x,0,0,0);
        if (opacity>=1) cimg_forC(*this,c) { *ptrd = (T)(val*(*col++)); ptrd+=whd; }
        else cimg_forC(*this,c) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whd; }
        col-=_spectrum;
      }
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


    CImg<T>& _distance_core(longT (*const sep)(const longT, const longT, const longT *const),
                            longT (*const f)(const longT, const longT, const longT *const)) {
 // Check for g++ 4.9.X, as OpenMP seems to crash for this particular function. I have no clues why.
#define cimg_is_gcc49x (__GNUC__==4 && __GNUC_MINOR__==9)

      const ulongT wh = (ulongT)_width*_height;
#if defined(cimg_use_openmp) && !cimg_is_gcc49x
      cimg_pragma_openmp(parallel for cimg_openmp_if(_spectrum>=2))
#endif
      cimg_forC(*this,c) {
        CImg<longT> g(_width), dt(_width), s(_width), t(_width);
        CImg<T> img = get_shared_channel(c);
#if defined(cimg_use_openmp) && !cimg_is_gcc49x
        cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if(_width>=512 && _height*_depth>=16)
                           firstprivate(g,dt,s,t))
#endif
        cimg_forYZ(*this,y,z) { // Over X-direction.
          cimg_forX(*this,x) g[x] = (longT)img(x,y,z,0,wh);
          _distance_scan(_width,g,sep,f,s,t,dt);
          cimg_forX(*this,x) img(x,y,z,0,wh) = (T)dt[x];
        }
        if (_height>1) {
          g.assign(_height); dt.assign(_height); s.assign(_height); t.assign(_height);
#if defined(cimg_use_openmp) && !cimg_is_gcc49x
          cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if(_height>=512 && _width*_depth>=16)
                             firstprivate(g,dt,s,t))
#endif
          cimg_forXZ(*this,x,z) { // Over Y-direction.
            cimg_forY(*this,y) g[y] = (longT)img(x,y,z,0,wh);
            _distance_scan(_height,g,sep,f,s,t,dt);
            cimg_forY(*this,y) img(x,y,z,0,wh) = (T)dt[y];
          }
        }
        if (_depth>1) {
          g.assign(_depth); dt.assign(_depth); s.assign(_depth); t.assign(_depth);
#if defined(cimg_use_openmp) && !cimg_is_gcc49x
          cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if(_depth>=512 && _width*_height>=16)
                             firstprivate(g,dt,s,t))
#endif
          cimg_forXY(*this,x,y) { // Over Z-direction.
            cimg_forZ(*this,z) g[z] = (longT)img(x,y,z,0,wh);
            _distance_scan(_depth,g,sep,f,s,t,dt);
            cimg_forZ(*this,z) img(x,y,z,0,wh) = (T)dt[z];
          }
        }
      }
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


    static DWORD WINAPI _events_thread(void* arg) {
      CImgDisplay *const disp = (CImgDisplay*)(((void**)arg)[0]);
      const char *const title = (const char*)(((void**)arg)[1]);
      MSG msg;
      delete[] (void**)arg;
      disp->_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
      disp->_bmi.bmiHeader.biWidth = disp->width();
      disp->_bmi.bmiHeader.biHeight = -disp->height();
      disp->_bmi.bmiHeader.biPlanes = 1;
      disp->_bmi.bmiHeader.biBitCount = 32;
      disp->_bmi.bmiHeader.biCompression = BI_RGB;
      disp->_bmi.bmiHeader.biSizeImage = 0;
      disp->_bmi.bmiHeader.biXPelsPerMeter = 1;
      disp->_bmi.bmiHeader.biYPelsPerMeter = 1;
      disp->_bmi.bmiHeader.biClrUsed = 0;
      disp->_bmi.bmiHeader.biClrImportant = 0;
      disp->_data = new unsigned int[(size_t)disp->_width*disp->_height];
      if (!disp->_is_fullscreen) { // Normal window
        RECT rect;
        rect.left = rect.top = 0; rect.right = (LONG)disp->_width - 1; rect.bottom = (LONG)disp->_height - 1;
        AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
        const int
          border1 = (int)((rect.right - rect.left + 1 - disp->_width)/2),
          border2 = (int)(rect.bottom - rect.top + 1 - disp->_height - border1);
        disp->_window = CreateWindowA("MDICLIENT",title?title:" ",
                                     WS_OVERLAPPEDWINDOW | (disp->_is_closed?0:WS_VISIBLE), CW_USEDEFAULT,CW_USEDEFAULT,
                                     disp->_width + 2*border1, disp->_height + border1 + border2,
                                     0,0,0,&(disp->_ccs));
        if (!disp->_is_closed) {
          GetWindowRect(disp->_window,&rect);
          disp->_window_x = rect.left + border1;
          disp->_window_y = rect.top + border2;
        } else disp->_window_x = disp->_window_y = 0;
      } else { // Fullscreen window
        const unsigned int
          sx = (unsigned int)screen_width(),
          sy = (unsigned int)screen_height();
        disp->_window = CreateWindowA("MDICLIENT",title?title:" ",
                                     WS_POPUP | (disp->_is_closed?0:WS_VISIBLE),
                                      (sx - disp->_width)/2,
                                      (sy - disp->_height)/2,
                                     disp->_width,disp->_height,0,0,0,&(disp->_ccs));
        disp->_window_x = disp->_window_y = 0;
      }
      SetForegroundWindow(disp->_window);
      disp->_hdc = GetDC(disp->_window);
      disp->_window_width = disp->_width;
      disp->_window_height = disp->_height;
      disp->flush();
#ifdef _WIN64
      SetWindowLongPtr(disp->_window,GWLP_USERDATA,(LONG_PTR)disp);
      SetWindowLongPtr(disp->_window,GWLP_WNDPROC,(LONG_PTR)_handle_events);
#else
      SetWindowLong(disp->_window,GWL_USERDATA,(LONG)disp);
      SetWindowLong(disp->_window,GWL_WNDPROC,(LONG)_handle_events);
#endif
      SetEvent(disp->_is_created);
      while (GetMessage(&msg,0,0,0)) DispatchMessage(&msg);
      return 0;

Project: CImg
File: CImg.h

    template<typename tp, typename tf, typename tc, typename to, 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 CImgList<to>& opacities,
                           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,
                           CImg<tz>& zbuffer) {
      return _draw_object3d(0,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities,
                            render_type,is_double_sided,focale,lightx,lighty,lightz,
                            specular_lightness,specular_shininess,1);

Project: CImg
File: CImg.h

    // (Note: Most of this function has been written by Eric Fausett)
    CImg<T>& _load_png(std::FILE *const file, const char *const filename, unsigned int *const bits_per_pixel) {
      if (!file && !filename)
        throw CImgArgumentException(_cimg_instance
                                    "load_png(): Specified filename is (null).",
                                    cimg_instance);

#ifndef cimg_use_png
      cimg::unused(bits_per_pixel);
      if (file)
        throw CImgIOException(_cimg_instance
                              "load_png(): Unable to load data from '(FILE*)' unless libpng is enabled.",
                              cimg_instance);

      else return load_other(filename);
#else
      // Open file and check for PNG validity
#if defined __GNUC__
      const char *volatile nfilename = filename; // Use 'volatile' to avoid (wrong) g++ warning.
      std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"rb");
#else
      const char *nfilename = filename;
      std::FILE *nfile = file?file:cimg::fopen(nfilename,"rb");
#endif
      unsigned char pngCheck[8] = { 0 };
      cimg::fread(pngCheck,8,(std::FILE*)nfile);
      if (png_sig_cmp(pngCheck,0,8)) {
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "load_png(): Invalid PNG file '%s'.",
                              cimg_instance,
                              nfilename?nfilename:"(FILE*)");
      }

      // Setup PNG structures for read
      png_voidp user_error_ptr = 0;
      png_error_ptr user_error_fn = 0, user_warning_fn = 0;
      png_structp png_ptr = png_create_read_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
                              "load_png(): Failed to initialize 'png_ptr' structure for file '%s'.",
                              cimg_instance,
                              nfilename?nfilename:"(FILE*)");
      }
      png_infop info_ptr = png_create_info_struct(png_ptr);
      if (!info_ptr) {
        if (!file) cimg::fclose(nfile);
        png_destroy_read_struct(&png_ptr,(png_infopp)0,(png_infopp)0);
        throw CImgIOException(_cimg_instance
                              "load_png(): Failed to initialize 'info_ptr' structure for file '%s'.",
                              cimg_instance,
                              nfilename?nfilename:"(FILE*)");
      }
      png_infop end_info = png_create_info_struct(png_ptr);
      if (!end_info) {
        if (!file) cimg::fclose(nfile);
        png_destroy_read_struct(&png_ptr,&info_ptr,(png_infopp)0);
        throw CImgIOException(_cimg_instance
                              "load_png(): Failed to initialize 'end_info' structure for file '%s'.",
                              cimg_instance,
                              nfilename?nfilename:"(FILE*)");
      }

      // Error handling callback for png file reading
      if (setjmp(png_jmpbuf(png_ptr))) {
        if (!file) cimg::fclose((std::FILE*)nfile);
        png_destroy_read_struct(&png_ptr, &end_info, (png_infopp)0);
        throw CImgIOException(_cimg_instance
                              "load_png(): Encountered unknown fatal error in libpng for file '%s'.",
                              cimg_instance,
                              nfilename?nfilename:"(FILE*)");
      }
      png_init_io(png_ptr, nfile);
      png_set_sig_bytes(png_ptr, 8);

      // Get PNG Header Info up to data block
      png_read_info(png_ptr,info_ptr);
      png_uint_32 W, H;
      int bit_depth, color_type, interlace_type;
      bool is_gray = false;
      png_get_IHDR(png_ptr,info_ptr,&W,&H,&bit_depth,&color_type,&interlace_type,(int*)0,(int*)0);
      if (bits_per_pixel) *bits_per_pixel = (unsigned int)bit_depth;

      // Transforms to unify image data
      if (color_type==PNG_COLOR_TYPE_PALETTE) {
        png_set_palette_to_rgb(png_ptr);
        color_type = PNG_COLOR_TYPE_RGB;
        bit_depth = 8;
      }
      if (color_type==PNG_COLOR_TYPE_GRAY && bit_depth<8) {
        png_set_expand_gray_1_2_4_to_8(png_ptr);
        is_gray = true;
        bit_depth = 8;
      }
      if (png_get_valid(png_ptr,info_ptr,PNG_INFO_tRNS)) {
        png_set_tRNS_to_alpha(png_ptr);
        color_type |= PNG_COLOR_MASK_ALPHA;
      }
      if (color_type==PNG_COLOR_TYPE_GRAY || color_type==PNG_COLOR_TYPE_GRAY_ALPHA) {
        png_set_gray_to_rgb(png_ptr);
        color_type |= PNG_COLOR_MASK_COLOR;
        is_gray = true;
      }
      if (color_type==PNG_COLOR_TYPE_RGB)
        png_set_filler(png_ptr,0xffffU,PNG_FILLER_AFTER);

      png_read_update_info(png_ptr,info_ptr);
      if (bit_depth!=8 && bit_depth!=16) {
        if (!file) cimg::fclose(nfile);
        png_destroy_read_struct(&png_ptr,&end_info,(png_infopp)0);
        throw CImgIOException(_cimg_instance
                              "load_png(): Invalid bit depth %u in file '%s'.",
                              cimg_instance,
                              bit_depth,nfilename?nfilename:"(FILE*)");
      }
      const int byte_depth = bit_depth>>3;

      // Allocate Memory for Image Read
      png_bytep *const imgData = new png_bytep[H];
      for (unsigned int row = 0; row<H; ++row) imgData[row] = new png_byte[(size_t)byte_depth*4*W];
      png_read_image(png_ptr,imgData);
      png_read_end(png_ptr,end_info);

      // Read pixel data
      if (color_type!=PNG_COLOR_TYPE_RGB && color_type!=PNG_COLOR_TYPE_RGB_ALPHA) {
        if (!file) cimg::fclose(nfile);
        png_destroy_read_struct(&png_ptr,&end_info,(png_infopp)0);
        throw CImgIOException(_cimg_instance
                              "load_png(): Invalid color coding type %u in file '%s'.",
                              cimg_instance,
                              color_type,nfilename?nfilename:"(FILE*)");
      }
      const bool is_alpha = (color_type==PNG_COLOR_TYPE_RGBA);
      try { assign(W,H,1,(is_gray?1:3) + (is_alpha?1:0)); }
      catch (...) { if (!file) cimg::fclose(nfile); throw; }
      T
        *ptr_r = data(0,0,0,0),
        *ptr_g = is_gray?0:data(0,0,0,1),
        *ptr_b = is_gray?0:data(0,0,0,2),
        *ptr_a = !is_alpha?0:data(0,0,0,is_gray?1:3);
      switch (bit_depth) {
      case 8 : {
        cimg_forY(*this,y) {
          const unsigned char *ptrs = (unsigned char*)imgData[y];
          cimg_forX(*this,x) {
            *(ptr_r++) = (T)*(ptrs++);
            if (ptr_g) *(ptr_g++) = (T)*(ptrs++); else ++ptrs;
            if (ptr_b) *(ptr_b++) = (T)*(ptrs++); else ++ptrs;
            if (ptr_a) *(ptr_a++) = (T)*(ptrs++); else ++ptrs;
          }
        }
      } break;
      case 16 : {
        cimg_forY(*this,y) {
          const unsigned short *ptrs = (unsigned short*)(imgData[y]);
          if (!cimg::endianness()) cimg::invert_endianness(ptrs,4*_width);
          cimg_forX(*this,x) {
            *(ptr_r++) = (T)*(ptrs++);
            if (ptr_g) *(ptr_g++) = (T)*(ptrs++); else ++ptrs;
            if (ptr_b) *(ptr_b++) = (T)*(ptrs++); else ++ptrs;
            if (ptr_a) *(ptr_a++) = (T)*(ptrs++); else ++ptrs;
          }
        }
      } break;
      }
      png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);

      // Deallocate Image Read Memory
      cimg_forY(*this,n) delete[] imgData[n];
      delete[] imgData;
      if (!file) cimg::fclose(nfile);
      return *this;
#endif

Project: CImg
File: CImg.h

    template<typename tf, typename tp, typename tff>
    CImg<T>& append_object3d(CImgList<tf>& primitives, const CImg<tp>& obj_vertices,
                             const CImgList<tff>& obj_primitives) {
      if (!obj_vertices || !obj_primitives) return *this;
      if (obj_vertices._height!=3 || obj_vertices._depth>1 || obj_vertices._spectrum>1)
        throw CImgInstanceException(_cimg_instance
                                    "append_object3d(): Specified vertice image (%u,%u,%u,%u,%p) is not a "
                                    "set of 3d vertices.",
                                    cimg_instance,
                                    obj_vertices._width,obj_vertices._height,
                                    obj_vertices._depth,obj_vertices._spectrum,obj_vertices._data);

      if (is_empty()) { primitives.assign(obj_primitives); return assign(obj_vertices); }
      if (_height!=3 || _depth>1 || _spectrum>1)
        throw CImgInstanceException(_cimg_instance
                                    "append_object3d(): Instance is not a set of 3d vertices.",
                                    cimg_instance);

      const unsigned int P = _width;
      append(obj_vertices,'x');
      const unsigned int N = primitives._width;
      primitives.insert(obj_primitives);
      for (unsigned int i = N; i<primitives._width; ++i) {
        CImg<tf> &p = primitives[i];
        switch (p.size()) {
        case 1 : p[0]+=P; break; // Point.
        case 5 : p[0]+=P; p[1]+=P; break; // Sphere.
        case 2 : case 6 : p[0]+=P; p[1]+=P; break; // Segment.
        case 3 : case 9 : p[0]+=P; p[1]+=P; p[2]+=P; break; // Triangle.
        case 4 : case 12 : p[0]+=P; p[1]+=P; p[2]+=P; p[3]+=P; break; // Rectangle.
        }
      }
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    //! Draw an image \specialization.
    CImg<T>& draw_image(const int x0, const int y0, const int z0, const int c0,
                        const CImg<T>& sprite, const float opacity=1) {
      if (is_empty() || !sprite) return *this;
      if (is_overlapped(sprite)) return draw_image(x0,y0,z0,c0,+sprite,opacity);
      if (x0==0 && y0==0 && z0==0 && c0==0 && is_sameXYZC(sprite) && opacity>=1 && !is_shared())
        return assign(sprite,false);
      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 T
        *ptrs = sprite._data +
        (bx?-x0:0) +
        (by?-y0*(ulongT)sprite.width():0) +
        (bz?-z0*(ulongT)sprite.width()*sprite.height():0) +
        (bc?-c0*(ulongT)sprite.width()*sprite.height()*sprite.depth():0);
      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),
        slX = lX*sizeof(T);
      const float nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.0f);
      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 v = 0; v<lC; ++v) {
          for (int z = 0; z<lZ; ++z) {
            if (opacity>=1)
              for (int y = 0; y<lY; ++y) { std::memcpy(ptrd,ptrs,slX); ptrd+=_width; ptrs+=sprite._width; }
            else for (int y = 0; y<lY; ++y) {
                for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*(*(ptrs++)) + *ptrd*copacity); ++ptrd; }
                ptrd+=offX; ptrs+=soffX;
              }
            ptrd+=offY; ptrs+=soffY;
          }
          ptrd+=offZ; ptrs+=soffZ;
        }
      }
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    **/
    inline cimg_long wait(const unsigned int milliseconds) {
      cimg::mutex(3);
      static cimg_ulong timer = 0;
      if (!timer) timer = cimg::time();
      cimg::mutex(3,0);
      return _wait(milliseconds,timer);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<_cimg_Ttfloat> _correlate(const CImg<t>& kernel, const bool boundary_conditions,
                                   const bool is_normalized, const bool is_convolution) const {
      if (is_empty() || !kernel) return *this;
      typedef _cimg_Ttfloat Ttfloat;
      CImg<Ttfloat> res;
      const ulongT
        res_whd = (ulongT)_width*_height*_depth,
        res_size = res_whd*std::max(_spectrum,kernel._spectrum);
      const bool
        is_inner_parallel = _width*_height*_depth>=32768,
        is_outer_parallel = res_size>=32768;
      _cimg_abort_init_omp;
      cimg_abort_init;

      if (kernel._width==kernel._height &&
          ((kernel._depth==1 && kernel._width<=6) || (kernel._depth==kernel._width && kernel._width<=3))) {

        // Special optimization done for 2x2, 3x3, 4x4, 5x5, 6x6, 2x2x2 and 3x3x3 kernel.
        if (!boundary_conditions && res_whd<=3000*3000) { // Dirichlet boundaries
          // For relatively small images, adding a zero border then use optimized NxN convolution loops is faster.
          res = (kernel._depth==1?get_crop(-1,-1,_width,_height):get_crop(-1,-1,-1,_width,_height,_depth)).
            _correlate(kernel,true,is_normalized,is_convolution);
          if (kernel._depth==1) res.crop(1,1,res._width - 2,res._height - 2);
          else res.crop(1,1,1,res._width - 2,res._height - 2,res._depth - 2);

        } else { // Neumann boundaries
          res.assign(_width,_height,_depth,std::max(_spectrum,kernel._spectrum));
          cimg::unused(is_inner_parallel,is_outer_parallel);
          CImg<t> _kernel;
          if (is_convolution) { // Add empty column/row/slice to shift kernel center in case of convolution
            const int dw = !(kernel.width()%2), dh = !(kernel.height()%2), dd = !(kernel.depth()%2);
            if (dw || dh || dd)
              kernel.get_resize(kernel.width() + dw,kernel.height() + dh,kernel.depth() + dd,-100,0,0).
                move_to(_kernel);
          }
          if (!_kernel) _kernel = kernel.get_shared();

          switch (_kernel._depth) {
          case 3 : {
            cimg_pragma_openmp(parallel for cimg_openmp_if(is_outer_parallel))
              cimg_forC(res,c) {
              cimg_abort_test;
              const CImg<T> img = get_shared_channel(c%_spectrum);
              const CImg<t> K = _kernel.get_shared_channel(c%kernel._spectrum);
              CImg<T> I(27);
              Ttfloat *ptrd = res.data(0,0,0,c);
              if (is_normalized) {
                const Ttfloat _M = (Ttfloat)K.magnitude(2), M = _M*_M;
                cimg_for3x3x3(img,x,y,z,0,I,T) {
                  const Ttfloat N = M*(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] +
                                       I[ 3]*I[ 3] + I[ 4]*I[ 4] + I[ 5]*I[ 5] +
                                       I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] +
                                       I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +
                                       I[12]*I[12] + I[13]*I[13] + I[14]*I[14] +
                                       I[15]*I[15] + I[16]*I[16] + I[17]*I[17] +
                                       I[18]*I[18] + I[19]*I[19] + I[20]*I[20] +
                                       I[21]*I[21] + I[22]*I[22] + I[23]*I[23] +
                                       I[24]*I[24] + I[25]*I[25] + I[26]*I[26]);
                  *(ptrd++) = (Ttfloat)(N?(I[ 0]*K[ 0] + I[ 1]*K[ 1] + I[ 2]*K[ 2] +
                                           I[ 3]*K[ 3] + I[ 4]*K[ 4] + I[ 5]*K[ 5] +
                                           I[ 6]*K[ 6] + I[ 7]*K[ 7] + I[ 8]*K[ 8] +
                                           I[ 9]*K[ 9] + I[10]*K[10] + I[11]*K[11] +
                                           I[12]*K[12] + I[13]*K[13] + I[14]*K[14] +
                                           I[15]*K[15] + I[16]*K[16] + I[17]*K[17] +
                                           I[18]*K[18] + I[19]*K[19] + I[20]*K[20] +
                                           I[21]*K[21] + I[22]*K[22] + I[23]*K[23] +
                                           I[24]*K[24] + I[25]*K[25] + I[26]*K[26])/std::sqrt(N):0);
                }
              } else cimg_for3x3x3(img,x,y,z,0,I,T)
                       *(ptrd++) = (Ttfloat)(I[ 0]*K[ 0] + I[ 1]*K[ 1] + I[ 2]*K[ 2] +
                                             I[ 3]*K[ 3] + I[ 4]*K[ 4] + I[ 5]*K[ 5] +
                                             I[ 6]*K[ 6] + I[ 7]*K[ 7] + I[ 8]*K[ 8] +
                                             I[ 9]*K[ 9] + I[10]*K[10] + I[11]*K[11] +
                                             I[12]*K[12] + I[13]*K[13] + I[14]*K[14] +
                                             I[15]*K[15] + I[16]*K[16] + I[17]*K[17] +
                                             I[18]*K[18] + I[19]*K[19] + I[20]*K[20] +
                                             I[21]*K[21] + I[22]*K[22] + I[23]*K[23] +
                                             I[24]*K[24] + I[25]*K[25] + I[26]*K[26]);
            }
          } break;
          case 2 : {
            cimg_pragma_openmp(parallel for cimg_openmp_if(is_outer_parallel))
              cimg_forC(res,c) {
              cimg_abort_test;
              const CImg<T> img = get_shared_channel(c%_spectrum);
              const CImg<t> K = _kernel.get_shared_channel(c%kernel._spectrum);
              CImg<T> I(8);
              Ttfloat *ptrd = res.data(0,0,0,c);
              if (is_normalized) {
                const Ttfloat _M = (Ttfloat)K.magnitude(2), M = _M*_M;
                cimg_for2x2x2(img,x,y,z,0,I,T) {
                  const Ttfloat N = M*(I[0]*I[0] + I[1]*I[1] +
                                       I[2]*I[2] + I[3]*I[3] +
                                       I[4]*I[4] + I[5]*I[5] +
                                       I[6]*I[6] + I[7]*I[7]);
                  *(ptrd++) = (Ttfloat)(N?(I[0]*K[0] + I[1]*K[1] +
                                           I[2]*K[2] + I[3]*K[3] +
                                           I[4]*K[4] + I[5]*K[5] +
                                           I[6]*K[6] + I[7]*K[7])/std::sqrt(N):0);
                }
              } else cimg_for2x2x2(img,x,y,z,0,I,T)
                       *(ptrd++) = (Ttfloat)(I[0]*K[0] + I[1]*K[1] +
                                             I[2]*K[2] + I[3]*K[3] +
                                             I[4]*K[4] + I[5]*K[5] +
                                             I[6]*K[6] + I[7]*K[7]);
            }
          } break;
          default :
          case 1 :
            switch (_kernel._width) {
            case 6 : {
              cimg_pragma_openmp(parallel for cimg_openmp_if(is_outer_parallel))
                cimg_forC(res,c) {
                cimg_abort_test;
                const CImg<T> img = get_shared_channel(c%_spectrum);
                const CImg<t> K = _kernel.get_shared_channel(c%kernel._spectrum);
                CImg<T> I(36);
                Ttfloat *ptrd = res.data(0,0,0,c);
                if (is_normalized) {
                  const Ttfloat _M = (Ttfloat)K.magnitude(2), M = _M*_M;
                  cimg_forZ(img,z) cimg_for6x6(img,x,y,z,0,I,T) {
                    const Ttfloat N = M*(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] + I[ 4]*I[ 4] +
                                         I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] +
                                         I[10]*I[10] + I[11]*I[11] + I[12]*I[12] + I[13]*I[13] + I[14]*I[14] +
                                         I[15]*I[15] + I[16]*I[16] + I[17]*I[17] + I[18]*I[18] + I[19]*I[19] +
                                         I[20]*I[20] + I[21]*I[21] + I[22]*I[22] + I[23]*I[23] + I[24]*I[24] +
                                         I[25]*I[25] + I[26]*I[26] + I[27]*I[27] + I[28]*I[28] + I[29]*I[29] +
                                         I[30]*I[30] + I[31]*I[31] + I[32]*I[32] + I[33]*I[33] + I[34]*I[34] +
                                         I[35]*I[35]);
                    *(ptrd++) = (Ttfloat)(N?(I[ 0]*K[ 0] + I[ 1]*K[ 1] + I[ 2]*K[ 2] + I[ 3]*K[ 3] +
                                             I[ 4]*K[ 4] + I[ 5]*K[ 5] + I[ 6]*K[ 6] + I[ 7]*K[ 7] +
                                             I[ 8]*K[ 8] + I[ 9]*K[ 9] + I[10]*K[10] + I[11]*K[11] +
                                             I[12]*K[12] + I[13]*K[13] + I[14]*K[14] + I[15]*K[15] +
                                             I[16]*K[16] + I[17]*K[17] + I[18]*K[18] + I[19]*K[19] +
                                             I[20]*K[20] + I[21]*K[21] + I[22]*K[22] + I[23]*K[23] +
                                             I[24]*K[24] + I[25]*K[25] + I[26]*K[26] + I[27]*K[27] +
                                             I[28]*K[28] + I[29]*K[29] + I[30]*K[30] + I[31]*K[31] +
                                             I[32]*K[32] + I[33]*K[33] + I[34]*K[34] + I[35]*K[35])/
                                          std::sqrt(N):0);
                  }
                } else cimg_forZ(img,z) cimg_for6x6(img,x,y,z,0,I,T)
                         *(ptrd++) = (Ttfloat)(I[ 0]*K[ 0] + I[ 1]*K[ 1] + I[ 2]*K[ 2] + I[ 3]*K[ 3] +
                                               I[ 4]*K[ 4] + I[ 5]*K[ 5] + I[ 6]*K[ 6] + I[ 7]*K[ 7] +
                                               I[ 8]*K[ 8] + I[ 9]*K[ 9] + I[10]*K[10] + I[11]*K[11] +
                                               I[12]*K[12] + I[13]*K[13] + I[14]*K[14] + I[15]*K[15] +
                                               I[16]*K[16] + I[17]*K[17] + I[18]*K[18] + I[19]*K[19] +
                                               I[20]*K[20] + I[21]*K[21] + I[22]*K[22] + I[23]*K[23] +
                                               I[24]*K[24] + I[25]*K[25] + I[26]*K[26] + I[27]*K[27] +
                                               I[28]*K[28] + I[29]*K[29] + I[30]*K[30] + I[31]*K[31] +
                                               I[32]*K[32] + I[33]*K[33] + I[34]*K[34] + I[35]*K[35]);
              }
            } break;
            case 5 : {
              cimg_pragma_openmp(parallel for cimg_openmp_if(is_outer_parallel))
                cimg_forC(res,c) {
                cimg_abort_test;
                const CImg<T> img = get_shared_channel(c%_spectrum);
                const CImg<t> K = _kernel.get_shared_channel(c%kernel._spectrum);
                CImg<T> I(25);
                Ttfloat *ptrd = res.data(0,0,0,c);
                if (is_normalized) {
                  const Ttfloat _M = (Ttfloat)K.magnitude(2), M = _M*_M;
                  cimg_forZ(img,z) cimg_for5x5(img,x,y,z,0,I,T) {
                    const Ttfloat N = M*(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] + I[ 4]*I[ 4] +
                                         I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] +
                                         I[10]*I[10] + I[11]*I[11] + I[12]*I[12] + I[13]*I[13] + I[14]*I[14] +
                                         I[15]*I[15] + I[16]*I[16] + I[17]*I[17] + I[18]*I[18] + I[19]*I[19] +
                                         I[20]*I[20] + I[21]*I[21] + I[22]*I[22] + I[23]*I[23] + I[24]*I[24]);
                    *(ptrd++) = (Ttfloat)(N?(I[ 0]*K[ 0] + I[ 1]*K[ 1] + I[ 2]*K[ 2] + I[ 3]*K[ 3] +
                                             I[ 4]*K[ 4] + I[ 5]*K[ 5] + I[ 6]*K[ 6] + I[ 7]*K[ 7] +
                                             I[ 8]*K[ 8] + I[ 9]*K[ 9] + I[10]*K[10] + I[11]*K[11] +
                                             I[12]*K[12] + I[13]*K[13] + I[14]*K[14] + I[15]*K[15] +
                                             I[16]*K[16] + I[17]*K[17] + I[18]*K[18] + I[19]*K[19] +
                                             I[20]*K[20] + I[21]*K[21] + I[22]*K[22] + I[23]*K[23] +
                                             I[24]*K[24])/std::sqrt(N):0);
                  }
                } else cimg_forZ(img,z) cimg_for5x5(img,x,y,z,0,I,T)
                         *(ptrd++) = (Ttfloat)(I[ 0]*K[ 0] + I[ 1]*K[ 1] + I[ 2]*K[ 2] + I[ 3]*K[ 3] +
                                               I[ 4]*K[ 4] + I[ 5]*K[ 5] + I[ 6]*K[ 6] + I[ 7]*K[ 7] +
                                               I[ 8]*K[ 8] + I[ 9]*K[ 9] + I[10]*K[10] + I[11]*K[11] +
                                               I[12]*K[12] + I[13]*K[13] + I[14]*K[14] + I[15]*K[15] +
                                               I[16]*K[16] + I[17]*K[17] + I[18]*K[18] + I[19]*K[19] +
                                               I[20]*K[20] + I[21]*K[21] + I[22]*K[22] + I[23]*K[23] +
                                               I[24]*K[24]);
              }
            } break;
            case 4 : {
              cimg_pragma_openmp(parallel for cimg_openmp_if(is_outer_parallel))
                cimg_forC(res,c) {
                cimg_abort_test;
                const CImg<T> img = get_shared_channel(c%_spectrum);
                const CImg<t> K = _kernel.get_shared_channel(c%kernel._spectrum);
                CImg<T> I(16);
                Ttfloat *ptrd = res.data(0,0,0,c);
                if (is_normalized) {
                  const Ttfloat _M = (Ttfloat)K.magnitude(2), M = _M*_M;
                  cimg_forZ(img,z) cimg_for4x4(img,x,y,z,0,I,T) {
                    const Ttfloat N = M*(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] +
                                         I[ 4]*I[ 4] + I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] +
                                         I[ 8]*I[ 8] + I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +
                                         I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + I[15]*I[15]);
                    *(ptrd++) = (Ttfloat)(N?(I[ 0]*K[ 0] + I[ 1]*K[ 1] + I[ 2]*K[ 2] + I[ 3]*K[ 3] +
                                             I[ 4]*K[ 4] + I[ 5]*K[ 5] + I[ 6]*K[ 6] + I[ 7]*K[ 7] +
                                             I[ 8]*K[ 8] + I[ 9]*K[ 9] + I[10]*K[10] + I[11]*K[11] +
                                             I[12]*K[12] + I[13]*K[13] + I[14]*K[14] + I[15]*K[15])/
                                          std::sqrt(N):0);
                  }
                } else cimg_forZ(img,z) cimg_for4x4(img,x,y,z,0,I,T)
                         *(ptrd++) = (Ttfloat)(I[ 0]*K[ 0] + I[ 1]*K[ 1] + I[ 2]*K[ 2] + I[ 3]*K[ 3] +
                                               I[ 4]*K[ 4] + I[ 5]*K[ 5] + I[ 6]*K[ 6] + I[ 7]*K[ 7] +
                                               I[ 8]*K[ 8] + I[ 9]*K[ 9] + I[10]*K[10] + I[11]*K[11] +
                                               I[12]*K[12] + I[13]*K[13] + I[14]*K[14] + I[15]*K[15]);
              }
            } break;
            case 3 : {
              cimg_pragma_openmp(parallel for cimg_openmp_if(is_outer_parallel))
                cimg_forC(res,c) {
                cimg_abort_test;
                const CImg<T> img = get_shared_channel(c%_spectrum);
                const CImg<t> K = _kernel.get_shared_channel(c%kernel._spectrum);
                CImg<T> I(9);
                Ttfloat *ptrd = res.data(0,0,0,c);
                if (is_normalized) {
                  const Ttfloat _M = (Ttfloat)K.magnitude(2), M = _M*_M;
                  cimg_forZ(img,z) cimg_for3x3(img,x,y,z,0,I,T) {
                    const Ttfloat N = M*(I[0]*I[0] + I[1]*I[1] + I[2]*I[2] +
                                         I[3]*I[3] + I[4]*I[4] + I[5]*I[5] +
                                         I[6]*I[6] + I[7]*I[7] + I[8]*I[8]);
                    *(ptrd++) = (Ttfloat)(N?(I[0]*K[0] + I[1]*K[1] + I[2]*K[2] +
                                             I[3]*K[3] + I[4]*K[4] + I[5]*K[5] +
                                             I[6]*K[6] + I[7]*K[7] + I[8]*K[8])/std::sqrt(N):0);
                  }
                } else cimg_forZ(img,z) cimg_for3x3(img,x,y,z,0,I,T)
                         *(ptrd++) = (Ttfloat)(I[0]*K[0] + I[1]*K[1] + I[2]*K[2] +
                                               I[3]*K[3] + I[4]*K[4] + I[5]*K[5] +
                                               I[6]*K[6] + I[7]*K[7] + I[8]*K[8]);
              }
            } break;
            case 2 : {
              cimg_pragma_openmp(parallel for cimg_openmp_if(is_outer_parallel))
                cimg_forC(res,c) {
                cimg_abort_test;
                const CImg<T> img = get_shared_channel(c%_spectrum);
                const CImg<t> K = _kernel.get_shared_channel(c%kernel._spectrum);
                CImg<T> I(4);
                Ttfloat *ptrd = res.data(0,0,0,c);
                if (is_normalized) {
                  const Ttfloat _M = (Ttfloat)K.magnitude(2), M = _M*_M;
                  cimg_forZ(img,z) cimg_for2x2(img,x,y,z,0,I,T) {
                    const Ttfloat N = M*(I[0]*I[0] + I[1]*I[1] +
                                         I[2]*I[2] + I[3]*I[3]);
                    *(ptrd++) = (Ttfloat)(N?(I[0]*K[0] + I[1]*K[1] +
                                             I[2]*K[2] + I[3]*K[3])/std::sqrt(N):0);
                  }
                } else cimg_forZ(img,z) cimg_for2x2(img,x,y,z,0,I,T)
                         *(ptrd++) = (Ttfloat)(I[0]*K[0] + I[1]*K[1] +
                                               I[2]*K[2] + I[3]*K[3]);
              }
            } break;
            case 1 :
              if (is_normalized) res.fill(1);
              else cimg_forC(res,c) {
                  cimg_abort_test;
                  const CImg<T> img = get_shared_channel(c%_spectrum);
                  const CImg<t> K = _kernel.get_shared_channel(c%kernel._spectrum);
                  res.get_shared_channel(c).assign(img)*=K[0];
                }
              break;
            }
          }
        }
      }

      if (!res) { // Generic version for other kernels and boundary conditions.
        res.assign(_width,_height,_depth,std::max(_spectrum,kernel._spectrum));
        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;
        if (is_convolution) cimg::swap(mx1,mx2,my1,my2,mz1,mz2); // Shift kernel center in case of convolution
        const int
          mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2;
        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_normalized) { // Normalized correlation.
            const Ttfloat _M = (Ttfloat)K.magnitude(2), M = _M*_M;
            cimg_pragma_openmp(parallel for 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;
                  Ttfloat val = 0, N = 0;
                  for (int zm = -mz1; zm<=mz2; ++zm)
                    for (int ym = -my1; ym<=my2; ++ym)
                      for (int xm = -mx1; xm<=mx2; ++xm) {
                        const Ttfloat _val = (Ttfloat)img(x + xm,y + ym,z + zm);
                        val+=_val*K(mx1 + xm,my1 + ym,mz1 + zm);
                        N+=_val*_val;
                      }
                  N*=M;
                  res(x,y,z,c) = (Ttfloat)(N?val/std::sqrt(N):0);
                } _cimg_abort_catch_omp2
            if (boundary_conditions)
              cimg_pragma_openmp(parallel for 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))) {
                  Ttfloat val = 0, N = 0;
                  for (int zm = -mz1; zm<=mz2; ++zm)
                    for (int ym = -my1; ym<=my2; ++ym)
                      for (int xm = -mx1; xm<=mx2; ++xm) {
                        const Ttfloat _val = (Ttfloat)img._atXYZ(x + xm,y + ym,z + zm);
                        val+=_val*K(mx1 + xm,my1 + ym,mz1 + zm);
                        N+=_val*_val;
                      }
                  N*=M;
                  res(x,y,z,c) = (Ttfloat)(N?val/std::sqrt(N):0);
                }
              } _cimg_abort_catch_omp2
            else
              cimg_pragma_openmp(parallel for 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))) {
                  Ttfloat val = 0, N = 0;
                  for (int zm = -mz1; zm<=mz2; ++zm)
                    for (int ym = -my1; ym<=my2; ++ym)
                      for (int xm = -mx1; xm<=mx2; ++xm) {
                        const Ttfloat _val = (Ttfloat)img.atXYZ(x + xm,y + ym,z + zm,0,(T)0);
                        val+=_val*K(mx1 + xm,my1 + ym,mz1 + zm);
                        N+=_val*_val;
                      }
                  N*=M;
                  res(x,y,z,c) = (Ttfloat)(N?val/std::sqrt(N):0);
                }
              } _cimg_abort_catch_omp2
          } else { // Classical correlation.
            cimg_pragma_openmp(parallel for 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;
                  Ttfloat val = 0;
                  for (int zm = -mz1; zm<=mz2; ++zm)
                    for (int ym = -my1; ym<=my2; ++ym)
                      for (int xm = -mx1; xm<=mx2; ++xm)
                        val+=img(x + xm,y + ym,z + zm)*K(mx1 + xm,my1 + ym,mz1 + zm);
                  res(x,y,z,c) = (Ttfloat)val;
                } _cimg_abort_catch_omp2
            if (boundary_conditions)
              cimg_pragma_openmp(parallel for 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))) {
                  Ttfloat val = 0;
                  for (int zm = -mz1; zm<=mz2; ++zm)
                    for (int ym = -my1; ym<=my2; ++ym)
                      for (int xm = -mx1; xm<=mx2; ++xm)
                        val+=img._atXYZ(x + xm,y + ym,z + zm)*K(mx1 + xm,my1 + ym,mz1 + zm);
                  res(x,y,z,c) = (Ttfloat)val;
                }
              } _cimg_abort_catch_omp2
            else
              cimg_pragma_openmp(parallel for 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))) {
                  Ttfloat val = 0;
                  for (int zm = -mz1; zm<=mz2; ++zm)
                    for (int ym = -my1; ym<=my2; ++ym)
                      for (int xm = -mx1; xm<=mx2; ++xm)
                        val+=img.atXYZ(x + xm,y + ym,z + zm,0,(T)0)*K(mx1 + xm,my1 + ym,mz1 + zm);
                  res(x,y,z,c) = (Ttfloat)val;
                }
              } _cimg_abort_catch_omp2
          }
        } _cimg_abort_catch_omp
      }
      cimg_abort_test;
      return res;

Project: CImg
File: CImg.h


    inline unsigned int srand(const unsigned int seed) {
      return _rand(seed,true);

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


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

Project: CImg
File: CImg.h

       \param filename Filename to write data to.
       \param fps Number of desired frames per second.
       \param nb_loops Number of loops (\c 0 for infinite looping).
    **/
    const CImgList<T>& save_gif_external(const char *const filename, const float fps=25,
                                         const unsigned int nb_loops=0) {
      CImg<charT> command(1024), filename_tmp(256), filename_tmp2(256);
      CImgList<charT> filenames;
      std::FILE *file = 0;

#ifdef cimg_use_png
#define _cimg_save_gif_ext "png"
#else
#define _cimg_save_gif_ext "ppm"
#endif

      do {
        cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s",
                      cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
        cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_000001." _cimg_save_gif_ext,filename_tmp._data);
        if ((file=std_fopen(filename_tmp2,"rb"))!=0) cimg::fclose(file);
      } while (file);
      cimglist_for(*this,l) {
        cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_%.6u." _cimg_save_gif_ext,filename_tmp._data,l + 1);
        CImg<charT>::string(filename_tmp2).move_to(filenames);
        if (_data[l]._depth>1 || _data[l]._spectrum!=3) _data[l].get_resize(-100,-100,1,3).save(filename_tmp2);
        else _data[l].save(filename_tmp2);
      }
      cimg_snprintf(command,command._width,"%s -delay %u -loop %u",
                    cimg::imagemagick_path(),(unsigned int)std::max(0.0f,cimg::round(100/fps)),nb_loops);
      CImg<ucharT>::string(command).move_to(filenames,0);
      cimg_snprintf(command,command._width,"\"%s\"",
                    CImg<charT>::string(filename)._system_strescape().data());
      CImg<ucharT>::string(command).move_to(filenames);
      CImg<charT> _command = filenames>'x';
      cimg_for(_command,p,char) if (!*p) *p = ' ';
      _command.back() = 0;

      cimg::system(_command);
      file = std_fopen(filename,"rb");
      if (!file)
        throw CImgIOException(_cimglist_instance
                              "save_gif_external(): Failed to save file '%s' with external command 'magick/convert'.",
                              cimglist_instance,
                              filename);

Project: CImg
File: CImg.h


      static double mp_variance(_cimg_math_parser& mp) {
        const unsigned int i_end = (unsigned int)mp.opcode[2];
        CImg<doubleT> vals(i_end - 3);
        double *p = vals.data();
        for (unsigned int i = 3; i<i_end; ++i) *(p++) = _mp_arg(i);
        return vals.variance();

Project: CImg
File: CImg.h

    **/
    T cubic_cut_atXY(const float fx, const float fy, const int z, const int c) const {
      return cimg::type<T>::cut(cubic_atXY(fx,fy,z,c));

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.0f/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

    template<typename tc>
    CImg<T>& draw_circle(const int x0, const int y0, int radius,
                         const tc *const color, const float opacity=1) {
      if (is_empty()) return *this;
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_circle(): Specified color is (null).",
                                    cimg_instance);
      cimg_init_scanline(color,opacity);
      if (radius<0 || x0 - radius>=width() || y0 + radius<0 || y0 - radius>=height()) return *this;
      if (y0>=0 && y0<height()) cimg_draw_scanline(x0 - radius,x0 + radius,y0,color,opacity,1);
      for (int f = 1 - radius, ddFx = 0, ddFy = -(radius<<1), x = 0, y = radius; x<y; ) {
        if (f>=0) {
          const int x1 = x0 - x, x2 = x0 + x, y1 = y0 - y, y2 = y0 + y;
          if (y1>=0 && y1<height()) cimg_draw_scanline(x1,x2,y1,color,opacity,1);
          if (y2>=0 && y2<height()) cimg_draw_scanline(x1,x2,y2,color,opacity,1);
          f+=(ddFy+=2); --y;
        }
        const bool no_diag = y!=(x++);
        ++(f+=(ddFx+=2));
        const int x1 = x0 - y, x2 = x0 + y, y1 = y0 - x, y2 = y0 + x;
        if (no_diag) {
          if (y1>=0 && y1<height()) cimg_draw_scanline(x1,x2,y1,color,opacity,1);
          if (y2>=0 && y2<height()) cimg_draw_scanline(x1,x2,y2,color,opacity,1);
        }
      }
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    **/
    inline unsigned int prand(const double z) {
      if (z<=1.0e-10) return 0;
      if (z>100) return (unsigned int)((std::sqrt(z) * cimg::grand()) + z);
      unsigned int k = 0;
      const double y = std::exp(-z);
      for (double s = 1.0; s>=y; ++k) s*=cimg::rand();
      return k - 1;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


      static double mp_vector_crop(_cimg_math_parser& mp) {
        double *const ptrd = &_mp_arg(1) + 1;
        const double *const ptrs = &_mp_arg(2) + 1;
        const longT
          length = (longT)mp.opcode[3],
          start = (longT)_mp_arg(4),
          sublength = (longT)mp.opcode[5];
        if (start<0 || start + sublength>length)
          throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Value accessor '[]': "
                                      "Out-of-bounds sub-vector request "
                                      "(length: %ld, start: %ld, sub-length: %ld).",
                                      mp.imgin.pixel_type(),length,start,sublength);
        std::memcpy(ptrd,ptrs + start,sublength*sizeof(double));
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

     **/
    CImg<T>& max(const T& val) {
      if (is_empty()) return *this;
      cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=65536))
      cimg_rof(*this,ptrd,T) *ptrd = std::max(*ptrd,val);
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    // Use the system RNG.
    inline unsigned int srand() {
      const unsigned int t = (unsigned int)cimg::time();
#if cimg_OS==1 || defined(__BORLANDC__)
      std::srand(t + (unsigned int)getpid());
#elif cimg_OS==2
      std::srand(t + (unsigned int)_getpid());
#else
      std::srand(t);
#endif
      return t;

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

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

Project: CImg
File: CImg.h

    **/
    CImg<T>& equalize(const unsigned int nb_levels, const T& min_value, const T& max_value) {
      if (!nb_levels || is_empty()) return *this;
      const T
        vmin = min_value<max_value?min_value:max_value,
        vmax = min_value<max_value?max_value:min_value;
      CImg<ulongT> hist = get_histogram(nb_levels,vmin,vmax);
      ulongT cumul = 0;
      cimg_forX(hist,pos) { cumul+=hist[pos]; hist[pos] = cumul; }
      if (!cumul) cumul = 1;
      cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=1048576))
      cimg_rof(*this,ptrd,T) {
        const int pos = (int)((*ptrd-vmin)*(nb_levels - 1.)/(vmax-vmin));
        if (pos>=0 && pos<(int)nb_levels) *ptrd = (T)(vmin + (vmax-vmin)*hist[pos]/cumul);
      }
      return *this;

Project: CImg
File: CImg.h

    return dt;
  }

  // Return a temporary string describing the size of a memory buffer.
  inline const char *strbuffersize(const cimg_ulong size) {
    static CImg<char> res(256);
    cimg::mutex(5);
    if (size<1024LU) cimg_snprintf(res,res._width,"%lu byte%s",(unsigned long)size,size>1?"s":"");
    else if (size<1024*1024LU) { const float nsize = size/1024.0f; cimg_snprintf(res,res._width,"%.1f Kio",nsize); }
    else if (size<1024*1024*1024LU) {
      const float nsize = size/(1024*1024.0f); cimg_snprintf(res,res._width,"%.1f Mio",nsize);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

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.0,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

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

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)),calling_function(0) {
#ifdef cimg_use_openmp
        mem[17] = omp_get_thread_num();
#endif
        opcode.assign();
        opcode._is_shared = true;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


      static double mp_isbool(_cimg_math_parser& mp) {
        const double val = _mp_arg(2);
        return (double)(val==0.0 || val==1.0);