1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/PTdecode/CImg-1.3.0/examples/gmic.cpp Mon Aug 03 14:09:20 2009 +0100 1.3 @@ -0,0 +1,4648 @@ 1.4 +/* 1.5 + # 1.6 + # File : gmic.cpp 1.7 + # ( C++ source file ) 1.8 + # 1.9 + # Description : GREYC's Magic Image Converter (library and executable) 1.10 + # ( http://gmic.sourceforge.net ) 1.11 + # This file is a part of the CImg Library project. 1.12 + # ( http://cimg.sourceforge.net ) 1.13 + # 1.14 + # Copyright : David Tschumperle 1.15 + # ( http://www.greyc.ensicaen.fr/~dtschump/ ) 1.16 + # 1.17 + # License : CeCILL v2.0 1.18 + # ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html ) 1.19 + # 1.20 + # This software is governed by the CeCILL license under French law and 1.21 + # abiding by the rules of distribution of free software. You can use, 1.22 + # modify and/ or redistribute the software under the terms of the CeCILL 1.23 + # license as circulated by CEA, CNRS and INRIA at the following URL 1.24 + # "http://www.cecill.info". 1.25 + # 1.26 + # As a counterpart to the access to the source code and rights to copy, 1.27 + # modify and redistribute granted by the license, users are provided only 1.28 + # with a limited warranty and the software's author, the holder of the 1.29 + # economic rights, and the successive licensors have only limited 1.30 + # liability. 1.31 + # 1.32 + # In this respect, the user's attention is drawn to the risks associated 1.33 + # with loading, using, modifying and/or developing or reproducing the 1.34 + # software by the user in light of its specific status of free software, 1.35 + # that may mean that it is complicated to manipulate, and that also 1.36 + # therefore means that it is reserved for developers and experienced 1.37 + # professionals having in-depth computer knowledge. Users are therefore 1.38 + # encouraged to load and test the software's suitability as regards their 1.39 + # requirements in conditions enabling the security of their systems and/or 1.40 + # data to be ensured and, more generally, to use and operate it in the 1.41 + # same conditions as regards security. 1.42 + # 1.43 + # The fact that you are presently reading this means that you have had 1.44 + # knowledge of the CeCILL license and that you accept its terms. 1.45 + # 1.46 +*/ 1.47 + 1.48 +// Add specific G'MIC methods to the CImg<T> class. 1.49 +//------------------------------------------------- 1.50 +#ifdef cimg_plugin 1.51 + 1.52 +template<typename t> 1.53 +CImg<T> get_replace(const CImg<t>& img) const { 1.54 + return +img; 1.55 +} 1.56 + 1.57 +template<typename t> 1.58 +CImg<T>& replace(CImg<t>& img) { 1.59 + return img.transfer_to(*this); 1.60 +} 1.61 + 1.62 +CImg<T>& gmic_set(const double value, const int x, const int y, const int z, const int v) { 1.63 + (*this).atXYZV(x,y,z,v,0) = (T)value; 1.64 + return *this; 1.65 +} 1.66 + 1.67 +CImg<T> get_gmic_set(const double value, const int x, const int y, const int z, const int v) const { 1.68 + return (+*this).gmic_set(value,x,y,z,v); 1.69 +} 1.70 + 1.71 +CImg<T> get_draw_point(const int x, const int y, const int z, 1.72 + const CImg<T>& col, const float opacity) const { 1.73 + return (+*this).draw_point(x,y,z,col,opacity); 1.74 +} 1.75 + 1.76 +CImg<T> get_draw_line(const int x0, const int y0, const int x1, const int y1, 1.77 + const CImg<T>& col, const float opacity) const { 1.78 + return (+*this).draw_line(x0,y0,x1,y1,col,opacity); 1.79 +} 1.80 + 1.81 +template<typename t> 1.82 +CImg<T> get_draw_polygon(const CImg<t>& pts, const CImg<T>& col, const float opacity) const { 1.83 + return (+*this).draw_polygon(pts,col,opacity); 1.84 +} 1.85 + 1.86 +CImg<T> get_draw_ellipse(const int x, const int y, const float r0, const float r1, 1.87 + const float ru, const float rv, const CImg<T>& col, const float opacity) const { 1.88 + return (+*this).draw_ellipse(x,y,r0,r1,ru,rv,col,opacity); 1.89 +} 1.90 + 1.91 +CImg<T> get_draw_text(const int x, const int y, const char *const text, const T *const col, 1.92 + const int bg, const float opacity,const int siz) const { 1.93 + return (+*this).draw_text(x,y,text,col,bg,opacity,siz); 1.94 +} 1.95 + 1.96 +CImg<T> get_draw_image(const int x, const int y, const int z, 1.97 + const CImg<T>& sprite, const CImg<T>& mask, const float opacity) const { 1.98 + return (+*this).draw_image(x,y,z,sprite,mask,opacity); 1.99 +} 1.100 + 1.101 +CImg<T> get_draw_image(const int x, const int y, const int z, 1.102 + const CImg<T>& sprite, const float opacity) const { 1.103 + return (+*this).draw_image(x,y,z,sprite,opacity); 1.104 +} 1.105 + 1.106 +CImg<T> get_draw_plasma(const float alpha, const float beta, const float opacity) const { 1.107 + return (+*this).draw_plasma(alpha,beta,opacity); 1.108 +} 1.109 + 1.110 +CImg<T> get_draw_mandelbrot(const CImg<T>& color_palette, const float opacity, 1.111 + const double z0r, const double z0i, const double z1r, const double z1i, 1.112 + const unsigned int itermax, const bool normalized_iteration, 1.113 + const bool julia_set, const double paramr, const double parami) const { 1.114 + return (+*this).draw_mandelbrot(color_palette,opacity,z0r,z0i,z1r,z1i,itermax, 1.115 + normalized_iteration,julia_set,paramr,parami); 1.116 +} 1.117 + 1.118 +CImg<T> get_draw_fill(const int x, const int y, const int z, 1.119 + const CImg<T>& col, const float opacity, const float tolerance) const { 1.120 + return (+*this).draw_fill(x,y,z,col,opacity,tolerance); 1.121 +} 1.122 + 1.123 +bool is_CImg3d() const { 1.124 + const bool is_header = (width==1 && height>=8 && depth==1 && dim==1 && 1.125 + (*this)[0]=='C'+0.5f && (*this)[1]=='I'+0.5f && 1.126 + (*this)[2]=='m'+0.5f && (*this)[3]=='g'+0.5f && 1.127 + (*this)[4]=='3'+0.5f && (*this)[5]=='d'+0.5f); 1.128 + if (!is_header) return false; 1.129 + const int 1.130 + nbv = (int)(*this)[6], 1.131 + nbp = (int)(*this)[7]; 1.132 + if (nbv<=0 || nbp<=0) return false; 1.133 + const T *ptrs = ptr() + 8 + 3*nbv, *const ptre = end(); 1.134 + if (ptrs>=ptre) return false; 1.135 + for (int i = 0; i<nbp && ptrs<ptre; ++i) { 1.136 + const int N = (int)*(ptrs++); 1.137 + if (N<=0 || N>=8) return false; 1.138 + ptrs+=N; 1.139 + } 1.140 + ptrs+=4*nbp; 1.141 + if (ptrs>ptre) return false; 1.142 + return true; 1.143 +} 1.144 + 1.145 +template<typename tp, typename tf, typename tc, typename to> 1.146 +CImg<T> get_draw_object3d(const float x0, const float y0, const float z0, 1.147 + const CImg<tp>& points, const CImgList<tf>& primitives, 1.148 + const CImgList<tc>& colors, const CImg<to>& opacities, 1.149 + const unsigned int render_type, const bool double_sided, 1.150 + const float focale, const float lightx, const float lighty, 1.151 + const float lightz, const float specular_light, const float specular_shine, 1.152 + float *const zbuffer) const { 1.153 + return (+*this).draw_object3d(x0,y0,z0,points,primitives,colors,opacities,render_type,double_sided,focale, 1.154 + lightx,lighty,lightz,specular_light,specular_shine,zbuffer); 1.155 +} 1.156 + 1.157 +template<typename tp, typename tc, typename to> 1.158 +CImg<T>& object3dtoCImg3d(CImgList<tp>& primitives, CImgList<tc>& colors, CImg<to>& opacities) { 1.159 + if (is_empty() || !primitives) { primitives.assign(); colors.assign(); opacities.assign(); return *this; } 1.160 + const unsigned int primitives_size = primitives.size; 1.161 + CImgList<floatT> res; 1.162 + res.insert(CImg<floatT>("CImg3d",1,6,1,1,false)+=0.5f); 1.163 + res.insert(CImg<floatT>::vector((float)width,(float)primitives.size)); 1.164 + res.insert(1); resize(-100,3,1,1,0).transpose().unroll('y').transfer_to(res.last()); 1.165 + cimglist_for(primitives,p) { 1.166 + res.insert(CImg<floatT>::vector((float)primitives[p].size())).insert(primitives[p]).last().unroll('y'); 1.167 + primitives[p].assign(); 1.168 + } 1.169 + primitives.assign(); 1.170 + const unsigned int defined_colors = colors.size; 1.171 + cimglist_for(colors,c) { res.insert(colors[c]).last().resize(1,3,1,1,-1); colors[c].assign(); } 1.172 + colors.assign(); 1.173 + if (defined_colors<primitives_size) res.insert(1).last().assign(1,3*(primitives_size-defined_colors),1,1,200); 1.174 + const unsigned int defined_opacities = opacities.size(); 1.175 + res.insert(opacities).last().unroll('y'); 1.176 + opacities.assign(); 1.177 + if (defined_opacities<primitives.size) res.insert(1).last().assign(1,primitives_size-defined_opacities,1,1,1); 1.178 + return res.get_append('y').transfer_to(*this); 1.179 +} 1.180 + 1.181 +template<typename tp, typename tc, typename to> 1.182 +CImg<T>& CImg3dtoobject3d(CImgList<tp>& primitives, CImgList<tc>& colors, CImg<to>& opacities) { 1.183 + const T *ptrs = ptr() + 6; 1.184 + const unsigned int 1.185 + nbv = (unsigned int)*(ptrs++), 1.186 + nbp = (unsigned int)*(ptrs++); 1.187 + CImg<T> points(nbv,3); 1.188 + primitives.assign(nbp); 1.189 + colors.assign(nbp,1,3,1,1); 1.190 + opacities.assign(nbp); 1.191 + cimg_forX(points,x) { points(x,0) = (T)*(ptrs++); points(x,1) = (T)*(ptrs++); points(x,2) = (T)*(ptrs++); } 1.192 + cimglist_for(primitives,p) { 1.193 + const unsigned int N = (unsigned int)*(ptrs++); 1.194 + primitives[p].assign(ptrs,1,N,1,1,false); 1.195 + ptrs+=N; 1.196 + } 1.197 + cimglist_for(colors,c) { colors(c,0) = (tc)*(ptrs++); colors(c,1) = (tc)*(ptrs++); colors(c,2) = (tc)*(ptrs++); } 1.198 + opacities.assign(ptrs,1,nbp,1,1,false); 1.199 + return assign(points); 1.200 +} 1.201 + 1.202 +CImg<T> get_appendCImg3d(const CImg<T>& img) const { 1.203 + CImg<T> res(1,img.size() + size() - 8); 1.204 + const T *ptrs = ptr() + 6, *ptrs0 = img.ptr() + 6; 1.205 + T *ptrd = res.ptr(); 1.206 + *(ptrd++) = (T)('C' + 0.5f); *(ptrd++) = (T)('I' + 0.5f); 1.207 + *(ptrd++) = (T)('m' + 0.5f); *(ptrd++) = (T)('g' + 0.5f); 1.208 + *(ptrd++) = (T)('3' + 0.5f); *(ptrd++) = (T)('d' + 0.5f); 1.209 + const unsigned int 1.210 + nbv = (unsigned int)*(ptrs++), 1.211 + nbv0 = (unsigned int)*(ptrs0++), 1.212 + nbp = (unsigned int)*(ptrs++), 1.213 + nbp0 = (unsigned int)*(ptrs0++); 1.214 + *(ptrd++) = (T)(nbv + nbv0); 1.215 + *(ptrd++) = (T)(nbp + nbp0); 1.216 + std::memcpy(ptrd,ptrs,sizeof(T)*nbv*3); 1.217 + ptrd+=3*nbv; ptrs+=3*nbv; 1.218 + std::memcpy(ptrd,ptrs0,sizeof(T)*nbv0*3); 1.219 + ptrd+=3*nbv0; ptrs0+=3*nbv0; 1.220 + for (unsigned int i = 0; i<nbp; ++i) { 1.221 + const unsigned int N = (unsigned int)*(ptrs++); 1.222 + *(ptrd++) = (T)N; 1.223 + std::memcpy(ptrd,ptrs,sizeof(T)*N); 1.224 + ptrd+=N; ptrs+=N; 1.225 + } 1.226 + for (unsigned int i = 0; i<nbp0; ++i) { 1.227 + const unsigned int N = (unsigned int)*(ptrs0++); 1.228 + *(ptrd++) = (T)N; 1.229 + for (unsigned int j = 0; j<N; ++j) *(ptrd++) = (T)(*(ptrs0++) + nbv); 1.230 + } 1.231 + std::memcpy(ptrd,ptrs,sizeof(T)*nbp*3); 1.232 + ptrd+=3*nbp; ptrs+=3*nbp; 1.233 + std::memcpy(ptrd,ptrs0,sizeof(T)*nbp0*3); 1.234 + ptrd+=3*nbp0; ptrs0+=3*nbp0; 1.235 + std::memcpy(ptrd,ptrs,sizeof(T)*nbp); 1.236 + ptrd+=nbp; 1.237 + std::memcpy(ptrd,ptrs0,sizeof(T)*nbp0); 1.238 + return res; 1.239 +} 1.240 + 1.241 +CImg<T>& appendCImg3d(const CImg<T>& img) { 1.242 + return get_appendCImg3d(img).transfer_to(*this); 1.243 +} 1.244 + 1.245 +CImg<T>& centerCImg3d() { 1.246 + const unsigned int nbv = (unsigned int)(*this)[6]; 1.247 + const T *ptrs = ptr() + 8; 1.248 + float xm = cimg::type<float>::max(), ym = xm, zm = xm, xM = cimg::type<float>::min(), yM = xM, zM = xM; 1.249 + for (unsigned int i = 0; i<nbv; ++i) { 1.250 + const float x = (float)*(ptrs++), y = (float)*(ptrs++), z = (float)*(ptrs++); 1.251 + if (x<xm) xm = x; if (x>xM) xM = x; 1.252 + if (y<ym) ym = y; if (y>yM) yM = y; 1.253 + if (z<zm) zm = z; if (z>zM) zM = z; 1.254 + } 1.255 + const float xc = (xm + xM)/2, yc = (ym + yM)/2, zc = (zm + zM)/2; 1.256 + T *ptrd = ptr() + 8; 1.257 + for (unsigned int i = 0; i<nbv; ++i) { *(ptrd++)-=(T)xc; *(ptrd++)-=(T)yc; *(ptrd++)-=(T)zc; } 1.258 + return *this; 1.259 +} 1.260 + 1.261 +CImg<T> get_centerCImg3d() const { 1.262 + return (+*this).centerCImg3d(); 1.263 +} 1.264 + 1.265 +CImg<T>& normalizeCImg3d() { 1.266 + const unsigned int nbv = (unsigned int)(*this)[6]; 1.267 + const T *ptrs = ptr() + 8; 1.268 + float xm = cimg::type<float>::max(), ym = xm, zm = xm, xM = cimg::type<float>::min(), yM = xM, zM = xM; 1.269 + for (unsigned int i = 0; i<nbv; ++i) { 1.270 + const float x = (float)*(ptrs++), y = (float)*(ptrs++), z = (float)*(ptrs++); 1.271 + if (x<xm) xm = x; if (x>xM) xM = x; 1.272 + if (y<ym) ym = y; if (y>yM) yM = y; 1.273 + if (z<zm) zm = z; if (z>zM) zM = z; 1.274 + } 1.275 + const float delta = cimg::max(xM-xm,yM-ym,zM-zm); 1.276 + if (delta>0) { 1.277 + T *ptrd = ptr() + 8; 1.278 + for (unsigned int i = 0; i<3*nbv; ++i) *(ptrd++)/=(T)delta; 1.279 + } 1.280 + return *this; 1.281 +} 1.282 + 1.283 +CImg<T> get_normalizeCImg3d() const { 1.284 + return (+*this).normalizeCImg3d(); 1.285 +} 1.286 + 1.287 +template<typename t> 1.288 +CImg<T>& rotateCImg3d(const CImg<t>& rot) { 1.289 + const unsigned int nbv = (unsigned int)(*this)[6]; 1.290 + const T *ptrs = ptr() + 8; 1.291 + const float 1.292 + a = (float)rot(0,0), b = (float)rot(1,0), c = (float)rot(2,0), 1.293 + d = (float)rot(0,1), e = (float)rot(1,1), f = (float)rot(2,1), 1.294 + g = (float)rot(0,2), h = (float)rot(1,2), i = (float)rot(2,2); 1.295 + T *ptrd = ptr() + 8; 1.296 + for (unsigned int j = 0; j<nbv; ++j) { 1.297 + const float x = (float)*(ptrs++), y = (float)*(ptrs++), z = (float)*(ptrs++); 1.298 + *(ptrd++) = (T)(a*x + b*y + c*z); 1.299 + *(ptrd++) = (T)(d*x + e*y + f*z); 1.300 + *(ptrd++) = (T)(g*x + h*y + i*z); 1.301 + } 1.302 + return *this; 1.303 +} 1.304 + 1.305 +template<typename t> 1.306 +CImg<T> get_rotateCImg3d(const CImg<t>& rot) const { 1.307 + return (+*this).rotateCImg3d(rot); 1.308 +} 1.309 + 1.310 +CImg<T>& translateCImg3d(const float tx, const float ty, const float tz) { 1.311 + const unsigned int nbv = (unsigned int)(*this)[6]; 1.312 + T *ptrd = ptr() + 8; 1.313 + for (unsigned int j = 0; j<nbv; ++j) { *(ptrd++) += (T)tx; *(ptrd++) += (T)ty; *(ptrd++) += (T)tz; } 1.314 + return *this; 1.315 +} 1.316 + 1.317 +CImg<T> get_translateCImg3d(const float tx, const float ty, const float tz) const { 1.318 + return (+*this).translateCImg3d(tx,ty,tz); 1.319 +} 1.320 + 1.321 +CImg<T>& coloropacityCImg3d(const float R, const float G, const float B, const float opacity, const bool set_RGB, const bool set_opacity) { 1.322 + T *ptrd = ptr() + 6; 1.323 + const unsigned int 1.324 + nbv = (unsigned int)*(ptrd++), 1.325 + nbp = (unsigned int)*(ptrd++); 1.326 + ptrd+=3*nbv; 1.327 + for (unsigned int i = 0; i<nbp; ++i) { const unsigned int N = (unsigned int)*(ptrd++); ptrd+=N; } 1.328 + if (set_RGB) for (unsigned int c = 0; c<nbp; ++c) { *(ptrd++) = (T)R; *(ptrd++) = (T)G; *(ptrd++) = (T)B; } else ptrd+=3*nbp; 1.329 + if (set_opacity) for (unsigned int o = 0; o<nbp; ++o) *(ptrd++) = (T)opacity; 1.330 + return *this; 1.331 +} 1.332 + 1.333 +CImg<T> get_coloropacityCImg3d(const float R, const float G, const float B, const float opacity, const bool set_RGB, const bool set_opacity) const { 1.334 + return (+*this).coloropacityCImg3d(R,G,B,opacity,set_RGB,set_opacity); 1.335 +} 1.336 + 1.337 +#else // eq. to #ifndef cimg_plugin 1.338 + 1.339 +#define cimg_debug 1 1.340 +#ifndef cimg_gmic_cpp 1.341 +#define cimg_gmic_cpp "examples/gmic.cpp" 1.342 +#define cimg_cimg_h "../CImg.h" 1.343 +#endif 1.344 +#define cimg_stdout stdout 1.345 +#define cimg_plugin cimg_gmic_cpp 1.346 +#include cimg_cimg_h 1.347 +#include "gmic.h" 1.348 +using namespace cimg_library; 1.349 + 1.350 +// The lines below are necessary when using a non-standard compiler such as visualcpp6. 1.351 +#ifdef cimg_use_visualcpp6 1.352 +#define std 1.353 +#endif 1.354 +#ifdef min 1.355 +#undef min 1.356 +#undef max 1.357 +#endif 1.358 + 1.359 +#if !defined(gmic_main) || !defined(gmic_separate_compilation) 1.360 + 1.361 +// Define some useful macros. 1.362 +//--------------------------- 1.363 + 1.364 +// Code for validity checking of indices. 1.365 +#define gmic_inds indices2string(indices,true) 1.366 +#define gmic_check_indice(ind,funcname) { \ 1.367 + const int indo = (int)ind; \ 1.368 + if (ind<0) ind+=images.size; \ 1.369 + if (ind<0 || ind>=(int)images.size) { \ 1.370 + if (images.size) error(funcname " : Invalid indice '[%d]' (valid indice range is -%u...%u).",gmic_inds,indo,images.size,images.size-1); \ 1.371 + else error(funcname " : Invalid indice '[%d]' (image list is empty).",gmic_inds,indo); \ 1.372 + } \ 1.373 +} 1.374 + 1.375 +// Code for having 'get' or 'non-get' versions of G'MIC commands. 1.376 +#define gmic_apply(instance,function) { \ 1.377 + if (get_version) { \ 1.378 + unsigned int posi = 0; \ 1.379 + if (images.contains(instance,posi)) filenames.insert(filenames[posi]); \ 1.380 + else filenames.insert(CImg<char>("(gmic)",7,1,1,1,false)); \ 1.381 + CImg<T> res = instance.get_##function; \ 1.382 + images.insert(1); res.transfer_to(images.last()); \ 1.383 + } else instance.function; \ 1.384 +} 1.385 + 1.386 +// Code for simple commands that has no parameters and act on images. 1.387 +#define gmic_simple_item(option,function,description) \ 1.388 + if (!cimg::strcmp(option,item0)) { \ 1.389 + print(description,gmic_inds); cimg_foroff(indices,l) gmic_apply(images[indices[l]],function()); \ 1.390 + continue; \ 1.391 +} 1.392 + 1.393 +// Code for the type cast command. 1.394 +#define gmic_cast(pixel_type,st_type) \ 1.395 + if (!cimg::strcmp(#pixel_type,argument)) { \ 1.396 + print("Set pixel type to '%s'.",#pixel_type); ++position; \ 1.397 + if (!cimg::strcmp(st_type,cimg::type<T>::string())) continue; \ 1.398 + CImgList<pixel_type> casted_images; \ 1.399 + while (images) { casted_images.insert(images[0]); images.remove(0); } \ 1.400 + return parse_##pixel_type(casted_images); \ 1.401 +} 1.402 + 1.403 +// Code for G'MIC arithmetic commands. 1.404 +#define gmic_arithmetic_item(option1,option2,\ 1.405 + function1,description1,arg1_1,arg1_2,value_type1, \ 1.406 + function2,description2_1,description2_2,arg2_1,arg2_2,description3) \ 1.407 + if (!cimg::strcmp(option1,item0) || !cimg::strcmp(option2,item0)) { \ 1.408 + double value = 0; char inds[4096] = { 0 }, sep = 0, end = 0; \ 1.409 + if (std::sscanf(argument,"%lf%c",&value,&end)==1) { \ 1.410 + print(description1 ".",arg1_1,arg1_2); \ 1.411 + cimg_foroff(indices,l) \ 1.412 + if (get_version) { \ 1.413 + images.insert(images[indices[l]]); images.last().function1((value_type1)value); \ 1.414 + filenames.insert(filenames[indices[l]]); } \ 1.415 + else images[indices[l]].function1((value_type1)value); \ 1.416 + ++position; \ 1.417 + } else if (std::sscanf(argument,"[%4095[0-9.eE%+-]%c%c",inds,&sep,&end)==2 && sep==']') { \ 1.418 + const CImg<unsigned int> ind = indices2cimg(inds,images.size,option1); \ 1.419 + if (ind.size()!=1) error(description2_1 " : Argument '[%s]' should contain one indice.",gmic_inds,inds); \ 1.420 + print(description2_2 ".",arg2_1,arg2_2); \ 1.421 + const CImg<T> img0 = images[ind[0]]; \ 1.422 + cimg_foroff(indices,l) \ 1.423 + if (get_version) { \ 1.424 + images.insert(images[indices[l]]); images.last().function2(img0); \ 1.425 + filenames.insert(filenames[indices[l]]); } \ 1.426 + else images[indices[l]].function2(img0); \ 1.427 + ++position; \ 1.428 + } else { \ 1.429 + print(description3 ".",gmic_inds); \ 1.430 + if (images && indices) { \ 1.431 + for (unsigned int siz = indices.size(), ind0 = indices[0], off = 0, l = 1; l<siz; ++l) { \ 1.432 + const unsigned int ind = indices[l] - off; \ 1.433 + images[ind0].function2(images[ind]); \ 1.434 + images.remove(ind); filenames.remove(ind); \ 1.435 + ++off; \ 1.436 + }}} continue; \ 1.437 +} 1.438 + 1.439 +// Constructors. 1.440 +//-------------- 1.441 +#if defined(gmic_float) || !defined(gmic_separate_compilation) 1.442 + 1.443 +#include "gmic_def.h" 1.444 + 1.445 +gmic_exception::gmic_exception() { 1.446 + message[0] = '\0'; 1.447 +} 1.448 + 1.449 +gmic_exception::gmic_exception(const char *format, ...) { 1.450 + std::va_list ap; 1.451 + va_start(ap,format); 1.452 + std::vsprintf(message,format,ap); 1.453 + va_end(ap); 1.454 +} 1.455 + 1.456 +gmic_exception::gmic_exception(const char *format, std::va_list ap) { 1.457 + std::vsprintf(message,format,ap); 1.458 +} 1.459 + 1.460 +gmic::gmic() { 1.461 + assign(0); 1.462 +} 1.463 + 1.464 +// Set default values of G'MIC parameters and macros. 1.465 +//---------------------------------------------------- 1.466 +gmic& gmic::assign(const unsigned int size, const char *const custom_macros, const bool add_macros_start) { 1.467 + filenames.assign(size,CImg<char>("(gmic)",7,1,1,1,false)); 1.468 + position = 0; 1.469 + verbosity_level = 0; 1.470 + is_released = true; 1.471 + is_debug = false; 1.472 + is_begin = true; 1.473 + background3d[0] = 120; 1.474 + background3d[1] = 120; 1.475 + background3d[2] = 140; 1.476 + render3d = 4; 1.477 + renderd3d = -1; 1.478 + is_oriented3d = false; 1.479 + focale3d = 500; 1.480 + light3d_x = 0; 1.481 + light3d_y = 0; 1.482 + light3d_z = -5000; 1.483 + specular_light3d = 0.15f; 1.484 + specular_shine3d = 0.8f; 1.485 + is_fullpath = false; 1.486 + add_macros(data_def,sizeof(data_def)-1,true); 1.487 + add_macros(custom_macros,cimg::strlen(custom_macros)-1,add_macros_start); 1.488 + return *this; 1.489 +} 1.490 + 1.491 +// Error procedure. 1.492 +//----------------- 1.493 +const gmic& gmic::error(const char *format, ...) const { 1.494 + va_list ap; 1.495 + va_start(ap,format); 1.496 + char message[1024] = { 0 }; 1.497 + std::vsprintf(message,format,ap); 1.498 + va_end(ap); 1.499 + if (verbosity_level>=0) { 1.500 + std::fprintf(cimg_stdout,"\n<gmic-#%u> ** Error ** %s",filenames.size,message); 1.501 + std::fprintf(cimg_stdout,"\n<gmic-#%u> Abort G'MIC instance.\n",filenames.size); 1.502 + std::fflush(cimg_stdout); 1.503 + } 1.504 + throw gmic_exception(message); 1.505 + return *this; 1.506 +} 1.507 + 1.508 +// Warning procedure. 1.509 +//------------------- 1.510 +const gmic& gmic::warning(const char *format, ...) const { 1.511 + va_list ap; 1.512 + va_start(ap,format); 1.513 + if (verbosity_level>=0) { 1.514 + std::fprintf(cimg_stdout,"\n<gmic-#%u> ** Warning ** ",filenames.size); 1.515 + std::vfprintf(cimg_stdout,format,ap); 1.516 + std::fflush(cimg_stdout); 1.517 + } 1.518 + va_end(ap); 1.519 + return *this; 1.520 +} 1.521 + 1.522 +// Print debug messages. 1.523 +//---------------------- 1.524 +const gmic& gmic::debug(const char *format, ...) const { 1.525 + const char t_normal[] = { 0x1b,'[','0',';','0',';','0','m','\0' }; 1.526 + const char t_red[] = { 0x1b,'[','4',';','3','1',';','5','9','m','\0' }; 1.527 + const char t_bold[] = { 0x1b,'[','1','m','\0' }; 1.528 + if (is_debug) { 1.529 + va_list ap; 1.530 + va_start(ap,format); 1.531 + std::fprintf(cimg_stdout,"\n%s%s<gmic-debug-#%u>%s ",t_bold,t_red,filenames.size,t_normal); 1.532 + std::vfprintf(cimg_stdout,format,ap); 1.533 + va_end(ap); 1.534 + std::fflush(cimg_stdout); 1.535 + } 1.536 + return *this; 1.537 +} 1.538 + 1.539 +// Print status messages. 1.540 +//----------------------- 1.541 +const gmic& gmic::print(const char *format, ...) const { 1.542 + va_list ap; 1.543 + va_start(ap,format); 1.544 + if (verbosity_level>=0) { 1.545 + std::fprintf(cimg_stdout,"\n<gmic-#%u> ",filenames.size); 1.546 + std::vfprintf(cimg_stdout,format,ap); 1.547 + std::fflush(cimg_stdout); 1.548 + } 1.549 + va_end(ap); 1.550 + return *this; 1.551 +} 1.552 + 1.553 +// Add macros from a char* buffer. 1.554 +//--------------------------------- 1.555 +gmic& gmic::add_macros(const char *const data_macros, const unsigned int data_size, const bool add_macros_at_start) { 1.556 + if (!data_macros || !data_size) return *this; 1.557 + char mac[4096] = { 0 }, com[256*1024] = { 0 }, line[256*1024] = { 0 }, sep = 0; 1.558 + const char *data = data_macros, *const data_end = data_macros + data_size; 1.559 + while (data<data_end) { 1.560 + if (*data=='\n') ++data; 1.561 + else { 1.562 + if (std::sscanf(data,"%262143[^\n]",line)>0) data += cimg::strlen(line) + 1; 1.563 + if (line[0]!='#') { // Useful line (not a comment) 1.564 + mac[0] = com[0] = 0; 1.565 + if (std::sscanf(line,"%4095[^: ] %c %262143[^\n]",mac,&sep,com)>=2 && sep==':' && 1.566 + std::sscanf(mac,"%4095s",line)==1) { // Macro definition. 1.567 + macros.insert(CImg<char>(line,cimg::strlen(line)+1,1,1,1,false),add_macros_at_start?0:macros.size); 1.568 + commands.insert(CImg<char>(com,cimg::strlen(com)+1,1,1,1,false),add_macros_at_start?0:commands.size); 1.569 + } else { // Possible continuation of a previous macro definition. 1.570 + if (!macros) error("Fatal error : Invalid G'MIC macros data."); 1.571 + CImg<char> &last = commands[add_macros_at_start?0:commands.size-1]; 1.572 + last[last.size()-1] = ' '; 1.573 + last.append(CImg<char>(line,cimg::strlen(line)+1,1,1,1,false),'x'); 1.574 + } 1.575 + } 1.576 + } 1.577 + } 1.578 + return *this; 1.579 +} 1.580 + 1.581 +// Add macros from a macro file. 1.582 +//------------------------------ 1.583 +gmic& gmic::add_macros(std::FILE *const file, const bool add_macros_at_start) { 1.584 + if (!file) return *this; 1.585 + char mac[4096] = { 0 }, com[256*1024] = { 0 }, line[256*1024] = { 0 }, sep = 0; 1.586 + int err = 0; 1.587 + while ((err=std::fscanf(file,"%262143[^\n] ",line)>=0)) { 1.588 + if (err) { // Non empty-line 1.589 + mac[0] = com[0] = 0; 1.590 + if (line[0]!='#') { // Useful line (not a comment). 1.591 + if (std::sscanf(line,"%4095[^: ] %c %262143[^\n]",mac,&sep,com)>=2 && sep==':' && 1.592 + std::sscanf(mac,"%4095s",line)==1) { // Macro definition. 1.593 + macros.insert(CImg<char>(line,cimg::strlen(line)+1,1,1,1,false),add_macros_at_start?0:macros.size); 1.594 + commands.insert(CImg<char>(com,cimg::strlen(com)+1,1,1,1,false),add_macros_at_start?0:commands.size); 1.595 + } else { // Possible continuation of a previous macro definition. 1.596 + if (!macros) error("Fatal error : Invalid G'MIC macros data."); 1.597 + CImg<char> &last = commands[add_macros_at_start?0:commands.size-1]; 1.598 + last[last.size()-1] = ' '; 1.599 + last.append(CImg<char>(line,cimg::strlen(line)+1,1,1,1,false),'x'); 1.600 + } 1.601 + } 1.602 + } 1.603 + } 1.604 + return *this; 1.605 +} 1.606 + 1.607 +// Return indices of the images from a string. 1.608 +//-------------------------------------------- 1.609 +CImg<unsigned int> gmic::indices2cimg(const char *const string, const unsigned int indice_max, 1.610 + const char *const command) const { 1.611 + if (!cimg::strlen(string)) return CImg<unsigned int>(); 1.612 + CImgList<unsigned int> inds; 1.613 + const char *it = string; 1.614 + for (bool stopflag = false; !stopflag; ) { 1.615 + char sep = 0, end = 0, item0[4096] = { 0 }, item1[4096] = { 0 }; 1.616 + float ind0 = 0, ind1 = 0, step = 1; 1.617 + if (std::sscanf(it,"%4095[^,]%c",item0,&end)!=2) stopflag = true; 1.618 + else it += 1 + cimg::strlen(item0); 1.619 + const int err = std::sscanf(item0,"%4095[^:]%c%f%c",item1,&sep,&step,&end); 1.620 + if (err!=1 && err!=3) error("Command '%s' : Invalid indice(s) '[%s]'.",command,string); 1.621 + if (std::sscanf(item1,"%f%%-%f%c%c",&ind0,&ind1,&sep,&end)==3 && sep=='%') { 1.622 + ind0 = (float)cimg::round(ind0*indice_max/100,1); 1.623 + ind1 = (float)cimg::round(ind1*indice_max/100,1); 1.624 + } else if (std::sscanf(item1,"%f%%-%f%c",&ind0,&ind1,&end)==2) 1.625 + ind0 = (float)cimg::round(ind0*indice_max/100,1); 1.626 + else if (std::sscanf(item1,"%f-%f%c%c",&ind0,&ind1,&sep,&end)==3 && sep=='%') 1.627 + ind1 = (float)cimg::round(ind1*indice_max/100,1); 1.628 + else if (std::sscanf(item1,"%f-%f%c",&ind0,&ind1,&end)==2) { } 1.629 + else if (std::sscanf(item1,"%f%c%c",&ind0,&sep,&end)==2 && sep=='%') 1.630 + ind1 = (ind0 = (float)cimg::round(ind0*indice_max/100,1)); 1.631 + else if (std::sscanf(item1,"%f%c",&ind0,&end)==1) 1.632 + ind1 = ind0; 1.633 + else error("Command '%s' : Invalid indice(s) '[%s]'.",command,string); 1.634 + if (ind0<0) ind0+=indice_max; 1.635 + if (ind1<0) ind1+=indice_max; 1.636 + if (ind0<0 || ind0>=indice_max || ind1<0 || ind1>=indice_max || step<=0) { 1.637 + if (indice_max) error("Command '%s' : Invalid indice(s) '[%s]' (valid indice range is -%u...%u).", 1.638 + command,string,indice_max,indice_max-1); 1.639 + else error("Command '%s' : Invalid indice(s) '[%s]' (image list is empty).", 1.640 + command,string); 1.641 + } 1.642 + if (ind0>ind1) cimg::swap(ind0,ind1); 1.643 + const unsigned int 1.644 + iind0 = (unsigned int)ind0, 1.645 + _ind1 = (unsigned int)ind1, 1.646 + iind1 = (unsigned int)(_ind1 - cimg::mod((float)_ind1,step)); 1.647 + if (iind0==iind1) inds.insert(CImg<unsigned int>::vector(iind0)); 1.648 + else inds.insert(CImg<unsigned int>::sequence((unsigned int)(1+(iind1-iind0)/step), 1.649 + (unsigned int)iind0, 1.650 + (unsigned int)iind1).get_split('y')); 1.651 + } 1.652 + inds = inds.get_append('y').sort().get_split('y'); 1.653 + cimglist_for(inds,l) if (l!=inds.size-1 && inds(l,0)==inds(l+1,0)) inds.remove(l--); 1.654 + if (is_debug) { 1.655 + debug("Indices : "); 1.656 + inds.get_append('y').print(); // List indices if debug mode is activated. 1.657 + } 1.658 + return inds.get_append('y').sort(); 1.659 +} 1.660 + 1.661 +// Return stringified version of indices or filenames. 1.662 +//---------------------------------------------------- 1.663 +char* gmic::indices2string(const CImg<unsigned int>& indices, const bool display_indices) const { 1.664 + static char res0[4096] = { 0 }, res1[4096] = { 0 }; 1.665 + const unsigned int siz = indices.size(); 1.666 + if (display_indices) { 1.667 + switch (siz) { 1.668 + case 0: std::sprintf(res0," []"); break; 1.669 + case 1: std::sprintf(res0," [%u]",indices[0]); break; 1.670 + case 2: std::sprintf(res0,"s [%u,%u]",indices[0],indices[1]); break; 1.671 + case 3: std::sprintf(res0,"s [%u,%u,%u]",indices[0],indices[1],indices[2]); break; 1.672 + case 4: std::sprintf(res0,"s [%u,%u,%u,%u]",indices[0],indices[1],indices[2],indices[3]); break; 1.673 + default: std::sprintf(res0,"s [%u,...,%u]",indices[0],indices[siz-1]); 1.674 + } 1.675 + return res0; 1.676 + } 1.677 + switch (siz) { 1.678 + case 0: std::sprintf(res1," "); break; 1.679 + case 1: std::sprintf(res1,"%s",filenames[indices[0]].ptr()); break; 1.680 + case 2: std::sprintf(res1,"%s, %s",filenames[indices[0]].ptr(),filenames[indices[1]].ptr()); break; 1.681 + case 3: std::sprintf(res1,"%s, %s, %s",filenames[indices[0]].ptr(),filenames[indices[1]].ptr(), 1.682 + filenames[indices[2]].ptr()); break; 1.683 + case 4: std::sprintf(res1,"%s, %s, %s, %s",filenames[indices[0]].ptr(),filenames[indices[1]].ptr(), 1.684 + filenames[indices[2]].ptr(), filenames[indices[3]].ptr()); break; 1.685 + default: std::sprintf(res1,"%s, ..., %s",filenames[indices[0]].ptr(),filenames[indices[siz-1]].ptr()); 1.686 + } 1.687 + return res1; 1.688 +} 1.689 +#endif // #if defined(gmic_float) || !defined(gmic_separate_compilation) 1.690 + 1.691 +// Template constructors. 1.692 +//----------------------- 1.693 +template<typename T> 1.694 +gmic::gmic(const int argc, const char *const *const argv, CImgList<T>& images, const char *custom_macros, const bool add_macros_at_start) { 1.695 + assign(images.size,custom_macros,add_macros_at_start); 1.696 + for (int pos = 1; pos<argc; ++pos) 1.697 + command_line.insert(CImg<char>(argv[pos],cimg::strlen(argv[pos])+1,1,1,1,false)); 1.698 + is_released = false; 1.699 + parse(images); 1.700 +} 1.701 + 1.702 +template<typename T> 1.703 +gmic::gmic(const char *const command, CImgList<T>& images, const char *custom_macros, const bool add_macros_at_start) { 1.704 + assign(images.size,custom_macros,add_macros_at_start); 1.705 + char item[4096] = { 0 }; 1.706 + for (const char *ncommand = command; *ncommand; ) { 1.707 + if (std::sscanf(ncommand,"%[^ ]",item)==1) { 1.708 + const int l = cimg::strlen(item); 1.709 + command_line.insert(CImg<char>(item,l+1,1,1,1,false)); 1.710 + ncommand += l; 1.711 + while (*ncommand==' ') ++ncommand; 1.712 + } else break; 1.713 + } 1.714 + is_released = true; 1.715 + parse(images); 1.716 +} 1.717 + 1.718 +// Display specified image(s). 1.719 +//----------------------------- 1.720 +template<typename T> 1.721 +bool gmic::display_images(const CImgList<T>& images, const CImg<unsigned int>& indices, 1.722 + const bool verbose) const { 1.723 + if (!images || !indices) { print("Display image []."); return false; } 1.724 + CImgList<unsigned int> inds = indices.get_unroll('x').get_split('x'); 1.725 + CImgList<T> visu; 1.726 + unsigned int max_height = 0; 1.727 + cimglist_for(inds,l) { 1.728 + const CImg<T>& img = images[inds(l,0)]; 1.729 + if (img.height>max_height && !img.is_CImg3d()) max_height = img.height; 1.730 + } 1.731 + cimglist_for(inds,l) { 1.732 + const unsigned int ind = inds(l,0); 1.733 + const CImg<T> &img = images[ind]; 1.734 + if (img) { 1.735 + if (!max_height || img.height<max_height) visu.insert(img,~0U,true); 1.736 + else visu.insert(img.get_lines(0,max_height-1)); 1.737 + } else if (verbose) { warning("Display image : Image [%d] is empty.",ind); inds.remove(l--); } 1.738 + } 1.739 + const CImg<unsigned int> nindices = inds.get_append('x'); 1.740 + const char *const fnames = indices2string(nindices,false); 1.741 + print("Display image%s = '%s'.\n\n",gmic_inds,fnames); 1.742 + if (visu.size) { 1.743 + if (visu.size!=1) visu.display(fnames,verbosity_level>=0,'x','p'); 1.744 + else { 1.745 + const CImg<T> &img = visu[0]; 1.746 + char title[4096] = { 0 }; 1.747 + std::sprintf(title,"%s (%dx%dx%dx%d)",fnames,img.dimx(),img.dimy(),img.dimz(),img.dimv()); 1.748 + img.display(title,verbosity_level>=0); 1.749 + } 1.750 + } 1.751 + return true; 1.752 +} 1.753 + 1.754 +// Display plots of specified image(s). 1.755 +//-------------------------------------- 1.756 +template<typename T> 1.757 +bool gmic::display_plots(const CImgList<T>& images, const CImg<unsigned int>& indices, 1.758 + const unsigned int plot_type, const unsigned int vertex_type, 1.759 + const double xmin, const double xmax, 1.760 + const double ymin, const double ymax, 1.761 + const bool verbose) const { 1.762 + if (!images || !indices) { print("Plot image []."); return false; } 1.763 + CImgDisplay disp(cimg_fitscreen(640,480,1),0,0); 1.764 + cimg_foroff(indices,l) { 1.765 + const unsigned int ind = indices[l]; 1.766 + const CImg<T>& img = images[ind]; 1.767 + if (img) { 1.768 + print("Plot image%s = '%s'.\n",gmic_inds,indices2string(indices,false)); 1.769 + if (verbosity_level>=0) { std::fputc('\n',cimg_stdout); img.print(filenames[ind].ptr()); } 1.770 + char title[4096] = { 0 }; 1.771 + std::sprintf(title,"%s (%dx%dx%dx%d)", 1.772 + filenames[ind].ptr(),img.dimx(),img.dimy(),img.dimz(),img.dimv()); 1.773 + img.display_graph(disp.set_title(title),plot_type,vertex_type,0,xmin,xmax,0,ymin,ymax); 1.774 + } else if (verbose) warning("Plot image : Image [%d] is empty.",ind); 1.775 + } 1.776 + return true; 1.777 +} 1.778 + 1.779 +// Display specified 3D object(s). 1.780 +//-------------------------------- 1.781 +template<typename T> 1.782 +bool gmic::display_objects3d(const CImgList<T>& images, const CImg<unsigned int>& indices, 1.783 + const bool verbose) const { 1.784 + if (!indices) { print("Display 3D object []."); return false; } 1.785 + CImg<unsigned char> background; 1.786 + bool exist3d = false; 1.787 + CImgDisplay disp; 1.788 + cimg_foroff(indices,l) { 1.789 + const unsigned int ind = indices[l]; 1.790 + const CImg<T> &img = images[ind]; 1.791 + if (!img.is_CImg3d()) { 1.792 + if (verbose) warning("Display 3D object : Image [%d] is not a 3D object.",ind); 1.793 + } else { 1.794 + exist3d = true; 1.795 + if (!background || !disp) { 1.796 + background.assign(cimg_fitscreen(640,480,1),1,3); 1.797 + cimg_forV(background,k) background.get_shared_channel(k).fill(background3d[k]); 1.798 + disp.assign(background); 1.799 + } 1.800 + CImgList<unsigned int> primitives3d; 1.801 + CImgList<unsigned char> colors3d; 1.802 + CImg<float> opacities3d; 1.803 + CImg<float> points3d(img); 1.804 + points3d.CImg3dtoobject3d(primitives3d,colors3d,opacities3d); 1.805 + print("Display 3D object [%u] = '%s' (%d points, %u primitives).", 1.806 + ind,filenames[ind].ptr(),points3d.dimx(),primitives3d.size); 1.807 + disp.set_title("%s (%d points, %u primitives)", 1.808 + filenames[ind].ptr(),points3d.dimx(),primitives3d.size); 1.809 + background.display_object3d(disp,points3d,primitives3d,colors3d,opacities3d, 1.810 + true,render3d,renderd3d,!is_oriented3d,focale3d,specular_light3d,specular_shine3d); 1.811 + if (disp.is_closed) break; 1.812 + } 1.813 + } 1.814 + return exist3d; 1.815 +} 1.816 + 1.817 +// Substitute '@' expressions. 1.818 +//---------------------------- 1.819 +template<typename T> 1.820 +CImg<char> gmic::substitute_arobace(const char *const argument, const CImgList<T>& images) const { 1.821 + if (!argument) return CImg<char>(); 1.822 + CImgList<char> _largument; 1.823 + char range[4096] = { 0 }; 1.824 + for (const char *nargument = argument; *nargument; ) { 1.825 + if (*nargument=='@') { 1.826 + char argx[4096] = { 0 }, argy[4096] = { 0 }, argz[4096] = { 0 }, argv[4096] = { 0 }; 1.827 + int ind = 0, bcond = 0; *range = 0; char sepx = 0, sepy = 0, sepz = 0, sepv = 0, sep = 0, end = 0; 1.828 + float x = 0, y = 0, z = 0, v = 0, m = 0, M = 1; 1.829 + if (nargument[1]=='#' || 1.830 + (std::sscanf(nargument,"@{#%c",&sep)==1 && sep=='}')) { 1.831 + std::sprintf(range,"%u",images.size); 1.832 + _largument.insert(CImg<char>(range,cimg::strlen(range),1,1,1,true)); 1.833 + if (sep=='}') nargument+=4; else nargument+=2; 1.834 + } else if (std::sscanf(nargument,"@%d",&ind)==1 || 1.835 + (std::sscanf(nargument,"@{%d%c",&ind,&sep)==2 && sep=='}') || 1.836 + (std::sscanf(nargument,"@{%d%*c%4095[^}]%c",&ind,range,&sep)==3 && sep=='}')) { 1.837 + int nind = ind; 1.838 + if (nind<0) nind+=images.size; 1.839 + if (nind<0 || nind>=(int)images.size) { 1.840 + if (images.size) error("Invalid indice '%d' in '@argument' (valid indice range is -%u...%u).", 1.841 + ind,images.size,images.size-1); 1.842 + else error("Invalid indice '%d' in '@argument' (image list is empty).",ind); 1.843 + } 1.844 + const unsigned int sizrange = cimg::strlen(range); 1.845 + const CImg<T>& img = images[nind]; 1.846 + CImg<T> values; 1.847 + if (sizrange) { 1.848 + const CImg<unsigned int> iinds = indices2cimg(range,img.size(),"parsing"); 1.849 + values.assign(iinds.size()); 1.850 + cimg_foroff(iinds,p) values[p] = img[iinds(p)]; 1.851 + } else values = img.get_shared(); 1.852 + const CImg<char> vs = values.value_string(); 1.853 + const unsigned int vsl = vs.size(); 1.854 + if (vsl>1) _largument.insert(CImg<char>(vs.ptr(),vsl-1,1,1,1,true)); 1.855 + nargument+= 1 + (sep?2:0) + (sizrange?1:0) + sizrange + std::sprintf(range,"%d",ind); 1.856 + } else if (((std::sscanf(nargument,"@(%d%*c%4095[0-9.eE%+-]%c",&ind,argx,&sep)==3 && sep==')') || 1.857 + (std::sscanf(nargument,"@(%d%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c",&ind,argx,argy,&sep)==4 && sep==')') || 1.858 + (std::sscanf(nargument,"@(%d%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c", 1.859 + &ind,argx,argy,argz,&sep)==5 && sep==')') || 1.860 + (std::sscanf(nargument,"@(%d%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c", 1.861 + &ind,argx,argy,argz,argv,&sep)==6 && sep==')') || 1.862 + (std::sscanf(nargument,"@(%d%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%d%c", 1.863 + &ind,argx,argy,argz,argv,&bcond,&sep)==7 && sep==')')) && 1.864 + (!*argx || 1.865 + (std::sscanf(argx,"%f%c%c",&x,&sepx,&end)==2 && sepx=='%') || 1.866 + std::sscanf(argx,"%f%c",&x,&end)==1) && 1.867 + (!*argy || 1.868 + (std::sscanf(argy,"%f%c%c",&y,&sepy,&end)==2 && sepy=='%') || 1.869 + std::sscanf(argy,"%f%c",&y,&end)==1) && 1.870 + (!*argz || 1.871 + (std::sscanf(argz,"%f%c%c",&z,&sepz,&end)==2 && sepz=='%') || 1.872 + std::sscanf(argz,"%f%c",&z,&end)==1) && 1.873 + (!*argv || 1.874 + (std::sscanf(argv,"%f%c%c",&v,&sepv,&end)==2 && sepv=='%') || 1.875 + std::sscanf(argv,"%f%c",&v,&end)==1)) { 1.876 + int nind = ind; 1.877 + if (nind<0) nind+=images.size; 1.878 + if (nind<0 || nind>=(int)images.size) { 1.879 + if (images.size) error("Invalid indice '%d' in '@argument' (valid indice range is -%u...%u).", 1.880 + ind,images.size,images.size-1); 1.881 + else error("Invalid indice '%d' in '@argument' (image list is empty).",ind); 1.882 + } 1.883 + const CImg<T>& img = images[nind]; 1.884 + const int 1.885 + nx = (int)cimg::round(sepx=='%'?x*(img.dimx()-1)/100:x,1), 1.886 + ny = (int)cimg::round(sepy=='%'?y*(img.dimy()-1)/100:y,1), 1.887 + nz = (int)cimg::round(sepz=='%'?z*(img.dimz()-1)/100:z,1), 1.888 + nv = (int)cimg::round(sepv=='%'?v*(img.dimv()-1)/100:v,1); 1.889 + std::sprintf(range,"%g",bcond?(double)img.atXYZV(nx,ny,nz,nv):(double)img.atXYZV(nx,ny,nz,nv,0)); 1.890 + _largument.insert(CImg<char>(range,cimg::strlen(range))); 1.891 + while (*nargument!=')') ++nargument; ++nargument; 1.892 + } else if ((std::sscanf(nargument,"@%c",&sep)==1 && sep=='?') || 1.893 + (std::sscanf(nargument,"@{?%c",&sep)==1 && sep=='}') || 1.894 + (std::sscanf(nargument,"@[?%c",&sep)==1 && sep==']') || 1.895 + (std::sscanf(nargument,"@{?%*c%f%c",&M,&sep)==2 && sep=='}') || 1.896 + (std::sscanf(nargument,"@[?%*c%f%c",&M,&sep)==2 && sep==']') || 1.897 + (std::sscanf(nargument,"@{?%*c%f%*c%f%c",&m,&M,&sep)==3 && sep=='}') || 1.898 + (std::sscanf(nargument,"@[?%*c%f%*c%f%c",&m,&M,&sep)==3 && sep==']')) { 1.899 + const double r = m + (M-m)*cimg::rand(); 1.900 + if (sep==']') std::sprintf(range,"%d",(int)cimg::round(r,1)); else std::sprintf(range,"%g",r); 1.901 + _largument.insert(CImg<char>(range,cimg::strlen(range),1,1,1,true)); 1.902 + if (sep=='?') nargument+=2; else { while (*nargument!=sep) ++nargument; ++nargument; } 1.903 + } else _largument.insert(CImg<char>(nargument++,1,1,1,1,true)); 1.904 + } else { 1.905 + std::sscanf(nargument,"%4095[^@]",range); 1.906 + const int l = cimg::strlen(range); 1.907 + _largument.insert(CImg<char>(range,l,1,1,1,true)); 1.908 + nargument+=l; 1.909 + } 1.910 + } 1.911 + _largument.insert(CImg<char>::vector(0)); 1.912 + return _largument.get_append('x'); 1.913 +} 1.914 + 1.915 +// Main parsing procedure. 1.916 +//------------------------ 1.917 +template<typename T> 1.918 +gmic& gmic::parse(CImgList<T> &images) { 1.919 + const unsigned int command_line_maxsize = 65535; 1.920 + const int no_ind = (int)(~0U>>1); 1.921 + cimg::exception_mode() = 0; 1.922 + 1.923 + // Begin command line parsing. 1.924 + while (position<command_line.size && command_line.size<command_line_maxsize) { 1.925 + const char 1.926 + *const orig_item = command_line[position].ptr(), 1.927 + *const orig_argument = position+1<command_line.size?command_line[position+1].ptr():""; 1.928 + 1.929 + // Substitute '@' expressions in 'orig_item' and 'orig_argument' if necessary. 1.930 + CImg<char> _item, _argument, _argument_text; 1.931 + if (*orig_item=='-' || *orig_item=='[' || *orig_item=='(') { 1.932 + if (std::strchr(orig_item,'@')) { 1.933 + _item = substitute_arobace(orig_item,images); 1.934 + if (_item.size()>4095) error("Buffer overflow when substituting item '%s'.",orig_item); 1.935 + } 1.936 + if (*orig_item=='-' && 1.937 + (*orig_argument!='-' || 1.938 + (*orig_argument=='-' && (orig_argument[1]=='.' || orig_argument[1]=='@' || 1.939 + (orig_argument[1]>='0' && orig_argument[1]<='9')))) 1.940 + && std::strchr(orig_argument,'@')) { 1.941 + _argument = substitute_arobace(orig_argument,images); 1.942 + if (_argument.size()>4095) error("Buffer overflow when substituting argument '%s'.",orig_argument); 1.943 + } 1.944 + } 1.945 + const char 1.946 + *item = _item?_item.ptr():orig_item, 1.947 + *argument = _argument?_argument.ptr():orig_argument; 1.948 + const char *argument_text = argument; 1.949 + if (cimg::strlen(argument)>=64) { 1.950 + _argument_text.assign(64,1,1,1,0); 1.951 + std::memcpy(_argument_text.ptr(),argument,60*sizeof(char)); 1.952 + _argument_text[60] = _argument_text[61] = _argument_text[62] = '.'; _argument_text[63] = 0; 1.953 + argument_text = _argument_text.ptr(); 1.954 + } 1.955 + 1.956 + // Get current item/command from the command line. 1.957 + char item0[4096] = { 0 }, item1[4096] = { 0 }; 1.958 + bool get_version = false; 1.959 + CImg<unsigned int> indices; 1.960 + if (item[0]=='-' && item[1] && item[1]!='.') { 1.961 + char sep0 = 0, sep1 = 0, end = 0; 1.962 + if (item[1]=='-' && item[2] && item[2]!='[' && item[2]!='3' && item[3]!='d') { ++item; get_version = true; } 1.963 + const int err = std::sscanf(item,"%4095[^[]%c%4095[0-9.eE%,:+-]%c%c",item0,&sep0,item1,&sep1,&end); 1.964 + if (err==1) indices = CImg<unsigned int>::sequence(images.size,0,images.size-1); 1.965 + else if (err==4 && sep1==']') 1.966 + indices = indices2cimg(item1,(!strcmp(item0,"-i")||!strcmp(item0,"-input"))?images.size+1:images.size,item0); 1.967 + else { std::strcpy(item0,item); item1[0] = 0; } 1.968 + } 1.969 + ++position; 1.970 + 1.971 + // Check for verbosity commands. 1.972 + if (*item=='-') { 1.973 + if (!cimg::strcmp("-verbose+",item) || !cimg::strcmp("-v+",item)) ++verbosity_level; 1.974 + else if (!cimg::strcmp("-verbose-",item) || !cimg::strcmp("-v-",item)) --verbosity_level; 1.975 + } 1.976 + 1.977 + if (is_begin) { print("Start G'MIC instance."); is_begin = false; } 1.978 + debug("Item : '%s', Argument : '%s'.",item,argument); 1.979 + 1.980 + // Begin command interpretation. 1.981 + try { 1.982 + if (*item=='-') { 1.983 + 1.984 + //---------------- 1.985 + // Global options 1.986 + //---------------- 1.987 + 1.988 + // Verbosity (actually, just continue to next command since verbosity has been already processed above). 1.989 + if (!cimg::strcmp("-verbose+",item) || !cimg::strcmp("-v+",item) || 1.990 + !cimg::strcmp("-verbose-",item) || !cimg::strcmp("-v-",item)) continue; 1.991 + 1.992 + // Load macro file. 1.993 + if (!cimg::strcmp("-macros",item) || !cimg::strcmp("-m",item)) { 1.994 + print("Load macro file '%s'",cimg::basename(argument)); 1.995 + std::FILE *const file = cimg::fopen(argument,"r"); 1.996 + if (file) { 1.997 + const unsigned int siz = macros.size; 1.998 + add_macros(file,true); 1.999 + cimg::fclose(file); 1.1000 + if (verbosity_level>=0) std::fprintf(cimg_stdout," (%u macros added).",macros.size-siz); 1.1001 + } 1.1002 + else error("Load macro file '%s' : File not found.",argument); 1.1003 + ++position; continue; 1.1004 + } 1.1005 + 1.1006 + // Switch 'is_debug' flag. 1.1007 + if (!cimg::strcmp("-debug",item)) { 1.1008 + is_debug = !is_debug; 1.1009 + continue; 1.1010 + } 1.1011 + 1.1012 + // Switch 'is_fullpath' flag. 1.1013 + if (!cimg::strcmp("-fullpath",item)) { 1.1014 + is_fullpath = !is_fullpath; 1.1015 + continue; 1.1016 + } 1.1017 + 1.1018 + //---------------------- 1.1019 + // Arithmetic operators 1.1020 + //---------------------- 1.1021 + 1.1022 + // Common arithmetic operators. 1.1023 + gmic_arithmetic_item("-add","-+", 1.1024 + operator+=,"Add %g to image%s",value,gmic_inds,T, 1.1025 + operator+=,"Add to image%s", 1.1026 + "Add image [%d] to image%s",ind[0],gmic_inds, 1.1027 + "Add image%s together"); 1.1028 + 1.1029 + gmic_arithmetic_item("-sub","--", 1.1030 + operator-=,"Substract %g to image%s",value,gmic_inds,T, 1.1031 + operator-=,"Substract to image%s", 1.1032 + "Substract image [%d] to image%s",ind[0],gmic_inds, 1.1033 + "Substract image%s together"); 1.1034 + 1.1035 + gmic_arithmetic_item("-mul","-*", 1.1036 + operator*=,"Multiply image%s by %g",gmic_inds,value,double, 1.1037 + mul,"Multiply image%s", 1.1038 + "Multiply image%s by image [%d]",gmic_inds,ind[0], 1.1039 + "Multiply image%s together"); 1.1040 + 1.1041 + gmic_arithmetic_item("-div","-/", 1.1042 + operator/=,"Divide image%s by %g",gmic_inds,value,double, 1.1043 + div,"Divide image%s", 1.1044 + "Divide image%s by image [%d]",gmic_inds,ind[0], 1.1045 + "Divide image%s together"); 1.1046 + 1.1047 + gmic_arithmetic_item("-pow","-^", 1.1048 + pow,"Compute image%s to the power of %g",gmic_inds,value,double, 1.1049 + pow,"Compute power of image%s", 1.1050 + "Compute image%s to the power of image [%d]",gmic_inds,ind[0], 1.1051 + "Compute the power of image%s together"); 1.1052 + 1.1053 + gmic_arithmetic_item("-min","-min", 1.1054 + min,"Compute pointwise minimum between image%s and %g",gmic_inds,value,T, 1.1055 + min,"Compute pointwise minimum with image%s", 1.1056 + "Compute pointwise minimum between image%s and image [%d]",gmic_inds,ind[0], 1.1057 + "Compute pointwise minimum between image%s together"); 1.1058 + 1.1059 + gmic_arithmetic_item("-max","-max", 1.1060 + max,"Compute pointwise maximum between image%s and %g",gmic_inds,value,T, 1.1061 + max,"Compute pointwise maximum with image%s", 1.1062 + "Compute pointwise maximum between image%s and image [%d]",gmic_inds,ind[0], 1.1063 + "Compute pointwise maximum between image%s together"); 1.1064 + 1.1065 + gmic_arithmetic_item("-mod","-%", 1.1066 + operator%=,"Compute pointwise modulo between image%s and %g.",gmic_inds,value,T, 1.1067 + operator%=,"Compute pointwise modulo with image%s", 1.1068 + "Compute pointwise modulo between image%s and image [%d]",gmic_inds,ind[0], 1.1069 + "Compute pointwise modulo between image%s together"); 1.1070 + 1.1071 + gmic_arithmetic_item("-and","-and", 1.1072 + operator&=,"Compute bitwise AND between image%s and %g.",gmic_inds,value,unsigned int, 1.1073 + operator&=,"Compute bitwise AND with image%s", 1.1074 + "Compute bitwise AND between image%s and image [%d]",gmic_inds,ind[0], 1.1075 + "Compute bitwise AND between image%s together"); 1.1076 + 1.1077 + gmic_arithmetic_item("-or","-or", 1.1078 + operator|=,"Compute bitwise OR between image%s and %g.",gmic_inds,value,unsigned int, 1.1079 + operator|=,"Compute bitwise OR with image%s", 1.1080 + "Compute bitwise OR between image%s and image [%d]",gmic_inds,ind[0], 1.1081 + "Compute bitwise OR between image%s together"); 1.1082 + 1.1083 + gmic_arithmetic_item("-xor","-xor", 1.1084 + operator^=,"Compute bitwise XOR between image%s and %g.",gmic_inds,value,unsigned int, 1.1085 + operator^=,"Compute bitwise XOR with image%s", 1.1086 + "Compute bitwise XOR between image%s and image [%d]",gmic_inds,ind[0], 1.1087 + "Compute bitwise XOR between image%s together"); 1.1088 + 1.1089 + // Other arithmetic operators. 1.1090 + gmic_simple_item("-cos",cos,"Compute cosine of image%s."); 1.1091 + gmic_simple_item("-sin",sin,"Compute sine of image%s."); 1.1092 + gmic_simple_item("-tan",tan,"Compute tangent of image%s."); 1.1093 + gmic_simple_item("-acos",acos,"Compute arccosine of image%s."); 1.1094 + gmic_simple_item("-asin",asin,"Compute arcsine of image%s."); 1.1095 + gmic_simple_item("-atan",atan,"Compute arctangent of image%s."); 1.1096 + gmic_simple_item("-abs",abs,"Compute absolute value of image%s."); 1.1097 + gmic_simple_item("-sqr",sqr,"Compute square function of image%s."); 1.1098 + gmic_simple_item("-sqrt",sqrt,"Compute square root of image%s."); 1.1099 + gmic_simple_item("-exp",exp,"Compute exponential of image%s."); 1.1100 + gmic_simple_item("-log",log,"Compute logarithm of image%s."); 1.1101 + gmic_simple_item("-log10",log10,"Compute logarithm_10 of image%s."); 1.1102 + 1.1103 + //--------------------------------------- 1.1104 + // Pointwise operations on pixel values 1.1105 + //--------------------------------------- 1.1106 + 1.1107 + // Type cast. 1.1108 + if (!cimg::strcmp("-type",item) || !cimg::strcmp("-t",item)) { 1.1109 + typedef unsigned char uchar; 1.1110 + typedef unsigned short ushort; 1.1111 + typedef unsigned int uint; 1.1112 +#ifndef gmic_minimal 1.1113 + gmic_cast(bool,"bool"); 1.1114 + gmic_cast(uchar,"unsigned char"); 1.1115 + gmic_cast(char,"char"); 1.1116 + gmic_cast(ushort,"unsigned short"); 1.1117 + gmic_cast(short,"short"); 1.1118 + gmic_cast(uint,"unsigned int"); 1.1119 + gmic_cast(int,"int"); 1.1120 + gmic_cast(double,"double"); 1.1121 +#endif 1.1122 + gmic_cast(float,"float"); 1.1123 + error("Set pixel type : Invalid argument '%s' " 1.1124 + "(should be '{bool,uchar,char,ushort,short,uint,int,float,double}').", 1.1125 + argument_text); 1.1126 + } 1.1127 + 1.1128 + // Set scalar value. 1.1129 + if (!cimg::strcmp("-set",item0) || !cimg::strcmp("-=",item0)) { 1.1130 + double value = 0; float x = 0, y = 0, z = 0, v = 0; char sepx = 0, sepy = 0, sepz = 0, sepv = 0, end = 0; 1.1131 + char argx[4096] = { 0 }, argy[4096] = { 0 }, argz[4096] = { 0 }, argv[4096] = { 0 }; 1.1132 + if ((std::sscanf(argument,"%lf%c",&value,&end)==1 || 1.1133 + std::sscanf(argument,"%lf%*c%4095[0-9.eE%+-]%c",&value,argx,&end)==2 || 1.1134 + std::sscanf(argument,"%lf%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c",&value,argx,argy,&end)==3 || 1.1135 + std::sscanf(argument,"%lf%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c",&value,argx,argy,argz,&end)==4 || 1.1136 + std::sscanf(argument,"%lf%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c",&value,argx,argy,argz,argv,&end)==5) && 1.1137 + (!*argx || 1.1138 + (std::sscanf(argx,"%f%c%c",&x,&sepx,&end)==2 && sepx=='%') || 1.1139 + std::sscanf(argx,"%f%c",&x,&end)==1) && 1.1140 + (!*argy || 1.1141 + (std::sscanf(argy,"%f%c%c",&y,&sepy,&end)==2 && sepy=='%') || 1.1142 + std::sscanf(argy,"%f%c",&y,&end)==1) && 1.1143 + (!*argz || 1.1144 + (std::sscanf(argz,"%f%c%c",&z,&sepz,&end)==2 && sepz=='%') || 1.1145 + std::sscanf(argz,"%f%c",&z,&end)==1) && 1.1146 + (!*argv || 1.1147 + (std::sscanf(argv,"%f%c%c",&v,&sepv,&end)==2 && sepv=='%') || 1.1148 + std::sscanf(argv,"%f%c",&v,&end)==1)) { 1.1149 + print("Set scalar value %g at position (%g%s,%g%s,%g%s,%g%s) in image%s", 1.1150 + value,x,sepx=='%'?"%":"",y,sepy=='%'?"%":"",z,sepz=='%'?"%":"",v,sepv=='%'?"%":"",gmic_inds); 1.1151 + cimg_foroff(indices,l) { 1.1152 + CImg<T> &img = images[indices[l]]; 1.1153 + const int 1.1154 + nx = (int)cimg::round(sepx=='%'?x*(img.dimx()-1)/100:x,1), 1.1155 + ny = (int)cimg::round(sepy=='%'?y*(img.dimy()-1)/100:y,1), 1.1156 + nz = (int)cimg::round(sepz=='%'?z*(img.dimz()-1)/100:z,1), 1.1157 + nv = (int)cimg::round(sepv=='%'?v*(img.dimv()-1)/100:v,1); 1.1158 + gmic_apply(images[indices[l]],gmic_set(value,nx,ny,nz,nv)); 1.1159 + } 1.1160 + } else error("Set scalar value in image%s : Invalid argument '%s' " 1.1161 + "(should be 'value,x[,y[,z[,v]]]').", 1.1162 + argument_text); 1.1163 + ++position; continue; 1.1164 + } 1.1165 + 1.1166 + // Invert endianness. 1.1167 + gmic_simple_item("-endian",invert_endianness,"Invert endianness of image%s."); 1.1168 + 1.1169 + // Fill. 1.1170 + if (!cimg::strcmp("-fill",item0) || !cimg::strcmp("-f",item0)) { 1.1171 + char sep = 0, end = 0; int ind0 = no_ind; 1.1172 + if (std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==2 && sep==']') { 1.1173 + gmic_check_indice(ind0,"Fill image%s"); 1.1174 + print("Fill image%s with values of image [%d].",gmic_inds,ind0); 1.1175 + const CImg<T> values = images[ind0]; 1.1176 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],fill(values)); 1.1177 + } else { 1.1178 + print("Fill image%s with values '%s'.",gmic_inds,argument_text); 1.1179 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],fill(argument,true)); 1.1180 + } 1.1181 + ++position; continue; 1.1182 + } 1.1183 + 1.1184 + // Threshold. 1.1185 + if (!cimg::strcmp("-threshold",item0)) { 1.1186 + char sep = 0, end = 0; int soft = 0; double value = 0; 1.1187 + if (std::sscanf(argument,"%lf%c",&value,&end)==1 || 1.1188 + (std::sscanf(argument,"%lf%c%c",&value,&sep,&end)==2 && sep=='%') || 1.1189 + std::sscanf(argument,"%lf%*c%d%c",&value,&soft,&end)==2 || 1.1190 + (std::sscanf(argument,"%lf%c%*c%d%c",&value,&sep,&soft,&end)==3 && sep=='%')) { 1.1191 + print("Threshold image%s with %g%s (%s threshold).",gmic_inds,value,sep=='%'?"%":"",soft?"soft":"hard"); 1.1192 + cimg_foroff(indices,l) { 1.1193 + CImg<T> &img = images[indices[l]]; 1.1194 + double vmin = 0, vmax = 0, nvalue = value; 1.1195 + if (sep=='%') { vmin = img.minmax(vmax); nvalue = vmin + (vmax - vmin)*value/100; } 1.1196 + gmic_apply(img,threshold((T)nvalue,soft?true:false)); 1.1197 + } 1.1198 + ++position; 1.1199 + } else { 1.1200 + print("Threshold image%s : Interactive mode.",gmic_inds); 1.1201 + CImgDisplay disp; 1.1202 + char title[4096] = { 0 }; 1.1203 + cimg_foroff(indices,l) { 1.1204 + CImg<T> 1.1205 + &img = images[indices[l]], 1.1206 + visu = img.depth>1?img.get_projections2d(img.dimx()/2,img.dimy()/2,img.dimz()/2). 1.1207 + channels(0,cimg::min(3,img.dimv())-1):img.get_channels(0,cimg::min(3,img.dimv()-1)); 1.1208 + if (disp) disp.resize(cimg_fitscreen(visu.dimx(),visu.dimy(),1),false); 1.1209 + else disp.assign(cimg_fitscreen(visu.dimx(),visu.dimy(),1),0,1); 1.1210 + double 1.1211 + vmin = 0, vmax = (double)img.maxmin(vmin), 1.1212 + distmax = std::sqrt(cimg::sqr(disp.dimx()-1.0) + cimg::sqr(disp.dimy()-1.0)), 1.1213 + amount = 50; 1.1214 + bool stopflag = false, obutt = false; 1.1215 + int omx = -1, omy = -1; 1.1216 + CImg<T> res; 1.1217 + for (disp.show().button = disp.key = 0; !stopflag; ) { 1.1218 + const unsigned int key = disp.key; 1.1219 + if (!res) { 1.1220 + std::sprintf(title,"%s : Interactive threshold %.3g%%",filenames[indices[l]].ptr(),amount); 1.1221 + disp.display(res=visu.get_threshold((T)(vmin + amount*(vmax-vmin)/100))). 1.1222 + set_title(title).wait(); 1.1223 + } 1.1224 + const int mx = disp.mouse_x, my = disp.mouse_y; 1.1225 + if (disp.button && mx>=0 && my>=0) { 1.1226 + if (omx==mx && omy==my && !obutt) break; 1.1227 + omx = mx; omy = my; obutt = true; 1.1228 + const double dist = std::sqrt((double)cimg::sqr(mx) + cimg::sqr(my)); 1.1229 + amount = dist*100/distmax; 1.1230 + res.assign(); 1.1231 + } else if (!disp.button) obutt = false; 1.1232 + if (disp.is_closed || (key && key!=cimg::keyCTRLLEFT)) stopflag = true; 1.1233 + if (key==cimg::keyD && disp.is_keyCTRLLEFT && 1.1234 + (disp.resize(cimg_fitscreen(3*disp.width/2,3*disp.height/2,1),stopflag=false).key=0)==0) 1.1235 + disp.is_resized = true; 1.1236 + if (key==cimg::keyC && disp.is_keyCTRLLEFT && 1.1237 + (disp.resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),stopflag=false).key=0)==0) 1.1238 + disp.is_resized = true; 1.1239 + if (disp.is_resized) { 1.1240 + disp.resize(false).display(res); 1.1241 + distmax = std::sqrt(cimg::sqr(disp.dimx()-1.0) + cimg::sqr(disp.dimy()-1.0)); 1.1242 + } 1.1243 + } 1.1244 + gmic_apply(img,threshold((T)(vmin + amount*(vmax-vmin)/100))); 1.1245 + } 1.1246 + } 1.1247 + continue; 1.1248 + } 1.1249 + 1.1250 + // Cut. 1.1251 + if (!cimg::strcmp("-cut",item0)) { 1.1252 + char sep0 = 0, sep1 = 0, end = 0, arg0[4096] = { 0 }, arg1[4096] = { 0 }; 1.1253 + double value0 = 0, value1 = 0; int ind0 = no_ind, ind1 = no_ind; 1.1254 + if (std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c",arg0,arg1,&end)==2 && 1.1255 + ((std::sscanf(arg0,"[%d%c%c",&ind0,&sep0,&end)==2 && sep0==']') || 1.1256 + (std::sscanf(arg0,"%lf%c%c",&value0,&sep0,&end)==2 && sep0=='%') || 1.1257 + std::sscanf(arg0,"%lf%c",&value0,&end)==1) && 1.1258 + ((std::sscanf(arg1,"[%d%c%c",&ind1,&sep1,&end)==2 && sep1==']') || 1.1259 + (std::sscanf(arg1,"%lf%c%c",&value1,&sep1,&end)==2 && sep1=='%') || 1.1260 + std::sscanf(arg1,"%lf%c",&value1,&end)==1)) { 1.1261 + if (ind0!=no_ind) { gmic_check_indice(ind0,"Cut image%s"); value0 = images[ind0].min(); sep0 = 0; } 1.1262 + if (ind1!=no_ind) { gmic_check_indice(ind1,"Cut image%s"); value1 = images[ind1].max(); sep1 = 0; } 1.1263 + print("Cut image%s in [%g%s,%g%s].",gmic_inds,value0,sep0=='%'?"%":"",value1,sep1=='%'?"%":""); 1.1264 + cimg_foroff(indices,l) { 1.1265 + CImg<T> &img = images[indices[l]]; 1.1266 + double vmin = 0, vmax = 0, nvalue0 = value0, nvalue1 = value1; 1.1267 + if (sep0=='%') { vmin = img.minmax(vmax); nvalue0 = vmin + (vmax - vmin)*value0/100; } 1.1268 + if (sep1=='%') { vmin = img.minmax(vmax); nvalue1 = vmin + (vmax - vmin)*value1/100; } 1.1269 + gmic_apply(img,cut((T)nvalue0,(T)nvalue1)); 1.1270 + } 1.1271 + ++position; 1.1272 + } else if (std::sscanf(argument,"[%d%c%c",&(ind0=no_ind),&sep0,&end)==2) { 1.1273 + if (ind0!=no_ind) gmic_check_indice(ind0,"Cut image%s"); 1.1274 + value0 = images[ind0].minmax(value1); 1.1275 + print("Cut image%s in [%g,%g].",gmic_inds,value0,value1); 1.1276 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],cut((T)value0,(T)value1)); 1.1277 + ++position; 1.1278 + } else { 1.1279 + print("Cut image%s : Interactive mode.",gmic_inds); 1.1280 + CImgDisplay disp; 1.1281 + char title[4096] = { 0 }; 1.1282 + cimg_foroff(indices,l) { 1.1283 + CImg<T> 1.1284 + &img = images[indices[l]], 1.1285 + visu = img.depth>1?img.get_projections2d(img.dimx()/2,img.dimy()/2,img.dimz()/2). 1.1286 + channels(0,cimg::min(3,img.dimv())-1):img.get_channels(0,cimg::min(3,img.dimv()-1)); 1.1287 + if (disp) disp.resize(cimg_fitscreen(visu.dimx(),visu.dimy(),1),false); 1.1288 + else disp.assign(cimg_fitscreen(visu.dimx(),visu.dimy(),1),0,1); 1.1289 + double vmin = 0, vmax = (double)img.maxmin(vmin), amount0 = 0, amount1 = 100; 1.1290 + bool stopflag = false, obutt = false; 1.1291 + int omx = -1, omy = -1; 1.1292 + CImg<T> res; 1.1293 + for (disp.show().button = disp.key = 0; !stopflag; ) { 1.1294 + const unsigned int key = disp.key; 1.1295 + if (!res) { 1.1296 + std::sprintf(title,"%s : Interactive cut [%.3g%%,%.3g%%]", 1.1297 + filenames[indices[l]].ptr(),amount0,amount1); 1.1298 + disp.display(res = visu.get_cut((T)(vmin + amount0*(vmax-vmin)/100), 1.1299 + (T)(vmin + amount1*(vmax-vmin)/100))). 1.1300 + set_title(title).wait(); 1.1301 + } 1.1302 + const int mx = disp.mouse_x, my = disp.mouse_y; 1.1303 + if (disp.button && mx>=0 && my>=0) { 1.1304 + if (omx==mx && omy==my && !obutt) break; 1.1305 + omx = mx; omy = my; obutt = true; 1.1306 + amount0 = mx*100/disp.dimx(); amount1 = my*100/disp.dimy(); 1.1307 + res.assign(); 1.1308 + } else if (!disp.button) obutt = false; 1.1309 + if (disp.is_closed || (key && key!=cimg::keyCTRLLEFT)) stopflag = true; 1.1310 + if (key==cimg::keyD && disp.is_keyCTRLLEFT && 1.1311 + (disp.resize(cimg_fitscreen(3*disp.width/2,3*disp.height/2,1),stopflag=false).key=0)==0) 1.1312 + disp.is_resized = true; 1.1313 + if (key==cimg::keyC && disp.is_keyCTRLLEFT && 1.1314 + (disp.resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),stopflag=false).key=0)==0) 1.1315 + disp.is_resized = true; 1.1316 + if (disp.is_resized) disp.resize(false).display(res); 1.1317 + } 1.1318 + gmic_apply(img,cut((T)(vmin + amount0*(vmax-vmin)/100),(T)(vmin + amount1*(vmax-vmin)/100))); 1.1319 + } 1.1320 + } 1.1321 + continue; 1.1322 + } 1.1323 + 1.1324 + // Normalize. 1.1325 + if (!cimg::strcmp("-normalize",item0) || !cimg::strcmp("-n",item0)) { 1.1326 + char sep0 = 0, sep1 = 0, end = 0, arg0[4096] = { 0 }, arg1[4096] = { 0 }; 1.1327 + double value0 = 0, value1 = 0; int ind0 = no_ind, ind1 = no_ind; 1.1328 + if (std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c",arg0,arg1,&end)==2 && 1.1329 + ((std::sscanf(arg0,"[%d%c%c",&ind0,&sep0,&end)==2 && sep0==']') || 1.1330 + (std::sscanf(arg0,"%lf%c%c",&value0,&sep0,&end)==2 && sep0=='%') || 1.1331 + std::sscanf(arg0,"%lf%c",&value0,&end)==1) && 1.1332 + ((std::sscanf(arg1,"[%d%c%c",&ind1,&sep1,&end)==2 && sep1==']') || 1.1333 + (std::sscanf(arg1,"%lf%c%c",&value1,&sep1,&end)==2 && sep1=='%') || 1.1334 + std::sscanf(arg1,"%lf%c",&value1,&end)==1)) { 1.1335 + if (ind0!=no_ind) { gmic_check_indice(ind0,"Normalize image%s"); value0 = images[ind0].min(); sep0 = 0; } 1.1336 + if (ind1!=no_ind) { gmic_check_indice(ind1,"Normalize image%s"); value1 = images[ind1].max(); sep1 = 0; } 1.1337 + print("Normalize image%s in [%g%s,%g%s].",gmic_inds,value0,sep0=='%'?"%":"",value1,sep1=='%'?"%":""); 1.1338 + cimg_foroff(indices,l) { 1.1339 + CImg<T> &img = images[indices[l]]; 1.1340 + double vmin = 0, vmax = 0, nvalue0 = value0, nvalue1 = value1; 1.1341 + if (sep0=='%') { vmin = img.minmax(vmax); nvalue0 = vmin + (vmax - vmin)*value0/100; } 1.1342 + if (sep1=='%') { vmin = img.minmax(vmax); nvalue1 = vmin + (vmax - vmin)*value1/100; } 1.1343 + gmic_apply(img,normalize((T)nvalue0,(T)nvalue1)); 1.1344 + } 1.1345 + } else if (std::sscanf(argument,"[%d%c%c",&(ind0=no_ind),&sep0,&end)==2) { 1.1346 + if (ind0!=no_ind) gmic_check_indice(ind0,"Normalize image%s"); 1.1347 + value0 = images[ind0].minmax(value1); 1.1348 + print("Normalize image%s in [%g,%g].",gmic_inds,value0,value1); 1.1349 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],normalize((T)value0,(T)value1)); 1.1350 + } else error("Normalize image%s : Invalid argument '%s' " 1.1351 + "(should be '{value1[%%],[indice]},{value2[%%],[indice]}').",gmic_inds,argument_text); 1.1352 + ++position; continue; 1.1353 + } 1.1354 + 1.1355 + // Round. 1.1356 + if (!cimg::strcmp("-round",item0)) { 1.1357 + char end = 0; double value = 0; int rtype = 0; 1.1358 + if (std::sscanf(argument,"%lf%c",&value,&end)==1 || 1.1359 + std::sscanf(argument,"%lf%*c%d%c",&value,&rtype,&end)==2) { 1.1360 + print("Round image%s with value %g (%s rounding).", 1.1361 + gmic_inds,value,rtype<0?"backward":rtype>0?"forward":"nearest"); 1.1362 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],round((float)value,rtype)); 1.1363 + } else error("Round image%s : Invalid argument '%s' " 1.1364 + "(should be 'round_value[,round_type]').",gmic_inds,argument_text); 1.1365 + ++position; continue; 1.1366 + } 1.1367 + 1.1368 + // Equalize histogram. 1.1369 + if (!cimg::strcmp("-equalize",item0)) { 1.1370 + float nb = 256; char sep = 0, end = 0; 1.1371 + if (std::sscanf(argument,"%f%c",&nb,&end)==1 || 1.1372 + (std::sscanf(argument,"%f%c%c",&nb,&sep,&end)==2 && sep=='%')) { 1.1373 + if (nb<=0) error("Equalize image%s : Invalid cluster number %g.",gmic_inds,nb); 1.1374 + print("Equalize image%s with %g%s clusters.",gmic_inds,nb,sep=='%'?"%":""); 1.1375 + cimg_foroff(indices,l) { 1.1376 + CImg<T>& img = images[indices[l]]; 1.1377 + unsigned int N = (unsigned int)nb; 1.1378 + if (sep=='%') { double m, M = img.maxmin(m); N = (unsigned int)cimg::round((M-m)*nb/100,1); } 1.1379 + gmic_apply(img,equalize((int)nb)); 1.1380 + } 1.1381 + } else error("Equalize image%s : Invalid argument '%s' " 1.1382 + "(should be 'nb_clusters[%%]').",gmic_inds,argument_text); 1.1383 + ++position; continue; 1.1384 + } 1.1385 + 1.1386 + // Quantize. 1.1387 + if (!cimg::strcmp("-quantize",item0)) { 1.1388 + int nb = 0; char end = 0; 1.1389 + if (std::sscanf(argument,"%d%c",&nb,&end)==1) { 1.1390 + print("Quantize image%s with %d levels.",gmic_inds,nb); 1.1391 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],quantize(nb)); 1.1392 + } else error("Quantize image%s : Invalid argument '%s' " 1.1393 + "(should be 'nb_levels').",gmic_inds,argument_text); 1.1394 + ++position; continue; 1.1395 + } 1.1396 + 1.1397 + // Add noise. 1.1398 + if (!cimg::strcmp("-noise",item0)) { 1.1399 + float sigma = 0; char sep = 0, end = 0; int ntype = 0; 1.1400 + if (std::sscanf(argument,"%f%c",&sigma,&end)==1 || 1.1401 + (std::sscanf(argument,"%f%c%c",&sigma,&sep,&end)==2 && sep=='%') || 1.1402 + std::sscanf(argument,"%f%*c%d%c",&sigma,&ntype,&end)==2 || 1.1403 + (std::sscanf(argument,"%f%c%*c%d%c",&sigma,&sep,&ntype,&end)==3 && sep=='%')) { 1.1404 + const char *st_type = ntype==0?"gaussian":ntype==1?"uniform":ntype==2?"salt&pepper":"poisson"; 1.1405 + if (sep=='%') sigma = -sigma; 1.1406 + print("Add %s noise with standard deviation %g%s to image%s.", 1.1407 + st_type,cimg::abs(sigma),sigma<0?"%":"",gmic_inds); 1.1408 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],noise(sigma,ntype)); 1.1409 + } else error("Add noise to image%s : Invalid argument '%s' " 1.1410 + "(should be 'std[%%][,noise_type]').",gmic_inds,argument_text); 1.1411 + ++position; continue; 1.1412 + } 1.1413 + 1.1414 + // Rand. 1.1415 + if (!cimg::strcmp("-rand",item0)) { 1.1416 + double value0 = 0, value1 = 0; char end = 0; 1.1417 + if (std::sscanf(argument,"%lf%*c%lf%c",&value0,&value1,&end)==2) { 1.1418 + print("Fill image%s with random values in [%g,%g].",gmic_inds,value0,value1); 1.1419 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],rand((T)value0,(T)value1)); 1.1420 + } else error("Fill image%s with random values : Invalid argument '%s' " 1.1421 + "(should be 'valmin,valmax').",gmic_inds,argument_text); 1.1422 + ++position; continue; 1.1423 + } 1.1424 + 1.1425 + // Compute pointwise norms and orientations. 1.1426 + gmic_simple_item("-norm",pointwise_norm,"Compute vector norm."); 1.1427 + gmic_simple_item("-orientation",pointwise_orientation,"Compute vector orientation."); 1.1428 + 1.1429 + //------------------------ 1.1430 + // Color base conversions 1.1431 + //------------------------ 1.1432 + gmic_simple_item("-rgb2hsv",RGBtoHSV,"Convert image%s from RGB to HSV colorbases."); 1.1433 + gmic_simple_item("-rgb2hsl",RGBtoHSL,"Convert image%s from RGB to HSL colorbases."); 1.1434 + gmic_simple_item("-rgb2hsi",RGBtoHSI,"Convert image%s from RGB to HSI colorbases."); 1.1435 + gmic_simple_item("-rgb2yuv",RGBtoYUV,"Convert image%s from RGB to YUV colorbases."); 1.1436 + gmic_simple_item("-rgb2ycbcr",RGBtoYCbCr,"Convert image%s from RGB to YCbCr colorbases."); 1.1437 + gmic_simple_item("-rgb2xyz",RGBtoXYZ,"Convert image%s from RGB to XYZ colorbases."); 1.1438 + gmic_simple_item("-rgb2lab",RGBtoLab,"Convert image%s from RGB to Lab colorbases."); 1.1439 + gmic_simple_item("-rgb2cmy",RGBtoCMY,"Convert image%s from RGB to CMY colorbases."); 1.1440 + gmic_simple_item("-rgb2cmyk",RGBtoCMYK,"Convert image%s from RGB to CMYK colorbases."); 1.1441 + gmic_simple_item("-cmyk2rgb",CMYKtoRGB,"Convert image%s from CMYK to RGB colorbases."); 1.1442 + gmic_simple_item("-cmy2rgb",CMYtoRGB,"Convert image%s from CMY to RGB colorbases."); 1.1443 + gmic_simple_item("-lab2rgb",LabtoRGB,"Convert image%s from Lab to RGB colorbases."); 1.1444 + gmic_simple_item("-xyz2rgb",XYZtoRGB,"Convert image%s from XYZ to RGB colorbases."); 1.1445 + gmic_simple_item("-ycbcr2rgb",YCbCrtoRGB,"Convert image%s from YCbCr to RGB colorbases."); 1.1446 + gmic_simple_item("-yuv2rgb",YUVtoRGB,"Convert image%s from YUV to RGB colorbases."); 1.1447 + gmic_simple_item("-hsi2rgb",HSItoRGB,"Convert image%s from HSI to RGB colorbases."); 1.1448 + gmic_simple_item("-hsl2rgb",HSLtoRGB,"Convert image%s from HSL to RGB colorbases."); 1.1449 + gmic_simple_item("-hsv2rgb",HSVtoRGB,"Convert image%s from HSV to RGB colorbases."); 1.1450 + 1.1451 + // Apply LUT. 1.1452 + if (!cimg::strcmp("-lut2rgb",item0)) { 1.1453 + int nb = 0, ind0 = 0; char sep = 0, end = 0; 1.1454 + if (std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==2 && sep==']') { 1.1455 + gmic_check_indice(ind0,"Map LUT on image%s"); 1.1456 + print("Map LUT [%d] on image%s.",ind0,gmic_inds); 1.1457 + const CImg<T> palette = images[ind0]; 1.1458 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],pointwise_norm().LUTtoRGB(palette)); 1.1459 + } else if (std::sscanf(argument,"%d%c",&nb,&end)==1) { 1.1460 + if (nb<0 || nb>2) error("Map LUT on image%s : Invalid LUT number %d.",gmic_inds,nb); 1.1461 + print("Map %s LUT on image%s.",nb==0?"default":nb==1?"rainbow":"cluster",gmic_inds); 1.1462 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],pointwise_norm(). 1.1463 + LUTtoRGB(nb==0?CImg<T>::default_LUT8():nb==1?CImg<T>::rainbow_LUT8():CImg<T>::contrast_LUT8())); 1.1464 + } else error("Map LUT on image%s : Invalid argument '%s' " 1.1465 + "(should be '[indice]' or '{0,1,2}').",gmic_inds,argument_text); 1.1466 + ++position; continue; 1.1467 + } 1.1468 + 1.1469 + // Convert to LUT. 1.1470 + if (!cimg::strcmp("-rgb2lut",item0)) { 1.1471 + int nb = 0, ind0 = 0, dithering = 0; char sep = 0, end = 0; 1.1472 + if (std::sscanf(argument,"[%d%c%*c%d",&ind0,&sep,&dithering)>=2 && sep==']') { 1.1473 + gmic_check_indice(ind0,"Index image%s with LUT"); 1.1474 + print("Index image%s with LUT [%d] %s dithering.",gmic_inds,ind0,dithering?"with":"without"); 1.1475 + const CImg<T> palette = images[ind0]; 1.1476 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],RGBtoLUT(palette,dithering,true)); 1.1477 + } else if (std::sscanf(argument,"%d%*c%d%c",&nb,&dithering,&end)==2 || 1.1478 + std::sscanf(argument,"%d%c",&nb,&end)==1) { 1.1479 + if (nb<0 || nb>2) error("Index image%s with LUT : Invalid LUT number %d.",gmic_inds,nb); 1.1480 + print("Index image%s with %s LUT.",gmic_inds,nb==0?"default":nb==1?"rainbow":"cluster"); 1.1481 + cimg_foroff(indices,l) gmic_apply(images[indices[l]], 1.1482 + RGBtoLUT(nb==0?CImg<T>::default_LUT8():nb==1?CImg<T>::rainbow_LUT8():CImg<T>::contrast_LUT8(), 1.1483 + dithering,true)); 1.1484 + } else error("Index image%s with LUT : Invalid argument '%s' " 1.1485 + "(should be '[indice][,dithering]', or '{0,1,2}[,dithering]').",gmic_inds,argument_text); 1.1486 + ++position; continue; 1.1487 + } 1.1488 + 1.1489 + //----------------------- 1.1490 + // Geometric manipulation 1.1491 + //----------------------- 1.1492 + 1.1493 + // Resize. 1.1494 + if (!cimg::strcmp("-resize",item0) || !cimg::strcmp("-r",item0)) { 1.1495 + char 1.1496 + sepx = 0, sepy = 0, sepz = 0, sepv = 0, end = 0, 1.1497 + argx[4096] = { 0 }, argy[4096] = { 0 }, argz[4096] = { 0 }, argv[4096] = { 0 }; 1.1498 + float valx = 0, valy = 0, valz = 0, valv = 0; 1.1499 + int interpolation = 1, borders = -1, center = 0, indx = no_ind, indy = no_ind, indz = no_ind, indv = no_ind; 1.1500 + if ((std::sscanf(argument,"[%d%c%c",&indx,&sepx,&end)==2 || 1.1501 + std::sscanf(argument,"[%d%c%*c%d%c",&indx,&sepx,&interpolation,&end)==3 || 1.1502 + std::sscanf(argument,"[%d%c%*c%d%*c%d%c",&indx,&sepx,&interpolation,&borders,&end)==4 || 1.1503 + std::sscanf(argument,"[%d%c%*c%d%*c%d%*c%d%c",&indx,&sepx,&interpolation,&borders,¢er,&end)==5) 1.1504 + && sepx==']') { 1.1505 + gmic_check_indice(indx,"Resize image%s"); 1.1506 + const int 1.1507 + ivalx = images[indx].dimx(), 1.1508 + ivaly = images[indx].dimy(), 1.1509 + ivalz = images[indx].dimz(), 1.1510 + ivalv = images[indx].dimv(); 1.1511 + print("Resize image%s to %dx%dx%dx%d with %s interpolation.", 1.1512 + gmic_inds,ivalx,ivaly,ivalz,ivalv, 1.1513 + interpolation==0?"no":interpolation==1?"nearest neighbor": 1.1514 + interpolation==2?"moving average":interpolation==3?"linear": 1.1515 + interpolation==4?"grid":"cubic"); 1.1516 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],resize(ivalx,ivaly,ivalz,ivalv,interpolation,borders,center?true:false)); 1.1517 + ++position; 1.1518 + } else if (((std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%d%*c%d%*c%d%c", 1.1519 + argx,argy,argz,argv,&(interpolation=1),&(borders=-1),&(center=0),&end)==7 || 1.1520 + std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%d%*c%d%c", 1.1521 + argx,argy,argz,argv,&interpolation,&borders,&end)==6 || 1.1522 + std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%d%c", 1.1523 + argx,argy,argz,argv,&interpolation,&end)==5 || 1.1524 + std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c", 1.1525 + argx,argy,argz,argv,&end)==4) && 1.1526 + ((std::sscanf(argx,"[%d%c%c",&indx,&sepx,&end)==2 && sepx==']') || 1.1527 + (std::sscanf(argx,"%f%c%c",&valx,&sepx,&end)==2 && sepx=='%') || 1.1528 + std::sscanf(argx,"%f%c",&valx,&end)==1) && 1.1529 + ((std::sscanf(argy,"[%d%c%c",&indy,&sepy,&end)==2 && sepy==']') || 1.1530 + (std::sscanf(argy,"%f%c%c",&valy,&sepy,&end)==2 && sepy=='%') || 1.1531 + std::sscanf(argy,"%f%c",&valy,&end)==1) && 1.1532 + ((std::sscanf(argz,"[%d%c%c",&indz,&sepz,&end)==2 && sepz==']') || 1.1533 + (std::sscanf(argz,"%f%c%c",&valz,&sepz,&end)==2 && sepz=='%') || 1.1534 + std::sscanf(argz,"%f%c",&valz,&end)==1) && 1.1535 + ((std::sscanf(argv,"[%d%c%c",&indv,&sepv,&end)==2 && sepv==']') || 1.1536 + (std::sscanf(argv,"%f%c%c",&valv,&sepv,&end)==2 && sepv=='%') || 1.1537 + std::sscanf(argv,"%f%c",&valv,&end)==1)) || 1.1538 + ((std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c", 1.1539 + argx,argy,argz,&end)==3) && 1.1540 + ((std::sscanf(argx,"[%d%c%c",&indx,&sepx,&end)==2 && sepx==']') || 1.1541 + (std::sscanf(argx,"%f%c%c",&valx,&sepx,&end)==2 && sepx=='%') || 1.1542 + std::sscanf(argx,"%f%c",&valx,&end)==1) && 1.1543 + ((std::sscanf(argy,"[%d%c%c",&indy,&sepy,&end)==2 && sepy==']') || 1.1544 + (std::sscanf(argy,"%f%c%c",&valy,&sepy,&end)==2 && sepy=='%') || 1.1545 + std::sscanf(argy,"%f%c",&valy,&end)==1) && 1.1546 + ((std::sscanf(argz,"[%d%c%c",&indz,&sepz,&end)==2 && sepz==']') || 1.1547 + (std::sscanf(argz,"%f%c%c",&valz,&sepz,&end)==2 && sepz=='%') || 1.1548 + std::sscanf(argz,"%f%c",&valz,&end)==1)) || 1.1549 + ((std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c", 1.1550 + argx,argy,&end)==2) && 1.1551 + ((std::sscanf(argx,"[%d%c%c",&indx,&sepx,&end)==2 && sepx==']') || 1.1552 + (std::sscanf(argx,"%f%c%c",&valx,&sepx,&end)==2 && sepx=='%') || 1.1553 + std::sscanf(argx,"%f%c",&valx,&end)==1) && 1.1554 + ((std::sscanf(argy,"[%d%c%c",&indy,&sepy,&end)==2 && sepy==']') || 1.1555 + (std::sscanf(argy,"%f%c%c",&valy,&sepy,&end)==2 && sepy=='%') || 1.1556 + std::sscanf(argy,"%f%c",&valy,&end)==1)) || 1.1557 + ((std::sscanf(argument,"%4095[][0-9.eE%+-]%c", 1.1558 + argx,&end)==1) && 1.1559 + ((std::sscanf(argx,"[%d%c%c",&indx,&sepx,&end)==2 && sepx==']') || 1.1560 + (std::sscanf(argx,"%f%c%c",&valx,&sepx,&end)==2 && sepx=='%') || 1.1561 + std::sscanf(argx,"%f%c",&valx,&end)==1))) { 1.1562 + if (indx!=no_ind) { gmic_check_indice(indx,"Resize image%s"); valx = (float)images[indx].dimx(); sepx = 0; } 1.1563 + if (indy!=no_ind) { gmic_check_indice(indy,"Resize image%s"); valy = (float)images[indy].dimy(); sepy = 0; } 1.1564 + if (indz!=no_ind) { gmic_check_indice(indz,"Resize image%s"); valz = (float)images[indz].dimz(); sepz = 0; } 1.1565 + if (indv!=no_ind) { gmic_check_indice(indv,"Resize image%s"); valv = (float)images[indv].dimv(); sepv = 0; } 1.1566 + if (!valx) { valx = 100; sepx = '%'; } 1.1567 + if (!valy) { valy = 100; sepy = '%'; } 1.1568 + if (!valz) { valz = 100; sepz = '%'; } 1.1569 + if (!valv) { valv = 100; sepv = '%'; } 1.1570 + print("Resize image%s to %g%s%g%s%g%s%g%s with %s interpolation.", 1.1571 + gmic_inds,valx,sepx=='%'?"%x":"x",valy,sepy=='%'?"%x":"x",valz, 1.1572 + sepz=='%'?"%x":"x",valv,sepv=='%'?"% ":" ", 1.1573 + interpolation==0?"no":interpolation==1?"nearest neighbor": 1.1574 + interpolation==2?"moving average":interpolation==3?"linear": 1.1575 + interpolation==4?"grid":"cubic"); 1.1576 + 1.1577 + cimg_foroff(indices,l) { 1.1578 + CImg<T>& img = images[indices[l]]; 1.1579 + const int 1.1580 + ivalx0 = (int)cimg::round(sepx=='%'?valx*img.dimx()/100:valx,1), 1.1581 + ivaly0 = (int)cimg::round(sepy=='%'?valy*img.dimy()/100:valy,1), 1.1582 + ivalz0 = (int)cimg::round(sepz=='%'?valz*img.dimz()/100:valz,1), 1.1583 + ivalv0 = (int)cimg::round(sepv=='%'?valv*img.dimv()/100:valv,1), 1.1584 + ivalx = ivalx0?ivalx0:1, 1.1585 + ivaly = ivaly0?ivaly0:1, 1.1586 + ivalz = ivalz0?ivalz0:1, 1.1587 + ivalv = ivalv0?ivalv0:1; 1.1588 + gmic_apply(img,resize(ivalx,ivaly,ivalz,ivalv,interpolation,borders,center?true:false)); 1.1589 + } 1.1590 + ++position; 1.1591 + } else { 1.1592 + print("Resize image%s : Interactive mode.",gmic_inds); 1.1593 + char title[4096] = { 0 }; 1.1594 + cimg_foroff(indices,l) { 1.1595 + CImg<T>& img = images[indices[l]]; 1.1596 + CImgDisplay disp(img,0,1); 1.1597 + std::sprintf(title,"%s : Interactive resize",filenames[indices[l]].ptr()); 1.1598 + disp.set_title(title); 1.1599 + img.get_select(0,disp); 1.1600 + print("Resize image [%d] to %dx%d.",indices[l],disp.dimx(),disp.dimy()); 1.1601 + gmic_apply(img,resize(disp)); 1.1602 + } 1.1603 + } 1.1604 + continue; 1.1605 + } 1.1606 + 1.1607 + // Resize2x. and Resize3x. 1.1608 + gmic_simple_item("-resize2x",resize_doubleXY,"Resize image%s using Scale2x algorithm."); 1.1609 + gmic_simple_item("-resize3x",resize_doubleXY,"Resize image%s using Scale3x algorithm."); 1.1610 + 1.1611 + // Crop. 1.1612 + if (!cimg::strcmp("-crop",item0) || !cimg::strcmp("-c",item0)) { 1.1613 + char st0[4096] = { 0 }, st1[4096] = { 0 }, st2[4096] = { 0 }, st3[4096] = { 0 }; 1.1614 + char st4[4096] = { 0 }, st5[4096] = { 0 }, st6[4096] = { 0 }, st7[4096] = { 0 }; 1.1615 + char sep0 = 0, sep1 = 0, sep2 = 0, sep3 = 0, sep4 = 0, sep5 = 0, sep6 = 0, sep7 = 0, end = 0; 1.1616 + float a0 = 0, a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0, a6 = 0, a7 = 0; int borders = 0; 1.1617 + if ((std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c" 1.1618 + "%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%d%c", 1.1619 + st0,st1,st2,st3,st4,st5,st6,st7,&borders,&end)==9 || 1.1620 + std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c" 1.1621 + "%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c", 1.1622 + st0,st1,st2,st3,st4,st5,st6,st7,&end)==8) && 1.1623 + (std::sscanf(st0,"%f%c",&a0,&end)==1 || (std::sscanf(st0,"%f%c%c",&a0,&sep0,&end)==2 && sep0=='%')) && 1.1624 + (std::sscanf(st1,"%f%c",&a1,&end)==1 || (std::sscanf(st1,"%f%c%c",&a1,&sep1,&end)==2 && sep1=='%')) && 1.1625 + (std::sscanf(st2,"%f%c",&a2,&end)==1 || (std::sscanf(st2,"%f%c%c",&a2,&sep2,&end)==2 && sep2=='%')) && 1.1626 + (std::sscanf(st3,"%f%c",&a3,&end)==1 || (std::sscanf(st3,"%f%c%c",&a3,&sep3,&end)==2 && sep3=='%')) && 1.1627 + (std::sscanf(st4,"%f%c",&a4,&end)==1 || (std::sscanf(st4,"%f%c%c",&a4,&sep4,&end)==2 && sep4=='%')) && 1.1628 + (std::sscanf(st5,"%f%c",&a5,&end)==1 || (std::sscanf(st5,"%f%c%c",&a5,&sep5,&end)==2 && sep5=='%')) && 1.1629 + (std::sscanf(st6,"%f%c",&a6,&end)==1 || (std::sscanf(st6,"%f%c%c",&a6,&sep6,&end)==2 && sep6=='%')) && 1.1630 + (std::sscanf(st7,"%f%c",&a7,&end)==1 || (std::sscanf(st7,"%f%c%c",&a7,&sep7,&end)==2 && sep7=='%'))) { 1.1631 + print("Crop image%s with (%g%s%g%s%g%s%g%s x (%g%s%g%s%g%s%g%s.",gmic_inds, 1.1632 + a0,sep0=='%'?"%,":",",a1,sep1=='%'?"%,":",", 1.1633 + a2,sep2=='%'?"%,":",",a3,sep3=='%'?"%)":")", 1.1634 + a4,sep4=='%'?"%,":",",a5,sep5=='%'?"%,":",", 1.1635 + a6,sep6=='%'?"%,":",",a7,sep7=='%'?"%)":")"); 1.1636 + cimg_foroff(indices,l) { 1.1637 + CImg<T> &img = images[indices[l]]; 1.1638 + const int 1.1639 + x0 = (int)cimg::round(sep0=='%'?a0*img.dimx()/100:a0,1), 1.1640 + y0 = (int)cimg::round(sep1=='%'?a1*img.dimy()/100:a1,1), 1.1641 + z0 = (int)cimg::round(sep2=='%'?a2*img.dimz()/100:a2,1), 1.1642 + v0 = (int)cimg::round(sep3=='%'?a3*img.dimv()/100:a3,1), 1.1643 + x1 = (int)cimg::round(sep4=='%'?a4*img.dimx()/100:a4,1), 1.1644 + y1 = (int)cimg::round(sep5=='%'?a5*img.dimy()/100:a5,1), 1.1645 + z1 = (int)cimg::round(sep6=='%'?a6*img.dimz()/100:a6,1), 1.1646 + v1 = (int)cimg::round(sep7=='%'?a7*img.dimv()/100:a7,1); 1.1647 + gmic_apply(img,crop(x0,y0,z0,v0,x1,y1,z1,v1,borders?true:false)); 1.1648 + } 1.1649 + ++position; 1.1650 + } else if ((std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c" 1.1651 + "%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%d%c", 1.1652 + st0,st1,st2,st3,st4,st5,&borders,&end)==7 || 1.1653 + std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c" 1.1654 + "%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c", 1.1655 + st0,st1,st2,st3,st4,st5,&end)==6) && 1.1656 + (std::sscanf(st0,"%f%c",&a0,&end)==1 || 1.1657 + (std::sscanf(st0,"%f%c%c",&a0,&sep0,&end)==2 && sep0=='%')) && 1.1658 + (std::sscanf(st1,"%f%c",&a1,&end)==1 || 1.1659 + (std::sscanf(st1,"%f%c%c",&a1,&sep1,&end)==2 && sep1=='%')) && 1.1660 + (std::sscanf(st2,"%f%c",&a2,&end)==1 || 1.1661 + (std::sscanf(st2,"%f%c%c",&a2,&sep2,&end)==2 && sep2=='%')) && 1.1662 + (std::sscanf(st3,"%f%c",&a3,&end)==1 || 1.1663 + (std::sscanf(st3,"%f%c%c",&a3,&sep3,&end)==2 && sep3=='%')) && 1.1664 + (std::sscanf(st4,"%f%c",&a4,&end)==1 || 1.1665 + (std::sscanf(st4,"%f%c%c",&a4,&sep4,&end)==2 && sep4=='%')) && 1.1666 + (std::sscanf(st5,"%f%c",&a5,&end)==1 || 1.1667 + (std::sscanf(st5,"%f%c%c",&a5,&sep5,&end)==2 && sep5=='%'))) { 1.1668 + print("Crop image%s with (%g%s%g%s%g%s x (%g%s%g%s%g%s.",gmic_inds, 1.1669 + a0,sep0=='%'?"%,":",",a1,sep1=='%'?"%,":",",a2,sep2=='%'?"%)":")", 1.1670 + a3,sep3=='%'?"%,":",",a4,sep4=='%'?"%,":",",a5,sep5=='%'?"%)":")"); 1.1671 + cimg_foroff(indices,l) { 1.1672 + CImg<T> &img = images[indices[l]]; 1.1673 + const int 1.1674 + x0 = (int)cimg::round(sep0=='%'?a0*img.dimx()/100:a0,1), 1.1675 + y0 = (int)cimg::round(sep1=='%'?a1*img.dimy()/100:a1,1), 1.1676 + z0 = (int)cimg::round(sep2=='%'?a2*img.dimz()/100:a2,1), 1.1677 + x1 = (int)cimg::round(sep3=='%'?a3*img.dimx()/100:a3,1), 1.1678 + y1 = (int)cimg::round(sep4=='%'?a4*img.dimy()/100:a4,1), 1.1679 + z1 = (int)cimg::round(sep5=='%'?a5*img.dimz()/100:a5,1); 1.1680 + gmic_apply(img,crop(x0,y0,z0,x1,y1,z1,borders?true:false)); 1.1681 + } 1.1682 + ++position; 1.1683 + } else if ((std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c" 1.1684 + "%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%d%c", 1.1685 + st0,st1,st2,st3,&borders,&end)==5 || 1.1686 + std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c" 1.1687 + "%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c", 1.1688 + st0,st1,st2,st3,&end)==4) && 1.1689 + (std::sscanf(st0,"%f%c",&a0,&end)==1 || 1.1690 + (std::sscanf(st0,"%f%c%c",&a0,&sep0,&end)==2 && sep0=='%')) && 1.1691 + (std::sscanf(st1,"%f%c",&a1,&end)==1 || 1.1692 + (std::sscanf(st1,"%f%c%c",&a1,&sep1,&end)==2 && sep1=='%')) && 1.1693 + (std::sscanf(st2,"%f%c",&a2,&end)==1 || 1.1694 + (std::sscanf(st2,"%f%c%c",&a2,&sep2,&end)==2 && sep2=='%')) && 1.1695 + (std::sscanf(st3,"%f%c",&a3,&end)==1 || 1.1696 + (std::sscanf(st3,"%f%c%c",&a3,&sep3,&end)==2 && sep3=='%'))) { 1.1697 + print("Crop image%s with (%g%s%g%s x (%g%s%g%s.",gmic_inds, 1.1698 + a0,sep0=='%'?"%,":",",a1,sep1=='%'?"%)":")", 1.1699 + a2,sep2=='%'?"%,":",",a3,sep3=='%'?"%)":")"); 1.1700 + cimg_foroff(indices,l) { 1.1701 + CImg<T> &img = images[indices[l]]; 1.1702 + const int 1.1703 + x0 = (int)cimg::round(sep0=='%'?a0*img.dimx()/100:a0,1), 1.1704 + y0 = (int)cimg::round(sep1=='%'?a1*img.dimy()/100:a1,1), 1.1705 + x1 = (int)cimg::round(sep2=='%'?a2*img.dimx()/100:a2,1), 1.1706 + y1 = (int)cimg::round(sep3=='%'?a3*img.dimy()/100:a3,1); 1.1707 + gmic_apply(img,crop(x0,y0,x1,y1,borders?true:false)); 1.1708 + } 1.1709 + ++position; 1.1710 + } else if ((std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%d%c",st0,st1,&borders,&end)==3 || 1.1711 + std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c",st0,st1,&end)==2) && 1.1712 + (std::sscanf(st0,"%f%c",&a0,&end)==1 || 1.1713 + (std::sscanf(st0,"%f%c%c",&a0,&sep0,&end)==2 && sep0=='%')) && 1.1714 + (std::sscanf(st1,"%f%c",&a1,&end)==1 || 1.1715 + (std::sscanf(st1,"%f%c%c",&a1,&sep1,&end)==2 && sep1=='%'))) { 1.1716 + print("Crop image%s with (%g%s x (%g%s.",gmic_inds, 1.1717 + a0,sep0=='%'?"%)":")",a1,sep1=='%'?"%)":")"); 1.1718 + cimg_foroff(indices,l) { 1.1719 + CImg<T> &img = images[indices[l]]; 1.1720 + const int 1.1721 + x0 = (int)cimg::round(sep0=='%'?a0*img.dimx()/100:a0,1), 1.1722 + x1 = (int)cimg::round(sep1=='%'?a1*img.dimx()/100:a1,1); 1.1723 + gmic_apply(img,crop(x0,x1,borders?true:false)); 1.1724 + } 1.1725 + ++position; 1.1726 + } else { 1.1727 + print("Crop image%s : Interactive mode.",gmic_inds); 1.1728 + char title[4096] = { 0 }; 1.1729 + cimg_foroff(indices,l) { 1.1730 + CImg<T>& img = images[indices[l]]; 1.1731 + CImgDisplay disp(cimg_fitscreen(img.dimx(),img.dimy(),1),0,1); 1.1732 + std::sprintf(title,"%s : Interactive crop",filenames[indices[l]].ptr()); 1.1733 + disp.set_title(title); 1.1734 + const CImg<int> s = img.get_select(disp,2); 1.1735 + print("Crop image [%d] with (%d,%d,%d) x (%d,%d,%d).", 1.1736 + indices[l],s[0],s[1],s[2],s[3],s[4],s[5]); 1.1737 + gmic_apply(img,crop(s[0],s[1],s[2],s[3],s[4],s[5])); 1.1738 + } 1.1739 + } 1.1740 + continue; 1.1741 + } 1.1742 + 1.1743 + // Autocrop. 1.1744 + if (!cimg::strcmp("-autocrop",item0)) { 1.1745 + print("Autocrop image%s with color '%s'.",gmic_inds,argument_text); 1.1746 + cimg_foroff(indices,l) { 1.1747 + CImg<T>& img = images[indices[l]]; 1.1748 + const CImg<T> col = CImg<T>(img.dimv()).fill(argument,true); 1.1749 + gmic_apply(img,autocrop(col)); 1.1750 + } 1.1751 + ++position; continue; 1.1752 + } 1.1753 + 1.1754 + // Select channels. 1.1755 + if (!cimg::strcmp("-channels",item0)) { 1.1756 + char sep0 = 0, sep1 = 0, end = 0, arg0[4096] = { 0 }, arg1[4096] = { 0 }; 1.1757 + float value0 = 0, value1 = 0; int ind0 = no_ind, ind1 = no_ind; 1.1758 + if (std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c",arg0,arg1,&end)==2 && 1.1759 + ((std::sscanf(arg0,"[%d%c%c]",&ind0,&sep0,&end)==2 && sep0==']') || 1.1760 + (std::sscanf(arg0,"%f%c%c",&value0,&sep0,&end)==2 && sep0=='%') || 1.1761 + std::sscanf(arg0,"%f%c",&value0,&end)==1) && 1.1762 + ((std::sscanf(arg1,"[%d%c%c]",&ind1,&sep1,&end)==2 && sep1==']') || 1.1763 + (std::sscanf(arg1,"%f%c%c",&value1,&sep1,&end)==2 && sep1=='%') || 1.1764 + std::sscanf(arg1,"%f%c",&value1,&end)==1)) { 1.1765 + if (ind0!=no_ind) { gmic_check_indice(ind0,"Keep channels of image%s"); value0 = images[ind0].dimv()-1.0f; sep0 = 0; } 1.1766 + if (ind1!=no_ind) { gmic_check_indice(ind1,"Keep channels of image%s"); value1 = images[ind1].dimv()-1.0f; sep1 = 0; } 1.1767 + print("Keep channels %g%s..%g%s of image%s.",value0,sep0=='%'?"%":"",value1,sep1=='%'?"%":"",gmic_inds); 1.1768 + cimg_foroff(indices,l) { 1.1769 + CImg<T> &img = images[indices[l]]; 1.1770 + const int 1.1771 + nvalue0 = (int)cimg::round(sep0=='%'?value0*(img.dimv()-1)/100:value0,1), 1.1772 + nvalue1 = (int)cimg::round(sep1=='%'?value1*(img.dimv()-1)/100:value1,1); 1.1773 + gmic_apply(img,channels(nvalue0,nvalue1)); 1.1774 + } 1.1775 + } else if (std::sscanf(argument,"%4095[][0-9.eE%+-]%c",arg0,&end)==1 && 1.1776 + ((std::sscanf(arg0,"[%d%c%c]",&ind0,&sep0,&end)==2 && sep0==']') || 1.1777 + (std::sscanf(arg0,"%f%c%c",&value0,&sep0,&end)==2 && sep0=='%') || 1.1778 + std::sscanf(arg0,"%f%c",&value0,&end)==1)) { 1.1779 + if (ind0!=no_ind) { gmic_check_indice(ind0,"Keep channel of image%s"); value0 = images[ind0].dimv()-1.0f; sep0 = 0; } 1.1780 + print("Keep channel %g%s of image%s.",value0,sep0=='%'?"%":"",gmic_inds); 1.1781 + cimg_foroff(indices,l) { 1.1782 + CImg<T> &img = images[indices[l]]; 1.1783 + const int nvalue0 = (int)cimg::round(sep0=='%'?value0*(img.dimv()-1)/100:value0,1); 1.1784 + gmic_apply(img,channel(nvalue0)); 1.1785 + } 1.1786 + } else error("Keep channels of image%s : Invalid argument '%s' " 1.1787 + "(should be 'channel0[%%][,channel1[%%]]').",gmic_inds,argument_text); 1.1788 + ++position; continue; 1.1789 + } 1.1790 + 1.1791 + // Select slices. 1.1792 + if (!cimg::strcmp("-slices",item0)) { 1.1793 + char sep0 = 0, sep1 = 0, end = 0, arg0[4096] = { 0 }, arg1[4096] = { 0 }; 1.1794 + float value0 = 0, value1 = 0; int ind0 = no_ind, ind1 = no_ind; 1.1795 + if (std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c",arg0,arg1,&end)==2 && 1.1796 + ((std::sscanf(arg0,"[%d%c%c]",&ind0,&sep0,&end)==2 && sep0==']') || 1.1797 + (std::sscanf(arg0,"%f%c%c",&value0,&sep0,&end)==2 && sep0=='%') || 1.1798 + std::sscanf(arg0,"%f%c",&value0,&end)==1) && 1.1799 + ((std::sscanf(arg1,"[%d%c%c]",&ind1,&sep1,&end)==2 && sep1==']') || 1.1800 + (std::sscanf(arg1,"%f%c%c",&value1,&sep1,&end)==2 && sep1=='%') || 1.1801 + std::sscanf(arg1,"%f%c",&value1,&end)==1)) { 1.1802 + if (ind0!=no_ind) { gmic_check_indice(ind0,"Select slices of image%s"); value0 = images[ind0].dimz()-1.0f; sep0 = 0; } 1.1803 + if (ind1!=no_ind) { gmic_check_indice(ind1,"Select slices of image%s"); value1 = images[ind1].dimz()-1.0f; sep1 = 0; } 1.1804 + print("Select slices %g%s..%g%s of image%s.",value0,sep0=='%'?"%":"",value1,sep1=='%'?"%":"",gmic_inds); 1.1805 + cimg_foroff(indices,l) { 1.1806 + CImg<T> &img = images[indices[l]]; 1.1807 + const int 1.1808 + nvalue0 = (int)cimg::round(sep0=='%'?value0*(img.dimv()-1)/100:value0,0), 1.1809 + nvalue1 = (int)cimg::round(sep1=='%'?value1*(img.dimv()-1)/100:value1,0); 1.1810 + gmic_apply(img,slices(nvalue0,nvalue1)); 1.1811 + } 1.1812 + } else if (std::sscanf(argument,"%4095[][0-9.eE%+-]%c",arg0,&end)==1 && 1.1813 + ((std::sscanf(arg0,"[%d%c%c]",&ind0,&sep0,&end)==2 && sep0==']') || 1.1814 + (std::sscanf(arg0,"%f%c%c",&value0,&sep0,&end)==2 && sep0=='%') || 1.1815 + std::sscanf(arg0,"%f%c",&value0,&end)==1)) { 1.1816 + if (ind0!=no_ind) { gmic_check_indice(ind0,"Select slice of image%s"); value0 = images[ind0].dimz()-1.0f; sep0 = 0; } 1.1817 + print("Select slice %g%s of image%s.",value0,sep0=='%'?"%":"",gmic_inds); 1.1818 + cimg_foroff(indices,l) { 1.1819 + CImg<T> &img = images[indices[l]]; 1.1820 + const int nvalue0 = (int)cimg::round(sep0=='%'?value0*(img.dimz()-1)/100:value0,1); 1.1821 + gmic_apply(img,slice(nvalue0)); 1.1822 + } 1.1823 + } else error("Select slices of image%s : Invalid argument '%s' " 1.1824 + "(should be 'slice0[%%][,slice1[%%]]').",gmic_inds,argument_text); 1.1825 + ++position; continue; 1.1826 + } 1.1827 + 1.1828 + // Select lines. 1.1829 + if (!cimg::strcmp("-lines",item0) || !cimg::strcmp("-l",item0)) { 1.1830 + char sep0 = 0, sep1 = 0, end = 0, arg0[4096] = { 0 }, arg1[4096] = { 0 }; 1.1831 + float value0 = 0, value1 = 0; int ind0 = no_ind, ind1 = no_ind; 1.1832 + if (std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c",arg0,arg1,&end)==2 && 1.1833 + ((std::sscanf(arg0,"[%d%c%c]",&ind0,&sep0,&end)==2 && sep0==']') || 1.1834 + (std::sscanf(arg0,"%f%c%c",&value0,&sep0,&end)==2 && sep0=='%') || 1.1835 + std::sscanf(arg0,"%f%c",&value0,&end)==1) && 1.1836 + ((std::sscanf(arg1,"[%d%c%c]",&ind1,&sep1,&end)==2 && sep1==']') || 1.1837 + (std::sscanf(arg1,"%f%c%c",&value1,&sep1,&end)==2 && sep1=='%') || 1.1838 + std::sscanf(arg1,"%f%c",&value1,&end)==1)) { 1.1839 + if (ind0!=no_ind) { gmic_check_indice(ind0,"Select lines of image%s"); value0 = images[ind0].dimy()-1.0f; sep0 = 0; } 1.1840 + if (ind1!=no_ind) { gmic_check_indice(ind1,"Select lines of image%s"); value1 = images[ind1].dimy()-1.0f; sep1 = 0; } 1.1841 + print("Select lines %g%s..%g%s of image%s.",value0,sep0=='%'?"%":"",value1,sep1=='%'?"%":"",gmic_inds); 1.1842 + cimg_foroff(indices,l) { 1.1843 + CImg<T> &img = images[indices[l]]; 1.1844 + const int 1.1845 + nvalue0 = (int)cimg::round(sep0=='%'?value0*(img.dimy()-1)/100:value0,1), 1.1846 + nvalue1 = (int)cimg::round(sep1=='%'?value1*(img.dimy()-1)/100:value1,1); 1.1847 + gmic_apply(img,lines(nvalue0,nvalue1)); 1.1848 + } 1.1849 + } else if (std::sscanf(argument,"%4095[][0-9.eE%+-]%c",arg0,&end)==1 && 1.1850 + ((std::sscanf(arg0,"[%d%c%c]",&ind0,&sep0,&end)==2 && sep0==']') || 1.1851 + (std::sscanf(arg0,"%f%c%c",&value0,&sep0,&end)==2 && sep0=='%') || 1.1852 + std::sscanf(arg0,"%f%c",&value0,&end)==1)) { 1.1853 + if (ind0!=no_ind) { gmic_check_indice(ind0,"Select lines of image%s"); value0 = images[ind0].dimy()-1.0f; sep0 = 0; } 1.1854 + print("Select lines %g%s of image%s.",value0,sep0=='%'?"%":"",gmic_inds); 1.1855 + cimg_foroff(indices,l) { 1.1856 + CImg<T> &img = images[indices[l]]; 1.1857 + const int nvalue0 = (int)cimg::round(sep0=='%'?value0*(img.dimy()-1)/100:value0,1); 1.1858 + gmic_apply(img,line(nvalue0)); 1.1859 + } 1.1860 + } else error("Select lines of image%s : Invalid argument '%s' " 1.1861 + "(should be 'line0[%%][,line1[%%]]').",gmic_inds,argument_text); 1.1862 + ++position; continue; 1.1863 + } 1.1864 + 1.1865 + // Columns. 1.1866 + if (!cimg::strcmp("-columns",item0)) { 1.1867 + char sep0 = 0, sep1 = 0, end = 0, arg0[4096] = { 0 }, arg1[4096] = { 0 }; 1.1868 + float value0 = 0, value1 = 0; int ind0 = no_ind, ind1 = no_ind; 1.1869 + if (std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c",arg0,arg1,&end)==2 && 1.1870 + ((std::sscanf(arg0,"[%d%c%c]",&ind0,&sep0,&end)==2 && sep0==']') || 1.1871 + (std::sscanf(arg0,"%f%c%c",&value0,&sep0,&end)==2 && sep0=='%') || 1.1872 + std::sscanf(arg0,"%f%c",&value0,&end)==1) && 1.1873 + ((std::sscanf(arg1,"[%d%c%c]",&ind1,&sep1,&end)==2 && sep1==']') || 1.1874 + (std::sscanf(arg1,"%f%c%c",&value1,&sep1,&end)==2 && sep1=='%') || 1.1875 + std::sscanf(arg1,"%f%c",&value1,&end)==1)) { 1.1876 + if (ind0!=no_ind) { gmic_check_indice(ind0,"Select columns of image%s"); value0 = images[ind0].dimx()-1.0f; sep0 = 0; } 1.1877 + if (ind1!=no_ind) { gmic_check_indice(ind1,"Select columns of image%s"); value1 = images[ind1].dimx()-1.0f; sep1 = 0; } 1.1878 + print("Select columns %g%s..%g%s of image%s.",value0,sep0=='%'?"%":"",value1,sep1=='%'?"%":"",gmic_inds); 1.1879 + cimg_foroff(indices,l) { 1.1880 + CImg<T> &img = images[indices[l]]; 1.1881 + const int 1.1882 + nvalue0 = (int)cimg::round(sep0=='%'?value0*(img.dimx()-1)/100:value0,1), 1.1883 + nvalue1 = (int)cimg::round(sep1=='%'?value1*(img.dimx()-1)/100:value1,1); 1.1884 + gmic_apply(img,lines(nvalue0,nvalue1)); 1.1885 + } 1.1886 + } else if (std::sscanf(argument,"%4095[][0-9.eE%+-]%c",arg0,&end)==1 && 1.1887 + ((std::sscanf(arg0,"[%d%c%c]",&ind0,&sep0,&end)==2 && sep0==']') || 1.1888 + (std::sscanf(arg0,"%f%c%c",&value0,&sep0,&end)==2 && sep0=='%') || 1.1889 + std::sscanf(arg0,"%f%c",&value0,&end)==1)) { 1.1890 + if (ind0!=no_ind) { gmic_check_indice(ind0,"Select columns of image%s"); value0 = images[ind0].dimx()-1.0f; sep0 = 0; } 1.1891 + print("Select columns %g%s of image%s.",value0,sep0=='%'?"%":"",gmic_inds); 1.1892 + cimg_foroff(indices,l) { 1.1893 + CImg<T> &img = images[indices[l]]; 1.1894 + const int nvalue0 = (int)cimg::round(sep0=='%'?value0*(img.dimx()-1)/100:value0,1); 1.1895 + gmic_apply(img,line(nvalue0)); 1.1896 + } 1.1897 + } else error("Select columns of image%s : Invalid argument '%s' " 1.1898 + "(should be 'column0[%%][,column1[%%]]').",gmic_inds,argument_text); 1.1899 + ++position; continue; 1.1900 + } 1.1901 + 1.1902 + // Rotate. 1.1903 + if (!cimg::strcmp("-rotate",item0)) { 1.1904 + float angle = 0; int borders = 0, interpolation = 1; char end = 0; 1.1905 + if (std::sscanf(argument,"%f%c",&angle,&end)==1 || 1.1906 + std::sscanf(argument,"%f%*c%d%c",&angle,&borders,&end)==2 || 1.1907 + std::sscanf(argument,"%f%*c%d%*c%d%c",&angle,&borders,&interpolation,&end)==3) { 1.1908 + print("Rotate image%s with an angle of %g deg and %s interpolation.", 1.1909 + gmic_inds,angle,interpolation?"linear":"nearest-neighbor"); 1.1910 + if (borders>=0) { cimg_foroff(indices,l) gmic_apply(images[indices[l]],rotate(angle,borders,interpolation)); } 1.1911 + else cimg_foroff(indices,l) { 1.1912 + CImg<T> &img = images[indices[l]]; 1.1913 + gmic_apply(img,rotate(angle,img.dimx()/2.0f,img.dimy()/2.0f,1,-1-borders,interpolation)); 1.1914 + } 1.1915 + } else error("Rotate image%s : Invalid argument '%s' " 1.1916 + "(should be 'angle[,border_conditions[,interpolation]]').",gmic_inds,argument_text); 1.1917 + ++position; 1.1918 + continue; 1.1919 + } 1.1920 + 1.1921 + // Mirror. 1.1922 + if (!cimg::strcmp("-mirror",item0)) { 1.1923 + const char axis = cimg::uncase(*argument); 1.1924 + if (cimg::strlen(argument)==1) { 1.1925 + print("Mirror image%s along the %c-axis.",gmic_inds,axis); 1.1926 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],mirror(axis)); 1.1927 + } else error("Mirror image%s : Invalid argument '%s' " 1.1928 + "(should be '{x,y,z,v}').",gmic_inds,argument_text); 1.1929 + ++position; continue; 1.1930 + } 1.1931 + 1.1932 + // Translate. 1.1933 + if (!cimg::strcmp("-translate",item0)) { 1.1934 + char stx[4096] = { 0 }, sty[4096] = { 0 }, stz[4096] = { 0 }, stv[4096] = { 0 }; 1.1935 + char sepx = 0, sepy = 0, sepz = 0, sepv = 0, end = 0; 1.1936 + float dx = 0, dy = 0, dz = 0, dv = 0; int borders = 0; 1.1937 + if (((std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%d%c", 1.1938 + stx,sty,stz,stv,&borders,&end)==5 || 1.1939 + std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c", 1.1940 + stx,sty,stz,stv,&end)==4) && 1.1941 + (std::sscanf(stx,"%f%c",&dx,&end)==1 || (std::sscanf(stx,"%f%c%c",&dx,&sepx,&end)==2 && sepx=='%')) && 1.1942 + (std::sscanf(sty,"%f%c",&dy,&end)==1 || (std::sscanf(sty,"%f%c%c",&dy,&sepy,&end)==2 && sepy=='%')) && 1.1943 + (std::sscanf(stz,"%f%c",&dz,&end)==1 || (std::sscanf(stz,"%f%c%c",&dz,&sepz,&end)==2 && sepz=='%')) && 1.1944 + (std::sscanf(stv,"%f%c",&dv,&end)==1 || (std::sscanf(stv,"%f%c%c",&dv,&sepv,&end)==2 && sepv=='%'))) || 1.1945 + (std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c",stx,sty,stz,&end)==3 && 1.1946 + (std::sscanf(stx,"%f%c",&dx,&end)==1 || (std::sscanf(stx,"%f%c%c",&dx,&sepx,&end)==2 && sepx=='%')) && 1.1947 + (std::sscanf(sty,"%f%c",&dy,&end)==1 || (std::sscanf(sty,"%f%c%c",&dy,&sepy,&end)==2 && sepy=='%')) && 1.1948 + (std::sscanf(stz,"%f%c",&dz,&end)==1 || (std::sscanf(stz,"%f%c%c",&dz,&sepz,&end)==2 && sepz=='%'))) || 1.1949 + (std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c",stx,sty,&end)==2 && 1.1950 + (std::sscanf(stx,"%f%c",&dx,&end)==1 || (std::sscanf(stx,"%f%c%c",&dx,&sepx,&end)==2 && sepx=='%')) && 1.1951 + (std::sscanf(sty,"%f%c",&dy,&end)==1 || (std::sscanf(sty,"%f%c%c",&dy,&sepy,&end)==2 && sepy=='%'))) || 1.1952 + (std::sscanf(argument,"%4095[0-9.eE%+-]%c",stx,&end)==1 && 1.1953 + (std::sscanf(stx,"%f%c",&dx,&end)==1 || (std::sscanf(stx,"%f%c%c",&dx,&sepx,&end)==2 && sepx=='%')))) { 1.1954 + print("Translate image%s with vector (%g%s,%g%s,%g%s,%g%s).", 1.1955 + gmic_inds,dx,sepx=='%'?"%":"",dy,sepy=='%'?"%":"",dz,sepz=='%'?"%":"",dv,sepv=='%'?"%":""); 1.1956 + cimg_foroff(indices,l) { 1.1957 + CImg<T> &img = images[indices[l]]; 1.1958 + const int 1.1959 + ndx = (int)cimg::round(sepx=='%'?dx*img.dimx()/100:dx,1), 1.1960 + ndy = (int)cimg::round(sepy=='%'?dy*img.dimy()/100:dy,1), 1.1961 + ndz = (int)cimg::round(sepz=='%'?dz*img.dimz()/100:dz,1), 1.1962 + ndv = (int)cimg::round(sepv=='%'?dv*img.dimv()/100:dv,1); 1.1963 + gmic_apply(images[indices[l]],translate(ndx,ndy,ndz,ndv,borders)); 1.1964 + } 1.1965 + } else error("Translate image%s : Invalid argument '%s' " 1.1966 + "(should be 'tx[%%][,ty[%%][,tz[%%][,tv[%%][,border_conditions]]]]').",gmic_inds,argument_text); 1.1967 + ++position; continue; 1.1968 + } 1.1969 + 1.1970 + // Transpose. 1.1971 + gmic_simple_item("-transpose",transpose,"Transpose image%s."); 1.1972 + 1.1973 + // Invert. 1.1974 + gmic_simple_item("-invert",invert,"Compute matrix inversion of image%s."); 1.1975 + 1.1976 + // Permute axes. 1.1977 + if (!cimg::strcmp("-permute",item0)) { 1.1978 + print("Permute axes of image%s with permutation '%s'.",gmic_inds,argument_text); 1.1979 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],permute_axes(argument)); 1.1980 + ++position; continue; 1.1981 + } 1.1982 + 1.1983 + // Unroll. 1.1984 + if (!cimg::strcmp("-unroll",item0)) { 1.1985 + const char axis = cimg::uncase(*argument); 1.1986 + if (cimg::strlen(argument)==1 && (axis=='x' || axis=='y' || axis=='z' || axis=='v')) { 1.1987 + print("Unroll image%s along the %c-axis.",gmic_inds,axis); 1.1988 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],unroll(axis)); 1.1989 + } else error("Unroll image%s : Invalid argument '%s' " 1.1990 + "(should be '{x,y,z,v}').",gmic_inds,argument_text); 1.1991 + ++position; continue; 1.1992 + } 1.1993 + 1.1994 + // Split image(s). 1.1995 + if (!cimg::strcmp("-split",item0) || !cimg::strcmp("-s",item0)) { 1.1996 + char axis = cimg::uncase(*argument), foo = 0, end = 0; int nb = 0, keep_value = 0; double value = 0; 1.1997 + if ((std::sscanf(argument,"%c%c",&foo,&end)==1 || 1.1998 + std::sscanf(argument,"%c%*c%d%c",&foo,&nb,&end)==2) & 1.1999 + (axis=='x' || axis=='y' || axis=='z' || axis=='v')) { 1.2000 + if (nb<0) error("Split image%s along the %c-axis in %d part : Invalid number of parts.", 1.2001 + gmic_inds,axis,nb); 1.2002 + if (nb>0) print("Split image%s along the %c-axis in %d parts.",gmic_inds,axis,nb); 1.2003 + else print("Split image%s along the %c-axis.",gmic_inds,axis); 1.2004 + unsigned int off = 0; 1.2005 + cimg_foroff(indices,l) { 1.2006 + const unsigned int ind = indices[l] + off; 1.2007 + const CImg<T>& img = images[ind]; 1.2008 + const CImg<char> filename = filenames[ind]; 1.2009 + const CImgList<T> split = img.get_split(axis,nb); 1.2010 + if (get_version) { 1.2011 + images.insert(split); 1.2012 + filenames.insert(split.size,filename); 1.2013 + } else { 1.2014 + images.remove(ind); images.insert(split,ind); 1.2015 + filenames.remove(ind); filenames.insert(split.size,filename,ind); 1.2016 + off+=split.size-1; 1.2017 + } 1.2018 + } 1.2019 + } else if (std::sscanf(argument,"%lf%c",&value,&end)==1 || 1.2020 + std::sscanf(argument,"%lf%*c%d%c",&value,&keep_value,&end)==2) { 1.2021 + print("Split image%s according to value %g.",gmic_inds,value); 1.2022 + unsigned int off = 0; 1.2023 + cimg_foroff(indices,l) { 1.2024 + const unsigned int ind = indices[l] + off; 1.2025 + CImg<T>& img = images[ind]; 1.2026 + const CImg<char> filename = filenames[ind]; 1.2027 + const CImgList<T> split = img.get_split((T)value,keep_value,false); 1.2028 + if (get_version) { 1.2029 + images.insert(split); 1.2030 + filenames.insert(split.size,filename); 1.2031 + } else { 1.2032 + images.remove(ind); images.insert(split,ind); 1.2033 + filenames.remove(ind); filenames.insert(split.size,filename,ind); 1.2034 + off+=split.size-1; 1.2035 + } 1.2036 + } 1.2037 + } else error("Split image%s : Invalid argument '%s' " 1.2038 + "(should be 'axis[,nb_parts]' where 'axis' can be '{x,y,z,v}').",gmic_inds,argument_text); 1.2039 + ++position; continue; 1.2040 + } 1.2041 + 1.2042 + // Append image(s). 1.2043 + if (!cimg::strcmp("-append",item0) || !cimg::strcmp("-a",item0)) { 1.2044 + char axis = 0, align='p', end = 0; 1.2045 + if ((std::sscanf(argument,"%c%c",&axis,&end)==1 || 1.2046 + std::sscanf(argument,"%c%*c%c%c",&axis,&align,&end)==2)) { 1.2047 + axis = cimg::uncase(axis); 1.2048 + print("Append image%s along the %c-axis with %s alignment.", 1.2049 + gmic_inds,axis,align=='p'?"left":align=='c'?"center":"right"); 1.2050 + CImgList<T> subimages; cimg_foroff(indices,l) subimages.insert(images[indices[l]],~0U,true); 1.2051 + if (get_version) { 1.2052 + images.insert(subimages.get_append(axis,align)); 1.2053 + filenames.insert(filenames[indices[0]]); 1.2054 + } else { 1.2055 + images.insert(subimages.get_append(axis,align),indices[0]); 1.2056 + filenames.insert(filenames[indices[0]],indices[0]); 1.2057 + int off = 1; 1.2058 + cimg_foroff(indices,l) { 1.2059 + const int ind = indices[l] + off; 1.2060 + images.remove(ind); filenames.remove(ind); 1.2061 + --off; 1.2062 + } 1.2063 + } 1.2064 + } else error("Append image%s : Invalid argument '%s' " 1.2065 + "(should be 'axis[,alignement]' where 'axis' can be '{x,y,z,v}' " 1.2066 + "and alignement '{p,c,n}').",gmic_inds,argument_text); 1.2067 + ++position; continue; 1.2068 + } 1.2069 + 1.2070 + // Warp image(s). 1.2071 + if (!cimg::strcmp("-warp",item0)) { 1.2072 + int ind0 = no_ind, interpolation = 1, relative = 0, nb = 1, borders = 1; char end = 0, sep = 0; 1.2073 + if ((std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==2 && sep==']')|| 1.2074 + std::sscanf(argument,"[%d]%*c%d%c",&ind0,&relative,&end)==2 || 1.2075 + std::sscanf(argument,"[%d]%*c%d%*c%d%c",&ind0,&relative,&interpolation,&end)==3 || 1.2076 + std::sscanf(argument,"[%d]%*c%d%*c%d%*c%d%c",&ind0,&relative,&interpolation,&borders,&end)==4 || 1.2077 + std::sscanf(argument,"[%d]%*c%d%*c%d%*c%d%*c%d%c",&ind0,&relative,&interpolation,&borders,&nb,&end)==5) { 1.2078 + gmic_check_indice(ind0,"Warp image%s"); 1.2079 + if (nb!=1) print("Warp image%s with %s field [%u] and %d frames.", 1.2080 + gmic_inds,relative?"relative":"absolute",ind0,nb); 1.2081 + else print("Warp image%s with %s field [%u].",gmic_inds,relative?"relative":"absolute",ind0); 1.2082 + if (nb>=1) { 1.2083 + const CImg<T> warp = images[ind0]; 1.2084 + unsigned int off = 0; 1.2085 + cimg_foroff(indices,l) { 1.2086 + const unsigned int ind = indices[l] + off; 1.2087 + CImg<T> &img = images[ind]; 1.2088 + CImgList<T> frames(nb); 1.2089 + cimglist_for(frames,t) { 1.2090 + const CImg<T> nwarp = warp.get_resize(img.dimx(),img.dimy(),img.dimz(),warp.dimv(),3)*=(t+1.0f)/nb; 1.2091 + frames[t] = img.get_warp(nwarp,relative?true:false,interpolation?true:false,borders); 1.2092 + } 1.2093 + if (get_version) { 1.2094 + images.insert(frames); 1.2095 + filenames.insert(nb-1,filenames[ind]); 1.2096 + } else { 1.2097 + images.remove(ind); images.insert(frames,ind); 1.2098 + filenames.insert(nb-1,filenames[ind],ind); 1.2099 + off+=nb-1; 1.2100 + } 1.2101 + } 1.2102 + } 1.2103 + } else error("Warp image%s : Invalid argument '%s' " 1.2104 + "(should be '[indice][,relative[,interpolation[,border_conditions[,nb_frames]]]]').", 1.2105 + gmic_inds,argument_text); 1.2106 + ++position; continue; 1.2107 + } 1.2108 + 1.2109 + //----------------------- 1.2110 + // Image filtering 1.2111 + //----------------------- 1.2112 + 1.2113 + // Gaussian blur. 1.2114 + if (!cimg::strcmp("-blur",item0)) { 1.2115 + float sigma = -1; int borders = 1; char end = 0; 1.2116 + if ((std::sscanf(argument,"%f%c",&sigma,&end)==1 || 1.2117 + std::sscanf(argument,"%f%*c%d%c",&sigma,&borders,&end)==2) 1.2118 + && sigma>=0) { 1.2119 + print("Blur image%s with standard deviation %g.",gmic_inds,sigma); 1.2120 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],blur(sigma,borders?true:false)); 1.2121 + } else error("Blur image%s : Invalid argument '%s' " 1.2122 + "(should be 'stdev[,border_conditions]', with stdev>=0).",gmic_inds,argument_text); 1.2123 + ++position; continue; 1.2124 + } 1.2125 + 1.2126 + // Bilateral filter. 1.2127 + if (!cimg::strcmp("-bilateral",item0)) { 1.2128 + float sigmas = 0, sigmar = 0; char end = 0; 1.2129 + if (std::sscanf(argument,"%f%*c%f%c",&sigmas,&sigmar,&end)==2) { 1.2130 + print("Apply bilateral filter on image%s with standart deviations %g and %g.", 1.2131 + gmic_inds,sigmas,sigmar); 1.2132 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],blur_bilateral(sigmas,sigmar)); 1.2133 + } else error("Apply bilateral filter on image%s : Invalid argument '%s' " 1.2134 + "(should be 'stdevs,stdevr').",gmic_inds,argument_text); 1.2135 + ++position; continue; 1.2136 + } 1.2137 + 1.2138 + // Smooth. 1.2139 + if (!cimg::strcmp("-smooth",item0)) { 1.2140 + float amplitude = 0, sharpness = 0.7f, anisotropy = 0.3f, alpha = 0.6f, sigma = 1.1f, dl =0.8f, da = 30.0f, gauss_prec = 2.0f; 1.2141 + unsigned int interpolation_type = 0, fast_approx = 1; 1.2142 + char end = 0; 1.2143 + if (std::sscanf(argument,"%f%c",&litude,&end)==1 || 1.2144 + std::sscanf(argument,"%f%*c%f%c",&litude,&sharpness,&end)==2 || 1.2145 + std::sscanf(argument,"%f%*c%f%*c%f%c",&litude,&sharpness,&anisotropy,&end)==3 || 1.2146 + std::sscanf(argument,"%f%*c%f%*c%f%*c%f%c",&litude,&sharpness,&anisotropy,&alpha,&end)==4 || 1.2147 + std::sscanf(argument,"%f%*c%f%*c%f%*c%f%*c%f%c",&litude,&sharpness,&anisotropy,&alpha,&sigma,&end)==5 || 1.2148 + std::sscanf(argument,"%f%*c%f%*c%f%*c%f%*c%f%*c%f%c",&litude,&sharpness,&anisotropy,&alpha,&sigma,&dl,&end)==6 || 1.2149 + std::sscanf(argument,"%f%*c%f%*c%f%*c%f%*c%f%*c%f%*c%f%c",&litude,&sharpness,&anisotropy,&alpha,&sigma,&dl,&da,&end)==7 || 1.2150 + std::sscanf(argument,"%f%*c%f%*c%f%*c%f%*c%f%*c%f%*c%f%*c%f%c", 1.2151 + &litude,&sharpness,&anisotropy,&alpha,&sigma,&dl,&da,&gauss_prec,&end)==8 || 1.2152 + std::sscanf(argument,"%f%*c%f%*c%f%*c%f%*c%f%*c%f%*c%f%*c%f%*c%u%c", 1.2153 + &litude,&sharpness,&anisotropy,&alpha,&sigma,&dl,&da,&gauss_prec,&interpolation_type,&end)==9 || 1.2154 + std::sscanf(argument,"%f%*c%f%*c%f%*c%f%*c%f%*c%f%*c%f%*c%f%*c%u%*c%u%c", 1.2155 + &litude,&sharpness,&anisotropy,&alpha,&sigma,&dl,&da,&gauss_prec,&interpolation_type,&fast_approx,&end)==10) { 1.2156 + print("Smooth image%s anisotropically with " 1.2157 + "amplitude %g, sharpness %g, anisotropy %g, alpha %g and sigma %g.", 1.2158 + gmic_inds,amplitude,sharpness,anisotropy,alpha,sigma); 1.2159 + cimg_foroff(indices,l) 1.2160 + gmic_apply(images[indices[l]],blur_anisotropic(amplitude,sharpness,anisotropy,alpha,sigma, 1.2161 + dl,da,gauss_prec,interpolation_type,fast_approx?true:false)); 1.2162 + } else error("Smooth image%s anisotropically : Invalid argument '%s' " 1.2163 + "(should be 'amplitude[,sharpness[,anisotropy[,alpha[,sigma[,dl[,da[,prec[,interp[,fast]]]]]]]]]').", 1.2164 + gmic_inds,argument_text); 1.2165 + ++position; continue; 1.2166 + } 1.2167 + 1.2168 + // Patch averaging. 1.2169 + if (!cimg::strcmp("-denoise",item0)) { 1.2170 + float sigmas = 10, sigmar = 10; int psize = 5, rsize = 6; char end = 0; 1.2171 + if (std::sscanf(argument,"%f%c",&sigmas,&end)==1 || 1.2172 + std::sscanf(argument,"%f%*c%f%c",&sigmas,&sigmar,&end)==2 || 1.2173 + std::sscanf(argument,"%f%*c%f%*c%d%c",&sigmas,&sigmar,&psize,&end)==3 || 1.2174 + std::sscanf(argument,"%f%*c%f%*c%d%*c%d%c",&sigmas,&sigmar,&psize,&rsize,&end)==4) { 1.2175 + if (sigmas<0 || sigmar<0 || psize<0 || rsize<0) 1.2176 + error("Denoise image%s with %dx%d patches, standard deviations %lg,%g and lookup size %d : " 1.2177 + "Invalid parameters.",gmic_inds,psize,psize,sigmas,sigmar,rsize); 1.2178 + print("Denoise image%s with %dx%d patches, standard deviations %lg,%g and lookup size %d.", 1.2179 + gmic_inds,psize,psize,sigmas,sigmar,rsize); 1.2180 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],blur_patch(psize,sigmas,sigmar,rsize)); 1.2181 + } else error("Denoise image%s : Invalid argument '%s' " 1.2182 + "(should be 'stdev_s[,stdev_p[,patch_size[,lookup_size]]]').", 1.2183 + gmic_inds,argument_text); 1.2184 + ++position; continue; 1.2185 + } 1.2186 + 1.2187 + // Median filter. 1.2188 + if (!cimg::strcmp("-median",item0)) { 1.2189 + int siz = 3; char end = 0; 1.2190 + if (std::sscanf(argument,"%d%c",&siz,&end)==1) { 1.2191 + if (siz<=0) error("Apply median filter on image%s : Invalid size %d.",gmic_inds,siz); 1.2192 + print("Apply median filter of size %d on image%s.",siz,gmic_inds); 1.2193 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],blur_median(siz)); 1.2194 + } else error("Apply median filter on image%s : Invalid argument '%s' " 1.2195 + "(should be 'size').",gmic_inds,argument_text); 1.2196 + ++position; continue; 1.2197 + } 1.2198 + 1.2199 + // Sharpen. 1.2200 + if (!cimg::strcmp("-sharpen",item0)) { 1.2201 + float amplitude = 0, edge = 1, alpha = 0, sigma = 0; int sharpen_type = 0; char end = 0; 1.2202 + if (std::sscanf(argument,"%f%c",&litude,&end)==1 || 1.2203 + std::sscanf(argument,"%f%*c%d%c",&litude,&sharpen_type,&end)==2 || 1.2204 + std::sscanf(argument,"%f%*c%d%*c%f%c",&litude,&sharpen_type,&edge,&end)==3 || 1.2205 + std::sscanf(argument,"%f%*c%d%*c%f%*c%f%c",&litude,&sharpen_type,&edge,&alpha,&end)==4 || 1.2206 + std::sscanf(argument,"%f%*c%d%*c%f%*c%f%*c%f%c",&litude,&sharpen_type,&edge,&alpha,&sigma,&end)==5) { 1.2207 + if (sharpen_type) 1.2208 + print("Sharpen image%s with shock filters and amplitude %g, edge %g, alpha %g and sigma %g.", 1.2209 + gmic_inds,amplitude,edge,alpha,sigma); 1.2210 + else 1.2211 + print("Sharpen image%s with inverse diffusion and amplitude %g.",gmic_inds,amplitude); 1.2212 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],sharpen(amplitude,sharpen_type?true:false,edge,alpha,sigma)); 1.2213 + } else error("Sharpen image%s : Invalid argument '%s' " 1.2214 + "(should be 'amplitude[,sharpen_type[,edge[,alpha[,sigma]]]]', " 1.2215 + "where 'sharpen_type' can be '{0=inverse diffusion, 1=shock filters}').", 1.2216 + gmic_inds,argument_text); 1.2217 + ++position; continue; 1.2218 + } 1.2219 + 1.2220 + // Convolve. 1.2221 + if (!cimg::strcmp("-convolve",item0)) { 1.2222 + int ind0 = no_ind, borders = 1; char sep = 0, end = 0; 1.2223 + if ((std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==2 && sep==']') || 1.2224 + std::sscanf(argument,"[%d]%*c%d%c",&ind0,&borders,&end)==2) { 1.2225 + gmic_check_indice(ind0,"Convolve image%s"); 1.2226 + print("Convolve image%s with mask [%d].",gmic_inds,ind0); 1.2227 + const CImg<T> mask = images[ind0]; 1.2228 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],convolve(mask,borders)); 1.2229 + } else error("Convolve image%s : Invalid argument '%s' " 1.2230 + "(should be '[indice][,border_conditions]').",gmic_inds,argument_text); 1.2231 + ++position; continue; 1.2232 + } 1.2233 + 1.2234 + // Correlate. 1.2235 + if (!cimg::strcmp("-correlate",item0)) { 1.2236 + int ind0 = no_ind, borders = 1; char sep = 0, end = 0; 1.2237 + if ((std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==2 && sep==']') || 1.2238 + std::sscanf(argument,"[%d]%*c%d%c",&ind0,&borders,&end)==2) { 1.2239 + gmic_check_indice(ind0,"Correlate image%s"); 1.2240 + print("Correlate image%s with mask [%d].",gmic_inds,ind0); 1.2241 + const CImg<T> mask = images[ind0]; 1.2242 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],correlate(mask,borders)); 1.2243 + } else error("Correlate image%s : Invalid argument '%s' " 1.2244 + "(should be '[indice][,border_conditions]').",gmic_inds,argument_text); 1.2245 + ++position; continue; 1.2246 + } 1.2247 + 1.2248 + // Erode. 1.2249 + if (!cimg::strcmp("-erode",item0)) { 1.2250 + int siz = 3, ind0 = no_ind, borders = 1; char sep = 0, end = 0; 1.2251 + if ((std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==2 && sep==']') || 1.2252 + std::sscanf(argument,"[%d]%*c%d%c",&ind0,&borders,&end)==2) { 1.2253 + gmic_check_indice(ind0,"Erode image%s"); 1.2254 + print("Erode image%s with mask [%d].",gmic_inds,ind0); 1.2255 + const CImg<T> mask = images[ind0]; 1.2256 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],erode(mask,borders)); 1.2257 + } else if (std::sscanf(argument,"%d%c",&siz,&end)==1 || 1.2258 + std::sscanf(argument,"%d%*c%d%c",&siz,&borders,&end)==2) { 1.2259 + if (siz<=0) error("Erode image%s : Invalid size %d.",gmic_inds,siz); 1.2260 + print("Erode image%s with size %d.",gmic_inds,siz); 1.2261 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],erode(siz,borders)); 1.2262 + } else error("Erode image%s : Invalid argument '%s' " 1.2263 + "(should be '[indice]' or 'size').",gmic_inds,argument_text); 1.2264 + ++position; continue; 1.2265 + } 1.2266 + 1.2267 + // Dilate. 1.2268 + if (!cimg::strcmp("-dilate",item0)) { 1.2269 + int siz = 3, ind0 = no_ind, borders = 1; char sep = 0, end = 0; 1.2270 + if ((std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==2 && sep==']') || 1.2271 + std::sscanf(argument,"[%d]%*c%d%c",&ind0,&borders,&end)==2) { 1.2272 + gmic_check_indice(ind0,"Dilate image%s"); 1.2273 + print("Dilate image%s with mask [%d].",gmic_inds,ind0); 1.2274 + const CImg<T> mask = images[ind0]; 1.2275 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],dilate(mask,borders)); 1.2276 + } else if (std::sscanf(argument,"%d%c",&siz,&end)==1 || 1.2277 + std::sscanf(argument,"%d%*c%d%c",&siz,&borders,&end)==2) { 1.2278 + if (siz<=0) error("Dilate image%s : Invalid size %d.",gmic_inds,siz); 1.2279 + print("Dilate image%s with size %d.",gmic_inds,siz); 1.2280 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],dilate(siz,borders)); 1.2281 + } else error("Dilate image%s : Invalid argument '%s' " 1.2282 + "(should be '[indice]' or 'size').",gmic_inds,argument_text); 1.2283 + ++position; continue; 1.2284 + } 1.2285 + 1.2286 + // Compute gradient. 1.2287 + if (!cimg::strcmp("-gradient",item0)) { 1.2288 + char axes[4096] = { 0 }, *naxes = 0, end = 0; int scheme = 3; 1.2289 + print("Compute gradient of image%s.",gmic_inds); 1.2290 + if (std::sscanf(argument,"%4095[xyz]%c",axes,&end)==1 || 1.2291 + std::sscanf(argument,"%4095[xyz]%*c%d%c",axes,&scheme,&end)==2) { naxes = axes; ++position; } 1.2292 + unsigned int off = 0; 1.2293 + cimg_foroff(indices,l) { 1.2294 + const unsigned int ind = indices[l] + off; 1.2295 + CImg<T>& img = images[ind]; 1.2296 + const CImg<char> filename = filenames[ind]; 1.2297 + const CImgList<T> gradient = img.get_gradient(naxes,scheme); 1.2298 + if (get_version) { 1.2299 + images.insert(gradient); 1.2300 + filenames.insert(gradient.size,filename); 1.2301 + } else { 1.2302 + images.remove(ind); images.insert(gradient,ind); 1.2303 + filenames.remove(ind); filenames.insert(gradient.size,filename,ind); 1.2304 + off+=gradient.size-1; 1.2305 + } 1.2306 + } 1.2307 + continue; 1.2308 + } 1.2309 + 1.2310 + // Compute Hessian. 1.2311 + if (!cimg::strcmp("-hessian",item0)) { 1.2312 + char axes[4096] = { 0 }, *naxes = 0, end = 0; 1.2313 + print("Compute Hessian of image%s.",gmic_inds); 1.2314 + if (std::sscanf(argument,"%4095[xyz]%c",axes,&end)==1) { naxes = axes; ++position; } 1.2315 + unsigned int off = 0; 1.2316 + cimg_foroff(indices,l) { 1.2317 + const unsigned int ind = indices[l] + off; 1.2318 + CImg<T>& img = images[ind]; 1.2319 + const CImg<char> filename = filenames[ind]; 1.2320 + const CImgList<T> hessian = img.get_hessian(naxes); 1.2321 + if (get_version) { 1.2322 + images.insert(hessian); 1.2323 + filenames.insert(hessian.size,filename); 1.2324 + } else { 1.2325 + images.remove(ind); images.insert(hessian,ind); 1.2326 + filenames.remove(ind); filenames.insert(hessian.size,filename,ind); 1.2327 + off+=hessian.size-1; 1.2328 + } 1.2329 + } 1.2330 + continue; 1.2331 + } 1.2332 + 1.2333 + // Compute direct or inverse FFT. 1.2334 + const bool inv_fft = !cimg::strcmp("-ifft",item0); 1.2335 + if (!cimg::strcmp("-fft",item0) || inv_fft) { 1.2336 + print("Compute %sFourier Transform of complex data",inv_fft?"inverse ":""); 1.2337 + cimg_foroff(indices,l) { 1.2338 + const unsigned int ind0 = indices[l], ind1 = l+1<_maxl?indices[l+1]:~0U; 1.2339 + if (ind1!=~0U) { 1.2340 + if (verbosity_level>=0) std::fprintf(cimg_stdout," ([%u],[%u])%c",ind0,ind1,l==_maxl-1?'.':','); 1.2341 + CImgList<T> fft(images[ind0],images[ind1],!get_version); 1.2342 + fft.FFT(inv_fft); 1.2343 + if (get_version) { 1.2344 + images.insert(2); 1.2345 + fft[0].transfer_to(images[images.size-2]); 1.2346 + fft[1].transfer_to(images[images.size-1]); 1.2347 + filenames.insert(filenames[ind0]); 1.2348 + filenames.insert(filenames[ind1]); 1.2349 + } else { 1.2350 + fft[0].transfer_to(images[ind0]); 1.2351 + fft[1].transfer_to(images[ind1]); 1.2352 + } 1.2353 + ++l; 1.2354 + } else { 1.2355 + if (verbosity_level>=0) std::fprintf(cimg_stdout," ([%u],0)",ind0); 1.2356 + CImgList<T> fft(images[ind0],!get_version); 1.2357 + fft.insert(fft[0],~0U,false); 1.2358 + fft[1].fill(0); 1.2359 + fft.FFT(inv_fft); 1.2360 + if (get_version) { 1.2361 + images.insert(2); 1.2362 + fft[0].transfer_to(images[images.size-2]); 1.2363 + fft[1].transfer_to(images[images.size-1]); 1.2364 + filenames.insert(2,filenames[ind0]); 1.2365 + } else { 1.2366 + fft[0].transfer_to(images[ind0]); 1.2367 + images.insert(fft[1],1+ind0); 1.2368 + filenames.insert(filenames[ind0],1+ind0); 1.2369 + } 1.2370 + } 1.2371 + } 1.2372 + continue; 1.2373 + } 1.2374 + 1.2375 + //----------------------------- 1.2376 + // Image creation and drawing 1.2377 + //----------------------------- 1.2378 + 1.2379 + // Dimensions. 1.2380 + if (!cimg::strcmp("-dimensions",item0)) { 1.2381 + print("Get dimensions of image%s.",gmic_inds); 1.2382 + cimg_foroff(indices,l) { 1.2383 + CImg<T>& img = images[indices[l]]; 1.2384 + CImg<int> dims = CImg<int>::vector(img.dimx(),img.dimy(),img.dimz(),img.dimv()); 1.2385 + gmic_apply(img,replace(dims)); 1.2386 + } 1.2387 + continue; 1.2388 + } 1.2389 + 1.2390 + // Stats. 1.2391 + if (!cimg::strcmp("-stats",item0)) { 1.2392 + print("Get statistics of image%s.",gmic_inds); 1.2393 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],stats()); 1.2394 + continue; 1.2395 + } 1.2396 + 1.2397 + // Histogram. 1.2398 + if (!cimg::strcmp("-histogram",item0)) { 1.2399 + int nb_levels = 256; char sep = 0, end = 0; 1.2400 + if (std::sscanf(argument,"%d%c",&nb_levels,&end)==1 || 1.2401 + (std::sscanf(argument,"%d%c%c",&nb_levels,&sep,&end)==2 && sep=='%')) { 1.2402 + print("Compute histogram of image%s using %d%s levels.",gmic_inds,nb_levels,sep=='%'?"%":""); 1.2403 + cimg_foroff(indices,l) { 1.2404 + CImg<T> &img = images[indices[l]]; 1.2405 + int nnb_levels = nb_levels; 1.2406 + if (sep=='%') { double m, M = img.maxmin(m); nnb_levels = (int)cimg::round(nb_levels*(1+M-m)/100,1); } 1.2407 + gmic_apply(images[indices[l]],histogram(nnb_levels)); 1.2408 + } 1.2409 + } else error("Compute histogram of image%s : Invalid argument '%s' " 1.2410 + "(should be 'nb_levels[%%]').",gmic_inds,argument_text); 1.2411 + ++position; continue; 1.2412 + } 1.2413 + 1.2414 + // Distance function. 1.2415 + if (!cimg::strcmp("-distance",item0)) { 1.2416 + double value = 0; char sep = 0, end = 0; 1.2417 + if (std::sscanf(argument,"%lf%c",&value,&end)==1 || 1.2418 + (std::sscanf(argument,"%lf%c%c",&value,&sep,&end)==2 && sep=='%')) { 1.2419 + print("Compute distance map of image%s to isovalue %g%s.",gmic_inds,value,sep=='%'?"%":""); 1.2420 + cimg_foroff(indices,l) { 1.2421 + CImg<T> &img = images[indices[l]]; 1.2422 + double isovalue = value; 1.2423 + if (sep=='%') { double m, M = img.maxmin(m); isovalue = m + value*(M - m)/100; } 1.2424 + gmic_apply(img,distance((T)isovalue)); 1.2425 + } 1.2426 + } else error("Compute distance function of image%s : Invalid argument '%s' " 1.2427 + "(should be 'value[%%]').",gmic_inds,argument_text); 1.2428 + ++position; continue; 1.2429 + } 1.2430 + 1.2431 + // Apply Hamilton-Jacobi PDE to compute distance to 0. 1.2432 + if (!cimg::strcmp("-hamilton",item0)) { 1.2433 + int nb_iter = 0; float band_size = 0; char end = 0; 1.2434 + if (std::sscanf(argument,"%d%c",&nb_iter,&end)==1 || 1.2435 + std::sscanf(argument,"%d%*c%f%c",&nb_iter,&band_size,&end)==2) { 1.2436 + print("Apply %d iterations of Hamilton-Jacobi PDE on image%s.",nb_iter,gmic_inds); 1.2437 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],distance_hamilton((unsigned int)nb_iter,band_size)); 1.2438 + } else error("Apply %d iterations of Hamilton-Jacobi PDE on image%s : Invalid argument '%s' " 1.2439 + "(should be 'nb_iter[,band_size]', with band_size>0).",nb_iter,gmic_inds,argument_text); 1.2440 + ++position; continue; 1.2441 + } 1.2442 + 1.2443 + // Label regions. 1.2444 + gmic_simple_item("-label",label_regions,"Label regions on image%s."); 1.2445 + 1.2446 + // Displacement field. 1.2447 + if (!cimg::strcmp("-displacement",item0)) { 1.2448 + float smooth = 0.1f, precision = 0.1f; int ind0 = no_ind, nbscales = 0, itermax = 1000; char sep = 0, end = 0; 1.2449 + if ((std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==2 && sep==']') || 1.2450 + std::sscanf(argument,"[%d]%*c%f%c",&ind0,&smooth,&end)==2 || 1.2451 + std::sscanf(argument,"[%d]%*c%f%*c%f%c",&ind0,&smooth,&precision,&end)==3 || 1.2452 + std::sscanf(argument,"[%d]%*c%f%*c%f%*c%d%c",&ind0,&smooth,&precision,&nbscales,&end)==4 || 1.2453 + std::sscanf(argument,"[%d]%*c%f%*c%f%*c%d%*c%d%c",&ind0,&smooth,&precision,&nbscales,&itermax,&end)==5) { 1.2454 + gmic_check_indice(ind0,"Compute displacement field of image%s"); 1.2455 + print("Compute displacement field of image%s with target [%u] and smoothness %g.", 1.2456 + gmic_inds,ind0,smooth); 1.2457 + const CImg<T> target = images[ind0]; 1.2458 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],displacement_field(target,smooth,precision,nbscales,itermax)); 1.2459 + } else error("Compute displacement field of image%s : Invalid argument '%s' " 1.2460 + "(should be '[indice][,smoothness[,precision[,nbscales[,itermax]]]]').",gmic_inds,argument_text); 1.2461 + ++position; continue; 1.2462 + } 1.2463 + 1.2464 + // Sort. 1.2465 + gmic_simple_item("-sort",sort,"Sort values in image%s."); 1.2466 + 1.2467 + // PSNR. 1.2468 + if (!cimg::strcmp("-psnr",item0)) { 1.2469 + double valmax = 255; char end = 0; 1.2470 + if (std::sscanf(argument,"%lf%c",&valmax,&end)==1) ++position; 1.2471 + if (images.size) { 1.2472 + const unsigned int siz = indices.size(); 1.2473 + print("Compute a %ux%u matrix [%u] of PSNR values (max. pixel value is %g).",siz,siz,images.size,valmax); 1.2474 + CImg<T> res(siz,siz,1,1,(T)-1); 1.2475 + cimg_forXY(res,x,y) if (x>y) res(x,y) = res(y,x) = (T)images[indices[x]].PSNR(images[indices[y]],(float)valmax); 1.2476 + images.insert(res); 1.2477 + filenames.insert(CImg<char>("PSNR",5,1,1,1,false)); 1.2478 + } else error("Compute PSNR : image list is empty."); 1.2479 + continue; 1.2480 + } 1.2481 + 1.2482 + // Draw point. 1.2483 + if (!cimg::strcmp("-point",item0)) { 1.2484 + char arg0[4096] = { 0 }, arg1[4096] = { 0 }, arg2[4096] = { 0 }, color[4096] = { 0 }; 1.2485 + char sepx0 = 0, sepy0 = 0, sepz0 = 0, end = 0; 1.2486 + float x0 = 0, y0 = 0, z0 = 0, opacity = 1; 1.2487 + if (std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%f%*c%4095[0-9.eE,+-]", 1.2488 + arg0,arg1,arg2,&opacity,color)>=2 && 1.2489 + ((std::sscanf(arg0,"%f%c%c",&x0,&sepx0,&end)==2 && sepx0=='%') || 1.2490 + std::sscanf(arg0,"%f%c",&x0,&end)==1) && 1.2491 + ((std::sscanf(arg1,"%f%c%c",&y0,&sepy0,&end)==2 && sepy0=='%') || 1.2492 + std::sscanf(arg1,"%f%c",&y0,&end)==1) && 1.2493 + ((std::sscanf(arg2,"%f%c%c",&z0,&sepz0,&end)==2 && sepz0=='%') || 1.2494 + std::sscanf(arg2,"%f%c",&z0,&end)==1 || !arg2[0])) { 1.2495 + print("Draw point (%g%s,%g%s,%g%s) with color '%s' and opacity %g on image%s.", 1.2496 + x0,sepx0=='%'?"%":"",y0,sepy0=='%'?"%":"",z0,sepz0=='%'?"%":"", 1.2497 + color[0]?color:"default",opacity,gmic_inds); 1.2498 + cimg_foroff(indices,l) { 1.2499 + CImg<T> &img = images[indices[l]]; 1.2500 + CImg<T> col(img.dimv(),1,1,1,0); 1.2501 + col.fill(color,true); 1.2502 + const int 1.2503 + nx0 = (int)cimg::round(sepx0=='%'?x0*(img.dimx()-1)/100:x0,1), 1.2504 + ny0 = (int)cimg::round(sepy0=='%'?y0*(img.dimy()-1)/100:y0,1), 1.2505 + nz0 = (int)cimg::round(sepz0=='%'?z0*(img.dimz()-1)/100:z0,1); 1.2506 + gmic_apply(img,draw_point(nx0,ny0,nz0,col,opacity)); 1.2507 + } 1.2508 + } else error("Draw point on image%s : Invalid argument '%s' " 1.2509 + "(should be 'x[%%],y[%%][,z[%%][,opacity[,color]]])",gmic_inds,argument_text); 1.2510 + ++position; continue; 1.2511 + } 1.2512 + 1.2513 + // Draw line. 1.2514 + if (!cimg::strcmp("-line",item0)) { 1.2515 + char arg0[4096] = { 0 }, arg1[4096] = { 0 }, arg2[4096] = { 0 }, arg3[4096] = { 0 }, color[4096] = { 0 }; 1.2516 + char sepx0 = 0, sepy0 = 0, sepx1 = 0, sepy1 = 0, end = 0; 1.2517 + float x0 = 0, y0 = 0, x1 = 0, y1 = 0, opacity = 1; 1.2518 + if (std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]" 1.2519 + "%*c%f%*c%4095[0-9.eE,+-]", 1.2520 + arg0,arg1,arg2,arg3,&opacity,color)>=4 && 1.2521 + ((std::sscanf(arg0,"%f%c%c",&x0,&sepx0,&end)==2 && sepx0=='%') || 1.2522 + std::sscanf(arg0,"%f%c",&x0,&end)==1) && 1.2523 + ((std::sscanf(arg1,"%f%c%c",&y0,&sepy0,&end)==2 && sepy0=='%') || 1.2524 + std::sscanf(arg1,"%f%c",&y0,&end)==1) && 1.2525 + ((std::sscanf(arg2,"%f%c%c",&x1,&sepx1,&end)==2 && sepx1=='%') || 1.2526 + std::sscanf(arg2,"%f%c",&x1,&end)==1) && 1.2527 + ((std::sscanf(arg3,"%f%c%c",&y1,&sepy1,&end)==2 && sepy1=='%') || 1.2528 + std::sscanf(arg3,"%f%c",&y1,&end)==1)) { 1.2529 + print("Draw line (%g%s,%g%s) - (%g%s,%g%s) with color '%s' and opacity %g on image%s.", 1.2530 + x0,sepx0=='%'?"%":"",y0,sepy0=='%'?"%":"",x1,sepx1=='%'?"%":"",y1,sepy1=='%'?"%":"", 1.2531 + color[0]?color:"default",opacity,gmic_inds); 1.2532 + cimg_foroff(indices,l) { 1.2533 + CImg<T> &img = images[indices[l]]; 1.2534 + CImg<T> col(img.dimv(),1,1,1,0); 1.2535 + col.fill(color,true); 1.2536 + const int 1.2537 + nx0 = (int)cimg::round(sepx0=='%'?x0*(img.dimx()-1)/100:x0,1), 1.2538 + ny0 = (int)cimg::round(sepy0=='%'?y0*(img.dimy()-1)/100:y0,1), 1.2539 + nx1 = (int)cimg::round(sepx1=='%'?x1*(img.dimx()-1)/100:x1,1), 1.2540 + ny1 = (int)cimg::round(sepy1=='%'?y1*(img.dimy()-1)/100:y1,1); 1.2541 + gmic_apply(img,draw_line(nx0,ny0,nx1,ny1,col,opacity)); 1.2542 + } 1.2543 + } else error("Draw line on image%s : Invalid argument '%s' " 1.2544 + "(should be 'x0[%%],y0[%%],x1[%%],y1[%%][,opacity[,color]]')",gmic_inds,argument_text); 1.2545 + ++position; continue; 1.2546 + } 1.2547 + 1.2548 + // Draw polygon. 1.2549 + if (!cimg::strcmp("-polygon",item0)) { 1.2550 + char arg0[4096] = { 0 }, arg1[4096] = { 0 }, tmp[4096] = { 0 }, sepx0 = 0, sepy0 = 0, end = 0; 1.2551 + int N = 0; float x0 = 0, y0 = 0, opacity = 1; 1.2552 + if (std::sscanf(argument,"%d%c",&N,&end)==2 && N>2) { 1.2553 + const char 1.2554 + *nargument = argument + std::sprintf(tmp,"%d",N) + 1, 1.2555 + *const eargument = argument + cimg::strlen(argument); 1.2556 + CImg<float> coords0(N,2,1,1,0); 1.2557 + CImg<bool> percents(N,2,1,1,0); 1.2558 + for (int n = 0; n<N; ++n) if (nargument<eargument) { 1.2559 + if (std::sscanf(nargument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]",arg0,arg1)==2 && 1.2560 + ((std::sscanf(arg0,"%f%c%c",&x0,&(sepx0=0),&end)==2 && sepx0=='%') || 1.2561 + std::sscanf(arg0,"%f%c",&x0,&end)==1) && 1.2562 + ((std::sscanf(arg1,"%f%c%c",&y0,&(sepy0=0),&end)==2 && sepy0=='%') || 1.2563 + std::sscanf(arg1,"%f%c",&y0,&end)==1)) { 1.2564 + coords0(n,0) = x0; percents(n,0) = (sepx0=='%'); 1.2565 + coords0(n,1) = y0; percents(n,1) = (sepy0=='%'); 1.2566 + nargument+=cimg::strlen(arg0) + cimg::strlen(arg1) + 2; 1.2567 + } else error("Draw polygon on image%s : Invalid or incomplete argument '%s' " 1.2568 + "(should be 'N,x0[%%],y0[%%],x1[%%],y1[%%],..,xN[%%],yN[%%][,opacity[,color]]' with N>=3)", 1.2569 + gmic_inds,argument_text); 1.2570 + } else error("Draw polygon on image%s : Incomplete argument '%s' " 1.2571 + "(%d xy-coordinates should be defined)", 1.2572 + gmic_inds,argument_text,N); 1.2573 + if (nargument<eargument && std::sscanf(nargument,"%4095[0-9.eE+-]",arg0)==1 && 1.2574 + std::sscanf(arg0,"%f",&opacity)==1) nargument+=cimg::strlen(arg0)+1; 1.2575 + const char *const color = nargument<eargument?nargument:&(end=0); 1.2576 + print("Draw %d-vertices polygon with color '%s' and opacity %g on image%s.", 1.2577 + N,color[0]?color:"default",opacity,gmic_inds); 1.2578 + cimg_foroff(indices,l) { 1.2579 + CImg<T> &img = images[indices[l]]; 1.2580 + CImg<int> coords(coords0); 1.2581 + cimg_forX(coords,p) { 1.2582 + if (percents(p,0)) coords(p,0) = (int)cimg::round(coords0(p,0)*(img.dimx()-1)/100,1); 1.2583 + if (percents(p,1)) coords(p,1) = (int)cimg::round(coords0(p,1)*(img.dimy()-1)/100,1); 1.2584 + } 1.2585 + CImg<T> col(img.dimv(),1,1,1,0); 1.2586 + col.fill(color,true); 1.2587 + gmic_apply(img,draw_polygon(coords,col,opacity)); 1.2588 + } 1.2589 + } else error("Draw polygon on image%s : Invalid argument '%s' " 1.2590 + "(should be 'N,x0[%%],y0[%%],x1[%%],y1[%%],..,xN[%%],yN[%%][,opacity[,color]]' with N>=3)", 1.2591 + gmic_inds,argument_text); 1.2592 + ++position; continue; 1.2593 + } 1.2594 + 1.2595 + // Draw ellipse. 1.2596 + if (!cimg::strcmp("-ellipse",item0)) { 1.2597 + char arg0[4096] = { 0 }, arg1[4096] = { 0 }, color[4096] = { 0 }; 1.2598 + char sepx0 = 0, sepy0 = 0, end = 0; 1.2599 + float x0 = 0, y0 = 0, r0 = 0, r1 = 0, ru = 1, rv = 0, opacity = 1; 1.2600 + if (std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%f%*c%f%*c%f%*c%f%*c%f%*c%4095[0-9.eE,+-]", 1.2601 + arg0,arg1,&r0,&r1,&ru,&rv,&opacity,color)>=4 && 1.2602 + ((std::sscanf(arg0,"%f%c%c",&x0,&sepx0,&end)==2 && sepx0=='%') || 1.2603 + std::sscanf(arg0,"%f%c",&x0,&end)==1) && 1.2604 + ((std::sscanf(arg1,"%f%c%c",&y0,&sepy0,&end)==2 && sepy0=='%') || 1.2605 + std::sscanf(arg1,"%f%c",&y0,&end)==1)) { 1.2606 + print("Draw ellipse centered at (%g%s,%g%s) with radii (%g,%g), orientation (%g,%g), color '%s' " 1.2607 + "and opacity %g on image%s.", 1.2608 + x0,sepx0=='%'?"%":"",y0,sepy0=='%'?"%":"", 1.2609 + r0,r1,ru,rv,color[0]?color:"default",opacity,gmic_inds); 1.2610 + cimg_foroff(indices,l) { 1.2611 + CImg<T> &img = images[indices[l]]; 1.2612 + CImg<T> col(img.dimv(),1,1,1,0); 1.2613 + col.fill(color,true); 1.2614 + const int 1.2615 + nx0 = (int)cimg::round(sepx0=='%'?x0*(img.dimx()-1)/100:x0,1), 1.2616 + ny0 = (int)cimg::round(sepy0=='%'?y0*(img.dimy()-1)/100:y0,1); 1.2617 + gmic_apply(img,draw_ellipse(nx0,ny0,r0,r1,ru,rv,col,opacity)); 1.2618 + } 1.2619 + } else error("Draw ellipse on image%s : Invalid argument '%s' " 1.2620 + "(should be 'x[%%],y[%%],r,R[,u,v[,opacity[,color]]])", 1.2621 + gmic_inds,argument_text); 1.2622 + ++position; continue; 1.2623 + } 1.2624 + 1.2625 + // Draw text. 1.2626 + if (!cimg::strcmp("-text",item0)) { 1.2627 + char arg0[4096] = { 0 }, arg1[4096] = { 0 }, color[4096] = { 0 }, text[4096] = { 0 }; 1.2628 + char sepx0 = 0, sepy0 = 0, end = 0; 1.2629 + float x0 = 0, y0 = 0, opacity = 1; int siz = 11; 1.2630 + if (std::sscanf(argument,"%4095[^,],%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%d%*c%f%*c%4095[0-9.eE,+-]", 1.2631 + text,arg0,arg1,&siz,&opacity,color)>=1 && 1.2632 + ((std::sscanf(arg0,"%f%c%c",&x0,&sepx0,&end)==2 && sepx0=='%') || 1.2633 + std::sscanf(arg0,"%f%c",&x0,&end)==1 || !arg0[0]) && 1.2634 + ((std::sscanf(arg1,"%f%c%c",&y0,&sepy0,&end)==2 && sepy0=='%') || 1.2635 + std::sscanf(arg1,"%f%c",&y0,&end)==1 || !arg1[0])) { 1.2636 + cimg::strclean(text); cimg::strescape(text); 1.2637 + print("Draw text \"%s\" at position (%g%s,%g%s) with font size %d, color '%s' " 1.2638 + "and opacity %f on image%s.", 1.2639 + text,x0,sepx0=='%'?"%":"",y0,sepy0=='%'?"%":"",siz,color[0]?color:"default",opacity,gmic_inds); 1.2640 + cimg_foroff(indices,l) { 1.2641 + CImg<T> &img = images[indices[l]]; 1.2642 + CImg<T> col(img.dimv(),1,1,1,0); 1.2643 + col.fill(color,true); 1.2644 + const int 1.2645 + nx0 = (int)cimg::round(sepx0=='%'?x0*(img.dimx()-1)/100:x0,1), 1.2646 + ny0 = (int)cimg::round(sepy0=='%'?y0*(img.dimy()-1)/100:y0,1); 1.2647 + gmic_apply(img,draw_text(nx0,ny0,text,col.ptr(),0,opacity,siz)); 1.2648 + } 1.2649 + } else error("Draw text on image%s : Invalid argument '%s' " 1.2650 + "(should be 'text[,x[%%],y[%%][,size[,opacity[,color]]]]').", 1.2651 + gmic_inds,argument_text); 1.2652 + ++position; continue; 1.2653 + } 1.2654 + 1.2655 + // Draw image. 1.2656 + if (!cimg::strcmp("-image",item0)) { 1.2657 + char arg0[4096] = { 0 }, arg1[4096] = { 0 }, arg2[4096] = { 0 }, sep = 0, sepx = 0, sepy = 0, sepz = 0, end = 0; 1.2658 + int ind0 = no_ind, indm0 = no_ind; float x = 0, y = 0, z = 0, opacity = 1; 1.2659 + if (((std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==1 && sep==']') || 1.2660 + std::sscanf(argument,"[%d]%*c%4095[0-9.eE%+-]%c",&ind0,arg0,&end)==2 || 1.2661 + std::sscanf(argument,"[%d]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c",&ind0,arg0,arg1,&end)==3 || 1.2662 + std::sscanf(argument,"[%d]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c",&ind0,arg0,arg1,arg2,&end)==4 || 1.2663 + std::sscanf(argument,"[%d]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%f%c",&ind0,arg0,arg1,arg2,&opacity,&end)==5 || 1.2664 + std::sscanf(argument,"[%d]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%f%*c[%d%c%c", 1.2665 + &ind0,arg0,arg1,arg2,&opacity,&indm0,&sep,&end)==7) && 1.2666 + (!*arg0 || 1.2667 + std::sscanf(arg0,"%f%c",&x,&end)==1 || 1.2668 + (std::sscanf(arg0,"%f%c%c",&x,&sepx,&end)==2 && sepx=='%')) && 1.2669 + (!*arg1 || 1.2670 + std::sscanf(arg1,"%f%c",&y,&end)==1 || 1.2671 + (std::sscanf(arg1,"%f%c%c",&y,&sepy,&end)==2 && sepy=='%')) && 1.2672 + (!*arg2 || 1.2673 + std::sscanf(arg2,"%f%c",&z,&end)==1 || 1.2674 + (std::sscanf(arg2,"%f%c%c",&z,&sepz,&end)==2 && sepz=='%'))) { 1.2675 + gmic_check_indice(ind0,"Draw image on image%s"); 1.2676 + const CImg<T> sprite = images[ind0]; 1.2677 + CImg<T> mask; 1.2678 + if (indm0!=no_ind) { 1.2679 + gmic_check_indice(indm0,"Draw image on image%s"); 1.2680 + mask = images[indm0]; 1.2681 + print("Draw image [%d] at (%g%s,%g%s,%g%s), with mask [%d] and opacity %f on image%s.", 1.2682 + ind0,x,sepx=='%'?"%":"",y,sepy=='%'?"%":"",z,sepz=='%'?"%":"",indm0,opacity,gmic_inds); 1.2683 + } else print("Draw image [%d] at (%g%s,%g%s,%g%s) with opacity %f on image%s.", 1.2684 + ind0,x,sepx=='%'?"%":"",y,sepy=='%'?"%":"",z,sepz=='%'?"%":"",opacity,gmic_inds); 1.2685 + cimg_foroff(indices,l) { 1.2686 + CImg<T> &img = images[indices[l]]; 1.2687 + const int 1.2688 + nx = (int)cimg::round(sepx=='%'?x*(img.dimx()-1)/100:x,1), 1.2689 + ny = (int)cimg::round(sepy=='%'?y*(img.dimy()-1)/100:y,1), 1.2690 + nz = (int)cimg::round(sepz=='%'?z*(img.dimz()-1)/100:z,1); 1.2691 + if (indm0!=no_ind) { gmic_apply(img,draw_image(nx,ny,nz,sprite,mask,opacity)); } 1.2692 + else { gmic_apply(img,draw_image(nx,ny,nz,sprite,opacity)); } 1.2693 + } 1.2694 + } else error("Draw image on image%s : Invalid argument '%s' " 1.2695 + "(should be '[indice][,x[%%][,y[%%][,z[%%][,opacity[,indice_mask]]]]]').", 1.2696 + gmic_inds,argument_text); 1.2697 + ++position; continue; 1.2698 + } 1.2699 + 1.2700 + // Draw 3D object. 1.2701 + if (!cimg::strcmp("-object3d",item0)) { 1.2702 + char arg0[4096] = { 0 }, arg1[4096] = { 0 }, sep = 0, sepx = 0, sepy = 0, end = 0; 1.2703 + float x = 0, y = 0, z = 0, opacity = 1; 1.2704 + int ind0 = no_ind; 1.2705 + if (((std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==2 && sep==']') || 1.2706 + std::sscanf(argument,"[%d]%*c%4095[0-9.eE%+-]%c",&ind0,arg0,&end)==2 || 1.2707 + std::sscanf(argument,"[%d]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c",&ind0,arg0,arg1,&end)==3 || 1.2708 + std::sscanf(argument,"[%d]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%f%c",&ind0,arg0,arg1,&z,&end)==4 || 1.2709 + std::sscanf(argument,"[%d]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%f%*c%f%c",&ind0,arg0,arg1,&z,&opacity,&end)==5) && 1.2710 + (!*arg0 || 1.2711 + std::sscanf(arg0,"%f%c",&x,&end)==1 || 1.2712 + (std::sscanf(arg0,"%f%c%c",&x,&sepx,&end)==2 && sepx=='%')) && 1.2713 + (!*arg1 || 1.2714 + std::sscanf(arg1,"%f%c",&y,&end)==1 || 1.2715 + (std::sscanf(arg1,"%f%c%c",&y,&sepy,&end)==2 && sepy=='%'))) { 1.2716 + gmic_check_indice(ind0,"Draw 3D object on image%s"); 1.2717 + if (!images[ind0].is_CImg3d()) 1.2718 + error("Draw 3D object on image%s : Image [%d] is not a 3D object.",gmic_inds,ind0); 1.2719 + print("Draw 3D object [%d] at (%g%s,%g%s,%g) on image%s, with opacity %g.", 1.2720 + ind0,x,sepx=='%'?"%":"",y,sepy=='%'?"%":"",z,gmic_inds,opacity); 1.2721 + CImgList<unsigned int> primitives3d; 1.2722 + CImgList<unsigned char> colors3d; 1.2723 + CImg<float> opacities3d, points3d(images[ind0]); 1.2724 + points3d.CImg3dtoobject3d(primitives3d,colors3d,opacities3d); 1.2725 + opacities3d*=opacity; 1.2726 + cimg_foroff(indices,l) { 1.2727 + CImg<T> &img = images[indices[l]]; 1.2728 + const float 1.2729 + nx = (float)cimg::round(sepx=='%'?x*(img.dimx()-1)/100:x,1), 1.2730 + ny = (float)cimg::round(sepy=='%'?y*(img.dimy()-1)/100:y,1); 1.2731 + gmic_apply(img,draw_object3d(nx,ny,z,points3d,primitives3d,colors3d,opacities3d, 1.2732 + render3d,!is_oriented3d,focale3d,light3d_x,light3d_y,light3d_z,specular_light3d, 1.2733 + specular_shine3d,0)); 1.2734 + } 1.2735 + } else error("Draw 3D object on image%s : Invalid argument '%s' " 1.2736 + "(should be '[indice][,x[%%][,y[%%][,z[,opacity[,zoom[,u1,v1,w1,angle1[,...]]]]]]]').", 1.2737 + gmic_inds,argument_text); 1.2738 + ++position; continue; 1.2739 + } 1.2740 + 1.2741 + // Draw plasma fractal. 1.2742 + if (!cimg::strcmp("-plasma",item0)) { 1.2743 + float alpha = 1, beta = 1, opacity = 1; char end = 0; 1.2744 + if (std::sscanf(argument,"%f%c",&alpha,&end)==1 || 1.2745 + std::sscanf(argument,"%f%*c%f%c",&alpha,&beta,&end)==2 || 1.2746 + std::sscanf(argument,"%f%*c%f%*c%f%c",&alpha,&beta,&opacity,&end)==3) { 1.2747 + print("Draw plasma in image%s with alpha %g, beta %g and opacity %g.",gmic_inds,alpha,beta,opacity); 1.2748 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],draw_plasma(alpha,beta,opacity)); 1.2749 + } else error("Draw plasma in image%d : Invalid argument '%s' " 1.2750 + "(should be 'alpha[,beta[,opacity]]').",gmic_inds,argument_text); 1.2751 + ++position; continue; 1.2752 + } 1.2753 + 1.2754 + // Draw Mandelbrot/Julia fractal. 1.2755 + if (!cimg::strcmp("-mandelbrot",item0)) { 1.2756 + double z0r = -2, z0i = -2, z1r = 2, z1i = 2, paramr = 0, parami = 0; char end = 0; 1.2757 + float opacity = 1; int itermax = 100, julia = 0; 1.2758 + if (std::sscanf(argument,"%lf%*c%lf%*c%lf%*c%lf%c",&z0r,&z0i,&z1r,&z1i,&end)==4 || 1.2759 + std::sscanf(argument,"%lf%*c%lf%*c%lf%*c%lf%*c%d%c",&z0r,&z0i,&z1r,&z1i,&itermax,&end)==5 || 1.2760 + std::sscanf(argument,"%lf%*c%lf%*c%lf%*c%lf%*c%d%*c%d%*c%lf%*c%lf%c", 1.2761 + &z0r,&z0i,&z1r,&z1i,&itermax,&julia,¶mr,¶mi,&end)==8 || 1.2762 + std::sscanf(argument,"%lf%*c%lf%*c%lf%*c%lf%*c%d%*c%d%*c%lf%*c%lf%*c%f%c", 1.2763 + &z0r,&z0i,&z1r,&z1i,&itermax,&julia,¶mr,¶mi,&opacity,&end)==9) { 1.2764 + print("Draw %s fractal in image%s from complex area (%g,%g)-(%g,%g) with c0 = (%g,%g) (%d iterations).", 1.2765 + julia?"Julia":"Mandelbrot",gmic_inds,z0r,z0i,z1r,z1i,paramr,parami,itermax); 1.2766 + cimg_foroff(indices,l) 1.2767 + gmic_apply(images[indices[l]],draw_mandelbrot(CImg<T>(),opacity,z0r,z0i,z1r,z1i,itermax,true, 1.2768 + julia?true:false,paramr,parami)); 1.2769 + } else error("Draw fractal in image%s : Invalid argument '%s' " 1.2770 + "(should be 'z0r,z0i,z1r,z1i[,itermax[,julia,c0r,c0i[,opacity]]]').",gmic_inds,argument_text); 1.2771 + ++position; continue; 1.2772 + } 1.2773 + 1.2774 + // Flood fill. 1.2775 + if (!cimg::strcmp("-flood",item0)) { 1.2776 + char arg0[4096] = { 0 }, arg1[4096] = { 0 }, arg2[4096] = { 0 }, color[4096] = { 0 }; 1.2777 + char sepx = 0, sepy = 0, sepz = 0, end = 0; 1.2778 + float x = 0, y = 0, z = 0, tolerance = 0, opacity = 1; 1.2779 + if (std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%f%*c%f%*c%4095[0-9.eE,+-]", 1.2780 + arg0,arg1,arg2,&tolerance,&opacity,color)>=1 && 1.2781 + ((std::sscanf(arg0,"%f%c%c",&x,&sepx,&end)==2 && sepx=='%') || 1.2782 + std::sscanf(arg0,"%f%c",&x,&end)==1) && 1.2783 + ((std::sscanf(arg1,"%f%c%c",&y,&sepy,&end)==2 && sepy=='%') || 1.2784 + std::sscanf(arg1,"%f%c",&y,&end)==1 || !arg1[0]) && 1.2785 + ((std::sscanf(arg2,"%f%c%c",&z,&sepz,&end)==2 && sepz=='%') || 1.2786 + std::sscanf(arg2,"%f%c",&z,&end)==1 || !arg2[0])) { 1.2787 + print("Flood fill image%s from (%g%s,%g%s,%g%s) with tolerance %g, opacity %g and color '%s'.", 1.2788 + gmic_inds,x,sepx=='%'?"%":"",y,sepy=='%'?"%":"",z,sepz=='%'?"%":"",tolerance,opacity,color); 1.2789 + cimg_foroff(indices,l) { 1.2790 + CImg<T> &img = images[indices[l]]; 1.2791 + CImg<T> col(img.dimv(),1,1,1,0); 1.2792 + col.fill(color,true); 1.2793 + const int 1.2794 + nx = (int)cimg::round(sepx=='%'?x*(img.dimx()-1)/100:x,1), 1.2795 + ny = (int)cimg::round(sepy=='%'?y*(img.dimy()-1)/100:y,1), 1.2796 + nz = (int)cimg::round(sepz=='%'?z*(img.dimz()-1)/100:z,1); 1.2797 + gmic_apply(img,draw_fill(nx,ny,nz,col,opacity,tolerance)); 1.2798 + } 1.2799 + } else error("Flood fill image%s : Invalid argument '%s' " 1.2800 + "(should be 'x[,y[,z[,tolerance[,opacity[,color]]]]]').",gmic_inds,argument_text); 1.2801 + ++position; continue; 1.2802 + } 1.2803 + 1.2804 + //------------------------- 1.2805 + // Image list manipulation 1.2806 + //------------------------- 1.2807 + 1.2808 + // Remove specified image(s). 1.2809 + if (!cimg::strcmp("-remove",item0) || !cimg::strcmp("-rm",item0)) { 1.2810 + print("Remove image%s",gmic_inds); 1.2811 + unsigned int off = 0; 1.2812 + cimg_foroff(indices,l) { 1.2813 + const unsigned int ind = indices[l] - off; 1.2814 + images.remove(ind); filenames.remove(ind); 1.2815 + ++off; 1.2816 + } 1.2817 + if (verbosity_level>=0) std::fprintf(cimg_stdout," (%u image%s left).",images.size,images.size==1?"":"s"); 1.2818 + continue; 1.2819 + } 1.2820 + 1.2821 + // Keep specified image(s). 1.2822 + if (!cimg::strcmp("-keep",item0) || !cimg::strcmp("-k",item0)) { 1.2823 + print("Keep image%s",gmic_inds); 1.2824 + CImgList<T> nimages(indices.size()); 1.2825 + cimg_foroff(indices,l) nimages[l].swap(images[indices[l]]); 1.2826 + nimages.transfer_to(images); 1.2827 + if (verbosity_level>=0) std::fprintf(cimg_stdout," (%u image%s left).",images.size,images.size==1?"":"s"); 1.2828 + continue; 1.2829 + } 1.2830 + 1.2831 + // Move image(s) to specified position. 1.2832 + if (!cimg::strcmp("-move",item0) || !cimg::strcmp("-mv",item0)) { 1.2833 + int ind0 = no_ind; char end = 0; 1.2834 + if (std::sscanf(argument,"%d%c",&ind0,&end)==1) { 1.2835 + if (ind0<0) ind0+=images.size; 1.2836 + if (ind0<0) ind0 = 0; 1.2837 + if (ind0>(int)images.size) ind0 = images.size; 1.2838 + print("Move image%s to position %d.",gmic_inds,ind0); 1.2839 + CImgList<T> nimages; 1.2840 + CImgList<char> nfilenames; 1.2841 + cimg_foroff(indices,l) { 1.2842 + const unsigned int ind = indices[l]; 1.2843 + nimages.insert(1); nimages.last().swap(images[ind]); 1.2844 + nfilenames.insert(1); nfilenames.last().swap(filenames[ind]); 1.2845 + } 1.2846 + images.insert(nimages,ind0); filenames.insert(nfilenames,ind0); 1.2847 + { cimglist_for(images,l) if (!images[l]) { images.remove(l); filenames.remove(l--); }} 1.2848 + } else error("Move image%s : Invalid argument '%s' " 1.2849 + "(should be 'position').",gmic_inds,argument_text); 1.2850 + ++position; continue; 1.2851 + } 1.2852 + 1.2853 + // Reverse images order. 1.2854 + if (!cimg::strcmp("-reverse",item0)) { 1.2855 + print("Reverse images order."); 1.2856 + CImgList<T> nimages(indices.size()); 1.2857 + CImgList<char> nfilenames(indices.size()); 1.2858 + cimg_foroff(indices,l) { nimages[l].swap(images[indices[l]]); nfilenames[l].swap(filenames[indices[l]]); } 1.2859 + nimages.reverse(); nfilenames.reverse(); 1.2860 + { cimg_foroff(indices,l) { nimages[l].swap(images[indices[l]]); nfilenames[l].swap(filenames[indices[l]]); }} 1.2861 + continue; 1.2862 + } 1.2863 + 1.2864 + // Set image name. 1.2865 + if (!cimg::strcmp("-name",item0)) { 1.2866 + cimg_foroff(indices,l) filenames[indices[l]].assign(argument,cimg::strlen(argument)+1,1,1,1,false); 1.2867 + ++position; continue; 1.2868 + } 1.2869 + 1.2870 + //------------------------- 1.2871 + // 3D objects manipulation 1.2872 + //------------------------- 1.2873 + 1.2874 + // Generate 3D cube. 1.2875 + if (!cimg::strcmp("-cube3d",item)) { 1.2876 + float size = 100; char end = 0; 1.2877 + if (std::sscanf(argument,"%f%c",&size,&end)==1) { 1.2878 + print("Generate 3D cube with size %g.",size); 1.2879 + CImgList<unsigned int> primitives3d; 1.2880 + CImg<float> points3d = CImg<T>::cube3d(primitives3d,size); 1.2881 + CImgList<unsigned char> colors3d(primitives3d.size,1,3,1,1,200); 1.2882 + CImg<float> opacities3d(1,primitives3d.size,1,1,1); 1.2883 + points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); 1.2884 + images.insert(points3d); 1.2885 + filenames.insert(CImg<char>("(gmic)",7,1,1,1,false)); 1.2886 + } else error("Generate 3D cube : Invalid argument '%s' " 1.2887 + "(should be 'size').",argument_text); 1.2888 + ++position; continue; 1.2889 + } 1.2890 + 1.2891 + // Generate 3D cone. 1.2892 + if (!cimg::strcmp("-cone3d",item)) { 1.2893 + float radius = 100, height = 200; char end = 0; unsigned int subdivisions = 24; 1.2894 + if (std::sscanf(argument,"%f%c",&radius,&end)==1 || 1.2895 + std::sscanf(argument,"%f%*c%f%c",&radius,&height,&end)==2 || 1.2896 + std::sscanf(argument,"%f%*c%f%*c%u%c",&radius,&height,&subdivisions,&end)==3) { 1.2897 + print("Generate 3D cone with radius %g, height %g and %u subdivisions.",radius,height,subdivisions); 1.2898 + CImgList<unsigned int> primitives3d; 1.2899 + CImg<float> points3d = CImg<T>::cone3d(primitives3d,radius,height,subdivisions); 1.2900 + CImgList<unsigned char> colors3d(primitives3d.size,1,3,1,1,200); 1.2901 + CImg<float> opacities3d(1,primitives3d.size,1,1,1); 1.2902 + points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); 1.2903 + images.insert(points3d); 1.2904 + filenames.insert(CImg<char>("(gmic)",7,1,1,1,false)); 1.2905 + } else error("Generate 3D cone : Invalid argument '%s' " 1.2906 + "(should be 'radius[,height[,subdivisions]]').",argument_text); 1.2907 + ++position; continue; 1.2908 + } 1.2909 + 1.2910 + // Generate 3D cylinder. 1.2911 + if (!cimg::strcmp("-cylinder3d",item)) { 1.2912 + float radius = 100, height = 200; char end = 0; unsigned int subdivisions = 24; 1.2913 + if (std::sscanf(argument,"%f%c",&radius,&end)==1 || 1.2914 + std::sscanf(argument,"%f%*c%f%c",&radius,&height,&end)==2 || 1.2915 + std::sscanf(argument,"%f%*c%f%*c%u%c",&radius,&height,&subdivisions,&end)==3) { 1.2916 + print("Generate 3D cylinder with radius %g, height %g and %u subdivisions.",radius,height,subdivisions); 1.2917 + CImgList<unsigned int> primitives3d; 1.2918 + CImg<float> points3d = CImg<T>::cylinder3d(primitives3d,radius,height,subdivisions); 1.2919 + CImgList<unsigned char> colors3d(primitives3d.size,1,3,1,1,200); 1.2920 + CImg<float> opacities3d(1,primitives3d.size,1,1,1); 1.2921 + points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); 1.2922 + images.insert(points3d); 1.2923 + filenames.insert(CImg<char>("(gmic)",7,1,1,1,false)); 1.2924 + } else error("Generate 3D cylinder : Invalid argument '%s' " 1.2925 + "(should be 'radius[,height[,subdivisions]]').",argument_text); 1.2926 + ++position; continue; 1.2927 + } 1.2928 + 1.2929 + // Generate 3D torus. 1.2930 + if (!cimg::strcmp("-torus3d",item)) { 1.2931 + float radius1 = 100, radius2 = 30; char end = 0; unsigned int subdivisions1 = 24, subdivisions2 = 12; 1.2932 + if (std::sscanf(argument,"%f%*c%f%c",&radius1,&radius2,&end)==2 || 1.2933 + std::sscanf(argument,"%f%*c%f%*c%u%*c%u%c",&radius1,&radius2,&subdivisions1,&subdivisions2,&end)==4) { 1.2934 + print("Generate 3D torus with radii %g and %g, and subdivisions %u and %u.",radius1,radius2,subdivisions1,subdivisions2); 1.2935 + CImgList<unsigned int> primitives3d; 1.2936 + CImg<float> points3d = CImg<T>::torus3d(primitives3d,radius1,radius2,subdivisions1,subdivisions2); 1.2937 + CImgList<unsigned char> colors3d(primitives3d.size,1,3,1,1,200); 1.2938 + CImg<float> opacities3d(1,primitives3d.size,1,1,1); 1.2939 + points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); 1.2940 + images.insert(points3d); 1.2941 + filenames.insert(CImg<char>("(gmic)",7,1,1,1,false)); 1.2942 + } else error("Generate 3D torus : Invalid argument '%s' " 1.2943 + "(should be 'radius1,radius2[,subdivisions1,subdivisions2]').",argument_text); 1.2944 + ++position; continue; 1.2945 + } 1.2946 + 1.2947 + // Generate 3D plane. 1.2948 + if (!cimg::strcmp("-plane3d",item)) { 1.2949 + float sizex = 100, sizey = 30; char end = 0; unsigned int subdivisionsx = 24, subdivisionsy = 12; 1.2950 + if (std::sscanf(argument,"%f%*c%f%c",&sizex,&sizey,&end)==2 || 1.2951 + std::sscanf(argument,"%f%*c%f%*c%u%*c%u%c",&sizex,&sizey,&subdivisionsx,&subdivisionsy,&end)==4) { 1.2952 + print("Generate 3D plane with dimensions %g and %g, and subdivisions %u and %u.",sizex,sizey,subdivisionsx,subdivisionsy); 1.2953 + CImgList<unsigned int> primitives3d; 1.2954 + CImg<float> points3d = CImg<T>::plane3d(primitives3d,sizex,sizey,subdivisionsx,subdivisionsy); 1.2955 + CImgList<unsigned char> colors3d(primitives3d.size,1,3,1,1,200); 1.2956 + CImg<float> opacities3d(1,primitives3d.size,1,1,1); 1.2957 + points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); 1.2958 + images.insert(points3d); 1.2959 + filenames.insert(CImg<char>("(gmic)",7,1,1,1,false)); 1.2960 + } else error("Generate 3D plane : Invalid argument '%s' " 1.2961 + "(should be 'sizex,sizey[,subdivisionsx,subdivisionsy]').",argument_text); 1.2962 + ++position; continue; 1.2963 + } 1.2964 + 1.2965 + // Generate 3D sphere. 1.2966 + if (!cimg::strcmp("-sphere3d",item)) { 1.2967 + float radius = 100; char end = 0; unsigned int subdivisions = 3; 1.2968 + if (std::sscanf(argument,"%f%c",&radius,&end)==1 || 1.2969 + std::sscanf(argument,"%f%*c%u%c",&radius,&subdivisions,&end)==2) { 1.2970 + print("Generate 3D sphere with radius %g and %u subdivisions.",radius,subdivisions); 1.2971 + CImgList<unsigned int> primitives3d; 1.2972 + CImg<float> points3d = CImg<T>::sphere3d(primitives3d,radius,subdivisions); 1.2973 + CImgList<unsigned char> colors3d(primitives3d.size,1,3,1,1,200); 1.2974 + CImg<float> opacities3d(1,primitives3d.size,1,1,1); 1.2975 + points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); 1.2976 + images.insert(points3d); 1.2977 + filenames.insert(CImg<char>("(gmic)",7,1,1,1,false)); 1.2978 + } else error("Generate 3D sphere : Invalid argument '%s' " 1.2979 + "(should be 'radius[,subdivisions]').",argument_text); 1.2980 + ++position; continue; 1.2981 + } 1.2982 + 1.2983 + // Build 3D elevation. 1.2984 + if (!cimg::strcmp("-elevation3d",item0)) { 1.2985 + float zfact = 0.2f; char end = 0, sep = 0; int ind0 = no_ind; 1.2986 + if (std::sscanf(argument,"%f%c",&zfact,&end)==1 || 1.2987 + (std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==2 && sep==']')) { 1.2988 + CImg<typename CImg<T>::Tfloat> elev; 1.2989 + if (ind0!=no_ind) { 1.2990 + gmic_check_indice(ind0,"Build 3D elevation of image%s"); 1.2991 + print("Build 3D elevation of image%s with elevation map [%d].",gmic_inds,ind0); 1.2992 + if (images[ind0].dimv()==1) elev = images[ind0]; 1.2993 + else elev = images[ind0].get_pointwise_norm(); 1.2994 + } else print("Build 3D elevation of image%s with z-factor %g.",gmic_inds,zfact); 1.2995 + cimg_foroff(indices,l) { 1.2996 + CImg<T>& img = images[indices[l]]; 1.2997 + CImgList<unsigned int> primitives3d; 1.2998 + CImgList<unsigned char> colors3d; 1.2999 + CImg<float> opacities3d, points3d; 1.3000 + if (elev) points3d = img.get_elevation3d(primitives3d,colors3d,elev); 1.3001 + else { 1.3002 + if (img.dimv()==1) (elev = img)*=zfact; else (elev = img.get_pointwise_norm())*=zfact; 1.3003 + points3d = img.get_elevation3d(primitives3d,colors3d,elev); 1.3004 + elev.assign(); 1.3005 + } 1.3006 + opacities3d.assign(1,primitives3d.size,1,1,1); 1.3007 + points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); 1.3008 + gmic_apply(img,replace(points3d)); 1.3009 + } 1.3010 + } else error("Build 3D elevation : invalid argument '%s' " 1.3011 + "(should be 'z-factor' or '[indice]').",argument_text); 1.3012 + ++position; continue; 1.3013 + } 1.3014 + 1.3015 + // Build 3D isovalue. 1.3016 + if (!cimg::strcmp("-isovalue3d",item0)) { 1.3017 + float value = 0; char end = 0; 1.3018 + if (std::sscanf(argument,"%f%c",&value,&end)==1) { 1.3019 + print("Build 3D isovalue %g of image%s.",value,gmic_inds); 1.3020 + cimg_foroff(indices,l) { 1.3021 + const unsigned int ind = indices[l]; 1.3022 + CImg<T>& img = images[ind]; 1.3023 + CImg<float> points3d; 1.3024 + CImgList<unsigned int> primitives3d; 1.3025 + CImgList<unsigned char> colors3d; 1.3026 + CImg<float> opacities3d; 1.3027 + CImg<unsigned char> palette; 1.3028 + palette.assign(3,img.dim,1,1,220).noise(35,1); 1.3029 + if (img.dim==1) palette(0) = palette(1) = palette(2) = 255; 1.3030 + else { 1.3031 + palette(0,0) = 255; palette(1,0) = 30; palette(2,0) = 30; 1.3032 + palette(0,1) = 30; palette(1,1) = 255; palette(2,1) = 30; 1.3033 + if (img.dim>=3) palette(0,2) = 30; palette(1,2) = 30; palette(2,2) = 255; 1.3034 + } 1.3035 + cimg_forV(img,k) { 1.3036 + CImgList<unsigned int> prims; 1.3037 + const CImg<float> pts = img.get_shared_channel(k).get_isovalue3d(prims,value); 1.3038 + if (pts) { 1.3039 + points3d.append_object3d(primitives3d,pts,prims); 1.3040 + colors3d.insert(prims.size, 1.3041 + CImg<unsigned char>::vector(palette(0,k),palette(1,k),palette(2,k))); 1.3042 + } 1.3043 + } 1.3044 + opacities3d.assign(1,primitives3d.size,1,1,1); 1.3045 + if (!points3d) 1.3046 + warning("Build 3D isovalue of image [%u] : Isovalue %g not found.",ind,value); 1.3047 + else points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); 1.3048 + gmic_apply(img,replace(points3d)); 1.3049 + } 1.3050 + } else error("Build 3D isovalue of image%s : Invalid argument '%s' " 1.3051 + "(should be 'isovalue').",gmic_inds,argument_text); 1.3052 + ++position; continue; 1.3053 + } 1.3054 + 1.3055 + // Center a 3D object. 1.3056 + if (!cimg::strcmp("-center3d",item0) || !cimg::strcmp("-c3d",item0)) { 1.3057 + print("Center 3D object%s.",gmic_inds); 1.3058 + cimg_foroff(indices,l) { 1.3059 + const unsigned int ind = indices[l]; 1.3060 + if (!images[ind].is_CImg3d()) 1.3061 + error("Center 3D object%s : Image [%d] is not a 3D object.",gmic_inds,ind); 1.3062 + gmic_apply(images[ind],centerCImg3d()); 1.3063 + } 1.3064 + continue; 1.3065 + } 1.3066 + 1.3067 + // Normalize a 3D object. 1.3068 + if (!cimg::strcmp("-normalize3d",item0) || !cimg::strcmp("-n3d",item0)) { 1.3069 + print("Normalize 3D object%s.",gmic_inds); 1.3070 + cimg_foroff(indices,l) { 1.3071 + const unsigned int ind = indices[l]; 1.3072 + if (!images[ind].is_CImg3d()) 1.3073 + error("Normalize 3D object%s : Image [%d] is not a 3D object.",gmic_inds,ind); 1.3074 + gmic_apply(images[ind],normalizeCImg3d()); 1.3075 + } 1.3076 + continue; 1.3077 + } 1.3078 + 1.3079 + // Rotate a 3D object. 1.3080 + if (!cimg::strcmp("-rotate3d",item0) || !cimg::strcmp("-rot3d",item0)) { 1.3081 + float u = 0, v = 0, w = 1, angle = 0; char end = 0; 1.3082 + if (std::sscanf(argument,"%f%*c%f%*c%f%*c%f%c",&u,&v,&w,&angle,&end)==4) { 1.3083 + print("Rotate 3D object%s around axis (%g,%g,%g) with angle %g.",gmic_inds,u,v,w,angle); 1.3084 + const CImg<float> rot = CImg<float>::rotation_matrix(u,v,w,(float)(angle*cimg::valuePI/180)); 1.3085 + cimg_foroff(indices,l) { 1.3086 + const unsigned int ind = indices[l]; 1.3087 + if (!images[ind].is_CImg3d()) 1.3088 + error("Rotate 3D object%s : Image [%d] is not a 3D object.",gmic_inds,ind); 1.3089 + gmic_apply(images[ind],rotateCImg3d(rot)); 1.3090 + } 1.3091 + } else error("Rotate 3D object%s : Invalid argument '%s' " 1.3092 + "(should be 'u,v,w,angle').",gmic_inds,argument_text); 1.3093 + ++position; continue; 1.3094 + } 1.3095 + 1.3096 + // Add 3D objects together or translate a 3D object. 1.3097 + if (!cimg::strcmp("-add3d",item0) || !cimg::strcmp("-+3d",item0)) { 1.3098 + float tx = 0, ty = 0, tz = 0; int ind0 = no_ind; char sep = 0, end = 0; 1.3099 + if (std::sscanf(argument,"%f%c",&tx,&end)==1 || 1.3100 + std::sscanf(argument,"%f%*c%f%c",&tx,&ty,&end)==2 || 1.3101 + std::sscanf(argument,"%f%*c%f%*c%f%c",&tx,&ty,&tz,&end)==3) { 1.3102 + print("Translate 3D object%s with vector (%g,%g,%g).",gmic_inds,tx,ty,tz); 1.3103 + cimg_foroff(indices,l) { 1.3104 + const unsigned int ind = indices[l]; 1.3105 + if (!images[ind].is_CImg3d()) 1.3106 + error("Translate 3D object%s : Image [%d] is not a 3D object.",gmic_inds,ind); 1.3107 + gmic_apply(images[ind],translateCImg3d(tx,ty,tz)); 1.3108 + } 1.3109 + ++position; 1.3110 + } else if (std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==2 && sep==']') { 1.3111 + gmic_check_indice(ind0,"Merge object with 3D object%s."); 1.3112 + const CImg<T> img0 = images[ind0]; 1.3113 + if (!img0.is_CImg3d()) error("Merge object [%d] with 3D object%s : Image [%d] is not a 3D object.",ind0,gmic_inds,ind0); 1.3114 + print("Merge object [%d] with 3D object%s.",ind0,gmic_inds); 1.3115 + cimg_foroff(indices,l) { 1.3116 + const unsigned int ind = indices[l]; 1.3117 + const CImg<T> &img = images[ind]; 1.3118 + if (!img.is_CImg3d()) 1.3119 + error("Merge object [%d] with 3D object%s : Image [%d] is not a 3D object.",ind0,gmic_inds,ind); 1.3120 + gmic_apply(images[ind],appendCImg3d(img0)); 1.3121 + } 1.3122 + ++position; 1.3123 + } else { 1.3124 + print("Merge 3D object%s together.",gmic_inds); 1.3125 + if (indices) { 1.3126 + const unsigned int ind0 = indices[0]; 1.3127 + if (!images[ind0].is_CImg3d()) 1.3128 + error("Merge 3D object%s together : Image [%d] is not a 3D object.",gmic_inds,ind0); 1.3129 + for (unsigned int siz = indices.size(), off = 0, l = 1; l<siz; ++l) { 1.3130 + const unsigned int ind = indices[l] - off; 1.3131 + if (!images[ind].is_CImg3d()) 1.3132 + error("Merge 3D object%s together : Image [%d] is not a 3D object.",gmic_inds,ind); 1.3133 + images[ind0].appendCImg3d(images[ind]); 1.3134 + images.remove(ind); filenames.remove(ind); 1.3135 + ++off; 1.3136 + } 1.3137 + } 1.3138 + } 1.3139 + continue; 1.3140 + } 1.3141 + 1.3142 + // Translate 3D object by the opposite vector. 1.3143 + if (!cimg::strcmp("-sub3d",item0) || !cimg::strcmp("--3d",item0)) { 1.3144 + float tx = 0, ty = 0, tz = 0; char end = 0; 1.3145 + if (std::sscanf(argument,"%f%c",&tx,&end)==1 || 1.3146 + std::sscanf(argument,"%f%*c%f%c",&tx,&ty,&end)==2 || 1.3147 + std::sscanf(argument,"%f%*c%f%*c%f%c",&tx,&ty,&tz,&end)==3) { 1.3148 + print("Translate 3D object%s with vector -(%g,%g,%g).",gmic_inds,tx,ty,tz); 1.3149 + cimg_foroff(indices,l) { 1.3150 + CImg<T>& img = images[indices[l]]; 1.3151 + CImgList<unsigned int> primitives3d; 1.3152 + CImgList<unsigned char> colors3d; 1.3153 + CImg<float> opacities3d; 1.3154 + CImg<T> points3d; 1.3155 + if (get_version) points3d.assign(img); else img.transfer_to(points3d); 1.3156 + points3d.CImg3dtoobject3d(primitives3d,colors3d,opacities3d); 1.3157 + points3d.get_shared_line(0)-=tx; 1.3158 + points3d.get_shared_line(1)-=ty; 1.3159 + points3d.get_shared_line(2)-=tz; 1.3160 + points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); 1.3161 + if (get_version) { 1.3162 + images.insert(1); points3d.transfer_to(images.last()); 1.3163 + filenames.insert(filenames[indices[l]]); 1.3164 + } else points3d.transfer_to(images[indices[l]]); 1.3165 + } 1.3166 + } else error("Translate 3D object%s : Invalid argument '%s' " 1.3167 + "(should be 'tx,ty,tz').",gmic_inds,argument_text); 1.3168 + ++position; continue; 1.3169 + } 1.3170 + 1.3171 + // Scale a 3D object. 1.3172 + bool divide = false; 1.3173 + if (!cimg::strcmp("-mul3d",item0) || !cimg::strcmp("-*3d",item0) || 1.3174 + ((divide=true)==true && (!cimg::strcmp("-div3d",item0) || !cimg::strcmp("-/3d",item0)))) { 1.3175 + float sx = 0, sy = 1, sz = 1; char end = 0; 1.3176 + if ((std::sscanf(argument,"%f%c",&sx,&end)==1 && (sy = sz = sx),1) || 1.3177 + std::sscanf(argument,"%f%*c%f%c",&sx,&sy,&end)==2 || 1.3178 + std::sscanf(argument,"%f%*c%f%*c%f%c",&sx,&sy,&sz,&end)==3) { 1.3179 + if (divide) print("Scale 3D object%s with factors (1/%g,1/%g,1/%g).",gmic_inds,sx,sy,sz); 1.3180 + else print("Scale 3D object%s with factors (%g,%g,%g).",gmic_inds,sx,sy,sz); 1.3181 + cimg_foroff(indices,l) { 1.3182 + CImg<T>& img = images[indices[l]]; 1.3183 + CImgList<unsigned int> primitives3d; 1.3184 + CImgList<unsigned char> colors3d; 1.3185 + CImg<float> opacities3d; 1.3186 + CImg<T> points3d; 1.3187 + if (get_version) points3d.assign(img); else img.transfer_to(points3d); 1.3188 + points3d.CImg3dtoobject3d(primitives3d,colors3d,opacities3d); 1.3189 + if (divide) { 1.3190 + points3d.get_shared_line(0)/=sx; 1.3191 + points3d.get_shared_line(1)/=sy; 1.3192 + points3d.get_shared_line(2)/=sz; 1.3193 + } else { 1.3194 + points3d.get_shared_line(0)*=sx; 1.3195 + points3d.get_shared_line(1)*=sy; 1.3196 + points3d.get_shared_line(2)*=sz; 1.3197 + } 1.3198 + points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); 1.3199 + if (get_version) { 1.3200 + images.insert(1); points3d.transfer_to(images.last()); 1.3201 + filenames.insert(filenames[indices[l]]); 1.3202 + } else points3d.transfer_to(images[indices[l]]); 1.3203 + } 1.3204 + } else error("Scale 3D object%s : Invalid argument '%s' " 1.3205 + "(should be 'fact' or 'factx,facty[,factz]').",gmic_inds,argument_text); 1.3206 + ++position; continue; 1.3207 + } 1.3208 + 1.3209 + // Set color of 3D object(s). 1.3210 + if (!cimg::strcmp("-color3d",item0) || !cimg::strcmp("-col3d",item0)) { 1.3211 + float R = 200, G = 200, B = 200, opacity = -1; char end = 0; 1.3212 + if (std::sscanf(argument,"%f%*c%f%*c%f%c",&R,&G,&B,&end)==3 || 1.3213 + std::sscanf(argument,"%f%*c%f%*c%f%*c%f%c",&R,&G,&B,&opacity,&end)==4) { 1.3214 + const bool set_opacity = (opacity>=0); 1.3215 + R = (float)cimg::round(R,1); G = (float)cimg::round(G,1); B = (float)cimg::round(B,1); 1.3216 + if (R<0) R = 0; if (R>255) R = 255; 1.3217 + if (G<0) G = 0; if (G>255) G = 255; 1.3218 + if (B<0) B = 0; if (B>255) B = 255; 1.3219 + if (set_opacity) print("Set colors of 3D object%s to (%g,%g,%g) and opacity to %g.",gmic_inds,R,G,B,opacity); 1.3220 + else print("Set color of 3D object%s to (%g,%g,%g).",gmic_inds,R,G,B); 1.3221 + cimg_foroff(indices,l) { 1.3222 + const unsigned int ind = indices[l]; 1.3223 + if (!images[ind].is_CImg3d()) 1.3224 + error("Set color of 3D object%s : Image [%d] is not a 3D object.",gmic_inds,ind); 1.3225 + gmic_apply(images[ind],coloropacityCImg3d(R,G,B,opacity,true,set_opacity)); 1.3226 + } 1.3227 + } else error("Set color of 3D object%s : Invalid argument '%s' " 1.3228 + "(should be 'R,G,B[,opacity]').",gmic_inds,argument_text); 1.3229 + ++position; continue; 1.3230 + } 1.3231 + 1.3232 + // Set opacity of 3D object(s). 1.3233 + if (!cimg::strcmp("-opacity3d",item0) || !cimg::strcmp("-opac3d",item0)) { 1.3234 + float opacity = 1; char end = 0; 1.3235 + if (std::sscanf(argument,"%f%c",&opacity,&end)==1) { 1.3236 + print("Set opacity of 3D object%s to %g.",gmic_inds,opacity); 1.3237 + cimg_foroff(indices,l) { 1.3238 + const unsigned int ind = indices[l]; 1.3239 + if (!images[ind].is_CImg3d()) 1.3240 + error("Set opacity of 3D object%s : Image [%d] is not a 3D object.",gmic_inds,ind); 1.3241 + gmic_apply(images[ind],coloropacityCImg3d(0,0,0,opacity,false,true)); 1.3242 + } 1.3243 + } else error("Set opacity of 3D object%s : Invalid argument '%s' " 1.3244 + "(should be 'opacity').",gmic_inds,argument_text); 1.3245 + ++position; continue; 1.3246 + } 1.3247 + 1.3248 + // Invert 3D orientation. 1.3249 + if (!cimg::strcmp("-invert3d",item0) || !cimg::strcmp("-i3d",item0)) { 1.3250 + print("Invert orientation of 3D object%s.",gmic_inds); 1.3251 + cimg_foroff(indices,l) { 1.3252 + CImg<T> &img = images[indices[l]]; 1.3253 + CImgList<unsigned int> primitives3d; 1.3254 + CImgList<unsigned char> colors3d; 1.3255 + CImg<float> opacities3d; 1.3256 + CImg<T> points3d; 1.3257 + if (get_version) points3d.assign(img); else img.transfer_to(points3d); 1.3258 + points3d.CImg3dtoobject3d(primitives3d,colors3d,opacities3d); 1.3259 + if (primitives3d) primitives3d.invert_object3d(); 1.3260 + points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); 1.3261 + if (get_version) { 1.3262 + images.insert(1); points3d.transfer_to(images.last()); 1.3263 + filenames.insert(filenames[indices[l]]); 1.3264 + } else points3d.transfer_to(images[indices[l]]); 1.3265 + } 1.3266 + continue; 1.3267 + } 1.3268 + 1.3269 + // Split 3D object(s) into 6 vector images {header,N,vertices,primitives,colors,opacities} 1.3270 + if (!cimg::strcmp("-split3d",item0) || !cimg::strcmp("-s3d",item0)) { 1.3271 + print("Split 3D object%s into its different characteristics.",gmic_inds); 1.3272 + unsigned int off = 0; 1.3273 + cimg_foroff(indices,l) { 1.3274 + const unsigned int ind = indices[l] + off; 1.3275 + CImg<T> &img = images[ind]; 1.3276 + const CImg<char> filename = filenames[ind]; 1.3277 + CImgList<unsigned int> primitives3d; 1.3278 + CImgList<unsigned char> colors3d; 1.3279 + CImg<float> opacities3d; 1.3280 + CImg<T> points3d; 1.3281 + if (get_version) points3d.assign(img); else img.transfer_to(points3d); 1.3282 + points3d.CImg3dtoobject3d(primitives3d,colors3d,opacities3d); 1.3283 + CImgList<T> split; 1.3284 + split.insert(CImg<T>("CImg3d",1,6,1,1,false)+=0.5f); 1.3285 + split.insert(CImg<T>::vector((T)points3d.dimx(),(T)primitives3d.size)); 1.3286 + split.insert(1); points3d.resize(-100,3,1,1,0).transpose().unroll('y').transfer_to(split.last()); 1.3287 + points3d.assign(); 1.3288 + CImgList<T> _prims; 1.3289 + cimglist_for(primitives3d,p) 1.3290 + _prims.insert(CImg<T>::vector((T)primitives3d[p].size())).insert(primitives3d[p]).last().unroll('y'); 1.3291 + primitives3d.assign(); 1.3292 + split.insert(_prims.get_append('y')); _prims.assign(); 1.3293 + split.insert(colors3d.get_append('x').transpose().unroll('y')); colors3d.assign(); 1.3294 + split.insert(1); opacities3d.transfer_to(split.last()); 1.3295 + if (get_version) { 1.3296 + images.insert(split); 1.3297 + filenames.insert(split.size,filename); 1.3298 + } else { 1.3299 + images.remove(ind); images.insert(split,ind); 1.3300 + filenames.remove(ind); filenames.insert(split.size,filename,ind); 1.3301 + off+=split.size-1; 1.3302 + } 1.3303 + } 1.3304 + continue; 1.3305 + } 1.3306 + 1.3307 + // Set 3D light position. 1.3308 + if (!cimg::strcmp("-light3d",item) || !cimg::strcmp("-l3d",item)) { 1.3309 + float lx = 0, ly = 0, lz = -5000; char end = 0; 1.3310 + if (std::sscanf(argument,"%f%*c%f%*c%f%c",&lx,&ly,&lz,&end)==3) { 1.3311 + print("Set 3D light position at (%g,%g,%g).",lx,ly,lz); 1.3312 + light3d_x = lx; 1.3313 + light3d_y = ly; 1.3314 + light3d_z = lz; 1.3315 + } else error("Set 3D light position : Invalid argument '%s' " 1.3316 + "(should be 'posx,posy,posz').",argument_text); 1.3317 + ++position; continue; 1.3318 + } 1.3319 + 1.3320 + // Set 3D focale. 1.3321 + if (!cimg::strcmp("-focale3d",item) || !cimg::strcmp("-f3d",item)) { 1.3322 + float focale = 500; char end = 0; 1.3323 + if (std::sscanf(argument,"%f%c",&focale,&end)==1) { 1.3324 + focale3d = focale; 1.3325 + print("Set 3D focale to %g.",focale); 1.3326 + } else error("Set 3D focale : Invalid argument '%s' " 1.3327 + "(should be 'value')."); 1.3328 + ++position; continue; 1.3329 + } 1.3330 + 1.3331 + // Set 3D specular light parameters. 1.3332 + if (!cimg::strcmp("-specl3d",item) || !cimg::strcmp("-sl3d",item)) { 1.3333 + float value = 0; char end = 0; 1.3334 + if (std::sscanf(argument,"%f%c",&value,&end)==1) { 1.3335 + specular_light3d = value; 1.3336 + print("Set amount of 3D specular light to %g.",specular_light3d); 1.3337 + } 1.3338 + else error("Set amount of 3D specular light : invalid argument '%s'" 1.3339 + "(should be 'value').", 1.3340 + argument_text); 1.3341 + ++position; continue; 1.3342 + } 1.3343 + 1.3344 + if (!cimg::strcmp("-specs3d",item) || !cimg::strcmp("-ss3d",item)) { 1.3345 + float value = 0; char end = 0; 1.3346 + if (std::sscanf(argument,"%f%c",&value,&end)==1) { 1.3347 + specular_shine3d = value; 1.3348 + print("Set shininess of 3D specular light to %g.",specular_shine3d); 1.3349 + } 1.3350 + else error("Set shininess of 3D specular light : invalid argument '%s'" 1.3351 + "(should be 'value').", 1.3352 + argument_text); 1.3353 + ++position; continue; 1.3354 + } 1.3355 + 1.3356 + // Switch double-sided mode for 3D rendering. 1.3357 + if (!cimg::strcmp("-orient3d",item) || !cimg::strcmp("-o3d",item)) { 1.3358 + is_oriented3d = !is_oriented3d; 1.3359 + continue; 1.3360 + } 1.3361 + 1.3362 + // Set 3D rendering mode. 1.3363 + if (!cimg::strcmp("-render3d",item) || !cimg::strcmp("-r3d",item)) { 1.3364 + unsigned int value = 0; char end = 0; 1.3365 + if (std::sscanf(argument,"%u%c",&value,&end)==1) { 1.3366 + render3d = value; 1.3367 + print("Set static 3D render mode to %s.", 1.3368 + render3d==-1?"bounding-box": 1.3369 + render3d==0?"pointwise":render3d==1?"linear":render3d==2?"flat": 1.3370 + render3d==3?"flat-shaded":render3d==4?"Gouraud-shaded": 1.3371 + render3d==5?"Phong-shaded":"none"); 1.3372 + } 1.3373 + else error("Set static 3D render mode : invalid argument '%s'" 1.3374 + "(should be '{0=pointwise, 1=linear, 2=flat, 3=flat shaded, 4=Gouraud shaded, 5=Phong-shaded}').", 1.3375 + argument_text); 1.3376 + ++position; continue; 1.3377 + } 1.3378 + 1.3379 + if (!cimg::strcmp("-renderd3d",item) || !cimg::strcmp("-rd3d",item)) { 1.3380 + unsigned int value = 0; char end = 0; 1.3381 + if (std::sscanf(argument,"%u%c",&value,&end)==1) { 1.3382 + renderd3d = value; 1.3383 + print("Set dynamic 3D render mode to %s.", 1.3384 + renderd3d==-1?"bounding-box": 1.3385 + renderd3d==0?"pointwise":renderd3d==1?"linear":renderd3d==2?"flat": 1.3386 + renderd3d==3?"flat-shaded":renderd3d==4?"Gouraud-shaded": 1.3387 + renderd3d==5?"Phong-shaded":"none"); 1.3388 + } 1.3389 + else error("Set dynamic 3D render mode : invalid argument '%s'" 1.3390 + "(should be '{0=pointwise, 1=linear, 2=flat, 3=flat shaded, 4=Gouraud shaded, 5=Phong-shaded}').", 1.3391 + argument_text); 1.3392 + ++position; continue; 1.3393 + } 1.3394 + 1.3395 + // Set 3D background color. 1.3396 + if (!cimg::strcmp("-background3d",item) || !cimg::strcmp("-b3d",item)) { 1.3397 + int R = 0, G = 0, B = 0; char end = 0; 1.3398 + const int nb = std::sscanf(argument,"%d%*c%d%*c%d%c",&R,&G,&B,&end); 1.3399 + switch (nb) { 1.3400 + case 1 : background3d[0] = background3d[1] = background3d[2] = R; break; 1.3401 + case 2 : background3d[0] = R; background3d[1] = background3d[2] = G; break; 1.3402 + case 3 : background3d[0] = R; background3d[1] = G; background3d[2] = B; break; 1.3403 + default: error("Set 3D background color : Invalid argument '%s'.",argument_text); 1.3404 + } 1.3405 + print("Set 3D background color to (%d,%d,%d).", 1.3406 + (int)background3d[0],(int)background3d[1],(int)background3d[2]); 1.3407 + ++position; continue; 1.3408 + } 1.3409 + 1.3410 + //---------------- 1.3411 + // Other commands. 1.3412 + //---------------- 1.3413 + 1.3414 + // No operations : do nothing 1.3415 + if (!cimg::strcmp("-nop",item)) { 1.3416 + continue; 1.3417 + } 1.3418 + 1.3419 + // Skip next argument; 1.3420 + if (!cimg::strcmp("-skip",item)) { 1.3421 + ++position; 1.3422 + continue; 1.3423 + } 1.3424 + 1.3425 + // Echo. 1.3426 + if (!cimg::strcmp("-echo",item) || !cimg::strcmp("-e",item)) { 1.3427 + const int l = cimg::strlen(argument); 1.3428 + if (l>=2 && argument[0]=='"' && argument[l-1]=='"') { 1.3429 + if (l==2) print(""); else { 1.3430 + CImg<char> nargument(argument+1,l-1,1,1,1,false); 1.3431 + nargument(l-2)=0; 1.3432 + print("%s",nargument.ptr()); 1.3433 + } 1.3434 + } else print("%s",argument); 1.3435 + ++position; continue; 1.3436 + } 1.3437 + 1.3438 + // Print. 1.3439 + if (!cimg::strcmp("-print",item0) || !cimg::strcmp("-p",item0)) { 1.3440 + if (images.size) { 1.3441 + print("Print image%s.\n\n",gmic_inds); 1.3442 + char title[4096]; 1.3443 + if (verbosity_level>=0) cimg_foroff(indices,l) { 1.3444 + const unsigned int ind = indices[l]; 1.3445 + std::sprintf(title,"image [%u] = '%s'",ind,filenames[ind].ptr()); 1.3446 + images[ind].print(title); 1.3447 + } 1.3448 + is_released = true; 1.3449 + } else print("Print image[]."); 1.3450 + continue; 1.3451 + } 1.3452 + 1.3453 + // Quit. 1.3454 + if (!cimg::strcmp("-quit",item) || !cimg::strcmp("-q",item)) { 1.3455 + print("Quit."); 1.3456 + is_released = true; 1.3457 + dowhile.assign(); 1.3458 + repeatdone.assign(); 1.3459 + position = command_line.size; 1.3460 + continue; 1.3461 + } 1.3462 + 1.3463 + // Do...while. 1.3464 + if (!cimg::strcmp("-do",item)) { 1.3465 + dowhile.insert(CImg<int>::vector((int)position)); 1.3466 + continue; 1.3467 + } 1.3468 + 1.3469 + if (!cimg::strcmp("-while",item)) { 1.3470 + double cond = 0; char end = 0; 1.3471 + if (std::sscanf(argument,"%lf%c",&cond,&end)!=1) cond = 0; 1.3472 + if (!dowhile) error("Directive '-while' is not associated with a '-do' command."); 1.3473 + if (cond<=0) dowhile.remove(); 1.3474 + else { position = (unsigned int)dowhile.last()(0); continue; } 1.3475 + ++position; continue; 1.3476 + } 1.3477 + 1.3478 + // If..else..endif 1.3479 + if (!cimg::strcmp("-if",item)) { 1.3480 + double cond = 0; char end = 0; 1.3481 + if (std::sscanf(argument,"%lf%c",&cond,&end)!=1) cond = 0; 1.3482 + if (cond<=0) { 1.3483 + for (int nbifs = 1; nbifs && position<command_line.size; ++position) { 1.3484 + const char *it = command_line[position].ptr(); 1.3485 + if (!cimg::strcmp("-if",it)) ++nbifs; 1.3486 + if (!cimg::strcmp("-endif",it)) --nbifs; 1.3487 + if (!cimg::strcmp("-else",it) && nbifs==1) --nbifs; 1.3488 + } 1.3489 + continue; 1.3490 + } 1.3491 + ++position; continue; 1.3492 + } 1.3493 + if (!cimg::strcmp("-else",item)) { 1.3494 + for (int nbifs = 1; nbifs && position<command_line.size; ++position) { 1.3495 + if (!cimg::strcmp("-if",command_line[position].ptr())) ++nbifs; 1.3496 + if (!cimg::strcmp("-endif",command_line[position].ptr())) --nbifs; 1.3497 + } 1.3498 + continue; 1.3499 + } 1.3500 + if (!cimg::strcmp("-endif",item)) continue; 1.3501 + 1.3502 + // Repeat...done 1.3503 + if (!cimg::strcmp("-repeat",item)) { 1.3504 + float fnb = 0; char end = 0; 1.3505 + if (std::sscanf(argument,"%f%c",&fnb,&end)==1) { 1.3506 + const int nb = (int)fnb; 1.3507 + if (nb>0) repeatdone.insert(CImg<int>::vector((int)position+1,nb)); 1.3508 + else { 1.3509 + int nbrepeats = 0; 1.3510 + for (nbrepeats = 1; nbrepeats && position<command_line.size; ++position) { 1.3511 + const char *it = command_line[position].ptr(); 1.3512 + if (!cimg::strcmp("-repeat",it)) ++nbrepeats; 1.3513 + if (!cimg::strcmp("-done",it)) --nbrepeats; 1.3514 + } 1.3515 + if (nbrepeats && position>=command_line.size) 1.3516 + error("Directive '-done' is missing after a '-repeat' command."); 1.3517 + continue; 1.3518 + } 1.3519 + } else error("Repeat operation : Invalid argument '%s' " 1.3520 + "(should be a number).",argument_text); 1.3521 + ++position; continue; 1.3522 + } 1.3523 + 1.3524 + if (!cimg::strcmp("-done",item)) { 1.3525 + if (!repeatdone) error("Directive '-done' is not associated with a '-repeat' command."); 1.3526 + if (--repeatdone.last()(1)) 1.3527 + position = (unsigned int)repeatdone.last()(0); 1.3528 + else repeatdone.remove(); 1.3529 + continue; 1.3530 + } 1.3531 + 1.3532 + // Check argument type 1.3533 + if (!cimg::strcmp("-int",item)) { 1.3534 + char it[4096], end = 0, sep = 0; int value = 0; 1.3535 + if (*argument) for (const char *nargument = argument; *nargument; ) { 1.3536 + const int nb = std::sscanf(nargument,"%4095[^,]%c",it,&sep); 1.3537 + if (nb) { 1.3538 + if (std::sscanf(it,"%d%c",&value,&end)==1) nargument+=cimg::strlen(it) + nb -1; 1.3539 + else error("Argument '%s' is not an integer value.",it); 1.3540 + } else error("Argument '%s' is not an integer value.",argument_text); 1.3541 + } 1.3542 + ++position; continue; 1.3543 + } 1.3544 + 1.3545 + if (!cimg::strcmp("-float",item)) { 1.3546 + char it[4096], end = 0, sep = 0; double value = 0; 1.3547 + if (*argument) for (const char *nargument = argument; *nargument; ) { 1.3548 + const int nb = std::sscanf(nargument,"%4095[^,]%c",it,&sep); 1.3549 + if (nb) { 1.3550 + if (std::sscanf(it,"%lf%c",&value,&end)==1) nargument+=cimg::strlen(it) + nb -1; 1.3551 + else error("Argument '%s' is not a float value.",it); 1.3552 + } else error("Argument '%s' is not a float value.",argument_text); 1.3553 + } 1.3554 + ++position; continue; 1.3555 + } 1.3556 + 1.3557 + //-------------------------- 1.3558 + // Input/Output and Display 1.3559 + //-------------------------- 1.3560 + 1.3561 + // Display. 1.3562 + if (!cimg::strcmp("-display",item0) || !cimg::strcmp("-d",item0)) { 1.3563 + if (display_images(images,indices,true)) is_released = true; 1.3564 + continue; 1.3565 + } 1.3566 + 1.3567 + // Display 3D object. 1.3568 + if (!cimg::strcmp("-display3d",item0) || !cimg::strcmp("-d3d",item0)) { 1.3569 + if (display_objects3d(images,indices,true)) is_released = true; 1.3570 + continue; 1.3571 + } 1.3572 + 1.3573 + // Display as a graph plot. 1.3574 + if (!cimg::strcmp("-plot",item0)) { 1.3575 + int plot_type = 1, vertex_type = 1; double ymin = 0, ymax = 0, xmin = 0, xmax = 0; char end = 0; 1.3576 + const int nb = std::sscanf(argument,"%d%*c%d%*c%lf%*c%lf%*c%lf%*c%lf%c",&plot_type,&vertex_type,&xmin,&xmax,&ymin,&ymax,&end); 1.3577 + if (nb==1 || nb==2 || nb==4 || nb==6) ++position; 1.3578 + else { plot_type = 1; vertex_type = 0; ymin = ymax = xmin = xmax = 0; } 1.3579 + is_released |= display_plots(images,indices,plot_type,vertex_type,xmin,xmax,ymin,ymax,true); 1.3580 + continue; 1.3581 + } 1.3582 + 1.3583 + // Select image feature. 1.3584 + if (!cimg::strcmp("-select",item0)) { 1.3585 + int select_type = 0; char end = 0; 1.3586 + if (std::sscanf(argument,"%d%c",&select_type,&end)==1) { 1.3587 + cimg_foroff(indices,l) gmic_apply(images[indices[l]],select(filenames[indices[l]].ptr(),select_type)); 1.3588 + } else error("Select image%s : Invalid argument '%s' " 1.3589 + "(should be 'select_type').",gmic_inds,argument_text); 1.3590 + ++position; continue; 1.3591 + } 1.3592 + 1.3593 + // Output. 1.3594 + if (!cimg::strcmp("-output",item0) || !cimg::strcmp("-o",item0)) { 1.3595 + char filename[4096] = { 0 }; char options[4096] = { 0 }; 1.3596 + if (std::sscanf(argument,"%4095[^,],%s",filename,options)!=2) std::strcpy(filename,argument); 1.3597 + const char *const ext = cimg::split_filename(filename); 1.3598 + if (!cimg::strcasecmp("off",ext)) { 1.3599 + char nfilename[4096] = { 0 }; 1.3600 + std::strcpy(nfilename,filename); 1.3601 + const unsigned int siz = indices.size(); 1.3602 + cimg_foroff(indices,l) { 1.3603 + const unsigned int ind = indices[l]; 1.3604 + if (siz!=1) cimg::number_filename(filename,l,6,nfilename); 1.3605 + if (!images[ind].is_CImg3d()) 1.3606 + error("Output 3D object [%u] as file '%s' : Image [%u] is not a 3D object.",ind,nfilename,ind); 1.3607 + print("Output 3D object [%u] as file '%s'.",ind,nfilename); 1.3608 + CImgList<unsigned int> primitives3d; 1.3609 + CImgList<unsigned char> colors3d; 1.3610 + CImg<float> opacities3d; 1.3611 + CImg<float> points3d(images[ind]); 1.3612 + points3d.CImg3dtoobject3d(primitives3d,colors3d,opacities3d).save_off(nfilename,primitives3d,colors3d); 1.3613 + } 1.3614 + } else if (!cimg::strcasecmp("jpeg",ext) || !cimg::strcasecmp("jpg",ext)) { 1.3615 + int quality = 100; char end = 0; 1.3616 + if (std::sscanf(options,"%d%c",&quality,&end)!=1) quality = 100; 1.3617 + if (quality<0) quality = 0; else if (quality>100) quality = 100; 1.3618 + CImgList<T> output_images; 1.3619 + cimg_foroff(indices,l) output_images.insert(images[indices[l]],~0U,true); 1.3620 + print("Output image%s as file '%s', with quality %u%%",gmic_inds,filename,quality); 1.3621 + if (!output_images) throw CImgInstanceException("CImgList<%s>::save() : File '%s, instance list (%u,%p) is empty.", 1.3622 + output_images.pixel_type(),filename, 1.3623 + output_images.size,output_images.data); 1.3624 + if (output_images.size==1) output_images[0].save_jpeg(filename,quality); 1.3625 + else { 1.3626 + char nfilename[1024]; 1.3627 + cimglist_for(output_images,l) { 1.3628 + cimg::number_filename(filename,l,6,nfilename); 1.3629 + output_images[l].save_jpeg(nfilename,quality); 1.3630 + } 1.3631 + } 1.3632 + } else { 1.3633 + CImgList<T> output_images; 1.3634 + cimg_foroff(indices,l) output_images.insert(images[indices[l]],~0U,true); 1.3635 + print("Output image%s as file '%s'.",gmic_inds,filename); 1.3636 + output_images.save(filename); 1.3637 + } 1.3638 + is_released = true; ++position; continue; 1.3639 + } 1.3640 + 1.3641 + // Substitute macros commands if necessary. 1.3642 + if (cimg::strcmp("-i",item0) && cimg::strcmp("-input",item0)) { 1.3643 + bool macro_found = false; 1.3644 + cimglist_for(macros,l) { 1.3645 + const char 1.3646 + *const macro = macros[l].ptr(), 1.3647 + *const command = commands[l].ptr(); 1.3648 + 1.3649 + if (!cimg::strcmp(item+1,macro) && *command) { 1.3650 + CImgList<char> arguments(256); 1.3651 + unsigned int nb_arguments = 0; 1.3652 + char s_argument[4096] = { 0 }, tmp[4096] = { 0 }, tmp2[4096] = { 0 }; 1.3653 + bool has_arguments = false; 1.3654 + macro_found = true; 1.3655 + debug("Found macro '%s', substituting by '%s'.",macro,command); 1.3656 + 1.3657 + // Get command-line values of macro arguments. 1.3658 + if (argument) 1.3659 + for (const char *nargument = argument; nb_arguments<256 && *nargument && 1.3660 + std::sscanf(nargument,"%4095[^,]",s_argument)==1;) { 1.3661 + CImg<char>(s_argument,cimg::strlen(s_argument)+1,1,1,1,false).transfer_to(arguments[nb_arguments++]); 1.3662 + nargument+=cimg::strlen(s_argument); 1.3663 + if (*nargument) ++nargument; 1.3664 + } 1.3665 + 1.3666 + // Substitute arguments in macro command expression. 1.3667 + CImg<char> substituted_command; 1.3668 + CImgList<char> lreplacement; 1.3669 + for (const char *ncommand = command; *ncommand;) if (*ncommand=='$') { 1.3670 + char *replace_text = 0, sep = 0; 1.3671 + int ind = 0, ind1 = 0; 1.3672 + 1.3673 + // Replace $# and ${#}. 1.3674 + if (ncommand[1]=='#' || (ncommand[1]=='{' && ncommand[2]=='#' && ncommand[3]=='}')) { 1.3675 + std::sprintf(replace_text=s_argument,"%u",nb_arguments); 1.3676 + ncommand+=(ncommand[1]=='#')?2:4; 1.3677 + has_arguments = true; 1.3678 + 1.3679 + // Replace $* and ${*}. 1.3680 + } else if (ncommand[1]=='*' || (ncommand[1]=='{' && ncommand[2]=='*' && ncommand[3]=='}')) { 1.3681 + replace_text = &(s_argument[0]=0); 1.3682 + for (unsigned int j = 1; j<=nb_arguments; ++j) { 1.3683 + replace_text+=std::sprintf(replace_text,"%s",arguments[j-1].ptr()); 1.3684 + if (j<nb_arguments) *(replace_text++) = ','; 1.3685 + } 1.3686 + replace_text = s_argument; 1.3687 + ncommand+=(ncommand[1]=='*')?2:4; 1.3688 + has_arguments = true; 1.3689 + 1.3690 + // Replace ${i*}. 1.3691 + } else if (std::sscanf(ncommand,"${%d*%c",&ind,&sep)==2 && 1.3692 + ind>0 && ind<256 && sep=='}') { 1.3693 + replace_text = &(s_argument[0]=0); 1.3694 + for (unsigned int j = ind; j<=nb_arguments; ++j) { 1.3695 + replace_text+=std::sprintf(replace_text,"%s",arguments[j-1].ptr()); 1.3696 + if (j<nb_arguments) *(replace_text++) = ','; 1.3697 + } 1.3698 + replace_text = s_argument; 1.3699 + ncommand+=std::sprintf(tmp,"${%d*}",ind); 1.3700 + has_arguments = true; 1.3701 + 1.3702 + // Replace $i and ${i}. 1.3703 + } else if ((std::sscanf(ncommand,"$%d",&ind)==1 || 1.3704 + (std::sscanf(ncommand,"${%d%c",&ind,&sep)==2 && sep=='}')) && 1.3705 + ind>0 && ind<256) { 1.3706 + if (!arguments[ind-1]) { 1.3707 + if (sep=='}') error("Macro '%s' : Argument '$%d' is undefined (in expression '${%d}').",macro,ind,ind); 1.3708 + else error("Macro '%s' : Argument '$%d' is undefined (in expression '$%d').",macro,ind,ind); 1.3709 + } 1.3710 + replace_text = arguments[ind-1].ptr(); 1.3711 + ncommand+=std::sprintf(tmp,"$%d",ind) + (sep=='}'?2:0); 1.3712 + has_arguments = true; 1.3713 + 1.3714 + // Replace ${i=$#}. 1.3715 + } else if (std::sscanf(ncommand,"${%d=$#%c",&ind,&sep)==2 && 1.3716 + ind>0 && ind<256 && sep=='}') { 1.3717 + std::sprintf(replace_text=s_argument,"%g",(double)nb_arguments); 1.3718 + CImg<char>(s_argument,cimg::strlen(s_argument)+1,1,1,1,false).transfer_to(arguments[ind-1]); 1.3719 + ncommand+=std::sprintf(tmp,"${%d=$#}",ind); 1.3720 + has_arguments = true; 1.3721 + 1.3722 + // Replace ${i=$j}. 1.3723 + } else if (std::sscanf(ncommand,"${%d=$%d%c",&ind,&ind1,&sep)==3 && sep=='}' && 1.3724 + ind>0 && ind<256 && ind1>0 && ind1<256) { 1.3725 + if (!arguments[ind1-1]) 1.3726 + error("Macro '%s' : Argument '$%d' is undefined (in expression '${%d=$%d}').",macro,ind1,ind,ind1); 1.3727 + if (!arguments[ind-1]) arguments[ind-1] = arguments[ind1-1]; 1.3728 + replace_text = arguments[ind-1].ptr(); 1.3729 + ncommand+=std::sprintf(tmp,"${%d=$%d}",ind,ind1); 1.3730 + has_arguments = true; 1.3731 + 1.3732 + // Replace ${i=default}. 1.3733 + } else if (std::sscanf(ncommand,"${%d=%4095[^}]%c",&ind,tmp,&sep)==3 && sep=='}' && 1.3734 + ind>0 && ind<256) { 1.3735 + if (!arguments[ind-1]) CImg<char>(tmp,cimg::strlen(tmp)+1,1,1,1,false).transfer_to(arguments[ind-1]); 1.3736 + replace_text = arguments[ind-1].ptr(); 1.3737 + ncommand+=cimg::strlen(tmp) + 4 + std::sprintf(tmp2,"%d",ind); 1.3738 + has_arguments = true; 1.3739 + 1.3740 + // Any other expression starting by '$'. 1.3741 + } else { 1.3742 + replace_text = &(s_argument[0]='$'); 1.3743 + if (std::sscanf(ncommand,"%4095[^$]",s_argument+1)!=1) { s_argument[1] = 0; ++ncommand; } 1.3744 + else ncommand+=cimg::strlen(s_argument); 1.3745 + } 1.3746 + 1.3747 + const int replace_length = cimg::strlen(replace_text); 1.3748 + if (replace_length) { 1.3749 + lreplacement.insert(1); 1.3750 + CImg<char>(replace_text,replace_length,1,1,1,false).transfer_to(lreplacement.last()); 1.3751 + } 1.3752 + 1.3753 + } else { 1.3754 + std::sscanf(ncommand,"%4095[^$]",s_argument); 1.3755 + const int replace_length = cimg::strlen(s_argument); 1.3756 + if (replace_length) { 1.3757 + lreplacement.insert(1); 1.3758 + CImg<char>(s_argument,replace_length,1,1,1,false).transfer_to(lreplacement.last()); 1.3759 + ncommand+=cimg::strlen(s_argument); 1.3760 + } 1.3761 + } 1.3762 + const CImg<char> zero(1,1,1,1,0); 1.3763 + lreplacement.insert(zero).get_append('x').transfer_to(substituted_command); 1.3764 + 1.3765 + // Substitute macro expression in command line. 1.3766 + bool is_dquote = false; 1.3767 + cimg_foroff(substituted_command,k) 1.3768 + if (substituted_command[k]=='"') is_dquote = !is_dquote; 1.3769 + else if (is_dquote && substituted_command[k]==' ') substituted_command[k] = 30; 1.3770 + CImgList<char> command_items = substituted_command.get_split(' ',false,false); 1.3771 + cimglist_for(command_items,k) { 1.3772 + CImg<char> &item = command_items[k]; 1.3773 + cimg_foroff(item,l) if (item[l]==30) item[l]=' '; 1.3774 + } 1.3775 + cimglist_for(command_items,k) command_items[k].append(zero,'y'); 1.3776 + if (position<command_line.size && has_arguments) command_line.remove(position); 1.3777 + command_line.remove(--position); 1.3778 + command_line.insert(command_items,position); 1.3779 + break; 1.3780 + } 1.3781 + } 1.3782 + if (macro_found) continue; 1.3783 + } 1.3784 + } 1.3785 + 1.3786 + // Input. 1.3787 + if (!cimg::strcmp("-i",item0) || !cimg::strcmp("-input",item0)) ++position; 1.3788 + else { if (get_version) --item; argument = item; item1[0] = 0; } 1.3789 + if (!cimg::strlen(item1)) indices.assign(1,1,1,1,images.size); 1.3790 + CImgList<T> input_images; 1.3791 + CImgList<char> input_filenames; 1.3792 + bool obj3d = false; 1.3793 + char st_inds[4096] = { 0 }, stx[4096] = { 0 }, sty[4096] = { 0 }, stz[4096] = { 0 }, stv[4096] = { 0 }; 1.3794 + char end = 0, sep = 0, sepx = 0, sepy = 0, sepz = 0, sepv = 0; 1.3795 + int nb = 1, indx = no_ind, indy = no_ind, indz = no_ind, indv = no_ind; 1.3796 + float dx = 0, dy = 1, dz = 1, dv = 1; 1.3797 + 1.3798 + if (std::sscanf(argument,"[%4095[0-9%,:-]]%*c%d%c",st_inds,&nb,&end)==2 || 1.3799 + (std::sscanf(argument,"[%4095[0-9%,:-]%c%c",st_inds,&sep,&end)==2 && sep==']')) { 1.3800 + 1.3801 + // nb copies of existing sub-images. 1.3802 + const CImg<unsigned int> indices0 = indices2cimg(st_inds,images.size,"-input"); 1.3803 + char st_tmp[4096] = { 0 }; std::strcpy(st_tmp,indices2string(indices0,true)); 1.3804 + if (nb<=0) error("Input %d copies of image%s : Invalid argument '%s'.", 1.3805 + nb,st_tmp,argument_text); 1.3806 + if (nb!=1) print("Input %d copies of image%s at position%s",nb,st_tmp,gmic_inds); 1.3807 + else print("Input copy of image%s at position%s",st_tmp,gmic_inds); 1.3808 + for (int i = 0; i<nb; ++i) cimg_foroff(indices0,l) { 1.3809 + input_images.insert(images[indices0[l]]); 1.3810 + input_filenames.insert(filenames[indices0[l]]); 1.3811 + } 1.3812 + } else if (((std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%d%c", 1.3813 + stx,sty,stz,stv,&(nb=1),&end)==5 || 1.3814 + std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c", 1.3815 + stx,sty,stz,stv,&end)==4) && 1.3816 + (std::sscanf(stx,"%f%c",&dx,&end)==1 || 1.3817 + (std::sscanf(stx,"%f%c%c",&dx,&sepx,&end)==2 && sepx=='%') || 1.3818 + (std::sscanf(stx,"[%d%c%c",&indx,&sepx,&end)==2 && sepx==']')) && 1.3819 + (std::sscanf(sty,"%f%c",&dy,&end)==1 || 1.3820 + (std::sscanf(sty,"%f%c%c",&dy,&sepy,&end)==2 && sepy=='%') || 1.3821 + (std::sscanf(sty,"[%d%c%c",&indy,&sepy,&end)==2 && sepy==']')) && 1.3822 + (std::sscanf(stz,"%f%c",&dz,&end)==1 || 1.3823 + (std::sscanf(stz,"%f%c%c",&dz,&sepz,&end)==2 && sepz=='%') || 1.3824 + (std::sscanf(stz,"[%d%c%c",&indz,&sepz,&end)==2 && sepz==']')) && 1.3825 + (std::sscanf(stv,"%f%c",&dv,&end)==1 || 1.3826 + (std::sscanf(stv,"%f%c%c",&dv,&sepv,&end)==2 && sepv=='%') || 1.3827 + (std::sscanf(stv,"[%d%c%c",&indv,&sepv,&end)==2 && sepv==']'))) || 1.3828 + (std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c",stx,sty,stz,&end)==3 && 1.3829 + (std::sscanf(stx,"%f%c",&dx,&end)==1 || 1.3830 + (std::sscanf(stx,"%f%c%c",&dx,&sepx,&end)==2 && sepx=='%') || 1.3831 + (std::sscanf(stx,"[%d%c%c",&indx,&sepx,&end)==2 && sepx==']')) && 1.3832 + (std::sscanf(sty,"%f%c",&dy,&end)==1 || 1.3833 + (std::sscanf(sty,"%f%c%c",&dy,&sepy,&end)==2 && sepy=='%') || 1.3834 + (std::sscanf(sty,"[%d%c%c",&indy,&sepy,&end)==2 && sepy==']')) && 1.3835 + (std::sscanf(stz,"%f%c",&dz,&end)==1 || 1.3836 + (std::sscanf(stz,"%f%c%c",&dz,&sepz,&end)==2 && sepz=='%') || 1.3837 + (std::sscanf(stz,"[%d%c%c",&indz,&sepz,&end)==2 && sepz==']'))) || 1.3838 + (std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c",stx,sty,&end)==2 && 1.3839 + (std::sscanf(stx,"%f%c",&dx,&end)==1 || 1.3840 + (std::sscanf(stx,"%f%c%c",&dx,&sepx,&end)==2 && sepx=='%') || 1.3841 + (std::sscanf(stx,"[%d%c%c",&indx,&sepx,&end)==2 && sepx==']')) && 1.3842 + (std::sscanf(sty,"%f%c",&dy,&end)==1 || 1.3843 + (std::sscanf(sty,"%f%c%c",&dy,&sepy,&end)==2 && sepy=='%') || 1.3844 + (std::sscanf(sty,"[%d%c%c",&indy,&sepy,&end)==2 && sepy==']'))) || 1.3845 + (std::sscanf(argument,"%4095[][0-9.eE%+-]%c",stx,&end)==1 && 1.3846 + (std::sscanf(stx,"%f%c",&dx,&end)==1 || 1.3847 + (std::sscanf(stx,"%f%c%c",&dx,&sepx,&end)==2 && sepx=='%') || 1.3848 + (std::sscanf(stx,"[%d%c%c",&indx,&sepx,&end)==2 && sepx==']')))) { 1.3849 + 1.3850 + // nb new black image. 1.3851 + if (indx!=no_ind) { gmic_check_indice(indx,"Input black image%s"); dx = (float)images[indx].dimx(); sepx = 0; } 1.3852 + if (indy!=no_ind) { gmic_check_indice(indy,"Input black image%s"); dy = (float)images[indy].dimy(); sepy = 0; } 1.3853 + if (indz!=no_ind) { gmic_check_indice(indz,"Input black image%s"); dz = (float)images[indz].dimz(); sepz = 0; } 1.3854 + if (indv!=no_ind) { gmic_check_indice(indv,"Input black image%s"); dv = (float)images[indv].dimv(); sepv = 0; } 1.3855 + if (sepx=='%') { dx = images.size?dx*images.last().dimx()/100:0; if (!(int)dx) ++dx; } 1.3856 + if (sepy=='%') { dy = images.size?dy*images.last().dimy()/100:0; if (!(int)dy) ++dy; } 1.3857 + if (sepz=='%') { dz = images.size?dz*images.last().dimz()/100:0; if (!(int)dz) ++dz; } 1.3858 + if (sepv=='%') { dv = images.size?dv*images.last().dimv()/100:0; if (!(int)dv) ++dv; } 1.3859 + 1.3860 + if (nb<=0) error("Input %d black image%s : Invalid number of copies.",nb,gmic_inds); 1.3861 + if (dx<=0 || dy<=0 || dz<=0 || dv<=0) 1.3862 + error("Input %d black image%s : Invalid image dimensions %gx%gx%gx%g.", 1.3863 + nb,gmic_inds,dx,dy,dz,dv); 1.3864 + if (nb!=1) print("Input %d black images at position%s",nb,gmic_inds); 1.3865 + else print("Input black image at position%s",gmic_inds); 1.3866 + CImg<T> empty((int)dx,(int)dy,(int)dz,(int)dv,0); 1.3867 + input_images.insert(nb-1,empty); input_images.insert(1); 1.3868 + input_images.last().swap(empty); 1.3869 + filenames.insert(input_images.size,CImg<char>("(gmic)",7,1,1,1,false)); 1.3870 + } else if (std::sscanf(argument,"(%4095[^)])x%d%c",stx,&(nb=1),&end)==2 || 1.3871 + (std::sscanf(argument,"(%4095[^)]%c%c",stx,&sep,&end)==2 && sep==')')) { 1.3872 + 1.3873 + // Insert nb IxJxKxL image(s) with specified values. 1.3874 + if (nb<=0) error("Input %d images : Invalid number of copies.",nb); 1.3875 + unsigned int cx = 0, cy = 0, cz = 0, cv = 0, maxcx = 0, maxcy = 0, maxcz = 0; 1.3876 + const char *nargument = 0; 1.3877 + for (nargument = argument+1; *nargument!=')'; ) { 1.3878 + char s_value[256] = { 0 }, separator = 0; double value = 0; 1.3879 + if (std::sscanf(nargument,"%255[0-9.eE+-]%c",s_value,&separator)==2 && std::sscanf(s_value,"%lf",&value)==1) { 1.3880 + if (cx>maxcx) maxcx = cx; 1.3881 + if (cy>maxcy) maxcy = cy; 1.3882 + if (cz>maxcz) maxcz = cz; 1.3883 + switch (separator) { 1.3884 + case '^' : cx = cy = cz = 0; ++cv; break; 1.3885 + case '/' : cx = cy = 0; ++cz; break; 1.3886 + case ';' : cx = 0; ++cy; break; 1.3887 + default : ++cx; 1.3888 + } 1.3889 + nargument+=cimg::strlen(s_value) + (separator==')'?0:1); 1.3890 + } else break; 1.3891 + } 1.3892 + if (*nargument!=')') error("Input %d images : Invalid input string '%s'.",nb,argument); 1.3893 + 1.3894 + CImg<T> img(maxcx+1,maxcy+1,maxcz+1,cv+1,0); 1.3895 + cx = cy = cz = cv = 0; 1.3896 + for (nargument = argument+1; *nargument; ) { 1.3897 + char s_value[256] = { 0 }, separator = 0; double value = 0; 1.3898 + if (std::sscanf(nargument,"%255[0-9.eE+-]%c",s_value,&separator)==2 && std::sscanf(s_value,"%lf",&value)==1) { 1.3899 + img(cx,cy,cz,cv) = (T)value; 1.3900 + switch (separator) { 1.3901 + case '^' : cx = cy = cz = 0; ++cv; break; 1.3902 + case '/' : cx = cy = 0; ++cz; break; 1.3903 + case ';' : cx = 0; ++cy; break; 1.3904 + default : ++cx; 1.3905 + } 1.3906 + nargument+=cimg::strlen(s_value) + (separator==')'?0:1); 1.3907 + } else break; 1.3908 + } 1.3909 + if (nb==1) print("Input image %dx%dx%dx%d",img.dimx(),img.dimy(),img.dimz(),img.dimv()); 1.3910 + else print("Input %d images %dx%d",nb,img.dimx(),img.dimy(),img.dimz(),img.dimv()); 1.3911 + input_images.insert(nb,img); filenames.insert(nb,CImg<char>("(gmic)",7,1,1,1,false)); 1.3912 + } else { 1.3913 + 1.3914 + // Insert image as a loaded filename. 1.3915 + char filename[4096] = { 0 }, options[4096] = { 0 }; const char *ext = 0, *basename = 0; 1.3916 + if (argument[0]!='-' || (argument[1] && argument[1]!='.')) { 1.3917 + std::FILE *file = std::fopen(argument,"r"); 1.3918 + if (file) { std::fclose(file); std::strcpy(filename,argument); } 1.3919 + else { 1.3920 + std::sscanf(argument,"%4095[^,],%s",filename,options); 1.3921 + if (!(file=std::fopen(filename,"r"))) { 1.3922 + if (filename[0]=='-') error("Input '%s' : Command not found.",filename); 1.3923 + else error("Input '%s' : File not found.",filename); 1.3924 + } 1.3925 + std::fclose(file); 1.3926 + } 1.3927 + } else std::strcpy(filename,argument); 1.3928 + basename = cimg::basename(filename); 1.3929 + ext = cimg::split_filename(filename); 1.3930 + 1.3931 + if (!cimg::strcasecmp("off",ext)) { // 3D object file. 1.3932 + print("Input 3D object '%s'",filename); 1.3933 + CImgList<unsigned int> primitives3d; 1.3934 + CImgList<unsigned char> colors3d; 1.3935 + CImg<float> opacities3d, points3d = CImg<float>::get_load_off(filename,primitives3d,colors3d); 1.3936 + opacities3d.assign(1,primitives3d.size,1,1,1); 1.3937 + points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); 1.3938 + input_images.insert(1); points3d.transfer_to(input_images[0]); 1.3939 + input_filenames.insert(CImg<char>(is_fullpath?filename:basename, 1.3940 + cimg::strlen(is_fullpath?filename:basename)+1,1,1,1,false)); 1.3941 + obj3d = true; 1.3942 + } else if (!cimg::strcasecmp(ext,"avi") || 1.3943 + !cimg::strcasecmp(ext,"mov") || 1.3944 + !cimg::strcasecmp(ext,"asf") || 1.3945 + !cimg::strcasecmp(ext,"divx") || 1.3946 + !cimg::strcasecmp(ext,"flv") || 1.3947 + !cimg::strcasecmp(ext,"mpg") || 1.3948 + !cimg::strcasecmp(ext,"m1v") || 1.3949 + !cimg::strcasecmp(ext,"m2v") || 1.3950 + !cimg::strcasecmp(ext,"m4v") || 1.3951 + !cimg::strcasecmp(ext,"mjp") || 1.3952 + !cimg::strcasecmp(ext,"mkv") || 1.3953 + !cimg::strcasecmp(ext,"mpe") || 1.3954 + !cimg::strcasecmp(ext,"movie") || 1.3955 + !cimg::strcasecmp(ext,"ogm") || 1.3956 + !cimg::strcasecmp(ext,"qt") || 1.3957 + !cimg::strcasecmp(ext,"rm") || 1.3958 + !cimg::strcasecmp(ext,"vob") || 1.3959 + !cimg::strcasecmp(ext,"wmv") || 1.3960 + !cimg::strcasecmp(ext,"xvid") || 1.3961 + !cimg::strcasecmp(ext,"mpeg")) { 1.3962 + unsigned int value0 = 0, value1 = 0, step = 1; char sep0 = 0, sep1 = 0, end = 0; 1.3963 + if ((std::sscanf(options,"%u%c%*c%u%c%*c%u%c",&value0,&sep0,&value1,&sep1,&step,&end)==5 && sep0=='%' && sep1=='%') || 1.3964 + (std::sscanf(options,"%u%c%*c%u%*c%u%c",&value0,&sep0,&value1,&step,&end)==4 && sep0=='%') || 1.3965 + (std::sscanf(options,"%u%*c%u%c%*c%u%c",&value0,&value1,&sep1,&step,&end)==4 && sep1=='%') || 1.3966 + (std::sscanf(options,"%u%*c%u%*c%u%c",&value0,&value1,&step,&end)==3) || 1.3967 + (std::sscanf(options,"%u%c%*c%u%c%c",&value0,&sep0,&value1,&sep1,&end)==4 && sep0=='%' && sep1=='%') || 1.3968 + (std::sscanf(options,"%u%c%*c%u%c",&value0,&sep0,&value1,&end)==3 && sep0=='%') || 1.3969 + (std::sscanf(options,"%u%*c%u%c%c",&value0,&value1,&sep1,&end)==3 && sep1=='%') || 1.3970 + (std::sscanf(options,"%u%*c%u%c",&value0,&value1,&end)==2)) { // Read several frames 1.3971 + print("Input frames %u%s...%u%s with step %u of file '%s'", 1.3972 + value0,sep0=='%'?"%":"",value1,sep1=='%'?"%":"",step,filename); 1.3973 + if (sep0=='%' || sep1=='%') { 1.3974 + const unsigned int nb_frames = CImg<unsigned int>::get_load_ffmpeg(filename,0,0,0)[0]; 1.3975 + if (sep0=='%') value0 = value0*nb_frames/100; 1.3976 + if (sep1=='%') value1 = value1*nb_frames/100; 1.3977 + } 1.3978 + } else if ((std::sscanf(options,"%u%c%c",&value0,&sep0,&end)==2 && sep0=='%') || 1.3979 + (std::sscanf(options,"%u%c",&value0,&end)==1)) { // Read one frame 1.3980 + print("Input frame %u%s of file '%s'",value0,sep0=='%'?"%":"",filename); 1.3981 + if (sep0=='%') { 1.3982 + const unsigned int nb_frames = CImg<unsigned int>::get_load_ffmpeg(filename,0,0,0)[0]; 1.3983 + value0 = value0*nb_frames/100; 1.3984 + } 1.3985 + value1 = value0; step = 1; 1.3986 + } else { // Read all frames 1.3987 + print("Input all frames of file '%s'",filename); 1.3988 + value0 = 0; value1 = ~0U; sep0 = sep1 = 0; step = 1; 1.3989 + } 1.3990 + input_images.load_ffmpeg(filename,value0,value1,step); 1.3991 + if (input_images) 1.3992 + input_filenames.insert(input_images.size,CImg<char>(is_fullpath?filename:basename, 1.3993 + cimg::strlen(is_fullpath?filename:basename)+1,1,1,1,false)); 1.3994 + } else if (!cimg::strcasecmp("raw",ext)) { // Raw file. 1.3995 + int dx = 0, dy = 1, dz = 1, dv = 1; 1.3996 + if (std::sscanf(options,"%d%*c%d%*c%d%*c%d",&dx,&dy,&dz,&dv)>0) { 1.3997 + if (dx<=0 || dy<=0 || dz<=0 || dv<=0) 1.3998 + error("Input raw file '%s' : Invalid specified dimensions %dx%dx%dx%d.",filename,dx,dy,dz,dv); 1.3999 + print("Input raw file '%s'",filename); 1.4000 + input_images.insert(1); input_images[0].load_raw(filename,dx,dy,dz,dv); 1.4001 + input_filenames.insert(CImg<char>(is_fullpath?filename:basename, 1.4002 + cimg::strlen(is_fullpath?filename:basename)+1,1,1,1,false)); 1.4003 + } else error("Input raw file '%s' : Image dimensions must be specified.",filename); 1.4004 + } else if (!cimg::strcasecmp("yuv",ext)) { // YUV file. 1.4005 + int dx = 0, dy = 0; unsigned int first = 0, last = ~0U, step = 1; 1.4006 + if (std::sscanf(options,"%d%*c%d%*c%u%*c%u%*c%u",&dx,&dy,&first,&last,&step)>0) { 1.4007 + if (dx<=0 || dy<=0) 1.4008 + error("Input yuv file '%s' : Invalid specified dimensions %dx%d.",filename,dx,dy); 1.4009 + print("Input yuv file '%s'",filename); 1.4010 + input_images.load_yuv(filename,dx,dy,first,last,step); 1.4011 + input_filenames.insert(input_images.size,CImg<char>(is_fullpath?filename:basename, 1.4012 + cimg::strlen(is_fullpath?filename:basename)+1,1,1,1,false)); 1.4013 + } else error("Input yuv file '%s' : Image dimensions must be specified.",filename); 1.4014 + } else { // Other file type. 1.4015 + print("Input file '%s'",filename); 1.4016 + input_images.load(filename); 1.4017 + input_filenames.insert(input_images.size, 1.4018 + CImg<char>(is_fullpath?filename:basename, 1.4019 + cimg::strlen(is_fullpath?filename:basename)+1,1,1,1,false)); 1.4020 + } 1.4021 + } 1.4022 + 1.4023 + if (verbosity_level>=0) { 1.4024 + if (input_images) { 1.4025 + const unsigned int last = input_images.size-1; 1.4026 + if (obj3d) 1.4027 + std::fprintf(cimg_stdout," (%d points, %u primitives, %u colors).", 1.4028 + (unsigned int)input_images(0,6), 1.4029 + (unsigned int)input_images(0,7), 1.4030 + (unsigned int)input_images(0,8)); 1.4031 + else if (input_images.size==1) 1.4032 + std::fprintf(cimg_stdout," (1 image %ux%ux%ux%u).", 1.4033 + input_images[0].width,input_images[0].height,input_images[0].depth, 1.4034 + input_images[0].dim); 1.4035 + else std::fprintf(cimg_stdout," (%u images [0] = %ux%ux%ux%u, %s[%u] = %ux%ux%ux%u).", 1.4036 + input_images.size, 1.4037 + input_images[0].width,input_images[0].height,input_images[0].depth, 1.4038 + input_images[0].dim, 1.4039 + last==1?"":"...,", 1.4040 + last, 1.4041 + input_images[last].width,input_images[last].height,input_images[last].depth, 1.4042 + input_images[last].dim); 1.4043 + } else std::fprintf(cimg_stdout," (no available data)."); 1.4044 + } 1.4045 + 1.4046 + for (unsigned int l = 0, siz = indices.size()-1, off = 0; l<=siz; ++l) { 1.4047 + const unsigned int ind = indices[l] + off; 1.4048 + if (l!=siz) images.insert(input_images,ind); 1.4049 + else { 1.4050 + images.insert(input_images.size,ind); 1.4051 + cimglist_for(input_images,k) images[ind+k].swap(input_images[k]); 1.4052 + } 1.4053 + filenames.insert(input_filenames,ind); 1.4054 + off+=input_images.size; 1.4055 + } 1.4056 + 1.4057 + } catch (CImgException &e) { 1.4058 + const char *error_message = e.message; 1.4059 + char tmp[4096] = { 0 }, sep = 0; 1.4060 + if (std::sscanf(error_message,"%4095[^>]>:%c",tmp,&sep)==2 && sep==':') error_message+=cimg::strlen(tmp)+3; 1.4061 + error(error_message); 1.4062 + } 1.4063 + } 1.4064 + 1.4065 + // Check if command line has grown too much (possible recursive macro calls). 1.4066 + if (command_line.size>=command_line_maxsize) 1.4067 + error("Command line overflow : There are too much commands specified (possible recursive macro substitution)."); 1.4068 + 1.4069 + // Check if some loops have not been terminated. 1.4070 + if (dowhile) warning("A '-while' directive is missing somewhere."); 1.4071 + if (repeatdone) warning("A '-done' directive is missing somewhere."); 1.4072 + 1.4073 + // Display final result if necessary (not 'released' before). 1.4074 + if (images.size && !is_released) { 1.4075 + if (!display_objects3d(images,CImg<unsigned int>::sequence(images.size,0,images.size-1),false)) 1.4076 + display_images(images,CImg<unsigned int>::sequence(images.size,0,images.size-1),true); 1.4077 + } 1.4078 + 1.4079 + print("End G'MIC instance.\n"); 1.4080 + return *this; 1.4081 +} 1.4082 + 1.4083 +// Small hack to separate the compilation of G'MIC in different pixel types. 1.4084 +// (only intended to save computer memory when compiling !) 1.4085 +//-------------------------------------------------------------------------- 1.4086 +#ifdef gmic_minimal 1.4087 +gmic& gmic::parse_float(CImgList<float>& images) { return parse(images); } 1.4088 +template gmic::gmic(const int, const char *const *const, CImgList<float>&, const char *const custom_macros, const bool add_macros_at_start); 1.4089 +template gmic::gmic(const char* const, CImgList<float>&, const char *const custom_macros, const bool add_macros_at_start); 1.4090 +#else 1.4091 +#if defined(gmic_bool) || !defined(gmic_separate_compilation) 1.4092 +gmic& gmic::parse_bool(CImgList<bool>& images) { return parse(images); } 1.4093 +template gmic::gmic(const int, const char *const *const, CImgList<bool>&, const char *const custom_macros, const bool add_macros_at_start); 1.4094 +template gmic::gmic(const char* const, CImgList<bool>&, const char *const custom_macros, const bool add_macros_at_start); 1.4095 +#endif 1.4096 +#if defined(gmic_uchar) || !defined(gmic_separate_compilation) 1.4097 +gmic& gmic::parse_uchar(CImgList<unsigned char>& images) { return parse(images); } 1.4098 +template gmic::gmic(const int, const char *const *const, CImgList<unsigned char>&, const char *const custom_macros, const bool add_macros_at_start); 1.4099 +template gmic::gmic(const char* const, CImgList<unsigned char>&, const char *const custom_macros, const bool add_macros_at_start); 1.4100 +#endif 1.4101 +#if defined(gmic_char) || !defined(gmic_separate_compilation) 1.4102 +gmic& gmic::parse_char(CImgList<char>& images) { return parse(images); } 1.4103 +template gmic::gmic(const int, const char *const *const, CImgList<char>&, const char *const custom_macros, const bool add_macros_at_start); 1.4104 +template gmic::gmic(const char* const, CImgList<char>&, const char *const custom_macros, const bool add_macros_at_start); 1.4105 +#endif 1.4106 +#if defined(gmic_ushort) || !defined(gmic_separate_compilation) 1.4107 +gmic& gmic::parse_ushort(CImgList<unsigned short>& images) { return parse(images); } 1.4108 +template gmic::gmic(const int, const char *const *const, CImgList<unsigned short>&, const char *const custom_macros, const bool add_macros_at_start); 1.4109 +template gmic::gmic(const char* const, CImgList<unsigned short>&, const char *const custom_macros, const bool add_macros_at_start); 1.4110 +#endif 1.4111 +#if defined(gmic_short) || !defined(gmic_separate_compilation) 1.4112 +gmic& gmic::parse_short(CImgList<short>& images) { return parse(images); } 1.4113 +template gmic::gmic(const int, const char *const *const, CImgList<short>&, const char *const custom_macros, const bool add_macros_at_start); 1.4114 +template gmic::gmic(const char* const, CImgList<short>&, const char *const custom_macros, const bool add_macros_at_start); 1.4115 +#endif 1.4116 +#if defined(gmic_uint) || !defined(gmic_separate_compilation) 1.4117 +gmic& gmic::parse_uint(CImgList<unsigned int>& images) { return parse(images); } 1.4118 +template gmic::gmic(const int, const char *const *const, CImgList<unsigned int>&, const char *const custom_macros, const bool add_macros_at_start); 1.4119 +template gmic::gmic(const char* const, CImgList<unsigned int>&, const char *const custom_macros, const bool add_macros_at_start); 1.4120 +#endif 1.4121 +#if defined(gmic_int) || !defined(gmic_separate_compilation) 1.4122 +gmic& gmic::parse_int(CImgList<int>& images) { return parse(images); } 1.4123 +template gmic::gmic(const int, const char *const *const, CImgList<int>&, const char *const custom_macros, const bool add_macros_at_start); 1.4124 +template gmic::gmic(const char* const, CImgList<int>&, const char *const custom_macros, const bool add_macros_at_start); 1.4125 +#endif 1.4126 +#if defined(gmic_float) || !defined(gmic_separate_compilation) 1.4127 +gmic& gmic::parse_float(CImgList<float>& images) { return parse(images); } 1.4128 +template gmic::gmic(const int, const char *const *const, CImgList<float>&, const char *const custom_macros, const bool add_macros_at_start); 1.4129 +template gmic::gmic(const char* const, CImgList<float>&, const char *const custom_macros, const bool add_macros_at_start); 1.4130 +#endif 1.4131 +#if defined(gmic_double) || !defined(gmic_separate_compilation) 1.4132 +gmic& gmic::parse_double(CImgList<double>& images) { return parse(images); } 1.4133 +template gmic::gmic(const int, const char *const *const, CImgList<double>&, const char *const custom_macros, const bool add_macros_at_start); 1.4134 +template gmic::gmic(const char* const, CImgList<double>&, const char *const custom_macros, const bool add_macros_at_start); 1.4135 +#endif 1.4136 +#endif 1.4137 +#endif 1.4138 + 1.4139 +//----------------------- 1.4140 +// Start main procedure. 1.4141 +//----------------------- 1.4142 +#if defined(gmic_main) || (!defined(gmic_separate_compilation) && !defined(gmic_minimal)) 1.4143 +extern char data_def[]; 1.4144 + 1.4145 +int main(int argc, char **argv) { 1.4146 + 1.4147 + // Display help if necessary. 1.4148 + //--------------------------- 1.4149 + if (argc==1) { 1.4150 + std::fprintf(cimg_stdout,"<gmic> No options or data provided. Try '%s -h' for help.\n",cimg::basename(argv[0])); 1.4151 + std::exit(0); 1.4152 + } 1.4153 + 1.4154 + if (cimg_option("-h",false,0) || cimg_option("-help",false,0) || cimg_option("--help",false,0)) { 1.4155 + cimg_usage("GREYC's Magic Image Converter"); 1.4156 + 1.4157 + char version[1024] = { 0 }; 1.4158 + std::sprintf(version," Version %d.%d.%d.%d, Copyright (C) 2008-2009, David Tschumperle (http://gmic.sourceforge.net)", 1.4159 + gmic_version/1000,(gmic_version/100)%10,(gmic_version/10)%10,gmic_version%10); 1.4160 + cimg_help(version); 1.4161 + 1.4162 + cimg_help("\n Usage\n" 1.4163 + " -----"); 1.4164 + cimg_help(" gmic [file_1] [file_2] .. [file_n] [command_1] .. [command_n] [file_n+1] ...\n"); 1.4165 + cimg_help(" G'MIC is an interpreter of image processing macros whose goal is to convert, manipulate and"); 1.4166 + cimg_help(" visualize generic 1D/2D/3D multi-spectral image and video files. It follows these simple rules :\n"); 1.4167 + cimg_help(" - G'MIC handles a numbered list of images which are all stored in computer memory."); 1.4168 + cimg_help(" - The first image of the list has indice '[0]'."); 1.4169 + cimg_help(" - Negative indices are treated in a cyclic way (i.e. '[-1]' is the last image,"); 1.4170 + cimg_help(" '[-2]' the penultimate one, and so on...)."); 1.4171 + cimg_help(" - Command line items tell how to add/remove/manipulate/display images of the list."); 1.4172 + cimg_help(" - Items are read and executed in the order they appear on the command line, from the left to the right."); 1.4173 + cimg_help(" - Items can thus appear more than one time on the command line."); 1.4174 + cimg_help(" - An item starting by '-' is a G'MIC instruction."); 1.4175 + cimg_help(" - One instruction may have two equivalent names (regular and short)."); 1.4176 + cimg_help(" - A G'MIC instruction may have mandatory or optional arguments."); 1.4177 + cimg_help(" - When multiple arguments are needed, they are separated by commas ','."); 1.4178 + cimg_help(" - Items that are not instructions are considered either as input filenames or input strings."); 1.4179 + cimg_help(" - When an input filename is encountered, the corresponding image data are loaded"); 1.4180 + cimg_help(" and added to the end of the image list."); 1.4181 + cimg_help(" (see section 'Filename options' below for more informations on file input/output)."); 1.4182 + cimg_help(" - Special filenames '-' or '-.ext' mean 'standard input/output' (optionally. in 'ext' format)."); 1.4183 + cimg_help(" - Special input strings can be used to insert new images to the list. They can be :"); 1.4184 + cimg_help(" - 'width[%][xheight[%][xdepth[%][xdim[%][xN]]]]' : Insert 'N' black images with specified size."); 1.4185 + cimg_help(" (adding '%' to a dimension means 'percentage of to the same dimension in the last image'),"); 1.4186 + cimg_help(" - '[indice]' or '[indice]xN' : Insert 1 or N copies of the existing image [indice]."); 1.4187 + cimg_help(" - '(v1,v2,...)' or '(v1,v2,...)xN' : Insert 1 or N copies of the specified IxJxKxL image."); 1.4188 + cimg_help(" Separators inside '(..)' can be ',' (column), ';' (line), '/' (slice) or '^' (channel)."); 1.4189 + cimg_help(" - A G'MIC instruction may be restricted to a specific subset of the list, by adding '[subset]' to"); 1.4190 + cimg_help(" the instruction name. Several usual expressions are possible for 'subset', for instance : "); 1.4191 + cimg_help(" '-command[0,1,3]' : Apply instruction on images 0,1 and 3."); 1.4192 + cimg_help(" '-command[3-5]' : Apply instruction on images 3 to 5."); 1.4193 + cimg_help(" '-command[50%-100%] : Apply instruction on the second half of the image list."); 1.4194 + cimg_help(" '-command[0,-2,-1]' : Apply instruction on the first and two latest images."); 1.4195 + cimg_help(" '-command[0-9:3]' : Apply instruction on images 0 to 9, with a step of 3 (i.e. images 0,3,6,9)."); 1.4196 + cimg_help(" '-command[0,2-4,50%--1]' : Apply instruction on images 0,2,3,4 and the second half of the list."); 1.4197 + cimg_help(" - When no image subset is specified, a G'MIC instruction is applied on all images of the list."); 1.4198 + cimg_help(" - Native (non-macro) instructions starting with '--' instead of '-' do not act 'in-place' but"); 1.4199 + cimg_help(" insert their result as a new image at the end of the list."); 1.4200 + cimg_help(" - On the command line, any item of the form '@indice' or '@{indice}' is replaced"); 1.4201 + cimg_help(" by the values of the image '[indice]' separated by commas."); 1.4202 + cimg_help(" - Items '@?' (or '@{?}'), '@{?,max}' or '@{?,min,max}' are replaced by a float random value between [0,1], [0,max] or [min,max]."); 1.4203 + cimg_help(" - Items '@[?]', '@[?,max]' or '@[?,min,max]' do the same but return integer random values."); 1.4204 + cimg_help(" - Restrictions to a subset of image values can be specified with '@{indice,subset}' (as in '@{2,0-50%}')."); 1.4205 + cimg_help(" - Restriction to a particular pixel coordinate can be specified with '@(indice,x[,y[,z[,v[,borders]]]])'."); 1.4206 + cimg_help(" - On the command line, the item '@#' is replaced by the number of images in the list."); 1.4207 + cimg_help(" - Input filenames or commands may result to the generation of 3D objects."); 1.4208 + cimg_help(" - A 3D object viewer, based on software rendering, is included in G'MIC."); 1.4209 + cimg_help(" - A 3D object is stored as a single-column image containing all object data, in the following order :"); 1.4210 + cimg_help(" { magic header, vertices, faces, colors, opacities }."); 1.4211 + cimg_help(" - Custom user-defined G'MIC instructions can be defined with the use of a macro file."); 1.4212 + cimg_help(" - A macro file is a simple ASCII text file, each line being of the form"); 1.4213 + cimg_help(" 'instruction_name : substitution' or 'substitution (continuation)' or '# comment'."); 1.4214 + cimg_help(" - Each invoked macro instruction is substituted as its defined content on the command line."); 1.4215 + cimg_help(" - A macro file 'gmic_def.raw' is distributed within the G'MIC package."); 1.4216 + cimg_help(" - The macros defined in 'gmic_def.raw' are included by default in G'MIC."); 1.4217 + cimg_help(" - Macros arguments, separated by commas, can be added after the invokation of a macro instruction."); 1.4218 + cimg_help(" - In macros definitions, expressions starting with '$' are used to reference macro arguments :"); 1.4219 + cimg_help(" $i and ${i} are replaced by the value of the i-th macro argument."); 1.4220 + cimg_help(" $# and ${#} are replaced by the number of macro arguments."); 1.4221 + cimg_help(" $* and ${*} are replaced by the entire string of macro arguments."); 1.4222 + cimg_help(" ${i*} is replaced by all macro arguments following the i-th argument (included)."); 1.4223 + cimg_help(" ${i=$#} is replaced by $i if defined, or by its new value $# else."); 1.4224 + cimg_help(" ${i=$j} is replaced by $i if defined, or by its new value $j else."); 1.4225 + cimg_help(" ${i=default} is replaced by $i if defined, or by its new value 'default' else."); 1.4226 + cimg_help("\n A list of available native and macro instructions is available below."); 1.4227 + cimg_help(" A parameter specified in '[]' is optional, except when standing for '[indices]' where it"); 1.4228 + cimg_help(" corresponds to one or several indices of the image list, as described above. In this case, the '[' and ']'"); 1.4229 + cimg_help(" characters must explicitly appear when writting the item."); 1.4230 + 1.4231 + cimg_help("\n Global options\n" 1.4232 + " --------------"); 1.4233 + cimg_option("-help","(no args)","Display this help (eq. to '-h')."); 1.4234 + cimg_option("-verbose+","(no args)","Increment verbosity level (eq. to '-v+')."); 1.4235 + cimg_option("-verbose-","(no args)","Decrement verbosity level (eq. to '-v-')."); 1.4236 + cimg_option("-macros","'filename'","Load macro file from specified filename (eq. to '-m')."); 1.4237 + cimg_option("-debug","(no args)","Switch debug flag (when on, displays internal infos for debugging)."); 1.4238 + cimg_option("-fullpath","(no args)","Switch full path flag (when on, displays full filename paths)."); 1.4239 + 1.4240 + cimg_help("\n Arithmetic operators\n" 1.4241 + " --------------------"); 1.4242 + cimg_option("-add","'value', '[indice]' or (no args)","Add 'value' or '[indice]' to image(s)"); 1.4243 + cimg_help(" " 1.4244 + "or add image(s) together (eq. to '-+')."); 1.4245 + cimg_option("-sub","'value', '[indice]' or (no args)","Substract 'value' or '[indice]' to image(s)"); 1.4246 + cimg_help(" " 1.4247 + "or substract image(s) together (eq. to '--')."); 1.4248 + cimg_option("-mul","'value', '[indice]' or (no args)","Multiply image(s) by 'value' or '[indice]'"); 1.4249 + cimg_help(" " 1.4250 + "or multiply image(s) together (eq. to '-*')."); 1.4251 + cimg_option("-div","'value', '[indice]' or (no args)","Divide image(s) by 'value' or '[indice]'"); 1.4252 + cimg_help(" " 1.4253 + "or divide image(s) together (eq. to '-/')."); 1.4254 + cimg_option("-pow","'value', '[indice]' or (no args)","Compute image(s) to the power of 'value' or '[indice]'"); 1.4255 + cimg_help(" " 1.4256 + "or power of the image(s) together (eq. to '-^')."); 1.4257 + cimg_option("-min","'value', '[indice]' or (no args)","Compute minimum between image(s) and 'value' or '[indice]'"); 1.4258 + cimg_help(" " 1.4259 + "or minimum of image(s) together."); 1.4260 + cimg_option("-max","'value', '[indice]' or (no args)","Compute maximum between image(s) and 'value' or '[indice]'"); 1.4261 + cimg_help(" " 1.4262 + "or maximum of image(s) together."); 1.4263 + cimg_option("-mod","'value', '[indice]' or (no args)","Compute modulo of image(s) with 'value' or '[indice]'"); 1.4264 + cimg_help(" " 1.4265 + "or modulo with image(s) together."); 1.4266 + cimg_option("-and","'value', '[indice]' or (no args)","Compute bitwise AND of image(s) with 'value' or '[indice]'"); 1.4267 + cimg_help(" " 1.4268 + "or bitwise AND of image(s) together."); 1.4269 + cimg_option("-or","'value', '[indice]' or (no args)","Compute bitwise OR of image(s) with 'value' or '[indice]'"); 1.4270 + cimg_help(" " 1.4271 + "or bitwise OR of image(s) together."); 1.4272 + cimg_option("-xor","'value', '[indice]' or (no args)","Compute bitwise XOR of image(s) with 'value' '[indice]'"); 1.4273 + cimg_help(" " 1.4274 + "or bitwise XOR of image(s) together."); 1.4275 + cimg_option("-cos","(no args)","Compute cosine of image(s) values."); 1.4276 + cimg_option("-sin","(no args)","Compute sine of image(s) values."); 1.4277 + cimg_option("-tan","(no args)","Compute tangent of image(s) values."); 1.4278 + cimg_option("-acos","(no args)","Compute arccosine of image(s) values."); 1.4279 + cimg_option("-asin","(no args)","Compute arcsine of image(s) values."); 1.4280 + cimg_option("-atan","(no args)","Compute arctangent of image(s) values."); 1.4281 + cimg_option("-abs","(no args)","Compute absolute value of image(s) values."); 1.4282 + cimg_option("-sqr","(no args)","Compute square of image(s) values."); 1.4283 + cimg_option("-sqrt","(no args)","Compute square root of image(s) values."); 1.4284 + cimg_option("-exp","(no args)","Compute exponential of image(s) values."); 1.4285 + cimg_option("-log","(no args)","Compute logarithm of image(s) values."); 1.4286 + cimg_option("-log10","(no args)","Compute logarithm_10 of image(s) values."); 1.4287 + 1.4288 + cimg_help("\n Pointwise pixel manipulation\n" 1.4289 + " ----------------------------"); 1.4290 + cimg_option("-type","'value_type'","Cast all images into specified value type (eq. to '-t')."); 1.4291 + cimg_help(" " 1.4292 + "('value_type' can be 'bool','uchar','char','ushort','short',"); 1.4293 + cimg_help(" " 1.4294 + "'uint','int','float','double')."); 1.4295 + cimg_option("-set","'value[,x[,y[,z[,v]]]]'","Set scalar value in image(s) at specified position (eq. to '-=')."); 1.4296 + cimg_option("-endian","(no args)","Invert endianness of the image(s) buffers."); 1.4297 + cimg_option("-fill","'value1,value2,...'","Fill image(s) with scalar values in a repetitive way (eq. to '-f')."); 1.4298 + cimg_option("-threshold","'value[%][,soft]' or (noargs)","Threshold pixel values ((noargs) for interactive mode)."); 1.4299 + cimg_option("-cut","'{value1[%],[indice]},{value2[%],[indice]}' or (noargs)","Cut pixel values in specified range "); 1.4300 + cimg_help(" " 1.4301 + "((noargs) for interactive mode)."); 1.4302 + cimg_option("-normalize","'{value1[%],[indice]},{value2[%],[indice]}'", 1.4303 + "Normalize pixel values in specified range (eq. to '-n')."); 1.4304 + cimg_option("-round","'round_value[,round_type]'","Round pixel values."); 1.4305 + cimg_option("-equalize","'nb_levels'","Equalize image(s) histogram(s) using specified number of levels."); 1.4306 + cimg_option("-quantize","'nb_levels'","Quantize image(s) with 'nb_levels' levels."); 1.4307 + cimg_option("-noise","'std[%][,noise_type]'","Add noise with specified standard deviation"); 1.4308 + cimg_help(" " 1.4309 + "('noise_type' can be '{0=gaussian, 1=uniform, 2=salt&pepper, 3=poisson}'."); 1.4310 + cimg_option("-norm","(no args)","Compute pointwise L2-norm of vector-valued image(s)."); 1.4311 + cimg_option("-orientation","(no args)","Compute pointwise orientation of vector-valued image(s)."); 1.4312 + 1.4313 + cimg_help("\n Color bases conversions\n" 1.4314 + " -----------------------"); 1.4315 + cimg_option("-rgb2hsv","(no args)","Convert image(s) from RGB to HSV colorbases."); 1.4316 + cimg_option("-rgb2hsl","(no args)","Convert image(s) from RGB to HSL colorbases."); 1.4317 + cimg_option("-rgb2hsi","(no args)","Convert image(s) from RGB to HSI colorbases."); 1.4318 + cimg_option("-rgb2yuv","(no args)","Convert image(s) from RGB to YUV colorbases."); 1.4319 + cimg_option("-rgb2ycbcr","(no args)","Convert image(s) from RGB to YCbCr colorbases."); 1.4320 + cimg_option("-rgb2xyz","(no args)","Convert image(s) from RGB to XYZ colorbases."); 1.4321 + cimg_option("-rgb2lab","(no args)","Convert image(s) from RGB to Lab colorbases."); 1.4322 + cimg_option("-rgb2cmy","(no args)","Convert image(s) from RGB to CMY colorbases."); 1.4323 + cimg_option("-rgb2cmyk","(no args)","Convert image(s) from RGB to CMYK colorbases."); 1.4324 + cimg_option("-rgb2lut","'[indice][,dithering]' or 'LUT_type[,dithering]'","Index image(s) with color palette "); 1.4325 + cimg_help(" " 1.4326 + "('LUT_type' can be '{0=default, 1=rainbow, 2=contrast}'"); 1.4327 + cimg_help(" " 1.4328 + "'dithering' can be '{0=off, 1=on}')."); 1.4329 + cimg_option("-hsv2rgb","(no args)","Convert image(s) from HSV to RGB colorbases."); 1.4330 + cimg_option("-hsl2rgb","(no args)","Convert image(s) from HSL to RGB colorbases."); 1.4331 + cimg_option("-hsi2rgb","(no args)","Convert image(s) from HSI to RGB colorbases."); 1.4332 + cimg_option("-yuv2rgb","(no args)","Convert image(s) from YUV to RGB colorbases."); 1.4333 + cimg_option("-ycbcr2rgb","(no args)","Convert image(s) from YCbCr to RGB colorbases."); 1.4334 + cimg_option("-xyz2rgb","(no args)","Convert image(s) from XYZ to RGB colorbases."); 1.4335 + cimg_option("-lab2rgb","(no args)","Convert image(s) from Lab to RGB colorbases."); 1.4336 + cimg_option("-cmy2rgb","(no args)","Convert image(s) from CMY to RGB colorbases."); 1.4337 + cimg_option("-cmyk2rgb","(no args)","Convert image(s) from CMYK to RGB colorbases."); 1.4338 + cimg_option("-lut2rgb","'[indice]' or 'LUT_type'","Map color palette to image(s) "); 1.4339 + cimg_help(" " 1.4340 + "('LUT_type' can be '{0=default, 1=rainbow, 2=contrast}'."); 1.4341 + 1.4342 + cimg_help("\n Geometric manipulation\n" 1.4343 + " ----------------------"); 1.4344 + cimg_option("-resize","'[indice][,interpolation[,borders[,center]]]' or ",""); 1.4345 + cimg_help(" " 1.4346 + "'{[indice],width[%]}[x{[indice],height[%]}[x{[indice],depth[%]}[x{[indice],dim[%]}[,interpolation[,borders[,center]]]]]]'"); 1.4347 + cimg_help(" " 1.4348 + "or (noargs)"); 1.4349 + cimg_help(" " 1.4350 + "Resize image(s) to specified geometry ((noargs) for interactive mode) (eq. to '-r')"); 1.4351 + cimg_help(" " 1.4352 + "('interpolation' can be '{0=none, 1=nearest, 2=average, 3=linear, 4=grid, 5=cubic}')."); 1.4353 + cimg_option("-resize2x","(no args)","Resize image(s) with Scale2x."); 1.4354 + cimg_option("-resize3x","(no args)","Resize image(s) with Scale3x."); 1.4355 + cimg_option("-crop","'x0[%],x1[%][,border_conditions]' or 'x0[%],y0[%],x1[%],y1[%][,border_conditions]' or ",""); 1.4356 + cimg_help(" " 1.4357 + "'x0[%],y0[%],z0[%],x1[%],y1[%],z1[%][,border_conditions]' or "); 1.4358 + cimg_help(" " 1.4359 + "'x0[%],y0[%],z0[%],v0[%],x1[%],y1[%],z1[%],v1[%][,border_conditions]' or (noargs)."); 1.4360 + cimg_help(" " 1.4361 + "Crop image(s) using specified geometry ((noargs) for interactive mode) (eq. to '-c') "); 1.4362 + cimg_help(" " 1.4363 + "('border_conditions' can be '{0=zero, 1=nearest}')"); 1.4364 + cimg_help(" " 1.4365 + "((no args) for interactive mode)."); 1.4366 + cimg_option("-autocrop","'value1,value2,...'","Autocrop image(s) using specified background color."); 1.4367 + cimg_option("-channels","'{[ind0],v0[%]}[,{[ind1],v1[%]}]'","Select channels v0..v1 of multi-spectral image(s)."); 1.4368 + cimg_option("-slices","'{[ind0],z0[%]}[,{[ind1],z1[%]}]'","Select slices z0..z1 of volumetric image(s)."); 1.4369 + cimg_option("-lines","'{[ind0],y0[%]}[,{[ind1],y1[%]}]'","Select lines y0..y1 of image(s)."); 1.4370 + cimg_option("-columns","'{[ind0],x0[%]}[,{[ind1],x1[%]}]'","Select columns x0..x1 of image(s)."); 1.4371 + cimg_option("-rotate","'angle[,border_conditions]'","Rotate image(s) with a given angle "); 1.4372 + cimg_help(" " 1.4373 + "('border_conditions' can be '{-3=cyclic (in-place), -2=nearest(ip), -1=zero(ip), 0=zero, 1=nearest, 2=cyclic}'"); 1.4374 + cimg_help(" " 1.4375 + "and 'interpolation' can be '{0=none, 1=linear, 2=cubic}')."); 1.4376 + cimg_option("-mirror","'axis'", 1.4377 + "Mirror image(s) along specified axis ('axis' can be '{x,y,z,v}')."); 1.4378 + cimg_option("-translate","'tx[%][,ty[%][,tz[%][,tv[%][,border_conditions]]]]'", 1.4379 + "Translate image(s) by vector (dx,dy,dz,dv)"); 1.4380 + cimg_help(" " 1.4381 + "('border_conditions' can be '{0=zero, 1=nearest, 2=cyclic}')."); 1.4382 + cimg_option("-transpose","(no args)","Transpose image(s)."); 1.4383 + cimg_option("-invert","(no args)","Compute inverse matrix."); 1.4384 + cimg_option("-permute","'permutation'","Permute image axes by the specified permutation " 1.4385 + "('permutation' can be 'yxzv',...)."); 1.4386 + cimg_option("-unroll","'axis'", 1.4387 + "Unroll image(s) along specified axis ('axis' can be '{x,y,z,v}')."); 1.4388 + cimg_option("-split","'axis[,nb_parts]' or 'value[,keep]'", 1.4389 + "Split image(s) along specified axis or value ('axis' can be '{x,y,z,v}') (eq. to '-s')."); 1.4390 + cimg_option("-append","'axis,[alignement]'","Append image(s) along specified axis and alignement (eq. to '-a')"); 1.4391 + cimg_help(" " 1.4392 + "('axis' can be '{x,y,z,v}' and 'alignement' can be '{p=left, c=center, n=right)'."); 1.4393 + cimg_option("-warp","'[indice][,relative[,interpolation[,border_conditions[,nb_frames]]]]'", 1.4394 + "Warp image(s) in 'nb_frames' with field '[indice]' "); 1.4395 + cimg_help(" " 1.4396 + "('relative' can be '{0,1}', 'interpolation' can be '{0,1}', " 1.4397 + "'border_conditions' can be '{0=zero, 1=nearest}')."); 1.4398 + 1.4399 + cimg_help("\n Image filtering\n" 1.4400 + " ---------------"); 1.4401 + cimg_option("-blur","'std[,border_conditions]'", 1.4402 + "Apply gaussian blur of specified standard deviation"); 1.4403 + cimg_help(" " 1.4404 + "('border_conditions' can be '{0=zero, 1=nearest}')."); 1.4405 + cimg_option("-bilateral","'stdevs,stdevr'", 1.4406 + "Apply bilateral filtering with specified standard deviations 'stdevs' and 'stdevr'."); 1.4407 + cimg_option("-smooth","'amplitude[,sharpness[,anisotropy[,alpha[,sigma[,dl[,da[,prec[,interp[,fast]]]]]]]]]'",""); 1.4408 + cimg_help(" " 1.4409 + "Smooth image(s) anisotropically with specified parameters."); 1.4410 + cimg_option("-denoise","'patch_size[,stdev_p[,stdev_s[,lookup_size]]]'", 1.4411 + "Denoise image(s) with a patch-averaging procedure."); 1.4412 + cimg_option("-median","'size'","Apply median filter with specified size."); 1.4413 + cimg_option("-sharpen","'amplitude[,0]' or 'amplitude,1[,edge[,alpha[,sigma]]]'", 1.4414 + "Sharpen image(s) with inverse diffusion or shock filters."); 1.4415 + cimg_option("-convolve","'[indice][,border_conditions]'", 1.4416 + "Convolve image(s) by the specified mask"); 1.4417 + cimg_help(" " 1.4418 + "('border_conditions' can be '{0=zero, 1=nearest}')."); 1.4419 + cimg_option("-correlate","'[indice][,border_conditions]'", 1.4420 + "Correlate image(s) by the specified mask (same parameters as above)."); 1.4421 + cimg_option("-erode","'size[,border_conditions]' or '[indice][,border_conditions]'",""); 1.4422 + cimg_help(" " 1.4423 + "Erode image(s) by the specified mask (same parameters as above)')."); 1.4424 + cimg_option("-dilate","'size[,border_conditions]' or '[indice][,border_conditions]'",""); 1.4425 + cimg_help(" " 1.4426 + "Dilate image(s) by the specified mask (same parameters as above)."); 1.4427 + cimg_option("-gradient","'x', 'xy', 'xyz' or (no args)","Compute image gradient."); 1.4428 + cimg_option("-hessian","'{xx,xy,xz,yy,yz,zz}' or (no args)","Compute image Hessian."); 1.4429 + cimg_option("-fft","(no args)","Compute direct Fourier transform."); 1.4430 + cimg_option("-ifft","(no args)","Compute inverse Fourier transform."); 1.4431 + 1.4432 + cimg_help("\n Image creation and drawing\n" 1.4433 + " --------------------------"); 1.4434 + cimg_option("-dimensions","(no args)","Get dimensions of the image(s) as a 1x4 vector."); 1.4435 + cimg_option("-stats","(no args)","Get statistics of the image(s) as a 1x6 vector."); 1.4436 + cimg_option("-histogram","'nb_values[%]'","Compute histogram of image(s) with 'nb_values' values."); 1.4437 + cimg_option("-distance","'isovalue'","Compute distance function(s) to specified isovalue."); 1.4438 + cimg_option("-hamilton","'nb_iter[,band_size]'","Apply Hamilton-Jacobi PDE to compute distance to 0."); 1.4439 + cimg_option("-label","(no args)","Label connected components of image(s)."); 1.4440 + cimg_option("-displacement","'[indice][,smoothness[,precision[,nbscales[,itermax]]]]","Estimate smooth displacement field between image(s) " 1.4441 + "and specified target '[indice]'."); 1.4442 + cimg_option("-sort","(no args)","Sort values of image(s) in increasing order."); 1.4443 + cimg_option("-psnr","'max_value' or (noargs)","Compute PSNR between specified image(s)."); 1.4444 + cimg_option("-point","'x[%],y[%][,z[%][,opacity[,color]]]'","Draw 3D colored point on specified image(s)."); 1.4445 + cimg_option("-line","'x0[%],y0[%],x1[%],y1[%][,opacity[,color]]'","Draw 2D colored line on specified image(s)."); 1.4446 + cimg_option("-polygon","'N,x0[%],y0[%],..,xN[%],yN[%][,opacity[,color]]'","Draw a 2D colored N-vertices polygon on specified image(s)."); 1.4447 + cimg_option("-ellipse","'x[%],y[%],r,R[,u,v[,opacity[,color]]]'","Draw 2D colored ellipse on specified image(s)."); 1.4448 + cimg_option("-text","text,x[%],y[%],size[,opacity[,color]]'", 1.4449 + "Draw specified text at position (x,y) and with specified font size."); 1.4450 + cimg_option("-image","'[indice][,x[%][,y[%][,z[%][,opacity[,ind_mask]]]]]'","Draw sprite image on specified image(s)."); 1.4451 + cimg_option("-object3d","'[indice][,x[%][,y[%][,z[,opacity]]]]'","Draw 3D object on specified image(s)."); 1.4452 + cimg_option("-plasma","'alpha[,beta[,opacity]]'","Draw plasma on specified image(s)."); 1.4453 + cimg_option("-mandelbrot","'z0r,z0i,z1r,z1i[,itermax[,julia,c0r,c0i[,opacity]]]'","Draw Mandelbrot/Julia fractals on specified image(s)."); 1.4454 + cimg_option("-flood","'x[%][,y[%][,z[%][,tolerance[,opacity[,color]]]]]'", 1.4455 + "Flood-fill image(s) starting from (x,y,z) with specified tolerance."); 1.4456 + 1.4457 + cimg_help("\n List manipulation\n" 1.4458 + " -----------------"); 1.4459 + cimg_option("-remove","(no args)","Remove image(s) from list (eq. to '-rm')."); 1.4460 + cimg_option("-keep","(no args)","Keep only specified image(s) (eq. to '-k')."); 1.4461 + cimg_option("-move","'position'","Move image(s) at specified position (eq. to '-mv')."); 1.4462 + cimg_option("-reverse","(no args)","Reverse image(s) order."); 1.4463 + cimg_option("-name","\"name\"","Set display name of image(s)."); 1.4464 + 1.4465 + cimg_help("\n 3D Rendering\n" 1.4466 + " ------------"); 1.4467 + cimg_option("-cube3d","'size'","Insert a 3D cube at the end of the list."); 1.4468 + cimg_option("-cone3d","'radius[,height[,subdivisions]]'","Insert a 3D cube at the end of the list."); 1.4469 + cimg_option("-cylinder3d","'radius[,height[,subdivisions]]'","Insert a 3D cylinder at the end of the list."); 1.4470 + cimg_option("-torus3d","'radius1,radius2[,subdivisions1,subdivisions2]'","Insert a 3D torus at the end of the list."); 1.4471 + cimg_option("-plane3d","'sizex,sizey[,subdivisionsx,subdisivionsy]'","Insert a 3D plane at the end of the list."); 1.4472 + cimg_option("-sphere3d","'radius[,subdivisions]'","Insert a 3D sphere at the end of the list."); 1.4473 + cimg_option("-elevation3d","'z-factor' or '[indice]'", 1.4474 + "Generate 3D elevation(s) of image(s) using specified z-factor or elevation map."); 1.4475 + cimg_option("-isovalue3d","'value'","Generate 3D object(s) by retrieving isophote or isosurface of image(s)."); 1.4476 + cimg_option("-center3d","(no args)","Center 3D object(s) (eq. to '-c3d')."); 1.4477 + cimg_option("-normalize3d","(no args)","Normalize 3D object(s) to a unit size (eq. to '-n3d')."); 1.4478 + cimg_option("-rotate3d","'u,v,w,angle'","Rotate 3D object(s) around axis (u,v,w) with specified angle (eq. to '-rot3d')."); 1.4479 + cimg_option("-add3d","'[indice]' or 'tx,ty,tz' or (noargs)","Append or translate 3D object(s), or append 3D object(s) together (eq. to '-+3d')."); 1.4480 + cimg_option("-sub3d","'tx,ty,tz'","Translate 3D object(s) with the opposite of the specified vector (eq. to '--3d')."); 1.4481 + cimg_option("-mul3d","'fact' or 'factx,facty[,factz]'","Scale 3D object(s) with specified factor (eq. to '-*3d')."); 1.4482 + cimg_option("-div3d","'fact' or 'factx,facty[,factz]'","Scale 3D object(s) with specified inverse factor (eq. to '-/3d')."); 1.4483 + cimg_option("-color3d","'R,G,B[,opacity]'","Set color of 3D object(s) (eq. to '-col3d')."); 1.4484 + cimg_option("-opacity3d","'opacity'","Set opacity of 3D object(s) (eq. to '-opac3d')."); 1.4485 + cimg_option("-invert3d","(no args)","Invert primitive orientations of 3D object(s) (eq. to '-i3d')."); 1.4486 + cimg_option("-split3d","(no args)","Split 3D object data into 6 data vectors 'header,N,vertices,primitives,colors,opacities' (eq. to '-s3d')."); 1.4487 + cimg_option("-light3d","'posx,posy,posz'","Set the 3D position of the light for 3D rendering (eq. to '-l3d')."); 1.4488 + cimg_option("-focale3d","'value'","Set focale value for 3D rendering (eq. to '-f3d')."); 1.4489 + cimg_option("-specl3d","'value'","Set amount of specular light for 3D rendering (eq. to '-sl3d')."); 1.4490 + cimg_option("-specs3d","'value'","Set shininess of specular light for 3D rendering (eq. to '-ss3d')."); 1.4491 + cimg_option("-orient3d","(no args)","Switch double-sided mode for 3D rendering (eq. to '-o3d')."); 1.4492 + cimg_option("-render3d","'mode'","Set 3D rendering mode"); 1.4493 + cimg_help(" " 1.4494 + "(can be '{-1=bounding-box, 0=pointwise, 1=linear, 2=flat, 3=flat-shaded, 4=Gouraud-shaded, 5=Phong-shaded}') (eq. to '-r3d')."); 1.4495 + cimg_option("-renderd3d","'mode'","Set dynamic rendering mode in 3D viewer (same values as above) (eq. to '-rd3d')."); 1.4496 + cimg_option("-background3d","'R,G,B'","Define background color in 3D viewer (eq. to '-b3d')."); 1.4497 + 1.4498 + cimg_help("\n Program controls\n" 1.4499 + " ----------------"); 1.4500 + cimg_option("-nop","(no args)","Do nothing."); 1.4501 + cimg_option("-skip","(any args)","Do nothing but skip the next argument."); 1.4502 + cimg_option("-echo","'text'","Output specified message (eq. to '-e')."); 1.4503 + cimg_option("-print","(no args)","Print image(s) informations (eq. to '-p')."); 1.4504 + cimg_option("-quit","(no args)","Force interpreter to quit (eq. to '-q')."); 1.4505 + cimg_option("-do","(no args)","Start a 'do-while' code bloc."); 1.4506 + cimg_option("-while","'cond'","End a 'do-while' code bloc and go back to associated '-do' if 'cond' is a strictly positive value."); 1.4507 + cimg_option("-if","'cond'","Start a 'if-then-else' code bloc and test if 'cond' is a strictly positive value."); 1.4508 + cimg_option("-else","(no args)","Execute following commands if previous '-if' condition failed."); 1.4509 + cimg_option("-endif","(no args)","End a 'if-then-else' code bloc"); 1.4510 + cimg_option("-repeat","'N'","Start a 'repeat-done' code bloc."); 1.4511 + cimg_option("-done","(no args)","End a 'repeat-done' code bloc, and go to associated '-repeat' if iterations remain."); 1.4512 + cimg_option("-int","'arg1,...,argN'","Check if all specified arguments are integer. If not, print an error message and exit."); 1.4513 + cimg_option("-float","'arg1,...,argN","Check if all specified arguments are float values. If not, print an error message and exit."); 1.4514 + 1.4515 + cimg_help("\n Input/output\n" 1.4516 + " ------------"); 1.4517 + cimg_option("-input","'filename' or 'width[%][xheight[%][xdepth[%][xdim[%][xN]]]]'",""); 1.4518 + cimg_help(" " 1.4519 + "or '[indice][xN]' or '(v11{,;/^}v21...vLM)[xN]'"); 1.4520 + cimg_help(" " 1.4521 + "Input filename, empty image, image copy, or image with specified values (eq. to '-i' or (no args))."); 1.4522 + cimg_option("-output","'filename'","Output image(s) in specified filename (eq. to '-o')."); 1.4523 + cimg_option("-display","(no args)","Display image(s) (eq. to '-d')."); 1.4524 + cimg_option("-display3d","(no args)","Display 3D object(s) (eq. to '-d3d')."); 1.4525 + cimg_option("-plot","'[plot_type[,vertex_type[,xmin[,xmax[,ymin[,ymax]]]]]]'", 1.4526 + "Display image(s) as 1D plot(s)"); 1.4527 + cimg_help(" " 1.4528 + "('plot_type' can be '{0=none, 1=lines, 2=splines, 3=bar}')."); 1.4529 + cimg_help(" " 1.4530 + "('vertex_type' can be in '[0-7]')."); 1.4531 + cimg_option("-select","'select_type'","Select feature from image(s) in an interactive way"); 1.4532 + cimg_help(" " 1.4533 + "('select_type' can be in '{0=point, 1=line, 2=rectangle, 3=circle')."); 1.4534 + 1.4535 + // Print descriptions of default macros. 1.4536 + char line[256*1024] = { 0 }, name[4096] = { 0 }, args[4096] = { 0 }, desc[4096] = { 0 }; 1.4537 + bool first_description = true; 1.4538 + for (const char *data = data_def; *data; ) { 1.4539 + if (*data=='\n') ++data; 1.4540 + else { 1.4541 + if (std::sscanf(data,"%262143[^\n]",line)>0) data += cimg::strlen(line); 1.4542 + if (line[0]=='#' && std::sscanf(line,"#@gmic %4095[^:] : %4095[^:] : %4095[^:]",name,args,desc)>0) { 1.4543 + if (first_description) cimg_help("\n Commands : Default macros\n" 1.4544 + " -------------------------"); 1.4545 + std::fprintf(cimg_stdout,"%s %s-%-15s%s %-24s %s%s%s", 1.4546 + first_description?"":"\n", 1.4547 + cimg::t_bold,name,cimg::t_normal,args,cimg::t_green,desc,cimg::t_normal); 1.4548 + first_description = false; 1.4549 + } 1.4550 + } 1.4551 + } 1.4552 + 1.4553 + // Print descriptions of use-defined macros. 1.4554 + first_description = true; 1.4555 + for (int i = 1; i<argc-1; ++i) if (!cimg::strcmp("-m",argv[i]) || !cimg::strcmp("-macros",argv[i])) { 1.4556 + std::FILE *file = cimg::fopen(argv[i+1],"r"); 1.4557 + if (file) { 1.4558 + int err = 0; 1.4559 + while ((err=std::fscanf(file,"%262143[^\n] ",line)>=0)) { 1.4560 + if (err) { // Non empty-line 1.4561 + name[0] = args[0] = desc[0] = 0; 1.4562 + if (line[0]=='#' && std::sscanf(line,"#@gmic %4095[^:] : %4095[^:] : %4095[^:]",name,args,desc)>0) { 1.4563 + if (first_description) cimg_help("\n\n Commands : User-defined macros\n" 1.4564 + " ------------------------------"); 1.4565 + std::fprintf(cimg_stdout,"%s %s-%-15s%s %-24s %s%s%s", 1.4566 + first_description?"":"\n", 1.4567 + cimg::t_bold,name,cimg::t_normal,args,cimg::t_green,desc,cimg::t_normal); 1.4568 + first_description = false; 1.4569 + } 1.4570 + } 1.4571 + } 1.4572 + } 1.4573 + cimg::fclose(file); 1.4574 + } 1.4575 + 1.4576 + cimg_help("\n\n Viewers shortcuts\n" 1.4577 + " -----------------"); 1.4578 + cimg_help(" When displaying image(s) or 3D object(s) with G'MIC, you can use these shortcuts in viewers :"); 1.4579 + cimg_help(" - CTRL+D : Increase window size."); 1.4580 + cimg_help(" - CTRL+C : Decrease window size."); 1.4581 + cimg_help(" - CTRL+R : Reset window size."); 1.4582 + cimg_help(" - CTRL+F : Toggle fullscreen mode."); 1.4583 + cimg_help(" - CTRL+S : Save current window snapshot."); 1.4584 + cimg_help(" - CTRL+O : Save current instance of viewed image or 3D object.\n"); 1.4585 + cimg_help(" Specific options for the viewer of image(s) :"); 1.4586 + cimg_help(" - CTRL+P : Play stack of frames as a movie."); 1.4587 + cimg_help(" - CTRL+(mousewheel) : Zoom in/out."); 1.4588 + cimg_help(" - SHIFT+(mousewheel) : Go left/right."); 1.4589 + cimg_help(" - ALT+(mousewheel) : Go up/down."); 1.4590 + cimg_help(" - Numeric PAD : Zoom in/out (+/-) and move zoomed region (numbers)."); 1.4591 + cimg_help(" - BACKSPACE : Reset zoom.\n"); 1.4592 + cimg_help(" Specific options for the viewer of 3D object(s) :"); 1.4593 + cimg_help(" - (mouse) + (left mouse button) : Rotate object."); 1.4594 + cimg_help(" - (mouse) + (right mouse button) : Zoom object."); 1.4595 + cimg_help(" - (mouse) + (middle mouse button) : Translate object."); 1.4596 + cimg_help(" - (mousewheel) : Zoom in/out."); 1.4597 + cimg_help(" - CTRL + Z : Enable/disable Z-buffer rendering"); 1.4598 + 1.4599 + cimg_help("\n File options\n" 1.4600 + " ------------"); 1.4601 + cimg_help(" G'MIC is able to read/write most of the classical image file formats, including :"); 1.4602 + cimg_help(" - 2D grayscale/color images : PNG,JPEG,GIF,PNM,TIFF,BMP,...."); 1.4603 + cimg_help(" - 3D volumetric images : DICOM,HDR,NII,PAN,CIMG,INR,...."); 1.4604 + cimg_help(" - Video files : MPEG,AVI,MOV,OGG,FLV,..."); 1.4605 + cimg_help(" - Generic data files : DLM,ASC,RAW,TXT."); 1.4606 + cimg_help(" - 3D objects : OFF.\n"); 1.4607 + cimg_help(" Specific options :"); 1.4608 + cimg_help(" - For video files : you can read only sub-frames of the image sequence (recommended) with the expression"); 1.4609 + cimg_help(" 'video.ext,[first_frame[%][,last_frame[%][,step]]]'."); 1.4610 + cimg_help(" - For RAW files : you must specify the image dimensions with the expression"); 1.4611 + cimg_help(" 'file.raw,width[,height[,depth[,dim]]]]'."); 1.4612 + cimg_help(" - For YUV files : you must specify the image dimensions and can read only sub-frames of the image sequence with the expression"); 1.4613 + cimg_help(" 'file.yuv,width,height[,first_frame[,last_frame[,step]]]'."); 1.4614 + cimg_help(" - For JPEG files : you can specify the quality (in %) of an output jpeg file format with the expression"); 1.4615 + cimg_help(" 'file.jpg,30%'."); 1.4616 + 1.4617 + cimg_help("\n Examples of use\n" 1.4618 + " ---------------"); 1.4619 + cimg_help(" G'MIC is a simple but quite complete interpreter of image processing instructions, and can be used for a wide variety of"); 1.4620 + cimg_help(" image processing tasks. Here are (very few) examples of how the command line tool G'MIC can be used :\n"); 1.4621 + cimg_help(" - View image data : "); 1.4622 + cimg_help(" gmic file1.bmp file2.jpeg"); 1.4623 + cimg_help(" - Convert image files : "); 1.4624 + cimg_help(" gmic input.bmp -o output.jpg"); 1.4625 + cimg_help(" - Create volumetric image(s) from movie sequence : "); 1.4626 + cimg_help(" gmic input.mpg -a z -o output.hdr"); 1.4627 + cimg_help(" - Compute image gradient norm : "); 1.4628 + cimg_help(" gmic input.bmp -gradient_norm"); 1.4629 + cimg_help(" - Create G'MIC 3D logo : "); 1.4630 + cimg_help(" gmic 180x70x1x3 -text G\\'MIC,30,5,50,1,1 -blur 2 -n 0,100 [0] -plasma[1] \\"); 1.4631 + cimg_help(" -+ -blur 1 -elevation -0.1 -rd3d 4"); 1.4632 + cimg_help("\n See also the macros defined in the provided macro file 'gmic_def.raw' for other examples."); 1.4633 + 1.4634 + cimg_help("\n ** G'MIC comes with ABSOLUTELY NO WARRANTY; " 1.4635 + "for details visit http://gmic.sourceforge.net **"); 1.4636 + std::exit(0); 1.4637 + } 1.4638 + 1.4639 + // Launch G'MIC instance. 1.4640 + //----------------------- 1.4641 + CImgList<float> images; 1.4642 + try { 1.4643 + gmic(argc,argv,images); 1.4644 + } catch (gmic_exception &e) { 1.4645 + std::fprintf(cimg_stdout,"\n** Error occurred : %s **\n",e.message); 1.4646 + } 1.4647 + return 0; 1.4648 +} 1.4649 +#endif 1.4650 + 1.4651 +#endif // #ifdef cimg_plugin ... #else ...