From c0f3e9f6dc8caba1d7c8965adeeaf3f343d70325 Mon Sep 17 00:00:00 2001 From: pgovyadi Date: Wed, 19 Aug 2015 17:01:40 -0500 Subject: [PATCH] UPDATE TO CIMG: version 1.63... minor bug fixes and print statements in cost.h, gl_spider.h --- stim/cuda/cost.h | 35 +---------------------------------- stim/gl/gl_spider.h | 4 ++-- stim/image/CImg.h | 13996 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 3 files changed, 7847 insertions(+), 6188 deletions(-) diff --git a/stim/cuda/cost.h b/stim/cuda/cost.h index b0effa0..64fcf49 100644 --- a/stim/cuda/cost.h +++ b/stim/cuda/cost.h @@ -15,21 +15,6 @@ texture texIn; float *result; cudaArray* srcArray; bool testing = false; -/* -struct SharedMemory -{ - __device__ inline operator float* () - { - extern __shared__ float __smem[]; - return (float *)__smem; - } - - __device__ inline operator const float* () const - { - extern __shared__ float __smem[]; - return (float *)__smem; - } -};*/ inline void checkCUDAerrors(const char *msg) { @@ -95,25 +80,6 @@ void get_diff (float *result) __syncthreads(); } __syncthreads(); -/* for(unsigned int step = 1; step < blockDim.x; step *= 2) - { - __syncthreads(); - if (x_t %(2*step) == 0) - { - shared[x_t][y_t] += shared[x_t + step][y_t]; - } - } - __syncthreads(); - - for(unsigned int step = 1; step < blockDim.y; step *= 2) - { - __syncthreads(); - if(y_t%(2*step) == 0) - { - shared[x_t][y_t] += shared[x_t][y_t + step]; - } - } - __syncthreads(); */ if(x_t == 0 && y_t == 0) result[g_idx] = shared[0][0]; @@ -213,6 +179,7 @@ stim::vec get_cost(cudaGraphicsResource_t src, int DIM_Y) //output[idx] = get_sum(result+(16*8*idx)); cleanUP(src); ret[0] = idx; ret[1] = (int) output[idx]; + std::cout << output[idx] << std::endl; free(output); return ret; } diff --git a/stim/gl/gl_spider.h b/stim/gl/gl_spider.h index 83de509..9187d2e 100644 --- a/stim/gl/gl_spider.h +++ b/stim/gl/gl_spider.h @@ -121,7 +121,7 @@ class gl_spider setMatrix(); glCallList(dList+3); -// int best = getCost(); + // int best = getCost(); } @@ -730,7 +730,7 @@ class gl_spider findOptimalDirection(); findOptimalPosition(); findOptimalScale(); - // branchDetection(); + branchDetection(); Unbind(); return current_cost; } diff --git a/stim/image/CImg.h b/stim/image/CImg.h index 40ff3cf..06cb44e 100644 --- a/stim/image/CImg.h +++ b/stim/image/CImg.h @@ -5,7 +5,7 @@ # # Description : The C++ Template Image Processing Toolkit. # This file is the main component of the CImg Library project. - # ( http://cimg.sourceforge.net ) + # ( http://cimg.eu ) # # Project manager : David Tschumperle. # ( http://tschumperle.users.greyc.fr/ ) @@ -54,7 +54,7 @@ // Set version number of the library. #ifndef cimg_version -#define cimg_version 160 +#define cimg_version 165 /*----------------------------------------------------------- # @@ -75,6 +75,7 @@ #include #include #include +#include #include #include @@ -108,13 +109,28 @@ // Disable silly warnings on some Microsoft VC++ compilers. #ifdef _MSC_VER #pragma warning(push) +#pragma warning(disable:4127) #pragma warning(disable:4311) #pragma warning(disable:4312) +#pragma warning(disable:4512) +#pragma warning(disable:4571) +#pragma warning(disable:4640) +#pragma warning(disable:4706) +#pragma warning(disable:4710) #pragma warning(disable:4800) #pragma warning(disable:4804) +#pragma warning(disable:4820) #pragma warning(disable:4996) #define _CRT_SECURE_NO_DEPRECATE 1 #define _CRT_NONSTDC_NO_DEPRECATE 1 +#define cimg_snprintf cimg::c99_snprintf +#define cimg_vsnprintf cimg::c99_vsnprintf +#endif + +#ifndef cimg_snprintf +#include +#define cimg_snprintf snprintf +#define cimg_vsnprintf vsnprintf #endif // Include OS-specific headers. @@ -123,6 +139,8 @@ #include #include #include +#include +#include #elif cimg_OS==2 #ifndef NOMINMAX #define NOMINMAX @@ -134,13 +152,6 @@ #include #include #include -#define cimg_snprintf _snprintf -#define cimg_vsnprintf _vsnprintf -#endif -#ifndef cimg_snprintf -#include -#define cimg_snprintf snprintf -#define cimg_vsnprintf vsnprintf #endif // Look for C++11 features @@ -311,28 +322,6 @@ extern "C" { #include "minc_1_simple_rw.h" #endif -// Configure FFMPEG support. -// (http://www.ffmpeg.org) -// -// Define 'cimg_use_ffmpeg' to enable FFMPEG lib support. -// -// Avcodec and Avformat libraries from FFMPEG may be used -// to get a native support of various video file formats. -// (see methods 'CImg[List]::load_ffmpeg()'). -#ifdef cimg_use_ffmpeg -#if (defined(_STDINT_H) || defined(_STDINT_H_)) && !defined(UINT64_C) -#warning "__STDC_CONSTANT_MACROS has to be defined before including , this file will probably not compile." -#endif -#ifndef __STDC_CONSTANT_MACROS -#define __STDC_CONSTANT_MACROS // ...or stdint.h wont' define UINT64_C, needed by libavutil -#endif -extern "C" { -#include -#include -#include -} -#endif - // Configure Zlib support. // (http://www.zlib.net) // @@ -346,6 +335,17 @@ extern "C" { } #endif +// Configure libcurl support. +// (http://curl.haxx.se/libcurl/) +// +// Define 'cimg_use_curl' to enable libcurl support. +// +// Libcurl may be used to get a native support of file downloading from the network. +// (see method 'cimg::load_network()'.) +#ifdef cimg_use_curl +#include "curl/curl.h" +#endif + // Configure Magick++ support. // (http://www.imagemagick.org/Magick++) // @@ -715,7 +715,7 @@ extern "C" { #define cimg_forYZC(img,y,z,c) cimg_forC(img,c) cimg_forYZ(img,y,z) #define cimg_forXYZC(img,x,y,z,c) cimg_forC(img,c) cimg_forXYZ(img,x,y,z) -#define cimg_rof1(bound,i) for (int i = (int)(bound)-1; i>=0; --i) +#define cimg_rof1(bound,i) for (int i = (int)(bound) - 1; i>=0; --i) #define cimg_rofX(img,x) cimg_rof1((img)._width,x) #define cimg_rofY(img,y) cimg_rof1((img)._height,y) #define cimg_rofZ(img,z) cimg_rof1((img)._depth,z) @@ -733,7 +733,7 @@ extern "C" { #define cimg_rofXYZC(img,x,y,z,c) cimg_rofC(img,c) cimg_rofXYZ(img,x,y,z) #define cimg_for_in1(bound,i0,i1,i) \ - for (int i = (int)(i0)<0?0:(int)(i0), _max##i = (int)(i1)<(int)(bound)?(int)(i1):(int)(bound)-1; i<=_max##i; ++i) + for (int i = (int)(i0)<0?0:(int)(i0), _max##i = (int)(i1)<(int)(bound)?(int)(i1):(int)(bound) - 1; i<=_max##i; ++i) #define cimg_for_inX(img,x0,x1,x) cimg_for_in1((img)._width,x0,x1,x) #define cimg_for_inY(img,y0,y1,y) cimg_for_in1((img)._height,y0,y1,y) #define cimg_for_inZ(img,z0,z1,z) cimg_for_in1((img)._depth,z0,z1,z) @@ -750,33 +750,33 @@ extern "C" { #define cimg_for_inYZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_inC(img,c0,c1,c) cimg_for_inYZ(img,y0,z0,y1,z1,y,z) #define cimg_for_inXYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \ cimg_for_inC(img,c0,c1,c) cimg_for_inXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) -#define cimg_for_insideX(img,x,n) cimg_for_inX(img,n,(img)._width-1-(n),x) -#define cimg_for_insideY(img,y,n) cimg_for_inY(img,n,(img)._height-1-(n),y) -#define cimg_for_insideZ(img,z,n) cimg_for_inZ(img,n,(img)._depth-1-(n),z) -#define cimg_for_insideC(img,c,n) cimg_for_inC(img,n,(img)._spectrum-1-(n),c) -#define cimg_for_insideXY(img,x,y,n) cimg_for_inXY(img,n,n,(img)._width-1-(n),(img)._height-1-(n),x,y) +#define cimg_for_insideX(img,x,n) cimg_for_inX(img,n,(img)._width - 1 - (n),x) +#define cimg_for_insideY(img,y,n) cimg_for_inY(img,n,(img)._height - 1 - (n),y) +#define cimg_for_insideZ(img,z,n) cimg_for_inZ(img,n,(img)._depth - 1 - (n),z) +#define cimg_for_insideC(img,c,n) cimg_for_inC(img,n,(img)._spectrum - 1 - (n),c) +#define cimg_for_insideXY(img,x,y,n) cimg_for_inXY(img,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),x,y) #define cimg_for_insideXYZ(img,x,y,z,n) \ - cimg_for_inXYZ(img,n,n,n,(img)._width-1-(n),(img)._height-1-(n),(img)._depth-1-(n),x,y,z) + cimg_for_inXYZ(img,n,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),(img)._depth - 1 - (n),x,y,z) #define cimg_for_insideXYZC(img,x,y,z,c,n) \ - cimg_for_inXYZ(img,n,n,n,(img)._width-1-(n),(img)._height-1-(n),(img)._depth-1-(n),x,y,z) + cimg_for_inXYZ(img,n,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),(img)._depth - 1 - (n),x,y,z) #define cimg_for_out1(boundi,i0,i1,i) \ - for (int i = (int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); ++i, i = i==(int)(i0)?(int)(i1)+1:i) + for (int i = (int)(i0)>0?0:(int)(i1) + 1; i<(int)(boundi); ++i, i = i==(int)(i0)?(int)(i1) + 1:i) #define cimg_for_out2(boundi,boundj,i0,j0,i1,j1,i,j) \ for (int j = 0; j<(int)(boundj); ++j) \ - for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \ - ++i, i = _n1j?i:(i==(int)(i0)?(int)(i1)+1:i)) + for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j?0:(int)(i0)>0?0:(int)(i1) + 1; i<(int)(boundi); \ + ++i, i = _n1j?i:(i==(int)(i0)?(int)(i1) + 1:i)) #define cimg_for_out3(boundi,boundj,boundk,i0,j0,k0,i1,j1,k1,i,j,k) \ for (int k = 0; k<(int)(boundk); ++k) \ for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \ - for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \ - ++i, i = _n1j || _n1k?i:(i==(int)(i0)?(int)(i1)+1:i)) + for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k?0:(int)(i0)>0?0:(int)(i1) + 1; i<(int)(boundi); \ + ++i, i = _n1j || _n1k?i:(i==(int)(i0)?(int)(i1) + 1:i)) #define cimg_for_out4(boundi,boundj,boundk,boundl,i0,j0,k0,l0,i1,j1,k1,l1,i,j,k,l) \ for (int l = 0; l<(int)(boundl); ++l) \ for (int _n1l = (int)(l<(int)(l0) || l>(int)(l1)), k = 0; k<(int)(boundk); ++k) \ for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \ - for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k || _n1l?0:(int)(i0)>0?0:(int)(i1)+1; \ - i<(int)(boundi); ++i, i = _n1j || _n1k || _n1l?i:(i==(int)(i0)?(int)(i1)+1:i)) + for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k || _n1l?0:(int)(i0)>0?0:(int)(i1) + 1; \ + i<(int)(boundi); ++i, i = _n1j || _n1k || _n1l?i:(i==(int)(i0)?(int)(i1) + 1:i)) #define cimg_for_outX(img,x0,x1,x) cimg_for_out1((img)._width,x0,x1,x) #define cimg_for_outY(img,y0,y1,y) cimg_for_out1((img)._height,y0,y1,y) #define cimg_for_outZ(img,z0,z1,z) cimg_for_out1((img)._depth,z0,z1,z) @@ -797,25 +797,26 @@ extern "C" { cimg_for_out3((img)._height,(img)._depth,(img)._spectrum,y0,z0,c0,y1,z1,c1,y,z,c) #define cimg_for_outXYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \ cimg_for_out4((img)._width,(img)._height,(img)._depth,(img)._spectrum,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) -#define cimg_for_borderX(img,x,n) cimg_for_outX(img,n,(img)._width-1-(n),x) -#define cimg_for_borderY(img,y,n) cimg_for_outY(img,n,(img)._height-1-(n),y) -#define cimg_for_borderZ(img,z,n) cimg_for_outZ(img,n,(img)._depth-1-(n),z) -#define cimg_for_borderC(img,c,n) cimg_for_outC(img,n,(img)._spectrum-1-(n),c) -#define cimg_for_borderXY(img,x,y,n) cimg_for_outXY(img,n,n,(img)._width-1-(n),(img)._height-1-(n),x,y) +#define cimg_for_borderX(img,x,n) cimg_for_outX(img,n,(img)._width - 1 - (n),x) +#define cimg_for_borderY(img,y,n) cimg_for_outY(img,n,(img)._height - 1 - (n),y) +#define cimg_for_borderZ(img,z,n) cimg_for_outZ(img,n,(img)._depth - 1 - (n),z) +#define cimg_for_borderC(img,c,n) cimg_for_outC(img,n,(img)._spectrum - 1 - (n),c) +#define cimg_for_borderXY(img,x,y,n) cimg_for_outXY(img,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),x,y) #define cimg_for_borderXYZ(img,x,y,z,n) \ - cimg_for_outXYZ(img,n,n,n,(img)._width-1-(n),(img)._height-1-(n),(img)._depth-1-(n),x,y,z) + cimg_for_outXYZ(img,n,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),(img)._depth - 1 - (n),x,y,z) #define cimg_for_borderXYZC(img,x,y,z,c,n) \ - cimg_for_outXYZC(img,n,n,n,n,(img)._width-1-(n),(img)._height-1-(n),(img)._depth-1-(n),(img)._spectrum-1-(n),x,y,z,c) + cimg_for_outXYZC(img,n,n,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n), \ + (img)._depth - 1 - (n),(img)._spectrum - 1 - (n),x,y,z,c) #define cimg_for_spiralXY(img,x,y) \ for (int x = 0, y = 0, _n1##x = 1, _n1##y = (img).width()*(img).height(); _n1##y; \ - --_n1##y, _n1##x+=(_n1##x>>2)-((!(_n1##x&3)?--y:((_n1##x&3)==1?(img)._width-1-++x:\ - ((_n1##x&3)==2?(img)._height-1-++y:--x))))?0:1) + --_n1##y, _n1##x+=(_n1##x>>2) - ((!(_n1##x&3)?--y:((_n1##x&3)==1?(img)._width - 1 - ++x:\ + ((_n1##x&3)==2?(img)._height - 1 - ++y:--x))))?0:1) #define cimg_for_lineXY(x,y,x0,y0,x1,y1) \ for (int x = (int)(x0), y = (int)(y0), _sx = 1, _sy = 1, _steep = 0, \ - _dx=(x1)>(x0)?(int)(x1)-(int)(x0):(_sx=-1,(int)(x0)-(int)(x1)), \ - _dy=(y1)>(y0)?(int)(y1)-(int)(y0):(_sy=-1,(int)(y0)-(int)(y1)), \ + _dx=(x1)>(x0)?(int)(x1) - (int)(x0):(_sx=-1,(int)(x0) - (int)(x1)), \ + _dy=(y1)>(y0)?(int)(y1) - (int)(y0):(_sy=-1,(int)(y0) - (int)(y1)), \ _counter = _dx, \ _err = _dx>_dy?(_dy>>1):((_steep=1),(_counter=_dy),(_dx>>1)); \ _counter>=0; \ @@ -824,7 +825,7 @@ extern "C" { (y+=(_err-=_dy)<0?_err+=_dx,_sy:0,_sx)) #define cimg_for2(bound,i) \ - for (int i = 0, _n1##i = 1>=(bound)?(int)(bound)-1:1; \ + for (int i = 0, _n1##i = 1>=(bound)?(int)(bound) - 1:1; \ _n1##i<(int)(bound) || i==--_n1##i; \ ++i, ++_n1##i) #define cimg_for2X(img,x) cimg_for2((img)._width,x) @@ -844,7 +845,7 @@ extern "C" { #define cimg_for_in2(bound,i0,i1,i) \ for (int i = (int)(i0)<0?0:(int)(i0), \ - _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1; \ + _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1; \ i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \ ++i, ++_n1##i) #define cimg_for_in2X(img,x0,x1,x) cimg_for_in2((img)._width,x0,x1,x) @@ -865,7 +866,7 @@ extern "C" { #define cimg_for3(bound,i) \ for (int i = 0, _p1##i = 0, \ - _n1##i = 1>=(bound)?(int)(bound)-1:1; \ + _n1##i = 1>=(bound)?(int)(bound) - 1:1; \ _n1##i<(int)(bound) || i==--_n1##i; \ _p1##i = i++, ++_n1##i) #define cimg_for3X(img,x) cimg_for3((img)._width,x) @@ -885,8 +886,8 @@ extern "C" { #define cimg_for_in3(bound,i0,i1,i) \ for (int i = (int)(i0)<0?0:(int)(i0), \ - _p1##i = i-1<0?0:i-1, \ - _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1; \ + _p1##i = i - 1<0?0:i - 1, \ + _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1; \ i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \ _p1##i = i++, ++_n1##i) #define cimg_for_in3X(img,x0,x1,x) cimg_for_in3((img)._width,x0,x1,x) @@ -906,8 +907,8 @@ extern "C" { cimg_for_in3C(img,c0,c1,c) cimg_for_in3XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) #define cimg_for4(bound,i) \ - for (int i = 0, _p1##i = 0, _n1##i = 1>=(bound)?(int)(bound)-1:1, \ - _n2##i = 2>=(bound)?(int)(bound)-1:2; \ + for (int i = 0, _p1##i = 0, _n1##i = 1>=(bound)?(int)(bound) - 1:1, \ + _n2##i = 2>=(bound)?(int)(bound) - 1:2; \ _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \ _p1##i = i++, ++_n1##i, ++_n2##i) #define cimg_for4X(img,x) cimg_for4((img)._width,x) @@ -927,9 +928,9 @@ extern "C" { #define cimg_for_in4(bound,i0,i1,i) \ for (int i = (int)(i0)<0?0:(int)(i0), \ - _p1##i = i-1<0?0:i-1, \ - _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \ - _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2; \ + _p1##i = i - 1<0?0:i - 1, \ + _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \ + _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2; \ i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \ _p1##i = i++, ++_n1##i, ++_n2##i) #define cimg_for_in4X(img,x0,x1,x) cimg_for_in4((img)._width,x0,x1,x) @@ -950,8 +951,8 @@ extern "C" { #define cimg_for5(bound,i) \ for (int i = 0, _p2##i = 0, _p1##i = 0, \ - _n1##i = 1>=(bound)?(int)(bound)-1:1, \ - _n2##i = 2>=(bound)?(int)(bound)-1:2; \ + _n1##i = 1>=(bound)?(int)(bound) - 1:1, \ + _n2##i = 2>=(bound)?(int)(bound) - 1:2; \ _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \ _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i) #define cimg_for5X(img,x) cimg_for5((img)._width,x) @@ -971,10 +972,10 @@ extern "C" { #define cimg_for_in5(bound,i0,i1,i) \ for (int i = (int)(i0)<0?0:(int)(i0), \ - _p2##i = i-2<0?0:i-2, \ - _p1##i = i-1<0?0:i-1, \ - _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \ - _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2; \ + _p2##i = i - 2<0?0:i - 2, \ + _p1##i = i - 1<0?0:i - 1, \ + _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \ + _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2; \ i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \ _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i) #define cimg_for_in5X(img,x0,x1,x) cimg_for_in5((img)._width,x0,x1,x) @@ -995,9 +996,9 @@ extern "C" { #define cimg_for6(bound,i) \ for (int i = 0, _p2##i = 0, _p1##i = 0, \ - _n1##i = 1>=(bound)?(int)(bound)-1:1, \ - _n2##i = 2>=(bound)?(int)(bound)-1:2, \ - _n3##i = 3>=(bound)?(int)(bound)-1:3; \ + _n1##i = 1>=(bound)?(int)(bound) - 1:1, \ + _n2##i = 2>=(bound)?(int)(bound) - 1:2, \ + _n3##i = 3>=(bound)?(int)(bound) - 1:3; \ _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \ _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i) #define cimg_for6X(img,x) cimg_for6((img)._width,x) @@ -1017,11 +1018,11 @@ extern "C" { #define cimg_for_in6(bound,i0,i1,i) \ for (int i = (int)(i0)<0?0:(int)(i0), \ - _p2##i = i-2<0?0:i-2, \ - _p1##i = i-1<0?0:i-1, \ - _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \ - _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \ - _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3; \ + _p2##i = i - 2<0?0:i - 2, \ + _p1##i = i - 1<0?0:i - 1, \ + _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \ + _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2, \ + _n3##i = i + 3>=(int)(bound)?(int)(bound) - 1:i + 3; \ i<=(int)(i1) && \ (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \ _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i) @@ -1043,9 +1044,9 @@ extern "C" { #define cimg_for7(bound,i) \ for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \ - _n1##i = 1>=(bound)?(int)(bound)-1:1, \ - _n2##i = 2>=(bound)?(int)(bound)-1:2, \ - _n3##i = 3>=(bound)?(int)(bound)-1:3; \ + _n1##i = 1>=(bound)?(int)(bound) - 1:1, \ + _n2##i = 2>=(bound)?(int)(bound) - 1:2, \ + _n3##i = 3>=(bound)?(int)(bound) - 1:3; \ _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \ _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i) #define cimg_for7X(img,x) cimg_for7((img)._width,x) @@ -1065,12 +1066,12 @@ extern "C" { #define cimg_for_in7(bound,i0,i1,i) \ for (int i = (int)(i0)<0?0:(int)(i0), \ - _p3##i = i-3<0?0:i-3, \ - _p2##i = i-2<0?0:i-2, \ - _p1##i = i-1<0?0:i-1, \ - _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \ - _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \ - _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3; \ + _p3##i = i - 3<0?0:i - 3, \ + _p2##i = i - 2<0?0:i - 2, \ + _p1##i = i - 1<0?0:i - 1, \ + _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \ + _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2, \ + _n3##i = i + 3>=(int)(bound)?(int)(bound) - 1:i + 3; \ i<=(int)(i1) && \ (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \ _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i) @@ -1092,10 +1093,10 @@ extern "C" { #define cimg_for8(bound,i) \ for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \ - _n1##i = 1>=(bound)?(int)(bound)-1:1, \ - _n2##i = 2>=(bound)?(int)(bound)-1:2, \ - _n3##i = 3>=(bound)?(int)(bound)-1:3, \ - _n4##i = 4>=(bound)?(int)(bound)-1:4; \ + _n1##i = 1>=(bound)?(int)(bound) - 1:1, \ + _n2##i = 2>=(bound)?(int)(bound) - 1:2, \ + _n3##i = 3>=(bound)?(int)(bound) - 1:3, \ + _n4##i = 4>=(bound)?(int)(bound) - 1:4; \ _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \ i==(_n4##i = _n3##i = _n2##i = --_n1##i); \ _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i) @@ -1116,13 +1117,13 @@ extern "C" { #define cimg_for_in8(bound,i0,i1,i) \ for (int i = (int)(i0)<0?0:(int)(i0), \ - _p3##i = i-3<0?0:i-3, \ - _p2##i = i-2<0?0:i-2, \ - _p1##i = i-1<0?0:i-1, \ - _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \ - _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \ - _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3, \ - _n4##i = i+4>=(int)(bound)?(int)(bound)-1:i+4; \ + _p3##i = i - 3<0?0:i - 3, \ + _p2##i = i - 2<0?0:i - 2, \ + _p1##i = i - 1<0?0:i - 1, \ + _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \ + _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2, \ + _n3##i = i + 3>=(int)(bound)?(int)(bound) - 1:i + 3, \ + _n4##i = i + 4>=(int)(bound)?(int)(bound) - 1:i + 4; \ i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \ i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \ _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i) @@ -1144,10 +1145,10 @@ extern "C" { #define cimg_for9(bound,i) \ for (int i = 0, _p4##i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \ - _n1##i = 1>=(int)(bound)?(int)(bound)-1:1, \ - _n2##i = 2>=(int)(bound)?(int)(bound)-1:2, \ - _n3##i = 3>=(int)(bound)?(int)(bound)-1:3, \ - _n4##i = 4>=(int)(bound)?(int)(bound)-1:4; \ + _n1##i = 1>=(int)(bound)?(int)(bound) - 1:1, \ + _n2##i = 2>=(int)(bound)?(int)(bound) - 1:2, \ + _n3##i = 3>=(int)(bound)?(int)(bound) - 1:3, \ + _n4##i = 4>=(int)(bound)?(int)(bound) - 1:4; \ _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \ i==(_n4##i = _n3##i = _n2##i = --_n1##i); \ _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i) @@ -1168,14 +1169,14 @@ extern "C" { #define cimg_for_in9(bound,i0,i1,i) \ for (int i = (int)(i0)<0?0:(int)(i0), \ - _p4##i = i-4<0?0:i-4, \ - _p3##i = i-3<0?0:i-3, \ - _p2##i = i-2<0?0:i-2, \ - _p1##i = i-1<0?0:i-1, \ - _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \ - _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \ - _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3, \ - _n4##i = i+4>=(int)(bound)?(int)(bound)-1:i+4; \ + _p4##i = i - 4<0?0:i - 4, \ + _p3##i = i - 3<0?0:i - 3, \ + _p2##i = i - 2<0?0:i - 2, \ + _p1##i = i - 1<0?0:i - 1, \ + _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \ + _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2, \ + _n3##i = i + 3>=(int)(bound)?(int)(bound) - 1:i + 3, \ + _n4##i = i + 4>=(int)(bound)?(int)(bound) - 1:i + 4; \ i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \ i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \ _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i) @@ -1200,7 +1201,7 @@ extern "C" { _n1##x = (int)( \ (I[0] = (T)(img)(0,y,z,c)), \ (I[2] = (T)(img)(0,_n1##y,z,c)), \ - 1>=(img)._width?(img).width()-1:1); \ + 1>=(img)._width?(img).width() - 1:1); \ (_n1##x<(img).width() && ( \ (I[1] = (T)(img)(_n1##x,y,z,c)), \ (I[3] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \ @@ -1214,7 +1215,7 @@ extern "C" { _n1##x = (int)( \ (I[0] = (T)(img)(x,y,z,c)), \ (I[2] = (T)(img)(x,_n1##y,z,c)), \ - x+1>=(int)(img)._width?(img).width()-1:x+1); \ + x + 1>=(int)(img)._width?(img).width() - 1:x + 1); \ x<=(int)(x1) && ((_n1##x<(img).width() && ( \ (I[1] = (T)(img)(_n1##x,y,z,c)), \ (I[3] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \ @@ -1229,8 +1230,8 @@ extern "C" { _n1##x = (int)( \ (I[0] = I[1] = (T)(img)(_p1##x,_p1##y,z,c)), \ (I[3] = I[4] = (T)(img)(0,y,z,c)), \ - (I[6] = I[7] = (T)(img)(0,_n1##y,z,c)), \ - 1>=(img)._width?(img).width()-1:1); \ + (I[6] = I[7] = (T)(img)(0,_n1##y,z,c)), \ + 1>=(img)._width?(img).width() - 1:1); \ (_n1##x<(img).width() && ( \ (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \ (I[5] = (T)(img)(_n1##x,y,z,c)), \ @@ -1243,7 +1244,7 @@ extern "C" { #define cimg_for_in3x3(img,x0,y0,x1,y1,x,y,z,c,I,T) \ cimg_for_in3((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ - _p1##x = x-1<0?0:x-1, \ + _p1##x = x - 1<0?0:x - 1, \ _n1##x = (int)( \ (I[0] = (T)(img)(_p1##x,_p1##y,z,c)), \ (I[3] = (T)(img)(_p1##x,y,z,c)), \ @@ -1251,12 +1252,12 @@ extern "C" { (I[1] = (T)(img)(x,_p1##y,z,c)), \ (I[4] = (T)(img)(x,y,z,c)), \ (I[7] = (T)(img)(x,_n1##y,z,c)), \ - x+1>=(int)(img)._width?(img).width()-1:x+1); \ + x + 1>=(int)(img)._width?(img).width() - 1:x + 1); \ x<=(int)(x1) && ((_n1##x<(img).width() && ( \ (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \ (I[5] = (T)(img)(_n1##x,y,z,c)), \ (I[8] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \ - x==--_n1##x); \ + x==--_n1##x); \ I[0] = I[1], I[1] = I[2], \ I[3] = I[4], I[4] = I[5], \ I[6] = I[7], I[7] = I[8], \ @@ -1265,7 +1266,7 @@ extern "C" { #define cimg_for4x4(img,x,y,z,c,I,T) \ cimg_for4((img)._height,y) for (int x = 0, \ _p1##x = 0, \ - _n1##x = 1>=(img)._width?(img).width()-1:1, \ + _n1##x = 1>=(img)._width?(img).width() - 1:1, \ _n2##x = (int)( \ (I[0] = I[1] = (T)(img)(_p1##x,_p1##y,z,c)), \ (I[4] = I[5] = (T)(img)(0,y,z,c)), \ @@ -1275,7 +1276,7 @@ extern "C" { (I[6] = (T)(img)(_n1##x,y,z,c)), \ (I[10] = (T)(img)(_n1##x,_n1##y,z,c)), \ (I[14] = (T)(img)(_n1##x,_n2##y,z,c)), \ - 2>=(img)._width?(img).width()-1:2); \ + 2>=(img)._width?(img).width() - 1:2); \ (_n2##x<(img).width() && ( \ (I[3] = (T)(img)(_n2##x,_p1##y,z,c)), \ (I[7] = (T)(img)(_n2##x,y,z,c)), \ @@ -1290,8 +1291,8 @@ extern "C" { #define cimg_for_in4x4(img,x0,y0,x1,y1,x,y,z,c,I,T) \ cimg_for_in4((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ - _p1##x = x-1<0?0:x-1, \ - _n1##x = x+1>=(int)(img)._width?(img).width()-1:x+1, \ + _p1##x = x - 1<0?0:x - 1, \ + _n1##x = x + 1>=(int)(img)._width?(img).width() - 1:x + 1, \ _n2##x = (int)( \ (I[0] = (T)(img)(_p1##x,_p1##y,z,c)), \ (I[4] = (T)(img)(_p1##x,y,z,c)), \ @@ -1305,7 +1306,7 @@ extern "C" { (I[6] = (T)(img)(_n1##x,y,z,c)), \ (I[10] = (T)(img)(_n1##x,_n1##y,z,c)), \ (I[14] = (T)(img)(_n1##x,_n2##y,z,c)), \ - x+2>=(int)(img)._width?(img).width()-1:x+2); \ + x + 2>=(int)(img)._width?(img).width() - 1:x + 2); \ x<=(int)(x1) && ((_n2##x<(img).width() && ( \ (I[3] = (T)(img)(_n2##x,_p1##y,z,c)), \ (I[7] = (T)(img)(_n2##x,y,z,c)), \ @@ -1321,7 +1322,7 @@ extern "C" { #define cimg_for5x5(img,x,y,z,c,I,T) \ cimg_for5((img)._height,y) for (int x = 0, \ _p2##x = 0, _p1##x = 0, \ - _n1##x = 1>=(img)._width?(img).width()-1:1, \ + _n1##x = 1>=(img)._width?(img).width() - 1:1, \ _n2##x = (int)( \ (I[0] = I[1] = I[2] = (T)(img)(_p2##x,_p2##y,z,c)), \ (I[5] = I[6] = I[7] = (T)(img)(0,_p1##y,z,c)), \ @@ -1333,7 +1334,7 @@ extern "C" { (I[13] = (T)(img)(_n1##x,y,z,c)), \ (I[18] = (T)(img)(_n1##x,_n1##y,z,c)), \ (I[23] = (T)(img)(_n1##x,_n2##y,z,c)), \ - 2>=(img)._width?(img).width()-1:2); \ + 2>=(img)._width?(img).width() - 1:2); \ (_n2##x<(img).width() && ( \ (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \ (I[9] = (T)(img)(_n2##x,_p1##y,z,c)), \ @@ -1350,9 +1351,9 @@ extern "C" { #define cimg_for_in5x5(img,x0,y0,x1,y1,x,y,z,c,I,T) \ cimg_for_in5((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ - _p2##x = x-2<0?0:x-2, \ - _p1##x = x-1<0?0:x-1, \ - _n1##x = x+1>=(int)(img)._width?(img).width()-1:x+1, \ + _p2##x = x - 2<0?0:x - 2, \ + _p1##x = x - 1<0?0:x - 1, \ + _n1##x = x + 1>=(int)(img)._width?(img).width() - 1:x + 1, \ _n2##x = (int)( \ (I[0] = (T)(img)(_p2##x,_p2##y,z,c)), \ (I[5] = (T)(img)(_p2##x,_p1##y,z,c)), \ @@ -1374,7 +1375,7 @@ extern "C" { (I[13] = (T)(img)(_n1##x,y,z,c)), \ (I[18] = (T)(img)(_n1##x,_n1##y,z,c)), \ (I[23] = (T)(img)(_n1##x,_n2##y,z,c)), \ - x+2>=(int)(img)._width?(img).width()-1:x+2); \ + x + 2>=(int)(img)._width?(img).width() - 1:x + 2); \ x<=(int)(x1) && ((_n2##x<(img).width() && ( \ (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \ (I[9] = (T)(img)(_n2##x,_p1##y,z,c)), \ @@ -1392,8 +1393,8 @@ extern "C" { #define cimg_for6x6(img,x,y,z,c,I,T) \ cimg_for6((img)._height,y) for (int x = 0, \ _p2##x = 0, _p1##x = 0, \ - _n1##x = 1>=(img)._width?(img).width()-1:1, \ - _n2##x = 2>=(img)._width?(img).width()-1:2, \ + _n1##x = 1>=(img)._width?(img).width() - 1:1, \ + _n2##x = 2>=(img)._width?(img).width() - 1:2, \ _n3##x = (int)( \ (I[0] = I[1] = I[2] = (T)(img)(_p2##x,_p2##y,z,c)), \ (I[6] = I[7] = I[8] = (T)(img)(0,_p1##y,z,c)), \ @@ -1413,7 +1414,7 @@ extern "C" { (I[22] = (T)(img)(_n2##x,_n1##y,z,c)), \ (I[28] = (T)(img)(_n2##x,_n2##y,z,c)), \ (I[34] = (T)(img)(_n2##x,_n3##y,z,c)), \ - 3>=(img)._width?(img).width()-1:3); \ + 3>=(img)._width?(img).width() - 1:3); \ (_n3##x<(img).width() && ( \ (I[5] = (T)(img)(_n3##x,_p2##y,z,c)), \ (I[11] = (T)(img)(_n3##x,_p1##y,z,c)), \ @@ -1432,10 +1433,10 @@ extern "C" { #define cimg_for_in6x6(img,x0,y0,x1,y1,x,y,z,c,I,T) \ cimg_for_in6((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)x0, \ - _p2##x = x-2<0?0:x-2, \ - _p1##x = x-1<0?0:x-1, \ - _n1##x = x+1>=(int)(img)._width?(img).width()-1:x+1, \ - _n2##x = x+2>=(int)(img)._width?(img).width()-1:x+2, \ + _p2##x = x - 2<0?0:x - 2, \ + _p1##x = x - 1<0?0:x - 1, \ + _n1##x = x + 1>=(int)(img)._width?(img).width() - 1:x + 1, \ + _n2##x = x + 2>=(int)(img)._width?(img).width() - 1:x + 2, \ _n3##x = (int)( \ (I[0] = (T)(img)(_p2##x,_p2##y,z,c)), \ (I[6] = (T)(img)(_p2##x,_p1##y,z,c)), \ @@ -1467,7 +1468,7 @@ extern "C" { (I[22] = (T)(img)(_n2##x,_n1##y,z,c)), \ (I[28] = (T)(img)(_n2##x,_n2##y,z,c)), \ (I[34] = (T)(img)(_n2##x,_n3##y,z,c)), \ - x+3>=(int)(img)._width?(img).width()-1:x+3); \ + x + 3>=(int)(img)._width?(img).width() - 1:x + 3); \ x<=(int)(x1) && ((_n3##x<(img).width() && ( \ (I[5] = (T)(img)(_n3##x,_p2##y,z,c)), \ (I[11] = (T)(img)(_n3##x,_p1##y,z,c)), \ @@ -1487,8 +1488,8 @@ extern "C" { #define cimg_for7x7(img,x,y,z,c,I,T) \ cimg_for7((img)._height,y) for (int x = 0, \ _p3##x = 0, _p2##x = 0, _p1##x = 0, \ - _n1##x = 1>=(img)._width?(img).width()-1:1, \ - _n2##x = 2>=(img)._width?(img).width()-1:2, \ + _n1##x = 1>=(img)._width?(img).width() - 1:1, \ + _n2##x = 2>=(img)._width?(img).width() - 1:2, \ _n3##x = (int)( \ (I[0] = I[1] = I[2] = I[3] = (T)(img)(_p3##x,_p3##y,z,c)), \ (I[7] = I[8] = I[9] = I[10] = (T)(img)(0,_p2##y,z,c)), \ @@ -1511,7 +1512,7 @@ extern "C" { (I[33] = (T)(img)(_n2##x,_n1##y,z,c)), \ (I[40] = (T)(img)(_n2##x,_n2##y,z,c)), \ (I[47] = (T)(img)(_n2##x,_n3##y,z,c)), \ - 3>=(img)._width?(img).width()-1:3); \ + 3>=(img)._width?(img).width() - 1:3); \ (_n3##x<(img).width() && ( \ (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \ (I[13] = (T)(img)(_n3##x,_p2##y,z,c)), \ @@ -1532,11 +1533,11 @@ extern "C" { #define cimg_for_in7x7(img,x0,y0,x1,y1,x,y,z,c,I,T) \ cimg_for_in7((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ - _p3##x = x-3<0?0:x-3, \ - _p2##x = x-2<0?0:x-2, \ - _p1##x = x-1<0?0:x-1, \ - _n1##x = x+1>=(int)(img)._width?(img).width()-1:x+1, \ - _n2##x = x+2>=(int)(img)._width?(img).width()-1:x+2, \ + _p3##x = x - 3<0?0:x - 3, \ + _p2##x = x - 2<0?0:x - 2, \ + _p1##x = x - 1<0?0:x - 1, \ + _n1##x = x + 1>=(int)(img)._width?(img).width() - 1:x + 1, \ + _n2##x = x + 2>=(int)(img)._width?(img).width() - 1:x + 2, \ _n3##x = (int)( \ (I[0] = (T)(img)(_p3##x,_p3##y,z,c)), \ (I[7] = (T)(img)(_p3##x,_p2##y,z,c)), \ @@ -1580,7 +1581,7 @@ extern "C" { (I[33] = (T)(img)(_n2##x,_n1##y,z,c)), \ (I[40] = (T)(img)(_n2##x,_n2##y,z,c)), \ (I[47] = (T)(img)(_n2##x,_n3##y,z,c)), \ - x+3>=(int)(img)._width?(img).width()-1:x+3); \ + x + 3>=(int)(img)._width?(img).width() - 1:x + 3); \ x<=(int)(x1) && ((_n3##x<(img).width() && ( \ (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \ (I[13] = (T)(img)(_n3##x,_p2##y,z,c)), \ @@ -1602,9 +1603,9 @@ extern "C" { #define cimg_for8x8(img,x,y,z,c,I,T) \ cimg_for8((img)._height,y) for (int x = 0, \ _p3##x = 0, _p2##x = 0, _p1##x = 0, \ - _n1##x = 1>=((img)._width)?(img).width()-1:1, \ - _n2##x = 2>=((img)._width)?(img).width()-1:2, \ - _n3##x = 3>=((img)._width)?(img).width()-1:3, \ + _n1##x = 1>=((img)._width)?(img).width() - 1:1, \ + _n2##x = 2>=((img)._width)?(img).width() - 1:2, \ + _n3##x = 3>=((img)._width)?(img).width() - 1:3, \ _n4##x = (int)( \ (I[0] = I[1] = I[2] = I[3] = (T)(img)(_p3##x,_p3##y,z,c)), \ (I[8] = I[9] = I[10] = I[11] = (T)(img)(0,_p2##y,z,c)), \ @@ -1638,7 +1639,7 @@ extern "C" { (I[46] = (T)(img)(_n3##x,_n2##y,z,c)), \ (I[54] = (T)(img)(_n3##x,_n3##y,z,c)), \ (I[62] = (T)(img)(_n3##x,_n4##y,z,c)), \ - 4>=((img)._width)?(img).width()-1:4); \ + 4>=((img)._width)?(img).width() - 1:4); \ (_n4##x<(img).width() && ( \ (I[7] = (T)(img)(_n4##x,_p3##y,z,c)), \ (I[15] = (T)(img)(_n4##x,_p2##y,z,c)), \ @@ -1661,12 +1662,12 @@ extern "C" { #define cimg_for_in8x8(img,x0,y0,x1,y1,x,y,z,c,I,T) \ cimg_for_in8((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ - _p3##x = x-3<0?0:x-3, \ - _p2##x = x-2<0?0:x-2, \ - _p1##x = x-1<0?0:x-1, \ - _n1##x = x+1>=(img).width()?(img).width()-1:x+1, \ - _n2##x = x+2>=(img).width()?(img).width()-1:x+2, \ - _n3##x = x+3>=(img).width()?(img).width()-1:x+3, \ + _p3##x = x - 3<0?0:x - 3, \ + _p2##x = x - 2<0?0:x - 2, \ + _p1##x = x - 1<0?0:x - 1, \ + _n1##x = x + 1>=(img).width()?(img).width() - 1:x + 1, \ + _n2##x = x + 2>=(img).width()?(img).width() - 1:x + 2, \ + _n3##x = x + 3>=(img).width()?(img).width() - 1:x + 3, \ _n4##x = (int)( \ (I[0] = (T)(img)(_p3##x,_p3##y,z,c)), \ (I[8] = (T)(img)(_p3##x,_p2##y,z,c)), \ @@ -1724,7 +1725,7 @@ extern "C" { (I[46] = (T)(img)(_n3##x,_n2##y,z,c)), \ (I[54] = (T)(img)(_n3##x,_n3##y,z,c)), \ (I[62] = (T)(img)(_n3##x,_n4##y,z,c)), \ - x+4>=(img).width()?(img).width()-1:x+4); \ + x + 4>=(img).width()?(img).width() - 1:x + 4); \ x<=(int)(x1) && ((_n4##x<(img).width() && ( \ (I[7] = (T)(img)(_n4##x,_p3##y,z,c)), \ (I[15] = (T)(img)(_n4##x,_p2##y,z,c)), \ @@ -1748,9 +1749,9 @@ extern "C" { #define cimg_for9x9(img,x,y,z,c,I,T) \ cimg_for9((img)._height,y) for (int x = 0, \ _p4##x = 0, _p3##x = 0, _p2##x = 0, _p1##x = 0, \ - _n1##x = 1>=((img)._width)?(img).width()-1:1, \ - _n2##x = 2>=((img)._width)?(img).width()-1:2, \ - _n3##x = 3>=((img)._width)?(img).width()-1:3, \ + _n1##x = 1>=((img)._width)?(img).width() - 1:1, \ + _n2##x = 2>=((img)._width)?(img).width() - 1:2, \ + _n3##x = 3>=((img)._width)?(img).width() - 1:3, \ _n4##x = (int)( \ (I[0] = I[1] = I[2] = I[3] = I[4] = (T)(img)(_p4##x,_p4##y,z,c)), \ (I[9] = I[10] = I[11] = I[12] = I[13] = (T)(img)(0,_p3##y,z,c)), \ @@ -1788,7 +1789,7 @@ extern "C" { (I[61] = (T)(img)(_n3##x,_n2##y,z,c)), \ (I[70] = (T)(img)(_n3##x,_n3##y,z,c)), \ (I[79] = (T)(img)(_n3##x,_n4##y,z,c)), \ - 4>=((img)._width)?(img).width()-1:4); \ + 4>=((img)._width)?(img).width() - 1:4); \ (_n4##x<(img).width() && ( \ (I[8] = (T)(img)(_n4##x,_p4##y,z,c)), \ (I[17] = (T)(img)(_n4##x,_p3##y,z,c)), \ @@ -1815,13 +1816,13 @@ extern "C" { #define cimg_for_in9x9(img,x0,y0,x1,y1,x,y,z,c,I,T) \ cimg_for_in9((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ - _p4##x = x-4<0?0:x-4, \ - _p3##x = x-3<0?0:x-3, \ - _p2##x = x-2<0?0:x-2, \ - _p1##x = x-1<0?0:x-1, \ - _n1##x = x+1>=(img).width()?(img).width()-1:x+1, \ - _n2##x = x+2>=(img).width()?(img).width()-1:x+2, \ - _n3##x = x+3>=(img).width()?(img).width()-1:x+3, \ + _p4##x = x - 4<0?0:x - 4, \ + _p3##x = x - 3<0?0:x - 3, \ + _p2##x = x - 2<0?0:x - 2, \ + _p1##x = x - 1<0?0:x - 1, \ + _n1##x = x + 1>=(img).width()?(img).width() - 1:x + 1, \ + _n2##x = x + 2>=(img).width()?(img).width() - 1:x + 2, \ + _n3##x = x + 3>=(img).width()?(img).width() - 1:x + 3, \ _n4##x = (int)( \ (I[0] = (T)(img)(_p4##x,_p4##y,z,c)), \ (I[9] = (T)(img)(_p4##x,_p3##y,z,c)), \ @@ -1895,7 +1896,7 @@ extern "C" { (I[61] = (T)(img)(_n3##x,_n2##y,z,c)), \ (I[70] = (T)(img)(_n3##x,_n3##y,z,c)), \ (I[79] = (T)(img)(_n3##x,_n4##y,z,c)), \ - x+4>=(img).width()?(img).width()-1:x+4); \ + x + 4>=(img).width()?(img).width() - 1:x + 4); \ x<=(int)(x1) && ((_n4##x<(img).width() && ( \ (I[8] = (T)(img)(_n4##x,_p4##y,z,c)), \ (I[17] = (T)(img)(_n4##x,_p3##y,z,c)), \ @@ -1927,7 +1928,7 @@ extern "C" { (I[2] = (T)(img)(0,_n1##y,z,c)), \ (I[4] = (T)(img)(0,y,_n1##z,c)), \ (I[6] = (T)(img)(0,_n1##y,_n1##z,c)), \ - 1>=(img)._width?(img).width()-1:1); \ + 1>=(img)._width?(img).width() - 1:1); \ (_n1##x<(img).width() && ( \ (I[1] = (T)(img)(_n1##x,y,z,c)), \ (I[3] = (T)(img)(_n1##x,_n1##y,z,c)), \ @@ -1944,7 +1945,7 @@ extern "C" { (I[2] = (T)(img)(x,_n1##y,z,c)), \ (I[4] = (T)(img)(x,y,_n1##z,c)), \ (I[6] = (T)(img)(x,_n1##y,_n1##z,c)), \ - x+1>=(int)(img)._width?(img).width()-1:x+1); \ + x + 1>=(int)(img)._width?(img).width() - 1:x + 1); \ x<=(int)(x1) && ((_n1##x<(img).width() && ( \ (I[1] = (T)(img)(_n1##x,y,z,c)), \ (I[3] = (T)(img)(_n1##x,_n1##y,z,c)), \ @@ -1967,7 +1968,7 @@ extern "C" { (I[18] = I[19] = (T)(img)(0,_p1##y,_n1##z,c)), \ (I[21] = I[22] = (T)(img)(0,y,_n1##z,c)), \ (I[24] = I[25] = (T)(img)(0,_n1##y,_n1##z,c)), \ - 1>=(img)._width?(img).width()-1:1); \ + 1>=(img)._width?(img).width() - 1:1); \ (_n1##x<(img).width() && ( \ (I[2] = (T)(img)(_n1##x,_p1##y,_p1##z,c)), \ (I[5] = (T)(img)(_n1##x,y,_p1##z,c)), \ @@ -1986,7 +1987,7 @@ extern "C" { #define cimg_for_in3x3x3(img,x0,y0,z0,x1,y1,z1,x,y,z,c,I,T) \ cimg_for_in3((img)._depth,z0,z1,z) cimg_for_in3((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ - _p1##x = x-1<0?0:x-1, \ + _p1##x = x - 1<0?0:x - 1, \ _n1##x = (int)( \ (I[0] = (T)(img)(_p1##x,_p1##y,_p1##z,c)), \ (I[3] = (T)(img)(_p1##x,y,_p1##z,c)), \ @@ -2006,7 +2007,7 @@ extern "C" { (I[19] = (T)(img)(x,_p1##y,_n1##z,c)), \ (I[22] = (T)(img)(x,y,_n1##z,c)), \ (I[25] = (T)(img)(x,_n1##y,_n1##z,c)), \ - x+1>=(int)(img)._width?(img).width()-1:x+1); \ + x + 1>=(int)(img)._width?(img).width() - 1:x + 1); \ x<=(int)(x1) && ((_n1##x<(img).width() && ( \ (I[2] = (T)(img)(_n1##x,_p1##y,_p1##z,c)), \ (I[5] = (T)(img)(_n1##x,y,_p1##z,c)), \ @@ -2025,7 +2026,7 @@ extern "C" { #define cimglist_for(list,l) for (int l = 0; l<(int)(list)._width; ++l) #define cimglist_for_in(list,l0,l1,l) \ - for (int l = (int)(l0)<0?0:(int)(l0), _max##l = (unsigned int)l1<(list)._width?(int)(l1):(int)(list)._width-1; \ + for (int l = (int)(l0)<0?0:(int)(l0), _max##l = (unsigned int)l1<(list)._width?(int)(l1):(int)(list)._width - 1; \ l<=_max##l; ++l) #define cimglist_apply(list,fn) cimglist_for(list,__##fn) (list)[__##fn].fn @@ -2108,7 +2109,7 @@ namespace cimg_library_suffixed { // [internal] Lock/unlock a mutex for managing concurrent threads. // 'lock_mode' can be { 0=unlock | 1=lock | 2=trylock }. - // 'n' can be in [0,31] but mutex range [0,16] is reserved by CImg. + // 'n' can be in [0,31] but mutex range [0,15] is reserved by CImg. inline int mutex(const unsigned int n, const int lock_mode=1); inline unsigned int& _exception_mode(const unsigned int value, const bool is_set) { @@ -2119,6 +2120,27 @@ namespace cimg_library_suffixed { return mode; } + // Mandatory because Microsoft's _snprintf() and _vsnprintf() do not add the '\0' character + // at the end of the string. +#if cimg_OS==2 && defined(_MSC_VER) + inline int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap) { + int count = -1; + cimg::mutex(6); + if (size) count = _vsnprintf_s(str,size,_TRUNCATE,format,ap); + if (count==-1) count = _vscprintf(format,ap); + cimg::mutex(6,0); + return count; + } + inline int c99_snprintf(char* str, size_t size, const char* format, ...) { + int count; + va_list ap; + va_start(ap, format); + count = c99_vsnprintf(str,size,format,ap); + va_end(ap); + return count; + } +#endif + //! Set current \CImg exception mode. /** The way error messages are handled by \CImg can be changed dynamically, using this function. @@ -2141,11 +2163,13 @@ namespace cimg_library_suffixed { return _exception_mode(0,false); } + // Display a simple dialog box, and wait for the user's response. inline int dialog(const char *const title, const char *const msg, const char *const button1_label="OK", const char *const button2_label=0, const char *const button3_label=0, const char *const button4_label=0, const char *const button5_label=0, const char *const button6_label=0, const bool centering=false); + // Evaluate math expression. inline double eval(const char *const expression, const double x=0, const double y=0, const double z=0, const double c=0); } @@ -2219,7 +2243,7 @@ namespace cimg_library_suffixed { **/ struct CImgException : public std::exception { #define _cimg_exception_err(etype,disp_flag) \ - std::va_list ap; va_start(ap,format); cimg_vsnprintf(_message,sizeof(_message),format,ap); va_end(ap); \ + std::va_list ap; va_start(ap,format); cimg_vsnprintf(_message,16384,format,ap); va_end(ap); \ if (cimg::exception_mode()) { \ std::fprintf(cimg::output(),"\n%s[CImg] *** %s ***%s %s\n",cimg::t_red,etype,cimg::t_normal,_message); \ if (cimg_display && disp_flag && !(cimg::exception_mode()%2)) try { cimg::dialog(etype,_message,"Abort"); } \ @@ -2227,9 +2251,12 @@ namespace cimg_library_suffixed { if (cimg::exception_mode()>=3) cimg_library_suffixed::cimg::info(); \ } - char _message[16384]; - CImgException() { *_message = 0; } - CImgException(const char *const format, ...) { _cimg_exception_err("CImgException",true); } + char *_message; + CImgException() { _message = new char[16384]; *_message = 0; } + CImgException(const char *const format, ...) { + _message = new char[16384]; *_message = 0; _cimg_exception_err("CImgException",true); + } + ~CImgException() throw() { delete[] _message; } //! Return a C-string containing the error message associated to the thrown exception. const char *what() const throw() { return _message; } }; @@ -2293,12 +2320,12 @@ namespace cimg_library_suffixed { static bool is_float() { return false; } static bool is_inf(const T) { return false; } static bool is_nan(const T) { return false; } - static T min() { return (T)-1>0?(T)0:(T)-1<<(8*sizeof(T)-1); } - static T max() { return (T)-1>0?(T)-1:~((T)-1<<(8*sizeof(T)-1)); } + static T min() { return ~max(); } + static T max() { return (T)(1UL<<(8*sizeof(T) - 1)); } static T inf() { return max(); } static T cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(T)val; } static const char* format() { return "%s"; } - static const char* format(const T val) { static const char *const s = "unknown"; cimg::unused(val); return s; } + static const char* format(const T& val) { static const char *const s = "unknown"; cimg::unused(val); return s; } }; template<> struct type { @@ -2321,7 +2348,7 @@ namespace cimg_library_suffixed { static bool is_inf(const unsigned char) { return false; } static bool is_nan(const unsigned char) { return false; } static unsigned char min() { return 0; } - static unsigned char max() { return (unsigned char)~0U; } + static unsigned char max() { return (unsigned char)-1; } static unsigned char inf() { return max(); } static unsigned char cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(unsigned char)val; } @@ -2329,31 +2356,47 @@ namespace cimg_library_suffixed { static unsigned int format(const unsigned char val) { return (unsigned int)val; } }; +#if defined(CHAR_MAX) && CHAR_MAX==255 + template<> struct type { + static const char* string() { static const char *const s = "char"; return s; } + static bool is_float() { return false; } + static bool is_inf(const char) { return false; } + static bool is_nan(const char) { return false; } + static char min() { return 0; } + static char max() { return (char)-1; } + static char inf() { return max(); } + static char cut(const double val) { + return val<(double)min()?min():val>(double)max()?max():(unsigned char)val; } + static const char* format() { return "%u"; } + static unsigned int format(const char val) { return (unsigned int)val; } + }; +#else template<> struct type { static const char* string() { static const char *const s = "char"; return s; } static bool is_float() { return false; } static bool is_inf(const char) { return false; } static bool is_nan(const char) { return false; } - static char min() { return (char)(-1L<<(8*sizeof(char)-1)); } - static char max() { return (char)~((char)(-1L<<(8*sizeof(char)-1))); } + static char min() { return ~max(); } + static char max() { return (char)((unsigned char)-1>>1); } static char inf() { return max(); } static char cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(char)val; } static const char* format() { return "%d"; } static int format(const char val) { return (int)val; } }; +#endif template<> struct type { static const char* string() { static const char *const s = "signed char"; return s; } static bool is_float() { return false; } static bool is_inf(const signed char) { return false; } static bool is_nan(const signed char) { return false; } - static signed char min() { return (signed char)(-1L<<(8*sizeof(signed char)-1)); } - static signed char max() { return ~((signed char)(-1L<<(8*sizeof(signed char)-1))); } + static signed char min() { return ~max(); } + static signed char max() { return (signed char)((unsigned char)-1>>1); } static signed char inf() { return max(); } static signed char cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(signed char)val; } static const char* format() { return "%d"; } - static unsigned int format(const signed char val) { return (int)val; } + static int format(const signed char val) { return (int)val; } }; template<> struct type { @@ -2362,7 +2405,7 @@ namespace cimg_library_suffixed { static bool is_inf(const unsigned short) { return false; } static bool is_nan(const unsigned short) { return false; } static unsigned short min() { return 0; } - static unsigned short max() { return (unsigned short)~0U; } + static unsigned short max() { return (unsigned short)-1; } static unsigned short inf() { return max(); } static unsigned short cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(unsigned short)val; } @@ -2375,8 +2418,8 @@ namespace cimg_library_suffixed { static bool is_float() { return false; } static bool is_inf(const short) { return false; } static bool is_nan(const short) { return false; } - static short min() { return (short)(-1L<<(8*sizeof(short)-1)); } - static short max() { return ~((short)(-1L<<(8*sizeof(short)-1))); } + static short min() { return ~max(); } + static short max() { return (short)((unsigned short)-1>>1); } static short inf() { return max(); } static short cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(short)val; } static const char* format() { return "%d"; } @@ -2389,7 +2432,7 @@ namespace cimg_library_suffixed { static bool is_inf(const unsigned int) { return false; } static bool is_nan(const unsigned int) { return false; } static unsigned int min() { return 0; } - static unsigned int max() { return (unsigned int)~0U; } + static unsigned int max() { return (unsigned int)-1; } static unsigned int inf() { return max(); } static unsigned int cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(unsigned int)val; } @@ -2402,8 +2445,8 @@ namespace cimg_library_suffixed { static bool is_float() { return false; } static bool is_inf(const int) { return false; } static bool is_nan(const int) { return false; } - static int min() { return (int)(-1L<<(8*sizeof(int)-1)); } - static int max() { return ~((int)(-1L<<(8*sizeof(int)-1))); } + static int min() { return ~max(); } + static int max() { return (int)((unsigned int)-1>>1); } static int inf() { return max(); } static int cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(int)val; } static const char* format() { return "%d"; } @@ -2416,7 +2459,7 @@ namespace cimg_library_suffixed { static bool is_inf(const unsigned long) { return false; } static bool is_nan(const unsigned long) { return false; } static unsigned long min() { return 0; } - static unsigned long max() { return (unsigned long)~0UL; } + static unsigned long max() { return (unsigned long)-1; } static unsigned long inf() { return max(); } static unsigned long cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(unsigned long)val; } @@ -2429,8 +2472,8 @@ namespace cimg_library_suffixed { static bool is_float() { return false; } static bool is_inf(const long) { return false; } static bool is_nan(const long) { return false; } - static long min() { return (long)(-1L<<(8*sizeof(long)-1)); } - static long max() { return ~((long)(-1L<<(8*sizeof(long)-1))); } + static long min() { return ~max(); } + static long max() { return (long)((unsigned long)-1>>1); } static long inf() { return max(); } static long cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(long)val; } static const char* format() { return "%ld"; } @@ -2457,7 +2500,7 @@ namespace cimg_library_suffixed { static double min() { return -1.7E308; } static double max() { return 1.7E308; } static double inf() { return max()*max(); } - static double nan() { static const double val_nan = -std::sqrt(-1.0); return val_nan; } + static double nan() { const double val_nan = -std::sqrt(-1.0); return val_nan; } static double cut(const double val) { return valmax()?max():val; } static const char* format() { return "%.16g"; } static double format(const double val) { return val; } @@ -2589,16 +2632,16 @@ namespace cimg_library_suffixed { // Define variables used internally by CImg. #if cimg_display==1 struct X11_info { - volatile unsigned int nb_wins; - pthread_t* events_thread; - pthread_cond_t wait_event; - pthread_mutex_t wait_event_mutex; - CImgDisplay* wins[1024]; - Display* display; - unsigned int nb_bits; - bool is_blue_first; - bool is_shm_enabled; - bool byte_order; + unsigned int nb_wins; + pthread_t *events_thread; + pthread_cond_t wait_event; + pthread_mutex_t wait_event_mutex; + CImgDisplay **wins; + Display *display; + unsigned int nb_bits; + bool is_blue_first; + bool is_shm_enabled; + bool byte_order; #ifdef cimg_use_xrandr XRRScreenSize *resolutions; Rotation curr_rotation; @@ -2607,7 +2650,10 @@ namespace cimg_library_suffixed { #endif X11_info():nb_wins(0),events_thread(0),display(0), nb_bits(0),is_blue_first(false),is_shm_enabled(false),byte_order(false) { +#ifdef __FreeBSD__ XInitThreads(); +#endif + wins = new CImgDisplay*[1024]; pthread_mutex_init(&wait_event_mutex,0); pthread_cond_init(&wait_event,0); #ifdef cimg_use_xrandr @@ -2618,14 +2664,17 @@ namespace cimg_library_suffixed { } ~X11_info() { - if (events_thread) { + delete[] wins; + /* + if (events_thread) { pthread_cancel(*events_thread); delete events_thread; - } - if (display) {} // XCloseDisplay(display); - pthread_cond_destroy(&wait_event); - pthread_mutex_unlock(&wait_event_mutex); - pthread_mutex_destroy(&wait_event_mutex); + } + if (display) { } // XCloseDisplay(display); } + pthread_cond_destroy(&wait_event); + pthread_mutex_unlock(&wait_event_mutex); + pthread_mutex_destroy(&wait_event_mutex); + */ } }; #if defined(cimg_module) @@ -2635,6 +2684,8 @@ namespace cimg_library_suffixed { #else inline X11_info& X11_attr() { static X11_info val; return val; } #endif +#define cimg_lock_display() cimg::mutex(15) +#define cimg_unlock_display() cimg::mutex(15,0) #elif cimg_display==2 struct Win32_info { @@ -3820,16 +3871,33 @@ namespace cimg_library_suffixed { 123,123,0,6,255,255,0,1,0,0,0,2,123,123,123,18,200,200,200,1,123,123,0,7,255,255,0,1,189,189,189,3,0,0,0,1,189, 189,189,6,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,17,200,200,200,1,123,123,0,8,255,255,0,3,0,0,0,8,255,255, 0,1,0,0,0,2,123,123,123,16,200,200,200,1,123,123,0,9,255,255,0,1,123,123,0,1,0,0,0,1,123,123,0,8,255,255,0,1,189, - 189,189,1,0,0,0,2,123,123,123,15,200,200,200,1,123,123,0,9,255,255,0,1,189,189,189,1,0,0,0,1,189,189,189,9,255,255, - 0,1,0,0,0,2,123,123,123,14,200,200,200,1,123,123,0,11,255,255,0,1,0,0,0,10,255,255,0,1,189,189,189,1,0,0,0,2,123, - 123,123,13,200,200,200,1,123,123,0,23,255,255,0,1,0,0,0,2,123,123,123,12,200,200,200,1,123,123,0,11,255,255,0,1,189, - 189,189,2,0,0,0,1,189,189,189,9,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,11,200,200,200,1,123,123,0,11,255,255, - 0,4,0,0,0,10,255,255,0,1,0,0,0,2,123,123,123,10,200,200,200,1,123,123,0,12,255,255,0,4,0,0,0,10,255,255,0,1,189,189, - 189,1,0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,12,255,255,0,1,189,189,189,2,0,0,0,1,189,189,189,11,255,255,0,1, - 0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,27,255,255,0,1,0,0,0,3,123,123,123,8,200,200,200,1,123,123,0,26,255, - 255,0,1,189,189,189,1,0,0,0,3,123,123,123,9,200,200,200,1,123,123,0,24,255,255,0,1,189,189,189,1,0,0,0,4,123,123, - 123,10,200,200,200,1,123,123,0,24,0,0,0,5,123,123,123,12,200,200,200,27,123,123,123,14,200,200,200,25,123,123,123,86, - 200,200,200,91,49,124,118,124,71,32,124,95,49,56,114,52,82,121,0}; + 189,189,1,0,0,0,2,123,123,123,15,200,200,200,1,123,123,0,9,255,255,0,1,189,189,189,1,0,0,0,1,189,189,189,9,255, + 255,0,1,0,0,0,2,123,123,123,14,200,200,200,1,123,123,0,11,255,255,0,1,0,0,0,10,255,255,0,1,189,189,189,1,0,0,0,2, + 123,123,123,13,200,200,200,1,123,123,0,23,255,255,0,1,0,0,0,2,123,123,123,12,200,200,200,1,123,123,0,11,255,255,0, + 1,189,189,189,2,0,0,0,1,189,189,189,9,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,11,200,200,200,1,123,123,0,11, + 255,255,0,4,0,0,0,10,255,255,0,1,0,0,0,2,123,123,123,10,200,200,200,1,123,123,0,12,255,255,0,4,0,0,0,10,255,255,0, + 1,189,189,189,1,0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,12,255,255,0,1,189,189,189,2,0,0,0,1,189,189,189,11, + 255,255,0,1,0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,27,255,255,0,1,0,0,0,3,123,123,123,8,200,200,200,1,123, + 123,0,26,255,255,0,1,189,189,189,1,0,0,0,3,123,123,123,9,200,200,200,1,123,123,0,24,255,255,0,1,189,189,189,1,0,0, + 0,4,123,123,123,10,200,200,200,1,123,123,0,24,0,0,0,5,123,123,123,12,200,200,200,27,123,123,123,14,200,200,200,25, + 123,123,123,86,200,200,200,91,49,124,118,124,71,32,124,95,49,56,114,52,82,121,0 }; + + // Mutex-protected version of sscanf. + // Used only MacOSX, as it seems std::sscanf() is not re-entrant on MacOSX. +#if (__MACOSX__) || defined(__APPLE__) +#define cimg_sscanf cimg::_sscanf + inline int _sscanf(const char *s, const char *format, ...) { + cimg::mutex(13); + va_list args; + va_start(args, format); + const int result = std::vsscanf(s,format,args); + va_end(args); + cimg::mutex(13,0); + return result; + } +#else +#define cimg_sscanf std::sscanf +#endif //! Get/set default output stream for the \CImg library messages. /** @@ -3883,16 +3951,17 @@ namespace cimg_library_suffixed { **/ inline void warn(const char *const format, ...) { if (cimg::exception_mode()>=1) { - char message[16384] = { 0 }; + char *const message = new char[16384]; std::va_list ap; va_start(ap,format); - cimg_vsnprintf(message,sizeof(message),format,ap); + cimg_vsnprintf(message,16384,format,ap); va_end(ap); #ifdef cimg_strict_warnings throw CImgWarningException(message); #else std::fprintf(cimg::output(),"\n%s[CImg] *** Warning ***%s%s",cimg::t_red,cimg::t_normal,message); #endif + delete[] message; } } @@ -3913,9 +3982,9 @@ namespace cimg_library_suffixed { #if cimg_OS==1 const unsigned int l = std::strlen(command); if (l) { - char *const ncommand = new char[l+16]; + char *const ncommand = new char[l + 16]; std::strncpy(ncommand,command,l); - std::strcpy(ncommand+l," 2> /dev/null"); // Make command silent. + std::strcpy(ncommand + l," 2> /dev/null"); // Make command silent. const int out_val = std::system(ncommand); delete[] ncommand; return out_val; @@ -4013,17 +4082,17 @@ namespace cimg_library_suffixed { inline void invert_endianness(T* const buffer, const unsigned long size) { if (size) switch (sizeof(T)) { case 1 : break; - case 2 : { for (unsigned short *ptr = (unsigned short*)buffer+size; ptr>(unsigned short*)buffer; ) { + case 2 : { for (unsigned short *ptr = (unsigned short*)buffer + size; ptr>(unsigned short*)buffer; ) { const unsigned short val = *(--ptr); *ptr = (unsigned short)((val>>8)|((val<<8))); } } break; - case 4 : { for (unsigned int *ptr = (unsigned int*)buffer+size; ptr>(unsigned int*)buffer; ) { + case 4 : { for (unsigned int *ptr = (unsigned int*)buffer + size; ptr>(unsigned int*)buffer; ) { const unsigned int val = *(--ptr); *ptr = (val>>24)|((val>>8)&0xff00)|((val<<8)&0xff0000)|(val<<24); } } break; - default : { for (T* ptr = buffer+size; ptr>buffer; ) { + default : { for (T* ptr = buffer + size; ptr>buffer; ) { unsigned char *pb = (unsigned char*)(--ptr), *pe = pb + sizeof(T); for (int i = 0; i<(int)sizeof(T)/2; ++i) swap(*(pb++),*(--pe)); } @@ -4073,7 +4142,7 @@ namespace cimg_library_suffixed { return (unsigned long)(st_time.tv_usec/1000 + st_time.tv_sec*1000); #elif cimg_OS==2 SYSTEMTIME st_time; - GetSystemTime(&st_time); + GetLocalTime(&st_time); return (unsigned long)(st_time.wMilliseconds + 1000*(st_time.wSecond + 60*(st_time.wMinute + 60*st_time.wHour))); #else return 0; @@ -4119,7 +4188,7 @@ namespace cimg_library_suffixed { inline unsigned int _wait(const unsigned int milliseconds, unsigned long& timer) { if (!timer) timer = cimg::time(); const unsigned long current_time = cimg::time(); - if (current_time>=timer+milliseconds) { timer = current_time; return 0; } + if (current_time>=timer + milliseconds) { timer = current_time; return 0; } const unsigned long time_diff = timer + milliseconds - current_time; timer = current_time + time_diff; cimg::sleep(time_diff); @@ -4162,9 +4231,9 @@ namespace cimg_library_suffixed { inline void srand() { const unsigned int t = (unsigned int)cimg::time(); #if cimg_OS==1 - cimg::_rand(t+(unsigned int)getpid(),true); + cimg::_rand(t + (unsigned int)getpid(),true); #elif cimg_OS==2 - cimg::_rand(t+(unsigned int)_getpid(),true); + cimg::_rand(t + (unsigned int)_getpid(),true); #else cimg::_rand(t,true); #endif @@ -4184,9 +4253,9 @@ namespace cimg_library_suffixed { inline void srand() { const unsigned int t = (unsigned int)cimg::time(); #if cimg_OS==1 - std::srand(t+(unsigned int)getpid()); + std::srand(t + (unsigned int)getpid()); #elif cimg_OS==2 - std::srand(t+(unsigned int)_getpid()); + std::srand(t + (unsigned int)_getpid()); #else std::srand(t); #endif @@ -4208,7 +4277,7 @@ namespace cimg_library_suffixed { /** **/ inline double crand() { - return 1-2*cimg::rand(); + return 1 - 2*cimg::rand(); } //! Return a random variable following a gaussian distribution and a standard deviation of 1. @@ -4218,7 +4287,7 @@ namespace cimg_library_suffixed { double x1, w; do { const double x2 = 2*cimg::rand() - 1.0; - x1 = 2*cimg::rand()-1.0; + x1 = 2*cimg::rand() - 1.0; w = x1*x1 + x2*x2; } while (w<=0 || w>=1.0); return x1*std::sqrt((-2*std::log(w))/w); @@ -4233,13 +4302,13 @@ namespace cimg_library_suffixed { unsigned int k = 0; const double y = std::exp(-z); for (double s = 1.0; s>=y; ++k) s*=cimg::rand(); - return k-1; + return k - 1; } //! Bitwise-rotate value on the left. template - inline T rol(const T a, const unsigned int n=1) { - return n?(T)((a<>((sizeof(T)<<3)-n))):a; + inline T rol(const T& a, const unsigned int n=1) { + return n?(T)((a<>((sizeof(T)<<3) - n))):a; } inline float rol(const float a, const unsigned int n=1) { @@ -4252,8 +4321,8 @@ namespace cimg_library_suffixed { //! Bitwise-rotate value on the right. template - inline T ror(const T a, const unsigned int n=1) { - return n?(T)((a>>n)|(a<<((sizeof(T)<<3)-n))):a; + inline T ror(const T& a, const unsigned int n=1) { + return n?(T)((a>>n)|(a<<((sizeof(T)<<3) - n))):a; } inline float ror(const float a, const unsigned int n=1) { @@ -4266,7 +4335,7 @@ namespace cimg_library_suffixed { //! Return absolute value of a value. template - inline T abs(const T a) { + inline T abs(const T& a) { return a>=0?a:-a; } inline bool abs(const bool a) { @@ -4296,13 +4365,13 @@ namespace cimg_library_suffixed { //! Return square of a value. template - inline T sqr(const T val) { + inline T sqr(const T& val) { return val*val; } //! Return 1 + log_10(x) of a value \c x. inline int xln(const int x) { - return x>0?(int)(1+std::log10((double)x)):1; + return x>0?(int)(1 + std::log10((double)x)):1; } //! Return the minimum between two values. @@ -4349,13 +4418,13 @@ namespace cimg_library_suffixed { //! Return the sign of a value. template - inline T sign(const T x) { + inline T sign(const T& x) { return (x<0)?(T)(-1):(x==0?(T)0:(T)1); } //! Return the nearest power of 2 higher than given value. template - inline unsigned long nearest_pow2(const T x) { + inline unsigned long nearest_pow2(const T& x) { unsigned long i = 1; while (x>i) i<<=1; return i; @@ -4381,16 +4450,20 @@ namespace cimg_library_suffixed { return m?(x?1:0):0; } inline int mod(const char x, const char m) { - return x>=0?x%m:(x%m?m+x%m:0); +#if defined(CHAR_MAX) && CHAR_MAX==255 + return x%m; +#else + return x>=0?x%m:(x%m?m + x%m:0); +#endif } inline int mod(const short x, const short m) { - return x>=0?x%m:(x%m?m+x%m:0); + return x>=0?x%m:(x%m?m + x%m:0); } inline int mod(const int x, const int m) { - return x>=0?x%m:(x%m?m+x%m:0); + return x>=0?x%m:(x%m?m + x%m:0); } inline int mod(const long x, const long m) { - return x>=0?x%m:(x%m?m+x%m:0); + return x>=0?x%m:(x%m?m + x%m:0); } inline int mod(const unsigned char x, const unsigned char m) { return x%m; @@ -4399,10 +4472,10 @@ namespace cimg_library_suffixed { return x%m; } inline int mod(const unsigned int x, const unsigned int m) { - return x%m; + return (int)(x%m); } inline int mod(const unsigned long x, const unsigned long m) { - return x%m; + return (long)(x%m); } //! Return the min-mod of two values. @@ -4412,13 +4485,13 @@ namespace cimg_library_suffixed { - minmod(\p a,\p b) = 0, if \p a and \p b have different signs. **/ template - inline T minmod(const T a, const T b) { + inline T minmod(const T& a, const T& b) { return a*b<=0?0:(a>0?(a - inline T round(const T x, const double y=1, const int rounding_type=0) { + inline T round(const T& x, const double y=1, const int rounding_type=0) { if (y<=0) return x; const double sx = (double)x/y, floor = std::floor(sx), delta = sx - floor; return (T)(y*(rounding_type<0?floor:rounding_type>0?std::ceil(sx):delta<0.5?floor:std::ceil(sx))); @@ -4438,8 +4511,8 @@ namespace cimg_library_suffixed { inline double _pythagore(double a, double b) { const double absa = cimg::abs(a), absb = cimg::abs(b); - if (absa>absb) { const double tmp = absb/absa; return absa*std::sqrt(1.0+tmp*tmp); } - else { const double tmp = absa/absb; return absb==0?0:absb*std::sqrt(1.0+tmp*tmp); } + if (absa>absb) { const double tmp = absb/absa; return absa*std::sqrt(1.0 + tmp*tmp); } + else { const double tmp = absa/absb; return absb==0?0:absb*std::sqrt(1.0 + tmp*tmp); } } inline bool _is_self_expr(const char *expression) { @@ -4451,7 +4524,7 @@ namespace cimg_library_suffixed { //! Convert ascii character to lower case. inline char uncase(const char x) { - return (char)((x<'A'||x>'Z')?x:x-'A'+'a'); + return (char)((x<'A'||x>'Z')?x:x - 'A' + 'a'); } //! Convert C-string to lower case. @@ -4468,7 +4541,7 @@ namespace cimg_library_suffixed { **/ inline double atof(const char *const str) { double x = 0, y = 1; - if (!str) return 0; else { std::sscanf(str,"%lf/%lf",&x,&y); return x/y; } + return str && cimg_sscanf(str,"%lf/%lf",&x,&y)>0?x/y:0; } //! Compare the first \p l characters of two C-strings, ignoring the case. @@ -4483,7 +4556,7 @@ namespace cimg_library_suffixed { if (!l) return 0; if (!str1) return str2?-1:0; const char *nstr1 = str1, *nstr2 = str2; - int k, diff = 0; for (k = 0; kp && str[q]==delimiter; ) { --q; if (!is_iterative) break; } + for (q = l - 1; q>p && str[q]==delimiter; ) { --q; if (!is_iterative) break; } } const int n = q - p + 1; - if (n!=l) { std::memmove(str,str+p,n); str[n] = 0; return true; } + if (n!=l) { std::memmove(str,str + p,(unsigned int)n); str[n] = 0; return true; } return false; } + //! Replace reserved characters (for Windows filename) by another character. + /** + \param[in,out] str C-string to work with (modified at output). + \param[in] c Replacement character. + **/ + inline void strwindows_reserved(char *const str, const char c='_') { + for (char *s = str; *s; ++s) { + const char i = *s; + if (i=='<' || i=='>' || i==':' || i=='\"' || i=='/' || i=='\\' || i=='|' || i=='?' || i=='*') *s = c; + } + } + //! Replace escape sequences in C-strings by their binary ascii values. /** \param[in,out] str C-string to work with (modified at output). - **/ + **/ inline void strunescape(char *const str) { -#define cimg_strunescape(ci,co) case ci: *nd = co; ++ns; break; +#define cimg_strunescape(ci,co) case ci : *nd = co; ++ns; break; unsigned int val = 0; for (char *ns = str, *nd = str; *ns || (bool)(*nd=0); ++nd) if (*ns=='\\') switch (*(++ns)) { + cimg_strunescape('a','\a'); + cimg_strunescape('b','\b'); + cimg_strunescape('e',0x1B); + cimg_strunescape('f','\f'); cimg_strunescape('n','\n'); + cimg_strunescape('r','\r'); cimg_strunescape('t','\t'); cimg_strunescape('v','\v'); - cimg_strunescape('b','\b'); - cimg_strunescape('r','\r'); - cimg_strunescape('f','\f'); - cimg_strunescape('a','\a'); cimg_strunescape('\\','\\'); - cimg_strunescape('\?','\?'); cimg_strunescape('\'','\''); cimg_strunescape('\"','\"'); + cimg_strunescape('\?','\?'); case 0 : *nd = 0; break; case '0' : case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' : - std::sscanf(ns,"%o",&val); while (*ns>='0' && *ns<='7') ++ns; - *nd = val; break; - case 'x': - std::sscanf(++ns,"%x",&val); + cimg_sscanf(ns,"%o",&val); while (*ns>='0' && *ns<='7') ++ns; + *nd = (char)val; break; + case 'x' : + cimg_sscanf(++ns,"%x",&val); while ((*ns>='0' && *ns<='7') || (*ns>='a' && *ns<='f') || (*ns>='A' && *ns<='F')) ++ns; - *nd = val; break; + *nd = (char)val; break; default : *nd = *(ns++); } else *nd = *(ns++); } // Return a temporary string describing the size of a memory buffer. - inline const char *strbuffersize(const unsigned long size) { - static char res[256] = { 0 }; - cimg::mutex(5); - if (size<1024LU) cimg_snprintf(res,sizeof(res),"%lu byte%s",size,size>1?"s":""); - else if (size<1024*1024LU) { const float nsize = size/1024.0f; cimg_snprintf(res,sizeof(res),"%.1f Kio",nsize); } - else if (size<1024*1024*1024LU) { - const float nsize = size/(1024*1024.0f); cimg_snprintf(res,sizeof(res),"%.1f Mio",nsize); - } else { const float nsize = size/(1024*1024*1024.0f); cimg_snprintf(res,sizeof(res),"%.1f Gio",nsize); } - cimg::mutex(5,0); - return res; - } + inline const char *strbuffersize(const unsigned long size); // Return string that identifies the running OS. inline const char *stros() { @@ -4598,9 +4674,9 @@ namespace cimg_library_suffixed { } //! Return the basename of a filename. - inline const char* basename(const char *const str) { - const char *p = 0; - for (const char *np = str; np>=str && (p=np); np = std::strchr(np,cimg_file_separator)+1) {} + inline const char* basename(const char *const s, const char separator=cimg_file_separator) { + const char *p = 0, *np = s; + while (np>=s && (p=np)) np = std::strchr(np,separator) + 1; return p; } @@ -4611,7 +4687,7 @@ namespace cimg_library_suffixed { cimg::srand(); for (unsigned int k = 0; k<8; ++k) { const int v = (int)std::rand()%3; - randomid[k] = (char)(v==0?('0'+(std::rand()%10)):(v==1?('a'+(std::rand()%26)):('A'+(std::rand()%26)))); + randomid[k] = (char)(v==0?('0' + (std::rand()%10)):(v==1?('a' + (std::rand()%26)):('A' + (std::rand()%26)))); } cimg::mutex(6,0); return randomid; @@ -4623,6 +4699,7 @@ namespace cimg_library_suffixed { #if cimg_OS==2 char *const nstr = new char[MAX_PATH]; if (GetShortPathNameA(str,nstr,MAX_PATH)) std::strcpy(str,nstr); + delete[] nstr; #endif } } @@ -4671,7 +4748,7 @@ namespace cimg_library_suffixed { return errn; } - //! Check if a path is a directory + //! Check if a path is a directory. /** \param path Specified path to test. **/ @@ -4679,615 +4756,131 @@ namespace cimg_library_suffixed { if (!path || !*path) return false; #if cimg_OS==1 struct stat st_buf; - if (!stat(path,&st_buf) && S_ISDIR(st_buf.st_mode)) return true; + return (!stat(path,&st_buf) && S_ISDIR(st_buf.st_mode)); #elif cimg_OS==2 - if (GetFileAttributes(path)&16) return true; -#endif - return false; - } - - //! Get/set path to store temporary files. - /** - \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=0, const bool reinit_path=false) { -#define _cimg_test_temporary_path(p) \ - if (!path_found) { \ - cimg_snprintf(s_path,1024,"%s",p); \ - cimg_snprintf(tmp,sizeof(tmp),"%s%c%s",s_path,cimg_file_separator,filetmp); \ - if ((file=std::fopen(tmp,"wb"))!=0) { cimg::fclose(file); std::remove(tmp); path_found = true; } \ - } - static char *s_path = 0; - cimg::mutex(7); - if (reinit_path) { delete[] s_path; s_path = 0; } - if (user_path) { - if (!s_path) s_path = new char[1024]; - std::memset(s_path,0,1024); - std::strncpy(s_path,user_path,1023); - } else if (!s_path) { - s_path = new char[1024]; - std::memset(s_path,0,1024); - bool path_found = false; - char tmp[1024] = { 0 }, filetmp[512] = { 0 }; - std::FILE *file = 0; - cimg_snprintf(filetmp,sizeof(filetmp),"%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"); + const unsigned int res = (unsigned int)GetFileAttributesA(path); + return res==INVALID_FILE_ATTRIBUTES?false:(res&16); #endif - if (!path_found) { - *s_path = 0; - std::strncpy(tmp,filetmp,sizeof(tmp)-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"); - } - } - cimg::mutex(7,0); - return s_path; } - //! Get/set path to the Program Files/ directory (Windows only). + //! Check if a path is a file. /** - \param user_path Specified path, or \c 0 to get the path currently used. - \param reinit_path Force path to be recalculated (may take some time). - \return Path containing the program files. + \param path Specified path to test. **/ -#if cimg_OS==2 - inline const char* programfiles_path(const char *const user_path=0, const bool reinit_path=false) { - static char *s_path = 0; - cimg::mutex(7); - if (reinit_path) { delete[] s_path; s_path = 0; } - if (user_path) { - if (!s_path) s_path = new char[1024]; - std::memset(s_path,0,1024); - std::strncpy(s_path,user_path,1023); - } else if (!s_path) { - s_path = new char[MAX_PATH]; - std::memset(s_path,0,MAX_PATH); - // Note: in the following line, 0x26 = CSIDL_PROGRAM_FILES (not defined on every compiler). -#if !defined(__INTEL_COMPILER) - if (!SHGetSpecialFolderPathA(0,s_path,0x0026,false)) { - const char *const pfPath = std::getenv("PROGRAMFILES"); - if (pfPath) std::strncpy(s_path,pfPath,MAX_PATH-1); - else std::strcpy(s_path,"C:\\PROGRA~1"); - } -#else - std::strcpy(s_path,"C:\\PROGRA~1"); -#endif - } - cimg::mutex(7,0); - return s_path; + inline bool is_file(const char *const path) { + if (!path || !*path) return false; + std::FILE *const file = std::fopen(path,"rb"); + if (!file) return false; + std::fclose(file); + return !is_directory(path); } -#endif - //! Get/set path to the ImageMagick's \c convert binary. + //! Get last write time of a given file or directory. /** - \param user_path Specified path, or \c 0 to get the path currently used. - \param reinit_path Force path to be recalculated (may take some time). - \return Path containing the \c convert binary. + \param path Specified path to get attributes from. + \param attr Type of requested time attribute. + Can be { 0=year | 1=month | 2=day | 3=day of week | 4=hour | 5=minute | 6=second } + \return -1 if requested attribute could not be read. **/ - inline const char* imagemagick_path(const char *const user_path=0, const bool reinit_path=false) { - static char *s_path = 0; - cimg::mutex(7); - if (reinit_path) { delete[] s_path; s_path = 0; } - if (user_path) { - if (!s_path) s_path = new char[1024]; - std::memset(s_path,0,1024); - std::strncpy(s_path,user_path,1023); - } else if (!s_path) { - s_path = new char[1024]; - std::memset(s_path,0,1024); - bool path_found = false; - std::FILE *file = 0; + inline int fdate(const char *const path, const unsigned int attr) { + int res = -1; + if (!path || !*path || attr>6) return -1; + cimg::mutex(6); #if cimg_OS==2 - const char *const pf_path = programfiles_path(); - if (!path_found) { - std::strcpy(s_path,".\\convert.exe"); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"%s\\IMAGEM~1.%.2d-\\convert.exe",pf_path,k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"%s\\IMAGEM~1.%d-Q\\convert.exe",pf_path,k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"%s\\IMAGEM~1.%d\\convert.exe",pf_path,k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"%s\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",pf_path,k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"%s\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",pf_path,k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"%s\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",pf_path,k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"C:\\IMAGEM~1.%.2d-\\convert.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"C:\\IMAGEM~1.%d-Q\\convert.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"C:\\IMAGEM~1.%d\\convert.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"C:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"C:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"C:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"D:\\IMAGEM~1.%.2d-\\convert.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"D:\\IMAGEM~1.%d-Q\\convert.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"D:\\IMAGEM~1.%d\\convert.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"D:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"D:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"D:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"convert.exe"); -#else - if (!path_found) { - std::strcpy(s_path,"./convert"); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"convert"); -#endif - winformat_string(s_path); + HANDLE file = CreateFileA(path,GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); + if (file!=INVALID_HANDLE_VALUE) { + FILETIME _ft; + SYSTEMTIME ft; + if (GetFileTime(file,0,0,&_ft) && FileTimeToSystemTime(&_ft,&ft)) + res = (int)(attr==0?ft.wYear:attr==1?ft.wMonth:attr==2?ft.wDay:attr==3?ft.wDayOfWeek: + attr==4?ft.wHour:attr==5?ft.wMinute:ft.wSecond); + CloseHandle(file); } - cimg::mutex(7,0); - return s_path; - } - - //! Get/set path to the GraphicsMagick's \c gm binary. - /** - \param user_path Specified path, or \c 0 to get the path currently used. - \param reinit_path Force path to be recalculated (may take some time). - \return Path containing the \c gm binary. - **/ - inline const char* graphicsmagick_path(const char *const user_path=0, const bool reinit_path=false) { - static char *s_path = 0; - cimg::mutex(7); - if (reinit_path) { delete[] s_path; s_path = 0; } - if (user_path) { - if (!s_path) s_path = new char[1024]; - std::memset(s_path,0,1024); - std::strncpy(s_path,user_path,1023); - } else if (!s_path) { - s_path = new char[1024]; - std::memset(s_path,0,1024); - bool path_found = false; - std::FILE *file = 0; -#if cimg_OS==2 - const char *const pf_path = programfiles_path(); - if (!path_found) { - std::strcpy(s_path,".\\gm.exe"); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"%s\\GRAPHI~1.%.2d-\\gm.exe",pf_path,k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"%s\\GRAPHI~1.%d-Q\\gm.exe",pf_path,k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"%s\\GRAPHI~1.%d\\gm.exe",pf_path,k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"%s\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",pf_path,k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"%s\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",pf_path,k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"%s\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",pf_path,k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"C:\\GRAPHI~1.%.2d-\\gm.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"C:\\GRAPHI~1.%d-Q\\gm.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"C:\\GRAPHI~1.%d\\gm.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"C:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"C:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"C:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"D:\\GRAPHI~1.%.2d-\\gm.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"D:\\GRAPHI~1.%d-Q\\gm.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"D:\\GRAPHI~1.%d\\gm.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"D:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"D:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,sizeof(s_path),"D:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"gm.exe"); #else - if (!path_found) { - std::strcpy(s_path,"./gm"); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"gm"); -#endif - winformat_string(s_path); + struct stat st_buf; + if (!stat(path,&st_buf)) { + const time_t _ft = st_buf.st_mtime; + const struct tm& ft = *std::localtime(&_ft); + res = (int)(attr==0?ft.tm_year + 1900:attr==1?ft.tm_mon + 1:attr==2?ft.tm_mday:attr==3?ft.tm_wday: + attr==4?ft.tm_hour:attr==5?ft.tm_min:ft.tm_sec); } - cimg::mutex(7,0); - return s_path; - } - - //! Get/set path to the XMedcon's \c medcon binary. - /** - \param user_path Specified path, or \c 0 to get the path currently used. - \param reinit_path Force path to be recalculated (may take some time). - \return Path containing the \c medcon binary. - **/ - inline const char* medcon_path(const char *const user_path=0, const bool reinit_path=false) { - static char *s_path = 0; - cimg::mutex(7); - if (reinit_path) { delete[] s_path; s_path = 0; } - if (user_path) { - if (!s_path) s_path = new char[1024]; - std::memset(s_path,0,1024); - std::strncpy(s_path,user_path,1023); - } else if (!s_path) { - s_path = new char[1024]; - std::memset(s_path,0,1024); - bool path_found = false; - std::FILE *file = 0; -#if cimg_OS==2 - const char *const pf_path = programfiles_path(); - if (!path_found) { - std::strcpy(s_path,".\\medcon.exe"); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) { - cimg_snprintf(s_path,sizeof(s_path),"%s\\XMedCon\\bin\\medcon.bat",pf_path); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) { - cimg_snprintf(s_path,sizeof(s_path),"%s\\XMedCon\\bin\\medcon.exe",pf_path); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) { - std::strcpy(s_path,"C:\\XMedCon\\bin\\medcon.exe"); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"medcon.exe"); -#else - if (!path_found) { - std::strcpy(s_path,"./medcon"); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"medcon"); #endif - winformat_string(s_path); - } - cimg::mutex(7,0); - return s_path; + cimg::mutex(6,0); + return res; } - //! Get/set path to the FFMPEG's \c ffmpeg binary. + //! Get current local time. /** - \param user_path Specified path, or \c 0 to get the path currently used. - \param reinit_path Force path to be recalculated (may take some time). - \return Path containing the \c ffmpeg binary. + \param attr Type of requested time attribute. + Can be { 0=year | 1=month | 2=day | 3=day of week | 4=hour | 5=minute | 6=second } **/ - inline const char *ffmpeg_path(const char *const user_path=0, const bool reinit_path=false) { - static char *s_path = 0; - cimg::mutex(7); - if (reinit_path) { delete[] s_path; s_path = 0; } - if (user_path) { - if (!s_path) s_path = new char[1024]; - std::memset(s_path,0,1024); - std::strncpy(s_path,user_path,1023); - } else if (!s_path) { - s_path = new char[1024]; - std::memset(s_path,0,1024); - bool path_found = false; - std::FILE *file = 0; + inline int date(const unsigned int attr) { + int res = -1; + cimg::mutex(6); #if cimg_OS==2 - if (!path_found) { - std::strcpy(s_path,".\\ffmpeg.exe"); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"ffmpeg.exe"); + SYSTEMTIME st; + GetLocalTime(&st); + res = (int)(attr==0?st.wYear:attr==1?st.wMonth:attr==2?st.wDay:attr==3?st.wDayOfWeek: + attr==4?st.wHour:attr==5?st.wMinute:st.wSecond); #else - if (!path_found) { - std::strcpy(s_path,"./ffmpeg"); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"ffmpeg"); + time_t _st; + std::time(&_st); + struct tm *st = std::localtime(&_st); + res = (int)(attr==0?st->tm_year + 1900:attr==1?st->tm_mon + 1:attr==2?st->tm_mday:attr==3?st->tm_wday: + attr==4?st->tm_hour:attr==5?st->tm_min:st->tm_sec); #endif - winformat_string(s_path); - } - cimg::mutex(7,0); - return s_path; + cimg::mutex(6,0); + return res; } - //! Get/set path to the \c gzip binary. - /** - \param user_path Specified path, or \c 0 to get the path currently used. - \param reinit_path Force path to be recalculated (may take some time). - \return Path containing the \c gzip binary. - **/ - inline const char *gzip_path(const char *const user_path=0, const bool reinit_path=false) { - static char *s_path = 0; - cimg::mutex(7); - if (reinit_path) { delete[] s_path; s_path = 0; } - if (user_path) { - if (!s_path) s_path = new char[1024]; - std::memset(s_path,0,1024); - std::strncpy(s_path,user_path,1023); - } else if (!s_path) { - s_path = new char[1024]; - std::memset(s_path,0,1024); - bool path_found = false; - std::FILE *file = 0; -#if cimg_OS==2 - if (!path_found) { - std::strcpy(s_path,".\\gzip.exe"); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"gzip.exe"); -#else - if (!path_found) { - std::strcpy(s_path,"./gzip"); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"gzip"); -#endif - winformat_string(s_path); - } - cimg::mutex(7,0); - return s_path; - } + // Get/set path to store temporary files. + inline const char* temporary_path(const char *const user_path=0, const bool reinit_path=false); - //! Get/set path to the \c gzip binary. - /** - \param user_path Specified path, or \c 0 to get the path currently used. - \param reinit_path Force path to be recalculated (may take some time). - \return Path containing the \c gunzip binary. - **/ - inline const char *gunzip_path(const char *const user_path=0, const bool reinit_path=false) { - static char *s_path = 0; - cimg::mutex(7); - if (reinit_path) { delete[] s_path; s_path = 0; } - if (user_path) { - if (!s_path) s_path = new char[1024]; - std::memset(s_path,0,1024); - std::strncpy(s_path,user_path,1023); - } else if (!s_path) { - s_path = new char[1024]; - std::memset(s_path,0,1024); - bool path_found = false; - std::FILE *file = 0; + // Get/set path to the Program Files/ directory (Windows only). #if cimg_OS==2 - if (!path_found) { - std::strcpy(s_path,".\\gunzip.exe"); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"gunzip.exe"); -#else - if (!path_found) { - std::strcpy(s_path,"./gunzip"); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"gunzip"); + inline const char* programfiles_path(const char *const user_path=0, const bool reinit_path=false); #endif - winformat_string(s_path); - } - cimg::mutex(7,0); - return s_path; - } - //! Get/set path to the \c dcraw binary. - /** - \param user_path Specified path, or \c 0 to get the path currently used. - \param reinit_path Force path to be recalculated (may take some time). - \return Path containing the \c dcraw binary. - **/ - inline const char *dcraw_path(const char *const user_path=0, const bool reinit_path=false) { - static char *s_path = 0; - cimg::mutex(7); - if (reinit_path) { delete[] s_path; s_path = 0; } - if (user_path) { - if (!s_path) s_path = new char[1024]; - std::memset(s_path,0,1024); - std::strncpy(s_path,user_path,1023); - } else if (!s_path) { - s_path = new char[1024]; - std::memset(s_path,0,1024); - bool path_found = false; - std::FILE *file = 0; -#if cimg_OS==2 - if (!path_found) { - std::strcpy(s_path,".\\dcraw.exe"); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"dcraw.exe"); -#else - if (!path_found) { - std::strcpy(s_path,"./dcraw"); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"dcraw"); -#endif - winformat_string(s_path); - } - cimg::mutex(7,0); - return s_path; - } + // Get/set path to the ImageMagick's \c convert binary. + inline const char* imagemagick_path(const char *const user_path=0, const bool reinit_path=false); - //! Get/set path to the \c wget binary. - /** - \param user_path Specified path, or \c 0 to get the path currently used. - \param reinit_path Force path to be recalculated (may take some time). - \return Path containing the \c wget binary. - **/ - inline const char *wget_path(const char *const user_path=0, const bool reinit_path=false) { - static char *s_path = 0; - cimg::mutex(7); - if (reinit_path) { delete[] s_path; s_path = 0; } - if (user_path) { - if (!s_path) s_path = new char[1024]; - std::memset(s_path,0,1024); - std::strncpy(s_path,user_path,1023); - } else if (!s_path) { - s_path = new char[1024]; - std::memset(s_path,0,1024); - bool path_found = false; - std::FILE *file = 0; -#if cimg_OS==2 - if (!path_found) { - std::strcpy(s_path,".\\wget.exe"); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"wget.exe"); -#else - if (!path_found) { - std::strcpy(s_path,"./wget"); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"wget"); -#endif - winformat_string(s_path); - } - cimg::mutex(7,0); - return s_path; - } + // Get/set path to the GraphicsMagick's \c gm binary. + inline const char* graphicsmagick_path(const char *const user_path=0, const bool reinit_path=false); - //! Get/set path to the \c curl binary. - /** - \param user_path Specified path, or \c 0 to get the path currently used. - \param reinit_path Force path to be recalculated (may take some time). - \return Path containing the \c curl binary. - **/ - inline const char *curl_path(const char *const user_path=0, const bool reinit_path=false) { - static char *s_path = 0; - cimg::mutex(7); - if (reinit_path) { delete[] s_path; s_path = 0; } - if (user_path) { - if (!s_path) s_path = new char[1024]; - std::memset(s_path,0,1024); - std::strncpy(s_path,user_path,1023); - } else if (!s_path) { - s_path = new char[1024]; - std::memset(s_path,0,1024); - bool path_found = false; - std::FILE *file = 0; -#if cimg_OS==2 - if (!path_found) { - std::strcpy(s_path,".\\curl.exe"); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"curl.exe"); -#else - if (!path_found) { - std::strcpy(s_path,"./curl"); - if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"curl"); -#endif - winformat_string(s_path); - } - cimg::mutex(7,0); - return s_path; - } + // Get/set path to the XMedcon's \c medcon binary. + inline const char* medcon_path(const char *const user_path=0, const bool reinit_path=false); + + // Get/set path to the FFMPEG's \c ffmpeg binary. + inline const char *ffmpeg_path(const char *const user_path=0, const bool reinit_path=false); + + // Get/set path to the \c gzip binary. + inline const char *gzip_path(const char *const user_path=0, const bool reinit_path=false); + + // Get/set path to the \c gunzip binary. + inline const char *gunzip_path(const char *const user_path=0, const bool reinit_path=false); + + // Get/set path to the \c dcraw binary. + inline const char *dcraw_path(const char *const user_path=0, const bool reinit_path=false); + + // Get/set path to the \c wget binary. + inline const char *wget_path(const char *const user_path=0, const bool reinit_path=false); + + // Get/set path to the \c curl binary. + inline const char *curl_path(const char *const user_path=0, const bool reinit_path=false); //! Split filename into two C-strings \c body and \c extension. + /** + filename and body must not overlap! + **/ inline const char *split_filename(const char *const filename, char *const body=0) { if (!filename) { if (body) *body = 0; return 0; } - const char *p = 0; for (const char *np = filename; np>=filename && (p=np); np = std::strchr(np,'.')+1) {} + const char *p = 0; for (const char *np = filename; np>=filename && (p=np); np = std::strchr(np,'.') + 1) {} if (p==filename) { if (body) std::strcpy(body,filename); return filename + std::strlen(filename); } const unsigned int l = (unsigned int)(p - filename - 1); - if (body) { std::memcpy(body,filename,l); body[l] = 0; } + if (body) { if (l) std::memcpy(body,filename,l); body[l] = 0; } return p; } @@ -5295,64 +4888,15 @@ namespace cimg_library_suffixed { inline char* number_filename(const char *const filename, const int number, const unsigned int digits, char *const str) { if (!filename) { if (str) *str = 0; return 0; } - char format[1024] = { 0 }, body[1024] = { 0 }; + char *const format = new char[1024], *const body = new char[1024]; const char *const ext = cimg::split_filename(filename,body); - if (*ext) cimg_snprintf(format,sizeof(format),"%%s_%%.%ud.%%s",digits); - else cimg_snprintf(format,sizeof(format),"%%s_%%.%ud",digits); + if (*ext) cimg_snprintf(format,1024,"%%s_%%.%ud.%%s",digits); + else cimg_snprintf(format,1024,"%%s_%%.%ud",digits); std::sprintf(str,format,body,number,ext); + delete[] format; delete[] body; return str; } - //! Try to guess format from an image file. - /** - \param file Input file (can be \c 0 if \c filename is set). - \param filename Filename, as a C-string (can be \c 0 if \c file is set). - \return C-string containing the guessed file format, or \c 0 if nothing has been guessed. - **/ - inline const char *file_type(std::FILE *const file, const char *const filename) { - if (!file && !filename) - throw CImgArgumentException("cimg::file_type(): Specified filename is (null)."); - static const char - *const _pnm = "pnm", - *const _pfm = "pfm", - *const _bmp = "bmp", - *const _gif = "gif", - *const _jpg = "jpg", - *const _off = "off", - *const _pan = "pan", - *const _png = "png", - *const _tif = "tif", - *const _inr = "inr", - *const _dcm = "dcm"; - std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); - const char *f_type = 0, *head; - char header[2048] = { 0 }, item[1024] = { 0 }; - const unsigned char *const uheader = (unsigned char*)header; - int err; char cerr; - const unsigned int siz = (unsigned int)std::fread(header,2048,1,nfile); // Read first 2048 bytes. - if (!file) cimg::fclose(nfile); - - if (!std::strncmp(header,"OFF\n",4)) f_type = _off; // OFF. - else if (!std::strncmp(header,"#INRIMAGE",9)) f_type = _inr; // INRIMAGE. - else if (!std::strncmp(header,"PANDORE",7)) f_type = _pan; // PANDORE. - else if (!std::strncmp(header+128,"DICM",4)) f_type = _dcm; // DICOM. - else if (uheader[0]==0xFF && uheader[1]==0xD8 && uheader[2]==0xFF) f_type = _jpg; // JPEG. - else if (header[0]=='B' && header[1]=='M') f_type = _bmp; // BMP. - else if (header[0]=='G' && header[1]=='I' && header[2]=='F' && header[3]=='8' && header[5]=='a' && // GIF. - (header[4]=='7' || header[4]=='9')) f_type = _gif; - else if (uheader[0]==0x89 && uheader[1]==0x50 && uheader[2]==0x4E && uheader[3]==0x47 && // PNG. - uheader[4]==0x0D && uheader[5]==0x0A && uheader[6]==0x1A && uheader[7]==0x0A) f_type = _png; - else if ((uheader[0]==0x49 && uheader[1]==0x49) || (uheader[0]==0x4D && uheader[1]==0x4D)) f_type = _tif; // TIFF. - else { // PNM or PFM. - head = header; - while (head inline int fread(T *const ptr, const unsigned long nmemb, std::FILE *stream) { - if (!ptr || nmemb<=0 || !stream) + if (!ptr || !stream) throw CImgArgumentException("cimg::fread(): Invalid reading request of %u %s%s from file %p to buffer %p.", nmemb,cimg::type::string(),nmemb>1?"s":"",stream,ptr); - + if (!nmemb) return 0; const unsigned long wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T); unsigned long to_read = nmemb, al_read = 0, l_to_read = 0, l_al_read = 0; do { l_to_read = (to_read*sizeof(T))0); if (to_read>0) warn("cimg::fread(): Only %u/%u elements could be read from file.", al_read,nmemb); - return al_read; + return (int)al_read; } //! Write data to file. @@ -5394,19 +4938,19 @@ namespace cimg_library_suffixed { if (!ptr || !stream) throw CImgArgumentException("cimg::fwrite(): Invalid writing request of %u %s%s from buffer %p to file %p.", nmemb,cimg::type::string(),nmemb>1?"s":"",ptr,stream); - if (nmemb<=0) return 0; + if (!nmemb) return 0; const unsigned long wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T); unsigned long to_write = nmemb, al_write = 0, l_to_write = 0, l_al_write = 0; do { l_to_write = (to_write*sizeof(T))0); if (to_write>0) warn("cimg::fwrite(): Only %u/%u elements could be written in file.", al_write,nmemb); - return al_write; + return (int)al_write; } //! Create an empty file. @@ -5416,69 +4960,17 @@ namespace cimg_library_suffixed { **/ inline void fempty(std::FILE *const file, const char *const filename) { if (!file && !filename) - throw CImgArgumentException("cimg::file_type(): Specified filename is (null)."); + throw CImgArgumentException("cimg::fempty(): Specified filename is (null)."); std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); if (!file) cimg::fclose(nfile); } - //! Load file from network as a local temporary file. - /** - \param filename Filename, as a C-string. - \param[out] filename_local C-string containing the path to a local copy of \c filename. - \return Value of \c filename_local. - \note Use external binaries \c wget or \c curl to perform. You must have one of these tools installed - to be able to use this function. - **/ - inline char *load_network_external(const char *const filename, char *const filename_local) { - if (!filename) - throw CImgArgumentException("cimg::load_network_external(): Specified filename is (null)."); - if (!filename_local) - throw CImgArgumentException("cimg::load_network_external(): Specified destination string is (null)."); - const char *const _ext = cimg::split_filename(filename), *const ext = (*_ext && _ext>filename)?_ext-1:_ext; - char command[1024] = { 0 }; - std::FILE *file = 0; - *filename_local = 0; - do { - cimg_snprintf(filename_local,512,"%s%c%s%s", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext); - if ((file=std::fopen(filename_local,"rb"))!=0) cimg::fclose(file); - } while (file); - - // Try with 'curl' first. - cimg_snprintf(command,sizeof(command),"%s -f --silent --compressed -o \"%s\" \"%s\"", - cimg::curl_path(),filename_local,filename); - cimg::system(command); - if (!(file = std::fopen(filename_local,"rb"))) { + // Try to guess format from an image file. + inline const char *ftype(std::FILE *const file, const char *const filename); - // Try with 'wget' else. - cimg_snprintf(command,sizeof(command),"%s -q -r -l 0 --no-cache -O \"%s\" \"%s\"", - cimg::wget_path(),filename_local,filename); - cimg::system(command); - if (!(file = std::fopen(filename_local,"rb"))) - throw CImgIOException("cimg::load_network_external(): Failed to load file '%s' with external commands " - "'wget' or 'curl'.",filename); - cimg::fclose(file); - - // Try gunzip it. - cimg_snprintf(command,sizeof(command),"%s.gz",filename_local); - std::rename(filename_local,command); - cimg_snprintf(command,sizeof(command),"%s --quiet \"%s.gz\"", - gunzip_path(),filename_local); - cimg::system(command); - file = std::fopen(filename_local,"rb"); - if (!file) { - cimg_snprintf(command,sizeof(command),"%s.gz",filename_local); - std::rename(command,filename_local); - file = std::fopen(filename_local,"rb"); - } - } - std::fseek(file,0,SEEK_END); // Check if file size is 0. - if (std::ftell(file)<=0) - throw CImgIOException("cimg::load_network_external(): Failed to load file '%s' with external commands " - "'wget' or 'curl'.",filename); - cimg::fclose(file); - return filename_local; - } + // Load file from network as a local temporary file. + inline char *load_network(const char *const url, char *const filename_local, + const unsigned int timeout=0, const bool try_fallback=false); //! Return options specified on the command line. inline const char* option(const char *const name, const int argc, const char *const *const argv, @@ -5530,9 +5022,10 @@ namespace cimg_library_suffixed { const int defaut, const char *const usage=0) { const char *const s = cimg::option(name,argc,argv,(char*)0); const int res = s?std::atoi(s):defaut; - char tmp[256] = { 0 }; - cimg_snprintf(tmp,sizeof(tmp),"%d",res); + char *const tmp = new char[256]; + cimg_snprintf(tmp,256,"%d",res); cimg::option(name,0,0,tmp,usage); + delete[] tmp; return res; } @@ -5550,9 +5043,10 @@ namespace cimg_library_suffixed { const float defaut, const char *const usage=0) { const char *const s = cimg::option(name,argc,argv,(char*)0); const float res = s?(float)cimg::atof(s):defaut; - char tmp[256] = { 0 }; - cimg_snprintf(tmp,sizeof(tmp),"%g",res); + char *const tmp = new char[256]; + cimg_snprintf(tmp,256,"%g",res); cimg::option(name,0,0,tmp,usage); + delete[] tmp; return res; } @@ -5560,9 +5054,10 @@ namespace cimg_library_suffixed { const double defaut, const char *const usage=0) { const char *const s = cimg::option(name,argc,argv,(char*)0); const double res = s?cimg::atof(s):defaut; - char tmp[256] = { 0 }; - cimg_snprintf(tmp,sizeof(tmp),"%g",res); + char *const tmp = new char[256]; + cimg_snprintf(tmp,256,"%g",res); cimg::option(name,0,0,tmp,usage); + delete[] tmp; return res; } @@ -5585,12 +5080,11 @@ namespace cimg_library_suffixed { return 0; } - //! Print informations about \CImg environement variables. + //! Print information about \CImg environement variables. /** \note Output is done on the default output stream. **/ inline void info() { - char tmp[1024] = { 0 }; std::fprintf(cimg::output(),"\n %s%sCImg Library %u.%u.%u%s, compiled %s ( %s ) with the following flags:\n\n", cimg::t_red,cimg::t_bold,cimg_version/100,(cimg_version/10)%10,cimg_version%10, cimg::t_normal,__DATE__,__TIME__); @@ -5722,31 +5216,33 @@ namespace cimg_library_suffixed { #endif cimg::t_normal); - cimg_snprintf(tmp,sizeof(tmp),"\"%.1020s\"",cimg::imagemagick_path()); + char *const tmp = new char[1024]; + cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::imagemagick_path()); std::fprintf(cimg::output()," > Path of ImageMagick: %s%-13s%s\n", cimg::t_bold, tmp, cimg::t_normal); - cimg_snprintf(tmp,sizeof(tmp),"\"%.1020s\"",cimg::graphicsmagick_path()); + cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::graphicsmagick_path()); std::fprintf(cimg::output()," > Path of GraphicsMagick: %s%-13s%s\n", cimg::t_bold, tmp, cimg::t_normal); - cimg_snprintf(tmp,sizeof(tmp),"\"%.1020s\"",cimg::medcon_path()); + cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::medcon_path()); std::fprintf(cimg::output()," > Path of 'medcon': %s%-13s%s\n", cimg::t_bold, tmp, cimg::t_normal); - cimg_snprintf(tmp,sizeof(tmp),"\"%.1020s\"",cimg::temporary_path()); + cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::temporary_path()); std::fprintf(cimg::output()," > Temporary path: %s%-13s%s\n", cimg::t_bold, tmp, cimg::t_normal); std::fprintf(cimg::output(),"\n"); + delete[] tmp; } // Declare LAPACK function signatures if LAPACK support is enabled. @@ -5802,12 +5298,12 @@ namespace cimg_library_suffixed { template inline void sgels(char & TRANS, int &M, int &N, int &NRHS, T* lapA, int &LDA, - T* lapB, int &LDB, T* WORK, int &LWORK, int &INFO){ + T* lapB, int &LDB, T* WORK, int &LWORK, int &INFO){ dgels_(&TRANS, &M, &N, &NRHS, lapA, &LDA, lapB, &LDB, WORK, &LWORK, &INFO); } inline void sgels(char & TRANS, int &M, int &N, int &NRHS, float* lapA, int &LDA, - float* lapB, int &LDB, float* WORK, int &LWORK, int &INFO){ + float* lapB, int &LDB, float* WORK, int &LWORK, int &INFO){ sgels_(&TRANS, &M, &N, &NRHS, lapA, &LDA, lapB, &LDB, WORK, &LWORK, &INFO); } @@ -6055,9 +5551,9 @@ namespace cimg_library_suffixed { float _fps_fps, _min, _max; bool _is_fullscreen; char *_title; - volatile unsigned int _window_width, _window_height, _button, _keys[128], _released_keys[128]; - volatile int _window_x, _window_y, _mouse_x, _mouse_y, _wheel; - volatile bool _is_closed, _is_resized, _is_moved, _is_event, + unsigned int _window_width, _window_height, _button, *_keys, *_released_keys; + int _window_x, _window_y, _mouse_x, _mouse_y, _wheel; + bool _is_closed, _is_resized, _is_moved, _is_event, _is_keyESC, _is_keyF1, _is_keyF2, _is_keyF3, _is_keyF4, _is_keyF5, _is_keyF6, _is_keyF7, _is_keyF8, _is_keyF9, _is_keyF10, _is_keyF11, _is_keyF12, _is_keyPAUSE, _is_key1, _is_key2, _is_key3, _is_key4, _is_key5, _is_key6, _is_key7, _is_key8, _is_key9, _is_key0, @@ -6119,6 +5615,8 @@ namespace cimg_library_suffixed { **/ ~CImgDisplay() { assign(); + delete[] _keys; + delete[] _released_keys; } //! Construct an empty display. @@ -6138,6 +5636,7 @@ namespace cimg_library_suffixed { _is_fullscreen(false), _title(0), _window_width(0),_window_height(0),_button(0), + _keys(new unsigned int[128]),_released_keys(new unsigned int[128]), _window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0), _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) { assign(); @@ -6161,6 +5660,7 @@ namespace cimg_library_suffixed { _is_fullscreen(false), _title(0), _window_width(0),_window_height(0),_button(0), + _keys(new unsigned int[128]),_released_keys(new unsigned int[128]), _window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0), _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) { assign(width,height,title,normalization,is_fullscreen,is_closed); @@ -6184,6 +5684,7 @@ namespace cimg_library_suffixed { _is_fullscreen(false), _title(0), _window_width(0),_window_height(0),_button(0), + _keys(new unsigned int[128]),_released_keys(new unsigned int[128]), _window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0), _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) { assign(img,title,normalization,is_fullscreen,is_closed); @@ -6207,6 +5708,7 @@ namespace cimg_library_suffixed { _is_fullscreen(false), _title(0), _window_width(0),_window_height(0),_button(0), + _keys(new unsigned int[128]),_released_keys(new unsigned int[128]), _window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0), _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) { assign(list,title,normalization,is_fullscreen,is_closed); @@ -6223,6 +5725,7 @@ namespace cimg_library_suffixed { _is_fullscreen(false), _title(0), _window_width(0),_window_height(0),_button(0), + _keys(new unsigned int[128]),_released_keys(new unsigned int[128]), _window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0), _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) { assign(disp); @@ -6306,7 +5809,8 @@ namespace cimg_library_suffixed { const unsigned int _nw = dx + (dz>1?dz:0), _nh = dy + (dz>1?dz:0); unsigned int nw = _nw?_nw:1, nh = _nh?_nh:1; const unsigned int - sw = CImgDisplay::screen_width(), sh = CImgDisplay::screen_height(), + sw = (unsigned int)CImgDisplay::screen_width(), + sh = (unsigned int)CImgDisplay::screen_height(), mw = dmin<0?(unsigned int)(sw*-dmin/100):(unsigned int)dmin, mh = dmin<0?(unsigned int)(sh*-dmin/100):(unsigned int)dmin, Mw = dmax<0?(unsigned int)(sw*-dmax/100):(unsigned int)dmax, @@ -6503,7 +6007,7 @@ namespace cimg_library_suffixed { } \endcode **/ - volatile bool& is_key(const char *const keycode) { + bool& is_key(const char *const keycode) { static bool f = false; f = false; #define _cimg_iskey_test2(k) if (!cimg::strcasecmp(keycode,#k)) return _is_key##k; @@ -6557,7 +6061,7 @@ namespace cimg_library_suffixed { if (keycodes_sequence && length) { const unsigned int *const ps_end = keycodes_sequence + length - 1, - *const pk_end = (unsigned int*)_keys + 1 + sizeof(_keys)/sizeof(unsigned int) - length, + *const pk_end = (unsigned int*)_keys + 1 + 128 - length, k = *ps_end; for (unsigned int *pk = (unsigned int*)_keys; pk=1) { _fps_fps = _fps_frames/delta; @@ -6924,10 +6428,15 @@ namespace cimg_library_suffixed { **/ template CImgDisplay& display(const CImgList& list, const char axis='x', const float align=0) { + if (list._width==1) { + const CImg& img = list[0]; + if (img._depth==1 && (img._spectrum==1 || img._spectrum>=3) && _normalization!=1) return display(img); + } CImgList::ucharT> visu(list._width); cimglist_for(list,l) { const CImg& img = list._data[l]; - img.__get_select(*this,_normalization,(img._width-1)/2,(img._height-1)/2,(img._depth-1)/2).move_to(visu[l]); + img.__get_select(*this,_normalization,(img._width - 1)/2,(img._height - 1)/2, + (img._depth - 1)/2).move_to(visu[l]); } visu.get_append(axis,align).display(*this); return *this; @@ -6979,7 +6488,7 @@ namespace cimg_library_suffixed { - The associated window is also resized to specified dimensions. **/ CImgDisplay& resize(const bool force_redraw=true) { - resize(_window_width,_window_height,force_redraw); + resize(window_width(),window_height(),force_redraw); return *this; } @@ -7022,14 +6531,14 @@ namespace cimg_library_suffixed { - The associated window is also resized to specified dimensions. **/ CImgDisplay& resize(const CImgDisplay& disp, const bool force_redraw=true) { - return resize(disp._width,disp._height,force_redraw); + return resize(disp.width(),disp.height(),force_redraw); } // [internal] Render pixel buffer with size (wd,hd) from source buffer of size (ws,hs). template static void _render_resize(const T *ptrs, const unsigned int ws, const unsigned int hs, t *ptrd, const unsigned int wd, const unsigned int hd) { - unsigned int *const offx = new unsigned int[wd], *const offy = new unsigned int[hd+1], *poffx, *poffy; + unsigned int *const offx = new unsigned int[wd], *const offy = new unsigned int[hd + 1], *poffx, *poffy; float s, curr, old; s = (float)ws/wd; poffx = offx; curr = 0; for (unsigned int x = 0; x_is_closed && event.xany.window==cimg::X11_attr().wins[i]->_window) cimg::X11_attr().wins[i]->_handle_events(&event); - XUnlockDisplay(dpy); + cimg_unlock_display(); pthread_testcancel(); cimg::sleep(8); } @@ -7646,7 +7155,7 @@ namespace cimg_library_suffixed { } void _set_colormap(Colormap& _colormap, const unsigned int dim) { - XColor colormap[256]; + XColor *const colormap = new XColor[256]; switch (dim) { case 1 : { // colormap for greyscale images for (unsigned int index = 0; index<256; ++index) { @@ -7677,6 +7186,7 @@ namespace cimg_library_suffixed { } } XStoreColors(cimg::X11_attr().display,_colormap,colormap,256); + delete[] colormap; } void _map_window() { @@ -7917,12 +7427,12 @@ namespace cimg_library_suffixed { XVisualInfo *vinfo = XGetVisualInfo(dpy,VisualIDMask,&vtemplate,&nb_visuals); if (vinfo && vinfo->red_maskblue_mask) cimg::X11_attr().is_blue_first = true; cimg::X11_attr().byte_order = ImageByteOrder(dpy); - XFree(vinfo); + XFree(vinfo); - XLockDisplay(dpy); + cimg_lock_display(); cimg::X11_attr().events_thread = new pthread_t; pthread_create(cimg::X11_attr().events_thread,0,_events_thread,0); - } else XLockDisplay(dpy); + } else cimg_lock_display(); // Set display variables. _width = cimg::min(dimw,(unsigned int)screen_width()); @@ -7940,14 +7450,14 @@ namespace cimg_library_suffixed { const unsigned int sx = screen_width(), sy = screen_height(); XSetWindowAttributes winattr; winattr.override_redirect = 1; - _window = XCreateWindow(dpy,DefaultRootWindow(dpy),(sx-_width)/2,(sy-_height)/2,_width,_height,0,0, + _window = XCreateWindow(dpy,DefaultRootWindow(dpy),(sx - _width)/2,(sy - _height)/2,_width,_height,0,0, InputOutput,CopyFromParent,CWOverrideRedirect,&winattr); } else _window = XCreateSimpleWindow(dpy,DefaultRootWindow(dpy),0,0,_width,_height,0,0L,0L); XSelectInput(dpy,_window, - ExposureMask | StructureNotifyMask | ButtonPressMask | KeyPressMask | PointerMotionMask | - EnterWindowMask | LeaveWindowMask | ButtonReleaseMask | KeyReleaseMask); + ExposureMask | StructureNotifyMask | ButtonPressMask | KeyPressMask | PointerMotionMask | + EnterWindowMask | LeaveWindowMask | ButtonReleaseMask | KeyReleaseMask); XStoreName(dpy,_window,_title?_title:" "); if (cimg::X11_attr().nb_bits==8) { @@ -8013,19 +7523,19 @@ namespace cimg_library_suffixed { if (_is_fullscreen) XGrabKeyboard(dpy,_window,1,GrabModeAsync,GrabModeAsync,CurrentTime); cimg::X11_attr().wins[cimg::X11_attr().nb_wins++]=this; if (!_is_closed) _map_window(); else { _window_x = _window_y = cimg::type::min(); } - XUnlockDisplay(dpy); + cimg_unlock_display(); cimg::mutex(14,0); } CImgDisplay& assign() { if (is_empty()) return flush(); Display *const dpy = cimg::X11_attr().display; - XLockDisplay(dpy); + cimg_lock_display(); // Remove display window from event thread list. unsigned int i; for (i = 0; i tmp; - const CImg& nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width-1)/2, - (img._height-1)/2, - (img._depth-1)/2)); + const CImg& nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width - 1)/2, + (img._height - 1)/2, + (img._depth - 1)/2)); _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag); if (_normalization==2) _min = (float)nimg.min_max(_max); return render(nimg).paint(); @@ -8094,9 +7604,9 @@ namespace cimg_library_suffixed { const bool fullscreen_flag=false, const bool closed_flag=false) { if (!list) return assign(); CImg tmp; - const CImg img = list>'x', &nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width-1)/2, - (img._height-1)/2, - (img._depth-1)/2)); + const CImg img = list>'x', &nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width - 1)/2, + (img._height - 1)/2, + (img._depth - 1)/2)); _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag); if (_normalization==2) _min = (float)nimg.min_max(_max); return render(nimg).paint(); @@ -8120,7 +7630,7 @@ namespace cimg_library_suffixed { tmpdimy = (nheight>0)?nheight:(-nheight*height()/100), dimx = tmpdimx?tmpdimx:1, dimy = tmpdimy?tmpdimy:1; - XLockDisplay(dpy); + cimg_lock_display(); if (_window_width!=dimx || _window_height!=dimy) { XWindowAttributes attr; for (unsigned int i = 0; i<10; ++i) { @@ -8137,8 +7647,8 @@ namespace cimg_library_suffixed { } _window_width = _width = dimx; _window_height = _height = dimy; _is_resized = false; - XUnlockDisplay(dpy); - if (_is_fullscreen) move((screen_width()-_width)/2,(screen_height()-_height)/2); + cimg_unlock_display(); + if (_is_fullscreen) move((screen_width() - _width)/2,(screen_height() - _height)/2); if (force_redraw) return paint(); return *this; } @@ -8160,24 +7670,23 @@ namespace cimg_library_suffixed { CImgDisplay& show() { if (is_empty() || !_is_closed) return *this; - Display *const dpy = cimg::X11_attr().display; - XLockDisplay(dpy); + cimg_lock_display(); if (_is_fullscreen) _init_fullscreen(); _map_window(); _is_closed = false; - XUnlockDisplay(dpy); + cimg_unlock_display(); return paint(); } CImgDisplay& close() { if (is_empty() || _is_closed) return *this; Display *const dpy = cimg::X11_attr().display; - XLockDisplay(dpy); + cimg_lock_display(); if (_is_fullscreen) _desinit_fullscreen(); XUnmapWindow(dpy,_window); _window_x = _window_y = -1; _is_closed = true; - XUnlockDisplay(dpy); + cimg_unlock_display(); return *this; } @@ -8185,27 +7694,27 @@ namespace cimg_library_suffixed { if (is_empty()) return *this; show(); Display *const dpy = cimg::X11_attr().display; - XLockDisplay(dpy); + cimg_lock_display(); XMoveWindow(dpy,_window,posx,posy); _window_x = posx; _window_y = posy; _is_moved = false; - XUnlockDisplay(dpy); + cimg_unlock_display(); return paint(); } CImgDisplay& show_mouse() { if (is_empty()) return *this; Display *const dpy = cimg::X11_attr().display; - XLockDisplay(dpy); + cimg_lock_display(); XUndefineCursor(dpy,_window); - XUnlockDisplay(dpy); + cimg_unlock_display(); return *this; } CImgDisplay& hide_mouse() { if (is_empty()) return *this; Display *const dpy = cimg::X11_attr().display; - XLockDisplay(dpy); + cimg_lock_display(); const char pix_data[8] = { 0 }; XColor col; col.red = col.green = col.blue = 0; @@ -8213,38 +7722,39 @@ namespace cimg_library_suffixed { Cursor cur = XCreatePixmapCursor(dpy,pix,pix,&col,&col,0,0); XFreePixmap(dpy,pix); XDefineCursor(dpy,_window,cur); - XUnlockDisplay(dpy); + cimg_unlock_display(); return *this; } CImgDisplay& set_mouse(const int posx, const int posy) { if (is_empty() || _is_closed) return *this; Display *const dpy = cimg::X11_attr().display; - XLockDisplay(dpy); + cimg_lock_display(); XWarpPointer(dpy,0L,_window,0,0,0,0,posx,posy); _mouse_x = posx; _mouse_y = posy; _is_moved = false; XSync(dpy,0); - XUnlockDisplay(dpy); + cimg_unlock_display(); return *this; } CImgDisplay& set_title(const char *const format, ...) { if (is_empty()) return *this; - char tmp[1024] = { 0 }; + char *const tmp = new char[1024]; va_list ap; va_start(ap, format); - cimg_vsnprintf(tmp,sizeof(tmp),format,ap); + cimg_vsnprintf(tmp,1024,format,ap); va_end(ap); - if (!std::strcmp(_title,tmp)) return *this; + if (!std::strcmp(_title,tmp)) { delete[] tmp; return *this; } delete[] _title; const unsigned int s = std::strlen(tmp) + 1; _title = new char[s]; std::memcpy(_title,tmp,s*sizeof(char)); Display *const dpy = cimg::X11_attr().display; - XLockDisplay(dpy); + cimg_lock_display(); XStoreName(dpy,_window,tmp); - XUnlockDisplay(dpy); + cimg_unlock_display(); + delete[] tmp; return *this; } @@ -8260,10 +7770,9 @@ namespace cimg_library_suffixed { CImgDisplay& paint(const bool wait_expose=true) { if (is_empty()) return *this; - Display *const dpy = cimg::X11_attr().display; - XLockDisplay(dpy); + cimg_lock_display(); _paint(wait_expose); - XUnlockDisplay(dpy); + cimg_unlock_display(); return *this; } @@ -8274,7 +7783,8 @@ namespace cimg_library_suffixed { "render(): Empty specified image.", cimgdisplay_instance); if (is_empty()) return *this; - if (img._depth!=1) return render(img.get_projections2d((img._width-1)/2,(img._height-1)/2,(img._depth-1)/2)); + if (img._depth!=1) return render(img.get_projections2d((img._width - 1)/2,(img._height - 1)/2, + (img._depth - 1)/2)); if (cimg::X11_attr().nb_bits==8 && (img._width!=_width || img._height!=_height)) return render(img.get_resize(_width,_height,1,-100,1)); if (cimg::X11_attr().nb_bits==8 && !flag8 && img._spectrum==3) { @@ -8282,78 +7792,95 @@ namespace cimg_library_suffixed { return render(img.get_index(default_colormap,1,false)); } - Display *const dpy = cimg::X11_attr().display; const T *data1 = img._data, *data2 = (img._spectrum>1)?img.data(0,0,0,1):data1, *data3 = (img._spectrum>2)?img.data(0,0,0,2):data1; if (cimg::X11_attr().is_blue_first) cimg::swap(data1,data3); - XLockDisplay(dpy); + cimg_lock_display(); if (!_normalization || (_normalization==3 && cimg::type::string()==cimg::type::string())) { _min = _max = 0; switch (cimg::X11_attr().nb_bits) { case 8 : { // 256 colormap, no normalization _set_colormap(_colormap,img._spectrum); - unsigned char *const ndata = (img._width==_width && img._height==_height)?(unsigned char*)_data:new unsigned char[(unsigned long)img._width*img._height]; - unsigned char *ptrd = (unsigned char*)ndata; + unsigned char + *const ndata = (img._width==_width && img._height==_height)?(unsigned char*)_data: + new unsigned char[(unsigned long)img._width*img._height], + *ptrd = (unsigned char*)ndata; switch (img._spectrum) { - case 1 : for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) (*ptrd++) = (unsigned char)*(data1++); + case 1 : + for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) + (*ptrd++) = (unsigned char)*(data1++); break; case 2 : for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++); - (*ptrd++) = (R&0xf0) | (G>>4); - } break; + const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++); + (*ptrd++) = (R&0xf0) | (G>>4); + } break; default : for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++), B = (unsigned char)*(data3++); - (*ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6); - } + const unsigned char + R = (unsigned char)*(data1++), + G = (unsigned char)*(data2++), + B = (unsigned char)*(data3++); + (*ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6); + } + } + if (ndata!=_data) { + _render_resize(ndata,img._width,img._height,(unsigned char*)_data,_width,_height); + delete[] ndata; } - if (ndata!=_data) { _render_resize(ndata,img._width,img._height,(unsigned char*)_data,_width,_height); delete[] ndata; } } break; case 16 : { // 16 bits colors, no normalization - unsigned short *const ndata = (img._width==_width && img._height==_height)?(unsigned short*)_data:new unsigned short[(unsigned long)img._width*img._height]; + unsigned short *const ndata = (img._width==_width && img._height==_height)?(unsigned short*)_data: + new unsigned short[(unsigned long)img._width*img._height]; unsigned char *ptrd = (unsigned char*)ndata; const unsigned int M = 248; switch (img._spectrum) { case 1 : - if (cimg::X11_attr().byte_order) for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - const unsigned char val = (unsigned char)*(data1++), G = val>>2; - *(ptrd++) = (val&M) | (G>>3); - *(ptrd++) = (G<<5) | (G>>1); + if (cimg::X11_attr().byte_order) + for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { + const unsigned char val = (unsigned char)*(data1++), G = val>>2; + *(ptrd++) = (val&M) | (G>>3); + *(ptrd++) = (G<<5) | (G>>1); } else for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - const unsigned char val = (unsigned char)*(data1++), G = val>>2; - *(ptrd++) = (G<<5) | (G>>1); - *(ptrd++) = (val&M) | (G>>3); - } + const unsigned char val = (unsigned char)*(data1++), G = val>>2; + *(ptrd++) = (G<<5) | (G>>1); + *(ptrd++) = (val&M) | (G>>3); + } break; case 2 : - if (cimg::X11_attr().byte_order) for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - const unsigned char G = (unsigned char)*(data2++)>>2; - *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3); - *(ptrd++) = (G<<5); + if (cimg::X11_attr().byte_order) + for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { + const unsigned char G = (unsigned char)*(data2++)>>2; + *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3); + *(ptrd++) = (G<<5); } else for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - const unsigned char G = (unsigned char)*(data2++)>>2; - *(ptrd++) = (G<<5); - *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3); - } + const unsigned char G = (unsigned char)*(data2++)>>2; + *(ptrd++) = (G<<5); + *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3); + } break; default : - if (cimg::X11_attr().byte_order) for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - const unsigned char G = (unsigned char)*(data2++)>>2; - *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3); - *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3); + if (cimg::X11_attr().byte_order) + for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { + const unsigned char G = (unsigned char)*(data2++)>>2; + *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3); + *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3); } else for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - const unsigned char G = (unsigned char)*(data2++)>>2; - *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3); - *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3); - } + const unsigned char G = (unsigned char)*(data2++)>>2; + *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3); + *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3); + } + } + if (ndata!=_data) { + _render_resize(ndata,img._width,img._height,(unsigned short*)_data,_width,_height); + delete[] ndata; } - if (ndata!=_data) { _render_resize(ndata,img._width,img._height,(unsigned short*)_data,_width,_height); delete[] ndata; } } break; default : { // 24 bits colors, no normalization - unsigned int *const ndata = (img._width==_width && img._height==_height)?(unsigned int*)_data:new unsigned int[(unsigned long)img._width*img._height]; + unsigned int *const ndata = (img._width==_width && img._height==_height)?(unsigned int*)_data: + new unsigned int[(unsigned long)img._width*img._height]; if (sizeof(int)==4) { // 32 bits int uses optimized version unsigned int *ptrd = ndata; switch (img._spectrum) { @@ -8380,26 +7907,29 @@ namespace cimg_library_suffixed { default : if (cimg::X11_attr().byte_order==cimg::endianness()) for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) - *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++); + *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | + (unsigned char)*(data3++); else for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) - *(ptrd++) = ((unsigned char)*(data3++)<<24) | ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8); + *(ptrd++) = ((unsigned char)*(data3++)<<24) | ((unsigned char)*(data2++)<<16) | + ((unsigned char)*(data1++)<<8); } } else { unsigned char *ptrd = (unsigned char*)ndata; switch (img._spectrum) { case 1 : - if (cimg::X11_attr().byte_order) for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - *(ptrd++) = 0; - *(ptrd++) = (unsigned char)*(data1++); - *(ptrd++) = 0; - *(ptrd++) = 0; + if (cimg::X11_attr().byte_order) + for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { + *(ptrd++) = 0; + *(ptrd++) = (unsigned char)*(data1++); + *(ptrd++) = 0; + *(ptrd++) = 0; } else for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - *(ptrd++) = 0; - *(ptrd++) = 0; - *(ptrd++) = (unsigned char)*(data1++); - *(ptrd++) = 0; - } + *(ptrd++) = 0; + *(ptrd++) = 0; + *(ptrd++) = (unsigned char)*(data1++); + *(ptrd++) = 0; + } break; case 2 : if (cimg::X11_attr().byte_order) cimg::swap(data1,data2); @@ -8411,20 +7941,24 @@ namespace cimg_library_suffixed { } break; default : - if (cimg::X11_attr().byte_order) for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - *(ptrd++) = 0; - *(ptrd++) = (unsigned char)*(data1++); - *(ptrd++) = (unsigned char)*(data2++); - *(ptrd++) = (unsigned char)*(data3++); + if (cimg::X11_attr().byte_order) + for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { + *(ptrd++) = 0; + *(ptrd++) = (unsigned char)*(data1++); + *(ptrd++) = (unsigned char)*(data2++); + *(ptrd++) = (unsigned char)*(data3++); } else for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - *(ptrd++) = (unsigned char)*(data3++); - *(ptrd++) = (unsigned char)*(data2++); - *(ptrd++) = (unsigned char)*(data1++); - *(ptrd++) = 0; - } + *(ptrd++) = (unsigned char)*(data3++); + *(ptrd++) = (unsigned char)*(data2++); + *(ptrd++) = (unsigned char)*(data1++); + *(ptrd++) = 0; + } } } - if (ndata!=_data) { _render_resize(ndata,img._width,img._height,(unsigned int*)_data,_width,_height); delete[] ndata; } + if (ndata!=_data) { + _render_resize(ndata,img._width,img._height,(unsigned int*)_data,_width,_height); + delete[] ndata; + } } } } else { @@ -8436,84 +7970,96 @@ namespace cimg_library_suffixed { switch (cimg::X11_attr().nb_bits) { case 8 : { // 256 colormap, with normalization _set_colormap(_colormap,img._spectrum); - unsigned char *const ndata = (img._width==_width && img._height==_height)?(unsigned char*)_data:new unsigned char[(unsigned long)img._width*img._height]; + unsigned char *const ndata = (img._width==_width && img._height==_height)?(unsigned char*)_data: + new unsigned char[(unsigned long)img._width*img._height]; unsigned char *ptrd = (unsigned char*)ndata; switch (img._spectrum) { case 1 : for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - const unsigned char R = (unsigned char)((*(data1++)-_min)*mm); + const unsigned char R = (unsigned char)((*(data1++) - _min)*mm); *(ptrd++) = R; } break; case 2 : for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { const unsigned char - R = (unsigned char)((*(data1++)-_min)*mm), - G = (unsigned char)((*(data2++)-_min)*mm); + R = (unsigned char)((*(data1++) - _min)*mm), + G = (unsigned char)((*(data2++) - _min)*mm); (*ptrd++) = (R&0xf0) | (G>>4); } break; default : for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { const unsigned char - R = (unsigned char)((*(data1++)-_min)*mm), - G = (unsigned char)((*(data2++)-_min)*mm), - B = (unsigned char)((*(data3++)-_min)*mm); + R = (unsigned char)((*(data1++) - _min)*mm), + G = (unsigned char)((*(data2++) - _min)*mm), + B = (unsigned char)((*(data3++) - _min)*mm); *(ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6); } } - if (ndata!=_data) { _render_resize(ndata,img._width,img._height,(unsigned char*)_data,_width,_height); delete[] ndata; } + if (ndata!=_data) { + _render_resize(ndata,img._width,img._height,(unsigned char*)_data,_width,_height); + delete[] ndata; + } } break; case 16 : { // 16 bits colors, with normalization - unsigned short *const ndata = (img._width==_width && img._height==_height)?(unsigned short*)_data:new unsigned short[(unsigned long)img._width*img._height]; + unsigned short *const ndata = (img._width==_width && img._height==_height)?(unsigned short*)_data: + new unsigned short[(unsigned long)img._width*img._height]; unsigned char *ptrd = (unsigned char*)ndata; const unsigned int M = 248; switch (img._spectrum) { case 1 : - if (cimg::X11_attr().byte_order) for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - const unsigned char val = (unsigned char)((*(data1++)-_min)*mm), G = val>>2; - *(ptrd++) = (val&M) | (G>>3); - *(ptrd++) = (G<<5) | (val>>3); + if (cimg::X11_attr().byte_order) + for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { + const unsigned char val = (unsigned char)((*(data1++) - _min)*mm), G = val>>2; + *(ptrd++) = (val&M) | (G>>3); + *(ptrd++) = (G<<5) | (val>>3); } else for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - const unsigned char val = (unsigned char)((*(data1++)-_min)*mm), G = val>>2; - *(ptrd++) = (G<<5) | (val>>3); - *(ptrd++) = (val&M) | (G>>3); - } + const unsigned char val = (unsigned char)((*(data1++) - _min)*mm), G = val>>2; + *(ptrd++) = (G<<5) | (val>>3); + *(ptrd++) = (val&M) | (G>>3); + } break; case 2 : - if (cimg::X11_attr().byte_order) for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - const unsigned char G = (unsigned char)((*(data2++)-_min)*mm)>>2; - *(ptrd++) = ((unsigned char)((*(data1++)-_min)*mm)&M) | (G>>3); - *(ptrd++) = (G<<5); + if (cimg::X11_attr().byte_order) + for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { + const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2; + *(ptrd++) = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3); + *(ptrd++) = (G<<5); } else for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - const unsigned char G = (unsigned char)((*(data2++)-_min)*mm)>>2; - *(ptrd++) = (G<<5); - *(ptrd++) = ((unsigned char)((*(data1++)-_min)*mm)&M) | (G>>3); - } + const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2; + *(ptrd++) = (G<<5); + *(ptrd++) = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3); + } break; default : - if (cimg::X11_attr().byte_order) for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - const unsigned char G = (unsigned char)((*(data2++)-_min)*mm)>>2; - *(ptrd++) = ((unsigned char)((*(data1++)-_min)*mm)&M) | (G>>3); - *(ptrd++) = (G<<5) | ((unsigned char)((*(data3++)-_min)*mm)>>3); + if (cimg::X11_attr().byte_order) + for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { + const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2; + *(ptrd++) = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3); + *(ptrd++) = (G<<5) | ((unsigned char)((*(data3++) - _min)*mm)>>3); } else for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - const unsigned char G = (unsigned char)((*(data2++)-_min)*mm)>>2; - *(ptrd++) = (G<<5) | ((unsigned char)((*(data3++)-_min)*mm)>>3); - *(ptrd++) = ((unsigned char)((*(data1++)-_min)*mm)&M) | (G>>3); - } + const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2; + *(ptrd++) = (G<<5) | ((unsigned char)((*(data3++) - _min)*mm)>>3); + *(ptrd++) = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3); + } + } + if (ndata!=_data) { + _render_resize(ndata,img._width,img._height,(unsigned short*)_data,_width,_height); + delete[] ndata; } - if (ndata!=_data) { _render_resize(ndata,img._width,img._height,(unsigned short*)_data,_width,_height); delete[] ndata; } } break; default : { // 24 bits colors, with normalization - unsigned int *const ndata = (img._width==_width && img._height==_height)?(unsigned int*)_data:new unsigned int[(unsigned long)img._width*img._height]; + unsigned int *const ndata = (img._width==_width && img._height==_height)?(unsigned int*)_data: + new unsigned int[(unsigned long)img._width*img._height]; if (sizeof(int)==4) { // 32 bits int uses optimized version unsigned int *ptrd = ndata; switch (img._spectrum) { case 1 : if (cimg::X11_attr().byte_order==cimg::endianness()) for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - const unsigned char val = (unsigned char)((*(data1++)-_min)*mm); + const unsigned char val = (unsigned char)((*(data1++) - _min)*mm); *(ptrd++) = (val<<16) | (val<<8) | val; } else for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - const unsigned char val = (unsigned char)((*(data1++)-_min)*mm); + const unsigned char val = (unsigned char)((*(data1++) - _min)*mm); *(ptrd++) = (val<<24) | (val<<16) | (val<<8); } break; @@ -8521,52 +8067,53 @@ namespace cimg_library_suffixed { if (cimg::X11_attr().byte_order==cimg::endianness()) for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) *(ptrd++) = - ((unsigned char)((*(data1++)-_min)*mm)<<16) | - ((unsigned char)((*(data2++)-_min)*mm)<<8); + ((unsigned char)((*(data1++) - _min)*mm)<<16) | + ((unsigned char)((*(data2++) - _min)*mm)<<8); else for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) *(ptrd++) = - ((unsigned char)((*(data2++)-_min)*mm)<<16) | - ((unsigned char)((*(data1++)-_min)*mm)<<8); + ((unsigned char)((*(data2++) - _min)*mm)<<16) | + ((unsigned char)((*(data1++) - _min)*mm)<<8); break; default : if (cimg::X11_attr().byte_order==cimg::endianness()) for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) *(ptrd++) = - ((unsigned char)((*(data1++)-_min)*mm)<<16) | - ((unsigned char)((*(data2++)-_min)*mm)<<8) | - (unsigned char)((*(data3++)-_min)*mm); + ((unsigned char)((*(data1++) - _min)*mm)<<16) | + ((unsigned char)((*(data2++) - _min)*mm)<<8) | + (unsigned char)((*(data3++) - _min)*mm); else for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) *(ptrd++) = - ((unsigned char)((*(data3++)-_min)*mm)<<24) | - ((unsigned char)((*(data2++)-_min)*mm)<<16) | - ((unsigned char)((*(data1++)-_min)*mm)<<8); + ((unsigned char)((*(data3++) - _min)*mm)<<24) | + ((unsigned char)((*(data2++) - _min)*mm)<<16) | + ((unsigned char)((*(data1++) - _min)*mm)<<8); } } else { unsigned char *ptrd = (unsigned char*)ndata; switch (img._spectrum) { case 1 : - if (cimg::X11_attr().byte_order) for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - const unsigned char val = (unsigned char)((*(data1++)-_min)*mm); - (*ptrd++) = 0; - (*ptrd++) = val; - (*ptrd++) = val; - (*ptrd++) = val; + if (cimg::X11_attr().byte_order) + for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { + const unsigned char val = (unsigned char)((*(data1++) - _min)*mm); + (*ptrd++) = 0; + (*ptrd++) = val; + (*ptrd++) = val; + (*ptrd++) = val; } else for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - const unsigned char val = (unsigned char)((*(data1++)-_min)*mm); - (*ptrd++) = val; - (*ptrd++) = val; - (*ptrd++) = val; - (*ptrd++) = 0; - } + const unsigned char val = (unsigned char)((*(data1++) - _min)*mm); + (*ptrd++) = val; + (*ptrd++) = val; + (*ptrd++) = val; + (*ptrd++) = 0; + } break; case 2 : if (cimg::X11_attr().byte_order) cimg::swap(data1,data2); for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { (*ptrd++) = 0; - (*ptrd++) = (unsigned char)((*(data2++)-_min)*mm); - (*ptrd++) = (unsigned char)((*(data1++)-_min)*mm); + (*ptrd++) = (unsigned char)((*(data2++) - _min)*mm); + (*ptrd++) = (unsigned char)((*(data1++) - _min)*mm); (*ptrd++) = 0; } break; @@ -8574,24 +8121,25 @@ namespace cimg_library_suffixed { if (cimg::X11_attr().byte_order) for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { (*ptrd++) = 0; - (*ptrd++) = (unsigned char)((*(data1++)-_min)*mm); - (*ptrd++) = (unsigned char)((*(data2++)-_min)*mm); - (*ptrd++) = (unsigned char)((*(data3++)-_min)*mm); + (*ptrd++) = (unsigned char)((*(data1++) - _min)*mm); + (*ptrd++) = (unsigned char)((*(data2++) - _min)*mm); + (*ptrd++) = (unsigned char)((*(data3++) - _min)*mm); } else for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - (*ptrd++) = (unsigned char)((*(data3++)-_min)*mm); - (*ptrd++) = (unsigned char)((*(data2++)-_min)*mm); - (*ptrd++) = (unsigned char)((*(data1++)-_min)*mm); + (*ptrd++) = (unsigned char)((*(data3++) - _min)*mm); + (*ptrd++) = (unsigned char)((*(data2++) - _min)*mm); + (*ptrd++) = (unsigned char)((*(data1++) - _min)*mm); (*ptrd++) = 0; } } } if (ndata!=_data) { - _render_resize(ndata,img._width,img._height,(unsigned int*)_data,_width,_height); delete[] ndata; + _render_resize(ndata,img._width,img._height,(unsigned int*)_data,_width,_height); + delete[] ndata; } - } + } } } - XUnlockDisplay(dpy); + cimg_unlock_display(); return *this; } @@ -8662,7 +8210,7 @@ namespace cimg_library_suffixed { mode.dmSize = sizeof(DEVMODE); mode.dmDriverExtra = 0; EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode); - return mode.dmPelsWidth; + return (int)mode.dmPelsWidth; } static int screen_height() { @@ -8670,7 +8218,7 @@ namespace cimg_library_suffixed { mode.dmSize = sizeof(DEVMODE); mode.dmDriverExtra = 0; EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode); - return mode.dmPelsHeight; + return (int)mode.dmPelsHeight; } static void wait_all() { @@ -8721,7 +8269,10 @@ namespace cimg_library_suffixed { } break; case WM_PAINT : disp->paint(); - if (disp->_is_cursor_visible) while (ShowCursor(TRUE)<0); else while (ShowCursor(FALSE)>=0); + if (disp->_is_cursor_visible) while (ShowCursor(TRUE)<0); else while (ShowCursor(FALSE)>=0); + break; + case WM_ERASEBKGND : + // return 0; break; case WM_KEYDOWN : disp->set_key((unsigned int)wParam); @@ -8748,12 +8299,12 @@ namespace cimg_library_suffixed { disp->_mouse_x = disp->_mouse_y = -1; disp->_is_event = true; SetEvent(cimg::Win32_attr().wait_event); - if (disp->_is_cursor_visible) while (ShowCursor(TRUE)<0); else while (ShowCursor(FALSE)>=0); - } break; + if (disp->_is_cursor_visible) while (ShowCursor(TRUE)<0); else while (ShowCursor(FALSE)>=0); + } break; case WM_MOUSELEAVE : { disp->_mouse_x = disp->_mouse_y = -1; disp->_is_mouse_tracked = false; - while (ShowCursor(TRUE)<0); + while (ShowCursor(TRUE)<0); } break; case WM_LBUTTONDOWN : disp->set_button(1); @@ -8805,11 +8356,11 @@ namespace cimg_library_suffixed { disp->_data = new unsigned int[(unsigned long)disp->_width*disp->_height]; if (!disp->_is_fullscreen) { // Normal window RECT rect; - rect.left = rect.top = 0; rect.right = disp->_width-1; rect.bottom = disp->_height-1; + 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 = (rect.right - rect.left + 1 - disp->_width)/2, - border2 = rect.bottom - rect.top + 1 - disp->_height - border1; + 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, @@ -8820,10 +8371,13 @@ namespace cimg_library_suffixed { disp->_window_y = rect.top + border2; } else disp->_window_x = disp->_window_y = 0; } else { // Fullscreen window - const unsigned int sx = screen_width(), sy = screen_height(); + 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, + 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; } @@ -8848,11 +8402,11 @@ namespace cimg_library_suffixed { if (_is_closed) _window_x = _window_y = -1; else { RECT rect; - rect.left = rect.top = 0; rect.right = _width-1; rect.bottom = _height-1; + rect.left = rect.top = 0; rect.right = (LONG)_width - 1; rect.bottom = (LONG)_height - 1; AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); const int - border1 = (rect.right - rect.left + 1 - _width)/2, - border2 = rect.bottom - rect.top + 1 - _height - border1; + border1 = (int)((rect.right - rect.left + 1 - _width)/2), + border2 = (int)(rect.bottom - rect.top + 1 - _height - border1); GetWindowRect(_window,&rect); _window_x = rect.left + border1; _window_y = rect.top + border2; @@ -8881,7 +8435,9 @@ namespace cimg_library_suffixed { ChangeDisplaySettings(&mode,0); } else _curr_mode.dmSize = 0; - const unsigned int sx = screen_width(), sy = screen_height(); + const unsigned int + sx = (unsigned int)screen_width(), + sy = (unsigned int)screen_height(); if (sx!=_width || sy!=_height) { CLIENTCREATESTRUCT background_ccs; _background_window = CreateWindowA("MDICLIENT","",WS_POPUP | WS_VISIBLE, 0,0,sx,sy,0,0,0,&background_ccs); @@ -8970,9 +8526,9 @@ namespace cimg_library_suffixed { const bool fullscreen_flag=false, const bool closed_flag=false) { if (!img) return assign(); CImg tmp; - const CImg& nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width-1)/2, - (img._height-1)/2, - (img._depth-1)/2)); + const CImg& nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width - 1)/2, + (img._height - 1)/2, + (img._depth - 1)/2)); _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag); if (_normalization==2) _min = (float)nimg.min_max(_max); return display(nimg); @@ -8984,9 +8540,9 @@ namespace cimg_library_suffixed { const bool fullscreen_flag=false, const bool closed_flag=false) { if (!list) return assign(); CImg tmp; - const CImg img = list>'x', &nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width-1)/2, - (img._height-1)/2, - (img._depth-1)/2)); + const CImg img = list>'x', &nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width - 1)/2, + (img._height - 1)/2, + (img._depth - 1)/2)); _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag); if (_normalization==2) _min = (float)nimg.min_max(_max); return display(nimg); @@ -9008,7 +8564,7 @@ namespace cimg_library_suffixed { dimx = tmpdimx?tmpdimx:1, dimy = tmpdimy?tmpdimy:1; if (_window_width!=dimx || _window_height!=dimy) { - RECT rect; rect.left = rect.top = 0; rect.right = dimx - 1; rect.bottom = dimy - 1; + RECT rect; rect.left = rect.top = 0; rect.right = (LONG)dimx - 1; rect.bottom = (LONG)dimy - 1; AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); const int cwidth = rect.right - rect.left + 1, cheight = rect.bottom - rect.top + 1; SetWindowPos(_window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS); @@ -9019,14 +8575,14 @@ namespace cimg_library_suffixed { else std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy); delete[] _data; _data = ndata; - _bmi.bmiHeader.biWidth = dimx; + _bmi.bmiHeader.biWidth = (LONG)dimx; _bmi.bmiHeader.biHeight = -(int)dimy; _width = dimx; _height = dimy; } _window_width = dimx; _window_height = dimy; _is_resized = false; - if (_is_fullscreen) move((screen_width()-_width)/2,(screen_height()-_height)/2); + if (_is_fullscreen) move((screen_width() - width())/2,(screen_height() - height())/2); if (force_redraw) return paint(); return *this; } @@ -9036,10 +8592,12 @@ namespace cimg_library_suffixed { if (force_redraw) { const unsigned long buf_size = _width*_height*4UL; void *odata = std::malloc(buf_size); - std::memcpy(odata,_data,buf_size); - assign(_width,_height,_title,_normalization,!_is_fullscreen,false); - std::memcpy(_data,odata,buf_size); - std::free(odata); + if (odata) { + std::memcpy(odata,_data,buf_size); + assign(_width,_height,_title,_normalization,!_is_fullscreen,false); + std::memcpy(_data,odata,buf_size); + std::free(odata); + } return paint(); } return assign(_width,_height,_title,_normalization,!_is_fullscreen,false); @@ -9066,10 +8624,13 @@ namespace cimg_library_suffixed { CImgDisplay& move(const int posx, const int posy) { if (is_empty()) return *this; if (!_is_fullscreen) { - RECT rect; rect.left = rect.top = 0; rect.right = _window_width-1; rect.bottom = _window_height-1; + RECT rect; + rect.left = rect.top = 0; rect.right = (LONG)_window_width - 1; rect.bottom = (LONG)_window_height - 1; AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); - const int border1 = (rect.right-rect.left+1-_width)/2, border2 = rect.bottom-rect.top+1-_height-border1; - SetWindowPos(_window,0,posx-border1,posy-border2,0,0,SWP_NOSIZE | SWP_NOZORDER); + const int + border1 = (int)((rect.right - rect.left + 1 -_width)/2), + border2 = (int)(rect.bottom - rect.top + 1 - _height - border1); + SetWindowPos(_window,0,posx - border1,posy - border2,0,0,SWP_NOSIZE | SWP_NOZORDER); } else SetWindowPos(_window,0,posx,posy,0,0,SWP_NOSIZE | SWP_NOZORDER); _window_x = posx; _window_y = posy; @@ -9099,17 +8660,18 @@ namespace cimg_library_suffixed { CImgDisplay& set_title(const char *const format, ...) { if (is_empty()) return *this; - char tmp[1024] = { 0 }; + char *const tmp = new char[1024]; va_list ap; va_start(ap, format); - cimg_vsnprintf(tmp,sizeof(tmp),format,ap); + cimg_vsnprintf(tmp,1024,format,ap); va_end(ap); - if (!std::strcmp(_title,tmp)) return *this; + if (!std::strcmp(_title,tmp)) { delete[] tmp; return *this; } delete[] _title; const unsigned int s = (unsigned int)std::strlen(tmp) + 1; _title = new char[s]; std::memcpy(_title,tmp,s*sizeof(char)); SetWindowTextA(_window, tmp); + delete[] tmp; return *this; } @@ -9139,7 +8701,8 @@ namespace cimg_library_suffixed { cimgdisplay_instance); if (is_empty()) return *this; - if (img._depth!=1) return render(img.get_projections2d((img._width-1)/2,(img._height-1)/2,(img._depth-1)/2)); + if (img._depth!=1) return render(img.get_projections2d((img._width - 1)/2,(img._height - 1)/2, + (img._depth - 1)/2)); const T *data1 = img._data, @@ -9158,16 +8721,25 @@ namespace cimg_library_suffixed { case 1 : { for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { const unsigned char val = (unsigned char)*(data1++); - *(ptrd++) = (val<<16) | (val<<8) | val; + *(ptrd++) = (unsigned int)((val<<16) | (val<<8) | val); } } break; case 2 : { - for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) - *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8); + for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { + const unsigned char + R = (unsigned char)*(data1++), + G = (unsigned char)*(data2++); + *(ptrd++) = (unsigned int)((R<<16) | (G<<8)); + } } break; default : { - for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) - *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++); + for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { + const unsigned char + R = (unsigned char)*(data1++), + G = (unsigned char)*(data2++), + B = (unsigned char)*(data3++); + *(ptrd++) = (unsigned int)((R<<16) | (G<<8) | B); + } } } } else { @@ -9179,25 +8751,25 @@ namespace cimg_library_suffixed { switch (img._spectrum) { case 1 : { for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { - const unsigned char val = (unsigned char)((*(data1++)-_min)*mm); - *(ptrd++) = (val<<16) | (val<<8) | val; + const unsigned char val = (unsigned char)((*(data1++) - _min)*mm); + *(ptrd++) = (unsigned int)((val<<16) | (val<<8) | val); } } break; case 2 : { for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { const unsigned char - R = (unsigned char)((*(data1++)-_min)*mm), - G = (unsigned char)((*(data2++)-_min)*mm); - *(ptrd++) = (R<<16) | (G<<8); + R = (unsigned char)((*(data1++) - _min)*mm), + G = (unsigned char)((*(data2++) - _min)*mm); + *(ptrd++) = (unsigned int)((R<<16) | (G<<8)); } } break; default : { for (unsigned long xy = (unsigned long)img._width*img._height; xy>0; --xy) { const unsigned char - R = (unsigned char)((*(data1++)-_min)*mm), - G = (unsigned char)((*(data2++)-_min)*mm), - B = (unsigned char)((*(data3++)-_min)*mm); - *(ptrd++) = (R<<16) | (G<<8) | B; + R = (unsigned char)((*(data1++) - _min)*mm), + G = (unsigned char)((*(data2++) - _min)*mm), + B = (unsigned char)((*(data3++) - _min)*mm); + *(ptrd++) = (unsigned int)((R<<16) | (G<<8) | B); } } } @@ -9536,7 +9108,7 @@ namespace cimg_library_suffixed { For this task, you may use fillC() after construction. **/ CImg(const unsigned int size_x, const unsigned int size_y, - const unsigned int size_z, const unsigned int size_c, const T value): + const unsigned int size_z, const unsigned int size_c, const T& value): _is_shared(false) { const unsigned long siz = (unsigned long)size_x*size_y*size_z*size_c; if (siz) { @@ -9585,18 +9157,18 @@ namespace cimg_library_suffixed { const int value0, const int value1, ...): _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { #define _CImg_stdarg(img,a0,a1,N,t) { \ - unsigned long _siz = (unsigned long)N; \ - if (_siz--) { \ - va_list ap; \ - va_start(ap,a1); \ - T *ptrd = (img)._data; \ - *(ptrd++) = (T)a0; \ - if (_siz--) { \ - *(ptrd++) = (T)a1; \ - for (; _siz; --_siz) *(ptrd++) = (T)va_arg(ap,t); \ - } \ - va_end(ap); \ - } \ + unsigned long _siz = (unsigned long)N; \ + if (_siz--) { \ + va_list ap; \ + va_start(ap,a1); \ + T *ptrd = (img)._data; \ + *(ptrd++) = (T)a0; \ + if (_siz--) { \ + *(ptrd++) = (T)a1; \ + for (; _siz; --_siz) *(ptrd++) = (T)va_arg(ap,t); \ + } \ + va_end(ap); \ + } \ } assign(size_x,size_y,size_z,size_c); _CImg_stdarg(*this,value0,value1,(unsigned long)size_x*size_y*size_z*size_c,int); @@ -9631,7 +9203,7 @@ namespace cimg_library_suffixed { template CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c, const std::initializer_list values, - const bool repeat_values=true): + const bool repeat_values=true): _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { #define _cimg_constructor_cpp11(repeat_values) \ auto it = values.begin(); \ @@ -9646,7 +9218,7 @@ namespace cimg_library_suffixed { template CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, std::initializer_list values, - const bool repeat_values=true): + const bool repeat_values=true): _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { assign(size_x,size_y,size_z); _cimg_constructor_cpp11(repeat_values); @@ -9655,7 +9227,7 @@ namespace cimg_library_suffixed { template CImg(const unsigned int size_x, const unsigned int size_y, std::initializer_list values, - const bool repeat_values=true): + const bool repeat_values=true): _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { assign(size_x,size_y); _cimg_constructor_cpp11(repeat_values); @@ -9762,7 +9334,7 @@ namespace cimg_library_suffixed { \image html ref_constructor2.jpg **/ CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c, - const char *const values, const bool repeat_values):_is_shared(false) { + const char *const values, const bool repeat_values):_is_shared(false) { const unsigned long siz = (unsigned long)size_x*size_y*size_z*size_c; if (siz) { _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; @@ -10036,7 +9608,7 @@ namespace cimg_library_suffixed { - Similar to CImg(const CImg&,const char*), but it also fills the pixel buffer with the specified \c value. **/ template - CImg(const CImg& img, const char *const dimensions, const T value): + CImg(const CImg& img, const char *const dimensions, const T& value): _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { assign(img,dimensions).fill(value); } @@ -10087,13 +9659,13 @@ namespace cimg_library_suffixed { if (!siz) return assign(); const unsigned long curr_siz = size(); if (siz!=curr_siz) { - if (_is_shared) + if (_is_shared) throw CImgArgumentException(_cimg_instance "assign(): Invalid assignement request of shared instance from specified " "image (%u,%u,%u,%u).", cimg_instance, size_x,size_y,size_z,size_c); - else { + else { delete[] _data; try { _data = new T[siz]; } catch (...) { _width = _height = _depth = _spectrum = 0; _data = 0; @@ -10114,7 +9686,7 @@ namespace cimg_library_suffixed { In-place version of the constructor CImg(unsigned int,unsigned int,unsigned int,unsigned int,T). **/ CImg& assign(const unsigned int size_x, const unsigned int size_y, - const unsigned int size_z, const unsigned int size_c, const T value) { + const unsigned int size_z, const unsigned int size_c, const T& value) { return assign(size_x,size_y,size_z,size_c).fill(value); } @@ -10173,7 +9745,7 @@ namespace cimg_library_suffixed { if (!values || !siz) return assign(); const unsigned long curr_siz = size(); if (values==_data && siz==curr_siz) return assign(size_x,size_y,size_z,size_c); - if (_is_shared || values+siz<_data || values>=_data+size()) { + if (_is_shared || values + siz<_data || values>=_data + size()) { assign(size_x,size_y,size_z,size_c); if (_is_shared) std::memmove(_data,values,siz*sizeof(T)); else std::memcpy(_data,values,siz*sizeof(T)); @@ -10210,24 +9782,17 @@ namespace cimg_library_suffixed { CImg& assign(const T *const values, const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c, const bool is_shared) { const unsigned long siz = (unsigned long)size_x*size_y*size_z*size_c; - if (!values || !siz) { - if (is_shared) - throw CImgArgumentException(_cimg_instance - "assign(): Invalid assignment request of shared instance from (null) or " - "empty buffer.", - cimg_instance); - else return assign(); - } + if (!values || !siz) return assign(); if (!is_shared) { if (_is_shared) assign(); assign(values,size_x,size_y,size_z,size_c); } else { - if (!_is_shared) { - if (values+siz<_data || values>=_data+size()) assign(); - else cimg::warn(_cimg_instance + if (!_is_shared) { + if (values + siz<_data || values>=_data + size()) assign(); + else cimg::warn(_cimg_instance "assign(): Shared image instance has overlapping memory.", cimg_instance); - } - _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; _is_shared = true; - _data = const_cast(values); + } + _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; _is_shared = true; + _data = const_cast(values); } return *this; } @@ -10266,12 +9831,12 @@ namespace cimg_library_suffixed { CImg& assign(const CImg& img, const char *const dimensions) { if (!dimensions || !*dimensions) return assign(img._width,img._height,img._depth,img._spectrum); unsigned int siz[4] = { 0,1,1,1 }, k = 0; + CImg item(256); for (const char *s = dimensions; *s && k<4; ++k) { - char item[256] = { 0 }; - if (std::sscanf(s,"%255[^0-9%xyzvwhdcXYZVWHDC]",item)>0) s+=std::strlen(item); + if (cimg_sscanf(s,"%255[^0-9%xyzvwhdcXYZVWHDC]",item._data)>0) s+=std::strlen(item); if (*s) { unsigned int val = 0; char sep = 0; - if (std::sscanf(s,"%u%c",&val,&sep)>0) { + if (cimg_sscanf(s,"%u%c",&val,&sep)>0) { if (sep=='%') siz[k] = val*(k==0?_width:k==1?_height:k==2?_depth:_spectrum)/100; else siz[k] = val; while (*s>='0' && *s<='9') ++s; if (sep=='%') ++s; @@ -10296,7 +9861,7 @@ namespace cimg_library_suffixed { In-place version of the constructor CImg(const CImg&,const char*,T). **/ template - CImg& assign(const CImg& img, const char *const dimensions, const T value) { + CImg& assign(const CImg& img, const char *const dimensions, const T& value) { return assign(img,dimensions).fill(value); } @@ -10430,7 +9995,7 @@ namespace cimg_library_suffixed { \param c C-coordinate of the pixel value. \note - Range of pixel coordinates start from (0,0,0,0) to - (width()-1,height()-1,depth()-1,spectrum()-1). + (width() - 1,height() - 1,depth() - 1,spectrum() - 1). - Due to the particular arrangement of the pixel buffers defined in %CImg, you can omit one coordinate if the corresponding dimension is equal to \c 1. For instance, pixels of a 2d image (depth() equal to \c 1) can be accessed by img(x,y,c) instead of @@ -10598,7 +10163,7 @@ namespace cimg_library_suffixed { img = 1.2; // Set all pixel values to '1' (cast of '1.2' as a 'char'). \endcode **/ - CImg& operator=(const T value) { + CImg& operator=(const T& value) { return fill(value); } @@ -10624,14 +10189,14 @@ namespace cimg_library_suffixed { **/ CImg& operator=(const char *const expression) { const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); try { fill(expression,true); } catch (CImgException&) { - cimg::exception_mode() = omode; + cimg::exception_mode(omode); load(expression); } - cimg::exception_mode() = omode; + cimg::exception_mode(omode); return *this; } @@ -10706,11 +10271,11 @@ namespace cimg_library_suffixed { CImg& operator+=(const char *const expression) { if (is_empty()) return *this; const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); try { const CImg _base = cimg::_is_self_expr(expression)?+*this:CImg(), &base = _base?_base:*this; - _cimg_math_parser mp(base,expression+(*expression=='>' || *expression=='<'?1:0),"operator+="); - T *ptrd = *expression=='<'?end()-1:_data; + _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator+="); + T *ptrd = *expression=='<'?end() - 1:_data; if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd + mp(x,y,z,c)); --ptrd; } else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd + mp(x,y,z,c)); ++ptrd; } else { @@ -10730,10 +10295,10 @@ namespace cimg_library_suffixed { cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd + mp(x,y,z,c)); ++ptrd; } } } catch (CImgException&) { - cimg::exception_mode() = omode; + cimg::exception_mode(omode); *this+=CImg(_width,_height,_depth,_spectrum,expression,true); } - cimg::exception_mode() = omode; + cimg::exception_mode(omode); return *this; } @@ -10805,7 +10370,7 @@ namespace cimg_library_suffixed { - Use this operator to ensure you get a non-shared copy of an image instance with same pixel type \c T. Indeed, the usual copy constructor CImg(const CImg&) returns a shared copy of a shared input image, and it may be not desirable to work on a regular copy (e.g. for a resize operation) if you have no - informations about the shared state of the input image. + information about the shared state of the input image. - Writing \c (+img) is equivalent to \c CImg(img,false). **/ CImg operator+() const { @@ -10862,11 +10427,11 @@ namespace cimg_library_suffixed { CImg& operator-=(const char *const expression) { if (is_empty()) return *this; const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); try { const CImg _base = cimg::_is_self_expr(expression)?+*this:CImg(), &base = _base?_base:*this; - _cimg_math_parser mp(base,expression+(*expression=='>' || *expression=='<'?1:0),"operator-="); - T *ptrd = *expression=='<'?end()-1:_data; + _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator-="); + T *ptrd = *expression=='<'?end() - 1:_data; if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd - mp(x,y,z,c)); --ptrd; } else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd - mp(x,y,z,c)); ++ptrd; } else { @@ -10886,10 +10451,10 @@ namespace cimg_library_suffixed { cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd - mp(x,y,z,c)); ++ptrd; } } } catch (CImgException&) { - cimg::exception_mode() = omode; + cimg::exception_mode(omode); *this-=CImg(_width,_height,_depth,_spectrum,expression,true); } - cimg::exception_mode() = omode; + cimg::exception_mode(omode); return *this; } @@ -10920,7 +10485,7 @@ namespace cimg_library_suffixed { #ifdef cimg_use_openmp #pragma omp parallel for if (size()>=524288) #endif - cimg_rof(*this,ptrd,T) *ptrd = *ptrd-(T)1; + cimg_rof(*this,ptrd,T) *ptrd = *ptrd - (T)1; return *this; } @@ -11002,11 +10567,11 @@ namespace cimg_library_suffixed { CImg& operator*=(const char *const expression) { if (is_empty()) return *this; const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); try { const CImg _base = cimg::_is_self_expr(expression)?+*this:CImg(), &base = _base?_base:*this; - _cimg_math_parser mp(base,expression+(*expression=='>' || *expression=='<'?1:0),"operator*="); - T *ptrd = *expression=='<'?end()-1:_data; + _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator*="); + T *ptrd = *expression=='<'?end() - 1:_data; if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd * mp(x,y,z,c)); --ptrd; } else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd * mp(x,y,z,c)); ++ptrd; } else { @@ -11026,10 +10591,10 @@ namespace cimg_library_suffixed { cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd * mp(x,y,z,c)); ++ptrd; } } } catch (CImgException&) { - cimg::exception_mode() = omode; + cimg::exception_mode(omode); mul(CImg(_width,_height,_depth,_spectrum,expression,true)); } - cimg::exception_mode() = omode; + cimg::exception_mode(omode); return *this; } @@ -11123,11 +10688,11 @@ namespace cimg_library_suffixed { CImg& operator/=(const char *const expression) { if (is_empty()) return *this; const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); try { const CImg _base = cimg::_is_self_expr(expression)?+*this:CImg(), &base = _base?_base:*this; - _cimg_math_parser mp(base,expression+(*expression=='>' || *expression=='<'?1:0),"operator/="); - T *ptrd = *expression=='<'?end()-1:_data; + _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator/="); + T *ptrd = *expression=='<'?end() - 1:_data; if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd / mp(x,y,z,c)); --ptrd; } else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd / mp(x,y,z,c)); ++ptrd; } else { @@ -11147,10 +10712,10 @@ namespace cimg_library_suffixed { cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd / mp(x,y,z,c)); ++ptrd; } } } catch (CImgException&) { - cimg::exception_mode() = omode; + cimg::exception_mode(omode); div(CImg(_width,_height,_depth,_spectrum,expression,true)); } - cimg::exception_mode() = omode; + cimg::exception_mode(omode); return *this; } @@ -11220,11 +10785,11 @@ namespace cimg_library_suffixed { CImg& operator%=(const char *const expression) { if (is_empty()) return *this; const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); try { const CImg _base = cimg::_is_self_expr(expression)?+*this:CImg(), &base = _base?_base:*this; - _cimg_math_parser mp(base,expression+(*expression=='>' || *expression=='<'?1:0),"operator%="); - T *ptrd = *expression=='<'?end()-1:_data; + _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator%="); + T *ptrd = *expression=='<'?end() - 1:_data; if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::mod(*ptrd,(T)mp(x,y,z,c)); --ptrd; } else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::mod(*ptrd,(T)mp(x,y,z,c)); ++ptrd; } else { @@ -11244,10 +10809,10 @@ namespace cimg_library_suffixed { cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::mod(*ptrd,(T)mp(x,y,z,c)); ++ptrd; } } } catch (CImgException&) { - cimg::exception_mode() = omode; + cimg::exception_mode(omode); *this%=CImg(_width,_height,_depth,_spectrum,expression,true); } - cimg::exception_mode() = omode; + cimg::exception_mode(omode); return *this; } @@ -11319,11 +10884,11 @@ namespace cimg_library_suffixed { CImg& operator&=(const char *const expression) { if (is_empty()) return *this; const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); try { const CImg _base = cimg::_is_self_expr(expression)?+*this:CImg(), &base = _base?_base:*this; - _cimg_math_parser mp(base,expression+(*expression=='>' || *expression=='<'?1:0),"operator&="); - T *ptrd = *expression=='<'?end()-1:_data; + _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator&="); + T *ptrd = *expression=='<'?end() - 1:_data; if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd & (unsigned long)mp(x,y,z,c)); --ptrd; } else if (*expression=='>') @@ -11345,10 +10910,10 @@ namespace cimg_library_suffixed { cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd & (unsigned long)mp(x,y,z,c)); ++ptrd; } } } catch (CImgException&) { - cimg::exception_mode() = omode; + cimg::exception_mode(omode); *this&=CImg(_width,_height,_depth,_spectrum,expression,true); } - cimg::exception_mode() = omode; + cimg::exception_mode(omode); return *this; } @@ -11420,11 +10985,11 @@ namespace cimg_library_suffixed { CImg& operator|=(const char *const expression) { if (is_empty()) return *this; const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); try { const CImg _base = cimg::_is_self_expr(expression)?+*this:CImg(), &base = _base?_base:*this; - _cimg_math_parser mp(base,expression+(*expression=='>' || *expression=='<'?1:0),"operator|="); - T *ptrd = *expression=='<'?end()-1:_data; + _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator|="); + T *ptrd = *expression=='<'?end() - 1:_data; if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd | (unsigned long)mp(x,y,z,c)); --ptrd; } else if (*expression=='>') @@ -11446,10 +11011,10 @@ namespace cimg_library_suffixed { cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd | (unsigned long)mp(x,y,z,c)); ++ptrd; } } } catch (CImgException&) { - cimg::exception_mode() = omode; + cimg::exception_mode(omode); *this|=CImg(_width,_height,_depth,_spectrum,expression,true); } - cimg::exception_mode() = omode; + cimg::exception_mode(omode); return *this; } @@ -11525,11 +11090,11 @@ namespace cimg_library_suffixed { CImg& operator^=(const char *const expression) { if (is_empty()) return *this; const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); try { const CImg _base = cimg::_is_self_expr(expression)?+*this:CImg(), &base = _base?_base:*this; - _cimg_math_parser mp(base,expression+(*expression=='>' || *expression=='<'?1:0),"operator^="); - T *ptrd = *expression=='<'?end()-1:_data; + _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator^="); + T *ptrd = *expression=='<'?end() - 1:_data; if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)mp(x,y,z,c)); --ptrd; } else if (*expression=='>') @@ -11551,10 +11116,10 @@ namespace cimg_library_suffixed { cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)mp(x,y,z,c)); ++ptrd; } } } catch (CImgException&) { - cimg::exception_mode() = omode; + cimg::exception_mode(omode); *this^=CImg(_width,_height,_depth,_spectrum,expression,true); } - cimg::exception_mode() = omode; + cimg::exception_mode(omode); return *this; } @@ -11628,11 +11193,11 @@ namespace cimg_library_suffixed { CImg& operator<<=(const char *const expression) { if (is_empty()) return *this; const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); try { const CImg _base = cimg::_is_self_expr(expression)?+*this:CImg(), &base = _base?_base:*this; - _cimg_math_parser mp(base,expression+(*expression=='>' || *expression=='<'?1:0),"operator<<="); - T *ptrd = *expression=='<'?end()-1:_data; + _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator<<="); + T *ptrd = *expression=='<'?end() - 1:_data; if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)((long)*ptrd << (int)mp(x,y,z,c)); --ptrd; } else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((long)*ptrd << (int)mp(x,y,z,c)); ++ptrd; } else { @@ -11652,10 +11217,10 @@ namespace cimg_library_suffixed { cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((long)*ptrd << (int)mp(x,y,z,c)); ++ptrd; } } } catch (CImgException&) { - cimg::exception_mode() = omode; + cimg::exception_mode(omode); *this<<=CImg(_width,_height,_depth,_spectrum,expression,true); } - cimg::exception_mode() = omode; + cimg::exception_mode(omode); return *this; } @@ -11728,11 +11293,11 @@ namespace cimg_library_suffixed { CImg& operator>>=(const char *const expression) { if (is_empty()) return *this; const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); try { const CImg _base = cimg::_is_self_expr(expression)?+*this:CImg(), &base = _base?_base:*this; - _cimg_math_parser mp(base,expression+(*expression=='>' || *expression=='<'?1:0),"operator<<="); - T *ptrd = *expression=='<'?end()-1:_data; + _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator<<="); + T *ptrd = *expression=='<'?end() - 1:_data; if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)((long)*ptrd >> (int)mp(x,y,z,c)); --ptrd; } else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((long)*ptrd >> (int)mp(x,y,z,c)); ++ptrd; } else { @@ -11752,10 +11317,10 @@ namespace cimg_library_suffixed { cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((long)*ptrd >> (int)mp(x,y,z,c)); ++ptrd; } } } catch (CImgException&) { - cimg::exception_mode() = omode; + cimg::exception_mode(omode); *this>>=CImg(_width,_height,_depth,_spectrum,expression,true); } - cimg::exception_mode() = omode; + cimg::exception_mode(omode); return *this; } @@ -11840,22 +11405,22 @@ namespace cimg_library_suffixed { bool operator==(const char *const expression) const { if (is_empty()) return !*expression; const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); bool is_equal = true; try { const CImg _base = cimg::_is_self_expr(expression)?+*this:CImg(), &base = _base?_base:*this; - _cimg_math_parser mp(base,expression+(*expression=='>' || *expression=='<'?1:0),"operator<<="); - const T *ptrs = *expression=='<'?end()-1:_data; + _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator<<="); + const T *ptrs = *expression=='<'?end() - 1:_data; if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { if (!is_equal) break; is_equal = ((double)*(ptrs--)==mp(x,y,z,c)); } else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { if (!is_equal) break; is_equal = ((double)*(ptrs++)==mp(x,y,z,c)); } else cimg_forXYZC(*this,x,y,z,c) { if (!is_equal) break; is_equal = ((double)*(ptrs++)==mp(x,y,z,c)); } } catch (CImgException&) { - cimg::exception_mode() = omode; + cimg::exception_mode(omode); is_equal = (*this==CImg(_width,_height,_depth,_spectrum,expression,true)); } - cimg::exception_mode() = omode; + cimg::exception_mode(omode); return is_equal; } @@ -12103,7 +11668,7 @@ namespace cimg_library_suffixed { \note - The data() of an empty image is equal to \c 0 (null pointer). - The allocated pixel buffer for the image instance starts from \c data() - and goes to data()+\ref size()-1 (included). + and goes to data()+\ref size() - 1 (included). - To get the pointer to one particular location of the pixel buffer, use data(unsigned int,unsigned int,unsigned int,unsigned int) instead. **/ @@ -12172,7 +11737,7 @@ namespace cimg_library_suffixed { \endcode **/ long offset(const int x, const int y=0, const int z=0, const int c=0) const { - return x + y*(long)_width + z*(long)_width*_height + c*(long)_width*_height*_depth; + return x + y*(long)_width + z*(long)(_width*_height) + c*(long)(_width*_height*_depth); } //! Return a CImg::iterator pointing to the first pixel value. @@ -12233,8 +11798,8 @@ namespace cimg_library_suffixed { //! Return a reference to the last pixel value. /** \note - - Writing \c img.end() is equivalent to img[img.size()-1], or - img(img.width()-1,img.height()-1,img.depth()-1,img.spectrum()-1). + - Writing \c img.end() is equivalent to img[img.size() - 1], or + img(img.width() - 1,img.height() - 1,img.depth() - 1,img.spectrum() - 1). - It has been mainly defined for compatibility with STL naming conventions. **/ T& back() { @@ -12259,12 +11824,12 @@ namespace cimg_library_suffixed { - Due to the additional boundary checking operation, this method is slower than operator()(). Use it when you are \e not sure about the validity of the specified pixel offset. **/ - T& at(const int offset, const T out_value) { + T& at(const int offset, const T& out_value) { return (offset<0 || offset>=(int)size())?(cimg::temporary(out_value)=out_value):(*this)[offset]; } //! Access to a pixel value at a specified offset, using Dirichlet boundary conditions \const. - T at(const int offset, const T out_value) const { + T at(const int offset, const T& out_value) const { return (offset<0 || offset>=(int)size())?out_value:(*this)[offset]; } @@ -12277,7 +11842,7 @@ namespace cimg_library_suffixed { - Similar to at(int,const T), except that an out-of-bounds access returns the value of the nearest pixel in the image instance, regarding the specified offset, i.e. - If \c offset<0, then \c img[0] is returned. - - If \c offset>=img.size(), then \c img[img.size()-1] is returned. + - If \c offset>=img.size(), then \c img[img.size() - 1] is returned. - Due to the additional boundary checking operation, this method is slower than operator()(). Use it when you are \e not sure about the validity of the specified pixel offset. - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _at(int). @@ -12292,11 +11857,11 @@ namespace cimg_library_suffixed { T& _at(const int offset) { const unsigned int siz = (unsigned int)size(); - return (*this)[offset<0?0:(unsigned int)offset>=siz?siz-1:offset]; + return (*this)[offset<0?0:(unsigned int)offset>=siz?siz - 1:offset]; } //! Access to a pixel value at a specified offset, using Neumann boundary conditions \const. - T at(const int offset) const { + const T& at(const int offset) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "at(): Empty instance.", @@ -12304,9 +11869,9 @@ namespace cimg_library_suffixed { return _at(offset); } - T _at(const int offset) const { + const T& _at(const int offset) const { const unsigned int siz = (unsigned int)size(); - return (*this)[offset<0?0:(unsigned int)offset>=siz?siz-1:offset]; + return (*this)[offset<0?0:(unsigned int)offset>=siz?siz - 1:offset]; } //! Access to a pixel value, using Dirichlet boundary conditions for the X-coordinate. @@ -12326,12 +11891,12 @@ namespace cimg_library_suffixed { \warning - There is \e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds. **/ - T& atX(const int x, const int y, const int z, const int c, const T out_value) { + T& atX(const int x, const int y, const int z, const int c, const T& out_value) { return (x<0 || x>=width())?(cimg::temporary(out_value)=out_value):(*this)(x,y,z,c); } //! Access to a pixel value, using Dirichlet boundary conditions for the X-coordinate \const. - T atX(const int x, const int y, const int z, const int c, const T out_value) const { + T atX(const int x, const int y, const int z, const int c, const T& out_value) const { return (x<0 || x>=width())?out_value:(*this)(x,y,z,c); } @@ -12362,11 +11927,11 @@ namespace cimg_library_suffixed { } T& _atX(const int x, const int y=0, const int z=0, const int c=0) { - return (*this)(x<0?0:(x>=width()?width()-1:x),y,z,c); + return (*this)(x<0?0:(x>=width()?width() - 1:x),y,z,c); } //! Access to a pixel value, using Neumann boundary conditions for the X-coordinate \const. - T atX(const int x, const int y=0, const int z=0, const int c=0) const { + const T& atX(const int x, const int y=0, const int z=0, const int c=0) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "atX(): Empty instance.", @@ -12374,20 +11939,20 @@ namespace cimg_library_suffixed { return _atX(x,y,z,c); } - T _atX(const int x, const int y=0, const int z=0, const int c=0) const { - return (*this)(x<0?0:(x>=width()?width()-1:x),y,z,c); + const T& _atX(const int x, const int y=0, const int z=0, const int c=0) const { + return (*this)(x<0?0:(x>=width()?width() - 1:x),y,z,c); } //! Access to a pixel value, using Dirichlet boundary conditions for the X and Y-coordinates. /** Similar to atX(int,int,int,int,const T), except that boundary checking is performed both on X and Y-coordinates. **/ - T& atXY(const int x, const int y, const int z, const int c, const T out_value) { + T& atXY(const int x, const int y, const int z, const int c, const T& out_value) { return (x<0 || y<0 || x>=width() || y>=height())?(cimg::temporary(out_value)=out_value):(*this)(x,y,z,c); } //! Access to a pixel value, using Dirichlet boundary conditions for the X and Y coordinates \const. - T atXY(const int x, const int y, const int z, const int c, const T out_value) const { + T atXY(const int x, const int y, const int z, const int c, const T& out_value) const { return (x<0 || y<0 || x>=width() || y>=height())?out_value:(*this)(x,y,z,c); } @@ -12407,11 +11972,11 @@ namespace cimg_library_suffixed { } T& _atXY(const int x, const int y, const int z=0, const int c=0) { - return (*this)(x<0?0:(x>=width()?width()-1:x), y<0?0:(y>=height()?height()-1:y),z,c); + return (*this)(x<0?0:(x>=width()?width() - 1:x), y<0?0:(y>=height()?height() - 1:y),z,c); } //! Access to a pixel value, using Neumann boundary conditions for the X and Y-coordinates \const. - T atXY(const int x, const int y, const int z=0, const int c=0) const { + const T& atXY(const int x, const int y, const int z=0, const int c=0) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "atXY(): Empty instance.", @@ -12419,8 +11984,8 @@ namespace cimg_library_suffixed { return _atXY(x,y,z,c); } - T _atXY(const int x, const int y, const int z=0, const int c=0) const { - return (*this)(x<0?0:(x>=width()?width()-1:x), y<0?0:(y>=height()?height()-1:y),z,c); + const T& _atXY(const int x, const int y, const int z=0, const int c=0) const { + return (*this)(x<0?0:(x>=width()?width() - 1:x), y<0?0:(y>=height()?height() - 1:y),z,c); } //! Access to a pixel value, using Dirichlet boundary conditions for the X,Y and Z-coordinates. @@ -12428,13 +11993,13 @@ namespace cimg_library_suffixed { Similar to atX(int,int,int,int,const T), except that boundary checking is performed both on X,Y and Z-coordinates. **/ - T& atXYZ(const int x, const int y, const int z, const int c, const T out_value) { + T& atXYZ(const int x, const int y, const int z, const int c, const T& out_value) { return (x<0 || y<0 || z<0 || x>=width() || y>=height() || z>=depth())? (cimg::temporary(out_value)=out_value):(*this)(x,y,z,c); } //! Access to a pixel value, using Dirichlet boundary conditions for the X,Y and Z-coordinates \const. - T atXYZ(const int x, const int y, const int z, const int c, const T out_value) const { + T atXYZ(const int x, const int y, const int z, const int c, const T& out_value) const { return (x<0 || y<0 || z<0 || x>=width() || y>=height() || z>=depth())?out_value:(*this)(x,y,z,c); } @@ -12454,12 +12019,12 @@ namespace cimg_library_suffixed { } T& _atXYZ(const int x, const int y, const int z, const int c=0) { - return (*this)(x<0?0:(x>=width()?width()-1:x),y<0?0:(y>=height()?height()-1:y), - z<0?0:(z>=depth()?depth()-1:z),c); + return (*this)(x<0?0:x>=width()?width() - 1:x,y<0?0:y>=height()?height() - 1:y, + z<0?0:z>=depth()?depth() - 1:z,c); } //! Access to a pixel value, using Neumann boundary conditions for the X,Y and Z-coordinates \const. - T atXYZ(const int x, const int y, const int z, const int c=0) const { + const T& atXYZ(const int x, const int y, const int z, const int c=0) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "atXYZ(): Empty instance.", @@ -12467,9 +12032,9 @@ namespace cimg_library_suffixed { return _atXYZ(x,y,z,c); } - T _atXYZ(const int x, const int y, const int z, const int c=0) const { - return (*this)(x<0?0:(x>=width()?width()-1:x),y<0?0:(y>=height()?height()-1:y), - z<0?0:(z>=depth()?depth()-1:z),c); + const T& _atXYZ(const int x, const int y, const int z, const int c=0) const { + return (*this)(x<0?0:(x>=width()?width() - 1:x),y<0?0:(y>=height()?height() - 1:y), + z<0?0:(z>=depth()?depth() - 1:z),c); } //! Access to a pixel value, using Dirichlet boundary conditions. @@ -12477,13 +12042,13 @@ namespace cimg_library_suffixed { Similar to atX(int,int,int,int,const T), except that boundary checking is performed on all X,Y,Z and C-coordinates. **/ - T& atXYZC(const int x, const int y, const int z, const int c, const T out_value) { + T& atXYZC(const int x, const int y, const int z, const int c, const T& out_value) { return (x<0 || y<0 || z<0 || c<0 || x>=width() || y>=height() || z>=depth() || c>=spectrum())? (cimg::temporary(out_value)=out_value):(*this)(x,y,z,c); } //! Access to a pixel value, using Dirichlet boundary conditions \const. - T atXYZC(const int x, const int y, const int z, const int c, const T out_value) const { + T atXYZC(const int x, const int y, const int z, const int c, const T& out_value) const { return (x<0 || y<0 || z<0 || c<0 || x>=width() || y>=height() || z>=depth() || c>=spectrum())?out_value: (*this)(x,y,z,c); } @@ -12504,12 +12069,12 @@ namespace cimg_library_suffixed { } T& _atXYZC(const int x, const int y, const int z, const int c) { - return (*this)(x<0?0:(x>=width()?width()-1:x), y<0?0:(y>=height()?height()-1:y), - z<0?0:(z>=depth()?depth()-1:z), c<0?0:(c>=spectrum()?spectrum()-1:c)); + return (*this)(x<0?0:(x>=width()?width() - 1:x), y<0?0:(y>=height()?height() - 1:y), + z<0?0:(z>=depth()?depth() - 1:z), c<0?0:(c>=spectrum()?spectrum() - 1:c)); } //! Access to a pixel value, using Neumann boundary conditions \const. - T atXYZC(const int x, const int y, const int z, const int c) const { + const T& atXYZC(const int x, const int y, const int z, const int c) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "atXYZC(): Empty instance.", @@ -12517,9 +12082,9 @@ namespace cimg_library_suffixed { return _atXYZC(x,y,z,c); } - T _atXYZC(const int x, const int y, const int z, const int c) const { - return (*this)(x<0?0:(x>=width()?width()-1:x), y<0?0:(y>=height()?height()-1:y), - z<0?0:(z>=depth()?depth()-1:z), c<0?0:(c>=spectrum()?spectrum()-1:c)); + const T& _atXYZC(const int x, const int y, const int z, const int c) const { + return (*this)(x<0?0:(x>=width()?width() - 1:x), y<0?0:(y>=height()?height() - 1:y), + z<0?0:(z>=depth()?depth() - 1:z), c<0?0:(c>=spectrum()?spectrum() - 1:c)); } //! Return pixel value, using linear interpolation and Dirichlet boundary conditions for the X-coordinate. @@ -12538,14 +12103,14 @@ namespace cimg_library_suffixed { \warning - There is \e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds. **/ - Tfloat linear_atX(const float fx, const int y, const int z, const int c, const T out_value) const { + Tfloat linear_atX(const float fx, const int y, const int z, const int c, const T& out_value) const { const int - x = (int)fx - (fx>=0?0:1), nx = x + 1; + x = (int)fx - (fx>=0?0:1), nx = x + 1; const float dx = fx - x; const Tfloat Ic = (Tfloat)atX(x,y,z,c,out_value), In = (Tfloat)atXY(nx,y,z,c,out_value); - return Ic + dx*(In-Ic); + return Ic + dx*(In - Ic); } //! Return pixel value, using linear interpolation and Neumann boundary conditions for the X-coordinate. @@ -12576,16 +12141,16 @@ namespace cimg_library_suffixed { Tfloat _linear_atX(const float fx, const int y=0, const int z=0, const int c=0) const { const float - nfx = fx<0?0:(fx>_width-1?_width-1:fx); + nfx = fx<0?0:(fx>_width - 1?_width - 1:fx); const unsigned int x = (unsigned int)nfx; const float dx = nfx - x; const unsigned int - nx = dx>0?x+1:x; + nx = dx>0?x + 1:x; const Tfloat Ic = (Tfloat)(*this)(x,y,z,c), In = (Tfloat)(*this)(nx,y,z,c); - return Ic + dx*(In-Ic); + return Ic + dx*(In - Ic); } //! Return pixel value, using linear interpolation and Dirichlet boundary conditions for the X and Y-coordinates. @@ -12593,7 +12158,7 @@ namespace cimg_library_suffixed { Similar to linear_atX(float,int,int,int,const T) const, except that the linear interpolation and the boundary checking are achieved both for X and Y-coordinates. **/ - Tfloat linear_atXY(const float fx, const float fy, const int z, const int c, const T out_value) const { + Tfloat linear_atXY(const float fx, const float fy, const int z, const int c, const T& out_value) const { const int x = (int)fx - (fx>=0?0:1), nx = x + 1, y = (int)fy - (fy>=0?0:1), ny = y + 1; @@ -12603,7 +12168,7 @@ namespace cimg_library_suffixed { const Tfloat Icc = (Tfloat)atXY(x,y,z,c,out_value), Inc = (Tfloat)atXY(nx,y,z,c,out_value), Icn = (Tfloat)atXY(x,ny,z,c,out_value), Inn = (Tfloat)atXY(nx,ny,z,c,out_value); - return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc); + return Icc + dx*(Inc - Icc + dy*(Icc + Inn - Icn - Inc)) + dy*(Icn - Icc); } //! Return pixel value, using linear interpolation and Neumann boundary conditions for the X and Y-coordinates. @@ -12625,8 +12190,8 @@ namespace cimg_library_suffixed { Tfloat _linear_atXY(const float fx, const float fy, const int z=0, const int c=0) const { const float - nfx = fx<0?0:(fx>_width-1?_width-1:fx), - nfy = fy<0?0:(fy>_height-1?_height-1:fy); + nfx = fx<0?0:(fx>_width - 1?_width - 1:fx), + nfy = fy<0?0:(fy>_height - 1?_height - 1:fy); const unsigned int x = (unsigned int)nfx, y = (unsigned int)nfy; @@ -12634,12 +12199,12 @@ namespace cimg_library_suffixed { dx = nfx - x, dy = nfy - y; const unsigned int - nx = dx>0?x+1:x, - ny = dy>0?y+1:y; + nx = dx>0?x + 1:x, + ny = dy>0?y + 1:y; const Tfloat Icc = (Tfloat)(*this)(x,y,z,c), Inc = (Tfloat)(*this)(nx,y,z,c), Icn = (Tfloat)(*this)(x,ny,z,c), Inn = (Tfloat)(*this)(nx,ny,z,c); - return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc); + return Icc + dx*(Inc - Icc + dy*(Icc + Inn - Icn - Inc)) + dy*(Icn - Icc); } //! Return pixel value, using linear interpolation and Dirichlet boundary conditions for the X,Y and Z-coordinates. @@ -12647,7 +12212,7 @@ namespace cimg_library_suffixed { Similar to linear_atX(float,int,int,int,const T) const, except that the linear interpolation and the boundary checking are achieved both for X,Y and Z-coordinates. **/ - Tfloat linear_atXYZ(const float fx, const float fy, const float fz, const int c, const T out_value) const { + Tfloat linear_atXYZ(const float fx, const float fy, const float fz, const int c, const T& out_value) const { const int x = (int)fx - (fx>=0?0:1), nx = x + 1, y = (int)fy - (fy>=0?0:1), ny = y + 1, @@ -12662,13 +12227,13 @@ namespace cimg_library_suffixed { Iccn = (Tfloat)atXYZ(x,y,nz,c,out_value), Incn = (Tfloat)atXYZ(nx,y,nz,c,out_value), Icnn = (Tfloat)atXYZ(x,ny,nz,c,out_value), Innn = (Tfloat)atXYZ(nx,ny,nz,c,out_value); return Iccc + - dx*(Incc-Iccc + - dy*(Iccc+Innc-Icnc-Incc + - dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) + - dz*(Iccc+Incn-Iccn-Incc)) + - dy*(Icnc-Iccc + - dz*(Iccc+Icnn-Iccn-Icnc)) + - dz*(Iccn-Iccc); + dx*(Incc - Iccc + + dy*(Iccc + Innc - Icnc - Incc + + dz*(Iccn + Innn + Icnc + Incc - Icnn - Incn - Iccc - Innc)) + + dz*(Iccc + Incn - Iccn - Incc)) + + dy*(Icnc - Iccc + + dz*(Iccc + Icnn - Iccn - Icnc)) + + dz*(Iccn - Iccc); } //! Return pixel value, using linear interpolation and Neumann boundary conditions for the X,Y and Z-coordinates. @@ -12690,9 +12255,9 @@ namespace cimg_library_suffixed { Tfloat _linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int c=0) const { const float - nfx = fx<0?0:(fx>_width-1?_width-1:fx), - nfy = fy<0?0:(fy>_height-1?_height-1:fy), - nfz = fz<0?0:(fz>_depth-1?_depth-1:fz); + nfx = fx<0?0:(fx>_width - 1?_width - 1:fx), + nfy = fy<0?0:(fy>_height - 1?_height - 1:fy), + nfz = fz<0?0:(fz>_depth - 1?_depth - 1:fz); const unsigned int x = (unsigned int)nfx, y = (unsigned int)nfy, @@ -12702,22 +12267,22 @@ namespace cimg_library_suffixed { dy = nfy - y, dz = nfz - z; const unsigned int - nx = dx>0?x+1:x, - ny = dy>0?y+1:y, - nz = dz>0?z+1:z; + nx = dx>0?x + 1:x, + ny = dy>0?y + 1:y, + nz = dz>0?z + 1:z; const Tfloat Iccc = (Tfloat)(*this)(x,y,z,c), Incc = (Tfloat)(*this)(nx,y,z,c), Icnc = (Tfloat)(*this)(x,ny,z,c), Innc = (Tfloat)(*this)(nx,ny,z,c), Iccn = (Tfloat)(*this)(x,y,nz,c), Incn = (Tfloat)(*this)(nx,y,nz,c), Icnn = (Tfloat)(*this)(x,ny,nz,c), Innn = (Tfloat)(*this)(nx,ny,nz,c); return Iccc + - dx*(Incc-Iccc + - dy*(Iccc+Innc-Icnc-Incc + - dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) + - dz*(Iccc+Incn-Iccn-Incc)) + - dy*(Icnc-Iccc + - dz*(Iccc+Icnn-Iccn-Icnc)) + - dz*(Iccn-Iccc); + dx*(Incc - Iccc + + dy*(Iccc + Innc - Icnc - Incc + + dz*(Iccn + Innn + Icnc + Incc - Icnn - Incn - Iccc - Innc)) + + dz*(Iccc + Incn - Iccn - Incc)) + + dy*(Icnc - Iccc + + dz*(Iccc + Icnn - Iccn - Icnc)) + + dz*(Iccn - Iccc); } //! Return pixel value, using linear interpolation and Dirichlet boundary conditions for all X,Y,Z,C-coordinates. @@ -12725,7 +12290,7 @@ namespace cimg_library_suffixed { Similar to linear_atX(float,int,int,int,const T) const, except that the linear interpolation and the boundary checking are achieved for all X,Y,Z and C-coordinates. **/ - Tfloat linear_atXYZC(const float fx, const float fy, const float fz, const float fc, const T out_value) const { + Tfloat linear_atXYZC(const float fx, const float fy, const float fz, const float fc, const T& out_value) const { const int x = (int)fx - (fx>=0?0:1), nx = x + 1, y = (int)fy - (fy>=0?0:1), ny = y + 1, @@ -12746,22 +12311,22 @@ namespace cimg_library_suffixed { Iccnn = (Tfloat)atXYZC(x,y,nz,nc,out_value), Incnn = (Tfloat)atXYZC(nx,y,nz,nc,out_value), Icnnn = (Tfloat)atXYZC(x,ny,nz,nc,out_value), Innnn = (Tfloat)atXYZC(nx,ny,nz,nc,out_value); return Icccc + - dx*(Inccc-Icccc + - dy*(Icccc+Inncc-Icncc-Inccc + - dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc + - dc*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc- - Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) + - dc*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) + - dz*(Icccc+Incnc-Iccnc-Inccc + - dc*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) + - dc*(Icccc+Inccn-Inccc-Icccn)) + - dy*(Icncc-Icccc + - dz*(Icccc+Icnnc-Iccnc-Icncc + - dc*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) + - dc*(Icccc+Icncn-Icncc-Icccn)) + - dz*(Iccnc-Icccc + - dc*(Icccc+Iccnn-Iccnc-Icccn)) + - dc*(Icccn-Icccc); + dx*(Inccc - Icccc + + dy*(Icccc + Inncc - Icncc - Inccc + + dz*(Iccnc + Innnc + Icncc + Inccc - Icnnc - Incnc - Icccc - Inncc + + dc*(Iccnn + Innnn + Icncn + Inccn + Icnnc + Incnc + Icccc + Inncc - + Icnnn - Incnn - Icccn - Inncn - Iccnc - Innnc - Icncc - Inccc)) + + dc*(Icccn + Inncn + Icncc + Inccc - Icncn - Inccn - Icccc - Inncc)) + + dz*(Icccc + Incnc - Iccnc - Inccc + + dc*(Icccn + Incnn + Iccnc + Inccc - Iccnn - Inccn - Icccc - Incnc)) + + dc*(Icccc + Inccn - Inccc - Icccn)) + + dy*(Icncc - Icccc + + dz*(Icccc + Icnnc - Iccnc - Icncc + + dc*(Icccn + Icnnn + Iccnc + Icncc - Iccnn - Icncn - Icccc - Icnnc)) + + dc*(Icccc + Icncn - Icncc - Icccn)) + + dz*(Iccnc - Icccc + + dc*(Icccc + Iccnn - Iccnc - Icccn)) + + dc*(Icccn -Icccc); } //! Return pixel value, using linear interpolation and Neumann boundary conditions for all X,Y,Z and C-coordinates. @@ -12783,10 +12348,10 @@ namespace cimg_library_suffixed { Tfloat _linear_atXYZC(const float fx, const float fy=0, const float fz=0, const float fc=0) const { const float - nfx = fx<0?0:(fx>_width-1?_width-1:fx), - nfy = fy<0?0:(fy>_height-1?_height-1:fy), - nfz = fz<0?0:(fz>_depth-1?_depth-1:fz), - nfc = fc<0?0:(fc>_spectrum-1?_spectrum-1:fc); + nfx = fx<0?0:(fx>_width - 1?_width - 1:fx), + nfy = fy<0?0:(fy>_height - 1?_height - 1:fy), + nfz = fz<0?0:(fz>_depth - 1?_depth - 1:fz), + nfc = fc<0?0:(fc>_spectrum - 1?_spectrum - 1:fc); const unsigned int x = (unsigned int)nfx, y = (unsigned int)nfy, @@ -12798,10 +12363,10 @@ namespace cimg_library_suffixed { dz = nfz - z, dc = nfc - c; const unsigned int - nx = dx>0?x+1:x, - ny = dy>0?y+1:y, - nz = dz>0?z+1:z, - nc = dc>0?c+1:c; + nx = dx>0?x + 1:x, + ny = dy>0?y + 1:y, + nz = dz>0?z + 1:z, + nc = dc>0?c + 1:c; const Tfloat Icccc = (Tfloat)(*this)(x,y,z,c), Inccc = (Tfloat)(*this)(nx,y,z,c), Icncc = (Tfloat)(*this)(x,ny,z,c), Inncc = (Tfloat)(*this)(nx,ny,z,c), @@ -12812,22 +12377,22 @@ namespace cimg_library_suffixed { Iccnn = (Tfloat)(*this)(x,y,nz,nc), Incnn = (Tfloat)(*this)(nx,y,nz,nc), Icnnn = (Tfloat)(*this)(x,ny,nz,nc), Innnn = (Tfloat)(*this)(nx,ny,nz,nc); return Icccc + - dx*(Inccc-Icccc + - dy*(Icccc+Inncc-Icncc-Inccc + - dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc + - dc*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc- - Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) + - dc*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) + - dz*(Icccc+Incnc-Iccnc-Inccc + - dc*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) + - dc*(Icccc+Inccn-Inccc-Icccn)) + - dy*(Icncc-Icccc + - dz*(Icccc+Icnnc-Iccnc-Icncc + - dc*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) + - dc*(Icccc+Icncn-Icncc-Icccn)) + - dz*(Iccnc-Icccc + - dc*(Icccc+Iccnn-Iccnc-Icccn)) + - dc*(Icccn-Icccc); + dx*(Inccc - Icccc + + dy*(Icccc + Inncc - Icncc - Inccc + + dz*(Iccnc + Innnc + Icncc + Inccc - Icnnc - Incnc - Icccc - Inncc + + dc*(Iccnn + Innnn + Icncn + Inccn + Icnnc + Incnc + Icccc + Inncc - + Icnnn - Incnn - Icccn - Inncn - Iccnc - Innnc - Icncc - Inccc)) + + dc*(Icccn + Inncn + Icncc + Inccc - Icncn - Inccn - Icccc - Inncc)) + + dz*(Icccc + Incnc - Iccnc - Inccc + + dc*(Icccn + Incnn + Iccnc + Inccc - Iccnn - Inccn - Icccc - Incnc)) + + dc*(Icccc + Inccn - Inccc - Icccn)) + + dy*(Icncc - Icccc + + dz*(Icccc + Icnnc - Iccnc - Icncc + + dc*(Icccn + Icnnn + Iccnc + Icncc - Iccnn - Icncn - Icccc - Icnnc)) + + dc*(Icccc + Icncn - Icncc - Icccn)) + + dz*(Iccnc - Icccc + + dc*(Icccc + Iccnn - Iccnc - Icccn)) + + dc*(Icccn - Icccc); } //! Return pixel value, using cubic interpolation and Dirichlet boundary conditions for the X-coordinate. @@ -12847,7 +12412,7 @@ namespace cimg_library_suffixed { \warning - There is \e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds. **/ - Tfloat cubic_atX(const float fx, const int y, const int z, const int c, const T out_value) const { + Tfloat cubic_atX(const float fx, const int y, const int z, const int c, const T& out_value) const { const int x = (int)fx - (fx>=0?0:1), px = x - 1, nx = x + 1, ax = x + 2; const float @@ -12855,7 +12420,7 @@ namespace cimg_library_suffixed { const Tfloat Ip = (Tfloat)atX(px,y,z,c,out_value), Ic = (Tfloat)atX(x,y,z,c,out_value), In = (Tfloat)atX(nx,y,z,c,out_value), Ia = (Tfloat)atX(ax,y,z,c,out_value); - return Ic + 0.5f*(dx*(-Ip+In) + dx*dx*(2*Ip-5*Ic+4*In-Ia) + dx*dx*dx*(-Ip+3*Ic-3*In+Ia)); + return Ic + 0.5f*(dx*(-Ip + In) + dx*dx*(2*Ip - 5*Ic + 4*In - Ia) + dx*dx*dx*(-Ip + 3*Ic - 3*In + Ia)); } //! Return damped pixel value, using cubic interpolation and Dirichlet boundary conditions for the X-coordinate. @@ -12863,7 +12428,7 @@ namespace cimg_library_suffixed { Similar to cubic_atX(float,int,int,int,const T) const, except that you can specify the authorized minimum and maximum of the returned value. **/ - Tfloat cubic_atX(const float fx, const int y, const int z, const int c, const T out_value, + Tfloat cubic_atX(const float fx, const int y, const int z, const int c, const T& out_value, const Tfloat min_value, const Tfloat max_value) const { const Tfloat val = cubic_atX(fx,y,z,c,out_value); return valmax_value?max_value:val; @@ -12896,17 +12461,17 @@ namespace cimg_library_suffixed { Tfloat _cubic_atX(const float fx, const int y=0, const int z=0, const int c=0) const { const float - nfx = fx<0?0:(fx>_width-1?_width-1:fx); + nfx = fx<0?0:(fx>_width - 1?_width - 1:fx); const int x = (int)nfx; const float dx = nfx - x; const int - px = x-1<0?0:x-1, nx = dx>0?x+1:x, ax = x+2>=width()?width()-1:x+2; + px = x - 1<0?0:x - 1, nx = dx>0?x + 1:x, ax = x + 2>=width()?width() - 1:x + 2; const Tfloat Ip = (Tfloat)(*this)(px,y,z,c), Ic = (Tfloat)(*this)(x,y,z,c), In = (Tfloat)(*this)(nx,y,z,c), Ia = (Tfloat)(*this)(ax,y,z,c); - return Ic + 0.5f*(dx*(-Ip+In) + dx*dx*(2*Ip-5*Ic+4*In-Ia) + dx*dx*dx*(-Ip+3*Ic-3*In+Ia)); + return Ic + 0.5f*(dx*(-Ip + In) + dx*dx*(2*Ip - 5*Ic + 4*In - Ia) + dx*dx*dx*(-Ip + 3*Ic - 3*In + Ia)); } //! Return damped pixel value, using cubic interpolation and Neumann boundary conditions for the X-coordinate. @@ -12931,7 +12496,7 @@ namespace cimg_library_suffixed { Similar to cubic_atX(float,int,int,int,const T) const, except that the cubic interpolation and boundary checking are achieved both for X and Y-coordinates. **/ - Tfloat cubic_atXY(const float fx, const float fy, const int z, const int c, const T out_value) const { + Tfloat cubic_atXY(const float fx, const float fy, const int z, const int c, const T& out_value) const { const int x = (int)fx - (fx>=0?0:1), px = x - 1, nx = x + 1, ax = x + 2, y = (int)fy - (fy>=0?0:1), py = y - 1, ny = y + 1, ay = y + 2; @@ -12939,17 +12504,17 @@ namespace cimg_library_suffixed { const Tfloat Ipp = (Tfloat)atXY(px,py,z,c,out_value), Icp = (Tfloat)atXY(x,py,z,c,out_value), Inp = (Tfloat)atXY(nx,py,z,c,out_value), Iap = (Tfloat)atXY(ax,py,z,c,out_value), - Ip = Icp + 0.5f*(dx*(-Ipp+Inp) + dx*dx*(2*Ipp-5*Icp+4*Inp-Iap) + dx*dx*dx*(-Ipp+3*Icp-3*Inp+Iap)), + Ip = Icp + 0.5f*(dx*(-Ipp + Inp) + dx*dx*(2*Ipp - 5*Icp + 4*Inp - Iap) + dx*dx*dx*(-Ipp + 3*Icp - 3*Inp + Iap)), Ipc = (Tfloat)atXY(px,y,z,c,out_value), Icc = (Tfloat)atXY(x, y,z,c,out_value), Inc = (Tfloat)atXY(nx,y,z,c,out_value), Iac = (Tfloat)atXY(ax,y,z,c,out_value), - Ic = Icc + 0.5f*(dx*(-Ipc+Inc) + dx*dx*(2*Ipc-5*Icc+4*Inc-Iac) + dx*dx*dx*(-Ipc+3*Icc-3*Inc+Iac)), + Ic = Icc + 0.5f*(dx*(-Ipc + Inc) + dx*dx*(2*Ipc - 5*Icc + 4*Inc - Iac) + dx*dx*dx*(-Ipc + 3*Icc - 3*Inc + Iac)), Ipn = (Tfloat)atXY(px,ny,z,c,out_value), Icn = (Tfloat)atXY(x,ny,z,c,out_value), Inn = (Tfloat)atXY(nx,ny,z,c,out_value), Ian = (Tfloat)atXY(ax,ny,z,c,out_value), - In = Icn + 0.5f*(dx*(-Ipn+Inn) + dx*dx*(2*Ipn-5*Icn+4*Inn-Ian) + dx*dx*dx*(-Ipn+3*Icn-3*Inn+Ian)), + In = Icn + 0.5f*(dx*(-Ipn + Inn) + dx*dx*(2*Ipn - 5*Icn + 4*Inn - Ian) + dx*dx*dx*(-Ipn + 3*Icn - 3*Inn + Ian)), Ipa = (Tfloat)atXY(px,ay,z,c,out_value), Ica = (Tfloat)atXY(x,ay,z,c,out_value), Ina = (Tfloat)atXY(nx,ay,z,c,out_value), Iaa = (Tfloat)atXY(ax,ay,z,c,out_value), - Ia = Ica + 0.5f*(dx*(-Ipa+Ina) + dx*dx*(2*Ipa-5*Ica+4*Ina-Iaa) + dx*dx*dx*(-Ipa+3*Ica-3*Ina+Iaa)); - return Ic + 0.5f*(dy*(-Ip+In) + dy*dy*(2*Ip-5*Ic+4*In-Ia) + dy*dy*dy*(-Ip+3*Ic-3*In+Ia)); + Ia = Ica + 0.5f*(dx*(-Ipa + Ina) + dx*dx*(2*Ipa - 5*Ica + 4*Ina - Iaa) + dx*dx*dx*(-Ipa + 3*Ica - 3*Ina + Iaa)); + return Ic + 0.5f*(dy*(-Ip + In) + dy*dy*(2*Ip - 5*Ic + 4*In - Ia) + dy*dy*dy*(-Ip + 3*Ic - 3*In + Ia)); } //! Return damped pixel value, using cubic interpolation and Dirichlet boundary conditions for the X,Y-coordinates. @@ -12957,7 +12522,7 @@ namespace cimg_library_suffixed { Similar to cubic_atXY(float,float,int,int,const T) const, except that you can specify the authorized minimum and maximum of the returned value. **/ - Tfloat cubic_atXY(const float fx, const float fy, const int z, const int c, const T out_value, + Tfloat cubic_atXY(const float fx, const float fy, const int z, const int c, const T& out_value, const Tfloat min_value, const Tfloat max_value) const { const Tfloat val = cubic_atXY(fx,fy,z,c,out_value); return valmax_value?max_value:val; @@ -12981,27 +12546,27 @@ namespace cimg_library_suffixed { Tfloat _cubic_atXY(const float fx, const float fy, const int z=0, const int c=0) const { const float - nfx = fx<0?0:(fx>_width-1?_width-1:fx), - nfy = fy<0?0:(fy>_height-1?_height-1:fy); + nfx = fx<0?0:(fx>_width - 1?_width - 1:fx), + nfy = fy<0?0:(fy>_height - 1?_height - 1:fy); const int x = (int)nfx, y = (int)nfy; const float dx = nfx - x, dy = nfy - y; const int - px = x-1<0?0:x-1, nx = dx>0?x+1:x, ax = x+2>=width()?width()-1:x+2, - py = y-1<0?0:y-1, ny = dy>0?y+1:y, ay = y+2>=height()?height()-1:y+2; + px = x - 1<0?0:x - 1, nx = dx>0?x + 1:x, ax = x + 2>=width()?width() - 1:x + 2, + py = y - 1<0?0:y - 1, ny = dy>0?y + 1:y, ay = y + 2>=height()?height() - 1:y + 2; const Tfloat Ipp = (Tfloat)(*this)(px,py,z,c), Icp = (Tfloat)(*this)(x,py,z,c), Inp = (Tfloat)(*this)(nx,py,z,c), Iap = (Tfloat)(*this)(ax,py,z,c), - Ip = Icp + 0.5f*(dx*(-Ipp+Inp) + dx*dx*(2*Ipp-5*Icp+4*Inp-Iap) + dx*dx*dx*(-Ipp+3*Icp-3*Inp+Iap)), + Ip = Icp + 0.5f*(dx*(-Ipp + Inp) + dx*dx*(2*Ipp - 5*Icp + 4*Inp - Iap) + dx*dx*dx*(-Ipp + 3*Icp - 3*Inp + Iap)), Ipc = (Tfloat)(*this)(px,y,z,c), Icc = (Tfloat)(*this)(x, y,z,c), Inc = (Tfloat)(*this)(nx,y,z,c), Iac = (Tfloat)(*this)(ax,y,z,c), - Ic = Icc + 0.5f*(dx*(-Ipc+Inc) + dx*dx*(2*Ipc-5*Icc+4*Inc-Iac) + dx*dx*dx*(-Ipc+3*Icc-3*Inc+Iac)), + Ic = Icc + 0.5f*(dx*(-Ipc + Inc) + dx*dx*(2*Ipc - 5*Icc + 4*Inc - Iac) + dx*dx*dx*(-Ipc + 3*Icc - 3*Inc + Iac)), Ipn = (Tfloat)(*this)(px,ny,z,c), Icn = (Tfloat)(*this)(x,ny,z,c), Inn = (Tfloat)(*this)(nx,ny,z,c), Ian = (Tfloat)(*this)(ax,ny,z,c), - In = Icn + 0.5f*(dx*(-Ipn+Inn) + dx*dx*(2*Ipn-5*Icn+4*Inn-Ian) + dx*dx*dx*(-Ipn+3*Icn-3*Inn+Ian)), + In = Icn + 0.5f*(dx*(-Ipn + Inn) + dx*dx*(2*Ipn - 5*Icn + 4*Inn - Ian) + dx*dx*dx*(-Ipn + 3*Icn - 3*Inn + Ian)), Ipa = (Tfloat)(*this)(px,ay,z,c), Ica = (Tfloat)(*this)(x,ay,z,c), Ina = (Tfloat)(*this)(nx,ay,z,c), Iaa = (Tfloat)(*this)(ax,ay,z,c), - Ia = Ica + 0.5f*(dx*(-Ipa+Ina) + dx*dx*(2*Ipa-5*Ica+4*Ina-Iaa) + dx*dx*dx*(-Ipa+3*Ica-3*Ina+Iaa)); - return Ic + 0.5f*(dy*(-Ip+In) + dy*dy*(2*Ip-5*Ic+4*In-Ia) + dy*dy*dy*(-Ip+3*Ic-3*In+Ia)); + Ia = Ica + 0.5f*(dx*(-Ipa + Ina) + dx*dx*(2*Ipa - 5*Ica + 4*Ina - Iaa) + dx*dx*dx*(-Ipa + 3*Ica - 3*Ina + Iaa)); + return Ic + 0.5f*(dy*(-Ip + In) + dy*dy*(2*Ip - 5*Ic + 4*In - Ia) + dy*dy*dy*(-Ip + 3*Ic - 3*In + Ia)); } //! Return damped pixel value, using cubic interpolation and Neumann boundary conditions for the X,Y-coordinates. @@ -13026,7 +12591,7 @@ namespace cimg_library_suffixed { Similar to cubic_atX(float,int,int,int,const T) const, except that the cubic interpolation and boundary checking are achieved both for X,Y and Z-coordinates. **/ - Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c, const T out_value) const { + Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c, const T& out_value) const { const int x = (int)fx - (fx>=0?0:1), px = x - 1, nx = x + 1, ax = x + 2, y = (int)fy - (fy>=0?0:1), py = y - 1, ny = y + 1, ay = y + 2, @@ -13035,57 +12600,77 @@ namespace cimg_library_suffixed { const Tfloat Ippp = (Tfloat)atXYZ(px,py,pz,c,out_value), Icpp = (Tfloat)atXYZ(x,py,pz,c,out_value), Inpp = (Tfloat)atXYZ(nx,py,pz,c,out_value), Iapp = (Tfloat)atXYZ(ax,py,pz,c,out_value), - Ipp = Icpp + 0.5f*(dx*(-Ippp+Inpp) + dx*dx*(2*Ippp-5*Icpp+4*Inpp-Iapp) + dx*dx*dx*(-Ippp+3*Icpp-3*Inpp+Iapp)), + Ipp = Icpp + 0.5f*(dx*(-Ippp + Inpp) + dx*dx*(2*Ippp - 5*Icpp + 4*Inpp - Iapp) + + dx*dx*dx*(-Ippp + 3*Icpp - 3*Inpp + Iapp)), Ipcp = (Tfloat)atXYZ(px,y,pz,c,out_value), Iccp = (Tfloat)atXYZ(x, y,pz,c,out_value), Incp = (Tfloat)atXYZ(nx,y,pz,c,out_value), Iacp = (Tfloat)atXYZ(ax,y,pz,c,out_value), - Icp = Iccp + 0.5f*(dx*(-Ipcp+Incp) + dx*dx*(2*Ipcp-5*Iccp+4*Incp-Iacp) + dx*dx*dx*(-Ipcp+3*Iccp-3*Incp+Iacp)), + Icp = Iccp + 0.5f*(dx*(-Ipcp + Incp) + dx*dx*(2*Ipcp - 5*Iccp + 4*Incp - Iacp) + + dx*dx*dx*(-Ipcp + 3*Iccp - 3*Incp + Iacp)), Ipnp = (Tfloat)atXYZ(px,ny,pz,c,out_value), Icnp = (Tfloat)atXYZ(x,ny,pz,c,out_value), Innp = (Tfloat)atXYZ(nx,ny,pz,c,out_value), Ianp = (Tfloat)atXYZ(ax,ny,pz,c,out_value), - Inp = Icnp + 0.5f*(dx*(-Ipnp+Innp) + dx*dx*(2*Ipnp-5*Icnp+4*Innp-Ianp) + dx*dx*dx*(-Ipnp+3*Icnp-3*Innp+Ianp)), + Inp = Icnp + 0.5f*(dx*(-Ipnp + Innp) + dx*dx*(2*Ipnp - 5*Icnp + 4*Innp - Ianp) + + dx*dx*dx*(-Ipnp + 3*Icnp - 3*Innp + Ianp)), Ipap = (Tfloat)atXYZ(px,ay,pz,c,out_value), Icap = (Tfloat)atXYZ(x,ay,pz,c,out_value), Inap = (Tfloat)atXYZ(nx,ay,pz,c,out_value), Iaap = (Tfloat)atXYZ(ax,ay,pz,c,out_value), - Iap = Icap + 0.5f*(dx*(-Ipap+Inap) + dx*dx*(2*Ipap-5*Icap+4*Inap-Iaap) + dx*dx*dx*(-Ipap+3*Icap-3*Inap+Iaap)), - Ip = Icp + 0.5f*(dy*(-Ipp+Inp) + dy*dy*(2*Ipp-5*Icp+4*Inp-Iap) + dy*dy*dy*(-Ipp+3*Icp-3*Inp+Iap)), + Iap = Icap + 0.5f*(dx*(-Ipap + Inap) + dx*dx*(2*Ipap - 5*Icap + 4*Inap - Iaap) + + dx*dx*dx*(-Ipap + 3*Icap - 3*Inap + Iaap)), + Ip = Icp + 0.5f*(dy*(-Ipp + Inp) + dy*dy*(2*Ipp - 5*Icp + 4*Inp - Iap) + + dy*dy*dy*(-Ipp + 3*Icp - 3*Inp + Iap)), Ippc = (Tfloat)atXYZ(px,py,z,c,out_value), Icpc = (Tfloat)atXYZ(x,py,z,c,out_value), Inpc = (Tfloat)atXYZ(nx,py,z,c,out_value), Iapc = (Tfloat)atXYZ(ax,py,z,c,out_value), - Ipc = Icpc + 0.5f*(dx*(-Ippc+Inpc) + dx*dx*(2*Ippc-5*Icpc+4*Inpc-Iapc) + dx*dx*dx*(-Ippc+3*Icpc-3*Inpc+Iapc)), + Ipc = Icpc + 0.5f*(dx*(-Ippc + Inpc) + dx*dx*(2*Ippc - 5*Icpc + 4*Inpc - Iapc) + + dx*dx*dx*(-Ippc + 3*Icpc - 3*Inpc + Iapc)), Ipcc = (Tfloat)atXYZ(px,y,z,c,out_value), Iccc = (Tfloat)atXYZ(x, y,z,c,out_value), Incc = (Tfloat)atXYZ(nx,y,z,c,out_value), Iacc = (Tfloat)atXYZ(ax,y,z,c,out_value), - Icc = Iccc + 0.5f*(dx*(-Ipcc+Incc) + dx*dx*(2*Ipcc-5*Iccc+4*Incc-Iacc) + dx*dx*dx*(-Ipcc+3*Iccc-3*Incc+Iacc)), + Icc = Iccc + 0.5f*(dx*(-Ipcc + Incc) + dx*dx*(2*Ipcc - 5*Iccc + 4*Incc - Iacc) + + dx*dx*dx*(-Ipcc + 3*Iccc - 3*Incc + Iacc)), Ipnc = (Tfloat)atXYZ(px,ny,z,c,out_value), Icnc = (Tfloat)atXYZ(x,ny,z,c,out_value), Innc = (Tfloat)atXYZ(nx,ny,z,c,out_value), Ianc = (Tfloat)atXYZ(ax,ny,z,c,out_value), - Inc = Icnc + 0.5f*(dx*(-Ipnc+Innc) + dx*dx*(2*Ipnc-5*Icnc+4*Innc-Ianc) + dx*dx*dx*(-Ipnc+3*Icnc-3*Innc+Ianc)), + Inc = Icnc + 0.5f*(dx*(-Ipnc + Innc) + dx*dx*(2*Ipnc - 5*Icnc + 4*Innc - Ianc) + + dx*dx*dx*(-Ipnc + 3*Icnc - 3*Innc + Ianc)), Ipac = (Tfloat)atXYZ(px,ay,z,c,out_value), Icac = (Tfloat)atXYZ(x,ay,z,c,out_value), Inac = (Tfloat)atXYZ(nx,ay,z,c,out_value), Iaac = (Tfloat)atXYZ(ax,ay,z,c,out_value), - Iac = Icac + 0.5f*(dx*(-Ipac+Inac) + dx*dx*(2*Ipac-5*Icac+4*Inac-Iaac) + dx*dx*dx*(-Ipac+3*Icac-3*Inac+Iaac)), - Ic = Icc + 0.5f*(dy*(-Ipc+Inc) + dy*dy*(2*Ipc-5*Icc+4*Inc-Iac) + dy*dy*dy*(-Ipc+3*Icc-3*Inc+Iac)), + Iac = Icac + 0.5f*(dx*(-Ipac + Inac) + dx*dx*(2*Ipac - 5*Icac + 4*Inac - Iaac) + + dx*dx*dx*(-Ipac + 3*Icac - 3*Inac + Iaac)), + Ic = Icc + 0.5f*(dy*(-Ipc + Inc) + dy*dy*(2*Ipc - 5*Icc + 4*Inc - Iac) + + dy*dy*dy*(-Ipc + 3*Icc - 3*Inc + Iac)), Ippn = (Tfloat)atXYZ(px,py,nz,c,out_value), Icpn = (Tfloat)atXYZ(x,py,nz,c,out_value), Inpn = (Tfloat)atXYZ(nx,py,nz,c,out_value), Iapn = (Tfloat)atXYZ(ax,py,nz,c,out_value), - Ipn = Icpn + 0.5f*(dx*(-Ippn+Inpn) + dx*dx*(2*Ippn-5*Icpn+4*Inpn-Iapn) + dx*dx*dx*(-Ippn+3*Icpn-3*Inpn+Iapn)), + Ipn = Icpn + 0.5f*(dx*(-Ippn + Inpn) + dx*dx*(2*Ippn - 5*Icpn + 4*Inpn - Iapn) + + dx*dx*dx*(-Ippn + 3*Icpn - 3*Inpn + Iapn)), Ipcn = (Tfloat)atXYZ(px,y,nz,c,out_value), Iccn = (Tfloat)atXYZ(x, y,nz,c,out_value), Incn = (Tfloat)atXYZ(nx,y,nz,c,out_value), Iacn = (Tfloat)atXYZ(ax,y,nz,c,out_value), - Icn = Iccn + 0.5f*(dx*(-Ipcn+Incn) + dx*dx*(2*Ipcn-5*Iccn+4*Incn-Iacn) + dx*dx*dx*(-Ipcn+3*Iccn-3*Incn+Iacn)), + Icn = Iccn + 0.5f*(dx*(-Ipcn + Incn) + dx*dx*(2*Ipcn - 5*Iccn + 4*Incn - Iacn) + + dx*dx*dx*(-Ipcn + 3*Iccn - 3*Incn + Iacn)), Ipnn = (Tfloat)atXYZ(px,ny,nz,c,out_value), Icnn = (Tfloat)atXYZ(x,ny,nz,c,out_value), Innn = (Tfloat)atXYZ(nx,ny,nz,c,out_value), Iann = (Tfloat)atXYZ(ax,ny,nz,c,out_value), - Inn = Icnn + 0.5f*(dx*(-Ipnn+Innn) + dx*dx*(2*Ipnn-5*Icnn+4*Innn-Iann) + dx*dx*dx*(-Ipnn+3*Icnn-3*Innn+Iann)), + Inn = Icnn + 0.5f*(dx*(-Ipnn + Innn) + dx*dx*(2*Ipnn - 5*Icnn + 4*Innn - Iann) + + dx*dx*dx*(-Ipnn + 3*Icnn - 3*Innn + Iann)), Ipan = (Tfloat)atXYZ(px,ay,nz,c,out_value), Ican = (Tfloat)atXYZ(x,ay,nz,c,out_value), Inan = (Tfloat)atXYZ(nx,ay,nz,c,out_value), Iaan = (Tfloat)atXYZ(ax,ay,nz,c,out_value), - Ian = Ican + 0.5f*(dx*(-Ipan+Inan) + dx*dx*(2*Ipan-5*Ican+4*Inan-Iaan) + dx*dx*dx*(-Ipan+3*Ican-3*Inan+Iaan)), - In = Icn + 0.5f*(dy*(-Ipn+Inn) + dy*dy*(2*Ipn-5*Icn+4*Inn-Ian) + dy*dy*dy*(-Ipn+3*Icn-3*Inn+Ian)), + Ian = Ican + 0.5f*(dx*(-Ipan + Inan) + dx*dx*(2*Ipan - 5*Ican + 4*Inan - Iaan) + + dx*dx*dx*(-Ipan + 3*Ican - 3*Inan + Iaan)), + In = Icn + 0.5f*(dy*(-Ipn + Inn) + dy*dy*(2*Ipn - 5*Icn + 4*Inn - Ian) + + dy*dy*dy*(-Ipn + 3*Icn - 3*Inn + Ian)), Ippa = (Tfloat)atXYZ(px,py,az,c,out_value), Icpa = (Tfloat)atXYZ(x,py,az,c,out_value), Inpa = (Tfloat)atXYZ(nx,py,az,c,out_value), Iapa = (Tfloat)atXYZ(ax,py,az,c,out_value), - Ipa = Icpa + 0.5f*(dx*(-Ippa+Inpa) + dx*dx*(2*Ippa-5*Icpa+4*Inpa-Iapa) + dx*dx*dx*(-Ippa+3*Icpa-3*Inpa+Iapa)), + Ipa = Icpa + 0.5f*(dx*(-Ippa + Inpa) + dx*dx*(2*Ippa - 5*Icpa + 4*Inpa - Iapa) + + dx*dx*dx*(-Ippa + 3*Icpa - 3*Inpa + Iapa)), Ipca = (Tfloat)atXYZ(px,y,az,c,out_value), Icca = (Tfloat)atXYZ(x, y,az,c,out_value), Inca = (Tfloat)atXYZ(nx,y,az,c,out_value), Iaca = (Tfloat)atXYZ(ax,y,az,c,out_value), - Ica = Icca + 0.5f*(dx*(-Ipca+Inca) + dx*dx*(2*Ipca-5*Icca+4*Inca-Iaca) + dx*dx*dx*(-Ipca+3*Icca-3*Inca+Iaca)), + Ica = Icca + 0.5f*(dx*(-Ipca + Inca) + dx*dx*(2*Ipca - 5*Icca + 4*Inca - Iaca) + + dx*dx*dx*(-Ipca + 3*Icca - 3*Inca + Iaca)), Ipna = (Tfloat)atXYZ(px,ny,az,c,out_value), Icna = (Tfloat)atXYZ(x,ny,az,c,out_value), Inna = (Tfloat)atXYZ(nx,ny,az,c,out_value), Iana = (Tfloat)atXYZ(ax,ny,az,c,out_value), - Ina = Icna + 0.5f*(dx*(-Ipna+Inna) + dx*dx*(2*Ipna-5*Icna+4*Inna-Iana) + dx*dx*dx*(-Ipna+3*Icna-3*Inna+Iana)), + Ina = Icna + 0.5f*(dx*(-Ipna + Inna) + dx*dx*(2*Ipna - 5*Icna + 4*Inna - Iana) + + dx*dx*dx*(-Ipna + 3*Icna - 3*Inna + Iana)), Ipaa = (Tfloat)atXYZ(px,ay,az,c,out_value), Icaa = (Tfloat)atXYZ(x,ay,az,c,out_value), Inaa = (Tfloat)atXYZ(nx,ay,az,c,out_value), Iaaa = (Tfloat)atXYZ(ax,ay,az,c,out_value), - Iaa = Icaa + 0.5f*(dx*(-Ipaa+Inaa) + dx*dx*(2*Ipaa-5*Icaa+4*Inaa-Iaaa) + dx*dx*dx*(-Ipaa+3*Icaa-3*Inaa+Iaaa)), - Ia = Ica + 0.5f*(dy*(-Ipa+Ina) + dy*dy*(2*Ipa-5*Ica+4*Ina-Iaa) + dy*dy*dy*(-Ipa+3*Ica-3*Ina+Iaa)); - return Ic + 0.5f*(dz*(-Ip+In) + dz*dz*(2*Ip-5*Ic+4*In-Ia) + dz*dz*dz*(-Ip+3*Ic-3*In+Ia)); + Iaa = Icaa + 0.5f*(dx*(-Ipaa + Inaa) + dx*dx*(2*Ipaa - 5*Icaa + 4*Inaa - Iaaa) + + dx*dx*dx*(-Ipaa + 3*Icaa - 3*Inaa + Iaaa)), + Ia = Ica + 0.5f*(dy*(-Ipa + Ina) + dy*dy*(2*Ipa - 5*Ica + 4*Ina - Iaa) + + dy*dy*dy*(-Ipa + 3*Ica - 3*Ina + Iaa)); + return Ic + 0.5f*(dz*(-Ip + In) + dz*dz*(2*Ip - 5*Ic + 4*In - Ia) + dz*dz*dz*(-Ip + 3*Ic - 3*In + Ia)); } //! Return damped pixel value, using cubic interpolation and Dirichlet boundary conditions for the XYZ-coordinates. @@ -13093,7 +12678,7 @@ namespace cimg_library_suffixed { Similar to cubic_atXYZ(float,float,float,int,const T) const, except that you can specify the authorized minimum and maximum of the returned value. **/ - Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c, const T out_value, + Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c, const T& out_value, const Tfloat min_value, const Tfloat max_value) const { const Tfloat val = cubic_atXYZ(fx,fy,fz,c,out_value); return valmax_value?max_value:val; @@ -13117,69 +12702,89 @@ namespace cimg_library_suffixed { Tfloat _cubic_atXYZ(const float fx, const float fy, const float fz, const int c=0) const { const float - nfx = fx<0?0:(fx>_width-1?_width-1:fx), - nfy = fy<0?0:(fy>_height-1?_height-1:fy), - nfz = fz<0?0:(fz>_depth-1?_depth-1:fz); + nfx = fx<0?0:(fx>_width - 1?_width - 1:fx), + nfy = fy<0?0:(fy>_height - 1?_height - 1:fy), + nfz = fz<0?0:(fz>_depth - 1?_depth - 1:fz); const int x = (int)nfx, y = (int)nfy, z = (int)nfz; const float dx = nfx - x, dy = nfy - y, dz = nfz - z; const int - px = x-1<0?0:x-1, nx = dx>0?x+1:x, ax = x+2>=width()?width()-1:x+2, - py = y-1<0?0:y-1, ny = dy>0?y+1:y, ay = y+2>=height()?height()-1:y+2, - pz = z-1<0?0:z-1, nz = dz>0?z+1:z, az = z+2>=depth()?depth()-1:z+2; + px = x - 1<0?0:x - 1, nx = dx>0?x + 1:x, ax = x + 2>=width()?width() - 1:x + 2, + py = y - 1<0?0:y - 1, ny = dy>0?y + 1:y, ay = y + 2>=height()?height() - 1:y + 2, + pz = z - 1<0?0:z - 1, nz = dz>0?z + 1:z, az = z + 2>=depth()?depth() - 1:z + 2; const Tfloat Ippp = (Tfloat)(*this)(px,py,pz,c), Icpp = (Tfloat)(*this)(x,py,pz,c), Inpp = (Tfloat)(*this)(nx,py,pz,c), Iapp = (Tfloat)(*this)(ax,py,pz,c), - Ipp = Icpp + 0.5f*(dx*(-Ippp+Inpp) + dx*dx*(2*Ippp-5*Icpp+4*Inpp-Iapp) + dx*dx*dx*(-Ippp+3*Icpp-3*Inpp+Iapp)), + Ipp = Icpp + 0.5f*(dx*(-Ippp + Inpp) + dx*dx*(2*Ippp - 5*Icpp + 4*Inpp - Iapp) + + dx*dx*dx*(-Ippp + 3*Icpp - 3*Inpp + Iapp)), Ipcp = (Tfloat)(*this)(px,y,pz,c), Iccp = (Tfloat)(*this)(x, y,pz,c), Incp = (Tfloat)(*this)(nx,y,pz,c), Iacp = (Tfloat)(*this)(ax,y,pz,c), - Icp = Iccp + 0.5f*(dx*(-Ipcp+Incp) + dx*dx*(2*Ipcp-5*Iccp+4*Incp-Iacp) + dx*dx*dx*(-Ipcp+3*Iccp-3*Incp+Iacp)), + Icp = Iccp + 0.5f*(dx*(-Ipcp + Incp) + dx*dx*(2*Ipcp - 5*Iccp + 4*Incp - Iacp) + + dx*dx*dx*(-Ipcp + 3*Iccp - 3*Incp + Iacp)), Ipnp = (Tfloat)(*this)(px,ny,pz,c), Icnp = (Tfloat)(*this)(x,ny,pz,c), Innp = (Tfloat)(*this)(nx,ny,pz,c), Ianp = (Tfloat)(*this)(ax,ny,pz,c), - Inp = Icnp + 0.5f*(dx*(-Ipnp+Innp) + dx*dx*(2*Ipnp-5*Icnp+4*Innp-Ianp) + dx*dx*dx*(-Ipnp+3*Icnp-3*Innp+Ianp)), + Inp = Icnp + 0.5f*(dx*(-Ipnp + Innp) + dx*dx*(2*Ipnp - 5*Icnp + 4*Innp - Ianp) + + dx*dx*dx*(-Ipnp + 3*Icnp - 3*Innp + Ianp)), Ipap = (Tfloat)(*this)(px,ay,pz,c), Icap = (Tfloat)(*this)(x,ay,pz,c), Inap = (Tfloat)(*this)(nx,ay,pz,c), Iaap = (Tfloat)(*this)(ax,ay,pz,c), - Iap = Icap + 0.5f*(dx*(-Ipap+Inap) + dx*dx*(2*Ipap-5*Icap+4*Inap-Iaap) + dx*dx*dx*(-Ipap+3*Icap-3*Inap+Iaap)), - Ip = Icp + 0.5f*(dy*(-Ipp+Inp) + dy*dy*(2*Ipp-5*Icp+4*Inp-Iap) + dy*dy*dy*(-Ipp+3*Icp-3*Inp+Iap)), + Iap = Icap + 0.5f*(dx*(-Ipap + Inap) + dx*dx*(2*Ipap - 5*Icap + 4*Inap - Iaap) + + dx*dx*dx*(-Ipap + 3*Icap - 3*Inap + Iaap)), + Ip = Icp + 0.5f*(dy*(-Ipp + Inp) + dy*dy*(2*Ipp - 5*Icp + 4*Inp - Iap) + + dy*dy*dy*(-Ipp + 3*Icp - 3*Inp + Iap)), Ippc = (Tfloat)(*this)(px,py,z,c), Icpc = (Tfloat)(*this)(x,py,z,c), Inpc = (Tfloat)(*this)(nx,py,z,c), Iapc = (Tfloat)(*this)(ax,py,z,c), - Ipc = Icpc + 0.5f*(dx*(-Ippc+Inpc) + dx*dx*(2*Ippc-5*Icpc+4*Inpc-Iapc) + dx*dx*dx*(-Ippc+3*Icpc-3*Inpc+Iapc)), + Ipc = Icpc + 0.5f*(dx*(-Ippc + Inpc) + dx*dx*(2*Ippc - 5*Icpc + 4*Inpc - Iapc) + + dx*dx*dx*(-Ippc + 3*Icpc - 3*Inpc + Iapc)), Ipcc = (Tfloat)(*this)(px,y,z,c), Iccc = (Tfloat)(*this)(x, y,z,c), Incc = (Tfloat)(*this)(nx,y,z,c), Iacc = (Tfloat)(*this)(ax,y,z,c), - Icc = Iccc + 0.5f*(dx*(-Ipcc+Incc) + dx*dx*(2*Ipcc-5*Iccc+4*Incc-Iacc) + dx*dx*dx*(-Ipcc+3*Iccc-3*Incc+Iacc)), + Icc = Iccc + 0.5f*(dx*(-Ipcc + Incc) + dx*dx*(2*Ipcc - 5*Iccc + 4*Incc - Iacc) + + dx*dx*dx*(-Ipcc + 3*Iccc - 3*Incc + Iacc)), Ipnc = (Tfloat)(*this)(px,ny,z,c), Icnc = (Tfloat)(*this)(x,ny,z,c), Innc = (Tfloat)(*this)(nx,ny,z,c), Ianc = (Tfloat)(*this)(ax,ny,z,c), - Inc = Icnc + 0.5f*(dx*(-Ipnc+Innc) + dx*dx*(2*Ipnc-5*Icnc+4*Innc-Ianc) + dx*dx*dx*(-Ipnc+3*Icnc-3*Innc+Ianc)), + Inc = Icnc + 0.5f*(dx*(-Ipnc + Innc) + dx*dx*(2*Ipnc - 5*Icnc + 4*Innc - Ianc) + + dx*dx*dx*(-Ipnc + 3*Icnc - 3*Innc + Ianc)), Ipac = (Tfloat)(*this)(px,ay,z,c), Icac = (Tfloat)(*this)(x,ay,z,c), Inac = (Tfloat)(*this)(nx,ay,z,c), Iaac = (Tfloat)(*this)(ax,ay,z,c), - Iac = Icac + 0.5f*(dx*(-Ipac+Inac) + dx*dx*(2*Ipac-5*Icac+4*Inac-Iaac) + dx*dx*dx*(-Ipac+3*Icac-3*Inac+Iaac)), - Ic = Icc + 0.5f*(dy*(-Ipc+Inc) + dy*dy*(2*Ipc-5*Icc+4*Inc-Iac) + dy*dy*dy*(-Ipc+3*Icc-3*Inc+Iac)), + Iac = Icac + 0.5f*(dx*(-Ipac + Inac) + dx*dx*(2*Ipac - 5*Icac + 4*Inac - Iaac) + + dx*dx*dx*(-Ipac + 3*Icac - 3*Inac + Iaac)), + Ic = Icc + 0.5f*(dy*(-Ipc + Inc) + dy*dy*(2*Ipc - 5*Icc + 4*Inc - Iac) + + dy*dy*dy*(-Ipc + 3*Icc - 3*Inc + Iac)), Ippn = (Tfloat)(*this)(px,py,nz,c), Icpn = (Tfloat)(*this)(x,py,nz,c), Inpn = (Tfloat)(*this)(nx,py,nz,c), Iapn = (Tfloat)(*this)(ax,py,nz,c), - Ipn = Icpn + 0.5f*(dx*(-Ippn+Inpn) + dx*dx*(2*Ippn-5*Icpn+4*Inpn-Iapn) + dx*dx*dx*(-Ippn+3*Icpn-3*Inpn+Iapn)), + Ipn = Icpn + 0.5f*(dx*(-Ippn + Inpn) + dx*dx*(2*Ippn - 5*Icpn + 4*Inpn - Iapn) + + dx*dx*dx*(-Ippn + 3*Icpn - 3*Inpn + Iapn)), Ipcn = (Tfloat)(*this)(px,y,nz,c), Iccn = (Tfloat)(*this)(x, y,nz,c), Incn = (Tfloat)(*this)(nx,y,nz,c), Iacn = (Tfloat)(*this)(ax,y,nz,c), - Icn = Iccn + 0.5f*(dx*(-Ipcn+Incn) + dx*dx*(2*Ipcn-5*Iccn+4*Incn-Iacn) + dx*dx*dx*(-Ipcn+3*Iccn-3*Incn+Iacn)), + Icn = Iccn + 0.5f*(dx*(-Ipcn + Incn) + dx*dx*(2*Ipcn - 5*Iccn + 4*Incn - Iacn) + + dx*dx*dx*(-Ipcn + 3*Iccn - 3*Incn + Iacn)), Ipnn = (Tfloat)(*this)(px,ny,nz,c), Icnn = (Tfloat)(*this)(x,ny,nz,c), Innn = (Tfloat)(*this)(nx,ny,nz,c), Iann = (Tfloat)(*this)(ax,ny,nz,c), - Inn = Icnn + 0.5f*(dx*(-Ipnn+Innn) + dx*dx*(2*Ipnn-5*Icnn+4*Innn-Iann) + dx*dx*dx*(-Ipnn+3*Icnn-3*Innn+Iann)), + Inn = Icnn + 0.5f*(dx*(-Ipnn + Innn) + dx*dx*(2*Ipnn - 5*Icnn + 4*Innn - Iann) + + dx*dx*dx*(-Ipnn + 3*Icnn - 3*Innn + Iann)), Ipan = (Tfloat)(*this)(px,ay,nz,c), Ican = (Tfloat)(*this)(x,ay,nz,c), Inan = (Tfloat)(*this)(nx,ay,nz,c), Iaan = (Tfloat)(*this)(ax,ay,nz,c), - Ian = Ican + 0.5f*(dx*(-Ipan+Inan) + dx*dx*(2*Ipan-5*Ican+4*Inan-Iaan) + dx*dx*dx*(-Ipan+3*Ican-3*Inan+Iaan)), - In = Icn + 0.5f*(dy*(-Ipn+Inn) + dy*dy*(2*Ipn-5*Icn+4*Inn-Ian) + dy*dy*dy*(-Ipn+3*Icn-3*Inn+Ian)), + Ian = Ican + 0.5f*(dx*(-Ipan + Inan) + dx*dx*(2*Ipan - 5*Ican + 4*Inan - Iaan) + + dx*dx*dx*(-Ipan + 3*Ican - 3*Inan + Iaan)), + In = Icn + 0.5f*(dy*(-Ipn + Inn) + dy*dy*(2*Ipn - 5*Icn + 4*Inn - Ian) + + dy*dy*dy*(-Ipn + 3*Icn - 3*Inn + Ian)), Ippa = (Tfloat)(*this)(px,py,az,c), Icpa = (Tfloat)(*this)(x,py,az,c), Inpa = (Tfloat)(*this)(nx,py,az,c), Iapa = (Tfloat)(*this)(ax,py,az,c), - Ipa = Icpa + 0.5f*(dx*(-Ippa+Inpa) + dx*dx*(2*Ippa-5*Icpa+4*Inpa-Iapa) + dx*dx*dx*(-Ippa+3*Icpa-3*Inpa+Iapa)), + Ipa = Icpa + 0.5f*(dx*(-Ippa + Inpa) + dx*dx*(2*Ippa - 5*Icpa + 4*Inpa - Iapa) + + dx*dx*dx*(-Ippa + 3*Icpa - 3*Inpa + Iapa)), Ipca = (Tfloat)(*this)(px,y,az,c), Icca = (Tfloat)(*this)(x, y,az,c), Inca = (Tfloat)(*this)(nx,y,az,c), Iaca = (Tfloat)(*this)(ax,y,az,c), - Ica = Icca + 0.5f*(dx*(-Ipca+Inca) + dx*dx*(2*Ipca-5*Icca+4*Inca-Iaca) + dx*dx*dx*(-Ipca+3*Icca-3*Inca+Iaca)), + Ica = Icca + 0.5f*(dx*(-Ipca + Inca) + dx*dx*(2*Ipca - 5*Icca + 4*Inca - Iaca) + + dx*dx*dx*(-Ipca + 3*Icca - 3*Inca + Iaca)), Ipna = (Tfloat)(*this)(px,ny,az,c), Icna = (Tfloat)(*this)(x,ny,az,c), Inna = (Tfloat)(*this)(nx,ny,az,c), Iana = (Tfloat)(*this)(ax,ny,az,c), - Ina = Icna + 0.5f*(dx*(-Ipna+Inna) + dx*dx*(2*Ipna-5*Icna+4*Inna-Iana) + dx*dx*dx*(-Ipna+3*Icna-3*Inna+Iana)), + Ina = Icna + 0.5f*(dx*(-Ipna + Inna) + dx*dx*(2*Ipna - 5*Icna + 4*Inna - Iana) + + dx*dx*dx*(-Ipna + 3*Icna - 3*Inna + Iana)), Ipaa = (Tfloat)(*this)(px,ay,az,c), Icaa = (Tfloat)(*this)(x,ay,az,c), Inaa = (Tfloat)(*this)(nx,ay,az,c), Iaaa = (Tfloat)(*this)(ax,ay,az,c), - Iaa = Icaa + 0.5f*(dx*(-Ipaa+Inaa) + dx*dx*(2*Ipaa-5*Icaa+4*Inaa-Iaaa) + dx*dx*dx*(-Ipaa+3*Icaa-3*Inaa+Iaaa)), - Ia = Ica + 0.5f*(dy*(-Ipa+Ina) + dy*dy*(2*Ipa-5*Ica+4*Ina-Iaa) + dy*dy*dy*(-Ipa+3*Ica-3*Ina+Iaa)); - return Ic + 0.5f*(dz*(-Ip+In) + dz*dz*(2*Ip-5*Ic+4*In-Ia) + dz*dz*dz*(-Ip+3*Ic-3*In+Ia)); + Iaa = Icaa + 0.5f*(dx*(-Ipaa + Inaa) + dx*dx*(2*Ipaa - 5*Icaa + 4*Inaa - Iaaa) + + dx*dx*dx*(-Ipaa + 3*Icaa - 3*Inaa + Iaaa)), + Ia = Ica + 0.5f*(dy*(-Ipa + Ina) + dy*dy*(2*Ipa - 5*Ica + 4*Ina - Iaa) + + dy*dy*dy*(-Ipa + 3*Ica - 3*Ina + Iaa)); + return Ic + 0.5f*(dz*(-Ip + In) + dz*dz*(2*Ip - 5*Ic + 4*In - Ia) + dz*dz*dz*(-Ip + 3*Ic - 3*In + Ia)); } //! Return damped pixel value, using cubic interpolation and Neumann boundary conditions for the XYZ-coordinates. @@ -13199,20 +12804,44 @@ namespace cimg_library_suffixed { return valmax_value?max_value:val; } - //! Set pixel value, using linear interpolation for the X and Y-coordinates. + //! Set pixel value, using linear interpolation for the X-coordinates. /** - Set pixel value at specified coordinates (\c fx,\c fy,\c z,\c c) in the image instance, in a way that - the value is spread amongst several neighbors if the pixel coordinates are indeed float-valued. + Set pixel value at specified coordinates (\c fx,\c y,\c z,\c c) in the image instance, in a way that + the value is spread amongst several neighbors if the pixel coordinates are float-valued. \param value Pixel value to set. \param fx X-coordinate of the pixel value (float-valued). - \param fy Y-coordinate of the pixel value (float-valued). + \param y Y-coordinate of the pixel value. \param z Z-coordinate of the pixel value. \param c C-coordinate of the pixel value. \param is_added Tells if the pixel value is added to (\c true), or simply replace (\c false) the current image pixel(s). \return A reference to the current image instance. \note - - If specified coordinates are outside image bounds, no operations are performed. + - Calling this method with out-of-bounds coordinates does nothing. + **/ + CImg& set_linear_atX(const T& value, const float fx, const int y=0, const int z=0, const int c=0, + const bool is_added=false) { + const int + x = (int)fx - (fx>=0?0:1), nx = x + 1; + const float + dx = fx - x; + if (y>=0 && y=0 && z=0 && c=0 && x=0 && nx& set_linear_atXY(const T& value, const float fx, const float fy=0, const int z=0, const int c=0, const bool is_added=false) { @@ -13225,21 +12854,21 @@ namespace cimg_library_suffixed { if (z>=0 && z=0 && c=0 && y=0 && x=0 && nx=0 && ny=0 && x=0 && nx=0 && z=0 && y=0 && x=0 && nx=0 && ny=0 && x=0 && nx=0 && nz=0 && y=0 && x=0 && nx=0 && ny=0 && x=0 && nx value_string(const char separator=',', const unsigned int max_size=0) const { if (is_empty()) return CImg::string(""); CImgList items; - char s_item[256] = { 0 }; + CImg s_item(256); *s_item = 0; const T *ptrs = _data; unsigned int string_size = 0; for (unsigned long off = 0, siz = (unsigned int)size(); off::format(),cimg::type::format(*(ptrs++))); - CImg item(s_item,printed_size); - item[printed_size-1] = separator; + CImg item(s_item._data,printed_size); + item[printed_size - 1] = separator; item.move_to(items); if (max_size) string_size+=printed_size; } @@ -13653,10 +13282,10 @@ namespace cimg_library_suffixed { \note - Return \c true only if all these conditions are verified: - The image instance is \e not empty. - - 0<=x<=\ref width()-1. - - 0<=y<=\ref height()-1. - - 0<=z<=\ref depth()-1. - - 0<=c<=\ref spectrum()-1. + - 0<=x<=\ref width() - 1. + - 0<=y<=\ref height() - 1. + - 0<=z<=\ref depth() - 1. + - 0<=c<=\ref spectrum() - 1. **/ bool containsXYZC(const int x, const int y=0, const int z=0, const int c=0) const { return !is_empty() && x>=0 && x=0 && y=0 && z=0 && c=_data+siz) return false; + if (is_empty() || ppixel<_data || ppixel>=_data + siz) return false; unsigned long off = (unsigned long)(ppixel - _data); const unsigned long nc = off/whd; off%=whd; @@ -13706,7 +13335,7 @@ namespace cimg_library_suffixed { bool contains(const T& pixel, t& x, t& y, t& z) const { const unsigned long wh = (unsigned long)_width*_height, whd = wh*_depth, siz = whd*_spectrum; const T *const ppixel = &pixel; - if (is_empty() || ppixel<_data || ppixel>=_data+siz) return false; + if (is_empty() || ppixel<_data || ppixel>=_data + siz) return false; unsigned long off = ((unsigned long)(ppixel - _data))%whd; const unsigned long nz = off/wh; off%=wh; @@ -13723,7 +13352,7 @@ namespace cimg_library_suffixed { bool contains(const T& pixel, t& x, t& y) const { const unsigned long wh = (unsigned long)_width*_height, siz = wh*_depth*_spectrum; const T *const ppixel = &pixel; - if (is_empty() || ppixel<_data || ppixel>=_data+siz) return false; + if (is_empty() || ppixel<_data || ppixel>=_data + siz) return false; unsigned long off = ((unsigned int)(ppixel - _data))%wh; const unsigned long ny = off/_width, nx = off%_width; x = (t)nx; y = (t)ny; @@ -13737,7 +13366,7 @@ namespace cimg_library_suffixed { template bool contains(const T& pixel, t& x) const { const T *const ppixel = &pixel; - if (is_empty() || ppixel<_data || ppixel>=_data+size()) return false; + if (is_empty() || ppixel<_data || ppixel>=_data + size()) return false; x = (t)(((unsigned long)(ppixel - _data))%_width); return true; } @@ -13818,7 +13447,7 @@ namespace cimg_library_suffixed { _width,primitives._width,_width,_height,_depth,_spectrum); return false; } - if (colors._width>primitives._width+1) { + if (colors._width>primitives._width + 1) { if (error_message) std::sprintf(error_message, "3d object (%u,%u) defines %u colors", _width,primitives._width,colors._width); @@ -13989,15 +13618,15 @@ namespace cimg_library_suffixed { if (error_message) std::sprintf(error_message, "CImg3d (%u,%u) is an empty object but contains %u value%s " "more than expected", - nb_points,nb_primitives,(unsigned int)(ptre-ptrs),(ptre-ptrs)>1?"s":""); + nb_points,nb_primitives,(unsigned int)(ptre - ptrs),(ptre - ptrs)>1?"s":""); return false; } return true; } - if (ptrs+3*nb_points>ptre) { + if (ptrs + 3*nb_points>ptre) { if (error_message) std::sprintf(error_message, "CImg3d (%u,%u) defines only %u vertices data", - nb_points,nb_primitives,(unsigned int)(ptre-ptrs)/3); + nb_points,nb_primitives,(unsigned int)(ptre - ptrs)/3); return false; } ptrs+=3*nb_points; @@ -14089,7 +13718,7 @@ namespace cimg_library_suffixed { if (error_message) std::sprintf(error_message, "CImg3d (%u,%u) has incomplete primitive data for primitive [%u], " "%u values missing", - nb_points,nb_primitives,p,(unsigned int)(ptrs-ptre)); + nb_points,nb_primitives,p,(unsigned int)(ptrs - ptre)); return false; } } @@ -14104,7 +13733,10 @@ namespace cimg_library_suffixed { for (unsigned int c = 0; c=c) { if (error_message) std::sprintf(error_message, @@ -14119,7 +13751,7 @@ namespace cimg_library_suffixed { if (error_message) std::sprintf(error_message, "CImg3d (%u,%u) has incomplete color/texture data for primitive [%u], " "%u values missing", - nb_points,nb_primitives,c,(unsigned int)(ptrs-ptre)); + nb_points,nb_primitives,c,(unsigned int)(ptrs - ptre)); return false; } } @@ -14133,7 +13765,10 @@ namespace cimg_library_suffixed { } for (unsigned int o = 0; o=o) { if (error_message) std::sprintf(error_message, @@ -14156,14 +13791,14 @@ namespace cimg_library_suffixed { if (ptrs1?"s":""); + nb_points,nb_primitives,(unsigned int)(ptre - ptrs),(ptre - ptrs)>1?"s":""); return false; } return true; } static bool _is_CImg3d(const T val, const char c) { - return val>=(T)c && val<(T)(c+1); + return val>=(T)c && val<(T)(c + 1); } //@} @@ -14179,11 +13814,13 @@ namespace cimg_library_suffixed { CImg opcode; const CImg* p_code; CImgList labelM; - CImg level, labelMpos, label1pos; + CImg level, labelMpos, reserved_label; CImg mem; CImg expr; const CImg& reference; CImg reference_stats; + double median_value; + bool is_median_value; unsigned int mempos, result; const char *const calling_function; typedef double (*mp_func)(_cimg_math_parser&); @@ -14200,34 +13837,25 @@ namespace cimg_library_suffixed { #if defined(_WIN64) // On Win64 and gcc 4.7, sizeof(long)!=sizeof(pointer), so a workaround is needed.. -#define _cimg_mp_enfunc(op) (long)((char*)(op)-(char*)mp_u) -#define _cimg_mp_defunc(mp) (*(mp_func)((char*)mp_u+(mp).opcode[0]))(mp) +#define _cimg_mp_enfunc(op) (long)((char*)(op) - (char*)mp_u) +#define _cimg_mp_defunc(mp) (*(mp_func)((char*)mp_u + (mp).opcode[0]))(mp) #else #define _cimg_mp_enfunc(op) (long)(op) #define _cimg_mp_defunc(mp) (*(mp_func)((mp).opcode[0]))(mp) #endif // Constructors. - _cimg_math_parser():reference(CImg::empty()),calling_function(0) {} + _cimg_math_parser():reference(CImg::empty()),median_value(0),is_median_value(false),calling_function(0) {} _cimg_math_parser(const CImg& img, const char *const expression, const char *const funcname=0): - reference(img),calling_function(funcname?funcname:"cimg_math_parser") { - unsigned int l = 0; - if (expression) { - l = (unsigned int)std::strlen(expression); - expr.assign(expression,l+1); - if (*expr._data) { - char *d = expr._data; - for (const char *s = expr._data; *s || (bool)(*d=0); ++s) if (*s!=' ') *(d++) = *s; - l = (unsigned int)(d - expr._data); - } - } - if (!l) throw CImgArgumentException("[_cimg_math_parser] " - "CImg<%s>::%s(): Empty specified expression.", - pixel_type(),calling_function); - + reference(img),median_value(0),is_median_value(false),calling_function(funcname?funcname:"cimg_math_parser") { + if (!expression || !*expression) + throw CImgArgumentException("[_cimg_math_parser] " + "CImg<%s>::%s(): Empty specified expression.", + pixel_type(),calling_function); + CImg::string(expression).move_to(expr); + level.assign(expr._width - 1); int lv = 0; // Count parentheses/brackets level of expression. - level.assign(l); unsigned int *pd = level._data; for (const char *ps = expr._data; *ps && lv>=0; ++ps) *(pd++) = (unsigned int)(*ps=='('||*ps=='['?lv++:*ps==')'||*ps==']'?--lv:lv); @@ -14237,31 +13865,43 @@ namespace cimg_library_suffixed { pixel_type(),calling_function, expr._data); } + // Init constant values. mem.assign(512); - mem[0] = 0; - mem[1] = 1; - mem[2] = 2; - mem[3] = (double)reference._width; - mem[4] = (double)reference._height; - mem[5] = (double)reference._depth; - mem[6] = (double)reference._spectrum; - mem[7] = cimg::PI; - mem[8] = std::exp(1.0); // Then [9] = x, [10] = y, [11] = z, [12] = c - mempos = 13; + mem[0] = 0.0; + mem[1] = 1.0; + mem[2] = 2.0; + mem[3] = 3.0; + mem[4] = 4.0; + mem[5] = 5.0; + mem[6] = (double)reference._width; + mem[7] = (double)reference._height; + mem[8] = (double)reference._depth; + mem[9] = (double)reference._spectrum; + mem[10] = (double)reference._is_shared; + mem[11] = (double)reference._width*reference._height; + mem[12] = (double)reference._width*reference._height*reference._depth; + mem[13] = (double)reference._width*reference._height*reference._depth*reference._spectrum; + mem[14] = cimg::PI; + mem[15] = std::exp(1.0); // Then [16] = x, [17] = y, [18] = z and [19] = c. + mempos = 20; labelMpos.assign(8); - label1pos.assign(128,1,1,1,~0U); - label1pos['w'] = 3; - label1pos['h'] = 4; - label1pos['d'] = 5; - label1pos['s'] = 6; - label1pos[0] = 7; // pi - label1pos['e'] = 8; - label1pos['x'] = 9; - label1pos['y'] = 10; - label1pos['z'] = 11; - label1pos['c'] = 12; - result = compile(expr._data,expr._data+l); // Compile formula into a serie of opcodes. + reserved_label.assign(128,1,1,1,~0U); + reserved_label['w'] = 6; + reserved_label['h'] = 7; + reserved_label['d'] = 8; + reserved_label['s'] = 9; + reserved_label['r'] = 10; + reserved_label[0] = 11; // wh + reserved_label[1] = 12; // whd + reserved_label[2] = 13; // whds + reserved_label[3] = 14; // pi + reserved_label['e'] = 15; + reserved_label['x'] = 16; + reserved_label['y'] = 17; + reserved_label['z'] = 18; + reserved_label['c'] = 19; + result = compile(expr._data,expr._data + expr._width - 1); // Compile formula into a serie of opcodes. } // Insert code instructions. @@ -14304,78 +13944,150 @@ namespace cimg_library_suffixed { } // Compilation procedure. - unsigned int compile(char *const ss, char *const se) { - if (!ss || se<=ss || !*ss) { + unsigned int compile(char *ss, char *se) { + while (*ss==' ') ++ss; + while (se>ss && *(se-1)==' ') --se; + if (se<=ss || !*ss) { throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s(): Missing item in specified expression '%s'.", pixel_type(),calling_function, expr._data); } char - *const se1 = se-1, *const se2 = se-2, *const se3 = se-3, *const se4 = se-4, - *const ss1 = ss+1, *const ss2 = ss+2, *const ss3 = ss+3, *const ss4 = ss+4, - *const ss5 = ss+5, *const ss6 = ss+6, *const ss7 = ss+7; + *const se1 = se - 1, *const se2 = se - 2, *const se3 = se - 3, *const se4 = se - 4, + *const ss1 = ss + 1, *const ss2 = ss + 2, *const ss3 = ss + 3, *const ss4 = ss + 4, + *const ss5 = ss + 5, *const ss6 = ss + 6, *const ss7 = ss + 7; const char saved_char = *se; *se = 0; - const unsigned int clevel = level[ss-expr._data], clevel1 = clevel+1; + const unsigned int clevel = level[ss - expr._data], clevel1 = clevel + 1; if (*se1==';') return compile(ss,se1); // Look for a single value, variable or variable assignment. char end = 0, sep = 0; double val = 0; - const int nb = std::sscanf(ss,"%lf%c%c",&val,&sep,&end); + int nb = cimg_sscanf(ss,"%lf%c%c",&val,&sep,&end); + +#if cimg_OS==2 + // Check for +/-NaN and +/-inf as Microsoft's sscanf() version is not able + // to read those particular values. + if (!nb && (*ss=='+' || *ss=='-' || *ss=='i' || *ss=='I' || *ss=='n' || *ss=='N')) { + bool is_positive = true; + const char *_ss = ss; + if (*_ss=='+') ++_ss; else if (*_ss=='-') { ++_ss; is_positive = false; } + if (!cimg::strcasecmp(_ss,"inf")) { val = cimg::type::inf(); nb = 1; } + else if (!cimg::strcasecmp(_ss,"nan")) { val = cimg::type::nan(); nb = 1; } + if (nb==1 && !is_positive) val = -val; + } +#endif + if (nb==1) { - if (val==0 || val==1 || val==2) _cimg_mp_return((int)val); + if (val==0 || val==1 || val==2 || val==3 || val==4 || val==5) + _cimg_mp_return((unsigned int)val); if (mempos>=mem._width) mem.resize(-200,1,1,1,0); const unsigned int pos = mempos++; mem[pos] = val; _cimg_mp_return(pos); } if (nb==2 && sep=='%') { - if (val==0 || val==100 || val==200) _cimg_mp_return((int)(val/100)); + if (val==0 || val==100 || val==200 || val==300 || val==400 || val==500) + _cimg_mp_return((unsigned int)val/100); if (mempos>=mem._width) mem.resize(-200,1,1,1,0); const unsigned int pos = mempos++; mem[pos] = val/100; _cimg_mp_return(pos); } - if (ss1==se) switch (*ss) { - case 'w' : case 'h' : case 'd' : case 's' : - case 'x' : case 'y' : case 'z' : case 'c' : case 'e' : _cimg_mp_return(label1pos[*ss]); - case 'u' : if (label1pos['u']!=~0U) _cimg_mp_return(label1pos['u']); _cimg_mp_opcode2(mp_u,0,1); - case 'g' : if (label1pos['g']!=~0U) _cimg_mp_return(label1pos['g']); _cimg_mp_opcode0(mp_g); - case 'i' : if (label1pos['i']!=~0U) _cimg_mp_return(label1pos['i']); _cimg_mp_opcode0(mp_i); + if (ss1==se) switch (*ss) { // One-char variable. + case 'w' : case 'h' : case 'd' : case 's' : case 'r' : + case 'x' : case 'y' : case 'z' : case 'c' : case 'e' : _cimg_mp_return(reserved_label[*ss]); + case 'u' : if (reserved_label['u']!=~0U) _cimg_mp_return(reserved_label['u']); _cimg_mp_opcode2(mp_u,0,1); + case 'g' : if (reserved_label['g']!=~0U) _cimg_mp_return(reserved_label['g']); _cimg_mp_opcode0(mp_g); + case 'i' : if (reserved_label['i']!=~0U) _cimg_mp_return(reserved_label['i']); _cimg_mp_opcode0(mp_i); case '?' : _cimg_mp_opcode2(mp_u,0,1); } - if (ss1==se1) { - if (*ss=='p' && *ss1=='i') _cimg_mp_return(label1pos[0]); // pi - if (*ss=='i') { - if (*ss1=='m') { if (label1pos[1]!=~0U) _cimg_mp_return(label1pos[1]); _cimg_mp_opcode0(mp_im); } // im - if (*ss1=='M') { if (label1pos[2]!=~0U) _cimg_mp_return(label1pos[2]); _cimg_mp_opcode0(mp_iM); } // iM - if (*ss1=='a') { if (label1pos[3]!=~0U) _cimg_mp_return(label1pos[3]); _cimg_mp_opcode0(mp_ia); } // ia - if (*ss1=='v') { if (label1pos[4]!=~0U) _cimg_mp_return(label1pos[4]); _cimg_mp_opcode0(mp_iv); } // iv + else if (ss2==se) { // Two-chars variable. + if (*ss=='w' && *ss1=='h') _cimg_mp_return(reserved_label[0]); // wh + if (*ss=='p' && *ss1=='i') _cimg_mp_return(reserved_label[3]); // pi + if (*ss=='i') { // im + if (*ss1=='m') { + if (!reference_stats) reference.get_stats().move_to(reference_stats); + if (reserved_label[4]!=~0U) _cimg_mp_return(reserved_label[4]); _cimg_mp_opcode0(mp_im); + } + if (*ss1=='M') { // iM + if (!reference_stats) reference.get_stats().move_to(reference_stats); + if (reserved_label[5]!=~0U) _cimg_mp_return(reserved_label[5]); _cimg_mp_opcode0(mp_iM); + } + if (*ss1=='a') { // ia + if (!reference_stats) reference.get_stats().move_to(reference_stats); + if (reserved_label[6]!=~0U) _cimg_mp_return(reserved_label[6]); _cimg_mp_opcode0(mp_ia); + } + if (*ss1=='v') { // iv + if (!reference_stats) reference.get_stats().move_to(reference_stats); + if (reserved_label[7]!=~0U) _cimg_mp_return(reserved_label[7]); _cimg_mp_opcode0(mp_iv); + } + if (*ss1=='s') { // is + if (!reference_stats) reference.get_stats().move_to(reference_stats); + if (reserved_label[8]!=~0U) _cimg_mp_return(reserved_label[8]); _cimg_mp_opcode0(mp_is); + } + if (*ss1=='p') { // ip + if (!reference_stats) reference.get_stats().move_to(reference_stats); + if (reserved_label[9]!=~0U) _cimg_mp_return(reserved_label[9]); _cimg_mp_opcode0(mp_ip); + } + if (*ss1=='c') { // ic + if (!is_median_value && reference) { median_value = reference.median(); is_median_value = true; } + if (reserved_label[10]!=~0U) _cimg_mp_return(reserved_label[10]); _cimg_mp_opcode0(mp_ic); + } } if (*ss1=='m') { - if (*ss=='x') { if (label1pos[5]!=~0U) _cimg_mp_return(label1pos[5]); _cimg_mp_opcode0(mp_xm); } // xm - if (*ss=='y') { if (label1pos[6]!=~0U) _cimg_mp_return(label1pos[6]); _cimg_mp_opcode0(mp_ym); } // ym - if (*ss=='z') { if (label1pos[7]!=~0U) _cimg_mp_return(label1pos[7]); _cimg_mp_opcode0(mp_zm); } // zm - if (*ss=='c') { if (label1pos[8]!=~0U) _cimg_mp_return(label1pos[8]); _cimg_mp_opcode0(mp_cm); } // cm + if (*ss=='x') { // xm + if (!reference_stats) reference.get_stats().move_to(reference_stats); + if (reserved_label[11]!=~0U) _cimg_mp_return(reserved_label[11]); _cimg_mp_opcode0(mp_xm); + } + if (*ss=='y') { // ym + if (!reference_stats) reference.get_stats().move_to(reference_stats); + if (reserved_label[12]!=~0U) _cimg_mp_return(reserved_label[12]); _cimg_mp_opcode0(mp_ym); + } + if (*ss=='z') { // zm + if (!reference_stats) reference.get_stats().move_to(reference_stats); + if (reserved_label[13]!=~0U) _cimg_mp_return(reserved_label[13]); _cimg_mp_opcode0(mp_zm); + } + if (*ss=='c') { // cm + if (!reference_stats) reference.get_stats().move_to(reference_stats); + if (reserved_label[14]!=~0U) _cimg_mp_return(reserved_label[14]); _cimg_mp_opcode0(mp_cm); + } } if (*ss1=='M') { - if (*ss=='x') { if (label1pos[9]!=~0U) _cimg_mp_return(label1pos[9]); _cimg_mp_opcode0(mp_xM); } // xM - if (*ss=='y') { if (label1pos[10]!=~0U) _cimg_mp_return(label1pos[10]); _cimg_mp_opcode0(mp_yM); } // yM - if (*ss=='z') { if (label1pos[11]!=~0U) _cimg_mp_return(label1pos[11]); _cimg_mp_opcode0(mp_zM); } // zM - if (*ss=='c') { if (label1pos[12]!=~0U) _cimg_mp_return(label1pos[12]); _cimg_mp_opcode0(mp_cM); } // cM + if (*ss=='x') { // xM + if (!reference_stats) reference.get_stats().move_to(reference_stats); + if (reserved_label[15]!=~0U) _cimg_mp_return(reserved_label[15]); _cimg_mp_opcode0(mp_xM); + } + if (*ss=='y') { // yM + if (!reference_stats) reference.get_stats().move_to(reference_stats); + if (reserved_label[16]!=~0U) _cimg_mp_return(reserved_label[16]); _cimg_mp_opcode0(mp_yM); + } + if (*ss=='z') { // zM + if (!reference_stats) reference.get_stats().move_to(reference_stats); + if (reserved_label[17]!=~0U) _cimg_mp_return(reserved_label[17]); _cimg_mp_opcode0(mp_zM); + } + if (*ss=='c') { // cM + if (!reference_stats) reference.get_stats().move_to(reference_stats); + if (reserved_label[18]!=~0U) _cimg_mp_return(reserved_label[18]); _cimg_mp_opcode0(mp_cM); + } } + } else if (ss3==se) { // Three-chars variable. + if (*ss=='w' && *ss1=='h' && *ss2=='d') _cimg_mp_return(reserved_label[1]); // whd + } else if (ss4==se) { // Four-chars variable. + if (*ss=='w' && *ss1=='h' && *ss2=='d' && *ss3=='s') _cimg_mp_return(reserved_label[2]); // whds } // Look for variable declarations. for (char *s = se2; s>ss; --s) - if (*s==';' && level[s-expr._data]==clevel) { compile(ss,s); _cimg_mp_return(compile(s+1,se)); } + if (*s==';' && level[s - expr._data]==clevel) { compile(ss,s); _cimg_mp_return(compile(s + 1,se)); } for (char *s = ss1, *ps = ss, *ns = ss2; s variable_name(ss,(unsigned int)(s-ss+1)); + if (*s=='=' && *ns!='=' && *ps!='=' && *ps!='>' && *ps!='<' && *ps!='!' && level[s - expr._data]==clevel) { + CImg variable_name(ss,(unsigned int)(s - ss + 1)); variable_name.back() = 0; + cimg::strpare(variable_name); bool is_valid_name = true; - if (*ss>='0' && *ss<='9') is_valid_name = false; - else for (const char *ns = ss+1; ns='0' && *variable_name<='9') is_valid_name = false; + else for (const char *ns = variable_name._data + 1; *ns; ++ns) if ((*ns<'a' || *ns>'z') && (*ns<'A' || *ns>'Z') && (*ns<'0' || *ns>'9') && *ns!='_') { is_valid_name = false; break; } @@ -14386,115 +14098,132 @@ namespace cimg_library_suffixed { "'%s%s%s'.", pixel_type(),calling_function, variable_name._data, - (ss-8)>expr._data?"...":"", - (ss-8)>expr._data?ss-8:expr._data, + (ss - 8)>expr._data?"...":"", + (ss - 8)>expr._data?ss - 8:expr._data, se<&expr.back()?"...":""); } - const unsigned int pos = compile(s+1,se); + const unsigned int pos = compile(s + 1,se); // Check for particular case of a reserved variable. - if (variable_name[0] && variable_name[1] && !variable_name[2]) { + if (variable_name[1] && !variable_name[2]) { // Two-chars variable. const char c1 = variable_name[0], c2 = variable_name[1]; - if (c1=='p' && c2=='i') variable_name.fill((char)0,(char)0); // pi + if (c1=='w' && c2=='h') variable_name.fill((char)0,(char)0); // wh + else if (c1=='p' && c2=='i') variable_name.fill(3,0); // pi else if (c1=='i') { - if (c2=='m') variable_name.fill(1,0); // im - else if (c2=='M') variable_name.fill(2,0); // iM - else if (c2=='a') variable_name.fill(3,0); // ia - else if (c2=='v') variable_name.fill(4,0); // iv + if (c2=='m') variable_name.fill(4,0); // im + else if (c2=='M') variable_name.fill(5,0); // iM + else if (c2=='a') variable_name.fill(6,0); // ia + else if (c2=='v') variable_name.fill(7,0); // iv + else if (c2=='s') variable_name.fill(8,0); // is + else if (c2=='p') variable_name.fill(9,0); // ip + else if (c2=='c') variable_name.fill(10,0); // ic } else if (c2=='m') { - if (c1=='x') variable_name.fill(5,0); // xm - else if (c1=='y') variable_name.fill(6,0); // ym - else if (c1=='z') variable_name.fill(7,0); // zm - else if (c1=='c') variable_name.fill(8,0); // cm + if (c1=='x') variable_name.fill(11,0); // xm + else if (c1=='y') variable_name.fill(12,0); // ym + else if (c1=='z') variable_name.fill(13,0); // zm + else if (c1=='c') variable_name.fill(14,0); // cm } else if (c2=='M') { - if (c1=='x') variable_name.fill(9,0); // xM - else if (c1=='y') variable_name.fill(10,0); // yM - else if (c1=='z') variable_name.fill(11,0); // zM - else if (c1=='c') variable_name.fill(12,0); // cM + if (c1=='x') variable_name.fill(15,0); // xM + else if (c1=='y') variable_name.fill(16,0); // yM + else if (c1=='z') variable_name.fill(17,0); // zM + else if (c1=='c') variable_name.fill(18,0); // cM } - } - if (variable_name[1]) { // Multi-char variable. + } else if (variable_name[1] && variable_name[2] && !variable_name[3]) { // Three-chars variable. + const char c1 = variable_name[0], c2 = variable_name[1], c3 = variable_name[2]; + if (c1=='w' && c2=='h' && c3=='d') variable_name.fill(1,0,0); // whd + } else if (variable_name[1] && variable_name[2] && variable_name[3] && + !variable_name[4]) { // Four-chars variable. + const char c1 = variable_name[0], c2 = variable_name[1], c3 = variable_name[2], + c4 = variable_name[3]; + if (c1=='w' && c2=='h' && c3=='d' && c4=='s') variable_name.fill(2,0,0,0); // whds + } + + // Set new variable value. + if (!variable_name[1]) reserved_label[*variable_name] = pos; + else { int label_pos = -1; cimglist_for(labelM,i) // Check for existing variable with same name. if (!std::strcmp(variable_name,labelM[i])) { label_pos = i; break; } if (label_pos<0) { // If new variable. if (labelM._width>=labelMpos._width) labelMpos.resize(-200,1,1,1,0); - label_pos = labelM._width; + label_pos = labelM.width(); variable_name.move_to(labelM); } labelMpos[label_pos] = pos; - } else label1pos[*variable_name] = pos; // Single-char variable. + } _cimg_mp_return(pos); } // Look for unary/binary operators. The operator precedences is defined as in C++. - for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='|' && *ns=='|' && level[s-expr._data]==clevel) { - const unsigned int mem_A = compile(ss,s), bp1 = code._width, mem_B = compile(s+2,se); + for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='|' && *ns=='|' && level[s - expr._data]==clevel) { + const unsigned int mem_A = compile(ss,s), bp1 = code._width, mem_B = compile(s + 2,se); if (mempos>=mem._width) mem.resize(-200,1,1,1,0); const unsigned int pos = mempos++; - CImg::vector(_cimg_mp_enfunc(mp_logical_or),pos,mem_A,mem_B,code._width-bp1).move_to(code,bp1); + CImg::vector(_cimg_mp_enfunc(mp_logical_or),pos,mem_A,mem_B,code._width - bp1).move_to(code,bp1); _cimg_mp_return(pos); } - for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='&' && *ns=='&' && level[s-expr._data]==clevel) { - const unsigned int mem_A = compile(ss,s), bp1 = code._width, mem_B = compile(s+2,se); + for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='&' && *ns=='&' && level[s - expr._data]==clevel) { + const unsigned int mem_A = compile(ss,s), bp1 = code._width, mem_B = compile(s + 2,se); if (mempos>=mem._width) mem.resize(-200,1,1,1,0); const unsigned int pos = mempos++; - CImg::vector(_cimg_mp_enfunc(mp_logical_and),pos,mem_A,mem_B,code._width-bp1).move_to(code,bp1); + CImg::vector(_cimg_mp_enfunc(mp_logical_and),pos,mem_A,mem_B,code._width - bp1).move_to(code,bp1); _cimg_mp_return(pos); } for (char *s = se2; s>ss; --s) - if (*s=='|' && level[s-expr._data]==clevel) - _cimg_mp_opcode2(mp_bitwise_or,compile(ss,s),compile(s+1,se)); + if (*s=='|' && level[s - expr._data]==clevel) + _cimg_mp_opcode2(mp_bitwise_or,compile(ss,s),compile(s + 1,se)); for (char *s = se2; s>ss; --s) - if (*s=='&' && level[s-expr._data]==clevel) - _cimg_mp_opcode2(mp_bitwise_and,compile(ss,s),compile(s+1,se)); + if (*s=='&' && level[s - expr._data]==clevel) + _cimg_mp_opcode2(mp_bitwise_and,compile(ss,s),compile(s + 1,se)); for (char *s = se3, *ns = se2; s>ss; --s, --ns) - if (*s=='!' && *ns=='=' && level[s-expr._data]==clevel) - _cimg_mp_opcode2(mp_noteq,compile(ss,s),compile(s+2,se)); + if (*s=='!' && *ns=='=' && level[s - expr._data]==clevel) + _cimg_mp_opcode2(mp_noteq,compile(ss,s),compile(s + 2,se)); for (char *s = se3, *ns = se2; s>ss; --s, --ns) - if (*s=='=' && *ns=='=' && level[s-expr._data]==clevel) - _cimg_mp_opcode2(mp_eqeq,compile(ss,s),compile(s+2,se)); + if (*s=='=' && *ns=='=' && level[s - expr._data]==clevel) + _cimg_mp_opcode2(mp_eqeq,compile(ss,s),compile(s + 2,se)); for (char *s = se3, *ns = se2; s>ss; --s, --ns) - if (*s=='<' && *ns=='=' && level[s-expr._data]==clevel) - _cimg_mp_opcode2(mp_infeq,compile(ss,s),compile(s+2,se)); + if (*s=='<' && *ns=='=' && level[s - expr._data]==clevel) + _cimg_mp_opcode2(mp_infeq,compile(ss,s),compile(s + 2,se)); for (char *s = se3, *ns = se2; s>ss; --s, --ns) - if (*s=='>' && *ns=='=' && level[s-expr._data]==clevel) - _cimg_mp_opcode2(mp_supeq,compile(ss,s),compile(s+2,se)); + if (*s=='>' && *ns=='=' && level[s - expr._data]==clevel) + _cimg_mp_opcode2(mp_supeq,compile(ss,s),compile(s + 2,se)); for (char *s = se2, *ns = se1, *ps = se3; s>ss; --s, --ns, --ps) - if (*s=='<' && *ns!='<' && *ps!='<' && level[s-expr._data]==clevel) - _cimg_mp_opcode2(mp_inf,compile(ss,s),compile(s+1,se)); + if (*s=='<' && *ns!='<' && *ps!='<' && level[s - expr._data]==clevel) + _cimg_mp_opcode2(mp_inf,compile(ss,s),compile(s + 1,se)); for (char *s = se2, *ns = se1, *ps = se3; s>ss; --s, --ns, --ps) - if (*s=='>' && *ns!='>' && *ps!='>' && level[s-expr._data]==clevel) - _cimg_mp_opcode2(mp_sup,compile(ss,s),compile(s+1,se)); + if (*s=='>' && *ns!='>' && *ps!='>' && level[s - expr._data]==clevel) + _cimg_mp_opcode2(mp_sup,compile(ss,s),compile(s + 1,se)); for (char *s = se3, *ns = se2; s>ss; --s, --ns) - if (*s=='<' && *ns=='<' && level[s-expr._data]==clevel) - _cimg_mp_opcode2(mp_lsl,compile(ss,s),compile(s+2,se)); + if (*s=='<' && *ns=='<' && level[s - expr._data]==clevel) + _cimg_mp_opcode2(mp_lsl,compile(ss,s),compile(s + 2,se)); for (char *s = se3, *ns = se2; s>ss; --s, --ns) - if (*s=='>' && *ns=='>' && level[s-expr._data]==clevel) - _cimg_mp_opcode2(mp_lsr,compile(ss,s),compile(s+2,se)); + if (*s=='>' && *ns=='>' && level[s - expr._data]==clevel) + _cimg_mp_opcode2(mp_lsr,compile(ss,s),compile(s + 2,se)); for (char *s = se2, *ps = se3; s>ss; --s, --ps) if (*s=='+' && *ps!='-' && *ps!='+' && *ps!='*' && *ps!='/' && *ps!='%' && *ps!='&' && *ps!='|' && *ps!='^' && *ps!='!' && *ps!='~' && - (*ps!='e' || !(ps>ss && (*(ps-1)=='.' || (*(ps-1)>='0' && *(ps-1)<='9')))) && level[s-expr._data]==clevel) - _cimg_mp_opcode2(mp_add,compile(ss,s),compile(s+1,se)); + (*ps!='e' || !(ps>ss && (*(ps - 1)=='.' || (*(ps - 1)>='0' && *(ps - 1)<='9')))) && + level[s - expr._data]==clevel) + _cimg_mp_opcode2(mp_add,compile(ss,s),compile(s + 1,se)); for (char *s = se2, *ps = se3; s>ss; --s, --ps) if (*s=='-' && *ps!='-' && *ps!='+' && *ps!='*' && *ps!='/' && *ps!='%' && *ps!='&' && *ps!='|' && *ps!='^' && *ps!='!' && *ps!='~' && - (*ps!='e' || !(ps>ss && (*(ps-1)=='.' || (*(ps-1)>='0' && *(ps-1)<='9')))) && level[s-expr._data]==clevel) - _cimg_mp_opcode2(mp_sub,compile(ss,s),compile(s+1,se)); - for (char *s = se2; s>ss; --s) if (*s=='*' && level[s-expr._data]==clevel) { - const unsigned int mem_A = compile(ss,s), bp1 = code._width, mem_B = compile(s+1,se); + (*ps!='e' || !(ps>ss && (*(ps - 1)=='.' || (*(ps - 1)>='0' && *(ps - 1)<='9')))) && + level[s - expr._data]==clevel) + _cimg_mp_opcode2(mp_sub,compile(ss,s),compile(s + 1,se)); + for (char *s = se2; s>ss; --s) if (*s=='*' && level[s - expr._data]==clevel) { + const unsigned int mem_A = compile(ss,s), bp1 = code._width, mem_B = compile(s + 1,se); if (mempos>=mem._width) mem.resize(-200,1,1,1,0); const unsigned int pos = mempos++; - CImg::vector(_cimg_mp_enfunc(mp_mul),pos,mem_A,mem_B,code._width-bp1).move_to(code,bp1); + CImg::vector(_cimg_mp_enfunc(mp_mul),pos,mem_A,mem_B,code._width - bp1).move_to(code,bp1); _cimg_mp_return(pos); } for (char *s = se2; s>ss; --s) - if (*s=='/' && level[s-expr._data]==clevel) - _cimg_mp_opcode2(mp_div,compile(ss,s),compile(s+1,se)); + if (*s=='/' && level[s - expr._data]==clevel) + _cimg_mp_opcode2(mp_div,compile(ss,s),compile(s + 1,se)); for (char *s = se2, *ns = se1; s>ss; --s, --ns) - if (*s=='%' && *ns!='^' && level[s-expr._data]==clevel) - _cimg_mp_opcode2(mp_modulo,compile(ss,s),compile(s+1,se)); + if (*s=='%' && *ns!='^' && level[s - expr._data]==clevel) + _cimg_mp_opcode2(mp_modulo,compile(ss,s),compile(s + 1,se)); if (ssss; --s) - if (*s=='^' && level[s-expr._data]==clevel) - _cimg_mp_opcode2(mp_pow,compile(ss,s),compile(s+1,se)); + if (*s=='^' && level[s - expr._data]==clevel) + _cimg_mp_opcode2(mp_pow,compile(ss,s),compile(s + 1,se)); - // Look for a function call or a parenthesis. + // Array-like access to image values 'i[]' and 'j[]'. if (*se1==']') { const bool is_relative = *ss=='j'; if ((*ss=='i' || is_relative) && *ss1=='[') { @@ -14513,122 +14242,113 @@ namespace cimg_library_suffixed { _cimg_mp_opcode1(is_relative?mp_joff:mp_ioff,compile(ss2,se1)); } } + + // Look for a function call or a parenthesis. if (*se1==')') { if (*ss=='(') _cimg_mp_return(compile(ss1,se1)); + + const bool is_relative = *ss=='j'; + if ((*ss=='i' || is_relative) && *ss1=='(') { + if (*ss2==')') _cimg_mp_opcode0(mp_i); + unsigned int + indx = is_relative?0U:16U, indy = is_relative?0U:17U, + indz = is_relative?0U:18U, indc = is_relative?0U:19U, + borders = 0, interpolation = 0; + if (ss2!=se1) { + char *s1 = ss2; while (s1=mem._width) mem.resize(-200,1,1,1,0); const unsigned int pos = mempos++; - CImg::vector(_cimg_mp_enfunc(mp_if),pos,mem_cond,mem_A,mem_B,bp2-bp1,code._width-bp2). + CImg::vector(_cimg_mp_enfunc(mp_if),pos,mem_cond,mem_A,mem_B,bp2 - bp1,code._width - bp2). move_to(code,bp1); _cimg_mp_return(pos); } - if (!std::strncmp(ss,"round(",6)) { - unsigned int value = 0, round = 1, direction = 0; - char *s1 = ss6; while (s1 opcode; if (mempos>=mem.size()) mem.resize(-200,1,1,1,0); const unsigned int pos = mempos++; - CImg::vector(_cimg_mp_enfunc(*ss=='k'?mp_kth:ss[1]=='i'?mp_min:ss[1]=='a'?mp_max:mp_med),pos). + CImg::vector(_cimg_mp_enfunc(*ss=='a'?mp_arg:*ss=='k'?mp_kth:ss[1]=='i'?mp_min: + ss[1]=='a'?mp_max:mp_med),pos). move_to(opcode); for (char *s = ss4; s::vector(compile(s,ns)).move_to(opcode); s = ns; } (opcode>'y').move_to(code); _cimg_mp_return(pos); } - if (!std::strncmp(ss,"arg(",4)) { - CImgList opcode; - if (mempos>=mem.size()) mem.resize(-200,1,1,1,0); - const unsigned int pos = mempos++; - CImg::vector(_cimg_mp_enfunc(mp_arg),pos).move_to(opcode); - for (char *s = ss4; s::vector(compile(s,ns)).move_to(opcode); - s = ns; + if (!std::strncmp(ss,"rol(",4) || !std::strncmp(ss,"ror(",4)) { + unsigned int value = 0, nb = 1; + char *s1 = ss4; while (s1'y').move_to(code); - _cimg_mp_return(pos); + _cimg_mp_opcode2(*ss2=='l'?mp_rol:mp_ror,value,nb); } if (!std::strncmp(ss,"narg(",5)) { if (*ss5==')') _cimg_mp_return(0); unsigned int nb_args = 0; for (char *s = ss5; s opcode; + if (mempos>=mem.size()) mem.resize(-200,1,1,1,0); + const unsigned int pos = mempos++; + CImg::vector(_cimg_mp_enfunc(mp_norm),pos,(longT)(norm_type==~0U?-1:(int)norm_type)). + move_to(opcode); + for (char *s = std::strchr(ss5,'(') + 1; s::vector(compile(s,ns)).move_to(opcode); + s = ns; + } + (opcode>'y').move_to(code); + _cimg_mp_return(pos); + } + if (!std::strncmp(ss,"date(",5)) { + char *s1 = ss5; while (s1=mem.size()) mem.resize(-200,1,1,1,0); + const unsigned int pos = mempos++; + mem[pos] = d; + _cimg_mp_return(pos); + } + if (!std::strncmp(ss,"fdate(",6)) { + char *s1 = ss6; while (s1=mem.size()) mem.resize(-200,1,1,1,0); + const unsigned int pos = mempos++; + mem[pos] = d; + _cimg_mp_return(pos); } - if (!std::strncmp(ss,"sinc(",5)) _cimg_mp_opcode1(mp_sinc,compile(ss5,se1)); - if (!std::strncmp(ss,"int(",4)) _cimg_mp_opcode1(mp_int,compile(ss4,se1)); + // Sub-family of 'is_?()' functions. + if (*ss=='i' && *ss1=='s') { + if (!std::strncmp(ss,"isin(",5)) { + CImgList opcode; + if (mempos>=mem.size()) mem.resize(-200,1,1,1,0); + const unsigned int pos = mempos++; + CImg::vector(_cimg_mp_enfunc(mp_isin),pos).move_to(opcode); + for (char *s = ss5; s::vector(compile(s,ns)).move_to(opcode); + s = ns; + } + (opcode>'y').move_to(code); + _cimg_mp_return(pos); + } + if (!std::strncmp(ss,"isval(",6)) { + double val = 0; + if (cimg_sscanf(ss6,"%lf%c%c",&val,&sep,&end)==2 && sep==')') _cimg_mp_return(1); + _cimg_mp_return(0); + } + if (!std::strncmp(ss,"isdir(",6)) { + *se1 = 0; + const bool is_dir = cimg::is_directory(ss6); + *se1 = ')'; + _cimg_mp_return(is_dir?1U:0U); + } + if (!std::strncmp(ss,"isfile(",7)) { + *se1 = 0; + const bool is_file = cimg::is_file(ss7); + *se1 = ')'; + _cimg_mp_return(is_file?1U:0U); + } + if (!std::strncmp(ss,"isnan(",6)) _cimg_mp_opcode1(mp_isnan,compile(ss6,se1)); + if (!std::strncmp(ss,"isinf(",6)) _cimg_mp_opcode1(mp_isinf,compile(ss6,se1)); + if (!std::strncmp(ss,"isint(",6)) _cimg_mp_opcode1(mp_isint,compile(ss6,se1)); + if (!std::strncmp(ss,"isbool(",7)) _cimg_mp_opcode1(mp_isbool,compile(ss7,se1)); + } } // No known item found, assuming this is an already initialized variable. - CImg variable_name(ss,(unsigned int)(se-ss+1)); + CImg variable_name(ss,(unsigned int)(se - ss + 1)); variable_name.back() = 0; if (variable_name[1]) { // Multi-char variable. cimglist_for(labelM,i) if (!std::strcmp(variable_name,labelM[i])) _cimg_mp_return(labelMpos[i]); - } else if (label1pos[*variable_name]!=~0U) _cimg_mp_return(label1pos[*variable_name]); // Single-char variable. + } else if (reserved_label[*variable_name]!=~0U) // Single-char variable. + _cimg_mp_return(reserved_label[*variable_name]); *se = saved_char; throw CImgArgumentException("[_cimg_math_parser] " "CImg<%s>::%s(): Invalid item '%s' in specified expression '%s%s%s'.\n", pixel_type(),calling_function, variable_name._data, - (ss-8)>expr._data?"...":"", - (ss-8)>expr._data?ss-8:expr._data, + (ss - 8)>expr._data?"...":"", + (ss - 8)>expr._data?ss - 8:expr._data, se<&expr.back()?"...":""); } @@ -14681,14 +14485,14 @@ namespace cimg_library_suffixed { // Defining these functions 'static' ensures that sizeof(mp_func)==sizeof(ulong), so we can store pointers to them // directly in the opcode vectors. static double mp_u(_cimg_math_parser& mp) { - return mp.mem[mp.opcode(2)] + cimg::rand()*(mp.mem[mp.opcode(3)]-mp.mem[mp.opcode(2)]); + return mp.mem[mp.opcode(2)] + cimg::rand()*(mp.mem[mp.opcode(3)] - mp.mem[mp.opcode(2)]); } static double mp_g(_cimg_math_parser& mp) { cimg::unused(mp); return cimg::grand(); } static double mp_i(_cimg_math_parser& mp) { - return (double)mp.reference.atXYZC((int)mp.mem[9],(int)mp.mem[10],(int)mp.mem[11],(int)mp.mem[12],0); + return (double)mp.reference.atXYZC((int)mp.mem[16],(int)mp.mem[17],(int)mp.mem[18],(int)mp.mem[19],0); } static double mp_logical_and(_cimg_math_parser& mp) { const bool is_A = (bool)mp.mem[mp.opcode(2)]; @@ -14762,9 +14566,6 @@ namespace cimg_library_suffixed { static double mp_minus(_cimg_math_parser& mp) { return -mp.mem[mp.opcode(2)]; } - static double mp_not(_cimg_math_parser& mp) { - return !mp.mem[mp.opcode(2)]; - } static double mp_logical_not(_cimg_math_parser& mp) { return !mp.mem[mp.opcode(2)]; } @@ -14829,12 +14630,63 @@ namespace cimg_library_suffixed { static double mp_exp(_cimg_math_parser& mp) { return std::exp(mp.mem[mp.opcode(2)]); } + static double mp_sqr(_cimg_math_parser& mp) { + return cimg::sqr(mp.mem[mp.opcode(2)]); + } static double mp_sqrt(_cimg_math_parser& mp) { return std::sqrt(mp.mem[mp.opcode(2)]); } + static double mp_cbrt(_cimg_math_parser& mp) { + return std::pow(mp.mem[mp.opcode(2)],1.0/3); + } + static double mp_hypot(_cimg_math_parser& mp) { + double + x = cimg::abs(mp.mem[mp.opcode(2)]), + y = cimg::abs(mp.mem[mp.opcode(3)]), + t; + if (x0) { t/=x; return x*std::sqrt(1+t*t); } + return 0; + } + static double mp_norm(_cimg_math_parser& mp) { + const unsigned int norm_type = (unsigned int)mp.opcode(2); + double res = 0; + switch (norm_type) { + case 0 : // L0-norm. + for (unsigned int i = 3; ires) res = val; + } + break; + default: // Lp-norm. + for (unsigned int i = 3; i0?res:0.0; + } static double mp_sign(_cimg_math_parser& mp) { return cimg::sign(mp.mem[mp.opcode(2)]); } + static double mp_time(_cimg_math_parser& mp) { + cimg::unused(mp); + return (double)cimg::time(); + } static double mp_abs(_cimg_math_parser& mp) { return cimg::abs(mp.mem[mp.opcode(2)]); } @@ -14870,64 +14722,46 @@ namespace cimg_library_suffixed { return cimg::round(mp.mem[mp.opcode(2)],mp.mem[mp.opcode(3)],(int)mp.mem[mp.opcode(4)]); } static double mp_ixyzc(_cimg_math_parser& mp) { + const double + x = mp.mem[mp.opcode(2)], y = mp.mem[mp.opcode(3)], z = mp.mem[mp.opcode(4)], c = mp.mem[mp.opcode(5)]; const int i = (int)mp.mem[mp.opcode(6)], b = (int)mp.mem[mp.opcode(7)]; if (i==0) { // Nearest neighbor interpolation. - if (b==2) return (double)mp.reference.atXYZC(cimg::mod((int)mp.mem[mp.opcode(2)],mp.reference.width()), - cimg::mod((int)mp.mem[mp.opcode(3)],mp.reference.height()), - cimg::mod((int)mp.mem[mp.opcode(4)],mp.reference.depth()), - cimg::mod((int)mp.mem[mp.opcode(5)],mp.reference.spectrum())); - if (b==1) return (double)mp.reference.atXYZC((int)mp.mem[mp.opcode(2)], - (int)mp.mem[mp.opcode(3)], - (int)mp.mem[mp.opcode(4)], - (int)mp.mem[mp.opcode(5)]); - return (double)mp.reference.atXYZC((int)mp.mem[mp.opcode(2)], - (int)mp.mem[mp.opcode(3)], - (int)mp.mem[mp.opcode(4)], - (int)mp.mem[mp.opcode(5)],0); + if (b==2) return (double)mp.reference.atXYZC(cimg::mod((int)x,mp.reference.width()), + cimg::mod((int)y,mp.reference.height()), + cimg::mod((int)z,mp.reference.depth()), + cimg::mod((int)c,mp.reference.spectrum())); + if (b==1) return (double)mp.reference.atXYZC((int)x,(int)y,(int)z,(int)c); + return (double)mp.reference.atXYZC((int)x,(int)y,(int)z,(int)c,0); } else { // Linear interpolation. - if (b==2) return (double)mp.reference.linear_atXYZC(cimg::mod((float)mp.mem[mp.opcode(2)],(float)mp.reference.width()), - cimg::mod((float)mp.mem[mp.opcode(3)],(float)mp.reference.height()), - cimg::mod((float)mp.mem[mp.opcode(4)],(float)mp.reference.depth()), - cimg::mod((float)mp.mem[mp.opcode(5)],(float)mp.reference.spectrum())); - if (b==1) return (double)mp.reference.linear_atXYZC((float)mp.mem[mp.opcode(2)], - (float)mp.mem[mp.opcode(3)], - (float)mp.mem[mp.opcode(4)], - (float)mp.mem[mp.opcode(5)]); - return (double)mp.reference.linear_atXYZC((float)mp.mem[mp.opcode(2)], - (float)mp.mem[mp.opcode(3)], - (float)mp.mem[mp.opcode(4)], - (float)mp.mem[mp.opcode(5)],0); + if (b==2) return (double)mp.reference.linear_atXYZC(cimg::mod((float)x,(float)mp.reference.width()), + cimg::mod((float)y,(float)mp.reference.height()), + cimg::mod((float)z,(float)mp.reference.depth()), + cimg::mod((float)c,(float)mp.reference.spectrum())); + if (b==1) return (double)mp.reference.linear_atXYZC((float)x,(float)y,(float)z,(float)c); + return (double)mp.reference.linear_atXYZC((float)x,(float)y,(float)z,(float)c,0); } } static double mp_jxyzc(_cimg_math_parser& mp) { - const double x = mp.mem[9], y = mp.mem[10], z = mp.mem[11], c = mp.mem[12]; + const double x = mp.mem[16], y = mp.mem[17], z = mp.mem[18], c = mp.mem[19]; + const double + dx = mp.mem[mp.opcode(2)], dy = mp.mem[mp.opcode(3)], dz = mp.mem[mp.opcode(4)], dc = mp.mem[mp.opcode(5)]; const int i = (int)mp.mem[mp.opcode(6)], b = (int)mp.mem[mp.opcode(7)]; if (i==0) { // Nearest neighbor interpolation. - if (b==2) return (double)mp.reference.atXYZC(cimg::mod((int)(x+mp.mem[mp.opcode(2)]),mp.reference.width()), - cimg::mod((int)(y+mp.mem[mp.opcode(3)]),mp.reference.height()), - cimg::mod((int)(z+mp.mem[mp.opcode(4)]),mp.reference.depth()), - cimg::mod((int)(c+mp.mem[mp.opcode(5)]),mp.reference.spectrum())); - if (b==1) return (double)mp.reference.atXYZC((int)(x+mp.mem[mp.opcode(2)]), - (int)(y+mp.mem[mp.opcode(3)]), - (int)(z+mp.mem[mp.opcode(4)]), - (int)(c+mp.mem[mp.opcode(5)])); - return (double)mp.reference.atXYZC((int)(x+mp.mem[mp.opcode(2)]), - (int)(y+mp.mem[mp.opcode(3)]), - (int)(z+mp.mem[mp.opcode(4)]), - (int)(c+mp.mem[mp.opcode(5)]),0); + if (b==2) return (double)mp.reference.atXYZC(cimg::mod((int)(x + dx),mp.reference.width()), + cimg::mod((int)(y + dy),mp.reference.height()), + cimg::mod((int)(z + dz),mp.reference.depth()), + cimg::mod((int)(c + dc),mp.reference.spectrum())); + if (b==1) return (double)mp.reference.atXYZC((int)(x + dx),(int)(y + dy),(int)(z + dz),(int)(c + dc)); + return (double)mp.reference.atXYZC((int)(x + dx),(int)(y + dy),(int)(z + dz),(int)(c + dc),0); } else { // Linear interpolation. - if (b==2) return (double)mp.reference.linear_atXYZC(cimg::mod((float)(x+mp.mem[mp.opcode(2)]),(float)mp.reference.width()), - cimg::mod((float)(y+mp.mem[mp.opcode(3)]),(float)mp.reference.height()), - cimg::mod((float)(z+mp.mem[mp.opcode(4)]),(float)mp.reference.depth()), - cimg::mod((float)(c+mp.mem[mp.opcode(5)]),(float)mp.reference.spectrum())); - if (b==1) return (double)mp.reference.linear_atXYZC((float)(x+mp.mem[mp.opcode(2)]), - (float)(y+mp.mem[mp.opcode(3)]), - (float)(z+mp.mem[mp.opcode(4)]), - (float)(c+mp.mem[mp.opcode(5)])); - return (double)mp.reference.linear_atXYZC((float)(x+mp.mem[mp.opcode(2)]), - (float)(y+mp.mem[mp.opcode(3)]), - (float)(z+mp.mem[mp.opcode(4)]), - (float)(c+mp.mem[mp.opcode(5)]),0); + if (b==2) + return (double)mp.reference.linear_atXYZC(cimg::mod((float)(x + dx),(float)mp.reference.width()), + cimg::mod((float)(y + dy),(float)mp.reference.height()), + cimg::mod((float)(z + dz),(float)mp.reference.depth()), + cimg::mod((float)(c + dc),(float)mp.reference.spectrum())); + if (b==1) return (double)mp.reference.linear_atXYZC((float)(x + dx),(float)(y + dy), + (float)(z + dz),(float)(c + dc)); + return (double)mp.reference.linear_atXYZC((float)(x + dx),(float)(y + dy),(float)(z + dz),(float)(c + dc),0); } } static double mp_min(_cimg_math_parser& mp) { @@ -14941,19 +14775,25 @@ namespace cimg_library_suffixed { return val; } static double mp_med(_cimg_math_parser& mp) { - CImg values(mp.opcode._height-2); + CImg values(mp.opcode._height - 2); double *p = values.data(); for (unsigned int i = 2; i values(mp.opcode._height-3); + CImg values(mp.opcode._height - 3); double *p = values.data(); for (unsigned int i = 3; i=nb_args) return 0; - return mp.mem[mp.opcode(ind+2)]; + return mp.mem[mp.opcode(ind + 2)]; } static double mp_int(_cimg_math_parser& mp) { return (double)(long)mp.mem[mp.opcode(2)]; @@ -15049,7 +14886,7 @@ namespace cimg_library_suffixed { return (double)mp.reference[off]; } static double mp_joff(_cimg_math_parser& mp) { - const int x = (int)mp.mem[9], y = (int)mp.mem[10], z = (int)mp.mem[11], c = (int)mp.mem[12]; + const int x = (int)mp.mem[16], y = (int)mp.mem[17], z = (int)mp.mem[18], c = (int)mp.mem[19]; const unsigned long off = mp.reference.offset(x,y,z,c) + (unsigned long)(mp.mem[mp.opcode(2)]); if (off>=mp.reference.size()) return 0; return (double)mp.reference[off]; @@ -15058,7 +14895,7 @@ namespace cimg_library_suffixed { // Evaluation procedure, with image data. double operator()(const double x, const double y, const double z, const double c) { if (!mem) return 0; - mem[9] = x; mem[10] = y; mem[11] = z; mem[12] = c; + mem[16] = x; mem[17] = y; mem[18] = z; mem[19] = c; opcode._is_shared = true; opcode._width = opcode._depth = opcode._spectrum = 1; for (p_code = code._data; p_code& pow(const char *const expression) { if (is_empty()) return *this; const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); try { const CImg _base = cimg::_is_self_expr(expression)?+*this:CImg(), &base = _base?_base:*this; - _cimg_math_parser mp(base,expression+(*expression=='>' || *expression=='<'?1:0),"pow"); - T *ptrd = *expression=='<'?end()-1:_data; + _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"pow"); + T *ptrd = *expression=='<'?end() - 1:_data; if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)std::pow((double)*ptrd,mp(x,y,z,c)); --ptrd; } else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)std::pow((double)*ptrd,mp(x,y,z,c)); ++ptrd; } @@ -15698,12 +15535,12 @@ namespace cimg_library_suffixed { try { values.fill(expression,true); } catch (CImgException&) { - cimg::exception_mode() = omode; + cimg::exception_mode(omode); values.load(expression); } pow(values); } - cimg::exception_mode() = omode; + cimg::exception_mode(omode); return *this; } @@ -15761,11 +15598,11 @@ namespace cimg_library_suffixed { CImg& rol(const char *const expression) { if (is_empty()) return *this; const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); try { const CImg _base = cimg::_is_self_expr(expression)?+*this:CImg(), &base = _base?_base:*this; - _cimg_math_parser mp(base,expression+(*expression=='>' || *expression=='<'?1:0),"rol"); - T *ptrd = *expression=='<'?end()-1:_data; + _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"rol"); + T *ptrd = *expression=='<'?end() - 1:_data; if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::rol(*ptrd,(unsigned int)mp(x,y,z,c)); --ptrd; } else if (*expression=='>') @@ -15791,12 +15628,12 @@ namespace cimg_library_suffixed { try { values.fill(expression,true); } catch (CImgException&) { - cimg::exception_mode() = omode; + cimg::exception_mode(omode); values.load(expression); } rol(values); } - cimg::exception_mode() = omode; + cimg::exception_mode(omode); return *this; } @@ -15854,11 +15691,11 @@ namespace cimg_library_suffixed { CImg& ror(const char *const expression) { if (is_empty()) return *this; const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); try { const CImg _base = cimg::_is_self_expr(expression)?+*this:CImg(), &base = _base?_base:*this; - _cimg_math_parser mp(base,expression+(*expression=='>' || *expression=='<'?1:0),"ror"); - T *ptrd = *expression=='<'?end()-1:_data; + _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"ror"); + T *ptrd = *expression=='<'?end() - 1:_data; if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::ror(*ptrd,(unsigned int)mp(x,y,z,c)); --ptrd; } else if (*expression=='>') @@ -15884,12 +15721,12 @@ namespace cimg_library_suffixed { try { values.fill(expression,true); } catch (CImgException&) { - cimg::exception_mode() = omode; + cimg::exception_mode(omode); values.load(expression); } ror(values); } - cimg::exception_mode() = omode; + cimg::exception_mode(omode); return *this; } @@ -15928,7 +15765,7 @@ namespace cimg_library_suffixed { \note Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by \f$\mathrm{min}(I_{(x,y,z,c)},\mathrm{val})\f$. **/ - CImg& min(const T val) { + CImg& min(const T& val) { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for if (size()>=65536) @@ -15938,7 +15775,7 @@ namespace cimg_library_suffixed { } //! Pointwise min operator between instance image and a value \newinstance. - CImg get_min(const T val) const { + CImg get_min(const T& val) const { return (+*this).min(val); } @@ -15977,11 +15814,11 @@ namespace cimg_library_suffixed { CImg& min(const char *const expression) { if (is_empty()) return *this; const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); try { const CImg _base = cimg::_is_self_expr(expression)?+*this:CImg(), &base = _base?_base:*this; - _cimg_math_parser mp(base,expression+(*expression=='>' || *expression=='<'?1:0),"min"); - T *ptrd = *expression=='<'?end()-1:_data; + _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"min"); + T *ptrd = *expression=='<'?end() - 1:_data; if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::min(*ptrd,(T)mp(x,y,z,c)); --ptrd; } else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::min(*ptrd,(T)mp(x,y,z,c)); ++ptrd; } else { @@ -16005,12 +15842,12 @@ namespace cimg_library_suffixed { try { values.fill(expression,true); } catch (CImgException&) { - cimg::exception_mode() = omode; + cimg::exception_mode(omode); values.load(expression); } min(values); } - cimg::exception_mode() = omode; + cimg::exception_mode(omode); return *this; } @@ -16025,7 +15862,7 @@ namespace cimg_library_suffixed { \note Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by \f$\mathrm{max}(I_{(x,y,z,c)},\mathrm{val})\f$. **/ - CImg& max(const T val) { + CImg& max(const T& val) { if (is_empty()) return *this; #ifdef cimg_use_openmp #pragma omp parallel for if (size()>=65536) @@ -16035,7 +15872,7 @@ namespace cimg_library_suffixed { } //! Pointwise max operator between instance image and a value \newinstance. - CImg get_max(const T val) const { + CImg get_max(const T& val) const { return (+*this).max(val); } @@ -16074,11 +15911,11 @@ namespace cimg_library_suffixed { CImg& max(const char *const expression) { if (is_empty()) return *this; const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); try { const CImg _base = cimg::_is_self_expr(expression)?+*this:CImg(), &base = _base?_base:*this; - _cimg_math_parser mp(base,expression+(*expression=='>' || *expression=='<'?1:0),"max"); - T *ptrd = *expression=='<'?end()-1:_data; + _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"max"); + T *ptrd = *expression=='<'?end() - 1:_data; if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::max(*ptrd,(T)mp(x,y,z,c)); --ptrd; } else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::max(*ptrd,(T)mp(x,y,z,c)); ++ptrd; } else { @@ -16102,12 +15939,12 @@ namespace cimg_library_suffixed { try { values.fill(expression,true); } catch (CImgException&) { - cimg::exception_mode() = omode; + cimg::exception_mode(omode); values.load(expression); } max(values); } - cimg::exception_mode() = omode; + cimg::exception_mode(omode); return *this; } @@ -16258,24 +16095,24 @@ namespace cimg_library_suffixed { CImg arr(*this); unsigned int l = 0, ir = size() - 1; for (;;) { - if (ir<=l+1) { - if (ir==l+1 && arr[ir]>1; - cimg::swap(arr[mid],arr[l+1]); + cimg::swap(arr[mid],arr[l + 1]); if (arr[l]>arr[ir]) cimg::swap(arr[l],arr[ir]); - if (arr[l+1]>arr[ir]) cimg::swap(arr[l+1],arr[ir]); - if (arr[l]>arr[l+1]) cimg::swap(arr[l],arr[l+1]); + if (arr[l + 1]>arr[ir]) cimg::swap(arr[l + 1],arr[ir]); + if (arr[l]>arr[l + 1]) cimg::swap(arr[l],arr[l + 1]); unsigned int i = l + 1, j = ir; - const T pivot = arr[l+1]; + const T pivot = arr[l + 1]; for (;;) { do ++i; while (arr[i]pivot); if (j=k) ir = j - 1; if (j<=k) l = i; @@ -16293,32 +16130,34 @@ namespace cimg_library_suffixed { cimg_instance); const unsigned int s = size(); const T res = kth_smallest(s>>1); - return (s%2)?res:((res+kth_smallest((s>>1)-1))/2); + return (s%2)?res:((res + kth_smallest((s>>1) - 1))/2); + } + + //! Return the product of all the pixel values. + /** + **/ + double product() const { + if (is_empty()) return 0; + double res = 1; + cimg_for(*this,ptrs,T) res*=(double)*ptrs; + return res; } //! Return the sum of all the pixel values. /** **/ - Tdouble sum() const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "sum(): Empty instance.", - cimg_instance); - Tdouble res = 0; - cimg_for(*this,ptrs,T) res+=(Tdouble)*ptrs; + double sum() const { + double res = 0; + cimg_for(*this,ptrs,T) res+=(double)*ptrs; return res; } //! Return the average pixel value. /** **/ - Tdouble mean() const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "mean(): Empty instance.", - cimg_instance); - Tdouble res = 0; - cimg_for(*this,ptrs,T) res+=(Tdouble)*ptrs; + double mean() const { + double res = 0; + cimg_for(*this,ptrs,T) res+=(double)*ptrs; return res/size(); } @@ -16329,12 +16168,12 @@ namespace cimg_library_suffixed { \f$1/N \sum\limits_{k=1}^{N} (x_k - \bar x)^2 = 1/N \left( \sum\limits_{k=1}^N x_k^2 - \left( \sum\limits_{k=1}^N x_k \right)^2 / N \right)\f$ with \f$ \bar x = 1/N \sum\limits_{k=1}^N x_k \f$. - - \c 1: Best unbiased estimator, computed as \f$\frac{1}{N-1} \sum\limits_{k=1}^{N} (x_k - \bar x)^2 \f$. + - \c 1: Best unbiased estimator, computed as \f$\frac{1}{N - 1} \sum\limits_{k=1}^{N} (x_k - \bar x)^2 \f$. - \c 2: Least median of squares. - \c 3: Least trimmed of squares. **/ - Tdouble variance(const unsigned int variance_method=1) const { - Tdouble foo; + double variance(const unsigned int variance_method=1) const { + double foo; return variance_mean(variance_method,foo); } @@ -16344,24 +16183,24 @@ namespace cimg_library_suffixed { \param[out] mean Average pixel value. **/ template - Tdouble variance_mean(const unsigned int variance_method, t& mean) const { + double variance_mean(const unsigned int variance_method, t& mean) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "variance_mean(): Empty instance.", cimg_instance); - Tdouble variance = 0, average = 0; + double variance = 0, average = 0; const unsigned long siz = size(); switch (variance_method) { - case 0 :{ // Least mean square (standard definition) - Tdouble S = 0, S2 = 0; - cimg_for(*this,ptrs,T) { const Tdouble val = (Tdouble)*ptrs; S+=val; S2+=val*val; } + case 0 : { // Least mean square (standard definition) + double S = 0, S2 = 0; + cimg_for(*this,ptrs,T) { const double val = (double)*ptrs; S+=val; S2+=val*val; } variance = (S2 - S*S/siz)/siz; average = S; } break; case 1 : { // Least mean square (robust definition) - Tdouble S = 0, S2 = 0; - cimg_for(*this,ptrs,T) { const Tdouble val = (Tdouble)*ptrs; S+=val; S2+=val*val; } + double S = 0, S2 = 0; + cimg_for(*this,ptrs,T) { const double val = (double)*ptrs; S+=val; S2+=val*val; } variance = siz>1?(S2 - S*S/siz)/(siz - 1):0; average = S; } break; @@ -16369,25 +16208,25 @@ namespace cimg_library_suffixed { CImg buf(*this,false); buf.sort(); const unsigned long siz2 = siz>>1; - const Tdouble med_i = (double)buf[siz2]; + const double med_i = (double)buf[siz2]; cimg_for(buf,ptrs,Tfloat) { - const Tdouble val = (Tdouble)*ptrs; *ptrs = (Tfloat)cimg::abs(val - med_i); average+=val; + const double val = (double)*ptrs; *ptrs = (Tfloat)cimg::abs(val - med_i); average+=val; } buf.sort(); - const Tdouble sig = (Tdouble)(1.4828*buf[siz2]); + const double sig = (double)(1.4828*buf[siz2]); variance = sig*sig; } break; default : { // Least trimmed of Squares CImg buf(*this,false); const unsigned long siz2 = siz>>1; cimg_for(buf,ptrs,Tfloat) { - const Tdouble val = (Tdouble)*ptrs; (*ptrs)=(Tfloat)((*ptrs)*val); average+=val; + const double val = (double)*ptrs; (*ptrs)=(Tfloat)((*ptrs)*val); average+=val; } buf.sort(); - Tdouble a = 0; + double a = 0; const Tfloat *ptrs = buf._data; - for (unsigned long j = 0; j1) { // Compute a scaled version of the Laplacian. CImg tmp(*this); if (_depth==1) { - const Tdouble cste = 1.0/std::sqrt(20.0); // Depends on how the Laplacian is computed. + const double cste = 1.0/std::sqrt(20.0); // Depends on how the Laplacian is computed. #ifdef cimg_use_openmp #pragma omp parallel for if (_width*_height>=262144 && _spectrum>=2) #endif cimg_forC(*this,c) { CImg_3x3(I,T); cimg_for3x3(*this,x,y,0,c,I,T) { - tmp(x,y,c) = cste*((Tdouble)Inc + (Tdouble)Ipc + (Tdouble)Icn + - (Tdouble)Icp - 4*(Tdouble)Icc); + tmp(x,y,c) = cste*((double)Inc + (double)Ipc + (double)Icn + + (double)Icp - 4*(double)Icc); } } } else { - const Tdouble cste = 1.0/std::sqrt(42.0); // Depends on how the Laplacian is computed. + const double cste = 1.0/std::sqrt(42.0); // Depends on how the Laplacian is computed. #ifdef cimg_use_openmp #pragma omp parallel for if (_width*_height*_depth>=262144 && _spectrum>=2) #endif @@ -16435,8 +16274,8 @@ namespace cimg_library_suffixed { CImg_3x3x3(I,T); cimg_for3x3x3(*this,x,y,z,c,I,T) { tmp(x,y,z,c) = cste*( - (Tdouble)Incc + (Tdouble)Ipcc + (Tdouble)Icnc + (Tdouble)Icpc + - (Tdouble)Iccn + (Tdouble)Iccp - 6*(Tdouble)Iccc); + (double)Incc + (double)Ipcc + (double)Icnc + (double)Icpc + + (double)Iccn + (double)Iccp - 6*(double)Iccc); } } } @@ -16444,23 +16283,23 @@ namespace cimg_library_suffixed { } // Version that doesn't need intermediate images. - Tdouble variance = 0, S = 0, S2 = 0; + double variance = 0, S = 0, S2 = 0; if (_depth==1) { - const Tdouble cste = 1.0/std::sqrt(20.0); + const double cste = 1.0/std::sqrt(20.0); CImg_3x3(I,T); cimg_forC(*this,c) cimg_for3x3(*this,x,y,0,c,I,T) { - const Tdouble val = cste*((Tdouble)Inc + (Tdouble)Ipc + - (Tdouble)Icn + (Tdouble)Icp - 4*(Tdouble)Icc); + const double val = cste*((double)Inc + (double)Ipc + + (double)Icn + (double)Icp - 4*(double)Icc); S+=val; S2+=val*val; } } else { - const Tdouble cste = 1.0/std::sqrt(42.0); + const double cste = 1.0/std::sqrt(42.0); CImg_3x3x3(I,T); cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,T) { - const Tdouble val = cste * - ((Tdouble)Incc + (Tdouble)Ipcc + (Tdouble)Icnc + - (Tdouble)Icpc + - (Tdouble)Iccn + (Tdouble)Iccp - 6*(Tdouble)Iccc); + const double val = cste * + ((double)Incc + (double)Ipcc + (double)Icnc + + (double)Icpc + + (double)Iccn + (double)Iccp - 6*(double)Iccc); S+=val; S2+=val*val; } } @@ -16474,16 +16313,16 @@ namespace cimg_library_suffixed { \param img Image used as the second argument of the MSE operator. **/ template - Tdouble MSE(const CImg& img) const { + double MSE(const CImg& img) const { if (img.size()!=size()) throw CImgArgumentException(_cimg_instance "MSE(): Instance and specified image (%u,%u,%u,%u,%p) have different dimensions.", cimg_instance, img._width,img._height,img._depth,img._spectrum,img._data); - Tdouble vMSE = 0; + double vMSE = 0; const t* ptr2 = img._data; cimg_for(*this,ptr1,T) { - const Tdouble diff = (Tdouble)*ptr1 - (Tdouble)*(ptr2++); + const double diff = (double)*ptr1 - (double)*(ptr2++); vMSE+=diff*diff; } const unsigned long siz = img.size(); @@ -16497,9 +16336,9 @@ namespace cimg_library_suffixed { \param max_value Maximum theoretical value of the signal. **/ template - Tdouble PSNR(const CImg& img, const Tdouble max_value=255) const { - const Tdouble vMSE = (Tdouble)std::sqrt(MSE(img)); - return (vMSE!=0)?(Tdouble)(20*std::log10(max_value/vMSE)):(Tdouble)(cimg::type::max()); + double PSNR(const CImg& img, const double max_value=255) const { + const double vMSE = (double)std::sqrt(MSE(img)); + return (vMSE!=0)?(double)(20*std::log10(max_value/vMSE)):(double)(cimg::type::max()); } //! Evaluate math formula. @@ -16513,6 +16352,13 @@ namespace cimg_library_suffixed { double eval(const char *const expression, const double x=0, const double y=0, const double z=0, const double c=0) const { if (!expression) return 0; + if (!expression[1]) switch (*expression) { // Single-char optimization. + case 'w' : return (double)_width; + case 'h' : return (double)_height; + case 'd' : return (double)_depth; + case 's' : return (double)_spectrum; + case 'r' : return (double)_is_shared; + } return _cimg_math_parser(*this,expression,"eval")(x,y,z,c); } @@ -16533,7 +16379,9 @@ namespace cimg_library_suffixed { #pragma omp for for (unsigned int i = 0; i[min; max; mean; variance; xmin; ymin; zmin; cmin; xmax; ymax; zmax; cmax]. + \return Statistics vector as + [min; max; mean; variance; xmin; ymin; zmin; cmin; xmax; ymax; zmax; cmax; sum; product]. **/ CImg get_stats(const unsigned int variance_method=1) const { if (is_empty()) return CImg(); const unsigned long siz = size(); const T *const odata = _data; const T *pm = odata, *pM = odata; - Tdouble S = 0, S2 = 0; + double S = 0, S2 = 0, P = _data?1:0; T m = *pm, M = m; cimg_for(*this,ptrs,T) { const T val = *ptrs; - const Tdouble _val = (Tdouble)val; + const double _val = (double)val; if (valM) { M = val; pM = ptrs; } S+=_val; S2+=_val*_val; + P*=_val; } - const Tdouble + const double mean_value = S/siz, _variance_value = variance_method==0?(S2 - S*S/siz)/siz: (variance_method==1?(siz>1?(S2 - S*S/siz)/(siz - 1):0): @@ -16578,9 +16428,10 @@ namespace cimg_library_suffixed { xM = 0, yM = 0, zM = 0, cM = 0; contains(*pm,xm,ym,zm,cm); contains(*pM,xM,yM,zM,cM); - return CImg(1,12).fill((Tdouble)m,(Tdouble)M,mean_value,variance_value, - (Tdouble)xm,(Tdouble)ym,(Tdouble)zm,(Tdouble)cm, - (Tdouble)xM,(Tdouble)yM,(Tdouble)zM,(Tdouble)cM); + return CImg(1,14).fill((double)m,(double)M,mean_value,variance_value, + (double)xm,(double)ym,(double)zm,(double)cm, + (double)xM,(double)yM,(double)zM,(double)cM, + S,P); } //! Compute statistics vector from the pixel values \inplace. @@ -16602,22 +16453,22 @@ namespace cimg_library_suffixed { - \c 0: L2-norm - \c 1: L1-norm **/ - Tdouble magnitude(const int magnitude_type=2) const { + double magnitude(const int magnitude_type=2) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "magnitude(): Empty instance.", cimg_instance); - Tdouble res = 0; + double res = 0; switch (magnitude_type) { case -1 : { - cimg_for(*this,ptrs,T) { const Tdouble val = (Tdouble)cimg::abs(*ptrs); if (val>res) res = val; } + cimg_for(*this,ptrs,T) { const double val = (double)cimg::abs(*ptrs); if (val>res) res = val; } } break; case 1 : { - cimg_for(*this,ptrs,T) res+=(Tdouble)cimg::abs(*ptrs); + cimg_for(*this,ptrs,T) res+=(double)cimg::abs(*ptrs); } break; default : { - cimg_for(*this,ptrs,T) res+=(Tdouble)cimg::sqr(*ptrs); - res = (Tdouble)std::sqrt(res); + cimg_for(*this,ptrs,T) res+=(double)cimg::sqr(*ptrs); + res = (double)std::sqrt(res); } } return res; @@ -16626,33 +16477,33 @@ namespace cimg_library_suffixed { //! Compute the trace of the image, viewed as a matrix. /** **/ - Tdouble trace() const { + double trace() const { if (is_empty()) throw CImgInstanceException(_cimg_instance "trace(): Empty instance.", cimg_instance); - Tdouble res = 0; - cimg_forX(*this,k) res+=(Tdouble)(*this)(k,k); + double res = 0; + cimg_forX(*this,k) res+=(double)(*this)(k,k); return res; } //! Compute the determinant of the image, viewed as a matrix. /** **/ - Tdouble det() const { + double det() const { if (is_empty() || _width!=_height || _depth!=1 || _spectrum!=1) throw CImgInstanceException(_cimg_instance "det(): Instance is not a square matrix.", cimg_instance); switch (_width) { - case 1 : return (Tdouble)((*this)(0,0)); - case 2 : return (Tdouble)((*this)(0,0))*(Tdouble)((*this)(1,1)) - (Tdouble)((*this)(0,1))*(Tdouble)((*this)(1,0)); + case 1 : return (double)((*this)(0,0)); + case 2 : return (double)((*this)(0,0))*(double)((*this)(1,1)) - (double)((*this)(0,1))*(double)((*this)(1,0)); case 3 : { - const Tdouble - a = (Tdouble)_data[0], d = (Tdouble)_data[1], g = (Tdouble)_data[2], - b = (Tdouble)_data[3], e = (Tdouble)_data[4], h = (Tdouble)_data[5], - c = (Tdouble)_data[6], f = (Tdouble)_data[7], i = (Tdouble)_data[8]; + const double + a = (double)_data[0], d = (double)_data[1], g = (double)_data[2], + b = (double)_data[3], e = (double)_data[4], h = (double)_data[5], + c = (double)_data[6], f = (double)_data[7], i = (double)_data[8]; return i*a*e - a*h*f - i*b*d + b*g*f + c*d*h - c*g*e; } default : { @@ -16660,7 +16511,7 @@ namespace cimg_library_suffixed { CImg indx; bool d; lu._LU(indx,d); - Tdouble res = d?(Tdouble)1:(Tdouble)-1; + double res = d?(double)1:(double)-1; cimg_forX(lu,i) res*=lu(i,i); return res; } @@ -16672,7 +16523,7 @@ namespace cimg_library_suffixed { \param img Image used as a second argument of the dot product. **/ template - Tdouble dot(const CImg& img) const { + double dot(const CImg& img) const { if (is_empty()) throw CImgInstanceException(_cimg_instance "dot(): Empty instance.", @@ -16683,8 +16534,8 @@ namespace cimg_library_suffixed { cimg_instance); const unsigned int nb = cimg::min(size(),img.size()); - Tdouble res = 0; - for (unsigned int off = 0; off get_tensor_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const { const T *ptrs = data(x,y,z,0); const unsigned long whd = (unsigned long)_width*_height*_depth; - if (_spectrum==6) return tensor(*ptrs,*(ptrs+whd),*(ptrs+2*whd),*(ptrs+3*whd),*(ptrs+4*whd),*(ptrs+5*whd)); - if (_spectrum==3) return tensor(*ptrs,*(ptrs+whd),*(ptrs+2*whd)); + if (_spectrum==6) + return tensor(*ptrs,*(ptrs + whd),*(ptrs + 2*whd),*(ptrs + 3*whd),*(ptrs + 4*whd),*(ptrs + 5*whd)); + if (_spectrum==3) + return tensor(*ptrs,*(ptrs + whd),*(ptrs + 2*whd)); return tensor(*ptrs); } @@ -16912,19 +16765,19 @@ namespace cimg_library_suffixed { \param a0 Starting value of the sequence. \param a1 Ending value of the sequence. **/ - CImg& sequence(const T a0, const T a1) { + CImg& sequence(const T& a0, const T& a1) { if (is_empty()) return *this; const unsigned int siz = size() - 1; T* ptr = _data; if (siz) { - const Tdouble delta = (Tdouble)a1 - (Tdouble)a0; + const double delta = (double)a1 - (double)a0; cimg_foroff(*this,l) *(ptr++) = (T)(a0 + delta*l/siz); } else *ptr = a0; return *this; } //! Fill image with a linear sequence of values \newinstance. - CImg get_sequence(const T a0, const T a1) const { + CImg get_sequence(const T& a0, const T& a1) const { return (+*this).sequence(a0,a1); } @@ -16989,7 +16842,7 @@ namespace cimg_library_suffixed { Tfloat *const lapA = new Tfloat[N*N], *const WORK = new Tfloat[LWORK]; - cimg_forXY(*this,k,l) lapA[k*N+l] = (Tfloat)((*this)(k,l)); + cimg_forXY(*this,k,l) lapA[k*N + l] = (Tfloat)((*this)(k,l)); cimg::getrf(N,lapA,IPIV,INFO); if (INFO) cimg::warn(_cimg_instance @@ -17004,7 +16857,7 @@ namespace cimg_library_suffixed { cimg_instance, INFO); } - if (!INFO) cimg_forXY(*this,k,l) (*this)(k,l) = (T)(lapA[k*N+l]); else fill(0); + if (!INFO) cimg_forXY(*this,k,l) (*this)(k,l) = (T)(lapA[k*N + l]); else fill(0); delete[] IPIV; delete[] lapA; delete[] WORK; #else const double dete = _width>3?-1.0:det(); @@ -17064,8 +16917,8 @@ namespace cimg_library_suffixed { SVD(U,S,V); const Tfloat tolerance = (sizeof(Tfloat)<=4?5.96e-8f:1.11e-16f)*cimg::max(_width,_height)*S.max(); cimg_forX(V,x) { - const Tfloat s = S(x), invs = s>tolerance?1/s:(Tfloat)0; - cimg_forY(V,y) V(x,y)*=invs; + const Tfloat s = S(x), invs = s>tolerance?1/s:(Tfloat)0; + cimg_forY(V,y) V(x,y)*=invs; } return V*U.transpose(); } @@ -17077,12 +16930,17 @@ namespace cimg_library_suffixed { **/ template CImg& solve(const CImg& A) { - if (_width!=1 || _depth!=1 || _spectrum!=1 || _height!=A._height || A._depth!=1 || A._spectrum!=1) + if (_depth!=1 || _spectrum!=1 || _height!=A._height || A._depth!=1 || A._spectrum!=1) throw CImgArgumentException(_cimg_instance "solve(): Instance and specified matrix (%u,%u,%u,%u,%p) have " "incompatible dimensions.", cimg_instance, A._width,A._height,A._depth,A._spectrum,A._data); + if (_width!=1) { + cimg_forX(*this,i) draw_image(i,get_column(i).solve(A)); + return *this; + } + typedef _cimg_Ttfloat Ttfloat; if (A._width==A._height) { #ifdef cimg_use_lapack @@ -17092,7 +16950,7 @@ namespace cimg_library_suffixed { *const lapA = new Ttfloat[N*N], *const lapB = new Ttfloat[N], *const WORK = new Ttfloat[LWORK]; - cimg_forXY(A,k,l) lapA[k*N+l] = (Ttfloat)(A(k,l)); + cimg_forXY(A,k,l) lapA[k*N + l] = (Ttfloat)(A(k,l)); cimg_forY(*this,i) lapB[i] = (Ttfloat)((*this)(i)); cimg::getrf(N,lapA,IPIV,INFO); if (INFO) @@ -17120,31 +16978,31 @@ namespace cimg_library_suffixed { #endif } else { // Least-square solution for non-square systems. #ifdef cimg_use_lapack - char TRANS = 'N'; + char TRANS = 'N'; int INFO, N = A._width, M = A._height, LWORK = -1, LDA = M, LDB = M, NRHS = _width; - Ttfloat WORK_QUERY; - Ttfloat - * const lapA = new Ttfloat[M*N], - * const lapB = new Ttfloat[M*NRHS]; - cimg::sgels(TRANS, M, N, NRHS, lapA, LDA, lapB, LDB, &WORK_QUERY, LWORK, INFO); - LWORK = (int) WORK_QUERY; - Ttfloat *const WORK = new Ttfloat[LWORK]; - cimg_forXY(A,k,l) lapA[k*M+l] = (Ttfloat)(A(k,l)); - cimg_forXY(*this,k,l) lapB[k*M+l] = (Ttfloat)((*this)(k,l)); - cimg::sgels(TRANS, M, N, NRHS, lapA, LDA, lapB, LDB, WORK, LWORK, INFO); + Ttfloat WORK_QUERY; + Ttfloat + * const lapA = new Ttfloat[M*N], + * const lapB = new Ttfloat[M*NRHS]; + cimg::sgels(TRANS, M, N, NRHS, lapA, LDA, lapB, LDB, &WORK_QUERY, LWORK, INFO); + LWORK = (int) WORK_QUERY; + Ttfloat *const WORK = new Ttfloat[LWORK]; + cimg_forXY(A,k,l) lapA[k*M + l] = (Ttfloat)(A(k,l)); + cimg_forXY(*this,k,l) lapB[k*M + l] = (Ttfloat)((*this)(k,l)); + cimg::sgels(TRANS, M, N, NRHS, lapA, LDA, lapB, LDB, WORK, LWORK, INFO); if (INFO != 0) cimg::warn(_cimg_instance "solve(): LAPACK library function sgels() returned error code %d.", cimg_instance, INFO); - assign(NRHS, N); - if (!INFO != 0) - cimg_forXY(*this,k,l) (*this)(k,l) = (T)lapB[k*M+l]; + assign(NRHS, N); + if (!INFO) + cimg_forXY(*this,k,l) (*this)(k,l) = (T)lapB[k*M + l]; else assign(A.get_pseudoinvert()*(*this)); delete[] lapA; delete[] lapB; delete[] WORK; #else - assign(A.get_pseudoinvert()*(*this)); + assign(A.get_pseudoinvert()*(*this)); #endif } return *this; @@ -17159,14 +17017,14 @@ namespace cimg_library_suffixed { template CImg& _solve(const CImg& A, const CImg& indx) { typedef _cimg_Ttfloat Ttfloat; - const int N = size(); + const int N = (int)size(); int ii = -1; Ttfloat sum; for (int i = 0; i=0) for (int j = ii; j<=i-1; ++j) sum-=A(j,i)*(*this)(j); + if (ii>=0) for (int j = ii; j<=i - 1; ++j) sum-=A(j,i)*(*this)(j); else if (sum!=0) ii = i; (*this)(i) = (T)sum; } @@ -17187,7 +17045,7 @@ namespace cimg_library_suffixed { **/ template CImg& solve_tridiagonal(const CImg& A) { - const unsigned int siz = (int)size(); + const unsigned int siz = (unsigned int)size(); if (A._width!=3 || A._height!=siz) throw CImgArgumentException(_cimg_instance "solve_tridiagonal(): Instance and tridiagonal matrix " @@ -17198,12 +17056,12 @@ namespace cimg_library_suffixed { const Ttfloat epsilon = 1e-4f; CImg B = A.get_column(1), V(*this,false); for (int i = 1; i<(int)siz; ++i) { - const Ttfloat m = A(0,i)/(B[i-1]?B[i-1]:epsilon); - B[i] -= m*A(2,i-1); - V[i] -= m*V[i-1]; + const Ttfloat m = A(0,i)/(B[i - 1]?B[i - 1]:epsilon); + B[i] -= m*A(2,i - 1); + V[i] -= m*V[i - 1]; } - (*this)[siz-1] = (T)(V[siz-1]/(B[siz-1]?B[siz-1]:epsilon)); - for (int i = (int)siz - 2; i>=0; --i) (*this)[i] = (T)((V[i] - A(2,i)*(*this)[i+1])/(B[i]?B[i]:epsilon)); + (*this)[siz - 1] = (T)(V[siz - 1]/(B[siz - 1]?B[siz - 1]:epsilon)); + for (int i = (int)siz - 2; i>=0; --i) (*this)[i] = (T)((V[i] - A(2,i)*(*this)[i + 1])/(B[i]?B[i]:epsilon)); return *this; } @@ -17216,7 +17074,7 @@ namespace cimg_library_suffixed { //! Compute eigenvalues and eigenvectors of the instance image, viewed as a matrix. /** \param[out] val Vector of the estimated eigenvalues, in decreasing order. - \param[out] vec Matrix of the estimated eigenvalues, sorted by columns. + \param[out] vec Matrix of the estimated eigenvectors, sorted by columns. **/ template const CImg& eigen(CImg& val, CImg &vec) const { @@ -17272,7 +17130,7 @@ namespace cimg_library_suffixed { //! Compute eigenvalues and eigenvectors of the instance image, viewed as a symmetric matrix. /** \param[out] val Vector of the estimated eigenvalues, in decreasing order. - \param[out] vec Matrix of the estimated eigenvalues, sorted by columns. + \param[out] vec Matrix of the estimated eigenvectors, sorted by columns. **/ template const CImg& symmetric_eigen(CImg& val, CImg& vec) const { @@ -17285,7 +17143,7 @@ namespace cimg_library_suffixed { *const lapA = new Tfloat[N*N], *const lapW = new Tfloat[N], *const WORK = new Tfloat[LWORK]; - cimg_forXY(*this,k,l) lapA[k*N+l] = (Tfloat)((*this)(k,l)); + cimg_forXY(*this,k,l) lapA[k*N + l] = (Tfloat)((*this)(k,l)); cimg::syev(JOB,UPLO,N,lapA,lapW,WORK,LWORK,INFO); if (INFO) cimg::warn(_cimg_instance @@ -17294,10 +17152,10 @@ namespace cimg_library_suffixed { INFO); val.assign(1,N); - vec.assign(N,N); + vec.assign(N,N); if (!INFO) { - cimg_forY(val,i) val(i) = (T)lapW[N-1-i]; - cimg_forXY(vec,k,l) vec(k,l) = (T)(lapA[(N-1-k)*N+l]); + cimg_forY(val,i) val(i) = (T)lapW[N - 1 -i]; + cimg_forXY(vec,k,l) vec(k,l) = (T)(lapA[(N - 1 - k)*N + l]); } else { val.fill(0); vec.fill(0); } delete[] lapA; delete[] lapW; delete[] WORK; #else @@ -17306,30 +17164,32 @@ namespace cimg_library_suffixed { "eigen(): Instance is not a square matrix.", cimg_instance); - val.assign(1,_width); - if (vec._data) vec.assign(_width,_width); + val.assign(1,_width); + if (vec._data) vec.assign(_width,_width); if (_width<3) { eigen(val,vec); if (_width==2) { vec[1] = -vec[2]; vec[3] = vec[0]; } // Force orthogonality for 2x2 matrices. return *this; } CImg V(_width,_width); - SVD(vec,val,V,false); - - bool is_ambiguous = false; - float eig = 0; - cimg_forY(val,p) { // check for ambiguous cases. - if (val[p]>eig) eig = (float)val[p]; + Tfloat M = 0, m = (Tfloat)min_max(M), maxabs = cimg::max((Tfloat)1.0f,cimg::abs(m),cimg::abs(M)); + (CImg(*this,false)/=maxabs).SVD(vec,val,V,false); + if (maxabs!=1) val*=maxabs; + + bool is_ambiguous = false; + float eig = 0; + cimg_forY(val,p) { // check for ambiguous cases. + if (val[p]>eig) eig = (float)val[p]; t scal = 0; cimg_forY(vec,y) scal+=vec(p,y)*V(p,y); if (cimg::abs(scal)<0.9f) is_ambiguous = true; if (scal<0) val[p] = -val[p]; } - if (is_ambiguous) { - ++(eig*=2); - SVD(vec,val,V,false,40,eig); - val-=eig; - } + if (is_ambiguous) { + ++(eig*=2); + SVD(vec,val,V,false,40,eig); + val-=eig; + } CImg permutations; // sort eigenvalues in decreasing order CImg tmp(_width); val.sort(permutations,false); @@ -17363,7 +17223,7 @@ namespace cimg_library_suffixed { permutations.assign(_width,_height,_depth,_spectrum); if (is_empty()) return *this; cimg_foroff(permutations,off) permutations[off] = (t)off; - return _quicksort(0,size()-1,permutations,is_increasing,true); + return _quicksort(0,size() - 1,permutations,is_increasing,true); } //! Sort pixel values and get sorting permutations \newinstance. @@ -17387,29 +17247,29 @@ namespace cimg_library_suffixed { CImg perm; switch (cimg::uncase(axis)) { case 0 : - _quicksort(0,size()-1,perm,is_increasing,false); + _quicksort(0,size() - 1,perm,is_increasing,false); break; case 'x' : { perm.assign(_width); - get_crop(0,0,0,0,_width-1,0,0,0).sort(perm,is_increasing); + get_crop(0,0,0,0,_width - 1,0,0,0).sort(perm,is_increasing); CImg img(*this,false); cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(perm[x],y,z,c); } break; case 'y' : { perm.assign(_height); - get_crop(0,0,0,0,0,_height-1,0,0).sort(perm,is_increasing); + get_crop(0,0,0,0,0,_height - 1,0,0).sort(perm,is_increasing); CImg img(*this,false); cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(x,perm[y],z,c); } break; case 'z' : { perm.assign(_depth); - get_crop(0,0,0,0,0,0,_depth-1,0).sort(perm,is_increasing); + get_crop(0,0,0,0,0,0,_depth - 1,0).sort(perm,is_increasing); CImg img(*this,false); cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(x,y,perm[z],c); } break; case 'c' : { perm.assign(_spectrum); - get_crop(0,0,0,0,0,0,0,_spectrum-1).sort(perm,is_increasing); + get_crop(0,0,0,0,0,0,0,_spectrum - 1).sort(perm,is_increasing); CImg img(*this,false); cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(x,y,z,perm[c]); } break; @@ -17512,10 +17372,10 @@ namespace cimg_library_suffixed { if (is_empty()) { U.assign(); S.assign(); V.assign(); } else { U = *this; - if (lambda!=0) { - const unsigned int delta = cimg::min(U._width,U._height); - for (unsigned int i = 0; i rv1(_width); @@ -17523,49 +17383,49 @@ namespace cimg_library_suffixed { int l = 0, nm = 0; cimg_forX(U,i) { - l = i+1; rv1[i] = scale*g; g = s = scale = 0; + l = i + 1; rv1[i] = scale*g; g = s = scale = 0; if (i=0?-1:1)*std::sqrt(s)); h=f*g-s; U(i,i) = f-g; for (int j = l; j=0?-1:1)*std::sqrt(s)); h = f*g-s; U(l,i) = f-g; for (int k = l; k=0; --i) { + for (int i = width() - 1; i>=0; --i) { if (i=0; --i) { - l = i+1; g = S[i]; + for (int i = cimg::min(width(),height()) - 1; i>=0; --i) { + l = i + 1; g = S[i]; for (int j = l; j=0; --k) { + for (int k = width() - 1; k>=0; --k) { for (unsigned int its = 0; its=1; --l) { - nm = l-1; - if ((cimg::abs(rv1[l])+anorm)==anorm) { flag = false; break; } - if ((cimg::abs(S[nm])+anorm)==anorm) break; + nm = l - 1; + if ((cimg::abs(rv1[l]) + anorm)==anorm) { flag = false; break; } + if ((cimg::abs(S[nm]) + anorm)==anorm) break; } if (flag) { c = 0; s = 1; for (int i = l; i<=k; ++i) { f = s*rv1[i]; rv1[i] = c*rv1[i]; - if ((cimg::abs(f)+anorm)==anorm) break; + if ((cimg::abs(f) + anorm)==anorm) break; g = S[i]; h = (t)cimg::_pythagore(f,g); S[i] = h; h = 1/h; c = g*h; s = -f*h; cimg_forY(U,j) { const t y = U(nm,j), z = U(i,j); U(nm,j) = y*c + z*s; U(i,j) = z*c - y*s; } } @@ -17608,24 +17468,24 @@ namespace cimg_library_suffixed { const t z = S[k]; if (l==k) { if (z<0) { S[k] = -z; cimg_forX(U,j) V(k,j) = -V(k,j); } break; } - nm = k-1; + nm = k - 1; t x = S[l], y = S[nm]; g = rv1[nm]; h = rv1[k]; - f = ((y-z)*(y+z)+(g-h)*(g+h))/cimg::max((t)1e-25,2*h*y); + f = ((y - z)*(y + z)+(g - h)*(g + h))/cimg::max((t)1e-25,2*h*y); g = (t)cimg::_pythagore(f,1.0); - f = ((x-z)*(x+z)+h*((y/(f + (f>=0?g:-g)))-h))/cimg::max((t)1e-25,x); + f = ((x - z)*(x + z)+h*((y/(f + (f>=0?g:-g))) - h))/cimg::max((t)1e-25,x); c = s = 1; for (int j = l; j<=nm; ++j) { - const int i = j+1; + const int i = j + 1; g = rv1[i]; h = s*g; g = c*g; t y = S[i]; t z = (t)cimg::_pythagore(f,h); rv1[j] = z; c = f/cimg::max((t)1e-25,z); s = h/cimg::max((t)1e-25,z); - f = x*c+g*s; g = g*c-x*s; h = y*s; y*=c; + f = x*c + g*s; g = g*c - x*s; h = y*s; y*=c; cimg_forX(U,jj) { const t x = V(j,jj), z = V(i,jj); V(j,jj) = x*c + z*s; V(i,jj) = z*c - x*s; } z = (t)cimg::_pythagore(f,h); S[j] = z; if (z) { z = 1/cimg::max((t)1e-25,z); c = f*z; s = h*z; } - f = c*g+s*y; x = c*y-s*g; + f = c*g + s*y; x = c*y - s*g; cimg_forY(U,jj) { const t y = U(j,jj); z = U(i,jj); U(j,jj) = y*c + z*s; U(i,jj) = z*c - y*s; } } rv1[l] = 0; rv1[k]=f; S[k]=x; @@ -17701,7 +17561,7 @@ namespace cimg_library_suffixed { if ((*this)(j,j)==0) (*this)(j,j) = (T)1e-20; if (j Q(nb_nodes); - cimg_forX(Q,u) Q(u) = u; + cimg_forX(Q,u) Q(u) = (unsigned int)u; cimg::swap(Q(starting_node),Q(0)); unsigned int sizeQ = nb_nodes; while (sizeQ) { @@ -17750,7 +17610,7 @@ namespace cimg_library_suffixed { dist(v) = alt; previous_node(v) = (t)umin; const T distpos = dist(Q(q)); - for (unsigned int pos = q, par = 0; pos && distposdist(Q(left))) || + ((right=2*(pos + 1),(left=right - 1))dist(Q(left))) || (rightdist(Q(right)));) { if (right string(const char *const str, const bool is_last_zero=true, const bool is_shared=false) { if (!str) return CImg(); - return CImg(str,(unsigned int)std::strlen(str)+(is_last_zero?1:0),1,1,1,is_shared); + return CImg(str,(unsigned int)std::strlen(str) + (is_last_zero?1:0),1,1,1,is_shared); } //! Return a \c 1x1 image containing specified value. @@ -17889,7 +17749,7 @@ namespace cimg_library_suffixed { //! Return a \c 1x7 image containing specified values. static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6) { + const T& a4, const T& a5, const T& a6) { CImg r(1,7); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; @@ -17898,7 +17758,7 @@ namespace cimg_library_suffixed { //! Return a \c 1x8 image containing specified values. static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6, const T& a7) { + const T& a4, const T& a5, const T& a6, const T& a7) { CImg r(1,8); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; @@ -17907,8 +17767,8 @@ namespace cimg_library_suffixed { //! Return a \c 1x9 image containing specified values. static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6, const T& a7, - const T& a8) { + const T& a4, const T& a5, const T& a6, const T& a7, + const T& a8) { CImg r(1,9); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; @@ -17953,7 +17813,7 @@ namespace cimg_library_suffixed { static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, const T& a7, const T& a8, const T& a9, const T& a10, const T& a11, - const T& a12) { + const T& a12) { CImg r(1,13); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; @@ -17966,7 +17826,7 @@ namespace cimg_library_suffixed { static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, const T& a7, const T& a8, const T& a9, const T& a10, const T& a11, - const T& a12, const T& a13) { + const T& a12, const T& a13) { CImg r(1,14); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; @@ -17979,7 +17839,7 @@ namespace cimg_library_suffixed { static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, const T& a7, const T& a8, const T& a9, const T& a10, const T& a11, - const T& a12, const T& a13, const T& a14) { + const T& a12, const T& a13, const T& a14) { CImg r(1,15); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; @@ -17992,7 +17852,7 @@ namespace cimg_library_suffixed { static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6, const T& a7, const T& a8, const T& a9, const T& a10, const T& a11, - const T& a12, const T& a13, const T& a14, const T& a15) { + const T& a12, const T& a13, const T& a14, const T& a15) { CImg r(1,16); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; @@ -18018,7 +17878,7 @@ namespace cimg_library_suffixed { \param a3 Fourth matrix value. **/ static CImg matrix(const T& a0, const T& a1, - const T& a2, const T& a3) { + const T& a2, const T& a3) { CImg r(2,2); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; @@ -18038,8 +17898,8 @@ namespace cimg_library_suffixed { \param a8 Nineth matrix value. **/ static CImg matrix(const T& a0, const T& a1, const T& a2, - const T& a3, const T& a4, const T& a5, - const T& a6, const T& a7, const T& a8) { + const T& a3, const T& a4, const T& a5, + const T& a6, const T& a7, const T& a8) { CImg r(3,3); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; @@ -18049,9 +17909,9 @@ namespace cimg_library_suffixed { //! Return a 4x4 matrix containing specified coefficients. static CImg matrix(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6, const T& a7, - const T& a8, const T& a9, const T& a10, const T& a11, - const T& a12, const T& a13, const T& a14, const T& a15) { + const T& a4, const T& a5, const T& a6, const T& a7, + const T& a8, const T& a9, const T& a10, const T& a11, + const T& a12, const T& a13, const T& a14, const T& a15) { CImg r(4,4); T *ptr = r._data; *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; @@ -18135,7 +17995,7 @@ namespace cimg_library_suffixed { \param a0 Starting value of the sequence. \param a1 Ending value of the sequence. **/ - static CImg sequence(const unsigned int N, const T a0, const T a1) { + static CImg sequence(const unsigned int N, const T& a0, const T& a1) { if (N) return CImg(1,N).sequence(a0,a1); return CImg(); } @@ -18169,9 +18029,9 @@ namespace cimg_library_suffixed { else { X = Y = Z = 0; W = 1; } } const float xx = X*X, xy = X*Y, xz = X*Z, xw = X*W, yy = Y*Y, yz = Y*Z, yw = Y*W, zz = Z*Z, zw = Z*W; - return CImg::matrix((T)(1-2*(yy+zz)), (T)(2*(xy+zw)), (T)(2*(xz-yw)), - (T)(2*(xy-zw)), (T)(1-2*(xx+zz)), (T)(2*(yz+xw)), - (T)(2*(xz+yw)), (T)(2*(yz-xw)), (T)(1-2*(xx+yy))); + return CImg::matrix((T)(1 - 2*(yy + zz)), (T)(2*(xy + zw)), (T)(2*(xz - yw)), + (T)(2*(xy - zw)), (T)(1 - 2*(xx + zz)), (T)(2*(yz + xw)), + (T)(2*(xz + yw)), (T)(2*(yz - xw)), (T)(1 - 2*(xx + yy))); } //@} @@ -18185,7 +18045,7 @@ namespace cimg_library_suffixed { /** \param val Fill value. **/ - CImg& fill(const T val) { + CImg& fill(const T& val) { if (is_empty()) return *this; if (val && sizeof(T)!=1) cimg_for(*this,ptrd,T) *ptrd = val; else std::memset(_data,(int)val,sizeof(T)*size()); @@ -18193,7 +18053,7 @@ namespace cimg_library_suffixed { } //! Fill all pixel values with specified value \newinstance. - CImg get_fill(const T val) const { + CImg get_fill(const T& val) const { return CImg(_width,_height,_depth,_spectrum).fill(val); } @@ -18202,23 +18062,23 @@ namespace cimg_library_suffixed { \param val0 First fill value. \param val1 Second fill value. **/ - CImg& fill(const T val0, const T val1) { + CImg& fill(const T& val0, const T& val1) { if (is_empty()) return *this; - T *ptrd, *ptre = end()-1; + T *ptrd, *ptre = end() - 1; for (ptrd = _data; ptrd get_fill(const T val0, const T val1) const { + CImg get_fill(const T& val0, const T& val1) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1); } //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T val0, const T val1, const T val2) { + CImg& fill(const T& val0, const T& val1, const T& val2) { if (is_empty()) return *this; - T *ptrd, *ptre = end()-2; + T *ptrd, *ptre = end() - 2; for (ptrd = _data; ptrd get_fill(const T val0, const T val1, const T val2) const { + CImg get_fill(const T& val0, const T& val1, const T& val2) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2); } //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T val0, const T val1, const T val2, const T val3) { + CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3) { if (is_empty()) return *this; - T *ptrd, *ptre = end()-3; + T *ptrd, *ptre = end() - 3; for (ptrd = _data; ptrd get_fill(const T val0, const T val1, const T val2, const T val3) const { + CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3); } //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T val0, const T val1, const T val2, const T val3, const T val4) { + CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4) { if (is_empty()) return *this; - T *ptrd, *ptre = end()-4; + T *ptrd, *ptre = end() - 4; for (ptrd = _data; ptrd get_fill(const T val0, const T val1, const T val2, const T val3, const T val4) const { + CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4); } //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5) { + CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5) { if (is_empty()) return *this; - T *ptrd, *ptre = end()-5; + T *ptrd, *ptre = end() - 5; for (ptrd = _data; ptrd get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5) const { + CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5); } //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6) { + CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, + const T& val6) { if (is_empty()) return *this; - T *ptrd, *ptre = end()-6; + T *ptrd, *ptre = end() - 6; for (ptrd = _data; ptrd get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, - const T val6) const { + CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, + const T& val6) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6); } //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, - const T val6, const T val7) { + CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, + const T& val6, const T& val7) { if (is_empty()) return *this; - T *ptrd, *ptre = end()-7; + T *ptrd, *ptre = end() - 7; for (ptrd = _data; ptrd get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, - const T val7) const { + CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, + const T& val6, const T& val7) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7); } //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, - const T val7, const T val8) { + CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, + const T& val6, const T& val7, const T& val8) { if (is_empty()) return *this; - T *ptrd, *ptre = end()-8; + T *ptrd, *ptre = end() - 8; for (ptrd = _data; ptrd get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, - const T val7, const T val8) const { + CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, + const T& val6, const T& val7, const T& val8) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8); } //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, - const T val7, const T val8, const T val9) { + CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, + const T& val6, const T& val7, const T& val8, const T& val9) { if (is_empty()) return *this; - T *ptrd, *ptre = end()-9; + T *ptrd, *ptre = end() - 9; for (ptrd = _data; ptrd get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, - const T val7, const T val8, const T val9) const { + CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, + const T& val6, const T& val7, const T& val8, const T& val9) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9); } //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, - const T val7, const T val8, const T val9, const T val10) { + CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, + const T& val6, const T& val7, const T& val8, const T& val9, const T& val10) { if (is_empty()) return *this; - T *ptrd, *ptre = end()-10; + T *ptrd, *ptre = end() - 10; for (ptrd = _data; ptrd get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, - const T val7, const T val8, const T val9, const T val10) const { + CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, + const T& val6, const T& val7, const T& val8, const T& val9, const T& val10) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10); } //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, - const T val7, const T val8, const T val9, const T val10, const T val11) { + CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, + const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11) { if (is_empty()) return *this; - T *ptrd, *ptre = end()-11; + T *ptrd, *ptre = end() - 11; for (ptrd = _data; ptrd get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, - const T val7, const T val8, const T val9, const T val10, const T val11) const { + CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, + const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10, val11); } //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, - const T val7, const T val8, const T val9, const T val10, const T val11, const T val12) { + CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, + const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, + const T& val12) { if (is_empty()) return *this; - T *ptrd, *ptre = end()-12; + T *ptrd, *ptre = end() - 12; for (ptrd = _data; ptrd get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, - const T val7, const T val8, const T val9, const T val10, const T val11, const T val12) const { + CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, + const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, + const T& val12) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10, val11,val12); } //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, - const T val7, const T val8, const T val9, const T val10, const T val11, const T val12, - const T val13) { + CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, + const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, + const T& val12, const T& val13) { if (is_empty()) return *this; - T *ptrd, *ptre = end()-13; + T *ptrd, *ptre = end() - 13; for (ptrd = _data; ptrd get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, - const T val7, const T val8, const T val9, const T val10, const T val11, const T val12, - const T val13) const { + CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, + const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, + const T& val12, const T& val13) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10, val11,val12,val13); } //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, - const T val7, const T val8, const T val9, const T val10, const T val11, const T val12, - const T val13, const T val14) { + CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, + const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, + const T& val12, const T& val13, const T& val14) { if (is_empty()) return *this; - T *ptrd, *ptre = end()-14; + T *ptrd, *ptre = end() - 14; for (ptrd = _data; ptrd get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, - const T val7, const T val8, const T val9, const T val10, const T val11, const T val12, - const T val13, const T val14) const { + CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, + const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, + const T& val12, const T& val13, const T& val14) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10, val11,val12,val13,val14); } //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, - const T val7, const T val8, const T val9, const T val10, const T val11, const T val12, - const T val13, const T val14, const T val15) { + CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, + const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, + const T& val12, const T& val13, const T& val14, const T& val15) { if (is_empty()) return *this; - T *ptrd, *ptre = end()-15; + T *ptrd, *ptre = end() - 15; for (ptrd = _data; ptrd get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, - const T val7, const T val8, const T val9, const T val10, const T val11, const T val12, - const T val13, const T val14, const T val15) const { + CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, + const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, + const T& val12, const T& val13, const T& val14, const T& val15) const { return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10, val11,val12,val13,val14,val15); } @@ -18631,16 +18494,19 @@ namespace cimg_library_suffixed { //! Fill sequentially pixel values according to a given expression. /** \param expression C-string describing a math formula, or a list of values. - \param repeat_flag In case a list of values is provided, tells if this list must be repeated for the filling. + \param repeat_values In case a list of values is provided, tells if this list must be repeated for the filling. + \param allow_formula tells if a formula is allowed or only a list of values. **/ - CImg& fill(const char *const expression, const bool repeat_flag) { + CImg& fill(const char *const expression, const bool repeat_values, const bool allow_formula=true) { if (is_empty() || !expression || !*expression) return *this; const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; - try { // Try to fill values according to a formula. + cimg::exception_mode(0); + CImg is_error; + + if (allow_formula) try { // Try to fill values according to a formula. const CImg _base = cimg::_is_self_expr(expression)?+*this:CImg(), &base = _base?_base:*this; - _cimg_math_parser mp(base,expression+(*expression=='>' || *expression=='<'?1:0),"fill"); - T *ptrd = *expression=='<'?end()-1:_data; + _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"fill"); + T *ptrd = *expression=='<'?end() - 1:_data; if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) *(ptrd--) = (T)mp(x,y,z,c); else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) *(ptrd++) = (T)mp(x,y,z,c); else { @@ -18659,33 +18525,41 @@ namespace cimg_library_suffixed { #endif cimg_forXYZC(*this,x,y,z,c) *(ptrd++) = (T)mp(x,y,z,c); } - } catch (CImgException& e) { // If failed, try to recognize a list of values. - char item[16384] = { 0 }, sep = 0; + } catch (CImgException& e) { CImg::string(e._message).move_to(is_error); } + + // If failed, try to recognize a list of values. + if (!allow_formula || is_error) { + char *const item = new char[16384], sep = 0; const char *nexpression = expression; unsigned long nb = 0; const unsigned long siz = size(); T *ptrd = _data; for (double val = 0; *nexpression && nb0 && std::sscanf(item,"%lf",&val)==1) { + const int err = cimg_sscanf(nexpression,"%16383[ \n\t0-9.eEinfa+-]%c",item,&sep); + if (err>0 && cimg_sscanf(item,"%lf",&val)==1 && (sep==',' || sep==';' || err==1)) { nexpression+=std::strlen(item) + (err>1?1:0); *(ptrd++) = (T)val; } else break; } - cimg::exception_mode() = omode; - if (nb get_fill(const char *const values, const bool repeat_values) const { - return (+*this).fill(values,repeat_values); + CImg get_fill(const char *const values, const bool repeat_values, const bool allow_formula=true) const { + return (+*this).fill(values,repeat_values,allow_formula); } //! Fill sequentially pixel values according to the values found in another image. @@ -18791,57 +18665,135 @@ namespace cimg_library_suffixed { return *this; } - //! Discard specified value in the image buffer. + //! Discard specified sequence of values in the image buffer, along a specific axis. /** - \param value Value to discard. + \param values Sequence of values to discard. + \param axis Axis along which the values are discarded. If set to \c 0 (default value) + the method does it for all the buffer values and returns a one-column vector. \note Discarded values will change the image geometry, so the resulting image is returned as a one-column vector. **/ - CImg& discard(const T value) { - return get_discard(value).move_to(*this); + template + CImg& discard(const CImg& values, const char axis=0) { + if (is_empty() || !values) return *this; + return get_discard(values,axis).move_to(*this); } - //! Discard specified value in the image buffer \newinstance. - CImg get_discard(const T value) const { - CImg res(1,size()); - T *pd = res._data; - for (const T *ps = _data, *const pse = end(); ps(); - return res.resize(1,pd-res._data,1,1,-1); + template + CImg get_discard(const CImg& values, const char axis=0) const { + CImg res; + if (!values) return +*this; + if (is_empty()) return res; + const unsigned long vsiz = values.size(); + const char _axis = cimg::uncase(axis); + unsigned long j = 0; + unsigned int k = 0; + int i0 = 0; + res.assign(width(),height(),depth(),spectrum()); + switch (_axis) { + case 'x' : { + cimg_forX(*this,i) { + if ((*this)(i)!=(T)values[j]) { + if (j) --i; + res.draw_image(k,get_columns(i0,i)); + k+=i - i0 + 1; i0 = i + 1; j = 0; + } else { ++j; if (j>=vsiz) { j = 0; i0 = i + 1; } } + } + if (i0=vsiz) { j = 0; i0 = i + 1; } } + } + if (i0=vsiz) { j = 0; i0 = i + 1; } } + } + if (i0=vsiz) { j = 0; i0 = i + 1; } } + } + if (i0=vsiz) { j = 0; i0 = (int)i + 1; }} + } + const unsigned long siz = size(); + if ((unsigned long)i0 - CImg& discard(const CImg& values) { - return get_discard(values).move_to(*this); + //! Discard neighboring duplicates in the image buffer, along the specified axis. + CImg& discard(const char axis=0) { + return get_discard(axis).move_to(*this); } - //! Discard specified sequence of values in the image buffer \newinstance. - template - CImg get_discard(const CImg& values) const { - if (!values) return *this; - if (values.size()==1) return get_discard(*values); - CImg res(1,size()); - T *pd = res._data; - const t *const pve = values.end(); - for (const T *ps = _data, *const pse = end(); ps(); - return res.resize(1,pd-res._data,1,1,-1); + //! Discard neighboring duplicates in the image buffer, along the specified axis \newinstance. + CImg get_discard(const char axis=0) const { + CImg res; + if (is_empty()) return res; + const char _axis = cimg::uncase(axis); + T current = *_data?0:(T)1; + int j = 0; + res.assign(width(),height(),depth(),spectrum()); + switch (_axis) { + case 'x' : { + cimg_forX(*this,i) + if ((*this)(i)!=current) { res.draw_image(j++,get_column(i)); current = (*this)(i); } + res.resize(j,-100,-100,-100,0); + } break; + case 'y' : { + cimg_forY(*this,i) + if ((*this)(0,i)!=current) { res.draw_image(0,j++,get_row(i)); current = (*this)(0,i); } + res.resize(-100,j,-100,-100,0); + } break; + case 'z' : { + cimg_forZ(*this,i) + if ((*this)(0,0,i)!=current) { res.draw_image(0,0,j++,get_slice(i)); current = (*this)(0,0,i); } + res.resize(-100,-100,j,-100,0); + } break; + case 'c' : { + cimg_forC(*this,i) + if ((*this)(0,0,0,i)!=current) { res.draw_image(0,0,0,j++,get_channel(i)); current = (*this)(0,0,0,i); } + res.resize(-100,-100,-100,j,0); + } break; + default : { + res.unroll('y'); + cimg_foroff(*this,i) + if ((*this)[i]!=current) res[j++] = current = (*this)[i]; + res.resize(-100,j,-100,-100,0); + } + } + return res; } //! Invert endianness of all pixel values. @@ -18863,14 +18815,15 @@ namespace cimg_library_suffixed { \param val_max Maximal random value. \note Random samples are following a uniform distribution. **/ - CImg& rand(const T val_min, const T val_max) { - const float delta = (float)val_max - (float)val_min; - cimg_for(*this,ptrd,T) *ptrd = (T)(val_min + cimg::rand()*delta); + CImg& rand(const T& val_min, const T& val_max) { + const float delta = (float)val_max - (float)val_min + (cimg::type::is_float()?0:1); + if (cimg::type::is_float()) cimg_for(*this,ptrd,T) *ptrd = (T)(val_min + cimg::rand()*delta); + else cimg_for(*this,ptrd,T) *ptrd = cimg::min(val_max,(T)(val_min + cimg::rand()*delta)); return *this; } //! Fill image with random values in specified range \newinstance. - CImg get_rand(const T val_min, const T val_max) const { + CImg get_rand(const T& val_min, const T& val_max) const { return (+*this).rand(val_min,val_max); } @@ -18915,59 +18868,56 @@ namespace cimg_library_suffixed { \image html ref_noise.jpg **/ CImg& noise(const double sigma, const unsigned int noise_type=0) { - if (!is_empty()) { - const Tfloat vmin = (Tfloat)cimg::type::min(), vmax = (Tfloat)cimg::type::max(); - Tfloat nsigma = (Tfloat)sigma, m = 0, M = 0; - if (nsigma==0 && noise_type!=3) return *this; - if (nsigma<0 || noise_type==2) m = (Tfloat)min_max(M); - if (nsigma<0) nsigma = (Tfloat)(-nsigma*(M-m)/100.0); - switch (noise_type) { - case 0 : { // Gaussian noise - cimg_rof(*this,ptrd,T) { - Tfloat val = (Tfloat)(*ptrd + nsigma*cimg::grand()); - if (val>vmax) val = vmax; - if (valvmax) val = vmax; - if (val::is_float()?1:cimg::type::max()); } - cimg_rof(*this,ptrd,T) if (cimg::rand()*100vmax) val = vmax; - if (val::min(), vmax = (Tfloat)cimg::type::max(); + Tfloat nsigma = (Tfloat)sigma, m = 0, M = 0; + if (nsigma==0 && noise_type!=3) return *this; + if (nsigma<0 || noise_type==2) m = (Tfloat)min_max(M); + if (nsigma<0) nsigma = (Tfloat)(-nsigma*(M-m)/100.0); + switch (noise_type) { + case 0 : { // Gaussian noise + cimg_rof(*this,ptrd,T) { + Tfloat val = (Tfloat)(*ptrd + nsigma*cimg::grand()); + if (val>vmax) val = vmax; + if (valvmax) val = vmax; + if (val::is_float()?1:cimg::type::max()); } + cimg_rof(*this,ptrd,T) if (cimg::rand()*100vmax) val = vmax; + if (val& normalize(const T min_value, const T max_value) { + CImg& normalize(const T& min_value, const T& max_value) { if (is_empty()) return *this; const T a = min_value=65536) #endif - cimg_rof(*this,ptrd,T) *ptrd = (T)((*ptrd-fm)/(fM-fm)*(b-a)+a); + cimg_rof(*this,ptrd,T) *ptrd = (T)((*ptrd - fm)/(fM - fm)*(b - a) + a); return *this; } //! Linearly normalize pixel values \newinstance. - CImg get_normalize(const T min_value, const T max_value) const { + CImg get_normalize(const T& min_value, const T& max_value) const { return CImg(*this,false).normalize((Tfloat)min_value,(Tfloat)max_value); } @@ -19041,9 +18991,9 @@ namespace cimg_library_suffixed { return CImg(*this,false).normalize(); } - //! Compute L2-norm of each multi-valued pixel of the image instance. + //! Compute Lp-norm of each multi-valued pixel of the image instance. /** - \param norm_type Type of computed vector norm (can be \p 0=Linf, \p 1=L1 or \p 2=L2). + \param norm_type Type of computed vector norm (can be \p -1=Linf, or \p>=0). \par Example \code const CImg img("reference.jpg"), res = img.get_norm(); @@ -19052,23 +19002,23 @@ namespace cimg_library_suffixed { \image html ref_norm.jpg **/ CImg& norm(const int norm_type=2) { - if (_spectrum==1) return abs(); + if (_spectrum==1 && norm_type) return abs(); return get_norm(norm_type).move_to(*this); } //! Compute L2-norm of each multi-valued pixel of the image instance \newinstance. CImg get_norm(const int norm_type=2) const { if (is_empty()) return *this; - if (_spectrum==1) return get_abs(); + if (_spectrum==1 && norm_type) return get_abs(); const unsigned long whd = (unsigned long)_width*_height*_depth; CImg res(_width,_height,_depth); switch (norm_type) { - case -1 : { // Linf norm + case -1 : { // Linf-norm. #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width>=512 && _height*_depth>=16) #endif cimg_forYZ(*this,y,z) { - const unsigned long off = offset(0,y,z); + const unsigned long off = (unsigned long)offset(0,y,z); const T *ptrs = _data + off; Tfloat *ptrd = res._data + off; cimg_forX(*this,x) { @@ -19079,12 +19029,28 @@ namespace cimg_library_suffixed { } } } break; - case 1 : { // L1 norm + case 0 : { // L0-norm. +#ifdef cimg_use_openmp +#pragma omp parallel for collapse(2) if (_width>=512 && _height*_depth>=16) +#endif + cimg_forYZ(*this,y,z) { + const unsigned long off = (unsigned long)offset(0,y,z); + const T *ptrs = _data + off; + Tfloat *ptrd = res._data + off; + cimg_forX(*this,x) { + unsigned int n = 0; + const T *_ptrs = ptrs++; + cimg_forC(*this,c) { n+=*_ptrs==0?0:1; _ptrs+=whd; } + *(ptrd++) = (Tfloat)n; + } + } + } break; + case 1 : { // L1-norm. #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width>=512 && _height*_depth>=16) #endif cimg_forYZ(*this,y,z) { - const unsigned long off = offset(0,y,z); + const unsigned long off = (unsigned long)offset(0,y,z); const T *ptrs = _data + off; Tfloat *ptrd = res._data + off; cimg_forX(*this,x) { @@ -19095,12 +19061,12 @@ namespace cimg_library_suffixed { } } } break; - default : { // L2 norm + case 2 : { // L2-norm. #ifdef cimg_use_openmp #pragma omp parallel for collapse(2) if (_width>=512 && _height*_depth>=16) #endif cimg_forYZ(*this,y,z) { - const unsigned long off = offset(0,y,z); + const unsigned long off = (unsigned long)offset(0,y,z); const T *ptrs = _data + off; Tfloat *ptrd = res._data + off; cimg_forX(*this,x) { @@ -19110,6 +19076,22 @@ namespace cimg_library_suffixed { *(ptrd++) = (Tfloat)std::sqrt((Tfloat)n); } } + } break; + default : { // Linf-norm. +#ifdef cimg_use_openmp +#pragma omp parallel for collapse(2) if (_width>=512 && _height*_depth>=16) +#endif + cimg_forYZ(*this,y,z) { + const unsigned long off = (unsigned long)offset(0,y,z); + const T *ptrs = _data + off; + Tfloat *ptrd = res._data + off; + cimg_forX(*this,x) { + Tfloat n = 0; + const T *_ptrs = ptrs++; + cimg_forC(*this,c) { n+=std::pow(cimg::abs((Tfloat)*_ptrs),(Tfloat)norm_type); _ptrs+=whd; } + *(ptrd++) = (Tfloat)std::pow((Tfloat)n,1/(Tfloat)norm_type); + } + } } } return res; @@ -19126,7 +19108,7 @@ namespace cimg_library_suffixed { \endcode \image html ref_cut.jpg **/ - CImg& cut(const T min_value, const T max_value) { + CImg& cut(const T& min_value, const T& max_value) { if (is_empty()) return *this; const T a = min_value get_cut(const T min_value, const T max_value) const { + CImg get_cut(const T& min_value, const T& max_value) const { return (+*this).cut(min_value,max_value); } @@ -19167,14 +19149,14 @@ namespace cimg_library_suffixed { #endif cimg_rof(*this,ptrd,T) { const unsigned int val = (unsigned int)((*ptrd-m)*nb_levels/range); - *ptrd = (T)(m + cimg::min(val,nb_levels-1)*range/nb_levels); + *ptrd = (T)(m + cimg::min(val,nb_levels - 1)*range/nb_levels); } else #ifdef cimg_use_openmp #pragma omp parallel for if (size()>=32768) #endif cimg_rof(*this,ptrd,T) { const unsigned int val = (unsigned int)((*ptrd-m)*nb_levels/range); - *ptrd = (T)cimg::min(val,nb_levels-1); + *ptrd = (T)cimg::min(val,nb_levels - 1); } } return *this; @@ -19197,14 +19179,17 @@ namespace cimg_library_suffixed { \endcode \image html ref_threshold.jpg **/ - CImg& threshold(const T value, const bool soft_threshold=false, const bool strict_threshold=false) { + CImg& threshold(const T& value, const bool soft_threshold=false, const bool strict_threshold=false) { if (is_empty()) return *this; if (strict_threshold) { if (soft_threshold) #ifdef cimg_use_openmp #pragma omp parallel for if (size()>=32768) #endif - cimg_rof(*this,ptrd,T) { const T v = *ptrd; *ptrd = v>value?(T)(v-value):v<-(float)value?(T)(v+value):(T)0; } + cimg_rof(*this,ptrd,T) { + const T v = *ptrd; + *ptrd = v>value?(T)(v-value):v<-(float)value?(T)(v + value):(T)0; + } else #ifdef cimg_use_openmp #pragma omp parallel for if (size()>=65536) @@ -19216,7 +19201,8 @@ namespace cimg_library_suffixed { #pragma omp parallel for if (size()>=32768) #endif cimg_rof(*this,ptrd,T) { - const T v = *ptrd; *ptrd = v>=value?(T)(v-value):v<=-(float)value?(T)(v+value):(T)0; + const T v = *ptrd; + *ptrd = v>=value?(T)(v-value):v<=-(float)value?(T)(v + value):(T)0; } else #ifdef cimg_use_openmp @@ -19228,7 +19214,7 @@ namespace cimg_library_suffixed { } //! Threshold pixel values \newinstance. - CImg get_threshold(const T value, const bool soft_threshold=false, const bool strict_threshold=false) const { + CImg get_threshold(const T& value, const bool soft_threshold=false, const bool strict_threshold=false) const { return (+*this).threshold(value,soft_threshold,strict_threshold); } @@ -19250,7 +19236,7 @@ namespace cimg_library_suffixed { \endcode \image html ref_histogram.jpg **/ - CImg& histogram(const unsigned int nb_levels, const T min_value, const T max_value) { + CImg& histogram(const unsigned int nb_levels, const T& min_value, const T& max_value) { return get_histogram(nb_levels,min_value,max_value).move_to(*this); } @@ -19260,13 +19246,15 @@ namespace cimg_library_suffixed { } //! Compute the histogram of pixel values \newinstance. - CImg get_histogram(const unsigned int nb_levels, const T min_value, const T max_value) const { + CImg get_histogram(const unsigned int nb_levels, const T& min_value, const T& max_value) const { if (!nb_levels || is_empty()) return CImg(); - T vmin = min_value res(nb_levels,1,1,1,0); cimg_rof(*this,ptrs,T) { const T val = *ptrs; - if (val>=vmin && val<=vmax) ++res[val==vmax?nb_levels-1:(unsigned int)((val-vmin)*nb_levels/(vmax-vmin))]; + if (val>=vmin && val<=vmax) ++res[val==vmax?nb_levels - 1:(unsigned int)((val - vmin)*nb_levels/(vmax - vmin))]; } return res; } @@ -19292,9 +19280,11 @@ namespace cimg_library_suffixed { \endcode \image html ref_equalize.jpg **/ - CImg& equalize(const unsigned int nb_levels, const T min_value, const T max_value) { + CImg& equalize(const unsigned int nb_levels, const T& min_value, const T& max_value) { if (!nb_levels || is_empty()) return *this; - T vmin = min_value hist = get_histogram(nb_levels,vmin,vmax); unsigned long cumul = 0; cimg_forX(hist,pos) { cumul+=hist[pos]; hist[pos] = cumul; } @@ -19303,7 +19293,7 @@ namespace cimg_library_suffixed { #pragma omp parallel for if (size()>=1048576) #endif cimg_rof(*this,ptrd,T) { - const int pos = (int)((*ptrd-vmin)*(nb_levels-1)/(vmax-vmin)); + 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; @@ -19317,7 +19307,7 @@ namespace cimg_library_suffixed { } //! Equalize histogram of pixel values \newinstance. - CImg get_equalize(const unsigned int nblevels, const T val_min, const T val_max) const { + CImg get_equalize(const unsigned int nblevels, const T& val_min, const T& val_max) const { return (+*this).equalize(nblevels,val_min,val_max); } @@ -19368,14 +19358,14 @@ namespace cimg_library_suffixed { const float ndithering = (dithering<0?0:dithering>1?1:dithering)/16; Tfloat valm = 0, valM = (Tfloat)max_min(valm); if (valm==valM && valm>=0 && valM<=255) { valm = 0; valM = 255; } - CImg cache = get_crop(-1,0,0,0,_width,1,0,_spectrum-1); + CImg cache = get_crop(-1,0,0,0,_width,1,0,_spectrum - 1); Tfloat *cache_current = cache.data(1,0,0,0), *cache_next = cache.data(1,1,0,0); const unsigned long cwhd = (unsigned long)cache._width*cache._height*cache._depth; switch (_spectrum) { case 1 : { // Optimized for scalars. cimg_forYZ(*this,y,z) { - if (y=(long)pwhd?pwhd-1:ind]; + *ptrd = colormap[ind<0?0:ind>=(long)pwhd?pwhd - 1:ind]; } break; default : // Dirichlet boundaries. cimg_for(res,ptrd,t) { @@ -19672,7 +19662,7 @@ namespace cimg_library_suffixed { const t *const ptrp0 = colormap._data, *ptrp1 = ptrp0 + pwhd; t *ptrd0 = res._data, *ptrd1 = ptrd0 + whd; for (const T *ptrs = _data, *ptrs_end = ptrs + whd; ptrs=(long)pwhd?pwhd-1:_ind; + const long _ind = (long)*(ptrs++), ind = _ind<0?0:_ind>=(long)pwhd?(long)pwhd - 1:_ind; *(ptrd0++) = ptrp0[ind]; *(ptrd1++) = ptrp1[ind]; } } break; @@ -19702,7 +19692,7 @@ namespace cimg_library_suffixed { const t *const ptrp0 = colormap._data, *ptrp1 = ptrp0 + pwhd, *ptrp2 = ptrp1 + pwhd; t *ptrd0 = res._data, *ptrd1 = ptrd0 + whd, *ptrd2 = ptrd1 + whd; for (const T *ptrs = _data, *ptrs_end = ptrs + whd; ptrs=(long)pwhd?pwhd-1:_ind; + const long _ind = (long)*(ptrs++), ind = _ind<0?0:_ind>=(long)pwhd?(long)pwhd - 1:_ind; *(ptrd0++) = ptrp0[ind]; *(ptrd1++) = ptrp1[ind]; *(ptrd2++) = ptrp2[ind]; } } break; @@ -19731,7 +19721,7 @@ namespace cimg_library_suffixed { case 1 : { // Neumann boundaries. t *ptrd = res._data; for (const T *ptrs = _data, *ptrs_end = ptrs + whd; ptrs=(long)pwhd?pwhd-1:_ind; + const long _ind = (long)*(ptrs++), ind = _ind<0?0:_ind>=(long)pwhd?(long)pwhd - 1:_ind; const t *ptrp = colormap._data + ind; t *_ptrd = ptrd++; cimg_forC(res,c) { *_ptrd = *ptrp; _ptrd+=whd; ptrp+=pwhd; } } @@ -19777,24 +19767,24 @@ namespace cimg_library_suffixed { // Create neighborhood tables. int dx[13], dy[13], dz[13], nb = 0; - dx[nb]=1; dy[nb] = 0; dz[nb++]=0; - dx[nb]=0; dy[nb] = 1; dz[nb++]=0; + dx[nb] = 1; dy[nb] = 0; dz[nb++] = 0; + dx[nb] = 0; dy[nb] = 1; dz[nb++] = 0; if (is_high_connectivity) { - dx[nb]=1; dy[nb] = 1; dz[nb++]=0; - dx[nb]=1; dy[nb] = -1; dz[nb++]=0; + dx[nb] = 1; dy[nb] = 1; dz[nb++] = 0; + dx[nb] = 1; dy[nb] = -1; dz[nb++] = 0; } if (_depth>1) { // 3d version. - dx[nb]=0; dy[nb] = 0; dz[nb++]=1; + dx[nb] = 0; dy[nb] = 0; dz[nb++]=1; if (is_high_connectivity) { - dx[nb]=1; dy[nb] = 1; dz[nb++]=-1; - dx[nb]=1; dy[nb] = 0; dz[nb++]=-1; - dx[nb]=1; dy[nb] = -1; dz[nb++]=-1; - dx[nb]=0; dy[nb] = 1; dz[nb++]=-1; + dx[nb] = 1; dy[nb] = 1; dz[nb++] = -1; + dx[nb] = 1; dy[nb] = 0; dz[nb++] = -1; + dx[nb] = 1; dy[nb] = -1; dz[nb++] = -1; + dx[nb] = 0; dy[nb] = 1; dz[nb++] = -1; - dx[nb]=0; dy[nb] = 1; dz[nb++]=1; - dx[nb]=1; dy[nb] = -1; dz[nb++]=1; - dx[nb]=1; dy[nb] = 0; dz[nb++]=1; - dx[nb]=1; dy[nb] = 1; dz[nb++]=1; + dx[nb] = 0; dy[nb] = 1; dz[nb++] = 1; + dx[nb] = 1; dy[nb] = -1; dz[nb++] = 1; + dx[nb] = 1; dy[nb] = 0; dz[nb++] = 1; + dx[nb] = 1; dy[nb] = 1; dz[nb++] = 1; } } return _get_label(nb,dx,dy,dz,tolerance); @@ -19842,22 +19832,35 @@ namespace cimg_library_suffixed { if (_dx || _dy || _dz) { const int x0 = _dx<0?-_dx:0, - x1 = _dx<0?_width:_width - _dx, + x1 = _dx<0?width():width() - _dx, y0 = _dy<0?-_dy:0, - y1 = _dy<0?_height:_height - _dy, + y1 = _dy<0?height():height() - _dy, z0 = _dz<0?-_dz:0, - z1 = _dz<0?_depth:_depth - _dz; - const long wh = (long)_width*_height, offset = (long)_dz*wh + (long)_dy*_width + _dx; + z1 = _dz<0?depth():depth() - _dz; + const long + wh = width()*height(), + whd = width()*height()*depth(), + offset = _dz*wh + _dy*width() + _dx; for (long z = z0, nz = z0 + _dz, pz = z0*wh; z& _system_strescape() { #define cimg_system_strescape(c,s) case c : if (p!=ptrs) CImg(ptrs,(unsigned int)(p-ptrs),1,1,1,false).\ move_to(list); \ - CImg(s,(unsigned int)std::strlen(s),1,1,1,false).move_to(list); ptrs = p+1; break + CImg(s,(unsigned int)std::strlen(s),1,1,1,false).move_to(list); ptrs = p + 1; break CImgList list; const T *ptrs = _data; cimg_for(*this,p,T) switch ((int)*p) { @@ -20061,7 +20064,7 @@ namespace cimg_library_suffixed { const Tfloat sval = (Tfloat)*ptr, nsval = (sval<0?0:sval>255?255:sval)/255, - val = (Tfloat)(nsval<=0.04045f?nsval/12.92f:std::pow((nsval+0.055f)/(1.055f),2.4f)); + val = (Tfloat)(nsval<=0.04045f?nsval/12.92f:std::pow((nsval + 0.055f)/(1.055f),2.4f)); *ptr = (T)(val*255); } return *this; @@ -20139,7 +20142,7 @@ namespace cimg_library_suffixed { T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); for (unsigned long N = (unsigned long)_width*_height*_depth; N; --N) { Tfloat - H = (Tfloat)*p1, + H = cimg::mod((Tfloat)*p1,(Tfloat)360), S = (Tfloat)*p2, V = (Tfloat)*p3, R = 0, G = 0, B = 0; @@ -20202,7 +20205,7 @@ namespace cimg_library_suffixed { H = (i-f/(M-m)); if (H>=6) H-=6; H*=60; - S = (2*L<=1)?((M-m)/(M+m)):((M-m)/(2-M-m)); + S = (2*L<=1)?((M - m)/(M + m)):((M - m)/(2 - M - m)); } *(p1++) = (T)H; *(p2++) = (T)S; @@ -20226,21 +20229,21 @@ namespace cimg_library_suffixed { T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); for (unsigned long N = (unsigned long)_width*_height*_depth; N; --N) { const Tfloat - H = (Tfloat)*p1, + H = cimg::mod((Tfloat)*p1,(Tfloat)360), S = (Tfloat)*p2, L = (Tfloat)*p3, - q = 2*L<1?L*(1+S):(L+S-L*S), - p = 2*L-q, + q = 2*L<1?L*(1 + S):(L + S - L*S), + p = 2*L - q, h = H/360, tr = h + 1.0f/3, tg = h, tb = h - 1.0f/3, - ntr = tr<0?tr+1:(tr>1?tr-1:tr), - ntg = tg<0?tg+1:(tg>1?tg-1:tg), - ntb = tb<0?tb+1:(tb>1?tb-1:tb), - R = 255*(6*ntr<1?p+(q-p)*6*ntr:(2*ntr<1?q:(3*ntr<2?p+(q-p)*6*(2.0f/3-ntr):p))), - G = 255*(6*ntg<1?p+(q-p)*6*ntg:(2*ntg<1?q:(3*ntg<2?p+(q-p)*6*(2.0f/3-ntg):p))), - B = 255*(6*ntb<1?p+(q-p)*6*ntb:(2*ntb<1?q:(3*ntb<2?p+(q-p)*6*(2.0f/3-ntb):p))); + ntr = tr<0?tr + 1:(tr>1?tr - 1:tr), + ntg = tg<0?tg + 1:(tg>1?tg - 1:tg), + ntb = tb<0?tb + 1:(tb>1?tb - 1:tb), + R = 255*(6*ntr<1?p + (q - p)*6*ntr:(2*ntr<1?q:(3*ntr<2?p + (q - p)*6*(2.0f/3 - ntr):p))), + G = 255*(6*ntg<1?p + (q - p)*6*ntg:(2*ntg<1?q:(3*ntg<2?p + (q - p)*6*(2.0f/3 - ntg):p))), + B = 255*(6*ntb<1?p + (q - p)*6*ntb:(2*ntb<1?q:(3*ntb<2?p + (q - p)*6*(2.0f/3 - ntb):p))); *(p1++) = (T)(R<0?0:(R>255?255:R)); *(p2++) = (T)(G<0?0:(G>255?255:G)); *(p3++) = (T)(B<0?0:(B>255?255:B)); @@ -20270,10 +20273,11 @@ namespace cimg_library_suffixed { nG = (G<0?0:(G>255?255:G))/255, nB = (B<0?0:(B>255?255:B))/255, m = cimg::min(nR,nG,nB), - theta = (Tfloat)(std::acos(0.5f*((nR-nG)+(nR-nB))/std::sqrt(std::pow(nR-nG,2)+(nR-nB)*(nG-nB)))*180/cimg::PI), + theta = (Tfloat)(std::acos(0.5f*((nR - nG) + (nR - nB))/ + std::sqrt(std::pow(nR - nG,2) + (nR - nB)*(nG - nB)))*180/cimg::PI), sum = nR + nG + nB; Tfloat H = 0, S = 0, I = 0; - if (theta>0) H = (nB<=nG)?theta:360-theta; + if (theta>0) H = (nB<=nG)?theta:360 - theta; if (sum>0) S = 1 - 3/sum*m; I = sum/3; *(p1++) = (T)H; @@ -20298,25 +20302,25 @@ namespace cimg_library_suffixed { T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); for (unsigned long N = (unsigned long)_width*_height*_depth; N; --N) { Tfloat - H = (Tfloat)*p1, + H = cimg::mod((Tfloat)*p1,(Tfloat)360), S = (Tfloat)*p2, I = (Tfloat)*p3, a = I*(1-S), R = 0, G = 0, B = 0; if (H<120) { B = a; - R = (Tfloat)(I*(1+S*std::cos(H*cimg::PI/180)/std::cos((60-H)*cimg::PI/180))); - G = 3*I-(R+B); + R = (Tfloat)(I*(1 + S*std::cos(H*cimg::PI/180)/std::cos((60 - H)*cimg::PI/180))); + G = 3*I - (R + B); } else if (H<240) { H-=120; R = a; - G = (Tfloat)(I*(1+S*std::cos(H*cimg::PI/180)/std::cos((60-H)*cimg::PI/180))); - B = 3*I-(R+G); + G = (Tfloat)(I*(1 + S*std::cos(H*cimg::PI/180)/std::cos((60 - H)*cimg::PI/180))); + B = 3*I - (R + G); } else { H-=240; G = a; - B = (Tfloat)(I*(1+S*std::cos(H*cimg::PI/180)/std::cos((60-H)*cimg::PI/180))); - R = 3*I-(G+B); + B = (Tfloat)(I*(1 + S*std::cos(H*cimg::PI/180)/std::cos((60 - H)*cimg::PI/180))); + R = 3*I - (G + B); } R*=255; G*=255; B*=255; *(p1++) = (T)(R<0?0:(R>255?255:R)); @@ -20514,12 +20518,12 @@ namespace cimg_library_suffixed { Tfloat *pd1 = res.data(0,0,0,0), *pd2 = res.data(0,0,0,1), *pd3 = res.data(0,0,0,2), *pd4 = res.data(0,0,0,3); for (unsigned long N = (unsigned long)_width*_height*_depth; N; --N) { Tfloat - C = (Tfloat)*(ps1++), - M = (Tfloat)*(ps2++), - Y = (Tfloat)*(ps3++), - K = cimg::min(C,M,Y); - if (K>=255) C = M = Y = 0; - else { const Tfloat K1 = 255 - K; C = 255*(C - K)/K1; M = 255*(M - K)/K1; Y = 255*(Y - K)/K1; } + C = (Tfloat)*(ps1++), + M = (Tfloat)*(ps2++), + Y = (Tfloat)*(ps3++), + K = cimg::min(C,M,Y); + if (K>=255) C = M = Y = 0; + else { const Tfloat K1 = 255 - K; C = 255*(C - K)/K1; M = 255*(M - K)/K1; Y = 255*(Y - K)/K1; } *(pd1++) = (Tfloat)(C<0?0:(C>255?255:C)); *(pd2++) = (Tfloat)(M<0?0:(M>255?255:M)); *(pd3++) = (Tfloat)(Y<0?0:(Y>255?255:Y)); @@ -20545,11 +20549,11 @@ namespace cimg_library_suffixed { Tfloat *pd1 = res.data(0,0,0,0), *pd2 = res.data(0,0,0,1), *pd3 = res.data(0,0,0,2); for (unsigned long N = (unsigned long)_width*_height*_depth; N; --N) { const Tfloat - C = (Tfloat)*(ps1++), - M = (Tfloat)*(ps2++), - Y = (Tfloat)*(ps3++), - K = (Tfloat)*(ps4++), - K1 = 1 - K/255, + C = (Tfloat)*(ps1++), + M = (Tfloat)*(ps2++), + Y = (Tfloat)*(ps3++), + K = (Tfloat)*(ps4++), + K1 = 1 - K/255, nC = C*K1 + K, nM = M*K1 + K, nY = Y*K1 + K; @@ -20618,7 +20622,7 @@ namespace cimg_library_suffixed { //! Convert pixel values from XYZ_709 to Lab color spaces. CImg& XYZtoLab() { -#define _cimg_Labf(x) ((x)>=0.008856f?(std::pow(x,(Tfloat)1/3)):(7.787f*(x)+16.0f/116)) +#define _cimg_Labf(x) ((x)>=0.008856f?(std::pow(x,(Tfloat)1/3)):(7.787f*(x) + 16.0f/116)) if (_spectrum!=3) throw CImgInstanceException(_cimg_instance @@ -20672,11 +20676,10 @@ namespace cimg_library_suffixed { b = (Tfloat)*p3, cY = (L + 16)/116, Y = (Tfloat)(Yn*_cimg_Labfi(cY)), - pY = (Tfloat)std::pow(Y/Yn,(Tfloat)1/3), - cX = a/500 + pY, - X = Xn*cX*cX*cX, - cZ = pY - b/200, - Z = Zn*cZ*cZ*cZ; + cX = a/500 + cY, + X = (Tfloat)(Xn*_cimg_Labfi(cX)), + cZ = cY - b/200, + Z = (Tfloat)(Zn*_cimg_Labfi(cZ)); *(p1++) = (T)(X); *(p2++) = (T)(Y); *(p3++) = (T)(Z); @@ -20702,7 +20705,7 @@ namespace cimg_library_suffixed { X = (Tfloat)*p1, Y = (Tfloat)*p2, Z = (Tfloat)*p3, - sum = (X+Y+Z), + sum = X + Y + Z, nsum = sum>0?sum:1; *(p1++) = (T)(X/nsum); *(p2++) = (T)(Y/nsum); @@ -20732,7 +20735,7 @@ namespace cimg_library_suffixed { ny = py>0?py:1; *(p1++) = (T)(px*Y/ny); *(p2++) = (T)Y; - *(p3++) = (T)((1-px-py)*Y/ny); + *(p3++) = (T)((1 - px - py)*Y/ny); } return *this; } @@ -20802,172 +20805,6 @@ namespace cimg_library_suffixed { return CImg(*this,false).CMYKtoRGB(); } - //! Convert RGB color image to a Bayer-coded scalar image. - /** - \note First (upper-left) pixel if the red component of the pixel color. - **/ - CImg& RGBtoBayer() { - return get_RGBtoBayer().move_to(*this); - } - - //! Convert RGB color image to a Bayer-coded scalar image \newinstance. - CImg get_RGBtoBayer() const { - if (_spectrum!=3) - throw CImgInstanceException(_cimg_instance - "RGBtoBayer(): Instance is not a RGB image.", - cimg_instance); - - CImg res(_width,_height,_depth,1); - const T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2); - T *ptrd = res._data; - cimg_forXYZ(*this,x,y,z) { - if (y%2) { - if (x%2) *(ptrd++) = *ptr_b; - else *(ptrd++) = *ptr_g; - } else { - if (x%2) *(ptrd++) = *ptr_g; - else *(ptrd++) = *ptr_r; - } - ++ptr_r; ++ptr_g; ++ptr_b; - } - return res; - } - - //! Convert Bayer-coded scalar image to a RGB color image. - CImg& BayertoRGB(const unsigned int interpolation_type=3) { - return get_BayertoRGB(interpolation_type).move_to(*this); - } - - //! Convert Bayer-coded scalar image to a RGB color image \newinstance. - CImg get_BayertoRGB(const unsigned int interpolation_type=3) const { - if (_spectrum!=1) - throw CImgInstanceException(_cimg_instance - "BayertoRGB(): Instance is not a Bayer image.", - cimg_instance); - - CImg res(_width,_height,_depth,3); - CImg_3x3(I,T); - Tuchar *ptr_r = res.data(0,0,0,0), *ptr_g = res.data(0,0,0,1), *ptr_b = res.data(0,0,0,2); - switch (interpolation_type) { - case 3 : { // Edge-directed - CImg_3x3(R,T); - CImg_3x3(G,T); - CImg_3x3(B,T); - cimg_forXYZ(*this,x,y,z) { - const int _p1x = x?x-1:1, _p1y = y?y-1:1, _n1x = x(sx,sy,sz,sc,0); - CImg res; switch (interpolation_type) { @@ -21087,36 +20923,38 @@ namespace cimg_library_suffixed { res.assign(sx,sy,sz,sc).draw_image(xc,yc,zc,cc,*this); CImg sprite; if (xc>0) { // X-backward - res.get_crop(xc,yc,zc,cc,xc,yc+height()-1,zc+depth()-1,cc+spectrum()-1).move_to(sprite); - for (int x = xc-1; x>=0; --x) res.draw_image(x,yc,zc,cc,sprite); + res.get_crop(xc,yc,zc,cc,xc,yc + height() - 1,zc + depth() - 1,cc + spectrum() - 1).move_to(sprite); + for (int x = xc - 1; x>=0; --x) res.draw_image(x,yc,zc,cc,sprite); } - if (xc+width()<(int)sx) { // X-forward - res.get_crop(xc+width()-1,yc,zc,cc,xc+width()-1,yc+height()-1,zc+depth()-1,cc+spectrum()-1).move_to(sprite); - for (int x = xc+width(); x<(int)sx; ++x) res.draw_image(x,yc,zc,cc,sprite); + if (xc + width()<(int)sx) { // X-forward + res.get_crop(xc + width() - 1,yc,zc,cc,xc + width() - 1,yc + height() - 1, + zc + depth() - 1,cc + spectrum() - 1).move_to(sprite); + for (int x = xc + width(); x<(int)sx; ++x) res.draw_image(x,yc,zc,cc,sprite); } if (yc>0) { // Y-backward - res.get_crop(0,yc,zc,cc,sx-1,yc,zc+depth()-1,cc+spectrum()-1).move_to(sprite); - for (int y = yc-1; y>=0; --y) res.draw_image(0,y,zc,cc,sprite); + res.get_crop(0,yc,zc,cc,sx - 1,yc,zc + depth() - 1,cc + spectrum() - 1).move_to(sprite); + for (int y = yc - 1; y>=0; --y) res.draw_image(0,y,zc,cc,sprite); } - if (yc+height()<(int)sy) { // Y-forward - res.get_crop(0,yc+height()-1,zc,cc,sx-1,yc+height()-1,zc+depth()-1,cc+spectrum()-1).move_to(sprite); - for (int y = yc+height(); y<(int)sy; ++y) res.draw_image(0,y,zc,cc,sprite); + if (yc + height()<(int)sy) { // Y-forward + res.get_crop(0,yc + height() - 1,zc,cc,sx - 1,yc + height() - 1, + zc + depth() - 1,cc + spectrum() - 1).move_to(sprite); + for (int y = yc + height(); y<(int)sy; ++y) res.draw_image(0,y,zc,cc,sprite); } if (zc>0) { // Z-backward - res.get_crop(0,0,zc,cc,sx-1,sy-1,zc,cc+spectrum()-1).move_to(sprite); - for (int z = zc-1; z>=0; --z) res.draw_image(0,0,z,cc,sprite); + res.get_crop(0,0,zc,cc,sx - 1,sy - 1,zc,cc + spectrum() - 1).move_to(sprite); + for (int z = zc - 1; z>=0; --z) res.draw_image(0,0,z,cc,sprite); } - if (zc+depth()<(int)sz) { // Z-forward - res.get_crop(0,0,zc+depth()-1,cc,sx-1,sy-1,zc+depth()-1,cc+spectrum()-1).move_to(sprite); - for (int z = zc+depth(); z<(int)sz; ++z) res.draw_image(0,0,z,cc,sprite); + if (zc + depth()<(int)sz) { // Z-forward + res.get_crop(0,0,zc +depth() - 1,cc,sx - 1,sy - 1,zc + depth() - 1,cc + spectrum() - 1).move_to(sprite); + for (int z = zc + depth(); z<(int)sz; ++z) res.draw_image(0,0,z,cc,sprite); } if (cc>0) { // C-backward - res.get_crop(0,0,0,cc,sx-1,sy-1,sz-1,cc).move_to(sprite); - for (int c = cc-1; c>=0; --c) res.draw_image(0,0,0,c,sprite); + res.get_crop(0,0,0,cc,sx - 1,sy - 1,sz - 1,cc).move_to(sprite); + for (int c = cc - 1; c>=0; --c) res.draw_image(0,0,0,c,sprite); } - if (cc+spectrum()<(int)sc) { // C-forward - res.get_crop(0,0,0,cc+spectrum()-1,sx-1,sy-1,sz-1,cc+spectrum()-1).move_to(sprite); - for (int c = cc+spectrum(); c<(int)sc; ++c) res.draw_image(0,0,0,c,sprite); + if (cc + spectrum()<(int)sc) { // C-forward + res.get_crop(0,0,0,cc + spectrum() - 1,sx - 1,sy - 1,sz - 1,cc + spectrum() - 1).move_to(sprite); + for (int c = cc + spectrum(); c<(int)sc; ++c) res.draw_image(0,0,0,c,sprite); } } break; default : // Dirichlet borders. @@ -21129,7 +20967,7 @@ namespace cimg_library_suffixed { // case 1 : { res.assign(sx,sy,sz,sc); - CImg off_x(sx), off_y(sy+1), off_z(sz+1), off_c(sc+1); + CImg off_x(sx), off_y(sy + 1), off_z(sz + 1), off_c(sc + 1); const unsigned long wh = (unsigned long)_width*_height, whd = (unsigned long)_width*_height*_depth, @@ -21138,14 +20976,18 @@ namespace cimg_library_suffixed { if (sx==_width) off_x.fill(1); else { unsigned long *poff_x = off_x._data, curr = 0; - cimg_forX(res,x) { const unsigned long old = curr; curr = ((x+1LU)*_width/sx); *(poff_x++) = curr - old; } + cimg_forX(res,x) { + const unsigned long old = curr; + curr = (unsigned long)((x + 1.0)*_width/sx); + *(poff_x++) = curr - old; + } } if (sy==_height) off_y.fill(_width); else { unsigned long *poff_y = off_y._data, curr = 0; cimg_forY(res,y) { const unsigned long old = curr; - curr = ((y+1LU)*_height/sy); + curr = (unsigned long)((y + 1.0)*_height/sy); *(poff_y++) = _width*(curr - old); } *poff_y = 0; @@ -21155,7 +20997,7 @@ namespace cimg_library_suffixed { unsigned long *poff_z = off_z._data, curr = 0; cimg_forZ(res,z) { const unsigned long old = curr; - curr = ((z+1LU)*_depth/sz); + curr = (unsigned long)((z + 1.0)*_depth/sz); *(poff_z++) = wh*(curr - old); } *poff_z = 0; @@ -21165,7 +21007,7 @@ namespace cimg_library_suffixed { unsigned long *poff_c = off_c._data, curr = 0; cimg_forC(res,c) { const unsigned long old = curr; - curr = ((c+1LU)*_spectrum/sc); + curr = (unsigned long)((c + 1.0)*_spectrum/sc); *(poff_c++) = whd*(curr - old); } *poff_c = 0; @@ -21292,7 +21134,7 @@ namespace cimg_library_suffixed { else { if (_width>sx) get_resize(sx,_height,_depth,_spectrum,2).move_to(resx); else { - const float fx = (!boundary_conditions && sx>_width)?(sx>1?(_width-1.0f)/(sx-1):0):(float)_width/sx; + const float fx = (!boundary_conditions && sx>_width)?(sx>1?(_width - 1.0f)/(sx - 1):0):(float)_width/sx; resx.assign(sx,_height,_depth,_spectrum); float curr = 0, old = 0; unsigned int *poff = off._data; @@ -21307,14 +21149,14 @@ namespace cimg_library_suffixed { #pragma omp parallel for collapse(3) if (resx.size()>=65536) #endif cimg_forYZC(resx,y,z,c) { - const T *ptrs = data(0,y,z,c), *const ptrsmax = ptrs + (_width-1); + const T *ptrs = data(0,y,z,c), *const ptrsmax = ptrs + _width - 1; T *ptrd = resx.data(0,y,z,c); const unsigned int *poff = off._data; const float *pfoff = foff._data; cimg_forX(resx,x) { const float alpha = *(pfoff++); - const T val1 = *ptrs, val2 = ptrssy) resx.get_resize(sx,sy,_depth,_spectrum,2).move_to(resy); else { - const float fy = (!boundary_conditions && sy>_height)?(sy>1?(_height-1.0f)/(sy-1):0):(float)_height/sy; + const float fy = (!boundary_conditions && sy>_height)?(sy>1?(_height - 1.0f)/(sy - 1):0): + (float)_height/sy; resy.assign(sx,sy,_depth,_spectrum); float curr = 0, old = 0; unsigned int *poff = off._data; @@ -21342,14 +21185,14 @@ namespace cimg_library_suffixed { #pragma omp parallel for collapse(3) if (resy.size()>=65536) #endif cimg_forXZC(resy,x,z,c) { - const T *ptrs = resx.data(x,0,z,c), *const ptrsmax = ptrs + (_height-1)*sx; + const T *ptrs = resx.data(x,0,z,c), *const ptrsmax = ptrs + (_height - 1)*sx; T *ptrd = resy.data(x,0,z,c); const unsigned int *poff = off._data; const float *pfoff = foff._data; cimg_forY(resy,y) { const float alpha = *(pfoff++); - const T val1 = *ptrs, val2 = ptrssz) resy.get_resize(sx,sy,sz,_spectrum,2).move_to(resz); else { - const float fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth-1.0f)/(sz-1):0):(float)_depth/sz; + const float fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth - 1.0f)/(sz - 1):0):(float)_depth/sz; const unsigned int sxy = sx*sy; resz.assign(sx,sy,sz,_spectrum); float curr = 0, old = 0; @@ -21380,14 +21223,14 @@ namespace cimg_library_suffixed { #pragma omp parallel for collapse(3) if (resz.size()>=65536) #endif cimg_forXYC(resz,x,y,c) { - const T *ptrs = resy.data(x,y,0,c), *const ptrsmax = ptrs + (_depth-1)*sxy; + const T *ptrs = resy.data(x,y,0,c), *const ptrsmax = ptrs + (_depth - 1)*sxy; T *ptrd = resz.data(x,y,0,c); const unsigned int *poff = off._data; const float *pfoff = foff._data; cimg_forZ(resz,z) { const float alpha = *(pfoff++); - const T val1 = *ptrs, val2 = ptrssc) resz.get_resize(sx,sy,sz,sc,2).move_to(resc); else { - const float fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum-1.0f)/(sc-1):0): + const float fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum - 1.0f)/(sc - 1):0): (float)_spectrum/sc; const unsigned int sxyz = sx*sy*sz; resc.assign(sx,sy,sz,sc); @@ -21419,14 +21262,14 @@ namespace cimg_library_suffixed { #pragma omp parallel for collapse(3) if (resc.size()>=65536) #endif cimg_forXYZ(resc,x,y,z) { - const T *ptrs = resz.data(x,y,z,0), *const ptrsmax = ptrs + (_spectrum-1)*sxyz; + const T *ptrs = resz.data(x,y,z,0), *const ptrsmax = ptrs + (_spectrum - 1)*sxyz; T *ptrd = resc.data(x,y,z,0); const unsigned int *poff = off._data; const float *pfoff = foff._data; cimg_forC(resc,c) { const float alpha = *(pfoff++); - const T val1 = *ptrs, val2 = ptrssx) get_resize(sx,_height,_depth,_spectrum,2).move_to(resx); else { - const float fx = (!boundary_conditions && sx>_width)?(sx>1?(_width-1.0f)/(sx-1):0):(float)_width/sx; + const float fx = (!boundary_conditions && sx>_width)?(sx>1?(_width - 1.0f)/(sx - 1):0):(float)_width/sx; resx.assign(sx,_height,_depth,_spectrum); float curr = 0, old = 0; unsigned int *poff = off._data; @@ -21532,7 +21375,7 @@ namespace cimg_library_suffixed { #pragma omp parallel for collapse(3) if (resx.size()>=65536) #endif cimg_forYZC(resx,y,z,c) { - const T *const ptrs0 = data(0,y,z,c), *ptrs = ptrs0, *const ptrsmax = ptrs + (_width-2); + const T *const ptrs0 = data(0,y,z,c), *ptrs = ptrs0, *const ptrsmax = ptrs + (_width - 2); T *ptrd = resx.data(0,y,z,c); const unsigned int *poff = off._data; const float *pfoff = foff._data; @@ -21540,11 +21383,11 @@ namespace cimg_library_suffixed { const float t = *(pfoff++); const Tfloat val1 = (Tfloat)*ptrs, - val0 = ptrs>ptrs0?(Tfloat)*(ptrs-1):val1, - val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs+1):val1, - val3 = ptrsptrs0?(Tfloat)*(ptrs - 1):val1, + val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs + 1):val1, + val3 = ptrsvmax?vmax:val); ptrs+=*(poff++); } @@ -21558,7 +21401,8 @@ namespace cimg_library_suffixed { else { if (_height>sy) resx.get_resize(sx,sy,_depth,_spectrum,2).move_to(resy); else { - const float fy = (!boundary_conditions && sy>_height)?(sy>1?(_height-1.0f)/(sy-1):0):(float)_height/sy; + const float fy = (!boundary_conditions && sy>_height)?(sy>1?(_height - 1.0f)/(sy - 1):0): + (float)_height/sy; resy.assign(sx,sy,_depth,_spectrum); float curr = 0, old = 0; unsigned int *poff = off._data; @@ -21567,13 +21411,13 @@ namespace cimg_library_suffixed { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fy; - *(poff++) = sx*((unsigned int)curr-(unsigned int)old); + *(poff++) = sx*((unsigned int)curr - (unsigned int)old); } #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (resy.size()>=65536) #endif cimg_forXZC(resy,x,z,c) { - const T *const ptrs0 = resx.data(x,0,z,c), *ptrs = ptrs0, *const ptrsmax = ptrs + (_height-2)*sx; + const T *const ptrs0 = resx.data(x,0,z,c), *ptrs = ptrs0, *const ptrsmax = ptrs + (_height - 2)*sx; T *ptrd = resy.data(x,0,z,c); const unsigned int *poff = off._data; const float *pfoff = foff._data; @@ -21581,11 +21425,11 @@ namespace cimg_library_suffixed { const float t = *(pfoff++); const Tfloat val1 = (Tfloat)*ptrs, - val0 = ptrs>ptrs0?(Tfloat)*(ptrs-sx):val1, - val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs+sx):val1, - val3 = ptrsptrs0?(Tfloat)*(ptrs - sx):val1, + val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sx):val1, + val3 = ptrsvmax?vmax:val); ptrd+=sx; ptrs+=*(poff++); @@ -21601,7 +21445,7 @@ namespace cimg_library_suffixed { else { if (_depth>sz) resy.get_resize(sx,sy,sz,_spectrum,2).move_to(resz); else { - const float fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth-1.0f)/(sz-1):0):(float)_depth/sz; + const float fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth - 1.0f)/(sz - 1):0):(float)_depth/sz; const unsigned int sxy = sx*sy; resz.assign(sx,sy,sz,_spectrum); float curr = 0, old = 0; @@ -21617,7 +21461,7 @@ namespace cimg_library_suffixed { #pragma omp parallel for collapse(3) if (resz.size()>=65536) #endif cimg_forXYC(resz,x,y,c) { - const T *const ptrs0 = resy.data(x,y,0,c), *ptrs = ptrs0, *const ptrsmax = ptrs + (_depth-2)*sxy; + const T *const ptrs0 = resy.data(x,y,0,c), *ptrs = ptrs0, *const ptrsmax = ptrs + (_depth - 2)*sxy; T *ptrd = resz.data(x,y,0,c); const unsigned int *poff = off._data; const float *pfoff = foff._data; @@ -21625,11 +21469,11 @@ namespace cimg_library_suffixed { const float t = *(pfoff++); const Tfloat val1 = (Tfloat)*ptrs, - val0 = ptrs>ptrs0?(Tfloat)*(ptrs-sxy):val1, - val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs+sxy):val1, - val3 = ptrsptrs0?(Tfloat)*(ptrs - sxy):val1, + val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sxy):val1, + val3 = ptrsvmax?vmax:val); ptrd+=sxy; ptrs+=*(poff++); @@ -21645,7 +21489,7 @@ namespace cimg_library_suffixed { else { if (_spectrum>sc) resz.get_resize(sx,sy,sz,sc,2).move_to(resc); else { - const float fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum-1.0f)/(sc-1):0): + const float fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum - 1.0f)/(sc - 1):0): (float)_spectrum/sc; const unsigned int sxyz = sx*sy*sz; resc.assign(sx,sy,sz,sc); @@ -21662,7 +21506,7 @@ namespace cimg_library_suffixed { #pragma omp parallel for collapse(3) if (resc.size()>=65536) #endif cimg_forXYZ(resc,x,y,z) { - const T *const ptrs0 = resz.data(x,y,z,0), *ptrs = ptrs0, *const ptrsmax = ptrs + (_spectrum-2)*sxyz; + const T *const ptrs0 = resz.data(x,y,z,0), *ptrs = ptrs0, *const ptrsmax = ptrs + (_spectrum - 2)*sxyz; T *ptrd = resc.data(x,y,z,0); const unsigned int *poff = off._data; const float *pfoff = foff._data; @@ -21670,11 +21514,11 @@ namespace cimg_library_suffixed { const float t = *(pfoff++); const Tfloat val1 = (Tfloat)*ptrs, - val0 = ptrs>ptrs0?(Tfloat)*(ptrs-sxyz):val1, - val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs+sxyz):val1, - val3 = ptrsptrs0?(Tfloat)*(ptrs - sxyz):val1, + val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sxyz):val1, + val3 = ptrsvmax?vmax:val); ptrd+=sxyz; ptrs+=*(poff++); @@ -21701,7 +21545,7 @@ namespace cimg_library_suffixed { else { if (_width>sx) get_resize(sx,_height,_depth,_spectrum,2).move_to(resx); else { - const float fx = (!boundary_conditions && sx>_width)?(sx>1?(_width-1.0f)/(sx-1):0):(float)_width/sx; + const float fx = (!boundary_conditions && sx>_width)?(sx>1?(_width - 1.0f)/(sx - 1):0):(float)_width/sx; resx.assign(sx,_height,_depth,_spectrum); float curr = 0, old = 0; unsigned int *poff = off._data; @@ -21717,24 +21561,24 @@ namespace cimg_library_suffixed { #endif cimg_forYZC(resx,y,z,c) { const T *const ptrs0 = data(0,y,z,c), *ptrs = ptrs0, *const ptrsmin = ptrs0 + 1, - *const ptrsmax = ptrs0 + (_width-2); + *const ptrsmax = ptrs0 + (_width - 2); T *ptrd = resx.data(0,y,z,c); const unsigned int *poff = off._data; const float *pfoff = foff._data; cimg_forX(resx,x) { const float t = *(pfoff++), - w0 = _cimg_lanczos(t+2), - w1 = _cimg_lanczos(t+1), + w0 = _cimg_lanczos(t + 2), + w1 = _cimg_lanczos(t + 1), w2 = _cimg_lanczos(t), - w3 = _cimg_lanczos(t-1), - w4 = _cimg_lanczos(t-2); + w3 = _cimg_lanczos(t - 1), + w4 = _cimg_lanczos(t - 2); const Tfloat val2 = (Tfloat)*ptrs, - val1 = ptrs>=ptrsmin?(Tfloat)*(ptrs-1):val2, - val0 = ptrs>ptrsmin?(Tfloat)*(ptrs-2):val1, - val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs+1):val2, - val4 = ptrs=ptrsmin?(Tfloat)*(ptrs - 1):val2, + val0 = ptrs>ptrsmin?(Tfloat)*(ptrs - 2):val1, + val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs + 1):val2, + val4 = ptrsvmax?vmax:val); ptrs+=*(poff++); @@ -21749,7 +21593,8 @@ namespace cimg_library_suffixed { else { if (_height>sy) resx.get_resize(sx,sy,_depth,_spectrum,2).move_to(resy); else { - const float fy = (!boundary_conditions && sy>_height)?(sy>1?(_height-1.0f)/(sy-1):0):(float)_height/sy; + const float fy = (!boundary_conditions && sy>_height)?(sy>1?(_height - 1.0f)/(sy - 1):0): + (float)_height/sy; resy.assign(sx,sy,_depth,_spectrum); float curr = 0, old = 0; unsigned int *poff = off._data; @@ -21758,31 +21603,31 @@ namespace cimg_library_suffixed { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fy; - *(poff++) = sx*((unsigned int)curr-(unsigned int)old); + *(poff++) = sx*((unsigned int)curr - (unsigned int)old); } #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (resy.size()>=65536) #endif cimg_forXZC(resy,x,z,c) { const T *const ptrs0 = resx.data(x,0,z,c), *ptrs = ptrs0, *const ptrsmin = ptrs0 + sx, - *const ptrsmax = ptrs0 + (_height-2)*sx; + *const ptrsmax = ptrs0 + (_height - 2)*sx; T *ptrd = resy.data(x,0,z,c); const unsigned int *poff = off._data; const float *pfoff = foff._data; cimg_forY(resy,y) { const float t = *(pfoff++), - w0 = _cimg_lanczos(t+2), - w1 = _cimg_lanczos(t+1), + w0 = _cimg_lanczos(t + 2), + w1 = _cimg_lanczos(t + 1), w2 = _cimg_lanczos(t), - w3 = _cimg_lanczos(t-1), - w4 = _cimg_lanczos(t-2); + w3 = _cimg_lanczos(t - 1), + w4 = _cimg_lanczos(t - 2); const Tfloat val2 = (Tfloat)*ptrs, - val1 = ptrs>=ptrsmin?(Tfloat)*(ptrs-sx):val2, - val0 = ptrs>ptrsmin?(Tfloat)*(ptrs-2*sx):val1, - val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs+sx):val2, - val4 = ptrs=ptrsmin?(Tfloat)*(ptrs - sx):val2, + val0 = ptrs>ptrsmin?(Tfloat)*(ptrs - 2*sx):val1, + val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sx):val2, + val4 = ptrsvmax?vmax:val); ptrd+=sx; @@ -21799,7 +21644,7 @@ namespace cimg_library_suffixed { else { if (_depth>sz) resy.get_resize(sx,sy,sz,_spectrum,2).move_to(resz); else { - const float fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth-1.0f)/(sz-1):0):(float)_depth/sz; + const float fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth - 1.0f)/(sz - 1):0):(float)_depth/sz; const unsigned int sxy = sx*sy; resz.assign(sx,sy,sz,_spectrum); float curr = 0, old = 0; @@ -21816,24 +21661,24 @@ namespace cimg_library_suffixed { #endif cimg_forXYC(resz,x,y,c) { const T *const ptrs0 = resy.data(x,y,0,c), *ptrs = ptrs0, *const ptrsmin = ptrs0 + sxy, - *const ptrsmax = ptrs0 + (_depth-2)*sxy; + *const ptrsmax = ptrs0 + (_depth - 2)*sxy; T *ptrd = resz.data(x,y,0,c); const unsigned int *poff = off._data; const float *pfoff = foff._data; cimg_forZ(resz,z) { const float t = *(pfoff++), - w0 = _cimg_lanczos(t+2), - w1 = _cimg_lanczos(t+1), + w0 = _cimg_lanczos(t + 2), + w1 = _cimg_lanczos(t + 1), w2 = _cimg_lanczos(t), - w3 = _cimg_lanczos(t-1), - w4 = _cimg_lanczos(t-2); + w3 = _cimg_lanczos(t - 1), + w4 = _cimg_lanczos(t - 2); const Tfloat val2 = (Tfloat)*ptrs, - val1 = ptrs>=ptrsmin?(Tfloat)*(ptrs-sxy):val2, - val0 = ptrs>ptrsmin?(Tfloat)*(ptrs-2*sxy):val1, - val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs+sxy):val2, - val4 = ptrs=ptrsmin?(Tfloat)*(ptrs - sxy):val2, + val0 = ptrs>ptrsmin?(Tfloat)*(ptrs - 2*sxy):val1, + val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sxy):val2, + val4 = ptrsvmax?vmax:val); ptrd+=sxy; @@ -21850,7 +21695,7 @@ namespace cimg_library_suffixed { else { if (_spectrum>sc) resz.get_resize(sx,sy,sz,sc,2).move_to(resc); else { - const float fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum-1.0f)/(sc-1):0): + const float fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum - 1.0f)/(sc - 1):0): (float)_spectrum/sc; const unsigned int sxyz = sx*sy*sz; resc.assign(sx,sy,sz,sc); @@ -21868,24 +21713,24 @@ namespace cimg_library_suffixed { #endif cimg_forXYZ(resc,x,y,z) { const T *const ptrs0 = resz.data(x,y,z,0), *ptrs = ptrs0, *const ptrsmin = ptrs0 + sxyz, - *const ptrsmax = ptrs + (_spectrum-2)*sxyz; + *const ptrsmax = ptrs + (_spectrum - 2)*sxyz; T *ptrd = resc.data(x,y,z,0); const unsigned int *poff = off._data; const float *pfoff = foff._data; cimg_forC(resc,c) { const float t = *(pfoff++), - w0 = _cimg_lanczos(t+2), - w1 = _cimg_lanczos(t+1), + w0 = _cimg_lanczos(t + 2), + w1 = _cimg_lanczos(t + 1), w2 = _cimg_lanczos(t), - w3 = _cimg_lanczos(t-1), - w4 = _cimg_lanczos(t-2); + w3 = _cimg_lanczos(t - 1), + w4 = _cimg_lanczos(t - 2); const Tfloat val2 = (Tfloat)*ptrs, - val1 = ptrs>=ptrsmin?(Tfloat)*(ptrs-sxyz):val2, - val0 = ptrs>ptrsmin?(Tfloat)*(ptrs-2*sxyz):val1, - val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs+sxyz):val2, - val4 = ptrs=ptrsmin?(Tfloat)*(ptrs - sxyz):val2, + val0 = ptrs>ptrsmin?(Tfloat)*(ptrs - 2*sxyz):val1, + val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sxyz):val2, + val4 = ptrsvmax?vmax:val); ptrd+=sxyz; @@ -22004,7 +21849,7 @@ namespace cimg_library_suffixed { CImg get_resize_doubleXY() const { #define _cimg_gs2x_for3(bound,i) \ for (int i = 0, _p1##i = 0, \ - _n1##i = 1>=(bound)?(int)(bound)-1:1; \ + _n1##i = 1>=(bound)?(int)(bound) - 1:1; \ _n1##i<(int)(bound) || i==--_n1##i; \ _p1##i = i++, ++_n1##i, ptrd1+=(res)._width, ptrd2+=(res)._width) @@ -22014,8 +21859,8 @@ namespace cimg_library_suffixed { _n1##x = (int)( \ (I[1] = (T)(img)(_p1##x,_p1##y,z,c)), \ (I[3] = I[4] = (T)(img)(0,y,z,c)), \ - (I[7] = (T)(img)(0,_n1##y,z,c)), \ - 1>=(img)._width?(img).width()-1:1); \ + (I[7] = (T)(img)(0,_n1##y,z,c)), \ + 1>=(img)._width?(img).width() - 1:1); \ (_n1##x<(img).width() && ( \ (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \ (I[5] = (T)(img)(_n1##x,y,z,c)), \ @@ -22058,7 +21903,7 @@ namespace cimg_library_suffixed { CImg get_resize_tripleXY() const { #define _cimg_gs3x_for3(bound,i) \ for (int i = 0, _p1##i = 0, \ - _n1##i = 1>=(bound)?(int)(bound)-1:1; \ + _n1##i = 1>=(bound)?(int)(bound) - 1:1; \ _n1##i<(int)(bound) || i==--_n1##i; \ _p1##i = i++, ++_n1##i, ptrd1+=2*(res)._width, ptrd2+=2*(res)._width, ptrd3+=2*(res)._width) @@ -22068,8 +21913,8 @@ namespace cimg_library_suffixed { _n1##x = (int)( \ (I[0] = I[1] = (T)(img)(_p1##x,_p1##y,z,c)), \ (I[3] = I[4] = (T)(img)(0,y,z,c)), \ - (I[6] = I[7] = (T)(img)(0,_n1##y,z,c)), \ - 1>=(img)._width?(img).width()-1:1); \ + (I[6] = I[7] = (T)(img)(0,_n1##y,z,c)), \ + 1>=(img)._width?(img).width() - 1:1); \ (_n1##x<(img).width() && ( \ (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \ (I[5] = (T)(img)(_n1##x,y,z,c)), \ @@ -22118,7 +21963,7 @@ namespace cimg_library_suffixed { T *pf, *pb, *buf = 0; switch (cimg::uncase(axis)) { case 'x' : { - pf = _data; pb = data(_width-1); + pf = _data; pb = data(_width - 1); const unsigned int width2 = _width/2; for (unsigned int yzv = 0; yzv<_height*_depth*_spectrum; ++yzv) { for (unsigned int x = 0; x& mirror(const char *const axes) { - for (const char *s = axes; *s; s++) mirror(*s); + for (const char *s = axes; *s; ++s) mirror(*s); return *this; } @@ -22221,8 +22066,8 @@ namespace cimg_library_suffixed { case 0 : if (cimg::abs(delta_x)>=width()) return fill(0); if (delta_x<0) cimg_forYZC(*this,y,z,c) { - std::memmove(data(0,y,z,c),data(-delta_x,y,z,c),(_width+delta_x)*sizeof(T)); - std::memset(data(_width+delta_x,y,z,c),0,-delta_x*sizeof(T)); + std::memmove(data(0,y,z,c),data(-delta_x,y,z,c),(_width + delta_x)*sizeof(T)); + std::memset(data(_width + delta_x,y,z,c),0,-delta_x*sizeof(T)); } else cimg_forYZC(*this,y,z,c) { std::memmove(data(delta_x,y,z,c),data(0,y,z,c),(_width-delta_x)*sizeof(T)); std::memset(data(0,y,z,c),0,delta_x*sizeof(T)); @@ -22230,36 +22075,36 @@ namespace cimg_library_suffixed { break; case 1 : if (delta_x<0) { - const int ndelta_x = (-delta_x>=width())?width()-1:-delta_x; + const int ndelta_x = (-delta_x>=width())?width() - 1:-delta_x; if (!ndelta_x) return *this; cimg_forYZC(*this,y,z,c) { std::memmove(data(0,y,z,c),data(ndelta_x,y,z,c),(_width-ndelta_x)*sizeof(T)); - T *ptrd = data(_width-1,y,z,c); + T *ptrd = data(_width - 1,y,z,c); const T val = *ptrd; - for (int l = 0; l=width())?width()-1:delta_x; + const int ndelta_x = (delta_x>=width())?width() - 1:delta_x; if (!ndelta_x) return *this; cimg_forYZC(*this,y,z,c) { std::memmove(data(ndelta_x,y,z,c),data(0,y,z,c),(_width-ndelta_x)*sizeof(T)); T *ptrd = data(0,y,z,c); const T val = *ptrd; - for (int l = 0; l0) cimg_forYZC(*this,y,z,c) { std::memcpy(buf,data(0,y,z,c),ndelta_x*sizeof(T)); std::memmove(data(0,y,z,c),data(ndelta_x,y,z,c),(_width-ndelta_x)*sizeof(T)); std::memcpy(data(_width-ndelta_x,y,z,c),buf,ndelta_x*sizeof(T)); } else cimg_forYZC(*this,y,z,c) { - std::memcpy(buf,data(_width+ndelta_x,y,z,c),-ndelta_x*sizeof(T)); - std::memmove(data(-ndelta_x,y,z,c),data(0,y,z,c),(_width+ndelta_x)*sizeof(T)); + std::memcpy(buf,data(_width + ndelta_x,y,z,c),-ndelta_x*sizeof(T)); + std::memmove(data(-ndelta_x,y,z,c),data(0,y,z,c),(_width + ndelta_x)*sizeof(T)); std::memcpy(data(0,y,z,c),buf,-ndelta_x*sizeof(T)); } delete[] buf; @@ -22271,8 +22116,8 @@ namespace cimg_library_suffixed { case 0 : if (cimg::abs(delta_y)>=height()) return fill(0); if (delta_y<0) cimg_forZC(*this,z,c) { - std::memmove(data(0,0,z,c),data(0,-delta_y,z,c),_width*(_height+delta_y)*sizeof(T)); - std::memset(data(0,_height+delta_y,z,c),0,-delta_y*_width*sizeof(T)); + std::memmove(data(0,0,z,c),data(0,-delta_y,z,c),_width*(_height + delta_y)*sizeof(T)); + std::memset(data(0,_height + delta_y,z,c),0,-delta_y*_width*sizeof(T)); } else cimg_forZC(*this,z,c) { std::memmove(data(0,delta_y,z,c),data(0,0,z,c),_width*(_height-delta_y)*sizeof(T)); std::memset(data(0,0,z,c),0,delta_y*_width*sizeof(T)); @@ -22280,20 +22125,20 @@ namespace cimg_library_suffixed { break; case 1 : if (delta_y<0) { - const int ndelta_y = (-delta_y>=height())?height()-1:-delta_y; + const int ndelta_y = (-delta_y>=height())?height() - 1:-delta_y; if (!ndelta_y) return *this; cimg_forZC(*this,z,c) { std::memmove(data(0,0,z,c),data(0,ndelta_y,z,c),_width*(_height-ndelta_y)*sizeof(T)); - T *ptrd = data(0,_height-ndelta_y,z,c), *ptrs = data(0,_height-1,z,c); - for (int l = 0; l=height())?height()-1:delta_y; + const int ndelta_y = (delta_y>=height())?height() - 1:delta_y; if (!ndelta_y) return *this; cimg_forZC(*this,z,c) { std::memmove(data(0,ndelta_y,z,c),data(0,0,z,c),_width*(_height-ndelta_y)*sizeof(T)); T *ptrd = data(0,1,z,c), *ptrs = data(0,0,z,c); - for (int l = 0; l=depth()) return fill(0); if (delta_z<0) cimg_forC(*this,c) { - std::memmove(data(0,0,0,c),data(0,0,-delta_z,c),_width*_height*(_depth+delta_z)*sizeof(T)); - std::memset(data(0,0,_depth+delta_z,c),0,_width*_height*(-delta_z)*sizeof(T)); + std::memmove(data(0,0,0,c),data(0,0,-delta_z,c),_width*_height*(_depth + delta_z)*sizeof(T)); + std::memset(data(0,0,_depth + delta_z,c),0,_width*_height*(-delta_z)*sizeof(T)); } else cimg_forC(*this,c) { std::memmove(data(0,0,delta_z,c),data(0,0,0,c),_width*_height*(_depth-delta_z)*sizeof(T)); std::memset(data(0,0,0,c),0,delta_z*_width*_height*sizeof(T)); @@ -22328,22 +22173,22 @@ namespace cimg_library_suffixed { break; case 1 : if (delta_z<0) { - const int ndelta_z = (-delta_z>=depth())?depth()-1:-delta_z; + const int ndelta_z = (-delta_z>=depth())?depth() - 1:-delta_z; if (!ndelta_z) return *this; cimg_forC(*this,c) { std::memmove(data(0,0,0,c),data(0,0,ndelta_z,c),_width*_height*(_depth-ndelta_z)*sizeof(T)); - T *ptrd = data(0,0,_depth-ndelta_z,c), *ptrs = data(0,0,_depth-1,c); - for (int l = 0; l=depth())?depth()-1:delta_z; + const int ndelta_z = (delta_z>=depth())?depth() - 1:delta_z; if (!ndelta_z) return *this; cimg_forC(*this,c) { std::memmove(data(0,0,ndelta_z,c),data(0,0,0,c),_width*_height*(_depth-ndelta_z)*sizeof(T)); T *ptrd = data(0,0,1,c), *ptrs = data(0,0,0,c); - for (int l = 0; l=spectrum()) return fill(0); if (delta_c<0) { - std::memmove(_data,data(0,0,0,-delta_c),_width*_height*_depth*(_spectrum+delta_c)*sizeof(T)); - std::memset(data(0,0,0,_spectrum+delta_c),0,_width*_height*_depth*(-delta_c)*sizeof(T)); + std::memmove(_data,data(0,0,0,-delta_c),_width*_height*_depth*(_spectrum + delta_c)*sizeof(T)); + std::memset(data(0,0,0,_spectrum + delta_c),0,_width*_height*_depth*(-delta_c)*sizeof(T)); } else { std::memmove(data(0,0,0,delta_c),_data,_width*_height*_depth*(_spectrum-delta_c)*sizeof(T)); std::memset(_data,0,delta_c*_width*_height*_depth*sizeof(T)); @@ -22380,19 +22225,19 @@ namespace cimg_library_suffixed { break; case 1 : if (delta_c<0) { - const int ndelta_c = (-delta_c>=spectrum())?spectrum()-1:-delta_c; + const int ndelta_c = (-delta_c>=spectrum())?spectrum() - 1:-delta_c; if (!ndelta_c) return *this; std::memmove(_data,data(0,0,0,ndelta_c),_width*_height*_depth*(_spectrum-ndelta_c)*sizeof(T)); - T *ptrd = data(0,0,0,_spectrum-ndelta_c), *ptrs = data(0,0,0,_spectrum-1); - for (int l = 0; l=spectrum())?spectrum()-1:delta_c; + const int ndelta_c = (delta_c>=spectrum())?spectrum() - 1:delta_c; if (!ndelta_c) return *this; std::memmove(data(0,0,0,ndelta_c),_data,_width*_height*_depth*(_spectrum-ndelta_c)*sizeof(T)); T *ptrd = data(0,0,0,1); - for (int l = 0; l& unroll(const char axis) { const unsigned int siz = size(); - if (siz) switch (axis) { + if (siz) switch (cimg::uncase(axis)) { case 'x' : _width = siz; _height = _depth = _spectrum = 1; break; case 'y' : _height = siz; _width = _depth = _spectrum = 1; break; case 'z' : _depth = siz; _width = _height = _spectrum = 1; break; @@ -22694,8 +22539,8 @@ namespace cimg_library_suffixed { ux = cimg::abs(_width*ca), uy = cimg::abs(_width*sa), vx = cimg::abs(_height*sa), vy = cimg::abs(_height*ca), w2 = 0.5f*_width, h2 = 0.5f*_height, - dw2 = 0.5f*(ux+vx), dh2 = 0.5f*(uy+vy); - res.assign((int)(ux+vx),(int)(uy+vy),_depth,_spectrum); + dw2 = 0.5f*(ux + vx), dh2 = 0.5f*(uy + vy); + res.assign((int)(ux + vx),(int)(uy + vy),_depth,_spectrum); switch (boundary) { case 0 : { // Dirichlet boundaries. switch (interpolation) { @@ -22781,11 +22626,11 @@ namespace cimg_library_suffixed { } } } break; - default : - throw CImgArgumentException(_cimg_instance + default : + throw CImgArgumentException(_cimg_instance "rotate(): Invalid specified border conditions %d " "(should be { 0=dirichlet | 1=neumann | 2=periodic }).", - cimg_instance, + cimg_instance, boundary); } } @@ -22920,22 +22765,23 @@ namespace cimg_library_suffixed { //! Warp image content by a warping field. /** \param warp Warping field. + \param mode Can be { 0=backward-absolute | 1=backward-relative | 2=forward-absolute | 3=foward-relative } \param is_relative Tells if warping field gives absolute or relative warping coordinates. \param interpolation Can be { 0=nearest | 1=linear | 2=cubic }. \param boundary_conditions Boundary conditions. Can be { 0=dirichlet | 1=neumann | 2=periodic }. **/ template - CImg& warp(const CImg& warp, const bool is_relative=false, + CImg& warp(const CImg& warp, const unsigned int mode=0, const unsigned int interpolation=1, const unsigned int boundary_conditions=0) { - return get_warp(warp,is_relative,interpolation,boundary_conditions).move_to(*this); + return get_warp(warp,mode,interpolation,boundary_conditions).move_to(*this); } //! Warp image content by a warping field \newinstance template - CImg get_warp(const CImg& warp, const bool is_relative=false, + CImg get_warp(const CImg& warp, const unsigned int mode=0, const unsigned int interpolation=1, const unsigned int boundary_conditions=0) const { if (is_empty() || !warp) return *this; - if (is_relative && !is_sameXYZ(warp)) + if (mode && !is_sameXYZ(warp)) throw CImgArgumentException(_cimg_instance "warp(): Instance and specified relative warping field (%u,%u,%u,%u,%p) " "have different XYZ dimensions.", @@ -22945,7 +22791,43 @@ namespace cimg_library_suffixed { CImg res(warp._width,warp._height,warp._depth,_spectrum); if (warp._spectrum==1) { // 1d warping. - if (is_relative) { // Relative warp. + if (mode>=3) { // Forward-relative warp. + res.fill(0); + if (interpolation>=1) // Linear interpolation. +#ifdef cimg_use_openmp +#pragma omp parallel for collapse(3) if (res.size()>=4096) +#endif + cimg_forYZC(res,y,z,c) { + const t *ptrs0 = warp.data(0,y,z); const T *ptrs = data(0,y,z,c); + cimg_forX(res,x) res.set_linear_atX(*(ptrs++),x + (float)*(ptrs0++),y,z,c); + } + else // Nearest-neighbor interpolation. + cimg_forYZC(res,y,z,c) { + const t *ptrs0 = warp.data(0,y,z); const T *ptrs = data(0,y,z,c); + cimg_forX(res,x) { + const int X = x + (int)*(ptrs0++); + if (X>=0 && X=1) // Linear interpolation. +#ifdef cimg_use_openmp +#pragma omp parallel for collapse(3) if (res.size()>=4096) +#endif + cimg_forYZC(res,y,z,c) { + const t *ptrs0 = warp.data(0,y,z); const T *ptrs = data(0,y,z,c); + cimg_forX(res,x) res.set_linear_atX(*(ptrs++),(float)*(ptrs0++),y,z,c); + } + else // Nearest-neighbor interpolation. + cimg_forYZC(res,y,z,c) { + const t *ptrs0 = warp.data(0,y,z); const T *ptrs = data(0,y,z,c); + cimg_forX(res,x) { + const int X = (int)*(ptrs0++); + if (X>=0 && X=3) { // Forward-relative warp. + res.fill(0); + if (interpolation>=1) // Linear interpolation. +#ifdef cimg_use_openmp +#pragma omp parallel for collapse(3) if (res.size()>=4096) +#endif + cimg_forYZC(res,y,z,c) { + const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); const T *ptrs = data(0,y,z,c); + cimg_forX(res,x) res.set_linear_atXY(*(ptrs++),x + (float)*(ptrs0++),y + (float)*(ptrs1++),z,c); + } + else // Nearest-neighbor interpolation. + cimg_forYZC(res,y,z,c) { + const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); const T *ptrs = data(0,y,z,c); + cimg_forX(res,x) { + const int X = x + (int)*(ptrs0++), Y = y + (int)*(ptrs1++); + if (X>=0 && X=0 && Y=1) // Linear interpolation. +#ifdef cimg_use_openmp +#pragma omp parallel for collapse(3) if (res.size()>=4096) +#endif + cimg_forYZC(res,y,z,c) { + const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); const T *ptrs = data(0,y,z,c); + cimg_forX(res,x) res.set_linear_atXY(*(ptrs++),(float)*(ptrs0++),(float)*(ptrs1++),z,c); + } + else // Nearest-neighbor interpolation. + cimg_forYZC(res,y,z,c) { + const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1); const T *ptrs = data(0,y,z,c); + cimg_forX(res,x) { + const int X = (int)*(ptrs0++), Y = (int)*(ptrs1++); + if (X>=0 && X=0 && Y=3) { // Forward-relative warp. + res.fill(0); + if (interpolation>=1) // Linear interpolation. +#ifdef cimg_use_openmp +#pragma omp parallel for collapse(3) if (res.size()>=4096) +#endif + cimg_forYZC(res,y,z,c) { + const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); + const T *ptrs = data(0,y,z,c); + cimg_forX(res,x) res.set_linear_atXYZ(*(ptrs++),x + (float)*(ptrs0++),y + (float)*(ptrs1++), + z + (float)*(ptrs2++),c); + } + else // Nearest-neighbor interpolation. + cimg_forYZC(res,y,z,c) { + const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); + const T *ptrs = data(0,y,z,c); + cimg_forX(res,x) { + const int X = x + (int)*(ptrs0++), Y = y + (int)*(ptrs1++), Z = z + (int)*(ptrs2++); + if (X>=0 && X=0 && Y=0 && Z=1) // Linear interpolation. +#ifdef cimg_use_openmp +#pragma omp parallel for collapse(3) if (res.size()>=4096) +#endif + cimg_forYZC(res,y,z,c) { + const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); + const T *ptrs = data(0,y,z,c); + cimg_forX(res,x) res.set_linear_atXYZ(*(ptrs++),(float)*(ptrs0++),(float)*(ptrs1++),(float)*(ptrs2++),c); + } + else // Nearest-neighbor interpolation. + cimg_forYZC(res,y,z,c) { + const t *ptrs0 = warp.data(0,y,z,0), *ptrs1 = warp.data(0,y,z,1), *ptrs2 = warp.data(0,y,z,2); + const T *ptrs = data(0,y,z,c); + cimg_forX(res,x) { + const int X = (int)*(ptrs0++), Y = (int)*(ptrs1++), Z = (int)*(ptrs2++); + if (X>=0 && X=0 && Y=0 && Z=_height)?_height - 1:y0, _z0 = (z0>=_depth)?_depth - 1:z0; const CImg - img_xy = get_crop(0,0,_z0,0,_width-1,_height-1,_z0,_spectrum-1), - img_zy = get_crop(_x0,0,0,0,_x0,_height-1,_depth-1,_spectrum-1).permute_axes("xzyc"). + img_xy = get_crop(0,0,_z0,0,_width - 1,_height - 1,_z0,_spectrum - 1), + img_zy = get_crop(_x0,0,0,0,_x0,_height - 1,_depth - 1,_spectrum - 1).permute_axes("xzyc"). resize(_depth,_height,1,-100,-1), - img_xz = get_crop(0,_y0,0,0,_width-1,_y0,_depth-1,_spectrum-1).resize(_width,_depth,1,-100,-1); + img_xz = get_crop(0,_y0,0,0,_width - 1,_y0,_depth - 1,_spectrum - 1).resize(_width,_depth,1,-100,-1); return CImg(_width + _depth,_height + _depth,1,_spectrum,cimg::min(img_xy.min(),img_zy.min(),img_xz.min())). draw_image(0,0,img_xy).draw_image(img_xy._width,0,img_zy). draw_image(0,img_xy._height,img_xz); @@ -23465,7 +23424,7 @@ namespace cimg_library_suffixed { nc0 = c0 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()) { - if (boundary_conditions) cimg_forXYZC(res,x,y,z,c) res(x,y,z,c) = _atXYZC(nx0+x,ny0+y,nz0+z,nc0+c); + if (boundary_conditions) cimg_forXYZC(res,x,y,z,c) res(x,y,z,c) = _atXYZC(nx0 + x,ny0 + y,nz0 + z,nc0 + c); else res.fill(0).draw_image(-nx0,-ny0,-nz0,-nc0,*this); } else res.draw_image(-nx0,-ny0,-nz0,-nc0,*this); return res; @@ -23475,14 +23434,14 @@ namespace cimg_library_suffixed { CImg& crop(const int x0, const int y0, const int z0, const int x1, const int y1, const int z1, const bool boundary_conditions=false) { - return crop(x0,y0,z0,0,x1,y1,z1,_spectrum-1,boundary_conditions); + return crop(x0,y0,z0,0,x1,y1,z1,_spectrum - 1,boundary_conditions); } //! Crop image region \newinstance. CImg get_crop(const int x0, const int y0, const int z0, const int x1, const int y1, const int z1, const bool boundary_conditions=false) const { - return get_crop(x0,y0,z0,0,x1,y1,z1,_spectrum-1,boundary_conditions); + return get_crop(x0,y0,z0,0,x1,y1,z1,_spectrum - 1,boundary_conditions); } //! Crop image region \overloading. @@ -23501,16 +23460,16 @@ namespace cimg_library_suffixed { //! Crop image region \overloading. CImg& crop(const int x0, const int x1, const bool boundary_conditions=false) { - return crop(x0,0,0,0,x1,_height-1,_depth-1,_spectrum-1,boundary_conditions); + return crop(x0,0,0,0,x1,_height - 1,_depth - 1,_spectrum - 1,boundary_conditions); } //! Crop image region \newinstance. CImg get_crop(const int x0, const int x1, const bool boundary_conditions=false) const { - return get_crop(x0,0,0,0,x1,_height-1,_depth-1,_spectrum-1,boundary_conditions); + return get_crop(x0,0,0,0,x1,_height - 1,_depth - 1,_spectrum - 1,boundary_conditions); } //! Autocrop image region, regarding the specified background value. - CImg& autocrop(const T value, const char *const axes="czyx") { + CImg& autocrop(const T& value, const char *const axes="czyx") { if (is_empty()) return *this; for (const char *s = axes; *s; ++s) { const char axis = cimg::uncase(*s); @@ -23518,28 +23477,28 @@ namespace cimg_library_suffixed { if (coords[0]==-1 && coords[1]==-1) return assign(); // Image has only 'value' pixels. else switch (axis) { case 'x' : { - const int x0 = coords[0], x1 = coords[1]; - if (x0>=0 && x1>=0) crop(x0,x1); - } break; + const int x0 = coords[0], x1 = coords[1]; + if (x0>=0 && x1>=0) crop(x0,x1); + } break; case 'y' : { - const int y0 = coords[0], y1 = coords[1]; - if (y0>=0 && y1>=0) crop(0,y0,_width-1,y1); - } break; + const int y0 = coords[0], y1 = coords[1]; + if (y0>=0 && y1>=0) crop(0,y0,_width - 1,y1); + } break; case 'z' : { - const int z0 = coords[0], z1 = coords[1]; - if (z0>=0 && z1>=0) crop(0,0,z0,_width-1,_height-1,z1); - } break; + const int z0 = coords[0], z1 = coords[1]; + if (z0>=0 && z1>=0) crop(0,0,z0,_width - 1,_height - 1,z1); + } break; default : { - const int c0 = coords[0], c1 = coords[1]; - if (c0>=0 && c1>=0) crop(0,0,0,c0,_width-1,_height-1,_depth-1,c1); - } + const int c0 = coords[0], c1 = coords[1]; + if (c0>=0 && c1>=0) crop(0,0,0,c0,_width - 1,_height - 1,_depth - 1,c1); + } } } return *this; } //! Autocrop image region, regarding the specified background value \newinstance. - CImg get_autocrop(const T value, const char *const axes="czyx") const { + CImg get_autocrop(const T& value, const char *const axes="czyx") const { return (+*this).autocrop(value,axes); } @@ -23555,7 +23514,7 @@ namespace cimg_library_suffixed { const unsigned int w = _width, h = _height, d = _depth, s = _spectrum; autocrop(col1,axes); if (_width==w && _height==h && _depth==d && _spectrum==s) { - const CImg col2 = get_vector_at(w-1,h-1,d-1); + const CImg col2 = get_vector_at(w - 1,h - 1,d - 1); autocrop(col2,axes); } return *this; @@ -23564,32 +23523,32 @@ namespace cimg_library_suffixed { const char axis = cimg::uncase(*s); switch (axis) { case 'x' : { - int x0 = width(), x1 = -1; - cimg_forC(*this,c) { - const CImg coords = get_shared_channel(c)._autocrop(color[c],'x'); - const int nx0 = coords[0], nx1 = coords[1]; - if (nx0>=0 && nx1>=0) { x0 = cimg::min(x0,nx0); x1 = cimg::max(x1,nx1); } - } + int x0 = width(), x1 = -1; + cimg_forC(*this,c) { + const CImg coords = get_shared_channel(c)._autocrop(color[c],'x'); + const int nx0 = coords[0], nx1 = coords[1]; + if (nx0>=0 && nx1>=0) { x0 = cimg::min(x0,nx0); x1 = cimg::max(x1,nx1); } + } if (x0==width() && x1==-1) return assign(); else crop(x0,x1); - } break; + } break; case 'y' : { - int y0 = height(), y1 = -1; - cimg_forC(*this,c) { - const CImg coords = get_shared_channel(c)._autocrop(color[c],'y'); - const int ny0 = coords[0], ny1 = coords[1]; - if (ny0>=0 && ny1>=0) { y0 = cimg::min(y0,ny0); y1 = cimg::max(y1,ny1); } - } - if (y0==height() && y1==-1) return assign(); else crop(0,y0,_width-1,y1); - } break; + int y0 = height(), y1 = -1; + cimg_forC(*this,c) { + const CImg coords = get_shared_channel(c)._autocrop(color[c],'y'); + const int ny0 = coords[0], ny1 = coords[1]; + if (ny0>=0 && ny1>=0) { y0 = cimg::min(y0,ny0); y1 = cimg::max(y1,ny1); } + } + if (y0==height() && y1==-1) return assign(); else crop(0,y0,_width - 1,y1); + } break; default : { - int z0 = depth(), z1 = -1; - cimg_forC(*this,c) { - const CImg coords = get_shared_channel(c)._autocrop(color[c],'z'); - const int nz0 = coords[0], nz1 = coords[1]; - if (nz0>=0 && nz1>=0) { z0 = cimg::min(z0,nz0); z1 = cimg::max(z1,nz1); } - } - if (z0==depth() && z1==-1) return assign(); else crop(0,0,z0,_width-1,_height-1,z1); - } + int z0 = depth(), z1 = -1; + cimg_forC(*this,c) { + const CImg coords = get_shared_channel(c)._autocrop(color[c],'z'); + const int nz0 = coords[0], nz1 = coords[1]; + if (nz0>=0 && nz1>=0) { z0 = cimg::min(z0,nz0); z1 = cimg::max(z1,nz1); } + } + if (z0==depth() && z1==-1) return assign(); else crop(0,0,z0,_width - 1,_height - 1,z1); + } } } return *this; @@ -23610,48 +23569,48 @@ namespace cimg_library_suffixed { return get_autocrop(color._data,axes); } - CImg _autocrop(const T value, const char axis) const { + CImg _autocrop(const T& value, const char axis) const { CImg res; switch (cimg::uncase(axis)) { case 'x' : { int x0 = -1, x1 = -1; cimg_forX(*this,x) cimg_forYZC(*this,y,z,c) if ((*this)(x,y,z,c)!=value) { x0 = x; x = width(); y = height(); z = depth(); c = spectrum(); } - if (x0>=0) { - for (int x = width()-1; x>=0; --x) cimg_forYZC(*this,y,z,c) + if (x0>=0) { + for (int x = width() - 1; x>=0; --x) cimg_forYZC(*this,y,z,c) if ((*this)(x,y,z,c)!=value) { x1 = x; x = 0; y = height(); z = depth(); c = spectrum(); } } - res = CImg::vector(x0,x1); + res = CImg::vector(x0,x1); } break; case 'y' : { int y0 = -1, y1 = -1; cimg_forY(*this,y) cimg_forXZC(*this,x,z,c) if ((*this)(x,y,z,c)!=value) { y0 = y; x = width(); y = height(); z = depth(); c = spectrum(); } - if (y0>=0) { - for (int y = height()-1; y>=0; --y) cimg_forXZC(*this,x,z,c) + if (y0>=0) { + for (int y = height() - 1; y>=0; --y) cimg_forXZC(*this,x,z,c) if ((*this)(x,y,z,c)!=value) { y1 = y; x = width(); y = 0; z = depth(); c = spectrum(); } } - res = CImg::vector(y0,y1); + res = CImg::vector(y0,y1); } break; case 'z' : { int z0 = -1, z1 = -1; cimg_forZ(*this,z) cimg_forXYC(*this,x,y,c) if ((*this)(x,y,z,c)!=value) { z0 = z; x = width(); y = height(); z = depth(); c = spectrum(); } - if (z0>=0) { - for (int z = depth()-1; z>=0; --z) cimg_forXYC(*this,x,y,c) + if (z0>=0) { + for (int z = depth() - 1; z>=0; --z) cimg_forXYC(*this,x,y,c) if ((*this)(x,y,z,c)!=value) { z1 = z; x = width(); y = height(); z = 0; c = spectrum(); } } - res = CImg::vector(z0,z1); + res = CImg::vector(z0,z1); } break; default : { int c0 = -1, c1 = -1; cimg_forC(*this,c) cimg_forXYZ(*this,x,y,z) if ((*this)(x,y,z,c)!=value) { c0 = c; x = width(); y = height(); z = depth(); c = spectrum(); } - if (c0>=0) { - for (int c = spectrum()-1; c>=0; --c) cimg_forXYZ(*this,x,y,z) + if (c0>=0) { + for (int c = spectrum() - 1; c>=0; --c) cimg_forXYZ(*this,x,y,z) if ((*this)(x,y,z,c)!=value) { c1 = c; x = width(); y = height(); z = depth(); c = 0; } } - res = CImg::vector(c0,c1); + res = CImg::vector(c0,c1); } } return res; @@ -23681,7 +23640,7 @@ namespace cimg_library_suffixed { //! Return specified range of image columns \inplace. CImg get_columns(const int x0, const int x1) const { - return get_crop(x0,0,0,0,x1,height()-1,depth()-1,spectrum()-1); + return get_crop(x0,0,0,0,x1,height() - 1,depth() - 1,spectrum() - 1); } //! Return specified image row. @@ -23703,7 +23662,7 @@ namespace cimg_library_suffixed { \param y1 Ending image row. **/ CImg get_rows(const int y0, const int y1) const { - return get_crop(0,y0,0,0,width()-1,y1,depth()-1,spectrum()-1); + return get_crop(0,y0,0,0,width() - 1,y1,depth() - 1,spectrum() - 1); } //! Return specified range of image rows \inplace. @@ -23730,7 +23689,7 @@ namespace cimg_library_suffixed { \param z1 Ending image slice. **/ CImg get_slices(const int z0, const int z1) const { - return get_crop(0,0,z0,0,width()-1,height()-1,z1,spectrum()-1); + return get_crop(0,0,z0,0,width() - 1,height() - 1,z1,spectrum() - 1); } //! Return specified range of image slices \inplace. @@ -23757,7 +23716,7 @@ namespace cimg_library_suffixed { \param c1 Ending image channel. **/ CImg get_channels(const int c0, const int c1) const { - return get_crop(0,0,0,c0,width()-1,height()-1,depth()-1,c1); + return get_crop(0,0,0,c0,width() - 1,height() - 1,depth() - 1,c1); } //! Return specified range of image channels \inplace. @@ -23778,21 +23737,21 @@ namespace cimg_library_suffixed { if (is_oriented_only) { typename CImg::_functor4d_streamline2d_oriented func(*this); return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,true, - 0,0,0,_width-1.0f,_height-1.0f,0.0f); + 0,0,0,_width - 1.0f,_height - 1.0f,0.0f); } else { typename CImg::_functor4d_streamline2d_directed func(*this); return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,false, - 0,0,0,_width-1.0f,_height-1.0f,0.0f); + 0,0,0,_width - 1.0f,_height - 1.0f,0.0f); } } if (is_oriented_only) { typename CImg::_functor4d_streamline3d_oriented func(*this); return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,true, - 0,0,0,_width-1.0f,_height-1.0f,_depth-1.0f); + 0,0,0,_width - 1.0f,_height - 1.0f,_depth - 1.0f); } typename CImg::_functor4d_streamline3d_directed func(*this); return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,false, - 0,0,0,_width-1.0f,_height-1.0f,_depth-1.0f); + 0,0,0,_width - 1.0f,_height - 1.0f,_depth - 1.0f); } //! Return stream line of a 3d vector field. @@ -23830,7 +23789,7 @@ namespace cimg_library_suffixed { const bool is_bounded = (x0!=x1 || y0!=y1 || z0!=z1); if (L<=0 || (is_bounded && (xx1 || yy1 || zz1))) return CImg(); - const unsigned int size_L = (unsigned int)cimg::round(L/dl+1); + const unsigned int size_L = (unsigned int)cimg::round(L/dl + 1); CImg coordinates(size_L,3); const float dl2 = dl/2; float @@ -23847,9 +23806,9 @@ namespace cimg_library_suffixed { cimg_forX(coordinates,l) { *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z; const int - xi = (int)(X>0?X+0.5f:X-0.5f), - yi = (int)(Y>0?Y+0.5f:Y-0.5f), - zi = (int)(Z>0?Z+0.5f:Z-0.5f); + xi = (int)(X>0?X + 0.5f:X - 0.5f), + yi = (int)(Y>0?Y + 0.5f:Y - 0.5f), + zi = (int)(Z>0?Z + 0.5f:Z - 0.5f); float u = (float)(dl*func((float)xi,(float)yi,(float)zi,0)), v = (float)(dl*func((float)xi,(float)yi,(float)zi,1)), @@ -23880,9 +23839,9 @@ namespace cimg_library_suffixed { w0 = (float)(dl2*func(X,Y,Z,2)); if (is_oriented_only && u0*pu + v0*pv + w0*pw<0) { u0 = -u0; v0 = -v0; w0 = -w0; } float - u = (float)(dl*func(X+u0,Y+v0,Z+w0,0)), - v = (float)(dl*func(X+u0,Y+v0,Z+w0,1)), - w = (float)(dl*func(X+u0,Y+v0,Z+w0,2)); + u = (float)(dl*func(X + u0,Y + v0,Z + w0,0)), + v = (float)(dl*func(X + u0,Y + v0,Z + w0,1)), + w = (float)(dl*func(X + u0,Y + v0,Z + w0,2)); if (is_oriented_only && u*pu + v*pv + w*pw<0) { u = -u; v = -v; w = -w; } if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); } if (is_bounded && (Xx1 || Yy1 || Zz1)) break; @@ -23897,19 +23856,19 @@ namespace cimg_library_suffixed { w0 = (float)(dl2*func(X,Y,Z,2)); if (is_oriented_only && u0*pu + v0*pv + w0*pw<0) { u0 = -u0; v0 = -v0; w0 = -w0; } float - u1 = (float)(dl2*func(X+u0,Y+v0,Z+w0,0)), - v1 = (float)(dl2*func(X+u0,Y+v0,Z+w0,1)), - w1 = (float)(dl2*func(X+u0,Y+v0,Z+w0,2)); + u1 = (float)(dl2*func(X + u0,Y + v0,Z + w0,0)), + v1 = (float)(dl2*func(X + u0,Y + v0,Z + w0,1)), + w1 = (float)(dl2*func(X + u0,Y + v0,Z + w0,2)); if (is_oriented_only && u1*pu + v1*pv + w1*pw<0) { u1 = -u1; v1 = -v1; w1 = -w1; } float - u2 = (float)(dl2*func(X+u1,Y+v1,Z+w1,0)), - v2 = (float)(dl2*func(X+u1,Y+v1,Z+w1,1)), - w2 = (float)(dl2*func(X+u1,Y+v1,Z+w1,2)); + u2 = (float)(dl2*func(X + u1,Y + v1,Z + w1,0)), + v2 = (float)(dl2*func(X + u1,Y + v1,Z + w1,1)), + w2 = (float)(dl2*func(X + u1,Y + v1,Z + w1,2)); if (is_oriented_only && u2*pu + v2*pv + w2*pw<0) { u2 = -u2; v2 = -v2; w2 = -w2; } float - u3 = (float)(dl2*func(X+u2,Y+v2,Z+w2,0)), - v3 = (float)(dl2*func(X+u2,Y+v2,Z+w2,1)), - w3 = (float)(dl2*func(X+u2,Y+v2,Z+w2,2)); + u3 = (float)(dl2*func(X + u2,Y + v2,Z + w2,0)), + v3 = (float)(dl2*func(X + u2,Y + v2,Z + w2,1)), + w3 = (float)(dl2*func(X + u2,Y + v2,Z + w2,2)); if (is_oriented_only && u2*pu + v2*pv + w2*pw<0) { u3 = -u3; v3 = -v3; w3 = -w3; } const float u = (u0 + u3)/3 + (u1 + u2)/1.5f, @@ -23958,7 +23917,8 @@ namespace cimg_library_suffixed { _functor4d_streamline2d_oriented(const CImg& pref):ref(pref),pI(0) { pI = new CImg(2,2,1,2); } ~_functor4d_streamline2d_oriented() { delete pI; } float operator()(const float x, const float y, const float z, const unsigned int c) const { -#define _cimg_vecalign2d(i,j) if (I(i,j,0)*I(0,0,0)+I(i,j,1)*I(0,0,1)<0) { I(i,j,0) = -I(i,j,0); I(i,j,1) = -I(i,j,1); } +#define _cimg_vecalign2d(i,j) \ + if (I(i,j,0)*I(0,0,0) + I(i,j,1)*I(0,0,1)<0) { I(i,j,0) = -I(i,j,0); I(i,j,1) = -I(i,j,1); } int xi = (int)x - (x>=0?0:1), nxi = xi + 1, yi = (int)y - (y>=0?0:1), nyi = yi + 1, @@ -23969,9 +23929,9 @@ namespace cimg_library_suffixed { if (c==0) { CImg& I = *pI; if (xi<0) xi = 0; if (nxi<0) nxi = 0; - if (xi>=ref.width()) xi = ref.width()-1; if (nxi>=ref.width()) nxi = ref.width()-1; + if (xi>=ref.width()) xi = ref.width() - 1; if (nxi>=ref.width()) nxi = ref.width() - 1; if (yi<0) yi = 0; if (nyi<0) nyi = 0; - if (yi>=ref.height()) yi = ref.height()-1; if (nyi>=ref.height()) nyi = ref.height()-1; + if (yi>=ref.height()) yi = ref.height() - 1; if (nyi>=ref.height()) nyi = ref.height() - 1; I(0,0,0) = (float)ref(xi,yi,zi,0); I(0,0,1) = (float)ref(xi,yi,zi,1); I(1,0,0) = (float)ref(nxi,yi,zi,0); I(1,0,1) = (float)ref(nxi,yi,zi,1); I(1,1,0) = (float)ref(nxi,nyi,zi,0); I(1,1,1) = (float)ref(nxi,nyi,zi,1); @@ -23988,7 +23948,7 @@ namespace cimg_library_suffixed { _functor4d_streamline3d_oriented(const CImg& pref):ref(pref),pI(0) { pI = new CImg(2,2,2,3); } ~_functor4d_streamline3d_oriented() { delete pI; } float operator()(const float x, const float y, const float z, const unsigned int c) const { -#define _cimg_vecalign3d(i,j,k) if (I(i,j,k,0)*I(0,0,0,0)+I(i,j,k,1)*I(0,0,0,1)+I(i,j,k,2)*I(0,0,0,2)<0) { \ +#define _cimg_vecalign3d(i,j,k) if (I(i,j,k,0)*I(0,0,0,0) + I(i,j,k,1)*I(0,0,0,1) + I(i,j,k,2)*I(0,0,0,2)<0) { \ I(i,j,k,0) = -I(i,j,k,0); I(i,j,k,1) = -I(i,j,k,1); I(i,j,k,2) = -I(i,j,k,2); } int xi = (int)x - (x>=0?0:1), nxi = xi + 1, @@ -24001,11 +23961,11 @@ namespace cimg_library_suffixed { if (c==0) { CImg& I = *pI; if (xi<0) xi = 0; if (nxi<0) nxi = 0; - if (xi>=ref.width()) xi = ref.width()-1; if (nxi>=ref.width()) nxi = ref.width()-1; + if (xi>=ref.width()) xi = ref.width() - 1; if (nxi>=ref.width()) nxi = ref.width() - 1; if (yi<0) yi = 0; if (nyi<0) nyi = 0; - if (yi>=ref.height()) yi = ref.height()-1; if (nyi>=ref.height()) nyi = ref.height()-1; + if (yi>=ref.height()) yi = ref.height() - 1; if (nyi>=ref.height()) nyi = ref.height() - 1; if (zi<0) zi = 0; if (nzi<0) nzi = 0; - if (zi>=ref.depth()) zi = ref.depth()-1; if (nzi>=ref.depth()) nzi = ref.depth()-1; + if (zi>=ref.depth()) zi = ref.depth() - 1; if (nzi>=ref.depth()) nzi = ref.depth() - 1; I(0,0,0,0) = (float)ref(xi,yi,zi,0); I(0,0,0,1) = (float)ref(xi,yi,zi,1); I(0,0,0,2) = (float)ref(xi,yi,zi,2); I(1,0,0,0) = (float)ref(nxi,yi,zi,0); I(1,0,0,1) = (float)ref(nxi,yi,zi,1); I(1,0,0,2) = (float)ref(nxi,yi,zi,2); @@ -24046,27 +24006,31 @@ namespace cimg_library_suffixed { **/ CImg get_shared_points(const unsigned int x0, const unsigned int x1, const unsigned int y0=0, const unsigned int z0=0, const unsigned int c0=0) { - const unsigned int beg = (unsigned int)offset(x0,y0,z0,c0), end = offset(x1,y0,z0,c0); + const unsigned int + beg = (unsigned int)offset(x0,y0,z0,c0), + end = (unsigned int)offset(x1,y0,z0,c0); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException(_cimg_instance "get_shared_points(): Invalid request of a shared-memory subset (%u->%u,%u,%u,%u).", cimg_instance, x0,x1,y0,z0,c0); - return CImg(_data+beg,x1-x0+1,1,1,1,true); + return CImg(_data + beg,x1 - x0 + 1,1,1,1,true); } //! Return a shared-memory image referencing a range of pixels of the image instance \const. const CImg get_shared_points(const unsigned int x0, const unsigned int x1, const unsigned int y0=0, const unsigned int z0=0, const unsigned int c0=0) const { - const unsigned int beg = (unsigned int)offset(x0,y0,z0,c0), end = offset(x1,y0,z0,c0); + const unsigned int + beg = (unsigned int)offset(x0,y0,z0,c0), + end = (unsigned int)offset(x1,y0,z0,c0); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException(_cimg_instance "get_shared_points(): Invalid request of a shared-memory subset (%u->%u,%u,%u,%u).", cimg_instance, x0,x1,y0,z0,c0); - return CImg(_data+beg,x1-x0+1,1,1,1,true); + return CImg(_data + beg,x1 - x0 + 1,1,1,1,true); } //! Return a shared-memory image referencing a range of rows of the image instance. @@ -24078,29 +24042,33 @@ namespace cimg_library_suffixed { **/ CImg get_shared_rows(const unsigned int y0, const unsigned int y1, const unsigned int z0=0, const unsigned int c0=0) { - const unsigned int beg = offset(0,y0,z0,c0), end = offset(0,y1,z0,c0); + const unsigned int + beg = (unsigned int)offset(0,y0,z0,c0), + end = (unsigned int)offset(0,y1,z0,c0); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException(_cimg_instance "get_shared_rows(): Invalid request of a shared-memory subset " "(0->%u,%u->%u,%u,%u).", cimg_instance, - _width-1,y0,y1,z0,c0); + _width - 1,y0,y1,z0,c0); - return CImg(_data+beg,_width,y1-y0+1,1,1,true); + return CImg(_data + beg,_width,y1 - y0 + 1,1,1,true); } //! Return a shared-memory image referencing a range of rows of the image instance \const. const CImg get_shared_rows(const unsigned int y0, const unsigned int y1, const unsigned int z0=0, const unsigned int c0=0) const { - const unsigned int beg = offset(0,y0,z0,c0), end = offset(0,y1,z0,c0); + const unsigned int + beg = (unsigned int)offset(0,y0,z0,c0), + end = (unsigned int)offset(0,y1,z0,c0); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException(_cimg_instance "get_shared_rows(): Invalid request of a shared-memory subset " "(0->%u,%u->%u,%u,%u).", cimg_instance, - _width-1,y0,y1,z0,c0); + _width - 1,y0,y1,z0,c0); - return CImg(_data+beg,_width,y1-y0+1,1,1,true); + return CImg(_data + beg,_width,y1 - y0 + 1,1,1,true); } //! Return a shared-memory image referencing one row of the image instance. @@ -24125,28 +24093,32 @@ namespace cimg_library_suffixed { \param c0 C-coordinate. **/ CImg get_shared_slices(const unsigned int z0, const unsigned int z1, const unsigned int c0=0) { - const unsigned int beg = offset(0,0,z0,c0), end = offset(0,0,z1,c0); + const unsigned int + beg = (unsigned int)offset(0,0,z0,c0), + end = (unsigned int)offset(0,0,z1,c0); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException(_cimg_instance "get_shared_slices(): Invalid request of a shared-memory subset " "(0->%u,0->%u,%u->%u,%u).", cimg_instance, - _width-1,_height-1,z0,z1,c0); + _width - 1,_height - 1,z0,z1,c0); - return CImg(_data+beg,_width,_height,z1-z0+1,1,true); + return CImg(_data + beg,_width,_height,z1 - z0 + 1,1,true); } //! Return a shared memory image referencing a range of slices of the image instance \const. const CImg get_shared_slices(const unsigned int z0, const unsigned int z1, const unsigned int c0=0) const { - const unsigned int beg = offset(0,0,z0,c0), end = offset(0,0,z1,c0); + const unsigned int + beg = (unsigned int)offset(0,0,z0,c0), + end = (unsigned int)offset(0,0,z1,c0); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException(_cimg_instance "get_shared_slices(): Invalid request of a shared-memory subset " "(0->%u,0->%u,%u->%u,%u).", cimg_instance, - _width-1,_height-1,z0,z1,c0); + _width - 1,_height - 1,z0,z1,c0); - return CImg(_data+beg,_width,_height,z1-z0+1,1,true); + return CImg(_data + beg,_width,_height,z1 - z0 + 1,1,true); } //! Return a shared-memory image referencing one slice of the image instance. @@ -24169,28 +24141,32 @@ namespace cimg_library_suffixed { \param c1 C-coordinate of the ending channel. **/ CImg get_shared_channels(const unsigned int c0, const unsigned int c1) { - const unsigned int beg = offset(0,0,0,c0), end = offset(0,0,0,c1); + const unsigned int + beg = (unsigned int)offset(0,0,0,c0), + end = (unsigned int)offset(0,0,0,c1); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException(_cimg_instance "get_shared_channels(): Invalid request of a shared-memory subset " "(0->%u,0->%u,0->%u,%u->%u).", cimg_instance, - _width-1,_height-1,_depth-1,c0,c1); + _width - 1,_height - 1,_depth - 1,c0,c1); - return CImg(_data+beg,_width,_height,_depth,c1-c0+1,true); + return CImg(_data + beg,_width,_height,_depth,c1 - c0 + 1,true); } //! Return a shared-memory image referencing a range of channels of the image instance \const. const CImg get_shared_channels(const unsigned int c0, const unsigned int c1) const { - const unsigned int beg = offset(0,0,0,c0), end = offset(0,0,0,c1); + const unsigned int + beg = (unsigned int)offset(0,0,0,c0), + end = (unsigned int)offset(0,0,0,c1); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException(_cimg_instance "get_shared_channels(): Invalid request of a shared-memory subset " "(0->%u,0->%u,0->%u,%u->%u).", cimg_instance, - _width-1,_height-1,_depth-1,c0,c1); + _width - 1,_height - 1,_depth - 1,c0,c1); - return CImg(_data+beg,_width,_height,_depth,c1-c0+1,true); + return CImg(_data + beg,_width,_height,_depth,c1 - c0 + 1,true); } //! Return a shared-memory image referencing one channel of the image instance. @@ -24221,68 +24197,68 @@ namespace cimg_library_suffixed { \param axis Splitting axis. Can be { 'x' | 'y' | 'z' | 'c' }. \param nb Number of splitted parts. \note - - If \c nb==0, there are as much splitted parts as the image size along the specified axis. + - If \c nb==0, instance image is splitted into blocs of egal values along the specified axis. - If \c nb<=0, instance image is splitted into blocs of -\c nb pixel wide. - If \c nb>0, instance image is splitted into \c nb blocs. **/ - CImgList get_split(const char axis, const int nb=0) const { + CImgList get_split(const char axis, const int nb=-1) const { CImgList res; if (is_empty()) return res; const char _axis = cimg::uncase(axis); - if (nb<=0) { // Split by bloc size. + if (nb<0) { // Split by bloc size. const unsigned int dp = (unsigned int)(nb?-nb:1); switch (_axis) { case 'x': { if (_width>dp) { - res.assign(_width/dp+(_width%dp?1:0),1,1); + res.assign(_width/dp + (_width%dp?1:0),1,1); const unsigned int pe = _width - dp; #ifdef cimg_use_openmp #pragma omp parallel for if (res._width>=128 && _height*_depth*_spectrum>=128) #endif for (unsigned int p = 0; pdp) { - res.assign(_height/dp+(_height%dp?1:0),1,1); + res.assign(_height/dp + (_height%dp?1:0),1,1); const unsigned int pe = _height - dp; #ifdef cimg_use_openmp #pragma omp parallel for if (res._width>=128 && _width*_depth*_spectrum>=128) #endif for (unsigned int p = 0; pdp) { - res.assign(_depth/dp+(_depth%dp?1:0),1,1); + res.assign(_depth/dp + (_depth%dp?1:0),1,1); const unsigned int pe = _depth - dp; #ifdef cimg_use_openmp #pragma omp parallel for if (res._width>=128 && _width*_height*_spectrum>=128) #endif for (unsigned int p = 0; pdp) { - res.assign(_spectrum/dp+(_spectrum%dp?1:0),1,1); + res.assign(_spectrum/dp + (_spectrum%dp?1:0),1,1); const unsigned int pe = _spectrum - dp; #ifdef cimg_use_openmp #pragma omp parallel for if (res._width>=128 && _width*_height*_depth>=128) #endif for (unsigned int p = 0; p0) { // Split by number of (non-homogeneous) blocs. const unsigned int siz = _axis=='x'?_width:_axis=='y'?_height:_axis=='z'?_depth:_axis=='c'?_spectrum:0; if ((unsigned int)nb>siz) throw CImgArgumentException(_cimg_instance @@ -24296,116 +24272,221 @@ namespace cimg_library_suffixed { switch (_axis) { case 'x' : { cimg_forX(*this,p) if ((err-=nb)<=0) { - get_crop(_p,0,0,0,p,_height-1,_depth-1,_spectrum-1).move_to(res); + get_crop(_p,0,0,0,p,_height - 1,_depth - 1,_spectrum - 1).move_to(res); err+=(int)siz; - _p=p+1; + _p = p + 1U; } } break; case 'y' : { cimg_forY(*this,p) if ((err-=nb)<=0) { - get_crop(0,_p,0,0,_width-1,p,_depth-1,_spectrum-1).move_to(res); + get_crop(0,_p,0,0,_width - 1,p,_depth - 1,_spectrum - 1).move_to(res); err+=(int)siz; - _p=p+1; + _p = p + 1U; } } break; case 'z' : { cimg_forZ(*this,p) if ((err-=nb)<=0) { - get_crop(0,0,_p,0,_width-1,_height-1,p,_spectrum-1).move_to(res); + get_crop(0,0,_p,0,_width - 1,_height - 1,p,_spectrum - 1).move_to(res); err+=(int)siz; - _p=p+1; + _p = p + 1U; } } break; - default : { + case 'c' : { cimg_forC(*this,p) if ((err-=nb)<=0) { - get_crop(0,0,0,_p,_width-1,_height-1,_depth-1,p).move_to(res); + get_crop(0,0,0,_p,_width - 1,_height - 1,_depth - 1,p).move_to(res); err+=(int)siz; - _p=p+1; + _p = p + 1U; } } } } + } else { // Split by egal values according to specified axis. + T current = *_data; + switch (_axis) { + case 'x' : { + int i0 = 0; + cimg_forX(*this,i) + if ((*this)(i)!=current) { get_columns(i0,i - 1).move_to(res); i0 = i; current = (*this)(i); } + get_columns(i0,width() - 1).move_to(res); + } break; + case 'y' : { + int i0 = 0; + cimg_forY(*this,i) + if ((*this)(0,i)!=current) { get_rows(i0,i - 1).move_to(res); i0 = i; current = (*this)(0,i); } + get_rows(i0,height() - 1).move_to(res); + } break; + case 'z' : { + int i0 = 0; + cimg_forZ(*this,i) + if ((*this)(0,0,i)!=current) { get_slices(i0,i - 1).move_to(res); i0 = i; current = (*this)(0,0,i); } + get_slices(i0,depth() - 1).move_to(res); + } break; + case 'c' : { + int i0 = 0; + cimg_forC(*this,i) + if ((*this)(0,0,0,i)!=current) { get_channels(i0,i - 1).move_to(res); i0 = i; current = (*this)(0,0,0,i); } + get_channels(i0,spectrum() - 1).move_to(res); + } break; + default : { + long i0 = 0; + cimg_foroff(*this,i) + if ((*this)[i]!=current) { CImg(_data + i0,1,i - i0).move_to(res); i0 = (long)i; current = (*this)[i]; } + CImg(_data + i0,1,size() - i0).move_to(res); + } + } } return res; } - //! Split image into a list of one-column vectors, according to a specified splitting value. - /** - \param value Splitting value. - \param keep_values Tells if the splitting value must be kept in the splitted blocs. - \param is_shared Tells if the splitted blocs have shared memory buffers. - **/ - CImgList get_split(const T value, const bool keep_values, const bool is_shared) const { - CImgList res; - if (is_empty()) return res; - for (const T *ps = _data, *_ps = ps, *const pe = end(); ps(ps,1,siz,1,1,is_shared),~0U,is_shared); - ps = _ps; - while (_ps(ps,1,siz,1,1,is_shared),~0U,is_shared); - ps = _ps; - } - return res; - } - - //! Split image into a list of one-column vectors, according to a specified splitting value sequence. + //! Split image into a list of sub-images, according to a specified splitting value sequence and optionnally axis. /** \param values Splitting value sequence. + \param axis Axis along which the splitting is performed. Can be '0' to ignore axis. \param keep_values Tells if the splitting sequence must be kept in the splitted blocs. - \param is_shared Tells if the splitted blocs have shared memory buffers. **/ template - CImgList get_split(const CImg& values, const bool keep_values, const bool is_shared) const { + CImgList get_split(const CImg& values, const char axis=0, const bool keep_values=true) const { CImgList res; if (is_empty()) return res; - if (!values) return CImgList(*this); - if (values.size()==1) return get_split(*values,keep_values,is_shared); - const t *pve = values.end(); - for (const T *ps = _data, *_ps = ps, *const pe = end(); ps(ps,1,siz,1,1,is_shared),~0U,is_shared); // If match found. - ps = _ps; - - // Try to find non-match from current position. - do { - pv = values._data; - while (_ps(ps,1,siz,1,1,is_shared),~0U,is_shared); - ps = _ps; - } - return res; - } - - //! Split the image into a list of one-column vectors each having same values. - CImgList get_split(const bool is_shared) const { - CImgList res; - if (is_empty()) return res; - T *p0 = _data, current = *p0; - cimg_for(*this,p,T) if (*p!=current) { - res.insert(CImg(p0,1,p-p0,1,1,is_shared),~0U,is_shared); p0 = p; current = *p; + const unsigned long vsiz = values.size(); + const char _axis = cimg::uncase(axis); + if (!vsiz) return CImgList(*this); + if (vsiz==1) { // Split according to a single value. + const T value = *values; + switch (_axis) { + case 'x' : { + unsigned int i0 = 0, i = 0; + do { + while (i<_width && (*this)(i)==value) ++i; + if (i>i0) { if (keep_values) get_columns(i0,i - 1).move_to(res); i0 = i; } + while (i<_width && (*this)(i)!=value) ++i; + if (i>i0) { get_columns(i0,i - 1).move_to(res); i0 = i; } + } while (i<_width); + } break; + case 'y' : { + unsigned int i0 = 0, i = 0; + do { + while (i<_height && (*this)(0,i)==value) ++i; + if (i>i0) { if (keep_values) get_rows(i0,i - 1).move_to(res); i0 = i; } + while (i<_height && (*this)(0,i)!=value) ++i; + if (i>i0) { get_rows(i0,i - 1).move_to(res); i0 = i; } + } while (i<_height); + } break; + case 'z' : { + unsigned int i0 = 0, i = 0; + do { + while (i<_depth && (*this)(0,0,i)==value) ++i; + if (i>i0) { if (keep_values) get_slices(i0,i - 1).move_to(res); i0 = i; } + while (i<_depth && (*this)(0,0,i)!=value) ++i; + if (i>i0) { get_slices(i0,i - 1).move_to(res); i0 = i; } + } while (i<_depth); + } break; + case 'c' : { + unsigned int i0 = 0, i = 0; + do { + while (i<_spectrum && (*this)(0,0,0,i)==value) ++i; + if (i>i0) { if (keep_values) get_channels(i0,i - 1).move_to(res); i0 = i; } + while (i<_spectrum && (*this)(0,0,0,i)!=value) ++i; + if (i>i0) { get_channels(i0,i - 1).move_to(res); i0 = i; } + } while (i<_spectrum); + } break; + default : { + const unsigned long siz = size(); + unsigned long i0 = 0, i = 0; + do { + while (ii0) { if (keep_values) CImg(_data + i0,1,i - i0).move_to(res); i0 = i; } + while (ii0) { CImg(_data + i0,1,i - i0).move_to(res); i0 = i; } + } while (i=vsiz) j = 0; } + i-=j; + if (i>i1) { + if (i1>i0) get_columns(i0,i1 - 1).move_to(res); + if (keep_values) get_columns(i1,i - 1).move_to(res); + i0 = i; + } else ++i; + } else ++i; + } while (i<_width); + if (i0<_width) get_columns(i0,width() - 1).move_to(res); + } break; + case 'y' : { + unsigned int i0 = 0, i1 = 0, i = 0; + do { + if ((*this)(0,i)==*values) { + i1 = i; j = 0; + while (i<_height && (*this)(0,i)==values[j]) { ++i; if (++j>=vsiz) j = 0; } + i-=j; + if (i>i1) { + if (i1>i0) get_rows(i0,i1 - 1).move_to(res); + if (keep_values) get_rows(i1,i - 1).move_to(res); + i0 = i; + } else ++i; + } else ++i; + } while (i<_height); + if (i0<_height) get_rows(i0,height() - 1).move_to(res); + } break; + case 'z' : { + unsigned int i0 = 0, i1 = 0, i = 0; + do { + if ((*this)(0,0,i)==*values) { + i1 = i; j = 0; + while (i<_depth && (*this)(0,0,i)==values[j]) { ++i; if (++j>=vsiz) j = 0; } + i-=j; + if (i>i1) { + if (i1>i0) get_slices(i0,i1 - 1).move_to(res); + if (keep_values) get_slices(i1,i - 1).move_to(res); + i0 = i; + } else ++i; + } else ++i; + } while (i<_depth); + if (i0<_depth) get_slices(i0,depth() - 1).move_to(res); + } break; + case 'c' : { + unsigned int i0 = 0, i1 = 0, i = 0; + do { + if ((*this)(0,0,0,i)==*values) { + i1 = i; j = 0; + while (i<_spectrum && (*this)(0,0,0,i)==values[j]) { ++i; if (++j>=vsiz) j = 0; } + i-=j; + if (i>i1) { + if (i1>i0) get_channels(i0,i1 - 1).move_to(res); + if (keep_values) get_channels(i1,i - 1).move_to(res); + i0 = i; + } else ++i; + } else ++i; + } while (i<_spectrum); + if (i0<_spectrum) get_channels(i0,spectrum() - 1).move_to(res); + } break; + default : { + unsigned long i0 = 0, i1 = 0, i = 0; + const unsigned long siz = size(); + do { + if ((*this)[i]==*values) { + i1 = i; j = 0; + while (i=vsiz) j = 0; } + i-=j; + if (i>i1) { + if (i1>i0) CImg(_data + i0,1,i1 - i0).move_to(res); + if (keep_values) CImg(_data + i1,1,i - i1).move_to(res); + i0 = i; + } else ++i; + } else ++i; + } while (i(_data + i0,1,siz - i0).move_to(res); + } break; + } } - res.insert(CImg(p0,1,end()-p0,1,1,is_shared),~0U,is_shared); return res; } @@ -24458,7 +24539,7 @@ namespace cimg_library_suffixed { \param is_normalized = enable local normalization. \note - The correlation of the image instance \p *this by the mask \p mask is defined to be: - res(x,y,z) = sum_{i,j,k} (*this)(x+i,y+j,z+k)*mask(i,j,k). + res(x,y,z) = sum_{i,j,k} (*this)(x + i,y + j,z + k)*mask(i,j,k). **/ template CImg& correlate(const CImg& mask, const unsigned int boundary_conditions=1, const bool is_normalized=false) { @@ -24552,26 +24633,35 @@ namespace cimg_library_suffixed { if (is_normalized) { const Ttfloat _M = (Ttfloat)_mask.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]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] + I[ 4]*_mask[ 4] + I[ 5]*_mask[ 5] + - I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] + I[ 8]*_mask[ 8] + I[ 9]*_mask[ 9] + I[10]*_mask[10] + I[11]*_mask[11] + - I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + I[15]*_mask[15] + I[16]*_mask[16] + I[17]*_mask[17] + - I[18]*_mask[18] + I[19]*_mask[19] + I[20]*_mask[20] + I[21]*_mask[21] + I[22]*_mask[22] + I[23]*_mask[23] + - I[24]*_mask[24] + I[25]*_mask[25] + I[26]*_mask[26] + I[27]*_mask[27] + I[28]*_mask[28] + I[29]*_mask[29] + - I[30]*_mask[30] + I[31]*_mask[31] + I[32]*_mask[32] + I[33]*_mask[33] + I[34]*_mask[34] + I[35]*_mask[35])/std::sqrt(N):0); + 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]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] + + I[ 4]*_mask[ 4] + I[ 5]*_mask[ 5] + I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] + + I[ 8]*_mask[ 8] + I[ 9]*_mask[ 9] + I[10]*_mask[10] + I[11]*_mask[11] + + I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + I[15]*_mask[15] + + I[16]*_mask[16] + I[17]*_mask[17] + I[18]*_mask[18] + I[19]*_mask[19] + + I[20]*_mask[20] + I[21]*_mask[21] + I[22]*_mask[22] + I[23]*_mask[23] + + I[24]*_mask[24] + I[25]*_mask[25] + I[26]*_mask[26] + I[27]*_mask[27] + + I[28]*_mask[28] + I[29]*_mask[29] + I[30]*_mask[30] + I[31]*_mask[31] + + I[32]*_mask[32] + I[33]*_mask[33] + I[34]*_mask[34] + I[35]*_mask[35])/ + std::sqrt(N):0); } } else cimg_forZ(_img,z) cimg_for6x6(_img,x,y,z,0,I,T) - *(ptrd++) = (Ttfloat)(I[ 0]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] + I[ 4]*_mask[ 4] + I[ 5]*_mask[ 5] + - I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] + I[ 8]*_mask[ 8] + I[ 9]*_mask[ 9] + I[10]*_mask[10] + I[11]*_mask[11] + - I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + I[15]*_mask[15] + I[16]*_mask[16] + I[17]*_mask[17] + - I[18]*_mask[18] + I[19]*_mask[19] + I[20]*_mask[20] + I[21]*_mask[21] + I[22]*_mask[22] + I[23]*_mask[23] + - I[24]*_mask[24] + I[25]*_mask[25] + I[26]*_mask[26] + I[27]*_mask[27] + I[28]*_mask[28] + I[29]*_mask[29] + - I[30]*_mask[30] + I[31]*_mask[31] + I[32]*_mask[32] + I[33]*_mask[33] + I[34]*_mask[34] + I[35]*_mask[35]); + *(ptrd++) = (Ttfloat)(I[ 0]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] + + I[ 4]*_mask[ 4] + I[ 5]*_mask[ 5] + I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] + + I[ 8]*_mask[ 8] + I[ 9]*_mask[ 9] + I[10]*_mask[10] + I[11]*_mask[11] + + I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + I[15]*_mask[15] + + I[16]*_mask[16] + I[17]*_mask[17] + I[18]*_mask[18] + I[19]*_mask[19] + + I[20]*_mask[20] + I[21]*_mask[21] + I[22]*_mask[22] + I[23]*_mask[23] + + I[24]*_mask[24] + I[25]*_mask[25] + I[26]*_mask[26] + I[27]*_mask[27] + + I[28]*_mask[28] + I[29]*_mask[29] + I[30]*_mask[30] + I[31]*_mask[31] + + I[32]*_mask[32] + I[33]*_mask[33] + I[34]*_mask[34] + I[35]*_mask[35]); } } break; case 5 : { @@ -24587,18 +24677,22 @@ namespace cimg_library_suffixed { 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]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] + I[ 4]*_mask[ 4] + - I[ 5]*_mask[ 5] + I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] + I[ 8]*_mask[ 8] + I[ 9]*_mask[ 9] + - I[10]*_mask[10] + I[11]*_mask[11] + I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + - I[15]*_mask[15] + I[16]*_mask[16] + I[17]*_mask[17] + I[18]*_mask[18] + I[19]*_mask[19] + - I[20]*_mask[20] + I[21]*_mask[21] + I[22]*_mask[22] + I[23]*_mask[23] + I[24]*_mask[24])/std::sqrt(N):0); + *(ptrd++) = (Ttfloat)(N?(I[ 0]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] + + I[ 4]*_mask[ 4] + I[ 5]*_mask[ 5] + I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] + + I[ 8]*_mask[ 8] + I[ 9]*_mask[ 9] + I[10]*_mask[10] + I[11]*_mask[11] + + I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + I[15]*_mask[15] + + I[16]*_mask[16] + I[17]*_mask[17] + I[18]*_mask[18] + I[19]*_mask[19] + + I[20]*_mask[20] + I[21]*_mask[21] + I[22]*_mask[22] + I[23]*_mask[23] + + I[24]*_mask[24])/std::sqrt(N):0); } } else cimg_forZ(_img,z) cimg_for5x5(_img,x,y,z,0,I,T) - *(ptrd++) = (Ttfloat)(I[ 0]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] + I[ 4]*_mask[ 4] + - I[ 5]*_mask[ 5] + I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] + I[ 8]*_mask[ 8] + I[ 9]*_mask[ 9] + - I[10]*_mask[10] + I[11]*_mask[11] + I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + - I[15]*_mask[15] + I[16]*_mask[16] + I[17]*_mask[17] + I[18]*_mask[18] + I[19]*_mask[19] + - I[20]*_mask[20] + I[21]*_mask[21] + I[22]*_mask[22] + I[23]*_mask[23] + I[24]*_mask[24]); + *(ptrd++) = (Ttfloat)(I[ 0]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] + + I[ 4]*_mask[ 4] + I[ 5]*_mask[ 5] + I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] + + I[ 8]*_mask[ 8] + I[ 9]*_mask[ 9] + I[10]*_mask[10] + I[11]*_mask[11] + + I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + I[15]*_mask[15] + + I[16]*_mask[16] + I[17]*_mask[17] + I[18]*_mask[18] + I[19]*_mask[19] + + I[20]*_mask[20] + I[21]*_mask[21] + I[22]*_mask[22] + I[23]*_mask[23] + + I[24]*_mask[24]); } } break; case 4 : { @@ -24616,7 +24710,8 @@ namespace cimg_library_suffixed { *(ptrd++) = (Ttfloat)(N?(I[ 0]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] + I[ 4]*_mask[ 4] + I[ 5]*_mask[ 5] + I[ 6]*_mask[ 6] + I[ 7]*_mask[ 7] + I[ 8]*_mask[ 8] + I[ 9]*_mask[ 9] + I[10]*_mask[10] + I[11]*_mask[11] + - I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + I[15]*_mask[15])/std::sqrt(N):0); + I[12]*_mask[12] + I[13]*_mask[13] + I[14]*_mask[14] + I[15]*_mask[15])/ + std::sqrt(N):0); } } else cimg_forZ(_img,z) cimg_for4x4(_img,x,y,z,0,I,T) *(ptrd++) = (Ttfloat)(I[ 0]*_mask[ 0] + I[ 1]*_mask[ 1] + I[ 2]*_mask[ 2] + I[ 3]*_mask[ 3] + @@ -24697,8 +24792,8 @@ namespace cimg_library_suffixed { 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*_mask(mx1+xm,my1+ym,mz1+zm); + const Ttfloat _val = (Ttfloat)_img(x + xm,y + ym,z + zm); + val+=_val*_mask(mx1 + xm,my1 + ym,mz1 + zm); N+=_val*_val; } N*=M; @@ -24709,13 +24804,14 @@ namespace cimg_library_suffixed { #pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128) #endif cimg_forYZ(res,y,z) - for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { + for (int x = 0; x=mye || z=mze)?++x:((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*_mask(mx1+xm,my1+ym,mz1+zm); + const Ttfloat _val = (Ttfloat)_img._atXYZ(x + xm,y + ym,z + zm); + val+=_val*_mask(mx1 + xm,my1 + ym,mz1 + zm); N+=_val*_val; } N*=M; @@ -24726,13 +24822,14 @@ namespace cimg_library_suffixed { #pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128) #endif cimg_forYZ(res,y,z) - for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { + for (int x = 0; x=mye || z=mze)?++x:((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,0); - val+=_val*_mask(mx1+xm,my1+ym,mz1+zm); + const Ttfloat _val = (Ttfloat)_img.atXYZ(x + xm,y + ym,z + zm,0,0); + val+=_val*_mask(mx1 + xm,my1 + ym,mz1 + zm); N+=_val*_val; } N*=M; @@ -24749,7 +24846,7 @@ namespace cimg_library_suffixed { 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)*_mask(mx1+xm,my1+ym,mz1+zm); + val+=_img(x + xm,y + ym,z + zm)*_mask(mx1 + xm,my1 + ym,mz1 + zm); res(x,y,z,c) = (Ttfloat)val; } if (boundary_conditions) @@ -24757,12 +24854,13 @@ namespace cimg_library_suffixed { #pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128) #endif cimg_forYZ(res,y,z) - for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { + for (int x = 0; x=mye || z=mze)?++x:((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)*_mask(mx1+xm,my1+ym,mz1+zm); + val+=_img._atXYZ(x + xm,y + ym,z + zm)*_mask(mx1 + xm,my1 + ym,mz1 + zm); res(x,y,z,c) = (Ttfloat)val; } else @@ -24770,12 +24868,13 @@ namespace cimg_library_suffixed { #pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128) #endif cimg_forYZ(res,y,z) - for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { + for (int x = 0; x=mye || z=mze)?++x:((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,0)*_mask(mx1+xm,my1+ym,mz1+zm); + val+=_img.atXYZ(x + xm,y + ym,z + zm,0,0)*_mask(mx1 + xm,my1 + ym,mz1 + zm); res(x,y,z,c) = (Ttfloat)val; } } @@ -24799,6 +24898,83 @@ namespace cimg_library_suffixed { return get_convolve(mask,boundary_conditions,is_normalized).move_to(*this); } + //! Cumulate image values, optionally along specified axis. + /** + \param axis Cumulation axis. Set it to 0 to cumulate all values globally without taking axes into account. + **/ + CImg& cumulate(const char axis=0) { + switch (cimg::uncase(axis)) { + case 'x' : +#ifdef cimg_use_openmp +#pragma omp parallel for collapse(3) if (_width>=512 && _height*_depth*_spectrum>=16) +#endif + cimg_forYZC(*this,y,z,c) { + T *ptrd = data(0,y,z,c); + Tlong cumul = 0; + cimg_forX(*this,x) { cumul+=(Tlong)*ptrd; *(ptrd++) = (T)cumul; } + } + break; + case 'y' : { + const unsigned long w = (unsigned long)_width; +#ifdef cimg_use_openmp +#pragma omp parallel for collapse(3) if (_height>=512 && _width*_depth*_spectrum>=16) +#endif + cimg_forXZC(*this,x,z,c) { + T *ptrd = data(x,0,z,c); + Tlong cumul = 0; + cimg_forY(*this,y) { cumul+=(Tlong)*ptrd; *ptrd = (T)cumul; ptrd+=w; } + } + } break; + case 'z' : { + const unsigned long wh = (unsigned long)_width*_height; +#ifdef cimg_use_openmp +#pragma omp parallel for collapse(3) if (_depth>=512 && _width*_depth*_spectrum>=16) +#endif + cimg_forXYC(*this,x,y,c) { + T *ptrd = data(x,y,0,c); + Tlong cumul = 0; + cimg_forZ(*this,z) { cumul+=(Tlong)*ptrd; *ptrd = (T)cumul; ptrd+=wh; } + } + } break; + case 'c' : { + const unsigned long whd = (unsigned long)_width*_height*_depth; +#ifdef cimg_use_openmp +#pragma omp parallel for collapse(3) if (_spectrum>=512 && _width*_height*_depth>=16) +#endif + cimg_forXYZ(*this,x,y,z) { + T *ptrd = data(x,y,z,0); + Tlong cumul = 0; + cimg_forC(*this,c) { cumul+=(Tlong)*ptrd; *ptrd = (T)cumul; ptrd+=whd; } + } + } break; + default : { // Global cumulation. + Tlong cumul = 0; + cimg_for(*this,ptrd,T) { cumul+=(Tlong)*ptrd; *ptrd = (T)cumul; } + } + } + return *this; + } + + //! Cumulate image values, optionally along specified axis \newinstance. + CImg get_cumulate(const char axis=0) const { + return CImg(*this,false).cumulate(axis); + } + + //! Cumulate image values, along specified axes. + /** + \param axes Cumulation axes, as a C-string. + \note \c axes may contains multiple characters, e.g. \c "xyz" + **/ + CImg& cumulate(const char *const axes) { + for (const char *s = axes; *s; ++s) cumulate(*s); + return *this; + } + + //! Cumulate image values, along specified axes \newintance. + CImg get_cumulate(const char *const axes) const { + return CImg(*this,false).cumulate(axes); + } + //! Convolve image by a mask \newinstance. template CImg<_cimg_Ttfloat> get_convolve(const CImg& mask, const unsigned int boundary_conditions=1, @@ -24849,8 +25025,8 @@ namespace cimg_library_suffixed { for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { - const t mval = _mask(mx1+xm,my1+ym,mz1+zm); - const Tt cval = (Tt)(_img(x+xm,y+ym,z+zm) + mval); + const t mval = _mask(mx1 + xm,my1 + ym,mz1 + zm); + const Tt cval = (Tt)(_img(x + xm,y + ym,z + zm) + mval); if (mval && cval=256 && _height*_depth>=128) #endif cimg_forYZ(res,y,z) - for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { + for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { Tt min_val = cimg::type::max(); for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { - const t mval = _mask(mx1+xm,my1+ym,mz1+zm); - const Tt cval = (Tt)(_img._atXYZ(x+xm,y+ym,z+zm) + mval); + const t mval = _mask(mx1 + xm,my1 + ym,mz1 + zm); + const Tt cval = (Tt)(_img._atXYZ(x + xm,y + ym,z + zm) + mval); if (mval && cval=256 && _height*_depth>=128) #endif cimg_forYZ(res,y,z) - for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { + for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { Tt min_val = cimg::type::max(); for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { - const t mval = _mask(mx1+xm,my1+ym,mz1+zm); - const Tt cval = (Tt)(_img.atXYZ(x+xm,y+ym,z+zm,0,0) + mval); + const t mval = _mask(mx1 + xm,my1 + ym,mz1 + zm); + const Tt cval = (Tt)(_img.atXYZ(x + xm,y + ym,z + zm,0,0) + mval); if (mval && cval=256 && _height*_depth>=128) #endif cimg_forYZ(res,y,z) - for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { + for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { Tt min_val = cimg::type::max(); for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { - const T cval = (Tt)_img._atXYZ(x+xm,y+ym,z+zm); - if (_mask(mx1+xm,my1+ym,mz1+zm) && cval=256 && _height*_depth>=128) #endif cimg_forYZ(res,y,z) - for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { + for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { Tt min_val = cimg::type::max(); for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { - const T cval = (Tt)_img.atXYZ(x+xm,y+ym,z+zm,0,0); - if (_mask(mx1+xm,my1+ym,mz1+zm) && cvalmax_val) max_val = cval; } res(x,y,z,c) = max_val; @@ -25149,13 +25325,13 @@ namespace cimg_library_suffixed { #pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128) #endif cimg_forYZ(res,y,z) - for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { + for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { Tt max_val = cimg::type::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 = _mask(mx1+xm,my1+ym,mz1+zm); - const Tt cval = (Tt)(_img._atXYZ(x+xm,y+ym,z+zm) - mval); + const t mval = _mask(mx1 + xm,my1 + ym,mz1 + zm); + const Tt cval = (Tt)(_img._atXYZ(x + xm,y + ym,z + zm) - mval); if (mval && cval>max_val) max_val = cval; } res(x,y,z,c) = max_val; @@ -25165,13 +25341,13 @@ namespace cimg_library_suffixed { #pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128) #endif cimg_forYZ(*this,y,z) - for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { + for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { Tt max_val = cimg::type::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 = _mask(mx1+xm,my1+ym,mz1+zm); - const Tt cval = (Tt)(_img.atXYZ(x+xm,y+ym,z+zm,0,0) - mval); + const t mval = _mask(mx1 + xm,my1 + ym,mz1 + zm); + const Tt cval = (Tt)(_img.atXYZ(x + xm,y + ym,z + zm,0,0) - mval); if (mval && cval>max_val) max_val = cval; } res(x,y,z,c) = max_val; @@ -25187,8 +25363,8 @@ namespace cimg_library_suffixed { for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { - const Tt cval = (Tt)_img(x+xm,y+ym,z+zm); - if (_mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval; + const Tt cval = (Tt)_img(x + xm,y + ym,z + zm); + if (_mask(mx1 + xm,my1 + ym,mz1 + zm) && cval>max_val) max_val = cval; } res(x,y,z,c) = max_val; } @@ -25197,13 +25373,13 @@ namespace cimg_library_suffixed { #pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128) #endif cimg_forYZ(res,y,z) - for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { + for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { Tt max_val = cimg::type::min(); for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { - const T cval = (Tt)_img._atXYZ(x+xm,y+ym,z+zm); - if (_mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval; + const T cval = (Tt)_img._atXYZ(x + xm,y + ym,z + zm); + if (_mask(mx1 + xm,my1 + ym,mz1 + zm) && cval>max_val) max_val = cval; } res(x,y,z,c) = max_val; } @@ -25212,13 +25388,13 @@ namespace cimg_library_suffixed { #pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=128) #endif cimg_forYZ(res,y,z) - for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { + for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { Tt max_val = cimg::type::min(); for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { - const T cval = (Tt)_img.atXYZ(x+xm,y+ym,z+zm,0,0); - if (_mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval; + const T cval = (Tt)_img.atXYZ(x + xm,y + ym,z + zm,0,0); + if (_mask(mx1 + xm,my1 + ym,mz1 + zm) && cval>max_val) max_val = cval; } res(x,y,z,c) = max_val; } @@ -25415,12 +25591,18 @@ namespace cimg_library_suffixed { // Find seed points and insert them in priority queue. const T *ptrs = _data; cimg_forXYZ(*this,x,y,z) if (*(ptrs++)) { - if (x-1>=0 && !(*this)(x-1,y,z)) Q._priority_queue_insert(is_queued,sizeQ,priority(x-1,y,z),x-1,y,z); - if (x+1=0 && !(*this)(x,y-1,z)) Q._priority_queue_insert(is_queued,sizeQ,priority(x,y-1,z),x,y-1,z); - if (y+1=0 && !(*this)(x,y,z-1)) Q._priority_queue_insert(is_queued,sizeQ,priority(x,y,z-1),x,y,z-1); - if (z+1=0 && !(*this)(x - 1,y,z)) + Q._priority_queue_insert(is_queued,sizeQ,priority(x - 1,y,z),x - 1,y,z); + if (x + 1=0 && !(*this)(x,y - 1,z)) + Q._priority_queue_insert(is_queued,sizeQ,priority(x,y - 1,z),x,y - 1,z); + if (y + 1=0 && !(*this)(x,y,z - 1)) + Q._priority_queue_insert(is_queued,sizeQ,priority(x,y,z - 1),x,y,z - 1); + if (z + 1=0) { - if ((*this)(x-1,y,z)) { - if (!label) label = (unsigned int)(*this)(x-1,y,z); - else if (label!=(*this)(x-1,y,z)) is_same_label = false; - } else Q._priority_queue_insert(is_queued,sizeQ,priority(x-1,y,z),x-1,y,z); - } - if (x+1=0) { - if ((*this)(x,y-1,z)) { - if (!label) label = (unsigned int)(*this)(x,y-1,z); - else if (label!=(*this)(x,y-1,z)) is_same_label = false; - } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y-1,z),x,y-1,z); - } - if (y+1=0) { - if ((*this)(x,y,z-1)) { - if (!label) label = (unsigned int)(*this)(x,y,z-1); - else if (label!=(*this)(x,y,z-1)) is_same_label = false; - } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y,z-1),x,y,z-1); - } - if (z+1=0) { + if ((*this)(x - 1,y,z)) { + if (!label) label = (unsigned int)(*this)(x - 1,y,z); + else if (label!=(*this)(x - 1,y,z)) is_same_label = false; + } else Q._priority_queue_insert(is_queued,sizeQ,priority(x - 1,y,z),x - 1,y,z); + } + if (x + 1=0) { + if ((*this)(x,y - 1,z)) { + if (!label) label = (unsigned int)(*this)(x,y - 1,z); + else if (label!=(*this)(x,y - 1,z)) is_same_label = false; + } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y - 1,z),x,y - 1,z); + } + if (y + 1=0) { + if ((*this)(x,y,z - 1)) { + if (!label) label = (unsigned int)(*this)(x,y,z - 1); + else if (label!=(*this)(x,y,z - 1)) is_same_label = false; + } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y,z - 1),x,y,z - 1); + } + if (z + 1=0 && (*this)(x-1,y,z)) || (x+1=0 && (*this)(x,y-1,z)) || (y+1=0 && (*this)(x,y,z-1)) || (z+1>depth() && (*this)(x,y,z+1)))) + ((x - 1>=0 && (*this)(x - 1,y,z)) || (x + 1=0 && (*this)(x,y - 1,z)) || (y + 1=0 && (*this)(x,y,z - 1)) || (z + 1>depth() && (*this)(x,y,z + 1)))) Q._priority_queue_insert(is_queued,sizeQ,priority(x,y,z),x,y,z); // Start line filling process. @@ -25490,35 +25672,35 @@ namespace cimg_library_suffixed { Q._priority_queue_remove(sizeQ); t pmax = cimg::type::min(); int xmax = 0, ymax = 0, zmax = 0; - if (x-1>=0) { - if ((*this)(x-1,y,z)) { - if (priority(x-1,y,z)>pmax) { pmax = priority(x-1,y,z); xmax = x-1; ymax = y; zmax = z; } - } else Q._priority_queue_insert(is_queued,sizeQ,priority(x-1,y,z),x-1,y,z); - } - if (x+1pmax) { pmax = priority(x+1,y,z); xmax = x+1; ymax = y; zmax = z; } - } else Q._priority_queue_insert(is_queued,sizeQ,priority(x+1,y,z),x+1,y,z); - } - if (y-1>=0) { - if ((*this)(x,y-1,z)) { - if (priority(x,y-1,z)>pmax) { pmax = priority(x,y-1,z); xmax = x; ymax = y-1; zmax = z; } - } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y-1,z),x,y-1,z); - } - if (y+1pmax) { pmax = priority(x,y+1,z); xmax = x; ymax = y+1; zmax = z; } - } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y+1,z),x,y+1,z); - } - if (z-1>=0) { - if ((*this)(x,y,z-1)) { - if (priority(x,y,z-1)>pmax) { pmax = priority(x,y,z-1); xmax = x; ymax = y; zmax = z-1; } - } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y,z-1),x,y,z-1); - } - if (z+1pmax) { pmax = priority(x,y,z+1); xmax = x; ymax = y; zmax = z+1; } - } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y,z+1),x,y,z+1); + if (x - 1>=0) { + if ((*this)(x - 1,y,z)) { + if (priority(x - 1,y,z)>pmax) { pmax = priority(x - 1,y,z); xmax = x - 1; ymax = y; zmax = z; } + } else Q._priority_queue_insert(is_queued,sizeQ,priority(x - 1,y,z),x - 1,y,z); + } + if (x + 1pmax) { pmax = priority(x + 1,y,z); xmax = x + 1; ymax = y; zmax = z; } + } else Q._priority_queue_insert(is_queued,sizeQ,priority(x + 1,y,z),x + 1,y,z); + } + if (y - 1>=0) { + if ((*this)(x,y - 1,z)) { + if (priority(x,y - 1,z)>pmax) { pmax = priority(x,y - 1,z); xmax = x; ymax = y - 1; zmax = z; } + } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y - 1,z),x,y - 1,z); + } + if (y + 1pmax) { pmax = priority(x,y + 1,z); xmax = x; ymax = y + 1; zmax = z; } + } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y + 1,z),x,y + 1,z); + } + if (z - 1>=0) { + if ((*this)(x,y,z - 1)) { + if (priority(x,y,z - 1)>pmax) { pmax = priority(x,y,z - 1); xmax = x; ymax = y; zmax = z - 1; } + } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y,z - 1),x,y,z - 1); + } + if (z + 1pmax) { pmax = priority(x,y,z + 1); xmax = x; ymax = y; zmax = z + 1; } + } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y,z + 1),x,y,z + 1); } (*this)(x,y,z) = (*this)(xmax,ymax,zmax); } @@ -25539,8 +25721,8 @@ namespace cimg_library_suffixed { if (is_queued(x,y,z)) return false; is_queued(x,y,z) = true; 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) { + (*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)); } @@ -25552,7 +25734,8 @@ namespace cimg_library_suffixed { (*this)(0,2) = (*this)(siz,2); (*this)(0,3) = (*this)(siz,3); const float value = (*this)(0,0); for (unsigned int pos = 0, left = 0, right = 0; - ((right=2*(pos+1),(left=right-1))(*this)(right,0)) { cimg::swap((*this)(pos,0),(*this)(left,0)); cimg::swap((*this)(pos,1),(*this)(left,1)); @@ -25579,7 +25762,8 @@ namespace cimg_library_suffixed { \param axis Axis along which the filter is computed. Can be { 'x' | 'y' | 'z' | 'c' }. \param boundary_conditions Boundary conditions. Can be { 0=dirichlet | 1=neumann }. **/ - CImg& deriche(const float sigma, const int order=0, const char axis='x', const bool boundary_conditions=true) { + CImg& deriche(const float sigma, const unsigned int order=0, const char axis='x', + const bool boundary_conditions=true) { #define _cimg_deriche_apply \ CImg Y(N); \ Tfloat *ptrY = Y._data, yb = 0, yp = 0; \ @@ -25593,7 +25777,7 @@ namespace cimg_library_suffixed { 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) { \ + 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; \ @@ -25612,26 +25796,26 @@ namespace cimg_library_suffixed { 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); + const float k = (1-ema)*(1-ema)/(1 + 2*alpha*ema-ema2); a0 = k; - a1 = k*(alpha-1)*ema; - a2 = k*(alpha+1)*ema; + 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; + 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)); + 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; + a1 = -kn*(1 + k*alpha)*ema; + a2 = kn*(1 - k*alpha)*ema; a3 = -kn*ema2; } break; default : @@ -25641,11 +25825,11 @@ namespace cimg_library_suffixed { cimg_instance, order); } - coefp = (a0+a1)/(1+b1+b2); - coefn = (a2+a3)/(1+b1+b2); + coefp = (a0 + a1)/(1 + b1 + b2); + coefn = (a2 + a3)/(1 + b1 + b2); switch (naxis) { case 'x' : { - const int N = _width; + const int N = width(); const unsigned long off = 1U; #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) @@ -25653,7 +25837,7 @@ namespace cimg_library_suffixed { cimg_forYZC(*this,y,z,c) { T *ptrX = data(0,y,z,c); _cimg_deriche_apply; } } break; case 'y' : { - const int N = _height; + const int N = height(); const unsigned long off = (unsigned long)_width; #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) @@ -25661,7 +25845,7 @@ namespace cimg_library_suffixed { cimg_forXZC(*this,x,z,c) { T *ptrX = data(x,0,z,c); _cimg_deriche_apply; } } break; case 'z' : { - const int N = _depth; + const int N = depth(); const unsigned long off = (unsigned long)_width*_height; #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) @@ -25669,7 +25853,7 @@ namespace cimg_library_suffixed { cimg_forXYC(*this,x,y,c) { T *ptrX = data(x,y,0,c); _cimg_deriche_apply; } } break; default : { - const int N = _spectrum; + const int N = spectrum(); const unsigned long off = (unsigned long)_width*_height*_depth; #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) @@ -25681,91 +25865,154 @@ namespace cimg_library_suffixed { } //! Apply recursive Deriche filter \newinstance. - CImg get_deriche(const float sigma, const int order=0, const char axis='x', + CImg get_deriche(const float sigma, const unsigned int order=0, const char axis='x', const bool boundary_conditions=true) const { return CImg(*this,false).deriche(sigma,order,axis,boundary_conditions); } // [internal] Apply a recursive filter (used by CImg::vanvliet()). - /** + /* \param ptr the pointer of the data - \param filter the coefficient of the filter in the following order [n,n-1,n-2,n-3]. + \param filter the coefficient of the filter in the following order [n,n - 1,n - 2,n - 3]. \param N size of the data \param off the offset between two data point \param order the order of the filter 0 (smoothing), 1st derivtive, 2nd derivative, 3rd derivative \param boundary_conditions Boundary conditions. Can be { 0=dirichlet | 1=neumann }. - \note dirichlet boundary conditions have a strange behavior. And - boundary condition should be corrected using Bill Triggs method (IEEE trans on Sig Proc 2005). - **/ - template - static void _cimg_recursive_apply(T *data, const Tfloat filter[], const int N, const unsigned long off, - const int order, const bool boundary_conditions) { - Tfloat val[K]; // res[n,n-1,n-2,n-3,..] or res[n,n+1,n+2,n+3,..] + \note Boundary condition using B. Triggs method (IEEE trans on Sig Proc 2005). + */ + static void _cimg_recursive_apply(T *data, const double filter[], const int N, const unsigned long off, + const unsigned int order, const bool boundary_conditions) { + double val[4] = { 0 }; // res[n,n - 1,n - 2,n - 3,..] or res[n,n + 1,n + 2,n + 3,..] + const double + sumsq = filter[0], sum = sumsq * sumsq, + a1 = filter[1], a2 = filter[2], a3 = filter[3], + scaleM = 1.0 / ( (1.0 + a1 - a2 + a3) * (1.0 - a1 - a2 - a3) * (1.0 + a2 + (a1 - a3) * a3) ); + double M[9]; // Triggs matrix + M[0] = scaleM * (-a3 * a1 + 1.0 - a3 * a3 - a2); + M[1] = scaleM * (a3 + a1) * (a2 + a3 * a1); + M[2] = scaleM * a3 * (a1 + a3 * a2); + M[3] = scaleM * (a1 + a3 * a2); + M[4] = -scaleM * (a2 - 1.0) * (a2 + a3 * a1); + M[5] = -scaleM * a3 * (a3 * a1 + a3 * a3 + a2 - 1.0); + M[6] = scaleM * (a3 * a1 + a2 + a1 * a1 - a2 * a2); + M[7] = scaleM * (a1 * a2 + a3 * a2 * a2 - a1 * a3 * a3 - a3 * a3 * a3 - a3 * a2 + a3); + M[8] = scaleM * a3 * (a1 + a3 * a2); switch (order) { case 0 : { + const double iplus = (boundary_conditions?data[(N - 1)*off]:0); for (int pass = 0; pass<2; ++pass) { - for (int k = 1; k0; --k) val[k] = val[k-1]; + data -= off; + for (int k = 3; k>0; --k) val[k] = val[k - 1]; } - if (!pass) data-=off; + for (int n = pass; n0; --k) val[k] = val[k - 1]; + } + if (!pass) data -= off; } } break; case 1 : { - Tfloat x[3]; // [front,center,back] + double x[3]; // [front,center,back] for (int pass = 0; pass<2; ++pass) { - for (int k = 0; k<3; ++k) x[k] = (Tfloat)(boundary_conditions?*data:0); - for (int k = 0; k0; --k) val[k] = val[k - 1]; + } + for (int n = pass; n0; --k) x[k] = x[k-1]; - } else data-=off; - for (int k = K-1; k>0; --k) val[k] = val[k-1]; + data += off; + for (int k = 2; k>0; --k) x[k] = x[k - 1]; + } else { data-=off;} + for (int k = 3; k>0; --k) val[k] = val[k - 1]; } *data = (T)0; } } break; case 2: { - Tfloat x[3]; // [front,center,back] + double x[3]; // [front,center,back] for (int pass = 0; pass<2; ++pass) { - for (int k = 0; k<3; ++k) x[k] = (Tfloat)(boundary_conditions?*data:0); - for (int k = 0; k0; --k) val[k] = val[k - 1]; + } + for (int n = pass; n0; --k) x[k] = x[k-1]; - for (int k = K-1; k>0; --k) val[k] = val[k-1]; + if (!pass) data += off; else data -= off; + for (int k = 2; k>0; --k) x[k] = x[k - 1]; + for (int k = 3; k>0; --k) val[k] = val[k - 1]; } *data = (T)0; } } break; case 3: { - Tfloat x[3]; // [front,center,back] + double x[3]; // [front,center,back] for (int pass = 0; pass<2; ++pass) { - for (int k = 0; k<3; ++k) x[k] = (Tfloat)(boundary_conditions?*data:0); - for (int k = 0; k0; --k) x[k] = x[k-1]; - for (int k = K-1; k>0; --k) val[k] = val[k-1]; + data -= off; + for (int k = 3; k>0; --k) val[k] = val[k - 1]; + } + for (int n = pass; n0; --k) x[k] = x[k - 1]; + for (int k = 3; k>0; --k) val[k] = val[k - 1]; } *data = (T)0; } @@ -25781,63 +26028,72 @@ namespace cimg_library_suffixed { \param boundary_conditions Boundary conditions. Can be { 0=dirichlet | 1=neumann }. \note dirichlet boundary condition has a strange behavior - Ian T. Young, Lucas J. van Vliet, Recursive implementation of the - Gaussian filter, Signal Processing, Volume 44, Issue 2, June 1995, - Pages 139-151, + I.T. Young, L.J. van Vliet, M. van Ginkel, Recursive Gabor filtering. + IEEE Trans. Sig. Proc., vol. 50, pp. 2799-2805, 2002. + + (this is an improvement over Young-Van Vliet, Sig. Proc. 44, 1995) + + Boundary conditions (only for order 0) using Triggs matrix, from + B. Triggs and M. Sdika. Boundary conditions for Young-van Vliet + recursive filtering. IEEE Trans. Signal Processing, + vol. 54, pp. 2365-2367, 2006. **/ - CImg& vanvliet(const float sigma, const int order, const char axis='x', const bool boundary_conditions=true) { + CImg& vanvliet(const float sigma, const unsigned int order, const char axis='x', + const bool boundary_conditions=true) { if (is_empty()) return *this; const char naxis = cimg::uncase(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 Tfloat - nnsigma = nsigma<0.1f?0.1f:nsigma, - q = (Tfloat)(nnsigma<2.5?3.97156-4.14554*std::sqrt(1-0.2689*nnsigma):0.98711*nnsigma-0.96330), - b0 = 1.57825f + 2.44413f*q + 1.4281f*q*q + 0.422205f*q*q*q, - b1 = (2.44413f*q + 2.85619f*q*q + 1.26661f*q*q*q), - b2 = -(1.4281f*q*q + 1.26661f*q*q*q), - b3 = 0.422205f*q*q*q, - B = 1.f - (b1 + b2 + b3)/b0; - Tfloat filter[4]; - filter[0] = B; filter[1] = b1/b0; filter[2] = b2/b0; filter[3] = b3/b0; - + if (is_empty() || (nsigma<0.5f && !order)) return *this; + const double + nnsigma = nsigma<0.5f?0.5f:nsigma, + m0 = 1.16680, m1 = 1.10783, m2 = 1.40586, + m1sq = m1 * m1, m2sq = m2 * m2, + q = (nnsigma<3.556?-0.2568 + 0.5784*nnsigma + 0.0561*nnsigma*nnsigma:2.5091 + 0.9804*(nnsigma - 3.556)), + qsq = q * q, + scale = (m0 + q) * (m1sq + m2sq + 2 * m1 * q + qsq), + b1 = -q * (2 * m0 * m1 + m1sq + m2sq + (2 * m0 + 4 * m1) * q + 3 * qsq) / scale, + b2 = qsq * (m0 + 2 * m1 + 3 * q) / scale, + b3 = -qsq * q / scale, + B = ( m0 * (m1sq + m2sq) ) / scale; + double filter[4]; + filter[0] = B; filter[1] = -b1; filter[2] = -b2; filter[3] = -b3; switch (naxis) { case 'x' : { #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) #endif cimg_forYZC(*this,y,z,c) - _cimg_recursive_apply<4>(data(0,y,z,c),filter,_width,1U,order,boundary_conditions); + _cimg_recursive_apply(data(0,y,z,c),filter,_width,1U,order,boundary_conditions); } break; case 'y' : { #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) #endif cimg_forXZC(*this,x,z,c) - _cimg_recursive_apply<4>(data(x,0,z,c),filter,_height,(unsigned long)_width,order,boundary_conditions); + _cimg_recursive_apply(data(x,0,z,c),filter,_height,(unsigned long)_width,order,boundary_conditions); } break; case 'z' : { #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) #endif cimg_forXYC(*this,x,y,c) - _cimg_recursive_apply<4>(data(x,y,0,c),filter,_depth,(unsigned long)(_width*_height), - order,boundary_conditions); + _cimg_recursive_apply(data(x,y,0,c),filter,_depth,(unsigned long)(_width*_height), + order,boundary_conditions); } break; default : { #ifdef cimg_use_openmp #pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) #endif cimg_forXYZ(*this,x,y,z) - _cimg_recursive_apply<4>(data(x,y,z,0),filter,_spectrum,(unsigned long)(_width*_height*_depth), - order,boundary_conditions); + _cimg_recursive_apply(data(x,y,z,0),filter,_spectrum,(unsigned long)(_width*_height*_depth), + order,boundary_conditions); } } return *this; } //! Blur image using Van Vliet recursive Gaussian filter. \newinstance. - CImg get_vanvliet(const float sigma, const int order, const char axis='x', + CImg get_vanvliet(const float sigma, const unsigned int order, const char axis='x', const bool boundary_conditions=true) const { return CImg(*this,false).vanvliet(sigma,order,axis,boundary_conditions); } @@ -25856,16 +26112,15 @@ namespace cimg_library_suffixed { **/ CImg& blur(const float sigma_x, const float sigma_y, const float sigma_z, const bool boundary_conditions=true, const bool is_gaussian=false) { - if (!is_empty()) { - if (is_gaussian) { - if (_width>1) vanvliet(sigma_x,0,'x',boundary_conditions); - if (_height>1) vanvliet(sigma_y,0,'y',boundary_conditions); - if (_depth>1) vanvliet(sigma_z,0,'z',boundary_conditions); - } else { - if (_width>1) deriche(sigma_x,0,'x',boundary_conditions); - if (_height>1) deriche(sigma_y,0,'y',boundary_conditions); - if (_depth>1) deriche(sigma_z,0,'z',boundary_conditions); - } + if (is_empty()) return *this; + if (is_gaussian) { + if (_width>1) vanvliet(sigma_x,0,'x',boundary_conditions); + if (_height>1) vanvliet(sigma_y,0,'y',boundary_conditions); + if (_depth>1) vanvliet(sigma_z,0,'z',boundary_conditions); + } else { + if (_width>1) deriche(sigma_x,0,'x',boundary_conditions); + if (_height>1) deriche(sigma_y,0,'y',boundary_conditions); + if (_depth>1) deriche(sigma_z,0,'z',boundary_conditions); } return *this; } @@ -25982,7 +26237,7 @@ namespace cimg_library_suffixed { u = (float)(a*vx + b*vy + c*vz), v = (float)(b*vx + d*vy + e*vz), w = (float)(c*vx + e*vy + f*vz), - n = (float)std::sqrt(1e-5+u*u+v*v+w*w), + n = (float)std::sqrt(1e-5 + u*u + v*v + w*w), dln = dl/n; *(pd0++) = (Tfloat)(u*dln); *(pd1++) = (Tfloat)(v*dln); @@ -26009,9 +26264,9 @@ namespace cimg_library_suffixed { case 0 : { // Nearest neighbor for (float l = 0; l=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) { const int - cx = (int)(X+0.5f), - cy = (int)(Y+0.5f), - cz = (int)(Z+0.5f); + cx = (int)(X + 0.5f), + cy = (int)(Y + 0.5f), + cz = (int)(Z + 0.5f); const float u = (float)W(cx,cy,cz,0), v = (float)W(cx,cy,cz,1), @@ -26046,9 +26301,9 @@ namespace cimg_library_suffixed { u0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,0)), v0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,1)), w0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,2)), - u = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,0)), - v = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,1)), - w = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,2)); + u = (float)(W._linear_atXYZ(X + u0,Y + v0,Z + w0,0)), + v = (float)(W._linear_atXYZ(X + u0,Y + v0,Z + w0,1)), + w = (float)(W._linear_atXYZ(X + u0,Y + v0,Z + w0,2)); if (is_fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)_linear_atXYZ(X,Y,Z,c); ++S; } else { const float coef = (float)std::exp(-l*l/fsigma2); @@ -26076,7 +26331,7 @@ namespace cimg_library_suffixed { const float u = (float)(a*vx + b*vy), v = (float)(b*vx + c*vy), - n = (float)std::sqrt(1e-5+u*u+v*v), + n = (float)std::sqrt(1e-5 + u*u + v*v), dln = dl/n; *(pd0++) = (Tfloat)(u*dln); *(pd1++) = (Tfloat)(v*dln); @@ -26101,8 +26356,8 @@ namespace cimg_library_suffixed { case 0 : { // Nearest-neighbor for (float l = 0; l=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) { const int - cx = (int)(X+0.5f), - cy = (int)(Y+0.5f); + cx = (int)(X + 0.5f), + cy = (int)(Y + 0.5f); const float u = (float)W(cx,cy,0,0), v = (float)W(cx,cy,0,1); @@ -26134,8 +26389,8 @@ namespace cimg_library_suffixed { const float u0 = (float)(0.5f*W._linear_atXY(X,Y,0,0)), v0 = (float)(0.5f*W._linear_atXY(X,Y,0,1)), - u = (float)(W._linear_atXY(X+u0,Y+v0,0,0)), - v = (float)(W._linear_atXY(X+u0,Y+v0,0,1)); + u = (float)(W._linear_atXY(X + u0,Y + v0,0,0)), + v = (float)(W._linear_atXY(X + u0,Y + v0,0,1)); if (is_fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)_linear_atXY(X,Y,0,c); ++S; } else { const float coef = (float)std::exp(-l*l/fsigma2); @@ -26163,11 +26418,11 @@ namespace cimg_library_suffixed { //! Blur image anisotropically, directed by a field of diffusion tensors \newinstance. template - CImg get_blur_anisotropic(const CImg& G, - const float amplitude=60, const float dl=0.8f, const float da=30, - const float gauss_prec=2, const unsigned int interpolation_type=0, - const bool is_fast_approx=true) const { - return (+*this).blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,is_fast_approx); + CImg get_blur_anisotropic(const CImg& G, + const float amplitude=60, const float dl=0.8f, const float da=30, + const float gauss_prec=2, const unsigned int interpolation_type=0, + const bool is_fast_approx=true) const { + return CImg(*this,false).blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,is_fast_approx); } //! Blur image anisotropically, in an edge-preserving way. @@ -26193,12 +26448,13 @@ namespace cimg_library_suffixed { } //! Blur image anisotropically, in an edge-preserving way \newinstance. - CImg get_blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.6f, - const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, - const float da=30, const float gauss_prec=2, const unsigned int interpolation_type=0, - const bool is_fast_approx=true) const { - return (+*this).blur_anisotropic(amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation_type, - is_fast_approx); + CImg get_blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.6f, + const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, + const float da=30, const float gauss_prec=2, + const unsigned int interpolation_type=0, + const bool is_fast_approx=true) const { + return CImg(*this,false).blur_anisotropic(amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec, + interpolation_type,is_fast_approx); } //! Blur image, with the joint bilateral filter. @@ -26208,47 +26464,57 @@ namespace cimg_library_suffixed { \param sigma_y Amount of blur along the Y-axis. \param sigma_z Amount of blur along the Z-axis. \param sigma_r Amount of blur along the value axis. - \param bgrid_x Size of the bilateral grid along the X-axis. - \param bgrid_y Size of the bilateral grid along the Y-axis. - \param bgrid_z Size of the bilateral grid along the Z-axis. - \param bgrid_r Size of the bilateral grid along the value axis. - \param interpolation_type Use interpolation for image slicing. + \param sampling_x Amount of downsampling along the X-axis used for the approximation. + Defaults (0) to sigma_x. + \param sampling_y Amount of downsampling along the Y-axis used for the approximation. + Defaults (0) to sigma_y. + \param sampling_z Amount of downsampling along the Z-axis used for the approximation. + Defaults (0) to sigma_z. + \param sampling_r Amount of downsampling along the value axis used for the approximation. + Defaults (0) to sigma_r. \note This algorithm uses the optimisation technique proposed by S. Paris and F. Durand, in ECCV'2006 (extended for 3d volumetric images). + It is based on the reference implementation http://people.csail.mit.edu/jiawen/software/bilateralFilter.m **/ template CImg& blur_bilateral(const CImg& guide, - const float sigma_x, const float sigma_y, const float sigma_z, const float sigma_r, - const int bgrid_x, const int bgrid_y, const int bgrid_z, const int bgrid_r, - const bool interpolation_type=true) { + const float sigma_x, const float sigma_y, + const float sigma_z, const float sigma_r, + const float sampling_x, const float sampling_y, + const float sampling_z, const float sampling_r) { if (!is_sameXYZ(guide)) throw CImgArgumentException(_cimg_instance "blur_bilateral(): Invalid size for specified guide image (%u,%u,%u,%u,%p).", cimg_instance, guide._width,guide._height,guide._depth,guide._spectrum,guide._data); if (is_empty()) return *this; - T m, M = guide.max_min(m); - if (m==M) return *this; - const float range = (float)(M - m); - const unsigned int - bx0 = bgrid_x>=0?bgrid_x:_width*-bgrid_x/100, - by0 = bgrid_y>=0?bgrid_y:_height*-bgrid_y/100, - bz0 = bgrid_z>=0?bgrid_z:_depth*-bgrid_z/100, - br0 = bgrid_r>=0?bgrid_r:(int)(-range*bgrid_r/100), - bx = bx0>0?bx0:1, - by = by0>0?by0:1, - bz = bz0>0?bz0:1, - br = br0>0?br0:1; + T edge_min, edge_max = guide.max_min(edge_min); + if (edge_min==edge_max || sigma_r == 0.) return *this; const float + edge_delta = (float)(edge_max - edge_min), _sigma_x = sigma_x>=0?sigma_x:-sigma_x*_width/100, _sigma_y = sigma_y>=0?sigma_y:-sigma_y*_height/100, _sigma_z = sigma_z>=0?sigma_z:-sigma_z*_depth/100, - _sigma_r = sigma_r>=0?sigma_r:-sigma_r*range/100, - nsigma_x = _sigma_x*bx/_width, - nsigma_y = _sigma_y*by/_height, - nsigma_z = _sigma_z*bz/_depth, - nsigma_r = _sigma_r*br/range; - if (nsigma_x>0 || nsigma_y>0 || nsigma_z>0 || nsigma_r>0) { + _sigma_r = sigma_r>=0?sigma_r:-sigma_r*(edge_max-edge_min)/100, + _sampling_x = sampling_x?sampling_x:cimg::max(_sigma_x,1.0f), + _sampling_y = sampling_y?sampling_y:cimg::max(_sigma_y,1.0f), + _sampling_z = sampling_z?sampling_z:cimg::max(_sigma_z,1.0f), + _sampling_r = sampling_r?sampling_r:cimg::max(_sigma_r,edge_delta/256), + derived_sigma_x = _sigma_x / _sampling_x, + derived_sigma_y = _sigma_y / _sampling_y, + derived_sigma_z = _sigma_z / _sampling_z, + derived_sigma_r = _sigma_r / _sampling_r; + const int + padding_x = (int)(2*derived_sigma_x) + 1, + padding_y = (int)(2*derived_sigma_y) + 1, + padding_z = (int)(2*derived_sigma_z) + 1, + padding_r = (int)(2*derived_sigma_r) + 1; + const unsigned int + bx = (unsigned int)((_width - 1)/_sampling_x + 1 + 2*padding_x), + by = (unsigned int)((_height - 1)/_sampling_y + 1 + 2*padding_y), + bz = (unsigned int)((_depth - 1)/_sampling_z + 1 + 2*padding_z), + br = (unsigned int)(edge_delta/_sampling_r + 1 + 2*padding_r); + if (bx>0 || by>0 || bz>0 || br>0) { const bool is_3d = (_depth>1); if (is_3d) { // 3d version of the algorithm CImg bgrid(bx,by,bz,br), bgridw(bx,by,bz,br); @@ -26257,25 +26523,25 @@ namespace cimg_library_suffixed { bgrid.fill(0); bgridw.fill(0); cimg_forXYZ(*this,x,y,z) { const T val = (*this)(x,y,z,c); - const float gval = (float)_guide(x,y,z); - const int X = x*bx/_width, Y = y*by/_height, Z = z*bz/_depth, - R = (int)cimg::min(br-1.0f,(gval-m)*br/range); - bgrid(X,Y,Z,R) += (float)val; - bgridw(X,Y,Z,R) += 1; - } - bgrid.blur(nsigma_x,nsigma_y,nsigma_z,true).deriche(nsigma_r,0,'c',false); - bgridw.blur(nsigma_x,nsigma_y,nsigma_z,true).deriche(nsigma_r,0,'c',false); - if (interpolation_type) cimg_forXYZ(*this,x,y,z) { - const float gval = (float)_guide(x,y,z), - X = (float)x*bx/_width, Y = (float)y*by/_height, Z = (float)z*bz/_depth, - R = (float)cimg::min(br-1.0f,(gval-m)*br/range), - bval0 = bgrid._linear_atXYZC(X,Y,Z,R), bval1 = bgridw._linear_atXYZC(X,Y,Z,R); - (*this)(x,y,z,c) = (T)(bval0/bval1); - } else cimg_forXYZ(*this,x,y,z) { - const float gval = (float)_guide(x,y,z); - const int X = x*bx/_width, Y = y*by/_height, Z = z*bz/_depth, - R = (int)cimg::min(br-1.0f,(gval-m)*br/range); - const float bval0 = bgrid(X,Y,Z,R), bval1 = bgridw(X,Y,Z,R); + const float edge = (float)_guide(x,y,z); + const int + X = (int)cimg::round(x/_sampling_x) + padding_x, + Y = (int)cimg::round(y/_sampling_y) + padding_y, + Z = (int)cimg::round(z/_sampling_z) + padding_z, + R = (int)cimg::round((edge-edge_min)/_sampling_r) + padding_r; + bgrid(X,Y,Z,R)+=(float)val; + bgridw(X,Y,Z,R)+=1; + } + bgrid.blur(derived_sigma_x,derived_sigma_y,derived_sigma_z,true).deriche(derived_sigma_r,0,'c',false); + bgridw.blur(derived_sigma_x,derived_sigma_y,derived_sigma_z,true).deriche(derived_sigma_r,0,'c',false); + cimg_forXYZ(*this,x,y,z) { + const float edge = (float)_guide(x,y,z); + const float + X = x/_sampling_x + padding_x, + Y = y/_sampling_y + padding_y, + Z = z/_sampling_z + padding_z, + R = (edge-edge_min)/_sampling_r + padding_r; + const float bval0 = bgrid.linear_atXYZC(X,Y,Z,R), bval1 = bgridw.linear_atXYZC(X,Y,Z,R); (*this)(x,y,z,c) = (T)(bval0/bval1); } } @@ -26286,21 +26552,22 @@ namespace cimg_library_suffixed { bgrid.fill(0); cimg_forXY(*this,x,y) { const T val = (*this)(x,y,c); - const float gval = (float)_guide(x,y); - const int X = x*bx/_width, Y = y*by/_height, R = (int)cimg::min(br-1.0f,(gval-m)*br/range); - bgrid(X,Y,R,0) += (float)val; - bgrid(X,Y,R,1) += 1; - } - bgrid.blur(nsigma_x,nsigma_y,0,true).blur(0,0,nsigma_r,false); - if (interpolation_type) cimg_forXY(*this,x,y) { - const float gval = (float)_guide(x,y), - X = (float)x*bx/_width, Y = (float)y*by/_height, R = (float)cimg::min(br-1.0f,(gval-m)*br/range), - bval0 = bgrid._linear_atXYZ(X,Y,R,0), bval1 = bgrid._linear_atXYZ(X,Y,R,1); - (*this)(x,y,c) = (T)(bval0/bval1); - } else cimg_forXY(*this,x,y) { - const float gval = (float)_guide(x,y); - const int X = x*bx/_width, Y = y*by/_height, R = (int)cimg::min(br-1.0f,(gval-m)*br/range); - const float bval0 = bgrid(X,Y,R,0), bval1 = bgrid(X,Y,R,1); + const float edge = (float)_guide(x,y); + const int + X = (int)cimg::round(x/_sampling_x) + padding_x, + Y = (int)cimg::round(y/_sampling_y) + padding_y, + R = (int)cimg::round((edge-edge_min)/_sampling_r) + padding_r; + bgrid(X,Y,R,0)+=(float)val; + bgrid(X,Y,R,1)+=1; + } + bgrid.blur(derived_sigma_x,derived_sigma_y,0,true).blur(0,0,derived_sigma_r,false); + cimg_forXY(*this,x,y) { + const float edge = (float)_guide(x,y); + const float + X = x/_sampling_x + padding_x, + Y = y/_sampling_y + padding_y, + R = (edge-edge_min)/_sampling_r + padding_r; + const float bval0 = bgrid.linear_atXYZ(X,Y,R,0), bval1 = bgrid.linear_atXYZ(X,Y,R,1); (*this)(x,y,c) = (T)(bval0/bval1); } } @@ -26311,12 +26578,13 @@ namespace cimg_library_suffixed { //! Blur image, with the joint bilateral filter \newinstance. template - CImg get_blur_bilateral(const CImg& guide, - const float sigma_x, const float sigma_y, const float sigma_z, const float sigma_r, - const int bgrid_x, const int bgrid_y, const int bgrid_z, const int bgrid_r, - const bool interpolation_type=true) const { - return (+*this).blur_bilateral(guide,sigma_x,sigma_y,sigma_z,sigma_r,bgrid_x,bgrid_y,bgrid_z,bgrid_r, - interpolation_type); + CImg get_blur_bilateral(const CImg& guide, + const float sigma_x, const float sigma_y, + const float sigma_z, const float sigma_r, + const float sampling_x, const float sampling_y, + const float sampling_z, const float sampling_r) const { + return CImg(*this,false).blur_bilateral(guide,sigma_x,sigma_y,sigma_z,sigma_r, + sampling_x,sampling_y,sampling_z,sampling_r); } //! Blur image using the joint bilateral filter. @@ -26324,26 +26592,254 @@ namespace cimg_library_suffixed { \param guide Image used to model the smoothing weights. \param sigma_s Amount of blur along the XYZ-axes. \param sigma_r Amount of blur along the value axis. - \param bgrid_s Size of the bilateral grid along the XYZ-axes. - \param bgrid_r Size of the bilateral grid along the value axis. - \param interpolation_type Use interpolation for image slicing. + \param sampling_s Amount of downsampling along the XYZ-axes used for the approximation. Defaults to sigma_s. + \param sampling_r Amount of downsampling along the value axis used for the approximation. Defaults to sigma_r. **/ template CImg& blur_bilateral(const CImg& guide, - const float sigma_s, const float sigma_r, const int bgrid_s=-33, const int bgrid_r=32, - const bool interpolation_type=true) { - const float nsigma_s = sigma_s>=0?sigma_s:-sigma_s*cimg::max(_width,_height,_depth)/100; - return blur_bilateral(guide,nsigma_s,nsigma_s,nsigma_s,sigma_r,bgrid_s,bgrid_s,bgrid_s,bgrid_r, - interpolation_type); + const float sigma_s, const float sigma_r, + const float sampling_s=0, const float sampling_r=0) { + const float _sigma_s = sigma_s>=0?sigma_s:-sigma_s*cimg::max(_width,_height,_depth)/100; + return blur_bilateral(guide,_sigma_s,_sigma_s,_sigma_s,sigma_r,sampling_s,sampling_s,sampling_s,sampling_r); } //! Blur image using the bilateral filter \newinstance. template - CImg get_blur_bilateral(const CImg& guide, - const float sigma_s, const float sigma_r, const int bgrid_s=-33, const int bgrid_r=32, - const bool interpolation_type=true) const { - return (+*this).blur_bilateral(guide,sigma_s,sigma_s,sigma_s,sigma_r,bgrid_s,bgrid_s,bgrid_s,bgrid_r, - interpolation_type); + CImg get_blur_bilateral(const CImg& guide, + const float sigma_s, const float sigma_r, + const float sampling_s=0, const float sampling_r=0) const { + return CImg(*this,false).blur_bilateral(guide,sigma_s,sigma_r,sampling_s,sampling_r); + } + + // [internal] Apply a box filter (used by CImg::boxfilter() and CImg::blur_box()). + /* + \param ptr the pointer of the data + \param N size of the data + \param sigma sigma of the box filter + \param off the offset between two data point + \param order the order of the filter 0 (smoothing), 1st derivtive and 2nd derivative. + \param boundary_conditions Boundary conditions. Can be { 0=dirichlet | 1=neumann }. + */ + static void _cimg_blur_box_apply(T *ptr, const float sigma, const int N, const unsigned long off, + const int order, const bool boundary_conditions) { + // Smooth. + if (sigma>1) { + const int w2 = (int)(sigma - 1)/2; + const unsigned int winsize = 2*w2 + 1U; + const double frac = (sigma - winsize)/2.0; + CImg win(winsize); + Tfloat 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; + Tfloat + 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/sigma); + 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/sigma); + } + + // 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) return boundary_conditions?ptr[(N - 1)*off]:T(); + return ptr[x*off]; + } + + // Apply box filter of order 0,1,2. + /** + \param sigma sigma of the box filter + \param order the order of the filter 0,1 or 2. + \param axis Axis along which the filter is computed. Can be { 'x' | 'y' | 'z' | 'c' }. + \param boundary_conditions Boundary conditions. Can be { 0=dirichlet | 1=neumann }. + **/ + CImg& boxfilter(const float sigma, const int order, const char axis='x', + const bool boundary_conditions=true) { + if (is_empty() || !sigma || (sigma<=1 && !order)) return *this; + const char naxis = cimg::uncase(axis); + const float nsigma = sigma>=0?sigma:-sigma*(naxis=='x'?_width:naxis=='y'?_height:naxis=='z'?_depth:_spectrum)/100; + switch (naxis) { + case 'x' : { +#ifdef cimg_use_openmp +#pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) +#endif + cimg_forYZC(*this,y,z,c) + _cimg_blur_box_apply(data(0,y,z,c),nsigma,_width,1U,order,boundary_conditions); + } break; + case 'y' : { +#ifdef cimg_use_openmp +#pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) +#endif + cimg_forXZC(*this,x,z,c) + _cimg_blur_box_apply(data(x,0,z,c),nsigma,_height,(unsigned long)_width,order,boundary_conditions); + } break; + case 'z' : { +#ifdef cimg_use_openmp +#pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) +#endif + cimg_forXYC(*this,x,y,c) + _cimg_blur_box_apply(data(x,y,0,c),nsigma,_depth,(unsigned long)(_width*_height),order,boundary_conditions); + } break; + default : { +#ifdef cimg_use_openmp +#pragma omp parallel for collapse(3) if (_width>=256 && _height*_depth*_spectrum>=16) +#endif + cimg_forXYZ(*this,x,y,z) + _cimg_blur_box_apply(data(x,y,z,0),nsigma,_spectrum,(unsigned long)(_width*_height*_depth), + order,boundary_conditions); + } + } + return *this; + } + + // Apply box filter of order 0,1 or 2 \newinstance. + CImg get_boxfilter(const float sigma, const int order, const char axis='x', + const bool boundary_conditions=true) const { + return CImg(*this,false).boxfilter(sigma,order,axis,boundary_conditions); + } + + //! Blur image with a box filter. + /** + \param sigma_x Size of the box window, along the X-axis. + \param sigma_y Size of the box window, along the Y-axis. + \param sigma_z Size of the box window, along the Z-axis. + \param boundary_conditions Boundary conditions. Can be { false=dirichlet | true=neumann }. + \note + - This is a recursive algorithm, not depending on the values of the box kernel size. + \see blur(). + **/ + CImg& blur_box(const float sigma_x, const float sigma_y, const float sigma_z, + const bool boundary_conditions=true) { + if (is_empty()) return *this; + if (_width>1) boxfilter(sigma_x,0,'x',boundary_conditions); + if (_height>1) boxfilter(sigma_y,0,'y',boundary_conditions); + if (_depth>1) boxfilter(sigma_z,0,'z',boundary_conditions); + return *this; + } + + //! Blur image with a box filter \newinstance. + CImg get_blur_box(const float sigma_x, const float sigma_y, const float sigma_z, + const bool boundary_conditions=true) const { + return CImg(*this,false).blur_box(sigma_x,sigma_y,sigma_z,boundary_conditions); + } + + //! Blur image with a box filter. + /** + \param sigma Size of the box window. + \param boundary_conditions Boundary conditions. Can be { 0=dirichlet | 1=neumann }.a + \see deriche(), vanvliet(). + **/ + CImg& blur_box(const float sigma, const bool boundary_conditions=true) { + const float nsigma = sigma>=0?sigma:-sigma*cimg::max(_width,_height,_depth)/100; + return blur_box(nsigma,nsigma,nsigma,boundary_conditions); + } + + //! Blur image with a box filter \newinstance. + CImg get_blur_box(const float sigma, const bool boundary_conditions=true) const { + return CImg(*this,false).blur_box(sigma,boundary_conditions); + } + + //! Blur image, with the image guided filter. + /** + \param guide Image used to guide the smoothing process. + \param radius Spatial radius. + \param regularization Regularization parameter. + + \note This method implements the filtering algorithm described in: + He, Kaiming; Sun, Jian; Tang, Xiaoou, "Guided Image Filtering," Pattern Analysis and Machine Intelligence, + IEEE Transactions on , vol.35, no.6, pp.1397,1409, June 2013 + **/ + template + CImg& blur_guided(const CImg& guide, const float radius, const float regularization) { + return get_blur_guided(guide,radius,regularization).move_to(*this); + } + + //! Blur image, with the image guided filter \newinstance. + template + CImg get_blur_guided(const CImg& guide, const float radius, const float regularization) const { + if (!is_sameXYZ(guide)) + throw CImgArgumentException(_cimg_instance + "blur_guided(): Invalid size for specified guide image (%u,%u,%u,%u,%p).", + cimg_instance, + guide._width,guide._height,guide._depth,guide._spectrum,guide._data); + if (is_empty() || !radius) return *this; + const int _radius = radius>=0?(int)radius:(int)(-radius*cimg::max(_width,_height,_depth)/100); + const unsigned int psize = (unsigned int)(1 + 2*_radius); + const CImg N = CImg(_width,_height,_depth,1,1)._blur_guided(psize); + CImg + mean_I = CImg(guide,false)._blur_guided(psize).div(N), + mean_p = CImg(*this,false)._blur_guided(psize).div(N), + cov_Ip = CImg(*this,false).mul(guide)._blur_guided(psize).div(N)-=mean_p.get_mul(mean_I), + var_I = CImg(guide,false).sqr()._blur_guided(psize).div(N)-=mean_I.get_sqr(), + &a = cov_Ip.div(var_I+=regularization), + &b = mean_p-=a.get_mul(mean_I); + a._blur_guided(psize).div(N); + b._blur_guided(psize).div(N); + return a.mul(guide)+=b; + } + + // [internal] Perform box filter with dirichlet boundary conditions. + CImg& _blur_guided(const unsigned int psize) { + const int p1 = (int)psize/2, p2 = (int)psize - p1; + if (_depth!=1) { + CImg cumul = get_cumulate('z'), cumul2 = cumul.get_shift(0,0,p2,0,1); + (cumul.shift(0,0,-p1,0,1)-=cumul2).move_to(*this); + } + if (_height!=1) { + CImg cumul = get_cumulate('y'), cumul2 = cumul.get_shift(0,p2,0,0,1); + (cumul.shift(0,-p1,0,0,1)-=cumul2).move_to(*this); + } + if (_width!=1) { + CImg cumul = get_cumulate('x'), cumul2 = cumul.get_shift(p2,0,0,0,1); + (cumul.shift(-p1,0,0,0,1)-=cumul2).move_to(*this); + } + return *this; } //! Blur image using patch-based space. @@ -26362,9 +26858,9 @@ namespace cimg_library_suffixed { } //! Blur image using patch-based space \newinstance. - CImg get_blur_patch(const float sigma_s, const float sigma_p, const unsigned int patch_size=3, - const unsigned int lookup_size=4, const float smoothness=0, - const bool is_fast_approx=true) const { + CImg get_blur_patch(const float sigma_s, const float sigma_p, const unsigned int patch_size=3, + const unsigned int lookup_size=4, const float smoothness=0, + const bool is_fast_approx=true) const { #define _cimg_blur_patch3d_fast(N) \ cimg_for##N##XYZ(res,x,y,z) { \ @@ -26581,7 +27077,7 @@ namespace cimg_library_suffixed { CImg res(_width,_height,_depth,_spectrum); T *ptrd = res._data; cimg::unused(ptrd); - const int hl = n/2, hr = hl - 1 + n%2; + const int hl = (int)n/2, hr = hl - 1 + (int)n%2; if (res._depth!=1) { // 3d if (threshold>0) #ifdef cimg_use_openmp @@ -26589,16 +27085,16 @@ namespace cimg_library_suffixed { #endif cimg_forXYZC(*this,x,y,z,c) { // With threshold. const int - x0 = x - hl, y0 = y - hl, z0 = z-hl, x1 = x + hr, y1 = y + hr, z1 = z+hr, + x0 = x - hl, y0 = y - hl, z0 = z - hl, x1 = x + hr, y1 = y + hr, z1 = z + hr, nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, nz0 = z0<0?0:z0, - nx1 = x1>=width()?width()-1:x1, ny1 = y1>=height()?height()-1:y1, nz1 = z1>=depth()?depth()-1:z1; + nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1, nz1 = z1>=depth()?depth() - 1:z1; const float val0 = (float)(*this)(x,y,z,c); CImg values(n*n*n); unsigned int nb_values = 0; T *ptrd = values.data(); cimg_for_inXYZ(*this,nx0,ny0,nz0,nx1,ny1,nz1,p,q,r) if (cimg::abs((float)(*this)(p,q,r,c)-val0)<=threshold) { *(ptrd++) = (*this)(p,q,r,c); ++nb_values; } - res(x,y,z,c) = values.get_shared_points(0,nb_values-1).median(); + res(x,y,z,c) = values.get_shared_points(0,nb_values - 1).median(); } else #ifdef cimg_use_openmp @@ -26606,9 +27102,9 @@ namespace cimg_library_suffixed { #endif cimg_forXYZC(*this,x,y,z,c) { // Without threshold. const int - x0 = x - hl, y0 = y - hl, z0 = z-hl, x1 = x + hr, y1 = y + hr, z1 = z+hr, + x0 = x - hl, y0 = y - hl, z0 = z - hl, x1 = x + hr, y1 = y + hr, z1 = z + hr, nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, nz0 = z0<0?0:z0, - nx1 = x1>=width()?width()-1:x1, ny1 = y1>=height()?height()-1:y1, nz1 = z1>=depth()?depth()-1:z1; + nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1, nz1 = z1>=depth()?depth() - 1:z1; res(x,y,z,c) = get_crop(nx0,ny0,nz0,c,nx1,ny1,nz1,c).median(); } } else { @@ -26622,14 +27118,14 @@ namespace cimg_library_suffixed { const int x0 = x - hl, y0 = y - hl, x1 = x + hr, y1 = y + hr, nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, - nx1 = x1>=width()?width()-1:x1, ny1 = y1>=height()?height()-1:y1; + nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1; const float val0 = (float)(*this)(x,y,c); CImg values(n*n); unsigned int nb_values = 0; T *ptrd = values.data(); cimg_for_inXY(*this,nx0,ny0,nx1,ny1,p,q) if (cimg::abs((float)(*this)(p,q,c)-val0)<=threshold) { *(ptrd++) = (*this)(p,q,c); ++nb_values; } - res(x,y,c) = values.get_shared_points(0,nb_values-1).median(); + res(x,y,c) = values.get_shared_points(0,nb_values - 1).median(); } else switch (n) { // Without threshold. case 3 : { @@ -26706,7 +27202,7 @@ namespace cimg_library_suffixed { const int x0 = x - hl, y0 = y - hl, x1 = x + hr, y1 = y + hr, nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, - nx1 = x1>=width()?width()-1:x1, ny1 = y1>=height()?height()-1:y1; + nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1; res(x,y,c) = get_crop(nx0,ny0,0,c,nx1,ny1,0,c).median(); } } @@ -26720,14 +27216,14 @@ namespace cimg_library_suffixed { cimg_forXC(*this,x,c) { // With threshold. const int x0 = x - hl, x1 = x + hr, - nx0 = x0<0?0:x0, nx1 = x1>=width()?width()-1:x1; + nx0 = x0<0?0:x0, nx1 = x1>=width()?width() - 1:x1; const float val0 = (float)(*this)(x,c); CImg values(n); unsigned int nb_values = 0; T *ptrd = values.data(); cimg_for_inX(*this,nx0,nx1,p) if (cimg::abs((float)(*this)(p,c)-val0)<=threshold) { *(ptrd++) = (*this)(p,c); ++nb_values; } - res(x,c) = values.get_shared_points(0,nb_values-1).median(); + res(x,c) = values.get_shared_points(0,nb_values - 1).median(); } else switch (n) { // Without threshold. case 2 : { @@ -26736,7 +27232,7 @@ namespace cimg_library_suffixed { #endif cimg_forC(*this,c) { T I[4] = { 0 }; - cimg_for2x2(*this,x,y,0,c,I,T) res(x,c) = (T)(0.5f*(I[0]+I[1])); + cimg_for2x2(*this,x,y,0,c,I,T) res(x,c) = (T)(0.5f*(I[0] + I[1])); } } break; case 3 : { @@ -26756,7 +27252,7 @@ namespace cimg_library_suffixed { cimg_forXC(*this,x,c) { const int x0 = x - hl, x1 = x + hr, - nx0 = x0<0?0:x0, nx1 = x1>=width()?width()-1:x1; + nx0 = x0<0?0:x0, nx1 = x1>=width()?width() - 1:x1; res(x,c) = get_crop(nx0,0,0,c,nx1,0,0,c).median(); } } @@ -26800,7 +27296,7 @@ namespace cimg_library_suffixed { *(ptrG0++) = vec(0,0); *(ptrG1++) = vec(0,1); *(ptrG2++) = vec(0,2); - *(ptrG3++) = 1 - (Tfloat)std::pow(1+val[0]+val[1]+val[2],-(Tfloat)nedge); + *(ptrG3++) = 1 - (Tfloat)std::pow(1 + val[0] + val[1] + val[2],-(Tfloat)nedge); } } #ifdef cimg_use_openmp @@ -27053,7 +27549,7 @@ namespace cimg_library_suffixed { const unsigned long off = c*_width*_height*_depth + z*_width*_height; Tfloat *ptrd0 = grad[0]._data + off, *ptrd1 = grad[1]._data + off; CImg_3x3(I,Tfloat); - const Tfloat a = (Tfloat)(0.25f*(2-std::sqrt(2.0f))), b = (Tfloat)(0.5f*(std::sqrt(2.0f)-1)); + const Tfloat a = (Tfloat)(0.25f*(2-std::sqrt(2.0f))), b = (Tfloat)(0.5f*(std::sqrt(2.0f) - 1)); cimg_for3x3(*this,x,y,z,c,I,Tfloat) { *(ptrd0++) = -a*Ipp - b*Ipc - a*Ipn + a*Inp + b*Inc + a*Inn; *(ptrd1++) = -a*Ipp - b*Icp - a*Inp + a*Ipn + b*Icn + a*Inn; @@ -27105,7 +27601,7 @@ namespace cimg_library_suffixed { CImgList 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 = std::strlen(naxes); + const unsigned int lmax = (unsigned int)std::strlen(naxes); if (lmax%2) throw CImgArgumentException(_cimg_instance "get_hessian(): Invalid specified axes '%s'.", @@ -27425,7 +27921,7 @@ namespace cimg_library_suffixed { const float nsharpness = cimg::max(sharpness,1e-5f), power1 = (is_sqrt?0.5f:1)*nsharpness, - power2 = power1/(1e-7f+1-anisotropy); + power2 = power1/(1e-7f + 1 - anisotropy); blur(alpha).normalize(0,(T)255); if (_depth>1) { // 3d @@ -27446,8 +27942,8 @@ namespace cimg_library_suffixed { ux = vec(0,0), uy = vec(0,1), uz = vec(0,2), vx = vec(1,0), vy = vec(1,1), vz = vec(1,2), wx = vec(2,0), wy = vec(2,1), wz = vec(2,2), - n1 = (float)std::pow(1+l1+l2+l3,-power1), - n2 = (float)std::pow(1+l1+l2+l3,-power2); + n1 = (float)std::pow(1 + l1 + l2 + l3,-power1), + n2 = (float)std::pow(1 + l1 + l2 + l3,-power2); *(ptrd0++) = n1*(ux*ux + vx*vx) + n2*wx*wx; *(ptrd1++) = n1*(ux*uy + vx*vy) + n2*wx*wy; *(ptrd2++) = n1*(ux*uz + vx*vz) + n2*wx*wz; @@ -27471,8 +27967,8 @@ namespace cimg_library_suffixed { l1 = _l1>0?_l1:0, l2 = _l2>0?_l2:0, ux = vec(1,0), uy = vec(1,1), vx = vec(0,0), vy = vec(0,1), - n1 = (float)std::pow(1+l1+l2,-power1), - n2 = (float)std::pow(1+l1+l2,-power2); + n1 = (float)std::pow(1 + l1 + l2,-power1), + n2 = (float)std::pow(1 + l1 + l2,-power2); *(ptrd0++) = n1*ux*ux + n2*vx*vx; *(ptrd1++) = n1*ux*uy + n2*vx*vy; *(ptrd2++) = n1*uy*uy + n2*vy*vy; @@ -27495,19 +27991,24 @@ namespace cimg_library_suffixed { \param precision Precision required for algorithm convergence. \param nb_scales Number of scales used to estimate the displacement field. \param iteration_max Maximum number of iterations allowed for one scale. - \param is_backward If false, match I2(X+U(X)) = I1(X), else match I2(X) = I1(X-U(X)). + \param is_backward If false, match I2(X + U(X)) = I1(X), else match I2(X) = I1(X - U(X)). + \param constraints A list of constrained pixels (as a Nx4 or Nx6 image), i.e defining N points + of the estimated flow having a known value. **/ CImg& displacement(const CImg& source, const float smoothness=0.1f, const float precision=5.0f, const unsigned int nb_scales=0, const unsigned int iteration_max=10000, - const bool is_backward=false) { - return get_displacement(source,smoothness,precision,nb_scales,iteration_max,is_backward).move_to(*this); + const bool is_backward=false, + const CImg& constraints=CImg::empty()) { + return get_displacement(source,smoothness,precision,nb_scales,iteration_max,is_backward,constraints). + move_to(*this); } //! Estimate displacement field between two images \newinstance. - CImg get_displacement(const CImg& source, + CImg get_displacement(const CImg& source, const float smoothness=0.1f, const float precision=5.0f, const unsigned int nb_scales=0, const unsigned int iteration_max=10000, - const bool is_backward=false) const { + const bool is_backward=false, + const CImg& constraints=CImg::empty()) const { if (is_empty() || !source) return +*this; if (!is_sameXYZC(source)) throw CImgArgumentException(_cimg_instance @@ -27521,15 +28022,26 @@ namespace cimg_library_suffixed { "(should be >=0)", cimg_instance, precision); - const unsigned int _nb_scales = nb_scales>0?nb_scales: - (unsigned int)(2*std::log((double)(cimg::max(_width,_height)))); + const bool is_3d = source._depth>1; + const unsigned int + mins = is_3d?cimg::min(_width,_height,_depth):cimg::min(_width,_height), + _nb_scales = nb_scales>0?nb_scales: + (unsigned int)cimg::round(std::log(mins/8.0)/std::log(1.5),1,1); + const float _precision = (float)std::pow(10.0,-(double)precision); float sm, sM = source.max_min(sm), tm, tM = max_min(tm); const float sdelta = sm==sM?1:(sM - sm), tdelta = tm==tM?1:(tM - tm); - const bool is_3d = source._depth>1; - CImg U; - for (int scale = _nb_scales-1; scale>=0; --scale) { + if (constraints && (constraints.height()!=4 || is_3d) && (constraints.height()!=6 || !is_3d)) + throw CImgArgumentException(_cimg_instance + "displacement(): Invalid specified constraints image (%u,%u,%u,%u,%p) " + " (should be a Nx4 or Nx6 image).", + cimg_instance, + constraints._width,constraints._height,constraints._depth,constraints._spectrum, + constraints._data); + CImg U; + floatT bound = 0; + for (int scale = (int)_nb_scales - 1; scale>=0; --scale) { const float factor = (float)std::pow(1.5,(double)scale); const unsigned int _sw = (unsigned int)(_width/factor), sw = _sw?_sw:1, @@ -27541,122 +28053,247 @@ namespace cimg_library_suffixed { I2 = (get_resize(I1,2)-=tm)/=tdelta; if (U) (U*=1.5f).resize(I2._width,I2._height,I2._depth,-100,3); else U.assign(I2._width,I2._height,I2._depth,is_3d?3:2,0); + if (constraints) { + if (is_3d) cimg_forX(constraints,k) { + const int + cx = (int)(constraints(k,0)*U.width()/width()), + cy = (int)(constraints(k,1)*U.height()/height()), + cz = (int)(constraints(k,2)*U.depth()/depth()); + if (U.contains(U(cx,cy,cz))) { + U(cx,cy,cz,0) = (float)(constraints(k,3)/factor); + U(cx,cy,cz,1) = (float)(constraints(k,4)/factor); + U(cx,cy,cz,2) = (float)(constraints(k,5)/factor); + } + } + else cimg_forX(constraints,k) { + const int + cx = (int)(constraints(k,0)*U.width()/width()), + cy = (int)(constraints(k,1)*U.height()/height()); + if (U.contains(U(cx,cy))) { + U(cx,cy,0) = (float)(constraints(k,2)/factor); + U(cx,cy,1) = (float)(constraints(k,3)/factor); + } + } + } + float dt = 2, energy = cimg::type::max(); const CImgList dI = is_backward?I1.get_gradient():I2.get_gradient(); for (unsigned int iteration = 0; iteration=0) cimg_for3XYZ(U,x,y,z) { // Isotropic regularization. - const float - X = is_backward?x - U(x,y,z,0):x + U(x,y,z,0), - Y = is_backward?y - U(x,y,z,1):y + U(x,y,z,1), - Z = is_backward?z - U(x,y,z,2):z + U(x,y,z,2); - float delta_I = 0, _energy_regul = 0; - if (is_backward) cimg_forC(I2,c) delta_I+=(float)(I1.linear_atXYZ(X,Y,Z,c) - I2(x,y,z,c)); - else cimg_forC(I2,c) delta_I+=(float)(I1(x,y,z,c) - I2.linear_atXYZ(X,Y,Z,c)); - cimg_forC(U,c) { + if (smoothness>=0) // Isotropic regularization. +#ifdef cimg_use_openmp +#pragma omp parallel for collapse(2) if (_height*_depth>=8 && _width>=16) reduction(+:_energy) +#endif + cimg_forYZ(U,y,z) { + const int + _p1y = y?y - 1:0, _n1y = yx) U(x,y,z,0) = (float)x; + if (U(x,y,z,1)>y) U(x,y,z,1) = (float)y; + if (U(x,y,z,2)>z) U(x,y,z,2) = (float)z; + bound = (float)x - _width; if (U(x,y,z,0)<=bound) U(x,y,z,0) = bound; + bound = (float)y - _height; if (U(x,y,z,1)<=bound) U(x,y,z,1) = bound; + bound = (float)z - _depth; if (U(x,y,z,2)<=bound) U(x,y,z,2) = bound; + } else { + if (U(x,y,z,0)<-x) U(x,y,z,0) = -(float)x; + if (U(x,y,z,1)<-y) U(x,y,z,1) = -(float)y; + if (U(x,y,z,2)<-z) U(x,y,z,2) = -(float)z; + bound = (float)_width - x; if (U(x,y,z,0)>=bound) U(x,y,z,0) = bound; + bound = (float)_height - y; if (U(x,y,z,1)>=bound) U(x,y,z,1) = bound; + bound = (float)_depth - z; if (U(x,y,z,2)>=bound) U(x,y,z,2) = bound; + } + _energy+=delta_I*delta_I + smoothness*_energy_regul; } - _energy+=delta_I*delta_I + smoothness*_energy_regul; - } else { + } else { // Anisotropic regularization. const float nsmoothness = -smoothness; - cimg_for3XYZ(U,x,y,z) { // Anisotropic regularization. - const float - X = is_backward?x - U(x,y,z,0):x + U(x,y,z,0), - Y = is_backward?y - U(x,y,z,1):y + U(x,y,z,1), - Z = is_backward?z - U(x,y,z,2):z + U(x,y,z,2); - float delta_I = 0, _energy_regul = 0; - if (is_backward) cimg_forC(I2,c) delta_I+=(float)(I1.linear_atXYZ(X,Y,Z,c) - I2(x,y,z,c)); - else cimg_forC(I2,c) delta_I+=(float)(I1(x,y,z,c) - I2.linear_atXYZ(X,Y,Z,c)); - cimg_forC(U,c) { +#ifdef cimg_use_openmp +#pragma omp parallel for collapse(2) if (_height*_depth>=8 && _width>=16) reduction(+:_energy) +#endif + cimg_forYZ(U,y,z) { + const int + _p1y = y?y - 1:0, _n1y = yx) U(x,y,z,0) = (float)x; + if (U(x,y,z,1)>y) U(x,y,z,1) = (float)y; + if (U(x,y,z,2)>z) U(x,y,z,2) = (float)z; + bound = (float)x - _width; if (U(x,y,z,0)<=bound) U(x,y,z,0) = bound; + bound = (float)y - _height; if (U(x,y,z,1)<=bound) U(x,y,z,1) = bound; + bound = (float)z - _depth; if (U(x,y,z,2)<=bound) U(x,y,z,2) = bound; + } else { + if (U(x,y,z,0)<-x) U(x,y,z,0) = -(float)x; + if (U(x,y,z,1)<-y) U(x,y,z,1) = -(float)y; + if (U(x,y,z,2)<-z) U(x,y,z,2) = -(float)z; + bound = (float)_width - x; if (U(x,y,z,0)>=bound) U(x,y,z,0) = bound; + bound = (float)_height - y; if (U(x,y,z,1)>=bound) U(x,y,z,1) = bound; + bound = (float)_depth - z; if (U(x,y,z,2)>=bound) U(x,y,z,2) = bound; + } + _energy+=delta_I*delta_I + nsmoothness*_energy_regul; } - _energy+=delta_I*delta_I + nsmoothness*_energy_regul; } } + if (constraints) cimg_forX(constraints,k) { + const int + cx = (int)(constraints(k,0)*U.width()/width()), + cy = (int)(constraints(k,1)*U.height()/height()), + cz = (int)(constraints(k,2)*U.depth()/depth()); + if (U.contains(U(cx,cy,cz))) { + U(cx,cy,cz,0) = (float)(constraints(k,3)/factor); + U(cx,cy,cz,1) = (float)(constraints(k,4)/factor); + U(cx,cy,cz,2) = (float)(constraints(k,5)/factor); + } + } } else { // 2d version. - if (smoothness>=0) cimg_for3XY(U,x,y) { // Isotropic regularization. - const float - X = is_backward?x - U(x,y,0):x + U(x,y,0), - Y = is_backward?y - U(x,y,1):y + U(x,y,1); - float delta_I = 0, _energy_regul = 0; - if (is_backward) cimg_forC(I2,c) delta_I+=(float)(I1.linear_atXY(X,Y,c) - I2(x,y,c)); - else cimg_forC(I2,c) delta_I+=(float)(I1(x,y,c) - I2.linear_atXY(X,Y,c)); - cimg_forC(U,c) { + if (smoothness>=0) // Isotropic regularization. +#ifdef cimg_use_openmp +#pragma omp parallel for if (_height>=8 && _width>=16) reduction(+:_energy) +#endif + cimg_forY(U,y) { + const int _p1y = y?y - 1:0, _n1y = yx) U(x,y,0) = (float)x; + if (U(x,y,1)>y) U(x,y,1) = (float)y; + bound = (float)x - _width; if (U(x,y,0)<=bound) U(x,y,0) = bound; + bound = (float)y - _height; if (U(x,y,1)<=bound) U(x,y,1) = bound; + } else { + if (U(x,y,0)<-x) U(x,y,0) = -(float)x; + if (U(x,y,1)<-y) U(x,y,1) = -(float)y; + bound = (float)_width - x; if (U(x,y,0)>=bound) U(x,y,0) = bound; + bound = (float)_height - y; if (U(x,y,1)>=bound) U(x,y,1) = bound; + } + _energy+=delta_I*delta_I + smoothness*_energy_regul; } - _energy+=delta_I*delta_I + smoothness*_energy_regul; - } else { + } else { // Anisotropic regularization. const float nsmoothness = -smoothness; - cimg_for3XY(U,x,y) { // Anisotropic regularization. - const float - X = is_backward?x - U(x,y,0):x + U(x,y,0), - Y = is_backward?y - U(x,y,1):y + U(x,y,1); - float delta_I = 0, _energy_regul = 0; - if (is_backward) cimg_forC(I2,c) delta_I+=(float)(I1.linear_atXY(X,Y,c) - I2(x,y,c)); - else cimg_forC(I2,c) delta_I+=(float)(I1(x,y,c) - I2.linear_atXY(X,Y,c)); - cimg_forC(U,c) { +#ifdef cimg_use_openmp +#pragma omp parallel for if (_height>=8 && _width>=16) reduction(+:_energy) +#endif + cimg_forY(U,y) { + const int _p1y = y?y - 1:0, _n1y = yx) U(x,y,0) = (float)x; + if (U(x,y,1)>y) U(x,y,1) = (float)y; + bound = (float)x - _width; if (U(x,y,0)<=bound) U(x,y,0) = bound; + bound = (float)y - _height; if (U(x,y,1)<=bound) U(x,y,1) = bound; + } else { + if (U(x,y,0)<-x) U(x,y,0) = -(float)x; + if (U(x,y,1)<-y) U(x,y,1) = -(float)y; + bound = (float)_width - x; if (U(x,y,0)>=bound) U(x,y,0) = bound; + bound = (float)_height - y; if (U(x,y,1)>=bound) U(x,y,1) = bound; + } + _energy+=delta_I*delta_I + nsmoothness*_energy_regul; } - _energy+=delta_I*delta_I + nsmoothness*_energy_regul; } } + if (constraints) cimg_forX(constraints,k) { + const int + cx = (int)(constraints(k,0)*U.width()/width()), + cy = (int)(constraints(k,1)*U.height()/height()); + if (U.contains(U(cx,cy))) { + U(cx,cy,0) = (float)(constraints(k,2)/factor); + U(cx,cy,1) = (float)(constraints(k,3)/factor); + } + } } const float d_energy = (_energy - energy)/(sw*sh*sd); if (d_energy<=0 && -d_energy<_precision) break; @@ -27679,10 +28316,13 @@ namespace cimg_library_suffixed { J. Goutsias, L. Vincent, and D.S. Bloomberg (eds.), Kluwer, 2000, pp. 331-340.' The submitted code has then been modified to fit CImg coding style and constraints. **/ - CImg& distance(const T value, const unsigned int metric=2) { + CImg& distance(const T& value, const unsigned int metric=2) { if (is_empty()) return *this; + if (cimg::type::string()!=cimg::type::string()) // For datatype < int. + return CImg(*this,false).distance((Tint)value,metric). + cut((Tint)cimg::type::min(),(Tint)cimg::type::max()).move_to(*this); bool is_value = false; - cimg_for(*this,ptr,T) *ptr = *ptr==value?is_value=true,0:(T)999999999; + cimg_for(*this,ptr,T) *ptr = *ptr==value?is_value=true,0:(T)cimg::max(0,99999999); // Trick to avoid VC++ warning if (!is_value) return fill(cimg::type::max()); switch (metric) { case 0 : return _distance_core(_distance_sep_cdt,_distance_dist_cdt); // Chebyshev. @@ -27694,34 +28334,34 @@ namespace cimg_library_suffixed { } //! Compute distance to a specified value \newinstance. - CImg get_distance(const T value, const unsigned int metric=2) const { + CImg get_distance(const T& value, const unsigned int metric=2) const { return CImg(*this,false).distance((Tfloat)value,metric); } static long _distance_sep_edt(const long i, const long u, const long *const g) { - return (u*u-i*i+g[u]-g[i])/(2*(u-i)); + return (u*u - i*i + g[u] - g[i])/(2*(u - i)); } static long _distance_dist_edt(const long x, const long i, const long *const g) { - return (x-i)*(x-i) + g[i]; + return (x - i)*(x - i) + g[i]; } static long _distance_sep_mdt(const long i, const long u, const long *const g) { - return (u-i<=g[u]-g[i]?999999999:(g[u]-g[i]+u+i)/2); + return (u - i<=g[u] - g[i]?999999999:(g[u] - g[i] + u + i)/2); } static long _distance_dist_mdt(const long x, const long i, const long *const g) { - return (x=0; --u) { dt[u] = f(u,s[q],g); if (u==t[q]) --q; } // Backward scan. + for (int u = (int)len - 1; u>=0; --u) { dt[u] = f(u,s[q],g); if (u==t[q]) --q; } // Backward scan. } CImg& _distance_core(long (*const sep)(const long, const long, const long *const), long (*const f)(const long, const long, const long *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 unsigned long wh = (unsigned long)_width*_height; -#ifdef cimg_use_openmp +#if defined(cimg_use_openmp) && !cimg_is_gcc49x #pragma omp parallel for if (_spectrum>=2) #endif cimg_forC(*this,c) { CImg g(_width), dt(_width), s(_width), t(_width); CImg img = get_shared_channel(c); -#ifdef cimg_use_openmp +#if defined(cimg_use_openmp) && !cimg_is_gcc49x #pragma omp parallel for collapse(2) if (_width>=512 && _height*_depth>=16) firstprivate(g,dt,s,t) #endif cimg_forYZ(*this,y,z) { // Over X-direction. @@ -27760,7 +28403,7 @@ namespace cimg_library_suffixed { } if (_height>1) { g.assign(_height); dt.assign(_height); s.assign(_height); t.assign(_height); -#ifdef cimg_use_openmp +#if defined(cimg_use_openmp) && !cimg_is_gcc49x #pragma omp parallel for collapse(2) if (_height>=512 && _width*_depth>=16) firstprivate(g,dt,s,t) #endif cimg_forXZ(*this,x,z) { // Over Y-direction. @@ -27771,7 +28414,7 @@ namespace cimg_library_suffixed { } if (_depth>1) { g.assign(_depth); dt.assign(_depth); s.assign(_depth); t.assign(_depth); -#ifdef cimg_use_openmp +#if defined(cimg_use_openmp) && !cimg_is_gcc49x #pragma omp parallel for collapse(2) if (_depth>=512 && _width*_height>=16) firstprivate(g,dt,s,t) #endif cimg_forXY(*this,x,y) { // Over Z-direction. @@ -27791,7 +28434,7 @@ namespace cimg_library_suffixed { \note The algorithm code has been initially proposed by A. Meijster, and modified by D. Tschumperlé. **/ template - CImg& distance(const T value, const CImg& metric_mask) { + CImg& distance(const T& value, const CImg& metric_mask) { if (is_empty()) return *this; bool is_value = false; cimg_for(*this,ptr,T) *ptr = *ptr==value?is_value=true,0:(T)999999999; @@ -27832,7 +28475,7 @@ namespace cimg_library_suffixed { //! Compute chamfer distance to a specified value, with a custom metric \newinstance. template - CImg get_distance(const T value, const CImg& metric_mask) const { + CImg get_distance(const T& value, const CImg& metric_mask) const { return CImg(*this,false).distance(value,metric_mask); } @@ -27843,7 +28486,7 @@ namespace cimg_library_suffixed { \param is_high_connectivity Tells if the algorithm uses low or high connectivity. **/ template - CImg& distance_dijkstra(const T value, const CImg& metric, const bool is_high_connectivity, + CImg& distance_dijkstra(const T& value, const CImg& metric, const bool is_high_connectivity, CImg& return_path) { return get_distance_dijkstra(value,metric,is_high_connectivity,return_path).move_to(*this); } @@ -27851,7 +28494,7 @@ namespace cimg_library_suffixed { //! Compute distance map to a specified value, according to a custom metric (use dijkstra algorithm). \newinstance. template CImg::type> - get_distance_dijkstra(const T value, const CImg& metric, const bool is_high_connectivity, + get_distance_dijkstra(const T& value, const CImg& metric, const bool is_high_connectivity, CImg& return_path) const { if (is_empty()) return return_path.assign(); if (!is_sameXYZ(metric)) @@ -27890,113 +28533,121 @@ namespace cimg_library_suffixed { // Update neighbors. td npot = 0; - if (x-1>=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x-1,y,z)+P),x-1,y,z)) { - res(x-1,y,z) = npot; if (path) path(x-1,y,z) = (to)2; + if (x - 1>=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x - 1,y,z) + P),x - 1,y,z)) { + res(x - 1,y,z) = npot; if (path) path(x - 1,y,z) = (to)2; } - if (x+1=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x,y-1,z)+P),x,y-1,z)) { - res(x,y-1,z) = npot; if (path) path(x,y-1,z) = (to)8; + if (y - 1>=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x,y - 1,z) + P),x,y - 1,z)) { + res(x,y - 1,z) = npot; if (path) path(x,y - 1,z) = (to)8; } - if (y+1=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x,y,z-1)+P),x,y,z-1)) { - res(x,y,z-1) = npot; if (path) path(x,y,z-1) = (to)32; + if (z - 1>=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x,y,z - 1) + P),x,y,z - 1)) { + res(x,y,z - 1) = npot; if (path) path(x,y,z - 1) = (to)32; } - if (z+1=0 && y-1>=0 && - Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x-1,y-1,z)+P)),x-1,y-1,z)) { - res(x-1,y-1,z) = npot; if (path) path(x-1,y-1,z) = (to)10; + if (x - 1>=0 && y - 1>=0 && + Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x - 1,y - 1,z) + P)),x - 1,y - 1,z)) { + res(x - 1,y - 1,z) = npot; if (path) path(x - 1,y - 1,z) = (to)10; } - if (x+1=0 && - Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x+1,y-1,z)+P)),x+1,y-1,z)) { - res(x+1,y-1,z) = npot; if (path) path(x+1,y-1,z) = (to)9; + if (x + 1=0 && + Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x + 1,y - 1,z) + P)),x + 1,y - 1,z)) { + res(x + 1,y - 1,z) = npot; if (path) path(x + 1,y - 1,z) = (to)9; } - if (x-1>=0 && y+1=0 && y + 1=0) { // Diagonal neighbors on slice z-1. - if (x-1>=0 && - Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x-1,y,z-1)+P)),x-1,y,z-1)) { - res(x-1,y,z-1) = npot; if (path) path(x-1,y,z-1) = (to)34; + if (z - 1>=0) { // Diagonal neighbors on slice z - 1. + if (x - 1>=0 && + Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x - 1,y,z - 1) + P)),x - 1,y,z - 1)) { + res(x - 1,y,z - 1) = npot; if (path) path(x - 1,y,z - 1) = (to)34; } - if (x+1=0 && - Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x,y-1,z-1)+P)),x,y-1,z-1)) { - res(x,y-1,z-1) = npot; if (path) path(x,y-1,z-1) = (to)40; + if (y - 1>=0 && + Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x,y - 1,z - 1) + P)),x,y - 1,z - 1)) { + res(x,y - 1,z - 1) = npot; if (path) path(x,y - 1,z - 1) = (to)40; } - if (y+1=0 && y-1>=0 && - Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x-1,y-1,z-1)+P)),x-1,y-1,z-1)) { - res(x-1,y-1,z-1) = npot; if (path) path(x-1,y-1,z-1) = (to)42; + if (x - 1>=0 && y - 1>=0 && + Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x - 1,y - 1,z - 1) + P)), + x - 1,y - 1,z - 1)) { + res(x - 1,y - 1,z - 1) = npot; if (path) path(x - 1,y - 1,z - 1) = (to)42; } - if (x+1=0 && - Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x+1,y-1,z-1)+P)),x+1,y-1,z-1)) { - res(x+1,y-1,z-1) = npot; if (path) path(x+1,y-1,z-1) = (to)41; + if (x + 1=0 && + Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x + 1,y - 1,z - 1) + P)), + x + 1,y - 1,z - 1)) { + res(x + 1,y - 1,z - 1) = npot; if (path) path(x + 1,y - 1,z - 1) = (to)41; } - if (x-1>=0 && y+1=0 && y + 1=0 && - Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x-1,y,z+1)+P)),x-1,y,z+1)) { - res(x-1,y,z+1) = npot; if (path) path(x-1,y,z+1) = (to)18; + if (z + 1=0 && + Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x - 1,y,z + 1) + P)),x - 1,y,z + 1)) { + res(x - 1,y,z + 1) = npot; if (path) path(x - 1,y,z + 1) = (to)18; } - if (x+1=0 && - Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x,y-1,z+1)+P)),x,y-1,z+1)) { - res(x,y-1,z+1) = npot; if (path) path(x,y-1,z+1) = (to)24; + if (y - 1>=0 && + Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x,y - 1,z + 1) + P)),x,y - 1,z + 1)) { + res(x,y - 1,z + 1) = npot; if (path) path(x,y - 1,z + 1) = (to)24; } - if (y+1=0 && y-1>=0 && - Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x-1,y-1,z+1)+P)),x-1,y-1,z+1)) { - res(x-1,y-1,z+1) = npot; if (path) path(x-1,y-1,z+1) = (to)26; + if (x - 1>=0 && y - 1>=0 && + Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x - 1,y - 1,z + 1) + P)), + x - 1,y - 1,z + 1)) { + res(x - 1,y - 1,z + 1) = npot; if (path) path(x - 1,y - 1,z + 1) = (to)26; } - if (x+1=0 && - Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x+1,y-1,z+1)+P)),x+1,y-1,z+1)) { - res(x+1,y-1,z+1) = npot; if (path) path(x+1,y-1,z+1) = (to)25; + if (x + 1=0 && + Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x + 1,y - 1,z + 1) + P)), + x + 1,y - 1,z + 1)) { + res(x + 1,y - 1,z + 1) = npot; if (path) path(x + 1,y - 1,z + 1) = (to)25; } - if (x-1>=0 && y+1=0 && y + 1 - CImg& distance_dijkstra(const T value, const CImg& metric, + CImg& distance_dijkstra(const T& value, const CImg& metric, const bool is_high_connectivity=false) { return get_distance_dijkstra(value,metric,is_high_connectivity).move_to(*this); } //! Compute distance map to a specified value, according to a custom metric (use dijkstra algorithm). \newinstance. template - CImg get_distance_dijkstra(const T value, const CImg& metric, + CImg get_distance_dijkstra(const T& value, const CImg& metric, const bool is_high_connectivity=false) const { CImg return_path; return get_distance_dijkstra(value,metric,is_high_connectivity,return_path); @@ -28026,13 +28677,13 @@ namespace cimg_library_suffixed { \param metric Field of distance potentials. **/ template - CImg& distance_eikonal(const T value, const CImg& metric) { + CImg& distance_eikonal(const T& value, const CImg& metric) { return get_distance_eikonal(value,metric).move_to(*this); } //! Compute distance map to one source point, according to a custom metric (use fast marching algorithm). template - CImg get_distance_eikonal(const T value, const CImg& metric) const { + CImg get_distance_eikonal(const T& value, const CImg& metric) const { if (is_empty()) return *this; if (!is_sameXYZ(metric)) throw CImgArgumentException(_cimg_instance @@ -28060,29 +28711,29 @@ namespace cimg_library_suffixed { // Initialize seeds neighbors. ptr2 = state._data; cimg_forXYZ(img,x,y,z) if (*(ptr2++)==1) { - if (x-1>=0 && state(x-1,y,z)==-1) { - const Tfloat dist = res(x-1,y,z) = __distance_eikonal(res,met(x-1,y,z),x-1,y,z); - Q._eik_priority_queue_insert(state,sizeQ,-dist,x-1,y,z); + if (x - 1>=0 && state(x - 1,y,z)==-1) { + const Tfloat dist = res(x - 1,y,z) = __distance_eikonal(res,met(x - 1,y,z),x - 1,y,z); + Q._eik_priority_queue_insert(state,sizeQ,-dist,x - 1,y,z); } - if (x+1=0 && state(x,y-1,z)==-1) { - const Tfloat dist = res(x,y-1,z) = __distance_eikonal(res,met(x,y-1,z),x,y-1,z); - Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y-1,z); + if (y - 1>=0 && state(x,y - 1,z)==-1) { + const Tfloat dist = res(x,y - 1,z) = __distance_eikonal(res,met(x,y - 1,z),x,y - 1,z); + Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y - 1,z); } - if (y+1=0 && state(x,y,z-1)==-1) { - const Tfloat dist = res(x,y,z-1) = __distance_eikonal(res,met(x,y,z-1),x,y,z-1); - Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y,z-1); + if (z - 1>=0 && state(x,y,z - 1)==-1) { + const Tfloat dist = res(x,y,z - 1) = __distance_eikonal(res,met(x,y,z - 1),x,y,z - 1); + Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y,z - 1); } - if (z+1=0) { - if (x-1>=0 && state(x-1,y,z)!=1) { - const Tfloat dist = __distance_eikonal(res,met(x-1,y,z),x-1,y,z); - if (dist=0 && state(x - 1,y,z)!=1) { + const Tfloat dist = __distance_eikonal(res,met(x - 1,y,z),x - 1,y,z); + if (dist=0 && state(x,y-1,z)!=1) { - const Tfloat dist = __distance_eikonal(res,met(x,y-1,z),x,y-1,z); - if (dist=0 && state(x,y - 1,z)!=1) { + const Tfloat dist = __distance_eikonal(res,met(x,y - 1,z),x,y - 1,z); + if (dist=0 && state(x,y,z-1)!=1) { - const Tfloat dist = __distance_eikonal(res,met(x,y,z-1),x,y,z-1); - if (dist=0 && state(x,y,z - 1)!=1) { + const Tfloat dist = __distance_eikonal(res,met(x,y,z - 1),x,y,z - 1); + if (dist& res, const Tfloat P, const int x=0, const int y=0, const int z=0) const { const T M = cimg::type::max(); - T T1 = cimg::min(x-1>=0?res(x-1,y,z):M,x+1=0?res(x - 1,y,z):M,x + 11) { // 3d. T - T2 = cimg::min(y-1>=0?res(x,y-1,z):M,y+1=0?res(x,y,z-1):M,z+1=0?res(x,y - 1,z):M,y + 1=0?res(x,y,z - 1):M,z + 1T2) 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 (T31) { // 2d. - T T2 = cimg::min(y-1>=0?res(x,y-1,z):M,y+1=0?res(x,y - 1,z):M,y + 1T2) cimg::swap(T1,T2); if (P<=0) return (Tfloat)T1; - if (T20) return; state(x,y,z) = 0; 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) { + (*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)); } @@ -28249,7 +28915,7 @@ namespace cimg_library_suffixed { CImg get_haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) const { if (is_empty() || !nb_scales) return +*this; CImg res; - const Tfloat sqrt2 = std::sqrt(2); + const Tfloat sqrt2 = std::sqrt(2.0f); if (nb_scales==1) { switch (cimg::uncase(axis)) { // Single scale transform case 'x' : { @@ -28341,18 +29007,18 @@ namespace cimg_library_suffixed { case 'x' : { unsigned int w = _width; for (unsigned int s = 1; w && s1) { unsigned int w = _width, d = _depth; for (unsigned int s = 1; w && d && s1) { unsigned int d = _depth; for (unsigned int s = 1; d && s1) for (unsigned int s = 1, w = _width/2, h = _height/2, d = _depth/2; w && h && d && s1) for (unsigned int s = 1, w = _width/2, d = _depth/2; w && d && s1) { if (_depth>1) for (unsigned int s = 1, h = _height/2, d = _depth/2; h && d && s1) for (unsigned int s = 1, d = _depth/2; d && s::FFT(): Failed to allocate memory (%s) " - "for computing FFT of image (%u,%u,%u,%u) along the C-axis.", - pixel_type(), - cimg::strbuffersize(sizeof(fftw_complex)*real._spectrum), - real._width,real._height,real._depth,real._spectrum); - - data_plan = fftw_plan_dft_1d(real._spectrum,data_in,data_in,is_invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE); - const unsigned long off = (unsigned long)real._width*real._height*real._depth; - cimg_forXYZ(real,x,y,z) { - T *ptrr = real.data(x,y,z,0), *ptri = imag.data(x,y,z,0); - double *ptrd = (double*)data_in; - cimg_forC(real,c) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; } - fftw_execute(data_plan); - const unsigned int fact = real._spectrum; - if (is_invert) - cimg_forC(real,c) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); } - else cimg_forC(real,c) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); } - } - } + default : + throw CImgArgumentException("CImgList<%s>::FFT(): Invalid specified axis '%c' for real and imaginary parts " + "(%u,%u,%u,%u) " + "(should be { x | y | z }).", + pixel_type(),axis, + real._width,real._height,real._depth,real._spectrum); } fftw_destroy_plan(data_plan); fftw_free(data_in); @@ -28627,7 +29278,7 @@ namespace cimg_library_suffixed { switch (cimg::uncase(axis)) { case 'x' : { // Fourier along X, using built-in functions. const unsigned int N = real._width, N2 = (N>>1); - if (((N-1)&N) && N!=1) + if (((N - 1)&N) && N!=1) throw CImgInstanceException("CImgList<%s>::FFT(): Specified real and imaginary parts (%u,%u,%u,%u) " "have non 2^N dimension along the X-axis.", pixel_type(), @@ -28637,7 +29288,7 @@ namespace cimg_library_suffixed { if (j>i) cimg_forYZC(real,y,z,c) { cimg::swap(real(i,y,z,c),real(j,y,z,c)); cimg::swap(imag(i,y,z,c),imag(j,y,z,c)); if (j>1); - if (((N-1)&N) && N!=1) + if (((N - 1)&N) && N!=1) throw CImgInstanceException("CImgList<%s>::FFT(): Specified real and imaginary parts (%u,%u,%u,%u) " "have non 2^N dimension along the Y-axis.", pixel_type(), @@ -28712,7 +29363,7 @@ namespace cimg_library_suffixed { } break; case 'z' : { // Fourier along Z, using built-in functions. const unsigned int N = real._depth, N2 = (N>>1); - if (((N-1)&N) && N!=1) + if (((N - 1)&N) && N!=1) throw CImgInstanceException("CImgList<%s>::FFT(): Specified real and imaginary parts (%u,%u,%u,%u) " "have non 2^N dimension along the Z-axis.", pixel_type(), @@ -28808,7 +29459,7 @@ namespace cimg_library_suffixed { cimg_forC(real,c) { T *ptrr = real.data(0,0,0,c), *ptri = imag.data(0,0,0,c); double *ptrd = (double*)data_in; - for (unsigned int x = 0; x _coords; + CImg _coords; if (!coords) { // If no texture coordinates specified, do a default XY-projection. _coords.assign(_width,2); float @@ -29014,8 +29665,8 @@ namespace cimg_library_suffixed { dx = xmax>xmin?xmax-xmin:1, dy = ymax>ymin?ymax-ymin:1; cimg_forX(*this,p) { - _coords(p,0) = (unsigned int)(((*this)(p,0)-xmin)*(texture._width-1)/dx); - _coords(p,1) = (unsigned int)(((*this)(p,1)-ymin)*(texture._height-1)/dy); + _coords(p,0) = (int)(((*this)(p,0) - xmin)*texture._width/dx); + _coords(p,1) = (int)(((*this)(p,1) - ymin)*texture._height/dy); } } else _coords = coords; @@ -29025,36 +29676,40 @@ namespace cimg_library_suffixed { const unsigned int siz = p.size(); switch (siz) { case 1 : { // Point. - const unsigned int - i0 = (unsigned int)p[0], - x0 = (unsigned int)_coords(i0,0), y0 = (unsigned int)_coords(i0,1); - texture.get_vector_at(x0,y0).move_to(colors[l]); + const unsigned int i0 = (unsigned int)p[0]; + const int x0 = _coords(i0,0), y0 = _coords(i0,1); + texture.get_vector_at(x0<=0?0:x0>=texture.width()?texture.width() - 1:x0, + y0<=0?0:y0>=texture.height()?texture.height() - 1:y0).move_to(colors[l]); } break; case 2 : case 6 : { // Line. - const unsigned int - i0 = (unsigned int)p[0], i1 = (unsigned int)p[1], - x0 = (unsigned int)_coords(i0,0), y0 = (unsigned int)_coords(i0,1), - x1 = (unsigned int)_coords(i1,0), y1 = (unsigned int)_coords(i1,1); - if (texture_ind<0) colors[texture_ind=l] = texture; else colors[l].assign(colors[texture_ind],true); + const unsigned int i0 = (unsigned int)p[0], i1 = (unsigned int)p[1]; + const int + x0 = _coords(i0,0), y0 = _coords(i0,1), + x1 = _coords(i1,0), y1 = _coords(i1,1); + if (texture_ind<0) colors[texture_ind=l].assign(texture,false); + else colors[l].assign(colors[texture_ind],true); CImg::vector(i0,i1,x0,y0,x1,y1).move_to(p); } break; case 3 : case 9 : { // Triangle. - const unsigned int - i0 = (unsigned int)p[0], i1 = (unsigned int)p[1], i2 = (unsigned int)p[2], - x0 = (unsigned int)_coords(i0,0), y0 = (unsigned int)_coords(i0,1), - x1 = (unsigned int)_coords(i1,0), y1 = (unsigned int)_coords(i1,1), - x2 = (unsigned int)_coords(i2,0), y2 = (unsigned int)_coords(i2,1); - if (texture_ind<0) colors[texture_ind=l] = texture; else colors[l].assign(colors[texture_ind],true); + const unsigned int i0 = (unsigned int)p[0], i1 = (unsigned int)p[1], i2 = (unsigned int)p[2]; + const int + x0 = _coords(i0,0), y0 = _coords(i0,1), + x1 = _coords(i1,0), y1 = _coords(i1,1), + x2 = _coords(i2,0), y2 = _coords(i2,1); + if (texture_ind<0) colors[texture_ind=l].assign(texture,false); + else colors[l].assign(colors[texture_ind],true); CImg::vector(i0,i1,i2,x0,y0,x1,y1,x2,y2).move_to(p); } break; case 4 : case 12 : { // Quadrangle. const unsigned int - i0 = (unsigned int)p[0], i1 = (unsigned int)p[1], i2 = (unsigned int)p[2], i3 = (unsigned int)p[3], - x0 = (unsigned int)_coords(i0,0), y0 = (unsigned int)_coords(i0,1), - x1 = (unsigned int)_coords(i1,0), y1 = (unsigned int)_coords(i1,1), - x2 = (unsigned int)_coords(i2,0), y2 = (unsigned int)_coords(i2,1), - x3 = (unsigned int)_coords(i3,0), y3 = (unsigned int)_coords(i3,1); - if (texture_ind<0) colors[texture_ind=l] = texture; else colors[l].assign(colors[texture_ind],true); + i0 = (unsigned int)p[0], i1 = (unsigned int)p[1], i2 = (unsigned int)p[2], i3 = (unsigned int)p[3]; + const int + x0 = _coords(i0,0), y0 = _coords(i0,1), + x1 = _coords(i1,0), y1 = _coords(i1,1), + x2 = _coords(i2,0), y2 = _coords(i2,1), + x3 = _coords(i3,0), y3 = _coords(i3,1); + if (texture_ind<0) colors[texture_ind=l].assign(texture,false); + else colors[l].assign(colors[texture_ind],true); CImg::vector(i0,i1,i2,i3,x0,y0,x1,y1,x2,y2,x3,y3).move_to(p); } break; } @@ -29068,7 +29723,7 @@ namespace cimg_library_suffixed { (template type \e tf should be at least \e unsigned \e int). \param[out] colors The returned list of the 3d object colors. \param elevation The input elevation map. - \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N-1). + \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N - 1). \par Example \code const CImg img("reference.jpg"); @@ -29097,12 +29752,12 @@ namespace cimg_library_suffixed { for (unsigned int x = 0; x1?(unsigned char)(((*this)(x,y,1) - m)*255/(M-m)):r, - b = _spectrum>2?(unsigned char)(((*this)(x,y,2) - m)*255/(M-m)):(_spectrum>1?0:r); + g = (unsigned char)(_spectrum>1?((*this)(x,y,1) - m)*255/(M-m):r), + b = (unsigned char)(_spectrum>2?((*this)(x,y,2) - m)*255/(M-m):_spectrum>1?0:r); CImg::vector((tc)r,(tc)g,(tc)b).move_to(colors); } const typename CImg::_functor2d_int func(elevation); - return elevation3d(primitives,func,0,0,_width-1.0f,_height-1.0f,_width,_height); + return elevation3d(primitives,func,0,0,_width - 1.0f,_height - 1.0f,_width,_height); } //! Generate the 3d projection planes of the image instance. @@ -29126,26 +29781,26 @@ namespace cimg_library_suffixed { _z0 = (z0>=_depth)?_depth - 1:z0; CImg img_xy, img_xz, img_yz; if (normalize_colors) { - ((get_crop(0,0,_z0,0,_width-1,_height-1,_z0,_spectrum-1)-=m)*=delta).move_to(img_xy); - ((get_crop(0,_y0,0,0,_width-1,_y0,_depth-1,_spectrum-1)-=m)*=delta).resize(_width,_depth,1,-100,-1). + ((get_crop(0,0,_z0,0,_width - 1,_height - 1,_z0,_spectrum - 1)-=m)*=delta).move_to(img_xy); + ((get_crop(0,_y0,0,0,_width - 1,_y0,_depth - 1,_spectrum - 1)-=m)*=delta).resize(_width,_depth,1,-100,-1). move_to(img_xz); - ((get_crop(_x0,0,0,0,_x0,_height-1,_depth-1,_spectrum-1)-=m)*=delta).resize(_height,_depth,1,-100,-1). + ((get_crop(_x0,0,0,0,_x0,_height - 1,_depth - 1,_spectrum - 1)-=m)*=delta).resize(_height,_depth,1,-100,-1). move_to(img_yz); } else { - get_crop(0,0,_z0,0,_width-1,_height-1,_z0,_spectrum-1).move_to(img_xy); - get_crop(0,_y0,0,0,_width-1,_y0,_depth-1,_spectrum-1).resize(_width,_depth,1,-100,-1).move_to(img_xz); - get_crop(_x0,0,0,0,_x0,_height-1,_depth-1,_spectrum-1).resize(_height,_depth,1,-100,-1).move_to(img_yz); + get_crop(0,0,_z0,0,_width - 1,_height - 1,_z0,_spectrum - 1).move_to(img_xy); + get_crop(0,_y0,0,0,_width - 1,_y0,_depth - 1,_spectrum - 1).resize(_width,_depth,1,-100,-1).move_to(img_xz); + get_crop(_x0,0,0,0,_x0,_height - 1,_depth - 1,_spectrum - 1).resize(_height,_depth,1,-100,-1).move_to(img_yz); } CImg points(12,3,1,1, - 0,_width-1,_width-1,0, 0,_width-1,_width-1,0, _x0,_x0,_x0,_x0, - 0,0,_height-1,_height-1, _y0,_y0,_y0,_y0, 0,_height-1,_height-1,0, - _z0,_z0,_z0,_z0, 0,0,_depth-1,_depth-1, 0,0,_depth-1,_depth-1); + 0,_width - 1,_width - 1,0, 0,_width - 1,_width - 1,0, _x0,_x0,_x0,_x0, + 0,0,_height - 1,_height - 1, _y0,_y0,_y0,_y0, 0,_height - 1,_height - 1,0, + _z0,_z0,_z0,_z0, 0,0,_depth - 1,_depth - 1, 0,0,_depth - 1,_depth - 1); primitives.assign(); - CImg::vector(0,1,2,3,0,0,img_xy._width-1,0,img_xy._width-1,img_xy._height-1,0,img_xy._height-1). + CImg::vector(0,1,2,3,0,0,img_xy._width - 1,0,img_xy._width - 1,img_xy._height - 1,0,img_xy._height - 1). move_to(primitives); - CImg::vector(4,5,6,7,0,0,img_xz._width-1,0,img_xz._width-1,img_xz._height-1,0,img_xz._height-1). + CImg::vector(4,5,6,7,0,0,img_xz._width - 1,0,img_xz._width - 1,img_xz._height - 1,0,img_xz._height - 1). move_to(primitives); - CImg::vector(8,9,10,11,0,0,img_yz._width-1,0,img_yz._width-1,img_yz._height-1,0,img_yz._height-1). + CImg::vector(8,9,10,11,0,0,img_yz._width - 1,0,img_yz._width - 1,img_yz._height - 1,0,img_yz._height - 1). move_to(primitives); colors.assign(); img_xy.move_to(colors); @@ -29161,7 +29816,7 @@ namespace cimg_library_suffixed { \param isovalue The returned list of the 3d object colors. \param size_x The number of subdivisions along the X-axis. \param size_y The number of subdisivions along the Y-axis. - \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N-1). + \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N - 1). \par Example \code const CImg img("reference.jpg"); @@ -29187,10 +29842,10 @@ namespace cimg_library_suffixed { CImg vertices; if ((size_x==-100 && size_y==-100) || (size_x==width() && size_y==height())) { const _functor2d_int func(*this); - vertices = isoline3d(primitives,func,isovalue,0,0,width()-1.0f,height()-1.0f,width(),height()); + vertices = isoline3d(primitives,func,isovalue,0,0,width() - 1.0f,height() - 1.0f,width(),height()); } else { const _functor2d_float func(*this); - vertices = isoline3d(primitives,func,isovalue,0,0,width()-1.0f,height()-1.0f,size_x,size_y); + vertices = isoline3d(primitives,func,isovalue,0,0,width() - 1.0f,height() - 1.0f,size_x,size_y); } return vertices; } @@ -29203,7 +29858,7 @@ namespace cimg_library_suffixed { \param size_x Number of subdivisions along the X-axis. \param size_y Number of subdisivions along the Y-axis. \param size_z Number of subdisivions along the Z-axis. - \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N-1). + \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N - 1). \par Example \code const CImg img = CImg("reference.jpg").resize(-100,-100,20); @@ -29225,11 +29880,11 @@ namespace cimg_library_suffixed { CImg vertices; if ((size_x==-100 && size_y==-100 && size_z==-100) || (size_x==width() && size_y==height() && size_z==depth())) { const _functor3d_int func(*this); - vertices = isosurface3d(primitives,func,isovalue,0,0,0,width()-1.0f,height()-1.0f,depth()-1.0f, + vertices = isosurface3d(primitives,func,isovalue,0,0,0,width() - 1.0f,height() - 1.0f,depth() - 1.0f, width(),height(),depth()); } else { const _functor3d_float func(*this); - vertices = isosurface3d(primitives,func,isovalue,0,0,0,width()-1.0f,height()-1.0f,depth()-1.0f, + vertices = isosurface3d(primitives,func,isovalue,0,0,0,width() - 1.0f,height() - 1.0f,depth() - 1.0f, size_x,size_y,size_z); } return vertices; @@ -29279,7 +29934,7 @@ namespace cimg_library_suffixed { const unsigned int yw = y*nsize_x; for (unsigned int x = 0; x::vector(Xi,Y,0).move_to(vertices); } if ((edge&2) && indices1(nxi,1)<0) { const float Yi = Y + (isovalue-val1)*dy/(val2-val1); - indices1(nxi,1) = vertices._width; + indices1(nxi,1) = vertices.width(); CImg::vector(nX,Yi,0).move_to(vertices); } if ((edge&4) && indices2(xi,0)<0) { const float Xi = X + (isovalue-val3)*dx/(val2-val3); - indices2(xi,0) = vertices._width; + indices2(xi,0) = vertices.width(); CImg::vector(Xi,nY,0).move_to(vertices); } if ((edge&8) && indices1(xi,1)<0) { const float Yi = Y + (isovalue-val0)*dy/(val3-val0); - indices1(xi,1) = vertices._width; + indices1(xi,1) = vertices.width(); CImg::vector(X,Yi,0).move_to(vertices); } // Create segments for (const int *segment = segments[configuration]; *segment!=-1; ) { - const unsigned int p0 = *(segment++), p1 = *(segment++); + const unsigned int p0 = (unsigned int)*(segment++), p1 = (unsigned int)*(segment++); const tf i0 = (tf)(_isoline3d_indice(p0,indices1,indices2,xi,nxi)), i1 = (tf)(_isoline3d_indice(p1,indices1,indices2,xi,nxi)); @@ -29757,76 +30413,79 @@ namespace cimg_library_suffixed { val7 = values2(xi,nyi) = (float)func(X,nY,nZ); const unsigned int configuration = - (val0::vector(Xi,Y,Z).move_to(vertices); } if ((edge&2) && indices1(nxi,yi,1)<0) { const float Yi = Y + (isovalue-val1)*dy/(val2-val1); - indices1(nxi,yi,1) = vertices._width; + indices1(nxi,yi,1) = vertices.width(); CImg::vector(nX,Yi,Z).move_to(vertices); } if ((edge&4) && indices1(xi,nyi,0)<0) { const float Xi = X + (isovalue-val3)*dx/(val2-val3); - indices1(xi,nyi,0) = vertices._width; + indices1(xi,nyi,0) = vertices.width(); CImg::vector(Xi,nY,Z).move_to(vertices); } if ((edge&8) && indices1(xi,yi,1)<0) { const float Yi = Y + (isovalue-val0)*dy/(val3-val0); - indices1(xi,yi,1) = vertices._width; + indices1(xi,yi,1) = vertices.width(); CImg::vector(X,Yi,Z).move_to(vertices); } if ((edge&16) && indices2(xi,yi,0)<0) { const float Xi = X + (isovalue-val4)*dx/(val5-val4); - indices2(xi,yi,0) = vertices._width; + indices2(xi,yi,0) = vertices.width(); CImg::vector(Xi,Y,nZ).move_to(vertices); } if ((edge&32) && indices2(nxi,yi,1)<0) { const float Yi = Y + (isovalue-val5)*dy/(val6-val5); - indices2(nxi,yi,1) = vertices._width; + indices2(nxi,yi,1) = vertices.width(); CImg::vector(nX,Yi,nZ).move_to(vertices); } if ((edge&64) && indices2(xi,nyi,0)<0) { const float Xi = X + (isovalue-val7)*dx/(val6-val7); - indices2(xi,nyi,0) = vertices._width; + indices2(xi,nyi,0) = vertices.width(); CImg::vector(Xi,nY,nZ).move_to(vertices); } if ((edge&128) && indices2(xi,yi,1)<0) { const float Yi = Y + (isovalue-val4)*dy/(val7-val4); - indices2(xi,yi,1) = vertices._width; + indices2(xi,yi,1) = vertices.width(); CImg::vector(X,Yi,nZ).move_to(vertices); } if ((edge&256) && indices1(xi,yi,2)<0) { const float Zi = Z+ (isovalue-val0)*dz/(val4-val0); - indices1(xi,yi,2) = vertices._width; + indices1(xi,yi,2) = vertices.width(); CImg::vector(X,Y,Zi).move_to(vertices); } if ((edge&512) && indices1(nxi,yi,2)<0) { const float Zi = Z + (isovalue-val1)*dz/(val5-val1); - indices1(nxi,yi,2) = vertices._width; + indices1(nxi,yi,2) = vertices.width(); CImg::vector(nX,Y,Zi).move_to(vertices); } if ((edge&1024) && indices1(nxi,nyi,2)<0) { const float Zi = Z + (isovalue-val2)*dz/(val6-val2); - indices1(nxi,nyi,2) = vertices._width; + indices1(nxi,nyi,2) = vertices.width(); CImg::vector(nX,nY,Zi).move_to(vertices); } if ((edge&2048) && indices1(xi,nyi,2)<0) { const float Zi = Z + (isovalue-val3)*dz/(val7-val3); - indices1(xi,nyi,2) = vertices._width; + indices1(xi,nyi,2) = vertices.width(); CImg::vector(X,nY,Zi).move_to(vertices); } // Create triangles for (const int *triangle = triangles[configuration]; *triangle!=-1; ) { - const unsigned int p0 = *(triangle++), p1 = *(triangle++), p2 = *(triangle++); + const unsigned int + p0 = (unsigned int)*(triangle++), + p1 = (unsigned int)*(triangle++), + p2 = (unsigned int)*(triangle++); const tf i0 = (tf)(_isosurface3d_indice(p0,indices1,indices2,xi,yi,nxi,nyi)), i1 = (tf)(_isosurface3d_indice(p1,indices1,indices2,xi,yi,nxi,nyi)), @@ -29939,7 +30598,7 @@ namespace cimg_library_suffixed { \param size_x The width of the box (dimension along the X-axis). \param size_y The height of the box (dimension along the Y-axis). \param size_z The depth of the box (dimension along the Z-axis). - \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N-1). + \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N - 1). \par Example \code CImgList faces3d; @@ -29965,7 +30624,7 @@ namespace cimg_library_suffixed { \param radius The radius of the cone basis. \param size_z The cone's height. \param subdivisions The number of basis angular subdivisions. - \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N-1). + \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N - 1). \par Example \code CImgList faces3d; @@ -29983,12 +30642,12 @@ namespace cimg_library_suffixed { 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); + const float a = (float)(angle*cimg::PI/180); CImg::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::vector(1,next,curr).move_to(primitives); CImg::vector(0,curr,next).move_to(primitives); } @@ -30002,7 +30661,7 @@ namespace cimg_library_suffixed { \param radius The radius of the cylinder basis. \param size_z The cylinder's height. \param subdivisions The number of basis angular subdivisions. - \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N-1). + \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N - 1). \par Example \code CImgList faces3d; @@ -30020,16 +30679,16 @@ namespace cimg_library_suffixed { 0.,0.,0., 0.,0.,size_z); for (float delta = 360.0f/subdivisions, angle = 0; angle<360; angle+=delta) { - const float a = (float)(angle*cimg::PI/180); + const float a = (float)(angle*cimg::PI/180); CImg::vector((float)(radius*std::cos(a)),(float)(radius*std::sin(a)),0.0f).move_to(vertices); CImg::vector((float)(radius*std::cos(a)),(float)(radius*std::sin(a)),size_z).move_to(vertices); } const unsigned int nbr = (vertices._width - 2)/2; for (unsigned int p = 0; p::vector(0,next,curr).move_to(primitives); - CImg::vector(1,curr+1,next+1).move_to(primitives); - CImg::vector(curr,next,next+1,curr+1).move_to(primitives); + CImg::vector(1,curr + 1,next + 1).move_to(primitives); + CImg::vector(curr,next,next + 1,curr + 1).move_to(primitives); } return vertices>'x'; } @@ -30042,7 +30701,7 @@ namespace cimg_library_suffixed { \param radius2 The small radius. \param subdivisions1 The number of angular subdivisions for the large radius. \param subdivisions2 The number of angular subdivisions for the small radius. - \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N-1). + \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N - 1). \par Example \code CImgList faces3d; @@ -30059,24 +30718,24 @@ namespace cimg_library_suffixed { if (!subdivisions1 || !subdivisions2) return CImg(); CImgList vertices; for (unsigned int v = 0; v::vector(x,y,z).move_to(vertices); } } for (unsigned int vv = 0; vv::vector(svv+nu,svv+uu,snv+uu,snv+nu).move_to(primitives); + const unsigned int nu = (uu + 1)%subdivisions2, svv = subdivisions2*vv, snv = subdivisions2*nv; + CImg::vector(svv + nu,svv + uu,snv + uu,snv + nu).move_to(primitives); } } return vertices>'x'; @@ -30090,7 +30749,7 @@ namespace cimg_library_suffixed { \param size_y The height of the plane (dimensions along the Y-axis). \param subdivisions_x The number of planar subdivisions along the X-axis. \param subdivisions_y The number of planar subdivisions along the Y-axis. - \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N-1). + \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N - 1). \par Example \code CImgList faces3d; @@ -30111,8 +30770,8 @@ namespace cimg_library_suffixed { for (unsigned int y = 0; y::vector(fx*x,fy*y,0).move_to(vertices); for (unsigned int y = 0; y::vector(off1,off4,off3,off2).move_to(primitives); + const int off1 = x + y*w, off2 = x + 1 + y*w, off3 = x + 1 + (y + 1)*w, off4 = x + (y + 1)*w; + CImg::vector(off1,off4,off3,off2).move_to(primitives); } return vertices>'x'; } @@ -30123,7 +30782,7 @@ namespace cimg_library_suffixed { (template type \e tf should be at least \e unsigned \e int). \param radius The radius of the sphere (dimension along the X-axis). \param subdivisions The number of recursive subdivisions from an initial icosahedron. - \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N-1). + \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N - 1). \par Example \code CImgList faces3d; @@ -30138,7 +30797,7 @@ namespace cimg_library_suffixed { // Create initial icosahedron primitives.assign(); - const double tmp = (1+std::sqrt(5.0f))/2, a = 1.0/std::sqrt(1+tmp*tmp), b = tmp*a; + const double tmp = (1 + std::sqrt(5.0f))/2, a = 1.0/std::sqrt(1 + tmp*tmp), b = tmp*a; CImgList vertices(12,1,3,1,1, b,a,0.0, -b,a,0.0, -b,-a,0.0, b,-a,0.0, a,0.0,b, a,0.0,-b, -a,0.0,-b, -a,0.0,b, 0.0,b,a, 0.0,-b,a, 0.0,-b,-a, 0.0,b,-a); primitives.assign(20,1,3,1,1, 4,8,7, 4,7,9, 5,6,11, 5,10,6, 0,4,3, 0,3,5, 2,7,1, 2,1,6, @@ -30150,8 +30809,8 @@ namespace cimg_library_suffixed { // Recurse subdivisions for (unsigned int i = 0; i::vector(nx0,ny0,nz0).move_to(vertices); i0 = vertices._width - 1; } - if (i1<0) { CImg::vector(nx1,ny1,nz1).move_to(vertices); i1 = vertices._width - 1; } - if (i2<0) { CImg::vector(nx2,ny2,nz2).move_to(vertices); i2 = vertices._width - 1; } + if (i0<0) { CImg::vector(nx0,ny0,nz0).move_to(vertices); i0 = vertices.width() - 1; } + if (i1<0) { CImg::vector(nx1,ny1,nz1).move_to(vertices); i1 = vertices.width() - 1; } + if (i2<0) { CImg::vector(nx2,ny2,nz2).move_to(vertices); i2 = vertices.width() - 1; } primitives.remove(0); CImg::vector(p0,i0,i1).move_to(primitives); CImg::vector((tf)i0,(tf)p1,(tf)i2).move_to(primitives); @@ -30191,7 +30853,7 @@ namespace cimg_library_suffixed { (template type \e tf should be at least \e unsigned \e int). \param tensor The tensor which gives the shape and size of the ellipsoid. \param subdivisions The number of recursive subdivisions from an initial stretched icosahedron. - \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N-1). + \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg image (0<=i<=N - 1). \par Example \code CImgList faces3d; @@ -30262,11 +30924,11 @@ namespace cimg_library_suffixed { const CImgList& colors, const to& opacities, const bool full_check=true) const { - char error_message[1024] = { 0 }; + CImg 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); + cimg_instance,_width,primitives._width,error_message.data()); CImg res(1,_size_object3dtoCImg3d(primitives,colors,opacities)); float *ptrd = res._data; @@ -30316,7 +30978,7 @@ namespace cimg_library_suffixed { } } } - const int csiz2 = primitives._width - colors._width; + const int csiz2 = primitives.width() - colors.width(); for (int c = 0; c& primitives, const CImgList& colors, const CImgList& opacities) const { - unsigned int siz = 8 + 3*width(); + unsigned int siz = 8U + 3*_width; cimglist_for(primitives,p) siz+=primitives[p].size() + 1; - for (int c = cimg::min(primitives._width,colors._width)-1; c>=0; --c) { + for (int c = cimg::min(primitives.width(),colors.width()) - 1; c>=0; --c) { if (colors[c].is_shared()) siz+=4; - else { const unsigned int csiz = colors[c].size(); siz+=(csiz!=3)?4+csiz:3; } + else { const unsigned int csiz = colors[c].size(); siz+=(csiz!=3)?4 + csiz:3; } } if (colors._width& primitives, const CImgList& colors, const CImg& opacities) const { - unsigned int siz = 8 + 3*width(); + unsigned int siz = 8U + 3*_width; cimglist_for(primitives,p) siz+=primitives[p].size() + 1; - for (int c = cimg::min(primitives._width,colors._width)-1; c>=0; --c) { - const unsigned int csiz = colors[c].size(); siz+=(csiz!=3)?4+csiz:3; + for (int c = cimg::min(primitives.width(),colors.width()) - 1; c>=0; --c) { + const unsigned int csiz = colors[c].size(); siz+=(csiz!=3)?4 + csiz:3; } if (colors._width& colors, CImgList& opacities, const bool full_check=true) const { - char error_message[1024] = { 0 }; + CImg error_message(1024); if (!is_CImg3d(full_check,error_message)) throw CImgInstanceException(_cimg_instance "CImg3dtoobject3d(): image instance is not a CImg3d (%s).", - cimg_instance,error_message); + cimg_instance,error_message.data()); const T *ptrs = _data + 6; const unsigned int nb_points = cimg::float2uint((float)*(ptrs++)), @@ -30500,7 +31162,7 @@ namespace cimg_library_suffixed { const float brightness, const float nopacity, const float copacity, const unsigned long whd) { static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); - const int nx0 = x0>0?x0:0, nx1 = x10?x0:0, nx1 = x1=0) { const tc *col = color; const unsigned long off = whd - dx - 1; @@ -30513,7 +31175,7 @@ namespace cimg_library_suffixed { ptrd+=off; } else cimg_forC(*this,c) { const T val = (T)*(col++); - std::memset(ptrd,(int)val,dx+1); + std::memset(ptrd,(int)val,dx + 1); ptrd+=whd; } } else if (brightness<1) { // Brightness<1 @@ -30523,17 +31185,17 @@ namespace cimg_library_suffixed { ptrd+=off; } else cimg_forC(*this,c) { const T val = (T)(*(col++)*brightness); - std::memset(ptrd,(int)val,dx+1); + 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); + 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); + const T val = (T)((2-brightness)**(col++) + (brightness - 1)*maxval); + std::memset(ptrd,(int)val,dx + 1); ptrd+=whd; } } @@ -30552,7 +31214,7 @@ namespace cimg_library_suffixed { } } else { // Brightness>1 cimg_forC(*this,c) { - const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval); + const T val = (T)((2-brightness)**(col++) + (brightness - 1)*maxval); for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; } ptrd+=off; } @@ -30664,10 +31326,10 @@ namespace cimg_library_suffixed { if (init_hatch) hatch = ~0U - (~0U>>1); const bool xdir = x0=width()) return *this; if (xleft<0) { yleft-=(int)((float)xleft*((float)yright - yleft)/((float)xright - xleft)); xleft = 0; } @@ -30805,7 +31467,7 @@ namespace cimg_library_suffixed { offx = (nx00?dx:1; + ndx = dx>0?(unsigned long)dx:1; if (opacity>=1) { if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { const tzfloat z = Z0 + x*dz/ndx; @@ -30921,7 +31583,7 @@ namespace cimg_library_suffixed { ny1+=(int)(d*(1.0f + ny0 - ny1)/D); nz1 = depth() - 1; } - const unsigned int dmax = cimg::max(cimg::abs(nx1 - nx0),cimg::abs(ny1 - ny0),nz1 - nz0); + const unsigned int dmax = (unsigned int)cimg::max(cimg::abs(nx1 - nx0),cimg::abs(ny1 - ny0),nz1 - nz0); const unsigned long whd = (unsigned long)_width*_height*_depth; const float px = (nx1 - nx0)/(float)dmax, py = (ny1 - ny0)/(float)dmax, pz = (nz1 - nz0)/(float)dmax; float x = (float)nx0, y = (float)ny0, z = (float)nz0; @@ -31031,14 +31693,17 @@ namespace cimg_library_suffixed { offx = (nx00?dx:1; - const unsigned long wh = (unsigned long)_width*_height; + const unsigned long + whd = (unsigned long)_width*_height*_depth, + twh = (unsigned long)texture._width*texture._height; if (opacity>=1) { if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { if (pattern&hatch) { T *ptrd = ptrd0; const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx; - cimg_forC(*this,c) { *ptrd = (T)texture(tx,ty,0,c); ptrd+=wh; } + const tc *col = &texture._atXY(tx,ty); + cimg_forC(*this,c) { *ptrd = (T)*col; ptrd+=whd; col+=twh; } } hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); ptrd0+=offx; @@ -31046,7 +31711,8 @@ namespace cimg_library_suffixed { } else for (int error = dx>>1, x = 0; x<=dx; ++x) { T *ptrd = ptrd0; const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx; - cimg_forC(*this,c) { *ptrd = (T)texture(tx,ty,0,c); ptrd+=wh; } + const tc *col = &texture._atXY(tx,ty); + cimg_forC(*this,c) { *ptrd = (T)*col; ptrd+=whd; col+=twh; } ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } } @@ -31056,7 +31722,8 @@ namespace cimg_library_suffixed { T *ptrd = ptrd0; if (pattern&hatch) { const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx; - cimg_forC(*this,c) { *ptrd = (T)(nopacity*texture(tx,ty,0,c) + *ptrd*copacity); ptrd+=wh; } + const tc *col = &texture._atXY(tx,ty); + cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; } } hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); ptrd0+=offx; @@ -31064,7 +31731,8 @@ namespace cimg_library_suffixed { } else for (int error = dx>>1, x = 0; x<=dx; ++x) { T *ptrd = ptrd0; const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx; - cimg_forC(*this,c) { *ptrd = (T)(nopacity*texture(tx,ty,0,c) + *ptrd*copacity); ptrd+=wh; } + const tc *col = &texture._atXY(tx,ty); + cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; } ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } } @@ -31166,20 +31834,26 @@ namespace cimg_library_suffixed { offx = (nx00?dx:1; - const unsigned long wh = (unsigned long)_width*_height; + const unsigned long + whd = (unsigned long)_width*_height*_depth, + twh = (unsigned long)texture._width*texture._height; if (opacity>=1) { if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { if (pattern&hatch) { const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx; - T *ptrd = ptrd0; cimg_forC(*this,c) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,c); ptrd+=wh; } + const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z)); + T *ptrd = ptrd0; + cimg_forC(*this,c) { *ptrd = (T)*col; ptrd+=whd; col+=twh; } } hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } } else for (int error = dx>>1, x = 0; x<=dx; ++x) { const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx; - T *ptrd = ptrd0; cimg_forC(*this,c) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,c); ptrd+=wh; } + const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z)); + T *ptrd = ptrd0; + cimg_forC(*this,c) { *ptrd = (T)*col; ptrd+=whd; col+=twh; } ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } } @@ -31188,18 +31862,18 @@ namespace cimg_library_suffixed { if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { if (pattern&hatch) { const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx; + const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z)); T *ptrd = ptrd0; - cimg_forC(*this,c) { - *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,c) + *ptrd*copacity); ptrd+=wh; - } + cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; } } hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } } else for (int error = dx>>1, x = 0; x<=dx; ++x) { const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx; + const tc *col = &texture._atXY((int)(tx/z),(int)(ty/z)); T *ptrd = ptrd0; - cimg_forC(*this,c) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,c) + *ptrd*copacity); ptrd+=wh; } + cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; } ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } } @@ -31289,7 +31963,7 @@ namespace cimg_library_suffixed { zright-=d*(zright - zleft)/D; txright-=d*(txright - txleft)/D; tyright-=d*(tyright - tyleft)/D; - xright = width()-1; + xright = width() - 1; } if (ydown<0 || yup>=height()) return *this; if (yup<0) { @@ -31306,7 +31980,7 @@ namespace cimg_library_suffixed { zdown-=d*(zdown - zup)/D; txdown-=d*(txdown - txup)/D; tydown-=d*(tydown - tyup)/D; - ydown = height()-1; + ydown = height() - 1; } T *ptrd0 = data(nx0,ny0); tz *ptrz = zbuffer.data(nx0,ny0); @@ -31317,7 +31991,9 @@ namespace cimg_library_suffixed { offx = (nx00?dx:1; - const unsigned long wh = (unsigned long)_width*_height; + const unsigned long + whd = (unsigned long)_width*_height*_depth, + twh = (unsigned long)texture._width*texture._height; if (opacity>=1) { if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { @@ -31326,7 +32002,9 @@ namespace cimg_library_suffixed { if (z>=(tzfloat)*ptrz) { *ptrz = (tz)z; const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx; - T *ptrd = ptrd0; cimg_forC(*this,c) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,c); ptrd+=wh; } + 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); @@ -31337,7 +32015,9 @@ namespace cimg_library_suffixed { if (z>=(tzfloat)*ptrz) { *ptrz = (tz)z; const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx; - T *ptrd = ptrd0; cimg_forC(*this,c) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,c); ptrd+=wh; } + 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; } @@ -31350,10 +32030,9 @@ namespace cimg_library_suffixed { 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*texture((int)(tx/z),(int)(ty/z),0,c) + *ptrd*copacity); ptrd+=wh; - } + cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; } } } hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); @@ -31364,10 +32043,9 @@ namespace cimg_library_suffixed { 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*texture((int)(tx/z),(int)(ty/z),0,c) + *ptrd*copacity); ptrd+=wh; - } + 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; } @@ -31453,7 +32131,7 @@ namespace cimg_library_suffixed { const int xl = x1 + (int)(l*cl), yl = y1 + (int)(l*sl), xr = x1 + (int)(l*cr), yr = y1 + (int)(l*sr), - xc = x1 + (int)((l+1)*(cl+cr))/2, yc = y1 + (int)((l+1)*(sl+sr))/2; + xc = x1 + (int)((l + 1)*(cl + cr))/2, yc = y1 + (int)((l + 1)*(sl + sr))/2; draw_line(x0,y0,xc,yc,color,opacity,pattern).draw_triangle(x1,y1,xl,yl,xr,yr,color,opacity); } else draw_point(x0,y0,color,opacity); return *this; @@ -31511,7 +32189,7 @@ namespace cimg_library_suffixed { bx = 3*(x1 - x0) - 2*u0 - u1, ay = v0 + v1 + 2*(y0 - y1), by = 3*(y1 - y0) - 2*v0 - v1, - _precision = 1/(std::sqrt(cimg::sqr((float)x0-x1)+cimg::sqr((float)y0-y1))*(precision>0?precision:1)); + _precision = 1/(std::sqrt(cimg::sqr((float)x0 - x1) + cimg::sqr((float)y0 - y1))*(precision>0?precision:1)); int ox = x0, oy = y0; for (float t = 0; t<1; t+=_precision) { const float t2 = t*t, t3 = t2*t; @@ -31550,7 +32228,7 @@ namespace cimg_library_suffixed { by = 3*(y1 - y0) - 2*v0 - v1, az = w0 + w1 + 2*(z0 - z1), bz = 3*(z1 - z0) - 2*w0 - w1, - _precision = 1/(std::sqrt(cimg::sqr(x0-x1)+cimg::sqr(y0-y1))*(precision>0?precision:1)); + _precision = 1/(std::sqrt(cimg::sqr(x0 - x1) + cimg::sqr(y0 - y1))*(precision>0?precision:1)); int ox = x0, oy = y0, oz = z0; for (float t = 0; t<1; t+=_precision) { const float t2 = t*t, t3 = t2*t; @@ -31601,22 +32279,24 @@ namespace cimg_library_suffixed { if (is_empty()) return *this; if (is_overlapped(texture)) return draw_spline(x0,y0,u0,v0,x1,y1,u1,v1,+texture,tx0,ty0,tx1,ty1,precision,opacity,pattern,init_hatch); - if (x0==x1 && y0==y1) return draw_point(x0,y0,texture.get_vector_at(x0,y0),opacity); + if (x0==x1 && y0==y1) + return draw_point(x0,y0,texture.get_vector_at(x0<=0?0:x0>=texture.width()?texture.width() - 1:x0, + y0<=0?0:y0>=texture.height()?texture.height() - 1:y0),opacity); bool ninit_hatch = init_hatch; const float ax = u0 + u1 + 2*(x0 - x1), bx = 3*(x1 - x0) - 2*u0 - u1, ay = v0 + v1 + 2*(y0 - y1), by = 3*(y1 - y0) - 2*v0 - v1, - _precision = 1/(std::sqrt(cimg::sqr(x0-x1)+cimg::sqr(y0-y1))*(precision>0?precision:1)); + _precision = 1/(std::sqrt(cimg::sqr(x0 - x1) + cimg::sqr(y0 - y1))*(precision>0?precision:1)); int ox = x0, oy = y0, otx = tx0, oty = ty0; for (float t1 = 0; t1<1; t1+=_precision) { const float t2 = t1*t1, t3 = t2*t1; const int nx = (int)(ax*t3 + bx*t2 + u0*t1 + x0), ny = (int)(ay*t3 + by*t2 + v0*t1 + y0), - ntx = tx0 + (int)((tx1-tx0)*t1), - nty = ty0 + (int)((ty1-ty0)*t1); + ntx = tx0 + (int)((tx1 - tx0)*t1), + nty = ty0 + (int)((ty1 - ty0)*t1); draw_line(ox,oy,nx,ny,texture,otx,oty,ntx,nty,opacity,pattern,ninit_hatch); ninit_hatch = false; ox = nx; oy = ny; otx = ntx; oty = nty; @@ -31702,8 +32382,8 @@ namespace cimg_library_suffixed { tangents.assign(points._width,points._height); cimg_forX(points,p) { const unsigned int - p0 = is_closed_set?(p+points._width-1)%points._width:(p?p-1:0), - p1 = is_closed_set?(p+1)%points._width:(p+1=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \ - xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \ + xr = y0>=0?x0:(x0 - y0*(x2 - x0)/(y2 - y0)), \ + xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0 - y0*(x1 - x0)/(y1 - y0))):(x1 - y1*(x2 - x1)/(y2 - y1)), \ _sxn=1, \ _sxr=1, \ _sxl=1, \ - _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \ - _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \ - _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \ + _dxn = x2>x1?x2-x1:(_sxn=-1,x1 - x2), \ + _dxr = x2>x0?x2-x0:(_sxr=-1,x0 - x2), \ + _dxl = x1>x0?x1-x0:(_sxl=-1,x0 - x1), \ _dyn = y2-y1, \ _dyr = y2-y0, \ _dyl = y1-y0, \ _counter = (_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \ _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \ _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \ - cimg::min((int)(img)._height-y-1,y2-y)), \ + cimg::min((int)(img)._height - y - 1,y2 - y)), \ _errn = _dyn/2, \ _errr = _dyr/2, \ _errl = _dyl/2, \ @@ -31795,19 +32475,19 @@ namespace cimg_library_suffixed { #define _cimg_for_triangle2(img,xl,cl,xr,cr,y,x0,y0,c0,x1,y1,c1,x2,y2,c2) \ for (int y = y0<0?0:y0, \ - xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \ - cr = y0>=0?c0:(c0-y0*(c2-c0)/(y2-y0)), \ - xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \ - cl = y1>=0?(y0>=0?(y0==y1?c1:c0):(c0-y0*(c1-c0)/(y1-y0))):(c1-y1*(c2-c1)/(y2-y1)), \ + xr = y0>=0?x0:(x0 - y0*(x2 - x0)/(y2 - y0)), \ + cr = y0>=0?c0:(c0 - y0*(c2 - c0)/(y2 - y0)), \ + xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0 - y0*(x1 - x0)/(y1 - y0))):(x1 - y1*(x2 - x1)/(y2 - y1)), \ + cl = y1>=0?(y0>=0?(y0==y1?c1:c0):(c0 - y0*(c1 - c0)/(y1 - y0))):(c1 - y1*(c2 - c1)/(y2 - y1)), \ _sxn=1, _scn=1, \ _sxr=1, _scr=1, \ _sxl=1, _scl=1, \ - _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \ - _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \ - _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \ - _dcn = c2>c1?c2-c1:(_scn=-1,c1-c2), \ - _dcr = c2>c0?c2-c0:(_scr=-1,c0-c2), \ - _dcl = c1>c0?c1-c0:(_scl=-1,c0-c1), \ + _dxn = x2>x1?x2-x1:(_sxn=-1,x1 - x2), \ + _dxr = x2>x0?x2-x0:(_sxr=-1,x0 - x2), \ + _dxl = x1>x0?x1-x0:(_sxl=-1,x0 - x1), \ + _dcn = c2>c1?c2-c1:(_scn=-1,c1 - c2), \ + _dcr = c2>c0?c2-c0:(_scr=-1,c0 - c2), \ + _dcl = c1>c0?c1-c0:(_scl=-1,c0 - c1), \ _dyn = y2-y1, \ _dyr = y2-y0, \ _dyl = y1-y0, \ @@ -31817,14 +32497,14 @@ namespace cimg_library_suffixed { _dcn-=_dyn?_dyn*(_dcn/_dyn):0, \ _dcr-=_dyr?_dyr*(_dcr/_dyr):0, \ _dcl-=_dyl?_dyl*(_dcl/_dyl):0, \ - cimg::min((int)(img)._height-y-1,y2-y)), \ + cimg::min((int)(img)._height - y - 1,y2 - y)), \ _errn = _dyn/2, _errcn = _errn, \ _errr = _dyr/2, _errcr = _errr, \ _errl = _dyl/2, _errcl = _errl, \ - _rxn = _dyn?(x2-x1)/_dyn:0, \ - _rcn = _dyn?(c2-c1)/_dyn:0, \ - _rxr = _dyr?(x2-x0)/_dyr:0, \ - _rcr = _dyr?(c2-c0)/_dyr:0, \ + _rxn = _dyn?(x2 - x1)/_dyn:0, \ + _rcn = _dyn?(c2 - c1)/_dyn:0, \ + _rxr = _dyr?(x2 - x0)/_dyr:0, \ + _rcr = _dyr?(c2 - c0)/_dyr:0, \ _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \ (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \ _rcl = (y0!=y1 && y1>0)?(_dyl?(c1-c0)/_dyl:0): \ @@ -31833,30 +32513,30 @@ namespace cimg_library_suffixed { xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \ cr+=_rcr+((_errcr-=_dcr)<0?_errcr+=_dyr,_scr:0), \ xl+=(y!=y1)?(cl+=_rcl+((_errcl-=_dcl)<0?(_errcl+=_dyl,_scl):0), \ - _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \ + _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \ (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcl=_rcn, cl=c1, \ _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl)) #define _cimg_for_triangle3(img,xl,txl,tyl,xr,txr,tyr,y,x0,y0,tx0,ty0,x1,y1,tx1,ty1,x2,y2,tx2,ty2) \ for (int y = y0<0?0:y0, \ - xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \ - txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \ - tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \ - xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \ - txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \ - tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \ + xr = y0>=0?x0:(x0 - y0*(x2 - x0)/(y2 - y0)), \ + txr = y0>=0?tx0:(tx0 - y0*(tx2 - tx0)/(y2 - y0)), \ + tyr = y0>=0?ty0:(ty0 - y0*(ty2 - ty0)/(y2 - y0)), \ + xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0 - y0*(x1 - x0)/(y1 - y0))):(x1 - y1*(x2 - x1)/(y2 - y1)), \ + txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0 - y0*(tx1 - tx0)/(y1 - y0))):(tx1 - y1*(tx2 - tx1)/(y2 - y1)), \ + tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0 - y0*(ty1 - ty0)/(y1 - y0))):(ty1 - y1*(ty2 - ty1)/(y2 - y1)), \ _sxn=1, _stxn=1, _styn=1, \ _sxr=1, _stxr=1, _styr=1, \ _sxl=1, _stxl=1, _styl=1, \ - _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \ - _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \ - _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \ - _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \ - _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \ - _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \ - _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \ - _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \ - _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \ + _dxn = x2>x1?x2 - x1:(_sxn=-1,x1 - x2), \ + _dxr = x2>x0?x2 - x0:(_sxr=-1,x0 - x2), \ + _dxl = x1>x0?x1 - x0:(_sxl=-1,x0 - x1), \ + _dtxn = tx2>tx1?tx2 - tx1:(_stxn=-1,tx1 - tx2), \ + _dtxr = tx2>tx0?tx2 - tx0:(_stxr=-1,tx0 - tx2), \ + _dtxl = tx1>tx0?tx1 - tx0:(_stxl=-1,tx0 - tx1), \ + _dtyn = ty2>ty1?ty2 - ty1:(_styn=-1,ty1 - ty2), \ + _dtyr = ty2>ty0?ty2 - ty0:(_styr=-1,ty0 - ty2), \ + _dtyl = ty1>ty0?ty1 - ty0:(_styl=-1,ty0 - ty1), \ _dyn = y2-y1, \ _dyr = y2-y0, \ _dyl = y1-y0, \ @@ -31869,21 +32549,21 @@ namespace cimg_library_suffixed { _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \ _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \ _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \ - cimg::min((int)(img)._height-y-1,y2-y)), \ + cimg::min((int)(img)._height - y - 1,y2 - y)), \ _errn = _dyn/2, _errtxn = _errn, _errtyn = _errn, \ _errr = _dyr/2, _errtxr = _errr, _errtyr = _errr, \ _errl = _dyl/2, _errtxl = _errl, _errtyl = _errl, \ - _rxn = _dyn?(x2-x1)/_dyn:0, \ - _rtxn = _dyn?(tx2-tx1)/_dyn:0, \ - _rtyn = _dyn?(ty2-ty1)/_dyn:0, \ - _rxr = _dyr?(x2-x0)/_dyr:0, \ - _rtxr = _dyr?(tx2-tx0)/_dyr:0, \ - _rtyr = _dyr?(ty2-ty0)/_dyr:0, \ - _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \ + _rxn = _dyn?(x2 - x1)/_dyn:0, \ + _rtxn = _dyn?(tx2 - tx1)/_dyn:0, \ + _rtyn = _dyn?(ty2 - ty1)/_dyn:0, \ + _rxr = _dyr?(x2 - x0)/_dyr:0, \ + _rtxr = _dyr?(tx2 - tx0)/_dyr:0, \ + _rtyr = _dyr?(ty2 - ty0)/_dyr:0, \ + _rxl = (y0!=y1 && y1>0)?(_dyl?(x1 - x0)/_dyl:0): \ (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \ - _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \ + _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1 - tx0)/_dyl:0): \ (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \ - _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \ + _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1 - ty0)/_dyl:0): \ (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ); \ _counter>=0; --_counter, ++y, \ xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \ @@ -31894,36 +32574,36 @@ namespace cimg_library_suffixed { _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \ (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \ _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1,\ - _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl)) + _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1 - xl)) #define _cimg_for_triangle4(img,xl,cl,txl,tyl,xr,cr,txr,tyr,y,x0,y0,c0,tx0,ty0,x1,y1,c1,tx1,ty1,x2,y2,c2,tx2,ty2) \ for (int y = y0<0?0:y0, \ - xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \ - cr = y0>=0?c0:(c0-y0*(c2-c0)/(y2-y0)), \ - txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \ - tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \ - xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \ - cl = y1>=0?(y0>=0?(y0==y1?c1:c0):(c0-y0*(c1-c0)/(y1-y0))):(c1-y1*(c2-c1)/(y2-y1)), \ - txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \ - tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \ + xr = y0>=0?x0:(x0 - y0*(x2 - x0)/(y2 - y0)), \ + cr = y0>=0?c0:(c0 - y0*(c2 - c0)/(y2 - y0)), \ + txr = y0>=0?tx0:(tx0 - y0*(tx2 - tx0)/(y2 - y0)), \ + tyr = y0>=0?ty0:(ty0 - y0*(ty2 - ty0)/(y2 - y0)), \ + xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0 - y0*(x1 - x0)/(y1 - y0))):(x1 - y1*(x2 - x1)/(y2 - y1)), \ + cl = y1>=0?(y0>=0?(y0==y1?c1:c0):(c0 - y0*(c1 - c0)/(y1 - y0))):(c1 - y1*(c2 - c1)/(y2 - y1)), \ + txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0 - y0*(tx1 - tx0)/(y1 - y0))):(tx1 - y1*(tx2 - tx1)/(y2 - y1)), \ + tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0 - y0*(ty1 - ty0)/(y1 - y0))):(ty1 - y1*(ty2 - ty1)/(y2 - y1)), \ _sxn=1, _scn=1, _stxn=1, _styn=1, \ _sxr=1, _scr=1, _stxr=1, _styr=1, \ _sxl=1, _scl=1, _stxl=1, _styl=1, \ - _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \ - _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \ - _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \ - _dcn = c2>c1?c2-c1:(_scn=-1,c1-c2), \ - _dcr = c2>c0?c2-c0:(_scr=-1,c0-c2), \ - _dcl = c1>c0?c1-c0:(_scl=-1,c0-c1), \ - _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \ - _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \ - _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \ - _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \ - _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \ - _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \ - _dyn = y2-y1, \ - _dyr = y2-y0, \ - _dyl = y1-y0, \ + _dxn = x2>x1?x2 - x1:(_sxn=-1,x1 - x2), \ + _dxr = x2>x0?x2 - x0:(_sxr=-1,x0 - x2), \ + _dxl = x1>x0?x1 - x0:(_sxl=-1,x0 - x1), \ + _dcn = c2>c1?c2 - c1:(_scn=-1,c1 - c2), \ + _dcr = c2>c0?c2 - c0:(_scr=-1,c0 - c2), \ + _dcl = c1>c0?c1 - c0:(_scl=-1,c0 - c1), \ + _dtxn = tx2>tx1?tx2 - tx1:(_stxn=-1,tx1 - tx2), \ + _dtxr = tx2>tx0?tx2 - tx0:(_stxr=-1,tx0 - tx2), \ + _dtxl = tx1>tx0?tx1 - tx0:(_stxl=-1,tx0 - tx1), \ + _dtyn = ty2>ty1?ty2 - ty1:(_styn=-1,ty1 - ty2), \ + _dtyr = ty2>ty0?ty2 - ty0:(_styr=-1,ty0 - ty2), \ + _dtyl = ty1>ty0?ty1 - ty0:(_styl=-1,ty0 - ty1), \ + _dyn = y2 - y1, \ + _dyr = y2 - y0, \ + _dyl = y1 - y0, \ _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \ _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \ _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \ @@ -31936,25 +32616,25 @@ namespace cimg_library_suffixed { _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \ _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \ _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \ - cimg::min((int)(img)._height-y-1,y2-y)), \ + cimg::min((int)(img)._height - y - 1,y2 - y)), \ _errn = _dyn/2, _errcn = _errn, _errtxn = _errn, _errtyn = _errn, \ _errr = _dyr/2, _errcr = _errr, _errtxr = _errr, _errtyr = _errr, \ _errl = _dyl/2, _errcl = _errl, _errtxl = _errl, _errtyl = _errl, \ - _rxn = _dyn?(x2-x1)/_dyn:0, \ - _rcn = _dyn?(c2-c1)/_dyn:0, \ - _rtxn = _dyn?(tx2-tx1)/_dyn:0, \ - _rtyn = _dyn?(ty2-ty1)/_dyn:0, \ - _rxr = _dyr?(x2-x0)/_dyr:0, \ - _rcr = _dyr?(c2-c0)/_dyr:0, \ - _rtxr = _dyr?(tx2-tx0)/_dyr:0, \ - _rtyr = _dyr?(ty2-ty0)/_dyr:0, \ - _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \ + _rxn = _dyn?(x2 - x1)/_dyn:0, \ + _rcn = _dyn?(c2 - c1)/_dyn:0, \ + _rtxn = _dyn?(tx2 - tx1)/_dyn:0, \ + _rtyn = _dyn?(ty2 - ty1)/_dyn:0, \ + _rxr = _dyr?(x2 - x0)/_dyr:0, \ + _rcr = _dyr?(c2 - c0)/_dyr:0, \ + _rtxr = _dyr?(tx2 - tx0)/_dyr:0, \ + _rtyr = _dyr?(ty2 - ty0)/_dyr:0, \ + _rxl = (y0!=y1 && y1>0)?(_dyl?(x1 - x0)/_dyl:0): \ (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \ - _rcl = (y0!=y1 && y1>0)?(_dyl?(c1-c0)/_dyl:0): \ + _rcl = (y0!=y1 && y1>0)?(_dyl?(c1 - c0)/_dyl:0): \ (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcn ), \ - _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \ + _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1 - tx0)/_dyl:0): \ (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \ - _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \ + _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1 - ty0)/_dyl:0): \ (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ); \ _counter>=0; --_counter, ++y, \ xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \ @@ -31968,39 +32648,39 @@ namespace cimg_library_suffixed { (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcl=_rcn, cl=c1, \ _errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \ _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1, \ - _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl)) + _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1 - xl)) #define _cimg_for_triangle5(img,xl,txl,tyl,lxl,lyl,xr,txr,tyr,lxr,lyr,y,x0,y0,\ tx0,ty0,lx0,ly0,x1,y1,tx1,ty1,lx1,ly1,x2,y2,tx2,ty2,lx2,ly2) \ for (int y = y0<0?0:y0, \ - xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \ - txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \ - tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \ - lxr = y0>=0?lx0:(lx0-y0*(lx2-lx0)/(y2-y0)), \ - lyr = y0>=0?ly0:(ly0-y0*(ly2-ly0)/(y2-y0)), \ - xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \ - txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \ - tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \ - lxl = y1>=0?(y0>=0?(y0==y1?lx1:lx0):(lx0-y0*(lx1-lx0)/(y1-y0))):(lx1-y1*(lx2-lx1)/(y2-y1)), \ - lyl = y1>=0?(y0>=0?(y0==y1?ly1:ly0):(ly0-y0*(ly1-ly0)/(y1-y0))):(ly1-y1*(ly2-ly1)/(y2-y1)), \ + xr = y0>=0?x0:(x0 - y0*(x2 - x0)/(y2 - y0)), \ + txr = y0>=0?tx0:(tx0 - y0*(tx2 - tx0)/(y2 - y0)), \ + tyr = y0>=0?ty0:(ty0 - y0*(ty2 - ty0)/(y2 - y0)), \ + lxr = y0>=0?lx0:(lx0 - y0*(lx2 - lx0)/(y2 - y0)), \ + lyr = y0>=0?ly0:(ly0 - y0*(ly2 - ly0)/(y2 - y0)), \ + xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0 - y0*(x1 - x0)/(y1 - y0))):(x1 - y1*(x2 - x1)/(y2 - y1)), \ + txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0 - y0*(tx1 - tx0)/(y1 - y0))):(tx1 - y1*(tx2 - tx1)/(y2 - y1)), \ + tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0 - y0*(ty1 - ty0)/(y1 - y0))):(ty1 - y1*(ty2 - ty1)/(y2 - y1)), \ + lxl = y1>=0?(y0>=0?(y0==y1?lx1:lx0):(lx0 - y0*(lx1 - lx0)/(y1 - y0))):(lx1 - y1*(lx2 - lx1)/(y2 - y1)), \ + lyl = y1>=0?(y0>=0?(y0==y1?ly1:ly0):(ly0 - y0*(ly1 - ly0)/(y1 - y0))):(ly1 - y1*(ly2 - ly1)/(y2 - y1)), \ _sxn=1, _stxn=1, _styn=1, _slxn=1, _slyn=1, \ _sxr=1, _stxr=1, _styr=1, _slxr=1, _slyr=1, \ _sxl=1, _stxl=1, _styl=1, _slxl=1, _slyl=1, \ - _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), _dyn = y2-y1, \ - _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), _dyr = y2-y0, \ - _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), _dyl = y1-y0, \ - _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \ - _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \ - _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \ - _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \ - _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \ - _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \ - _dlxn = lx2>lx1?lx2-lx1:(_slxn=-1,lx1-lx2), \ - _dlxr = lx2>lx0?lx2-lx0:(_slxr=-1,lx0-lx2), \ - _dlxl = lx1>lx0?lx1-lx0:(_slxl=-1,lx0-lx1), \ - _dlyn = ly2>ly1?ly2-ly1:(_slyn=-1,ly1-ly2), \ - _dlyr = ly2>ly0?ly2-ly0:(_slyr=-1,ly0-ly2), \ - _dlyl = ly1>ly0?ly1-ly0:(_slyl=-1,ly0-ly1), \ + _dxn = x2>x1?x2 - x1:(_sxn=-1,x1 - x2), _dyn = y2 - y1, \ + _dxr = x2>x0?x2 - x0:(_sxr=-1,x0 - x2), _dyr = y2 - y0, \ + _dxl = x1>x0?x1 - x0:(_sxl=-1,x0 - x1), _dyl = y1 - y0, \ + _dtxn = tx2>tx1?tx2 - tx1:(_stxn=-1,tx1 - tx2), \ + _dtxr = tx2>tx0?tx2 - tx0:(_stxr=-1,tx0 - tx2), \ + _dtxl = tx1>tx0?tx1 - tx0:(_stxl=-1,tx0 - tx1), \ + _dtyn = ty2>ty1?ty2 - ty1:(_styn=-1,ty1 - ty2), \ + _dtyr = ty2>ty0?ty2 - ty0:(_styr=-1,ty0 - ty2), \ + _dtyl = ty1>ty0?ty1 - ty0:(_styl=-1,ty0 - ty1), \ + _dlxn = lx2>lx1?lx2 - lx1:(_slxn=-1,lx1 - lx2), \ + _dlxr = lx2>lx0?lx2 - lx0:(_slxr=-1,lx0 - lx2), \ + _dlxl = lx1>lx0?lx1 - lx0:(_slxl=-1,lx0 - lx1), \ + _dlyn = ly2>ly1?ly2 - ly1:(_slyn=-1,ly1 - ly2), \ + _dlyr = ly2>ly0?ly2 - ly0:(_slyr=-1,ly0 - ly2), \ + _dlyl = ly1>ly0?ly1 - ly0:(_slyl=-1,ly0 - ly1), \ _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \ _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \ _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \ @@ -32016,29 +32696,29 @@ namespace cimg_library_suffixed { _dlyn-=_dyn?_dyn*(_dlyn/_dyn):0, \ _dlyr-=_dyr?_dyr*(_dlyr/_dyr):0, \ _dlyl-=_dyl?_dyl*(_dlyl/_dyl):0, \ - cimg::min((int)(img)._height-y-1,y2-y)), \ + cimg::min((int)(img)._height - y - 1,y2 - y)), \ _errn = _dyn/2, _errtxn = _errn, _errtyn = _errn, _errlxn = _errn, _errlyn = _errn, \ _errr = _dyr/2, _errtxr = _errr, _errtyr = _errr, _errlxr = _errr, _errlyr = _errr, \ _errl = _dyl/2, _errtxl = _errl, _errtyl = _errl, _errlxl = _errl, _errlyl = _errl, \ - _rxn = _dyn?(x2-x1)/_dyn:0, \ - _rtxn = _dyn?(tx2-tx1)/_dyn:0, \ - _rtyn = _dyn?(ty2-ty1)/_dyn:0, \ - _rlxn = _dyn?(lx2-lx1)/_dyn:0, \ - _rlyn = _dyn?(ly2-ly1)/_dyn:0, \ - _rxr = _dyr?(x2-x0)/_dyr:0, \ - _rtxr = _dyr?(tx2-tx0)/_dyr:0, \ - _rtyr = _dyr?(ty2-ty0)/_dyr:0, \ - _rlxr = _dyr?(lx2-lx0)/_dyr:0, \ - _rlyr = _dyr?(ly2-ly0)/_dyr:0, \ - _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \ + _rxn = _dyn?(x2 - x1)/_dyn:0, \ + _rtxn = _dyn?(tx2 - tx1)/_dyn:0, \ + _rtyn = _dyn?(ty2 - ty1)/_dyn:0, \ + _rlxn = _dyn?(lx2 - lx1)/_dyn:0, \ + _rlyn = _dyn?(ly2 - ly1)/_dyn:0, \ + _rxr = _dyr?(x2 - x0)/_dyr:0, \ + _rtxr = _dyr?(tx2 - tx0)/_dyr:0, \ + _rtyr = _dyr?(ty2 - ty0)/_dyr:0, \ + _rlxr = _dyr?(lx2 - lx0)/_dyr:0, \ + _rlyr = _dyr?(ly2 - ly0)/_dyr:0, \ + _rxl = (y0!=y1 && y1>0)?(_dyl?(x1 - x0)/_dyl:0): \ (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \ - _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \ + _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1 - tx0)/_dyl:0): \ (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \ - _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \ + _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1 - ty0)/_dyl:0): \ (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ), \ - _rlxl = (y0!=y1 && y1>0)?(_dyl?(lx1-lx0)/_dyl:0): \ + _rlxl = (y0!=y1 && y1>0)?(_dyl?(lx1 - lx0)/_dyl:0): \ (_errlxl=_errlxn, _dlxl=_dlxn, _dyl=_dyn, _slxl=_slxn, _rlxn ), \ - _rlyl = (y0!=y1 && y1>0)?(_dyl?(ly1-ly0)/_dyl:0): \ + _rlyl = (y0!=y1 && y1>0)?(_dyl?(ly1 - ly0)/_dyl:0): \ (_errlyl=_errlyn, _dlyl=_dlyn, _dyl=_dyn, _slyl=_slyn, _rlyn ); \ _counter>=0; --_counter, ++y, \ xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \ @@ -32055,7 +32735,7 @@ namespace cimg_library_suffixed { _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1, \ _errlxl=_errlxn, _dlxl=_dlxn, _dyl=_dyn, _slxl=_slxn, _rlxl=_rlxn, lxl=lx1, \ _errlyl=_errlyn, _dlyl=_dlyn, _dyl=_dyn, _slyl=_slyn, _rlyl=_rlyn, lyl=ly1, \ - _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl)) + _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1 - xl)) // [internal] Draw a filled triangle. template @@ -32174,7 +32854,7 @@ namespace cimg_library_suffixed { const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0), nbrightness = brightness<0?0:(brightness>2?2:brightness); - const long whd = (long)_width*_height*_depth, offx = _spectrum*whd; + const long whd = width()*height()*depth(), offx = spectrum()*whd; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2; tzfloat nz0 = 1/(tzfloat)z0, nz1 = 1/(tzfloat)z1, nz2 = 1/(tzfloat)z2; if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1); @@ -32196,9 +32876,9 @@ namespace cimg_library_suffixed { const tzfloat pentez = (zright - zleft)/dx; if (xleft<0 && dx) zleft-=xleft*(zright - zleft)/dx; if (xleft<0) xleft = 0; - if (xright>=width()-1) xright = width() - 1; + if (xright>=width() - 1) xright = width() - 1; T* ptrd = data(xleft,y,0,0); - tz *ptrz = zbuffer.data(xleft,y); + tz *ptrz = xleft<=xright?zbuffer.data(xleft,y):0; if (opacity>=1) { if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { if (zleft>=(tzfloat)*ptrz) { @@ -32218,7 +32898,7 @@ namespace cimg_library_suffixed { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tc *col = color; - cimg_forC(*this,c) { *ptrd = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval); ptrd+=whd; } + cimg_forC(*this,c) { *ptrd = (T)((2 - nbrightness)**(col++) + (nbrightness - 1)*maxval); ptrd+=whd; } ptrd-=offx; } zleft+=pentez; @@ -32244,7 +32924,7 @@ namespace cimg_library_suffixed { *ptrz = (tz)zleft; const tc *col = color; cimg_forC(*this,c) { - const T val = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval); + const T val = (T)((2 - nbrightness)**(col++) + (nbrightness - 1)*maxval); *ptrd = (T)(nopacity*val + *ptrd*copacity); ptrd+=whd; } @@ -32288,7 +32968,7 @@ namespace cimg_library_suffixed { cimg_instance); static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); - const long whd = (long)_width*_height*_depth, offx = _spectrum*whd-1; + const long whd = width()*height()*depth(), offx = spectrum()*whd - 1; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f), nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f), @@ -32305,16 +32985,16 @@ namespace cimg_library_suffixed { 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); + ndc = dc - (dx?dx*(dc/dx):0); int errc = dx>>1; if (xleft<0 && dx) cleft-=xleft*(cright - cleft)/dx; if (xleft<0) xleft = 0; - if (xright>=width()-1) xright = width() - 1; + if (xright>=width() - 1) xright = width() - 1; T* ptrd = data(xleft,y); if (opacity>=1) for (int x = xleft; x<=xright; ++x) { const tc *col = color; cimg_forC(*this,c) { - *ptrd = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256); + *ptrd = (T)(cleft<256?cleft**(col++)/256:((512 - cleft)**(col++)+(cleft - 256)*maxval)/256); ptrd+=whd; } ptrd-=offx; @@ -32322,7 +33002,7 @@ namespace cimg_library_suffixed { } else for (int x = xleft; x<=xright; ++x) { const tc *col = color; cimg_forC(*this,c) { - const T val = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256); + const T val = (T)(cleft<256?cleft**(col++)/256:((512 - cleft)**(col++)+(cleft - 256)*maxval)/256); *ptrd = (T)(nopacity*val + *ptrd*copacity); ptrd+=whd; } @@ -32358,7 +33038,7 @@ namespace cimg_library_suffixed { zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); - const long whd = (long)_width*_height*_depth, offx = _spectrum*whd; + const long whd = 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), @@ -32382,9 +33062,9 @@ namespace cimg_library_suffixed { const int dx = xright - xleft, dc = cright>cleft?cright - cleft:cleft - cright, - rc = dx?(cright-cleft)/dx:0, + rc = dx?(cright - cleft)/dx:0, sc = cright>cleft?1:-1, - ndc = dc-(dx?dx*(dc/dx):0); + ndc = dc - (dx?dx*(dc/dx):0); const tzfloat pentez = (zright - zleft)/dx; int errc = dx>>1; if (xleft<0 && dx) { @@ -32392,15 +33072,15 @@ namespace cimg_library_suffixed { zleft-=xleft*(zright - zleft)/dx; } if (xleft<0) xleft = 0; - if (xright>=width()-1) xright = width()-1; + if (xright>=width() - 1) xright = width() - 1; T *ptrd = data(xleft,y); - tz *ptrz = zbuffer.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 = (T)(cleft<256?cleft**(col++)/256:((512 - cleft)**(col++)+(cleft - 256)*maxval)/256); ptrd+=whd; } ptrd-=offx; @@ -32412,7 +33092,7 @@ namespace cimg_library_suffixed { *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); + const T val = (T)(cleft<256?cleft**(col++)/256:((512 - cleft)**(col++)+(cleft - 256)*maxval)/256); *ptrd = (T)(nopacity*val + *ptrd*copacity); ptrd+=whd; } @@ -32493,8 +33173,10 @@ namespace cimg_library_suffixed { const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0), nbrightness = brightness<0?0:(brightness>2?2:brightness); - const long whd = (long)_width*_height*_depth, twhd = (long)texture._width*texture._height*texture._depth, - offx = _spectrum*whd-1; + const unsigned long + whd = (unsigned long)_width*_height*_depth, + twh = (unsigned long)texture._width*texture._height, + offx = _spectrum*whd - 1; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2; if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1); @@ -32524,32 +33206,32 @@ namespace cimg_library_suffixed { tyleft-=xleft*(tyright - tyleft)/dx; } if (xleft<0) xleft = 0; - if (xright>=width()-1) xright = width()-1; + 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 tc *col = texture.data(txleft,tyleft); + const tc *col = &texture._atXY(txleft,tyleft); cimg_forC(*this,c) { *ptrd = (T)*col; - ptrd+=whd; col+=twhd; + ptrd+=whd; col+=twh; } ptrd-=offx; txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) { - const tc *col = texture.data(txleft,tyleft); + const tc *col = &texture._atXY(txleft,tyleft); cimg_forC(*this,c) { *ptrd = (T)(nbrightness**col); - ptrd+=whd; col+=twhd; + ptrd+=whd; col+=twh; } ptrd-=offx; txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); } else for (int x = xleft; x<=xright; ++x) { - const tc *col = texture.data(txleft,tyleft); + const tc *col = &texture._atXY(txleft,tyleft); cimg_forC(*this,c) { - *ptrd = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval); - ptrd+=whd; col+=twhd; + *ptrd = (T)((2 - nbrightness)**(col++) + (nbrightness - 1)*maxval); + ptrd+=whd; col+=twh; } ptrd-=offx; txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); @@ -32557,29 +33239,29 @@ namespace cimg_library_suffixed { } } else { if (nbrightness==1) for (int x = xleft; x<=xright; ++x) { - const tc *col = texture.data(txleft,tyleft); + const tc *col = &texture._atXY(txleft,tyleft); cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); - ptrd+=whd; col+=twhd; + ptrd+=whd; col+=twh; } ptrd-=offx; txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) { - const tc *col = texture.data(txleft,tyleft); + const tc *col = &texture._atXY(txleft,tyleft); cimg_forC(*this,c) { *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity); - ptrd+=whd; col+=twhd; + ptrd+=whd; col+=twh; } ptrd-=offx; txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); } else for (int x = xleft; x<=xright; ++x) { - const tc *col = texture.data(txleft,tyleft); + const tc *col = &texture._atXY(txleft,tyleft); cimg_forC(*this,c) { - const T val = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval); + const T val = (T)((2 - nbrightness)**(col++) + (nbrightness - 1)*maxval); *ptrd = (T)(nopacity*val + *ptrd*copacity); - ptrd+=whd; col+=twhd; + ptrd+=whd; col+=twh; } ptrd-=offx; txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); @@ -32613,8 +33295,10 @@ namespace cimg_library_suffixed { const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0), nbrightness = brightness<0?0:(brightness>2?2:brightness); - const long whd = (long)_width*_height*_depth, twhd = (long)texture._width*texture._height*texture._depth, - offx = _spectrum*whd-1; + const unsigned long + whd = (unsigned long)_width*_height*_depth, + twh = (unsigned long)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, @@ -32662,58 +33346,58 @@ namespace cimg_library_suffixed { tyleft-=xleft*(tyright - tyleft)/dx; } if (xleft<0) xleft = 0; - if (xright>=width()-1) xright = width()-1; + 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.data((int)(txleft*invz),(int)(tyleft*invz)); + const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { *ptrd = (T)*col; - ptrd+=whd; col+=twhd; + 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.data((int)(txleft*invz),(int)(tyleft*invz)); + const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { *ptrd = (T)(nbrightness**col); - ptrd+=whd; col+=twhd; + 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.data((int)(txleft*invz),(int)(tyleft*invz)); + 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+=twhd; + *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.data((int)(txleft*invz),(int)(tyleft*invz)); + const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); - ptrd+=whd; col+=twhd; + 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.data((int)(txleft*invz),(int)(tyleft*invz)); + 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+=twhd; + 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.data((int)(txleft*invz),(int)(tyleft*invz)); + 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); + const T val = (T)((2 - nbrightness)**col + (nbrightness - 1)*maxval); *ptrd = (T)(nopacity*val + *ptrd*copacity); - ptrd+=whd; col+=twhd; + ptrd+=whd; col+=twh; } ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; } @@ -32755,7 +33439,9 @@ namespace cimg_library_suffixed { const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0), nbrightness = brightness<0?0:(brightness>2?2:brightness); - const long whd = (long)_width*_height*_depth, twhd = (long)texture._width*texture._height*texture._depth, + const unsigned long + whd = (unsigned long)_width*_height*_depth, + twh = (unsigned long)texture._width*texture._height, offx = _spectrum*whd; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2; float @@ -32801,7 +33487,7 @@ namespace cimg_library_suffixed { tyleft-=xleft*(tyright - tyleft)/dx; } if (xleft<0) xleft = 0; - if (xright>=width()-1) xright = width()-1; + if (xright>=width() - 1) xright = width() - 1; T *ptrd = data(xleft,y,0,0); tz *ptrz = zbuffer.data(xleft,y); if (opacity>=1) { @@ -32809,10 +33495,10 @@ namespace cimg_library_suffixed { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tzfloat invz = 1/zleft; - const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); + const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { *ptrd = (T)*col; - ptrd+=whd; col+=twhd; + ptrd+=whd; col+=twh; } ptrd-=offx; } @@ -32821,10 +33507,10 @@ namespace cimg_library_suffixed { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tzfloat invz = 1/zleft; - const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); + const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { *ptrd = (T)(nbrightness**col); - ptrd+=whd; col+=twhd; + ptrd+=whd; col+=twh; } ptrd-=offx; } @@ -32833,10 +33519,10 @@ namespace cimg_library_suffixed { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tzfloat invz = 1/zleft; - const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); + 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+=twhd; + *ptrd = (T)((2 - nbrightness)**col + (nbrightness - 1)*maxval); + ptrd+=whd; col+=twh; } ptrd-=offx; } @@ -32847,10 +33533,10 @@ namespace cimg_library_suffixed { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tzfloat invz = 1/zleft; - const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); + const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); - ptrd+=whd; col+=twhd; + ptrd+=whd; col+=twh; } ptrd-=offx; } @@ -32859,10 +33545,10 @@ namespace cimg_library_suffixed { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tzfloat invz = 1/zleft; - const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); + 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+=twhd; + ptrd+=whd; col+=twh; } ptrd-=offx; } @@ -32871,11 +33557,11 @@ namespace cimg_library_suffixed { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tzfloat invz = 1/zleft; - const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); + 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); + const T val = (T)((2 - nbrightness)**col + (nbrightness - 1)*maxval); *ptrd = (T)(nopacity*val + *ptrd*copacity); - ptrd+=whd; col+=twhd; + ptrd+=whd; col+=twh; } ptrd-=offx; } @@ -32929,7 +33615,10 @@ namespace cimg_library_suffixed { const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2; - const long whd = (long)_width*_height*_depth, offx = _spectrum*whd-1; + const unsigned long + whd = (unsigned long)_width*_height*_depth, + lwh = (unsigned long)light._width*light._height, + offx = _spectrum*whd - 1; if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nlx0,nlx1,nly0,nly1); if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nlx0,nlx2,nly0,nly2); if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nlx1,nlx2,nly1,nly2); @@ -32957,25 +33646,27 @@ namespace cimg_library_suffixed { lyleft-=xleft*(lyright - lyleft)/dx; } if (xleft<0) xleft = 0; - if (xright>=width()-1) xright = width()-1; + if (xright>=width() - 1) xright = width() - 1; T* ptrd = data(xleft,y,0,0); if (opacity>=1) for (int x = xleft; x<=xright; ++x) { const tc *col = color; + const tl *lig = &light._atXY(lxleft,lyleft); cimg_forC(*this,c) { - const tl l = light(lxleft,lyleft,c); - *ptrd = (T)(l<1?l**(col++):((2-l)**(col++)+(l-1)*maxval)); - ptrd+=whd; + const tl l = *lig; + *ptrd = (T)(l<1?l**(col++):((2 - l)**(col++) + (l - 1)*maxval)); + ptrd+=whd; lig+=lwh; } ptrd-=offx; lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0); } else for (int x = xleft; x<=xright; ++x) { const tc *col = color; + const tl *lig = &light._atXY(lxleft,lyleft); cimg_forC(*this,c) { - const tl l = light(lxleft,lyleft,c); - const T val = (T)(l<1?l**(col++):((2-l)**(col++)+(l-1)*maxval)); + const tl l = *lig; + const T val = (T)(l<1?l**(col++):((2 - l)**(col++) + (l - 1)*maxval)); *ptrd = (T)(nopacity*val + *ptrd*copacity); - ptrd+=whd; + ptrd+=whd; lig+=lwh; } ptrd-=offx; lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); @@ -33017,7 +33708,10 @@ namespace cimg_library_suffixed { +light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); - const long whd = (long)_width*_height*_depth, offx = _spectrum*whd; + const unsigned long + whd = (unsigned long)_width*_height*_depth, + lwh = (unsigned long)light._width*light._height, + offx = _spectrum*whd; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2; tzfloat nz0 = 1/(tzfloat)z0, nz1 = 1/(tzfloat)z1, nz2 = 1/(tzfloat)z2; @@ -33058,18 +33752,19 @@ namespace cimg_library_suffixed { lyleft-=xleft*(lyright - lyleft)/dx; } if (xleft<0) xleft = 0; - if (xright>=width()-1) xright = width()-1; + if (xright>=width() - 1) xright = width() - 1; T *ptrd = data(xleft,y,0,0); - tz *ptrz = zbuffer.data(xleft,y); + tz *ptrz = xleft<=xright?zbuffer.data(xleft,y):0; if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tc *col = color; + const tl *lig = &light._atXY(lxleft,lyleft); cimg_forC(*this,c) { - const tl l = light(lxleft,lyleft,c); + const tl l = *lig; const tc cval = *(col++); - *ptrd = (T)(l<1?l*cval:(2-l)*cval+(l-1)*maxval); - ptrd+=whd; + *ptrd = (T)(l<1?l*cval:(2 - l)*cval + (l - 1)*maxval); + ptrd+=whd; lig+=lwh; } ptrd-=offx; } @@ -33080,12 +33775,13 @@ namespace cimg_library_suffixed { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tc *col = color; + const tl *lig = &light._atXY(lxleft,lyleft); cimg_forC(*this,c) { - const tl l = light(lxleft,lyleft,c); + const tl l = *lig; const tc cval = *(col++); - const T val = (T)(l<1?l*cval:(2-l)*cval+(l-1)*maxval); + const T val = (T)(l<1?l*cval:(2 - l)*cval + (l - 1)*maxval); *ptrd = (T)(nopacity*val + *ptrd*copacity); - ptrd+=whd; + ptrd+=whd; lig+=lwh; } ptrd-=offx; } @@ -33141,8 +33837,10 @@ namespace cimg_library_suffixed { brightness0,brightness1,brightness2,opacity); static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); - const long whd = (long)_width*_height*_depth, twhd = (long)texture._width*texture._height*texture._depth, - offx = _spectrum*whd-1; + const unsigned long + whd = (unsigned long)_width*_height*_depth, + twh = (unsigned long)texture._width*texture._height, + offx = _spectrum*whd - 1; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2, nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f), @@ -33181,24 +33879,24 @@ namespace cimg_library_suffixed { tyleft-=xleft*(tyright - tyleft)/dx; } if (xleft<0) xleft = 0; - if (xright>=width()-1) xright = width()-1; + if (xright>=width() - 1) xright = width() - 1; T* ptrd = data(xleft,y,0,0); if (opacity>=1) for (int x = xleft; x<=xright; ++x) { - const tc *col = texture.data(txleft,tyleft); + const tc *col = &texture._atXY(txleft,tyleft); cimg_forC(*this,c) { - *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256); - ptrd+=whd; col+=twhd; + *ptrd = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256); + ptrd+=whd; col+=twh; } ptrd-=offx; cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); } else for (int x = xleft; x<=xright; ++x) { - const tc *col = texture.data(txleft,tyleft); + const tc *col = &texture._atXY(txleft,tyleft); cimg_forC(*this,c) { - const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256); + const T val = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256); *ptrd = (T)(nopacity*val + *ptrd*copacity); - ptrd+=whd; col+=twhd; + ptrd+=whd; col+=twh; } ptrd-=offx; cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); @@ -33232,8 +33930,10 @@ namespace cimg_library_suffixed { brightness0,brightness1,brightness2,opacity); static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); - const long whd = (long)_width*_height*_depth, twhd = (long)texture._width*texture._height*texture._depth, - offx = _spectrum*whd-1; + const unsigned long + whd = (unsigned long)_width*_height*_depth, + twh = (unsigned long)texture._width*texture._height, + offx = _spectrum*whd - 1; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f), nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f), @@ -33293,24 +33993,24 @@ namespace cimg_library_suffixed { tyleft-=xleft*(tyright - tyleft)/dx; } if (xleft<0) xleft = 0; - if (xright>=width()-1) xright = width()-1; + if (xright>=width() - 1) xright = width() - 1; T* ptrd = data(xleft,y,0,0); if (opacity>=1) for (int x = xleft; x<=xright; ++x) { const float invz = 1/zleft; - const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); + const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { - *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256); - ptrd+=whd; col+=twhd; + *ptrd = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256); + ptrd+=whd; col+=twh; } ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); } else for (int x = xleft; x<=xright; ++x) { const float invz = 1/zleft; - const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); + const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { - const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256); + const T val = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256); *ptrd = (T)(nopacity*val + *ptrd*copacity); - ptrd+=whd; col+=twhd; + ptrd+=whd; col+=twh; } ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); @@ -33352,7 +34052,9 @@ namespace cimg_library_suffixed { brightness0,brightness1,brightness2,opacity); static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); - const long whd = (long)_width*_height*_depth, twhd = (long)texture._width*texture._height*texture._depth, + const unsigned long + whd = (unsigned long)_width*_height*_depth, + twh = (unsigned long)texture._width*texture._height, offx = _spectrum*whd; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f), @@ -33408,17 +34110,17 @@ namespace cimg_library_suffixed { tyleft-=xleft*(tyright - tyleft)/dx; } if (xleft<0) xleft = 0; - if (xright>=width()-1) xright = width()-1; + if (xright>=width() - 1) xright = width() - 1; T* ptrd = data(xleft,y); tz *ptrz = zbuffer.data(xleft,y); if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tzfloat invz = 1/zleft; - const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); + const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { - *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256); - ptrd+=whd; col+=twhd; + *ptrd = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256); + ptrd+=whd; col+=twh; } ptrd-=offx; } @@ -33428,11 +34130,11 @@ namespace cimg_library_suffixed { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tzfloat invz = 1/zleft; - const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); + const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); cimg_forC(*this,c) { - const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256); + const T val = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256); *ptrd = (T)(nopacity*val + *ptrd*copacity); - ptrd+=whd; col+=twhd; + ptrd+=whd; col+=twh; } ptrd-=offx; } @@ -33497,8 +34199,11 @@ namespace cimg_library_suffixed { return draw_triangle(x0,y0,x1,y1,x2,y2,texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); - const long whd = (long)_width*_height*_depth, twhd = (long)texture._width*texture._height*texture._depth, - offx = _spectrum*whd-1; + const unsigned long + whd = (unsigned long)_width*_height*_depth, + twh = (unsigned long)texture._width*texture._height, + lwh = (unsigned long)light._width*light._height, + offx = _spectrum*whd - 1; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2, nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2; @@ -33541,14 +34246,15 @@ namespace cimg_library_suffixed { tyleft-=xleft*(tyright - tyleft)/dx; } if (xleft<0) xleft = 0; - if (xright>=width()-1) xright = width()-1; + if (xright>=width() - 1) xright = width() - 1; T* ptrd = data(xleft,y,0,0); if (opacity>=1) for (int x = xleft; x<=xright; ++x) { - const tc *col = texture.data(txleft,tyleft); + const tc *col = &texture._atXY(txleft,tyleft); + const tl *lig = &light._atXY(lxleft,lyleft); cimg_forC(*this,c) { - const tl l = light(lxleft,lyleft,c); - *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval); - ptrd+=whd; col+=twhd; + const tl l = *lig; + *ptrd = (T)(l<1?l**col:(2 - l)**col + (l - 1)*maxval); + ptrd+=whd; col+=twh; lig+=lwh; } ptrd-=offx; lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); @@ -33556,12 +34262,13 @@ namespace cimg_library_suffixed { txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); } else for (int x = xleft; x<=xright; ++x) { - const tc *col = texture.data(txleft,tyleft); + const tc *col = &texture._atXY(txleft,tyleft); + const tl *lig = &light._atXY(lxleft,lyleft); cimg_forC(*this,c) { - const tl l = light(lxleft,lyleft,c); - const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval); + const tl l = *lig; + const T val = (T)(l<1?l**col:(2 - l)**col + (l - 1)*maxval); *ptrd = (T)(nopacity*val + *ptrd*copacity); - ptrd+=whd; col+=twhd; + ptrd+=whd; col+=twh; lig+=lwh; } ptrd-=offx; lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); @@ -33605,8 +34312,11 @@ namespace cimg_library_suffixed { +light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); - const long whd = (long)_width*_height*_depth, twhd = (long)texture._width*texture._height*texture._depth, - offx = _spectrum*whd-1; + const unsigned long + whd = (unsigned long)_width*_height*_depth, + twh = (unsigned long)texture._width*texture._height, + lwh = (unsigned long)light._width*light._height, + offx = _spectrum*whd - 1; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2; float @@ -33672,27 +34382,29 @@ namespace cimg_library_suffixed { tyleft-=xleft*(tyright - tyleft)/dx; } if (xleft<0) xleft = 0; - if (xright>=width()-1) xright = width()-1; + if (xright>=width() - 1) xright = width() - 1; T* ptrd = data(xleft,y,0,0); if (opacity>=1) for (int x = xleft; x<=xright; ++x) { const float invz = 1/zleft; - const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); + const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); + const tl *lig = &light._atXY(lxleft,lyleft); cimg_forC(*this,c) { - const tl l = light(lxleft,lyleft,c); - *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval); - ptrd+=whd; col+=twhd; + const tl l = *lig; + *ptrd = (T)(l<1?l**col:(2 - l)**col + (l - 1)*maxval); + ptrd+=whd; col+=twh; lig+=lwh; } ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0); } else for (int x = xleft; x<=xright; ++x) { const float invz = 1/zleft; - const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); + const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); + const tl *lig = &light._atXY(lxleft,lyleft); cimg_forC(*this,c) { - const tl l = light(lxleft,lyleft,c); - const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval); + const tl l = *lig; + const T val = (T)(l<1?l**col:(2 - l)**col + (l - 1)*maxval); *ptrd = (T)(nopacity*val + *ptrd*copacity); - ptrd+=whd; col+=twhd; + ptrd+=whd; col+=twh; lig+=lwh; } ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); @@ -33743,7 +34455,10 @@ namespace cimg_library_suffixed { texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); static const T maxval = (T)cimg::min(cimg::type::max(),cimg::type::max()); const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); - const long whd = (long)_width*_height*_depth, twhd = (long)texture._width*texture._height*texture._depth, + const unsigned long + whd = (unsigned long)_width*_height*_depth, + twh = (unsigned long)texture._width*texture._height, + lwh = (unsigned long)light._width*light._height, offx = _spectrum*whd; int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2; @@ -33807,18 +34522,19 @@ namespace cimg_library_suffixed { tyleft-=xleft*(tyright - tyleft)/dx; } if (xleft<0) xleft = 0; - if (xright>=width()-1) xright = width()-1; + if (xright>=width() - 1) xright = width() - 1; T* ptrd = data(xleft,y); tz *ptrz = zbuffer.data(xleft,y); if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tzfloat invz = 1/zleft; - const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); + const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); + const tl *lig = &light._atXY(lxleft,lyleft); cimg_forC(*this,c) { - const tl l = light(lxleft,lyleft,c); - *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval); - ptrd+=whd; col+=twhd; + const tl l = *lig; + *ptrd = (T)(l<1?l**col:(2 - l)**col + (l - 1)*maxval); + ptrd+=whd; col+=twh; lig+=lwh; } ptrd-=offx; } @@ -33829,12 +34545,13 @@ namespace cimg_library_suffixed { if (zleft>=(tzfloat)*ptrz) { *ptrz = (tz)zleft; const tzfloat invz = 1/zleft; - const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); + const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz)); + const tl *lig = &light._atXY(lxleft,lyleft); cimg_forC(*this,c) { - const tl l = light(lxleft,lyleft,c); - const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval); + const tl l = *lig; + const T val = (T)(l<1?l**col:(2 - l)**col + (l - 1)*maxval); *ptrd = (T)(nopacity*val + *ptrd*copacity); - ptrd+=whd; col+=twhd; + ptrd+=whd; col+=twh; lig+=lwh; } ptrd-=offx; } @@ -33928,17 +34645,17 @@ namespace cimg_library_suffixed { const tc *const color, const float opacity, const unsigned int pattern) { return draw_line(x0,y0,z0,x1,y0,z0,color,opacity,pattern,true). - draw_line(x1,y0,z0,x1,y1,z0,color,opacity,pattern,false). - draw_line(x1,y1,z0,x0,y1,z0,color,opacity,pattern,false). - draw_line(x0,y1,z0,x0,y0,z0,color,opacity,pattern,false). - draw_line(x0,y0,z1,x1,y0,z1,color,opacity,pattern,true). - draw_line(x1,y0,z1,x1,y1,z1,color,opacity,pattern,false). - draw_line(x1,y1,z1,x0,y1,z1,color,opacity,pattern,false). - draw_line(x0,y1,z1,x0,y0,z1,color,opacity,pattern,false). - draw_line(x0,y0,z0,x0,y0,z1,color,opacity,pattern,true). - draw_line(x1,y0,z0,x1,y0,z1,color,opacity,pattern,true). - draw_line(x1,y1,z0,x1,y1,z1,color,opacity,pattern,true). - draw_line(x0,y1,z0,x0,y1,z1,color,opacity,pattern,true); + draw_line(x1,y0,z0,x1,y1,z0,color,opacity,pattern,false). + draw_line(x1,y1,z0,x0,y1,z0,color,opacity,pattern,false). + draw_line(x0,y1,z0,x0,y0,z0,color,opacity,pattern,false). + draw_line(x0,y0,z1,x1,y0,z1,color,opacity,pattern,true). + draw_line(x1,y0,z1,x1,y1,z1,color,opacity,pattern,false). + draw_line(x1,y1,z1,x0,y1,z1,color,opacity,pattern,false). + draw_line(x0,y1,z1,x0,y0,z1,color,opacity,pattern,false). + draw_line(x0,y0,z0,x0,y0,z1,color,opacity,pattern,true). + draw_line(x1,y0,z0,x1,y0,z1,color,opacity,pattern,true). + draw_line(x1,y1,z0,x1,y1,z1,color,opacity,pattern,true). + draw_line(x0,y1,z0,x0,y1,z1,color,opacity,pattern,true); } //! Draw a filled 2d rectangle. @@ -33954,7 +34671,7 @@ namespace cimg_library_suffixed { CImg& draw_rectangle(const int x0, const int y0, const int x1, const int y1, const tc *const color, const float opacity=1) { - return draw_rectangle(x0,y0,0,x1,y1,_depth-1,color,opacity); + return draw_rectangle(x0,y0,0,x1,y1,_depth - 1,color,opacity); } //! Draw a outlined 2d rectangle \overloading. @@ -33970,12 +34687,12 @@ namespace cimg_library_suffixed { const int nx0 = bx?x0:x1, nx1 = bx?x1:x0, ny0 = by?y0:y1, ny1 = by?y1:y0; - if (ny1==ny0+1) return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true). + if (ny1==ny0 + 1) return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true). draw_line(nx1,ny1,nx0,ny1,color,opacity,pattern,false); return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true). - draw_line(nx1,ny0+1,nx1,ny1-1,color,opacity,pattern,false). + draw_line(nx1,ny0 + 1,nx1,ny1 - 1,color,opacity,pattern,false). draw_line(nx1,ny1,nx0,ny1,color,opacity,pattern,false). - draw_line(nx0,ny1-1,nx0,ny0+1,color,opacity,pattern,false); + draw_line(nx0,ny1 - 1,nx0,ny0 + 1,color,opacity,pattern,false); } //! Draw a filled 2d polygon. @@ -34012,13 +34729,13 @@ namespace cimg_library_suffixed { (int)npoints(2,0),(int)npoints(2,1),color,opacity); // Shift the coordinates so that the first and last vertices are not located on the same scanline. - if (npoints(0,1)==npoints(nb_points-1,1)) { + if (npoints(0,1)==npoints(nb_points - 1,1)) { const intT y0 = npoints(0,1); unsigned int off = 1; while ((int)npoints(off,1)==y0 && off=width() || ymax<0 || ymin>=height()) return *this; if (ymin==ymax) return cimg_draw_scanline(xmin,xmax,ymin,color,opacity,1); const unsigned int - nxmin = xmin<0?0:(unsigned int)xmin, nxmax = xmax>=width()?_width-1:(unsigned int)xmax, - nymin = ymin<0?0:(unsigned int)ymin, nymax = ymax>=height()?_height-1:(unsigned int)ymax, + nxmin = xmin<0?0:(unsigned int)xmin, nxmax = xmax>=width()?_width - 1:(unsigned int)xmax, + nymin = ymin<0?0:(unsigned int)ymin, nymax = ymax>=height()?_height - 1:(unsigned int)ymax, dx = 1 + nxmax - nxmin, dy = 1 + nymax - nymin; npoints_x-=nxmin; npoints_y-=nymin; @@ -34045,38 +34762,38 @@ namespace cimg_library_suffixed { // Draw polygon segments. int - xmax = 0, xmin = (int)npoints.get_shared_points(0,nb_points-1,0).min_max(xmax), - ymax = 0, ymin = (int)npoints.get_shared_points(0,nb_points-1,1).min_max(ymax); + xmax = 0, xmin = (int)npoints.get_shared_points(0,nb_points - 1,0).min_max(xmax), + ymax = 0, ymin = (int)npoints.get_shared_points(0,nb_points - 1,1).min_max(ymax); if (xmax<0 || xmin>=width() || ymax<0 || ymin>=height()) return *this; if (ymin==ymax) return cimg_draw_scanline(xmin,xmax,ymin,color,1,1); const unsigned int nymin = ymin<0?0:(unsigned int)ymin, - nymax = ymax>=height()?_height-1:(unsigned int)ymax, + nymax = ymax>=height()?_height - 1:(unsigned int)ymax, dy = 1 + nymax - nymin; - CImg X(1+2*nb_points,dy,1,1,0), tmp; + CImg X(1 + 2*nb_points,dy,1,1,0), tmp; cx = (int)npoints(0,0), cy = (int)npoints(0,1); unsigned int cp = 0; for (unsigned int p = 0; pay && cy>ny))?1:0; for (int x = cx, y = y0, _sx = 1, _sy = 1, - _dx = nx>cx?nx-cx:((_sx=-1),cx-nx), - _dy = y1>y0?y1-y0:((_sy=-1),y0-y1), + _dx = nx>cx?nx - cx:((_sx=-1),cx - nx), + _dy = y1>y0?y1 - y0:((_sy=-1),y0 - y1), _counter = ((_dx-=_dy?_dy*(_dx/_dy):0),_dy), _err = _dx>>1, - _rx = _dy?(nx-cx)/_dy:0; + _rx = _dy?(nx - cx)/_dy:0; _counter>=countermin; --_counter, y+=_sy, x+=_rx + ((_err-=_dx)<0?_err+=_dy,_sx:0)) if (y>=0 && y<(int)dy) X(++X(0,y),y) = x; cp = np; cx = nx; cy = ny; } else { - const int pp = (cp?cp-1:nb_points-1), py = (int)npoints(pp,1); + const int pp = (int)(cp?cp - 1:nb_points - 1), py = (int)npoints(pp,1); if (y0>=0 && y0<(int)dy) { - cimg_draw_scanline(cxpy && ay>cy) || (cy0?nr1:1e-6),2), l2 = (float)std::pow(rmax/(nr2>0?nr2:1e-6),2), a = l1*u*u + l2*v*v, - b = u*v*(l1-l2), + b = u*v*(l1 - l2), c = l1*v*v + l2*u*u; const int yb = (int)std::sqrt(a*rmax*rmax/(a*c - b*b)), tymin = y0 - yb - 1, tymax = y0 + yb + 1, ymin = tymin<0?0:tymin, - ymax = tymax>=height()?height()-1:tymax; + ymax = tymax>=height()?height() - 1:tymax; int oxmin = 0, oxmax = 0; bool first_line = true; for (int y = ymin; y<=ymax; ++y) { @@ -34265,15 +34982,15 @@ namespace cimg_library_suffixed { if (!pattern) cimg_draw_scanline(xmin,xmax,y,color,opacity,1); else { if (first_line) { - if (y0-yb>=0) cimg_draw_scanline(xmin,xmax,y,color,opacity,1); + if (y0 - yb>=0) cimg_draw_scanline(xmin,xmax,y,color,opacity,1); else draw_point(xmin,y,color,opacity).draw_point(xmax,y,color,opacity); first_line = false; } else { - if (xmin=width() || y0+radius<0 || y0-radius>=height()) return *this; - if (y0>=0 && y0=width() || y0 + radius<0 || y0 - radius>=height()) return *this; + if (y0>=0 && y0=0) { - const int x1 = x0-x, x2 = x0+x, y1 = y0-y, y2 = y0+y; + const int x1 = x0 - x, x2 = x0 + x, y1 = y0 - y, y2 = y0 + y; if (y1>=0 && y1=0 && y2=0 && y1=0 && y2=width() || y0+radius<0 || y0-radius>=height()) return *this; + if (radius<0 || x0 - radius>=width() || y0 + radius<0 || y0 - radius>=height()) return *this; if (!radius) return draw_point(x0,y0,color,opacity); - draw_point(x0-radius,y0,color,opacity).draw_point(x0+radius,y0,color,opacity). - draw_point(x0,y0-radius,color,opacity).draw_point(x0,y0+radius,color,opacity); + draw_point(x0 - radius,y0,color,opacity).draw_point(x0 + radius,y0,color,opacity). + draw_point(x0,y0 - radius,color,opacity).draw_point(x0,y0 + radius,color,opacity); if (radius==1) return *this; - for (int f = 1-radius, ddFx = 0, ddFy = -(radius<<1), x = 0, y = radius; x=0) { f+=(ddFy+=2); --y; } ++x; ++(f+=(ddFx+=2)); - if (x!=y+1) { - const int x1 = x0-y, x2 = x0+y, y1 = y0-x, y2 = y0+x, x3 = x0-x, x4 = x0+x, y3 = y0-y, y4 = y0+y; + if (x!=y + 1) { + const int x1 = x0 - y, x2 = x0 + y, y1 = y0 - x, y2 = y0 + x, + x3 = x0 - x, x4 = x0 + x, y3 = y0 - y, y4 = y0 + y; draw_point(x1,y1,color,opacity).draw_point(x1,y2,color,opacity). draw_point(x2,y1,color,opacity).draw_point(x2,y2,color,opacity); if (x!=y) @@ -34505,7 +35223,7 @@ namespace cimg_library_suffixed { 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 (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 " @@ -34521,7 +35239,7 @@ namespace cimg_library_suffixed { 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 int - coff = -(bx?x0:0)-(by?y0*mask.width():0)-(bz?z0*mask.width()*mask.height():0)- + coff = -(bx?x0:0) - (by?y0*mask.width():0) - (bz?z0*mask.width()*mask.height():0) - (bc?c0*mask.width()*mask.height()*mask.depth():0), ssize = mask.width()*mask.height()*mask.depth()*mask.spectrum(); const ti *ptrs = sprite._data + coff; @@ -34534,7 +35252,7 @@ namespace cimg_library_suffixed { offZ = (unsigned long)_width*_height*(_depth - lZ), soffZ = (unsigned long)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); + T *ptrd = data(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,c0<0?0:c0); for (int c = 0; c& font, ...) { if (!font) return *this; - char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,font); - cimg_vsnprintf(tmp,sizeof(tmp),text,ap); va_end(ap); + CImg tmp(2048); + std::va_list ap; va_start(ap,font); + cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap); return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font,false); } @@ -34617,8 +35336,9 @@ namespace cimg_library_suffixed { const tc *const foreground_color, const int, const float opacity, const CImgList& font, ...) { if (!font) return *this; - char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,font); - cimg_vsnprintf(tmp,sizeof(tmp),text,ap); va_end(ap); + CImg tmp(2048); + std::va_list ap; va_start(ap,font); + cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap); return _draw_text(x0,y0,tmp,foreground_color,(tc*)0,opacity,font,false); } @@ -34632,8 +35352,9 @@ namespace cimg_library_suffixed { const int, const tc *const background_color, const float opacity, const CImgList& font, ...) { if (!font) return *this; - char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,font); - cimg_vsnprintf(tmp,sizeof(tmp),text,ap); va_end(ap); + CImg tmp(2048); + std::va_list ap; va_start(ap,font); + cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap); return _draw_text(x0,y0,tmp,(tc*)0,background_color,opacity,font,false); } @@ -34655,8 +35376,9 @@ namespace cimg_library_suffixed { const tc1 *const foreground_color, const tc2 *const background_color, const float opacity=1, const unsigned int font_height=13, ...) { if (!font_height) return *this; - char tmp[2048] = { 0 }; - std::va_list ap; va_start(ap,font_height); cimg_vsnprintf(tmp,sizeof(tmp),text,ap); va_end(ap); + CImg tmp(2048); + std::va_list ap; va_start(ap,font_height); + cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap); const CImgList& font = CImgList::font(font_height,true); _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font,true); return *this; @@ -34670,9 +35392,10 @@ namespace cimg_library_suffixed { const float opacity=1, const unsigned int font_height=13, ...) { if (!font_height) return *this; cimg::unused(background_color); - char tmp[2048] = { 0 }; - std::va_list ap; va_start(ap,font_height); cimg_vsnprintf(tmp,sizeof(tmp),text,ap); va_end(ap); - return draw_text(x0,y0,"%s",foreground_color,(const tc*)0,opacity,font_height,tmp); + CImg tmp(2048); + std::va_list ap; va_start(ap,font_height); + cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap); + return draw_text(x0,y0,"%s",foreground_color,(const tc*)0,opacity,font_height,tmp._data); } //! Draw a text string \overloading. @@ -34682,9 +35405,10 @@ namespace cimg_library_suffixed { const int, const tc *const background_color, const float opacity=1, const unsigned int font_height=13, ...) { if (!font_height) return *this; - char tmp[2048] = { 0 }; - std::va_list ap; va_start(ap,font_height); cimg_vsnprintf(tmp,sizeof(tmp),text,ap); va_end(ap); - return draw_text(x0,y0,"%s",(tc*)0,background_color,opacity,font_height,tmp); + CImg tmp(2048); + std::va_list ap; va_start(ap,font_height); + cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap); + return draw_text(x0,y0,"%s",(tc*)0,background_color,opacity,font_height,tmp._data); } template @@ -34706,7 +35430,7 @@ namespace cimg_library_suffixed { int x = 0, y = 0, w = 0; unsigned char c = 0; for (unsigned int i = 0; iw) w = x; x = 0; break; case '\t' : x+=4*font[' ']._width; break; @@ -34717,12 +35441,12 @@ namespace cimg_library_suffixed { if (x>w) w=x; y+=font[0]._height; } - assign(x0+w,y0+y,1,is_native_font?1:font[0]._spectrum,0); + assign(x0 + w,y0 + y,1,is_native_font?1:font[0]._spectrum,0); } int x = x0, y = y0; for (unsigned int i = 0; i label; if (siz<=0) { // Degenerated case. - draw_line(0,y,_width-1,y,color,opacity,pattern); + draw_line(0,y,_width - 1,y,color,opacity,pattern); if (!siz) { cimg_snprintf(txt,sizeof(txt),"%g",(double)*values_x); label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height); const int _xt = (width() - label.width())/2, - xt = _xt<3?3:_xt+label.width()>=width()-2?width()-3-label.width():_xt; - draw_point(width()/2,y-1,color,opacity).draw_point(width()/2,y+1,color,opacity); + xt = _xt<3?3:_xt + label.width()>=width() - 2?width() - 3 - label.width():_xt; + draw_point(width()/2,y - 1,color,opacity).draw_point(width()/2,y + 1,color,opacity); if (allow_zero || txt[0]!='0' || txt[1]!=0) draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height); } } else { // Regular case. - if (values_x[0]=width()-2?width()-3-label.width():_xt; - draw_point(xi,y-1,color,opacity).draw_point(xi,y+1,color,opacity); + xt = _xt<3?3:_xt + label.width()>=width() - 2?width() - 3 - label.width():_xt; + draw_point(xi,y - 1,color,opacity).draw_point(xi,y + 1,color,opacity); if (allow_zero || txt[0]!='0' || txt[1]!=0) draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height); } @@ -34891,36 +35616,36 @@ namespace cimg_library_suffixed { const unsigned int pattern=~0U, const unsigned int font_height=13, const bool allow_zero=true) { if (is_empty()) return *this; - int siz = (int)values_y.size()-1; + int siz = (int)values_y.size() - 1; char txt[32] = { 0 }; CImg label; if (siz<=0) { // Degenerated case. - draw_line(x,0,x,_height-1,color,opacity,pattern); + draw_line(x,0,x,_height - 1,color,opacity,pattern); if (!siz) { cimg_snprintf(txt,sizeof(txt),"%g",(double)*values_y); label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height); const int _yt = (height() - label.height())/2, - yt = _yt<0?0:_yt+label.height()>=height()?height()-1-label.height():_yt, + yt = _yt<0?0:_yt + label.height()>=height()?height() - 1-label.height():_yt, _xt = x - 2 - label.width(), - xt = _xt>=0?_xt:x+3; - draw_point(x-1,height()/2,color,opacity).draw_point(x+1,height()/2,color,opacity); + xt = _xt>=0?_xt:x + 3; + draw_point(x - 1,height()/2,color,opacity).draw_point(x + 1,height()/2,color,opacity); if (allow_zero || txt[0]!='0' || txt[1]!=0) draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height); } } else { // Regular case. - if (values_y[0]=height()?height()-1-label.height():_yt, + yt = _yt<0?0:_yt + label.height()>=height()?height() - 1-label.height():_yt, _xt = x - 2 - label.width(), - xt = _xt>=0?_xt:x+3; - draw_point(x-1,yi,color,opacity).draw_point(x+1,yi,color,opacity); + xt = _xt>=0?_xt:x + 3; + draw_point(x - 1,yi,color,opacity).draw_point(x + 1,yi,color,opacity); if (allow_zero || txt[0]!='0' || txt[1]!=0) draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height); } @@ -34946,22 +35671,22 @@ namespace cimg_library_suffixed { const unsigned int font_height=13, const bool allow_zero=true) { if (is_empty()) return *this; const CImg nvalues_x(values_x._data,values_x.size(),1,1,1,true); - const int sizx = (int)values_x.size()-1, wm1 = width()-1; + const int sizx = (int)values_x.size() - 1, wm1 = width() - 1; if (sizx>=0) { float ox = (float)*nvalues_x; - for (unsigned int x = sizx?1:0; x<_width; ++x) { + for (unsigned int x = sizx?1U:0U; x<_width; ++x) { const float nx = (float)nvalues_x._linear_atX((float)x*sizx/wm1); - if (nx*ox<=0) { draw_axis(nx==0?x:x-1,values_y,color,opacity,pattern_y,font_height,allow_zero); break; } + if (nx*ox<=0) { draw_axis(nx==0?x:x - 1,values_y,color,opacity,pattern_y,font_height,allow_zero); break; } ox = nx; } } const CImg nvalues_y(values_y._data,values_y.size(),1,1,1,true); - const int sizy = (int)values_y.size()-1, hm1 = height()-1; + const int sizy = (int)values_y.size() - 1, hm1 = height() - 1; if (sizy>0) { float oy = (float)nvalues_y[0]; - for (unsigned int y = sizy?1:0; y<_height; ++y) { + for (unsigned int y = sizy?1U:0U; y<_height; ++y) { const float ny = (float)nvalues_y._linear_atX((float)y*sizy/hm1); - if (ny*oy<=0) { draw_axis(values_x,ny==0?y:y-1,color,opacity,pattern_x,font_height,allow_zero); break; } + if (ny*oy<=0) { draw_axis(values_x,ny==0?y:y - 1,color,opacity,pattern_x,font_height,allow_zero); break; } oy = ny; } } @@ -34980,8 +35705,8 @@ namespace cimg_library_suffixed { const bool allow_zero = (x0*x1>0) || (y0*y1>0); const float dx = cimg::abs(x1-x0), dy = cimg::abs(y1-y0), - px = dx<=0?1:precisionx==0?(float)std::pow(10.0,(int)std::log10(dx)-2.0):precisionx, - py = dy<=0?1:precisiony==0?(float)std::pow(10.0,(int)std::log10(dy)-2.0):precisiony; + px = dx<=0?1:precisionx==0?(float)std::pow(10.0,(int)std::log10(dx) - 2.0):precisionx, + py = dy<=0?1:precisiony==0?(float)std::pow(10.0,(int)std::log10(dy) - 2.0):precisiony; if (x0!=x1 && y0!=y1) draw_axes(CImg::sequence(subdivisionx>0?subdivisionx:1-width()/subdivisionx,x0,x1).round(px), CImg::sequence(subdivisiony>0?subdivisiony:1-height()/subdivisiony,y0,y1).round(py), @@ -35011,11 +35736,11 @@ namespace cimg_library_suffixed { if (is_empty()) return *this; if (values_x) cimg_foroff(values_x,x) { const int xi = (int)values_x[x]; - if (xi>=0 && xi=0 && xi=0 && yi=0 && yi0?delta_x:_width*-delta_x/100; const unsigned int nx = (unsigned int)(_width/dx); - seqx = CImg::sequence(1+nx,0,(unsigned int)(dx*nx)); - if (offsetx) cimg_foroff(seqx,x) seqx(x) = (unsigned int)cimg::mod(seqx(x)+offsetx,(float)_width); + seqx = CImg::sequence(1 + nx,0,(unsigned int)(dx*nx)); + if (offsetx) cimg_foroff(seqx,x) seqx(x) = (unsigned int)cimg::mod(seqx(x) + offsetx,(float)_width); if (invertx) cimg_foroff(seqx,x) seqx(x) = _width - 1 - seqx(x); } if (delta_y!=0) { const float dy = delta_y>0?delta_y:_height*-delta_y/100; const unsigned int ny = (unsigned int)(_height/dy); - seqy = CImg::sequence(1+ny,0,(unsigned int)(dy*ny)); - if (offsety) cimg_foroff(seqy,y) seqy(y) = (unsigned int)cimg::mod(seqy(y)+offsety,(float)_height); + seqy = CImg::sequence(1 + ny,0,(unsigned int)(dy*ny)); + if (offsety) cimg_foroff(seqy,y) seqy(y) = (unsigned int)cimg::mod(seqy(y) + offsety,(float)_height); if (inverty) cimg_foroff(seqy,y) seqy(y) = _height - 1 - seqy(y); } return draw_grid(seqx,seqy,color,opacity,pattern_x,pattern_y); @@ -35104,50 +35829,52 @@ namespace cimg_library_suffixed { 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); + 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); - const float fx = (float)_width1/siz1; + 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 for (unsigned long off = 1; off ndata(data._data,siz,1,1,1,true); - int oY = (int)((data[0]-m)/ca); + 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); + 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/(siz-1); + const float fx = (float)_width/siz1; int oX = 0; cimg_foroff(data,off) { const int - X = (int)((off+1)*fx), - Y = (int)((data[off]-m)/ca); + 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; + oX = X + 1; } } break; default : break; // No edges @@ -35160,7 +35887,7 @@ namespace cimg_library_suffixed { case 1 : { // Point cimg_foroff(data,off) { const int - X = (int)(off*fx) + wb2, + X = (int)(off*fx + wb2), Y = (int)((data[off]-m)/ca); draw_point(X,Y,color,opacity); } @@ -35168,23 +35895,23 @@ namespace cimg_library_suffixed { case 2 : { // Straight Cross cimg_foroff(data,off) { const int - X = (int)(off*fx) + wb2, + 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); + 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, + 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); + 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, + X = (int)(off*fx + wb2), Y = (int)((data[off]-m)/ca); draw_circle(X,Y,3,color,opacity); } @@ -35192,7 +35919,7 @@ namespace cimg_library_suffixed { case 5 : { // Outlined circle cimg_foroff(data,off) { const int - X = (int)(off*fx) + wb2, + X = (int)(off*fx + wb2), Y = (int)((data[off]-m)/ca); draw_circle(X,Y,3,color,opacity,0U); } @@ -35200,20 +35927,20 @@ namespace cimg_library_suffixed { case 6 : { // Square cimg_foroff(data,off) { const int - X = (int)(off*fx) + wb2, + X = (int)(off*fx + wb2), Y = (int)((data[off]-m)/ca); - draw_rectangle(X-3,Y-3,X+3,Y+3,color,opacity,~0U); + 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, + 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); + 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 @@ -35273,14 +36000,16 @@ namespace cimg_library_suffixed { if (x>=0 && x=0 && y=0 && z1); const CImg reference_color = get_vector_at(x,y,z); CImg remaining(3,512,1,1,0); - remaining(0,0) = x; remaining(1,0) = y; remaining(2,0) = z; + remaining(0,0) = (unsigned int)x; + remaining(1,0) = (unsigned int)y; + remaining(2,0) = (unsigned int)z; unsigned int posr0 = 0, posr1 = 1; region(x,y,z) = (t)1; - const t noregion = ((t)1==(t)2)?(t)0:(t)(-1); + const t noregion = ((t)1==(t)2)?(t)0:(t)-1; if (is_3d) do { // 3d version of the filling algorithm const unsigned int *pcurr = remaining.data(0,posr0++), xc = *(pcurr++), yc = *(pcurr++), zc = *(pcurr++); if (posr0>=512) { remaining.shift(0,-(int)posr0); posr1-=posr0; posr0 = 0; } @@ -35288,10 +36017,10 @@ namespace cimg_library_suffixed { unsigned int nxc = xc; do { // X-backward _cimg_draw_fill_set(nxc,yc,zc); - _cimg_draw_fill_test_neighbor(nxc,yc-1,zc,yc!=0); - _cimg_draw_fill_test_neighbor(nxc,yc+1,zc,ycposr0); @@ -35357,13 +36086,13 @@ namespace cimg_library_suffixed { unsigned int nxc = xc; do { // X-backward _cimg_draw_fill_set(nxc,yc,0); - _cimg_draw_fill_test_neighbor(nxc,yc-1,0,yc!=0); - _cimg_draw_fill_test_neighbor(nxc,yc+1,0,yc=width()?width()-1:x0, - _y0 = y0<0?0:y0>=height()?height()-1:y0, - _x1 = x1<0?1:x1>=width()?width()-1:x1, - _y1 = y1<0?1:y1>=height()?height()-1:y1; + _x0 = x0<0?0:x0>=width()?width() - 1:x0, + _y0 = y0<0?0:y0>=height()?height() - 1:y0, + _x1 = x1<0?1:x1>=width()?width() - 1:x1, + _y1 = y1<0?1:y1>=height()?height() - 1:y1; #ifdef cimg_use_openmp -#pragma omp parallel for collapse(2) if ((1+_x1-_x0)*(1+_y1-_y0)>=2048) +#pragma omp parallel for collapse(2) if ((1 + _x1 - _x0)*(1 + _y1 - _y0)>=2048) #endif for (int q = _y0; q<=_y1; ++q) for (int p = _x0; p<=_x1; ++p) { @@ -35556,7 +36285,7 @@ namespace cimg_library_suffixed { } } else if (is_normalized_iteration) { const float - normz = (float)cimg::abs(zr*zr+zi*zi), + normz = (float)cimg::abs(zr*zr + zi*zi), niteration = (float)(iteration + 1 - std::log(std::log(normz))/ln2); if (palette) { if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)palette._linear_atX(niteration,c); @@ -35587,7 +36316,7 @@ namespace cimg_library_suffixed { const bool is_normalized_iteration=false, const bool is_julia_set=false, const double param_r=0, const double param_i=0) { - return draw_mandelbrot(0,0,_width-1,_height-1,colormap,opacity, + return draw_mandelbrot(0,0,_width - 1,_height - 1,colormap,opacity, z0r,z0i,z1r,z1i,iteration_max,is_normalized_iteration,is_julia_set,param_r,param_i); } @@ -35928,6 +36657,16 @@ namespace cimg_library_suffixed { return n_primitive>=opacities._width?1.0f:(float)opacities[n_primitive]; } + template + static float ___draw_object3d(const CImgList& opacities, const unsigned int n_primitive) { + return n_primitive + static float ___draw_object3d(const CImg& opacities, const unsigned int n_primitive) { + return n_primitive CImg& _draw_object3d(void *const pboard, CImg& zbuffer, const float X, const float Y, const float Z, @@ -35941,17 +36680,18 @@ namespace cimg_library_suffixed { const float specular_lightness, const float specular_shininess, const float sprite_scale) { typedef typename cimg::superset2::type tpfloat; + typedef typename to::value_type _to; if (is_empty() || !vertices || !primitives) return *this; - char error_message[1024] = { 0 }; + CImg error_message(1024); if (!vertices.is_object3d(primitives,colors,opacities,false,error_message)) throw CImgArgumentException(_cimg_instance "draw_object3d(): Invalid specified 3d object (%u,%u) (%s).", - cimg_instance,vertices._width,primitives._width,error_message); - if (render_type==5) cimg::mutex(10); // Static variable used in this case, breaks thread-safety. - + cimg_instance,vertices._width,primitives._width,error_message.data()); #ifndef cimg_use_board if (pboard) return *this; #endif + if (render_type==5) cimg::mutex(10); // Static variable used in this case, breaks thread-safety. + const float nspec = 1 - (specular_lightness<0.0f?0.0f:(specular_lightness>1.0f?1.0f:specular_lightness)), nspec2 = 1 + (specular_shininess<0.0f?0.0f:specular_shininess), @@ -35971,7 +36711,7 @@ namespace cimg_library_suffixed { if (is_same_texture) for (unsigned int r = 0, j = 0; j<8; ++j) for (unsigned int i = 0; i<8; ++i) - if (ref_values[r++]!=img(i*img._width/9,j*img._height/9,0,(i+j)%img._spectrum)) { + if (ref_values[r++]!=img(i*img._width/9,j*img._height/9,0,(i + j)%img._spectrum)) { is_same_texture = false; break; } if (!is_same_texture || default_light_texture._spectrum<_spectrum) { @@ -35979,7 +36719,7 @@ namespace cimg_library_suffixed { lptr = colors.back().data(); for (unsigned int r = 0, j = 0; j<8; ++j) for (unsigned int i = 0; i<8; ++i) - ref_values[r++] = img(i*img._width/9,j*img._height/9,0,(i+j)%img._spectrum); + ref_values[r++] = img(i*img._width/9,j*img._height/9,0,(i + j)%img._spectrum); } light_texture.assign(default_light_texture,true); } else { @@ -36042,11 +36782,14 @@ namespace cimg_library_suffixed { } } const float _focale = absfocale?absfocale:(1e5f-parallzmin); + float zmax = 0; + if (zbuffer) zmax = vertices.get_shared_row(2).max(); // Compute visible primitives. CImg visibles(primitives._width,1,1,1,~0U); CImg zrange(primitives._width); const tpfloat zmin = absfocale?(tpfloat)(1.5f - absfocale):cimg::type::min(); + bool is_forward = zbuffer?true:false; #ifdef cimg_use_openmp #pragma omp parallel for if (primitives.size()>4096) @@ -36055,6 +36798,9 @@ namespace cimg_library_suffixed { const CImg& primitive = primitives[l]; switch (primitive.size()) { case 1 : { // Point + CImg<_to> _opacity; + __draw_object3d(opacities,l,_opacity); + if (l<=colors.width() && (colors[l].size()!=_spectrum || _opacity)) is_forward = false; const unsigned int i0 = (unsigned int)primitive(0); const tpfloat z0 = Z + vertices(i0,2); if (z0>zmin) { @@ -36085,6 +36831,7 @@ namespace cimg_library_suffixed { visibles(l) = (unsigned int)l; zrange(l) = _zc; } + is_forward = false; } break; case 2 : // Segment case 6 : { @@ -36159,6 +36906,7 @@ namespace cimg_library_suffixed { } } break; default : + if (render_type==5) cimg::mutex(10,0); throw CImgArgumentException(_cimg_instance "draw_object3d(): Invalid primitive[%u] with size %u " "(should have size 1,2,3,4,5,6,9 or 12).", @@ -36167,18 +36915,27 @@ namespace cimg_library_suffixed { } } + // Force transparent primitives to be drawn last when zbuffer is activated + // (and if object contains no spheres or sprites). + if (is_forward) + cimglist_for(primitives,l) + if (___draw_object3d(opacities,l)!=1) zrange(l) = 2*zmax - zrange(l); + // Sort only visibles primitives. unsigned int *p_visibles = visibles._data; - float *p_zrange = zrange._data; - const float *ptrz = p_zrange; + tpfloat *p_zrange = zrange._data; + const tpfloat *ptrz = p_zrange; cimg_for(visibles,ptr,unsigned int) { if (*ptr!=~0U) { *(p_visibles++) = *ptr; *(p_zrange++) = *ptrz; } ++ptrz; } - const unsigned int nb_visibles = p_zrange - zrange._data; - if (!nb_visibles) return *this; + const unsigned int nb_visibles = (unsigned int)(p_zrange - zrange._data); + if (!nb_visibles) { + if (render_type==5) cimg::mutex(10,0); + return *this; + } CImg permutations; - CImg(zrange._data,nb_visibles,1,1,1,true).sort(permutations,false); + CImg(zrange._data,nb_visibles,1,1,1,true).sort(permutations,is_forward); // Compute light properties CImg lightprops; @@ -36218,7 +36975,7 @@ namespace cimg_library_suffixed { case 4 : // Gouraud Shading case 5 : { // Phong-Shading - CImg vertices_normals(vertices._width,3,1,1,0); + CImg vertices_normals(vertices._width,6,1,1,0); #ifdef cimg_use_openmp #pragma omp parallel for if (nb_visibles>4096) #endif @@ -36247,18 +37004,28 @@ namespace cimg_library_suffixed { nx = nnx/norm, ny = nny/norm, nz = nnz/norm; - vertices_normals(i0,0)+=nx; vertices_normals(i0,1)+=ny; vertices_normals(i0,2)+=nz; - vertices_normals(i1,0)+=nx; vertices_normals(i1,1)+=ny; vertices_normals(i1,2)+=nz; - vertices_normals(i2,0)+=nx; vertices_normals(i2,1)+=ny; vertices_normals(i2,2)+=nz; - if (rectangle_flag) { vertices_normals(i3,0)+=nx; vertices_normals(i3,1)+=ny; vertices_normals(i3,2)+=nz; } + unsigned int ix = 0, iy = 1, iz = 2; + if (is_double_sided && nz>0) { ix = 3; iy = 4; iz = 5; } + vertices_normals(i0,ix)+=nx; vertices_normals(i0,iy)+=ny; vertices_normals(i0,iz)+=nz; + vertices_normals(i1,ix)+=nx; vertices_normals(i1,iy)+=ny; vertices_normals(i1,iz)+=nz; + vertices_normals(i2,ix)+=nx; vertices_normals(i2,iy)+=ny; vertices_normals(i2,iz)+=nz; + if (rectangle_flag) { + vertices_normals(i3,ix)+=nx; vertices_normals(i3,iy)+=ny; vertices_normals(i3,iz)+=nz; + } } } - if (is_double_sided) cimg_forX(vertices_normals,p) if (vertices_normals(p,2)>0) { - vertices_normals(p,0) = -vertices_normals(p,0); - vertices_normals(p,1) = -vertices_normals(p,1); - vertices_normals(p,2) = -vertices_normals(p,2); - } + if (is_double_sided) cimg_forX(vertices_normals,p) { + const float + nx0 = vertices_normals(p,0), ny0 = vertices_normals(p,1), nz0 = vertices_normals(p,2), + nx1 = vertices_normals(p,3), ny1 = vertices_normals(p,4), nz1 = vertices_normals(p,5), + n0 = nx0*nx0 + ny0*ny0 + nz0*nz0, n1 = nx1*nx1 + ny1*ny1 + nz1*nz1; + if (n1>n0) { + vertices_normals(p,0) = -nx1; + vertices_normals(p,1) = -ny1; + vertices_normals(p,2) = -nz1; + } + } if (render_type==4) { lightprops.assign(vertices._width); @@ -36303,7 +37070,6 @@ namespace cimg_library_suffixed { // Draw visible primitives const CImg default_color(1,_spectrum,1,1,(tc)200); - typedef typename to::value_type _to; CImg<_to> _opacity; for (unsigned int l = 0; l=0 || nx0-(int)sw/2=0 || ny0-(int)sh/2=0 || nx0 - (int)sw/2=0 || ny0 - (int)sh/2 _sprite = (sw!=color._width || sh!=color._height)? color.get_resize(sw,sh,1,-100,render_type<=3?1:3):CImg(), @@ -36355,7 +37121,7 @@ namespace cimg_library_suffixed { if (pboard) { board.setPenColorRGBi(128,128,128); board.setFillColor(LibBoard::Color::None); - board.drawRectangle((float)nx0,height()-(float)ny0,sw,sh); + board.drawRectangle((float)nx0,height() - (float)ny0,sw,sh); } #endif } @@ -36369,7 +37135,7 @@ namespace cimg_library_suffixed { sw = _sw?_sw:1, sh = _sh?_sh:1; const int nx0 = x0 - (int)sw/2, ny0 = y0 - (int)sh/2; if (sw<=3*_width/2 && sh<=3*_height/2 && - (nx0+(int)sw/2>=0 || nx0-(int)sw/2=0 || ny0-(int)sh/2=0 || nx0 - (int)sw/2=0 || ny0 - (int)sh/2 _sprite = (sw!=color._width || sh!=color._height)? color.get_resize(sw,sh,1,-100,render_type<=3?1:3):CImg(), @@ -36383,7 +37149,7 @@ namespace cimg_library_suffixed { if (pboard) { board.setPenColorRGBi(128,128,128); board.setFillColor(LibBoard::Color::None); - board.drawRectangle((float)nx0,height()-(float)ny0,sw,sh); + board.drawRectangle((float)nx0,height() - (float)ny0,sw,sh); } #endif } @@ -36405,7 +37171,7 @@ namespace cimg_library_suffixed { #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); - board.drawLine((float)x0,height()-(float)y0,x1,height()-(float)y1); + board.drawLine((float)x0,height() - (float)y0,x1,height() - (float)y1); } #endif } else { @@ -36413,8 +37179,8 @@ namespace cimg_library_suffixed { #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); - board.drawCircle((float)x0,height()-(float)y0,0); - board.drawCircle((float)x1,height()-(float)y1,0); + board.drawCircle((float)x0,height() - (float)y0,0); + board.drawCircle((float)x1,height() - (float)y1,0); } #endif } @@ -36440,7 +37206,7 @@ namespace cimg_library_suffixed { #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); - board.fillCircle(xc,height()-yc,0); + board.fillCircle(xc,height() - yc,0); } #endif break; @@ -36450,7 +37216,7 @@ namespace cimg_library_suffixed { if (pboard) { board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); board.setFillColor(LibBoard::Color::None); - board.drawCircle(xc,height()-yc,radius); + board.drawCircle(xc,height() - yc,radius); } #endif break; @@ -36460,10 +37226,10 @@ namespace cimg_library_suffixed { #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); - if (!is_wireframe) board.fillCircle(xc,height()-yc,radius); + if (!is_wireframe) board.fillCircle(xc,height() - yc,radius); else { board.setFillColor(LibBoard::Color::None); - board.drawCircle(xc,height()-yc,radius); + board.drawCircle(xc,height() - yc,radius); } } #endif @@ -36471,18 +37237,18 @@ namespace cimg_library_suffixed { } } break; case 6 : { // Textured line - if (!__color) + if (!__color) { + if (render_type==5) cimg::mutex(10,0); throw CImgArgumentException(_cimg_instance "draw_object3d(): Undefined texture for line primitive [%u].", cimg_instance,n_primitive); + } const unsigned int n0 = (unsigned int)primitive[0], - n1 = (unsigned int)primitive[1], - tx0 = (unsigned int)primitive[2], - ty0 = (unsigned int)primitive[3], - tx1 = (unsigned int)primitive[4], - ty1 = (unsigned int)primitive[5]; + n1 = (unsigned int)primitive[1]; const int + tx0 = (int)primitive[2], ty0 = (int)primitive[3], + tx1 = (int)primitive[4], ty1 = (int)primitive[5], x0 = (int)projections(n0,0), y0 = (int)projections(n0,1), x1 = (int)projections(n1,0), y1 = (int)projections(n1,1); const float @@ -36494,17 +37260,19 @@ namespace cimg_library_suffixed { #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.drawLine((float)x0,height()-(float)y0,(float)x1,height()-(float)y1); + board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1); } #endif } else { - draw_point(x0,y0,color.get_vector_at(tx0,ty0)._data,opacity). - draw_point(x1,y1,color.get_vector_at(tx1,ty1)._data,opacity); + draw_point(x0,y0,color.get_vector_at(tx0<=0?0:tx0>=color.width()?color.width() - 1:tx0, + ty0<=0?0:ty0>=color.height()?color.height() - 1:ty0)._data,opacity). + draw_point(x1,y1,color.get_vector_at(tx1<=0?0:tx1>=color.width()?color.width() - 1:tx1, + ty1<=0?0:ty1>=color.height()?color.height() - 1:ty1)._data,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.drawCircle((float)x0,height()-(float)y0,0); - board.drawCircle((float)x1,height()-(float)y1,0); + board.drawCircle((float)x0,height() - (float)y0,0); + board.drawCircle((float)x1,height() - (float)y1,0); } #endif } @@ -36528,9 +37296,9 @@ namespace cimg_library_suffixed { #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); - board.drawCircle((float)x0,height()-(float)y0,0); - board.drawCircle((float)x1,height()-(float)y1,0); - board.drawCircle((float)x2,height()-(float)y2,0); + board.drawCircle((float)x0,height() - (float)y0,0); + board.drawCircle((float)x1,height() - (float)y1,0); + board.drawCircle((float)x2,height() - (float)y2,0); } #endif break; @@ -36544,9 +37312,9 @@ namespace cimg_library_suffixed { #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); - board.drawLine((float)x0,height()-(float)y0,(float)x1,height()-(float)y1); - board.drawLine((float)x0,height()-(float)y0,(float)x2,height()-(float)y2); - board.drawLine((float)x1,height()-(float)y1,(float)x2,height()-(float)y2); + board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1); + board.drawLine((float)x0,height() - (float)y0,(float)x2,height() - (float)y2); + board.drawLine((float)x1,height() - (float)y1,(float)x2,height() - (float)y2); } #endif break; @@ -36556,9 +37324,9 @@ namespace cimg_library_suffixed { #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); - board.fillTriangle((float)x0,height()-(float)y0, - (float)x1,height()-(float)y1, - (float)x2,height()-(float)y2); + board.fillTriangle((float)x0,height() - (float)y0, + (float)x1,height() - (float)y1, + (float)x2,height() - (float)y2); } #endif break; @@ -36572,9 +37340,9 @@ namespace cimg_library_suffixed { (unsigned char)(color[1]*lp), (unsigned char)(color[2]*lp), (unsigned char)(opacity*255)); - board.fillTriangle((float)x0,height()-(float)y0, - (float)x1,height()-(float)y1, - (float)x2,height()-(float)y2); + board.fillTriangle((float)x0,height() - (float)y0, + (float)x1,height() - (float)y1, + (float)x2,height() - (float)y2); } #endif break; @@ -36589,9 +37357,9 @@ namespace cimg_library_suffixed { (unsigned char)(color[1]), (unsigned char)(color[2]), (unsigned char)(opacity*255)); - board.fillGouraudTriangle((float)x0,height()-(float)y0,lightprops(n0), - (float)x1,height()-(float)y1,lightprops(n1), - (float)x2,height()-(float)y2,lightprops(n2)); + board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprops(n0), + (float)x1,height() - (float)y1,lightprops(n1), + (float)x2,height() - (float)y2,lightprops(n2)); } #endif break; @@ -36606,19 +37374,19 @@ namespace cimg_library_suffixed { #ifdef cimg_use_board if (pboard) { const float - l0 = light_texture((int)(light_texture.width()/2*(1+lightprops(n0,0))), - (int)(light_texture.height()/2*(1+lightprops(n0,1)))), - l1 = light_texture((int)(light_texture.width()/2*(1+lightprops(n1,0))), - (int)(light_texture.height()/2*(1+lightprops(n1,1)))), - l2 = light_texture((int)(light_texture.width()/2*(1+lightprops(n2,0))), - (int)(light_texture.height()/2*(1+lightprops(n2,1)))); + l0 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n0,0))), + (int)(light_texture.height()/2*(1 + lightprops(n0,1)))), + l1 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n1,0))), + (int)(light_texture.height()/2*(1 + lightprops(n1,1)))), + l2 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n2,0))), + (int)(light_texture.height()/2*(1 + lightprops(n2,1)))); board.setPenColorRGBi((unsigned char)(color[0]), (unsigned char)(color[1]), (unsigned char)(color[2]), (unsigned char)(opacity*255)); - board.fillGouraudTriangle((float)x0,height()-(float)y0,l0, - (float)x1,height()-(float)y1,l1, - (float)x2,height()-(float)y2,l2); + board.fillGouraudTriangle((float)x0,height() - (float)y0,l0, + (float)x1,height() - (float)y1,l1, + (float)x2,height() - (float)y2,l2); } #endif } break; @@ -36648,10 +37416,10 @@ namespace cimg_library_suffixed { #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); - board.drawCircle((float)x0,height()-(float)y0,0); - board.drawCircle((float)x1,height()-(float)y1,0); - board.drawCircle((float)x2,height()-(float)y2,0); - board.drawCircle((float)x3,height()-(float)y3,0); + board.drawCircle((float)x0,height() - (float)y0,0); + board.drawCircle((float)x1,height() - (float)y1,0); + board.drawCircle((float)x2,height() - (float)y2,0); + board.drawCircle((float)x3,height() - (float)y3,0); } #endif break; @@ -36665,10 +37433,10 @@ namespace cimg_library_suffixed { #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); - board.drawLine((float)x0,height()-(float)y0,(float)x1,height()-(float)y1); - board.drawLine((float)x1,height()-(float)y1,(float)x2,height()-(float)y2); - board.drawLine((float)x2,height()-(float)y2,(float)x3,height()-(float)y3); - board.drawLine((float)x3,height()-(float)y3,(float)x0,height()-(float)y0); + board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1); + board.drawLine((float)x1,height() - (float)y1,(float)x2,height() - (float)y2); + board.drawLine((float)x2,height() - (float)y2,(float)x3,height() - (float)y3); + board.drawLine((float)x3,height() - (float)y3,(float)x0,height() - (float)y0); } #endif break; @@ -36681,12 +37449,12 @@ namespace cimg_library_suffixed { #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); - board.fillTriangle((float)x0,height()-(float)y0, - (float)x1,height()-(float)y1, - (float)x2,height()-(float)y2); - board.fillTriangle((float)x0,height()-(float)y0, - (float)x2,height()-(float)y2, - (float)x3,height()-(float)y3); + board.fillTriangle((float)x0,height() - (float)y0, + (float)x1,height() - (float)y1, + (float)x2,height() - (float)y2); + board.fillTriangle((float)x0,height() - (float)y0, + (float)x2,height() - (float)y2, + (float)x3,height() - (float)y3); } #endif break; @@ -36703,12 +37471,12 @@ namespace cimg_library_suffixed { board.setPenColorRGBi((unsigned char)(color[0]*lp), (unsigned char)(color[1]*lp), (unsigned char)(color[2]*lp),(unsigned char)(opacity*255)); - board.fillTriangle((float)x0,height()-(float)y0, - (float)x1,height()-(float)y1, - (float)x2,height()-(float)y2); - board.fillTriangle((float)x0,height()-(float)y0, - (float)x2,height()-(float)y2, - (float)x3,height()-(float)y3); + board.fillTriangle((float)x0,height() - (float)y0, + (float)x1,height() - (float)y1, + (float)x2,height() - (float)y2); + board.fillTriangle((float)x0,height() - (float)y0, + (float)x2,height() - (float)y2, + (float)x3,height() - (float)y3); } #endif break; @@ -36728,12 +37496,12 @@ namespace cimg_library_suffixed { (unsigned char)(color[1]), (unsigned char)(color[2]), (unsigned char)(opacity*255)); - board.fillGouraudTriangle((float)x0,height()-(float)y0,lightprop0, - (float)x1,height()-(float)y1,lightprop1, - (float)x2,height()-(float)y2,lightprop2); - board.fillGouraudTriangle((float)x0,height()-(float)y0,lightprop0, - (float)x2,height()-(float)y2,lightprop2, - (float)x3,height()-(float)y3,lightprop3); + board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprop0, + (float)x1,height() - (float)y1,lightprop1, + (float)x2,height() - (float)y2,lightprop2); + board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprop0, + (float)x2,height() - (float)y2,lightprop2, + (float)x3,height() - (float)y3,lightprop3); } #endif } break; @@ -36752,41 +37520,40 @@ namespace cimg_library_suffixed { #ifdef cimg_use_board if (pboard) { const float - l0 = light_texture((int)(light_texture.width()/2*(1+lx0)), (int)(light_texture.height()/2*(1+ly0))), - l1 = light_texture((int)(light_texture.width()/2*(1+lx1)), (int)(light_texture.height()/2*(1+ly1))), - l2 = light_texture((int)(light_texture.width()/2*(1+lx2)), (int)(light_texture.height()/2*(1+ly2))), - l3 = light_texture((int)(light_texture.width()/2*(1+lx3)), (int)(light_texture.height()/2*(1+ly3))); + l0 = light_texture((int)(light_texture.width()/2*(1 + lx0)), (int)(light_texture.height()/2*(1 + ly0))), + l1 = light_texture((int)(light_texture.width()/2*(1 + lx1)), (int)(light_texture.height()/2*(1 + ly1))), + l2 = light_texture((int)(light_texture.width()/2*(1 + lx2)), (int)(light_texture.height()/2*(1 + ly2))), + l3 = light_texture((int)(light_texture.width()/2*(1 + lx3)), (int)(light_texture.height()/2*(1 + ly3))); board.setPenColorRGBi((unsigned char)(color[0]), (unsigned char)(color[1]), (unsigned char)(color[2]), (unsigned char)(opacity*255)); - board.fillGouraudTriangle((float)x0,height()-(float)y0,l0, - (float)x1,height()-(float)y1,l1, - (float)x2,height()-(float)y2,l2); - board.fillGouraudTriangle((float)x0,height()-(float)y0,l0, - (float)x2,height()-(float)y2,l2, - (float)x3,height()-(float)y3,l3); + board.fillGouraudTriangle((float)x0,height() - (float)y0,l0, + (float)x1,height() - (float)y1,l1, + (float)x2,height() - (float)y2,l2); + board.fillGouraudTriangle((float)x0,height() - (float)y0,l0, + (float)x2,height() - (float)y2,l2, + (float)x3,height() - (float)y3,l3); } #endif } break; } } break; case 9 : { // Textured triangle - if (!__color) + if (!__color) { + if (render_type==5) cimg::mutex(10,0); throw CImgArgumentException(_cimg_instance "draw_object3d(): Undefined texture for triangle primitive [%u].", cimg_instance,n_primitive); + } const unsigned int n0 = (unsigned int)primitive[0], n1 = (unsigned int)primitive[1], - n2 = (unsigned int)primitive[2], - tx0 = (unsigned int)primitive[3], - ty0 = (unsigned int)primitive[4], - tx1 = (unsigned int)primitive[5], - ty1 = (unsigned int)primitive[6], - tx2 = (unsigned int)primitive[7], - ty2 = (unsigned int)primitive[8]; + n2 = (unsigned int)primitive[2]; const int + tx0 = (int)primitive[3], ty0 = (int)primitive[4], + tx1 = (int)primitive[5], ty1 = (int)primitive[6], + tx2 = (int)primitive[7], ty2 = (int)primitive[8], x0 = (int)projections(n0,0), y0 = (int)projections(n0,1), x1 = (int)projections(n1,0), y1 = (int)projections(n1,1), x2 = (int)projections(n2,0), y2 = (int)projections(n2,1); @@ -36796,15 +37563,18 @@ namespace cimg_library_suffixed { z2 = vertices(n2,2) + Z + _focale; switch (render_type) { case 0 : - draw_point(x0,y0,color.get_vector_at(tx0,ty0)._data,opacity). - draw_point(x1,y1,color.get_vector_at(tx1,ty1)._data,opacity). - draw_point(x2,y2,color.get_vector_at(tx2,ty2)._data,opacity); + draw_point(x0,y0,color.get_vector_at(tx0<=0?0:tx0>=color.width()?color.width() - 1:tx0, + ty0<=0?0:ty0>=color.height()?color.height() - 1:ty0)._data,opacity). + draw_point(x1,y1,color.get_vector_at(tx1<=0?0:tx1>=color.width()?color.width() - 1:tx1, + ty1<=0?0:ty1>=color.height()?color.height() - 1:ty1)._data,opacity). + draw_point(x2,y2,color.get_vector_at(tx2<=0?0:tx2>=color.width()?color.width() - 1:tx2, + ty2<=0?0:ty2>=color.height()?color.height() - 1:ty2)._data,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.drawCircle((float)x0,height()-(float)y0,0); - board.drawCircle((float)x1,height()-(float)y1,0); - board.drawCircle((float)x2,height()-(float)y2,0); + board.drawCircle((float)x0,height() - (float)y0,0); + board.drawCircle((float)x1,height() - (float)y1,0); + board.drawCircle((float)x2,height() - (float)y2,0); } #endif break; @@ -36820,9 +37590,9 @@ namespace cimg_library_suffixed { #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.drawLine((float)x0,height()-(float)y0,(float)x1,height()-(float)y1); - board.drawLine((float)x0,height()-(float)y0,(float)x2,height()-(float)y2); - board.drawLine((float)x1,height()-(float)y1,(float)x2,height()-(float)y2); + board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1); + board.drawLine((float)x0,height() - (float)y0,(float)x2,height() - (float)y2); + board.drawLine((float)x1,height() - (float)y1,(float)x2,height() - (float)y2); } #endif break; @@ -36832,9 +37602,9 @@ namespace cimg_library_suffixed { #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.fillTriangle((float)x0,height()-(float)y0, - (float)x1,height()-(float)y1, - (float)x2,height()-(float)y2); + board.fillTriangle((float)x0,height() - (float)y0, + (float)x1,height() - (float)y1, + (float)x2,height() - (float)y2); } #endif break; @@ -36849,9 +37619,9 @@ namespace cimg_library_suffixed { (unsigned char)(128*lp), (unsigned char)(128*lp), (unsigned char)(opacity*255)); - board.fillTriangle((float)x0,height()-(float)y0, - (float)x1,height()-(float)y1, - (float)x2,height()-(float)y2); + board.fillTriangle((float)x0,height() - (float)y0, + (float)x1,height() - (float)y1, + (float)x2,height() - (float)y2); } #endif break; @@ -36865,9 +37635,9 @@ namespace cimg_library_suffixed { #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.fillGouraudTriangle((float)x0,height()-(float)y0,lightprops(n0), - (float)x1,height()-(float)y1,lightprops(n1), - (float)x2,height()-(float)y2,lightprops(n2)); + board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprops(n0), + (float)x1,height() - (float)y1,lightprops(n1), + (float)x2,height() - (float)y2,lightprops(n2)); } #endif break; @@ -36887,40 +37657,38 @@ namespace cimg_library_suffixed { #ifdef cimg_use_board if (pboard) { const float - l0 = light_texture((int)(light_texture.width()/2*(1+lightprops(n0,0))), - (int)(light_texture.height()/2*(1+lightprops(n0,1)))), - l1 = light_texture((int)(light_texture.width()/2*(1+lightprops(n1,0))), - (int)(light_texture.height()/2*(1+lightprops(n1,1)))), - l2 = light_texture((int)(light_texture.width()/2*(1+lightprops(n2,0))), - (int)(light_texture.height()/2*(1+lightprops(n2,1)))); + l0 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n0,0))), + (int)(light_texture.height()/2*(1 + lightprops(n0,1)))), + l1 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n1,0))), + (int)(light_texture.height()/2*(1 + lightprops(n1,1)))), + l2 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n2,0))), + (int)(light_texture.height()/2*(1 + lightprops(n2,1)))); board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.fillGouraudTriangle((float)x0,height()-(float)y0,l0, - (float)x1,height()-(float)y1,l1, - (float)x2,height()-(float)y2,l2); + board.fillGouraudTriangle((float)x0,height() - (float)y0,l0, + (float)x1,height() - (float)y1,l1, + (float)x2,height() - (float)y2,l2); } #endif break; } } break; case 12 : { // Textured quadrangle - if (!__color) + if (!__color) { + if (render_type==5) cimg::mutex(10,0); throw CImgArgumentException(_cimg_instance "draw_object3d(): Undefined texture for quadrangle primitive [%u].", cimg_instance,n_primitive); + } const unsigned int n0 = (unsigned int)primitive[0], n1 = (unsigned int)primitive[1], n2 = (unsigned int)primitive[2], - n3 = (unsigned int)primitive[3], - tx0 = (unsigned int)primitive[4], - ty0 = (unsigned int)primitive[5], - tx1 = (unsigned int)primitive[6], - ty1 = (unsigned int)primitive[7], - tx2 = (unsigned int)primitive[8], - ty2 = (unsigned int)primitive[9], - tx3 = (unsigned int)primitive[10], - ty3 = (unsigned int)primitive[11]; + n3 = (unsigned int)primitive[3]; const int + tx0 = (int)primitive[4], ty0 = (int)primitive[5], + tx1 = (int)primitive[6], ty1 = (int)primitive[7], + tx2 = (int)primitive[8], ty2 = (int)primitive[9], + tx3 = (int)primitive[10], ty3 = (int)primitive[11], x0 = (int)projections(n0,0), y0 = (int)projections(n0,1), x1 = (int)projections(n1,0), y1 = (int)projections(n1,1), x2 = (int)projections(n2,0), y2 = (int)projections(n2,1), @@ -36933,17 +37701,21 @@ namespace cimg_library_suffixed { switch (render_type) { case 0 : - draw_point(x0,y0,color.get_vector_at(tx0,ty0)._data,opacity). - draw_point(x1,y1,color.get_vector_at(tx1,ty1)._data,opacity). - draw_point(x2,y2,color.get_vector_at(tx2,ty2)._data,opacity). - draw_point(x3,y3,color.get_vector_at(tx3,ty3)._data,opacity); + draw_point(x0,y0,color.get_vector_at(tx0<=0?0:tx0>=color.width()?color.width() - 1:tx0, + ty0<=0?0:ty0>=color.height()?color.height() - 1:ty0)._data,opacity). + draw_point(x1,y1,color.get_vector_at(tx1<=0?0:tx1>=color.width()?color.width() - 1:tx1, + ty1<=0?0:ty1>=color.height()?color.height() - 1:ty1)._data,opacity). + draw_point(x2,y2,color.get_vector_at(tx2<=0?0:tx2>=color.width()?color.width() - 1:tx2, + ty2<=0?0:ty2>=color.height()?color.height() - 1:ty2)._data,opacity). + draw_point(x3,y3,color.get_vector_at(tx3<=0?0:tx3>=color.width()?color.width() - 1:tx3, + ty3<=0?0:ty3>=color.height()?color.height() - 1:ty3)._data,opacity); #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.drawCircle((float)x0,height()-(float)y0,0); - board.drawCircle((float)x1,height()-(float)y1,0); - board.drawCircle((float)x2,height()-(float)y2,0); - board.drawCircle((float)x3,height()-(float)y3,0); + board.drawCircle((float)x0,height() - (float)y0,0); + board.drawCircle((float)x1,height() - (float)y1,0); + board.drawCircle((float)x2,height() - (float)y2,0); + board.drawCircle((float)x3,height() - (float)y3,0); } #endif break; @@ -36961,10 +37733,10 @@ namespace cimg_library_suffixed { #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.drawLine((float)x0,height()-(float)y0,(float)x1,height()-(float)y1); - board.drawLine((float)x1,height()-(float)y1,(float)x2,height()-(float)y2); - board.drawLine((float)x2,height()-(float)y2,(float)x3,height()-(float)y3); - board.drawLine((float)x3,height()-(float)y3,(float)x0,height()-(float)y0); + board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1); + board.drawLine((float)x1,height() - (float)y1,(float)x2,height() - (float)y2); + board.drawLine((float)x2,height() - (float)y2,(float)x3,height() - (float)y3); + board.drawLine((float)x3,height() - (float)y3,(float)x0,height() - (float)y0); } #endif break; @@ -36978,12 +37750,12 @@ namespace cimg_library_suffixed { #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.fillTriangle((float)x0,height()-(float)y0, - (float)x1,height()-(float)y1, - (float)x2,height()-(float)y2); - board.fillTriangle((float)x0,height()-(float)y0, - (float)x2,height()-(float)y2, - (float)x3,height()-(float)y3); + board.fillTriangle((float)x0,height() - (float)y0, + (float)x1,height() - (float)y1, + (float)x2,height() - (float)y2); + board.fillTriangle((float)x0,height() - (float)y0, + (float)x2,height() - (float)y2, + (float)x3,height() - (float)y3); } #endif break; @@ -37001,12 +37773,12 @@ namespace cimg_library_suffixed { (unsigned char)(128*lp), (unsigned char)(128*lp), (unsigned char)(opacity*255)); - board.fillTriangle((float)x0,height()-(float)y0, - (float)x1,height()-(float)y1, - (float)x2,height()-(float)y2); - board.fillTriangle((float)x0,height()-(float)y0, - (float)x2,height()-(float)y2, - (float)x3,height()-(float)y3); + board.fillTriangle((float)x0,height() - (float)y0, + (float)x1,height() - (float)y1, + (float)x2,height() - (float)y2); + board.fillTriangle((float)x0,height() - (float)y0, + (float)x2,height() - (float)y2, + (float)x3,height() - (float)y3); } #endif break; @@ -37027,12 +37799,12 @@ namespace cimg_library_suffixed { #ifdef cimg_use_board if (pboard) { board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.fillGouraudTriangle((float)x0,height()-(float)y0,lightprop0, - (float)x1,height()-(float)y1,lightprop1, - (float)x2,height()-(float)y2,lightprop2); - board.fillGouraudTriangle((float)x0,height()-(float)y0,lightprop0, - (float)x2,height()-(float)y2,lightprop2, - (float)x3,height()-(float)y3,lightprop3); + board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprop0, + (float)x1,height() - (float)y1,lightprop1, + (float)x2,height() - (float)y2,lightprop2); + board.fillGouraudTriangle((float)x0,height() -(float)y0,lightprop0, + (float)x2,height() - (float)y2,lightprop2, + (float)x3,height() - (float)y3,lightprop3); } #endif } break; @@ -37055,17 +37827,17 @@ namespace cimg_library_suffixed { #ifdef cimg_use_board if (pboard) { const float - l0 = light_texture((int)(light_texture.width()/2*(1+lx0)), (int)(light_texture.height()/2*(1+ly0))), - l1 = light_texture((int)(light_texture.width()/2*(1+lx1)), (int)(light_texture.height()/2*(1+ly1))), - l2 = light_texture((int)(light_texture.width()/2*(1+lx2)), (int)(light_texture.height()/2*(1+ly2))), - l3 = light_texture((int)(light_texture.width()/2*(1+lx3)), (int)(light_texture.height()/2*(1+ly3))); + l0 = light_texture((int)(light_texture.width()/2*(1 + lx0)), (int)(light_texture.height()/2*(1 + ly0))), + l1 = light_texture((int)(light_texture.width()/2*(1 + lx1)), (int)(light_texture.height()/2*(1 + ly1))), + l2 = light_texture((int)(light_texture.width()/2*(1 + lx2)), (int)(light_texture.height()/2*(1 + ly2))), + l3 = light_texture((int)(light_texture.width()/2*(1 + lx3)), (int)(light_texture.height()/2*(1 + ly3))); board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.fillGouraudTriangle((float)x0,height()-(float)y0,l0, - (float)x1,height()-(float)y1,l1, - (float)x2,height()-(float)y2,l2); - board.fillGouraudTriangle((float)x0,height()-(float)y0,l0, - (float)x2,height()-(float)y2,l2, - (float)x3,height()-(float)y3,l3); + board.fillGouraudTriangle((float)x0,height() - (float)y0,l0, + (float)x1,height() - (float)y1,l1, + (float)x2,height() - (float)y2,l2); + board.fillGouraudTriangle((float)x0,height() -(float)y0,l0, + (float)x2,height() - (float)y2,l2, + (float)x3,height() - (float)y3,l3); } #endif } break; @@ -37092,32 +37864,32 @@ namespace cimg_library_suffixed { \param XYZ Pointer to 3 values X,Y,Z which tells about the projection point coordinates, for volumetric images. **/ CImg& select(CImgDisplay &disp, - const unsigned int feature_type=2, unsigned int *const XYZ=0) { + const unsigned int feature_type=2, unsigned int *const XYZ=0) { return get_select(disp,feature_type,XYZ).move_to(*this); } //! Simple interface to select a shape from an image \overloading. CImg& select(const char *const title, - const unsigned int feature_type=2, unsigned int *const XYZ=0) { + const unsigned int feature_type=2, unsigned int *const XYZ=0) { return get_select(title,feature_type,XYZ).move_to(*this); } //! Simple interface to select a shape from an image \newinstance. CImg get_select(CImgDisplay &disp, - const unsigned int feature_type=2, unsigned int *const XYZ=0) const { + const unsigned int feature_type=2, unsigned int *const XYZ=0) const { return _get_select(disp,0,feature_type,XYZ,0,0,0,true,false); } //! Simple interface to select a shape from an image \newinstance. CImg get_select(const char *const title, - const unsigned int feature_type=2, unsigned int *const XYZ=0) const { + const unsigned int feature_type=2, unsigned int *const XYZ=0) const { CImgDisplay disp; return _get_select(disp,title,feature_type,XYZ,0,0,0,true,false); } CImg _get_select(CImgDisplay &disp, const char *const title, - const unsigned int feature_type, unsigned int *const XYZ, - const int origX, const int origY, const int origZ, + const unsigned int feature_type, unsigned int *const XYZ, + const int origX, const int origY, const int origZ, const bool reset_view3d, const bool force_display_z_coord) const { if (is_empty()) return CImg(1,feature_type==0?3:6,1,1,-1); @@ -37130,13 +37902,14 @@ namespace cimg_library_suffixed { bool old_is_resized = disp.is_resized(); disp._normalization = 0; disp.show().set_key(0).set_wheel().show_mouse(); + disp._mouse_x = disp._mouse_y = -1; unsigned char foreground_color[] = { 255,255,255 }, background_color[] = { 0,0,0 }; int area = 0, starting_area = 0, clicked_area = 0, phase = 0, - X0 = (int)((XYZ?XYZ[0]:(_width-1)/2)%_width), - Y0 = (int)((XYZ?XYZ[1]:(_height-1)/2)%_height), - Z0 = (int)((XYZ?XYZ[2]:(_depth-1)/2)%_depth), + X0 = (int)((XYZ?XYZ[0]:(_width - 1)/2)%_width), + Y0 = (int)((XYZ?XYZ[1]:(_height - 1)/2)%_height), + Z0 = (int)((XYZ?XYZ[2]:(_depth - 1)/2)%_depth), X1 =-1, Y1 = -1, Z1 = -1, X3d = -1, Y3d = -1, oX3d = X3d, oY3d = -1, @@ -37152,7 +37925,7 @@ namespace cimg_library_suffixed { CImgList primitives3d, sel_primitives3d; CImgList colors3d, sel_colors3d; CImg visu, visu0, view3d; - char text[1024] = { 0 }; + CImg text(1024); *text = 0; while (!key && !disp.is_closed() && !shape_selected) { @@ -37162,8 +37935,8 @@ namespace cimg_library_suffixed { my = disp.mouse_y(); const float - mX = mx<0?-1.0f:(float)mx*(width()+(depth()>1?depth():0))/disp.width(), - mY = my<0?-1.0f:(float)my*(height()+(depth()>1?depth():0))/disp.height(); + mX = mx<0?-1.0f:(float)mx*(width() + (depth()>1?depth():0))/disp.width(), + mY = my<0?-1.0f:(float)my*(height() + (depth()>1?depth():0))/disp.height(); area = 0; if (mX>=0 && mY>=0 && mX1?_depth:0)); - Y3d = my - _height*disp.height()/(_height+(_depth>1?_depth:0)); + X3d = mx - width()*disp.width()/(width() + (depth()>1?depth():0)); + Y3d = my - height()*disp.height()/(height() + (depth()>1?depth():0)); if (oX3d<0) { oX3d = X3d; oY3d = Y3d; } // Left + right buttons: reset. if ((disp.button()&3)==3) { pose3d.assign(); view3d.assign(); oX3d = oY3d = X3d = Y3d = -1; } @@ -37320,22 +38093,22 @@ namespace cimg_library_suffixed { const float R = 0.45f*cimg::min(view3d._width,view3d._height), R2 = R*R, - u0 = (float)(oX3d-view3d.width()/2), - v0 = (float)(oY3d-view3d.height()/2), - u1 = (float)(X3d-view3d.width()/2), - v1 = (float)(Y3d-view3d.height()/2), - n0 = (float)std::sqrt(u0*u0+v0*v0), - n1 = (float)std::sqrt(u1*u1+v1*v1), + u0 = (float)(oX3d - view3d.width()/2), + v0 = (float)(oY3d - view3d.height()/2), + u1 = (float)(X3d - view3d.width()/2), + v1 = (float)(Y3d - view3d.height()/2), + n0 = (float)std::sqrt(u0*u0 + v0*v0), + n1 = (float)std::sqrt(u1*u1 + v1*v1), nu0 = n0>R?(u0*R/n0):u0, nv0 = n0>R?(v0*R/n0):v0, - nw0 = (float)std::sqrt(cimg::max(0,R2-nu0*nu0-nv0*nv0)), + nw0 = (float)std::sqrt(cimg::max(0,R2 - nu0*nu0 - nv0*nv0)), nu1 = n1>R?(u1*R/n1):u1, nv1 = n1>R?(v1*R/n1):v1, - nw1 = (float)std::sqrt(cimg::max(0,R2-nu1*nu1-nv1*nv1)), + nw1 = (float)std::sqrt(cimg::max(0,R2 - nu1*nu1 - nv1*nv1)), u = nv0*nw1 - nw0*nv1, v = nw0*nu1 - nu0*nw1, w = nv0*nu1 - nu0*nv1, - n = (float)std::sqrt(u*u+v*v+w*w), + n = (float)std::sqrt(u*u + v*v + w*w), alpha = (float)std::asin(n/R2); pose3d.draw_image(CImg::rotation_matrix(u,v,w,alpha)*pose3d.get_crop(0,0,2,2)); view3d.assign(); @@ -37380,17 +38153,18 @@ namespace cimg_library_suffixed { if (is_view3d && _depth>1 && !view3d) { // Create 3d view for volumetric images. const unsigned int - _x3d = (unsigned int)cimg::round((float)_width*visu0._width/(_width+_depth),1,1), - _y3d = (unsigned int)cimg::round((float)_height*visu0._height/(_height+_depth),1,1), - x3d = _x3d>=visu0._width?visu0._width-1:_x3d, - y3d = _y3d>=visu0._height?visu0._height-1:_y3d; - CImg(1,2,1,1,64,128).resize(visu0._width-x3d,visu0._height-y3d,1,visu0._spectrum,3).move_to(view3d); + _x3d = (unsigned int)cimg::round((float)_width*visu0._width/(_width + _depth),1,1), + _y3d = (unsigned int)cimg::round((float)_height*visu0._height/(_height + _depth),1,1), + x3d = _x3d>=visu0._width?visu0._width - 1:_x3d, + y3d = _y3d>=visu0._height?visu0._height - 1:_y3d; + CImg(1,2,1,1,64,128).resize(visu0._width - x3d,visu0._height - y3d,1,visu0._spectrum,3). + move_to(view3d); if (!points3d) { get_projections3d(primitives3d,colors3d,phase?X1:X0,phase?Y1:Y0,phase?Z1:Z0,true).move_to(points3d); points3d.append(CImg(8,3,1,1, - 0,_width-1,_width-1,0,0,_width-1,_width-1,0, - 0,0,_height-1,_height-1,0,0,_height-1,_height-1, - 0,0,0,0,_depth-1,_depth-1,_depth-1,_depth-1),'x'); + 0,_width - 1,_width - 1,0,0,_width - 1,_width - 1,0, + 0,0,_height - 1,_height - 1,0,0,_height - 1,_height - 1, + 0,0,0,0,_depth - 1,_depth - 1,_depth - 1,_depth - 1),'x'); CImg::vector(12,13).move_to(primitives3d); CImg::vector(13,14).move_to(primitives3d); CImg::vector(14,15).move_to(primitives3d); CImg::vector(15,12).move_to(primitives3d); CImg::vector(16,17).move_to(primitives3d); CImg::vector(17,18).move_to(primitives3d); @@ -37433,7 +38207,7 @@ namespace cimg_library_suffixed { sel_colors3d.assign(sel_primitives3d._width,CImg::vector(255,255,255)); sel_opacities3d.assign(sel_primitives3d._width,1,1,1,0.8f); } - points3d.shift_object3d(-0.5f*(_width-1),-0.5f*(_height-1),-0.5f*(_depth-1)).resize_object3d(); + points3d.shift_object3d(-0.5f*(_width - 1),-0.5f*(_height - 1),-0.5f*(_depth - 1)).resize_object3d(); points3d*=0.75f*cimg::min(view3d._width,view3d._height); } @@ -37459,34 +38233,37 @@ namespace cimg_library_suffixed { else { if (is_axes) { if (visible_cursor) { disp.hide_mouse(); visible_cursor = false; }} else { if (!visible_cursor) { disp.show_mouse(); visible_cursor = true; }} - const int d = (_depth>1)?_depth:0; + const int d = (depth()>1)?depth():0; int + _X = (int)X, _Y = (int)Y, _Z = (int)Z, w = disp.width(), W = width() + d, h = disp.height(), H = height() + d, - _xp = (int)X*w/W, xp = _xp + (_xp*W/w!=(int)X?1:0), - _yp = (int)Y*h/H, yp = _yp + (_yp*H/h!=(int)Y?1:0), - _xn = (int)(X+1)*w/W-1, xn = _xn + ((_xn+1)*W/w!=(int)X+1?1:0), - _yn = (int)(Y+1)*h/H-1, yn = _yn + ((_yn+1)*H/h!=(int)Y+1?1:0), - _zxp = ((int)Z+width())*w/W, zxp = _zxp + (_zxp*W/w!=(int)Z+width()?1:0), - _zyp = ((int)Z+height())*h/H, zyp = _zyp + (_zyp*H/h!=(int)Z+height()?1:0), - _zxn = ((int)Z+width()+1)*w/W-1, zxn = _zxn + ((_zxn+1)*W/w!=(int)Z+width()+1?1:0), - _zyn = ((int)Z+height()+1)*h/H-1, zyn = _zyn + ((_zyn+1)*H/h!=(int)Z+height()+1?1:0), - _xM = width()*w/W-1, xM = _xM + ((_xM+1)*W/w!=width()?1:0), - _yM = height()*h/H-1, yM = _yM + ((_yM+1)*H/h!=height()?1:0), + _xp = (int)(_X*(float)w/W), xp = _xp + ((int)(_xp*(float)W/w)!=_X?1:0), + _yp = (int)(_Y*(float)h/H), yp = _yp + ((int)(_yp*(float)H/h)!=_Y?1:0), + _xn = (int)((_X + 1.0f)*w/W - 1), xn = _xn + ((int)((_xn + 1.0f)*W/w)!=_X + 1?1:0), + _yn = (int)((_Y + 1.0f)*h/H - 1), yn = _yn + ((int)((_yn + 1.0f)*H/h)!=_Y + 1?1:0), + _zxp = (int)((_Z + width())*(float)w/W), zxp = _zxp + ((int)(_zxp*(float)W/w)!=_Z + width()?1:0), + _zyp = (int)((_Z + height())*(float)h/H), zyp = _zyp + ((int)(_zyp*(float)H/h)!=_Z + height()?1:0), + _zxn = (int)((_Z + width() + 1.0f)*w/W - 1), + zxn = _zxn + ((int)((_zxn + 1.0f)*W/w)!=_Z + width() + 1?1:0), + _zyn = (int)((_Z + height() + 1.0f)*h/H - 1), + zyn = _zyn + ((int)((_zyn + 1.0f)*H/h)!=_Z + height() + 1?1:0), + _xM = (int)(width()*(float)w/W - 1), xM = _xM + ((int)((_xM + 1.0f)*W/w)!=width()?1:0), + _yM = (int)(height()*(float)h/H - 1), yM = _yM + ((int)((_yM + 1.0f)*H/h)!=height()?1:0), xc = (xp + xn)/2, yc = (yp + yn)/2, zxc = (zxp + zxn)/2, zyc = (zyp + zyn)/2, xf = (int)(X*w/W), yf = (int)(Y*h/H), - zxf = (int)((Z+width())*w/W), - zyf = (int)((Z+height())*h/H); + zxf = (int)((Z + width())*w/W), + zyf = (int)((Z + height())*h/H); if (is_axes) { // Draw axes. - visu.draw_line(0,yf,visu.width()-1,yf,foreground_color,0.7f,0xFF00FF00). - draw_line(0,yf,visu.width()-1,yf,background_color,0.7f,0x00FF00FF). - draw_line(xf,0,xf,visu.height()-1,foreground_color,0.7f,0xFF00FF00). - draw_line(xf,0,xf,visu.height()-1,background_color,0.7f,0x00FF00FF); + visu.draw_line(0,yf,visu.width() - 1,yf,foreground_color,0.7f,0xFF00FF00). + draw_line(0,yf,visu.width() - 1,yf,background_color,0.7f,0x00FF00FF). + draw_line(xf,0,xf,visu.height() - 1,foreground_color,0.7f,0xFF00FF00). + draw_line(xf,0,xf,visu.height() - 1,background_color,0.7f,0x00FF00FF); if (_depth>1) visu.draw_line(zxf,0,zxf,yM,foreground_color,0.7f,0xFF00FF00). draw_line(zxf,0,zxf,yM,background_color,0.7f,0x00FF00FF). @@ -37495,14 +38272,14 @@ namespace cimg_library_suffixed { } // Draw box cursor. - if (xn-xp>=4 && yn-yp>=4) visu.draw_rectangle(xp,yp,xn,yn,foreground_color,0.2f). + if (xn - xp>=4 && yn - yp>=4) visu.draw_rectangle(xp,yp,xn,yn,foreground_color,0.2f). draw_rectangle(xp,yp,xn,yn,foreground_color,1,0xAAAAAAAA). draw_rectangle(xp,yp,xn,yn,background_color,1,0x55555555); if (_depth>1) { - if (yn-yp>=4 && zxn-zxp>=4) visu.draw_rectangle(zxp,yp,zxn,yn,background_color,0.2f). + if (yn - yp>=4 && zxn - zxp>=4) visu.draw_rectangle(zxp,yp,zxn,yn,background_color,0.2f). draw_rectangle(zxp,yp,zxn,yn,foreground_color,1,0xAAAAAAAA). draw_rectangle(zxp,yp,zxn,yn,background_color,1,0x55555555); - if (xn-xp>=4 && zyn-zyp>=4) visu.draw_rectangle(xp,zyp,xn,zyn,background_color,0.2f). + if (xn - xp>=4 && zyn - zyp>=4) visu.draw_rectangle(xp,zyp,xn,zyn,background_color,0.2f). draw_rectangle(xp,zyp,xn,zyn,foreground_color,1,0xAAAAAAAA). draw_rectangle(xp,zyp,xn,zyn,background_color,1,0x55555555); } @@ -37510,14 +38287,16 @@ namespace cimg_library_suffixed { // Draw selection. if (phase) { const int - _xp0 = X0*w/W, xp0 = _xp0 + (_xp0*W/w!=X0?1:0), - _yp0 = Y0*h/H, yp0 = _yp0 + (_yp0*H/h!=Y0?1:0), - _xn0 = (X0+1)*w/W-1, xn0 = _xn0 + ((_xn0+1)*W/w!=X0+1?1:0), - _yn0 = (Y0+1)*h/H-1, yn0 = _yn0 + ((_yn0+1)*H/h!=Y0+1?1:0), - _zxp0 = (Z0+width())*w/W, zxp0 = _zxp0 + (_zxp0*W/w!=Z0+width()?1:0), - _zyp0 = (Z0+height())*h/H, zyp0 = _zyp0 + (_zyp0*H/h!=Z0+height()?1:0), - _zxn0 = (Z0+width()+1)*w/W-1, zxn0 = _zxn0 + ((_zxn0+1)*W/w!=Z0+width()+1?1:0), - _zyn0 = (Z0+height()+1)*h/H-1, zyn0 = _zyn0 + ((_zyn0+1)*H/h!=Z0+height()+1?1:0), + _xp0 = (int)(X0*(float)w/W), xp0 = _xp0 + ((int)(_xp0*(float)W/w)!=X0?1:0), + _yp0 = (int)(Y0*(float)h/H), yp0 = _yp0 + ((int)(_yp0*(float)H/h)!=Y0?1:0), + _xn0 = (int)((X0 + 1.0f)*w/W - 1), xn0 = _xn0 + ((int)((_xn0 + 1.0f)*W/w)!=X0 + 1?1:0), + _yn0 = (int)((Y0 + 1.0f)*h/H - 1), yn0 = _yn0 + ((int)((_yn0 + 1.0f)*H/h)!=Y0 + 1?1:0), + _zxp0 = (int)((Z0 + width())*(float)w/W), zxp0 = _zxp0 + ((int)(_zxp0*(float)W/w)!=Z0 + width()?1:0), + _zyp0 = (int)((Z0 + height())*(float)h/H), zyp0 = _zyp0 + ((int)(_zyp0*(float)H/h)!=Z0 + height()?1:0), + _zxn0 = (int)((Z0 + width() + 1.0f)*w/W - 1), + zxn0 = _zxn0 + ((int)((_zxn0 + 1.0f)*W/w)!=Z0 + width() + 1?1:0), + _zyn0 = (int)((Z0 + height() + 1.0f)*h/H - 1), + zyn0 = _zyn0 + ((int)((_zyn0 + 1.0f)*H/h)!=Z0 + height() + 1?1:0), xc0 = (xp0 + xn0)/2, yc0 = (yp0 + yn0)/2, zxc0 = (zxp0 + zxn0)/2, @@ -37553,18 +38332,22 @@ namespace cimg_library_suffixed { } } break; case 3 : { - visu.draw_ellipse(xc0,yc0,(float)cimg::abs(xc-xc0),(float)cimg::abs(yc-yc0),0,background_color,0.2f). - draw_ellipse(xc0,yc0,(float)cimg::abs(xc-xc0),(float)cimg::abs(yc-yc0),0,foreground_color,0.9f,~0U). + visu.draw_ellipse(xc0,yc0, + (float)cimg::abs(xc - xc0), + (float)cimg::abs(yc - yc0),0,background_color,0.2f). + draw_ellipse(xc0,yc0, + (float)cimg::abs(xc - xc0), + (float)cimg::abs(yc - yc0),0,foreground_color,0.9f,~0U). draw_point(xc0,yc0,foreground_color,0.9f); if (d) { - visu.draw_ellipse(zxc0,yc0,(float)cimg::abs(zxc-zxc0),(float)cimg::abs(yc-yc0),0, + visu.draw_ellipse(zxc0,yc0,(float)cimg::abs(zxc - zxc0),(float)cimg::abs(yc - yc0),0, background_color,0.2f). - draw_ellipse(zxc0,yc0,(float)cimg::abs(zxc-zxc0),(float)cimg::abs(yc-yc0),0, + draw_ellipse(zxc0,yc0,(float)cimg::abs(zxc - zxc0),(float)cimg::abs(yc - yc0),0, foreground_color,0.9f,~0U). draw_point(zxc0,yc0,foreground_color,0.9f). - draw_ellipse(xc0,zyc0,(float)cimg::abs(xc-xc0),(float)cimg::abs(zyc-zyc0),0, + draw_ellipse(xc0,zyc0,(float)cimg::abs(xc - xc0),(float)cimg::abs(zyc - zyc0),0, background_color,0.2f). - draw_ellipse(xc0,zyc0,(float)cimg::abs(xc-xc0),(float)cimg::abs(zyc-zyc0),0, + draw_ellipse(xc0,zyc0,(float)cimg::abs(xc - xc0),(float)cimg::abs(zyc - zyc0),0, foreground_color,0.9f,~0U). draw_point(xc0,zyc0,foreground_color,0.9f); } @@ -37573,51 +38356,53 @@ namespace cimg_library_suffixed { } // Draw text info. - if (my>=0 && my<13) text_down = true; else if (my>=visu.height()-13) text_down = false; + if (my>=0 && my<13) text_down = true; else if (my>=visu.height() - 13) text_down = false; if (!feature_type || !phase) { if (X>=0 && Y>=0 && Z>=0 && X1 || force_display_z_coord) - cimg_snprintf(text,sizeof(text)," Point (%d,%d,%d) = [ ",origX+(int)X,origY+(int)Y,origZ+(int)Z); - else cimg_snprintf(text,sizeof(text)," Point (%d,%d) = [ ",origX+(int)X,origY+(int)Y); - char *ctext = text + std::strlen(text), *const ltext = text + 512; + cimg_snprintf(text,text._width," Point (%d,%d,%d) = [ ",origX + (int)X,origY + (int)Y,origZ + (int)Z); + else cimg_snprintf(text,text._width," Point (%d,%d) = [ ",origX + (int)X,origY + (int)Y); + char *ctext = text._data + std::strlen(text), *const ltext = text._data + 512; for (unsigned int c = 0; c<_spectrum && ctext::format(), + cimg_snprintf(ctext,text._width/2,cimg::type::format(), cimg::type::format((*this)((int)X,(int)Y,(int)Z,c))); - ctext = text + std::strlen(text); + ctext = text._data + std::strlen(text); *(ctext++) = ' '; *ctext = 0; } - std::strcpy(text + std::strlen(text),"] "); + std::strcpy(text._data + std::strlen(text),"] "); } } else switch (feature_type) { case 1 : { const double dX = (double)(X0 - X1), dY = (double)(Y0 - Y1), dZ = (double)(Z0 - Z1), - norm = std::sqrt(dX*dX+dY*dY+dZ*dZ); + norm = std::sqrt(dX*dX + dY*dY + dZ*dZ); if (_depth>1 || force_display_z_coord) - cimg_snprintf(text,sizeof(text)," Vect (%d,%d,%d)-(%d,%d,%d), Norm = %g ", - origX+X0,origY+Y0,origZ+Z0,origX+X1,origY+Y1,origZ+Z1,norm); - else cimg_snprintf(text,sizeof(text)," Vect (%d,%d)-(%d,%d), Norm = %g ", - origX+X0,origY+Y0,origX+X1,origY+Y1,norm); + cimg_snprintf(text,text._width," Vect (%d,%d,%d)-(%d,%d,%d), Norm = %g ", + origX + X0,origY + Y0,origZ + Z0,origX + X1,origY + Y1,origZ + Z1,norm); + else cimg_snprintf(text,text._width," Vect (%d,%d)-(%d,%d), Norm = %g ", + origX + X0,origY + Y0,origX + X1,origY + Y1,norm); } break; case 2 : if (_depth>1 || force_display_z_coord) - cimg_snprintf(text,sizeof(text)," Box (%d,%d,%d)-(%d,%d,%d), Size = (%d,%d,%d) ", - origX+(X01 || force_display_z_coord) - cimg_snprintf(text,sizeof(text)," Ellipse (%d,%d,%d)-(%d,%d,%d), Radii = (%d,%d,%d) ", - origX+X0,origY+Y0,origZ+Z0,origX+X1,origY+Y1,origZ+Z1, - 1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1)); - else cimg_snprintf(text,sizeof(text)," Ellipse (%d,%d)-(%d,%d), Radii = (%d,%d) ", - origX+X0,origY+Y0,origX+X1,origY+Y1,1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1)); + cimg_snprintf(text,text._width," Ellipse (%d,%d,%d)-(%d,%d,%d), Radii = (%d,%d,%d) ", + origX + X0,origY + Y0,origZ + Z0,origX + X1,origY + Y1,origZ + Z1, + 1 + cimg::abs(X0 - X1),1 + cimg::abs(Y0 - Y1),1 + cimg::abs(Z0 - Z1)); + else cimg_snprintf(text,text._width," Ellipse (%d,%d)-(%d,%d), Radii = (%d,%d) ", + origX + X0,origY + Y0,origX + X1,origY + Y1, + 1 + cimg::abs(X0 - X1),1 + cimg::abs(Y0 - Y1)); } if (phase || (mx>=0 && my>=0)) - visu.draw_text(0,text_down?visu.height()-13:0,text,foreground_color,background_color,0.7f,13); + visu.draw_text(0,text_down?visu.height() - 13:0,text,foreground_color,background_color,0.7f,13); } disp.display(visu).wait(); @@ -37635,13 +38420,13 @@ namespace cimg_library_suffixed { if (Y0>Y1) cimg::swap(Y0,Y1); if (Z0>Z1) cimg::swap(Z0,Z1); } - if (X1<0 || Y1<0 || Z1<0) X0 = Y0 = Z0 = X1 = Y1 = Z1 = -1; - switch (feature_type) { - case 1 : case 2 : res[0] = X0; res[1] = Y0; res[2] = Z0; res[3] = X1; res[4] = Y1; res[5] = Z1; break; + if (X1<0 || Y1<0 || Z1<0) X0 = Y0 = Z0 = X1 = Y1 = Z1 = -1; + switch (feature_type) { + case 1 : case 2 : res[0] = X0; res[1] = Y0; res[2] = Z0; res[3] = X1; res[4] = Y1; res[5] = Z1; break; case 3 : - res[3] = cimg::abs(X1-X0); res[4] = cimg::abs(Y1-Y0); res[5] = cimg::abs(Z1-Z0); // keep no break here! - default : res[0] = X0; res[1] = Y0; res[2] = Z0; - } + res[3] = cimg::abs(X1 - X0); res[4] = cimg::abs(Y1 - Y0); res[5] = cimg::abs(Z1 - Z0); // keep no break here! + default : res[0] = X0; res[1] = Y0; res[2] = Z0; + } } disp.set_button(); if (!visible_cursor) disp.show_mouse(); @@ -37655,28 +38440,31 @@ namespace cimg_library_suffixed { CImg __get_select(const CImgDisplay& disp, const int normalization, const int x, const int y, const int z) const { if (is_empty()) return CImg(1,1,1,1,0); - const CImg crop = get_shared_channels(0,cimg::min(2,spectrum()-1)); + const CImg crop = get_shared_channels(0,cimg::min(2,spectrum() - 1)); CImg img2d; if (_depth>1) crop.get_projections2d(x,y,z).move_to(img2d); else CImg(crop,false).move_to(img2d); - if (cimg::type::is_float()) { // Check for inf and nan values. + // Check for inf and nan values. + if (cimg::type::is_float() && disp._normalization && + (disp._normalization!=3 || cimg::type::string()!=cimg::type::string())) { bool is_inf = false, is_nan = false; cimg_for(img2d,ptr,Tuchar) if (cimg::type::is_inf(*ptr)) { is_inf = true; break; } else if (cimg::type::is_nan(*ptr)) { is_nan = true; break; } if (is_inf || is_nan) { - T m0 = cimg::type::max(), M0 = cimg::type::min(); + Tint m0 = (Tint)cimg::type::max(), M0 = (Tint)cimg::type::min(); if (!normalization) { m0 = 0; M0 = 255; } - else if (normalization==2) { m0 = (T)disp._min; M0 = (T)disp._max; } + else if (normalization==2) { m0 = (Tint)disp._min; M0 = (Tint)disp._max; } else cimg_for(img2d,ptr,Tuchar) if (!cimg::type::is_inf(*ptr) && !cimg::type::is_nan(*ptr)) { - if (*ptrM0) M0 = *ptr; + if (*ptr<(Tuchar)m0) m0 = *ptr; + if (*ptr>(Tuchar)M0) M0 = *ptr; } const T - val_minf = (normalization==1 || normalization==3)?m0-(M0-m0)*20-1:m0, - val_pinf = (normalization==1 || normalization==3)?M0+(M0-m0)*20+1:M0; + val_minf = (T)(normalization==1 || normalization==3?m0 - (M0 - m0)*20 - 1:m0), + val_pinf = (T)(normalization==1 || normalization==3?M0 + (M0 - m0)*20 + 1:M0); if (is_nan) cimg_for(img2d,ptr,Tuchar) if (cimg::type::is_nan(*ptr)) *ptr = val_minf; // Replace nan values. @@ -37690,13 +38478,13 @@ namespace cimg_library_suffixed { case 1 : img2d.normalize(0,255); break; case 2 : { const float m = disp._min, M = disp._max; - (img2d-=m)*=255.0f/(M-m>0?M-m:1); + (img2d-=m)*=255.0f/(M - m>0?M - m:1); } break; case 3 : if (cimg::type::is_float()) img2d.normalize(0,255); else { const float m = (float)cimg::type::min(), M = (float)cimg::type::max(); - (img2d-=m)*=255.0f/(M-m>0?M-m:1); + (img2d-=m)*=255.0f/(M - m>0?M - m:1); } break; } @@ -37741,9 +38529,9 @@ namespace cimg_library_suffixed { CImg visu0, visu, graph, text, axes; int x0 = -1, x1 = -1, y0 = -1, y1 = -1, omouse_x = -2, omouse_y = -2; - const unsigned int one = plot_type==3?0:1; + const unsigned int one = plot_type==3?0U:1U; unsigned int okey = 0, obutton = 0; - char message[1024] = { 0 }; + CImg message(1024); CImg_3x3(I,unsigned char); for (bool selected = false; !selected && !disp.is_closed() && !okey && !disp.wheel(); ) { @@ -37766,20 +38554,20 @@ namespace cimg_library_suffixed { axes.assign(gdimx,gdimy,1,1,0); const float - dx = (float)cimg::abs(nxmax-nxmin), dy = (float)cimg::abs(nymax-nymin), - px = (float)std::pow(10.0,(int)std::log10(dx?dx:1)-2.0), - py = (float)std::pow(10.0,(int)std::log10(dy?dy:1)-2.0); + dx = (float)cimg::abs(nxmax - nxmin), dy = (float)cimg::abs(nymax - nymin), + px = (float)std::pow(10.0,(int)std::log10(dx?dx:1) - 2.0), + py = (float)std::pow(10.0,(int)std::log10(dy?dy:1) - 2.0); const CImg seqx = dx<=0?CImg::vector(nxmin): - CImg::sequence(1 + gdimx/60,nxmin,one?nxmax:nxmin+(nxmax-nxmin)*(siz+1)/siz).round(px), + CImg::sequence(1 + gdimx/60,nxmin,one?nxmax:nxmin + (nxmax - nxmin)*(siz + 1)/siz).round(px), seqy = CImg::sequence(1 + gdimy/60,nymax,nymin).round(py); const bool allow_zero = (nxmin*nxmax>0) || (nymin*nymax>0); axes.draw_axes(seqx,seqy,white,1,~0U,~0U,13,allow_zero); - if (nymin>0) axes.draw_axis(seqx,gdimy-1,gray,1,~0U,13,allow_zero); + if (nymin>0) axes.draw_axis(seqx,gdimy - 1,gray,1,~0U,13,allow_zero); if (nymax<0) axes.draw_axis(seqx,0,gray,1,~0U,13,allow_zero); - if (nxmin>0) axes.draw_axis(0,seqy,gray,1,~0U,13,allow_zero); - if (nxmax<0) axes.draw_axis(gdimx-1,seqy,gray,1,~0U,13,allow_zero); + if (nxmin>0) axes.draw_axis(0,seqy,gray,1,~0U,13,allow_zero); + if (nxmax<0) axes.draw_axis(gdimx - 1,seqy,gray,1,~0U,13,allow_zero); cimg_for3x3(axes,x,y,0,0,I,unsigned char) if (Icc) { @@ -37787,16 +38575,16 @@ namespace cimg_library_suffixed { else cimg_forC(graph,c) graph(x,y,c) = (unsigned char)(2*graph(x,y,c)/3); } else if (Ipc || Inc || Icp || Icn || Ipp || Inn || Ipn || Inp) - cimg_forC(graph,c) graph(x,y,c) = (graph(x,y,c)+511)/3; + cimg_forC(graph,c) graph(x,y,c) = (unsigned char)((graph(x,y,c) + 511)/3); visu0.draw_image(16,16,graph); - visu0.draw_line(15,15,16+gdimx,15,gray2).draw_line(16+gdimx,15,16+gdimx,16+gdimy,gray2). - draw_line(16+gdimx,16+gdimy,15,16+gdimy,white).draw_line(15,16+gdimy,15,15,white); + visu0.draw_line(15,15,16 + gdimx,15,gray2).draw_line(16 + gdimx,15,16 + gdimx,16 + gdimy,gray2). + draw_line(16 + gdimx,16 + gdimy,15,16 + gdimy,white).draw_line(15,16 + gdimy,15,15,white); } else graph.assign(); text.assign().draw_text(0,0,labelx?labelx:"X-axis",white,ngray,1,13).resize(-100,-100,1,3); - visu0.draw_image((visu0.width()-text.width())/2,visu0.height()-14,~text); + visu0.draw_image((visu0.width() - text.width())/2,visu0.height() - 14,~text); text.assign().draw_text(0,0,labely?labely:"Y-axis",white,ngray,1,13).rotate(-90).resize(-100,-100,1,3); - visu0.draw_image(1,(visu0.height()-text.height())/2,~text); + visu0.draw_image(1,(visu0.height() - text.height())/2,~text); visu.assign(); } @@ -37809,50 +38597,51 @@ namespace cimg_library_suffixed { nx1 = x0<=x1?x1:x0, ny0 = y0<=y1?y0:y1, ny1 = y0<=y1?y1:y0, - sx0 = 16 + nx0*(visu.width()-32)/cimg::max(1U,siz-one), - sx1 = 15 + (nx1+1)*(visu.width()-32)/cimg::max(1U,siz-one), + sx0 = (int)(16 + nx0*(visu.width() - 32)/cimg::max(1U,siz - one)), + sx1 = (int)(15 + (nx1 + 1)*(visu.width() - 32)/cimg::max(1U,siz - one)), sy0 = 16 + ny0, sy1 = 16 + ny1; if (y0>=0 && y1>=0) visu.draw_rectangle(sx0,sy0,sx1,sy1,gray,0.5f).draw_rectangle(sx0,sy0,sx1,sy1,black,0.5f,0xCCCCCCCCU); - else visu.draw_rectangle(sx0,0,sx1,visu.height()-17,gray,0.5f). - draw_line(sx0,16,sx0,visu.height()-17,black,0.5f,0xCCCCCCCCU). - draw_line(sx1,16,sx1,visu.height()-17,black,0.5f,0xCCCCCCCCU); - } - if (mouse_x>=16 && mouse_y>=16 && mouse_x=16 && mouse_y>=16 && mouse_x=7) - cimg_snprintf(message,sizeof(message),"Value[%u:%g] = ( %g %g %g ... %g %g %g )",x,cx, + cimg_snprintf(message,message._width,"Value[%u:%g] = ( %g %g %g ... %g %g %g )",x,cx, (double)(*this)(x,0,0,0),(double)(*this)(x,0,0,1),(double)(*this)(x,0,0,2), - (double)(*this)(x,0,0,_spectrum-4),(double)(*this)(x,0,0,_spectrum-3), - (double)(*this)(x,0,0,_spectrum-1)); + (double)(*this)(x,0,0,_spectrum - 4),(double)(*this)(x,0,0,_spectrum - 3), + (double)(*this)(x,0,0,_spectrum - 1)); else { - cimg_snprintf(message,sizeof(message),"Value[%u:%g] = ( ",x,cx); - cimg_forC(*this,c) std::sprintf(message + std::strlen(message),"%g ",(double)(*this)(x,0,0,c)); - std::sprintf(message + std::strlen(message),")"); - } - if (x0>=0 && x1>=0) { - const unsigned int - nx0 = x0<=x1?x0:x1, - nx1 = x0<=x1?x1:x0, - ny0 = y0<=y1?y0:y1, - ny1 = y0<=y1?y1:y0; - const double - cx0 = nxmin + nx0*(nxmax-nxmin)/cimg::max(1U,siz-1), - cx1 = nxmin + (nx1+one)*(nxmax-nxmin)/cimg::max(1U,siz-1), - cy0 = nymax - ny0*(nymax-nymin)/(visu._height-32), - cy1 = nymax - ny1*(nymax-nymin)/(visu._height-32); - if (y0>=0 && y1>=0) - std::sprintf(message + std::strlen(message)," - Range ( %u:%g, %g ) - ( %u:%g, %g )", - x0,cx0,cy0,x1+one,cx1,cy1); - else - std::sprintf(message + std::strlen(message)," - Range [ %u:%g - %u:%g ]", - x0,cx0,x1+one,cx1); - } + cimg_snprintf(message,message._width,"Value[%u:%g] = ( ",x,cx); + cimg_forC(*this,c) std::sprintf(message._data + std::strlen(message),"%g ",(double)(*this)(x,0,0,c)); + std::sprintf(message._data + std::strlen(message),")"); + } + if (x0>=0 && x1>=0) { + const unsigned int + nx0 = (unsigned int)(x0<=x1?x0:x1), + nx1 = (unsigned int)(x0<=x1?x1:x0), + ny0 = (unsigned int)(y0<=y1?y0:y1), + ny1 = (unsigned int)(y0<=y1?y1:y0); + const double + cx0 = nxmin + nx0*(nxmax - nxmin)/cimg::max(1U,siz - 1), + cx1 = nxmin + (nx1 + one)*(nxmax - nxmin)/cimg::max(1U,siz - 1), + cy0 = nymax - ny0*(nymax - nymin)/(visu._height - 32), + cy1 = nymax - ny1*(nymax - nymin)/(visu._height - 32); + if (y0>=0 && y1>=0) + std::sprintf(message._data + std::strlen(message)," - Range ( %u:%g, %g ) - ( %u:%g, %g )", + x0,cx0,cy0,x1 + one,cx1,cy1); + else + std::sprintf(message._data + std::strlen(message)," - Range [ %u:%g - %u:%g ]", + x0,cx0,x1 + one,cx1); + } text.assign().draw_text(0,0,message,white,ngray,1,13).resize(-100,-100,1,3); - visu.draw_image((visu.width()-text.width())/2,1,~text); + visu.draw_image((visu.width() - text.width())/2,1,~text); } visu.display(disp); } @@ -37928,14 +38717,14 @@ namespace cimg_library_suffixed { visu.assign(); if (disp.mouse_x()>=0 && disp.mouse_y()>=0) { const int - mx = (mouse_x -16)*(int)(siz-one)/(disp.width()-32), - cx = mx<0?0:(mx>=(int)(siz-one)?(int)(siz-1-one):mx), + mx = (mouse_x - 16)*(int)(siz - one)/(disp.width() - 32), + cx = mx<0?0:(mx>=(int)(siz - one)?(int)(siz - 1 - one):mx), my = mouse_y - 16, - cy = my<=0?0:(my>=(disp.height()-32)?(disp.height()-32):my); - if (button&1) { + cy = my<=0?0:(my>=(disp.height() - 32)?(disp.height() - 32):my); + if (button&1) { if (!obutton) { x0 = cx; y0 = -1; } else { x1 = cx; y1 = -1; } } - else if (button&2) { + else if (button&2) { if (!obutton) { x0 = cx; y0 = cy; } else { x1 = cx; y1 = cy; } } else if (obutton) { x1 = x1>=0?cx:-1; y1 = y1>=0?cy:-1; selected = true; } @@ -37950,7 +38739,7 @@ namespace cimg_library_suffixed { if (x1>=0 && x1(4,1,1,1,x0,y0,x1>=0?x1+(int)one:-1,y1); + return CImg(4,1,1,1,x0,y0,x1>=0?x1 + (int)one:-1,y1); } //! Load image from a file. @@ -37966,15 +38755,15 @@ namespace cimg_library_suffixed { cimg_instance); if (!cimg::strncasecmp(filename,"http://",7) || !cimg::strncasecmp(filename,"https://",8)) { - char filename_local[1024] = { 0 }; - load(cimg::load_network_external(filename,filename_local)); + CImg filename_local(256); + load(cimg::load_network(filename,filename_local)); std::remove(filename_local); return *this; } const char *const ext = cimg::split_filename(filename); const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); try { #ifdef cimg_load_plugin cimg_load_plugin(filename); @@ -38077,7 +38866,7 @@ namespace cimg_library_suffixed { !cimg::strcasecmp(ext,"vob") || !cimg::strcasecmp(ext,"wmv") || !cimg::strcasecmp(ext,"xvid") || - !cimg::strcasecmp(ext,"mpeg")) load_ffmpeg(filename); + !cimg::strcasecmp(ext,"mpeg")) load_video(filename); else throw CImgIOException("CImg<%s>::load()", pixel_type()); } catch (CImgIOException&) { @@ -38085,7 +38874,7 @@ namespace cimg_library_suffixed { try { file = cimg::fopen(filename,"rb"); } catch (CImgIOException&) { - cimg::exception_mode() = omode; + cimg::exception_mode(omode); throw CImgIOException(_cimg_instance "load(): Failed to open file '%s'.", cimg_instance, @@ -38093,16 +38882,17 @@ namespace cimg_library_suffixed { } try { - const char *const f_type = cimg::file_type(file,filename); + const char *const f_type = cimg::ftype(file,filename); std::fclose(file); if (!cimg::strcasecmp(f_type,"pnm")) load_pnm(filename); else if (!cimg::strcasecmp(f_type,"pfm")) load_pfm(filename); else if (!cimg::strcasecmp(f_type,"bmp")) load_bmp(filename); + else if (!cimg::strcasecmp(f_type,"inr")) load_inr(filename); else if (!cimg::strcasecmp(f_type,"jpg")) load_jpeg(filename); else if (!cimg::strcasecmp(f_type,"pan")) load_pandore(filename); else if (!cimg::strcasecmp(f_type,"png")) load_png(filename); else if (!cimg::strcasecmp(f_type,"tif")) load_tiff(filename); - else if (!cimg::strcasecmp(f_type,"inr")) load_inr(filename); + else if (!cimg::strcasecmp(f_type,"gif")) load_gif_external(filename); else if (!cimg::strcasecmp(f_type,"dcm")) load_medcon_external(filename); else throw CImgIOException("CImg<%s>::load()", pixel_type()); @@ -38110,7 +38900,7 @@ namespace cimg_library_suffixed { try { load_other(filename); } catch (CImgIOException&) { - cimg::exception_mode() = omode; + cimg::exception_mode(omode); throw CImgIOException(_cimg_instance "load(): Failed to recognize format of file '%s'.", cimg_instance, @@ -38118,7 +38908,7 @@ namespace cimg_library_suffixed { } } } - cimg::exception_mode() = omode; + cimg::exception_mode(omode); return *this; } @@ -38157,11 +38947,11 @@ namespace cimg_library_suffixed { cimg_instance); std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); - char line[256] = { 0 }; - int err = std::fscanf(nfile,"%255[^\n]",line); + CImg line(256); *line = 0; + int err = std::fscanf(nfile,"%255[^\n]",line._data); unsigned int dx = 0, dy = 1, dz = 1, dc = 1; - std::sscanf(line,"%u%*c%u%*c%u%*c%u",&dx,&dy,&dz,&dc); - err = std::fscanf(nfile,"%*[^0-9.eE+-]"); + 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 @@ -38176,14 +38966,14 @@ namespace cimg_library_suffixed { double val; T *ptr = _data; for (err = 1, off = 0; off delimiter(256), tmp(256); *delimiter = *tmp = 0; unsigned int cdx = 0, dx = 0, dy = 0; int err = 0; double val; assign(256,256); - while ((err = std::fscanf(nfile,"%lf%255[^0-9.+-]",&val,delimiter))>0) { + while ((err = std::fscanf(nfile,"%lf%255[^0-9eEinfa.+-]",&val,delimiter._data))>0) { if (err>0) (*this)(cdx++,dy) = (T)val; if (cdx>=_width) resize(3*_width/2,_height,1,1,0); char c = 0; - if (!std::sscanf(delimiter,"%255[^\n]%c",tmp,&c) || c=='\n') { + if (!cimg_sscanf(delimiter,"%255[^\n]%c",tmp._data,&c) || c=='\n') { dx = cimg::max(cdx,dx); if (++dy>=_height) resize(_width,3*_height/2,1,1,0); cdx = 0; @@ -38306,9 +39096,9 @@ namespace cimg_library_suffixed { if (header_size>40) std::fseek(nfile, header_size - 40, SEEK_CUR); const int - cimg_iobuffer = 12*1024*1024, - dx_bytes = (bpp==1)?(dx/8+(dx%8?1:0)):((bpp==4)?(dx/2+(dx%2?1:0)):(dx*bpp/8)), - align_bytes = (4-dx_bytes%4)%4, + cimg_iobuffer = 24*1024*1024, + dx_bytes = (bpp==1)?(dx/8 + (dx%8?1:0)):((bpp==4)?(dx/2 + (dx%2?1:0)):(dx*bpp/8)), + align_bytes = (4 - dx_bytes%4)%4, buf_size = cimg::min(cimg::abs(dy)*(dx_bytes + align_bytes),file_size - offset); CImg colormap; @@ -38338,7 +39128,7 @@ namespace cimg_library_suffixed { assign(dx,cimg::abs(dy),1,3); switch (bpp) { case 1 : { // Monochrome - for (int y = height()-1; y>=0; --y) { + for (int y = height() - 1; y>=0; --y) { if (buf_size>=cimg_iobuffer) { cimg::fread(ptrs=buffer._data,dx_bytes,nfile); std::fseek(nfile,align_bytes,SEEK_CUR); @@ -38356,7 +39146,7 @@ namespace cimg_library_suffixed { } } break; case 4 : { // 16 colors - for (int y = height()-1; y>=0; --y) { + for (int y = height() - 1; y>=0; --y) { if (buf_size>=cimg_iobuffer) { cimg::fread(ptrs=buffer._data,dx_bytes,nfile); std::fseek(nfile,align_bytes,SEEK_CUR); @@ -38375,7 +39165,7 @@ namespace cimg_library_suffixed { } } break; case 8 : { // 256 colors - for (int y = height()-1; y>=0; --y) { + for (int y = height() - 1; y>=0; --y) { if (buf_size>=cimg_iobuffer) { cimg::fread(ptrs=buffer._data,dx_bytes,nfile); std::fseek(nfile,align_bytes,SEEK_CUR); @@ -38390,7 +39180,7 @@ namespace cimg_library_suffixed { } } break; case 16 : { // 16 bits colors - for (int y = height()-1; y>=0; --y) { + for (int y = height() - 1; y>=0; --y) { if (buf_size>=cimg_iobuffer) { cimg::fread(ptrs=buffer._data,dx_bytes,nfile); std::fseek(nfile,align_bytes,SEEK_CUR); @@ -38406,7 +39196,7 @@ namespace cimg_library_suffixed { } } break; case 24 : { // 24 bits colors - for (int y = height()-1; y>=0; --y) { + for (int y = height() - 1; y>=0; --y) { if (buf_size>=cimg_iobuffer) { cimg::fread(ptrs=buffer._data,dx_bytes,nfile); std::fseek(nfile,align_bytes,SEEK_CUR); @@ -38420,7 +39210,7 @@ namespace cimg_library_suffixed { } } break; case 32 : { // 32 bits colors - for (int y = height()-1; y>=0; --y) { + for (int y = height() - 1; y>=0; --y) { if (buf_size>=cimg_iobuffer) { cimg::fread(ptrs=buffer._data,dx_bytes,nfile); std::fseek(nfile,align_bytes,SEEK_CUR); @@ -38863,9 +39653,9 @@ namespace cimg_library_suffixed { unsigned int ppm_type, W, H, D = 1, colormax = 255; CImg item(16384,1,1,1,0); int err, rval, gval, bval; - const long cimg_iobuffer = 12*1024*1024; + const long cimg_iobuffer = 24*1024*1024; while ((err=std::fscanf(nfile,"%16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile); - if (std::sscanf(item," P%u",&ppm_type)!=1) { + if (cimg_sscanf(item," P%u",&ppm_type)!=1) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_pnm(): PNM header not found in file '%s'.", @@ -38873,7 +39663,7 @@ namespace cimg_library_suffixed { filename?filename:"(FILE*)"); } while ((err=std::fscanf(nfile," %16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile); - if ((err=std::sscanf(item," %u %u %u %u",&W,&H,&D,&colormax))<2) { + if ((err=cimg_sscanf(item," %u %u %u %u",&W,&H,&D,&colormax))<2) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_pnm(): WIDTH and HEIGHT fields undefined in file '%s'.", @@ -38883,7 +39673,7 @@ namespace cimg_library_suffixed { if (ppm_type!=1 && ppm_type!=4) { if (err==2 || (err==3 && (ppm_type==5 || ppm_type==7 || ppm_type==8 || ppm_type==9))) { while ((err=std::fscanf(nfile," %16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile); - if (std::sscanf(item,"%u",&colormax)!=1) + if (cimg_sscanf(item,"%u",&colormax)!=1) cimg::warn(_cimg_instance "load_pnm(): COLORMAX field is undefined in file '%s'.", cimg_instance, @@ -38949,7 +39739,7 @@ namespace cimg_library_suffixed { for (long to_read = (long)size(); to_read>0; ) { raw.assign(cimg::min(to_read,cimg_iobuffer/2)); cimg::fread(raw._data,raw._width,nfile); - if (!cimg::endianness()) cimg::invert_endianness(raw._data,raw._width); + if (!cimg::endianness()) cimg::invert_endianness(raw._data,raw._width); to_read-=raw._width; const unsigned short *ptrs = raw._data; for (unsigned long off = (unsigned long)raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); @@ -39067,7 +39857,7 @@ namespace cimg_library_suffixed { int W = 0, H = 0, err = 0; double scale = 0; while ((err=std::fscanf(nfile,"%16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile); - if (std::sscanf(item," P%c",&pfm_type)!=1) { + if (cimg_sscanf(item," P%c",&pfm_type)!=1) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_pfm(): PFM header not found in file '%s'.", @@ -39075,7 +39865,7 @@ namespace cimg_library_suffixed { filename?filename:"(FILE*)"); } while ((err=std::fscanf(nfile," %16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile); - if ((err=std::sscanf(item," %d %d",&W,&H))<2) { + if ((err=cimg_sscanf(item," %d %d",&W,&H))<2) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_pfm(): WIDTH and HEIGHT fields are undefined in file '%s'.", @@ -39084,7 +39874,7 @@ namespace cimg_library_suffixed { } if (err==2) { while ((err=std::fscanf(nfile," %16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile); - if (std::sscanf(item,"%lf",&scale)!=1) + if (cimg_sscanf(item,"%lf",&scale)!=1) cimg::warn(_cimg_instance "load_pfm(): SCALE field is undefined in file '%s'.", cimg_instance, @@ -39154,7 +39944,7 @@ namespace cimg_library_suffixed { cimg_instance); if (!dimw || !dimh) return assign(); - const long cimg_iobuffer = 12*1024*1024; + const long cimg_iobuffer = 24*1024*1024; std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); CImg raw; assign(dimw,dimh,1,3); @@ -39210,7 +40000,7 @@ namespace cimg_library_suffixed { cimg_instance); if (!dimw || !dimh) return assign(); - const long cimg_iobuffer = 12*1024*1024; + const long cimg_iobuffer = 24*1024*1024; std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); CImg raw; assign(dimw,dimh,1,4); @@ -39251,21 +40041,22 @@ namespace cimg_library_suffixed { function uses CImg& load_other(const char*). **/ CImg& load_tiff(const char *const filename, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, - float *const voxel_size=0) { + const unsigned int first_frame=0, const unsigned int last_frame=~0U, + const unsigned int step_frame=1, + float *const voxel_size=0, + CImg *const description=0) { if (!filename) throw CImgArgumentException(_cimg_instance "load_tiff(): Specified filename is (null).", cimg_instance); const unsigned int - nfirst_frame = first_frame1) throw CImgArgumentException(_cimg_instance "load_tiff(): Unable to read sub-images from file '%s' unless libtiff is enabled.", @@ -39284,18 +40075,18 @@ namespace cimg_library_suffixed { filename,nb_images,nfirst_frame,nlast_frame,nstep_frame); if (nfirst_frame>=nb_images) return assign(); - if (nlast_frame>=nb_images) nlast_frame = nb_images-1; + if (nlast_frame>=nb_images) nlast_frame = nb_images - 1; TIFFSetDirectory(tif,0); CImg frame; for (unsigned int l = nfirst_frame; l<=nlast_frame; l+=nstep_frame) { - frame._load_tiff(tif,l,voxel_size); + frame._load_tiff(tif,l,voxel_size,description); if (l==nfirst_frame) - assign(frame._width,frame._height,1+(nlast_frame-nfirst_frame)/nstep_frame,frame._spectrum); + assign(frame._width,frame._height,1 + (nlast_frame - nfirst_frame)/nstep_frame,frame._spectrum); if (frame._width>_width || frame._height>_height || frame._spectrum>_spectrum) resize(cimg::max(frame._width,_width), cimg::max(frame._height,_height),-100, cimg::max(frame._spectrum,_spectrum),0); - draw_image(0,0,(l-nfirst_frame)/nstep_frame,frame); + draw_image(0,0,(l - nfirst_frame)/nstep_frame,frame); } TIFFClose(tif); } else throw CImgIOException(_cimg_instance @@ -39308,10 +40099,11 @@ namespace cimg_library_suffixed { //! Load image from a TIFF file \newinstance. static CImg get_load_tiff(const char *const filename, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, - float *const voxel_size=0) { - return CImg().load_tiff(filename,first_frame,last_frame,step_frame,voxel_size); + const unsigned int first_frame=0, const unsigned int last_frame=~0U, + const unsigned int step_frame=1, + float *const voxel_size=0, + CImg *const description=0) { + return CImg().load_tiff(filename,first_frame,last_frame,step_frame,voxel_size,description); } // (Original contribution by Jerome Boulanger). @@ -39331,10 +40123,10 @@ namespace cimg_library_suffixed { TIFFFileName(tif)); } const t *ptr = buf; - for (unsigned int rr = row; rrny?ny-row:rowsperstrip); + uint32 nrow = (row + rowsperstrip>ny?ny - row:rowsperstrip); tstrip_t strip = TIFFComputeStrip(tif, row, 0); if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) { _TIFFfree(buf); TIFFClose(tif); @@ -39383,7 +40175,7 @@ namespace cimg_library_suffixed { const t *ptr = buf; for (unsigned int rr = 0; rrny?ny-row:rowsperstrip); + uint32 nrow = (row + rowsperstrip>ny?ny - row:rowsperstrip); tstrip_t strip = TIFFComputeStrip(tif, row, vv); if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) { _TIFFfree(buf); TIFFClose(tif); @@ -39409,13 +40201,14 @@ namespace cimg_library_suffixed { const t *ptr = buf; for (unsigned int rr = 0;rr& _load_tiff(TIFF *const tif, const unsigned int directory, float *const voxel_size) { + CImg& _load_tiff(TIFF *const tif, const unsigned int directory, + float *const voxel_size, CImg *const description) { if (!TIFFSetDirectory(tif,directory)) return assign(); uint16 samplesperpixel = 1, bitspersample = 8, photo = 0; uint16 sampleformat = 1; @@ -39432,16 +40225,23 @@ namespace cimg_library_suffixed { float vx = 0, vy = 0, vz = 0; if (TIFFGetField(tif,TIFFTAG_IMAGEDESCRIPTION,&s_description) && s_description) { const char *s_desc = std::strstr(s_description,"VX="); - if (s_desc && std::sscanf(s_desc,"VX=%f VY=%f VZ=%f",&vx,&vy,&vz)==3) { // CImg format. + if (s_desc && cimg_sscanf(s_desc,"VX=%f VY=%f VZ=%f",&vx,&vy,&vz)==3) { // CImg format. voxel_size[0] = vx; voxel_size[1] = vy; voxel_size[2] = vz; } s_desc = std::strstr(s_description,"spacing="); - if (s_desc && std::sscanf(s_desc,"spacing=%f",&vz)==1) { // fiji format. + if (s_desc && cimg_sscanf(s_desc,"spacing=%f",&vz)==1) { // fiji format. voxel_size[2] = vz; } } TIFFGetField(tif,TIFFTAG_XRESOLUTION,voxel_size); - TIFFGetField(tif,TIFFTAG_YRESOLUTION,voxel_size+1); + TIFFGetField(tif,TIFFTAG_YRESOLUTION,voxel_size + 1); + voxel_size[0] = 1.0f/voxel_size[0]; + voxel_size[1] = 1.0f/voxel_size[1]; + } + if (description) { + const char *s_description = 0; + if (TIFFGetField(tif,TIFFTAG_IMAGEDESCRIPTION,&s_description) && s_description) + CImg::string(s_description).move_to(*description); } const unsigned int spectrum = is_spp?samplesperpixel:photo==3?3:1; assign(nx,ny,1,spectrum); @@ -39459,21 +40259,21 @@ namespace cimg_library_suffixed { TIFFReadRGBAImage(tif,nx,ny,raster,0); switch (spectrum) { case 1 : { - cimg_forXY(*this,x,y) (*this)(x,y) = (T)(float)((raster[nx*(ny-1-y)+x] + 128)/257); + cimg_forXY(*this,x,y) (*this)(x,y) = (T)(float)((raster[nx*(ny - 1 - y) + x] + 128)/257); } break; case 3 : { cimg_forXY(*this,x,y) { - (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny-1-y)+x]); - (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny-1-y)+x]); - (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny-1-y)+x]); + (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 -y) + x]); + (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny - 1 -y) + x]); + (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny - 1 -y) + x]); } } break; case 4 : { cimg_forXY(*this,x,y) { - (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny-1-y)+x]); - (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny-1-y)+x]); - (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny-1-y)+x]); - (*this)(x,y,3) = (T)(float)TIFFGetA(raster[nx*(ny-1-y)+x]); + (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 - y) + x]); + (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny - 1 - y) + x]); + (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny - 1 - y) + x]); + (*this)(x,y,3) = (T)(float)TIFFGetA(raster[nx*(ny - 1 - y) + x]); } } break; } @@ -39628,15 +40428,15 @@ namespace cimg_library_suffixed { std::FILE *nfile_header = 0, *nfile = 0; if (!file) { - char body[1024] = { 0 }; + CImg body(1024); const char *const ext = cimg::split_filename(filename,body); if (!cimg::strcasecmp(ext,"hdr")) { // File is an Analyze header file. nfile_header = cimg::fopen(filename,"rb"); - std::sprintf(body + std::strlen(body),".img"); + std::sprintf(body._data + std::strlen(body),".img"); nfile = cimg::fopen(body,"rb"); } else if (!cimg::strcasecmp(ext,"img")) { // File is an Analyze data file. nfile = cimg::fopen(filename,"rb"); - std::sprintf(body + std::strlen(body),".hdr"); + std::sprintf(body._data + std::strlen(body),".hdr"); nfile_header = cimg::fopen(body,"rb"); } else nfile_header = nfile = cimg::fopen(filename,"rb"); // File is a Niftii file. } else nfile_header = nfile = file; // File is a Niftii file. @@ -39658,16 +40458,16 @@ namespace cimg_library_suffixed { if (header_size>=4096) { endian = true; cimg::invert_endianness(header_size); } unsigned char *const header = new unsigned char[header_size]; - cimg::fread(header+4,header_size-4,nfile_header); + cimg::fread(header + 4,header_size - 4,nfile_header); if (!file && nfile_header!=nfile) cimg::fclose(nfile_header); if (endian) { - cimg::invert_endianness((short*)(header+40),5); - cimg::invert_endianness((short*)(header+70),1); - cimg::invert_endianness((short*)(header+72),1); - cimg::invert_endianness((float*)(header+76),4); - cimg::invert_endianness((float*)(header+112),1); + cimg::invert_endianness((short*)(header + 40),5); + cimg::invert_endianness((short*)(header + 70),1); + cimg::invert_endianness((short*)(header + 72),1); + cimg::invert_endianness((float*)(header + 76),4); + cimg::invert_endianness((float*)(header + 112),1); } - unsigned short *dim = (unsigned short*)(header+40), dimx = 1, dimy = 1, dimz = 1, dimv = 1; + unsigned short *dim = (unsigned short*)(header + 40), dimx = 1, dimy = 1, dimz = 1, dimv = 1; if (!dim[0]) cimg::warn(_cimg_instance "load_analyze(): File '%s' defines an image with zero dimensions.", @@ -39684,10 +40484,10 @@ namespace cimg_library_suffixed { if (dim[0]>=2) dimy = dim[2]; if (dim[0]>=3) dimz = dim[3]; if (dim[0]>=4) dimv = dim[4]; - float scalefactor = *(float*)(header+112); if (scalefactor==0) scalefactor=1; - const unsigned short datatype = *(short*)(header+70); + float scalefactor = *(float*)(header + 112); if (scalefactor==0) scalefactor=1; + const unsigned short datatype = *(unsigned short*)(header + 70); if (voxel_size) { - const float *vsize = (float*)(header+76); + const float *vsize = (float*)(header + 76); voxel_size[0] = vsize[1]; voxel_size[1] = vsize[2]; voxel_size[2] = vsize[3]; } delete[] header; @@ -39696,34 +40496,34 @@ namespace cimg_library_suffixed { assign(dimx,dimy,dimz,dimv); switch (datatype) { case 2 : { - unsigned char *const buffer = new unsigned char[dimx*dimy*dimz*dimv]; + unsigned char *const buffer = new unsigned char[(unsigned int)dimx*dimy*dimz*dimv]; cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile); cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor); delete[] buffer; } break; case 4 : { - short *const buffer = new short[dimx*dimy*dimz*dimv]; + short *const buffer = new short[(unsigned int)dimx*dimy*dimz*dimv]; cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile); if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv); cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor); delete[] buffer; } break; case 8 : { - int *const buffer = new int[dimx*dimy*dimz*dimv]; + int *const buffer = new int[(unsigned int)dimx*dimy*dimz*dimv]; cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile); if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv); cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor); delete[] buffer; } break; case 16 : { - float *const buffer = new float[dimx*dimy*dimz*dimv]; + float *const buffer = new float[(unsigned int)dimx*dimy*dimz*dimv]; cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile); if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv); cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor); delete[] buffer; } break; case 64 : { - double *const buffer = new double[dimx*dimy*dimz*dimv]; + double *const buffer = new double[(unsigned int)dimx*dimy*dimz*dimv]; cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile); if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv); cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor); @@ -39861,28 +40661,29 @@ namespace cimg_library_suffixed { } static void _load_inr_header(std::FILE *file, int out[8], float *const voxel_size) { - char item[1024] = { 0 }, tmp1[64] = { 0 }, tmp2[64] = { 0 }; - out[0] = std::fscanf(file,"%63s",item); + CImg item(1024); *item = 0; + char tmp1[64] = { 0 }, tmp2[64] = { 0 }; + out[0] = std::fscanf(file,"%63s",item._data); out[0] = out[1] = out[2] = out[3] = out[5] = 1; out[4] = out[6] = out[7] = -1; if(cimg::strncasecmp(item,"#INRIMAGE-4#{",13)!=0) throw CImgIOException("CImg<%s>::load_inr(): INRIMAGE-4 header not found.", pixel_type()); - while (std::fscanf(file," %63[^\n]%*c",item)!=EOF && std::strncmp(item,"##}",3)) { - std::sscanf(item," XDIM%*[^0-9]%d",out); - std::sscanf(item," YDIM%*[^0-9]%d",out+1); - std::sscanf(item," ZDIM%*[^0-9]%d",out+2); - std::sscanf(item," VDIM%*[^0-9]%d",out+3); - std::sscanf(item," PIXSIZE%*[^0-9]%d",out+6); + while (std::fscanf(file," %63[^\n]%*c",item._data)!=EOF && std::strncmp(item,"##}",3)) { + cimg_sscanf(item," XDIM%*[^0-9]%d",out); + cimg_sscanf(item," YDIM%*[^0-9]%d",out + 1); + cimg_sscanf(item," ZDIM%*[^0-9]%d",out + 2); + cimg_sscanf(item," VDIM%*[^0-9]%d",out + 3); + cimg_sscanf(item," PIXSIZE%*[^0-9]%d",out + 6); if (voxel_size) { - std::sscanf(item," VX%*[^0-9.+-]%f",voxel_size); - std::sscanf(item," VY%*[^0-9.+-]%f",voxel_size+1); - std::sscanf(item," VZ%*[^0-9.+-]%f",voxel_size+2); + cimg_sscanf(item," VX%*[^0-9.+-]%f",voxel_size); + cimg_sscanf(item," VY%*[^0-9.+-]%f",voxel_size + 1); + cimg_sscanf(item," VZ%*[^0-9.+-]%f",voxel_size + 2); } - if (std::sscanf(item," CPU%*[ =]%s",tmp1)) out[7]=cimg::strncasecmp(tmp1,"sun",3)?0:1; - switch (std::sscanf(item," TYPE%*[ =]%s %s",tmp1,tmp2)) { + if (cimg_sscanf(item," CPU%*[ =]%s",tmp1)) out[7]=cimg::strncasecmp(tmp1,"sun",3)?0:1; + switch (cimg_sscanf(item," TYPE%*[ =]%s %s",tmp1,tmp2)) { case 0 : break; - case 2 : out[5] = cimg::strncasecmp(tmp1,"unsigned",8)?1:0; std::strncpy(tmp1,tmp2,sizeof(tmp1)-1); + case 2 : out[5] = cimg::strncasecmp(tmp1,"unsigned",8)?1:0; std::strncpy(tmp1,tmp2,sizeof(tmp1) - 1); case 1 : if (!cimg::strncasecmp(tmp1,"int",3) || !cimg::strncasecmp(tmp1,"fixed",5)) out[4] = 0; if (!cimg::strncasecmp(tmp1,"float",5) || !cimg::strncasecmp(tmp1,"double",6)) out[4] = 1; @@ -39912,7 +40713,7 @@ namespace cimg_library_suffixed { CImg& _load_inr(std::FILE *const file, const char *const filename, float *const voxel_size) { #define _cimg_load_inr_case(Tf,sign,pixsize,Ts) \ if (!loaded && fopt[6]==pixsize && fopt[4]==Tf && fopt[5]==sign) { \ - Ts *xval, *const val = new Ts[fopt[0]*fopt[3]]; \ + Ts *xval, *const val = new Ts[(unsigned int)fopt[0]*fopt[3]]; \ cimg_forYZ(*this,y,z) { \ cimg::fread(val,fopt[0]*fopt[3],nfile); \ if (fopt[7]!=endian) cimg::invert_endianness(val,fopt[0]*fopt[3]); \ @@ -40061,15 +40862,15 @@ namespace cimg_library_suffixed { cimg::fread(header,20,nfile); switch (imageid) { - case 2: _cimg_load_pandore_case(2,dims[1],1,1,1,unsigned char,unsigned char,unsigned char,1); break; - case 3: _cimg_load_pandore_case(2,dims[1],1,1,1,long,int,short,4); break; - case 4: _cimg_load_pandore_case(2,dims[1],1,1,1,double,float,float,4); break; - case 5: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,unsigned char,unsigned char,unsigned char,1); break; - case 6: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,long,int,short,4); break; - case 7: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,double,float,float,4); break; - case 8: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,unsigned char,unsigned char,unsigned char,1); break; - case 9: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,long,int,short,4); break; - case 10: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,double,float,float,4); break; + case 2 : _cimg_load_pandore_case(2,dims[1],1,1,1,unsigned char,unsigned char,unsigned char,1); break; + case 3 : _cimg_load_pandore_case(2,dims[1],1,1,1,long,int,short,4); break; + case 4 : _cimg_load_pandore_case(2,dims[1],1,1,1,double,float,float,4); break; + case 5 : _cimg_load_pandore_case(3,dims[2],dims[1],1,1,unsigned char,unsigned char,unsigned char,1); break; + case 6 : _cimg_load_pandore_case(3,dims[2],dims[1],1,1,long,int,short,4); break; + case 7 : _cimg_load_pandore_case(3,dims[2],dims[1],1,1,double,float,float,4); break; + case 8 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,unsigned char,unsigned char,unsigned char,1); break; + case 9 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,long,int,short,4); break; + case 10 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,double,float,float,4); break; case 11 : { // Region 1d cimg::fread(dims,3,nfile); if (endian) cimg::invert_endianness(dims,3); @@ -40169,26 +40970,26 @@ namespace cimg_library_suffixed { } } break; - case 16: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,unsigned char,unsigned char,unsigned char,1); break; - case 17: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,long,int,short,4); break; - case 18: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,double,float,float,4); break; - case 19: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,unsigned char,unsigned char,unsigned char,1); break; - case 20: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,long,int,short,4); break; - case 21: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,double,float,float,4); break; - case 22: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],unsigned char,unsigned char,unsigned char,1); break; - case 23: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],long,int,short,4); - case 24: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],unsigned long,unsigned int,unsigned short,4); break; - case 25: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],double,float,float,4); break; - case 26: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],unsigned char,unsigned char,unsigned char,1); break; - case 27: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],long,int,short,4); break; - case 28: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],unsigned long,unsigned int,unsigned short,4); break; - case 29: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],double,float,float,4); break; - case 30: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],unsigned char,unsigned char,unsigned char,1); + case 16 : _cimg_load_pandore_case(4,dims[2],dims[1],1,3,unsigned char,unsigned char,unsigned char,1); break; + case 17 : _cimg_load_pandore_case(4,dims[2],dims[1],1,3,long,int,short,4); break; + case 18 : _cimg_load_pandore_case(4,dims[2],dims[1],1,3,double,float,float,4); break; + case 19 : _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,unsigned char,unsigned char,unsigned char,1); break; + case 20 : _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,long,int,short,4); break; + case 21 : _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,double,float,float,4); break; + case 22 : _cimg_load_pandore_case(2,dims[1],1,1,dims[0],unsigned char,unsigned char,unsigned char,1); break; + case 23 : _cimg_load_pandore_case(2,dims[1],1,1,dims[0],long,int,short,4); + case 24 : _cimg_load_pandore_case(2,dims[1],1,1,dims[0],unsigned long,unsigned int,unsigned short,4); break; + case 25 : _cimg_load_pandore_case(2,dims[1],1,1,dims[0],double,float,float,4); break; + case 26 : _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],unsigned char,unsigned char,unsigned char,1); break; + case 27 : _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],long,int,short,4); break; + case 28 : _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],unsigned long,unsigned int,unsigned short,4); break; + case 29 : _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],double,float,float,4); break; + case 30 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],unsigned char,unsigned char,unsigned char,1); break; - case 31: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],long,int,short,4); break; - case 32: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],unsigned long,unsigned int,unsigned short,4); + case 31 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],long,int,short,4); break; + case 32 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],unsigned long,unsigned int,unsigned short,4); break; - case 33: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],double,float,float,4); break; + case 33 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],double,float,float,4); break; case 34 : { // Points 1d int ptbuf[4] = { 0 }; cimg::fread(ptbuf,1,nfile); @@ -40283,9 +41084,9 @@ namespace cimg_library_suffixed { } CImg& _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 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 unsigned long offset) { if (!file && !filename) throw CImgArgumentException(_cimg_instance @@ -40311,10 +41112,10 @@ namespace cimg_library_suffixed { } std::fseek(nfile,(long)offset,SEEK_SET); assign(_size_x,_size_y,_size_z,_size_c,0); - if (!is_multiplexed || size_c==1) { + if (siz && (!is_multiplexed || size_c==1)) { cimg::fread(_data,siz,nfile); if (invert_endianness) cimg::invert_endianness(_data,siz); - } else { + } else if (siz) { CImg buf(1,1,1,_size_c); cimg_forXYZ(*this,x,y,z) { cimg::fread(buf._data,_size_c,nfile); @@ -40326,34 +41127,6 @@ namespace cimg_library_suffixed { return *this; } - //! Load image sequence using FFMPEG av's libraries. - /** - \param filename Filename, as a C-string. - \param first_frame Index of the first frame to read. - \param last_frame Index of the last frame to read. - \param step_frame Step value for frame reading. - \param pixel_format To be documented. - \param resume To be documented. - \param axis Appending axis, if file contains multiple images. Can be { 'x' | 'y' | 'z' | 'c' }. - \param align Appending alignment. - **/ - CImg& load_ffmpeg(const char *const filename, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false, - const char axis='z', const float align=0) { - return get_load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format,resume,axis,align).move_to(*this); - } - - //! Load image sequence using FFMPEG av's libraries \newinstance. - static CImg get_load_ffmpeg(const char *const filename, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, const bool pixel_format=true, - const bool resume=false, - const char axis='z', const float align=0) { - return CImgList().load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format,resume). - get_append(axis,align); - } - //! Load image sequence from a YUV file. /** \param filename Filename, as a C-string. @@ -40384,7 +41157,7 @@ namespace cimg_library_suffixed { CImg& load_yuv(std::FILE *const file, const unsigned int size_x, const unsigned int size_y=1, const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z') { + const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z') { return get_load_yuv(file,size_x,size_y,first_frame,last_frame,step_frame,yuv2rgb,axis).move_to(*this); } @@ -40392,7 +41165,7 @@ namespace cimg_library_suffixed { static CImg get_load_yuv(std::FILE *const file, const unsigned int size_x, const unsigned int size_y=1, const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z') { + const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z') { return CImgList().load_yuv(file,size_x,size_y,first_frame,last_frame,step_frame,yuv2rgb).get_append(axis); } @@ -40435,11 +41208,11 @@ namespace cimg_library_suffixed { std::FILE *const nfile = file?file:cimg::fopen(filename,"r"); unsigned int nb_points = 0, nb_primitives = 0, nb_read = 0; - char line[256] = { 0 }; + CImg line(256); *line = 0; int err; // Skip comments, and read magic string OFF - do { err = std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && *line=='#')); + do { err = std::fscanf(nfile,"%255[^\n] ",line._data); } while (!err || (err==1 && *line=='#')); if (cimg::strncasecmp(line,"OFF",3) && cimg::strncasecmp(line,"COFF",4)) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance @@ -40447,8 +41220,8 @@ namespace cimg_library_suffixed { cimg_instance, filename?filename:"(FILE*)"); } - do { err = std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && *line=='#')); - if ((err = std::sscanf(line,"%u%u%*[^\n] ",&nb_points,&nb_primitives))!=2) { + do { err = std::fscanf(nfile,"%255[^\n] ",line._data); } while (!err || (err==1 && *line=='#')); + if ((err = cimg_sscanf(line,"%u%u%*[^\n] ",&nb_points,&nb_primitives))!=2) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_off(): Invalid number of vertices or primitives specified in file '%s'.", @@ -40460,13 +41233,13 @@ namespace cimg_library_suffixed { assign(nb_points,3); float X = 0, Y = 0, Z = 0; cimg_forX(*this,l) { - do { err = std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && *line=='#')); - if ((err = std::sscanf(line,"%f%f%f%*[^\n] ",&X,&Y,&Z))!=3) { + do { err = std::fscanf(nfile,"%255[^\n] ",line._data); } while (!err || (err==1 && *line=='#')); + if ((err = cimg_sscanf(line,"%f%f%f%*[^\n] ",&X,&Y,&Z))!=3) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimg_instance "load_off(): Failed to read vertex %u/%u in file '%s'.", cimg_instance, - l+1,nb_points,filename?filename:"(FILE*)"); + l + 1,nb_points,filename?filename:"(FILE*)"); } (*this)(l,0) = (T)X; (*this)(l,1) = (T)Y; (*this)(l,2) = (T)Z; } @@ -40484,7 +41257,7 @@ namespace cimg_library_suffixed { ++nb_read; switch (prim) { case 1 : { - if ((err = std::fscanf(nfile,"%u%255[^\n] ",&i0,line))<2) { + if ((err = std::fscanf(nfile,"%u%255[^\n] ",&i0,line._data))<2) { cimg::warn(_cimg_instance "load_off(): Failed to read primitive %u/%u from file '%s'.", cimg_instance, @@ -40492,13 +41265,13 @@ namespace cimg_library_suffixed { err = std::fscanf(nfile,"%*[^\n] "); } else { - err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2); + err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); CImg::vector(i0).move_to(primitives); CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)).move_to(colors); } } break; case 2 : { - if ((err = std::fscanf(nfile,"%u%u%255[^\n] ",&i0,&i1,line))<2) { + if ((err = std::fscanf(nfile,"%u%u%255[^\n] ",&i0,&i1,line._data))<2) { cimg::warn(_cimg_instance "load_off(): Failed to read primitive %u/%u from file '%s'.", cimg_instance, @@ -40506,13 +41279,13 @@ namespace cimg_library_suffixed { err = std::fscanf(nfile,"%*[^\n] "); } else { - err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2); + err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); CImg::vector(i0,i1).move_to(primitives); CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)).move_to(colors); } } break; case 3 : { - if ((err = std::fscanf(nfile,"%u%u%u%255[^\n] ",&i0,&i1,&i2,line))<3) { + if ((err = std::fscanf(nfile,"%u%u%u%255[^\n] ",&i0,&i1,&i2,line._data))<3) { cimg::warn(_cimg_instance "load_off(): Failed to read primitive %u/%u from file '%s'.", cimg_instance, @@ -40520,13 +41293,13 @@ namespace cimg_library_suffixed { err = std::fscanf(nfile,"%*[^\n] "); } else { - err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2); + err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); CImg::vector(i0,i2,i1).move_to(primitives); CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)).move_to(colors); } } break; case 4 : { - if ((err = std::fscanf(nfile,"%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,line))<4) { + if ((err = std::fscanf(nfile,"%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,line._data))<4) { cimg::warn(_cimg_instance "load_off(): Failed to read primitive %u/%u from file '%s'.", cimg_instance, @@ -40534,13 +41307,13 @@ namespace cimg_library_suffixed { err = std::fscanf(nfile,"%*[^\n] "); } else { - err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2); + err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); CImg::vector(i0,i3,i2,i1).move_to(primitives); CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)).move_to(colors); } } break; case 5 : { - if ((err = std::fscanf(nfile,"%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,line))<5) { + if ((err = std::fscanf(nfile,"%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,line._data))<5) { cimg::warn(_cimg_instance "load_off(): Failed to read primitive %u/%u from file '%s'.", cimg_instance, @@ -40548,7 +41321,7 @@ namespace cimg_library_suffixed { err = std::fscanf(nfile,"%*[^\n] "); } else { - err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2); + err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); CImg::vector(i0,i3,i2,i1).move_to(primitives); CImg::vector(i0,i4,i3).move_to(primitives); colors.insert(2,CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255))); @@ -40556,7 +41329,7 @@ namespace cimg_library_suffixed { } } break; case 6 : { - if ((err = std::fscanf(nfile,"%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,line))<6) { + if ((err = std::fscanf(nfile,"%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,line._data))<6) { cimg::warn(_cimg_instance "load_off(): Failed to read primitive %u/%u from file '%s'.", cimg_instance, @@ -40564,7 +41337,7 @@ namespace cimg_library_suffixed { err = std::fscanf(nfile,"%*[^\n] "); } else { - err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2); + err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); CImg::vector(i0,i3,i2,i1).move_to(primitives); CImg::vector(i0,i5,i4,i3).move_to(primitives); colors.insert(2,CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255))); @@ -40572,7 +41345,7 @@ namespace cimg_library_suffixed { } } break; case 7 : { - if ((err = std::fscanf(nfile,"%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,line))<7) { + if ((err = std::fscanf(nfile,"%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,line._data))<7) { cimg::warn(_cimg_instance "load_off(): Failed to read primitive %u/%u from file '%s'.", cimg_instance, @@ -40580,7 +41353,7 @@ namespace cimg_library_suffixed { err = std::fscanf(nfile,"%*[^\n] "); } else { - err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2); + err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); CImg::vector(i0,i4,i3,i1).move_to(primitives); CImg::vector(i0,i6,i5,i4).move_to(primitives); CImg::vector(i3,i2,i1).move_to(primitives); @@ -40589,7 +41362,7 @@ namespace cimg_library_suffixed { } } break; case 8 : { - if ((err = std::fscanf(nfile,"%u%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,&i7,line))<7) { + if ((err = std::fscanf(nfile,"%u%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,&i7,line._data))<7) { cimg::warn(_cimg_instance "load_off(): Failed to read primitive %u/%u from file '%s'.", cimg_instance, @@ -40597,7 +41370,7 @@ namespace cimg_library_suffixed { err = std::fscanf(nfile,"%*[^\n] "); } else { - err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2); + err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); CImg::vector(i0,i3,i2,i1).move_to(primitives); CImg::vector(i0,i5,i4,i3).move_to(primitives); CImg::vector(i0,i7,i6,i5).move_to(primitives); @@ -40624,6 +41397,28 @@ namespace cimg_library_suffixed { return *this; } + //! Load image sequence from a video file, using OpenCV library. + /** + \param filename Filename, as a C-string. + \param first_frame Index of the first frame to read. + \param last_frame Index of the last frame to read. + \param step_frame Step value for frame reading. + **/ + CImg& load_video(const char *const filename, + const unsigned int first_frame=0, const unsigned int last_frame=~0U, + const unsigned int step_frame=1, + const char axis='z', const float align=0) { + return get_load_video(filename,first_frame,last_frame,step_frame,axis,align).move_to(*this); + } + + //! Load image sequence from a video file, using OpenCV library \newinstance. + static CImg get_load_video(const char *const filename, + const unsigned int first_frame=0, const unsigned int last_frame=~0U, + const unsigned int step_frame=1, + const char axis='z', const float align=0) { + return CImgList().load_video(filename,first_frame,last_frame,step_frame).get_append(axis,align); + } + //! Load image sequence using FFMPEG's external tool 'ffmpeg'. /** \param filename Filename, as a C-string. @@ -40667,19 +41462,19 @@ namespace cimg_library_suffixed { "load_graphicsmagick_external(): Specified filename is (null).", cimg_instance); std::fclose(cimg::fopen(filename,"rb")); // Check if file exists. - char command[1024] = { 0 }, filetmp[512] = { 0 }; + CImg command(1024), filename_tmp(256); std::FILE *file = 0; const CImg s_filename = CImg::string(filename)._system_strescape(); #if cimg_OS==1 - cimg_snprintf(command,sizeof(command),"%s convert \"%s\" pnm:-", + cimg_snprintf(command,command._width,"%s convert \"%s\" pnm:-", cimg::graphicsmagick_path(),s_filename.data()); file = popen(command,"r"); if (file) { const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); try { load_pnm(file); } catch (...) { pclose(file); - cimg::exception_mode() = omode; + cimg::exception_mode(omode); throw CImgIOException(_cimg_instance "load_graphicsmagick_external(): Failed to load file '%s' with external command 'gm'.", cimg_instance, @@ -40690,15 +41485,15 @@ namespace cimg_library_suffixed { } #endif do { - cimg_snprintf(filetmp,sizeof(filetmp),"%s%c%s.pnm", + cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.pnm", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); - if ((file=std::fopen(filetmp,"rb"))!=0) cimg::fclose(file); + if ((file=std::fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); } while (file); - cimg_snprintf(command,sizeof(command),"%s convert \"%s\" \"%s\"", + cimg_snprintf(command,command._width,"%s convert \"%s\" \"%s\"", cimg::graphicsmagick_path(),s_filename.data(), - CImg::string(filetmp)._system_strescape().data()); + CImg::string(filename_tmp)._system_strescape().data()); cimg::system(command,cimg::graphicsmagick_path()); - if (!(file = std::fopen(filetmp,"rb"))) { + if (!(file = std::fopen(filename_tmp,"rb"))) { cimg::fclose(cimg::fopen(filename,"r")); throw CImgIOException(_cimg_instance "load_graphicsmagick_external(): Failed to load file '%s' with external command 'gm'.", @@ -40706,8 +41501,8 @@ namespace cimg_library_suffixed { filename); } else cimg::fclose(file); - load_pnm(filetmp); - std::remove(filetmp); + load_pnm(filename_tmp); + std::remove(filename_tmp); return *this; } @@ -40726,7 +41521,7 @@ namespace cimg_library_suffixed { "load_gzip_external(): Specified filename is (null).", cimg_instance); std::fclose(cimg::fopen(filename,"rb")); // Check if file exists. - char command[1024] = { 0 }, filetmp[512] = { 0 }, body[512] = { 0 }; + CImg command(1024), filename_tmp(256), body(256); const char *const ext = cimg::split_filename(filename,body), *const ext2 = cimg::split_filename(body,0); @@ -40734,24 +41529,24 @@ namespace cimg_library_suffixed { std::FILE *file = 0; do { if (!cimg::strcasecmp(ext,"gz")) { - if (*ext2) cimg_snprintf(filetmp,sizeof(filetmp),"%s%c%s.%s", + 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(filetmp,sizeof(filetmp),"%s%c%s", + else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); } else { - if (*ext) cimg_snprintf(filetmp,sizeof(filetmp),"%s%c%s.%s", + 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(filetmp,sizeof(filetmp),"%s%c%s", + else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); } - if ((file=std::fopen(filetmp,"rb"))!=0) cimg::fclose(file); + if ((file=std::fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); } while (file); - cimg_snprintf(command,sizeof(command),"%s -c \"%s\" > \"%s\"", + cimg_snprintf(command,command._width,"%s -c \"%s\" > \"%s\"", cimg::gunzip_path(), CImg::string(filename)._system_strescape().data(), - CImg::string(filetmp)._system_strescape().data()); + CImg::string(filename_tmp)._system_strescape().data()); cimg::system(command); - if (!(file = std::fopen(filetmp,"rb"))) { + if (!(file = std::fopen(filename_tmp,"rb"))) { cimg::fclose(cimg::fopen(filename,"r")); throw CImgIOException(_cimg_instance "load_gzip_external(): Failed to load file '%s' with external command 'gunzip'.", @@ -40759,8 +41554,8 @@ namespace cimg_library_suffixed { filename); } else cimg::fclose(file); - load(filetmp); - std::remove(filetmp); + load(filename_tmp); + std::remove(filename_tmp); return *this; } @@ -40779,21 +41574,21 @@ namespace cimg_library_suffixed { "load_imagemagick_external(): Specified filename is (null).", cimg_instance); std::fclose(cimg::fopen(filename,"rb")); // Check if file exists. - char command[1024] = { 0 }, filetmp[512] = { 0 }; + CImg command(1024), filename_tmp(256); std::FILE *file = 0; const CImg s_filename = CImg::string(filename)._system_strescape(); #if cimg_OS==1 - cimg_snprintf(command,sizeof(command),"%s%s \"%s\" pnm:-", + cimg_snprintf(command,command._width,"%s%s \"%s\" pnm:-", cimg::imagemagick_path(), !cimg::strcasecmp(cimg::split_filename(filename),"pdf")?" -density 400x400":"", s_filename.data()); file = popen(command,"r"); if (file) { const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); try { load_pnm(file); } catch (...) { pclose(file); - cimg::exception_mode() = omode; + cimg::exception_mode(omode); throw CImgIOException(_cimg_instance "load_imagemagick_external(): Failed to load file '%s' with " "external command 'convert'.", @@ -40805,16 +41600,16 @@ namespace cimg_library_suffixed { } #endif do { - cimg_snprintf(filetmp,sizeof(filetmp),"%s%c%s.pnm", + cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.pnm", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); - if ((file=std::fopen(filetmp,"rb"))!=0) cimg::fclose(file); + if ((file=std::fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); } while (file); - cimg_snprintf(command,sizeof(command),"%s%s \"%s\" \"%s\"", + cimg_snprintf(command,command._width,"%s%s \"%s\" \"%s\"", cimg::imagemagick_path(), !cimg::strcasecmp(cimg::split_filename(filename),"pdf")?" -density 400x400":"", - s_filename.data(),CImg::string(filetmp)._system_strescape().data()); + s_filename.data(),CImg::string(filename_tmp)._system_strescape().data()); cimg::system(command,cimg::imagemagick_path()); - if (!(file = std::fopen(filetmp,"rb"))) { + if (!(file = std::fopen(filename_tmp,"rb"))) { cimg::fclose(cimg::fopen(filename,"r")); throw CImgIOException(_cimg_instance "load_imagemagick_external(): Failed to load file '%s' with external command 'convert'.", @@ -40822,8 +41617,8 @@ namespace cimg_library_suffixed { filename); } else cimg::fclose(file); - load_pnm(filetmp); - std::remove(filetmp); + load_pnm(filename_tmp); + std::remove(filename_tmp); return *this; } @@ -40842,24 +41637,24 @@ namespace cimg_library_suffixed { "load_medcon_external(): Specified filename is (null).", cimg_instance); std::fclose(cimg::fopen(filename,"rb")); // Check if file exists. - char command[1024] = { 0 }, filetmp[512] = { 0 }, body[512] = { 0 }; + CImg command(1024), filename_tmp(256), body(256); cimg::fclose(cimg::fopen(filename,"r")); std::FILE *file = 0; do { - cimg_snprintf(filetmp,sizeof(filetmp),"%s.hdr",cimg::filenamerand()); - if ((file=std::fopen(filetmp,"rb"))!=0) cimg::fclose(file); + cimg_snprintf(filename_tmp,filename_tmp._width,"%s.hdr",cimg::filenamerand()); + if ((file=std::fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); } while (file); - cimg_snprintf(command,sizeof(command),"%s -w -c anlz -o \"%s\" -f \"%s\"", + cimg_snprintf(command,command._width,"%s -w -c anlz -o \"%s\" -f \"%s\"", cimg::medcon_path(), - CImg::string(filetmp)._system_strescape().data(), + CImg::string(filename_tmp)._system_strescape().data(), CImg::string(filename)._system_strescape().data()); cimg::system(command); - cimg::split_filename(filetmp,body); + cimg::split_filename(filename_tmp,body); - cimg_snprintf(command,sizeof(command),"%s.hdr",body); + cimg_snprintf(command,command._width,"%s.hdr",body._data); file = std::fopen(command,"rb"); if (!file) { - cimg_snprintf(command,sizeof(command),"m000-%s.hdr",body); + cimg_snprintf(command,command._width,"m000-%s.hdr",body._data); file = std::fopen(command,"rb"); if (!file) { throw CImgIOException(_cimg_instance @@ -40872,7 +41667,7 @@ namespace cimg_library_suffixed { load_analyze(command); std::remove(command); cimg::split_filename(command,body); - cimg_snprintf(command,sizeof(command),"%s.img",body); + cimg_snprintf(command,command._width,"%s.img",body._data); std::remove(command); return *this; } @@ -40892,19 +41687,19 @@ namespace cimg_library_suffixed { "load_dcraw_external(): Specified filename is (null).", cimg_instance); std::fclose(cimg::fopen(filename,"rb")); // Check if file exists. - char command[1024] = { 0 }, filetmp[512] = { 0 }; + CImg command(1024), filename_tmp(256); std::FILE *file = 0; const CImg s_filename = CImg::string(filename)._system_strescape(); #if cimg_OS==1 - cimg_snprintf(command,sizeof(command),"%s -w -4 -c \"%s\"", + cimg_snprintf(command,command._width,"%s -w -4 -c \"%s\"", cimg::dcraw_path(),s_filename.data()); file = popen(command,"r"); if (file) { const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); try { load_pnm(file); } catch (...) { pclose(file); - cimg::exception_mode() = omode; + cimg::exception_mode(omode); throw CImgIOException(_cimg_instance "load_dcraw_external(): Failed to load file '%s' with external command 'dcraw'.", cimg_instance, @@ -40915,14 +41710,14 @@ namespace cimg_library_suffixed { } #endif do { - cimg_snprintf(filetmp,sizeof(filetmp),"%s%c%s.ppm", + cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.ppm", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); - if ((file=std::fopen(filetmp,"rb"))!=0) cimg::fclose(file); + if ((file=std::fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); } while (file); - cimg_snprintf(command,sizeof(command),"%s -w -4 -c \"%s\" > \"%s\"", - cimg::dcraw_path(),s_filename.data(),CImg::string(filetmp)._system_strescape().data()); + cimg_snprintf(command,command._width,"%s -w -4 -c \"%s\" > \"%s\"", + cimg::dcraw_path(),s_filename.data(),CImg::string(filename_tmp)._system_strescape().data()); cimg::system(command,cimg::dcraw_path()); - if (!(file = std::fopen(filetmp,"rb"))) { + if (!(file = std::fopen(filename_tmp,"rb"))) { cimg::fclose(cimg::fopen(filename,"r")); throw CImgIOException(_cimg_instance "load_dcraw_external(): Failed to load file '%s' with external command 'dcraw'.", @@ -40930,8 +41725,8 @@ namespace cimg_library_suffixed { filename); } else cimg::fclose(file); - load_pnm(filetmp); - std::remove(filetmp); + load_pnm(filename_tmp); + std::remove(filename_tmp); return *this; } @@ -40950,20 +41745,28 @@ namespace cimg_library_suffixed { const bool release_camera=true, const unsigned int capture_width=0, const unsigned int capture_height=0) { #ifdef cimg_use_opencv - if (camera_index>255) + if (camera_index>99) throw CImgArgumentException(_cimg_instance "load_camera(): Invalid request for camera #%u " - "(no more than 256 cameras can be managed).", + "(no more than 100 cameras can be managed simultaneously).", cimg_instance, camera_index); - static CvCapture *capture[256] = { 0 }; + static CvCapture *capture[100] = { 0 }; + static unsigned int capture_w[100], capture_h[100]; if (release_camera) { + cimg::mutex(9); if (capture[camera_index]) cvReleaseCapture(&(capture[camera_index])); capture[camera_index] = 0; + capture_w[camera_index] = capture_h[camera_index] = 0; + cimg::mutex(9,0); return *this; } if (!capture[camera_index]) { + cimg::mutex(9); capture[camera_index] = cvCreateCameraCapture(camera_index); + capture_w[camera_index] = 0; + capture_h[camera_index] = 0; + cimg::mutex(9,0); if (!capture[camera_index]) { throw CImgIOException(_cimg_instance "load_camera(): Failed to initialize camera #%u.", @@ -40971,8 +41774,15 @@ namespace cimg_library_suffixed { camera_index); } } - if (capture_width) cvSetCaptureProperty(capture[camera_index],CV_CAP_PROP_FRAME_WIDTH,capture_width); - if (capture_height) cvSetCaptureProperty(capture[camera_index],CV_CAP_PROP_FRAME_HEIGHT,capture_height); + cimg::mutex(9); + if (capture_width!=capture_w[camera_index]) { + cvSetCaptureProperty(capture[camera_index],CV_CAP_PROP_FRAME_WIDTH,capture_width); + capture_w[camera_index] = capture_width; + } + if (capture_height!=capture_h[camera_index]) { + cvSetCaptureProperty(capture[camera_index],CV_CAP_PROP_FRAME_HEIGHT,capture_height); + capture_h[camera_index] = capture_height; + } const IplImage *img = 0; for (unsigned int i = 0; i",pixel_type()); @@ -41085,19 +41896,20 @@ namespace cimg_library_suffixed { mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)), mdisp==0?"b":(mdisp==1?"Kio":"Mio"), cimg::t_bold,cimg::t_normal,pixel_type(),(void*)begin()); - if (_data) std::fprintf(cimg::output(),"..%p (%s) = [ ",(void*)((char*)end()-1),_is_shared?"shared":"non-shared"); + if (_data) + std::fprintf(cimg::output(),"..%p (%s) = [ ",(void*)((char*)end() - 1),_is_shared?"shared":"non-shared"); else std::fprintf(cimg::output()," (%s) = [ ",_is_shared?"shared":"non-shared"); if (!is_empty()) cimg_foroff(*this,off) { std::fprintf(cimg::output(),cimg::type::format(),cimg::type::format(_data[off])); if (off!=siz1) std::fprintf(cimg::output(),"%s",off%_width==width1?" ; ":" "); - if (off==7 && siz>16) { off = siz1-8; std::fprintf(cimg::output(),"... "); } + if (off==7 && siz>16) { off = siz1 - 8; std::fprintf(cimg::output(),"... "); } } if (!is_empty() && display_stats) - std::fprintf(cimg::output(), + std::fprintf(cimg::output(), " ], %smin%s = %g, %smax%s = %g, %smean%s = %g, %sstd%s = %g, %scoords_min%s = (%u,%u,%u,%u), " "%scoords_max%s = (%u,%u,%u,%u).\n", - cimg::t_bold,cimg::t_normal,st[0], + cimg::t_bold,cimg::t_normal,st[0], cimg::t_bold,cimg::t_normal,st[1], cimg::t_bold,cimg::t_normal,st[2], cimg::t_bold,cimg::t_normal,std::sqrt(st[3]), @@ -41120,7 +41932,7 @@ namespace cimg_library_suffixed { //! Display image into a CImgDisplay window, in an interactive way. /** \param disp Display window. - \param display_info Tells if image informations are displayed on the standard output. + \param display_info Tells if image information are displayed on the standard output. **/ const CImg& display(CImgDisplay &disp, const bool display_info, unsigned int *const XYZ=0) const { return _display(disp,0,display_info,XYZ,false); @@ -41129,7 +41941,7 @@ namespace cimg_library_suffixed { //! Display image into an interactive window. /** \param title Window title - \param display_info Tells if image informations are displayed on the standard output. + \param display_info Tells if image information are displayed on the standard output. **/ const CImg& display(const char *const title=0, const bool display_info=true, unsigned int *const XYZ=0) const { CImgDisplay disp; @@ -41140,7 +41952,7 @@ namespace cimg_library_suffixed { const bool display_info, unsigned int *const XYZ, const bool exit_on_simpleclick) const { unsigned int oldw = 0, oldh = 0, _XYZ[3] = { 0 }, key = 0; - int x0 = 0, y0 = 0, z0 = 0, x1 = width()-1, y1 = height()-1, z1 = depth()-1; + int x0 = 0, y0 = 0, z0 = 0, x1 = width() - 1, y1 = height() - 1, z1 = depth() - 1; if (!disp) { disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,1); @@ -41156,18 +41968,22 @@ namespace cimg_library_suffixed { for (bool reset_view = true, resize_disp = false, is_first_select = true; !key && !disp.is_closed(); ) { if (reset_view) { if (XYZ) { _XYZ[0] = XYZ[0]; _XYZ[1] = XYZ[1]; _XYZ[2] = XYZ[2]; } - else { _XYZ[0] = (x0 + x1)/2; _XYZ[1] = (y0 + y1)/2; _XYZ[2] = (z0 + z1)/2; } - x0 = 0; y0 = 0; z0 = 0; x1 = width()-1; y1 = height()-1; z1 = depth()-1; - oldw = disp.width(); oldh = disp.height(); + else { + _XYZ[0] = (unsigned int)(x0 + x1)/2; + _XYZ[1] = (unsigned int)(y0 + y1)/2; + _XYZ[2] = (unsigned int)(z0 + z1)/2; + } + x0 = 0; y0 = 0; z0 = 0; x1 = width() - 1; y1 = height() - 1; z1 = depth() - 1; + oldw = disp._width; oldh = disp._height; reset_view = false; } - if (!x0 && !y0 && !z0 && x1==width()-1 && y1==height()-1 && z1==depth()-1) { + if (!x0 && !y0 && !z0 && x1==width() - 1 && y1==height() - 1 && z1==depth() - 1) { if (is_empty()) zoom.assign(1,1,1,1,0); else zoom.assign(); } else zoom = get_crop(x0,y0,z0,x1,y1,z1); const unsigned int - dx = 1 + x1 - x0, dy = 1 + y1 - y0, dz = 1 + z1 - z0, - tw = dx + (dz>1?dz:0), th = dy + (dz>1?dz:0); + dx = 1U + x1 - x0, dy = 1U + y1 - y0, dz = 1U + z1 - z0, + tw = dx + (dz>1?dz:0U), th = dy + (dz>1?dz:0U); if (!is_empty() && !disp.is_fullscreen() && resize_disp) { const unsigned int ttw = tw*disp.width()/oldw, tth = th*disp.height()/oldh, @@ -41189,7 +42005,11 @@ namespace cimg_library_suffixed { if (_height>1 && visu._height==1) disp.set_title("%s | y=%u",disp._title,y0); if (_depth>1 && visu._depth==1) disp.set_title("%s | z=%u",disp._title,z0); - if (!is_first_select) { _XYZ[0] = (x1-x0)/2; _XYZ[1] = (y1-y0)/2; _XYZ[2] = (z1-z0)/2; } + if (!is_first_select) { + _XYZ[0] = (unsigned int)(x1 - x0)/2; + _XYZ[1] = (unsigned int)(y1 - y0)/2; + _XYZ[2] = (unsigned int)(z1 - z0)/2; + } const CImg selection = visu._get_select(disp,0,2,_XYZ,x0,y0,z0,is_first_select,_depth>1); is_first_select = false; @@ -41223,8 +42043,8 @@ namespace cimg_library_suffixed { case cimg::keyP : if (visu._depth>1 && (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT())) { // Special mode: play stack of frames const unsigned int - w1 = visu._width*disp.width()/(visu._width+(visu._depth>1?visu._depth:0)), - h1 = visu._height*disp.height()/(visu._height+(visu._depth>1?visu._depth:0)); + w1 = visu._width*disp.width()/(visu._width + (visu._depth>1?visu._depth:0)), + h1 = visu._height*disp.height()/(visu._height + (visu._depth>1?visu._depth:0)); float frame_timing = 5; bool is_stopped = false; disp.set_key(key,false).set_wheel().resize(cimg_fitscreen(w1,h1,1),false); key = 0; @@ -41246,7 +42066,7 @@ namespace cimg_library_suffixed { case cimg::keySPACE : is_stopped = !is_stopped; disp.set_key(key,false); key = 0; break; case cimg::keyARROWLEFT : case cimg::keyARROWUP : is_stopped = true; timer = 0; key = 0; break; case cimg::keyARROWRIGHT : case cimg::keyARROWDOWN : is_stopped = true; - (_XYZ[2]+=visu._depth-2)%=visu._depth; timer = 0; key = 0; break; + (_XYZ[2]+=visu._depth - 2)%=visu._depth; timer = 0; key = 0; break; case cimg::keyD : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_fullscreen(false). resize(CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,false), @@ -41293,25 +42113,25 @@ namespace cimg_library_suffixed { const int mx = go_in_center?disp.width()/2:disp.mouse_x(), my = go_in_center?disp.height()/2:disp.mouse_y(), - mX = mx*(_width+(_depth>1?_depth:0))/disp.width(), - mY = my*(_height+(_depth>1?_depth:0))/disp.height(); - int X = _XYZ[0], Y = _XYZ[1], Z = _XYZ[2]; + mX = mx*(width() + (depth()>1?depth():0))/disp.width(), + mY = my*(height() + (depth()>1?depth():0))/disp.height(); + int X = (int)_XYZ[0], Y = (int)_XYZ[1], Z = (int)_XYZ[2]; if (mX=height()) { - X = x0 + mX*(1+x1-x0)/_width; Z = z0 + (mY-_height)*(1+z1-z0)/_depth; Y = _XYZ[1]; + X = x0 + mX*(1 + x1 - x0)/width(); Z = z0 + (mY - height())*(1 + z1 - z0)/depth(); Y = (int)_XYZ[1]; } if (mX>=width() && mY4) { x0 = X - 3*(X-x0)/4; x1 = X + 3*(x1-X)/4; } - if (y1-y0>4) { y0 = Y - 3*(Y-y0)/4; y1 = Y + 3*(y1-Y)/4; } - if (z1-z0>4) { z0 = Z - 3*(Z-z0)/4; z1 = Z + 3*(z1-Z)/4; } + if (x1 - x0>4) { x0 = X - 3*(X - x0)/4; x1 = X + 3*(x1 - X)/4; } + if (y1 - y0>4) { y0 = Y - 3*(Y - y0)/4; y1 = Y + 3*(y1 - Y)/4; } + if (z1 - z0>4) { z0 = Z - 3*(Z - z0)/4; z1 = Z + 3*(z1 - Z)/4; } } if (go_out) { const int - delta_x = (x1-x0)/8, delta_y = (y1-y0)/8, delta_z = (z1-z0)/8, + delta_x = (x1 - x0)/8, delta_y = (y1 - y0)/8, delta_z = (z1 - z0)/8, ndelta_x = delta_x?delta_x:(_width>1?1:0), ndelta_y = delta_y?delta_y:(_height>1?1:0), ndelta_z = delta_z?delta_z:(_depth>1?1:0); @@ -41320,39 +42140,39 @@ namespace cimg_library_suffixed { if (x0<0) { x1-=x0; x0 = 0; if (x1>=width()) x1 = width() - 1; } if (y0<0) { y1-=y0; y0 = 0; if (y1>=height()) y1 = height() - 1; } if (z0<0) { z1-=z0; z0 = 0; if (z1>=depth()) z1 = depth() - 1; } - if (x1>=width()) { x0-=(x1-width()+1); x1 = width()-1; if (x0<0) x0 = 0; } - if (y1>=height()) { y0-=(y1-height()+1); y1 = height()-1; if (y0<0) y0 = 0; } - if (z1>=depth()) { z0-=(z1-depth()+1); z1 = depth()-1; if (z0<0) z0 = 0; } + if (x1>=width()) { x0-=(x1 - width() + 1); x1 = width() - 1; if (x0<0) x0 = 0; } + if (y1>=height()) { y0-=(y1 - height() + 1); y1 = height() - 1; if (y0<0) y0 = 0; } + if (z1>=depth()) { z0-=(z1 - depth() + 1); z1 = depth() - 1; if (z0<0) z0 = 0; } } if (go_left) { - const int delta = (x1-x0)/4, ndelta = delta?delta:(_width>1?1:0); - if (x0-ndelta>=0) { x0-=ndelta; x1-=ndelta; } + const int delta = (x1 - x0)/4, ndelta = delta?delta:(_width>1?1:0); + if (x0 - ndelta>=0) { x0-=ndelta; x1-=ndelta; } else { x1-=x0; x0 = 0; } } if (go_right) { - const int delta = (x1-x0)/4, ndelta = delta?delta:(_width>1?1:0); + const int delta = (x1 - x0)/4, ndelta = delta?delta:(_width>1?1:0); if (x1+ndelta1?1:0); - if (y0-ndelta>=0) { y0-=ndelta; y1-=ndelta; } + const int delta = (y1 - y0)/4, ndelta = delta?delta:(_height>1?1:0); + if (y0 - ndelta>=0) { y0-=ndelta; y1-=ndelta; } else { y1-=y0; y0 = 0; } } if (go_down) { - const int delta = (y1-y0)/4, ndelta = delta?delta:(_height>1?1:0); + const int delta = (y1 - y0)/4, ndelta = delta?delta:(_height>1?1:0); if (y1+ndelta1?1:0); - if (z0-ndelta>=0) { z0-=ndelta; z1-=ndelta; } + const int delta = (z1 - z0)/4, ndelta = delta?delta:(_depth>1?1:0); + if (z0 - ndelta>=0) { z0-=ndelta; z1-=ndelta; } else { z1-=z0; z0 = 0; } } if (go_dec) { - const int delta = (z1-z0)/4, ndelta = delta?delta:(_depth>1?1:0); + const int delta = (z1 - z0)/4, ndelta = delta?delta:(_depth>1?1:0); if (z1+ndelta(),centering, - render_static,render_motion,is_double_sided,focale, + render_static,render_motion,is_double_sided,focale, light_x,light_y,light_z,specular_lightness,specular_shininess, - display_axes,pose_matrix); + display_axes,pose_matrix); } //! Display object 3d in an interactive window \simplification. template const CImg& display_object3d(const char *const title, - const CImg& vertices, + const CImg& vertices, const CImgList& primitives, const CImgList& colors, const bool centering=true, @@ -41476,7 +42296,7 @@ namespace cimg_library_suffixed { //! Display object 3d in an interactive window \simplification. template const CImg& display_object3d(const char *const title, - const CImg& vertices, + const CImg& vertices, const CImgList& primitives, const bool centering=true, const int render_static=4, const int render_motion=1, @@ -41509,7 +42329,7 @@ namespace cimg_library_suffixed { //! Display object 3d in an interactive window \simplification. template const CImg& display_object3d(const char *const title, - const CImg& vertices, + const CImg& vertices, const bool centering=true, const int render_static=4, const int render_motion=1, const bool is_double_sided=true, const float focale=700, @@ -41524,48 +42344,48 @@ namespace cimg_library_suffixed { template const CImg& _display_object3d(CImgDisplay& disp, const char *const title, - const CImg& vertices, - const CImgList& primitives, - const CImgList& colors, + const CImg& vertices, + const CImgList& primitives, + const CImgList& colors, const to& opacities, - const bool centering, - const int render_static, const int render_motion, - const bool is_double_sided, const float focale, + const bool centering, + const int render_static, const int render_motion, + const bool is_double_sided, const float focale, const float light_x, const float light_y, const float light_z, - const float specular_lightness, const float specular_shininess, - const bool display_axes, float *const pose_matrix) const { + const float specular_lightness, const float specular_shininess, + const bool display_axes, float *const pose_matrix) const { typedef typename cimg::superset::type tpfloat; // Check input arguments if (is_empty()) { - if (disp) return CImg(disp.width(),disp.height(),1,(colors && colors[0].size()==1)?1:3,0). - _display_object3d(disp,title,vertices,primitives,colors,opacities,centering, + if (disp) return CImg(disp.width(),disp.height(),1,(colors && colors[0].size()==1)?1:3,0). + _display_object3d(disp,title,vertices,primitives,colors,opacities,centering, render_static,render_motion,is_double_sided,focale, light_x,light_y,light_z,specular_lightness,specular_shininess, display_axes,pose_matrix); - else return CImg(1,2,1,1,64,128).resize(cimg_fitscreen(CImgDisplay::screen_width()/2, + else return CImg(1,2,1,1,64,128).resize(cimg_fitscreen(CImgDisplay::screen_width()/2, CImgDisplay::screen_height()/2,1), 1,(colors && colors[0].size()==1)?1:3,3). _display_object3d(disp,title,vertices,primitives,colors,opacities,centering, - render_static,render_motion,is_double_sided,focale, + render_static,render_motion,is_double_sided,focale, light_x,light_y,light_z,specular_lightness,specular_shininess, - display_axes,pose_matrix); + display_axes,pose_matrix); } else { if (disp) disp.resize(*this,false); } - char error_message[1024] = { 0 }; + CImg error_message(1024); if (!vertices.is_object3d(primitives,colors,opacities,true,error_message)) throw CImgArgumentException(_cimg_instance "display_object3d(): Invalid specified 3d object (%u,%u) (%s).", - cimg_instance,vertices._width,primitives._width,error_message); + cimg_instance,vertices._width,primitives._width,error_message.data()); if (vertices._width && !primitives) { CImgList nprimitives(vertices._width,1,1,1,1); - cimglist_for(nprimitives,l) nprimitives(l,0) = l; + cimglist_for(nprimitives,l) nprimitives(l,0) = (tf)l; return _display_object3d(disp,title,vertices,nprimitives,colors,opacities,centering, - render_static,render_motion,is_double_sided,focale, + render_static,render_motion,is_double_sided,focale, light_x,light_y,light_z,specular_lightness,specular_shininess, - display_axes,pose_matrix); + display_axes,pose_matrix); } if (!disp) { - disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,3); + disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,3); if (!title) disp.set_title("CImg<%s> (%u vertices, %u primitives)", pixel_type(),vertices._width,primitives._width); } else if (title) disp.set_title("%s",title); @@ -41591,7 +42411,7 @@ namespace cimg_library_suffixed { xm = 0, xM = vertices?vertices.get_shared_row(0).max_min(xm):0, ym = 0, yM = vertices?vertices.get_shared_row(1).max_min(ym):0, zm = 0, zM = vertices?vertices.get_shared_row(2).max_min(zm):0; - const float delta = cimg::max(xM-xm,yM-ym,zM-zm); + const float delta = cimg::max(xM - xm,yM - ym,zM - zm); rotated_bbox_vertices = bbox_vertices.assign(8,3,1,1, xm,xM,xM,xm,xm,xM,xM,xm, @@ -41663,11 +42483,11 @@ namespace cimg_library_suffixed { } // Draw objects -#ifdef cimg_use_openmp - const bool render_with_zbuffer = true; -#else + //#ifdef cimg_use_openmp + // const bool render_with_zbuffer = true; + //#else const bool render_with_zbuffer = !clicked && nrender_static>0; -#endif + //#endif visu = visu0; if ((clicked && nrender_motion<0) || (!clicked && nrender_static<0)) visu.draw_object3d(Xoff + visu._width/2.0f,Yoff + visu._height/2.0f,Zoff, @@ -41678,7 +42498,7 @@ namespace cimg_library_suffixed { Xoff + visu._width/2.0f,Yoff + visu._height/2.0f,Zoff, rotated_vertices,reverse_primitives?reverse_primitives:primitives, colors,opacities,clicked?nrender_motion:nrender_static,_is_double_sided==1,focale, - width()/2.0f+light_x,height()/2.0f+light_y,light_z+Zoff, + width()/2.0f + light_x,height()/2.0f + light_y,light_z + Zoff, specular_lightness,specular_shininess,sprite_scale); // Draw axes if (ndisplay_axes) { @@ -41702,14 +42522,14 @@ namespace cimg_library_suffixed { axes_opacities(2,0) = (rotated_axes_vertices(3,2)>0)?0.5f:1.0f; visu.draw_object3d(Xaxes,Yaxes,0,rotated_axes_vertices,axes_primitives, axes_colors,axes_opacities,1,false,focale). - draw_text((int)(Xaxes+rotated_axes_vertices(4,0)), - (int)(Yaxes+rotated_axes_vertices(4,1)), + draw_text((int)(Xaxes + rotated_axes_vertices(4,0)), + (int)(Yaxes + rotated_axes_vertices(4,1)), "X",axes_colors[0]._data,0,axes_opacities(0,0),13). - draw_text((int)(Xaxes+rotated_axes_vertices(5,0)), - (int)(Yaxes+rotated_axes_vertices(5,1)), + draw_text((int)(Xaxes + rotated_axes_vertices(5,0)), + (int)(Yaxes + rotated_axes_vertices(5,1)), "Y",axes_colors[1]._data,0,axes_opacities(1,0),13). - draw_text((int)(Xaxes+rotated_axes_vertices(6,0)), - (int)(Yaxes+rotated_axes_vertices(6,1)), + draw_text((int)(Xaxes + rotated_axes_vertices(6,0)), + (int)(Yaxes + rotated_axes_vertices(6,1)), "Z",axes_colors[2]._data,0,axes_opacities(2,0),13); } visu.display(disp); @@ -41726,29 +42546,29 @@ namespace cimg_library_suffixed { const float R = 0.45f*cimg::min(disp.width(),disp.height()), R2 = R*R, - u0 = (float)(x0-disp.width()/2), - v0 = (float)(y0-disp.height()/2), - u1 = (float)(x1-disp.width()/2), - v1 = (float)(y1-disp.height()/2), - n0 = (float)std::sqrt(u0*u0+v0*v0), - n1 = (float)std::sqrt(u1*u1+v1*v1), + u0 = (float)(x0 - disp.width()/2), + v0 = (float)(y0 - disp.height()/2), + u1 = (float)(x1 - disp.width()/2), + v1 = (float)(y1 - disp.height()/2), + n0 = (float)std::sqrt(u0*u0 + v0*v0), + n1 = (float)std::sqrt(u1*u1 + v1*v1), nu0 = n0>R?(u0*R/n0):u0, nv0 = n0>R?(v0*R/n0):v0, - nw0 = (float)std::sqrt(cimg::max(0,R2-nu0*nu0-nv0*nv0)), + nw0 = (float)std::sqrt(cimg::max(0,R2 - nu0*nu0 - nv0*nv0)), nu1 = n1>R?(u1*R/n1):u1, nv1 = n1>R?(v1*R/n1):v1, - nw1 = (float)std::sqrt(cimg::max(0,R2-nu1*nu1-nv1*nv1)), - u = nv0*nw1-nw0*nv1, - v = nw0*nu1-nu0*nw1, - w = nv0*nu1-nu0*nv1, - n = (float)std::sqrt(u*u+v*v+w*w), + nw1 = (float)std::sqrt(cimg::max(0,R2 - nu1*nu1 - nv1*nv1)), + u = nv0*nw1 - nw0*nv1, + v = nw0*nu1 - nu0*nw1, + w = nv0*nu1 - nu0*nv1, + n = (float)std::sqrt(u*u + v*v + w*w), alpha = (float)std::asin(n/R2); (CImg::rotation_matrix(u,v,w,alpha)*pose).move_to(pose); x0 = x1; y0 = y1; } if (disp.button()&2) { - if (focale>0) Zoff-=(y0-y1)*focale/400; - else { const float s = std::exp((y0-y1)/400.0f); pose*=s; sprite_scale*=s; } + if (focale>0) Zoff-=(y0 - y1)*focale/400; + else { const float s = std::exp((y0 - y1)/400.0f); pose*=s; sprite_scale*=s; } x0 = x1; y0 = y1; } if (disp.wheel()) { @@ -41756,7 +42576,7 @@ namespace cimg_library_suffixed { else { const float s = std::exp(disp.wheel()/20.0f); pose*=s; sprite_scale*=s; } disp.set_wheel(); } - if (disp.button()&4) { Xoff+=(x1-x0); Yoff+=(y1-y0); x0 = x1; y0 = y1; } + if (disp.button()&4) { Xoff+=(x1 - x0); Yoff+=(y1 - y0); x0 = x1; y0 = y1; } if ((disp.button()&1) && (disp.button()&2)) { init_pose = true; disp.set_button(); x0 = x1; y0 = y1; pose = CImg(4,3,1,1, 1,0,0,0, 0,1,0,0, 0,0,1,0); @@ -41792,7 +42612,7 @@ namespace cimg_library_suffixed { } if (disp.is_fullscreen()) disp.resize(ns_width,ns_height,false); else { - ns_width = (unsigned int)disp.width(); ns_height = disp.height(); + ns_width = disp._width; ns_height = disp._height; disp.resize(disp.screen_width(),disp.screen_height(),false); } disp.toggle_fullscreen()._is_resized = true; @@ -41906,7 +42726,7 @@ namespace cimg_library_suffixed { rotated_vertices,reverse_primitives?reverse_primitives:primitives, colors,opacities,clicked?nrender_motion:nrender_static, _is_double_sided==1,focale, - visu.width()/2.0f+light_x,visu.height()/2.0f+light_y,light_z+Zoff, + visu.width()/2.0f + light_x,visu.height()/2.0f + light_y,light_z + Zoff, specular_lightness,specular_shininess, sprite_scale); board.saveEPS(filename); @@ -41930,7 +42750,7 @@ namespace cimg_library_suffixed { rotated_vertices,reverse_primitives?reverse_primitives:primitives, colors,opacities,clicked?nrender_motion:nrender_static, _is_double_sided==1,focale, - visu.width()/2.0f+light_x,visu.height()/2.0f+light_y,light_z+Zoff, + visu.width()/2.0f + light_x,visu.height()/2.0f + light_y,light_z + Zoff, specular_lightness,specular_shininess, sprite_scale); board.saveSVG(filename); @@ -41992,7 +42812,7 @@ namespace cimg_library_suffixed { 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 unsigned long siz = (unsigned long)_width*_height*_depth, siz1 = cimg::max(1U,siz-1); + const unsigned long siz = (unsigned long)_width*_height*_depth, siz1 = cimg::max(1U,siz - 1); const unsigned int old_normalization = disp.normalization(); disp.show().flush()._normalization = 0; @@ -42001,30 +42821,30 @@ namespace cimg_library_suffixed { 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 zoom(x1-x0+1,1,1,spectrum()); - cimg_forC(*this,c) zoom.get_shared_channel(c) = CImg(data(x0,0,0,c),x1-x0+1,1,1,1,true); + if (reset_view) { x0 = 0; x1 = width()*height()*depth() - 1; y0 = ymin; y1 = ymax; reset_view = false; } + CImg zoom(x1 - x0 + 1,1,1,spectrum()); + cimg_forC(*this,c) zoom.get_shared_channel(c) = CImg(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 selection = zoom.get_select_graph(disp,plot_type,vertex_type, - labelx, - nxmin + x0*(nxmax-nxmin)/siz1, - nxmin + x1*(nxmax-nxmin)/siz1, + labelx, + nxmin + x0*(nxmax - nxmin)/siz1, + nxmin + x1*(nxmax - nxmin)/siz1, labely,y0,y1); - const int mouse_x = disp.mouse_x(), mouse_y = disp.mouse_y(); + 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); + 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 = disp.key()) { + 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; @@ -42049,48 +42869,48 @@ namespace cimg_library_suffixed { if (go_in) { const int xsiz = x1 - x0, - mx = (mouse_x-16)*xsiz/(disp.width()-32), + mx = (mouse_x - 16)*xsiz/(disp.width() - 32), cx = x0 + (mx<0?0:(mx>=xsiz?xsiz:mx)); - if (x1-x0>4) { - x0 = cx - 7*(cx-x0)/8; x1 = cx + 7*(x1-cx)/8; + 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), + my = (mouse_y - 16)*ysiz/(disp.height() - 32), cy = y1 - (my<0?0:(my>=ysiz?ysiz:my)); - y0 = cy - 7*(cy-y0)/8; y1 = cy + 7*(y1-cy)/8; + 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?1:0); - const double ndelta_y = (y1-y0)/8; + const int delta_x = (x1 - x0)/8, ndelta_x = delta_x?delta_x:(siz>1?1:0); + 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 (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; } + 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 = siz1; } + 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; + 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; + const double delta = (y1 - y0)/10, ndelta = delta?delta:1; y0-=ndelta; y1-=ndelta; go_down = false; } @@ -42118,7 +42938,7 @@ namespace cimg_library_suffixed { // Do not test for empty instances, since .cimg format is able to manage empty instances. const bool is_stdout = *filename=='-' && (!filename[1] || filename[1]=='.'); const char *const ext = cimg::split_filename(filename); - char nfilename[1024] = { 0 }; + CImg nfilename(1024); const char *const fn = is_stdout?filename:(number>=0)?cimg::number_filename(filename,number,digits,nfilename): filename; @@ -42215,7 +43035,7 @@ namespace cimg_library_suffixed { !cimg::strcasecmp(ext,"vob") || !cimg::strcasecmp(ext,"wmv") || !cimg::strcasecmp(ext,"xvid") || - !cimg::strcasecmp(ext,"mpeg")) return save_ffmpeg(fn); + !cimg::strcasecmp(ext,"mpeg")) return save_video(fn); return save_other(fn); } @@ -42267,18 +43087,18 @@ namespace cimg_library_suffixed { "save_cpp(): Specified filename is (null).", cimg_instance); std::FILE *const nfile = file?file:cimg::fopen(filename,"w"); - char varname[1024] = { 0 }; - if (filename) std::sscanf(cimg::basename(filename),"%1023[a-zA-Z0-9_]",varname); - if (!*varname) cimg_snprintf(varname,sizeof(varname),"unnamed"); + CImg varname(1024); *varname = 0; + if (filename) cimg_sscanf(cimg::basename(filename),"%1023[a-zA-Z0-9_]",varname._data); + if (!*varname) cimg_snprintf(varname,varname._width,"unnamed"); std::fprintf(nfile, "/* Define image '%s' of size %ux%ux%ux%u and type '%s' */\n" "%s data_%s[] = { %s\n ", - varname,_width,_height,_depth,_spectrum,pixel_type(),pixel_type(),varname, + varname._data,_width,_height,_depth,_spectrum,pixel_type(),pixel_type(),varname._data, is_empty()?"};":""); - if (!is_empty()) for (unsigned long off = 0, siz = size()-1; off<=siz; ++off) { + if (!is_empty()) for (unsigned long off = 0, siz = size() - 1; off<=siz; ++off) { std::fprintf(nfile,cimg::type::format(),cimg::type::format((*this)[off])); if (off==siz) std::fprintf(nfile," };\n"); - else if (!((off+1)%16)) std::fprintf(nfile,",\n "); + else if (!((off + 1)%16)) std::fprintf(nfile,",\n "); else std::fprintf(nfile,", "); } if (!file) cimg::fclose(nfile); @@ -42318,7 +43138,7 @@ namespace cimg_library_suffixed { std::FILE *const nfile = file?file:cimg::fopen(filename,"w"); const T* ptrs = _data; cimg_forYZC(*this,y,z,c) { - cimg_forX(*this,x) std::fprintf(nfile,"%.16g%s",(double)*(ptrs++),(x==width()-1)?"":","); + cimg_forX(*this,x) std::fprintf(nfile,"%.16g%s",(double)*(ptrs++),(x==width() - 1)?"":","); std::fputc('\n',nfile); } if (!file) cimg::fclose(nfile); @@ -42389,9 +43209,9 @@ namespace cimg_library_suffixed { cimg::fwrite(header,54,nfile); const T - *ptr_r = data(0,_height-1,0,0), - *ptr_g = (_spectrum>=2)?data(0,_height-1,0,1):0, - *ptr_b = (_spectrum>=3)?data(0,_height-1,0,2):0; + *ptr_r = data(0,_height - 1,0,0), + *ptr_g = (_spectrum>=2)?data(0,_height - 1,0,1):0, + *ptr_b = (_spectrum>=3)?data(0,_height - 1,0,2):0; switch (_spectrum) { case 1 : { @@ -42716,7 +43536,7 @@ namespace cimg_library_suffixed { png_write_info(png_ptr,info_ptr); const int byte_depth = bit_depth>>3; const int numChan = spectrum()>4?4:spectrum(); - const int pixel_bit_depth_flag = numChan * (bit_depth-1); + const int pixel_bit_depth_flag = numChan * (bit_depth - 1); // Allocate Memory for Image Save and Fill pixel data png_bytep *const imgData = new png_byte*[_height]; @@ -42878,7 +43698,7 @@ namespace cimg_library_suffixed { case 1 : { // Scalar image if (bytes_per_pixel==1 || (!bytes_per_pixel && stmax<256)) { // Binary PGM 8 bits CImg buf(buf_size); - for (long to_write = (long)_width*_height; to_write>0; ) { + for (long to_write = width()*height(); to_write>0; ) { const unsigned long N = cimg::min((unsigned long)to_write,buf_size); unsigned char *ptrd = buf._data; for (unsigned long i = N; i>0; --i) *(ptrd++) = (unsigned char)*(ptr_r++); @@ -42887,7 +43707,7 @@ namespace cimg_library_suffixed { } } else { // Binary PGM 16 bits CImg buf(buf_size); - for (long to_write = (long)_width*_height; to_write>0; ) { + for (long to_write = width()*height(); to_write>0; ) { const unsigned long N = cimg::min((unsigned long)to_write,buf_size); unsigned short *ptrd = buf._data; for (unsigned long i = N; i>0; --i) *(ptrd++) = (unsigned short)*(ptr_r++); @@ -42900,7 +43720,7 @@ namespace cimg_library_suffixed { case 2 : { // RG image if (bytes_per_pixel==1 || (!bytes_per_pixel && stmax<256)) { // Binary PPM 8 bits CImg buf(buf_size); - for (long to_write = (long)_width*_height; to_write>0; ) { + for (long to_write = width()*height(); to_write>0; ) { const unsigned long N = cimg::min((unsigned long)to_write,buf_size/3); unsigned char *ptrd = buf._data; for (unsigned long i = N; i>0; --i) { @@ -42913,7 +43733,7 @@ namespace cimg_library_suffixed { } } else { // Binary PPM 16 bits CImg buf(buf_size); - for (long to_write = (long)_width*_height; to_write>0; ) { + for (long to_write = width()*height(); to_write>0; ) { const unsigned long N = cimg::min((unsigned long)to_write,buf_size/3); unsigned short *ptrd = buf._data; for (unsigned long i = N; i>0; --i) { @@ -42930,7 +43750,7 @@ namespace cimg_library_suffixed { default : { // RGB image if (bytes_per_pixel==1 || (!bytes_per_pixel && stmax<256)) { // Binary PPM 8 bits CImg buf(buf_size); - for (long to_write = (long)_width*_height; to_write>0; ) { + for (long to_write = width()*height(); to_write>0; ) { const unsigned long N = cimg::min((unsigned long)to_write,buf_size/3); unsigned char *ptrd = buf._data; for (unsigned long i = N; i>0; --i) { @@ -42943,7 +43763,7 @@ namespace cimg_library_suffixed { } } else { // Binary PPM 16 bits CImg buf(buf_size); - for (long to_write = (long)_width*_height; to_write>0; ) { + for (long to_write = width()*height(); to_write>0; ) { const unsigned long N = cimg::min((unsigned long)to_write,buf_size/3); unsigned short *ptrd = buf._data; for (unsigned long i = N; i>0; --i) { @@ -42996,7 +43816,7 @@ namespace cimg_library_suffixed { else if (!cimg::type::is_float() && sizeof(T)==1) { // Save as extended P5 file: Binary byte-valued 3d. std::fprintf(nfile,"P5\n%u %u %u\n255\n",_width,_height,_depth); CImg buf(buf_size); - for (long to_write = (long)_width*_height*_depth; to_write>0; ) { + for (long to_write = width()*height()*depth(); to_write>0; ) { const unsigned long N = cimg::min((unsigned long)to_write,buf_size); unsigned char *ptrd = buf._data; for (unsigned long i = N; i>0; --i) *(ptrd++) = (unsigned char)*(ptr++); @@ -43007,7 +43827,7 @@ namespace cimg_library_suffixed { if (_depth>1) std::fprintf(nfile,"P8\n%u %u %u\n%d\n",_width,_height,_depth,(int)max()); else std::fprintf(nfile,"P8\n%u %u\n%d\n",_width,_height,(int)max()); CImg buf(buf_size); - for (long to_write = (long)_width*_height*_depth; to_write>0; ) { + for (long to_write = width()*height()*depth(); to_write>0; ) { const unsigned long N = cimg::min((unsigned long)to_write,buf_size); int *ptrd = buf._data; for (unsigned long i = N; i>0; --i) *(ptrd++) = (int)*(ptr++); @@ -43018,7 +43838,7 @@ namespace cimg_library_suffixed { if (_depth>1) std::fprintf(nfile,"P9\n%u %u %u\n%g\n",_width,_height,_depth,(double)max()); else std::fprintf(nfile,"P9\n%u %u\n%g\n",_width,_height,(double)max()); CImg buf(buf_size); - for (long to_write = (long)_width*_height*_depth; to_write>0; ) { + for (long to_write = width()*height()*depth(); to_write>0; ) { const unsigned long N = cimg::min((unsigned long)to_write,buf_size); float *ptrd = buf._data; for (unsigned long i = N; i>0; --i) *(ptrd++) = (float)*(ptr++); @@ -43036,12 +43856,14 @@ namespace cimg_library_suffixed { \param filename Filename, as a C-string. **/ const CImg& save_pfm(const char *const filename) const { - return get_mirror('y')._save_pfm(0,filename); + get_mirror('y')._save_pfm(0,filename); + return *this; } //! Save image as a PFM file \overloading. const CImg& save_pfm(std::FILE *const file) const { - return get_mirror('y')._save_pfm(file,0); + get_mirror('y')._save_pfm(file,0); + return *this; } const CImg& _save_pfm(std::FILE *const file, const char *const filename) const { @@ -43075,7 +43897,7 @@ namespace cimg_library_suffixed { switch (_spectrum) { case 1 : { // Scalar image CImg buf(buf_size); - for (long to_write = (long)_width*_height; to_write>0; ) { + for (long to_write = width()*height(); to_write>0; ) { const unsigned long N = cimg::min((unsigned long)to_write,buf_size); float *ptrd = buf._data; for (unsigned long i = N; i>0; --i) *(ptrd++) = (float)*(ptr_r++); @@ -43086,7 +43908,7 @@ namespace cimg_library_suffixed { } break; case 2 : { // RG image CImg buf(buf_size); - for (long to_write = (long)_width*_height; to_write>0; ) { + for (long to_write = width()*height(); to_write>0; ) { const unsigned int N = cimg::min((unsigned int)to_write,buf_size/3); float *ptrd = buf._data; for (unsigned long i = N; i>0; --i) { @@ -43101,7 +43923,7 @@ namespace cimg_library_suffixed { } break; default : { // RGB image CImg buf(buf_size); - for (long to_write = (long)_width*_height; to_write>0; ) { + for (long to_write = width()*height(); to_write>0; ) { const unsigned int N = cimg::min((unsigned int)to_write,buf_size/3); float *ptrd = buf._data; for (unsigned long i = N; i>0; --i) { @@ -43258,8 +44080,7 @@ namespace cimg_library_suffixed { //! Save image as a TIFF file. /** \param filename Filename, as a C-string. - \param compression_type Type of data compression. - Can be { 1=None | 2=CCITTRLE | 3=CCITTFAX3 | 4=CCITTFAX4 | 5=LZW | 6=JPEG }. + \param compression_type Type of data compression. Can be { 0=None | 1=LZW | 2=JPEG }. \note - libtiff support is enabled by defining the precompilation directive \c cimg_use_tif. @@ -43270,7 +44091,7 @@ namespace cimg_library_suffixed { function uses CImg&save_other(const char*). **/ const CImg& save_tiff(const char *const filename, const unsigned int compression_type=0, - const float *const voxel_size=0) const { + const float *const voxel_size=0, const char *const description=0) const { if (!filename) throw CImgArgumentException(_cimg_instance "save_tiff(): Specified filename is (null).", @@ -43280,7 +44101,7 @@ namespace cimg_library_suffixed { #ifdef cimg_use_tiff TIFF *tif = TIFFOpen(filename,"w"); if (tif) { - cimg_forZ(*this,z) get_slice(z)._save_tiff(tif,z,compression_type,voxel_size); + cimg_forZ(*this,z) get_slice(z)._save_tiff(tif,z,compression_type,voxel_size,description); TIFFClose(tif); } else throw CImgIOException(_cimg_instance "save_tiff(): Failed to open file '%s' for writing.", @@ -43288,21 +44109,21 @@ namespace cimg_library_suffixed { filename); return *this; #else - cimg::unused(compression_type,voxel_size); + cimg::unused(compression_type,voxel_size,description); return save_other(filename); #endif } #ifdef cimg_use_tiff -#define _cimg_save_tiff(types,typed,compression_type,voxel_size) if (!std::strcmp(types,pixel_type())) { \ - const typed foo = (typed)0; return _save_tiff(tif,directory,foo,compression_type,voxel_size); } +#define _cimg_save_tiff(types,typed,compression_type) if (!std::strcmp(types,pixel_type())) { \ + const typed foo = (typed)0; return _save_tiff(tif,directory,foo,compression_type,voxel_size,description); } // [internal] Save a plane into a tiff file template const CImg& _save_tiff(TIFF *tif, const unsigned int directory, const t& pixel_t, const unsigned int compression_type, - const float *const voxel_size=0) const { + const float *const voxel_size, const char *const description) const { if (is_empty() || !tif || pixel_t) return *this; const char *const filename = TIFFFileName(tif); uint32 rowsperstrip = (uint32)-1; @@ -43313,14 +44134,15 @@ namespace cimg_library_suffixed { TIFFSetField(tif,TIFFTAG_IMAGEWIDTH,_width); TIFFSetField(tif,TIFFTAG_IMAGELENGTH,_height); if (voxel_size) { - const float vx = voxel_size[0], vy = voxel_size[1], _vz = voxel_size[2], vz = _vz>0?_vz:1; + const float vx = voxel_size[0], vy = voxel_size[1], vz = voxel_size[2]; TIFFSetField(tif,TIFFTAG_RESOLUTIONUNIT,RESUNIT_NONE); - TIFFSetField(tif,TIFFTAG_XRESOLUTION,vx/vz); - TIFFSetField(tif,TIFFTAG_YRESOLUTION,vy/vz); + TIFFSetField(tif,TIFFTAG_XRESOLUTION,1.0f/vx); + TIFFSetField(tif,TIFFTAG_YRESOLUTION,1.0f/vy); CImg s_description(256); cimg_snprintf(s_description,s_description._width,"VX=%g VY=%g VZ=%g spacing=%g",vx,vy,vz,vz); TIFFSetField(tif,TIFFTAG_IMAGEDESCRIPTION,s_description.data()); } + if (description) TIFFSetField(tif,TIFFTAG_IMAGEDESCRIPTION,description); TIFFSetField(tif,TIFFTAG_ORIENTATION,ORIENTATION_TOPLEFT); TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,spp); if (cimg::type::is_float()) TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,3); @@ -43329,7 +44151,8 @@ namespace cimg_library_suffixed { TIFFSetField(tif,TIFFTAG_BITSPERSAMPLE,bpp); TIFFSetField(tif,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG); TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,photometric); - TIFFSetField(tif,TIFFTAG_COMPRESSION,compression_type?(compression_type-1):COMPRESSION_NONE); + TIFFSetField(tif,TIFFTAG_COMPRESSION,compression_type==2?COMPRESSION_JPEG: + compression_type==1?COMPRESSION_LZW:COMPRESSION_NONE); rowsperstrip = TIFFDefaultStripSize(tif,rowsperstrip); TIFFSetField(tif,TIFFTAG_ROWSPERSTRIP,rowsperstrip); TIFFSetField(tif,TIFFTAG_FILLORDER,FILLORDER_MSB2LSB); @@ -43337,7 +44160,7 @@ namespace cimg_library_suffixed { t *const buf = (t*)_TIFFmalloc(TIFFStripSize(tif)); if (buf) { for (unsigned int row = 0; row<_height; row+=rowsperstrip) { - uint32 nrow = (row + rowsperstrip>_height?_height-row:rowsperstrip); + uint32 nrow = (row + rowsperstrip>_height?_height - row:rowsperstrip); tstrip_t strip = TIFFComputeStrip(tif,row,0); tsize_t i = 0; for (unsigned int rr = 0; rr& _save_tiff(TIFF *tif, const unsigned int directory, const unsigned int compression_type, - const float *const voxel_size) const { - _cimg_save_tiff("bool",unsigned char,compression_type,voxel_size); - _cimg_save_tiff("char",char,compression_type,voxel_size); - _cimg_save_tiff("unsigned char",unsigned char,compression_type,voxel_size); - _cimg_save_tiff("short",short,compression_type,voxel_size); - _cimg_save_tiff("unsigned short",unsigned short,compression_type,voxel_size); - _cimg_save_tiff("int",int,compression_type,voxel_size); - _cimg_save_tiff("unsigned int",unsigned int,compression_type,voxel_size); - _cimg_save_tiff("long",int,compression_type,voxel_size); - _cimg_save_tiff("unsigned long",unsigned int,compression_type,voxel_size); - _cimg_save_tiff("float",float,compression_type,voxel_size); - _cimg_save_tiff("double",float,compression_type,voxel_size); + const float *const voxel_size, const char *const description) const { + _cimg_save_tiff("bool",unsigned char,compression_type); + _cimg_save_tiff("char",char,compression_type); + _cimg_save_tiff("unsigned char",unsigned char,compression_type); + _cimg_save_tiff("short",short,compression_type); + _cimg_save_tiff("unsigned short",unsigned short,compression_type); + _cimg_save_tiff("int",int,compression_type); + _cimg_save_tiff("unsigned int",unsigned int,compression_type); + _cimg_save_tiff("long",int,compression_type); + _cimg_save_tiff("unsigned long",unsigned int,compression_type); + _cimg_save_tiff("float",float,compression_type); + _cimg_save_tiff("double",float,compression_type); const char *const filename = TIFFFileName(tif); throw CImgInstanceException(_cimg_instance "save_tiff(): Unsupported pixel type '%s' for file '%s'.", @@ -43400,11 +44223,11 @@ namespace cimg_library_suffixed { wtr.open(filename, imitate_file); else { minc::minc_info di; - if(width()) di.push_back(minc::dim_info(width(), width()*0.5, -1, minc::dim_info::DIM_X)); - if(height()) di.push_back(minc::dim_info(height(), height()*0.5, -1, minc::dim_info::DIM_Y)); - if(depth()) di.push_back(minc::dim_info(depth(), depth()*0.5, -1, minc::dim_info::DIM_Z)); - if(spectrum()) di.push_back(minc::dim_info(spectrum(), spectrum()*0.5, -1, minc::dim_info::DIM_TIME)); - wtr.open(filename, di, 1, NC_FLOAT, 0); + if(width()) di.push_back(minc::dim_info(width(),width()*0.5,-1,minc::dim_info::DIM_X)); + if(height()) di.push_back(minc::dim_info(height(),height()*0.5,-1,minc::dim_info::DIM_Y)); + if(depth()) di.push_back(minc::dim_info(depth(),depth()*0.5,-1,minc::dim_info::DIM_Z)); + if(spectrum()) di.push_back(minc::dim_info(spectrum(),spectrum()*0.5,-1,minc::dim_info::DIM_TIME)); + wtr.open(filename,di,1,NC_FLOAT,0); } if(typeid(T)==typeid(unsigned char)) wtr.setup_write_byte(); @@ -43432,26 +44255,27 @@ namespace cimg_library_suffixed { if (is_empty()) { cimg::fempty(0,filename); return *this; } std::FILE *file; - char header[348] = { 0 }, hname[1024] = { 0 }, iname[1024] = { 0 }; + char header[348] = { 0 }; + CImg hname(1024), iname(1024); const char *const ext = cimg::split_filename(filename); - short datatype=-1; + short datatype = -1; std::memset(header,0,348); if (!*ext) { - cimg_snprintf(hname,sizeof(hname),"%s.hdr",filename); - cimg_snprintf(iname,sizeof(iname),"%s.img",filename); + cimg_snprintf(hname,hname._width,"%s.hdr",filename); + cimg_snprintf(iname,iname._width,"%s.img",filename); } if (!cimg::strncasecmp(ext,"hdr",3)) { std::strcpy(hname,filename); - std::strncpy(iname,filename,sizeof(iname)-1); - std::sprintf(iname + std::strlen(iname)-3,"img"); + std::strncpy(iname,filename,iname._width - 1); + std::sprintf(iname._data + std::strlen(iname) - 3,"img"); } if (!cimg::strncasecmp(ext,"img",3)) { std::strcpy(hname,filename); - std::strncpy(iname,filename,sizeof(iname)-1); - std::sprintf(hname + std::strlen(iname)-3,"hdr"); + std::strncpy(iname,filename,iname._width - 1); + std::sprintf(hname._data + std::strlen(iname) - 3,"hdr"); } if (!cimg::strncasecmp(ext,"nii",3)) { - std::strncpy(hname,filename,sizeof(hname)-1); *iname = 0; + std::strncpy(hname,filename,hname._width - 1); *iname = 0; } int *const iheader = (int*)header; *iheader = 348; @@ -43460,10 +44284,10 @@ namespace cimg_library_suffixed { ((short*)(header + 36))[0] = 4096; ((char*)(header + 38))[0] = 114; ((short*)(header + 40))[0] = 4; - ((short*)(header + 40))[1] = _width; - ((short*)(header + 40))[2] = _height; - ((short*)(header + 40))[3] = _depth; - ((short*)(header + 40))[4] = _spectrum; + ((short*)(header + 40))[1] = (short)_width; + ((short*)(header + 40))[2] = (short)_height; + ((short*)(header + 40))[3] = (short)_depth; + ((short*)(header + 40))[4] = (short)_spectrum; if (!cimg::strcasecmp(pixel_type(),"bool")) datatype = 2; if (!cimg::strcasecmp(pixel_type(),"unsigned char")) datatype = 2; if (!cimg::strcasecmp(pixel_type(),"char")) datatype = 2; @@ -43481,15 +44305,15 @@ namespace cimg_library_suffixed { cimg_instance, pixel_type(),filename); - ((short*)(header+70))[0] = datatype; - ((short*)(header+72))[0] = sizeof(T); - ((float*)(header+112))[0] = 1; - ((float*)(header+76))[0] = 0; + ((short*)(header + 70))[0] = datatype; + ((short*)(header + 72))[0] = sizeof(T); + ((float*)(header + 112))[0] = 1; + ((float*)(header + 76))[0] = 0; if (voxel_size) { - ((float*)(header+76))[1] = voxel_size[0]; - ((float*)(header+76))[2] = voxel_size[1]; - ((float*)(header+76))[3] = voxel_size[2]; - } else ((float*)(header+76))[1] = ((float*)(header+76))[2] = ((float*)(header+76))[3] = 1; + ((float*)(header + 76))[1] = voxel_size[0]; + ((float*)(header + 76))[2] = voxel_size[1]; + ((float*)(header + 76))[3] = voxel_size[2]; + } else ((float*)(header + 76))[1] = ((float*)(header + 76))[2] = ((float*)(header + 76))[3] = 1; file = cimg::fopen(hname,"wb"); cimg::fwrite(header,348,file); if (*iname) { cimg::fclose(file); file = cimg::fopen(iname,"wb"); } @@ -43533,9 +44357,9 @@ namespace cimg_library_suffixed { //! Save image as a sub-image into an existing .cimg file \overloading. const CImg& save_cimg(std::FILE *const file, - const unsigned int n0, - const unsigned int x0, const unsigned int y0, - const unsigned int z0, const unsigned int c0) const { + const unsigned int n0, + const unsigned int x0, const unsigned int y0, + const unsigned int z0, const unsigned int c0) const { CImgList(*this,true).save_cimg(file,n0,x0,y0,z0,c0); return *this; } @@ -43589,7 +44413,7 @@ namespace cimg_library_suffixed { cimg_instance); if (is_empty()) { cimg::fempty(file,filename); return *this; } - int inrpixsize=-1; + int inrpixsize = -1; const char *inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0"; if (!cimg::strcasecmp(pixel_type(),"unsigned char")) { inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; @@ -43710,7 +44534,7 @@ namespace cimg_library_suffixed { \param filename Filename, as a C-string. \param colorspace Colorspace data field in output file (see Pandore file specifications - for more informations). + for more information). **/ const CImg& save_pandore(const char *const filename, const unsigned int colorspace=0) const { return _save_pandore(0,filename,colorspace); @@ -43768,22 +44592,22 @@ namespace cimg_library_suffixed { #define _cimg_save_pandore_case(sy,sz,sv,stype,id) \ if (!saved && (sy?(sy==_height):true) && (sz?(sz==_depth):true) && \ (sv?(sv==_spectrum):true) && !std::strcmp(stype,pixel_type())) { \ - unsigned int *iheader = (unsigned int*)(header+12); \ - nbdims = _save_pandore_header_length((*iheader=id),dims,colorspace); \ - cimg::fwrite(header,36,nfile); \ - if (sizeof(unsigned long)==4) { unsigned long ndims[5] = { 0 }; \ - for (int d = 0; d<5; ++d) ndims[d] = (unsigned long)dims[d]; cimg::fwrite(ndims,nbdims,nfile); } \ - else if (sizeof(unsigned int)==4) { unsigned int ndims[5] = { 0 }; \ - for (int d = 0; d<5; ++d) ndims[d] = (unsigned int)dims[d]; cimg::fwrite(ndims,nbdims,nfile); } \ - else if (sizeof(unsigned short)==4) { unsigned short ndims[5] = { 0 }; \ - for (int d = 0; d<5; ++d) ndims[d] = (unsigned short)dims[d]; cimg::fwrite(ndims,nbdims,nfile); } \ + unsigned int *iheader = (unsigned int*)(header + 12); \ + nbdims = _save_pandore_header_length((*iheader=id),dims,colorspace); \ + cimg::fwrite(header,36,nfile); \ + if (sizeof(unsigned long)==4) { CImg ndims(5); \ + for (int d = 0; d<5; ++d) ndims[d] = (unsigned long)dims[d]; cimg::fwrite(ndims._data,nbdims,nfile); } \ + else if (sizeof(unsigned int)==4) { CImg ndims(5); \ + for (int d = 0; d<5; ++d) ndims[d] = (unsigned int)dims[d]; cimg::fwrite(ndims._data,nbdims,nfile); } \ + else if (sizeof(unsigned short)==4) { CImg ndims(5); \ + for (int d = 0; d<5; ++d) ndims[d] = (unsigned short)dims[d]; cimg::fwrite(ndims._data,nbdims,nfile); } \ else throw CImgIOException(_cimg_instance \ "save_pandore(): Unsupported datatype for file '%s'.",\ cimg_instance, \ filename?filename:"(FILE*)"); \ - if (id==2 || id==5 || id==8 || id==16 || id==19 || id==22 || id==26 || id==30) { \ + if (id==2 || id==5 || id==8 || id==16 || id==19 || id==22 || id==26 || id==30) { \ __cimg_save_pandore_case(unsigned char); \ - } else if (id==3 || id==6 || id==9 || id==17 || id==20 || id==23 || id==27 || id==31) { \ + } else if (id==3 || id==6 || id==9 || id==17 || id==20 || id==23 || id==27 || id==31) { \ if (sizeof(unsigned long)==4) { __cimg_save_pandore_case(unsigned long); } \ else if (sizeof(unsigned int)==4) { __cimg_save_pandore_case(unsigned int); } \ else if (sizeof(unsigned short)==4) { __cimg_save_pandore_case(unsigned short); } \ @@ -43791,7 +44615,7 @@ namespace cimg_library_suffixed { "save_pandore(): Unsupported datatype for file '%s'.",\ cimg_instance, \ filename?filename:"(FILE*)"); \ - } else if (id==4 || id==7 || id==10 || id==18 || id==21 || id==25 || id==29 || id==33) { \ + } else if (id==4 || id==7 || id==10 || id==18 || id==21 || id==25 || id==29 || id==33) { \ if (sizeof(double)==4) { __cimg_save_pandore_case(double); } \ else if (sizeof(float)==4) { __cimg_save_pandore_case(float); } \ else throw CImgIOException(_cimg_instance \ @@ -43799,7 +44623,7 @@ namespace cimg_library_suffixed { cimg_instance, \ filename?filename:"(FILE*)"); \ } \ - saved = true; \ + saved = true; \ } if (!file && !filename) @@ -43945,41 +44769,6 @@ namespace cimg_library_suffixed { return *this; } - //! Save image as a video file, using the FFmpeg library. - /** - \param filename Filename, as a C-string. - \param fps Video framerate. - \param bitrate Video bitrate. - \note - - Each slice of the instance image is considered to be a single frame of the output video file. - - This method uses functions provided by the FFmpeg library. - Configuration macro \c cimg_use_ffmpeg must be set for the method to succeed natively. - Otherwise, the method calls - save_ffmpeg_external(const char*,unsigned int,unsigned int,const char*,unsigned int,unsigned int) const. - **/ - const CImg& save_ffmpeg(const char *const filename, const unsigned int fps=25, - const unsigned int bitrate=2048) const { - if (!filename) - throw CImgArgumentException(_cimg_instance - "save_ffmpeg(): Specified filename is (null).", - cimg_instance); - if (!fps) - throw CImgArgumentException(_cimg_instance - "save_ffmpeg(): Invalid specified framerate 0, for file '%s'.", - cimg_instance, - filename); - if (is_empty()) { cimg::fempty(0,filename); return *this; } - -#ifndef cimg_use_ffmpeg - return save_ffmpeg_external(filename,0,fps,bitrate); -#else - CImgList list; - get_split('z').move_to(list); - list.save_ffmpeg(filename,fps,bitrate); - return *this; -#endif - } - //! Save image as a .yuv video file. /** \param filename Filename, as a C-string. @@ -44043,12 +44832,12 @@ namespace cimg_library_suffixed { filename?filename:"(FILE*)"); CImgList opacities; - char error_message[1024] = { 0 }; + CImg error_message(1024); if (!is_object3d(primitives,colors,opacities,true,error_message)) throw CImgInstanceException(_cimg_instance "save_off(): Invalid specified 3d object, for file '%s' (%s).", cimg_instance, - filename?filename:"(FILE*)",error_message); + filename?filename:"(FILE*)",error_message.data()); const CImg default_color(1,3,1,1,200); std::FILE *const nfile = file?file:cimg::fopen(filename,"w"); @@ -44109,11 +44898,28 @@ namespace cimg_library_suffixed { return *this; } + //! Save volumetric image as a video, using the OpenCV library. + /** + \param filename Filename to write data to. + \param fps Number of frames per second. + \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 CImg& save_video(const char *const filename, const unsigned int fps=25, + const char *codec=0, const bool keep_open=false) const { + if (is_empty()) { CImgList().save_video(filename,fps,codec,keep_open); return *this; } + CImgList list; + get_split('z').move_to(list); + list.save_video(filename,fps,codec,keep_open); + return *this; + } + //! Save volumetric image as a video, using ffmpeg external binary. /** \param filename Filename, as a C-string. - \param codec Video codec, as a C-string. \param fps Video framerate. + \param codec Video codec, as a C-string. \param bitrate Video bitrate. \note - Each slice of the instance image is considered to be a single frame of the output video file. @@ -44121,8 +44927,8 @@ namespace cimg_library_suffixed { FFmpeg. It must be installed for the method to succeed. **/ - const CImg& save_ffmpeg_external(const char *const filename, const char *const codec=0, - const unsigned int fps=25, const unsigned int bitrate=2048) const { + const CImg& save_ffmpeg_external(const char *const filename, const unsigned int fps=25, + const char *const codec=0, const unsigned int bitrate=2048) const { if (!filename) throw CImgArgumentException(_cimg_instance "save_ffmpeg_external(): Specified filename is (null).", @@ -44131,7 +44937,7 @@ namespace cimg_library_suffixed { CImgList list; get_split('z').move_to(list); - list.save_ffmpeg_external(filename,codec,fps,bitrate); + list.save_ffmpeg_external(filename,fps,codec,bitrate); return *this; } @@ -44149,29 +44955,29 @@ namespace cimg_library_suffixed { cimg_instance); if (is_empty()) { cimg::fempty(0,filename); return *this; } - char command[1024] = { 0 }, filetmp[512] = { 0 }, body[512] = { 0 }; + CImg 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(filetmp,sizeof(filetmp),"%s%c%s.%s", + 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(filetmp,sizeof(filetmp),"%s%c%s.cimg", + 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(filetmp,sizeof(filetmp),"%s%c%s.%s", + 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(filetmp,sizeof(filetmp),"%s%c%s.cimg", + else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.cimg", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); } - if ((file=std::fopen(filetmp,"rb"))!=0) cimg::fclose(file); + if ((file=std::fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); } while (file); - save(filetmp); - cimg_snprintf(command,sizeof(command),"%s -c \"%s\" > \"%s\"", + save(filename_tmp); + cimg_snprintf(command,command._width,"%s -c \"%s\" > \"%s\"", cimg::gzip_path(), - CImg::string(filetmp)._system_strescape().data(), + CImg::string(filename_tmp)._system_strescape().data(), CImg::string(filename)._system_strescape().data()); cimg::system(command); file = std::fopen(filename,"rb"); @@ -44182,7 +44988,7 @@ namespace cimg_library_suffixed { filename); else cimg::fclose(file); - std::remove(filetmp); + std::remove(filename_tmp); return *this; } @@ -44208,22 +45014,22 @@ namespace cimg_library_suffixed { #define _cimg_sge_ext1 "pgm" #define _cimg_sge_ext2 "ppm" #endif - char command[1024] = { 0 }, filetmp[512] = { 0 }; + CImg command(1024), filename_tmp(256); std::FILE *file; do { - cimg_snprintf(filetmp,sizeof(filetmp),"%s%c%s.%s", + cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(), _spectrum==1?_cimg_sge_ext1:_cimg_sge_ext2); - if ((file=std::fopen(filetmp,"rb"))!=0) cimg::fclose(file); + if ((file=std::fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); } while (file); #ifdef cimg_use_png - save_png(filetmp); + save_png(filename_tmp); #else - save_pnm(filetmp); + save_pnm(filename_tmp); #endif - cimg_snprintf(command,sizeof(command),"%s convert -quality %u \"%s\" \"%s\"", + cimg_snprintf(command,command._width,"%s convert -quality %u \"%s\" \"%s\"", cimg::graphicsmagick_path(),quality, - CImg::string(filetmp)._system_strescape().data(), + CImg::string(filename_tmp)._system_strescape().data(), CImg::string(filename)._system_strescape().data()); cimg::system(command); file = std::fopen(filename,"rb"); @@ -44234,7 +45040,7 @@ namespace cimg_library_suffixed { filename); if (file) cimg::fclose(file); - std::remove(filetmp); + std::remove(filename_tmp); return *this; } @@ -44260,21 +45066,21 @@ namespace cimg_library_suffixed { #define _cimg_sie_ext1 "pgm" #define _cimg_sie_ext2 "ppm" #endif - char command[1024] = { 0 }, filetmp[512] = { 0 }; + CImg command(1024), filename_tmp(256); std::FILE *file; do { - cimg_snprintf(filetmp,sizeof(filetmp),"%s%c%s.%s",cimg::temporary_path(), + cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s",cimg::temporary_path(), cimg_file_separator,cimg::filenamerand(),_spectrum==1?_cimg_sie_ext1:_cimg_sie_ext2); - if ((file=std::fopen(filetmp,"rb"))!=0) cimg::fclose(file); + if ((file=std::fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); } while (file); #ifdef cimg_use_png - save_png(filetmp); + save_png(filename_tmp); #else - save_pnm(filetmp); + save_pnm(filename_tmp); #endif - cimg_snprintf(command,sizeof(command),"%s -quality %u \"%s\" \"%s\"", + cimg_snprintf(command,command._width,"%s -quality %u \"%s\" \"%s\"", cimg::imagemagick_path(),quality, - CImg::string(filetmp)._system_strescape().data(), + CImg::string(filename_tmp)._system_strescape().data(), CImg::string(filename)._system_strescape().data()); cimg::system(command); file = std::fopen(filename,"rb"); @@ -44285,7 +45091,7 @@ namespace cimg_library_suffixed { filename); if (file) cimg::fclose(file); - std::remove(filetmp); + std::remove(filename_tmp); return *this; } @@ -44303,26 +45109,26 @@ namespace cimg_library_suffixed { cimg_instance); if (is_empty()) { cimg::fempty(0,filename); return *this; } - char command[1024] = { 0 }, filetmp[512] = { 0 }, body[512] = { 0 }; + CImg command(1024), filename_tmp(256), body(256); std::FILE *file; do { - cimg_snprintf(filetmp,sizeof(filetmp),"%s.hdr",cimg::filenamerand()); - if ((file=std::fopen(filetmp,"rb"))!=0) cimg::fclose(file); + cimg_snprintf(filename_tmp,filename_tmp._width,"%s.hdr",cimg::filenamerand()); + if ((file=std::fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); } while (file); - save_analyze(filetmp); - cimg_snprintf(command,sizeof(command),"%s -w -c dicom -o \"%s\" -f \"%s\"", + save_analyze(filename_tmp); + cimg_snprintf(command,command._width,"%s -w -c dicom -o \"%s\" -f \"%s\"", cimg::medcon_path(), CImg::string(filename)._system_strescape().data(), - CImg::string(filetmp)._system_strescape().data()); + CImg::string(filename_tmp)._system_strescape().data()); cimg::system(command); - std::remove(filetmp); - cimg::split_filename(filetmp,body); - cimg_snprintf(filetmp,sizeof(filetmp),"%s.img",body); - std::remove(filetmp); + std::remove(filename_tmp); + cimg::split_filename(filename_tmp,body); + cimg_snprintf(filename_tmp,filename_tmp._width,"%s.img",body._data); + std::remove(filename_tmp); file = std::fopen(filename,"rb"); if (!file) { - cimg_snprintf(command,sizeof(command),"m000-%s",filename); + cimg_snprintf(command,command._width,"m000-%s",filename); file = std::fopen(command,"rb"); if (!file) { cimg::fclose(cimg::fopen(filename,"r")); @@ -44359,7 +45165,7 @@ namespace cimg_library_suffixed { const unsigned int omode = cimg::exception_mode(); bool is_saved = true; - cimg::exception_mode() = 0; + cimg::exception_mode(0); try { save_magick(filename); } catch (CImgException&) { try { save_imagemagick_external(filename,quality); } @@ -44370,7 +45176,7 @@ namespace cimg_library_suffixed { } } } - cimg::exception_mode() = omode; + cimg::exception_mode(omode); if (!is_saved) throw CImgIOException(_cimg_instance "save_other(): Failed to save file '%s'. Format is not natively supported, " @@ -44380,6 +45186,15 @@ namespace cimg_library_suffixed { return *this; } + //! Serialize a CImg instance into a raw CImg buffer. + /** + \param is_compressed tells if zlib compression must be used for serialization + (this requires 'cimg_use_zlib' been enabled). + **/ + CImg get_serialize(const bool is_compressed=false) const { + return CImgList(*this,true).get_serialize(is_compressed); + } + // [internal] Return a 40x38 color logo of a 'danger' item. static CImg _logo40x38() { CImg res(40,38,1,3); @@ -44573,7 +45388,7 @@ namespace cimg_library_suffixed { \param val Initialization value for images pixels. **/ CImgList(const unsigned int n, const unsigned int width, const unsigned int height, - const unsigned int depth, const unsigned int spectrum, const T val): + const unsigned int depth, const unsigned int spectrum, const T& val): _width(0),_allocated_width(0),_data(0) { assign(n); cimglist_apply(*this,assign)(width,height,depth,spectrum,val); @@ -44595,16 +45410,16 @@ namespace cimg_library_suffixed { const unsigned int depth, const unsigned int spectrum, const int val0, const int val1, ...): _width(0),_allocated_width(0),_data(0) { #define _CImgList_stdarg(t) { \ - assign(n,width,height,depth,spectrum); \ - const unsigned long siz = (unsigned long)width*height*depth*spectrum, nsiz = siz*n; \ - T *ptrd = _data->_data; \ - va_list ap; \ - va_start(ap,val1); \ - for (unsigned long l = 0, s = 0, i = 0; i_data; \ + va_list ap; \ + va_start(ap,val1); \ + for (unsigned long l = 0, s = 0, i = 0; i& assign(const unsigned int n, const unsigned int width, const unsigned int height, - const unsigned int depth, const unsigned int spectrum, const T val) { + const unsigned int depth, const unsigned int spectrum, const T& val) { assign(n); cimglist_apply(*this,assign)(width,height,depth,spectrum,val); return *this; @@ -45094,8 +45909,8 @@ namespace cimg_library_suffixed { list.insert(_width,npos); bool is_one_shared_element = false; cimglist_for(*this,l) is_one_shared_element|=_data[l]._is_shared; - if (is_one_shared_element) cimglist_for(*this,l) list[npos+l].assign(_data[l]); - else cimglist_for(*this,l) _data[l].move_to(list[npos+l]); + if (is_one_shared_element) cimglist_for(*this,l) list[npos + l].assign(_data[l]); + else cimglist_for(*this,l) _data[l].move_to(list[npos + l]); assign(); return list; } @@ -45426,7 +46241,7 @@ namespace cimg_library_suffixed { "at(): Empty instance.", cimglist_instance); - return _data[pos<0?0:pos>=(int)_width?(int)_width-1:pos]; + return _data[pos<0?0:pos>=(int)_width?(int)_width - 1:pos]; } //! Access to pixel value with Dirichlet boundary conditions. @@ -45439,12 +46254,12 @@ namespace cimg_library_suffixed { \param out_value Default value returned if \c offset is outside image bounds. \note list.atNXYZC(p,x,y,z,c); is equivalent to list[p].atXYZC(x,y,z,c);. **/ - T& atNXYZC(const int pos, const int x, const int y, const int z, const int c, const T out_value) { + T& atNXYZC(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].atXYZC(x,y,z,c,out_value); } //! 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 { + 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); } @@ -45477,11 +46292,11 @@ namespace cimg_library_suffixed { } T& _atNXYZC(const int pos, const int x, const int y, const int z, const int c) { - return _data[pos<0?0:(pos>=(int)_width?(int)_width-1:pos)].atXYZC(x,y,z,c); + return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atXYZC(x,y,z,c); } T _atNXYZC(const int pos, const int x, const int y, const int z, const int c) const { - return _data[pos<0?0:(pos>=(int)_width?(int)_width-1:pos)].atXYZC(x,y,z,c); + return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atXYZC(x,y,z,c); } //! Access pixel value with Dirichlet boundary conditions for the 3 first coordinates (\c pos, \c x,\c y,\c z). @@ -45494,12 +46309,12 @@ namespace cimg_library_suffixed { \param out_value Default value returned if \c offset is outside image bounds. \note list.atNXYZ(p,x,y,z,c); is equivalent to list[p].atXYZ(x,y,z,c);. **/ - T& atNXYZ(const int pos, const int x, const int y, const int z, const int c, const T out_value) { + 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); } //! Access pixel value with Dirichlet boundary conditions for the 3 first coordinates (\c pos, \c x,\c y,\c z) \const. - T atNXYZ(const int pos, const int x, const int y, const int z, const int c, const T out_value) const { + T atNXYZ(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].atXYZ(x,y,z,c,out_value); } @@ -45532,11 +46347,11 @@ namespace cimg_library_suffixed { } T& _atNXYZ(const int pos, const int x, const int y, const int z, const int c=0) { - return _data[pos<0?0:(pos>=(int)_width?(int)_width-1:pos)].atXYZ(x,y,z,c); + return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atXYZ(x,y,z,c); } T _atNXYZ(const int pos, const int x, const int y, const int z, const int c=0) const { - return _data[pos<0?0:(pos>=(int)_width?(int)_width-1:pos)].atXYZ(x,y,z,c); + return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atXYZ(x,y,z,c); } //! Access to pixel value with Dirichlet boundary conditions for the 3 first coordinates (\c pos, \c x,\c y). @@ -45549,12 +46364,12 @@ namespace cimg_library_suffixed { \param out_value Default value returned if \c offset is outside image bounds. \note list.atNXYZ(p,x,y,z,c); is equivalent to list[p].atXYZ(x,y,z,c);. **/ - T& atNXY(const int pos, const int x, const int y, const int z, const int c, const T out_value) { + T& atNXY(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].atXY(x,y,z,c,out_value); } //! Access to pixel value with Dirichlet boundary conditions for the 3 first 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 { + 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); } @@ -45587,11 +46402,11 @@ namespace cimg_library_suffixed { } T& _atNXY(const int pos, const int x, const int y, const int z=0, const int c=0) { - return _data[pos<0?0:(pos>=(int)_width?(int)_width-1:pos)].atXY(x,y,z,c); + return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atXY(x,y,z,c); } T _atNXY(const int pos, const int x, const int y, const int z=0, const int c=0) const { - return _data[pos<0?0:(pos>=(int)_width?(int)_width-1:pos)].atXY(x,y,z,c); + return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atXY(x,y,z,c); } //! Access to pixel value with Dirichlet boundary conditions for the 2 first coordinates (\c pos,\c x). @@ -45604,12 +46419,12 @@ namespace cimg_library_suffixed { \param out_value Default value returned if \c offset is outside image bounds. \note list.atNXYZ(p,x,y,z,c); is equivalent to list[p].atXYZ(x,y,z,c);. **/ - T& atNX(const int pos, const int x, const int y, const int z, const int c, const T out_value) { + 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); } //! Access to pixel value with Dirichlet boundary conditions for the 2 first coordinates (\c pos,\c x) \const. - T atNX(const int pos, const int x, const int y, const int z, const int c, const T out_value) const { + T atNX(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].atX(x,y,z,c,out_value); } @@ -45642,11 +46457,11 @@ namespace cimg_library_suffixed { } T& _atNX(const int pos, const int x, const int y=0, const int z=0, const int c=0) { - return _data[pos<0?0:(pos>=(int)_width?(int)_width-1:pos)].atX(x,y,z,c); + return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atX(x,y,z,c); } T _atNX(const int pos, const int x, const int y=0, const int z=0, const int c=0) const { - return _data[pos<0?0:(pos>=(int)_width?(int)_width-1:pos)].atX(x,y,z,c); + return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)].atX(x,y,z,c); } //! Access to pixel value with Dirichlet boundary conditions for the first coordinate (\c pos). @@ -45659,12 +46474,12 @@ namespace cimg_library_suffixed { \param out_value Default value returned if \c offset is outside image bounds. \note list.atNXYZ(p,x,y,z,c); is equivalent to list[p].atXYZ(x,y,z,c);. **/ - T& atN(const int pos, const int x, const int y, const int z, const int c, const T out_value) { + T& atN(const int pos, const int x, const int y, const int z, const int c, const T& out_value) { return (pos<0 || pos>=(int)_width)?(cimg::temporary(out_value)=out_value):(*this)(pos,x,y,z,c); } //! Access to pixel value with Dirichlet boundary conditions for the first 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 { + 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); } @@ -45695,11 +46510,11 @@ namespace cimg_library_suffixed { } T& _atN(const int pos, const int x=0, const int y=0, const int z=0, const int c=0) { - return _data[pos<0?0:(pos>=(int)_width?(int)_width-1:pos)](x,y,z,c); + return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)](x,y,z,c); } T _atN(const int pos, const int x=0, const int y=0, const int z=0, const int c=0) const { - return _data[pos<0?0:(pos>=(int)_width?(int)_width-1:pos)](x,y,z,c); + return _data[pos<0?0:(pos>=(int)_width?(int)_width - 1:pos)](x,y,z,c); } //! Return a C-string containing the values of all images in the instance list. @@ -45711,12 +46526,12 @@ namespace cimg_library_suffixed { CImg value_string(const char separator=',', const unsigned int max_size=0) const { if (is_empty()) return CImg(1,1,1,1,0); CImgList items; - for (unsigned int l = 0; l<_width-1; ++l) { + for (unsigned int l = 0; l<_width - 1; ++l) { CImg item = _data[l].value_string(separator,0); item.back() = separator; item.move_to(items); } - _data[_width-1].value_string(separator,0).move_to(items); + _data[_width - 1].value_string(separator,0).move_to(items); CImg res; (items>'x').move_to(res); if (max_size) { res.crop(0,max_size); res(max_size) = 0; } return res; @@ -45965,7 +46780,7 @@ namespace cimg_library_suffixed { bool contains(const CImg& img, t& n) const { if (is_empty()) return false; const CImg *const ptr = &img; - cimglist_for(*this,i) if (_data+i==ptr) { n = (t)i; return true; } + cimglist_for(*this,i) if (_data + i==ptr) { n = (t)i; return true; } return false; } @@ -46179,13 +46994,14 @@ namespace cimg_library_suffixed { } else { if (new_data) { // Insert with re-allocation. if (npos) std::memcpy(new_data,_data,sizeof(CImg)*npos); - if (npos!=_width-1) std::memcpy(new_data+npos+1,_data+npos,sizeof(CImg)*(_width-1-npos)); - std::memset(_data,0,sizeof(CImg)*(_width-1)); + if (npos!=_width - 1) std::memcpy(new_data + npos + 1,_data + npos,sizeof(CImg)*(_width - 1 - npos)); + std::memset(_data,0,sizeof(CImg)*(_width - 1)); delete[] _data; _data = new_data; - } else if (npos!=_width-1) - std::memmove(_data+npos+1,_data+npos,sizeof(CImg)*(_width-1-npos)); // Insert without re-allocation. - _data[npos]._width = _data[npos]._height = _data[npos]._depth = _data[npos]._spectrum = 0; _data[npos]._data = 0; + } else if (npos!=_width - 1) // Insert without re-allocation. + std::memmove(_data + npos + 1,_data + npos,sizeof(CImg)*(_width - 1 - npos)); + _data[npos]._width = _data[npos]._height = _data[npos]._depth = _data[npos]._spectrum = 0; + _data[npos]._data = 0; _data[npos] = img; } return *this; @@ -46216,7 +47032,7 @@ namespace cimg_library_suffixed { else { if (new_data) { // Insert with re-allocation. if (npos) std::memcpy(new_data,_data,sizeof(CImg)*npos); - if (npos!=_width-1) std::memcpy(new_data+npos+1,_data+npos,sizeof(CImg)*(_width-1-npos)); + if (npos!=_width - 1) std::memcpy(new_data + npos + 1,_data + npos,sizeof(CImg)*(_width - 1 - npos)); if (is_shared && img) { new_data[npos]._width = img._width; new_data[npos]._height = img._height; @@ -46229,11 +47045,11 @@ namespace cimg_library_suffixed { new_data[npos]._data = 0; new_data[npos] = img; } - std::memset(_data,0,sizeof(CImg)*(_width-1)); + std::memset(_data,0,sizeof(CImg)*(_width - 1)); delete[] _data; _data = new_data; } else { // Insert without re-allocation. - if (npos!=_width-1) std::memmove(_data+npos+1,_data+npos,sizeof(CImg)*(_width-1-npos)); + if (npos!=_width - 1) std::memmove(_data + npos + 1,_data + npos,sizeof(CImg)*(_width - 1 - npos)); if (is_shared && img) { _data[npos]._width = img._width; _data[npos]._height = img._height; @@ -46288,7 +47104,7 @@ namespace cimg_library_suffixed { if (!n) return *this; const unsigned int npos = pos==~0U?_width:pos; insert(img,npos,is_shared); - for (unsigned int i = 1; i CImgList& insert(const CImgList& list, const unsigned int pos=~0U, const bool is_shared=false) { const unsigned int npos = pos==~0U?_width:pos; - if ((void*)this!=(void*)&list) cimglist_for(list,l) insert(list[l],npos+l,is_shared); + if ((void*)this!=(void*)&list) cimglist_for(list,l) insert(list[l],npos + l,is_shared); else insert(CImgList(list),npos,is_shared); return *this; } @@ -46351,7 +47167,7 @@ namespace cimg_library_suffixed { const unsigned int npos1 = pos1=_width) throw CImgArgumentException(_cimglist_instance "remove(): Invalid remove request at positions %u->%u.", @@ -46368,16 +47184,16 @@ namespace cimg_library_suffixed { const unsigned int nb = 1 + npos2 - npos1; if (!(_width-=nb)) return assign(); if (_width>(_allocated_width>>2) || _allocated_width<=16) { // Removing items without reallocation. - if (npos1!=_width) std::memmove(_data+npos1,_data+npos2+1,sizeof(CImg)*(_width - npos1)); + if (npos1!=_width) std::memmove(_data + npos1,_data + npos2 + 1,sizeof(CImg)*(_width - npos1)); std::memset(_data + _width,0,sizeof(CImg)*nb); } else { // Removing items with reallocation. _allocated_width>>=2; while (_allocated_width>16 && _width<(_allocated_width>>1)) _allocated_width>>=1; CImg *const new_data = new CImg[_allocated_width]; if (npos1) std::memcpy(new_data,_data,sizeof(CImg)*npos1); - if (npos1!=_width) std::memcpy(new_data+npos1,_data+npos2+1,sizeof(CImg)*(_width-npos1)); - if (_width!=_allocated_width) std::memset(new_data+_width,0,sizeof(_allocated_width - _width)); - std::memset(_data,0,sizeof(CImg)*(_width+nb)); + if (npos1!=_width) std::memcpy(new_data + npos1,_data + npos2 + 1,sizeof(CImg)*(_width - npos1)); + if (_width!=_allocated_width) std::memset(new_data + _width,0,sizeof(CImg)*(_allocated_width - _width)); + std::memset(_data,0,sizeof(CImg)*(_width + nb)); delete[] _data; _data = new_data; } @@ -46407,7 +47223,7 @@ namespace cimg_library_suffixed { /** **/ CImgList& remove() { - return remove(_width-1); + return remove(_width - 1); } //! Remove last image \newinstance. @@ -46417,7 +47233,7 @@ namespace cimg_library_suffixed { //! Reverse list order. CImgList& reverse() { - for (unsigned int l = 0; l<_width/2; ++l) (*this)[l].swap((*this)[_width-1-l]); + for (unsigned int l = 0; l<_width/2; ++l) (*this)[l].swap((*this)[_width - 1 - l]); return *this; } @@ -46442,8 +47258,8 @@ namespace cimg_library_suffixed { "images(): Specified sub-list indices (%u->%u) are out of bounds.", cimglist_instance, pos0,pos1); - CImgList res(pos1-pos0+1); - cimglist_for(res,l) res[l].assign(_data[pos0+l]); + CImgList res(pos1 - pos0 + 1); + cimglist_for(res,l) res[l].assign(_data[pos0 + l]); return res; } @@ -46458,8 +47274,8 @@ namespace cimg_library_suffixed { "get_shared_images(): Specified sub-list indices (%u->%u) are out of bounds.", cimglist_instance, pos0,pos1); - CImgList res(pos1-pos0+1); - cimglist_for(res,l) res[l].assign(_data[pos0+l],_data[pos0+l]?true:false); + CImgList res(pos1 - pos0 + 1); + cimglist_for(res,l) res[l].assign(_data[pos0 + l],_data[pos0 + l]?true:false); return res; } @@ -46470,8 +47286,8 @@ namespace cimg_library_suffixed { "get_shared_images(): Specified sub-list indices (%u->%u) are out of bounds.", cimglist_instance, pos0,pos1); - CImgList res(pos1-pos0+1); - cimglist_for(res,l) res[l].assign(_data[pos0+l],_data[pos0+l]?true:false); + CImgList res(pos1 - pos0 + 1); + cimglist_for(res,l) res[l].assign(_data[pos0 + l],_data[pos0 + l]?true:false); return res; } @@ -46500,9 +47316,9 @@ namespace cimg_library_suffixed { if (res) cimglist_for(*this,l) { const CImg& img = (*this)[l]; if (img) res.draw_image(pos, - (int)(align*(dy-img._height)), - (int)(align*(dz-img._depth)), - (int)(align*(dc-img._spectrum)), + (int)(align*(dy - img._height)), + (int)(align*(dz - img._depth)), + (int)(align*(dc - img._spectrum)), img); pos+=img._width; } @@ -46520,10 +47336,10 @@ namespace cimg_library_suffixed { res.assign(dx,dy,dz,dc,0); if (res) cimglist_for(*this,l) { const CImg& img = (*this)[l]; - if (img) res.draw_image((int)(align*(dx-img._width)), + if (img) res.draw_image((int)(align*(dx - img._width)), pos, - (int)(align*(dz-img._depth)), - (int)(align*(dc-img._spectrum)), + (int)(align*(dz - img._depth)), + (int)(align*(dc - img._spectrum)), img); pos+=img._height; } @@ -46541,10 +47357,10 @@ namespace cimg_library_suffixed { res.assign(dx,dy,dz,dc,0); if (res) cimglist_for(*this,l) { const CImg& img = (*this)[l]; - if (img) res.draw_image((int)(align*(dx-img._width)), - (int)(align*(dy-img._height)), + if (img) res.draw_image((int)(align*(dx - img._width)), + (int)(align*(dy - img._height)), pos, - (int)(align*(dc-img._spectrum)), + (int)(align*(dc - img._spectrum)), img); pos+=img._depth; } @@ -46562,9 +47378,9 @@ namespace cimg_library_suffixed { res.assign(dx,dy,dz,dc,0); if (res) cimglist_for(*this,l) { const CImg& img = (*this)[l]; - if (img) res.draw_image((int)(align*(dx-img._width)), - (int)(align*(dy-img._height)), - (int)(align*(dz-img._depth)), + 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; @@ -46579,12 +47395,12 @@ namespace cimg_library_suffixed { \param axis Axis to split images along. \param nb Number of spliting parts for each image. **/ - CImgList& split(const char axis, const int nb=0) { + CImgList& split(const char axis, const int nb=-1) { return get_split(axis,nb).move_to(*this); } //! Return a list where each image has been split along the specified axis \newinstance. - CImgList get_split(const char axis, const int nb=0) const { + CImgList get_split(const char axis, const int nb=-1) const { CImgList res; cimglist_for(*this,l) _data[l].get_split(axis,nb).move_to(res,~0U); return res; @@ -46630,7 +47446,7 @@ namespace cimg_library_suffixed { /** **/ CImgList& pop_back() { - return remove(_width-1); + return remove(_width - 1); } //! Remove first image. @@ -46645,7 +47461,7 @@ namespace cimg_library_suffixed { \param iter Iterator pointing to the image to remove. **/ CImgList& erase(const iterator iter) { - return remove(iter-_data); + return remove(iter - _data); } //@} @@ -46746,11 +47562,12 @@ namespace cimg_library_suffixed { onexone(1,1,1,1,0), &src = _data[ind]?_data[ind]:onexone; CImg res; - src.__get_select(disp,old_normalization,(src._width-1)/2,(src._height-1)/2,(src._depth-1)/2).move_to(res); + src.__get_select(disp,old_normalization,(src._width - 1)/2,(src._height - 1)/2,(src._depth - 1)/2). + move_to(res); const unsigned int h = CImgDisplay::_fitscreen(res._width,res._height,1,128,-85,true); res.resize(x - x0,cimg::max(32U,h*disp._height/max_height),1,res._spectrum==1?3:-100); positions(ind,0) = positions(ind,2) = (int)x0; - positions(ind,1) = positions(ind,3) = (int)(align*(visu0.height()-res.height())); + positions(ind,1) = positions(ind,3) = (int)(align*(visu0.height() - res.height())); positions(ind,2)+=res._width; positions(ind,3)+=res._height - 1; visu0.draw_image(positions(ind,0),positions(ind,1),res); @@ -46758,11 +47575,10 @@ namespace cimg_library_suffixed { const unsigned int y0 = y; ind = indices[y]; while (y - &src = _data[ind], - _img2d = src._depth>1?src.get_projections2d((src._width-1)/2,(src._height-1)/2,(src._depth-1)/2): - CImg(), - &img2d = _img2d?_img2d:src; + const CImg &src = _data[ind]; + const CImg + img2d = src._depth>1?src.get_projections2d((src._width - 1)/2,(src._height - 1)/2,(src._depth - 1)/2): + cimg::type::string()==cimg::type::string()?src.get_shared():src; CImg res = old_normalization==1 || (old_normalization==3 && cimg::type::string()!=cimg::type::string())? CImg(img2d.get_normalize(0,255)): @@ -46770,7 +47586,7 @@ namespace cimg_library_suffixed { if (res._spectrum>3) res.channels(0,2); const unsigned int w = CImgDisplay::_fitscreen(res._width,res._height,1,128,-85,false); res.resize(cimg::max(32U,w*disp._width/max_width),y - y0,1,res._spectrum==1?3:-100); - positions(ind,0) = positions(ind,2) = (int)(align*(visu0.width()-res.width())); + positions(ind,0) = positions(ind,2) = (int)(align*(visu0.width() - res.width())); positions(ind,1) = positions(ind,3) = (int)y0; positions(ind,2)+=res._width - 1; positions(ind,3)+=res._height; @@ -46792,16 +47608,16 @@ namespace cimg_library_suffixed { visu.draw_rectangle(positions(ind,0),positions(ind,1),positions(ind,2),positions(ind,3), foreground_color,0.9f,0xAAAAAAAA); } - const int yt = (int)text_down?visu.height()-13:0; + const int yt = (int)text_down?visu.height() - 13:0; if (is_clicked) visu.draw_text(0,yt," Images #%u - #%u, Size = %u", foreground_color,background_color,0.7f,13, orig + indm,orig + indM,indM - indm + 1); else visu.draw_text(0,yt," Image #%u (%u,%u,%u,%u)",foreground_color,background_color,0.7f,13, orig + indice0, - _data[orig+indice0]._width, - _data[orig+indice0]._height, - _data[orig+indice0]._depth, - _data[orig+indice0]._spectrum); + _data[indice0]._width, + _data[indice0]._height, + _data[indice0]._depth, + _data[indice0]._spectrum); update_display = true; } else visu.assign(); } @@ -46901,7 +47717,7 @@ namespace cimg_library_suffixed { } if (disp.is_resized()) { disp.resize(false); visu0.assign(); } if (ym>=0 && ym<13) { if (!text_down) { visu.assign(); text_down = true; }} - else if (ym>=visu.height()-13) { if(text_down) { visu.assign(); text_down = false; }} + else if (ym>=visu.height() - 13) { if(text_down) { visu.assign(); text_down = false; }} } CImg res(1,2,1,1,-1); if (is_selected) { @@ -46926,15 +47742,16 @@ namespace cimg_library_suffixed { cimglist_instance); if (!cimg::strncasecmp(filename,"http://",7) || !cimg::strncasecmp(filename,"https://",8)) { - char filename_local[1024] = { 0 }; - load(cimg::load_network_external(filename,filename_local)); + CImg filename_local(256); + load(cimg::load_network(filename,filename_local)); std::remove(filename_local); return *this; } + const bool is_stdin = *filename=='-' && (!filename[1] || filename[1]=='.'); const char *const ext = cimg::split_filename(filename); const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); try { #ifdef cimglist_load_plugin cimglist_load_plugin(filename); @@ -46993,32 +47810,46 @@ namespace cimg_library_suffixed { !cimg::strcasecmp(ext,"vob") || !cimg::strcasecmp(ext,"wmv") || !cimg::strcasecmp(ext,"xvid") || - !cimg::strcasecmp(ext,"mpeg")) load_ffmpeg(filename); + !cimg::strcasecmp(ext,"mpeg")) load_video(filename); else if (!cimg::strcasecmp(ext,"gz")) load_gzip_external(filename); else throw CImgIOException("CImgList<%s>::load()", pixel_type()); } catch (CImgIOException&) { + std::FILE *file = 0; + if (!is_stdin) try { + file = cimg::fopen(filename,"rb"); + } catch (CImgIOException&) { + cimg::exception_mode(omode); + throw CImgIOException(_cimglist_instance + "load(): Failed to open file '%s'.", + cimglist_instance, + filename); + } + try { - cimg::fclose(cimg::fopen(filename,"rb")); - } catch (CImgIOException&) { - cimg::exception_mode() = omode; - throw CImgIOException(_cimglist_instance - "load(): Failed to open file '%s'.", - cimglist_instance, - filename); - } - assign(1); - try { - _data->load(filename); + if (!is_stdin) { + const char *const f_type = cimg::ftype(file,filename); + std::fclose(file); + if (!cimg::strcasecmp(f_type,"gif")) load_gif_external(filename); + else if (!cimg::strcasecmp(f_type,"tif")) load_tiff(filename); + else throw CImgIOException("CImgList<%s>::load()", + pixel_type()); + } else throw CImgIOException("CImgList<%s>::load()", + pixel_type()); } catch (CImgIOException&) { - cimg::exception_mode() = omode; + assign(1); + try { + _data->load(filename); + } catch (CImgIOException&) { + cimg::exception_mode(omode); throw CImgIOException(_cimglist_instance "load(): Failed to recognize format of file '%s'.", cimglist_instance, filename); + } } } - cimg::exception_mode() = omode; + cimg::exception_mode(omode); return *this; } @@ -47062,8 +47893,8 @@ namespace cimg_library_suffixed { unsigned long destlen = (unsigned long)raw.size()*sizeof(Tss); \ uncompress((Bytef*)raw._data,&destlen,cbuf,csiz); \ delete[] cbuf; \ - const Tss *ptrs = raw._data; \ - for (unsigned long off = raw.size(); off; --off) *(ptrd++) = (T)*(ptrs++); \ + if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw.size()); \ + raw.move_to(img); \ } #else #define _cimgz_load_cimg_case(Tss) \ @@ -47076,26 +47907,28 @@ namespace cimg_library_suffixed { #define _cimg_load_cimg_case(Ts,Tss) \ if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \ for (unsigned int l = 0; l=0) tmp[j++] = (char)i; tmp[j] = 0; \ + j = 0; while ((i=std::fgetc(nfile))!='\n' && i>=0 && j<255) tmp[j++] = (char)i; tmp[j] = 0; \ W = H = D = C = 0; csiz = 0; \ - if ((err = std::sscanf(tmp,"%u %u %u %u #%u",&W,&H,&D,&C,&csiz))<4) \ + if ((err = cimg_sscanf(tmp,"%u %u %u %u #%lu",&W,&H,&D,&C,&csiz))<4) \ throw CImgIOException(_cimglist_instance \ - "load_cimg(): Invalid specified size (%u,%u,%u,%u) of image %u in file '%s'", \ + "load_cimg(): Invalid specified size (%u,%u,%u,%u) of image %u in file '%s'.", \ cimglist_instance, \ W,H,D,C,l,filename?filename:("(FILE*)")); \ if (W*H*D*C>0) { \ CImg raw; \ CImg &img = _data[l]; \ - img.assign(W,H,D,C); \ - T *ptrd = img._data; \ if (err==5) _cimgz_load_cimg_case(Tss) \ - else for (long to_read = (long)img.size(); to_read>0; ) { \ - raw.assign(cimg::min(to_read,cimg_iobuffer)); \ - cimg::fread(raw._data,raw._width,nfile); \ - if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw._width); \ - to_read-=raw._width; \ - const Tss *ptrs = raw._data; \ - for (unsigned long off = (unsigned long)raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); \ + else { \ + img.assign(W,H,D,C); \ + T *ptrd = img._data; \ + for (unsigned long to_read = img.size(); to_read; ) { \ + raw.assign(cimg::min(to_read,cimg_iobuffer)); \ + cimg::fread(raw._data,raw._width,nfile); \ + if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw.size()); \ + const Tss *ptrs = raw._data; \ + for (unsigned long off = (unsigned long)raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); \ + to_read-=raw._width; \ + } \ } \ } \ } \ @@ -47107,16 +47940,19 @@ namespace cimg_library_suffixed { "load_cimg(): Specified filename is (null).", cimglist_instance); - const int cimg_iobuffer = 12*1024*1024; + const unsigned long cimg_iobuffer = 24*1024*1024; std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); bool loaded = false, endian = cimg::endianness(); - char tmp[256] = { 0 }, str_pixeltype[256] = { 0 }, str_endian[256] = { 0 }; - unsigned int j, err, N = 0, W, H, D, C, csiz; - int i; + CImg tmp(256), str_pixeltype(256), str_endian(256); + *tmp = *str_pixeltype = *str_endian = 0; + unsigned int j, N = 0, W, H, D, C; + unsigned long csiz; + int i, err; do { - j = 0; while ((i=std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = 0; - } while (*tmp=='#' && i!=EOF); - err = std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian); + j = 0; while ((i=std::fgetc(nfile))!='\n' && i>=0 && j<255) tmp[j++] = (char)i; tmp[j] = 0; + } while (*tmp=='#' && i>=0); + err = cimg_sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]", + &N,str_pixeltype._data,str_endian._data); if (err<2) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimglist_instance @@ -47142,12 +47978,13 @@ namespace cimg_library_suffixed { _cimg_load_cimg_case("long",long); _cimg_load_cimg_case("float",float); _cimg_load_cimg_case("double",double); + if (!loaded) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimglist_instance "load_cimg(): Unsupported pixel type '%s' for file '%s'.", cimglist_instance, - str_pixeltype,filename?filename:"(FILE*)"); + str_pixeltype._data,filename?filename:"(FILE*)"); } if (!file) cimg::fclose(nfile); return *this; @@ -47207,17 +48044,17 @@ namespace cimg_library_suffixed { } CImgList& _load_cimg(std::FILE *const file, const char *const filename, - const unsigned int n0, const unsigned int n1, - const unsigned int x0, const unsigned int y0, + const unsigned int n0, const unsigned int n1, + const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0, - const unsigned int x1, const unsigned int y1, + const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int c1) { #define _cimg_load_cimg_case2(Ts,Tss) \ if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \ for (unsigned int l = 0; l<=nn1; ++l) { \ j = 0; while ((i=std::fgetc(nfile))!='\n' && i>=0) tmp[j++] = (char)i; tmp[j] = 0; \ W = H = D = C = 0; \ - if (std::sscanf(tmp,"%u %u %u %u",&W,&H,&D,&C)!=4) \ + if (cimg_sscanf(tmp,"%u %u %u %u",&W,&H,&D,&C)!=4) \ throw CImgIOException(_cimglist_instance \ "load_cimg(): Invalid specified size (%u,%u,%u,%u) of image %u in file '%s'", \ cimglist_instance, \ @@ -47226,10 +48063,10 @@ namespace cimg_library_suffixed { if (l=W || ny0>=H || nz0>=D || nc0>=C) std::fseek(nfile,W*H*D*C*sizeof(Tss),SEEK_CUR); \ else { \ const unsigned int \ - _nx1 = nx1==~0U?W-1:nx1, \ - _ny1 = ny1==~0U?H-1:ny1, \ - _nz1 = nz1==~0U?D-1:nz1, \ - _nc1 = nc1==~0U?C-1:nc1; \ + _nx1 = nx1==~0U?W - 1:nx1, \ + _ny1 = ny1==~0U?H - 1:ny1, \ + _nz1 = nz1==~0U?D - 1:nz1, \ + _nc1 = nc1==~0U?C - 1:nc1; \ if (_nx1>=W || _ny1>=H || _nz1>=D || _nc1>=C) \ throw CImgArgumentException(_cimglist_instance \ "load_cimg(): Invalid specified coordinates " \ @@ -47256,16 +48093,16 @@ namespace cimg_library_suffixed { if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw._width); \ const Tss *ptrs = raw._data; \ for (unsigned int off = raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); \ - const unsigned int skipxe = (W-1-_nx1)*sizeof(Tss); \ + const unsigned int skipxe = (W - 1 - _nx1)*sizeof(Tss); \ if (skipxe) std::fseek(nfile,skipxe,SEEK_CUR); \ } \ - const unsigned int skipye = (H-1-_ny1)*W*sizeof(Tss); \ + const unsigned int skipye = (H - 1 - _ny1)*W*sizeof(Tss); \ if (skipye) std::fseek(nfile,skipye,SEEK_CUR); \ } \ - const unsigned int skipze = (D-1-_nz1)*W*H*sizeof(Tss); \ + const unsigned int skipze = (D - 1 - _nz1)*W*H*sizeof(Tss); \ if (skipze) std::fseek(nfile,skipze,SEEK_CUR); \ } \ - const unsigned int skipve = (C-1-_nc1)*W*H*D*sizeof(Tss); \ + const unsigned int skipve = (C - 1 - _nc1)*W*H*D*sizeof(Tss); \ if (skipve) std::fseek(nfile,skipve,SEEK_CUR); \ } \ } \ @@ -47286,11 +48123,13 @@ namespace cimg_library_suffixed { std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); bool loaded = false, endian = cimg::endianness(); - char tmp[256] = { 0 }, str_pixeltype[256] = { 0 }, str_endian[256] = { 0 }; - unsigned int j, err, N, W, H, D, C; - int i; + CImg tmp(256), str_pixeltype(256), str_endian(256); + *tmp = *str_pixeltype = *str_endian = 0; + unsigned int j, N, W, H, D, C; + int i, err; j = 0; while((i=std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = 0; - err = std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian); + err = cimg_sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]", + &N,str_pixeltype._data,str_endian._data); if (err<2) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimglist_instance @@ -47300,14 +48139,14 @@ namespace cimg_library_suffixed { } if (!cimg::strncasecmp("little",str_endian,6)) endian = false; else if (!cimg::strncasecmp("big",str_endian,3)) endian = true; - nn1 = n1==~0U?N-1:n1; + nn1 = n1==~0U?N - 1:n1; if (nn1>=N) throw CImgArgumentException(_cimglist_instance "load_cimg(): Invalid specified coordinates [%u](%u,%u,%u,%u) -> [%u](%u,%u,%u,%u) " "because file '%s' contains only %u images.", cimglist_instance, n0,x0,y0,z0,c0,n1,x1,y1,z1,c1,filename?filename:"(FILE*)",N); - assign(1+nn1-n0); + assign(1 + nn1 - n0); _cimg_load_cimg_case2("bool",bool); _cimg_load_cimg_case2("unsigned_char",unsigned char); _cimg_load_cimg_case2("uchar",unsigned char); @@ -47328,7 +48167,7 @@ namespace cimg_library_suffixed { throw CImgIOException(_cimglist_instance "load_cimg(): Unsupported pixel type '%s' for file '%s'.", cimglist_instance, - str_pixeltype,filename?filename:"(FILE*)"); + str_pixeltype._data,filename?filename:"(FILE*)"); } if (!file) cimg::fclose(nfile); return *this; @@ -47344,32 +48183,33 @@ namespace cimg_library_suffixed { "load_parrec(): Specified filename is (null).", cimglist_instance); - char body[1024] = { 0 }, filenamepar[1024] = { 0 }, filenamerec[1024] = { 0 }; + CImg body(1024), filenamepar(1024), filenamerec(1024); + *body = *filenamepar = *filenamerec = 0; const char *const ext = cimg::split_filename(filename,body); if (!std::strcmp(ext,"par")) { - std::strncpy(filenamepar,filename,sizeof(filenamepar)-1); - cimg_snprintf(filenamerec,sizeof(filenamerec),"%s.rec",body); + std::strncpy(filenamepar,filename,filenamepar._width - 1); + cimg_snprintf(filenamerec,filenamerec._width,"%s.rec",body._data); } if (!std::strcmp(ext,"PAR")) { - std::strncpy(filenamepar,filename,sizeof(filenamepar)-1); - cimg_snprintf(filenamerec,sizeof(filenamerec),"%s.REC",body); + std::strncpy(filenamepar,filename,filenamepar._width - 1); + cimg_snprintf(filenamerec,filenamerec._width,"%s.REC",body._data); } if (!std::strcmp(ext,"rec")) { - std::strncpy(filenamerec,filename,sizeof(filenamerec)-1); - cimg_snprintf(filenamepar,sizeof(filenamepar),"%s.par",body); + std::strncpy(filenamerec,filename,filenamerec._width - 1); + cimg_snprintf(filenamepar,filenamepar._width,"%s.par",body._data); } if (!std::strcmp(ext,"REC")) { - std::strncpy(filenamerec,filename,sizeof(filenamerec)-1); - cimg_snprintf(filenamepar,sizeof(filenamepar),"%s.PAR",body); + std::strncpy(filenamerec,filename,filenamerec._width - 1); + cimg_snprintf(filenamepar,filenamepar._width,"%s.PAR",body._data); } std::FILE *file = cimg::fopen(filenamepar,"r"); // Parse header file CImgList st_slices; CImgList st_global; + CImg line(256); *line = 0; int err; - char line[256] = { 0 }; - do { err=std::fscanf(file,"%255[^\n]%*c",line); } while (err!=EOF && (*line=='#' || *line=='.')); + do { err = std::fscanf(file,"%255[^\n]%*c",line._data); } while (err!=EOF && (*line=='#' || *line=='.')); do { unsigned int sn,size_x,size_y,pixsize; float rs,ri,ss; @@ -47384,7 +48224,7 @@ namespace cimg_library_suffixed { if (size_y>vec[1]) vec[1] = size_y; vec[2] = sn; } - st_slices[st_slices._width-1][7] = (float)i; + st_slices[st_slices._width - 1][7] = (float)i; } } while (err==7); @@ -47492,9 +48332,9 @@ namespace cimg_library_suffixed { } CImgList& _load_yuv(std::FILE *const file, const char *const filename, - const unsigned int size_x, const unsigned int size_y, - const unsigned int first_frame, const unsigned int last_frame, - const unsigned int step_frame, const bool yuv2rgb) { + const unsigned int size_x, const unsigned int size_y, + const unsigned int first_frame, const unsigned int last_frame, + const unsigned int step_frame, const bool yuv2rgb) { if (!filename && !file) throw CImgArgumentException(_cimglist_instance "load_yuv(): Specified filename is (null).", @@ -47511,9 +48351,9 @@ namespace cimg_library_suffixed { size_x,size_y,filename?filename:"(FILE*)"); const unsigned int - nfirst_frame = first_frame tmp(size_x,size_y,1,3), UV(size_x/2,size_y/2,1,2); std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); @@ -47557,12 +48397,12 @@ namespace cimg_library_suffixed { } else { cimg_forXY(UV,x,y) { const int x2 = x*2, y2 = y*2; - tmp(x2,y2,1) = tmp(x2+1,y2,1) = tmp(x2,y2+1,1) = tmp(x2+1,y2+1,1) = UV(x,y,0); - tmp(x2,y2,2) = tmp(x2+1,y2,2) = tmp(x2,y2+1,2) = tmp(x2+1,y2+1,2) = UV(x,y,1); + tmp(x2,y2,1) = tmp(x2 + 1,y2,1) = tmp(x2,y2 + 1,1) = tmp(x2 + 1,y2 + 1,1) = UV(x,y,0); + tmp(x2,y2,2) = tmp(x2 + 1,y2,2) = tmp(x2,y2 + 1,2) = tmp(x2 + 1,y2 + 1,2) = UV(x,y,1); } if (yuv2rgb) tmp.YCbCrtoRGB(); insert(tmp); - if (nstep_frame>1) std::fseek(nfile,(nstep_frame-1)*(size_x*size_y + size_x*size_y/2),SEEK_CUR); + if (nstep_frame>1) std::fseek(nfile,(nstep_frame - 1)*(size_x*size_y + size_x*size_y/2),SEEK_CUR); } } } @@ -47570,179 +48410,168 @@ namespace cimg_library_suffixed { cimg::warn(_cimglist_instance "load_yuv(): Frame %d not reached since only %u frames were found in file '%s'.", cimglist_instance, - nlast_frame,frame-1,filename?filename:"(FILE*)"); + nlast_frame,frame - 1,filename?filename:"(FILE*)"); if (!file) cimg::fclose(nfile); return *this; } - //! Load an image from a video file, using ffmpeg libraries. + //! Load an image from a video file, using OpenCV library. /** \param filename Filename, as a C-string. \param first_frame Index of the first frame to read. \param last_frame Index of the last frame to read. \param step_frame Step value for frame reading. - \param pixel_format To be documented. - \param resume To be documented. - **/ - // This piece of code has been firstly created by David Starweather (starkdg(at)users(dot)sourceforge(dot)net) - // I modified it afterwards for direct inclusion in the library core. - CImgList& load_ffmpeg(const char *const filename, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false) { - if (!filename) - throw CImgArgumentException(_cimglist_instance - "load_ffmpeg(): Specified filename is (null).", - cimglist_instance); - - const unsigned int - nfirst_frame = first_frame1) || (resume && (pixel_format || !pixel_format))) + \note If step_frame==0, the current video stream is open or released without any frames read. + **/ + CImgList& load_video(const char *const filename, + const unsigned int first_frame=0, const unsigned int last_frame=~0U, + const unsigned int step_frame=1) { +#ifndef cimg_use_opencv + if (first_frame || last_frame!=~0U || step_frame>1) throw CImgArgumentException(_cimglist_instance - "load_ffmpeg(): Unable to load sub-frames from file '%s' unless libffmpeg " - "is enabled.", - cimglist_instance, - filename); - + "load_video() : File '%s', arguments 'first_frame', 'last_frame' " + "and 'step_frame' can be only set when using OpenCV " + "(-Dcimg_use_opencv must be enabled).", + cimglist_instance,filename); return load_ffmpeg_external(filename); #else - const PixelFormat ffmpeg_pixfmt = pixel_format?PIX_FMT_RGB24:PIX_FMT_GRAY8; - avcodec_register_all(); - av_register_all(); - static AVFormatContext *format_ctx = 0; - static AVCodecContext *codec_ctx = 0; - static AVCodec *codec = 0; - static AVFrame *avframe = avcodec_alloc_frame(), *converted_frame = avcodec_alloc_frame(); - static int vstream = 0; - - if (resume) { - if (!format_ctx || !codec_ctx || !codec || !avframe || !converted_frame) + static CvCapture *captures[32] = { 0 }; + static CImgList filenames(32); + static CImg positions(32,1,1,1,0); + static int last_used_index = -1; + + // Detect if a video capture 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); + + // Release stream if needed. + if (!step_frame || (index>=0 && positions[index]>first_frame)) { + if (index>=0) { + cimg::mutex(9); + cvReleaseCapture(&captures[index]); + captures[index] = 0; filenames[index].assign(); positions[index] = 0; + if (last_used_index==index) last_used_index = -1; + index = -1; + cimg::mutex(9,0); + } else + if (filename) + cimg::warn(_cimglist_instance + "load_video() : File '%s', opened video stream associated with filename not found.", + cimglist_instance,filename); + else + cimg::warn(_cimglist_instance + "load_video() : No opened video stream found.", + cimglist_instance,filename); + if (!step_frame) return *this; + } + + // Find empty slot for capturing video stream. + if (index<0) { + if (!filename) throw CImgArgumentException(_cimglist_instance - "load_ffmpeg(): Failed to resume loading of file '%s', " - "due to unallocated FFMPEG structures.", - cimglist_instance, - filename); - } else { - // Open video file, find main video stream and codec. - if (format_ctx) avformat_close_input(&format_ctx); - if (avformat_open_input(&format_ctx,filename,0,0)!=0) + "load_video(): No already open video reader 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 - "load_ffmpeg(): Failed to open file '%s'.", - cimglist_instance, - filename); - - if (!avframe || !converted_frame || avformat_find_stream_info(format_ctx,NULL)<0) { - avformat_close_input(&format_ctx); format_ctx = 0; - return load_ffmpeg_external(filename); + "load_video(): File '%s', no video reader slots available. " + "You have to release some of your previously opened videos.", + cimglist_instance,filename); + cimg::mutex(9); + captures[index] = cvCaptureFromFile(filename); + CImg::string(filename).move_to(filenames[index]); + positions[index] = 0; + cimg::mutex(9,0); + if (!captures[index]) { + filenames[index].assign(); + std::fclose(cimg::fopen(filename,"rb")); // Check file availability. + throw CImgIOException(_cimglist_instance + "load_video(): File '%s', unable to detect format of video file.", + cimglist_instance,filename); } -#if cimg_verbosity>=3 - dump_format(format_ctx,0,0,0); -#endif + } - // Special command: Return informations on main video stream. - // as a vector 1x4 containing: (nb_frames,width,height,fps). - if (!first_frame && !last_frame && !step_frame) { - for (vstream = 0; vstream<(int)(format_ctx->nb_streams); ++vstream) - if (format_ctx->streams[vstream]->codec->codec_type==AVMEDIA_TYPE_VIDEO) break; - if (vstream==(int)format_ctx->nb_streams) assign(); - else { - CImgList timestamps; - int nb_frames; - AVPacket packet; - // Count frames and store timestamps. - for (nb_frames = 0; av_read_frame(format_ctx,&packet)>=0; av_free_packet(&packet)) - if (packet.stream_index==vstream) { - CImg::vector((double)packet.pts).move_to(timestamps); - ++nb_frames; - } - // Get frame with, height and fps. - const int - framew = format_ctx->streams[vstream]->codec->width, - frameh = format_ctx->streams[vstream]->codec->height; - const float - num = (float)(format_ctx->streams[vstream]->r_frame_rate).num, - den = (float)(format_ctx->streams[vstream]->r_frame_rate).den, - fps = num/den; - // Return infos as a list. - assign(2); - (*this)[0].assign(1,4).fill((T)nb_frames,(T)framew,(T)frameh,(T)fps); - (*this)[1] = (timestamps>'y'); - } - avformat_close_input(&format_ctx); format_ctx = 0; - return *this; - } + cimg::mutex(9); + const unsigned int nb_frames = (unsigned int)cimg::max(0.,cvGetCaptureProperty(captures[index], + CV_CAP_PROP_FRAME_COUNT)); + cimg::mutex(9,0); + assign(); - for (vstream = 0; vstream<(int)(format_ctx->nb_streams) && - format_ctx->streams[vstream]->codec->codec_type!=AVMEDIA_TYPE_VIDEO; ) ++vstream; - if (vstream==(int)format_ctx->nb_streams) { - avformat_close_input(&format_ctx); format_ctx = 0; - return load_ffmpeg_external(filename); - } - codec_ctx = format_ctx->streams[vstream]->codec; - codec = avcodec_find_decoder(codec_ctx->codec_id); - if (!codec) { - return load_ffmpeg_external(filename); + // Skip frames if necessary. + unsigned int &pos = positions[index]; + while (pos frame(src->width,src->height,1,3); + const int step = (int)(src->widthStep - 3*src->width); + const unsigned char* ptrs = (unsigned char*)src->imageData; + T *ptr_r = frame.data(0,0,0,0), *ptr_g = frame.data(0,0,0,1), *ptr_b = frame.data(0,0,0,2); + if (step>0) cimg_forY(frame,y) { + cimg_forX(frame,x) { *(ptr_b++) = (T)*(ptrs++); *(ptr_g++) = (T)*(ptrs++); *(ptr_r++) = (T)*(ptrs++); } + ptrs+=step; + } else for (unsigned long siz = (unsigned long)src->width*src->height; siz; --siz) { + *(ptr_b++) = (T)*(ptrs++); *(ptr_g++) = (T)*(ptrs++); *(ptr_r++) = (T)*(ptrs++); + } + frame.move_to(*this); + ++pos; + + bool skip_failed = false; + for (unsigned int i = 1; iwidth,codec_ctx->height); - uint8_t *const buffer = new uint8_t[numBytes]; - avpicture_fill((AVPicture *)converted_frame,buffer,ffmpeg_pixfmt,codec_ctx->width,codec_ctx->height); - const T foo = (T)0; - AVPacket packet; - for (unsigned int frame = 0, next_frame = nfirst_frame; - frame<=nlast_frame && av_read_frame(format_ctx,&packet)>=0; ) { - if (packet.stream_index==(int)vstream) { - int decoded = 0; -#if defined(AV_VERSION_INT) -#if LIBAVCODEC_VERSION_INTwidth,codec_ctx->height,codec_ctx->pix_fmt,codec_ctx->width, - codec_ctx->height,ffmpeg_pixfmt,1,0,0,0); - sws_scale(c,avframe->data,avframe->linesize,0,codec_ctx->height, - converted_frame->data,converted_frame->linesize); - if (ffmpeg_pixfmt==PIX_FMT_RGB24) { - CImg next_image(*converted_frame->data,3,codec_ctx->width,codec_ctx->height,1,true); - next_image._get_permute_axes("yzcx",foo).move_to(*this); - } else { - CImg next_image(*converted_frame->data,1,codec_ctx->width,codec_ctx->height,1,true); - next_image._get_permute_axes("yzcx",foo).move_to(*this); - } - next_frame+=nstep_frame; - } - ++frame; - } - av_free_packet(&packet); - if (next_frame>nlast_frame) break; - } + if (!src || (nb_frames && pos>=nb_frames)) { // Close video stream when necessary. + cimg::mutex(9); + cvReleaseCapture(&captures[index]); + captures[index] = 0; + filenames[index].assign(); + positions[index] = 0; + index = -1; + cimg::mutex(9,0); } - delete[] buffer; + + cimg::mutex(9); + last_used_index = index; + cimg::mutex(9,0); return *this; #endif } - //! Load an image from a video file, using ffmpeg libraries \newinstance. - static CImgList get_load_ffmpeg(const char *const filename, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, const bool pixel_format=true) { - return CImgList().load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format); + //! Load an image from a video file, using OpenCV library \newinstance. + static CImgList get_load_video(const char *const filename, + const unsigned int first_frame=0, const unsigned int last_frame=~0U, + const unsigned int step_frame=1) { + return CImgList().load_video(filename,first_frame,last_frame,step_frame); } //! Load an image from a video file using the external tool 'ffmpeg'. @@ -47755,38 +48584,39 @@ namespace cimg_library_suffixed { "load_ffmpeg_external(): Specified filename is (null).", cimglist_instance); std::fclose(cimg::fopen(filename,"rb")); // Check if file exists. - char command[1024] = { 0 }, filetmp[512] = { 0 }, filetmp2[512] = { 0 }; + CImg command(1024), filename_tmp(256), filename_tmp2(256); std::FILE *file = 0; do { - cimg_snprintf(filetmp,sizeof(filetmp),"%s%c%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); - cimg_snprintf(filetmp2,sizeof(filetmp2),"%s_000001.ppm",filetmp); - if ((file=std::fopen(filetmp2,"rb"))!=0) cimg::fclose(file); + cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s", + cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); + cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_000001.ppm",filename_tmp._data); + if ((file=std::fopen(filename_tmp2,"rb"))!=0) cimg::fclose(file); } while (file); - cimg_snprintf(filetmp2,sizeof(filetmp2),"%s_%%6d.ppm",filetmp); + cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_%%6d.ppm",filename_tmp._data); #if cimg_OS!=2 - cimg_snprintf(command,sizeof(command),"%s -i \"%s\" \"%s\" >/dev/null 2>&1", + cimg_snprintf(command,command._width,"%s -i \"%s\" \"%s\" >/dev/null 2>&1", cimg::ffmpeg_path(), CImg::string(filename)._system_strescape().data(), - CImg::string(filetmp2)._system_strescape().data()); + CImg::string(filename_tmp2)._system_strescape().data()); #else - cimg_snprintf(command,sizeof(command),"\"%s -i \"%s\" \"%s\"\" >NUL 2>&1", + cimg_snprintf(command,command._width,"\"%s -i \"%s\" \"%s\"\" >NUL 2>&1", cimg::ffmpeg_path(), CImg::string(filename)._system_strescape().data(), - CImg::string(filetmp2)._system_strescape().data()); + CImg::string(filename_tmp2)._system_strescape().data()); #endif cimg::system(command,0); const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); assign(); unsigned int i = 1; for (bool stop_flag = false; !stop_flag; ++i) { - cimg_snprintf(filetmp2,sizeof(filetmp2),"%s_%.6u.ppm",filetmp,i); + cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_%.6u.ppm",filename_tmp._data,i); CImg img; - try { img.load_pnm(filetmp2); } + try { img.load_pnm(filename_tmp2); } catch (CImgException&) { stop_flag = true; } - if (img) { img.move_to(*this); std::remove(filetmp2); } + if (img) { img.move_to(*this); std::remove(filename_tmp2); } } - cimg::exception_mode() = omode; + cimg::exception_mode(omode); if (is_empty()) throw CImgIOException(_cimglist_instance "load_ffmpeg_external(): Failed to open file '%s' with external command 'ffmpeg'.", @@ -47822,56 +48652,57 @@ namespace cimg_library_suffixed { } CImgList& _load_gif_external(const char *const filename, const bool use_graphicsmagick=false) { - char command[1024] = { 0 }, filetmp[512] = { 0 }, filetmp2[512] = { 0 }; + CImg command(1024), filename_tmp(256), filename_tmp2(256); std::FILE *file = 0; do { - cimg_snprintf(filetmp,sizeof(filetmp),"%s%c%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); - if (use_graphicsmagick) cimg_snprintf(filetmp2,sizeof(filetmp2),"%s.png.0",filetmp); - else cimg_snprintf(filetmp2,sizeof(filetmp2),"%s-0.png",filetmp); - if ((file=std::fopen(filetmp2,"rb"))!=0) cimg::fclose(file); + cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s", + cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); + if (use_graphicsmagick) cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s.png.0",filename_tmp._data); + else cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s-0.png",filename_tmp._data); + if ((file=std::fopen(filename_tmp2,"rb"))!=0) cimg::fclose(file); } while (file); #if cimg_OS!=2 - if (use_graphicsmagick) cimg_snprintf(command,sizeof(command),"%s convert \"%s\" \"%s.png\" >/dev/null 2>&1", + if (use_graphicsmagick) cimg_snprintf(command,command._width,"%s convert \"%s\" \"%s.png\" >/dev/null 2>&1", cimg::graphicsmagick_path(), CImg::string(filename)._system_strescape().data(), - CImg::string(filetmp)._system_strescape().data()); - else cimg_snprintf(command,sizeof(command),"%s \"%s\" \"%s.png\" >/dev/null 2>&1", + CImg::string(filename_tmp)._system_strescape().data()); + else cimg_snprintf(command,command._width,"%s \"%s\" \"%s.png\" >/dev/null 2>&1", cimg::imagemagick_path(), CImg::string(filename)._system_strescape().data(), - CImg::string(filetmp)._system_strescape().data()); + CImg::string(filename_tmp)._system_strescape().data()); #else - if (use_graphicsmagick) cimg_snprintf(command,sizeof(command),"\"%s convert \"%s\" \"%s.png\"\" >NUL 2>&1", + if (use_graphicsmagick) cimg_snprintf(command,command._width,"\"%s convert \"%s\" \"%s.png\"\" >NUL 2>&1", cimg::graphicsmagick_path(), CImg::string(filename)._system_strescape().data(), - CImg::string(filetmp)._system_strescape().data()); - else cimg_snprintf(command,sizeof(command),"\"%s \"%s\" \"%s.png\"\" >NUL 2>&1", + CImg::string(filename_tmp)._system_strescape().data()); + else cimg_snprintf(command,command._width,"\"%s \"%s\" \"%s.png\"\" >NUL 2>&1", cimg::imagemagick_path(), CImg::string(filename)._system_strescape().data(), - CImg::string(filetmp)._system_strescape().data()); + CImg::string(filename_tmp)._system_strescape().data()); #endif cimg::system(command,0); const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode() = 0; + cimg::exception_mode(0); assign(); // Try to read a single frame gif. - cimg_snprintf(filetmp2,sizeof(filetmp2),"%s.png",filetmp); + cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s.png",filename_tmp._data); CImg img; - try { img.load_png(filetmp2); } + try { img.load_png(filename_tmp2); } catch (CImgException&) { } - if (img) { img.move_to(*this); std::remove(filetmp2); } + if (img) { img.move_to(*this); std::remove(filename_tmp2); } else { // Try to read animated gif. unsigned int i = 0; for (bool stop_flag = false; !stop_flag; ++i) { - if (use_graphicsmagick) cimg_snprintf(filetmp2,sizeof(filetmp2),"%s.png.%u",filetmp,i); - else cimg_snprintf(filetmp2,sizeof(filetmp2),"%s-%u.png",filetmp,i); + if (use_graphicsmagick) cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s.png.%u",filename_tmp._data,i); + else cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s-%u.png",filename_tmp._data,i); CImg img; - try { img.load_png(filetmp2); } + try { img.load_png(filename_tmp2); } catch (CImgException&) { stop_flag = true; } - if (img) { img.move_to(*this); std::remove(filetmp2); } + if (img) { img.move_to(*this); std::remove(filename_tmp2); } } } - cimg::exception_mode() = omode; + cimg::exception_mode(omode); return *this; } @@ -47890,31 +48721,31 @@ namespace cimg_library_suffixed { "load_gzip_external(): Specified filename is (null).", cimglist_instance); std::fclose(cimg::fopen(filename,"rb")); // Check if file exists. - char command[1024] = { 0 }, filetmp[512] = { 0 }, body[512] = { 0 }; + CImg command(1024), filename_tmp(256), body(256); const char *ext = cimg::split_filename(filename,body), *ext2 = cimg::split_filename(body,0); std::FILE *file = 0; do { if (!cimg::strcasecmp(ext,"gz")) { - if (*ext2) cimg_snprintf(filetmp,sizeof(filetmp),"%s%c%s.%s", + 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(filetmp,sizeof(filetmp),"%s%c%s", + else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); } else { - if (*ext) cimg_snprintf(filetmp,sizeof(filetmp),"%s%c%s.%s", + 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(filetmp,sizeof(filetmp),"%s%c%s", + else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); } - if ((file=std::fopen(filetmp,"rb"))!=0) cimg::fclose(file); + if ((file=std::fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); } while (file); - cimg_snprintf(command,sizeof(command),"%s -c \"%s\" > \"%s\"", + cimg_snprintf(command,command._width,"%s -c \"%s\" > \"%s\"", cimg::gunzip_path(), CImg::string(filename)._system_strescape().data(), - CImg::string(filetmp)._system_strescape().data()); + CImg::string(filename_tmp)._system_strescape().data()); cimg::system(command); - if (!(file = std::fopen(filetmp,"rb"))) { + if (!(file = std::fopen(filename_tmp,"rb"))) { cimg::fclose(cimg::fopen(filename,"r")); throw CImgIOException(_cimglist_instance "load_gzip_external(): Failed to open file '%s'.", @@ -47922,8 +48753,8 @@ namespace cimg_library_suffixed { filename); } else cimg::fclose(file); - load(filetmp); - std::remove(filetmp); + load(filename_tmp); + std::remove(filename_tmp); return *this; } @@ -47941,7 +48772,7 @@ namespace cimg_library_suffixed { **/ template CImgList& load_off(const char *const filename, - CImgList& primitives, CImgList& colors) { + CImgList& primitives, CImgList& colors) { return get_load_off(filename,primitives,colors).move_to(*this); } @@ -47960,15 +48791,16 @@ namespace cimg_library_suffixed { \param step_frame Step applied between each frame. **/ CImgList& load_tiff(const char *const filename, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, - float *const voxel_size=0) { + const unsigned int first_frame=0, const unsigned int last_frame=~0U, + const unsigned int step_frame=1, + float *const voxel_size=0, + CImg *const description=0) { const unsigned int - nfirst_frame = first_frame=nb_images) return assign(); - if (nlast_frame>=nb_images) nlast_frame = nb_images-1; - assign(1+(nlast_frame-nfirst_frame)/nstep_frame); + if (nlast_frame>=nb_images) nlast_frame = nb_images - 1; + assign(1 + (nlast_frame - nfirst_frame)/nstep_frame); TIFFSetDirectory(tif,0); #if cimg_verbosity>=3 TIFFSetWarningHandler(0); TIFFSetErrorHandler(0); #endif - cimglist_for(*this,l) _data[l]._load_tiff(tif,nfirst_frame + l*nstep_frame,voxel_size); + cimglist_for(*this,l) _data[l]._load_tiff(tif,nfirst_frame + l*nstep_frame,voxel_size,description); TIFFClose(tif); } else throw CImgIOException(_cimglist_instance "load_tiff(): Failed to open file '%s'.", @@ -48008,10 +48840,11 @@ namespace cimg_library_suffixed { //! Load a multi-page TIFF file \newinstance. static CImgList get_load_tiff(const char *const filename, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, - float *const voxel_size=0) { - return CImgList().load_tiff(filename,first_frame,last_frame,step_frame,voxel_size); + const unsigned int first_frame=0, const unsigned int last_frame=~0U, + const unsigned int step_frame=1, + float *const voxel_size=0, + CImg *const description=0) { + return CImgList().load_tiff(filename,first_frame,last_frame,step_frame,voxel_size,description); } //@} @@ -48021,16 +48854,16 @@ namespace cimg_library_suffixed { //@{ //---------------------------------- - //! Print informations about the list on the standard output. + //! Print information about the list on the standard output. /** - \param title Label set to the informations displayed. + \param title Label set to the information displayed. \param display_stats Tells if image statistics must be computed and displayed. **/ const CImgList& print(const char *const title=0, const bool display_stats=true) const { unsigned int msiz = 0; cimglist_for(*this,l) msiz+=_data[l].size(); msiz*=sizeof(T); - const unsigned int mdisp = msiz<8*1024?0:(msiz<8*1024*1024?1:2); + const unsigned int mdisp = msiz<8*1024?0U:msiz<8*1024*1024?1U:2U; char _title[64] = { 0 }; if (!title) cimg_snprintf(_title,sizeof(_title),"CImgList<%s>",pixel_type()); std::fprintf(cimg::output(),"%s%s%s%s: %sthis%s = %p, %ssize%s = %u/%u [%u %s], %sdata%s = (CImg<%s>*)%p", @@ -48040,7 +48873,7 @@ namespace cimg_library_suffixed { mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)), mdisp==0?"b":(mdisp==1?"Kio":"Mio"), cimg::t_bold,cimg::t_normal,pixel_type(),(void*)begin()); - if (_data) std::fprintf(cimg::output(),"..%p.\n",(void*)((char*)end()-1)); + if (_data) std::fprintf(cimg::output(),"..%p.\n",(void*)((char*)end() - 1)); else std::fprintf(cimg::output(),".\n"); char tmp[16] = { 0 }; @@ -48048,7 +48881,7 @@ namespace cimg_library_suffixed { cimg_snprintf(tmp,sizeof(tmp),"[%d]",ll); std::fprintf(cimg::output()," "); _data[ll].print(tmp,display_stats); - if (ll==3 && _width>8) { ll = _width-5; std::fprintf(cimg::output()," ...\n"); } + if (ll==3 && width()>8) { ll = width() - 5; std::fprintf(cimg::output()," ...\n"); } } std::fflush(cimg::output()); return *this; @@ -48072,7 +48905,7 @@ namespace cimg_library_suffixed { //! Display the current CImgList instance in a new display window. /** \param disp Display window. - \param display_info Tells if image informations are displayed on the standard output. + \param display_info Tells if image information are displayed on the standard output. \param axis Alignment axis for images viewing. \param align Apending alignment. \note This function opens a new window with a specific title and displays the list images of the @@ -48090,7 +48923,7 @@ namespace cimg_library_suffixed { //! Display the current CImgList instance in a new display window. /** \param title Title of the opening display window. - \param display_info Tells if list informations must be written on standard output. + \param display_info Tells if list information must be written on standard output. \param axis Appending axis. Can be { 'x' | 'y' | 'z' | 'c' }. \param align Appending alignment. **/ @@ -48165,11 +48998,11 @@ namespace cimg_library_suffixed { delta = cimg::max(1U,(unsigned int)cimg::round(0.3*_width)), ind0 = (unsigned int)cimg::max(0,s[0] - (int)delta), ind1 = (unsigned int)cimg::min(width() - 1,s[0] + (int)delta); - if ((ind0!=0 || ind1!=_width-1) && ind1 - ind0>=3) + if ((ind0!=0 || ind1!=_width - 1) && ind1 - ind0>=3) get_shared_images(ind0,ind1)._display(disp,0,false,axis,align,XYZ,orig + ind0,false,is_exit); } - } else if (s[0]!=0 || s[1]!=width()-1) - get_shared_images(s[0],s[1])._display(disp,0,false,axis,align,XYZ,orig+s[0],false,is_exit); + } else if (s[0]!=0 || s[1]!=width() - 1) + get_shared_images(s[0],s[1])._display(disp,0,false,axis,align,XYZ,orig + s[0],false,is_exit); } } return *this; @@ -48189,7 +49022,7 @@ namespace cimg_library_suffixed { // Do not test for empty instances, since .cimg format is able to manage empty instances. const bool is_stdout = *filename=='-' && (!filename[1] || filename[1]=='.'); const char *const ext = cimg::split_filename(filename); - char nfilename[1024] = { 0 }; + CImg nfilename(1024); const char *const fn = is_stdout?filename:number>=0?cimg::number_filename(filename,number,digits,nfilename): filename; @@ -48245,7 +49078,7 @@ namespace cimg_library_suffixed { !cimg::strcasecmp(ext,"vob") || !cimg::strcasecmp(ext,"wmv") || !cimg::strcasecmp(ext,"xvid") || - !cimg::strcasecmp(ext,"mpeg")) return save_ffmpeg(fn); + !cimg::strcasecmp(ext,"mpeg")) return save_video(fn); #ifdef cimg_use_tiff else if (!cimg::strcasecmp(ext,"tif") || !cimg::strcasecmp(ext,"tiff")) return save_tiff(fn); @@ -48305,7 +49138,7 @@ namespace cimg_library_suffixed { **/ const CImgList& save_gif_external(const char *const filename, const unsigned int fps=25, const unsigned int nb_loops=0) { - char command[1024] = { 0 }, filetmp[512] = { 0 }, filetmp2[512] = { 0 }; + CImg command(1024), filename_tmp(256), filename_tmp2(256); CImgList filenames; std::FILE *file = 0; @@ -48316,29 +49149,30 @@ namespace cimg_library_suffixed { #endif do { - cimg_snprintf(filetmp,sizeof(filetmp),"%s%c%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); - cimg_snprintf(filetmp2,sizeof(filetmp2),"%s_000001." _cimg_save_gif_ext,filetmp); - if ((file=std::fopen(filetmp2,"rb"))!=0) cimg::fclose(file); + 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(filetmp2,sizeof(filetmp2),"%s_%.6u." _cimg_save_gif_ext,filetmp,l+1); - CImg::string(filetmp2).move_to(filenames); - if (_data[l]._depth>1 || _data[l]._spectrum!=3) _data[l].get_resize(-100,-100,1,3).save(filetmp2); - else _data[l].save(filetmp2); + cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_%.6u." _cimg_save_gif_ext,filename_tmp._data,l + 1); + CImg::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); } #if cimg_OS!=2 - cimg_snprintf(command,sizeof(command),"%s -delay 1x%u -loop %u", + cimg_snprintf(command,command._width,"%s -delay 1x%u -loop %u", cimg::imagemagick_path(),fps,nb_loops); CImg::string(command).move_to(filenames,0); - cimg_snprintf(command,sizeof(command),"\"%s\" >/dev/null 2>&1", + cimg_snprintf(command,command._width,"\"%s\" >/dev/null 2>&1", CImg::string(filename)._system_strescape().data()); CImg::string(command).move_to(filenames); #else - cimg_snprintf(command,sizeof(command),"\"%s -delay 1x%u -loop %u", + cimg_snprintf(command,command._width,"\"%s -delay 1x%u -loop %u", cimg::imagemagick_path(),fps,nb_loops); CImg::string(command).move_to(filenames,0); - cimg_snprintf(command,sizeof(command),"\"%s\"\" >NUL 2>&1", + cimg_snprintf(command,command._width,"\"%s\"\" >NUL 2>&1", CImg::string(filename)._system_strescape().data()); CImg::string(command).move_to(filenames); #endif @@ -48354,312 +49188,10 @@ namespace cimg_library_suffixed { cimglist_instance, filename); else cimg::fclose(file); - cimglist_for_in(*this,1,filenames._width-1,l) std::remove(filenames[l]); + cimglist_for_in(*this,1,filenames._width - 1,l) std::remove(filenames[l]); return *this; } - //! Save image sequence, using FFMPEG library. - /** - \param filename Filename to write data to. - \param fps Desired framerate (in frames per seconds) if chosen format supports it. - \param bitrate Desired bitrate (in bits per seconds) if chosen format supports it. - **/ - // This piece of code has been originally written by David. G. Starkweather. - const CImgList& save_ffmpeg(const char *const filename, const unsigned int fps=25, - const unsigned int bitrate=2048) const { - if (!filename) - throw CImgArgumentException(_cimglist_instance - "save_ffmpeg(): Specified filename is (null).", - cimglist_instance); - if (!fps) - throw CImgArgumentException(_cimglist_instance - "save_ffmpeg(): Invalid specified framerate 0, for file '%s'.", - cimglist_instance, - filename); - if (is_empty()) { cimg::fempty(0,filename); return *this; } - - cimglist_for(*this,l) if (!_data[l].is_sameXYZ(_data[0])) - throw CImgInstanceException(_cimglist_instance - "save_ffmpeg(): Invalid instance dimensions, for file '%s'.", - cimglist_instance, - filename); - -#ifndef cimg_use_ffmpeg - return save_ffmpeg_external(filename,0,fps,bitrate); -#else - avcodec_register_all(); - av_register_all(); - const int - frame_dimx = _data[0].width(), - frame_dimy = _data[0].height(), - frame_dimv = _data[0].spectrum(); - if (frame_dimv!=1 && frame_dimv!=3) - throw CImgInstanceException(_cimglist_instance - "save_ffmpeg(): Image[0] (%u,%u,%u,%u,%p) has not 1 or 3 channels, for file '%s'.", - cimglist_instance, - _data[0]._width,_data[0]._height,_data[0]._depth,_data[0]._spectrum,_data,filename); - - PixelFormat dest_pxl_fmt = PIX_FMT_YUV420P; - PixelFormat src_pxl_fmt = (frame_dimv==3)?PIX_FMT_RGB24:PIX_FMT_GRAY8; - - int sws_flags = SWS_FAST_BILINEAR; // Interpolation method (keeping same size images for now). - AVOutputFormat *fmt = 0; -#if defined(AV_VERSION_INT) -#if LIBAVFORMAT_VERSION_INToformat = fmt; - std::sprintf(oc->filename,"%s",filename); - - // Add video stream. - AVStream *video_str = 0; - if (fmt->video_codec!=CODEC_ID_NONE) { - video_str = avformat_new_stream(oc,NULL); - if (!video_str) { // Failed to allocate stream. - av_free(oc); - throw CImgIOException(_cimglist_instance - "save_ffmpeg(): Failed to allocate FFMPEG structure for video stream, for file '%s'.", - cimglist_instance, - filename); - } - } else { // No codec identified. - av_free(oc); - throw CImgIOException(_cimglist_instance - "save_ffmpeg(): Failed to identify proper codec, for file '%s'.", - cimglist_instance, - filename); - } - - AVCodecContext *c = video_str->codec; - c->codec_id = fmt->video_codec; - c->codec_type = AVMEDIA_TYPE_VIDEO; - c->bit_rate = 1024*bitrate; - c->width = frame_dimx; - c->height = frame_dimy; - c->time_base.num = 1; - c->time_base.den = fps; - c->gop_size = 12; - c->pix_fmt = dest_pxl_fmt; - if (c->codec_id==CODEC_ID_MPEG2VIDEO) c->max_b_frames = 2; - if (c->codec_id==CODEC_ID_MPEG1VIDEO) c->mb_decision = 2; - - // Open codecs and alloc buffers. - codec = avcodec_find_encoder(c->codec_id); - if (!codec) { // Failed to find codec. - av_free(oc); - throw CImgIOException(_cimglist_instance - "save_ffmpeg(): No valid codec found for file '%s'.", - cimglist_instance, - filename); - } - if (avcodec_open2(c,codec,NULL)<0) // Failed to open codec. - throw CImgIOException(_cimglist_instance - "save_ffmpeg(): Failed to open codec for file '%s'.", - cimglist_instance, - filename); - - tmp_pict = avcodec_alloc_frame(); - if (!tmp_pict) { // Failed to allocate memory for tmp_pict frame. - avcodec_close(video_str->codec); - av_free(oc); - throw CImgIOException(_cimglist_instance - "save_ffmpeg(): Failed to allocate memory for file '%s'.", - cimglist_instance, - filename); - } - tmp_pict->linesize[0] = (src_pxl_fmt==PIX_FMT_RGB24)?3*frame_dimx:frame_dimx; - // tmp_pict->type = FF_BUFFER_TYPE_USER; - int tmp_size = avpicture_get_size(src_pxl_fmt,frame_dimx,frame_dimy); - uint8_t *tmp_buffer = (uint8_t*)av_malloc(tmp_size); - if (!tmp_buffer) { // Failed to allocate memory for tmp buffer. - av_free(tmp_pict); - avcodec_close(video_str->codec); - av_free(oc); - throw CImgIOException(_cimglist_instance - "save_ffmpeg(): Failed to allocate memory for file '%s'.", - cimglist_instance, - filename); - } - - // Associate buffer with tmp_pict. - avpicture_fill((AVPicture*)tmp_pict,tmp_buffer,src_pxl_fmt,frame_dimx,frame_dimy); - picture = avcodec_alloc_frame(); - if (!picture) { // Failed to allocate picture frame. - av_free(tmp_pict->data[0]); - av_free(tmp_pict); - avcodec_close(video_str->codec); - av_free(oc); - throw CImgIOException(_cimglist_instance - "save_ffmpeg(): Failed to allocate memory for file '%s'.", - cimglist_instance, - filename); - } - - int size = avpicture_get_size(c->pix_fmt,frame_dimx,frame_dimy); - uint8_t *buffer = (uint8_t*)av_malloc(size); - if (!buffer) { // Failed to allocate picture frame buffer. - av_free(picture); - av_free(tmp_pict->data[0]); - av_free(tmp_pict); - avcodec_close(video_str->codec); - av_free(oc); - throw CImgIOException(_cimglist_instance - "save_ffmpeg(): Failed to allocate memory for file '%s'.", - cimglist_instance, - filename); - } - - // Associate the buffer with picture. - avpicture_fill((AVPicture*)picture,buffer,c->pix_fmt,frame_dimx,frame_dimy); - - // Open file. - if (!(fmt->flags&AVFMT_NOFILE)) { - if (avio_open(&oc->pb,filename,AVIO_FLAG_WRITE)<0) - throw CImgIOException(_cimglist_instance - "save_ffmpeg(): Failed to open file '%s'.", - cimglist_instance, - filename); - } - - if (avformat_write_header(oc,NULL)<0) - throw CImgIOException(_cimglist_instance - "save_ffmpeg(): Failed to write header in file '%s'.", - cimglist_instance, - filename); - - SwsContext *img_convert_context = 0; - img_convert_context = sws_getContext(frame_dimx,frame_dimy,src_pxl_fmt, - c->width,c->height,c->pix_fmt,sws_flags,0,0,0); - if (!img_convert_context) { // Failed to get swscale context. - // if (!(fmt->flags & AVFMT_NOFILE)) url_fclose(&oc->pb); - av_free(picture->data); - av_free(picture); - av_free(tmp_pict->data[0]); - av_free(tmp_pict); - avcodec_close(video_str->codec); - av_free(oc); - throw CImgIOException(_cimglist_instance - "save_ffmpeg(): Failed to get conversion context for file '%s'.", - cimglist_instance, - filename); - } - int ret = 0, out_size; - uint8_t *video_outbuf = 0; - int video_outbuf_size = 1000000; - video_outbuf = (uint8_t*)av_malloc(video_outbuf_size); - if (!video_outbuf) { - // if (!(fmt->flags & AVFMT_NOFILE)) url_fclose(&oc->pb); - av_free(picture->data); - av_free(picture); - av_free(tmp_pict->data[0]); - av_free(tmp_pict); - avcodec_close(video_str->codec); - av_free(oc); - throw CImgIOException(_cimglist_instance - "save_ffmpeg(): Failed to allocate memory, for file '%s'.", - cimglist_instance, - filename); - } - - // Loop through each desired image in list. - cimglist_for(*this,i) { - CImg currentIm = _data[i], red, green, blue, gray; - if (src_pxl_fmt==PIX_FMT_RGB24) { - red = currentIm.get_shared_channel(0); - green = currentIm.get_shared_channel(1); - blue = currentIm.get_shared_channel(2); - cimg_forXY(currentIm,X,Y) { // Assign pizel values to data buffer in interlaced RGBRGB ... format. - tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X] = red(X,Y); - tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X + 1] = green(X,Y); - tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X + 2] = blue(X,Y); - } - } else { - gray = currentIm.get_shared_channel(0); - cimg_forXY(currentIm,X,Y) tmp_pict->data[0][Y*tmp_pict->linesize[0] + X] = gray(X,Y); - } - if (!video_str) break; - if (sws_scale(img_convert_context,tmp_pict->data,tmp_pict->linesize,0, - c->height,picture->data,picture->linesize)<0) break; - - AVPacket pkt; - int got_packet; - av_init_packet(&pkt); - out_size = avcodec_encode_video2(c,&pkt,picture,&got_packet); - if (got_packet) { - pkt.pts = av_rescale_q(c->coded_frame->pts,c->time_base,video_str->time_base); - if (c->coded_frame->key_frame) pkt.flags|=AV_PKT_FLAG_KEY; - pkt.stream_index = video_str->index; - pkt.data = video_outbuf; - pkt.size = out_size; - ret = av_write_frame(oc,&pkt); - } else if (out_size<0) break; - if (ret) break; // Error occured in writing frame. - } - - // Close codec. - if (video_str) { - avcodec_close(video_str->codec); - av_free(picture->data[0]); - av_free(picture); - av_free(tmp_pict->data[0]); - av_free(tmp_pict); - } - if (av_write_trailer(oc)<0) - throw CImgIOException(_cimglist_instance - "save_ffmpeg(): Failed to write trailer for file '%s'.", - cimglist_instance, - filename); - - av_freep(&oc->streams[0]->codec); - av_freep(&oc->streams[0]); - if (!(fmt->flags&AVFMT_NOFILE)) { - /*if (url_fclose(oc->pb)<0) - throw CImgIOException(_cimglist_instance - "save_ffmpeg(): File '%s', failed to close file.", - cimglist_instance, - filename); - */ - } - av_free(oc); - av_free(video_outbuf); - return *this; -#endif - } - const CImgList& _save_yuv(std::FILE *const file, const char *const filename, const bool is_rgb) const { if (!file && !filename) throw CImgArgumentException(_cimglist_instance @@ -48718,7 +49250,7 @@ namespace cimg_library_suffixed { #endif std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); const char *const ptype = pixel_type(), *const etype = cimg::endianness()?"big":"little"; - if (std::strstr(ptype,"unsigned")==ptype) std::fprintf(nfile,"%u unsigned_%s %s_endian\n",_width,ptype+9,etype); + if (std::strstr(ptype,"unsigned")==ptype) std::fprintf(nfile,"%u unsigned_%s %s_endian\n",_width,ptype + 9,etype); else std::fprintf(nfile,"%u %s %s_endian\n",_width,ptype,etype); cimglist_for(*this,l) { const CImg& img = _data[l]; @@ -48783,7 +49315,7 @@ namespace cimg_library_suffixed { for (unsigned int l = 0; l=W?W-1:x1, \ - ny1 = y1>=H?H-1:y1, \ - nz1 = z1>=D?D-1:z1, \ - nc1 = c1>=C?C-1:c1; \ - CImg raw(1+nx1-x0); \ + nx1 = x1>=W?W - 1:x1, \ + ny1 = y1>=H?H - 1:y1, \ + nz1 = z1>=D?D - 1:z1, \ + nc1 = c1>=C?C - 1:c1; \ + CImg raw(1 + nx1 - x0); \ const unsigned int skipvb = c0*W*H*D*sizeof(Tss); \ if (skipvb) std::fseek(nfile,skipvb,SEEK_CUR); \ for (unsigned int v = 1 + nc1 - c0; v; --v) { \ @@ -48847,11 +49379,12 @@ namespace cimg_library_suffixed { std::FILE *const nfile = file?file:cimg::fopen(filename,"rb+"); bool saved = false, endian = cimg::endianness(); - char tmp[256] = { 0 }, str_pixeltype[256] = { 0 }, str_endian[256] = { 0 }; - unsigned int j, err, N, W, H, D, C; - int i; + CImg tmp(256), str_pixeltype(256), str_endian(256); + *tmp = *str_pixeltype = *str_endian = 0; + unsigned int j, N, W, H, D, C; + int i, err; j = 0; while((i=std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = 0; - err = std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian); + err = cimg_sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype._data,str_endian._data); if (err<2) { if (!file) cimg::fclose(nfile); throw CImgIOException(_cimglist_instance @@ -48861,7 +49394,7 @@ namespace cimg_library_suffixed { } if (!cimg::strncasecmp("little",str_endian,6)) endian = false; else if (!cimg::strncasecmp("big",str_endian,3)) endian = true; - const unsigned int lmax = cimg::min(N,n0+_width); + const unsigned int lmax = cimg::min(N,n0 + _width); _cimg_save_cimg_case("bool",bool); _cimg_save_cimg_case("unsigned_char",unsigned char); _cimg_save_cimg_case("uchar",unsigned char); @@ -48882,7 +49415,7 @@ namespace cimg_library_suffixed { throw CImgIOException(_cimglist_instance "save_cimg(): Unsupported data type '%s' for file '%s'.", cimglist_instance, - filename?filename:"(FILE*)",str_pixeltype); + filename?filename:"(FILE*)",str_pixeltype._data); } if (!file) cimg::fclose(nfile); return *this; @@ -48929,7 +49462,7 @@ namespace cimg_library_suffixed { std::fprintf(nfile,"%u %s\n",nb,pixel_type()); for (unsigned int i=nb; i; --i) { std::fprintf(nfile,"%u %u %u %u\n",dx,dy,dz,dc); - for (unsigned long off=siz; off; --off) std::fputc(0,nfile); + for (unsigned long off=siz; off; --off) std::fputc(0,nfile); } if (!file) cimg::fclose(nfile); } @@ -48972,7 +49505,7 @@ namespace cimg_library_suffixed { \param compression_type Compression mode used to write data. **/ const CImgList& save_tiff(const char *const filename, const unsigned int compression_type=0, - const float *const voxel_size=0) const { + const float *const voxel_size=0, const char *const description=0) const { if (!filename) throw CImgArgumentException(_cimglist_instance "save_tiff(): Specified filename is (null).", @@ -48980,11 +49513,11 @@ namespace cimg_library_suffixed { if (is_empty()) { cimg::fempty(0,filename); return *this; } #ifndef cimg_use_tiff - if (_width==1) _data[0].save_tiff(filename,compression_type,voxel_size); + if (_width==1) _data[0].save_tiff(filename,compression_type,voxel_size,description); else cimglist_for(*this,l) { - char nfilename[1024] = { 0 }; + CImg nfilename(1024); cimg::number_filename(filename,l,6,nfilename); - _data[l].save_tiff(nfilename,compression_type,voxel_size); + _data[l].save_tiff(nfilename,compression_type,voxel_size,description); } #else TIFF *tif = TIFFOpen(filename,"w"); @@ -48992,8 +49525,8 @@ namespace cimg_library_suffixed { for (unsigned int dir = 0, l = 0; l<_width; ++l) { const CImg& img = (*this)[l]; if (img) { - if (img._depth==1) img._save_tiff(tif,dir++,compression_type,voxel_size); - else cimg_forZ(img,z) img.get_slice(z)._save_tiff(tif,dir++,compression_type,voxel_size); + if (img._depth==1) img._save_tiff(tif,dir++,compression_type,voxel_size,description); + else cimg_forZ(img,z) img.get_slice(z)._save_tiff(tif,dir++,compression_type,voxel_size,description); } } TIFFClose(tif); @@ -49006,7 +49539,6 @@ namespace cimg_library_suffixed { return *this; } - //! Save list as a gzipped file, using external tool 'gzip'. /** \param filename Filename to write data to. @@ -49017,31 +49549,31 @@ namespace cimg_library_suffixed { "save_gzip_external(): Specified filename is (null).", cimglist_instance); - char command[1024] = { 0 }, filetmp[512] = { 0 }, body[512] = { 0 }; + CImg 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(filetmp,sizeof(filetmp),"%s%c%s.%s", + 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(filetmp,sizeof(filetmp),"%s%c%s.cimg", + 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(filetmp,sizeof(filetmp),"%s%c%s.%s", + 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(filetmp,sizeof(filetmp),"%s%c%s.cimg", + else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.cimg", cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); } - if ((file=std::fopen(filetmp,"rb"))!=0) cimg::fclose(file); + if ((file=std::fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); } while (file); if (is_saveable(body)) { - save(filetmp); - cimg_snprintf(command,sizeof(command),"%s -c \"%s\" > \"%s\"", + save(filename_tmp); + cimg_snprintf(command,command._width,"%s -c \"%s\" > \"%s\"", cimg::gzip_path(), - CImg::string(filetmp)._system_strescape().data(), + CImg::string(filename_tmp)._system_strescape().data(), CImg::string(filename)._system_strescape().data()); cimg::system(command); file = std::fopen(filename,"rb"); @@ -49051,27 +49583,152 @@ namespace cimg_library_suffixed { cimglist_instance, filename); else cimg::fclose(file); - std::remove(filetmp); + std::remove(filename_tmp); } else { - char nfilename[1024] = { 0 }; + CImg nfilename(1024); cimglist_for(*this,l) { cimg::number_filename(body,l,6,nfilename); - if (*ext) std::sprintf(nfilename + std::strlen(nfilename),".%s",ext); + if (*ext) std::sprintf(nfilename._data + std::strlen(nfilename),".%s",ext); _data[l].save_gzip_external(nfilename); } } return *this; } + //! Save image sequence, using the OpenCV library. + /** + \param filename Filename to write data to. + \param fps Number of frames per second. + \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& 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 filenames(32); + static CImg 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:"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::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 &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 _src(src,false); + _src.channels(0,cimg::min(_src._spectrum - 1,2U)).resize(W,H); + _src.resize(W,H,1,3,_src._spectrum==1?1:0); + 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); + + return *this; +#endif + } + //! Save image sequence, using the external tool 'ffmpeg'. /** \param filename Filename to write data to. - \param codec Type of compression. \param fps Number of frames per second. + \param codec Type of compression. \param bitrate Output bitrate **/ - const CImgList& save_ffmpeg_external(const char *const filename, const char *const codec=0, - const unsigned int fps=25, const unsigned int bitrate=2048) const { + const CImgList& save_ffmpeg_external(const char *const filename, const unsigned int fps=25, + const char *const codec=0, const unsigned int bitrate=2048) const { if (!filename) throw CImgArgumentException(_cimglist_instance "save_ffmpeg_external(): Specified filename is (null).", @@ -49082,7 +49739,7 @@ namespace cimg_library_suffixed { *const ext = cimg::split_filename(filename), *const _codec = codec?codec:!cimg::strcasecmp(ext,"flv")?"flv":"mpeg2video"; - char command[1024] = { 0 }, filetmp[512] = { 0 }, filetmp2[512] = { 0 }; + CImg command(1024), filename_tmp(256), filename_tmp2(256); CImgList filenames; std::FILE *file = 0; cimglist_for(*this,l) if (!_data[l].is_sameXYZ(_data[0])) @@ -49091,26 +49748,27 @@ namespace cimg_library_suffixed { cimglist_instance, filename); do { - cimg_snprintf(filetmp,sizeof(filetmp),"%s%c%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); - cimg_snprintf(filetmp2,sizeof(filetmp2),"%s_000001.ppm",filetmp); - if ((file=std::fopen(filetmp2,"rb"))!=0) cimg::fclose(file); + cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s", + cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); + cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_000001.ppm",filename_tmp._data); + if ((file=std::fopen(filename_tmp2,"rb"))!=0) cimg::fclose(file); } while (file); cimglist_for(*this,l) { - cimg_snprintf(filetmp2,sizeof(filetmp2),"%s_%.6u.ppm",filetmp,l+1); - CImg::string(filetmp2).move_to(filenames); - if (_data[l]._depth>1 || _data[l]._spectrum!=3) _data[l].get_resize(-100,-100,1,3).save_pnm(filetmp2); - else _data[l].save_pnm(filetmp2); + cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_%.6u.ppm",filename_tmp._data,l + 1); + CImg::string(filename_tmp2).move_to(filenames); + if (_data[l]._depth>1 || _data[l]._spectrum!=3) _data[l].get_resize(-100,-100,1,3).save_pnm(filename_tmp2); + else _data[l].save_pnm(filename_tmp2); } #if cimg_OS!=2 - cimg_snprintf(command,sizeof(command),"%s -i \"%s_%%6d.ppm\" -vcodec %s -b %uk -r %u -y \"%s\" >/dev/null 2>&1", + cimg_snprintf(command,command._width,"%s -i \"%s_%%6d.ppm\" -vcodec %s -b %uk -r %u -y \"%s\" >/dev/null 2>&1", cimg::ffmpeg_path(), - CImg::string(filetmp)._system_strescape().data(), + CImg::string(filename_tmp)._system_strescape().data(), _codec,bitrate,fps, CImg::string(filename)._system_strescape().data()); #else - cimg_snprintf(command,sizeof(command),"\"%s -i \"%s_%%6d.ppm\" -vcodec %s -b %uk -r %u -y \"%s\"\" >NUL 2>&1", + cimg_snprintf(command,command._width,"\"%s -i \"%s_%%6d.ppm\" -vcodec %s -b %uk -r %u -y \"%s\"\" >NUL 2>&1", cimg::ffmpeg_path(), - CImg::string(filetmp)._system_strescape().data(), + CImg::string(filename_tmp)._system_strescape().data(), _codec,bitrate,fps, CImg::string(filename)._system_strescape().data()); #endif @@ -49126,6 +49784,162 @@ namespace cimg_library_suffixed { return *this; } + //! Serialize a CImgList instance into a raw CImg buffer. + /** + \param is_compressed tells if zlib compression must be used for serialization + (this requires 'cimg_use_zlib' been enabled). + **/ + CImg get_serialize(const bool is_compressed=false) const { +#ifndef cimg_use_zlib + if (is_compressed) + cimg::warn(_cimglist_instance + "get_serialize(): Unable to compress data unless zlib is enabled, " + "storing them uncompressed.", + cimglist_instance); +#endif + CImgList stream; + CImg tmpstr(128); + const char *const ptype = pixel_type(), *const etype = cimg::endianness()?"big":"little"; + if (std::strstr(ptype,"unsigned")==ptype) + cimg_snprintf(tmpstr,tmpstr._width,"%u unsigned_%s %s_endian\n",_width,ptype + 9,etype); + else + cimg_snprintf(tmpstr,tmpstr._width,"%u %s %s_endian\n",_width,ptype,etype); + CImg::string(tmpstr,false).move_to(stream); + cimglist_for(*this,l) { + const CImg& img = _data[l]; + cimg_snprintf(tmpstr,tmpstr._width,"%u %u %u %u",img._width,img._height,img._depth,img._spectrum); + CImg::string(tmpstr,false).move_to(stream); + if (img._data) { + CImg tmp; + if (cimg::endianness()) { tmp = img; cimg::invert_endianness(tmp._data,tmp.size()); } + const CImg& ref = cimg::endianness()?tmp:img; + bool failed_to_compress = true; + if (is_compressed) { +#ifdef cimg_use_zlib + const unsigned long siz = sizeof(T)*ref.size(); + unsigned long csiz = compressBound(siz); + Bytef *const cbuf = new Bytef[csiz]; + if (compress(cbuf,&csiz,(Bytef*)ref._data,siz)) + cimg::warn(_cimglist_instance + "get_serialize(): Failed to save compressed data, saving them uncompressed.", + cimglist_instance); + else { + cimg_snprintf(tmpstr,tmpstr._width," #%lu\n",csiz); + CImg::string(tmpstr,false).move_to(stream); + CImg(cbuf,csiz).move_to(stream); + delete[] cbuf; + failed_to_compress = false; + } +#endif + } + if (failed_to_compress) { // Write in a non-compressed way. + CImg::string("\n",false).move_to(stream); + stream.insert(1); + stream.back().assign((unsigned char*)ref._data,ref.size()*sizeof(T),1,1,1,true); + } + } else CImg::string("\n",false).move_to(stream); + } + cimglist_apply(stream,unroll)('y'); + return stream>'y'; + } + + //! Unserialize a CImg serialized buffer into a CImgList list. + template + static CImgList get_unserialize(const CImg& buffer) { +#ifdef cimg_use_zlib +#define _cimgz_unserialize_case(Tss) { \ + Bytef *cbuf = (Bytef*)stream; \ + if (sizeof(t)!=1 || cimg::type::string()==cimg::type::string()) { \ + cbuf = new Bytef[csiz]; Bytef *_cbuf = cbuf; \ + for (unsigned long i = 0; i raw(W,H,D,C); \ + unsigned long destlen = (unsigned long)raw.size()*sizeof(Tss); \ + uncompress((Bytef*)raw._data,&destlen,cbuf,csiz); \ + if (!is_bytef) delete[] cbuf; \ + if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw.size()); \ + raw.move_to(img); \ + } +#else +#define _cimgz_unserialize_case(Tss) \ + throw CImgArgumentException("CImgList<%s>::get_unserialize(): Unable to unserialize compressed data " \ + "unless zlib is enabled.", \ + pixel_type()); +#endif + +#define _cimg_unserialize_case(Ts,Tss) \ + if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \ + for (unsigned int l = 0; l::unserialize(): Invalid specified size (%u,%u,%u,%u) for " \ + "image #%u in serialized buffer.", \ + pixel_type(),W,H,D,C,l); \ + if (W*H*D*C>0) { \ + CImg &img = res._data[l]; \ + if (err==5) _cimgz_unserialize_case(Tss) \ + else { \ + if (sizeof(t)!=1) { \ + CImg raw(W*sizeof(Tss),H,D,C); \ + cimg_for(raw,p,unsigned char) *p = (unsigned char)*(stream++); \ + img.assign((Tss*)raw._data,W,H,D,C); \ + } else img.assign((Tss*)stream,W,H,D,C); \ + if (endian!=cimg::endianness()) cimg::invert_endianness(img._data,img.size()); \ + } \ + } \ + } \ + loaded = true; \ + } + + if (buffer.is_empty()) + throw CImgArgumentException("CImgList<%s>::get_unserialize(): Specified serialized buffer is (null).", + pixel_type()); + CImgList res; + const t *stream = buffer._data, *const estream = buffer._data + buffer.size(); + bool loaded = false, endian = cimg::endianness(), is_bytef = false; + CImg tmp(256), str_pixeltype(256), str_endian(256); + *tmp = *str_pixeltype = *str_endian = 0; + unsigned int j, N = 0, W, H, D, C; + unsigned long csiz; + int i, err; + cimg::unused(is_bytef); + do { + j = 0; while ((i=(int)*stream)!='\n' && stream::get_unserialize(): CImg header not found in serialized buffer.", + pixel_type()); + if (!cimg::strncasecmp("little",str_endian,6)) endian = false; + else if (!cimg::strncasecmp("big",str_endian,3)) endian = true; + res.assign(N); + _cimg_unserialize_case("bool",bool); + _cimg_unserialize_case("unsigned_char",unsigned char); + _cimg_unserialize_case("uchar",unsigned char); + _cimg_unserialize_case("char",char); + _cimg_unserialize_case("unsigned_short",unsigned short); + _cimg_unserialize_case("ushort",unsigned short); + _cimg_unserialize_case("short",short); + _cimg_unserialize_case("unsigned_int",unsigned int); + _cimg_unserialize_case("uint",unsigned int); + _cimg_unserialize_case("int",int); + _cimg_unserialize_case("unsigned_long",unsigned long); + _cimg_unserialize_case("ulong",unsigned long); + _cimg_unserialize_case("long",long); + _cimg_unserialize_case("float",float); + _cimg_unserialize_case("double",double); + if (!loaded) + throw CImgArgumentException("CImgList<%s>::get_unserialize(): Unsupported pixel type '%s' defined " + "in serialized buffer.", + pixel_type(),str_pixeltype._data); + return res; + } + //@} //---------------------------------- // @@ -49147,13 +49961,13 @@ namespace cimg_library_suffixed { CImgList res; cimglist_for(*this,l) { const CImg& letter = (*this)[l]; - int xmin = letter._width, xmax = 0; + int xmin = letter.width(), xmax = 0; cimg_forXY(letter,x,y) if (letter(x,y)) { if (xxmax) xmax = x; } if (xmin>xmax) CImg(letter._width,letter._height,1,letter._spectrum,0).move_to(res); - else letter.get_crop(xmin,0,xmax,letter._height-1).move_to(res); + else letter.get_crop(xmin,0,xmax,letter._height - 1).move_to(res); } res[' '].resize(res['f']._width,-100,-100,-100,0); - if (' '+256 base_fonts[4]; CImg &base_font = base_fonts[data_ind]; if (!base_font) { @@ -49186,16 +50000,16 @@ namespace cimg_library_suffixed { ((CImg(cimg::_data_font90x103[0], (unsigned int)std::strlen(cimg::_data_font90x103[0]),1,1,1,true), CImg(cimg::_data_font90x103[1], - (unsigned int)std::strlen(cimg::_data_font90x103[1])+1,1,1,1,true))>'x'). + (unsigned int)std::strlen(cimg::_data_font90x103[1]) + 1,1,1,1,true))>'x'). move_to(data90x103); data_font = data90x103.data(); } // Uncompress font data (decode RLE). for (const char *ptrs = data_font; *ptrs; ++ptrs) { - const int c = *ptrs-M-32, v = c>=0?255:0, n = c>=0?c:-c; - if (ptrd+n<=ptrde) { std::memset(ptrd,v,n); ptrd+=n; } - else { std::memset(ptrd,v,ptrde-ptrd); break; } + const int c = (int)(*ptrs - M - 32), v = c>=0?255:0, n = c>=0?c:-c; + if (ptrd + n<=ptrde) { std::memset(ptrd,v,n); ptrd+=n; } + else { std::memset(ptrd,v,ptrde - ptrd); break; } } } @@ -49205,18 +50019,18 @@ namespace cimg_library_suffixed { unsigned int ind = ~0U; for (int i = 0; i<16; ++i) if (!fonts[i] || (is_variable_widths[i]==is_variable_width && font_height==fonts[i][0]._height)) { - ind = i; break; // Found empty slot or cached font. + ind = (unsigned int)i; break; // Found empty slot or cached font. } if (ind==~0U) { // No empty slots nor existing font in cache. - std::memmove(fonts,fonts+1,15*sizeof(CImgList)); - std::memmove(is_variable_widths,is_variable_widths+1,15*sizeof(bool)); - std::memset(fonts+(ind=15),0,sizeof(CImgList)); // Free a slot in cache for new font. + std::memmove(fonts,fonts + 1,15*sizeof(CImgList)); + std::memmove(is_variable_widths,is_variable_widths + 1,15*sizeof(bool)); + std::memset(fonts + (ind=15),0,sizeof(CImgList)); // Free a slot in cache for new font. } CImgList &font = fonts[ind]; // Render requested font. if (!font) { - const unsigned int padding_x = font_height<33?1:font_height<53?2:font_height<103?3:4; + const unsigned int padding_x = font_height<33U?1U:font_height<53U?2U:font_height<103U?3U:4U; is_variable_widths[ind] = is_variable_width; font = base_font.get_split('x',256); if (font_height!=font[0]._height) @@ -49226,7 +50040,7 @@ namespace cimg_library_suffixed { if (is_variable_width) font.crop_font(); cimglist_for(font,l) font[l].resize(font[l]._width + padding_x,-100,1,1,0,0,0.5); font.insert(256,0); - cimglist_for_in(font,0,255,l) font[l].assign(font[l+256]._width,font[l+256]._height,1,3,1); + cimglist_for_in(font,0,255,l) font[l].assign(font[l + 256]._width,font[l + 256]._height,1,3,1); } cimg::mutex(11,0); return font; @@ -49282,11 +50096,11 @@ namespace cimg_library_suffixed { cimglist_for(*this,l) { CImg& p = _data[l]; switch (p.size()) { - case 2: case 3: cimg::swap(p[0],p[1]); break; - case 6: cimg::swap(p[0],p[1],p[2],p[4],p[3],p[5]); break; - case 9: cimg::swap(p[0],p[1],p[3],p[5],p[4],p[6]); break; - case 4: cimg::swap(p[0],p[1],p[2],p[3]); break; - case 12: cimg::swap(p[0],p[1],p[2],p[3],p[4],p[6],p[5],p[7],p[8],p[10],p[9],p[11]); break; + case 2 : case 3: cimg::swap(p[0],p[1]); break; + case 6 : cimg::swap(p[0],p[1],p[2],p[4],p[3],p[5]); break; + case 9 : cimg::swap(p[0],p[1],p[3],p[5],p[4],p[6]); break; + case 4 : cimg::swap(p[0],p[1],p[2],p[3]); break; + case 12 : cimg::swap(p[0],p[1],p[2],p[3],p[4],p[6],p[5],p[7],p[8],p[10],p[9],p[11]); break; } } return *this; @@ -49301,65 +50115,939 @@ namespace cimg_library_suffixed { }; // struct CImgList { ... /* - #--------------------------------------------- - # - # Completion of previously declared functions - # - #---------------------------------------------- + #--------------------------------------------- + # + # Completion of previously declared functions + # + #---------------------------------------------- */ namespace cimg { - // Implement a tic/toc mechanism to display elapsed time of algorithms. - inline unsigned long tictoc(const bool is_tic) { - cimg::mutex(2); - static CImg times(64); - static unsigned int pos = 0; - const unsigned long t1 = cimg::time(); - if (is_tic) { // Tic. - times[pos++] = t1; - if (pos>=times._width) - throw CImgArgumentException("cimg::tic(): Too much calls to 'cimg::tic()' without calls to 'cimg::toc()'."); - cimg::mutex(2,0); - return t1; - } - // Toc. - if (!pos) - throw CImgArgumentException("cimg::toc(): No previous call to 'cimg::tic()' has been made."); - const unsigned long - t0 = times[--pos], - dt = t1>=t0?(t1-t0):cimg::type::max(); - const unsigned int - edays = (unsigned int)(dt/86400000.0), - ehours = (unsigned int)((dt - edays*86400000.0)/3600000.0), - emin = (unsigned int)((dt - edays*86400000.0 - ehours*3600000.0)/60000.0), - esec = (unsigned int)((dt - edays*86400000.0 - ehours*3600000.0 - emin*60000.0)/1000.0), - ems = (unsigned int)(dt - edays*86400000.0 - ehours*3600000.0 - emin*60000.0 - esec*1000.0); - if (!edays && !ehours && !emin && !esec) - std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u ms%s\n", - cimg::t_red,1+2*pos,"",ems,cimg::t_normal); + //! Get/set path to store temporary files. + /** + \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 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 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"); + } + } + cimg::mutex(7,0); + return s_path; + } + + //! Get/set path to the Program Files/ directory (Windows only). + /** + \param user_path Specified path, or \c 0 to get the path currently used. + \param reinit_path Force path to be recalculated (may take some time). + \return Path containing the program files. + **/ +#if cimg_OS==2 + inline const char* programfiles_path(const char *const user_path, const bool reinit_path) { + static CImg 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(MAX_PATH); + *s_path = 0; + // Note: in the following line, 0x26 = CSIDL_PROGRAM_FILES (not defined on every compiler). +#if !defined(__INTEL_COMPILER) + if (!SHGetSpecialFolderPathA(0,s_path,0x0026,false)) { + const char *const pfPath = std::getenv("PROGRAMFILES"); + if (pfPath) std::strncpy(s_path,pfPath,MAX_PATH - 1); + else std::strcpy(s_path,"C:\\PROGRA~1"); + } +#else + std::strcpy(s_path,"C:\\PROGRA~1"); +#endif + } + cimg::mutex(7,0); + return s_path; + } +#endif + + //! Get/set path to the ImageMagick's \c convert binary. + /** + \param user_path Specified path, or \c 0 to get the path currently used. + \param reinit_path Force path to be recalculated (may take some time). + \return Path containing the \c convert binary. + **/ + inline const char* imagemagick_path(const char *const user_path, const bool reinit_path) { + static CImg s_path; + cimg::mutex(7); + if (reinit_path) s_path.assign(); + if (user_path) { + if (!s_path) s_path.assign(1024); + std::strncpy(s_path,user_path,1023); + } else if (!s_path) { + s_path.assign(1024); + bool path_found = false; + std::FILE *file = 0; +#if cimg_OS==2 + const char *const pf_path = programfiles_path(); + if (!path_found) { + std::strcpy(s_path,".\\convert.exe"); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=10 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%.2d-\\convert.exe",pf_path,k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 9; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%d-Q\\convert.exe",pf_path,k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%d\\convert.exe",pf_path,k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=10 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",pf_path,k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 9; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",pf_path,k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",pf_path,k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=10 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%.2d-\\convert.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 9; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%d-Q\\convert.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%d\\convert.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=10 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 9; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=10 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%.2d-\\convert.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 9; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%d-Q\\convert.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%d\\convert.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=10 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 9; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + if (!path_found) std::strcpy(s_path,"convert.exe"); +#else + if (!path_found) { + std::strcpy(s_path,"./convert"); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + if (!path_found) std::strcpy(s_path,"convert"); +#endif + winformat_string(s_path); + } + cimg::mutex(7,0); + return s_path; + } + + //! Get/set path to the GraphicsMagick's \c gm binary. + /** + \param user_path Specified path, or \c 0 to get the path currently used. + \param reinit_path Force path to be recalculated (may take some time). + \return Path containing the \c gm binary. + **/ + inline const char* graphicsmagick_path(const char *const user_path, const bool reinit_path) { + static CImg s_path; + cimg::mutex(7); + if (reinit_path) s_path.assign(); + if (user_path) { + if (!s_path) s_path.assign(1024); + std::strncpy(s_path,user_path,1023); + } else if (!s_path) { + s_path.assign(1024); + bool path_found = false; + std::FILE *file = 0; +#if cimg_OS==2 + const char *const pf_path = programfiles_path(); + if (!path_found) { + std::strcpy(s_path,".\\gm.exe"); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=10 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"%s\\GRAPHI~1.%.2d-\\gm.exe",pf_path,k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 9; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"%s\\GRAPHI~1.%d-Q\\gm.exe",pf_path,k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"%s\\GRAPHI~1.%d\\gm.exe",pf_path,k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=10 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"%s\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",pf_path,k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 9; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"%s\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",pf_path,k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"%s\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",pf_path,k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=10 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"C:\\GRAPHI~1.%.2d-\\gm.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 9; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"C:\\GRAPHI~1.%d-Q\\gm.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"C:\\GRAPHI~1.%d\\gm.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=10 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"C:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 9; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"C:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"C:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=10 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"D:\\GRAPHI~1.%.2d-\\gm.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 9; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"D:\\GRAPHI~1.%d-Q\\gm.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"D:\\GRAPHI~1.%d\\gm.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=10 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"D:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 9; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"D:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + for (int k = 32; k>=0 && !path_found; --k) { + cimg_snprintf(s_path,s_path._width,"D:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + if (!path_found) std::strcpy(s_path,"gm.exe"); +#else + if (!path_found) { + std::strcpy(s_path,"./gm"); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + if (!path_found) std::strcpy(s_path,"gm"); +#endif + winformat_string(s_path); + } + cimg::mutex(7,0); + return s_path; + } + + //! Get/set path to the XMedcon's \c medcon binary. + /** + \param user_path Specified path, or \c 0 to get the path currently used. + \param reinit_path Force path to be recalculated (may take some time). + \return Path containing the \c medcon binary. + **/ + inline const char* medcon_path(const char *const user_path, const bool reinit_path) { + static CImg s_path; + cimg::mutex(7); + if (reinit_path) s_path.assign(); + if (user_path) { + if (!s_path) s_path.assign(1024); + std::strncpy(s_path,user_path,1023); + } else if (!s_path) { + s_path.assign(1024); + bool path_found = false; + std::FILE *file = 0; +#if cimg_OS==2 + const char *const pf_path = programfiles_path(); + if (!path_found) { + std::strcpy(s_path,".\\medcon.exe"); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + if (!path_found) { + cimg_snprintf(s_path,s_path._width,"%s\\XMedCon\\bin\\medcon.bat",pf_path); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + if (!path_found) { + cimg_snprintf(s_path,s_path._width,"%s\\XMedCon\\bin\\medcon.exe",pf_path); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + if (!path_found) { + std::strcpy(s_path,"C:\\XMedCon\\bin\\medcon.exe"); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + if (!path_found) std::strcpy(s_path,"medcon.exe"); +#else + if (!path_found) { + std::strcpy(s_path,"./medcon"); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + if (!path_found) std::strcpy(s_path,"medcon"); +#endif + winformat_string(s_path); + } + cimg::mutex(7,0); + return s_path; + } + + //! Get/set path to the FFMPEG's \c ffmpeg binary. + /** + \param user_path Specified path, or \c 0 to get the path currently used. + \param reinit_path Force path to be recalculated (may take some time). + \return Path containing the \c ffmpeg binary. + **/ + inline const char *ffmpeg_path(const char *const user_path, const bool reinit_path) { + static CImg s_path; + cimg::mutex(7); + if (reinit_path) s_path.assign(); + if (user_path) { + if (!s_path) s_path.assign(1024); + std::strncpy(s_path,user_path,1023); + } else if (!s_path) { + s_path.assign(1024); + bool path_found = false; + std::FILE *file = 0; +#if cimg_OS==2 + if (!path_found) { + std::strcpy(s_path,".\\ffmpeg.exe"); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + if (!path_found) std::strcpy(s_path,"ffmpeg.exe"); +#else + if (!path_found) { + std::strcpy(s_path,"./ffmpeg"); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + if (!path_found) std::strcpy(s_path,"ffmpeg"); +#endif + winformat_string(s_path); + } + cimg::mutex(7,0); + return s_path; + } + + //! Get/set path to the \c gzip binary. + /** + \param user_path Specified path, or \c 0 to get the path currently used. + \param reinit_path Force path to be recalculated (may take some time). + \return Path containing the \c gzip binary. + **/ + inline const char *gzip_path(const char *const user_path, const bool reinit_path) { + static CImg s_path; + cimg::mutex(7); + if (reinit_path) s_path.assign(); + if (user_path) { + if (!s_path) s_path.assign(1024); + std::strncpy(s_path,user_path,1023); + } else if (!s_path) { + s_path.assign(1024); + bool path_found = false; + std::FILE *file = 0; +#if cimg_OS==2 + if (!path_found) { + std::strcpy(s_path,".\\gzip.exe"); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + if (!path_found) std::strcpy(s_path,"gzip.exe"); +#else + if (!path_found) { + std::strcpy(s_path,"./gzip"); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + if (!path_found) std::strcpy(s_path,"gzip"); +#endif + winformat_string(s_path); + } + cimg::mutex(7,0); + return s_path; + } + + //! Get/set path to the \c gunzip binary. + /** + \param user_path Specified path, or \c 0 to get the path currently used. + \param reinit_path Force path to be recalculated (may take some time). + \return Path containing the \c gunzip binary. + **/ + inline const char *gunzip_path(const char *const user_path, const bool reinit_path) { + static CImg s_path; + cimg::mutex(7); + if (reinit_path) s_path.assign(); + if (user_path) { + if (!s_path) s_path.assign(1024); + std::strncpy(s_path,user_path,1023); + } else if (!s_path) { + s_path.assign(1024); + bool path_found = false; + std::FILE *file = 0; +#if cimg_OS==2 + if (!path_found) { + std::strcpy(s_path,".\\gunzip.exe"); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + if (!path_found) std::strcpy(s_path,"gunzip.exe"); +#else + if (!path_found) { + std::strcpy(s_path,"./gunzip"); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + if (!path_found) std::strcpy(s_path,"gunzip"); +#endif + winformat_string(s_path); + } + cimg::mutex(7,0); + return s_path; + } + + //! Get/set path to the \c dcraw binary. + /** + \param user_path Specified path, or \c 0 to get the path currently used. + \param reinit_path Force path to be recalculated (may take some time). + \return Path containing the \c dcraw binary. + **/ + inline const char *dcraw_path(const char *const user_path, const bool reinit_path) { + static CImg s_path; + cimg::mutex(7); + if (reinit_path) s_path.assign(); + if (user_path) { + if (!s_path) s_path.assign(1024); + std::strncpy(s_path,user_path,1023); + } else if (!s_path) { + s_path.assign(1024); + bool path_found = false; + std::FILE *file = 0; +#if cimg_OS==2 + if (!path_found) { + std::strcpy(s_path,".\\dcraw.exe"); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + if (!path_found) std::strcpy(s_path,"dcraw.exe"); +#else + if (!path_found) { + std::strcpy(s_path,"./dcraw"); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + if (!path_found) std::strcpy(s_path,"dcraw"); +#endif + winformat_string(s_path); + } + cimg::mutex(7,0); + return s_path; + } + + //! Get/set path to the \c wget binary. + /** + \param user_path Specified path, or \c 0 to get the path currently used. + \param reinit_path Force path to be recalculated (may take some time). + \return Path containing the \c wget binary. + **/ + inline const char *wget_path(const char *const user_path, const bool reinit_path) { + static CImg s_path; + cimg::mutex(7); + if (reinit_path) s_path.assign(); + if (user_path) { + if (!s_path) s_path.assign(1024); + std::strncpy(s_path,user_path,1023); + } else if (!s_path) { + s_path.assign(1024); + bool path_found = false; + std::FILE *file = 0; +#if cimg_OS==2 + if (!path_found) { + std::strcpy(s_path,".\\wget.exe"); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + if (!path_found) std::strcpy(s_path,"wget.exe"); +#else + if (!path_found) { + std::strcpy(s_path,"./wget"); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + if (!path_found) std::strcpy(s_path,"wget"); +#endif + winformat_string(s_path); + } + cimg::mutex(7,0); + return s_path; + } + + //! Get/set path to the \c curl binary. + /** + \param user_path Specified path, or \c 0 to get the path currently used. + \param reinit_path Force path to be recalculated (may take some time). + \return Path containing the \c curl binary. + **/ + inline const char *curl_path(const char *const user_path, const bool reinit_path) { + static CImg s_path; + cimg::mutex(7); + if (reinit_path) s_path.assign(); + if (user_path) { + if (!s_path) s_path.assign(1024); + std::strncpy(s_path,user_path,1023); + } else if (!s_path) { + s_path.assign(1024); + bool path_found = false; + std::FILE *file = 0; +#if cimg_OS==2 + if (!path_found) { + std::strcpy(s_path,".\\curl.exe"); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + if (!path_found) std::strcpy(s_path,"curl.exe"); +#else + if (!path_found) { + std::strcpy(s_path,"./curl"); + if ((file=std::fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } + } + if (!path_found) std::strcpy(s_path,"curl"); +#endif + winformat_string(s_path); + } + cimg::mutex(7,0); + return s_path; + } + + // [internal] Sorting function, used by cimg::files(). + inline int _sort_files(const void* a, const void* b) { + const CImg &sa = *(CImg*)a, &sb = *(CImg*)b; + return std::strcmp(sa._data,sb._data); + } + + //! Return list of files/directories in specified directory. + /** + \param path Path to the directory. Set to 0 for current directory. + \param is_pattern Tell if specified path has a matching pattern in it. + \param mode Output type, can be primary { 0=files only | 1=folders only | 2=files + folders }. + \param include_path Tell if \c path must be included in resulting filenames. + \return A list of filenames. + **/ + inline CImgList files(const char *const path, const bool is_pattern=false, + const unsigned int mode=2, const bool include_path=false) { + if (!path || !*path) return files("*",true,mode,include_path); + CImgList res; + + // If path is a valid folder name, ignore argument 'is_pattern'. + const bool _is_pattern = is_pattern && !cimg::is_directory(path); + bool is_root = false, is_current = false; + cimg::unused(is_root,is_current); + + // Clean format of input path. + CImg pattern, _path = CImg::string(path); +#if cimg_OS==2 + for (char *ps = _path; *ps; ++ps) if (*ps=='\\') *ps='/'; +#endif + char *pd = _path; + for (char *ps = pd; *ps; ++ps) { if (*ps!='/' || *ps!=*(ps+1)) *(pd++) = *ps; } + *pd = 0; + unsigned int lp = std::strlen(_path); + if (!_is_pattern && lp && _path[lp - 1]=='/') { + _path[lp - 1] = 0; --lp; +#if cimg_OS!=2 + is_root = !*_path; +#endif + } + + // Separate folder path and matching pattern. + if (_is_pattern) { + const unsigned int bpos = (unsigned int)(cimg::basename(_path,'/') - _path.data()); + CImg::string(_path).move_to(pattern); + if (bpos) { + _path[bpos - 1] = 0; // End 'path' at last slash. +#if cimg_OS!=2 + is_root = !*_path; +#endif + } else { // No path to folder specified, assuming current folder. + is_current = true; *_path = 0; + } + lp = std::strlen(_path); + } + + // Windows version. +#if cimg_OS==2 + if (!_is_pattern) { + pattern.assign(lp + 3); + std::memcpy(pattern,_path,lp); + pattern[lp] = '/'; pattern[lp + 1] = '*'; pattern[lp + 2] = 0; + } + + WIN32_FIND_DATAA file_data; + const HANDLE dir = FindFirstFileA(pattern.data(),&file_data); + if (dir==INVALID_HANDLE_VALUE) return CImgList::empty(); + do { + const char *const filename = file_data.cFileName; + if (*filename!='.' || (filename[1] && (filename[1]!='.' || filename[2]))) { + const unsigned int lf = std::strlen(filename); + const bool is_directory = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)!=0; + if ((!mode && !is_directory) || (mode==1 && is_directory) || mode>=2) { + if (include_path) { + CImg full_filename(lp + lf + 2); + std::memcpy(full_filename,_path,lp); + full_filename[lp] = '/'; + std::memcpy(full_filename._data + lp + 1,filename,lf + 1); + full_filename.move_to(res); + } else CImg(filename,lf + 1).move_to(res); + } + } + } while (FindNextFileA(dir,&file_data)); + FindClose(dir); + + // Unix version (posix). +#else + DIR *const dir = opendir(is_root?"/":is_current?".":_path.data()); + if (!dir) return CImgList::empty(); + struct dirent *ent; + while ((ent=readdir(dir))!=0) { + const char *const filename = ent->d_name; + if (*filename!='.' || (filename[1] && (filename[1]!='.' || filename[2]))) { + const unsigned int lf = std::strlen(filename); + CImg full_filename(lp + lf + 2); + + if (!is_current) { + full_filename.assign(lp + lf + 2); + if (lp) std::memcpy(full_filename,_path,lp); + full_filename[lp] = '/'; + std::memcpy(full_filename._data + lp + 1,filename,lf + 1); + } else full_filename.assign(filename,lf + 1); + + struct stat st; + if (stat(full_filename,&st)==-1) continue; + const bool is_directory = (st.st_mode & S_IFDIR)!=0; + if ((!mode && !is_directory) || (mode==1 && is_directory) || mode==2) { + if (include_path) { + if (!_is_pattern || (_is_pattern && !fnmatch(pattern,full_filename,0))) + full_filename.move_to(res); + } else { + if (!_is_pattern || (_is_pattern && !fnmatch(pattern,full_filename,0))) + CImg(filename,lf + 1).move_to(res); + } + } + } + } + closedir(dir); +#endif + + // Sort resulting list by lexicographic order. + if (res._width>=2) std::qsort(res._data,res._width,sizeof(CImg),_sort_files); + + return res; + } + + //! Try to guess format from an image file. + /** + \param file Input file (can be \c 0 if \c filename is set). + \param filename Filename, as a C-string (can be \c 0 if \c file is set). + \return C-string containing the guessed file format, or \c 0 if nothing has been guessed. + **/ + inline const char *ftype(std::FILE *const file, const char *const filename) { + if (!file && !filename) + throw CImgArgumentException("cimg::ftype(): Specified filename is (null)."); + static const char + *const _pnm = "pnm", + *const _pfm = "pfm", + *const _bmp = "bmp", + *const _gif = "gif", + *const _jpg = "jpg", + *const _off = "off", + *const _pan = "pan", + *const _png = "png", + *const _tif = "tif", + *const _inr = "inr", + *const _dcm = "dcm"; + const char *f_type = 0; + CImg header; + const unsigned int omode = cimg::exception_mode(); + cimg::exception_mode(0); + try { + header._load_raw(file,filename,512,1,1,1,false,false,0); + const unsigned char *const uheader = (unsigned char*)header._data; + if (!std::strncmp(header,"OFF\n",4)) f_type = _off; // OFF. + else if (!std::strncmp(header,"#INRIMAGE",9)) f_type = _inr; // INRIMAGE. + else if (!std::strncmp(header,"PANDORE",7)) f_type = _pan; // PANDORE. + else if (!std::strncmp(header.data() + 128,"DICM",4)) f_type = _dcm; // DICOM. + else if (uheader[0]==0xFF && uheader[1]==0xD8 && uheader[2]==0xFF) f_type = _jpg; // JPEG. + else if (header[0]=='B' && header[1]=='M') f_type = _bmp; // BMP. + else if (header[0]=='G' && header[1]=='I' && header[2]=='F' && header[3]=='8' && header[5]=='a' && // GIF. + (header[4]=='7' || header[4]=='9')) f_type = _gif; + else if (uheader[0]==0x89 && uheader[1]==0x50 && uheader[2]==0x4E && uheader[3]==0x47 && // PNG. + uheader[4]==0x0D && uheader[5]==0x0A && uheader[6]==0x1A && uheader[7]==0x0A) f_type = _png; + else if ((uheader[0]==0x49 && uheader[1]==0x49) || (uheader[0]==0x4D && uheader[1]==0x4D)) f_type = _tif; // TIFF. + else { // PNM or PFM. + CImgList _header = header.get_split(CImg::vector('\n'),0,false); + cimglist_for(_header,l) { + if (_header(l,0)=='#') continue; + if (_header[l]._height==2 && _header(l,0)=='P') { + const char c = _header(l,1); + if (c=='f' || c=='F') { f_type = _pfm; break; } + if (c>='1' && c<='9') { f_type = _pnm; break; } + } + f_type = 0; break; + } + } + } catch (CImgIOException&) { } + cimg::exception_mode(omode); + return f_type; + } + + //! Load file from network as a local temporary file. + /** + \param filename Filename, as a C-string. + \param[out] filename_local C-string containing the path to a local copy of \c filename. + \param timeout Maximum time (in seconds) authorized for downloading the file from the URL. + \param try_fallback When using libcurl, tells using system calls as fallbacks in case of libcurl failure. + \return Value of \c filename_local. + \note Use the \c libcurl library, or the external binaries \c wget or \c curl to perform the download. + **/ + inline char *load_network(const char *const url, char *const filename_local, + const unsigned int timeout, const bool try_fallback) { + if (!url) + throw CImgArgumentException("cimg::load_network(): Specified URL is (null)."); + if (!filename_local) + throw CImgArgumentException("cimg::load_network(): Specified destination string is (null)."); + + const char *const __ext = cimg::split_filename(url), *const _ext = (*__ext && __ext>url)?__ext - 1:__ext; + CImg ext = CImg::string(_ext); + std::FILE *file = 0; + *filename_local = 0; + if (ext._width>16 || !cimg::strncasecmp(ext,"cgi",3)) *ext = 0; + else cimg::strwindows_reserved(ext); + do { + cimg_snprintf(filename_local,256,"%s%c%s%s", + cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext._data); + if ((file=std::fopen(filename_local,"rb"))!=0) cimg::fclose(file); + } while (file); + +#ifdef cimg_use_curl + const unsigned int omode = cimg::exception_mode(); + cimg::exception_mode(0); + try { + CURL *curl = 0; + CURLcode res; + curl = curl_easy_init(); + if (curl) { + file = cimg::fopen(filename_local,"wb"); + curl_easy_setopt(curl,CURLOPT_URL,url); + curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,0); + curl_easy_setopt(curl,CURLOPT_WRITEDATA,file); + curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,0L); + curl_easy_setopt(curl,CURLOPT_SSL_VERIFYHOST,0L); + curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,1L); + if (timeout) curl_easy_setopt(curl,CURLOPT_TIMEOUT,(long)timeout); + if (std::strchr(url,'?')) curl_easy_setopt(curl,CURLOPT_HTTPGET,1L); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + std::fseek(file,0,SEEK_END); // Check if file size is 0. + const long siz = std::ftell(file); + cimg::fclose(file); + if (siz>0 && res==CURLE_OK) { + cimg::exception_mode(omode); + return filename_local; + } else std::remove(filename_local); + } + } catch (...) { } + cimg::exception_mode(omode); + if (!try_fallback) throw CImgIOException("cimg::load_network(): Failed to load file '%s' with libcurl.",url); +#endif + + CImg command((unsigned int)std::strlen(url) + 64); + cimg::unused(try_fallback); + + // Try with 'curl' first. + if (timeout) + cimg_snprintf(command,command._width,"%s -m %u -f --silent --compressed -o \"%s\" \"%s\"", + cimg::curl_path(),timeout,filename_local,url); + else + cimg_snprintf(command,command._width,"%s -f --silent --compressed -o \"%s\" \"%s\"", + cimg::curl_path(),filename_local,url); + cimg::system(command); + + if (!(file = std::fopen(filename_local,"rb"))) { + + // Try with 'wget' otherwise. + if (timeout) + cimg_snprintf(command,command._width,"%s -T %u -q -r -l 0 --no-cache -O \"%s\" \"%s\"", + cimg::wget_path(),timeout,filename_local,url); + else + cimg_snprintf(command,command._width,"%s -q -r -l 0 --no-cache -O \"%s\" \"%s\"", + cimg::wget_path(),filename_local,url); + cimg::system(command); + + if (!(file = std::fopen(filename_local,"rb"))) + throw CImgIOException("cimg::load_network(): Failed to load file '%s' with external commands " + "'wget' or 'curl'.",url); + cimg::fclose(file); + + // Try gunzip it. + cimg_snprintf(command,command._width,"%s.gz",filename_local); + std::rename(filename_local,command); + cimg_snprintf(command,command._width,"%s --quiet \"%s.gz\"", + gunzip_path(),filename_local); + cimg::system(command); + file = std::fopen(filename_local,"rb"); + if (!file) { + cimg_snprintf(command,command._width,"%s.gz",filename_local); + std::rename(command,filename_local); + file = std::fopen(filename_local,"rb"); + } + } + std::fseek(file,0,SEEK_END); // Check if file size is 0. + if (std::ftell(file)<=0) + throw CImgIOException("cimg::load_network(): Failed to load URL '%s' with external commands " + "'wget' or 'curl'.",url); + cimg::fclose(file); + return filename_local; + } + + // Implement a tic/toc mechanism to display elapsed time of algorithms. + inline unsigned long tictoc(const bool is_tic) { + cimg::mutex(2); + static CImg times(64); + static unsigned int pos = 0; + const unsigned long t1 = cimg::time(); + if (is_tic) { // Tic. + times[pos++] = t1; + if (pos>=times._width) + throw CImgArgumentException("cimg::tic(): Too much calls to 'cimg::tic()' without calls to 'cimg::toc()'."); + cimg::mutex(2,0); + return t1; + } + // Toc. + if (!pos) + throw CImgArgumentException("cimg::toc(): No previous call to 'cimg::tic()' has been made."); + const unsigned long + t0 = times[--pos], + dt = t1>=t0?(t1 - t0):cimg::type::max(); + const unsigned int + edays = (unsigned int)(dt/86400000.0), + ehours = (unsigned int)((dt - edays*86400000.0)/3600000.0), + emin = (unsigned int)((dt - edays*86400000.0 - ehours*3600000.0)/60000.0), + esec = (unsigned int)((dt - edays*86400000.0 - ehours*3600000.0 - emin*60000.0)/1000.0), + ems = (unsigned int)(dt - edays*86400000.0 - ehours*3600000.0 - emin*60000.0 - esec*1000.0); + if (!edays && !ehours && !emin && !esec) + std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u ms%s\n", + cimg::t_red,1 + 2*pos,"",ems,cimg::t_normal); + else { + if (!edays && !ehours && !emin) + std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u sec %u ms%s\n", + cimg::t_red,1 + 2*pos,"",esec,ems,cimg::t_normal); else { - if (!edays && !ehours && !emin) - std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u sec %u ms%s\n", - cimg::t_red,1+2*pos,"",esec,ems,cimg::t_normal); - else { - if (!edays && !ehours) - std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u min %u sec %u ms%s\n", - cimg::t_red,1+2*pos,"",emin,esec,ems,cimg::t_normal); + if (!edays && !ehours) + std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u min %u sec %u ms%s\n", + cimg::t_red,1 + 2*pos,"",emin,esec,ems,cimg::t_normal); + else{ + if (!edays) + std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u hours %u min %u sec %u ms%s\n", + cimg::t_red,1 + 2*pos,"",ehours,emin,esec,ems,cimg::t_normal); else{ - if (!edays) - std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u hours %u min %u sec %u ms%s\n", - cimg::t_red,1+2*pos,"",ehours,emin,esec,ems,cimg::t_normal); - else{ - std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u days %u hours %u min %u sec %u ms%s\n", - cimg::t_red,1+2*pos,"",edays,ehours,emin,esec,ems,cimg::t_normal); - } + std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u days %u hours %u min %u sec %u ms%s\n", + cimg::t_red,1 + 2*pos,"",edays,ehours,emin,esec,ems,cimg::t_normal); } } } - cimg::mutex(2,0); - return dt; } + cimg::mutex(2,0); + return dt; + } + + // Return a temporary string describing the size of a memory buffer. + inline const char *strbuffersize(const unsigned long size) { + static CImg res(256); + cimg::mutex(5); + if (size<1024LU) cimg_snprintf(res,res._width,"%lu byte%s",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); + } else { const float nsize = size/(1024*1024*1024.0f); cimg_snprintf(res,res._width,"%.1f Gio",nsize); } + cimg::mutex(5,0); + return res; + } //! Display a simple dialog box, and wait for the user's response. /** @@ -49378,14 +51066,14 @@ namespace cimg { - Up to 6 buttons can be defined in the dialog window. - The function returns when a user clicked one of the button or closed the dialog window. - If a button text is set to 0, the corresponding button (and the followings) will not appear in the dialog box. - At least one button must be specified. + At least one button must be specified. **/ template inline int dialog(const char *const title, const char *const msg, const char *const button1_label, const char *const button2_label, const char *const button3_label, const char *const button4_label, const char *const button5_label, const char *const button6_label, - const CImg& logo, const bool is_centered = false) { + const CImg& logo, const bool is_centered=false) { #if cimg_display==0 cimg::unused(title,msg,button1_label,button2_label,button3_label,button4_label,button5_label,button6_label, logo._data,is_centered); @@ -49416,30 +51104,34 @@ namespace cimg { if (bh>48) bh = 48; CImg button(bw,bh,1,3); - button.draw_rectangle(0,0,bw-1,bh-1,gray); - button.draw_line(0,0,bw-1,0,white).draw_line(0,bh-1,0,0,white); - button.draw_line(bw-1,0,bw-1,bh-1,black).draw_line(bw-1,bh-1,0,bh-1,black); - button.draw_line(1,bh-2,bw-2,bh-2,gray2).draw_line(bw-2,bh-2,bw-2,1,gray2); + button.draw_rectangle(0,0,bw - 1,bh - 1,gray); + button.draw_line(0,0,bw - 1,0,white).draw_line(0,bh - 1,0,0,white); + button.draw_line(bw - 1,0,bw - 1,bh - 1,black).draw_line(bw - 1,bh - 1,0,bh - 1,black); + button.draw_line(1,bh - 2,bw - 2,bh - 2,gray2).draw_line(bw - 2,bh - 2,bw - 2,1,gray2); CImg sbutton(bw,bh,1,3); - sbutton.draw_rectangle(0,0,bw-1,bh-1,gray); - sbutton.draw_line(0,0,bw-1,0,black).draw_line(bw-1,0,bw-1,bh-1,black); - sbutton.draw_line(bw-1,bh-1,0,bh-1,black).draw_line(0,bh-1,0,0,black); - sbutton.draw_line(1,1,bw-2,1,white).draw_line(1,bh-2,1,1,white); - sbutton.draw_line(bw-2,1,bw-2,bh-2,black).draw_line(bw-2,bh-2,1,bh-2,black); - sbutton.draw_line(2,bh-3,bw-3,bh-3,gray2).draw_line(bw-3,bh-3,bw-3,2,gray2); - sbutton.draw_line(4,4,bw-5,4,black,1,0xAAAAAAAA,true).draw_line(bw-5,4,bw-5,bh-5,black,1,0xAAAAAAAA,false); - sbutton.draw_line(bw-5,bh-5,4,bh-5,black,1,0xAAAAAAAA,false).draw_line(4,bh-5,4,4,black,1,0xAAAAAAAA,false); + sbutton.draw_rectangle(0,0,bw - 1,bh - 1,gray); + sbutton.draw_line(0,0,bw - 1,0,black).draw_line(bw - 1,0,bw - 1,bh - 1,black); + sbutton.draw_line(bw - 1,bh - 1,0,bh - 1,black).draw_line(0,bh - 1,0,0,black); + sbutton.draw_line(1,1,bw - 2,1,white).draw_line(1,bh - 2,1,1,white); + sbutton.draw_line(bw - 2,1,bw - 2,bh - 2,black).draw_line(bw - 2,bh - 2,1,bh - 2,black); + sbutton.draw_line(2,bh - 3,bw - 3,bh - 3,gray2).draw_line(bw - 3,bh - 3,bw - 3,2,gray2); + sbutton.draw_line(4,4,bw - 5,4,black,1,0xAAAAAAAA,true).draw_line(bw - 5,4,bw - 5,bh - 5,black,1,0xAAAAAAAA,false); + sbutton.draw_line(bw - 5,bh - 5,4,bh - 5,black,1,0xAAAAAAAA,false).draw_line(4,bh - 5,4,4,black,1,0xAAAAAAAA,false); CImg cbutton(bw,bh,1,3); - cbutton.draw_rectangle(0,0,bw-1,bh-1,black).draw_rectangle(1,1,bw-2,bh-2,gray2).draw_rectangle(2,2,bw-3,bh-3,gray); - cbutton.draw_line(4,4,bw-5,4,black,1,0xAAAAAAAA,true).draw_line(bw-5,4,bw-5,bh-5,black,1,0xAAAAAAAA,false); - cbutton.draw_line(bw-5,bh-5,4,bh-5,black,1,0xAAAAAAAA,false).draw_line(4,bh-5,4,4,black,1,0xAAAAAAAA,false); + cbutton.draw_rectangle(0,0,bw - 1,bh - 1,black).draw_rectangle(1,1,bw - 2,bh - 2,gray2). + draw_rectangle(2,2,bw - 3,bh - 3,gray); + cbutton.draw_line(4,4,bw - 5,4,black,1,0xAAAAAAAA,true).draw_line(bw - 5,4,bw - 5,bh - 5,black,1,0xAAAAAAAA,false); + cbutton.draw_line(bw - 5,bh - 5,4,bh - 5,black,1,0xAAAAAAAA,false).draw_line(4,bh - 5,4,4,black,1,0xAAAAAAAA,false); cimglist_for(buttons,ll) { - CImg(cbutton).draw_image(1+(bw-buttons[ll].width())/2,1+(bh-buttons[ll].height())/2,buttons[ll]). + CImg(cbutton). + draw_image(1 + (bw -buttons[ll].width())/2,1 + (bh - buttons[ll].height())/2,buttons[ll]). move_to(cbuttons); - CImg(sbutton).draw_image((bw-buttons[ll].width())/2,(bh-buttons[ll].height())/2,buttons[ll]). + CImg(sbutton). + draw_image((bw - buttons[ll].width())/2,(bh - buttons[ll].height())/2,buttons[ll]). move_to(sbuttons); - CImg(button).draw_image((bw-buttons[ll].width())/2,(bh-buttons[ll].height())/2,buttons[ll]). + CImg(button). + draw_image((bw - buttons[ll].width())/2,(bh - buttons[ll].height())/2,buttons[ll]). move_to(buttons[ll]); } @@ -49448,36 +51140,36 @@ namespace cimg { ((CImg().draw_text(0,0,"%s",gray,0,1,13,msg)*=-1)+=200).resize(-100,-100,1,3).move_to(canvas); const unsigned int - bwall = (buttons._width-1)*(12+bw) + bw, - w = cimg::max(196U,36+logo._width+canvas._width,24+bwall), - h = cimg::max(96U,36+canvas._height+bh,36+logo._height+bh), - lx = 12 + (canvas._data?0:((w-24-logo._width)/2)), - ly = (h-12-bh-logo._height)/2, - tx = lx+logo._width+12, - ty = (h-12-bh-canvas._height)/2, - bx = (w-bwall)/2, - by = h-12-bh; + bwall = (buttons._width - 1)*(12 + bw) + bw, + w = cimg::max(196U,36 + logo._width + canvas._width,24 + bwall), + h = cimg::max(96U,36 + canvas._height + bh,36 + logo._height + bh), + lx = 12 + (canvas._data?0:((w - 24 - logo._width)/2)), + ly = (h - 12 - bh - logo._height)/2, + tx = lx + logo._width + 12, + ty = (h - 12 - bh - canvas._height)/2, + bx = (w - bwall)/2, + by = h - 12 - bh; if (canvas._data) canvas = CImg(w,h,1,3). - draw_rectangle(0,0,w-1,h-1,gray). - draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white). - draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black). + draw_rectangle(0,0,w - 1,h - 1,gray). + draw_line(0,0,w - 1,0,white).draw_line(0,h - 1,0,0,white). + draw_line(w - 1,0,w - 1,h - 1,black).draw_line(w - 1,h - 1,0,h - 1,black). draw_image(tx,ty,canvas); else canvas = CImg(w,h,1,3). - draw_rectangle(0,0,w-1,h-1,gray). - draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white). - draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black); + draw_rectangle(0,0,w - 1,h - 1,gray). + draw_line(0,0,w - 1,0,white).draw_line(0,h - 1,0,0,white). + draw_line(w - 1,0,w - 1,h - 1,black).draw_line(w - 1,h - 1,0,h - 1,black); if (logo._data) canvas.draw_image(lx,ly,logo); unsigned int xbuttons[6] = { 0 }; - cimglist_for(buttons,lll) { xbuttons[lll] = bx+(bw+12)*lll; canvas.draw_image(xbuttons[lll],by,buttons[lll]); } + cimglist_for(buttons,lll) { xbuttons[lll] = bx + (bw + 12)*lll; canvas.draw_image(xbuttons[lll],by,buttons[lll]); } // Open window and enter events loop CImgDisplay disp(canvas,title?title:" ",0,false,is_centered?true:false); if (is_centered) disp.move((CImgDisplay::screen_width() - disp.width())/2, - (CImgDisplay::screen_height() - disp.height())/2); + (CImgDisplay::screen_height() - disp.height())/2); bool stop_flag = false, refresh = false; int oselected = -1, oclicked = -1, selected = -1, clicked = -1; while (!disp.is_closed() && !stop_flag) { @@ -49498,8 +51190,8 @@ namespace cimg { oclicked = clicked; clicked = -1; cimglist_for(buttons,l) - if (disp.mouse_y()>=(int)by && disp.mouse_y()<(int)(by+bh) && - disp.mouse_x()>=(int)xbuttons[l] && disp.mouse_x()<(int)(xbuttons[l]+bw)) { + if (disp.mouse_y()>=(int)by && disp.mouse_y()<(int)(by + bh) && + disp.mouse_x()>=(int)xbuttons[l] && disp.mouse_x()<(int)(xbuttons[l] + bw)) { clicked = selected = l; refresh = true; } @@ -49509,13 +51201,13 @@ namespace cimg { if (disp.key()) { oselected = selected; switch (disp.key()) { - case cimg::keyESC : selected=-1; stop_flag = true; break; + case cimg::keyESC : selected = -1; stop_flag = true; break; case cimg::keyENTER : if (selected<0) selected = 0; stop_flag = true; break; case cimg::keyTAB : case cimg::keyARROWRIGHT : - case cimg::keyARROWDOWN : selected = (selected+1)%buttons._width; break; + case cimg::keyARROWDOWN : selected = (selected + 1)%buttons.width(); break; case cimg::keyARROWLEFT : - case cimg::keyARROWUP : selected = (selected+buttons._width-1)%buttons._width; break; + case cimg::keyARROWUP : selected = (selected + buttons.width() - 1)%buttons.width(); break; } disp.set_key(); if (selected!=oselected) refresh = true; @@ -49547,8 +51239,8 @@ namespace cimg { \par Example \code const double - res1 = cimg::eval("cos(x)^2+sin(y)^2",2,2), // will return '1'. - res2 = cimg::eval(0,1,1); // will return '1' too. + res1 = cimg::eval("cos(x)^2 + sin(y)^2",2,2), // will return '1'. + res2 = cimg::eval(0,1,1); // will return '1' too. \endcode **/ inline double eval(const char *const expression, const double x, const double y, const double z, const double c) { -- libgit2 0.21.4