Mon, 03 Aug 2009 14:21:23 +0100
added keepme for ptdecode obj directory
philpem@5 | 1 | /* |
philpem@5 | 2 | # |
philpem@5 | 3 | # File : gmic.cpp |
philpem@5 | 4 | # ( C++ source file ) |
philpem@5 | 5 | # |
philpem@5 | 6 | # Description : GREYC's Magic Image Converter (library and executable) |
philpem@5 | 7 | # ( http://gmic.sourceforge.net ) |
philpem@5 | 8 | # This file is a part of the CImg Library project. |
philpem@5 | 9 | # ( http://cimg.sourceforge.net ) |
philpem@5 | 10 | # |
philpem@5 | 11 | # Copyright : David Tschumperle |
philpem@5 | 12 | # ( http://www.greyc.ensicaen.fr/~dtschump/ ) |
philpem@5 | 13 | # |
philpem@5 | 14 | # License : CeCILL v2.0 |
philpem@5 | 15 | # ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html ) |
philpem@5 | 16 | # |
philpem@5 | 17 | # This software is governed by the CeCILL license under French law and |
philpem@5 | 18 | # abiding by the rules of distribution of free software. You can use, |
philpem@5 | 19 | # modify and/ or redistribute the software under the terms of the CeCILL |
philpem@5 | 20 | # license as circulated by CEA, CNRS and INRIA at the following URL |
philpem@5 | 21 | # "http://www.cecill.info". |
philpem@5 | 22 | # |
philpem@5 | 23 | # As a counterpart to the access to the source code and rights to copy, |
philpem@5 | 24 | # modify and redistribute granted by the license, users are provided only |
philpem@5 | 25 | # with a limited warranty and the software's author, the holder of the |
philpem@5 | 26 | # economic rights, and the successive licensors have only limited |
philpem@5 | 27 | # liability. |
philpem@5 | 28 | # |
philpem@5 | 29 | # In this respect, the user's attention is drawn to the risks associated |
philpem@5 | 30 | # with loading, using, modifying and/or developing or reproducing the |
philpem@5 | 31 | # software by the user in light of its specific status of free software, |
philpem@5 | 32 | # that may mean that it is complicated to manipulate, and that also |
philpem@5 | 33 | # therefore means that it is reserved for developers and experienced |
philpem@5 | 34 | # professionals having in-depth computer knowledge. Users are therefore |
philpem@5 | 35 | # encouraged to load and test the software's suitability as regards their |
philpem@5 | 36 | # requirements in conditions enabling the security of their systems and/or |
philpem@5 | 37 | # data to be ensured and, more generally, to use and operate it in the |
philpem@5 | 38 | # same conditions as regards security. |
philpem@5 | 39 | # |
philpem@5 | 40 | # The fact that you are presently reading this means that you have had |
philpem@5 | 41 | # knowledge of the CeCILL license and that you accept its terms. |
philpem@5 | 42 | # |
philpem@5 | 43 | */ |
philpem@5 | 44 | |
philpem@5 | 45 | // Add specific G'MIC methods to the CImg<T> class. |
philpem@5 | 46 | //------------------------------------------------- |
philpem@5 | 47 | #ifdef cimg_plugin |
philpem@5 | 48 | |
philpem@5 | 49 | template<typename t> |
philpem@5 | 50 | CImg<T> get_replace(const CImg<t>& img) const { |
philpem@5 | 51 | return +img; |
philpem@5 | 52 | } |
philpem@5 | 53 | |
philpem@5 | 54 | template<typename t> |
philpem@5 | 55 | CImg<T>& replace(CImg<t>& img) { |
philpem@5 | 56 | return img.transfer_to(*this); |
philpem@5 | 57 | } |
philpem@5 | 58 | |
philpem@5 | 59 | CImg<T>& gmic_set(const double value, const int x, const int y, const int z, const int v) { |
philpem@5 | 60 | (*this).atXYZV(x,y,z,v,0) = (T)value; |
philpem@5 | 61 | return *this; |
philpem@5 | 62 | } |
philpem@5 | 63 | |
philpem@5 | 64 | CImg<T> get_gmic_set(const double value, const int x, const int y, const int z, const int v) const { |
philpem@5 | 65 | return (+*this).gmic_set(value,x,y,z,v); |
philpem@5 | 66 | } |
philpem@5 | 67 | |
philpem@5 | 68 | CImg<T> get_draw_point(const int x, const int y, const int z, |
philpem@5 | 69 | const CImg<T>& col, const float opacity) const { |
philpem@5 | 70 | return (+*this).draw_point(x,y,z,col,opacity); |
philpem@5 | 71 | } |
philpem@5 | 72 | |
philpem@5 | 73 | CImg<T> get_draw_line(const int x0, const int y0, const int x1, const int y1, |
philpem@5 | 74 | const CImg<T>& col, const float opacity) const { |
philpem@5 | 75 | return (+*this).draw_line(x0,y0,x1,y1,col,opacity); |
philpem@5 | 76 | } |
philpem@5 | 77 | |
philpem@5 | 78 | template<typename t> |
philpem@5 | 79 | CImg<T> get_draw_polygon(const CImg<t>& pts, const CImg<T>& col, const float opacity) const { |
philpem@5 | 80 | return (+*this).draw_polygon(pts,col,opacity); |
philpem@5 | 81 | } |
philpem@5 | 82 | |
philpem@5 | 83 | CImg<T> get_draw_ellipse(const int x, const int y, const float r0, const float r1, |
philpem@5 | 84 | const float ru, const float rv, const CImg<T>& col, const float opacity) const { |
philpem@5 | 85 | return (+*this).draw_ellipse(x,y,r0,r1,ru,rv,col,opacity); |
philpem@5 | 86 | } |
philpem@5 | 87 | |
philpem@5 | 88 | CImg<T> get_draw_text(const int x, const int y, const char *const text, const T *const col, |
philpem@5 | 89 | const int bg, const float opacity,const int siz) const { |
philpem@5 | 90 | return (+*this).draw_text(x,y,text,col,bg,opacity,siz); |
philpem@5 | 91 | } |
philpem@5 | 92 | |
philpem@5 | 93 | CImg<T> get_draw_image(const int x, const int y, const int z, |
philpem@5 | 94 | const CImg<T>& sprite, const CImg<T>& mask, const float opacity) const { |
philpem@5 | 95 | return (+*this).draw_image(x,y,z,sprite,mask,opacity); |
philpem@5 | 96 | } |
philpem@5 | 97 | |
philpem@5 | 98 | CImg<T> get_draw_image(const int x, const int y, const int z, |
philpem@5 | 99 | const CImg<T>& sprite, const float opacity) const { |
philpem@5 | 100 | return (+*this).draw_image(x,y,z,sprite,opacity); |
philpem@5 | 101 | } |
philpem@5 | 102 | |
philpem@5 | 103 | CImg<T> get_draw_plasma(const float alpha, const float beta, const float opacity) const { |
philpem@5 | 104 | return (+*this).draw_plasma(alpha,beta,opacity); |
philpem@5 | 105 | } |
philpem@5 | 106 | |
philpem@5 | 107 | CImg<T> get_draw_mandelbrot(const CImg<T>& color_palette, const float opacity, |
philpem@5 | 108 | const double z0r, const double z0i, const double z1r, const double z1i, |
philpem@5 | 109 | const unsigned int itermax, const bool normalized_iteration, |
philpem@5 | 110 | const bool julia_set, const double paramr, const double parami) const { |
philpem@5 | 111 | return (+*this).draw_mandelbrot(color_palette,opacity,z0r,z0i,z1r,z1i,itermax, |
philpem@5 | 112 | normalized_iteration,julia_set,paramr,parami); |
philpem@5 | 113 | } |
philpem@5 | 114 | |
philpem@5 | 115 | CImg<T> get_draw_fill(const int x, const int y, const int z, |
philpem@5 | 116 | const CImg<T>& col, const float opacity, const float tolerance) const { |
philpem@5 | 117 | return (+*this).draw_fill(x,y,z,col,opacity,tolerance); |
philpem@5 | 118 | } |
philpem@5 | 119 | |
philpem@5 | 120 | bool is_CImg3d() const { |
philpem@5 | 121 | const bool is_header = (width==1 && height>=8 && depth==1 && dim==1 && |
philpem@5 | 122 | (*this)[0]=='C'+0.5f && (*this)[1]=='I'+0.5f && |
philpem@5 | 123 | (*this)[2]=='m'+0.5f && (*this)[3]=='g'+0.5f && |
philpem@5 | 124 | (*this)[4]=='3'+0.5f && (*this)[5]=='d'+0.5f); |
philpem@5 | 125 | if (!is_header) return false; |
philpem@5 | 126 | const int |
philpem@5 | 127 | nbv = (int)(*this)[6], |
philpem@5 | 128 | nbp = (int)(*this)[7]; |
philpem@5 | 129 | if (nbv<=0 || nbp<=0) return false; |
philpem@5 | 130 | const T *ptrs = ptr() + 8 + 3*nbv, *const ptre = end(); |
philpem@5 | 131 | if (ptrs>=ptre) return false; |
philpem@5 | 132 | for (int i = 0; i<nbp && ptrs<ptre; ++i) { |
philpem@5 | 133 | const int N = (int)*(ptrs++); |
philpem@5 | 134 | if (N<=0 || N>=8) return false; |
philpem@5 | 135 | ptrs+=N; |
philpem@5 | 136 | } |
philpem@5 | 137 | ptrs+=4*nbp; |
philpem@5 | 138 | if (ptrs>ptre) return false; |
philpem@5 | 139 | return true; |
philpem@5 | 140 | } |
philpem@5 | 141 | |
philpem@5 | 142 | template<typename tp, typename tf, typename tc, typename to> |
philpem@5 | 143 | CImg<T> get_draw_object3d(const float x0, const float y0, const float z0, |
philpem@5 | 144 | const CImg<tp>& points, const CImgList<tf>& primitives, |
philpem@5 | 145 | const CImgList<tc>& colors, const CImg<to>& opacities, |
philpem@5 | 146 | const unsigned int render_type, const bool double_sided, |
philpem@5 | 147 | const float focale, const float lightx, const float lighty, |
philpem@5 | 148 | const float lightz, const float specular_light, const float specular_shine, |
philpem@5 | 149 | float *const zbuffer) const { |
philpem@5 | 150 | return (+*this).draw_object3d(x0,y0,z0,points,primitives,colors,opacities,render_type,double_sided,focale, |
philpem@5 | 151 | lightx,lighty,lightz,specular_light,specular_shine,zbuffer); |
philpem@5 | 152 | } |
philpem@5 | 153 | |
philpem@5 | 154 | template<typename tp, typename tc, typename to> |
philpem@5 | 155 | CImg<T>& object3dtoCImg3d(CImgList<tp>& primitives, CImgList<tc>& colors, CImg<to>& opacities) { |
philpem@5 | 156 | if (is_empty() || !primitives) { primitives.assign(); colors.assign(); opacities.assign(); return *this; } |
philpem@5 | 157 | const unsigned int primitives_size = primitives.size; |
philpem@5 | 158 | CImgList<floatT> res; |
philpem@5 | 159 | res.insert(CImg<floatT>("CImg3d",1,6,1,1,false)+=0.5f); |
philpem@5 | 160 | res.insert(CImg<floatT>::vector((float)width,(float)primitives.size)); |
philpem@5 | 161 | res.insert(1); resize(-100,3,1,1,0).transpose().unroll('y').transfer_to(res.last()); |
philpem@5 | 162 | cimglist_for(primitives,p) { |
philpem@5 | 163 | res.insert(CImg<floatT>::vector((float)primitives[p].size())).insert(primitives[p]).last().unroll('y'); |
philpem@5 | 164 | primitives[p].assign(); |
philpem@5 | 165 | } |
philpem@5 | 166 | primitives.assign(); |
philpem@5 | 167 | const unsigned int defined_colors = colors.size; |
philpem@5 | 168 | cimglist_for(colors,c) { res.insert(colors[c]).last().resize(1,3,1,1,-1); colors[c].assign(); } |
philpem@5 | 169 | colors.assign(); |
philpem@5 | 170 | if (defined_colors<primitives_size) res.insert(1).last().assign(1,3*(primitives_size-defined_colors),1,1,200); |
philpem@5 | 171 | const unsigned int defined_opacities = opacities.size(); |
philpem@5 | 172 | res.insert(opacities).last().unroll('y'); |
philpem@5 | 173 | opacities.assign(); |
philpem@5 | 174 | if (defined_opacities<primitives.size) res.insert(1).last().assign(1,primitives_size-defined_opacities,1,1,1); |
philpem@5 | 175 | return res.get_append('y').transfer_to(*this); |
philpem@5 | 176 | } |
philpem@5 | 177 | |
philpem@5 | 178 | template<typename tp, typename tc, typename to> |
philpem@5 | 179 | CImg<T>& CImg3dtoobject3d(CImgList<tp>& primitives, CImgList<tc>& colors, CImg<to>& opacities) { |
philpem@5 | 180 | const T *ptrs = ptr() + 6; |
philpem@5 | 181 | const unsigned int |
philpem@5 | 182 | nbv = (unsigned int)*(ptrs++), |
philpem@5 | 183 | nbp = (unsigned int)*(ptrs++); |
philpem@5 | 184 | CImg<T> points(nbv,3); |
philpem@5 | 185 | primitives.assign(nbp); |
philpem@5 | 186 | colors.assign(nbp,1,3,1,1); |
philpem@5 | 187 | opacities.assign(nbp); |
philpem@5 | 188 | cimg_forX(points,x) { points(x,0) = (T)*(ptrs++); points(x,1) = (T)*(ptrs++); points(x,2) = (T)*(ptrs++); } |
philpem@5 | 189 | cimglist_for(primitives,p) { |
philpem@5 | 190 | const unsigned int N = (unsigned int)*(ptrs++); |
philpem@5 | 191 | primitives[p].assign(ptrs,1,N,1,1,false); |
philpem@5 | 192 | ptrs+=N; |
philpem@5 | 193 | } |
philpem@5 | 194 | cimglist_for(colors,c) { colors(c,0) = (tc)*(ptrs++); colors(c,1) = (tc)*(ptrs++); colors(c,2) = (tc)*(ptrs++); } |
philpem@5 | 195 | opacities.assign(ptrs,1,nbp,1,1,false); |
philpem@5 | 196 | return assign(points); |
philpem@5 | 197 | } |
philpem@5 | 198 | |
philpem@5 | 199 | CImg<T> get_appendCImg3d(const CImg<T>& img) const { |
philpem@5 | 200 | CImg<T> res(1,img.size() + size() - 8); |
philpem@5 | 201 | const T *ptrs = ptr() + 6, *ptrs0 = img.ptr() + 6; |
philpem@5 | 202 | T *ptrd = res.ptr(); |
philpem@5 | 203 | *(ptrd++) = (T)('C' + 0.5f); *(ptrd++) = (T)('I' + 0.5f); |
philpem@5 | 204 | *(ptrd++) = (T)('m' + 0.5f); *(ptrd++) = (T)('g' + 0.5f); |
philpem@5 | 205 | *(ptrd++) = (T)('3' + 0.5f); *(ptrd++) = (T)('d' + 0.5f); |
philpem@5 | 206 | const unsigned int |
philpem@5 | 207 | nbv = (unsigned int)*(ptrs++), |
philpem@5 | 208 | nbv0 = (unsigned int)*(ptrs0++), |
philpem@5 | 209 | nbp = (unsigned int)*(ptrs++), |
philpem@5 | 210 | nbp0 = (unsigned int)*(ptrs0++); |
philpem@5 | 211 | *(ptrd++) = (T)(nbv + nbv0); |
philpem@5 | 212 | *(ptrd++) = (T)(nbp + nbp0); |
philpem@5 | 213 | std::memcpy(ptrd,ptrs,sizeof(T)*nbv*3); |
philpem@5 | 214 | ptrd+=3*nbv; ptrs+=3*nbv; |
philpem@5 | 215 | std::memcpy(ptrd,ptrs0,sizeof(T)*nbv0*3); |
philpem@5 | 216 | ptrd+=3*nbv0; ptrs0+=3*nbv0; |
philpem@5 | 217 | for (unsigned int i = 0; i<nbp; ++i) { |
philpem@5 | 218 | const unsigned int N = (unsigned int)*(ptrs++); |
philpem@5 | 219 | *(ptrd++) = (T)N; |
philpem@5 | 220 | std::memcpy(ptrd,ptrs,sizeof(T)*N); |
philpem@5 | 221 | ptrd+=N; ptrs+=N; |
philpem@5 | 222 | } |
philpem@5 | 223 | for (unsigned int i = 0; i<nbp0; ++i) { |
philpem@5 | 224 | const unsigned int N = (unsigned int)*(ptrs0++); |
philpem@5 | 225 | *(ptrd++) = (T)N; |
philpem@5 | 226 | for (unsigned int j = 0; j<N; ++j) *(ptrd++) = (T)(*(ptrs0++) + nbv); |
philpem@5 | 227 | } |
philpem@5 | 228 | std::memcpy(ptrd,ptrs,sizeof(T)*nbp*3); |
philpem@5 | 229 | ptrd+=3*nbp; ptrs+=3*nbp; |
philpem@5 | 230 | std::memcpy(ptrd,ptrs0,sizeof(T)*nbp0*3); |
philpem@5 | 231 | ptrd+=3*nbp0; ptrs0+=3*nbp0; |
philpem@5 | 232 | std::memcpy(ptrd,ptrs,sizeof(T)*nbp); |
philpem@5 | 233 | ptrd+=nbp; |
philpem@5 | 234 | std::memcpy(ptrd,ptrs0,sizeof(T)*nbp0); |
philpem@5 | 235 | return res; |
philpem@5 | 236 | } |
philpem@5 | 237 | |
philpem@5 | 238 | CImg<T>& appendCImg3d(const CImg<T>& img) { |
philpem@5 | 239 | return get_appendCImg3d(img).transfer_to(*this); |
philpem@5 | 240 | } |
philpem@5 | 241 | |
philpem@5 | 242 | CImg<T>& centerCImg3d() { |
philpem@5 | 243 | const unsigned int nbv = (unsigned int)(*this)[6]; |
philpem@5 | 244 | const T *ptrs = ptr() + 8; |
philpem@5 | 245 | float xm = cimg::type<float>::max(), ym = xm, zm = xm, xM = cimg::type<float>::min(), yM = xM, zM = xM; |
philpem@5 | 246 | for (unsigned int i = 0; i<nbv; ++i) { |
philpem@5 | 247 | const float x = (float)*(ptrs++), y = (float)*(ptrs++), z = (float)*(ptrs++); |
philpem@5 | 248 | if (x<xm) xm = x; if (x>xM) xM = x; |
philpem@5 | 249 | if (y<ym) ym = y; if (y>yM) yM = y; |
philpem@5 | 250 | if (z<zm) zm = z; if (z>zM) zM = z; |
philpem@5 | 251 | } |
philpem@5 | 252 | const float xc = (xm + xM)/2, yc = (ym + yM)/2, zc = (zm + zM)/2; |
philpem@5 | 253 | T *ptrd = ptr() + 8; |
philpem@5 | 254 | for (unsigned int i = 0; i<nbv; ++i) { *(ptrd++)-=(T)xc; *(ptrd++)-=(T)yc; *(ptrd++)-=(T)zc; } |
philpem@5 | 255 | return *this; |
philpem@5 | 256 | } |
philpem@5 | 257 | |
philpem@5 | 258 | CImg<T> get_centerCImg3d() const { |
philpem@5 | 259 | return (+*this).centerCImg3d(); |
philpem@5 | 260 | } |
philpem@5 | 261 | |
philpem@5 | 262 | CImg<T>& normalizeCImg3d() { |
philpem@5 | 263 | const unsigned int nbv = (unsigned int)(*this)[6]; |
philpem@5 | 264 | const T *ptrs = ptr() + 8; |
philpem@5 | 265 | float xm = cimg::type<float>::max(), ym = xm, zm = xm, xM = cimg::type<float>::min(), yM = xM, zM = xM; |
philpem@5 | 266 | for (unsigned int i = 0; i<nbv; ++i) { |
philpem@5 | 267 | const float x = (float)*(ptrs++), y = (float)*(ptrs++), z = (float)*(ptrs++); |
philpem@5 | 268 | if (x<xm) xm = x; if (x>xM) xM = x; |
philpem@5 | 269 | if (y<ym) ym = y; if (y>yM) yM = y; |
philpem@5 | 270 | if (z<zm) zm = z; if (z>zM) zM = z; |
philpem@5 | 271 | } |
philpem@5 | 272 | const float delta = cimg::max(xM-xm,yM-ym,zM-zm); |
philpem@5 | 273 | if (delta>0) { |
philpem@5 | 274 | T *ptrd = ptr() + 8; |
philpem@5 | 275 | for (unsigned int i = 0; i<3*nbv; ++i) *(ptrd++)/=(T)delta; |
philpem@5 | 276 | } |
philpem@5 | 277 | return *this; |
philpem@5 | 278 | } |
philpem@5 | 279 | |
philpem@5 | 280 | CImg<T> get_normalizeCImg3d() const { |
philpem@5 | 281 | return (+*this).normalizeCImg3d(); |
philpem@5 | 282 | } |
philpem@5 | 283 | |
philpem@5 | 284 | template<typename t> |
philpem@5 | 285 | CImg<T>& rotateCImg3d(const CImg<t>& rot) { |
philpem@5 | 286 | const unsigned int nbv = (unsigned int)(*this)[6]; |
philpem@5 | 287 | const T *ptrs = ptr() + 8; |
philpem@5 | 288 | const float |
philpem@5 | 289 | a = (float)rot(0,0), b = (float)rot(1,0), c = (float)rot(2,0), |
philpem@5 | 290 | d = (float)rot(0,1), e = (float)rot(1,1), f = (float)rot(2,1), |
philpem@5 | 291 | g = (float)rot(0,2), h = (float)rot(1,2), i = (float)rot(2,2); |
philpem@5 | 292 | T *ptrd = ptr() + 8; |
philpem@5 | 293 | for (unsigned int j = 0; j<nbv; ++j) { |
philpem@5 | 294 | const float x = (float)*(ptrs++), y = (float)*(ptrs++), z = (float)*(ptrs++); |
philpem@5 | 295 | *(ptrd++) = (T)(a*x + b*y + c*z); |
philpem@5 | 296 | *(ptrd++) = (T)(d*x + e*y + f*z); |
philpem@5 | 297 | *(ptrd++) = (T)(g*x + h*y + i*z); |
philpem@5 | 298 | } |
philpem@5 | 299 | return *this; |
philpem@5 | 300 | } |
philpem@5 | 301 | |
philpem@5 | 302 | template<typename t> |
philpem@5 | 303 | CImg<T> get_rotateCImg3d(const CImg<t>& rot) const { |
philpem@5 | 304 | return (+*this).rotateCImg3d(rot); |
philpem@5 | 305 | } |
philpem@5 | 306 | |
philpem@5 | 307 | CImg<T>& translateCImg3d(const float tx, const float ty, const float tz) { |
philpem@5 | 308 | const unsigned int nbv = (unsigned int)(*this)[6]; |
philpem@5 | 309 | T *ptrd = ptr() + 8; |
philpem@5 | 310 | for (unsigned int j = 0; j<nbv; ++j) { *(ptrd++) += (T)tx; *(ptrd++) += (T)ty; *(ptrd++) += (T)tz; } |
philpem@5 | 311 | return *this; |
philpem@5 | 312 | } |
philpem@5 | 313 | |
philpem@5 | 314 | CImg<T> get_translateCImg3d(const float tx, const float ty, const float tz) const { |
philpem@5 | 315 | return (+*this).translateCImg3d(tx,ty,tz); |
philpem@5 | 316 | } |
philpem@5 | 317 | |
philpem@5 | 318 | CImg<T>& coloropacityCImg3d(const float R, const float G, const float B, const float opacity, const bool set_RGB, const bool set_opacity) { |
philpem@5 | 319 | T *ptrd = ptr() + 6; |
philpem@5 | 320 | const unsigned int |
philpem@5 | 321 | nbv = (unsigned int)*(ptrd++), |
philpem@5 | 322 | nbp = (unsigned int)*(ptrd++); |
philpem@5 | 323 | ptrd+=3*nbv; |
philpem@5 | 324 | for (unsigned int i = 0; i<nbp; ++i) { const unsigned int N = (unsigned int)*(ptrd++); ptrd+=N; } |
philpem@5 | 325 | if (set_RGB) for (unsigned int c = 0; c<nbp; ++c) { *(ptrd++) = (T)R; *(ptrd++) = (T)G; *(ptrd++) = (T)B; } else ptrd+=3*nbp; |
philpem@5 | 326 | if (set_opacity) for (unsigned int o = 0; o<nbp; ++o) *(ptrd++) = (T)opacity; |
philpem@5 | 327 | return *this; |
philpem@5 | 328 | } |
philpem@5 | 329 | |
philpem@5 | 330 | 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 { |
philpem@5 | 331 | return (+*this).coloropacityCImg3d(R,G,B,opacity,set_RGB,set_opacity); |
philpem@5 | 332 | } |
philpem@5 | 333 | |
philpem@5 | 334 | #else // eq. to #ifndef cimg_plugin |
philpem@5 | 335 | |
philpem@5 | 336 | #define cimg_debug 1 |
philpem@5 | 337 | #ifndef cimg_gmic_cpp |
philpem@5 | 338 | #define cimg_gmic_cpp "examples/gmic.cpp" |
philpem@5 | 339 | #define cimg_cimg_h "../CImg.h" |
philpem@5 | 340 | #endif |
philpem@5 | 341 | #define cimg_stdout stdout |
philpem@5 | 342 | #define cimg_plugin cimg_gmic_cpp |
philpem@5 | 343 | #include cimg_cimg_h |
philpem@5 | 344 | #include "gmic.h" |
philpem@5 | 345 | using namespace cimg_library; |
philpem@5 | 346 | |
philpem@5 | 347 | // The lines below are necessary when using a non-standard compiler such as visualcpp6. |
philpem@5 | 348 | #ifdef cimg_use_visualcpp6 |
philpem@5 | 349 | #define std |
philpem@5 | 350 | #endif |
philpem@5 | 351 | #ifdef min |
philpem@5 | 352 | #undef min |
philpem@5 | 353 | #undef max |
philpem@5 | 354 | #endif |
philpem@5 | 355 | |
philpem@5 | 356 | #if !defined(gmic_main) || !defined(gmic_separate_compilation) |
philpem@5 | 357 | |
philpem@5 | 358 | // Define some useful macros. |
philpem@5 | 359 | //--------------------------- |
philpem@5 | 360 | |
philpem@5 | 361 | // Code for validity checking of indices. |
philpem@5 | 362 | #define gmic_inds indices2string(indices,true) |
philpem@5 | 363 | #define gmic_check_indice(ind,funcname) { \ |
philpem@5 | 364 | const int indo = (int)ind; \ |
philpem@5 | 365 | if (ind<0) ind+=images.size; \ |
philpem@5 | 366 | if (ind<0 || ind>=(int)images.size) { \ |
philpem@5 | 367 | if (images.size) error(funcname " : Invalid indice '[%d]' (valid indice range is -%u...%u).",gmic_inds,indo,images.size,images.size-1); \ |
philpem@5 | 368 | else error(funcname " : Invalid indice '[%d]' (image list is empty).",gmic_inds,indo); \ |
philpem@5 | 369 | } \ |
philpem@5 | 370 | } |
philpem@5 | 371 | |
philpem@5 | 372 | // Code for having 'get' or 'non-get' versions of G'MIC commands. |
philpem@5 | 373 | #define gmic_apply(instance,function) { \ |
philpem@5 | 374 | if (get_version) { \ |
philpem@5 | 375 | unsigned int posi = 0; \ |
philpem@5 | 376 | if (images.contains(instance,posi)) filenames.insert(filenames[posi]); \ |
philpem@5 | 377 | else filenames.insert(CImg<char>("(gmic)",7,1,1,1,false)); \ |
philpem@5 | 378 | CImg<T> res = instance.get_##function; \ |
philpem@5 | 379 | images.insert(1); res.transfer_to(images.last()); \ |
philpem@5 | 380 | } else instance.function; \ |
philpem@5 | 381 | } |
philpem@5 | 382 | |
philpem@5 | 383 | // Code for simple commands that has no parameters and act on images. |
philpem@5 | 384 | #define gmic_simple_item(option,function,description) \ |
philpem@5 | 385 | if (!cimg::strcmp(option,item0)) { \ |
philpem@5 | 386 | print(description,gmic_inds); cimg_foroff(indices,l) gmic_apply(images[indices[l]],function()); \ |
philpem@5 | 387 | continue; \ |
philpem@5 | 388 | } |
philpem@5 | 389 | |
philpem@5 | 390 | // Code for the type cast command. |
philpem@5 | 391 | #define gmic_cast(pixel_type,st_type) \ |
philpem@5 | 392 | if (!cimg::strcmp(#pixel_type,argument)) { \ |
philpem@5 | 393 | print("Set pixel type to '%s'.",#pixel_type); ++position; \ |
philpem@5 | 394 | if (!cimg::strcmp(st_type,cimg::type<T>::string())) continue; \ |
philpem@5 | 395 | CImgList<pixel_type> casted_images; \ |
philpem@5 | 396 | while (images) { casted_images.insert(images[0]); images.remove(0); } \ |
philpem@5 | 397 | return parse_##pixel_type(casted_images); \ |
philpem@5 | 398 | } |
philpem@5 | 399 | |
philpem@5 | 400 | // Code for G'MIC arithmetic commands. |
philpem@5 | 401 | #define gmic_arithmetic_item(option1,option2,\ |
philpem@5 | 402 | function1,description1,arg1_1,arg1_2,value_type1, \ |
philpem@5 | 403 | function2,description2_1,description2_2,arg2_1,arg2_2,description3) \ |
philpem@5 | 404 | if (!cimg::strcmp(option1,item0) || !cimg::strcmp(option2,item0)) { \ |
philpem@5 | 405 | double value = 0; char inds[4096] = { 0 }, sep = 0, end = 0; \ |
philpem@5 | 406 | if (std::sscanf(argument,"%lf%c",&value,&end)==1) { \ |
philpem@5 | 407 | print(description1 ".",arg1_1,arg1_2); \ |
philpem@5 | 408 | cimg_foroff(indices,l) \ |
philpem@5 | 409 | if (get_version) { \ |
philpem@5 | 410 | images.insert(images[indices[l]]); images.last().function1((value_type1)value); \ |
philpem@5 | 411 | filenames.insert(filenames[indices[l]]); } \ |
philpem@5 | 412 | else images[indices[l]].function1((value_type1)value); \ |
philpem@5 | 413 | ++position; \ |
philpem@5 | 414 | } else if (std::sscanf(argument,"[%4095[0-9.eE%+-]%c%c",inds,&sep,&end)==2 && sep==']') { \ |
philpem@5 | 415 | const CImg<unsigned int> ind = indices2cimg(inds,images.size,option1); \ |
philpem@5 | 416 | if (ind.size()!=1) error(description2_1 " : Argument '[%s]' should contain one indice.",gmic_inds,inds); \ |
philpem@5 | 417 | print(description2_2 ".",arg2_1,arg2_2); \ |
philpem@5 | 418 | const CImg<T> img0 = images[ind[0]]; \ |
philpem@5 | 419 | cimg_foroff(indices,l) \ |
philpem@5 | 420 | if (get_version) { \ |
philpem@5 | 421 | images.insert(images[indices[l]]); images.last().function2(img0); \ |
philpem@5 | 422 | filenames.insert(filenames[indices[l]]); } \ |
philpem@5 | 423 | else images[indices[l]].function2(img0); \ |
philpem@5 | 424 | ++position; \ |
philpem@5 | 425 | } else { \ |
philpem@5 | 426 | print(description3 ".",gmic_inds); \ |
philpem@5 | 427 | if (images && indices) { \ |
philpem@5 | 428 | for (unsigned int siz = indices.size(), ind0 = indices[0], off = 0, l = 1; l<siz; ++l) { \ |
philpem@5 | 429 | const unsigned int ind = indices[l] - off; \ |
philpem@5 | 430 | images[ind0].function2(images[ind]); \ |
philpem@5 | 431 | images.remove(ind); filenames.remove(ind); \ |
philpem@5 | 432 | ++off; \ |
philpem@5 | 433 | }}} continue; \ |
philpem@5 | 434 | } |
philpem@5 | 435 | |
philpem@5 | 436 | // Constructors. |
philpem@5 | 437 | //-------------- |
philpem@5 | 438 | #if defined(gmic_float) || !defined(gmic_separate_compilation) |
philpem@5 | 439 | |
philpem@5 | 440 | #include "gmic_def.h" |
philpem@5 | 441 | |
philpem@5 | 442 | gmic_exception::gmic_exception() { |
philpem@5 | 443 | message[0] = '\0'; |
philpem@5 | 444 | } |
philpem@5 | 445 | |
philpem@5 | 446 | gmic_exception::gmic_exception(const char *format, ...) { |
philpem@5 | 447 | std::va_list ap; |
philpem@5 | 448 | va_start(ap,format); |
philpem@5 | 449 | std::vsprintf(message,format,ap); |
philpem@5 | 450 | va_end(ap); |
philpem@5 | 451 | } |
philpem@5 | 452 | |
philpem@5 | 453 | gmic_exception::gmic_exception(const char *format, std::va_list ap) { |
philpem@5 | 454 | std::vsprintf(message,format,ap); |
philpem@5 | 455 | } |
philpem@5 | 456 | |
philpem@5 | 457 | gmic::gmic() { |
philpem@5 | 458 | assign(0); |
philpem@5 | 459 | } |
philpem@5 | 460 | |
philpem@5 | 461 | // Set default values of G'MIC parameters and macros. |
philpem@5 | 462 | //---------------------------------------------------- |
philpem@5 | 463 | gmic& gmic::assign(const unsigned int size, const char *const custom_macros, const bool add_macros_start) { |
philpem@5 | 464 | filenames.assign(size,CImg<char>("(gmic)",7,1,1,1,false)); |
philpem@5 | 465 | position = 0; |
philpem@5 | 466 | verbosity_level = 0; |
philpem@5 | 467 | is_released = true; |
philpem@5 | 468 | is_debug = false; |
philpem@5 | 469 | is_begin = true; |
philpem@5 | 470 | background3d[0] = 120; |
philpem@5 | 471 | background3d[1] = 120; |
philpem@5 | 472 | background3d[2] = 140; |
philpem@5 | 473 | render3d = 4; |
philpem@5 | 474 | renderd3d = -1; |
philpem@5 | 475 | is_oriented3d = false; |
philpem@5 | 476 | focale3d = 500; |
philpem@5 | 477 | light3d_x = 0; |
philpem@5 | 478 | light3d_y = 0; |
philpem@5 | 479 | light3d_z = -5000; |
philpem@5 | 480 | specular_light3d = 0.15f; |
philpem@5 | 481 | specular_shine3d = 0.8f; |
philpem@5 | 482 | is_fullpath = false; |
philpem@5 | 483 | add_macros(data_def,sizeof(data_def)-1,true); |
philpem@5 | 484 | add_macros(custom_macros,cimg::strlen(custom_macros)-1,add_macros_start); |
philpem@5 | 485 | return *this; |
philpem@5 | 486 | } |
philpem@5 | 487 | |
philpem@5 | 488 | // Error procedure. |
philpem@5 | 489 | //----------------- |
philpem@5 | 490 | const gmic& gmic::error(const char *format, ...) const { |
philpem@5 | 491 | va_list ap; |
philpem@5 | 492 | va_start(ap,format); |
philpem@5 | 493 | char message[1024] = { 0 }; |
philpem@5 | 494 | std::vsprintf(message,format,ap); |
philpem@5 | 495 | va_end(ap); |
philpem@5 | 496 | if (verbosity_level>=0) { |
philpem@5 | 497 | std::fprintf(cimg_stdout,"\n<gmic-#%u> ** Error ** %s",filenames.size,message); |
philpem@5 | 498 | std::fprintf(cimg_stdout,"\n<gmic-#%u> Abort G'MIC instance.\n",filenames.size); |
philpem@5 | 499 | std::fflush(cimg_stdout); |
philpem@5 | 500 | } |
philpem@5 | 501 | throw gmic_exception(message); |
philpem@5 | 502 | return *this; |
philpem@5 | 503 | } |
philpem@5 | 504 | |
philpem@5 | 505 | // Warning procedure. |
philpem@5 | 506 | //------------------- |
philpem@5 | 507 | const gmic& gmic::warning(const char *format, ...) const { |
philpem@5 | 508 | va_list ap; |
philpem@5 | 509 | va_start(ap,format); |
philpem@5 | 510 | if (verbosity_level>=0) { |
philpem@5 | 511 | std::fprintf(cimg_stdout,"\n<gmic-#%u> ** Warning ** ",filenames.size); |
philpem@5 | 512 | std::vfprintf(cimg_stdout,format,ap); |
philpem@5 | 513 | std::fflush(cimg_stdout); |
philpem@5 | 514 | } |
philpem@5 | 515 | va_end(ap); |
philpem@5 | 516 | return *this; |
philpem@5 | 517 | } |
philpem@5 | 518 | |
philpem@5 | 519 | // Print debug messages. |
philpem@5 | 520 | //---------------------- |
philpem@5 | 521 | const gmic& gmic::debug(const char *format, ...) const { |
philpem@5 | 522 | const char t_normal[] = { 0x1b,'[','0',';','0',';','0','m','\0' }; |
philpem@5 | 523 | const char t_red[] = { 0x1b,'[','4',';','3','1',';','5','9','m','\0' }; |
philpem@5 | 524 | const char t_bold[] = { 0x1b,'[','1','m','\0' }; |
philpem@5 | 525 | if (is_debug) { |
philpem@5 | 526 | va_list ap; |
philpem@5 | 527 | va_start(ap,format); |
philpem@5 | 528 | std::fprintf(cimg_stdout,"\n%s%s<gmic-debug-#%u>%s ",t_bold,t_red,filenames.size,t_normal); |
philpem@5 | 529 | std::vfprintf(cimg_stdout,format,ap); |
philpem@5 | 530 | va_end(ap); |
philpem@5 | 531 | std::fflush(cimg_stdout); |
philpem@5 | 532 | } |
philpem@5 | 533 | return *this; |
philpem@5 | 534 | } |
philpem@5 | 535 | |
philpem@5 | 536 | // Print status messages. |
philpem@5 | 537 | //----------------------- |
philpem@5 | 538 | const gmic& gmic::print(const char *format, ...) const { |
philpem@5 | 539 | va_list ap; |
philpem@5 | 540 | va_start(ap,format); |
philpem@5 | 541 | if (verbosity_level>=0) { |
philpem@5 | 542 | std::fprintf(cimg_stdout,"\n<gmic-#%u> ",filenames.size); |
philpem@5 | 543 | std::vfprintf(cimg_stdout,format,ap); |
philpem@5 | 544 | std::fflush(cimg_stdout); |
philpem@5 | 545 | } |
philpem@5 | 546 | va_end(ap); |
philpem@5 | 547 | return *this; |
philpem@5 | 548 | } |
philpem@5 | 549 | |
philpem@5 | 550 | // Add macros from a char* buffer. |
philpem@5 | 551 | //--------------------------------- |
philpem@5 | 552 | gmic& gmic::add_macros(const char *const data_macros, const unsigned int data_size, const bool add_macros_at_start) { |
philpem@5 | 553 | if (!data_macros || !data_size) return *this; |
philpem@5 | 554 | char mac[4096] = { 0 }, com[256*1024] = { 0 }, line[256*1024] = { 0 }, sep = 0; |
philpem@5 | 555 | const char *data = data_macros, *const data_end = data_macros + data_size; |
philpem@5 | 556 | while (data<data_end) { |
philpem@5 | 557 | if (*data=='\n') ++data; |
philpem@5 | 558 | else { |
philpem@5 | 559 | if (std::sscanf(data,"%262143[^\n]",line)>0) data += cimg::strlen(line) + 1; |
philpem@5 | 560 | if (line[0]!='#') { // Useful line (not a comment) |
philpem@5 | 561 | mac[0] = com[0] = 0; |
philpem@5 | 562 | if (std::sscanf(line,"%4095[^: ] %c %262143[^\n]",mac,&sep,com)>=2 && sep==':' && |
philpem@5 | 563 | std::sscanf(mac,"%4095s",line)==1) { // Macro definition. |
philpem@5 | 564 | macros.insert(CImg<char>(line,cimg::strlen(line)+1,1,1,1,false),add_macros_at_start?0:macros.size); |
philpem@5 | 565 | commands.insert(CImg<char>(com,cimg::strlen(com)+1,1,1,1,false),add_macros_at_start?0:commands.size); |
philpem@5 | 566 | } else { // Possible continuation of a previous macro definition. |
philpem@5 | 567 | if (!macros) error("Fatal error : Invalid G'MIC macros data."); |
philpem@5 | 568 | CImg<char> &last = commands[add_macros_at_start?0:commands.size-1]; |
philpem@5 | 569 | last[last.size()-1] = ' '; |
philpem@5 | 570 | last.append(CImg<char>(line,cimg::strlen(line)+1,1,1,1,false),'x'); |
philpem@5 | 571 | } |
philpem@5 | 572 | } |
philpem@5 | 573 | } |
philpem@5 | 574 | } |
philpem@5 | 575 | return *this; |
philpem@5 | 576 | } |
philpem@5 | 577 | |
philpem@5 | 578 | // Add macros from a macro file. |
philpem@5 | 579 | //------------------------------ |
philpem@5 | 580 | gmic& gmic::add_macros(std::FILE *const file, const bool add_macros_at_start) { |
philpem@5 | 581 | if (!file) return *this; |
philpem@5 | 582 | char mac[4096] = { 0 }, com[256*1024] = { 0 }, line[256*1024] = { 0 }, sep = 0; |
philpem@5 | 583 | int err = 0; |
philpem@5 | 584 | while ((err=std::fscanf(file,"%262143[^\n] ",line)>=0)) { |
philpem@5 | 585 | if (err) { // Non empty-line |
philpem@5 | 586 | mac[0] = com[0] = 0; |
philpem@5 | 587 | if (line[0]!='#') { // Useful line (not a comment). |
philpem@5 | 588 | if (std::sscanf(line,"%4095[^: ] %c %262143[^\n]",mac,&sep,com)>=2 && sep==':' && |
philpem@5 | 589 | std::sscanf(mac,"%4095s",line)==1) { // Macro definition. |
philpem@5 | 590 | macros.insert(CImg<char>(line,cimg::strlen(line)+1,1,1,1,false),add_macros_at_start?0:macros.size); |
philpem@5 | 591 | commands.insert(CImg<char>(com,cimg::strlen(com)+1,1,1,1,false),add_macros_at_start?0:commands.size); |
philpem@5 | 592 | } else { // Possible continuation of a previous macro definition. |
philpem@5 | 593 | if (!macros) error("Fatal error : Invalid G'MIC macros data."); |
philpem@5 | 594 | CImg<char> &last = commands[add_macros_at_start?0:commands.size-1]; |
philpem@5 | 595 | last[last.size()-1] = ' '; |
philpem@5 | 596 | last.append(CImg<char>(line,cimg::strlen(line)+1,1,1,1,false),'x'); |
philpem@5 | 597 | } |
philpem@5 | 598 | } |
philpem@5 | 599 | } |
philpem@5 | 600 | } |
philpem@5 | 601 | return *this; |
philpem@5 | 602 | } |
philpem@5 | 603 | |
philpem@5 | 604 | // Return indices of the images from a string. |
philpem@5 | 605 | //-------------------------------------------- |
philpem@5 | 606 | CImg<unsigned int> gmic::indices2cimg(const char *const string, const unsigned int indice_max, |
philpem@5 | 607 | const char *const command) const { |
philpem@5 | 608 | if (!cimg::strlen(string)) return CImg<unsigned int>(); |
philpem@5 | 609 | CImgList<unsigned int> inds; |
philpem@5 | 610 | const char *it = string; |
philpem@5 | 611 | for (bool stopflag = false; !stopflag; ) { |
philpem@5 | 612 | char sep = 0, end = 0, item0[4096] = { 0 }, item1[4096] = { 0 }; |
philpem@5 | 613 | float ind0 = 0, ind1 = 0, step = 1; |
philpem@5 | 614 | if (std::sscanf(it,"%4095[^,]%c",item0,&end)!=2) stopflag = true; |
philpem@5 | 615 | else it += 1 + cimg::strlen(item0); |
philpem@5 | 616 | const int err = std::sscanf(item0,"%4095[^:]%c%f%c",item1,&sep,&step,&end); |
philpem@5 | 617 | if (err!=1 && err!=3) error("Command '%s' : Invalid indice(s) '[%s]'.",command,string); |
philpem@5 | 618 | if (std::sscanf(item1,"%f%%-%f%c%c",&ind0,&ind1,&sep,&end)==3 && sep=='%') { |
philpem@5 | 619 | ind0 = (float)cimg::round(ind0*indice_max/100,1); |
philpem@5 | 620 | ind1 = (float)cimg::round(ind1*indice_max/100,1); |
philpem@5 | 621 | } else if (std::sscanf(item1,"%f%%-%f%c",&ind0,&ind1,&end)==2) |
philpem@5 | 622 | ind0 = (float)cimg::round(ind0*indice_max/100,1); |
philpem@5 | 623 | else if (std::sscanf(item1,"%f-%f%c%c",&ind0,&ind1,&sep,&end)==3 && sep=='%') |
philpem@5 | 624 | ind1 = (float)cimg::round(ind1*indice_max/100,1); |
philpem@5 | 625 | else if (std::sscanf(item1,"%f-%f%c",&ind0,&ind1,&end)==2) { } |
philpem@5 | 626 | else if (std::sscanf(item1,"%f%c%c",&ind0,&sep,&end)==2 && sep=='%') |
philpem@5 | 627 | ind1 = (ind0 = (float)cimg::round(ind0*indice_max/100,1)); |
philpem@5 | 628 | else if (std::sscanf(item1,"%f%c",&ind0,&end)==1) |
philpem@5 | 629 | ind1 = ind0; |
philpem@5 | 630 | else error("Command '%s' : Invalid indice(s) '[%s]'.",command,string); |
philpem@5 | 631 | if (ind0<0) ind0+=indice_max; |
philpem@5 | 632 | if (ind1<0) ind1+=indice_max; |
philpem@5 | 633 | if (ind0<0 || ind0>=indice_max || ind1<0 || ind1>=indice_max || step<=0) { |
philpem@5 | 634 | if (indice_max) error("Command '%s' : Invalid indice(s) '[%s]' (valid indice range is -%u...%u).", |
philpem@5 | 635 | command,string,indice_max,indice_max-1); |
philpem@5 | 636 | else error("Command '%s' : Invalid indice(s) '[%s]' (image list is empty).", |
philpem@5 | 637 | command,string); |
philpem@5 | 638 | } |
philpem@5 | 639 | if (ind0>ind1) cimg::swap(ind0,ind1); |
philpem@5 | 640 | const unsigned int |
philpem@5 | 641 | iind0 = (unsigned int)ind0, |
philpem@5 | 642 | _ind1 = (unsigned int)ind1, |
philpem@5 | 643 | iind1 = (unsigned int)(_ind1 - cimg::mod((float)_ind1,step)); |
philpem@5 | 644 | if (iind0==iind1) inds.insert(CImg<unsigned int>::vector(iind0)); |
philpem@5 | 645 | else inds.insert(CImg<unsigned int>::sequence((unsigned int)(1+(iind1-iind0)/step), |
philpem@5 | 646 | (unsigned int)iind0, |
philpem@5 | 647 | (unsigned int)iind1).get_split('y')); |
philpem@5 | 648 | } |
philpem@5 | 649 | inds = inds.get_append('y').sort().get_split('y'); |
philpem@5 | 650 | cimglist_for(inds,l) if (l!=inds.size-1 && inds(l,0)==inds(l+1,0)) inds.remove(l--); |
philpem@5 | 651 | if (is_debug) { |
philpem@5 | 652 | debug("Indices : "); |
philpem@5 | 653 | inds.get_append('y').print(); // List indices if debug mode is activated. |
philpem@5 | 654 | } |
philpem@5 | 655 | return inds.get_append('y').sort(); |
philpem@5 | 656 | } |
philpem@5 | 657 | |
philpem@5 | 658 | // Return stringified version of indices or filenames. |
philpem@5 | 659 | //---------------------------------------------------- |
philpem@5 | 660 | char* gmic::indices2string(const CImg<unsigned int>& indices, const bool display_indices) const { |
philpem@5 | 661 | static char res0[4096] = { 0 }, res1[4096] = { 0 }; |
philpem@5 | 662 | const unsigned int siz = indices.size(); |
philpem@5 | 663 | if (display_indices) { |
philpem@5 | 664 | switch (siz) { |
philpem@5 | 665 | case 0: std::sprintf(res0," []"); break; |
philpem@5 | 666 | case 1: std::sprintf(res0," [%u]",indices[0]); break; |
philpem@5 | 667 | case 2: std::sprintf(res0,"s [%u,%u]",indices[0],indices[1]); break; |
philpem@5 | 668 | case 3: std::sprintf(res0,"s [%u,%u,%u]",indices[0],indices[1],indices[2]); break; |
philpem@5 | 669 | case 4: std::sprintf(res0,"s [%u,%u,%u,%u]",indices[0],indices[1],indices[2],indices[3]); break; |
philpem@5 | 670 | default: std::sprintf(res0,"s [%u,...,%u]",indices[0],indices[siz-1]); |
philpem@5 | 671 | } |
philpem@5 | 672 | return res0; |
philpem@5 | 673 | } |
philpem@5 | 674 | switch (siz) { |
philpem@5 | 675 | case 0: std::sprintf(res1," "); break; |
philpem@5 | 676 | case 1: std::sprintf(res1,"%s",filenames[indices[0]].ptr()); break; |
philpem@5 | 677 | case 2: std::sprintf(res1,"%s, %s",filenames[indices[0]].ptr(),filenames[indices[1]].ptr()); break; |
philpem@5 | 678 | case 3: std::sprintf(res1,"%s, %s, %s",filenames[indices[0]].ptr(),filenames[indices[1]].ptr(), |
philpem@5 | 679 | filenames[indices[2]].ptr()); break; |
philpem@5 | 680 | case 4: std::sprintf(res1,"%s, %s, %s, %s",filenames[indices[0]].ptr(),filenames[indices[1]].ptr(), |
philpem@5 | 681 | filenames[indices[2]].ptr(), filenames[indices[3]].ptr()); break; |
philpem@5 | 682 | default: std::sprintf(res1,"%s, ..., %s",filenames[indices[0]].ptr(),filenames[indices[siz-1]].ptr()); |
philpem@5 | 683 | } |
philpem@5 | 684 | return res1; |
philpem@5 | 685 | } |
philpem@5 | 686 | #endif // #if defined(gmic_float) || !defined(gmic_separate_compilation) |
philpem@5 | 687 | |
philpem@5 | 688 | // Template constructors. |
philpem@5 | 689 | //----------------------- |
philpem@5 | 690 | template<typename T> |
philpem@5 | 691 | gmic::gmic(const int argc, const char *const *const argv, CImgList<T>& images, const char *custom_macros, const bool add_macros_at_start) { |
philpem@5 | 692 | assign(images.size,custom_macros,add_macros_at_start); |
philpem@5 | 693 | for (int pos = 1; pos<argc; ++pos) |
philpem@5 | 694 | command_line.insert(CImg<char>(argv[pos],cimg::strlen(argv[pos])+1,1,1,1,false)); |
philpem@5 | 695 | is_released = false; |
philpem@5 | 696 | parse(images); |
philpem@5 | 697 | } |
philpem@5 | 698 | |
philpem@5 | 699 | template<typename T> |
philpem@5 | 700 | gmic::gmic(const char *const command, CImgList<T>& images, const char *custom_macros, const bool add_macros_at_start) { |
philpem@5 | 701 | assign(images.size,custom_macros,add_macros_at_start); |
philpem@5 | 702 | char item[4096] = { 0 }; |
philpem@5 | 703 | for (const char *ncommand = command; *ncommand; ) { |
philpem@5 | 704 | if (std::sscanf(ncommand,"%[^ ]",item)==1) { |
philpem@5 | 705 | const int l = cimg::strlen(item); |
philpem@5 | 706 | command_line.insert(CImg<char>(item,l+1,1,1,1,false)); |
philpem@5 | 707 | ncommand += l; |
philpem@5 | 708 | while (*ncommand==' ') ++ncommand; |
philpem@5 | 709 | } else break; |
philpem@5 | 710 | } |
philpem@5 | 711 | is_released = true; |
philpem@5 | 712 | parse(images); |
philpem@5 | 713 | } |
philpem@5 | 714 | |
philpem@5 | 715 | // Display specified image(s). |
philpem@5 | 716 | //----------------------------- |
philpem@5 | 717 | template<typename T> |
philpem@5 | 718 | bool gmic::display_images(const CImgList<T>& images, const CImg<unsigned int>& indices, |
philpem@5 | 719 | const bool verbose) const { |
philpem@5 | 720 | if (!images || !indices) { print("Display image []."); return false; } |
philpem@5 | 721 | CImgList<unsigned int> inds = indices.get_unroll('x').get_split('x'); |
philpem@5 | 722 | CImgList<T> visu; |
philpem@5 | 723 | unsigned int max_height = 0; |
philpem@5 | 724 | cimglist_for(inds,l) { |
philpem@5 | 725 | const CImg<T>& img = images[inds(l,0)]; |
philpem@5 | 726 | if (img.height>max_height && !img.is_CImg3d()) max_height = img.height; |
philpem@5 | 727 | } |
philpem@5 | 728 | cimglist_for(inds,l) { |
philpem@5 | 729 | const unsigned int ind = inds(l,0); |
philpem@5 | 730 | const CImg<T> &img = images[ind]; |
philpem@5 | 731 | if (img) { |
philpem@5 | 732 | if (!max_height || img.height<max_height) visu.insert(img,~0U,true); |
philpem@5 | 733 | else visu.insert(img.get_lines(0,max_height-1)); |
philpem@5 | 734 | } else if (verbose) { warning("Display image : Image [%d] is empty.",ind); inds.remove(l--); } |
philpem@5 | 735 | } |
philpem@5 | 736 | const CImg<unsigned int> nindices = inds.get_append('x'); |
philpem@5 | 737 | const char *const fnames = indices2string(nindices,false); |
philpem@5 | 738 | print("Display image%s = '%s'.\n\n",gmic_inds,fnames); |
philpem@5 | 739 | if (visu.size) { |
philpem@5 | 740 | if (visu.size!=1) visu.display(fnames,verbosity_level>=0,'x','p'); |
philpem@5 | 741 | else { |
philpem@5 | 742 | const CImg<T> &img = visu[0]; |
philpem@5 | 743 | char title[4096] = { 0 }; |
philpem@5 | 744 | std::sprintf(title,"%s (%dx%dx%dx%d)",fnames,img.dimx(),img.dimy(),img.dimz(),img.dimv()); |
philpem@5 | 745 | img.display(title,verbosity_level>=0); |
philpem@5 | 746 | } |
philpem@5 | 747 | } |
philpem@5 | 748 | return true; |
philpem@5 | 749 | } |
philpem@5 | 750 | |
philpem@5 | 751 | // Display plots of specified image(s). |
philpem@5 | 752 | //-------------------------------------- |
philpem@5 | 753 | template<typename T> |
philpem@5 | 754 | bool gmic::display_plots(const CImgList<T>& images, const CImg<unsigned int>& indices, |
philpem@5 | 755 | const unsigned int plot_type, const unsigned int vertex_type, |
philpem@5 | 756 | const double xmin, const double xmax, |
philpem@5 | 757 | const double ymin, const double ymax, |
philpem@5 | 758 | const bool verbose) const { |
philpem@5 | 759 | if (!images || !indices) { print("Plot image []."); return false; } |
philpem@5 | 760 | CImgDisplay disp(cimg_fitscreen(640,480,1),0,0); |
philpem@5 | 761 | cimg_foroff(indices,l) { |
philpem@5 | 762 | const unsigned int ind = indices[l]; |
philpem@5 | 763 | const CImg<T>& img = images[ind]; |
philpem@5 | 764 | if (img) { |
philpem@5 | 765 | print("Plot image%s = '%s'.\n",gmic_inds,indices2string(indices,false)); |
philpem@5 | 766 | if (verbosity_level>=0) { std::fputc('\n',cimg_stdout); img.print(filenames[ind].ptr()); } |
philpem@5 | 767 | char title[4096] = { 0 }; |
philpem@5 | 768 | std::sprintf(title,"%s (%dx%dx%dx%d)", |
philpem@5 | 769 | filenames[ind].ptr(),img.dimx(),img.dimy(),img.dimz(),img.dimv()); |
philpem@5 | 770 | img.display_graph(disp.set_title(title),plot_type,vertex_type,0,xmin,xmax,0,ymin,ymax); |
philpem@5 | 771 | } else if (verbose) warning("Plot image : Image [%d] is empty.",ind); |
philpem@5 | 772 | } |
philpem@5 | 773 | return true; |
philpem@5 | 774 | } |
philpem@5 | 775 | |
philpem@5 | 776 | // Display specified 3D object(s). |
philpem@5 | 777 | //-------------------------------- |
philpem@5 | 778 | template<typename T> |
philpem@5 | 779 | bool gmic::display_objects3d(const CImgList<T>& images, const CImg<unsigned int>& indices, |
philpem@5 | 780 | const bool verbose) const { |
philpem@5 | 781 | if (!indices) { print("Display 3D object []."); return false; } |
philpem@5 | 782 | CImg<unsigned char> background; |
philpem@5 | 783 | bool exist3d = false; |
philpem@5 | 784 | CImgDisplay disp; |
philpem@5 | 785 | cimg_foroff(indices,l) { |
philpem@5 | 786 | const unsigned int ind = indices[l]; |
philpem@5 | 787 | const CImg<T> &img = images[ind]; |
philpem@5 | 788 | if (!img.is_CImg3d()) { |
philpem@5 | 789 | if (verbose) warning("Display 3D object : Image [%d] is not a 3D object.",ind); |
philpem@5 | 790 | } else { |
philpem@5 | 791 | exist3d = true; |
philpem@5 | 792 | if (!background || !disp) { |
philpem@5 | 793 | background.assign(cimg_fitscreen(640,480,1),1,3); |
philpem@5 | 794 | cimg_forV(background,k) background.get_shared_channel(k).fill(background3d[k]); |
philpem@5 | 795 | disp.assign(background); |
philpem@5 | 796 | } |
philpem@5 | 797 | CImgList<unsigned int> primitives3d; |
philpem@5 | 798 | CImgList<unsigned char> colors3d; |
philpem@5 | 799 | CImg<float> opacities3d; |
philpem@5 | 800 | CImg<float> points3d(img); |
philpem@5 | 801 | points3d.CImg3dtoobject3d(primitives3d,colors3d,opacities3d); |
philpem@5 | 802 | print("Display 3D object [%u] = '%s' (%d points, %u primitives).", |
philpem@5 | 803 | ind,filenames[ind].ptr(),points3d.dimx(),primitives3d.size); |
philpem@5 | 804 | disp.set_title("%s (%d points, %u primitives)", |
philpem@5 | 805 | filenames[ind].ptr(),points3d.dimx(),primitives3d.size); |
philpem@5 | 806 | background.display_object3d(disp,points3d,primitives3d,colors3d,opacities3d, |
philpem@5 | 807 | true,render3d,renderd3d,!is_oriented3d,focale3d,specular_light3d,specular_shine3d); |
philpem@5 | 808 | if (disp.is_closed) break; |
philpem@5 | 809 | } |
philpem@5 | 810 | } |
philpem@5 | 811 | return exist3d; |
philpem@5 | 812 | } |
philpem@5 | 813 | |
philpem@5 | 814 | // Substitute '@' expressions. |
philpem@5 | 815 | //---------------------------- |
philpem@5 | 816 | template<typename T> |
philpem@5 | 817 | CImg<char> gmic::substitute_arobace(const char *const argument, const CImgList<T>& images) const { |
philpem@5 | 818 | if (!argument) return CImg<char>(); |
philpem@5 | 819 | CImgList<char> _largument; |
philpem@5 | 820 | char range[4096] = { 0 }; |
philpem@5 | 821 | for (const char *nargument = argument; *nargument; ) { |
philpem@5 | 822 | if (*nargument=='@') { |
philpem@5 | 823 | char argx[4096] = { 0 }, argy[4096] = { 0 }, argz[4096] = { 0 }, argv[4096] = { 0 }; |
philpem@5 | 824 | int ind = 0, bcond = 0; *range = 0; char sepx = 0, sepy = 0, sepz = 0, sepv = 0, sep = 0, end = 0; |
philpem@5 | 825 | float x = 0, y = 0, z = 0, v = 0, m = 0, M = 1; |
philpem@5 | 826 | if (nargument[1]=='#' || |
philpem@5 | 827 | (std::sscanf(nargument,"@{#%c",&sep)==1 && sep=='}')) { |
philpem@5 | 828 | std::sprintf(range,"%u",images.size); |
philpem@5 | 829 | _largument.insert(CImg<char>(range,cimg::strlen(range),1,1,1,true)); |
philpem@5 | 830 | if (sep=='}') nargument+=4; else nargument+=2; |
philpem@5 | 831 | } else if (std::sscanf(nargument,"@%d",&ind)==1 || |
philpem@5 | 832 | (std::sscanf(nargument,"@{%d%c",&ind,&sep)==2 && sep=='}') || |
philpem@5 | 833 | (std::sscanf(nargument,"@{%d%*c%4095[^}]%c",&ind,range,&sep)==3 && sep=='}')) { |
philpem@5 | 834 | int nind = ind; |
philpem@5 | 835 | if (nind<0) nind+=images.size; |
philpem@5 | 836 | if (nind<0 || nind>=(int)images.size) { |
philpem@5 | 837 | if (images.size) error("Invalid indice '%d' in '@argument' (valid indice range is -%u...%u).", |
philpem@5 | 838 | ind,images.size,images.size-1); |
philpem@5 | 839 | else error("Invalid indice '%d' in '@argument' (image list is empty).",ind); |
philpem@5 | 840 | } |
philpem@5 | 841 | const unsigned int sizrange = cimg::strlen(range); |
philpem@5 | 842 | const CImg<T>& img = images[nind]; |
philpem@5 | 843 | CImg<T> values; |
philpem@5 | 844 | if (sizrange) { |
philpem@5 | 845 | const CImg<unsigned int> iinds = indices2cimg(range,img.size(),"parsing"); |
philpem@5 | 846 | values.assign(iinds.size()); |
philpem@5 | 847 | cimg_foroff(iinds,p) values[p] = img[iinds(p)]; |
philpem@5 | 848 | } else values = img.get_shared(); |
philpem@5 | 849 | const CImg<char> vs = values.value_string(); |
philpem@5 | 850 | const unsigned int vsl = vs.size(); |
philpem@5 | 851 | if (vsl>1) _largument.insert(CImg<char>(vs.ptr(),vsl-1,1,1,1,true)); |
philpem@5 | 852 | nargument+= 1 + (sep?2:0) + (sizrange?1:0) + sizrange + std::sprintf(range,"%d",ind); |
philpem@5 | 853 | } else if (((std::sscanf(nargument,"@(%d%*c%4095[0-9.eE%+-]%c",&ind,argx,&sep)==3 && sep==')') || |
philpem@5 | 854 | (std::sscanf(nargument,"@(%d%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c",&ind,argx,argy,&sep)==4 && sep==')') || |
philpem@5 | 855 | (std::sscanf(nargument,"@(%d%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c", |
philpem@5 | 856 | &ind,argx,argy,argz,&sep)==5 && sep==')') || |
philpem@5 | 857 | (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", |
philpem@5 | 858 | &ind,argx,argy,argz,argv,&sep)==6 && sep==')') || |
philpem@5 | 859 | (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", |
philpem@5 | 860 | &ind,argx,argy,argz,argv,&bcond,&sep)==7 && sep==')')) && |
philpem@5 | 861 | (!*argx || |
philpem@5 | 862 | (std::sscanf(argx,"%f%c%c",&x,&sepx,&end)==2 && sepx=='%') || |
philpem@5 | 863 | std::sscanf(argx,"%f%c",&x,&end)==1) && |
philpem@5 | 864 | (!*argy || |
philpem@5 | 865 | (std::sscanf(argy,"%f%c%c",&y,&sepy,&end)==2 && sepy=='%') || |
philpem@5 | 866 | std::sscanf(argy,"%f%c",&y,&end)==1) && |
philpem@5 | 867 | (!*argz || |
philpem@5 | 868 | (std::sscanf(argz,"%f%c%c",&z,&sepz,&end)==2 && sepz=='%') || |
philpem@5 | 869 | std::sscanf(argz,"%f%c",&z,&end)==1) && |
philpem@5 | 870 | (!*argv || |
philpem@5 | 871 | (std::sscanf(argv,"%f%c%c",&v,&sepv,&end)==2 && sepv=='%') || |
philpem@5 | 872 | std::sscanf(argv,"%f%c",&v,&end)==1)) { |
philpem@5 | 873 | int nind = ind; |
philpem@5 | 874 | if (nind<0) nind+=images.size; |
philpem@5 | 875 | if (nind<0 || nind>=(int)images.size) { |
philpem@5 | 876 | if (images.size) error("Invalid indice '%d' in '@argument' (valid indice range is -%u...%u).", |
philpem@5 | 877 | ind,images.size,images.size-1); |
philpem@5 | 878 | else error("Invalid indice '%d' in '@argument' (image list is empty).",ind); |
philpem@5 | 879 | } |
philpem@5 | 880 | const CImg<T>& img = images[nind]; |
philpem@5 | 881 | const int |
philpem@5 | 882 | nx = (int)cimg::round(sepx=='%'?x*(img.dimx()-1)/100:x,1), |
philpem@5 | 883 | ny = (int)cimg::round(sepy=='%'?y*(img.dimy()-1)/100:y,1), |
philpem@5 | 884 | nz = (int)cimg::round(sepz=='%'?z*(img.dimz()-1)/100:z,1), |
philpem@5 | 885 | nv = (int)cimg::round(sepv=='%'?v*(img.dimv()-1)/100:v,1); |
philpem@5 | 886 | std::sprintf(range,"%g",bcond?(double)img.atXYZV(nx,ny,nz,nv):(double)img.atXYZV(nx,ny,nz,nv,0)); |
philpem@5 | 887 | _largument.insert(CImg<char>(range,cimg::strlen(range))); |
philpem@5 | 888 | while (*nargument!=')') ++nargument; ++nargument; |
philpem@5 | 889 | } else if ((std::sscanf(nargument,"@%c",&sep)==1 && sep=='?') || |
philpem@5 | 890 | (std::sscanf(nargument,"@{?%c",&sep)==1 && sep=='}') || |
philpem@5 | 891 | (std::sscanf(nargument,"@[?%c",&sep)==1 && sep==']') || |
philpem@5 | 892 | (std::sscanf(nargument,"@{?%*c%f%c",&M,&sep)==2 && sep=='}') || |
philpem@5 | 893 | (std::sscanf(nargument,"@[?%*c%f%c",&M,&sep)==2 && sep==']') || |
philpem@5 | 894 | (std::sscanf(nargument,"@{?%*c%f%*c%f%c",&m,&M,&sep)==3 && sep=='}') || |
philpem@5 | 895 | (std::sscanf(nargument,"@[?%*c%f%*c%f%c",&m,&M,&sep)==3 && sep==']')) { |
philpem@5 | 896 | const double r = m + (M-m)*cimg::rand(); |
philpem@5 | 897 | if (sep==']') std::sprintf(range,"%d",(int)cimg::round(r,1)); else std::sprintf(range,"%g",r); |
philpem@5 | 898 | _largument.insert(CImg<char>(range,cimg::strlen(range),1,1,1,true)); |
philpem@5 | 899 | if (sep=='?') nargument+=2; else { while (*nargument!=sep) ++nargument; ++nargument; } |
philpem@5 | 900 | } else _largument.insert(CImg<char>(nargument++,1,1,1,1,true)); |
philpem@5 | 901 | } else { |
philpem@5 | 902 | std::sscanf(nargument,"%4095[^@]",range); |
philpem@5 | 903 | const int l = cimg::strlen(range); |
philpem@5 | 904 | _largument.insert(CImg<char>(range,l,1,1,1,true)); |
philpem@5 | 905 | nargument+=l; |
philpem@5 | 906 | } |
philpem@5 | 907 | } |
philpem@5 | 908 | _largument.insert(CImg<char>::vector(0)); |
philpem@5 | 909 | return _largument.get_append('x'); |
philpem@5 | 910 | } |
philpem@5 | 911 | |
philpem@5 | 912 | // Main parsing procedure. |
philpem@5 | 913 | //------------------------ |
philpem@5 | 914 | template<typename T> |
philpem@5 | 915 | gmic& gmic::parse(CImgList<T> &images) { |
philpem@5 | 916 | const unsigned int command_line_maxsize = 65535; |
philpem@5 | 917 | const int no_ind = (int)(~0U>>1); |
philpem@5 | 918 | cimg::exception_mode() = 0; |
philpem@5 | 919 | |
philpem@5 | 920 | // Begin command line parsing. |
philpem@5 | 921 | while (position<command_line.size && command_line.size<command_line_maxsize) { |
philpem@5 | 922 | const char |
philpem@5 | 923 | *const orig_item = command_line[position].ptr(), |
philpem@5 | 924 | *const orig_argument = position+1<command_line.size?command_line[position+1].ptr():""; |
philpem@5 | 925 | |
philpem@5 | 926 | // Substitute '@' expressions in 'orig_item' and 'orig_argument' if necessary. |
philpem@5 | 927 | CImg<char> _item, _argument, _argument_text; |
philpem@5 | 928 | if (*orig_item=='-' || *orig_item=='[' || *orig_item=='(') { |
philpem@5 | 929 | if (std::strchr(orig_item,'@')) { |
philpem@5 | 930 | _item = substitute_arobace(orig_item,images); |
philpem@5 | 931 | if (_item.size()>4095) error("Buffer overflow when substituting item '%s'.",orig_item); |
philpem@5 | 932 | } |
philpem@5 | 933 | if (*orig_item=='-' && |
philpem@5 | 934 | (*orig_argument!='-' || |
philpem@5 | 935 | (*orig_argument=='-' && (orig_argument[1]=='.' || orig_argument[1]=='@' || |
philpem@5 | 936 | (orig_argument[1]>='0' && orig_argument[1]<='9')))) |
philpem@5 | 937 | && std::strchr(orig_argument,'@')) { |
philpem@5 | 938 | _argument = substitute_arobace(orig_argument,images); |
philpem@5 | 939 | if (_argument.size()>4095) error("Buffer overflow when substituting argument '%s'.",orig_argument); |
philpem@5 | 940 | } |
philpem@5 | 941 | } |
philpem@5 | 942 | const char |
philpem@5 | 943 | *item = _item?_item.ptr():orig_item, |
philpem@5 | 944 | *argument = _argument?_argument.ptr():orig_argument; |
philpem@5 | 945 | const char *argument_text = argument; |
philpem@5 | 946 | if (cimg::strlen(argument)>=64) { |
philpem@5 | 947 | _argument_text.assign(64,1,1,1,0); |
philpem@5 | 948 | std::memcpy(_argument_text.ptr(),argument,60*sizeof(char)); |
philpem@5 | 949 | _argument_text[60] = _argument_text[61] = _argument_text[62] = '.'; _argument_text[63] = 0; |
philpem@5 | 950 | argument_text = _argument_text.ptr(); |
philpem@5 | 951 | } |
philpem@5 | 952 | |
philpem@5 | 953 | // Get current item/command from the command line. |
philpem@5 | 954 | char item0[4096] = { 0 }, item1[4096] = { 0 }; |
philpem@5 | 955 | bool get_version = false; |
philpem@5 | 956 | CImg<unsigned int> indices; |
philpem@5 | 957 | if (item[0]=='-' && item[1] && item[1]!='.') { |
philpem@5 | 958 | char sep0 = 0, sep1 = 0, end = 0; |
philpem@5 | 959 | if (item[1]=='-' && item[2] && item[2]!='[' && item[2]!='3' && item[3]!='d') { ++item; get_version = true; } |
philpem@5 | 960 | const int err = std::sscanf(item,"%4095[^[]%c%4095[0-9.eE%,:+-]%c%c",item0,&sep0,item1,&sep1,&end); |
philpem@5 | 961 | if (err==1) indices = CImg<unsigned int>::sequence(images.size,0,images.size-1); |
philpem@5 | 962 | else if (err==4 && sep1==']') |
philpem@5 | 963 | indices = indices2cimg(item1,(!strcmp(item0,"-i")||!strcmp(item0,"-input"))?images.size+1:images.size,item0); |
philpem@5 | 964 | else { std::strcpy(item0,item); item1[0] = 0; } |
philpem@5 | 965 | } |
philpem@5 | 966 | ++position; |
philpem@5 | 967 | |
philpem@5 | 968 | // Check for verbosity commands. |
philpem@5 | 969 | if (*item=='-') { |
philpem@5 | 970 | if (!cimg::strcmp("-verbose+",item) || !cimg::strcmp("-v+",item)) ++verbosity_level; |
philpem@5 | 971 | else if (!cimg::strcmp("-verbose-",item) || !cimg::strcmp("-v-",item)) --verbosity_level; |
philpem@5 | 972 | } |
philpem@5 | 973 | |
philpem@5 | 974 | if (is_begin) { print("Start G'MIC instance."); is_begin = false; } |
philpem@5 | 975 | debug("Item : '%s', Argument : '%s'.",item,argument); |
philpem@5 | 976 | |
philpem@5 | 977 | // Begin command interpretation. |
philpem@5 | 978 | try { |
philpem@5 | 979 | if (*item=='-') { |
philpem@5 | 980 | |
philpem@5 | 981 | //---------------- |
philpem@5 | 982 | // Global options |
philpem@5 | 983 | //---------------- |
philpem@5 | 984 | |
philpem@5 | 985 | // Verbosity (actually, just continue to next command since verbosity has been already processed above). |
philpem@5 | 986 | if (!cimg::strcmp("-verbose+",item) || !cimg::strcmp("-v+",item) || |
philpem@5 | 987 | !cimg::strcmp("-verbose-",item) || !cimg::strcmp("-v-",item)) continue; |
philpem@5 | 988 | |
philpem@5 | 989 | // Load macro file. |
philpem@5 | 990 | if (!cimg::strcmp("-macros",item) || !cimg::strcmp("-m",item)) { |
philpem@5 | 991 | print("Load macro file '%s'",cimg::basename(argument)); |
philpem@5 | 992 | std::FILE *const file = cimg::fopen(argument,"r"); |
philpem@5 | 993 | if (file) { |
philpem@5 | 994 | const unsigned int siz = macros.size; |
philpem@5 | 995 | add_macros(file,true); |
philpem@5 | 996 | cimg::fclose(file); |
philpem@5 | 997 | if (verbosity_level>=0) std::fprintf(cimg_stdout," (%u macros added).",macros.size-siz); |
philpem@5 | 998 | } |
philpem@5 | 999 | else error("Load macro file '%s' : File not found.",argument); |
philpem@5 | 1000 | ++position; continue; |
philpem@5 | 1001 | } |
philpem@5 | 1002 | |
philpem@5 | 1003 | // Switch 'is_debug' flag. |
philpem@5 | 1004 | if (!cimg::strcmp("-debug",item)) { |
philpem@5 | 1005 | is_debug = !is_debug; |
philpem@5 | 1006 | continue; |
philpem@5 | 1007 | } |
philpem@5 | 1008 | |
philpem@5 | 1009 | // Switch 'is_fullpath' flag. |
philpem@5 | 1010 | if (!cimg::strcmp("-fullpath",item)) { |
philpem@5 | 1011 | is_fullpath = !is_fullpath; |
philpem@5 | 1012 | continue; |
philpem@5 | 1013 | } |
philpem@5 | 1014 | |
philpem@5 | 1015 | //---------------------- |
philpem@5 | 1016 | // Arithmetic operators |
philpem@5 | 1017 | //---------------------- |
philpem@5 | 1018 | |
philpem@5 | 1019 | // Common arithmetic operators. |
philpem@5 | 1020 | gmic_arithmetic_item("-add","-+", |
philpem@5 | 1021 | operator+=,"Add %g to image%s",value,gmic_inds,T, |
philpem@5 | 1022 | operator+=,"Add to image%s", |
philpem@5 | 1023 | "Add image [%d] to image%s",ind[0],gmic_inds, |
philpem@5 | 1024 | "Add image%s together"); |
philpem@5 | 1025 | |
philpem@5 | 1026 | gmic_arithmetic_item("-sub","--", |
philpem@5 | 1027 | operator-=,"Substract %g to image%s",value,gmic_inds,T, |
philpem@5 | 1028 | operator-=,"Substract to image%s", |
philpem@5 | 1029 | "Substract image [%d] to image%s",ind[0],gmic_inds, |
philpem@5 | 1030 | "Substract image%s together"); |
philpem@5 | 1031 | |
philpem@5 | 1032 | gmic_arithmetic_item("-mul","-*", |
philpem@5 | 1033 | operator*=,"Multiply image%s by %g",gmic_inds,value,double, |
philpem@5 | 1034 | mul,"Multiply image%s", |
philpem@5 | 1035 | "Multiply image%s by image [%d]",gmic_inds,ind[0], |
philpem@5 | 1036 | "Multiply image%s together"); |
philpem@5 | 1037 | |
philpem@5 | 1038 | gmic_arithmetic_item("-div","-/", |
philpem@5 | 1039 | operator/=,"Divide image%s by %g",gmic_inds,value,double, |
philpem@5 | 1040 | div,"Divide image%s", |
philpem@5 | 1041 | "Divide image%s by image [%d]",gmic_inds,ind[0], |
philpem@5 | 1042 | "Divide image%s together"); |
philpem@5 | 1043 | |
philpem@5 | 1044 | gmic_arithmetic_item("-pow","-^", |
philpem@5 | 1045 | pow,"Compute image%s to the power of %g",gmic_inds,value,double, |
philpem@5 | 1046 | pow,"Compute power of image%s", |
philpem@5 | 1047 | "Compute image%s to the power of image [%d]",gmic_inds,ind[0], |
philpem@5 | 1048 | "Compute the power of image%s together"); |
philpem@5 | 1049 | |
philpem@5 | 1050 | gmic_arithmetic_item("-min","-min", |
philpem@5 | 1051 | min,"Compute pointwise minimum between image%s and %g",gmic_inds,value,T, |
philpem@5 | 1052 | min,"Compute pointwise minimum with image%s", |
philpem@5 | 1053 | "Compute pointwise minimum between image%s and image [%d]",gmic_inds,ind[0], |
philpem@5 | 1054 | "Compute pointwise minimum between image%s together"); |
philpem@5 | 1055 | |
philpem@5 | 1056 | gmic_arithmetic_item("-max","-max", |
philpem@5 | 1057 | max,"Compute pointwise maximum between image%s and %g",gmic_inds,value,T, |
philpem@5 | 1058 | max,"Compute pointwise maximum with image%s", |
philpem@5 | 1059 | "Compute pointwise maximum between image%s and image [%d]",gmic_inds,ind[0], |
philpem@5 | 1060 | "Compute pointwise maximum between image%s together"); |
philpem@5 | 1061 | |
philpem@5 | 1062 | gmic_arithmetic_item("-mod","-%", |
philpem@5 | 1063 | operator%=,"Compute pointwise modulo between image%s and %g.",gmic_inds,value,T, |
philpem@5 | 1064 | operator%=,"Compute pointwise modulo with image%s", |
philpem@5 | 1065 | "Compute pointwise modulo between image%s and image [%d]",gmic_inds,ind[0], |
philpem@5 | 1066 | "Compute pointwise modulo between image%s together"); |
philpem@5 | 1067 | |
philpem@5 | 1068 | gmic_arithmetic_item("-and","-and", |
philpem@5 | 1069 | operator&=,"Compute bitwise AND between image%s and %g.",gmic_inds,value,unsigned int, |
philpem@5 | 1070 | operator&=,"Compute bitwise AND with image%s", |
philpem@5 | 1071 | "Compute bitwise AND between image%s and image [%d]",gmic_inds,ind[0], |
philpem@5 | 1072 | "Compute bitwise AND between image%s together"); |
philpem@5 | 1073 | |
philpem@5 | 1074 | gmic_arithmetic_item("-or","-or", |
philpem@5 | 1075 | operator|=,"Compute bitwise OR between image%s and %g.",gmic_inds,value,unsigned int, |
philpem@5 | 1076 | operator|=,"Compute bitwise OR with image%s", |
philpem@5 | 1077 | "Compute bitwise OR between image%s and image [%d]",gmic_inds,ind[0], |
philpem@5 | 1078 | "Compute bitwise OR between image%s together"); |
philpem@5 | 1079 | |
philpem@5 | 1080 | gmic_arithmetic_item("-xor","-xor", |
philpem@5 | 1081 | operator^=,"Compute bitwise XOR between image%s and %g.",gmic_inds,value,unsigned int, |
philpem@5 | 1082 | operator^=,"Compute bitwise XOR with image%s", |
philpem@5 | 1083 | "Compute bitwise XOR between image%s and image [%d]",gmic_inds,ind[0], |
philpem@5 | 1084 | "Compute bitwise XOR between image%s together"); |
philpem@5 | 1085 | |
philpem@5 | 1086 | // Other arithmetic operators. |
philpem@5 | 1087 | gmic_simple_item("-cos",cos,"Compute cosine of image%s."); |
philpem@5 | 1088 | gmic_simple_item("-sin",sin,"Compute sine of image%s."); |
philpem@5 | 1089 | gmic_simple_item("-tan",tan,"Compute tangent of image%s."); |
philpem@5 | 1090 | gmic_simple_item("-acos",acos,"Compute arccosine of image%s."); |
philpem@5 | 1091 | gmic_simple_item("-asin",asin,"Compute arcsine of image%s."); |
philpem@5 | 1092 | gmic_simple_item("-atan",atan,"Compute arctangent of image%s."); |
philpem@5 | 1093 | gmic_simple_item("-abs",abs,"Compute absolute value of image%s."); |
philpem@5 | 1094 | gmic_simple_item("-sqr",sqr,"Compute square function of image%s."); |
philpem@5 | 1095 | gmic_simple_item("-sqrt",sqrt,"Compute square root of image%s."); |
philpem@5 | 1096 | gmic_simple_item("-exp",exp,"Compute exponential of image%s."); |
philpem@5 | 1097 | gmic_simple_item("-log",log,"Compute logarithm of image%s."); |
philpem@5 | 1098 | gmic_simple_item("-log10",log10,"Compute logarithm_10 of image%s."); |
philpem@5 | 1099 | |
philpem@5 | 1100 | //--------------------------------------- |
philpem@5 | 1101 | // Pointwise operations on pixel values |
philpem@5 | 1102 | //--------------------------------------- |
philpem@5 | 1103 | |
philpem@5 | 1104 | // Type cast. |
philpem@5 | 1105 | if (!cimg::strcmp("-type",item) || !cimg::strcmp("-t",item)) { |
philpem@5 | 1106 | typedef unsigned char uchar; |
philpem@5 | 1107 | typedef unsigned short ushort; |
philpem@5 | 1108 | typedef unsigned int uint; |
philpem@5 | 1109 | #ifndef gmic_minimal |
philpem@5 | 1110 | gmic_cast(bool,"bool"); |
philpem@5 | 1111 | gmic_cast(uchar,"unsigned char"); |
philpem@5 | 1112 | gmic_cast(char,"char"); |
philpem@5 | 1113 | gmic_cast(ushort,"unsigned short"); |
philpem@5 | 1114 | gmic_cast(short,"short"); |
philpem@5 | 1115 | gmic_cast(uint,"unsigned int"); |
philpem@5 | 1116 | gmic_cast(int,"int"); |
philpem@5 | 1117 | gmic_cast(double,"double"); |
philpem@5 | 1118 | #endif |
philpem@5 | 1119 | gmic_cast(float,"float"); |
philpem@5 | 1120 | error("Set pixel type : Invalid argument '%s' " |
philpem@5 | 1121 | "(should be '{bool,uchar,char,ushort,short,uint,int,float,double}').", |
philpem@5 | 1122 | argument_text); |
philpem@5 | 1123 | } |
philpem@5 | 1124 | |
philpem@5 | 1125 | // Set scalar value. |
philpem@5 | 1126 | if (!cimg::strcmp("-set",item0) || !cimg::strcmp("-=",item0)) { |
philpem@5 | 1127 | double value = 0; float x = 0, y = 0, z = 0, v = 0; char sepx = 0, sepy = 0, sepz = 0, sepv = 0, end = 0; |
philpem@5 | 1128 | char argx[4096] = { 0 }, argy[4096] = { 0 }, argz[4096] = { 0 }, argv[4096] = { 0 }; |
philpem@5 | 1129 | if ((std::sscanf(argument,"%lf%c",&value,&end)==1 || |
philpem@5 | 1130 | std::sscanf(argument,"%lf%*c%4095[0-9.eE%+-]%c",&value,argx,&end)==2 || |
philpem@5 | 1131 | std::sscanf(argument,"%lf%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c",&value,argx,argy,&end)==3 || |
philpem@5 | 1132 | 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 || |
philpem@5 | 1133 | 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) && |
philpem@5 | 1134 | (!*argx || |
philpem@5 | 1135 | (std::sscanf(argx,"%f%c%c",&x,&sepx,&end)==2 && sepx=='%') || |
philpem@5 | 1136 | std::sscanf(argx,"%f%c",&x,&end)==1) && |
philpem@5 | 1137 | (!*argy || |
philpem@5 | 1138 | (std::sscanf(argy,"%f%c%c",&y,&sepy,&end)==2 && sepy=='%') || |
philpem@5 | 1139 | std::sscanf(argy,"%f%c",&y,&end)==1) && |
philpem@5 | 1140 | (!*argz || |
philpem@5 | 1141 | (std::sscanf(argz,"%f%c%c",&z,&sepz,&end)==2 && sepz=='%') || |
philpem@5 | 1142 | std::sscanf(argz,"%f%c",&z,&end)==1) && |
philpem@5 | 1143 | (!*argv || |
philpem@5 | 1144 | (std::sscanf(argv,"%f%c%c",&v,&sepv,&end)==2 && sepv=='%') || |
philpem@5 | 1145 | std::sscanf(argv,"%f%c",&v,&end)==1)) { |
philpem@5 | 1146 | print("Set scalar value %g at position (%g%s,%g%s,%g%s,%g%s) in image%s", |
philpem@5 | 1147 | value,x,sepx=='%'?"%":"",y,sepy=='%'?"%":"",z,sepz=='%'?"%":"",v,sepv=='%'?"%":"",gmic_inds); |
philpem@5 | 1148 | cimg_foroff(indices,l) { |
philpem@5 | 1149 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 1150 | const int |
philpem@5 | 1151 | nx = (int)cimg::round(sepx=='%'?x*(img.dimx()-1)/100:x,1), |
philpem@5 | 1152 | ny = (int)cimg::round(sepy=='%'?y*(img.dimy()-1)/100:y,1), |
philpem@5 | 1153 | nz = (int)cimg::round(sepz=='%'?z*(img.dimz()-1)/100:z,1), |
philpem@5 | 1154 | nv = (int)cimg::round(sepv=='%'?v*(img.dimv()-1)/100:v,1); |
philpem@5 | 1155 | gmic_apply(images[indices[l]],gmic_set(value,nx,ny,nz,nv)); |
philpem@5 | 1156 | } |
philpem@5 | 1157 | } else error("Set scalar value in image%s : Invalid argument '%s' " |
philpem@5 | 1158 | "(should be 'value,x[,y[,z[,v]]]').", |
philpem@5 | 1159 | argument_text); |
philpem@5 | 1160 | ++position; continue; |
philpem@5 | 1161 | } |
philpem@5 | 1162 | |
philpem@5 | 1163 | // Invert endianness. |
philpem@5 | 1164 | gmic_simple_item("-endian",invert_endianness,"Invert endianness of image%s."); |
philpem@5 | 1165 | |
philpem@5 | 1166 | // Fill. |
philpem@5 | 1167 | if (!cimg::strcmp("-fill",item0) || !cimg::strcmp("-f",item0)) { |
philpem@5 | 1168 | char sep = 0, end = 0; int ind0 = no_ind; |
philpem@5 | 1169 | if (std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==2 && sep==']') { |
philpem@5 | 1170 | gmic_check_indice(ind0,"Fill image%s"); |
philpem@5 | 1171 | print("Fill image%s with values of image [%d].",gmic_inds,ind0); |
philpem@5 | 1172 | const CImg<T> values = images[ind0]; |
philpem@5 | 1173 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],fill(values)); |
philpem@5 | 1174 | } else { |
philpem@5 | 1175 | print("Fill image%s with values '%s'.",gmic_inds,argument_text); |
philpem@5 | 1176 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],fill(argument,true)); |
philpem@5 | 1177 | } |
philpem@5 | 1178 | ++position; continue; |
philpem@5 | 1179 | } |
philpem@5 | 1180 | |
philpem@5 | 1181 | // Threshold. |
philpem@5 | 1182 | if (!cimg::strcmp("-threshold",item0)) { |
philpem@5 | 1183 | char sep = 0, end = 0; int soft = 0; double value = 0; |
philpem@5 | 1184 | if (std::sscanf(argument,"%lf%c",&value,&end)==1 || |
philpem@5 | 1185 | (std::sscanf(argument,"%lf%c%c",&value,&sep,&end)==2 && sep=='%') || |
philpem@5 | 1186 | std::sscanf(argument,"%lf%*c%d%c",&value,&soft,&end)==2 || |
philpem@5 | 1187 | (std::sscanf(argument,"%lf%c%*c%d%c",&value,&sep,&soft,&end)==3 && sep=='%')) { |
philpem@5 | 1188 | print("Threshold image%s with %g%s (%s threshold).",gmic_inds,value,sep=='%'?"%":"",soft?"soft":"hard"); |
philpem@5 | 1189 | cimg_foroff(indices,l) { |
philpem@5 | 1190 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 1191 | double vmin = 0, vmax = 0, nvalue = value; |
philpem@5 | 1192 | if (sep=='%') { vmin = img.minmax(vmax); nvalue = vmin + (vmax - vmin)*value/100; } |
philpem@5 | 1193 | gmic_apply(img,threshold((T)nvalue,soft?true:false)); |
philpem@5 | 1194 | } |
philpem@5 | 1195 | ++position; |
philpem@5 | 1196 | } else { |
philpem@5 | 1197 | print("Threshold image%s : Interactive mode.",gmic_inds); |
philpem@5 | 1198 | CImgDisplay disp; |
philpem@5 | 1199 | char title[4096] = { 0 }; |
philpem@5 | 1200 | cimg_foroff(indices,l) { |
philpem@5 | 1201 | CImg<T> |
philpem@5 | 1202 | &img = images[indices[l]], |
philpem@5 | 1203 | visu = img.depth>1?img.get_projections2d(img.dimx()/2,img.dimy()/2,img.dimz()/2). |
philpem@5 | 1204 | channels(0,cimg::min(3,img.dimv())-1):img.get_channels(0,cimg::min(3,img.dimv()-1)); |
philpem@5 | 1205 | if (disp) disp.resize(cimg_fitscreen(visu.dimx(),visu.dimy(),1),false); |
philpem@5 | 1206 | else disp.assign(cimg_fitscreen(visu.dimx(),visu.dimy(),1),0,1); |
philpem@5 | 1207 | double |
philpem@5 | 1208 | vmin = 0, vmax = (double)img.maxmin(vmin), |
philpem@5 | 1209 | distmax = std::sqrt(cimg::sqr(disp.dimx()-1.0) + cimg::sqr(disp.dimy()-1.0)), |
philpem@5 | 1210 | amount = 50; |
philpem@5 | 1211 | bool stopflag = false, obutt = false; |
philpem@5 | 1212 | int omx = -1, omy = -1; |
philpem@5 | 1213 | CImg<T> res; |
philpem@5 | 1214 | for (disp.show().button = disp.key = 0; !stopflag; ) { |
philpem@5 | 1215 | const unsigned int key = disp.key; |
philpem@5 | 1216 | if (!res) { |
philpem@5 | 1217 | std::sprintf(title,"%s : Interactive threshold %.3g%%",filenames[indices[l]].ptr(),amount); |
philpem@5 | 1218 | disp.display(res=visu.get_threshold((T)(vmin + amount*(vmax-vmin)/100))). |
philpem@5 | 1219 | set_title(title).wait(); |
philpem@5 | 1220 | } |
philpem@5 | 1221 | const int mx = disp.mouse_x, my = disp.mouse_y; |
philpem@5 | 1222 | if (disp.button && mx>=0 && my>=0) { |
philpem@5 | 1223 | if (omx==mx && omy==my && !obutt) break; |
philpem@5 | 1224 | omx = mx; omy = my; obutt = true; |
philpem@5 | 1225 | const double dist = std::sqrt((double)cimg::sqr(mx) + cimg::sqr(my)); |
philpem@5 | 1226 | amount = dist*100/distmax; |
philpem@5 | 1227 | res.assign(); |
philpem@5 | 1228 | } else if (!disp.button) obutt = false; |
philpem@5 | 1229 | if (disp.is_closed || (key && key!=cimg::keyCTRLLEFT)) stopflag = true; |
philpem@5 | 1230 | if (key==cimg::keyD && disp.is_keyCTRLLEFT && |
philpem@5 | 1231 | (disp.resize(cimg_fitscreen(3*disp.width/2,3*disp.height/2,1),stopflag=false).key=0)==0) |
philpem@5 | 1232 | disp.is_resized = true; |
philpem@5 | 1233 | if (key==cimg::keyC && disp.is_keyCTRLLEFT && |
philpem@5 | 1234 | (disp.resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),stopflag=false).key=0)==0) |
philpem@5 | 1235 | disp.is_resized = true; |
philpem@5 | 1236 | if (disp.is_resized) { |
philpem@5 | 1237 | disp.resize(false).display(res); |
philpem@5 | 1238 | distmax = std::sqrt(cimg::sqr(disp.dimx()-1.0) + cimg::sqr(disp.dimy()-1.0)); |
philpem@5 | 1239 | } |
philpem@5 | 1240 | } |
philpem@5 | 1241 | gmic_apply(img,threshold((T)(vmin + amount*(vmax-vmin)/100))); |
philpem@5 | 1242 | } |
philpem@5 | 1243 | } |
philpem@5 | 1244 | continue; |
philpem@5 | 1245 | } |
philpem@5 | 1246 | |
philpem@5 | 1247 | // Cut. |
philpem@5 | 1248 | if (!cimg::strcmp("-cut",item0)) { |
philpem@5 | 1249 | char sep0 = 0, sep1 = 0, end = 0, arg0[4096] = { 0 }, arg1[4096] = { 0 }; |
philpem@5 | 1250 | double value0 = 0, value1 = 0; int ind0 = no_ind, ind1 = no_ind; |
philpem@5 | 1251 | if (std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c",arg0,arg1,&end)==2 && |
philpem@5 | 1252 | ((std::sscanf(arg0,"[%d%c%c",&ind0,&sep0,&end)==2 && sep0==']') || |
philpem@5 | 1253 | (std::sscanf(arg0,"%lf%c%c",&value0,&sep0,&end)==2 && sep0=='%') || |
philpem@5 | 1254 | std::sscanf(arg0,"%lf%c",&value0,&end)==1) && |
philpem@5 | 1255 | ((std::sscanf(arg1,"[%d%c%c",&ind1,&sep1,&end)==2 && sep1==']') || |
philpem@5 | 1256 | (std::sscanf(arg1,"%lf%c%c",&value1,&sep1,&end)==2 && sep1=='%') || |
philpem@5 | 1257 | std::sscanf(arg1,"%lf%c",&value1,&end)==1)) { |
philpem@5 | 1258 | if (ind0!=no_ind) { gmic_check_indice(ind0,"Cut image%s"); value0 = images[ind0].min(); sep0 = 0; } |
philpem@5 | 1259 | if (ind1!=no_ind) { gmic_check_indice(ind1,"Cut image%s"); value1 = images[ind1].max(); sep1 = 0; } |
philpem@5 | 1260 | print("Cut image%s in [%g%s,%g%s].",gmic_inds,value0,sep0=='%'?"%":"",value1,sep1=='%'?"%":""); |
philpem@5 | 1261 | cimg_foroff(indices,l) { |
philpem@5 | 1262 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 1263 | double vmin = 0, vmax = 0, nvalue0 = value0, nvalue1 = value1; |
philpem@5 | 1264 | if (sep0=='%') { vmin = img.minmax(vmax); nvalue0 = vmin + (vmax - vmin)*value0/100; } |
philpem@5 | 1265 | if (sep1=='%') { vmin = img.minmax(vmax); nvalue1 = vmin + (vmax - vmin)*value1/100; } |
philpem@5 | 1266 | gmic_apply(img,cut((T)nvalue0,(T)nvalue1)); |
philpem@5 | 1267 | } |
philpem@5 | 1268 | ++position; |
philpem@5 | 1269 | } else if (std::sscanf(argument,"[%d%c%c",&(ind0=no_ind),&sep0,&end)==2) { |
philpem@5 | 1270 | if (ind0!=no_ind) gmic_check_indice(ind0,"Cut image%s"); |
philpem@5 | 1271 | value0 = images[ind0].minmax(value1); |
philpem@5 | 1272 | print("Cut image%s in [%g,%g].",gmic_inds,value0,value1); |
philpem@5 | 1273 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],cut((T)value0,(T)value1)); |
philpem@5 | 1274 | ++position; |
philpem@5 | 1275 | } else { |
philpem@5 | 1276 | print("Cut image%s : Interactive mode.",gmic_inds); |
philpem@5 | 1277 | CImgDisplay disp; |
philpem@5 | 1278 | char title[4096] = { 0 }; |
philpem@5 | 1279 | cimg_foroff(indices,l) { |
philpem@5 | 1280 | CImg<T> |
philpem@5 | 1281 | &img = images[indices[l]], |
philpem@5 | 1282 | visu = img.depth>1?img.get_projections2d(img.dimx()/2,img.dimy()/2,img.dimz()/2). |
philpem@5 | 1283 | channels(0,cimg::min(3,img.dimv())-1):img.get_channels(0,cimg::min(3,img.dimv()-1)); |
philpem@5 | 1284 | if (disp) disp.resize(cimg_fitscreen(visu.dimx(),visu.dimy(),1),false); |
philpem@5 | 1285 | else disp.assign(cimg_fitscreen(visu.dimx(),visu.dimy(),1),0,1); |
philpem@5 | 1286 | double vmin = 0, vmax = (double)img.maxmin(vmin), amount0 = 0, amount1 = 100; |
philpem@5 | 1287 | bool stopflag = false, obutt = false; |
philpem@5 | 1288 | int omx = -1, omy = -1; |
philpem@5 | 1289 | CImg<T> res; |
philpem@5 | 1290 | for (disp.show().button = disp.key = 0; !stopflag; ) { |
philpem@5 | 1291 | const unsigned int key = disp.key; |
philpem@5 | 1292 | if (!res) { |
philpem@5 | 1293 | std::sprintf(title,"%s : Interactive cut [%.3g%%,%.3g%%]", |
philpem@5 | 1294 | filenames[indices[l]].ptr(),amount0,amount1); |
philpem@5 | 1295 | disp.display(res = visu.get_cut((T)(vmin + amount0*(vmax-vmin)/100), |
philpem@5 | 1296 | (T)(vmin + amount1*(vmax-vmin)/100))). |
philpem@5 | 1297 | set_title(title).wait(); |
philpem@5 | 1298 | } |
philpem@5 | 1299 | const int mx = disp.mouse_x, my = disp.mouse_y; |
philpem@5 | 1300 | if (disp.button && mx>=0 && my>=0) { |
philpem@5 | 1301 | if (omx==mx && omy==my && !obutt) break; |
philpem@5 | 1302 | omx = mx; omy = my; obutt = true; |
philpem@5 | 1303 | amount0 = mx*100/disp.dimx(); amount1 = my*100/disp.dimy(); |
philpem@5 | 1304 | res.assign(); |
philpem@5 | 1305 | } else if (!disp.button) obutt = false; |
philpem@5 | 1306 | if (disp.is_closed || (key && key!=cimg::keyCTRLLEFT)) stopflag = true; |
philpem@5 | 1307 | if (key==cimg::keyD && disp.is_keyCTRLLEFT && |
philpem@5 | 1308 | (disp.resize(cimg_fitscreen(3*disp.width/2,3*disp.height/2,1),stopflag=false).key=0)==0) |
philpem@5 | 1309 | disp.is_resized = true; |
philpem@5 | 1310 | if (key==cimg::keyC && disp.is_keyCTRLLEFT && |
philpem@5 | 1311 | (disp.resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),stopflag=false).key=0)==0) |
philpem@5 | 1312 | disp.is_resized = true; |
philpem@5 | 1313 | if (disp.is_resized) disp.resize(false).display(res); |
philpem@5 | 1314 | } |
philpem@5 | 1315 | gmic_apply(img,cut((T)(vmin + amount0*(vmax-vmin)/100),(T)(vmin + amount1*(vmax-vmin)/100))); |
philpem@5 | 1316 | } |
philpem@5 | 1317 | } |
philpem@5 | 1318 | continue; |
philpem@5 | 1319 | } |
philpem@5 | 1320 | |
philpem@5 | 1321 | // Normalize. |
philpem@5 | 1322 | if (!cimg::strcmp("-normalize",item0) || !cimg::strcmp("-n",item0)) { |
philpem@5 | 1323 | char sep0 = 0, sep1 = 0, end = 0, arg0[4096] = { 0 }, arg1[4096] = { 0 }; |
philpem@5 | 1324 | double value0 = 0, value1 = 0; int ind0 = no_ind, ind1 = no_ind; |
philpem@5 | 1325 | if (std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c",arg0,arg1,&end)==2 && |
philpem@5 | 1326 | ((std::sscanf(arg0,"[%d%c%c",&ind0,&sep0,&end)==2 && sep0==']') || |
philpem@5 | 1327 | (std::sscanf(arg0,"%lf%c%c",&value0,&sep0,&end)==2 && sep0=='%') || |
philpem@5 | 1328 | std::sscanf(arg0,"%lf%c",&value0,&end)==1) && |
philpem@5 | 1329 | ((std::sscanf(arg1,"[%d%c%c",&ind1,&sep1,&end)==2 && sep1==']') || |
philpem@5 | 1330 | (std::sscanf(arg1,"%lf%c%c",&value1,&sep1,&end)==2 && sep1=='%') || |
philpem@5 | 1331 | std::sscanf(arg1,"%lf%c",&value1,&end)==1)) { |
philpem@5 | 1332 | if (ind0!=no_ind) { gmic_check_indice(ind0,"Normalize image%s"); value0 = images[ind0].min(); sep0 = 0; } |
philpem@5 | 1333 | if (ind1!=no_ind) { gmic_check_indice(ind1,"Normalize image%s"); value1 = images[ind1].max(); sep1 = 0; } |
philpem@5 | 1334 | print("Normalize image%s in [%g%s,%g%s].",gmic_inds,value0,sep0=='%'?"%":"",value1,sep1=='%'?"%":""); |
philpem@5 | 1335 | cimg_foroff(indices,l) { |
philpem@5 | 1336 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 1337 | double vmin = 0, vmax = 0, nvalue0 = value0, nvalue1 = value1; |
philpem@5 | 1338 | if (sep0=='%') { vmin = img.minmax(vmax); nvalue0 = vmin + (vmax - vmin)*value0/100; } |
philpem@5 | 1339 | if (sep1=='%') { vmin = img.minmax(vmax); nvalue1 = vmin + (vmax - vmin)*value1/100; } |
philpem@5 | 1340 | gmic_apply(img,normalize((T)nvalue0,(T)nvalue1)); |
philpem@5 | 1341 | } |
philpem@5 | 1342 | } else if (std::sscanf(argument,"[%d%c%c",&(ind0=no_ind),&sep0,&end)==2) { |
philpem@5 | 1343 | if (ind0!=no_ind) gmic_check_indice(ind0,"Normalize image%s"); |
philpem@5 | 1344 | value0 = images[ind0].minmax(value1); |
philpem@5 | 1345 | print("Normalize image%s in [%g,%g].",gmic_inds,value0,value1); |
philpem@5 | 1346 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],normalize((T)value0,(T)value1)); |
philpem@5 | 1347 | } else error("Normalize image%s : Invalid argument '%s' " |
philpem@5 | 1348 | "(should be '{value1[%%],[indice]},{value2[%%],[indice]}').",gmic_inds,argument_text); |
philpem@5 | 1349 | ++position; continue; |
philpem@5 | 1350 | } |
philpem@5 | 1351 | |
philpem@5 | 1352 | // Round. |
philpem@5 | 1353 | if (!cimg::strcmp("-round",item0)) { |
philpem@5 | 1354 | char end = 0; double value = 0; int rtype = 0; |
philpem@5 | 1355 | if (std::sscanf(argument,"%lf%c",&value,&end)==1 || |
philpem@5 | 1356 | std::sscanf(argument,"%lf%*c%d%c",&value,&rtype,&end)==2) { |
philpem@5 | 1357 | print("Round image%s with value %g (%s rounding).", |
philpem@5 | 1358 | gmic_inds,value,rtype<0?"backward":rtype>0?"forward":"nearest"); |
philpem@5 | 1359 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],round((float)value,rtype)); |
philpem@5 | 1360 | } else error("Round image%s : Invalid argument '%s' " |
philpem@5 | 1361 | "(should be 'round_value[,round_type]').",gmic_inds,argument_text); |
philpem@5 | 1362 | ++position; continue; |
philpem@5 | 1363 | } |
philpem@5 | 1364 | |
philpem@5 | 1365 | // Equalize histogram. |
philpem@5 | 1366 | if (!cimg::strcmp("-equalize",item0)) { |
philpem@5 | 1367 | float nb = 256; char sep = 0, end = 0; |
philpem@5 | 1368 | if (std::sscanf(argument,"%f%c",&nb,&end)==1 || |
philpem@5 | 1369 | (std::sscanf(argument,"%f%c%c",&nb,&sep,&end)==2 && sep=='%')) { |
philpem@5 | 1370 | if (nb<=0) error("Equalize image%s : Invalid cluster number %g.",gmic_inds,nb); |
philpem@5 | 1371 | print("Equalize image%s with %g%s clusters.",gmic_inds,nb,sep=='%'?"%":""); |
philpem@5 | 1372 | cimg_foroff(indices,l) { |
philpem@5 | 1373 | CImg<T>& img = images[indices[l]]; |
philpem@5 | 1374 | unsigned int N = (unsigned int)nb; |
philpem@5 | 1375 | if (sep=='%') { double m, M = img.maxmin(m); N = (unsigned int)cimg::round((M-m)*nb/100,1); } |
philpem@5 | 1376 | gmic_apply(img,equalize((int)nb)); |
philpem@5 | 1377 | } |
philpem@5 | 1378 | } else error("Equalize image%s : Invalid argument '%s' " |
philpem@5 | 1379 | "(should be 'nb_clusters[%%]').",gmic_inds,argument_text); |
philpem@5 | 1380 | ++position; continue; |
philpem@5 | 1381 | } |
philpem@5 | 1382 | |
philpem@5 | 1383 | // Quantize. |
philpem@5 | 1384 | if (!cimg::strcmp("-quantize",item0)) { |
philpem@5 | 1385 | int nb = 0; char end = 0; |
philpem@5 | 1386 | if (std::sscanf(argument,"%d%c",&nb,&end)==1) { |
philpem@5 | 1387 | print("Quantize image%s with %d levels.",gmic_inds,nb); |
philpem@5 | 1388 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],quantize(nb)); |
philpem@5 | 1389 | } else error("Quantize image%s : Invalid argument '%s' " |
philpem@5 | 1390 | "(should be 'nb_levels').",gmic_inds,argument_text); |
philpem@5 | 1391 | ++position; continue; |
philpem@5 | 1392 | } |
philpem@5 | 1393 | |
philpem@5 | 1394 | // Add noise. |
philpem@5 | 1395 | if (!cimg::strcmp("-noise",item0)) { |
philpem@5 | 1396 | float sigma = 0; char sep = 0, end = 0; int ntype = 0; |
philpem@5 | 1397 | if (std::sscanf(argument,"%f%c",&sigma,&end)==1 || |
philpem@5 | 1398 | (std::sscanf(argument,"%f%c%c",&sigma,&sep,&end)==2 && sep=='%') || |
philpem@5 | 1399 | std::sscanf(argument,"%f%*c%d%c",&sigma,&ntype,&end)==2 || |
philpem@5 | 1400 | (std::sscanf(argument,"%f%c%*c%d%c",&sigma,&sep,&ntype,&end)==3 && sep=='%')) { |
philpem@5 | 1401 | const char *st_type = ntype==0?"gaussian":ntype==1?"uniform":ntype==2?"salt&pepper":"poisson"; |
philpem@5 | 1402 | if (sep=='%') sigma = -sigma; |
philpem@5 | 1403 | print("Add %s noise with standard deviation %g%s to image%s.", |
philpem@5 | 1404 | st_type,cimg::abs(sigma),sigma<0?"%":"",gmic_inds); |
philpem@5 | 1405 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],noise(sigma,ntype)); |
philpem@5 | 1406 | } else error("Add noise to image%s : Invalid argument '%s' " |
philpem@5 | 1407 | "(should be 'std[%%][,noise_type]').",gmic_inds,argument_text); |
philpem@5 | 1408 | ++position; continue; |
philpem@5 | 1409 | } |
philpem@5 | 1410 | |
philpem@5 | 1411 | // Rand. |
philpem@5 | 1412 | if (!cimg::strcmp("-rand",item0)) { |
philpem@5 | 1413 | double value0 = 0, value1 = 0; char end = 0; |
philpem@5 | 1414 | if (std::sscanf(argument,"%lf%*c%lf%c",&value0,&value1,&end)==2) { |
philpem@5 | 1415 | print("Fill image%s with random values in [%g,%g].",gmic_inds,value0,value1); |
philpem@5 | 1416 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],rand((T)value0,(T)value1)); |
philpem@5 | 1417 | } else error("Fill image%s with random values : Invalid argument '%s' " |
philpem@5 | 1418 | "(should be 'valmin,valmax').",gmic_inds,argument_text); |
philpem@5 | 1419 | ++position; continue; |
philpem@5 | 1420 | } |
philpem@5 | 1421 | |
philpem@5 | 1422 | // Compute pointwise norms and orientations. |
philpem@5 | 1423 | gmic_simple_item("-norm",pointwise_norm,"Compute vector norm."); |
philpem@5 | 1424 | gmic_simple_item("-orientation",pointwise_orientation,"Compute vector orientation."); |
philpem@5 | 1425 | |
philpem@5 | 1426 | //------------------------ |
philpem@5 | 1427 | // Color base conversions |
philpem@5 | 1428 | //------------------------ |
philpem@5 | 1429 | gmic_simple_item("-rgb2hsv",RGBtoHSV,"Convert image%s from RGB to HSV colorbases."); |
philpem@5 | 1430 | gmic_simple_item("-rgb2hsl",RGBtoHSL,"Convert image%s from RGB to HSL colorbases."); |
philpem@5 | 1431 | gmic_simple_item("-rgb2hsi",RGBtoHSI,"Convert image%s from RGB to HSI colorbases."); |
philpem@5 | 1432 | gmic_simple_item("-rgb2yuv",RGBtoYUV,"Convert image%s from RGB to YUV colorbases."); |
philpem@5 | 1433 | gmic_simple_item("-rgb2ycbcr",RGBtoYCbCr,"Convert image%s from RGB to YCbCr colorbases."); |
philpem@5 | 1434 | gmic_simple_item("-rgb2xyz",RGBtoXYZ,"Convert image%s from RGB to XYZ colorbases."); |
philpem@5 | 1435 | gmic_simple_item("-rgb2lab",RGBtoLab,"Convert image%s from RGB to Lab colorbases."); |
philpem@5 | 1436 | gmic_simple_item("-rgb2cmy",RGBtoCMY,"Convert image%s from RGB to CMY colorbases."); |
philpem@5 | 1437 | gmic_simple_item("-rgb2cmyk",RGBtoCMYK,"Convert image%s from RGB to CMYK colorbases."); |
philpem@5 | 1438 | gmic_simple_item("-cmyk2rgb",CMYKtoRGB,"Convert image%s from CMYK to RGB colorbases."); |
philpem@5 | 1439 | gmic_simple_item("-cmy2rgb",CMYtoRGB,"Convert image%s from CMY to RGB colorbases."); |
philpem@5 | 1440 | gmic_simple_item("-lab2rgb",LabtoRGB,"Convert image%s from Lab to RGB colorbases."); |
philpem@5 | 1441 | gmic_simple_item("-xyz2rgb",XYZtoRGB,"Convert image%s from XYZ to RGB colorbases."); |
philpem@5 | 1442 | gmic_simple_item("-ycbcr2rgb",YCbCrtoRGB,"Convert image%s from YCbCr to RGB colorbases."); |
philpem@5 | 1443 | gmic_simple_item("-yuv2rgb",YUVtoRGB,"Convert image%s from YUV to RGB colorbases."); |
philpem@5 | 1444 | gmic_simple_item("-hsi2rgb",HSItoRGB,"Convert image%s from HSI to RGB colorbases."); |
philpem@5 | 1445 | gmic_simple_item("-hsl2rgb",HSLtoRGB,"Convert image%s from HSL to RGB colorbases."); |
philpem@5 | 1446 | gmic_simple_item("-hsv2rgb",HSVtoRGB,"Convert image%s from HSV to RGB colorbases."); |
philpem@5 | 1447 | |
philpem@5 | 1448 | // Apply LUT. |
philpem@5 | 1449 | if (!cimg::strcmp("-lut2rgb",item0)) { |
philpem@5 | 1450 | int nb = 0, ind0 = 0; char sep = 0, end = 0; |
philpem@5 | 1451 | if (std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==2 && sep==']') { |
philpem@5 | 1452 | gmic_check_indice(ind0,"Map LUT on image%s"); |
philpem@5 | 1453 | print("Map LUT [%d] on image%s.",ind0,gmic_inds); |
philpem@5 | 1454 | const CImg<T> palette = images[ind0]; |
philpem@5 | 1455 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],pointwise_norm().LUTtoRGB(palette)); |
philpem@5 | 1456 | } else if (std::sscanf(argument,"%d%c",&nb,&end)==1) { |
philpem@5 | 1457 | if (nb<0 || nb>2) error("Map LUT on image%s : Invalid LUT number %d.",gmic_inds,nb); |
philpem@5 | 1458 | print("Map %s LUT on image%s.",nb==0?"default":nb==1?"rainbow":"cluster",gmic_inds); |
philpem@5 | 1459 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],pointwise_norm(). |
philpem@5 | 1460 | LUTtoRGB(nb==0?CImg<T>::default_LUT8():nb==1?CImg<T>::rainbow_LUT8():CImg<T>::contrast_LUT8())); |
philpem@5 | 1461 | } else error("Map LUT on image%s : Invalid argument '%s' " |
philpem@5 | 1462 | "(should be '[indice]' or '{0,1,2}').",gmic_inds,argument_text); |
philpem@5 | 1463 | ++position; continue; |
philpem@5 | 1464 | } |
philpem@5 | 1465 | |
philpem@5 | 1466 | // Convert to LUT. |
philpem@5 | 1467 | if (!cimg::strcmp("-rgb2lut",item0)) { |
philpem@5 | 1468 | int nb = 0, ind0 = 0, dithering = 0; char sep = 0, end = 0; |
philpem@5 | 1469 | if (std::sscanf(argument,"[%d%c%*c%d",&ind0,&sep,&dithering)>=2 && sep==']') { |
philpem@5 | 1470 | gmic_check_indice(ind0,"Index image%s with LUT"); |
philpem@5 | 1471 | print("Index image%s with LUT [%d] %s dithering.",gmic_inds,ind0,dithering?"with":"without"); |
philpem@5 | 1472 | const CImg<T> palette = images[ind0]; |
philpem@5 | 1473 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],RGBtoLUT(palette,dithering,true)); |
philpem@5 | 1474 | } else if (std::sscanf(argument,"%d%*c%d%c",&nb,&dithering,&end)==2 || |
philpem@5 | 1475 | std::sscanf(argument,"%d%c",&nb,&end)==1) { |
philpem@5 | 1476 | if (nb<0 || nb>2) error("Index image%s with LUT : Invalid LUT number %d.",gmic_inds,nb); |
philpem@5 | 1477 | print("Index image%s with %s LUT.",gmic_inds,nb==0?"default":nb==1?"rainbow":"cluster"); |
philpem@5 | 1478 | cimg_foroff(indices,l) gmic_apply(images[indices[l]], |
philpem@5 | 1479 | RGBtoLUT(nb==0?CImg<T>::default_LUT8():nb==1?CImg<T>::rainbow_LUT8():CImg<T>::contrast_LUT8(), |
philpem@5 | 1480 | dithering,true)); |
philpem@5 | 1481 | } else error("Index image%s with LUT : Invalid argument '%s' " |
philpem@5 | 1482 | "(should be '[indice][,dithering]', or '{0,1,2}[,dithering]').",gmic_inds,argument_text); |
philpem@5 | 1483 | ++position; continue; |
philpem@5 | 1484 | } |
philpem@5 | 1485 | |
philpem@5 | 1486 | //----------------------- |
philpem@5 | 1487 | // Geometric manipulation |
philpem@5 | 1488 | //----------------------- |
philpem@5 | 1489 | |
philpem@5 | 1490 | // Resize. |
philpem@5 | 1491 | if (!cimg::strcmp("-resize",item0) || !cimg::strcmp("-r",item0)) { |
philpem@5 | 1492 | char |
philpem@5 | 1493 | sepx = 0, sepy = 0, sepz = 0, sepv = 0, end = 0, |
philpem@5 | 1494 | argx[4096] = { 0 }, argy[4096] = { 0 }, argz[4096] = { 0 }, argv[4096] = { 0 }; |
philpem@5 | 1495 | float valx = 0, valy = 0, valz = 0, valv = 0; |
philpem@5 | 1496 | int interpolation = 1, borders = -1, center = 0, indx = no_ind, indy = no_ind, indz = no_ind, indv = no_ind; |
philpem@5 | 1497 | if ((std::sscanf(argument,"[%d%c%c",&indx,&sepx,&end)==2 || |
philpem@5 | 1498 | std::sscanf(argument,"[%d%c%*c%d%c",&indx,&sepx,&interpolation,&end)==3 || |
philpem@5 | 1499 | std::sscanf(argument,"[%d%c%*c%d%*c%d%c",&indx,&sepx,&interpolation,&borders,&end)==4 || |
philpem@5 | 1500 | std::sscanf(argument,"[%d%c%*c%d%*c%d%*c%d%c",&indx,&sepx,&interpolation,&borders,¢er,&end)==5) |
philpem@5 | 1501 | && sepx==']') { |
philpem@5 | 1502 | gmic_check_indice(indx,"Resize image%s"); |
philpem@5 | 1503 | const int |
philpem@5 | 1504 | ivalx = images[indx].dimx(), |
philpem@5 | 1505 | ivaly = images[indx].dimy(), |
philpem@5 | 1506 | ivalz = images[indx].dimz(), |
philpem@5 | 1507 | ivalv = images[indx].dimv(); |
philpem@5 | 1508 | print("Resize image%s to %dx%dx%dx%d with %s interpolation.", |
philpem@5 | 1509 | gmic_inds,ivalx,ivaly,ivalz,ivalv, |
philpem@5 | 1510 | interpolation==0?"no":interpolation==1?"nearest neighbor": |
philpem@5 | 1511 | interpolation==2?"moving average":interpolation==3?"linear": |
philpem@5 | 1512 | interpolation==4?"grid":"cubic"); |
philpem@5 | 1513 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],resize(ivalx,ivaly,ivalz,ivalv,interpolation,borders,center?true:false)); |
philpem@5 | 1514 | ++position; |
philpem@5 | 1515 | } 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", |
philpem@5 | 1516 | argx,argy,argz,argv,&(interpolation=1),&(borders=-1),&(center=0),&end)==7 || |
philpem@5 | 1517 | 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", |
philpem@5 | 1518 | argx,argy,argz,argv,&interpolation,&borders,&end)==6 || |
philpem@5 | 1519 | 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", |
philpem@5 | 1520 | argx,argy,argz,argv,&interpolation,&end)==5 || |
philpem@5 | 1521 | std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c", |
philpem@5 | 1522 | argx,argy,argz,argv,&end)==4) && |
philpem@5 | 1523 | ((std::sscanf(argx,"[%d%c%c",&indx,&sepx,&end)==2 && sepx==']') || |
philpem@5 | 1524 | (std::sscanf(argx,"%f%c%c",&valx,&sepx,&end)==2 && sepx=='%') || |
philpem@5 | 1525 | std::sscanf(argx,"%f%c",&valx,&end)==1) && |
philpem@5 | 1526 | ((std::sscanf(argy,"[%d%c%c",&indy,&sepy,&end)==2 && sepy==']') || |
philpem@5 | 1527 | (std::sscanf(argy,"%f%c%c",&valy,&sepy,&end)==2 && sepy=='%') || |
philpem@5 | 1528 | std::sscanf(argy,"%f%c",&valy,&end)==1) && |
philpem@5 | 1529 | ((std::sscanf(argz,"[%d%c%c",&indz,&sepz,&end)==2 && sepz==']') || |
philpem@5 | 1530 | (std::sscanf(argz,"%f%c%c",&valz,&sepz,&end)==2 && sepz=='%') || |
philpem@5 | 1531 | std::sscanf(argz,"%f%c",&valz,&end)==1) && |
philpem@5 | 1532 | ((std::sscanf(argv,"[%d%c%c",&indv,&sepv,&end)==2 && sepv==']') || |
philpem@5 | 1533 | (std::sscanf(argv,"%f%c%c",&valv,&sepv,&end)==2 && sepv=='%') || |
philpem@5 | 1534 | std::sscanf(argv,"%f%c",&valv,&end)==1)) || |
philpem@5 | 1535 | ((std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c", |
philpem@5 | 1536 | argx,argy,argz,&end)==3) && |
philpem@5 | 1537 | ((std::sscanf(argx,"[%d%c%c",&indx,&sepx,&end)==2 && sepx==']') || |
philpem@5 | 1538 | (std::sscanf(argx,"%f%c%c",&valx,&sepx,&end)==2 && sepx=='%') || |
philpem@5 | 1539 | std::sscanf(argx,"%f%c",&valx,&end)==1) && |
philpem@5 | 1540 | ((std::sscanf(argy,"[%d%c%c",&indy,&sepy,&end)==2 && sepy==']') || |
philpem@5 | 1541 | (std::sscanf(argy,"%f%c%c",&valy,&sepy,&end)==2 && sepy=='%') || |
philpem@5 | 1542 | std::sscanf(argy,"%f%c",&valy,&end)==1) && |
philpem@5 | 1543 | ((std::sscanf(argz,"[%d%c%c",&indz,&sepz,&end)==2 && sepz==']') || |
philpem@5 | 1544 | (std::sscanf(argz,"%f%c%c",&valz,&sepz,&end)==2 && sepz=='%') || |
philpem@5 | 1545 | std::sscanf(argz,"%f%c",&valz,&end)==1)) || |
philpem@5 | 1546 | ((std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c", |
philpem@5 | 1547 | argx,argy,&end)==2) && |
philpem@5 | 1548 | ((std::sscanf(argx,"[%d%c%c",&indx,&sepx,&end)==2 && sepx==']') || |
philpem@5 | 1549 | (std::sscanf(argx,"%f%c%c",&valx,&sepx,&end)==2 && sepx=='%') || |
philpem@5 | 1550 | std::sscanf(argx,"%f%c",&valx,&end)==1) && |
philpem@5 | 1551 | ((std::sscanf(argy,"[%d%c%c",&indy,&sepy,&end)==2 && sepy==']') || |
philpem@5 | 1552 | (std::sscanf(argy,"%f%c%c",&valy,&sepy,&end)==2 && sepy=='%') || |
philpem@5 | 1553 | std::sscanf(argy,"%f%c",&valy,&end)==1)) || |
philpem@5 | 1554 | ((std::sscanf(argument,"%4095[][0-9.eE%+-]%c", |
philpem@5 | 1555 | argx,&end)==1) && |
philpem@5 | 1556 | ((std::sscanf(argx,"[%d%c%c",&indx,&sepx,&end)==2 && sepx==']') || |
philpem@5 | 1557 | (std::sscanf(argx,"%f%c%c",&valx,&sepx,&end)==2 && sepx=='%') || |
philpem@5 | 1558 | std::sscanf(argx,"%f%c",&valx,&end)==1))) { |
philpem@5 | 1559 | if (indx!=no_ind) { gmic_check_indice(indx,"Resize image%s"); valx = (float)images[indx].dimx(); sepx = 0; } |
philpem@5 | 1560 | if (indy!=no_ind) { gmic_check_indice(indy,"Resize image%s"); valy = (float)images[indy].dimy(); sepy = 0; } |
philpem@5 | 1561 | if (indz!=no_ind) { gmic_check_indice(indz,"Resize image%s"); valz = (float)images[indz].dimz(); sepz = 0; } |
philpem@5 | 1562 | if (indv!=no_ind) { gmic_check_indice(indv,"Resize image%s"); valv = (float)images[indv].dimv(); sepv = 0; } |
philpem@5 | 1563 | if (!valx) { valx = 100; sepx = '%'; } |
philpem@5 | 1564 | if (!valy) { valy = 100; sepy = '%'; } |
philpem@5 | 1565 | if (!valz) { valz = 100; sepz = '%'; } |
philpem@5 | 1566 | if (!valv) { valv = 100; sepv = '%'; } |
philpem@5 | 1567 | print("Resize image%s to %g%s%g%s%g%s%g%s with %s interpolation.", |
philpem@5 | 1568 | gmic_inds,valx,sepx=='%'?"%x":"x",valy,sepy=='%'?"%x":"x",valz, |
philpem@5 | 1569 | sepz=='%'?"%x":"x",valv,sepv=='%'?"% ":" ", |
philpem@5 | 1570 | interpolation==0?"no":interpolation==1?"nearest neighbor": |
philpem@5 | 1571 | interpolation==2?"moving average":interpolation==3?"linear": |
philpem@5 | 1572 | interpolation==4?"grid":"cubic"); |
philpem@5 | 1573 | |
philpem@5 | 1574 | cimg_foroff(indices,l) { |
philpem@5 | 1575 | CImg<T>& img = images[indices[l]]; |
philpem@5 | 1576 | const int |
philpem@5 | 1577 | ivalx0 = (int)cimg::round(sepx=='%'?valx*img.dimx()/100:valx,1), |
philpem@5 | 1578 | ivaly0 = (int)cimg::round(sepy=='%'?valy*img.dimy()/100:valy,1), |
philpem@5 | 1579 | ivalz0 = (int)cimg::round(sepz=='%'?valz*img.dimz()/100:valz,1), |
philpem@5 | 1580 | ivalv0 = (int)cimg::round(sepv=='%'?valv*img.dimv()/100:valv,1), |
philpem@5 | 1581 | ivalx = ivalx0?ivalx0:1, |
philpem@5 | 1582 | ivaly = ivaly0?ivaly0:1, |
philpem@5 | 1583 | ivalz = ivalz0?ivalz0:1, |
philpem@5 | 1584 | ivalv = ivalv0?ivalv0:1; |
philpem@5 | 1585 | gmic_apply(img,resize(ivalx,ivaly,ivalz,ivalv,interpolation,borders,center?true:false)); |
philpem@5 | 1586 | } |
philpem@5 | 1587 | ++position; |
philpem@5 | 1588 | } else { |
philpem@5 | 1589 | print("Resize image%s : Interactive mode.",gmic_inds); |
philpem@5 | 1590 | char title[4096] = { 0 }; |
philpem@5 | 1591 | cimg_foroff(indices,l) { |
philpem@5 | 1592 | CImg<T>& img = images[indices[l]]; |
philpem@5 | 1593 | CImgDisplay disp(img,0,1); |
philpem@5 | 1594 | std::sprintf(title,"%s : Interactive resize",filenames[indices[l]].ptr()); |
philpem@5 | 1595 | disp.set_title(title); |
philpem@5 | 1596 | img.get_select(0,disp); |
philpem@5 | 1597 | print("Resize image [%d] to %dx%d.",indices[l],disp.dimx(),disp.dimy()); |
philpem@5 | 1598 | gmic_apply(img,resize(disp)); |
philpem@5 | 1599 | } |
philpem@5 | 1600 | } |
philpem@5 | 1601 | continue; |
philpem@5 | 1602 | } |
philpem@5 | 1603 | |
philpem@5 | 1604 | // Resize2x. and Resize3x. |
philpem@5 | 1605 | gmic_simple_item("-resize2x",resize_doubleXY,"Resize image%s using Scale2x algorithm."); |
philpem@5 | 1606 | gmic_simple_item("-resize3x",resize_doubleXY,"Resize image%s using Scale3x algorithm."); |
philpem@5 | 1607 | |
philpem@5 | 1608 | // Crop. |
philpem@5 | 1609 | if (!cimg::strcmp("-crop",item0) || !cimg::strcmp("-c",item0)) { |
philpem@5 | 1610 | char st0[4096] = { 0 }, st1[4096] = { 0 }, st2[4096] = { 0 }, st3[4096] = { 0 }; |
philpem@5 | 1611 | char st4[4096] = { 0 }, st5[4096] = { 0 }, st6[4096] = { 0 }, st7[4096] = { 0 }; |
philpem@5 | 1612 | char sep0 = 0, sep1 = 0, sep2 = 0, sep3 = 0, sep4 = 0, sep5 = 0, sep6 = 0, sep7 = 0, end = 0; |
philpem@5 | 1613 | float a0 = 0, a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0, a6 = 0, a7 = 0; int borders = 0; |
philpem@5 | 1614 | if ((std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c" |
philpem@5 | 1615 | "%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%d%c", |
philpem@5 | 1616 | st0,st1,st2,st3,st4,st5,st6,st7,&borders,&end)==9 || |
philpem@5 | 1617 | std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c" |
philpem@5 | 1618 | "%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c", |
philpem@5 | 1619 | st0,st1,st2,st3,st4,st5,st6,st7,&end)==8) && |
philpem@5 | 1620 | (std::sscanf(st0,"%f%c",&a0,&end)==1 || (std::sscanf(st0,"%f%c%c",&a0,&sep0,&end)==2 && sep0=='%')) && |
philpem@5 | 1621 | (std::sscanf(st1,"%f%c",&a1,&end)==1 || (std::sscanf(st1,"%f%c%c",&a1,&sep1,&end)==2 && sep1=='%')) && |
philpem@5 | 1622 | (std::sscanf(st2,"%f%c",&a2,&end)==1 || (std::sscanf(st2,"%f%c%c",&a2,&sep2,&end)==2 && sep2=='%')) && |
philpem@5 | 1623 | (std::sscanf(st3,"%f%c",&a3,&end)==1 || (std::sscanf(st3,"%f%c%c",&a3,&sep3,&end)==2 && sep3=='%')) && |
philpem@5 | 1624 | (std::sscanf(st4,"%f%c",&a4,&end)==1 || (std::sscanf(st4,"%f%c%c",&a4,&sep4,&end)==2 && sep4=='%')) && |
philpem@5 | 1625 | (std::sscanf(st5,"%f%c",&a5,&end)==1 || (std::sscanf(st5,"%f%c%c",&a5,&sep5,&end)==2 && sep5=='%')) && |
philpem@5 | 1626 | (std::sscanf(st6,"%f%c",&a6,&end)==1 || (std::sscanf(st6,"%f%c%c",&a6,&sep6,&end)==2 && sep6=='%')) && |
philpem@5 | 1627 | (std::sscanf(st7,"%f%c",&a7,&end)==1 || (std::sscanf(st7,"%f%c%c",&a7,&sep7,&end)==2 && sep7=='%'))) { |
philpem@5 | 1628 | print("Crop image%s with (%g%s%g%s%g%s%g%s x (%g%s%g%s%g%s%g%s.",gmic_inds, |
philpem@5 | 1629 | a0,sep0=='%'?"%,":",",a1,sep1=='%'?"%,":",", |
philpem@5 | 1630 | a2,sep2=='%'?"%,":",",a3,sep3=='%'?"%)":")", |
philpem@5 | 1631 | a4,sep4=='%'?"%,":",",a5,sep5=='%'?"%,":",", |
philpem@5 | 1632 | a6,sep6=='%'?"%,":",",a7,sep7=='%'?"%)":")"); |
philpem@5 | 1633 | cimg_foroff(indices,l) { |
philpem@5 | 1634 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 1635 | const int |
philpem@5 | 1636 | x0 = (int)cimg::round(sep0=='%'?a0*img.dimx()/100:a0,1), |
philpem@5 | 1637 | y0 = (int)cimg::round(sep1=='%'?a1*img.dimy()/100:a1,1), |
philpem@5 | 1638 | z0 = (int)cimg::round(sep2=='%'?a2*img.dimz()/100:a2,1), |
philpem@5 | 1639 | v0 = (int)cimg::round(sep3=='%'?a3*img.dimv()/100:a3,1), |
philpem@5 | 1640 | x1 = (int)cimg::round(sep4=='%'?a4*img.dimx()/100:a4,1), |
philpem@5 | 1641 | y1 = (int)cimg::round(sep5=='%'?a5*img.dimy()/100:a5,1), |
philpem@5 | 1642 | z1 = (int)cimg::round(sep6=='%'?a6*img.dimz()/100:a6,1), |
philpem@5 | 1643 | v1 = (int)cimg::round(sep7=='%'?a7*img.dimv()/100:a7,1); |
philpem@5 | 1644 | gmic_apply(img,crop(x0,y0,z0,v0,x1,y1,z1,v1,borders?true:false)); |
philpem@5 | 1645 | } |
philpem@5 | 1646 | ++position; |
philpem@5 | 1647 | } else if ((std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c" |
philpem@5 | 1648 | "%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%d%c", |
philpem@5 | 1649 | st0,st1,st2,st3,st4,st5,&borders,&end)==7 || |
philpem@5 | 1650 | std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c" |
philpem@5 | 1651 | "%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c", |
philpem@5 | 1652 | st0,st1,st2,st3,st4,st5,&end)==6) && |
philpem@5 | 1653 | (std::sscanf(st0,"%f%c",&a0,&end)==1 || |
philpem@5 | 1654 | (std::sscanf(st0,"%f%c%c",&a0,&sep0,&end)==2 && sep0=='%')) && |
philpem@5 | 1655 | (std::sscanf(st1,"%f%c",&a1,&end)==1 || |
philpem@5 | 1656 | (std::sscanf(st1,"%f%c%c",&a1,&sep1,&end)==2 && sep1=='%')) && |
philpem@5 | 1657 | (std::sscanf(st2,"%f%c",&a2,&end)==1 || |
philpem@5 | 1658 | (std::sscanf(st2,"%f%c%c",&a2,&sep2,&end)==2 && sep2=='%')) && |
philpem@5 | 1659 | (std::sscanf(st3,"%f%c",&a3,&end)==1 || |
philpem@5 | 1660 | (std::sscanf(st3,"%f%c%c",&a3,&sep3,&end)==2 && sep3=='%')) && |
philpem@5 | 1661 | (std::sscanf(st4,"%f%c",&a4,&end)==1 || |
philpem@5 | 1662 | (std::sscanf(st4,"%f%c%c",&a4,&sep4,&end)==2 && sep4=='%')) && |
philpem@5 | 1663 | (std::sscanf(st5,"%f%c",&a5,&end)==1 || |
philpem@5 | 1664 | (std::sscanf(st5,"%f%c%c",&a5,&sep5,&end)==2 && sep5=='%'))) { |
philpem@5 | 1665 | print("Crop image%s with (%g%s%g%s%g%s x (%g%s%g%s%g%s.",gmic_inds, |
philpem@5 | 1666 | a0,sep0=='%'?"%,":",",a1,sep1=='%'?"%,":",",a2,sep2=='%'?"%)":")", |
philpem@5 | 1667 | a3,sep3=='%'?"%,":",",a4,sep4=='%'?"%,":",",a5,sep5=='%'?"%)":")"); |
philpem@5 | 1668 | cimg_foroff(indices,l) { |
philpem@5 | 1669 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 1670 | const int |
philpem@5 | 1671 | x0 = (int)cimg::round(sep0=='%'?a0*img.dimx()/100:a0,1), |
philpem@5 | 1672 | y0 = (int)cimg::round(sep1=='%'?a1*img.dimy()/100:a1,1), |
philpem@5 | 1673 | z0 = (int)cimg::round(sep2=='%'?a2*img.dimz()/100:a2,1), |
philpem@5 | 1674 | x1 = (int)cimg::round(sep3=='%'?a3*img.dimx()/100:a3,1), |
philpem@5 | 1675 | y1 = (int)cimg::round(sep4=='%'?a4*img.dimy()/100:a4,1), |
philpem@5 | 1676 | z1 = (int)cimg::round(sep5=='%'?a5*img.dimz()/100:a5,1); |
philpem@5 | 1677 | gmic_apply(img,crop(x0,y0,z0,x1,y1,z1,borders?true:false)); |
philpem@5 | 1678 | } |
philpem@5 | 1679 | ++position; |
philpem@5 | 1680 | } else if ((std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c" |
philpem@5 | 1681 | "%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%d%c", |
philpem@5 | 1682 | st0,st1,st2,st3,&borders,&end)==5 || |
philpem@5 | 1683 | std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c" |
philpem@5 | 1684 | "%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c", |
philpem@5 | 1685 | st0,st1,st2,st3,&end)==4) && |
philpem@5 | 1686 | (std::sscanf(st0,"%f%c",&a0,&end)==1 || |
philpem@5 | 1687 | (std::sscanf(st0,"%f%c%c",&a0,&sep0,&end)==2 && sep0=='%')) && |
philpem@5 | 1688 | (std::sscanf(st1,"%f%c",&a1,&end)==1 || |
philpem@5 | 1689 | (std::sscanf(st1,"%f%c%c",&a1,&sep1,&end)==2 && sep1=='%')) && |
philpem@5 | 1690 | (std::sscanf(st2,"%f%c",&a2,&end)==1 || |
philpem@5 | 1691 | (std::sscanf(st2,"%f%c%c",&a2,&sep2,&end)==2 && sep2=='%')) && |
philpem@5 | 1692 | (std::sscanf(st3,"%f%c",&a3,&end)==1 || |
philpem@5 | 1693 | (std::sscanf(st3,"%f%c%c",&a3,&sep3,&end)==2 && sep3=='%'))) { |
philpem@5 | 1694 | print("Crop image%s with (%g%s%g%s x (%g%s%g%s.",gmic_inds, |
philpem@5 | 1695 | a0,sep0=='%'?"%,":",",a1,sep1=='%'?"%)":")", |
philpem@5 | 1696 | a2,sep2=='%'?"%,":",",a3,sep3=='%'?"%)":")"); |
philpem@5 | 1697 | cimg_foroff(indices,l) { |
philpem@5 | 1698 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 1699 | const int |
philpem@5 | 1700 | x0 = (int)cimg::round(sep0=='%'?a0*img.dimx()/100:a0,1), |
philpem@5 | 1701 | y0 = (int)cimg::round(sep1=='%'?a1*img.dimy()/100:a1,1), |
philpem@5 | 1702 | x1 = (int)cimg::round(sep2=='%'?a2*img.dimx()/100:a2,1), |
philpem@5 | 1703 | y1 = (int)cimg::round(sep3=='%'?a3*img.dimy()/100:a3,1); |
philpem@5 | 1704 | gmic_apply(img,crop(x0,y0,x1,y1,borders?true:false)); |
philpem@5 | 1705 | } |
philpem@5 | 1706 | ++position; |
philpem@5 | 1707 | } else if ((std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%d%c",st0,st1,&borders,&end)==3 || |
philpem@5 | 1708 | std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c",st0,st1,&end)==2) && |
philpem@5 | 1709 | (std::sscanf(st0,"%f%c",&a0,&end)==1 || |
philpem@5 | 1710 | (std::sscanf(st0,"%f%c%c",&a0,&sep0,&end)==2 && sep0=='%')) && |
philpem@5 | 1711 | (std::sscanf(st1,"%f%c",&a1,&end)==1 || |
philpem@5 | 1712 | (std::sscanf(st1,"%f%c%c",&a1,&sep1,&end)==2 && sep1=='%'))) { |
philpem@5 | 1713 | print("Crop image%s with (%g%s x (%g%s.",gmic_inds, |
philpem@5 | 1714 | a0,sep0=='%'?"%)":")",a1,sep1=='%'?"%)":")"); |
philpem@5 | 1715 | cimg_foroff(indices,l) { |
philpem@5 | 1716 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 1717 | const int |
philpem@5 | 1718 | x0 = (int)cimg::round(sep0=='%'?a0*img.dimx()/100:a0,1), |
philpem@5 | 1719 | x1 = (int)cimg::round(sep1=='%'?a1*img.dimx()/100:a1,1); |
philpem@5 | 1720 | gmic_apply(img,crop(x0,x1,borders?true:false)); |
philpem@5 | 1721 | } |
philpem@5 | 1722 | ++position; |
philpem@5 | 1723 | } else { |
philpem@5 | 1724 | print("Crop image%s : Interactive mode.",gmic_inds); |
philpem@5 | 1725 | char title[4096] = { 0 }; |
philpem@5 | 1726 | cimg_foroff(indices,l) { |
philpem@5 | 1727 | CImg<T>& img = images[indices[l]]; |
philpem@5 | 1728 | CImgDisplay disp(cimg_fitscreen(img.dimx(),img.dimy(),1),0,1); |
philpem@5 | 1729 | std::sprintf(title,"%s : Interactive crop",filenames[indices[l]].ptr()); |
philpem@5 | 1730 | disp.set_title(title); |
philpem@5 | 1731 | const CImg<int> s = img.get_select(disp,2); |
philpem@5 | 1732 | print("Crop image [%d] with (%d,%d,%d) x (%d,%d,%d).", |
philpem@5 | 1733 | indices[l],s[0],s[1],s[2],s[3],s[4],s[5]); |
philpem@5 | 1734 | gmic_apply(img,crop(s[0],s[1],s[2],s[3],s[4],s[5])); |
philpem@5 | 1735 | } |
philpem@5 | 1736 | } |
philpem@5 | 1737 | continue; |
philpem@5 | 1738 | } |
philpem@5 | 1739 | |
philpem@5 | 1740 | // Autocrop. |
philpem@5 | 1741 | if (!cimg::strcmp("-autocrop",item0)) { |
philpem@5 | 1742 | print("Autocrop image%s with color '%s'.",gmic_inds,argument_text); |
philpem@5 | 1743 | cimg_foroff(indices,l) { |
philpem@5 | 1744 | CImg<T>& img = images[indices[l]]; |
philpem@5 | 1745 | const CImg<T> col = CImg<T>(img.dimv()).fill(argument,true); |
philpem@5 | 1746 | gmic_apply(img,autocrop(col)); |
philpem@5 | 1747 | } |
philpem@5 | 1748 | ++position; continue; |
philpem@5 | 1749 | } |
philpem@5 | 1750 | |
philpem@5 | 1751 | // Select channels. |
philpem@5 | 1752 | if (!cimg::strcmp("-channels",item0)) { |
philpem@5 | 1753 | char sep0 = 0, sep1 = 0, end = 0, arg0[4096] = { 0 }, arg1[4096] = { 0 }; |
philpem@5 | 1754 | float value0 = 0, value1 = 0; int ind0 = no_ind, ind1 = no_ind; |
philpem@5 | 1755 | if (std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c",arg0,arg1,&end)==2 && |
philpem@5 | 1756 | ((std::sscanf(arg0,"[%d%c%c]",&ind0,&sep0,&end)==2 && sep0==']') || |
philpem@5 | 1757 | (std::sscanf(arg0,"%f%c%c",&value0,&sep0,&end)==2 && sep0=='%') || |
philpem@5 | 1758 | std::sscanf(arg0,"%f%c",&value0,&end)==1) && |
philpem@5 | 1759 | ((std::sscanf(arg1,"[%d%c%c]",&ind1,&sep1,&end)==2 && sep1==']') || |
philpem@5 | 1760 | (std::sscanf(arg1,"%f%c%c",&value1,&sep1,&end)==2 && sep1=='%') || |
philpem@5 | 1761 | std::sscanf(arg1,"%f%c",&value1,&end)==1)) { |
philpem@5 | 1762 | if (ind0!=no_ind) { gmic_check_indice(ind0,"Keep channels of image%s"); value0 = images[ind0].dimv()-1.0f; sep0 = 0; } |
philpem@5 | 1763 | if (ind1!=no_ind) { gmic_check_indice(ind1,"Keep channels of image%s"); value1 = images[ind1].dimv()-1.0f; sep1 = 0; } |
philpem@5 | 1764 | print("Keep channels %g%s..%g%s of image%s.",value0,sep0=='%'?"%":"",value1,sep1=='%'?"%":"",gmic_inds); |
philpem@5 | 1765 | cimg_foroff(indices,l) { |
philpem@5 | 1766 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 1767 | const int |
philpem@5 | 1768 | nvalue0 = (int)cimg::round(sep0=='%'?value0*(img.dimv()-1)/100:value0,1), |
philpem@5 | 1769 | nvalue1 = (int)cimg::round(sep1=='%'?value1*(img.dimv()-1)/100:value1,1); |
philpem@5 | 1770 | gmic_apply(img,channels(nvalue0,nvalue1)); |
philpem@5 | 1771 | } |
philpem@5 | 1772 | } else if (std::sscanf(argument,"%4095[][0-9.eE%+-]%c",arg0,&end)==1 && |
philpem@5 | 1773 | ((std::sscanf(arg0,"[%d%c%c]",&ind0,&sep0,&end)==2 && sep0==']') || |
philpem@5 | 1774 | (std::sscanf(arg0,"%f%c%c",&value0,&sep0,&end)==2 && sep0=='%') || |
philpem@5 | 1775 | std::sscanf(arg0,"%f%c",&value0,&end)==1)) { |
philpem@5 | 1776 | if (ind0!=no_ind) { gmic_check_indice(ind0,"Keep channel of image%s"); value0 = images[ind0].dimv()-1.0f; sep0 = 0; } |
philpem@5 | 1777 | print("Keep channel %g%s of image%s.",value0,sep0=='%'?"%":"",gmic_inds); |
philpem@5 | 1778 | cimg_foroff(indices,l) { |
philpem@5 | 1779 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 1780 | const int nvalue0 = (int)cimg::round(sep0=='%'?value0*(img.dimv()-1)/100:value0,1); |
philpem@5 | 1781 | gmic_apply(img,channel(nvalue0)); |
philpem@5 | 1782 | } |
philpem@5 | 1783 | } else error("Keep channels of image%s : Invalid argument '%s' " |
philpem@5 | 1784 | "(should be 'channel0[%%][,channel1[%%]]').",gmic_inds,argument_text); |
philpem@5 | 1785 | ++position; continue; |
philpem@5 | 1786 | } |
philpem@5 | 1787 | |
philpem@5 | 1788 | // Select slices. |
philpem@5 | 1789 | if (!cimg::strcmp("-slices",item0)) { |
philpem@5 | 1790 | char sep0 = 0, sep1 = 0, end = 0, arg0[4096] = { 0 }, arg1[4096] = { 0 }; |
philpem@5 | 1791 | float value0 = 0, value1 = 0; int ind0 = no_ind, ind1 = no_ind; |
philpem@5 | 1792 | if (std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c",arg0,arg1,&end)==2 && |
philpem@5 | 1793 | ((std::sscanf(arg0,"[%d%c%c]",&ind0,&sep0,&end)==2 && sep0==']') || |
philpem@5 | 1794 | (std::sscanf(arg0,"%f%c%c",&value0,&sep0,&end)==2 && sep0=='%') || |
philpem@5 | 1795 | std::sscanf(arg0,"%f%c",&value0,&end)==1) && |
philpem@5 | 1796 | ((std::sscanf(arg1,"[%d%c%c]",&ind1,&sep1,&end)==2 && sep1==']') || |
philpem@5 | 1797 | (std::sscanf(arg1,"%f%c%c",&value1,&sep1,&end)==2 && sep1=='%') || |
philpem@5 | 1798 | std::sscanf(arg1,"%f%c",&value1,&end)==1)) { |
philpem@5 | 1799 | if (ind0!=no_ind) { gmic_check_indice(ind0,"Select slices of image%s"); value0 = images[ind0].dimz()-1.0f; sep0 = 0; } |
philpem@5 | 1800 | if (ind1!=no_ind) { gmic_check_indice(ind1,"Select slices of image%s"); value1 = images[ind1].dimz()-1.0f; sep1 = 0; } |
philpem@5 | 1801 | print("Select slices %g%s..%g%s of image%s.",value0,sep0=='%'?"%":"",value1,sep1=='%'?"%":"",gmic_inds); |
philpem@5 | 1802 | cimg_foroff(indices,l) { |
philpem@5 | 1803 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 1804 | const int |
philpem@5 | 1805 | nvalue0 = (int)cimg::round(sep0=='%'?value0*(img.dimv()-1)/100:value0,0), |
philpem@5 | 1806 | nvalue1 = (int)cimg::round(sep1=='%'?value1*(img.dimv()-1)/100:value1,0); |
philpem@5 | 1807 | gmic_apply(img,slices(nvalue0,nvalue1)); |
philpem@5 | 1808 | } |
philpem@5 | 1809 | } else if (std::sscanf(argument,"%4095[][0-9.eE%+-]%c",arg0,&end)==1 && |
philpem@5 | 1810 | ((std::sscanf(arg0,"[%d%c%c]",&ind0,&sep0,&end)==2 && sep0==']') || |
philpem@5 | 1811 | (std::sscanf(arg0,"%f%c%c",&value0,&sep0,&end)==2 && sep0=='%') || |
philpem@5 | 1812 | std::sscanf(arg0,"%f%c",&value0,&end)==1)) { |
philpem@5 | 1813 | if (ind0!=no_ind) { gmic_check_indice(ind0,"Select slice of image%s"); value0 = images[ind0].dimz()-1.0f; sep0 = 0; } |
philpem@5 | 1814 | print("Select slice %g%s of image%s.",value0,sep0=='%'?"%":"",gmic_inds); |
philpem@5 | 1815 | cimg_foroff(indices,l) { |
philpem@5 | 1816 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 1817 | const int nvalue0 = (int)cimg::round(sep0=='%'?value0*(img.dimz()-1)/100:value0,1); |
philpem@5 | 1818 | gmic_apply(img,slice(nvalue0)); |
philpem@5 | 1819 | } |
philpem@5 | 1820 | } else error("Select slices of image%s : Invalid argument '%s' " |
philpem@5 | 1821 | "(should be 'slice0[%%][,slice1[%%]]').",gmic_inds,argument_text); |
philpem@5 | 1822 | ++position; continue; |
philpem@5 | 1823 | } |
philpem@5 | 1824 | |
philpem@5 | 1825 | // Select lines. |
philpem@5 | 1826 | if (!cimg::strcmp("-lines",item0) || !cimg::strcmp("-l",item0)) { |
philpem@5 | 1827 | char sep0 = 0, sep1 = 0, end = 0, arg0[4096] = { 0 }, arg1[4096] = { 0 }; |
philpem@5 | 1828 | float value0 = 0, value1 = 0; int ind0 = no_ind, ind1 = no_ind; |
philpem@5 | 1829 | if (std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c",arg0,arg1,&end)==2 && |
philpem@5 | 1830 | ((std::sscanf(arg0,"[%d%c%c]",&ind0,&sep0,&end)==2 && sep0==']') || |
philpem@5 | 1831 | (std::sscanf(arg0,"%f%c%c",&value0,&sep0,&end)==2 && sep0=='%') || |
philpem@5 | 1832 | std::sscanf(arg0,"%f%c",&value0,&end)==1) && |
philpem@5 | 1833 | ((std::sscanf(arg1,"[%d%c%c]",&ind1,&sep1,&end)==2 && sep1==']') || |
philpem@5 | 1834 | (std::sscanf(arg1,"%f%c%c",&value1,&sep1,&end)==2 && sep1=='%') || |
philpem@5 | 1835 | std::sscanf(arg1,"%f%c",&value1,&end)==1)) { |
philpem@5 | 1836 | if (ind0!=no_ind) { gmic_check_indice(ind0,"Select lines of image%s"); value0 = images[ind0].dimy()-1.0f; sep0 = 0; } |
philpem@5 | 1837 | if (ind1!=no_ind) { gmic_check_indice(ind1,"Select lines of image%s"); value1 = images[ind1].dimy()-1.0f; sep1 = 0; } |
philpem@5 | 1838 | print("Select lines %g%s..%g%s of image%s.",value0,sep0=='%'?"%":"",value1,sep1=='%'?"%":"",gmic_inds); |
philpem@5 | 1839 | cimg_foroff(indices,l) { |
philpem@5 | 1840 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 1841 | const int |
philpem@5 | 1842 | nvalue0 = (int)cimg::round(sep0=='%'?value0*(img.dimy()-1)/100:value0,1), |
philpem@5 | 1843 | nvalue1 = (int)cimg::round(sep1=='%'?value1*(img.dimy()-1)/100:value1,1); |
philpem@5 | 1844 | gmic_apply(img,lines(nvalue0,nvalue1)); |
philpem@5 | 1845 | } |
philpem@5 | 1846 | } else if (std::sscanf(argument,"%4095[][0-9.eE%+-]%c",arg0,&end)==1 && |
philpem@5 | 1847 | ((std::sscanf(arg0,"[%d%c%c]",&ind0,&sep0,&end)==2 && sep0==']') || |
philpem@5 | 1848 | (std::sscanf(arg0,"%f%c%c",&value0,&sep0,&end)==2 && sep0=='%') || |
philpem@5 | 1849 | std::sscanf(arg0,"%f%c",&value0,&end)==1)) { |
philpem@5 | 1850 | if (ind0!=no_ind) { gmic_check_indice(ind0,"Select lines of image%s"); value0 = images[ind0].dimy()-1.0f; sep0 = 0; } |
philpem@5 | 1851 | print("Select lines %g%s of image%s.",value0,sep0=='%'?"%":"",gmic_inds); |
philpem@5 | 1852 | cimg_foroff(indices,l) { |
philpem@5 | 1853 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 1854 | const int nvalue0 = (int)cimg::round(sep0=='%'?value0*(img.dimy()-1)/100:value0,1); |
philpem@5 | 1855 | gmic_apply(img,line(nvalue0)); |
philpem@5 | 1856 | } |
philpem@5 | 1857 | } else error("Select lines of image%s : Invalid argument '%s' " |
philpem@5 | 1858 | "(should be 'line0[%%][,line1[%%]]').",gmic_inds,argument_text); |
philpem@5 | 1859 | ++position; continue; |
philpem@5 | 1860 | } |
philpem@5 | 1861 | |
philpem@5 | 1862 | // Columns. |
philpem@5 | 1863 | if (!cimg::strcmp("-columns",item0)) { |
philpem@5 | 1864 | char sep0 = 0, sep1 = 0, end = 0, arg0[4096] = { 0 }, arg1[4096] = { 0 }; |
philpem@5 | 1865 | float value0 = 0, value1 = 0; int ind0 = no_ind, ind1 = no_ind; |
philpem@5 | 1866 | if (std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c",arg0,arg1,&end)==2 && |
philpem@5 | 1867 | ((std::sscanf(arg0,"[%d%c%c]",&ind0,&sep0,&end)==2 && sep0==']') || |
philpem@5 | 1868 | (std::sscanf(arg0,"%f%c%c",&value0,&sep0,&end)==2 && sep0=='%') || |
philpem@5 | 1869 | std::sscanf(arg0,"%f%c",&value0,&end)==1) && |
philpem@5 | 1870 | ((std::sscanf(arg1,"[%d%c%c]",&ind1,&sep1,&end)==2 && sep1==']') || |
philpem@5 | 1871 | (std::sscanf(arg1,"%f%c%c",&value1,&sep1,&end)==2 && sep1=='%') || |
philpem@5 | 1872 | std::sscanf(arg1,"%f%c",&value1,&end)==1)) { |
philpem@5 | 1873 | if (ind0!=no_ind) { gmic_check_indice(ind0,"Select columns of image%s"); value0 = images[ind0].dimx()-1.0f; sep0 = 0; } |
philpem@5 | 1874 | if (ind1!=no_ind) { gmic_check_indice(ind1,"Select columns of image%s"); value1 = images[ind1].dimx()-1.0f; sep1 = 0; } |
philpem@5 | 1875 | print("Select columns %g%s..%g%s of image%s.",value0,sep0=='%'?"%":"",value1,sep1=='%'?"%":"",gmic_inds); |
philpem@5 | 1876 | cimg_foroff(indices,l) { |
philpem@5 | 1877 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 1878 | const int |
philpem@5 | 1879 | nvalue0 = (int)cimg::round(sep0=='%'?value0*(img.dimx()-1)/100:value0,1), |
philpem@5 | 1880 | nvalue1 = (int)cimg::round(sep1=='%'?value1*(img.dimx()-1)/100:value1,1); |
philpem@5 | 1881 | gmic_apply(img,lines(nvalue0,nvalue1)); |
philpem@5 | 1882 | } |
philpem@5 | 1883 | } else if (std::sscanf(argument,"%4095[][0-9.eE%+-]%c",arg0,&end)==1 && |
philpem@5 | 1884 | ((std::sscanf(arg0,"[%d%c%c]",&ind0,&sep0,&end)==2 && sep0==']') || |
philpem@5 | 1885 | (std::sscanf(arg0,"%f%c%c",&value0,&sep0,&end)==2 && sep0=='%') || |
philpem@5 | 1886 | std::sscanf(arg0,"%f%c",&value0,&end)==1)) { |
philpem@5 | 1887 | if (ind0!=no_ind) { gmic_check_indice(ind0,"Select columns of image%s"); value0 = images[ind0].dimx()-1.0f; sep0 = 0; } |
philpem@5 | 1888 | print("Select columns %g%s of image%s.",value0,sep0=='%'?"%":"",gmic_inds); |
philpem@5 | 1889 | cimg_foroff(indices,l) { |
philpem@5 | 1890 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 1891 | const int nvalue0 = (int)cimg::round(sep0=='%'?value0*(img.dimx()-1)/100:value0,1); |
philpem@5 | 1892 | gmic_apply(img,line(nvalue0)); |
philpem@5 | 1893 | } |
philpem@5 | 1894 | } else error("Select columns of image%s : Invalid argument '%s' " |
philpem@5 | 1895 | "(should be 'column0[%%][,column1[%%]]').",gmic_inds,argument_text); |
philpem@5 | 1896 | ++position; continue; |
philpem@5 | 1897 | } |
philpem@5 | 1898 | |
philpem@5 | 1899 | // Rotate. |
philpem@5 | 1900 | if (!cimg::strcmp("-rotate",item0)) { |
philpem@5 | 1901 | float angle = 0; int borders = 0, interpolation = 1; char end = 0; |
philpem@5 | 1902 | if (std::sscanf(argument,"%f%c",&angle,&end)==1 || |
philpem@5 | 1903 | std::sscanf(argument,"%f%*c%d%c",&angle,&borders,&end)==2 || |
philpem@5 | 1904 | std::sscanf(argument,"%f%*c%d%*c%d%c",&angle,&borders,&interpolation,&end)==3) { |
philpem@5 | 1905 | print("Rotate image%s with an angle of %g deg and %s interpolation.", |
philpem@5 | 1906 | gmic_inds,angle,interpolation?"linear":"nearest-neighbor"); |
philpem@5 | 1907 | if (borders>=0) { cimg_foroff(indices,l) gmic_apply(images[indices[l]],rotate(angle,borders,interpolation)); } |
philpem@5 | 1908 | else cimg_foroff(indices,l) { |
philpem@5 | 1909 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 1910 | gmic_apply(img,rotate(angle,img.dimx()/2.0f,img.dimy()/2.0f,1,-1-borders,interpolation)); |
philpem@5 | 1911 | } |
philpem@5 | 1912 | } else error("Rotate image%s : Invalid argument '%s' " |
philpem@5 | 1913 | "(should be 'angle[,border_conditions[,interpolation]]').",gmic_inds,argument_text); |
philpem@5 | 1914 | ++position; |
philpem@5 | 1915 | continue; |
philpem@5 | 1916 | } |
philpem@5 | 1917 | |
philpem@5 | 1918 | // Mirror. |
philpem@5 | 1919 | if (!cimg::strcmp("-mirror",item0)) { |
philpem@5 | 1920 | const char axis = cimg::uncase(*argument); |
philpem@5 | 1921 | if (cimg::strlen(argument)==1) { |
philpem@5 | 1922 | print("Mirror image%s along the %c-axis.",gmic_inds,axis); |
philpem@5 | 1923 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],mirror(axis)); |
philpem@5 | 1924 | } else error("Mirror image%s : Invalid argument '%s' " |
philpem@5 | 1925 | "(should be '{x,y,z,v}').",gmic_inds,argument_text); |
philpem@5 | 1926 | ++position; continue; |
philpem@5 | 1927 | } |
philpem@5 | 1928 | |
philpem@5 | 1929 | // Translate. |
philpem@5 | 1930 | if (!cimg::strcmp("-translate",item0)) { |
philpem@5 | 1931 | char stx[4096] = { 0 }, sty[4096] = { 0 }, stz[4096] = { 0 }, stv[4096] = { 0 }; |
philpem@5 | 1932 | char sepx = 0, sepy = 0, sepz = 0, sepv = 0, end = 0; |
philpem@5 | 1933 | float dx = 0, dy = 0, dz = 0, dv = 0; int borders = 0; |
philpem@5 | 1934 | 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", |
philpem@5 | 1935 | stx,sty,stz,stv,&borders,&end)==5 || |
philpem@5 | 1936 | std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c", |
philpem@5 | 1937 | stx,sty,stz,stv,&end)==4) && |
philpem@5 | 1938 | (std::sscanf(stx,"%f%c",&dx,&end)==1 || (std::sscanf(stx,"%f%c%c",&dx,&sepx,&end)==2 && sepx=='%')) && |
philpem@5 | 1939 | (std::sscanf(sty,"%f%c",&dy,&end)==1 || (std::sscanf(sty,"%f%c%c",&dy,&sepy,&end)==2 && sepy=='%')) && |
philpem@5 | 1940 | (std::sscanf(stz,"%f%c",&dz,&end)==1 || (std::sscanf(stz,"%f%c%c",&dz,&sepz,&end)==2 && sepz=='%')) && |
philpem@5 | 1941 | (std::sscanf(stv,"%f%c",&dv,&end)==1 || (std::sscanf(stv,"%f%c%c",&dv,&sepv,&end)==2 && sepv=='%'))) || |
philpem@5 | 1942 | (std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c",stx,sty,stz,&end)==3 && |
philpem@5 | 1943 | (std::sscanf(stx,"%f%c",&dx,&end)==1 || (std::sscanf(stx,"%f%c%c",&dx,&sepx,&end)==2 && sepx=='%')) && |
philpem@5 | 1944 | (std::sscanf(sty,"%f%c",&dy,&end)==1 || (std::sscanf(sty,"%f%c%c",&dy,&sepy,&end)==2 && sepy=='%')) && |
philpem@5 | 1945 | (std::sscanf(stz,"%f%c",&dz,&end)==1 || (std::sscanf(stz,"%f%c%c",&dz,&sepz,&end)==2 && sepz=='%'))) || |
philpem@5 | 1946 | (std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c",stx,sty,&end)==2 && |
philpem@5 | 1947 | (std::sscanf(stx,"%f%c",&dx,&end)==1 || (std::sscanf(stx,"%f%c%c",&dx,&sepx,&end)==2 && sepx=='%')) && |
philpem@5 | 1948 | (std::sscanf(sty,"%f%c",&dy,&end)==1 || (std::sscanf(sty,"%f%c%c",&dy,&sepy,&end)==2 && sepy=='%'))) || |
philpem@5 | 1949 | (std::sscanf(argument,"%4095[0-9.eE%+-]%c",stx,&end)==1 && |
philpem@5 | 1950 | (std::sscanf(stx,"%f%c",&dx,&end)==1 || (std::sscanf(stx,"%f%c%c",&dx,&sepx,&end)==2 && sepx=='%')))) { |
philpem@5 | 1951 | print("Translate image%s with vector (%g%s,%g%s,%g%s,%g%s).", |
philpem@5 | 1952 | gmic_inds,dx,sepx=='%'?"%":"",dy,sepy=='%'?"%":"",dz,sepz=='%'?"%":"",dv,sepv=='%'?"%":""); |
philpem@5 | 1953 | cimg_foroff(indices,l) { |
philpem@5 | 1954 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 1955 | const int |
philpem@5 | 1956 | ndx = (int)cimg::round(sepx=='%'?dx*img.dimx()/100:dx,1), |
philpem@5 | 1957 | ndy = (int)cimg::round(sepy=='%'?dy*img.dimy()/100:dy,1), |
philpem@5 | 1958 | ndz = (int)cimg::round(sepz=='%'?dz*img.dimz()/100:dz,1), |
philpem@5 | 1959 | ndv = (int)cimg::round(sepv=='%'?dv*img.dimv()/100:dv,1); |
philpem@5 | 1960 | gmic_apply(images[indices[l]],translate(ndx,ndy,ndz,ndv,borders)); |
philpem@5 | 1961 | } |
philpem@5 | 1962 | } else error("Translate image%s : Invalid argument '%s' " |
philpem@5 | 1963 | "(should be 'tx[%%][,ty[%%][,tz[%%][,tv[%%][,border_conditions]]]]').",gmic_inds,argument_text); |
philpem@5 | 1964 | ++position; continue; |
philpem@5 | 1965 | } |
philpem@5 | 1966 | |
philpem@5 | 1967 | // Transpose. |
philpem@5 | 1968 | gmic_simple_item("-transpose",transpose,"Transpose image%s."); |
philpem@5 | 1969 | |
philpem@5 | 1970 | // Invert. |
philpem@5 | 1971 | gmic_simple_item("-invert",invert,"Compute matrix inversion of image%s."); |
philpem@5 | 1972 | |
philpem@5 | 1973 | // Permute axes. |
philpem@5 | 1974 | if (!cimg::strcmp("-permute",item0)) { |
philpem@5 | 1975 | print("Permute axes of image%s with permutation '%s'.",gmic_inds,argument_text); |
philpem@5 | 1976 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],permute_axes(argument)); |
philpem@5 | 1977 | ++position; continue; |
philpem@5 | 1978 | } |
philpem@5 | 1979 | |
philpem@5 | 1980 | // Unroll. |
philpem@5 | 1981 | if (!cimg::strcmp("-unroll",item0)) { |
philpem@5 | 1982 | const char axis = cimg::uncase(*argument); |
philpem@5 | 1983 | if (cimg::strlen(argument)==1 && (axis=='x' || axis=='y' || axis=='z' || axis=='v')) { |
philpem@5 | 1984 | print("Unroll image%s along the %c-axis.",gmic_inds,axis); |
philpem@5 | 1985 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],unroll(axis)); |
philpem@5 | 1986 | } else error("Unroll image%s : Invalid argument '%s' " |
philpem@5 | 1987 | "(should be '{x,y,z,v}').",gmic_inds,argument_text); |
philpem@5 | 1988 | ++position; continue; |
philpem@5 | 1989 | } |
philpem@5 | 1990 | |
philpem@5 | 1991 | // Split image(s). |
philpem@5 | 1992 | if (!cimg::strcmp("-split",item0) || !cimg::strcmp("-s",item0)) { |
philpem@5 | 1993 | char axis = cimg::uncase(*argument), foo = 0, end = 0; int nb = 0, keep_value = 0; double value = 0; |
philpem@5 | 1994 | if ((std::sscanf(argument,"%c%c",&foo,&end)==1 || |
philpem@5 | 1995 | std::sscanf(argument,"%c%*c%d%c",&foo,&nb,&end)==2) & |
philpem@5 | 1996 | (axis=='x' || axis=='y' || axis=='z' || axis=='v')) { |
philpem@5 | 1997 | if (nb<0) error("Split image%s along the %c-axis in %d part : Invalid number of parts.", |
philpem@5 | 1998 | gmic_inds,axis,nb); |
philpem@5 | 1999 | if (nb>0) print("Split image%s along the %c-axis in %d parts.",gmic_inds,axis,nb); |
philpem@5 | 2000 | else print("Split image%s along the %c-axis.",gmic_inds,axis); |
philpem@5 | 2001 | unsigned int off = 0; |
philpem@5 | 2002 | cimg_foroff(indices,l) { |
philpem@5 | 2003 | const unsigned int ind = indices[l] + off; |
philpem@5 | 2004 | const CImg<T>& img = images[ind]; |
philpem@5 | 2005 | const CImg<char> filename = filenames[ind]; |
philpem@5 | 2006 | const CImgList<T> split = img.get_split(axis,nb); |
philpem@5 | 2007 | if (get_version) { |
philpem@5 | 2008 | images.insert(split); |
philpem@5 | 2009 | filenames.insert(split.size,filename); |
philpem@5 | 2010 | } else { |
philpem@5 | 2011 | images.remove(ind); images.insert(split,ind); |
philpem@5 | 2012 | filenames.remove(ind); filenames.insert(split.size,filename,ind); |
philpem@5 | 2013 | off+=split.size-1; |
philpem@5 | 2014 | } |
philpem@5 | 2015 | } |
philpem@5 | 2016 | } else if (std::sscanf(argument,"%lf%c",&value,&end)==1 || |
philpem@5 | 2017 | std::sscanf(argument,"%lf%*c%d%c",&value,&keep_value,&end)==2) { |
philpem@5 | 2018 | print("Split image%s according to value %g.",gmic_inds,value); |
philpem@5 | 2019 | unsigned int off = 0; |
philpem@5 | 2020 | cimg_foroff(indices,l) { |
philpem@5 | 2021 | const unsigned int ind = indices[l] + off; |
philpem@5 | 2022 | CImg<T>& img = images[ind]; |
philpem@5 | 2023 | const CImg<char> filename = filenames[ind]; |
philpem@5 | 2024 | const CImgList<T> split = img.get_split((T)value,keep_value,false); |
philpem@5 | 2025 | if (get_version) { |
philpem@5 | 2026 | images.insert(split); |
philpem@5 | 2027 | filenames.insert(split.size,filename); |
philpem@5 | 2028 | } else { |
philpem@5 | 2029 | images.remove(ind); images.insert(split,ind); |
philpem@5 | 2030 | filenames.remove(ind); filenames.insert(split.size,filename,ind); |
philpem@5 | 2031 | off+=split.size-1; |
philpem@5 | 2032 | } |
philpem@5 | 2033 | } |
philpem@5 | 2034 | } else error("Split image%s : Invalid argument '%s' " |
philpem@5 | 2035 | "(should be 'axis[,nb_parts]' where 'axis' can be '{x,y,z,v}').",gmic_inds,argument_text); |
philpem@5 | 2036 | ++position; continue; |
philpem@5 | 2037 | } |
philpem@5 | 2038 | |
philpem@5 | 2039 | // Append image(s). |
philpem@5 | 2040 | if (!cimg::strcmp("-append",item0) || !cimg::strcmp("-a",item0)) { |
philpem@5 | 2041 | char axis = 0, align='p', end = 0; |
philpem@5 | 2042 | if ((std::sscanf(argument,"%c%c",&axis,&end)==1 || |
philpem@5 | 2043 | std::sscanf(argument,"%c%*c%c%c",&axis,&align,&end)==2)) { |
philpem@5 | 2044 | axis = cimg::uncase(axis); |
philpem@5 | 2045 | print("Append image%s along the %c-axis with %s alignment.", |
philpem@5 | 2046 | gmic_inds,axis,align=='p'?"left":align=='c'?"center":"right"); |
philpem@5 | 2047 | CImgList<T> subimages; cimg_foroff(indices,l) subimages.insert(images[indices[l]],~0U,true); |
philpem@5 | 2048 | if (get_version) { |
philpem@5 | 2049 | images.insert(subimages.get_append(axis,align)); |
philpem@5 | 2050 | filenames.insert(filenames[indices[0]]); |
philpem@5 | 2051 | } else { |
philpem@5 | 2052 | images.insert(subimages.get_append(axis,align),indices[0]); |
philpem@5 | 2053 | filenames.insert(filenames[indices[0]],indices[0]); |
philpem@5 | 2054 | int off = 1; |
philpem@5 | 2055 | cimg_foroff(indices,l) { |
philpem@5 | 2056 | const int ind = indices[l] + off; |
philpem@5 | 2057 | images.remove(ind); filenames.remove(ind); |
philpem@5 | 2058 | --off; |
philpem@5 | 2059 | } |
philpem@5 | 2060 | } |
philpem@5 | 2061 | } else error("Append image%s : Invalid argument '%s' " |
philpem@5 | 2062 | "(should be 'axis[,alignement]' where 'axis' can be '{x,y,z,v}' " |
philpem@5 | 2063 | "and alignement '{p,c,n}').",gmic_inds,argument_text); |
philpem@5 | 2064 | ++position; continue; |
philpem@5 | 2065 | } |
philpem@5 | 2066 | |
philpem@5 | 2067 | // Warp image(s). |
philpem@5 | 2068 | if (!cimg::strcmp("-warp",item0)) { |
philpem@5 | 2069 | int ind0 = no_ind, interpolation = 1, relative = 0, nb = 1, borders = 1; char end = 0, sep = 0; |
philpem@5 | 2070 | if ((std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==2 && sep==']')|| |
philpem@5 | 2071 | std::sscanf(argument,"[%d]%*c%d%c",&ind0,&relative,&end)==2 || |
philpem@5 | 2072 | std::sscanf(argument,"[%d]%*c%d%*c%d%c",&ind0,&relative,&interpolation,&end)==3 || |
philpem@5 | 2073 | std::sscanf(argument,"[%d]%*c%d%*c%d%*c%d%c",&ind0,&relative,&interpolation,&borders,&end)==4 || |
philpem@5 | 2074 | std::sscanf(argument,"[%d]%*c%d%*c%d%*c%d%*c%d%c",&ind0,&relative,&interpolation,&borders,&nb,&end)==5) { |
philpem@5 | 2075 | gmic_check_indice(ind0,"Warp image%s"); |
philpem@5 | 2076 | if (nb!=1) print("Warp image%s with %s field [%u] and %d frames.", |
philpem@5 | 2077 | gmic_inds,relative?"relative":"absolute",ind0,nb); |
philpem@5 | 2078 | else print("Warp image%s with %s field [%u].",gmic_inds,relative?"relative":"absolute",ind0); |
philpem@5 | 2079 | if (nb>=1) { |
philpem@5 | 2080 | const CImg<T> warp = images[ind0]; |
philpem@5 | 2081 | unsigned int off = 0; |
philpem@5 | 2082 | cimg_foroff(indices,l) { |
philpem@5 | 2083 | const unsigned int ind = indices[l] + off; |
philpem@5 | 2084 | CImg<T> &img = images[ind]; |
philpem@5 | 2085 | CImgList<T> frames(nb); |
philpem@5 | 2086 | cimglist_for(frames,t) { |
philpem@5 | 2087 | const CImg<T> nwarp = warp.get_resize(img.dimx(),img.dimy(),img.dimz(),warp.dimv(),3)*=(t+1.0f)/nb; |
philpem@5 | 2088 | frames[t] = img.get_warp(nwarp,relative?true:false,interpolation?true:false,borders); |
philpem@5 | 2089 | } |
philpem@5 | 2090 | if (get_version) { |
philpem@5 | 2091 | images.insert(frames); |
philpem@5 | 2092 | filenames.insert(nb-1,filenames[ind]); |
philpem@5 | 2093 | } else { |
philpem@5 | 2094 | images.remove(ind); images.insert(frames,ind); |
philpem@5 | 2095 | filenames.insert(nb-1,filenames[ind],ind); |
philpem@5 | 2096 | off+=nb-1; |
philpem@5 | 2097 | } |
philpem@5 | 2098 | } |
philpem@5 | 2099 | } |
philpem@5 | 2100 | } else error("Warp image%s : Invalid argument '%s' " |
philpem@5 | 2101 | "(should be '[indice][,relative[,interpolation[,border_conditions[,nb_frames]]]]').", |
philpem@5 | 2102 | gmic_inds,argument_text); |
philpem@5 | 2103 | ++position; continue; |
philpem@5 | 2104 | } |
philpem@5 | 2105 | |
philpem@5 | 2106 | //----------------------- |
philpem@5 | 2107 | // Image filtering |
philpem@5 | 2108 | //----------------------- |
philpem@5 | 2109 | |
philpem@5 | 2110 | // Gaussian blur. |
philpem@5 | 2111 | if (!cimg::strcmp("-blur",item0)) { |
philpem@5 | 2112 | float sigma = -1; int borders = 1; char end = 0; |
philpem@5 | 2113 | if ((std::sscanf(argument,"%f%c",&sigma,&end)==1 || |
philpem@5 | 2114 | std::sscanf(argument,"%f%*c%d%c",&sigma,&borders,&end)==2) |
philpem@5 | 2115 | && sigma>=0) { |
philpem@5 | 2116 | print("Blur image%s with standard deviation %g.",gmic_inds,sigma); |
philpem@5 | 2117 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],blur(sigma,borders?true:false)); |
philpem@5 | 2118 | } else error("Blur image%s : Invalid argument '%s' " |
philpem@5 | 2119 | "(should be 'stdev[,border_conditions]', with stdev>=0).",gmic_inds,argument_text); |
philpem@5 | 2120 | ++position; continue; |
philpem@5 | 2121 | } |
philpem@5 | 2122 | |
philpem@5 | 2123 | // Bilateral filter. |
philpem@5 | 2124 | if (!cimg::strcmp("-bilateral",item0)) { |
philpem@5 | 2125 | float sigmas = 0, sigmar = 0; char end = 0; |
philpem@5 | 2126 | if (std::sscanf(argument,"%f%*c%f%c",&sigmas,&sigmar,&end)==2) { |
philpem@5 | 2127 | print("Apply bilateral filter on image%s with standart deviations %g and %g.", |
philpem@5 | 2128 | gmic_inds,sigmas,sigmar); |
philpem@5 | 2129 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],blur_bilateral(sigmas,sigmar)); |
philpem@5 | 2130 | } else error("Apply bilateral filter on image%s : Invalid argument '%s' " |
philpem@5 | 2131 | "(should be 'stdevs,stdevr').",gmic_inds,argument_text); |
philpem@5 | 2132 | ++position; continue; |
philpem@5 | 2133 | } |
philpem@5 | 2134 | |
philpem@5 | 2135 | // Smooth. |
philpem@5 | 2136 | if (!cimg::strcmp("-smooth",item0)) { |
philpem@5 | 2137 | 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; |
philpem@5 | 2138 | unsigned int interpolation_type = 0, fast_approx = 1; |
philpem@5 | 2139 | char end = 0; |
philpem@5 | 2140 | if (std::sscanf(argument,"%f%c",&litude,&end)==1 || |
philpem@5 | 2141 | std::sscanf(argument,"%f%*c%f%c",&litude,&sharpness,&end)==2 || |
philpem@5 | 2142 | std::sscanf(argument,"%f%*c%f%*c%f%c",&litude,&sharpness,&anisotropy,&end)==3 || |
philpem@5 | 2143 | std::sscanf(argument,"%f%*c%f%*c%f%*c%f%c",&litude,&sharpness,&anisotropy,&alpha,&end)==4 || |
philpem@5 | 2144 | std::sscanf(argument,"%f%*c%f%*c%f%*c%f%*c%f%c",&litude,&sharpness,&anisotropy,&alpha,&sigma,&end)==5 || |
philpem@5 | 2145 | std::sscanf(argument,"%f%*c%f%*c%f%*c%f%*c%f%*c%f%c",&litude,&sharpness,&anisotropy,&alpha,&sigma,&dl,&end)==6 || |
philpem@5 | 2146 | 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 || |
philpem@5 | 2147 | std::sscanf(argument,"%f%*c%f%*c%f%*c%f%*c%f%*c%f%*c%f%*c%f%c", |
philpem@5 | 2148 | &litude,&sharpness,&anisotropy,&alpha,&sigma,&dl,&da,&gauss_prec,&end)==8 || |
philpem@5 | 2149 | std::sscanf(argument,"%f%*c%f%*c%f%*c%f%*c%f%*c%f%*c%f%*c%f%*c%u%c", |
philpem@5 | 2150 | &litude,&sharpness,&anisotropy,&alpha,&sigma,&dl,&da,&gauss_prec,&interpolation_type,&end)==9 || |
philpem@5 | 2151 | std::sscanf(argument,"%f%*c%f%*c%f%*c%f%*c%f%*c%f%*c%f%*c%f%*c%u%*c%u%c", |
philpem@5 | 2152 | &litude,&sharpness,&anisotropy,&alpha,&sigma,&dl,&da,&gauss_prec,&interpolation_type,&fast_approx,&end)==10) { |
philpem@5 | 2153 | print("Smooth image%s anisotropically with " |
philpem@5 | 2154 | "amplitude %g, sharpness %g, anisotropy %g, alpha %g and sigma %g.", |
philpem@5 | 2155 | gmic_inds,amplitude,sharpness,anisotropy,alpha,sigma); |
philpem@5 | 2156 | cimg_foroff(indices,l) |
philpem@5 | 2157 | gmic_apply(images[indices[l]],blur_anisotropic(amplitude,sharpness,anisotropy,alpha,sigma, |
philpem@5 | 2158 | dl,da,gauss_prec,interpolation_type,fast_approx?true:false)); |
philpem@5 | 2159 | } else error("Smooth image%s anisotropically : Invalid argument '%s' " |
philpem@5 | 2160 | "(should be 'amplitude[,sharpness[,anisotropy[,alpha[,sigma[,dl[,da[,prec[,interp[,fast]]]]]]]]]').", |
philpem@5 | 2161 | gmic_inds,argument_text); |
philpem@5 | 2162 | ++position; continue; |
philpem@5 | 2163 | } |
philpem@5 | 2164 | |
philpem@5 | 2165 | // Patch averaging. |
philpem@5 | 2166 | if (!cimg::strcmp("-denoise",item0)) { |
philpem@5 | 2167 | float sigmas = 10, sigmar = 10; int psize = 5, rsize = 6; char end = 0; |
philpem@5 | 2168 | if (std::sscanf(argument,"%f%c",&sigmas,&end)==1 || |
philpem@5 | 2169 | std::sscanf(argument,"%f%*c%f%c",&sigmas,&sigmar,&end)==2 || |
philpem@5 | 2170 | std::sscanf(argument,"%f%*c%f%*c%d%c",&sigmas,&sigmar,&psize,&end)==3 || |
philpem@5 | 2171 | std::sscanf(argument,"%f%*c%f%*c%d%*c%d%c",&sigmas,&sigmar,&psize,&rsize,&end)==4) { |
philpem@5 | 2172 | if (sigmas<0 || sigmar<0 || psize<0 || rsize<0) |
philpem@5 | 2173 | error("Denoise image%s with %dx%d patches, standard deviations %lg,%g and lookup size %d : " |
philpem@5 | 2174 | "Invalid parameters.",gmic_inds,psize,psize,sigmas,sigmar,rsize); |
philpem@5 | 2175 | print("Denoise image%s with %dx%d patches, standard deviations %lg,%g and lookup size %d.", |
philpem@5 | 2176 | gmic_inds,psize,psize,sigmas,sigmar,rsize); |
philpem@5 | 2177 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],blur_patch(psize,sigmas,sigmar,rsize)); |
philpem@5 | 2178 | } else error("Denoise image%s : Invalid argument '%s' " |
philpem@5 | 2179 | "(should be 'stdev_s[,stdev_p[,patch_size[,lookup_size]]]').", |
philpem@5 | 2180 | gmic_inds,argument_text); |
philpem@5 | 2181 | ++position; continue; |
philpem@5 | 2182 | } |
philpem@5 | 2183 | |
philpem@5 | 2184 | // Median filter. |
philpem@5 | 2185 | if (!cimg::strcmp("-median",item0)) { |
philpem@5 | 2186 | int siz = 3; char end = 0; |
philpem@5 | 2187 | if (std::sscanf(argument,"%d%c",&siz,&end)==1) { |
philpem@5 | 2188 | if (siz<=0) error("Apply median filter on image%s : Invalid size %d.",gmic_inds,siz); |
philpem@5 | 2189 | print("Apply median filter of size %d on image%s.",siz,gmic_inds); |
philpem@5 | 2190 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],blur_median(siz)); |
philpem@5 | 2191 | } else error("Apply median filter on image%s : Invalid argument '%s' " |
philpem@5 | 2192 | "(should be 'size').",gmic_inds,argument_text); |
philpem@5 | 2193 | ++position; continue; |
philpem@5 | 2194 | } |
philpem@5 | 2195 | |
philpem@5 | 2196 | // Sharpen. |
philpem@5 | 2197 | if (!cimg::strcmp("-sharpen",item0)) { |
philpem@5 | 2198 | float amplitude = 0, edge = 1, alpha = 0, sigma = 0; int sharpen_type = 0; char end = 0; |
philpem@5 | 2199 | if (std::sscanf(argument,"%f%c",&litude,&end)==1 || |
philpem@5 | 2200 | std::sscanf(argument,"%f%*c%d%c",&litude,&sharpen_type,&end)==2 || |
philpem@5 | 2201 | std::sscanf(argument,"%f%*c%d%*c%f%c",&litude,&sharpen_type,&edge,&end)==3 || |
philpem@5 | 2202 | std::sscanf(argument,"%f%*c%d%*c%f%*c%f%c",&litude,&sharpen_type,&edge,&alpha,&end)==4 || |
philpem@5 | 2203 | std::sscanf(argument,"%f%*c%d%*c%f%*c%f%*c%f%c",&litude,&sharpen_type,&edge,&alpha,&sigma,&end)==5) { |
philpem@5 | 2204 | if (sharpen_type) |
philpem@5 | 2205 | print("Sharpen image%s with shock filters and amplitude %g, edge %g, alpha %g and sigma %g.", |
philpem@5 | 2206 | gmic_inds,amplitude,edge,alpha,sigma); |
philpem@5 | 2207 | else |
philpem@5 | 2208 | print("Sharpen image%s with inverse diffusion and amplitude %g.",gmic_inds,amplitude); |
philpem@5 | 2209 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],sharpen(amplitude,sharpen_type?true:false,edge,alpha,sigma)); |
philpem@5 | 2210 | } else error("Sharpen image%s : Invalid argument '%s' " |
philpem@5 | 2211 | "(should be 'amplitude[,sharpen_type[,edge[,alpha[,sigma]]]]', " |
philpem@5 | 2212 | "where 'sharpen_type' can be '{0=inverse diffusion, 1=shock filters}').", |
philpem@5 | 2213 | gmic_inds,argument_text); |
philpem@5 | 2214 | ++position; continue; |
philpem@5 | 2215 | } |
philpem@5 | 2216 | |
philpem@5 | 2217 | // Convolve. |
philpem@5 | 2218 | if (!cimg::strcmp("-convolve",item0)) { |
philpem@5 | 2219 | int ind0 = no_ind, borders = 1; char sep = 0, end = 0; |
philpem@5 | 2220 | if ((std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==2 && sep==']') || |
philpem@5 | 2221 | std::sscanf(argument,"[%d]%*c%d%c",&ind0,&borders,&end)==2) { |
philpem@5 | 2222 | gmic_check_indice(ind0,"Convolve image%s"); |
philpem@5 | 2223 | print("Convolve image%s with mask [%d].",gmic_inds,ind0); |
philpem@5 | 2224 | const CImg<T> mask = images[ind0]; |
philpem@5 | 2225 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],convolve(mask,borders)); |
philpem@5 | 2226 | } else error("Convolve image%s : Invalid argument '%s' " |
philpem@5 | 2227 | "(should be '[indice][,border_conditions]').",gmic_inds,argument_text); |
philpem@5 | 2228 | ++position; continue; |
philpem@5 | 2229 | } |
philpem@5 | 2230 | |
philpem@5 | 2231 | // Correlate. |
philpem@5 | 2232 | if (!cimg::strcmp("-correlate",item0)) { |
philpem@5 | 2233 | int ind0 = no_ind, borders = 1; char sep = 0, end = 0; |
philpem@5 | 2234 | if ((std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==2 && sep==']') || |
philpem@5 | 2235 | std::sscanf(argument,"[%d]%*c%d%c",&ind0,&borders,&end)==2) { |
philpem@5 | 2236 | gmic_check_indice(ind0,"Correlate image%s"); |
philpem@5 | 2237 | print("Correlate image%s with mask [%d].",gmic_inds,ind0); |
philpem@5 | 2238 | const CImg<T> mask = images[ind0]; |
philpem@5 | 2239 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],correlate(mask,borders)); |
philpem@5 | 2240 | } else error("Correlate image%s : Invalid argument '%s' " |
philpem@5 | 2241 | "(should be '[indice][,border_conditions]').",gmic_inds,argument_text); |
philpem@5 | 2242 | ++position; continue; |
philpem@5 | 2243 | } |
philpem@5 | 2244 | |
philpem@5 | 2245 | // Erode. |
philpem@5 | 2246 | if (!cimg::strcmp("-erode",item0)) { |
philpem@5 | 2247 | int siz = 3, ind0 = no_ind, borders = 1; char sep = 0, end = 0; |
philpem@5 | 2248 | if ((std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==2 && sep==']') || |
philpem@5 | 2249 | std::sscanf(argument,"[%d]%*c%d%c",&ind0,&borders,&end)==2) { |
philpem@5 | 2250 | gmic_check_indice(ind0,"Erode image%s"); |
philpem@5 | 2251 | print("Erode image%s with mask [%d].",gmic_inds,ind0); |
philpem@5 | 2252 | const CImg<T> mask = images[ind0]; |
philpem@5 | 2253 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],erode(mask,borders)); |
philpem@5 | 2254 | } else if (std::sscanf(argument,"%d%c",&siz,&end)==1 || |
philpem@5 | 2255 | std::sscanf(argument,"%d%*c%d%c",&siz,&borders,&end)==2) { |
philpem@5 | 2256 | if (siz<=0) error("Erode image%s : Invalid size %d.",gmic_inds,siz); |
philpem@5 | 2257 | print("Erode image%s with size %d.",gmic_inds,siz); |
philpem@5 | 2258 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],erode(siz,borders)); |
philpem@5 | 2259 | } else error("Erode image%s : Invalid argument '%s' " |
philpem@5 | 2260 | "(should be '[indice]' or 'size').",gmic_inds,argument_text); |
philpem@5 | 2261 | ++position; continue; |
philpem@5 | 2262 | } |
philpem@5 | 2263 | |
philpem@5 | 2264 | // Dilate. |
philpem@5 | 2265 | if (!cimg::strcmp("-dilate",item0)) { |
philpem@5 | 2266 | int siz = 3, ind0 = no_ind, borders = 1; char sep = 0, end = 0; |
philpem@5 | 2267 | if ((std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==2 && sep==']') || |
philpem@5 | 2268 | std::sscanf(argument,"[%d]%*c%d%c",&ind0,&borders,&end)==2) { |
philpem@5 | 2269 | gmic_check_indice(ind0,"Dilate image%s"); |
philpem@5 | 2270 | print("Dilate image%s with mask [%d].",gmic_inds,ind0); |
philpem@5 | 2271 | const CImg<T> mask = images[ind0]; |
philpem@5 | 2272 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],dilate(mask,borders)); |
philpem@5 | 2273 | } else if (std::sscanf(argument,"%d%c",&siz,&end)==1 || |
philpem@5 | 2274 | std::sscanf(argument,"%d%*c%d%c",&siz,&borders,&end)==2) { |
philpem@5 | 2275 | if (siz<=0) error("Dilate image%s : Invalid size %d.",gmic_inds,siz); |
philpem@5 | 2276 | print("Dilate image%s with size %d.",gmic_inds,siz); |
philpem@5 | 2277 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],dilate(siz,borders)); |
philpem@5 | 2278 | } else error("Dilate image%s : Invalid argument '%s' " |
philpem@5 | 2279 | "(should be '[indice]' or 'size').",gmic_inds,argument_text); |
philpem@5 | 2280 | ++position; continue; |
philpem@5 | 2281 | } |
philpem@5 | 2282 | |
philpem@5 | 2283 | // Compute gradient. |
philpem@5 | 2284 | if (!cimg::strcmp("-gradient",item0)) { |
philpem@5 | 2285 | char axes[4096] = { 0 }, *naxes = 0, end = 0; int scheme = 3; |
philpem@5 | 2286 | print("Compute gradient of image%s.",gmic_inds); |
philpem@5 | 2287 | if (std::sscanf(argument,"%4095[xyz]%c",axes,&end)==1 || |
philpem@5 | 2288 | std::sscanf(argument,"%4095[xyz]%*c%d%c",axes,&scheme,&end)==2) { naxes = axes; ++position; } |
philpem@5 | 2289 | unsigned int off = 0; |
philpem@5 | 2290 | cimg_foroff(indices,l) { |
philpem@5 | 2291 | const unsigned int ind = indices[l] + off; |
philpem@5 | 2292 | CImg<T>& img = images[ind]; |
philpem@5 | 2293 | const CImg<char> filename = filenames[ind]; |
philpem@5 | 2294 | const CImgList<T> gradient = img.get_gradient(naxes,scheme); |
philpem@5 | 2295 | if (get_version) { |
philpem@5 | 2296 | images.insert(gradient); |
philpem@5 | 2297 | filenames.insert(gradient.size,filename); |
philpem@5 | 2298 | } else { |
philpem@5 | 2299 | images.remove(ind); images.insert(gradient,ind); |
philpem@5 | 2300 | filenames.remove(ind); filenames.insert(gradient.size,filename,ind); |
philpem@5 | 2301 | off+=gradient.size-1; |
philpem@5 | 2302 | } |
philpem@5 | 2303 | } |
philpem@5 | 2304 | continue; |
philpem@5 | 2305 | } |
philpem@5 | 2306 | |
philpem@5 | 2307 | // Compute Hessian. |
philpem@5 | 2308 | if (!cimg::strcmp("-hessian",item0)) { |
philpem@5 | 2309 | char axes[4096] = { 0 }, *naxes = 0, end = 0; |
philpem@5 | 2310 | print("Compute Hessian of image%s.",gmic_inds); |
philpem@5 | 2311 | if (std::sscanf(argument,"%4095[xyz]%c",axes,&end)==1) { naxes = axes; ++position; } |
philpem@5 | 2312 | unsigned int off = 0; |
philpem@5 | 2313 | cimg_foroff(indices,l) { |
philpem@5 | 2314 | const unsigned int ind = indices[l] + off; |
philpem@5 | 2315 | CImg<T>& img = images[ind]; |
philpem@5 | 2316 | const CImg<char> filename = filenames[ind]; |
philpem@5 | 2317 | const CImgList<T> hessian = img.get_hessian(naxes); |
philpem@5 | 2318 | if (get_version) { |
philpem@5 | 2319 | images.insert(hessian); |
philpem@5 | 2320 | filenames.insert(hessian.size,filename); |
philpem@5 | 2321 | } else { |
philpem@5 | 2322 | images.remove(ind); images.insert(hessian,ind); |
philpem@5 | 2323 | filenames.remove(ind); filenames.insert(hessian.size,filename,ind); |
philpem@5 | 2324 | off+=hessian.size-1; |
philpem@5 | 2325 | } |
philpem@5 | 2326 | } |
philpem@5 | 2327 | continue; |
philpem@5 | 2328 | } |
philpem@5 | 2329 | |
philpem@5 | 2330 | // Compute direct or inverse FFT. |
philpem@5 | 2331 | const bool inv_fft = !cimg::strcmp("-ifft",item0); |
philpem@5 | 2332 | if (!cimg::strcmp("-fft",item0) || inv_fft) { |
philpem@5 | 2333 | print("Compute %sFourier Transform of complex data",inv_fft?"inverse ":""); |
philpem@5 | 2334 | cimg_foroff(indices,l) { |
philpem@5 | 2335 | const unsigned int ind0 = indices[l], ind1 = l+1<_maxl?indices[l+1]:~0U; |
philpem@5 | 2336 | if (ind1!=~0U) { |
philpem@5 | 2337 | if (verbosity_level>=0) std::fprintf(cimg_stdout," ([%u],[%u])%c",ind0,ind1,l==_maxl-1?'.':','); |
philpem@5 | 2338 | CImgList<T> fft(images[ind0],images[ind1],!get_version); |
philpem@5 | 2339 | fft.FFT(inv_fft); |
philpem@5 | 2340 | if (get_version) { |
philpem@5 | 2341 | images.insert(2); |
philpem@5 | 2342 | fft[0].transfer_to(images[images.size-2]); |
philpem@5 | 2343 | fft[1].transfer_to(images[images.size-1]); |
philpem@5 | 2344 | filenames.insert(filenames[ind0]); |
philpem@5 | 2345 | filenames.insert(filenames[ind1]); |
philpem@5 | 2346 | } else { |
philpem@5 | 2347 | fft[0].transfer_to(images[ind0]); |
philpem@5 | 2348 | fft[1].transfer_to(images[ind1]); |
philpem@5 | 2349 | } |
philpem@5 | 2350 | ++l; |
philpem@5 | 2351 | } else { |
philpem@5 | 2352 | if (verbosity_level>=0) std::fprintf(cimg_stdout," ([%u],0)",ind0); |
philpem@5 | 2353 | CImgList<T> fft(images[ind0],!get_version); |
philpem@5 | 2354 | fft.insert(fft[0],~0U,false); |
philpem@5 | 2355 | fft[1].fill(0); |
philpem@5 | 2356 | fft.FFT(inv_fft); |
philpem@5 | 2357 | if (get_version) { |
philpem@5 | 2358 | images.insert(2); |
philpem@5 | 2359 | fft[0].transfer_to(images[images.size-2]); |
philpem@5 | 2360 | fft[1].transfer_to(images[images.size-1]); |
philpem@5 | 2361 | filenames.insert(2,filenames[ind0]); |
philpem@5 | 2362 | } else { |
philpem@5 | 2363 | fft[0].transfer_to(images[ind0]); |
philpem@5 | 2364 | images.insert(fft[1],1+ind0); |
philpem@5 | 2365 | filenames.insert(filenames[ind0],1+ind0); |
philpem@5 | 2366 | } |
philpem@5 | 2367 | } |
philpem@5 | 2368 | } |
philpem@5 | 2369 | continue; |
philpem@5 | 2370 | } |
philpem@5 | 2371 | |
philpem@5 | 2372 | //----------------------------- |
philpem@5 | 2373 | // Image creation and drawing |
philpem@5 | 2374 | //----------------------------- |
philpem@5 | 2375 | |
philpem@5 | 2376 | // Dimensions. |
philpem@5 | 2377 | if (!cimg::strcmp("-dimensions",item0)) { |
philpem@5 | 2378 | print("Get dimensions of image%s.",gmic_inds); |
philpem@5 | 2379 | cimg_foroff(indices,l) { |
philpem@5 | 2380 | CImg<T>& img = images[indices[l]]; |
philpem@5 | 2381 | CImg<int> dims = CImg<int>::vector(img.dimx(),img.dimy(),img.dimz(),img.dimv()); |
philpem@5 | 2382 | gmic_apply(img,replace(dims)); |
philpem@5 | 2383 | } |
philpem@5 | 2384 | continue; |
philpem@5 | 2385 | } |
philpem@5 | 2386 | |
philpem@5 | 2387 | // Stats. |
philpem@5 | 2388 | if (!cimg::strcmp("-stats",item0)) { |
philpem@5 | 2389 | print("Get statistics of image%s.",gmic_inds); |
philpem@5 | 2390 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],stats()); |
philpem@5 | 2391 | continue; |
philpem@5 | 2392 | } |
philpem@5 | 2393 | |
philpem@5 | 2394 | // Histogram. |
philpem@5 | 2395 | if (!cimg::strcmp("-histogram",item0)) { |
philpem@5 | 2396 | int nb_levels = 256; char sep = 0, end = 0; |
philpem@5 | 2397 | if (std::sscanf(argument,"%d%c",&nb_levels,&end)==1 || |
philpem@5 | 2398 | (std::sscanf(argument,"%d%c%c",&nb_levels,&sep,&end)==2 && sep=='%')) { |
philpem@5 | 2399 | print("Compute histogram of image%s using %d%s levels.",gmic_inds,nb_levels,sep=='%'?"%":""); |
philpem@5 | 2400 | cimg_foroff(indices,l) { |
philpem@5 | 2401 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 2402 | int nnb_levels = nb_levels; |
philpem@5 | 2403 | if (sep=='%') { double m, M = img.maxmin(m); nnb_levels = (int)cimg::round(nb_levels*(1+M-m)/100,1); } |
philpem@5 | 2404 | gmic_apply(images[indices[l]],histogram(nnb_levels)); |
philpem@5 | 2405 | } |
philpem@5 | 2406 | } else error("Compute histogram of image%s : Invalid argument '%s' " |
philpem@5 | 2407 | "(should be 'nb_levels[%%]').",gmic_inds,argument_text); |
philpem@5 | 2408 | ++position; continue; |
philpem@5 | 2409 | } |
philpem@5 | 2410 | |
philpem@5 | 2411 | // Distance function. |
philpem@5 | 2412 | if (!cimg::strcmp("-distance",item0)) { |
philpem@5 | 2413 | double value = 0; char sep = 0, end = 0; |
philpem@5 | 2414 | if (std::sscanf(argument,"%lf%c",&value,&end)==1 || |
philpem@5 | 2415 | (std::sscanf(argument,"%lf%c%c",&value,&sep,&end)==2 && sep=='%')) { |
philpem@5 | 2416 | print("Compute distance map of image%s to isovalue %g%s.",gmic_inds,value,sep=='%'?"%":""); |
philpem@5 | 2417 | cimg_foroff(indices,l) { |
philpem@5 | 2418 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 2419 | double isovalue = value; |
philpem@5 | 2420 | if (sep=='%') { double m, M = img.maxmin(m); isovalue = m + value*(M - m)/100; } |
philpem@5 | 2421 | gmic_apply(img,distance((T)isovalue)); |
philpem@5 | 2422 | } |
philpem@5 | 2423 | } else error("Compute distance function of image%s : Invalid argument '%s' " |
philpem@5 | 2424 | "(should be 'value[%%]').",gmic_inds,argument_text); |
philpem@5 | 2425 | ++position; continue; |
philpem@5 | 2426 | } |
philpem@5 | 2427 | |
philpem@5 | 2428 | // Apply Hamilton-Jacobi PDE to compute distance to 0. |
philpem@5 | 2429 | if (!cimg::strcmp("-hamilton",item0)) { |
philpem@5 | 2430 | int nb_iter = 0; float band_size = 0; char end = 0; |
philpem@5 | 2431 | if (std::sscanf(argument,"%d%c",&nb_iter,&end)==1 || |
philpem@5 | 2432 | std::sscanf(argument,"%d%*c%f%c",&nb_iter,&band_size,&end)==2) { |
philpem@5 | 2433 | print("Apply %d iterations of Hamilton-Jacobi PDE on image%s.",nb_iter,gmic_inds); |
philpem@5 | 2434 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],distance_hamilton((unsigned int)nb_iter,band_size)); |
philpem@5 | 2435 | } else error("Apply %d iterations of Hamilton-Jacobi PDE on image%s : Invalid argument '%s' " |
philpem@5 | 2436 | "(should be 'nb_iter[,band_size]', with band_size>0).",nb_iter,gmic_inds,argument_text); |
philpem@5 | 2437 | ++position; continue; |
philpem@5 | 2438 | } |
philpem@5 | 2439 | |
philpem@5 | 2440 | // Label regions. |
philpem@5 | 2441 | gmic_simple_item("-label",label_regions,"Label regions on image%s."); |
philpem@5 | 2442 | |
philpem@5 | 2443 | // Displacement field. |
philpem@5 | 2444 | if (!cimg::strcmp("-displacement",item0)) { |
philpem@5 | 2445 | float smooth = 0.1f, precision = 0.1f; int ind0 = no_ind, nbscales = 0, itermax = 1000; char sep = 0, end = 0; |
philpem@5 | 2446 | if ((std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==2 && sep==']') || |
philpem@5 | 2447 | std::sscanf(argument,"[%d]%*c%f%c",&ind0,&smooth,&end)==2 || |
philpem@5 | 2448 | std::sscanf(argument,"[%d]%*c%f%*c%f%c",&ind0,&smooth,&precision,&end)==3 || |
philpem@5 | 2449 | std::sscanf(argument,"[%d]%*c%f%*c%f%*c%d%c",&ind0,&smooth,&precision,&nbscales,&end)==4 || |
philpem@5 | 2450 | std::sscanf(argument,"[%d]%*c%f%*c%f%*c%d%*c%d%c",&ind0,&smooth,&precision,&nbscales,&itermax,&end)==5) { |
philpem@5 | 2451 | gmic_check_indice(ind0,"Compute displacement field of image%s"); |
philpem@5 | 2452 | print("Compute displacement field of image%s with target [%u] and smoothness %g.", |
philpem@5 | 2453 | gmic_inds,ind0,smooth); |
philpem@5 | 2454 | const CImg<T> target = images[ind0]; |
philpem@5 | 2455 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],displacement_field(target,smooth,precision,nbscales,itermax)); |
philpem@5 | 2456 | } else error("Compute displacement field of image%s : Invalid argument '%s' " |
philpem@5 | 2457 | "(should be '[indice][,smoothness[,precision[,nbscales[,itermax]]]]').",gmic_inds,argument_text); |
philpem@5 | 2458 | ++position; continue; |
philpem@5 | 2459 | } |
philpem@5 | 2460 | |
philpem@5 | 2461 | // Sort. |
philpem@5 | 2462 | gmic_simple_item("-sort",sort,"Sort values in image%s."); |
philpem@5 | 2463 | |
philpem@5 | 2464 | // PSNR. |
philpem@5 | 2465 | if (!cimg::strcmp("-psnr",item0)) { |
philpem@5 | 2466 | double valmax = 255; char end = 0; |
philpem@5 | 2467 | if (std::sscanf(argument,"%lf%c",&valmax,&end)==1) ++position; |
philpem@5 | 2468 | if (images.size) { |
philpem@5 | 2469 | const unsigned int siz = indices.size(); |
philpem@5 | 2470 | print("Compute a %ux%u matrix [%u] of PSNR values (max. pixel value is %g).",siz,siz,images.size,valmax); |
philpem@5 | 2471 | CImg<T> res(siz,siz,1,1,(T)-1); |
philpem@5 | 2472 | cimg_forXY(res,x,y) if (x>y) res(x,y) = res(y,x) = (T)images[indices[x]].PSNR(images[indices[y]],(float)valmax); |
philpem@5 | 2473 | images.insert(res); |
philpem@5 | 2474 | filenames.insert(CImg<char>("PSNR",5,1,1,1,false)); |
philpem@5 | 2475 | } else error("Compute PSNR : image list is empty."); |
philpem@5 | 2476 | continue; |
philpem@5 | 2477 | } |
philpem@5 | 2478 | |
philpem@5 | 2479 | // Draw point. |
philpem@5 | 2480 | if (!cimg::strcmp("-point",item0)) { |
philpem@5 | 2481 | char arg0[4096] = { 0 }, arg1[4096] = { 0 }, arg2[4096] = { 0 }, color[4096] = { 0 }; |
philpem@5 | 2482 | char sepx0 = 0, sepy0 = 0, sepz0 = 0, end = 0; |
philpem@5 | 2483 | float x0 = 0, y0 = 0, z0 = 0, opacity = 1; |
philpem@5 | 2484 | 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,+-]", |
philpem@5 | 2485 | arg0,arg1,arg2,&opacity,color)>=2 && |
philpem@5 | 2486 | ((std::sscanf(arg0,"%f%c%c",&x0,&sepx0,&end)==2 && sepx0=='%') || |
philpem@5 | 2487 | std::sscanf(arg0,"%f%c",&x0,&end)==1) && |
philpem@5 | 2488 | ((std::sscanf(arg1,"%f%c%c",&y0,&sepy0,&end)==2 && sepy0=='%') || |
philpem@5 | 2489 | std::sscanf(arg1,"%f%c",&y0,&end)==1) && |
philpem@5 | 2490 | ((std::sscanf(arg2,"%f%c%c",&z0,&sepz0,&end)==2 && sepz0=='%') || |
philpem@5 | 2491 | std::sscanf(arg2,"%f%c",&z0,&end)==1 || !arg2[0])) { |
philpem@5 | 2492 | print("Draw point (%g%s,%g%s,%g%s) with color '%s' and opacity %g on image%s.", |
philpem@5 | 2493 | x0,sepx0=='%'?"%":"",y0,sepy0=='%'?"%":"",z0,sepz0=='%'?"%":"", |
philpem@5 | 2494 | color[0]?color:"default",opacity,gmic_inds); |
philpem@5 | 2495 | cimg_foroff(indices,l) { |
philpem@5 | 2496 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 2497 | CImg<T> col(img.dimv(),1,1,1,0); |
philpem@5 | 2498 | col.fill(color,true); |
philpem@5 | 2499 | const int |
philpem@5 | 2500 | nx0 = (int)cimg::round(sepx0=='%'?x0*(img.dimx()-1)/100:x0,1), |
philpem@5 | 2501 | ny0 = (int)cimg::round(sepy0=='%'?y0*(img.dimy()-1)/100:y0,1), |
philpem@5 | 2502 | nz0 = (int)cimg::round(sepz0=='%'?z0*(img.dimz()-1)/100:z0,1); |
philpem@5 | 2503 | gmic_apply(img,draw_point(nx0,ny0,nz0,col,opacity)); |
philpem@5 | 2504 | } |
philpem@5 | 2505 | } else error("Draw point on image%s : Invalid argument '%s' " |
philpem@5 | 2506 | "(should be 'x[%%],y[%%][,z[%%][,opacity[,color]]])",gmic_inds,argument_text); |
philpem@5 | 2507 | ++position; continue; |
philpem@5 | 2508 | } |
philpem@5 | 2509 | |
philpem@5 | 2510 | // Draw line. |
philpem@5 | 2511 | if (!cimg::strcmp("-line",item0)) { |
philpem@5 | 2512 | char arg0[4096] = { 0 }, arg1[4096] = { 0 }, arg2[4096] = { 0 }, arg3[4096] = { 0 }, color[4096] = { 0 }; |
philpem@5 | 2513 | char sepx0 = 0, sepy0 = 0, sepx1 = 0, sepy1 = 0, end = 0; |
philpem@5 | 2514 | float x0 = 0, y0 = 0, x1 = 0, y1 = 0, opacity = 1; |
philpem@5 | 2515 | if (std::sscanf(argument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]" |
philpem@5 | 2516 | "%*c%f%*c%4095[0-9.eE,+-]", |
philpem@5 | 2517 | arg0,arg1,arg2,arg3,&opacity,color)>=4 && |
philpem@5 | 2518 | ((std::sscanf(arg0,"%f%c%c",&x0,&sepx0,&end)==2 && sepx0=='%') || |
philpem@5 | 2519 | std::sscanf(arg0,"%f%c",&x0,&end)==1) && |
philpem@5 | 2520 | ((std::sscanf(arg1,"%f%c%c",&y0,&sepy0,&end)==2 && sepy0=='%') || |
philpem@5 | 2521 | std::sscanf(arg1,"%f%c",&y0,&end)==1) && |
philpem@5 | 2522 | ((std::sscanf(arg2,"%f%c%c",&x1,&sepx1,&end)==2 && sepx1=='%') || |
philpem@5 | 2523 | std::sscanf(arg2,"%f%c",&x1,&end)==1) && |
philpem@5 | 2524 | ((std::sscanf(arg3,"%f%c%c",&y1,&sepy1,&end)==2 && sepy1=='%') || |
philpem@5 | 2525 | std::sscanf(arg3,"%f%c",&y1,&end)==1)) { |
philpem@5 | 2526 | print("Draw line (%g%s,%g%s) - (%g%s,%g%s) with color '%s' and opacity %g on image%s.", |
philpem@5 | 2527 | x0,sepx0=='%'?"%":"",y0,sepy0=='%'?"%":"",x1,sepx1=='%'?"%":"",y1,sepy1=='%'?"%":"", |
philpem@5 | 2528 | color[0]?color:"default",opacity,gmic_inds); |
philpem@5 | 2529 | cimg_foroff(indices,l) { |
philpem@5 | 2530 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 2531 | CImg<T> col(img.dimv(),1,1,1,0); |
philpem@5 | 2532 | col.fill(color,true); |
philpem@5 | 2533 | const int |
philpem@5 | 2534 | nx0 = (int)cimg::round(sepx0=='%'?x0*(img.dimx()-1)/100:x0,1), |
philpem@5 | 2535 | ny0 = (int)cimg::round(sepy0=='%'?y0*(img.dimy()-1)/100:y0,1), |
philpem@5 | 2536 | nx1 = (int)cimg::round(sepx1=='%'?x1*(img.dimx()-1)/100:x1,1), |
philpem@5 | 2537 | ny1 = (int)cimg::round(sepy1=='%'?y1*(img.dimy()-1)/100:y1,1); |
philpem@5 | 2538 | gmic_apply(img,draw_line(nx0,ny0,nx1,ny1,col,opacity)); |
philpem@5 | 2539 | } |
philpem@5 | 2540 | } else error("Draw line on image%s : Invalid argument '%s' " |
philpem@5 | 2541 | "(should be 'x0[%%],y0[%%],x1[%%],y1[%%][,opacity[,color]]')",gmic_inds,argument_text); |
philpem@5 | 2542 | ++position; continue; |
philpem@5 | 2543 | } |
philpem@5 | 2544 | |
philpem@5 | 2545 | // Draw polygon. |
philpem@5 | 2546 | if (!cimg::strcmp("-polygon",item0)) { |
philpem@5 | 2547 | char arg0[4096] = { 0 }, arg1[4096] = { 0 }, tmp[4096] = { 0 }, sepx0 = 0, sepy0 = 0, end = 0; |
philpem@5 | 2548 | int N = 0; float x0 = 0, y0 = 0, opacity = 1; |
philpem@5 | 2549 | if (std::sscanf(argument,"%d%c",&N,&end)==2 && N>2) { |
philpem@5 | 2550 | const char |
philpem@5 | 2551 | *nargument = argument + std::sprintf(tmp,"%d",N) + 1, |
philpem@5 | 2552 | *const eargument = argument + cimg::strlen(argument); |
philpem@5 | 2553 | CImg<float> coords0(N,2,1,1,0); |
philpem@5 | 2554 | CImg<bool> percents(N,2,1,1,0); |
philpem@5 | 2555 | for (int n = 0; n<N; ++n) if (nargument<eargument) { |
philpem@5 | 2556 | if (std::sscanf(nargument,"%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]",arg0,arg1)==2 && |
philpem@5 | 2557 | ((std::sscanf(arg0,"%f%c%c",&x0,&(sepx0=0),&end)==2 && sepx0=='%') || |
philpem@5 | 2558 | std::sscanf(arg0,"%f%c",&x0,&end)==1) && |
philpem@5 | 2559 | ((std::sscanf(arg1,"%f%c%c",&y0,&(sepy0=0),&end)==2 && sepy0=='%') || |
philpem@5 | 2560 | std::sscanf(arg1,"%f%c",&y0,&end)==1)) { |
philpem@5 | 2561 | coords0(n,0) = x0; percents(n,0) = (sepx0=='%'); |
philpem@5 | 2562 | coords0(n,1) = y0; percents(n,1) = (sepy0=='%'); |
philpem@5 | 2563 | nargument+=cimg::strlen(arg0) + cimg::strlen(arg1) + 2; |
philpem@5 | 2564 | } else error("Draw polygon on image%s : Invalid or incomplete argument '%s' " |
philpem@5 | 2565 | "(should be 'N,x0[%%],y0[%%],x1[%%],y1[%%],..,xN[%%],yN[%%][,opacity[,color]]' with N>=3)", |
philpem@5 | 2566 | gmic_inds,argument_text); |
philpem@5 | 2567 | } else error("Draw polygon on image%s : Incomplete argument '%s' " |
philpem@5 | 2568 | "(%d xy-coordinates should be defined)", |
philpem@5 | 2569 | gmic_inds,argument_text,N); |
philpem@5 | 2570 | if (nargument<eargument && std::sscanf(nargument,"%4095[0-9.eE+-]",arg0)==1 && |
philpem@5 | 2571 | std::sscanf(arg0,"%f",&opacity)==1) nargument+=cimg::strlen(arg0)+1; |
philpem@5 | 2572 | const char *const color = nargument<eargument?nargument:&(end=0); |
philpem@5 | 2573 | print("Draw %d-vertices polygon with color '%s' and opacity %g on image%s.", |
philpem@5 | 2574 | N,color[0]?color:"default",opacity,gmic_inds); |
philpem@5 | 2575 | cimg_foroff(indices,l) { |
philpem@5 | 2576 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 2577 | CImg<int> coords(coords0); |
philpem@5 | 2578 | cimg_forX(coords,p) { |
philpem@5 | 2579 | if (percents(p,0)) coords(p,0) = (int)cimg::round(coords0(p,0)*(img.dimx()-1)/100,1); |
philpem@5 | 2580 | if (percents(p,1)) coords(p,1) = (int)cimg::round(coords0(p,1)*(img.dimy()-1)/100,1); |
philpem@5 | 2581 | } |
philpem@5 | 2582 | CImg<T> col(img.dimv(),1,1,1,0); |
philpem@5 | 2583 | col.fill(color,true); |
philpem@5 | 2584 | gmic_apply(img,draw_polygon(coords,col,opacity)); |
philpem@5 | 2585 | } |
philpem@5 | 2586 | } else error("Draw polygon on image%s : Invalid argument '%s' " |
philpem@5 | 2587 | "(should be 'N,x0[%%],y0[%%],x1[%%],y1[%%],..,xN[%%],yN[%%][,opacity[,color]]' with N>=3)", |
philpem@5 | 2588 | gmic_inds,argument_text); |
philpem@5 | 2589 | ++position; continue; |
philpem@5 | 2590 | } |
philpem@5 | 2591 | |
philpem@5 | 2592 | // Draw ellipse. |
philpem@5 | 2593 | if (!cimg::strcmp("-ellipse",item0)) { |
philpem@5 | 2594 | char arg0[4096] = { 0 }, arg1[4096] = { 0 }, color[4096] = { 0 }; |
philpem@5 | 2595 | char sepx0 = 0, sepy0 = 0, end = 0; |
philpem@5 | 2596 | float x0 = 0, y0 = 0, r0 = 0, r1 = 0, ru = 1, rv = 0, opacity = 1; |
philpem@5 | 2597 | 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,+-]", |
philpem@5 | 2598 | arg0,arg1,&r0,&r1,&ru,&rv,&opacity,color)>=4 && |
philpem@5 | 2599 | ((std::sscanf(arg0,"%f%c%c",&x0,&sepx0,&end)==2 && sepx0=='%') || |
philpem@5 | 2600 | std::sscanf(arg0,"%f%c",&x0,&end)==1) && |
philpem@5 | 2601 | ((std::sscanf(arg1,"%f%c%c",&y0,&sepy0,&end)==2 && sepy0=='%') || |
philpem@5 | 2602 | std::sscanf(arg1,"%f%c",&y0,&end)==1)) { |
philpem@5 | 2603 | print("Draw ellipse centered at (%g%s,%g%s) with radii (%g,%g), orientation (%g,%g), color '%s' " |
philpem@5 | 2604 | "and opacity %g on image%s.", |
philpem@5 | 2605 | x0,sepx0=='%'?"%":"",y0,sepy0=='%'?"%":"", |
philpem@5 | 2606 | r0,r1,ru,rv,color[0]?color:"default",opacity,gmic_inds); |
philpem@5 | 2607 | cimg_foroff(indices,l) { |
philpem@5 | 2608 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 2609 | CImg<T> col(img.dimv(),1,1,1,0); |
philpem@5 | 2610 | col.fill(color,true); |
philpem@5 | 2611 | const int |
philpem@5 | 2612 | nx0 = (int)cimg::round(sepx0=='%'?x0*(img.dimx()-1)/100:x0,1), |
philpem@5 | 2613 | ny0 = (int)cimg::round(sepy0=='%'?y0*(img.dimy()-1)/100:y0,1); |
philpem@5 | 2614 | gmic_apply(img,draw_ellipse(nx0,ny0,r0,r1,ru,rv,col,opacity)); |
philpem@5 | 2615 | } |
philpem@5 | 2616 | } else error("Draw ellipse on image%s : Invalid argument '%s' " |
philpem@5 | 2617 | "(should be 'x[%%],y[%%],r,R[,u,v[,opacity[,color]]])", |
philpem@5 | 2618 | gmic_inds,argument_text); |
philpem@5 | 2619 | ++position; continue; |
philpem@5 | 2620 | } |
philpem@5 | 2621 | |
philpem@5 | 2622 | // Draw text. |
philpem@5 | 2623 | if (!cimg::strcmp("-text",item0)) { |
philpem@5 | 2624 | char arg0[4096] = { 0 }, arg1[4096] = { 0 }, color[4096] = { 0 }, text[4096] = { 0 }; |
philpem@5 | 2625 | char sepx0 = 0, sepy0 = 0, end = 0; |
philpem@5 | 2626 | float x0 = 0, y0 = 0, opacity = 1; int siz = 11; |
philpem@5 | 2627 | if (std::sscanf(argument,"%4095[^,],%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%d%*c%f%*c%4095[0-9.eE,+-]", |
philpem@5 | 2628 | text,arg0,arg1,&siz,&opacity,color)>=1 && |
philpem@5 | 2629 | ((std::sscanf(arg0,"%f%c%c",&x0,&sepx0,&end)==2 && sepx0=='%') || |
philpem@5 | 2630 | std::sscanf(arg0,"%f%c",&x0,&end)==1 || !arg0[0]) && |
philpem@5 | 2631 | ((std::sscanf(arg1,"%f%c%c",&y0,&sepy0,&end)==2 && sepy0=='%') || |
philpem@5 | 2632 | std::sscanf(arg1,"%f%c",&y0,&end)==1 || !arg1[0])) { |
philpem@5 | 2633 | cimg::strclean(text); cimg::strescape(text); |
philpem@5 | 2634 | print("Draw text \"%s\" at position (%g%s,%g%s) with font size %d, color '%s' " |
philpem@5 | 2635 | "and opacity %f on image%s.", |
philpem@5 | 2636 | text,x0,sepx0=='%'?"%":"",y0,sepy0=='%'?"%":"",siz,color[0]?color:"default",opacity,gmic_inds); |
philpem@5 | 2637 | cimg_foroff(indices,l) { |
philpem@5 | 2638 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 2639 | CImg<T> col(img.dimv(),1,1,1,0); |
philpem@5 | 2640 | col.fill(color,true); |
philpem@5 | 2641 | const int |
philpem@5 | 2642 | nx0 = (int)cimg::round(sepx0=='%'?x0*(img.dimx()-1)/100:x0,1), |
philpem@5 | 2643 | ny0 = (int)cimg::round(sepy0=='%'?y0*(img.dimy()-1)/100:y0,1); |
philpem@5 | 2644 | gmic_apply(img,draw_text(nx0,ny0,text,col.ptr(),0,opacity,siz)); |
philpem@5 | 2645 | } |
philpem@5 | 2646 | } else error("Draw text on image%s : Invalid argument '%s' " |
philpem@5 | 2647 | "(should be 'text[,x[%%],y[%%][,size[,opacity[,color]]]]').", |
philpem@5 | 2648 | gmic_inds,argument_text); |
philpem@5 | 2649 | ++position; continue; |
philpem@5 | 2650 | } |
philpem@5 | 2651 | |
philpem@5 | 2652 | // Draw image. |
philpem@5 | 2653 | if (!cimg::strcmp("-image",item0)) { |
philpem@5 | 2654 | char arg0[4096] = { 0 }, arg1[4096] = { 0 }, arg2[4096] = { 0 }, sep = 0, sepx = 0, sepy = 0, sepz = 0, end = 0; |
philpem@5 | 2655 | int ind0 = no_ind, indm0 = no_ind; float x = 0, y = 0, z = 0, opacity = 1; |
philpem@5 | 2656 | if (((std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==1 && sep==']') || |
philpem@5 | 2657 | std::sscanf(argument,"[%d]%*c%4095[0-9.eE%+-]%c",&ind0,arg0,&end)==2 || |
philpem@5 | 2658 | std::sscanf(argument,"[%d]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c",&ind0,arg0,arg1,&end)==3 || |
philpem@5 | 2659 | 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 || |
philpem@5 | 2660 | 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 || |
philpem@5 | 2661 | 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", |
philpem@5 | 2662 | &ind0,arg0,arg1,arg2,&opacity,&indm0,&sep,&end)==7) && |
philpem@5 | 2663 | (!*arg0 || |
philpem@5 | 2664 | std::sscanf(arg0,"%f%c",&x,&end)==1 || |
philpem@5 | 2665 | (std::sscanf(arg0,"%f%c%c",&x,&sepx,&end)==2 && sepx=='%')) && |
philpem@5 | 2666 | (!*arg1 || |
philpem@5 | 2667 | std::sscanf(arg1,"%f%c",&y,&end)==1 || |
philpem@5 | 2668 | (std::sscanf(arg1,"%f%c%c",&y,&sepy,&end)==2 && sepy=='%')) && |
philpem@5 | 2669 | (!*arg2 || |
philpem@5 | 2670 | std::sscanf(arg2,"%f%c",&z,&end)==1 || |
philpem@5 | 2671 | (std::sscanf(arg2,"%f%c%c",&z,&sepz,&end)==2 && sepz=='%'))) { |
philpem@5 | 2672 | gmic_check_indice(ind0,"Draw image on image%s"); |
philpem@5 | 2673 | const CImg<T> sprite = images[ind0]; |
philpem@5 | 2674 | CImg<T> mask; |
philpem@5 | 2675 | if (indm0!=no_ind) { |
philpem@5 | 2676 | gmic_check_indice(indm0,"Draw image on image%s"); |
philpem@5 | 2677 | mask = images[indm0]; |
philpem@5 | 2678 | print("Draw image [%d] at (%g%s,%g%s,%g%s), with mask [%d] and opacity %f on image%s.", |
philpem@5 | 2679 | ind0,x,sepx=='%'?"%":"",y,sepy=='%'?"%":"",z,sepz=='%'?"%":"",indm0,opacity,gmic_inds); |
philpem@5 | 2680 | } else print("Draw image [%d] at (%g%s,%g%s,%g%s) with opacity %f on image%s.", |
philpem@5 | 2681 | ind0,x,sepx=='%'?"%":"",y,sepy=='%'?"%":"",z,sepz=='%'?"%":"",opacity,gmic_inds); |
philpem@5 | 2682 | cimg_foroff(indices,l) { |
philpem@5 | 2683 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 2684 | const int |
philpem@5 | 2685 | nx = (int)cimg::round(sepx=='%'?x*(img.dimx()-1)/100:x,1), |
philpem@5 | 2686 | ny = (int)cimg::round(sepy=='%'?y*(img.dimy()-1)/100:y,1), |
philpem@5 | 2687 | nz = (int)cimg::round(sepz=='%'?z*(img.dimz()-1)/100:z,1); |
philpem@5 | 2688 | if (indm0!=no_ind) { gmic_apply(img,draw_image(nx,ny,nz,sprite,mask,opacity)); } |
philpem@5 | 2689 | else { gmic_apply(img,draw_image(nx,ny,nz,sprite,opacity)); } |
philpem@5 | 2690 | } |
philpem@5 | 2691 | } else error("Draw image on image%s : Invalid argument '%s' " |
philpem@5 | 2692 | "(should be '[indice][,x[%%][,y[%%][,z[%%][,opacity[,indice_mask]]]]]').", |
philpem@5 | 2693 | gmic_inds,argument_text); |
philpem@5 | 2694 | ++position; continue; |
philpem@5 | 2695 | } |
philpem@5 | 2696 | |
philpem@5 | 2697 | // Draw 3D object. |
philpem@5 | 2698 | if (!cimg::strcmp("-object3d",item0)) { |
philpem@5 | 2699 | char arg0[4096] = { 0 }, arg1[4096] = { 0 }, sep = 0, sepx = 0, sepy = 0, end = 0; |
philpem@5 | 2700 | float x = 0, y = 0, z = 0, opacity = 1; |
philpem@5 | 2701 | int ind0 = no_ind; |
philpem@5 | 2702 | if (((std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==2 && sep==']') || |
philpem@5 | 2703 | std::sscanf(argument,"[%d]%*c%4095[0-9.eE%+-]%c",&ind0,arg0,&end)==2 || |
philpem@5 | 2704 | std::sscanf(argument,"[%d]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%c",&ind0,arg0,arg1,&end)==3 || |
philpem@5 | 2705 | std::sscanf(argument,"[%d]%*c%4095[0-9.eE%+-]%*c%4095[0-9.eE%+-]%*c%f%c",&ind0,arg0,arg1,&z,&end)==4 || |
philpem@5 | 2706 | 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) && |
philpem@5 | 2707 | (!*arg0 || |
philpem@5 | 2708 | std::sscanf(arg0,"%f%c",&x,&end)==1 || |
philpem@5 | 2709 | (std::sscanf(arg0,"%f%c%c",&x,&sepx,&end)==2 && sepx=='%')) && |
philpem@5 | 2710 | (!*arg1 || |
philpem@5 | 2711 | std::sscanf(arg1,"%f%c",&y,&end)==1 || |
philpem@5 | 2712 | (std::sscanf(arg1,"%f%c%c",&y,&sepy,&end)==2 && sepy=='%'))) { |
philpem@5 | 2713 | gmic_check_indice(ind0,"Draw 3D object on image%s"); |
philpem@5 | 2714 | if (!images[ind0].is_CImg3d()) |
philpem@5 | 2715 | error("Draw 3D object on image%s : Image [%d] is not a 3D object.",gmic_inds,ind0); |
philpem@5 | 2716 | print("Draw 3D object [%d] at (%g%s,%g%s,%g) on image%s, with opacity %g.", |
philpem@5 | 2717 | ind0,x,sepx=='%'?"%":"",y,sepy=='%'?"%":"",z,gmic_inds,opacity); |
philpem@5 | 2718 | CImgList<unsigned int> primitives3d; |
philpem@5 | 2719 | CImgList<unsigned char> colors3d; |
philpem@5 | 2720 | CImg<float> opacities3d, points3d(images[ind0]); |
philpem@5 | 2721 | points3d.CImg3dtoobject3d(primitives3d,colors3d,opacities3d); |
philpem@5 | 2722 | opacities3d*=opacity; |
philpem@5 | 2723 | cimg_foroff(indices,l) { |
philpem@5 | 2724 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 2725 | const float |
philpem@5 | 2726 | nx = (float)cimg::round(sepx=='%'?x*(img.dimx()-1)/100:x,1), |
philpem@5 | 2727 | ny = (float)cimg::round(sepy=='%'?y*(img.dimy()-1)/100:y,1); |
philpem@5 | 2728 | gmic_apply(img,draw_object3d(nx,ny,z,points3d,primitives3d,colors3d,opacities3d, |
philpem@5 | 2729 | render3d,!is_oriented3d,focale3d,light3d_x,light3d_y,light3d_z,specular_light3d, |
philpem@5 | 2730 | specular_shine3d,0)); |
philpem@5 | 2731 | } |
philpem@5 | 2732 | } else error("Draw 3D object on image%s : Invalid argument '%s' " |
philpem@5 | 2733 | "(should be '[indice][,x[%%][,y[%%][,z[,opacity[,zoom[,u1,v1,w1,angle1[,...]]]]]]]').", |
philpem@5 | 2734 | gmic_inds,argument_text); |
philpem@5 | 2735 | ++position; continue; |
philpem@5 | 2736 | } |
philpem@5 | 2737 | |
philpem@5 | 2738 | // Draw plasma fractal. |
philpem@5 | 2739 | if (!cimg::strcmp("-plasma",item0)) { |
philpem@5 | 2740 | float alpha = 1, beta = 1, opacity = 1; char end = 0; |
philpem@5 | 2741 | if (std::sscanf(argument,"%f%c",&alpha,&end)==1 || |
philpem@5 | 2742 | std::sscanf(argument,"%f%*c%f%c",&alpha,&beta,&end)==2 || |
philpem@5 | 2743 | std::sscanf(argument,"%f%*c%f%*c%f%c",&alpha,&beta,&opacity,&end)==3) { |
philpem@5 | 2744 | print("Draw plasma in image%s with alpha %g, beta %g and opacity %g.",gmic_inds,alpha,beta,opacity); |
philpem@5 | 2745 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],draw_plasma(alpha,beta,opacity)); |
philpem@5 | 2746 | } else error("Draw plasma in image%d : Invalid argument '%s' " |
philpem@5 | 2747 | "(should be 'alpha[,beta[,opacity]]').",gmic_inds,argument_text); |
philpem@5 | 2748 | ++position; continue; |
philpem@5 | 2749 | } |
philpem@5 | 2750 | |
philpem@5 | 2751 | // Draw Mandelbrot/Julia fractal. |
philpem@5 | 2752 | if (!cimg::strcmp("-mandelbrot",item0)) { |
philpem@5 | 2753 | double z0r = -2, z0i = -2, z1r = 2, z1i = 2, paramr = 0, parami = 0; char end = 0; |
philpem@5 | 2754 | float opacity = 1; int itermax = 100, julia = 0; |
philpem@5 | 2755 | if (std::sscanf(argument,"%lf%*c%lf%*c%lf%*c%lf%c",&z0r,&z0i,&z1r,&z1i,&end)==4 || |
philpem@5 | 2756 | std::sscanf(argument,"%lf%*c%lf%*c%lf%*c%lf%*c%d%c",&z0r,&z0i,&z1r,&z1i,&itermax,&end)==5 || |
philpem@5 | 2757 | std::sscanf(argument,"%lf%*c%lf%*c%lf%*c%lf%*c%d%*c%d%*c%lf%*c%lf%c", |
philpem@5 | 2758 | &z0r,&z0i,&z1r,&z1i,&itermax,&julia,¶mr,¶mi,&end)==8 || |
philpem@5 | 2759 | std::sscanf(argument,"%lf%*c%lf%*c%lf%*c%lf%*c%d%*c%d%*c%lf%*c%lf%*c%f%c", |
philpem@5 | 2760 | &z0r,&z0i,&z1r,&z1i,&itermax,&julia,¶mr,¶mi,&opacity,&end)==9) { |
philpem@5 | 2761 | print("Draw %s fractal in image%s from complex area (%g,%g)-(%g,%g) with c0 = (%g,%g) (%d iterations).", |
philpem@5 | 2762 | julia?"Julia":"Mandelbrot",gmic_inds,z0r,z0i,z1r,z1i,paramr,parami,itermax); |
philpem@5 | 2763 | cimg_foroff(indices,l) |
philpem@5 | 2764 | gmic_apply(images[indices[l]],draw_mandelbrot(CImg<T>(),opacity,z0r,z0i,z1r,z1i,itermax,true, |
philpem@5 | 2765 | julia?true:false,paramr,parami)); |
philpem@5 | 2766 | } else error("Draw fractal in image%s : Invalid argument '%s' " |
philpem@5 | 2767 | "(should be 'z0r,z0i,z1r,z1i[,itermax[,julia,c0r,c0i[,opacity]]]').",gmic_inds,argument_text); |
philpem@5 | 2768 | ++position; continue; |
philpem@5 | 2769 | } |
philpem@5 | 2770 | |
philpem@5 | 2771 | // Flood fill. |
philpem@5 | 2772 | if (!cimg::strcmp("-flood",item0)) { |
philpem@5 | 2773 | char arg0[4096] = { 0 }, arg1[4096] = { 0 }, arg2[4096] = { 0 }, color[4096] = { 0 }; |
philpem@5 | 2774 | char sepx = 0, sepy = 0, sepz = 0, end = 0; |
philpem@5 | 2775 | float x = 0, y = 0, z = 0, tolerance = 0, opacity = 1; |
philpem@5 | 2776 | 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,+-]", |
philpem@5 | 2777 | arg0,arg1,arg2,&tolerance,&opacity,color)>=1 && |
philpem@5 | 2778 | ((std::sscanf(arg0,"%f%c%c",&x,&sepx,&end)==2 && sepx=='%') || |
philpem@5 | 2779 | std::sscanf(arg0,"%f%c",&x,&end)==1) && |
philpem@5 | 2780 | ((std::sscanf(arg1,"%f%c%c",&y,&sepy,&end)==2 && sepy=='%') || |
philpem@5 | 2781 | std::sscanf(arg1,"%f%c",&y,&end)==1 || !arg1[0]) && |
philpem@5 | 2782 | ((std::sscanf(arg2,"%f%c%c",&z,&sepz,&end)==2 && sepz=='%') || |
philpem@5 | 2783 | std::sscanf(arg2,"%f%c",&z,&end)==1 || !arg2[0])) { |
philpem@5 | 2784 | print("Flood fill image%s from (%g%s,%g%s,%g%s) with tolerance %g, opacity %g and color '%s'.", |
philpem@5 | 2785 | gmic_inds,x,sepx=='%'?"%":"",y,sepy=='%'?"%":"",z,sepz=='%'?"%":"",tolerance,opacity,color); |
philpem@5 | 2786 | cimg_foroff(indices,l) { |
philpem@5 | 2787 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 2788 | CImg<T> col(img.dimv(),1,1,1,0); |
philpem@5 | 2789 | col.fill(color,true); |
philpem@5 | 2790 | const int |
philpem@5 | 2791 | nx = (int)cimg::round(sepx=='%'?x*(img.dimx()-1)/100:x,1), |
philpem@5 | 2792 | ny = (int)cimg::round(sepy=='%'?y*(img.dimy()-1)/100:y,1), |
philpem@5 | 2793 | nz = (int)cimg::round(sepz=='%'?z*(img.dimz()-1)/100:z,1); |
philpem@5 | 2794 | gmic_apply(img,draw_fill(nx,ny,nz,col,opacity,tolerance)); |
philpem@5 | 2795 | } |
philpem@5 | 2796 | } else error("Flood fill image%s : Invalid argument '%s' " |
philpem@5 | 2797 | "(should be 'x[,y[,z[,tolerance[,opacity[,color]]]]]').",gmic_inds,argument_text); |
philpem@5 | 2798 | ++position; continue; |
philpem@5 | 2799 | } |
philpem@5 | 2800 | |
philpem@5 | 2801 | //------------------------- |
philpem@5 | 2802 | // Image list manipulation |
philpem@5 | 2803 | //------------------------- |
philpem@5 | 2804 | |
philpem@5 | 2805 | // Remove specified image(s). |
philpem@5 | 2806 | if (!cimg::strcmp("-remove",item0) || !cimg::strcmp("-rm",item0)) { |
philpem@5 | 2807 | print("Remove image%s",gmic_inds); |
philpem@5 | 2808 | unsigned int off = 0; |
philpem@5 | 2809 | cimg_foroff(indices,l) { |
philpem@5 | 2810 | const unsigned int ind = indices[l] - off; |
philpem@5 | 2811 | images.remove(ind); filenames.remove(ind); |
philpem@5 | 2812 | ++off; |
philpem@5 | 2813 | } |
philpem@5 | 2814 | if (verbosity_level>=0) std::fprintf(cimg_stdout," (%u image%s left).",images.size,images.size==1?"":"s"); |
philpem@5 | 2815 | continue; |
philpem@5 | 2816 | } |
philpem@5 | 2817 | |
philpem@5 | 2818 | // Keep specified image(s). |
philpem@5 | 2819 | if (!cimg::strcmp("-keep",item0) || !cimg::strcmp("-k",item0)) { |
philpem@5 | 2820 | print("Keep image%s",gmic_inds); |
philpem@5 | 2821 | CImgList<T> nimages(indices.size()); |
philpem@5 | 2822 | cimg_foroff(indices,l) nimages[l].swap(images[indices[l]]); |
philpem@5 | 2823 | nimages.transfer_to(images); |
philpem@5 | 2824 | if (verbosity_level>=0) std::fprintf(cimg_stdout," (%u image%s left).",images.size,images.size==1?"":"s"); |
philpem@5 | 2825 | continue; |
philpem@5 | 2826 | } |
philpem@5 | 2827 | |
philpem@5 | 2828 | // Move image(s) to specified position. |
philpem@5 | 2829 | if (!cimg::strcmp("-move",item0) || !cimg::strcmp("-mv",item0)) { |
philpem@5 | 2830 | int ind0 = no_ind; char end = 0; |
philpem@5 | 2831 | if (std::sscanf(argument,"%d%c",&ind0,&end)==1) { |
philpem@5 | 2832 | if (ind0<0) ind0+=images.size; |
philpem@5 | 2833 | if (ind0<0) ind0 = 0; |
philpem@5 | 2834 | if (ind0>(int)images.size) ind0 = images.size; |
philpem@5 | 2835 | print("Move image%s to position %d.",gmic_inds,ind0); |
philpem@5 | 2836 | CImgList<T> nimages; |
philpem@5 | 2837 | CImgList<char> nfilenames; |
philpem@5 | 2838 | cimg_foroff(indices,l) { |
philpem@5 | 2839 | const unsigned int ind = indices[l]; |
philpem@5 | 2840 | nimages.insert(1); nimages.last().swap(images[ind]); |
philpem@5 | 2841 | nfilenames.insert(1); nfilenames.last().swap(filenames[ind]); |
philpem@5 | 2842 | } |
philpem@5 | 2843 | images.insert(nimages,ind0); filenames.insert(nfilenames,ind0); |
philpem@5 | 2844 | { cimglist_for(images,l) if (!images[l]) { images.remove(l); filenames.remove(l--); }} |
philpem@5 | 2845 | } else error("Move image%s : Invalid argument '%s' " |
philpem@5 | 2846 | "(should be 'position').",gmic_inds,argument_text); |
philpem@5 | 2847 | ++position; continue; |
philpem@5 | 2848 | } |
philpem@5 | 2849 | |
philpem@5 | 2850 | // Reverse images order. |
philpem@5 | 2851 | if (!cimg::strcmp("-reverse",item0)) { |
philpem@5 | 2852 | print("Reverse images order."); |
philpem@5 | 2853 | CImgList<T> nimages(indices.size()); |
philpem@5 | 2854 | CImgList<char> nfilenames(indices.size()); |
philpem@5 | 2855 | cimg_foroff(indices,l) { nimages[l].swap(images[indices[l]]); nfilenames[l].swap(filenames[indices[l]]); } |
philpem@5 | 2856 | nimages.reverse(); nfilenames.reverse(); |
philpem@5 | 2857 | { cimg_foroff(indices,l) { nimages[l].swap(images[indices[l]]); nfilenames[l].swap(filenames[indices[l]]); }} |
philpem@5 | 2858 | continue; |
philpem@5 | 2859 | } |
philpem@5 | 2860 | |
philpem@5 | 2861 | // Set image name. |
philpem@5 | 2862 | if (!cimg::strcmp("-name",item0)) { |
philpem@5 | 2863 | cimg_foroff(indices,l) filenames[indices[l]].assign(argument,cimg::strlen(argument)+1,1,1,1,false); |
philpem@5 | 2864 | ++position; continue; |
philpem@5 | 2865 | } |
philpem@5 | 2866 | |
philpem@5 | 2867 | //------------------------- |
philpem@5 | 2868 | // 3D objects manipulation |
philpem@5 | 2869 | //------------------------- |
philpem@5 | 2870 | |
philpem@5 | 2871 | // Generate 3D cube. |
philpem@5 | 2872 | if (!cimg::strcmp("-cube3d",item)) { |
philpem@5 | 2873 | float size = 100; char end = 0; |
philpem@5 | 2874 | if (std::sscanf(argument,"%f%c",&size,&end)==1) { |
philpem@5 | 2875 | print("Generate 3D cube with size %g.",size); |
philpem@5 | 2876 | CImgList<unsigned int> primitives3d; |
philpem@5 | 2877 | CImg<float> points3d = CImg<T>::cube3d(primitives3d,size); |
philpem@5 | 2878 | CImgList<unsigned char> colors3d(primitives3d.size,1,3,1,1,200); |
philpem@5 | 2879 | CImg<float> opacities3d(1,primitives3d.size,1,1,1); |
philpem@5 | 2880 | points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); |
philpem@5 | 2881 | images.insert(points3d); |
philpem@5 | 2882 | filenames.insert(CImg<char>("(gmic)",7,1,1,1,false)); |
philpem@5 | 2883 | } else error("Generate 3D cube : Invalid argument '%s' " |
philpem@5 | 2884 | "(should be 'size').",argument_text); |
philpem@5 | 2885 | ++position; continue; |
philpem@5 | 2886 | } |
philpem@5 | 2887 | |
philpem@5 | 2888 | // Generate 3D cone. |
philpem@5 | 2889 | if (!cimg::strcmp("-cone3d",item)) { |
philpem@5 | 2890 | float radius = 100, height = 200; char end = 0; unsigned int subdivisions = 24; |
philpem@5 | 2891 | if (std::sscanf(argument,"%f%c",&radius,&end)==1 || |
philpem@5 | 2892 | std::sscanf(argument,"%f%*c%f%c",&radius,&height,&end)==2 || |
philpem@5 | 2893 | std::sscanf(argument,"%f%*c%f%*c%u%c",&radius,&height,&subdivisions,&end)==3) { |
philpem@5 | 2894 | print("Generate 3D cone with radius %g, height %g and %u subdivisions.",radius,height,subdivisions); |
philpem@5 | 2895 | CImgList<unsigned int> primitives3d; |
philpem@5 | 2896 | CImg<float> points3d = CImg<T>::cone3d(primitives3d,radius,height,subdivisions); |
philpem@5 | 2897 | CImgList<unsigned char> colors3d(primitives3d.size,1,3,1,1,200); |
philpem@5 | 2898 | CImg<float> opacities3d(1,primitives3d.size,1,1,1); |
philpem@5 | 2899 | points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); |
philpem@5 | 2900 | images.insert(points3d); |
philpem@5 | 2901 | filenames.insert(CImg<char>("(gmic)",7,1,1,1,false)); |
philpem@5 | 2902 | } else error("Generate 3D cone : Invalid argument '%s' " |
philpem@5 | 2903 | "(should be 'radius[,height[,subdivisions]]').",argument_text); |
philpem@5 | 2904 | ++position; continue; |
philpem@5 | 2905 | } |
philpem@5 | 2906 | |
philpem@5 | 2907 | // Generate 3D cylinder. |
philpem@5 | 2908 | if (!cimg::strcmp("-cylinder3d",item)) { |
philpem@5 | 2909 | float radius = 100, height = 200; char end = 0; unsigned int subdivisions = 24; |
philpem@5 | 2910 | if (std::sscanf(argument,"%f%c",&radius,&end)==1 || |
philpem@5 | 2911 | std::sscanf(argument,"%f%*c%f%c",&radius,&height,&end)==2 || |
philpem@5 | 2912 | std::sscanf(argument,"%f%*c%f%*c%u%c",&radius,&height,&subdivisions,&end)==3) { |
philpem@5 | 2913 | print("Generate 3D cylinder with radius %g, height %g and %u subdivisions.",radius,height,subdivisions); |
philpem@5 | 2914 | CImgList<unsigned int> primitives3d; |
philpem@5 | 2915 | CImg<float> points3d = CImg<T>::cylinder3d(primitives3d,radius,height,subdivisions); |
philpem@5 | 2916 | CImgList<unsigned char> colors3d(primitives3d.size,1,3,1,1,200); |
philpem@5 | 2917 | CImg<float> opacities3d(1,primitives3d.size,1,1,1); |
philpem@5 | 2918 | points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); |
philpem@5 | 2919 | images.insert(points3d); |
philpem@5 | 2920 | filenames.insert(CImg<char>("(gmic)",7,1,1,1,false)); |
philpem@5 | 2921 | } else error("Generate 3D cylinder : Invalid argument '%s' " |
philpem@5 | 2922 | "(should be 'radius[,height[,subdivisions]]').",argument_text); |
philpem@5 | 2923 | ++position; continue; |
philpem@5 | 2924 | } |
philpem@5 | 2925 | |
philpem@5 | 2926 | // Generate 3D torus. |
philpem@5 | 2927 | if (!cimg::strcmp("-torus3d",item)) { |
philpem@5 | 2928 | float radius1 = 100, radius2 = 30; char end = 0; unsigned int subdivisions1 = 24, subdivisions2 = 12; |
philpem@5 | 2929 | if (std::sscanf(argument,"%f%*c%f%c",&radius1,&radius2,&end)==2 || |
philpem@5 | 2930 | std::sscanf(argument,"%f%*c%f%*c%u%*c%u%c",&radius1,&radius2,&subdivisions1,&subdivisions2,&end)==4) { |
philpem@5 | 2931 | print("Generate 3D torus with radii %g and %g, and subdivisions %u and %u.",radius1,radius2,subdivisions1,subdivisions2); |
philpem@5 | 2932 | CImgList<unsigned int> primitives3d; |
philpem@5 | 2933 | CImg<float> points3d = CImg<T>::torus3d(primitives3d,radius1,radius2,subdivisions1,subdivisions2); |
philpem@5 | 2934 | CImgList<unsigned char> colors3d(primitives3d.size,1,3,1,1,200); |
philpem@5 | 2935 | CImg<float> opacities3d(1,primitives3d.size,1,1,1); |
philpem@5 | 2936 | points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); |
philpem@5 | 2937 | images.insert(points3d); |
philpem@5 | 2938 | filenames.insert(CImg<char>("(gmic)",7,1,1,1,false)); |
philpem@5 | 2939 | } else error("Generate 3D torus : Invalid argument '%s' " |
philpem@5 | 2940 | "(should be 'radius1,radius2[,subdivisions1,subdivisions2]').",argument_text); |
philpem@5 | 2941 | ++position; continue; |
philpem@5 | 2942 | } |
philpem@5 | 2943 | |
philpem@5 | 2944 | // Generate 3D plane. |
philpem@5 | 2945 | if (!cimg::strcmp("-plane3d",item)) { |
philpem@5 | 2946 | float sizex = 100, sizey = 30; char end = 0; unsigned int subdivisionsx = 24, subdivisionsy = 12; |
philpem@5 | 2947 | if (std::sscanf(argument,"%f%*c%f%c",&sizex,&sizey,&end)==2 || |
philpem@5 | 2948 | std::sscanf(argument,"%f%*c%f%*c%u%*c%u%c",&sizex,&sizey,&subdivisionsx,&subdivisionsy,&end)==4) { |
philpem@5 | 2949 | print("Generate 3D plane with dimensions %g and %g, and subdivisions %u and %u.",sizex,sizey,subdivisionsx,subdivisionsy); |
philpem@5 | 2950 | CImgList<unsigned int> primitives3d; |
philpem@5 | 2951 | CImg<float> points3d = CImg<T>::plane3d(primitives3d,sizex,sizey,subdivisionsx,subdivisionsy); |
philpem@5 | 2952 | CImgList<unsigned char> colors3d(primitives3d.size,1,3,1,1,200); |
philpem@5 | 2953 | CImg<float> opacities3d(1,primitives3d.size,1,1,1); |
philpem@5 | 2954 | points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); |
philpem@5 | 2955 | images.insert(points3d); |
philpem@5 | 2956 | filenames.insert(CImg<char>("(gmic)",7,1,1,1,false)); |
philpem@5 | 2957 | } else error("Generate 3D plane : Invalid argument '%s' " |
philpem@5 | 2958 | "(should be 'sizex,sizey[,subdivisionsx,subdivisionsy]').",argument_text); |
philpem@5 | 2959 | ++position; continue; |
philpem@5 | 2960 | } |
philpem@5 | 2961 | |
philpem@5 | 2962 | // Generate 3D sphere. |
philpem@5 | 2963 | if (!cimg::strcmp("-sphere3d",item)) { |
philpem@5 | 2964 | float radius = 100; char end = 0; unsigned int subdivisions = 3; |
philpem@5 | 2965 | if (std::sscanf(argument,"%f%c",&radius,&end)==1 || |
philpem@5 | 2966 | std::sscanf(argument,"%f%*c%u%c",&radius,&subdivisions,&end)==2) { |
philpem@5 | 2967 | print("Generate 3D sphere with radius %g and %u subdivisions.",radius,subdivisions); |
philpem@5 | 2968 | CImgList<unsigned int> primitives3d; |
philpem@5 | 2969 | CImg<float> points3d = CImg<T>::sphere3d(primitives3d,radius,subdivisions); |
philpem@5 | 2970 | CImgList<unsigned char> colors3d(primitives3d.size,1,3,1,1,200); |
philpem@5 | 2971 | CImg<float> opacities3d(1,primitives3d.size,1,1,1); |
philpem@5 | 2972 | points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); |
philpem@5 | 2973 | images.insert(points3d); |
philpem@5 | 2974 | filenames.insert(CImg<char>("(gmic)",7,1,1,1,false)); |
philpem@5 | 2975 | } else error("Generate 3D sphere : Invalid argument '%s' " |
philpem@5 | 2976 | "(should be 'radius[,subdivisions]').",argument_text); |
philpem@5 | 2977 | ++position; continue; |
philpem@5 | 2978 | } |
philpem@5 | 2979 | |
philpem@5 | 2980 | // Build 3D elevation. |
philpem@5 | 2981 | if (!cimg::strcmp("-elevation3d",item0)) { |
philpem@5 | 2982 | float zfact = 0.2f; char end = 0, sep = 0; int ind0 = no_ind; |
philpem@5 | 2983 | if (std::sscanf(argument,"%f%c",&zfact,&end)==1 || |
philpem@5 | 2984 | (std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==2 && sep==']')) { |
philpem@5 | 2985 | CImg<typename CImg<T>::Tfloat> elev; |
philpem@5 | 2986 | if (ind0!=no_ind) { |
philpem@5 | 2987 | gmic_check_indice(ind0,"Build 3D elevation of image%s"); |
philpem@5 | 2988 | print("Build 3D elevation of image%s with elevation map [%d].",gmic_inds,ind0); |
philpem@5 | 2989 | if (images[ind0].dimv()==1) elev = images[ind0]; |
philpem@5 | 2990 | else elev = images[ind0].get_pointwise_norm(); |
philpem@5 | 2991 | } else print("Build 3D elevation of image%s with z-factor %g.",gmic_inds,zfact); |
philpem@5 | 2992 | cimg_foroff(indices,l) { |
philpem@5 | 2993 | CImg<T>& img = images[indices[l]]; |
philpem@5 | 2994 | CImgList<unsigned int> primitives3d; |
philpem@5 | 2995 | CImgList<unsigned char> colors3d; |
philpem@5 | 2996 | CImg<float> opacities3d, points3d; |
philpem@5 | 2997 | if (elev) points3d = img.get_elevation3d(primitives3d,colors3d,elev); |
philpem@5 | 2998 | else { |
philpem@5 | 2999 | if (img.dimv()==1) (elev = img)*=zfact; else (elev = img.get_pointwise_norm())*=zfact; |
philpem@5 | 3000 | points3d = img.get_elevation3d(primitives3d,colors3d,elev); |
philpem@5 | 3001 | elev.assign(); |
philpem@5 | 3002 | } |
philpem@5 | 3003 | opacities3d.assign(1,primitives3d.size,1,1,1); |
philpem@5 | 3004 | points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); |
philpem@5 | 3005 | gmic_apply(img,replace(points3d)); |
philpem@5 | 3006 | } |
philpem@5 | 3007 | } else error("Build 3D elevation : invalid argument '%s' " |
philpem@5 | 3008 | "(should be 'z-factor' or '[indice]').",argument_text); |
philpem@5 | 3009 | ++position; continue; |
philpem@5 | 3010 | } |
philpem@5 | 3011 | |
philpem@5 | 3012 | // Build 3D isovalue. |
philpem@5 | 3013 | if (!cimg::strcmp("-isovalue3d",item0)) { |
philpem@5 | 3014 | float value = 0; char end = 0; |
philpem@5 | 3015 | if (std::sscanf(argument,"%f%c",&value,&end)==1) { |
philpem@5 | 3016 | print("Build 3D isovalue %g of image%s.",value,gmic_inds); |
philpem@5 | 3017 | cimg_foroff(indices,l) { |
philpem@5 | 3018 | const unsigned int ind = indices[l]; |
philpem@5 | 3019 | CImg<T>& img = images[ind]; |
philpem@5 | 3020 | CImg<float> points3d; |
philpem@5 | 3021 | CImgList<unsigned int> primitives3d; |
philpem@5 | 3022 | CImgList<unsigned char> colors3d; |
philpem@5 | 3023 | CImg<float> opacities3d; |
philpem@5 | 3024 | CImg<unsigned char> palette; |
philpem@5 | 3025 | palette.assign(3,img.dim,1,1,220).noise(35,1); |
philpem@5 | 3026 | if (img.dim==1) palette(0) = palette(1) = palette(2) = 255; |
philpem@5 | 3027 | else { |
philpem@5 | 3028 | palette(0,0) = 255; palette(1,0) = 30; palette(2,0) = 30; |
philpem@5 | 3029 | palette(0,1) = 30; palette(1,1) = 255; palette(2,1) = 30; |
philpem@5 | 3030 | if (img.dim>=3) palette(0,2) = 30; palette(1,2) = 30; palette(2,2) = 255; |
philpem@5 | 3031 | } |
philpem@5 | 3032 | cimg_forV(img,k) { |
philpem@5 | 3033 | CImgList<unsigned int> prims; |
philpem@5 | 3034 | const CImg<float> pts = img.get_shared_channel(k).get_isovalue3d(prims,value); |
philpem@5 | 3035 | if (pts) { |
philpem@5 | 3036 | points3d.append_object3d(primitives3d,pts,prims); |
philpem@5 | 3037 | colors3d.insert(prims.size, |
philpem@5 | 3038 | CImg<unsigned char>::vector(palette(0,k),palette(1,k),palette(2,k))); |
philpem@5 | 3039 | } |
philpem@5 | 3040 | } |
philpem@5 | 3041 | opacities3d.assign(1,primitives3d.size,1,1,1); |
philpem@5 | 3042 | if (!points3d) |
philpem@5 | 3043 | warning("Build 3D isovalue of image [%u] : Isovalue %g not found.",ind,value); |
philpem@5 | 3044 | else points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); |
philpem@5 | 3045 | gmic_apply(img,replace(points3d)); |
philpem@5 | 3046 | } |
philpem@5 | 3047 | } else error("Build 3D isovalue of image%s : Invalid argument '%s' " |
philpem@5 | 3048 | "(should be 'isovalue').",gmic_inds,argument_text); |
philpem@5 | 3049 | ++position; continue; |
philpem@5 | 3050 | } |
philpem@5 | 3051 | |
philpem@5 | 3052 | // Center a 3D object. |
philpem@5 | 3053 | if (!cimg::strcmp("-center3d",item0) || !cimg::strcmp("-c3d",item0)) { |
philpem@5 | 3054 | print("Center 3D object%s.",gmic_inds); |
philpem@5 | 3055 | cimg_foroff(indices,l) { |
philpem@5 | 3056 | const unsigned int ind = indices[l]; |
philpem@5 | 3057 | if (!images[ind].is_CImg3d()) |
philpem@5 | 3058 | error("Center 3D object%s : Image [%d] is not a 3D object.",gmic_inds,ind); |
philpem@5 | 3059 | gmic_apply(images[ind],centerCImg3d()); |
philpem@5 | 3060 | } |
philpem@5 | 3061 | continue; |
philpem@5 | 3062 | } |
philpem@5 | 3063 | |
philpem@5 | 3064 | // Normalize a 3D object. |
philpem@5 | 3065 | if (!cimg::strcmp("-normalize3d",item0) || !cimg::strcmp("-n3d",item0)) { |
philpem@5 | 3066 | print("Normalize 3D object%s.",gmic_inds); |
philpem@5 | 3067 | cimg_foroff(indices,l) { |
philpem@5 | 3068 | const unsigned int ind = indices[l]; |
philpem@5 | 3069 | if (!images[ind].is_CImg3d()) |
philpem@5 | 3070 | error("Normalize 3D object%s : Image [%d] is not a 3D object.",gmic_inds,ind); |
philpem@5 | 3071 | gmic_apply(images[ind],normalizeCImg3d()); |
philpem@5 | 3072 | } |
philpem@5 | 3073 | continue; |
philpem@5 | 3074 | } |
philpem@5 | 3075 | |
philpem@5 | 3076 | // Rotate a 3D object. |
philpem@5 | 3077 | if (!cimg::strcmp("-rotate3d",item0) || !cimg::strcmp("-rot3d",item0)) { |
philpem@5 | 3078 | float u = 0, v = 0, w = 1, angle = 0; char end = 0; |
philpem@5 | 3079 | if (std::sscanf(argument,"%f%*c%f%*c%f%*c%f%c",&u,&v,&w,&angle,&end)==4) { |
philpem@5 | 3080 | print("Rotate 3D object%s around axis (%g,%g,%g) with angle %g.",gmic_inds,u,v,w,angle); |
philpem@5 | 3081 | const CImg<float> rot = CImg<float>::rotation_matrix(u,v,w,(float)(angle*cimg::valuePI/180)); |
philpem@5 | 3082 | cimg_foroff(indices,l) { |
philpem@5 | 3083 | const unsigned int ind = indices[l]; |
philpem@5 | 3084 | if (!images[ind].is_CImg3d()) |
philpem@5 | 3085 | error("Rotate 3D object%s : Image [%d] is not a 3D object.",gmic_inds,ind); |
philpem@5 | 3086 | gmic_apply(images[ind],rotateCImg3d(rot)); |
philpem@5 | 3087 | } |
philpem@5 | 3088 | } else error("Rotate 3D object%s : Invalid argument '%s' " |
philpem@5 | 3089 | "(should be 'u,v,w,angle').",gmic_inds,argument_text); |
philpem@5 | 3090 | ++position; continue; |
philpem@5 | 3091 | } |
philpem@5 | 3092 | |
philpem@5 | 3093 | // Add 3D objects together or translate a 3D object. |
philpem@5 | 3094 | if (!cimg::strcmp("-add3d",item0) || !cimg::strcmp("-+3d",item0)) { |
philpem@5 | 3095 | float tx = 0, ty = 0, tz = 0; int ind0 = no_ind; char sep = 0, end = 0; |
philpem@5 | 3096 | if (std::sscanf(argument,"%f%c",&tx,&end)==1 || |
philpem@5 | 3097 | std::sscanf(argument,"%f%*c%f%c",&tx,&ty,&end)==2 || |
philpem@5 | 3098 | std::sscanf(argument,"%f%*c%f%*c%f%c",&tx,&ty,&tz,&end)==3) { |
philpem@5 | 3099 | print("Translate 3D object%s with vector (%g,%g,%g).",gmic_inds,tx,ty,tz); |
philpem@5 | 3100 | cimg_foroff(indices,l) { |
philpem@5 | 3101 | const unsigned int ind = indices[l]; |
philpem@5 | 3102 | if (!images[ind].is_CImg3d()) |
philpem@5 | 3103 | error("Translate 3D object%s : Image [%d] is not a 3D object.",gmic_inds,ind); |
philpem@5 | 3104 | gmic_apply(images[ind],translateCImg3d(tx,ty,tz)); |
philpem@5 | 3105 | } |
philpem@5 | 3106 | ++position; |
philpem@5 | 3107 | } else if (std::sscanf(argument,"[%d%c%c",&ind0,&sep,&end)==2 && sep==']') { |
philpem@5 | 3108 | gmic_check_indice(ind0,"Merge object with 3D object%s."); |
philpem@5 | 3109 | const CImg<T> img0 = images[ind0]; |
philpem@5 | 3110 | if (!img0.is_CImg3d()) error("Merge object [%d] with 3D object%s : Image [%d] is not a 3D object.",ind0,gmic_inds,ind0); |
philpem@5 | 3111 | print("Merge object [%d] with 3D object%s.",ind0,gmic_inds); |
philpem@5 | 3112 | cimg_foroff(indices,l) { |
philpem@5 | 3113 | const unsigned int ind = indices[l]; |
philpem@5 | 3114 | const CImg<T> &img = images[ind]; |
philpem@5 | 3115 | if (!img.is_CImg3d()) |
philpem@5 | 3116 | error("Merge object [%d] with 3D object%s : Image [%d] is not a 3D object.",ind0,gmic_inds,ind); |
philpem@5 | 3117 | gmic_apply(images[ind],appendCImg3d(img0)); |
philpem@5 | 3118 | } |
philpem@5 | 3119 | ++position; |
philpem@5 | 3120 | } else { |
philpem@5 | 3121 | print("Merge 3D object%s together.",gmic_inds); |
philpem@5 | 3122 | if (indices) { |
philpem@5 | 3123 | const unsigned int ind0 = indices[0]; |
philpem@5 | 3124 | if (!images[ind0].is_CImg3d()) |
philpem@5 | 3125 | error("Merge 3D object%s together : Image [%d] is not a 3D object.",gmic_inds,ind0); |
philpem@5 | 3126 | for (unsigned int siz = indices.size(), off = 0, l = 1; l<siz; ++l) { |
philpem@5 | 3127 | const unsigned int ind = indices[l] - off; |
philpem@5 | 3128 | if (!images[ind].is_CImg3d()) |
philpem@5 | 3129 | error("Merge 3D object%s together : Image [%d] is not a 3D object.",gmic_inds,ind); |
philpem@5 | 3130 | images[ind0].appendCImg3d(images[ind]); |
philpem@5 | 3131 | images.remove(ind); filenames.remove(ind); |
philpem@5 | 3132 | ++off; |
philpem@5 | 3133 | } |
philpem@5 | 3134 | } |
philpem@5 | 3135 | } |
philpem@5 | 3136 | continue; |
philpem@5 | 3137 | } |
philpem@5 | 3138 | |
philpem@5 | 3139 | // Translate 3D object by the opposite vector. |
philpem@5 | 3140 | if (!cimg::strcmp("-sub3d",item0) || !cimg::strcmp("--3d",item0)) { |
philpem@5 | 3141 | float tx = 0, ty = 0, tz = 0; char end = 0; |
philpem@5 | 3142 | if (std::sscanf(argument,"%f%c",&tx,&end)==1 || |
philpem@5 | 3143 | std::sscanf(argument,"%f%*c%f%c",&tx,&ty,&end)==2 || |
philpem@5 | 3144 | std::sscanf(argument,"%f%*c%f%*c%f%c",&tx,&ty,&tz,&end)==3) { |
philpem@5 | 3145 | print("Translate 3D object%s with vector -(%g,%g,%g).",gmic_inds,tx,ty,tz); |
philpem@5 | 3146 | cimg_foroff(indices,l) { |
philpem@5 | 3147 | CImg<T>& img = images[indices[l]]; |
philpem@5 | 3148 | CImgList<unsigned int> primitives3d; |
philpem@5 | 3149 | CImgList<unsigned char> colors3d; |
philpem@5 | 3150 | CImg<float> opacities3d; |
philpem@5 | 3151 | CImg<T> points3d; |
philpem@5 | 3152 | if (get_version) points3d.assign(img); else img.transfer_to(points3d); |
philpem@5 | 3153 | points3d.CImg3dtoobject3d(primitives3d,colors3d,opacities3d); |
philpem@5 | 3154 | points3d.get_shared_line(0)-=tx; |
philpem@5 | 3155 | points3d.get_shared_line(1)-=ty; |
philpem@5 | 3156 | points3d.get_shared_line(2)-=tz; |
philpem@5 | 3157 | points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); |
philpem@5 | 3158 | if (get_version) { |
philpem@5 | 3159 | images.insert(1); points3d.transfer_to(images.last()); |
philpem@5 | 3160 | filenames.insert(filenames[indices[l]]); |
philpem@5 | 3161 | } else points3d.transfer_to(images[indices[l]]); |
philpem@5 | 3162 | } |
philpem@5 | 3163 | } else error("Translate 3D object%s : Invalid argument '%s' " |
philpem@5 | 3164 | "(should be 'tx,ty,tz').",gmic_inds,argument_text); |
philpem@5 | 3165 | ++position; continue; |
philpem@5 | 3166 | } |
philpem@5 | 3167 | |
philpem@5 | 3168 | // Scale a 3D object. |
philpem@5 | 3169 | bool divide = false; |
philpem@5 | 3170 | if (!cimg::strcmp("-mul3d",item0) || !cimg::strcmp("-*3d",item0) || |
philpem@5 | 3171 | ((divide=true)==true && (!cimg::strcmp("-div3d",item0) || !cimg::strcmp("-/3d",item0)))) { |
philpem@5 | 3172 | float sx = 0, sy = 1, sz = 1; char end = 0; |
philpem@5 | 3173 | if ((std::sscanf(argument,"%f%c",&sx,&end)==1 && (sy = sz = sx),1) || |
philpem@5 | 3174 | std::sscanf(argument,"%f%*c%f%c",&sx,&sy,&end)==2 || |
philpem@5 | 3175 | std::sscanf(argument,"%f%*c%f%*c%f%c",&sx,&sy,&sz,&end)==3) { |
philpem@5 | 3176 | if (divide) print("Scale 3D object%s with factors (1/%g,1/%g,1/%g).",gmic_inds,sx,sy,sz); |
philpem@5 | 3177 | else print("Scale 3D object%s with factors (%g,%g,%g).",gmic_inds,sx,sy,sz); |
philpem@5 | 3178 | cimg_foroff(indices,l) { |
philpem@5 | 3179 | CImg<T>& img = images[indices[l]]; |
philpem@5 | 3180 | CImgList<unsigned int> primitives3d; |
philpem@5 | 3181 | CImgList<unsigned char> colors3d; |
philpem@5 | 3182 | CImg<float> opacities3d; |
philpem@5 | 3183 | CImg<T> points3d; |
philpem@5 | 3184 | if (get_version) points3d.assign(img); else img.transfer_to(points3d); |
philpem@5 | 3185 | points3d.CImg3dtoobject3d(primitives3d,colors3d,opacities3d); |
philpem@5 | 3186 | if (divide) { |
philpem@5 | 3187 | points3d.get_shared_line(0)/=sx; |
philpem@5 | 3188 | points3d.get_shared_line(1)/=sy; |
philpem@5 | 3189 | points3d.get_shared_line(2)/=sz; |
philpem@5 | 3190 | } else { |
philpem@5 | 3191 | points3d.get_shared_line(0)*=sx; |
philpem@5 | 3192 | points3d.get_shared_line(1)*=sy; |
philpem@5 | 3193 | points3d.get_shared_line(2)*=sz; |
philpem@5 | 3194 | } |
philpem@5 | 3195 | points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); |
philpem@5 | 3196 | if (get_version) { |
philpem@5 | 3197 | images.insert(1); points3d.transfer_to(images.last()); |
philpem@5 | 3198 | filenames.insert(filenames[indices[l]]); |
philpem@5 | 3199 | } else points3d.transfer_to(images[indices[l]]); |
philpem@5 | 3200 | } |
philpem@5 | 3201 | } else error("Scale 3D object%s : Invalid argument '%s' " |
philpem@5 | 3202 | "(should be 'fact' or 'factx,facty[,factz]').",gmic_inds,argument_text); |
philpem@5 | 3203 | ++position; continue; |
philpem@5 | 3204 | } |
philpem@5 | 3205 | |
philpem@5 | 3206 | // Set color of 3D object(s). |
philpem@5 | 3207 | if (!cimg::strcmp("-color3d",item0) || !cimg::strcmp("-col3d",item0)) { |
philpem@5 | 3208 | float R = 200, G = 200, B = 200, opacity = -1; char end = 0; |
philpem@5 | 3209 | if (std::sscanf(argument,"%f%*c%f%*c%f%c",&R,&G,&B,&end)==3 || |
philpem@5 | 3210 | std::sscanf(argument,"%f%*c%f%*c%f%*c%f%c",&R,&G,&B,&opacity,&end)==4) { |
philpem@5 | 3211 | const bool set_opacity = (opacity>=0); |
philpem@5 | 3212 | R = (float)cimg::round(R,1); G = (float)cimg::round(G,1); B = (float)cimg::round(B,1); |
philpem@5 | 3213 | if (R<0) R = 0; if (R>255) R = 255; |
philpem@5 | 3214 | if (G<0) G = 0; if (G>255) G = 255; |
philpem@5 | 3215 | if (B<0) B = 0; if (B>255) B = 255; |
philpem@5 | 3216 | if (set_opacity) print("Set colors of 3D object%s to (%g,%g,%g) and opacity to %g.",gmic_inds,R,G,B,opacity); |
philpem@5 | 3217 | else print("Set color of 3D object%s to (%g,%g,%g).",gmic_inds,R,G,B); |
philpem@5 | 3218 | cimg_foroff(indices,l) { |
philpem@5 | 3219 | const unsigned int ind = indices[l]; |
philpem@5 | 3220 | if (!images[ind].is_CImg3d()) |
philpem@5 | 3221 | error("Set color of 3D object%s : Image [%d] is not a 3D object.",gmic_inds,ind); |
philpem@5 | 3222 | gmic_apply(images[ind],coloropacityCImg3d(R,G,B,opacity,true,set_opacity)); |
philpem@5 | 3223 | } |
philpem@5 | 3224 | } else error("Set color of 3D object%s : Invalid argument '%s' " |
philpem@5 | 3225 | "(should be 'R,G,B[,opacity]').",gmic_inds,argument_text); |
philpem@5 | 3226 | ++position; continue; |
philpem@5 | 3227 | } |
philpem@5 | 3228 | |
philpem@5 | 3229 | // Set opacity of 3D object(s). |
philpem@5 | 3230 | if (!cimg::strcmp("-opacity3d",item0) || !cimg::strcmp("-opac3d",item0)) { |
philpem@5 | 3231 | float opacity = 1; char end = 0; |
philpem@5 | 3232 | if (std::sscanf(argument,"%f%c",&opacity,&end)==1) { |
philpem@5 | 3233 | print("Set opacity of 3D object%s to %g.",gmic_inds,opacity); |
philpem@5 | 3234 | cimg_foroff(indices,l) { |
philpem@5 | 3235 | const unsigned int ind = indices[l]; |
philpem@5 | 3236 | if (!images[ind].is_CImg3d()) |
philpem@5 | 3237 | error("Set opacity of 3D object%s : Image [%d] is not a 3D object.",gmic_inds,ind); |
philpem@5 | 3238 | gmic_apply(images[ind],coloropacityCImg3d(0,0,0,opacity,false,true)); |
philpem@5 | 3239 | } |
philpem@5 | 3240 | } else error("Set opacity of 3D object%s : Invalid argument '%s' " |
philpem@5 | 3241 | "(should be 'opacity').",gmic_inds,argument_text); |
philpem@5 | 3242 | ++position; continue; |
philpem@5 | 3243 | } |
philpem@5 | 3244 | |
philpem@5 | 3245 | // Invert 3D orientation. |
philpem@5 | 3246 | if (!cimg::strcmp("-invert3d",item0) || !cimg::strcmp("-i3d",item0)) { |
philpem@5 | 3247 | print("Invert orientation of 3D object%s.",gmic_inds); |
philpem@5 | 3248 | cimg_foroff(indices,l) { |
philpem@5 | 3249 | CImg<T> &img = images[indices[l]]; |
philpem@5 | 3250 | CImgList<unsigned int> primitives3d; |
philpem@5 | 3251 | CImgList<unsigned char> colors3d; |
philpem@5 | 3252 | CImg<float> opacities3d; |
philpem@5 | 3253 | CImg<T> points3d; |
philpem@5 | 3254 | if (get_version) points3d.assign(img); else img.transfer_to(points3d); |
philpem@5 | 3255 | points3d.CImg3dtoobject3d(primitives3d,colors3d,opacities3d); |
philpem@5 | 3256 | if (primitives3d) primitives3d.invert_object3d(); |
philpem@5 | 3257 | points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); |
philpem@5 | 3258 | if (get_version) { |
philpem@5 | 3259 | images.insert(1); points3d.transfer_to(images.last()); |
philpem@5 | 3260 | filenames.insert(filenames[indices[l]]); |
philpem@5 | 3261 | } else points3d.transfer_to(images[indices[l]]); |
philpem@5 | 3262 | } |
philpem@5 | 3263 | continue; |
philpem@5 | 3264 | } |
philpem@5 | 3265 | |
philpem@5 | 3266 | // Split 3D object(s) into 6 vector images {header,N,vertices,primitives,colors,opacities} |
philpem@5 | 3267 | if (!cimg::strcmp("-split3d",item0) || !cimg::strcmp("-s3d",item0)) { |
philpem@5 | 3268 | print("Split 3D object%s into its different characteristics.",gmic_inds); |
philpem@5 | 3269 | unsigned int off = 0; |
philpem@5 | 3270 | cimg_foroff(indices,l) { |
philpem@5 | 3271 | const unsigned int ind = indices[l] + off; |
philpem@5 | 3272 | CImg<T> &img = images[ind]; |
philpem@5 | 3273 | const CImg<char> filename = filenames[ind]; |
philpem@5 | 3274 | CImgList<unsigned int> primitives3d; |
philpem@5 | 3275 | CImgList<unsigned char> colors3d; |
philpem@5 | 3276 | CImg<float> opacities3d; |
philpem@5 | 3277 | CImg<T> points3d; |
philpem@5 | 3278 | if (get_version) points3d.assign(img); else img.transfer_to(points3d); |
philpem@5 | 3279 | points3d.CImg3dtoobject3d(primitives3d,colors3d,opacities3d); |
philpem@5 | 3280 | CImgList<T> split; |
philpem@5 | 3281 | split.insert(CImg<T>("CImg3d",1,6,1,1,false)+=0.5f); |
philpem@5 | 3282 | split.insert(CImg<T>::vector((T)points3d.dimx(),(T)primitives3d.size)); |
philpem@5 | 3283 | split.insert(1); points3d.resize(-100,3,1,1,0).transpose().unroll('y').transfer_to(split.last()); |
philpem@5 | 3284 | points3d.assign(); |
philpem@5 | 3285 | CImgList<T> _prims; |
philpem@5 | 3286 | cimglist_for(primitives3d,p) |
philpem@5 | 3287 | _prims.insert(CImg<T>::vector((T)primitives3d[p].size())).insert(primitives3d[p]).last().unroll('y'); |
philpem@5 | 3288 | primitives3d.assign(); |
philpem@5 | 3289 | split.insert(_prims.get_append('y')); _prims.assign(); |
philpem@5 | 3290 | split.insert(colors3d.get_append('x').transpose().unroll('y')); colors3d.assign(); |
philpem@5 | 3291 | split.insert(1); opacities3d.transfer_to(split.last()); |
philpem@5 | 3292 | if (get_version) { |
philpem@5 | 3293 | images.insert(split); |
philpem@5 | 3294 | filenames.insert(split.size,filename); |
philpem@5 | 3295 | } else { |
philpem@5 | 3296 | images.remove(ind); images.insert(split,ind); |
philpem@5 | 3297 | filenames.remove(ind); filenames.insert(split.size,filename,ind); |
philpem@5 | 3298 | off+=split.size-1; |
philpem@5 | 3299 | } |
philpem@5 | 3300 | } |
philpem@5 | 3301 | continue; |
philpem@5 | 3302 | } |
philpem@5 | 3303 | |
philpem@5 | 3304 | // Set 3D light position. |
philpem@5 | 3305 | if (!cimg::strcmp("-light3d",item) || !cimg::strcmp("-l3d",item)) { |
philpem@5 | 3306 | float lx = 0, ly = 0, lz = -5000; char end = 0; |
philpem@5 | 3307 | if (std::sscanf(argument,"%f%*c%f%*c%f%c",&lx,&ly,&lz,&end)==3) { |
philpem@5 | 3308 | print("Set 3D light position at (%g,%g,%g).",lx,ly,lz); |
philpem@5 | 3309 | light3d_x = lx; |
philpem@5 | 3310 | light3d_y = ly; |
philpem@5 | 3311 | light3d_z = lz; |
philpem@5 | 3312 | } else error("Set 3D light position : Invalid argument '%s' " |
philpem@5 | 3313 | "(should be 'posx,posy,posz').",argument_text); |
philpem@5 | 3314 | ++position; continue; |
philpem@5 | 3315 | } |
philpem@5 | 3316 | |
philpem@5 | 3317 | // Set 3D focale. |
philpem@5 | 3318 | if (!cimg::strcmp("-focale3d",item) || !cimg::strcmp("-f3d",item)) { |
philpem@5 | 3319 | float focale = 500; char end = 0; |
philpem@5 | 3320 | if (std::sscanf(argument,"%f%c",&focale,&end)==1) { |
philpem@5 | 3321 | focale3d = focale; |
philpem@5 | 3322 | print("Set 3D focale to %g.",focale); |
philpem@5 | 3323 | } else error("Set 3D focale : Invalid argument '%s' " |
philpem@5 | 3324 | "(should be 'value')."); |
philpem@5 | 3325 | ++position; continue; |
philpem@5 | 3326 | } |
philpem@5 | 3327 | |
philpem@5 | 3328 | // Set 3D specular light parameters. |
philpem@5 | 3329 | if (!cimg::strcmp("-specl3d",item) || !cimg::strcmp("-sl3d",item)) { |
philpem@5 | 3330 | float value = 0; char end = 0; |
philpem@5 | 3331 | if (std::sscanf(argument,"%f%c",&value,&end)==1) { |
philpem@5 | 3332 | specular_light3d = value; |
philpem@5 | 3333 | print("Set amount of 3D specular light to %g.",specular_light3d); |
philpem@5 | 3334 | } |
philpem@5 | 3335 | else error("Set amount of 3D specular light : invalid argument '%s'" |
philpem@5 | 3336 | "(should be 'value').", |
philpem@5 | 3337 | argument_text); |
philpem@5 | 3338 | ++position; continue; |
philpem@5 | 3339 | } |
philpem@5 | 3340 | |
philpem@5 | 3341 | if (!cimg::strcmp("-specs3d",item) || !cimg::strcmp("-ss3d",item)) { |
philpem@5 | 3342 | float value = 0; char end = 0; |
philpem@5 | 3343 | if (std::sscanf(argument,"%f%c",&value,&end)==1) { |
philpem@5 | 3344 | specular_shine3d = value; |
philpem@5 | 3345 | print("Set shininess of 3D specular light to %g.",specular_shine3d); |
philpem@5 | 3346 | } |
philpem@5 | 3347 | else error("Set shininess of 3D specular light : invalid argument '%s'" |
philpem@5 | 3348 | "(should be 'value').", |
philpem@5 | 3349 | argument_text); |
philpem@5 | 3350 | ++position; continue; |
philpem@5 | 3351 | } |
philpem@5 | 3352 | |
philpem@5 | 3353 | // Switch double-sided mode for 3D rendering. |
philpem@5 | 3354 | if (!cimg::strcmp("-orient3d",item) || !cimg::strcmp("-o3d",item)) { |
philpem@5 | 3355 | is_oriented3d = !is_oriented3d; |
philpem@5 | 3356 | continue; |
philpem@5 | 3357 | } |
philpem@5 | 3358 | |
philpem@5 | 3359 | // Set 3D rendering mode. |
philpem@5 | 3360 | if (!cimg::strcmp("-render3d",item) || !cimg::strcmp("-r3d",item)) { |
philpem@5 | 3361 | unsigned int value = 0; char end = 0; |
philpem@5 | 3362 | if (std::sscanf(argument,"%u%c",&value,&end)==1) { |
philpem@5 | 3363 | render3d = value; |
philpem@5 | 3364 | print("Set static 3D render mode to %s.", |
philpem@5 | 3365 | render3d==-1?"bounding-box": |
philpem@5 | 3366 | render3d==0?"pointwise":render3d==1?"linear":render3d==2?"flat": |
philpem@5 | 3367 | render3d==3?"flat-shaded":render3d==4?"Gouraud-shaded": |
philpem@5 | 3368 | render3d==5?"Phong-shaded":"none"); |
philpem@5 | 3369 | } |
philpem@5 | 3370 | else error("Set static 3D render mode : invalid argument '%s'" |
philpem@5 | 3371 | "(should be '{0=pointwise, 1=linear, 2=flat, 3=flat shaded, 4=Gouraud shaded, 5=Phong-shaded}').", |
philpem@5 | 3372 | argument_text); |
philpem@5 | 3373 | ++position; continue; |
philpem@5 | 3374 | } |
philpem@5 | 3375 | |
philpem@5 | 3376 | if (!cimg::strcmp("-renderd3d",item) || !cimg::strcmp("-rd3d",item)) { |
philpem@5 | 3377 | unsigned int value = 0; char end = 0; |
philpem@5 | 3378 | if (std::sscanf(argument,"%u%c",&value,&end)==1) { |
philpem@5 | 3379 | renderd3d = value; |
philpem@5 | 3380 | print("Set dynamic 3D render mode to %s.", |
philpem@5 | 3381 | renderd3d==-1?"bounding-box": |
philpem@5 | 3382 | renderd3d==0?"pointwise":renderd3d==1?"linear":renderd3d==2?"flat": |
philpem@5 | 3383 | renderd3d==3?"flat-shaded":renderd3d==4?"Gouraud-shaded": |
philpem@5 | 3384 | renderd3d==5?"Phong-shaded":"none"); |
philpem@5 | 3385 | } |
philpem@5 | 3386 | else error("Set dynamic 3D render mode : invalid argument '%s'" |
philpem@5 | 3387 | "(should be '{0=pointwise, 1=linear, 2=flat, 3=flat shaded, 4=Gouraud shaded, 5=Phong-shaded}').", |
philpem@5 | 3388 | argument_text); |
philpem@5 | 3389 | ++position; continue; |
philpem@5 | 3390 | } |
philpem@5 | 3391 | |
philpem@5 | 3392 | // Set 3D background color. |
philpem@5 | 3393 | if (!cimg::strcmp("-background3d",item) || !cimg::strcmp("-b3d",item)) { |
philpem@5 | 3394 | int R = 0, G = 0, B = 0; char end = 0; |
philpem@5 | 3395 | const int nb = std::sscanf(argument,"%d%*c%d%*c%d%c",&R,&G,&B,&end); |
philpem@5 | 3396 | switch (nb) { |
philpem@5 | 3397 | case 1 : background3d[0] = background3d[1] = background3d[2] = R; break; |
philpem@5 | 3398 | case 2 : background3d[0] = R; background3d[1] = background3d[2] = G; break; |
philpem@5 | 3399 | case 3 : background3d[0] = R; background3d[1] = G; background3d[2] = B; break; |
philpem@5 | 3400 | default: error("Set 3D background color : Invalid argument '%s'.",argument_text); |
philpem@5 | 3401 | } |
philpem@5 | 3402 | print("Set 3D background color to (%d,%d,%d).", |
philpem@5 | 3403 | (int)background3d[0],(int)background3d[1],(int)background3d[2]); |
philpem@5 | 3404 | ++position; continue; |
philpem@5 | 3405 | } |
philpem@5 | 3406 | |
philpem@5 | 3407 | //---------------- |
philpem@5 | 3408 | // Other commands. |
philpem@5 | 3409 | //---------------- |
philpem@5 | 3410 | |
philpem@5 | 3411 | // No operations : do nothing |
philpem@5 | 3412 | if (!cimg::strcmp("-nop",item)) { |
philpem@5 | 3413 | continue; |
philpem@5 | 3414 | } |
philpem@5 | 3415 | |
philpem@5 | 3416 | // Skip next argument; |
philpem@5 | 3417 | if (!cimg::strcmp("-skip",item)) { |
philpem@5 | 3418 | ++position; |
philpem@5 | 3419 | continue; |
philpem@5 | 3420 | } |
philpem@5 | 3421 | |
philpem@5 | 3422 | // Echo. |
philpem@5 | 3423 | if (!cimg::strcmp("-echo",item) || !cimg::strcmp("-e",item)) { |
philpem@5 | 3424 | const int l = cimg::strlen(argument); |
philpem@5 | 3425 | if (l>=2 && argument[0]=='"' && argument[l-1]=='"') { |
philpem@5 | 3426 | if (l==2) print(""); else { |
philpem@5 | 3427 | CImg<char> nargument(argument+1,l-1,1,1,1,false); |
philpem@5 | 3428 | nargument(l-2)=0; |
philpem@5 | 3429 | print("%s",nargument.ptr()); |
philpem@5 | 3430 | } |
philpem@5 | 3431 | } else print("%s",argument); |
philpem@5 | 3432 | ++position; continue; |
philpem@5 | 3433 | } |
philpem@5 | 3434 | |
philpem@5 | 3435 | // Print. |
philpem@5 | 3436 | if (!cimg::strcmp("-print",item0) || !cimg::strcmp("-p",item0)) { |
philpem@5 | 3437 | if (images.size) { |
philpem@5 | 3438 | print("Print image%s.\n\n",gmic_inds); |
philpem@5 | 3439 | char title[4096]; |
philpem@5 | 3440 | if (verbosity_level>=0) cimg_foroff(indices,l) { |
philpem@5 | 3441 | const unsigned int ind = indices[l]; |
philpem@5 | 3442 | std::sprintf(title,"image [%u] = '%s'",ind,filenames[ind].ptr()); |
philpem@5 | 3443 | images[ind].print(title); |
philpem@5 | 3444 | } |
philpem@5 | 3445 | is_released = true; |
philpem@5 | 3446 | } else print("Print image[]."); |
philpem@5 | 3447 | continue; |
philpem@5 | 3448 | } |
philpem@5 | 3449 | |
philpem@5 | 3450 | // Quit. |
philpem@5 | 3451 | if (!cimg::strcmp("-quit",item) || !cimg::strcmp("-q",item)) { |
philpem@5 | 3452 | print("Quit."); |
philpem@5 | 3453 | is_released = true; |
philpem@5 | 3454 | dowhile.assign(); |
philpem@5 | 3455 | repeatdone.assign(); |
philpem@5 | 3456 | position = command_line.size; |
philpem@5 | 3457 | continue; |
philpem@5 | 3458 | } |
philpem@5 | 3459 | |
philpem@5 | 3460 | // Do...while. |
philpem@5 | 3461 | if (!cimg::strcmp("-do",item)) { |
philpem@5 | 3462 | dowhile.insert(CImg<int>::vector((int)position)); |
philpem@5 | 3463 | continue; |
philpem@5 | 3464 | } |
philpem@5 | 3465 | |
philpem@5 | 3466 | if (!cimg::strcmp("-while",item)) { |
philpem@5 | 3467 | double cond = 0; char end = 0; |
philpem@5 | 3468 | if (std::sscanf(argument,"%lf%c",&cond,&end)!=1) cond = 0; |
philpem@5 | 3469 | if (!dowhile) error("Directive '-while' is not associated with a '-do' command."); |
philpem@5 | 3470 | if (cond<=0) dowhile.remove(); |
philpem@5 | 3471 | else { position = (unsigned int)dowhile.last()(0); continue; } |
philpem@5 | 3472 | ++position; continue; |
philpem@5 | 3473 | } |
philpem@5 | 3474 | |
philpem@5 | 3475 | // If..else..endif |
philpem@5 | 3476 | if (!cimg::strcmp("-if",item)) { |
philpem@5 | 3477 | double cond = 0; char end = 0; |
philpem@5 | 3478 | if (std::sscanf(argument,"%lf%c",&cond,&end)!=1) cond = 0; |
philpem@5 | 3479 | if (cond<=0) { |
philpem@5 | 3480 | for (int nbifs = 1; nbifs && position<command_line.size; ++position) { |
philpem@5 | 3481 | const char *it = command_line[position].ptr(); |
philpem@5 | 3482 | if (!cimg::strcmp("-if",it)) ++nbifs; |
philpem@5 | 3483 | if (!cimg::strcmp("-endif",it)) --nbifs; |
philpem@5 | 3484 | if (!cimg::strcmp("-else",it) && nbifs==1) --nbifs; |
philpem@5 | 3485 | } |
philpem@5 | 3486 | continue; |
philpem@5 | 3487 | } |
philpem@5 | 3488 | ++position; continue; |
philpem@5 | 3489 | } |
philpem@5 | 3490 | if (!cimg::strcmp("-else",item)) { |
philpem@5 | 3491 | for (int nbifs = 1; nbifs && position<command_line.size; ++position) { |
philpem@5 | 3492 | if (!cimg::strcmp("-if",command_line[position].ptr())) ++nbifs; |
philpem@5 | 3493 | if (!cimg::strcmp("-endif",command_line[position].ptr())) --nbifs; |
philpem@5 | 3494 | } |
philpem@5 | 3495 | continue; |
philpem@5 | 3496 | } |
philpem@5 | 3497 | if (!cimg::strcmp("-endif",item)) continue; |
philpem@5 | 3498 | |
philpem@5 | 3499 | // Repeat...done |
philpem@5 | 3500 | if (!cimg::strcmp("-repeat",item)) { |
philpem@5 | 3501 | float fnb = 0; char end = 0; |
philpem@5 | 3502 | if (std::sscanf(argument,"%f%c",&fnb,&end)==1) { |
philpem@5 | 3503 | const int nb = (int)fnb; |
philpem@5 | 3504 | if (nb>0) repeatdone.insert(CImg<int>::vector((int)position+1,nb)); |
philpem@5 | 3505 | else { |
philpem@5 | 3506 | int nbrepeats = 0; |
philpem@5 | 3507 | for (nbrepeats = 1; nbrepeats && position<command_line.size; ++position) { |
philpem@5 | 3508 | const char *it = command_line[position].ptr(); |
philpem@5 | 3509 | if (!cimg::strcmp("-repeat",it)) ++nbrepeats; |
philpem@5 | 3510 | if (!cimg::strcmp("-done",it)) --nbrepeats; |
philpem@5 | 3511 | } |
philpem@5 | 3512 | if (nbrepeats && position>=command_line.size) |
philpem@5 | 3513 | error("Directive '-done' is missing after a '-repeat' command."); |
philpem@5 | 3514 | continue; |
philpem@5 | 3515 | } |
philpem@5 | 3516 | } else error("Repeat operation : Invalid argument '%s' " |
philpem@5 | 3517 | "(should be a number).",argument_text); |
philpem@5 | 3518 | ++position; continue; |
philpem@5 | 3519 | } |
philpem@5 | 3520 | |
philpem@5 | 3521 | if (!cimg::strcmp("-done",item)) { |
philpem@5 | 3522 | if (!repeatdone) error("Directive '-done' is not associated with a '-repeat' command."); |
philpem@5 | 3523 | if (--repeatdone.last()(1)) |
philpem@5 | 3524 | position = (unsigned int)repeatdone.last()(0); |
philpem@5 | 3525 | else repeatdone.remove(); |
philpem@5 | 3526 | continue; |
philpem@5 | 3527 | } |
philpem@5 | 3528 | |
philpem@5 | 3529 | // Check argument type |
philpem@5 | 3530 | if (!cimg::strcmp("-int",item)) { |
philpem@5 | 3531 | char it[4096], end = 0, sep = 0; int value = 0; |
philpem@5 | 3532 | if (*argument) for (const char *nargument = argument; *nargument; ) { |
philpem@5 | 3533 | const int nb = std::sscanf(nargument,"%4095[^,]%c",it,&sep); |
philpem@5 | 3534 | if (nb) { |
philpem@5 | 3535 | if (std::sscanf(it,"%d%c",&value,&end)==1) nargument+=cimg::strlen(it) + nb -1; |
philpem@5 | 3536 | else error("Argument '%s' is not an integer value.",it); |
philpem@5 | 3537 | } else error("Argument '%s' is not an integer value.",argument_text); |
philpem@5 | 3538 | } |
philpem@5 | 3539 | ++position; continue; |
philpem@5 | 3540 | } |
philpem@5 | 3541 | |
philpem@5 | 3542 | if (!cimg::strcmp("-float",item)) { |
philpem@5 | 3543 | char it[4096], end = 0, sep = 0; double value = 0; |
philpem@5 | 3544 | if (*argument) for (const char *nargument = argument; *nargument; ) { |
philpem@5 | 3545 | const int nb = std::sscanf(nargument,"%4095[^,]%c",it,&sep); |
philpem@5 | 3546 | if (nb) { |
philpem@5 | 3547 | if (std::sscanf(it,"%lf%c",&value,&end)==1) nargument+=cimg::strlen(it) + nb -1; |
philpem@5 | 3548 | else error("Argument '%s' is not a float value.",it); |
philpem@5 | 3549 | } else error("Argument '%s' is not a float value.",argument_text); |
philpem@5 | 3550 | } |
philpem@5 | 3551 | ++position; continue; |
philpem@5 | 3552 | } |
philpem@5 | 3553 | |
philpem@5 | 3554 | //-------------------------- |
philpem@5 | 3555 | // Input/Output and Display |
philpem@5 | 3556 | //-------------------------- |
philpem@5 | 3557 | |
philpem@5 | 3558 | // Display. |
philpem@5 | 3559 | if (!cimg::strcmp("-display",item0) || !cimg::strcmp("-d",item0)) { |
philpem@5 | 3560 | if (display_images(images,indices,true)) is_released = true; |
philpem@5 | 3561 | continue; |
philpem@5 | 3562 | } |
philpem@5 | 3563 | |
philpem@5 | 3564 | // Display 3D object. |
philpem@5 | 3565 | if (!cimg::strcmp("-display3d",item0) || !cimg::strcmp("-d3d",item0)) { |
philpem@5 | 3566 | if (display_objects3d(images,indices,true)) is_released = true; |
philpem@5 | 3567 | continue; |
philpem@5 | 3568 | } |
philpem@5 | 3569 | |
philpem@5 | 3570 | // Display as a graph plot. |
philpem@5 | 3571 | if (!cimg::strcmp("-plot",item0)) { |
philpem@5 | 3572 | int plot_type = 1, vertex_type = 1; double ymin = 0, ymax = 0, xmin = 0, xmax = 0; char end = 0; |
philpem@5 | 3573 | 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); |
philpem@5 | 3574 | if (nb==1 || nb==2 || nb==4 || nb==6) ++position; |
philpem@5 | 3575 | else { plot_type = 1; vertex_type = 0; ymin = ymax = xmin = xmax = 0; } |
philpem@5 | 3576 | is_released |= display_plots(images,indices,plot_type,vertex_type,xmin,xmax,ymin,ymax,true); |
philpem@5 | 3577 | continue; |
philpem@5 | 3578 | } |
philpem@5 | 3579 | |
philpem@5 | 3580 | // Select image feature. |
philpem@5 | 3581 | if (!cimg::strcmp("-select",item0)) { |
philpem@5 | 3582 | int select_type = 0; char end = 0; |
philpem@5 | 3583 | if (std::sscanf(argument,"%d%c",&select_type,&end)==1) { |
philpem@5 | 3584 | cimg_foroff(indices,l) gmic_apply(images[indices[l]],select(filenames[indices[l]].ptr(),select_type)); |
philpem@5 | 3585 | } else error("Select image%s : Invalid argument '%s' " |
philpem@5 | 3586 | "(should be 'select_type').",gmic_inds,argument_text); |
philpem@5 | 3587 | ++position; continue; |
philpem@5 | 3588 | } |
philpem@5 | 3589 | |
philpem@5 | 3590 | // Output. |
philpem@5 | 3591 | if (!cimg::strcmp("-output",item0) || !cimg::strcmp("-o",item0)) { |
philpem@5 | 3592 | char filename[4096] = { 0 }; char options[4096] = { 0 }; |
philpem@5 | 3593 | if (std::sscanf(argument,"%4095[^,],%s",filename,options)!=2) std::strcpy(filename,argument); |
philpem@5 | 3594 | const char *const ext = cimg::split_filename(filename); |
philpem@5 | 3595 | if (!cimg::strcasecmp("off",ext)) { |
philpem@5 | 3596 | char nfilename[4096] = { 0 }; |
philpem@5 | 3597 | std::strcpy(nfilename,filename); |
philpem@5 | 3598 | const unsigned int siz = indices.size(); |
philpem@5 | 3599 | cimg_foroff(indices,l) { |
philpem@5 | 3600 | const unsigned int ind = indices[l]; |
philpem@5 | 3601 | if (siz!=1) cimg::number_filename(filename,l,6,nfilename); |
philpem@5 | 3602 | if (!images[ind].is_CImg3d()) |
philpem@5 | 3603 | error("Output 3D object [%u] as file '%s' : Image [%u] is not a 3D object.",ind,nfilename,ind); |
philpem@5 | 3604 | print("Output 3D object [%u] as file '%s'.",ind,nfilename); |
philpem@5 | 3605 | CImgList<unsigned int> primitives3d; |
philpem@5 | 3606 | CImgList<unsigned char> colors3d; |
philpem@5 | 3607 | CImg<float> opacities3d; |
philpem@5 | 3608 | CImg<float> points3d(images[ind]); |
philpem@5 | 3609 | points3d.CImg3dtoobject3d(primitives3d,colors3d,opacities3d).save_off(nfilename,primitives3d,colors3d); |
philpem@5 | 3610 | } |
philpem@5 | 3611 | } else if (!cimg::strcasecmp("jpeg",ext) || !cimg::strcasecmp("jpg",ext)) { |
philpem@5 | 3612 | int quality = 100; char end = 0; |
philpem@5 | 3613 | if (std::sscanf(options,"%d%c",&quality,&end)!=1) quality = 100; |
philpem@5 | 3614 | if (quality<0) quality = 0; else if (quality>100) quality = 100; |
philpem@5 | 3615 | CImgList<T> output_images; |
philpem@5 | 3616 | cimg_foroff(indices,l) output_images.insert(images[indices[l]],~0U,true); |
philpem@5 | 3617 | print("Output image%s as file '%s', with quality %u%%",gmic_inds,filename,quality); |
philpem@5 | 3618 | if (!output_images) throw CImgInstanceException("CImgList<%s>::save() : File '%s, instance list (%u,%p) is empty.", |
philpem@5 | 3619 | output_images.pixel_type(),filename, |
philpem@5 | 3620 | output_images.size,output_images.data); |
philpem@5 | 3621 | if (output_images.size==1) output_images[0].save_jpeg(filename,quality); |
philpem@5 | 3622 | else { |
philpem@5 | 3623 | char nfilename[1024]; |
philpem@5 | 3624 | cimglist_for(output_images,l) { |
philpem@5 | 3625 | cimg::number_filename(filename,l,6,nfilename); |
philpem@5 | 3626 | output_images[l].save_jpeg(nfilename,quality); |
philpem@5 | 3627 | } |
philpem@5 | 3628 | } |
philpem@5 | 3629 | } else { |
philpem@5 | 3630 | CImgList<T> output_images; |
philpem@5 | 3631 | cimg_foroff(indices,l) output_images.insert(images[indices[l]],~0U,true); |
philpem@5 | 3632 | print("Output image%s as file '%s'.",gmic_inds,filename); |
philpem@5 | 3633 | output_images.save(filename); |
philpem@5 | 3634 | } |
philpem@5 | 3635 | is_released = true; ++position; continue; |
philpem@5 | 3636 | } |
philpem@5 | 3637 | |
philpem@5 | 3638 | // Substitute macros commands if necessary. |
philpem@5 | 3639 | if (cimg::strcmp("-i",item0) && cimg::strcmp("-input",item0)) { |
philpem@5 | 3640 | bool macro_found = false; |
philpem@5 | 3641 | cimglist_for(macros,l) { |
philpem@5 | 3642 | const char |
philpem@5 | 3643 | *const macro = macros[l].ptr(), |
philpem@5 | 3644 | *const command = commands[l].ptr(); |
philpem@5 | 3645 | |
philpem@5 | 3646 | if (!cimg::strcmp(item+1,macro) && *command) { |
philpem@5 | 3647 | CImgList<char> arguments(256); |
philpem@5 | 3648 | unsigned int nb_arguments = 0; |
philpem@5 | 3649 | char s_argument[4096] = { 0 }, tmp[4096] = { 0 }, tmp2[4096] = { 0 }; |
philpem@5 | 3650 | bool has_arguments = false; |
philpem@5 | 3651 | macro_found = true; |
philpem@5 | 3652 | debug("Found macro '%s', substituting by '%s'.",macro,command); |
philpem@5 | 3653 | |
philpem@5 | 3654 | // Get command-line values of macro arguments. |
philpem@5 | 3655 | if (argument) |
philpem@5 | 3656 | for (const char *nargument = argument; nb_arguments<256 && *nargument && |
philpem@5 | 3657 | std::sscanf(nargument,"%4095[^,]",s_argument)==1;) { |
philpem@5 | 3658 | CImg<char>(s_argument,cimg::strlen(s_argument)+1,1,1,1,false).transfer_to(arguments[nb_arguments++]); |
philpem@5 | 3659 | nargument+=cimg::strlen(s_argument); |
philpem@5 | 3660 | if (*nargument) ++nargument; |
philpem@5 | 3661 | } |
philpem@5 | 3662 | |
philpem@5 | 3663 | // Substitute arguments in macro command expression. |
philpem@5 | 3664 | CImg<char> substituted_command; |
philpem@5 | 3665 | CImgList<char> lreplacement; |
philpem@5 | 3666 | for (const char *ncommand = command; *ncommand;) if (*ncommand=='$') { |
philpem@5 | 3667 | char *replace_text = 0, sep = 0; |
philpem@5 | 3668 | int ind = 0, ind1 = 0; |
philpem@5 | 3669 | |
philpem@5 | 3670 | // Replace $# and ${#}. |
philpem@5 | 3671 | if (ncommand[1]=='#' || (ncommand[1]=='{' && ncommand[2]=='#' && ncommand[3]=='}')) { |
philpem@5 | 3672 | std::sprintf(replace_text=s_argument,"%u",nb_arguments); |
philpem@5 | 3673 | ncommand+=(ncommand[1]=='#')?2:4; |
philpem@5 | 3674 | has_arguments = true; |
philpem@5 | 3675 | |
philpem@5 | 3676 | // Replace $* and ${*}. |
philpem@5 | 3677 | } else if (ncommand[1]=='*' || (ncommand[1]=='{' && ncommand[2]=='*' && ncommand[3]=='}')) { |
philpem@5 | 3678 | replace_text = &(s_argument[0]=0); |
philpem@5 | 3679 | for (unsigned int j = 1; j<=nb_arguments; ++j) { |
philpem@5 | 3680 | replace_text+=std::sprintf(replace_text,"%s",arguments[j-1].ptr()); |
philpem@5 | 3681 | if (j<nb_arguments) *(replace_text++) = ','; |
philpem@5 | 3682 | } |
philpem@5 | 3683 | replace_text = s_argument; |
philpem@5 | 3684 | ncommand+=(ncommand[1]=='*')?2:4; |
philpem@5 | 3685 | has_arguments = true; |
philpem@5 | 3686 | |
philpem@5 | 3687 | // Replace ${i*}. |
philpem@5 | 3688 | } else if (std::sscanf(ncommand,"${%d*%c",&ind,&sep)==2 && |
philpem@5 | 3689 | ind>0 && ind<256 && sep=='}') { |
philpem@5 | 3690 | replace_text = &(s_argument[0]=0); |
philpem@5 | 3691 | for (unsigned int j = ind; j<=nb_arguments; ++j) { |
philpem@5 | 3692 | replace_text+=std::sprintf(replace_text,"%s",arguments[j-1].ptr()); |
philpem@5 | 3693 | if (j<nb_arguments) *(replace_text++) = ','; |
philpem@5 | 3694 | } |
philpem@5 | 3695 | replace_text = s_argument; |
philpem@5 | 3696 | ncommand+=std::sprintf(tmp,"${%d*}",ind); |
philpem@5 | 3697 | has_arguments = true; |
philpem@5 | 3698 | |
philpem@5 | 3699 | // Replace $i and ${i}. |
philpem@5 | 3700 | } else if ((std::sscanf(ncommand,"$%d",&ind)==1 || |
philpem@5 | 3701 | (std::sscanf(ncommand,"${%d%c",&ind,&sep)==2 && sep=='}')) && |
philpem@5 | 3702 | ind>0 && ind<256) { |
philpem@5 | 3703 | if (!arguments[ind-1]) { |
philpem@5 | 3704 | if (sep=='}') error("Macro '%s' : Argument '$%d' is undefined (in expression '${%d}').",macro,ind,ind); |
philpem@5 | 3705 | else error("Macro '%s' : Argument '$%d' is undefined (in expression '$%d').",macro,ind,ind); |
philpem@5 | 3706 | } |
philpem@5 | 3707 | replace_text = arguments[ind-1].ptr(); |
philpem@5 | 3708 | ncommand+=std::sprintf(tmp,"$%d",ind) + (sep=='}'?2:0); |
philpem@5 | 3709 | has_arguments = true; |
philpem@5 | 3710 | |
philpem@5 | 3711 | // Replace ${i=$#}. |
philpem@5 | 3712 | } else if (std::sscanf(ncommand,"${%d=$#%c",&ind,&sep)==2 && |
philpem@5 | 3713 | ind>0 && ind<256 && sep=='}') { |
philpem@5 | 3714 | std::sprintf(replace_text=s_argument,"%g",(double)nb_arguments); |
philpem@5 | 3715 | CImg<char>(s_argument,cimg::strlen(s_argument)+1,1,1,1,false).transfer_to(arguments[ind-1]); |
philpem@5 | 3716 | ncommand+=std::sprintf(tmp,"${%d=$#}",ind); |
philpem@5 | 3717 | has_arguments = true; |
philpem@5 | 3718 | |
philpem@5 | 3719 | // Replace ${i=$j}. |
philpem@5 | 3720 | } else if (std::sscanf(ncommand,"${%d=$%d%c",&ind,&ind1,&sep)==3 && sep=='}' && |
philpem@5 | 3721 | ind>0 && ind<256 && ind1>0 && ind1<256) { |
philpem@5 | 3722 | if (!arguments[ind1-1]) |
philpem@5 | 3723 | error("Macro '%s' : Argument '$%d' is undefined (in expression '${%d=$%d}').",macro,ind1,ind,ind1); |
philpem@5 | 3724 | if (!arguments[ind-1]) arguments[ind-1] = arguments[ind1-1]; |
philpem@5 | 3725 | replace_text = arguments[ind-1].ptr(); |
philpem@5 | 3726 | ncommand+=std::sprintf(tmp,"${%d=$%d}",ind,ind1); |
philpem@5 | 3727 | has_arguments = true; |
philpem@5 | 3728 | |
philpem@5 | 3729 | // Replace ${i=default}. |
philpem@5 | 3730 | } else if (std::sscanf(ncommand,"${%d=%4095[^}]%c",&ind,tmp,&sep)==3 && sep=='}' && |
philpem@5 | 3731 | ind>0 && ind<256) { |
philpem@5 | 3732 | if (!arguments[ind-1]) CImg<char>(tmp,cimg::strlen(tmp)+1,1,1,1,false).transfer_to(arguments[ind-1]); |
philpem@5 | 3733 | replace_text = arguments[ind-1].ptr(); |
philpem@5 | 3734 | ncommand+=cimg::strlen(tmp) + 4 + std::sprintf(tmp2,"%d",ind); |
philpem@5 | 3735 | has_arguments = true; |
philpem@5 | 3736 | |
philpem@5 | 3737 | // Any other expression starting by '$'. |
philpem@5 | 3738 | } else { |
philpem@5 | 3739 | replace_text = &(s_argument[0]='$'); |
philpem@5 | 3740 | if (std::sscanf(ncommand,"%4095[^$]",s_argument+1)!=1) { s_argument[1] = 0; ++ncommand; } |
philpem@5 | 3741 | else ncommand+=cimg::strlen(s_argument); |
philpem@5 | 3742 | } |
philpem@5 | 3743 | |
philpem@5 | 3744 | const int replace_length = cimg::strlen(replace_text); |
philpem@5 | 3745 | if (replace_length) { |
philpem@5 | 3746 | lreplacement.insert(1); |
philpem@5 | 3747 | CImg<char>(replace_text,replace_length,1,1,1,false).transfer_to(lreplacement.last()); |
philpem@5 | 3748 | } |
philpem@5 | 3749 | |
philpem@5 | 3750 | } else { |
philpem@5 | 3751 | std::sscanf(ncommand,"%4095[^$]",s_argument); |
philpem@5 | 3752 | const int replace_length = cimg::strlen(s_argument); |
philpem@5 | 3753 | if (replace_length) { |
philpem@5 | 3754 | lreplacement.insert(1); |
philpem@5 | 3755 | CImg<char>(s_argument,replace_length,1,1,1,false).transfer_to(lreplacement.last()); |
philpem@5 | 3756 | ncommand+=cimg::strlen(s_argument); |
philpem@5 | 3757 | } |
philpem@5 | 3758 | } |
philpem@5 | 3759 | const CImg<char> zero(1,1,1,1,0); |
philpem@5 | 3760 | lreplacement.insert(zero).get_append('x').transfer_to(substituted_command); |
philpem@5 | 3761 | |
philpem@5 | 3762 | // Substitute macro expression in command line. |
philpem@5 | 3763 | bool is_dquote = false; |
philpem@5 | 3764 | cimg_foroff(substituted_command,k) |
philpem@5 | 3765 | if (substituted_command[k]=='"') is_dquote = !is_dquote; |
philpem@5 | 3766 | else if (is_dquote && substituted_command[k]==' ') substituted_command[k] = 30; |
philpem@5 | 3767 | CImgList<char> command_items = substituted_command.get_split(' ',false,false); |
philpem@5 | 3768 | cimglist_for(command_items,k) { |
philpem@5 | 3769 | CImg<char> &item = command_items[k]; |
philpem@5 | 3770 | cimg_foroff(item,l) if (item[l]==30) item[l]=' '; |
philpem@5 | 3771 | } |
philpem@5 | 3772 | cimglist_for(command_items,k) command_items[k].append(zero,'y'); |
philpem@5 | 3773 | if (position<command_line.size && has_arguments) command_line.remove(position); |
philpem@5 | 3774 | command_line.remove(--position); |
philpem@5 | 3775 | command_line.insert(command_items,position); |
philpem@5 | 3776 | break; |
philpem@5 | 3777 | } |
philpem@5 | 3778 | } |
philpem@5 | 3779 | if (macro_found) continue; |
philpem@5 | 3780 | } |
philpem@5 | 3781 | } |
philpem@5 | 3782 | |
philpem@5 | 3783 | // Input. |
philpem@5 | 3784 | if (!cimg::strcmp("-i",item0) || !cimg::strcmp("-input",item0)) ++position; |
philpem@5 | 3785 | else { if (get_version) --item; argument = item; item1[0] = 0; } |
philpem@5 | 3786 | if (!cimg::strlen(item1)) indices.assign(1,1,1,1,images.size); |
philpem@5 | 3787 | CImgList<T> input_images; |
philpem@5 | 3788 | CImgList<char> input_filenames; |
philpem@5 | 3789 | bool obj3d = false; |
philpem@5 | 3790 | char st_inds[4096] = { 0 }, stx[4096] = { 0 }, sty[4096] = { 0 }, stz[4096] = { 0 }, stv[4096] = { 0 }; |
philpem@5 | 3791 | char end = 0, sep = 0, sepx = 0, sepy = 0, sepz = 0, sepv = 0; |
philpem@5 | 3792 | int nb = 1, indx = no_ind, indy = no_ind, indz = no_ind, indv = no_ind; |
philpem@5 | 3793 | float dx = 0, dy = 1, dz = 1, dv = 1; |
philpem@5 | 3794 | |
philpem@5 | 3795 | if (std::sscanf(argument,"[%4095[0-9%,:-]]%*c%d%c",st_inds,&nb,&end)==2 || |
philpem@5 | 3796 | (std::sscanf(argument,"[%4095[0-9%,:-]%c%c",st_inds,&sep,&end)==2 && sep==']')) { |
philpem@5 | 3797 | |
philpem@5 | 3798 | // nb copies of existing sub-images. |
philpem@5 | 3799 | const CImg<unsigned int> indices0 = indices2cimg(st_inds,images.size,"-input"); |
philpem@5 | 3800 | char st_tmp[4096] = { 0 }; std::strcpy(st_tmp,indices2string(indices0,true)); |
philpem@5 | 3801 | if (nb<=0) error("Input %d copies of image%s : Invalid argument '%s'.", |
philpem@5 | 3802 | nb,st_tmp,argument_text); |
philpem@5 | 3803 | if (nb!=1) print("Input %d copies of image%s at position%s",nb,st_tmp,gmic_inds); |
philpem@5 | 3804 | else print("Input copy of image%s at position%s",st_tmp,gmic_inds); |
philpem@5 | 3805 | for (int i = 0; i<nb; ++i) cimg_foroff(indices0,l) { |
philpem@5 | 3806 | input_images.insert(images[indices0[l]]); |
philpem@5 | 3807 | input_filenames.insert(filenames[indices0[l]]); |
philpem@5 | 3808 | } |
philpem@5 | 3809 | } 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", |
philpem@5 | 3810 | stx,sty,stz,stv,&(nb=1),&end)==5 || |
philpem@5 | 3811 | std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c", |
philpem@5 | 3812 | stx,sty,stz,stv,&end)==4) && |
philpem@5 | 3813 | (std::sscanf(stx,"%f%c",&dx,&end)==1 || |
philpem@5 | 3814 | (std::sscanf(stx,"%f%c%c",&dx,&sepx,&end)==2 && sepx=='%') || |
philpem@5 | 3815 | (std::sscanf(stx,"[%d%c%c",&indx,&sepx,&end)==2 && sepx==']')) && |
philpem@5 | 3816 | (std::sscanf(sty,"%f%c",&dy,&end)==1 || |
philpem@5 | 3817 | (std::sscanf(sty,"%f%c%c",&dy,&sepy,&end)==2 && sepy=='%') || |
philpem@5 | 3818 | (std::sscanf(sty,"[%d%c%c",&indy,&sepy,&end)==2 && sepy==']')) && |
philpem@5 | 3819 | (std::sscanf(stz,"%f%c",&dz,&end)==1 || |
philpem@5 | 3820 | (std::sscanf(stz,"%f%c%c",&dz,&sepz,&end)==2 && sepz=='%') || |
philpem@5 | 3821 | (std::sscanf(stz,"[%d%c%c",&indz,&sepz,&end)==2 && sepz==']')) && |
philpem@5 | 3822 | (std::sscanf(stv,"%f%c",&dv,&end)==1 || |
philpem@5 | 3823 | (std::sscanf(stv,"%f%c%c",&dv,&sepv,&end)==2 && sepv=='%') || |
philpem@5 | 3824 | (std::sscanf(stv,"[%d%c%c",&indv,&sepv,&end)==2 && sepv==']'))) || |
philpem@5 | 3825 | (std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c",stx,sty,stz,&end)==3 && |
philpem@5 | 3826 | (std::sscanf(stx,"%f%c",&dx,&end)==1 || |
philpem@5 | 3827 | (std::sscanf(stx,"%f%c%c",&dx,&sepx,&end)==2 && sepx=='%') || |
philpem@5 | 3828 | (std::sscanf(stx,"[%d%c%c",&indx,&sepx,&end)==2 && sepx==']')) && |
philpem@5 | 3829 | (std::sscanf(sty,"%f%c",&dy,&end)==1 || |
philpem@5 | 3830 | (std::sscanf(sty,"%f%c%c",&dy,&sepy,&end)==2 && sepy=='%') || |
philpem@5 | 3831 | (std::sscanf(sty,"[%d%c%c",&indy,&sepy,&end)==2 && sepy==']')) && |
philpem@5 | 3832 | (std::sscanf(stz,"%f%c",&dz,&end)==1 || |
philpem@5 | 3833 | (std::sscanf(stz,"%f%c%c",&dz,&sepz,&end)==2 && sepz=='%') || |
philpem@5 | 3834 | (std::sscanf(stz,"[%d%c%c",&indz,&sepz,&end)==2 && sepz==']'))) || |
philpem@5 | 3835 | (std::sscanf(argument,"%4095[][0-9.eE%+-]%*c%4095[][0-9.eE%+-]%c",stx,sty,&end)==2 && |
philpem@5 | 3836 | (std::sscanf(stx,"%f%c",&dx,&end)==1 || |
philpem@5 | 3837 | (std::sscanf(stx,"%f%c%c",&dx,&sepx,&end)==2 && sepx=='%') || |
philpem@5 | 3838 | (std::sscanf(stx,"[%d%c%c",&indx,&sepx,&end)==2 && sepx==']')) && |
philpem@5 | 3839 | (std::sscanf(sty,"%f%c",&dy,&end)==1 || |
philpem@5 | 3840 | (std::sscanf(sty,"%f%c%c",&dy,&sepy,&end)==2 && sepy=='%') || |
philpem@5 | 3841 | (std::sscanf(sty,"[%d%c%c",&indy,&sepy,&end)==2 && sepy==']'))) || |
philpem@5 | 3842 | (std::sscanf(argument,"%4095[][0-9.eE%+-]%c",stx,&end)==1 && |
philpem@5 | 3843 | (std::sscanf(stx,"%f%c",&dx,&end)==1 || |
philpem@5 | 3844 | (std::sscanf(stx,"%f%c%c",&dx,&sepx,&end)==2 && sepx=='%') || |
philpem@5 | 3845 | (std::sscanf(stx,"[%d%c%c",&indx,&sepx,&end)==2 && sepx==']')))) { |
philpem@5 | 3846 | |
philpem@5 | 3847 | // nb new black image. |
philpem@5 | 3848 | if (indx!=no_ind) { gmic_check_indice(indx,"Input black image%s"); dx = (float)images[indx].dimx(); sepx = 0; } |
philpem@5 | 3849 | if (indy!=no_ind) { gmic_check_indice(indy,"Input black image%s"); dy = (float)images[indy].dimy(); sepy = 0; } |
philpem@5 | 3850 | if (indz!=no_ind) { gmic_check_indice(indz,"Input black image%s"); dz = (float)images[indz].dimz(); sepz = 0; } |
philpem@5 | 3851 | if (indv!=no_ind) { gmic_check_indice(indv,"Input black image%s"); dv = (float)images[indv].dimv(); sepv = 0; } |
philpem@5 | 3852 | if (sepx=='%') { dx = images.size?dx*images.last().dimx()/100:0; if (!(int)dx) ++dx; } |
philpem@5 | 3853 | if (sepy=='%') { dy = images.size?dy*images.last().dimy()/100:0; if (!(int)dy) ++dy; } |
philpem@5 | 3854 | if (sepz=='%') { dz = images.size?dz*images.last().dimz()/100:0; if (!(int)dz) ++dz; } |
philpem@5 | 3855 | if (sepv=='%') { dv = images.size?dv*images.last().dimv()/100:0; if (!(int)dv) ++dv; } |
philpem@5 | 3856 | |
philpem@5 | 3857 | if (nb<=0) error("Input %d black image%s : Invalid number of copies.",nb,gmic_inds); |
philpem@5 | 3858 | if (dx<=0 || dy<=0 || dz<=0 || dv<=0) |
philpem@5 | 3859 | error("Input %d black image%s : Invalid image dimensions %gx%gx%gx%g.", |
philpem@5 | 3860 | nb,gmic_inds,dx,dy,dz,dv); |
philpem@5 | 3861 | if (nb!=1) print("Input %d black images at position%s",nb,gmic_inds); |
philpem@5 | 3862 | else print("Input black image at position%s",gmic_inds); |
philpem@5 | 3863 | CImg<T> empty((int)dx,(int)dy,(int)dz,(int)dv,0); |
philpem@5 | 3864 | input_images.insert(nb-1,empty); input_images.insert(1); |
philpem@5 | 3865 | input_images.last().swap(empty); |
philpem@5 | 3866 | filenames.insert(input_images.size,CImg<char>("(gmic)",7,1,1,1,false)); |
philpem@5 | 3867 | } else if (std::sscanf(argument,"(%4095[^)])x%d%c",stx,&(nb=1),&end)==2 || |
philpem@5 | 3868 | (std::sscanf(argument,"(%4095[^)]%c%c",stx,&sep,&end)==2 && sep==')')) { |
philpem@5 | 3869 | |
philpem@5 | 3870 | // Insert nb IxJxKxL image(s) with specified values. |
philpem@5 | 3871 | if (nb<=0) error("Input %d images : Invalid number of copies.",nb); |
philpem@5 | 3872 | unsigned int cx = 0, cy = 0, cz = 0, cv = 0, maxcx = 0, maxcy = 0, maxcz = 0; |
philpem@5 | 3873 | const char *nargument = 0; |
philpem@5 | 3874 | for (nargument = argument+1; *nargument!=')'; ) { |
philpem@5 | 3875 | char s_value[256] = { 0 }, separator = 0; double value = 0; |
philpem@5 | 3876 | if (std::sscanf(nargument,"%255[0-9.eE+-]%c",s_value,&separator)==2 && std::sscanf(s_value,"%lf",&value)==1) { |
philpem@5 | 3877 | if (cx>maxcx) maxcx = cx; |
philpem@5 | 3878 | if (cy>maxcy) maxcy = cy; |
philpem@5 | 3879 | if (cz>maxcz) maxcz = cz; |
philpem@5 | 3880 | switch (separator) { |
philpem@5 | 3881 | case '^' : cx = cy = cz = 0; ++cv; break; |
philpem@5 | 3882 | case '/' : cx = cy = 0; ++cz; break; |
philpem@5 | 3883 | case ';' : cx = 0; ++cy; break; |
philpem@5 | 3884 | default : ++cx; |
philpem@5 | 3885 | } |
philpem@5 | 3886 | nargument+=cimg::strlen(s_value) + (separator==')'?0:1); |
philpem@5 | 3887 | } else break; |
philpem@5 | 3888 | } |
philpem@5 | 3889 | if (*nargument!=')') error("Input %d images : Invalid input string '%s'.",nb,argument); |
philpem@5 | 3890 | |
philpem@5 | 3891 | CImg<T> img(maxcx+1,maxcy+1,maxcz+1,cv+1,0); |
philpem@5 | 3892 | cx = cy = cz = cv = 0; |
philpem@5 | 3893 | for (nargument = argument+1; *nargument; ) { |
philpem@5 | 3894 | char s_value[256] = { 0 }, separator = 0; double value = 0; |
philpem@5 | 3895 | if (std::sscanf(nargument,"%255[0-9.eE+-]%c",s_value,&separator)==2 && std::sscanf(s_value,"%lf",&value)==1) { |
philpem@5 | 3896 | img(cx,cy,cz,cv) = (T)value; |
philpem@5 | 3897 | switch (separator) { |
philpem@5 | 3898 | case '^' : cx = cy = cz = 0; ++cv; break; |
philpem@5 | 3899 | case '/' : cx = cy = 0; ++cz; break; |
philpem@5 | 3900 | case ';' : cx = 0; ++cy; break; |
philpem@5 | 3901 | default : ++cx; |
philpem@5 | 3902 | } |
philpem@5 | 3903 | nargument+=cimg::strlen(s_value) + (separator==')'?0:1); |
philpem@5 | 3904 | } else break; |
philpem@5 | 3905 | } |
philpem@5 | 3906 | if (nb==1) print("Input image %dx%dx%dx%d",img.dimx(),img.dimy(),img.dimz(),img.dimv()); |
philpem@5 | 3907 | else print("Input %d images %dx%d",nb,img.dimx(),img.dimy(),img.dimz(),img.dimv()); |
philpem@5 | 3908 | input_images.insert(nb,img); filenames.insert(nb,CImg<char>("(gmic)",7,1,1,1,false)); |
philpem@5 | 3909 | } else { |
philpem@5 | 3910 | |
philpem@5 | 3911 | // Insert image as a loaded filename. |
philpem@5 | 3912 | char filename[4096] = { 0 }, options[4096] = { 0 }; const char *ext = 0, *basename = 0; |
philpem@5 | 3913 | if (argument[0]!='-' || (argument[1] && argument[1]!='.')) { |
philpem@5 | 3914 | std::FILE *file = std::fopen(argument,"r"); |
philpem@5 | 3915 | if (file) { std::fclose(file); std::strcpy(filename,argument); } |
philpem@5 | 3916 | else { |
philpem@5 | 3917 | std::sscanf(argument,"%4095[^,],%s",filename,options); |
philpem@5 | 3918 | if (!(file=std::fopen(filename,"r"))) { |
philpem@5 | 3919 | if (filename[0]=='-') error("Input '%s' : Command not found.",filename); |
philpem@5 | 3920 | else error("Input '%s' : File not found.",filename); |
philpem@5 | 3921 | } |
philpem@5 | 3922 | std::fclose(file); |
philpem@5 | 3923 | } |
philpem@5 | 3924 | } else std::strcpy(filename,argument); |
philpem@5 | 3925 | basename = cimg::basename(filename); |
philpem@5 | 3926 | ext = cimg::split_filename(filename); |
philpem@5 | 3927 | |
philpem@5 | 3928 | if (!cimg::strcasecmp("off",ext)) { // 3D object file. |
philpem@5 | 3929 | print("Input 3D object '%s'",filename); |
philpem@5 | 3930 | CImgList<unsigned int> primitives3d; |
philpem@5 | 3931 | CImgList<unsigned char> colors3d; |
philpem@5 | 3932 | CImg<float> opacities3d, points3d = CImg<float>::get_load_off(filename,primitives3d,colors3d); |
philpem@5 | 3933 | opacities3d.assign(1,primitives3d.size,1,1,1); |
philpem@5 | 3934 | points3d.object3dtoCImg3d(primitives3d,colors3d,opacities3d); |
philpem@5 | 3935 | input_images.insert(1); points3d.transfer_to(input_images[0]); |
philpem@5 | 3936 | input_filenames.insert(CImg<char>(is_fullpath?filename:basename, |
philpem@5 | 3937 | cimg::strlen(is_fullpath?filename:basename)+1,1,1,1,false)); |
philpem@5 | 3938 | obj3d = true; |
philpem@5 | 3939 | } else if (!cimg::strcasecmp(ext,"avi") || |
philpem@5 | 3940 | !cimg::strcasecmp(ext,"mov") || |
philpem@5 | 3941 | !cimg::strcasecmp(ext,"asf") || |
philpem@5 | 3942 | !cimg::strcasecmp(ext,"divx") || |
philpem@5 | 3943 | !cimg::strcasecmp(ext,"flv") || |
philpem@5 | 3944 | !cimg::strcasecmp(ext,"mpg") || |
philpem@5 | 3945 | !cimg::strcasecmp(ext,"m1v") || |
philpem@5 | 3946 | !cimg::strcasecmp(ext,"m2v") || |
philpem@5 | 3947 | !cimg::strcasecmp(ext,"m4v") || |
philpem@5 | 3948 | !cimg::strcasecmp(ext,"mjp") || |
philpem@5 | 3949 | !cimg::strcasecmp(ext,"mkv") || |
philpem@5 | 3950 | !cimg::strcasecmp(ext,"mpe") || |
philpem@5 | 3951 | !cimg::strcasecmp(ext,"movie") || |
philpem@5 | 3952 | !cimg::strcasecmp(ext,"ogm") || |
philpem@5 | 3953 | !cimg::strcasecmp(ext,"qt") || |
philpem@5 | 3954 | !cimg::strcasecmp(ext,"rm") || |
philpem@5 | 3955 | !cimg::strcasecmp(ext,"vob") || |
philpem@5 | 3956 | !cimg::strcasecmp(ext,"wmv") || |
philpem@5 | 3957 | !cimg::strcasecmp(ext,"xvid") || |
philpem@5 | 3958 | !cimg::strcasecmp(ext,"mpeg")) { |
philpem@5 | 3959 | unsigned int value0 = 0, value1 = 0, step = 1; char sep0 = 0, sep1 = 0, end = 0; |
philpem@5 | 3960 | if ((std::sscanf(options,"%u%c%*c%u%c%*c%u%c",&value0,&sep0,&value1,&sep1,&step,&end)==5 && sep0=='%' && sep1=='%') || |
philpem@5 | 3961 | (std::sscanf(options,"%u%c%*c%u%*c%u%c",&value0,&sep0,&value1,&step,&end)==4 && sep0=='%') || |
philpem@5 | 3962 | (std::sscanf(options,"%u%*c%u%c%*c%u%c",&value0,&value1,&sep1,&step,&end)==4 && sep1=='%') || |
philpem@5 | 3963 | (std::sscanf(options,"%u%*c%u%*c%u%c",&value0,&value1,&step,&end)==3) || |
philpem@5 | 3964 | (std::sscanf(options,"%u%c%*c%u%c%c",&value0,&sep0,&value1,&sep1,&end)==4 && sep0=='%' && sep1=='%') || |
philpem@5 | 3965 | (std::sscanf(options,"%u%c%*c%u%c",&value0,&sep0,&value1,&end)==3 && sep0=='%') || |
philpem@5 | 3966 | (std::sscanf(options,"%u%*c%u%c%c",&value0,&value1,&sep1,&end)==3 && sep1=='%') || |
philpem@5 | 3967 | (std::sscanf(options,"%u%*c%u%c",&value0,&value1,&end)==2)) { // Read several frames |
philpem@5 | 3968 | print("Input frames %u%s...%u%s with step %u of file '%s'", |
philpem@5 | 3969 | value0,sep0=='%'?"%":"",value1,sep1=='%'?"%":"",step,filename); |
philpem@5 | 3970 | if (sep0=='%' || sep1=='%') { |
philpem@5 | 3971 | const unsigned int nb_frames = CImg<unsigned int>::get_load_ffmpeg(filename,0,0,0)[0]; |
philpem@5 | 3972 | if (sep0=='%') value0 = value0*nb_frames/100; |
philpem@5 | 3973 | if (sep1=='%') value1 = value1*nb_frames/100; |
philpem@5 | 3974 | } |
philpem@5 | 3975 | } else if ((std::sscanf(options,"%u%c%c",&value0,&sep0,&end)==2 && sep0=='%') || |
philpem@5 | 3976 | (std::sscanf(options,"%u%c",&value0,&end)==1)) { // Read one frame |
philpem@5 | 3977 | print("Input frame %u%s of file '%s'",value0,sep0=='%'?"%":"",filename); |
philpem@5 | 3978 | if (sep0=='%') { |
philpem@5 | 3979 | const unsigned int nb_frames = CImg<unsigned int>::get_load_ffmpeg(filename,0,0,0)[0]; |
philpem@5 | 3980 | value0 = value0*nb_frames/100; |
philpem@5 | 3981 | } |
philpem@5 | 3982 | value1 = value0; step = 1; |
philpem@5 | 3983 | } else { // Read all frames |
philpem@5 | 3984 | print("Input all frames of file '%s'",filename); |
philpem@5 | 3985 | value0 = 0; value1 = ~0U; sep0 = sep1 = 0; step = 1; |
philpem@5 | 3986 | } |
philpem@5 | 3987 | input_images.load_ffmpeg(filename,value0,value1,step); |
philpem@5 | 3988 | if (input_images) |
philpem@5 | 3989 | input_filenames.insert(input_images.size,CImg<char>(is_fullpath?filename:basename, |
philpem@5 | 3990 | cimg::strlen(is_fullpath?filename:basename)+1,1,1,1,false)); |
philpem@5 | 3991 | } else if (!cimg::strcasecmp("raw",ext)) { // Raw file. |
philpem@5 | 3992 | int dx = 0, dy = 1, dz = 1, dv = 1; |
philpem@5 | 3993 | if (std::sscanf(options,"%d%*c%d%*c%d%*c%d",&dx,&dy,&dz,&dv)>0) { |
philpem@5 | 3994 | if (dx<=0 || dy<=0 || dz<=0 || dv<=0) |
philpem@5 | 3995 | error("Input raw file '%s' : Invalid specified dimensions %dx%dx%dx%d.",filename,dx,dy,dz,dv); |
philpem@5 | 3996 | print("Input raw file '%s'",filename); |
philpem@5 | 3997 | input_images.insert(1); input_images[0].load_raw(filename,dx,dy,dz,dv); |
philpem@5 | 3998 | input_filenames.insert(CImg<char>(is_fullpath?filename:basename, |
philpem@5 | 3999 | cimg::strlen(is_fullpath?filename:basename)+1,1,1,1,false)); |
philpem@5 | 4000 | } else error("Input raw file '%s' : Image dimensions must be specified.",filename); |
philpem@5 | 4001 | } else if (!cimg::strcasecmp("yuv",ext)) { // YUV file. |
philpem@5 | 4002 | int dx = 0, dy = 0; unsigned int first = 0, last = ~0U, step = 1; |
philpem@5 | 4003 | if (std::sscanf(options,"%d%*c%d%*c%u%*c%u%*c%u",&dx,&dy,&first,&last,&step)>0) { |
philpem@5 | 4004 | if (dx<=0 || dy<=0) |
philpem@5 | 4005 | error("Input yuv file '%s' : Invalid specified dimensions %dx%d.",filename,dx,dy); |
philpem@5 | 4006 | print("Input yuv file '%s'",filename); |
philpem@5 | 4007 | input_images.load_yuv(filename,dx,dy,first,last,step); |
philpem@5 | 4008 | input_filenames.insert(input_images.size,CImg<char>(is_fullpath?filename:basename, |
philpem@5 | 4009 | cimg::strlen(is_fullpath?filename:basename)+1,1,1,1,false)); |
philpem@5 | 4010 | } else error("Input yuv file '%s' : Image dimensions must be specified.",filename); |
philpem@5 | 4011 | } else { // Other file type. |
philpem@5 | 4012 | print("Input file '%s'",filename); |
philpem@5 | 4013 | input_images.load(filename); |
philpem@5 | 4014 | input_filenames.insert(input_images.size, |
philpem@5 | 4015 | CImg<char>(is_fullpath?filename:basename, |
philpem@5 | 4016 | cimg::strlen(is_fullpath?filename:basename)+1,1,1,1,false)); |
philpem@5 | 4017 | } |
philpem@5 | 4018 | } |
philpem@5 | 4019 | |
philpem@5 | 4020 | if (verbosity_level>=0) { |
philpem@5 | 4021 | if (input_images) { |
philpem@5 | 4022 | const unsigned int last = input_images.size-1; |
philpem@5 | 4023 | if (obj3d) |
philpem@5 | 4024 | std::fprintf(cimg_stdout," (%d points, %u primitives, %u colors).", |
philpem@5 | 4025 | (unsigned int)input_images(0,6), |
philpem@5 | 4026 | (unsigned int)input_images(0,7), |
philpem@5 | 4027 | (unsigned int)input_images(0,8)); |
philpem@5 | 4028 | else if (input_images.size==1) |
philpem@5 | 4029 | std::fprintf(cimg_stdout," (1 image %ux%ux%ux%u).", |
philpem@5 | 4030 | input_images[0].width,input_images[0].height,input_images[0].depth, |
philpem@5 | 4031 | input_images[0].dim); |
philpem@5 | 4032 | else std::fprintf(cimg_stdout," (%u images [0] = %ux%ux%ux%u, %s[%u] = %ux%ux%ux%u).", |
philpem@5 | 4033 | input_images.size, |
philpem@5 | 4034 | input_images[0].width,input_images[0].height,input_images[0].depth, |
philpem@5 | 4035 | input_images[0].dim, |
philpem@5 | 4036 | last==1?"":"...,", |
philpem@5 | 4037 | last, |
philpem@5 | 4038 | input_images[last].width,input_images[last].height,input_images[last].depth, |
philpem@5 | 4039 | input_images[last].dim); |
philpem@5 | 4040 | } else std::fprintf(cimg_stdout," (no available data)."); |
philpem@5 | 4041 | } |
philpem@5 | 4042 | |
philpem@5 | 4043 | for (unsigned int l = 0, siz = indices.size()-1, off = 0; l<=siz; ++l) { |
philpem@5 | 4044 | const unsigned int ind = indices[l] + off; |
philpem@5 | 4045 | if (l!=siz) images.insert(input_images,ind); |
philpem@5 | 4046 | else { |
philpem@5 | 4047 | images.insert(input_images.size,ind); |
philpem@5 | 4048 | cimglist_for(input_images,k) images[ind+k].swap(input_images[k]); |
philpem@5 | 4049 | } |
philpem@5 | 4050 | filenames.insert(input_filenames,ind); |
philpem@5 | 4051 | off+=input_images.size; |
philpem@5 | 4052 | } |
philpem@5 | 4053 | |
philpem@5 | 4054 | } catch (CImgException &e) { |
philpem@5 | 4055 | const char *error_message = e.message; |
philpem@5 | 4056 | char tmp[4096] = { 0 }, sep = 0; |
philpem@5 | 4057 | if (std::sscanf(error_message,"%4095[^>]>:%c",tmp,&sep)==2 && sep==':') error_message+=cimg::strlen(tmp)+3; |
philpem@5 | 4058 | error(error_message); |
philpem@5 | 4059 | } |
philpem@5 | 4060 | } |
philpem@5 | 4061 | |
philpem@5 | 4062 | // Check if command line has grown too much (possible recursive macro calls). |
philpem@5 | 4063 | if (command_line.size>=command_line_maxsize) |
philpem@5 | 4064 | error("Command line overflow : There are too much commands specified (possible recursive macro substitution)."); |
philpem@5 | 4065 | |
philpem@5 | 4066 | // Check if some loops have not been terminated. |
philpem@5 | 4067 | if (dowhile) warning("A '-while' directive is missing somewhere."); |
philpem@5 | 4068 | if (repeatdone) warning("A '-done' directive is missing somewhere."); |
philpem@5 | 4069 | |
philpem@5 | 4070 | // Display final result if necessary (not 'released' before). |
philpem@5 | 4071 | if (images.size && !is_released) { |
philpem@5 | 4072 | if (!display_objects3d(images,CImg<unsigned int>::sequence(images.size,0,images.size-1),false)) |
philpem@5 | 4073 | display_images(images,CImg<unsigned int>::sequence(images.size,0,images.size-1),true); |
philpem@5 | 4074 | } |
philpem@5 | 4075 | |
philpem@5 | 4076 | print("End G'MIC instance.\n"); |
philpem@5 | 4077 | return *this; |
philpem@5 | 4078 | } |
philpem@5 | 4079 | |
philpem@5 | 4080 | // Small hack to separate the compilation of G'MIC in different pixel types. |
philpem@5 | 4081 | // (only intended to save computer memory when compiling !) |
philpem@5 | 4082 | //-------------------------------------------------------------------------- |
philpem@5 | 4083 | #ifdef gmic_minimal |
philpem@5 | 4084 | gmic& gmic::parse_float(CImgList<float>& images) { return parse(images); } |
philpem@5 | 4085 | template gmic::gmic(const int, const char *const *const, CImgList<float>&, const char *const custom_macros, const bool add_macros_at_start); |
philpem@5 | 4086 | template gmic::gmic(const char* const, CImgList<float>&, const char *const custom_macros, const bool add_macros_at_start); |
philpem@5 | 4087 | #else |
philpem@5 | 4088 | #if defined(gmic_bool) || !defined(gmic_separate_compilation) |
philpem@5 | 4089 | gmic& gmic::parse_bool(CImgList<bool>& images) { return parse(images); } |
philpem@5 | 4090 | template gmic::gmic(const int, const char *const *const, CImgList<bool>&, const char *const custom_macros, const bool add_macros_at_start); |
philpem@5 | 4091 | template gmic::gmic(const char* const, CImgList<bool>&, const char *const custom_macros, const bool add_macros_at_start); |
philpem@5 | 4092 | #endif |
philpem@5 | 4093 | #if defined(gmic_uchar) || !defined(gmic_separate_compilation) |
philpem@5 | 4094 | gmic& gmic::parse_uchar(CImgList<unsigned char>& images) { return parse(images); } |
philpem@5 | 4095 | template gmic::gmic(const int, const char *const *const, CImgList<unsigned char>&, const char *const custom_macros, const bool add_macros_at_start); |
philpem@5 | 4096 | template gmic::gmic(const char* const, CImgList<unsigned char>&, const char *const custom_macros, const bool add_macros_at_start); |
philpem@5 | 4097 | #endif |
philpem@5 | 4098 | #if defined(gmic_char) || !defined(gmic_separate_compilation) |
philpem@5 | 4099 | gmic& gmic::parse_char(CImgList<char>& images) { return parse(images); } |
philpem@5 | 4100 | template gmic::gmic(const int, const char *const *const, CImgList<char>&, const char *const custom_macros, const bool add_macros_at_start); |
philpem@5 | 4101 | template gmic::gmic(const char* const, CImgList<char>&, const char *const custom_macros, const bool add_macros_at_start); |
philpem@5 | 4102 | #endif |
philpem@5 | 4103 | #if defined(gmic_ushort) || !defined(gmic_separate_compilation) |
philpem@5 | 4104 | gmic& gmic::parse_ushort(CImgList<unsigned short>& images) { return parse(images); } |
philpem@5 | 4105 | template gmic::gmic(const int, const char *const *const, CImgList<unsigned short>&, const char *const custom_macros, const bool add_macros_at_start); |
philpem@5 | 4106 | template gmic::gmic(const char* const, CImgList<unsigned short>&, const char *const custom_macros, const bool add_macros_at_start); |
philpem@5 | 4107 | #endif |
philpem@5 | 4108 | #if defined(gmic_short) || !defined(gmic_separate_compilation) |
philpem@5 | 4109 | gmic& gmic::parse_short(CImgList<short>& images) { return parse(images); } |
philpem@5 | 4110 | template gmic::gmic(const int, const char *const *const, CImgList<short>&, const char *const custom_macros, const bool add_macros_at_start); |
philpem@5 | 4111 | template gmic::gmic(const char* const, CImgList<short>&, const char *const custom_macros, const bool add_macros_at_start); |
philpem@5 | 4112 | #endif |
philpem@5 | 4113 | #if defined(gmic_uint) || !defined(gmic_separate_compilation) |
philpem@5 | 4114 | gmic& gmic::parse_uint(CImgList<unsigned int>& images) { return parse(images); } |
philpem@5 | 4115 | template gmic::gmic(const int, const char *const *const, CImgList<unsigned int>&, const char *const custom_macros, const bool add_macros_at_start); |
philpem@5 | 4116 | template gmic::gmic(const char* const, CImgList<unsigned int>&, const char *const custom_macros, const bool add_macros_at_start); |
philpem@5 | 4117 | #endif |
philpem@5 | 4118 | #if defined(gmic_int) || !defined(gmic_separate_compilation) |
philpem@5 | 4119 | gmic& gmic::parse_int(CImgList<int>& images) { return parse(images); } |
philpem@5 | 4120 | template gmic::gmic(const int, const char *const *const, CImgList<int>&, const char *const custom_macros, const bool add_macros_at_start); |
philpem@5 | 4121 | template gmic::gmic(const char* const, CImgList<int>&, const char *const custom_macros, const bool add_macros_at_start); |
philpem@5 | 4122 | #endif |
philpem@5 | 4123 | #if defined(gmic_float) || !defined(gmic_separate_compilation) |
philpem@5 | 4124 | gmic& gmic::parse_float(CImgList<float>& images) { return parse(images); } |
philpem@5 | 4125 | template gmic::gmic(const int, const char *const *const, CImgList<float>&, const char *const custom_macros, const bool add_macros_at_start); |
philpem@5 | 4126 | template gmic::gmic(const char* const, CImgList<float>&, const char *const custom_macros, const bool add_macros_at_start); |
philpem@5 | 4127 | #endif |
philpem@5 | 4128 | #if defined(gmic_double) || !defined(gmic_separate_compilation) |
philpem@5 | 4129 | gmic& gmic::parse_double(CImgList<double>& images) { return parse(images); } |
philpem@5 | 4130 | template gmic::gmic(const int, const char *const *const, CImgList<double>&, const char *const custom_macros, const bool add_macros_at_start); |
philpem@5 | 4131 | template gmic::gmic(const char* const, CImgList<double>&, const char *const custom_macros, const bool add_macros_at_start); |
philpem@5 | 4132 | #endif |
philpem@5 | 4133 | #endif |
philpem@5 | 4134 | #endif |
philpem@5 | 4135 | |
philpem@5 | 4136 | //----------------------- |
philpem@5 | 4137 | // Start main procedure. |
philpem@5 | 4138 | //----------------------- |
philpem@5 | 4139 | #if defined(gmic_main) || (!defined(gmic_separate_compilation) && !defined(gmic_minimal)) |
philpem@5 | 4140 | extern char data_def[]; |
philpem@5 | 4141 | |
philpem@5 | 4142 | int main(int argc, char **argv) { |
philpem@5 | 4143 | |
philpem@5 | 4144 | // Display help if necessary. |
philpem@5 | 4145 | //--------------------------- |
philpem@5 | 4146 | if (argc==1) { |
philpem@5 | 4147 | std::fprintf(cimg_stdout,"<gmic> No options or data provided. Try '%s -h' for help.\n",cimg::basename(argv[0])); |
philpem@5 | 4148 | std::exit(0); |
philpem@5 | 4149 | } |
philpem@5 | 4150 | |
philpem@5 | 4151 | if (cimg_option("-h",false,0) || cimg_option("-help",false,0) || cimg_option("--help",false,0)) { |
philpem@5 | 4152 | cimg_usage("GREYC's Magic Image Converter"); |
philpem@5 | 4153 | |
philpem@5 | 4154 | char version[1024] = { 0 }; |
philpem@5 | 4155 | std::sprintf(version," Version %d.%d.%d.%d, Copyright (C) 2008-2009, David Tschumperle (http://gmic.sourceforge.net)", |
philpem@5 | 4156 | gmic_version/1000,(gmic_version/100)%10,(gmic_version/10)%10,gmic_version%10); |
philpem@5 | 4157 | cimg_help(version); |
philpem@5 | 4158 | |
philpem@5 | 4159 | cimg_help("\n Usage\n" |
philpem@5 | 4160 | " -----"); |
philpem@5 | 4161 | cimg_help(" gmic [file_1] [file_2] .. [file_n] [command_1] .. [command_n] [file_n+1] ...\n"); |
philpem@5 | 4162 | cimg_help(" G'MIC is an interpreter of image processing macros whose goal is to convert, manipulate and"); |
philpem@5 | 4163 | cimg_help(" visualize generic 1D/2D/3D multi-spectral image and video files. It follows these simple rules :\n"); |
philpem@5 | 4164 | cimg_help(" - G'MIC handles a numbered list of images which are all stored in computer memory."); |
philpem@5 | 4165 | cimg_help(" - The first image of the list has indice '[0]'."); |
philpem@5 | 4166 | cimg_help(" - Negative indices are treated in a cyclic way (i.e. '[-1]' is the last image,"); |
philpem@5 | 4167 | cimg_help(" '[-2]' the penultimate one, and so on...)."); |
philpem@5 | 4168 | cimg_help(" - Command line items tell how to add/remove/manipulate/display images of the list."); |
philpem@5 | 4169 | cimg_help(" - Items are read and executed in the order they appear on the command line, from the left to the right."); |
philpem@5 | 4170 | cimg_help(" - Items can thus appear more than one time on the command line."); |
philpem@5 | 4171 | cimg_help(" - An item starting by '-' is a G'MIC instruction."); |
philpem@5 | 4172 | cimg_help(" - One instruction may have two equivalent names (regular and short)."); |
philpem@5 | 4173 | cimg_help(" - A G'MIC instruction may have mandatory or optional arguments."); |
philpem@5 | 4174 | cimg_help(" - When multiple arguments are needed, they are separated by commas ','."); |
philpem@5 | 4175 | cimg_help(" - Items that are not instructions are considered either as input filenames or input strings."); |
philpem@5 | 4176 | cimg_help(" - When an input filename is encountered, the corresponding image data are loaded"); |
philpem@5 | 4177 | cimg_help(" and added to the end of the image list."); |
philpem@5 | 4178 | cimg_help(" (see section 'Filename options' below for more informations on file input/output)."); |
philpem@5 | 4179 | cimg_help(" - Special filenames '-' or '-.ext' mean 'standard input/output' (optionally. in 'ext' format)."); |
philpem@5 | 4180 | cimg_help(" - Special input strings can be used to insert new images to the list. They can be :"); |
philpem@5 | 4181 | cimg_help(" - 'width[%][xheight[%][xdepth[%][xdim[%][xN]]]]' : Insert 'N' black images with specified size."); |
philpem@5 | 4182 | cimg_help(" (adding '%' to a dimension means 'percentage of to the same dimension in the last image'),"); |
philpem@5 | 4183 | cimg_help(" - '[indice]' or '[indice]xN' : Insert 1 or N copies of the existing image [indice]."); |
philpem@5 | 4184 | cimg_help(" - '(v1,v2,...)' or '(v1,v2,...)xN' : Insert 1 or N copies of the specified IxJxKxL image."); |
philpem@5 | 4185 | cimg_help(" Separators inside '(..)' can be ',' (column), ';' (line), '/' (slice) or '^' (channel)."); |
philpem@5 | 4186 | cimg_help(" - A G'MIC instruction may be restricted to a specific subset of the list, by adding '[subset]' to"); |
philpem@5 | 4187 | cimg_help(" the instruction name. Several usual expressions are possible for 'subset', for instance : "); |
philpem@5 | 4188 | cimg_help(" '-command[0,1,3]' : Apply instruction on images 0,1 and 3."); |
philpem@5 | 4189 | cimg_help(" '-command[3-5]' : Apply instruction on images 3 to 5."); |
philpem@5 | 4190 | cimg_help(" '-command[50%-100%] : Apply instruction on the second half of the image list."); |
philpem@5 | 4191 | cimg_help(" '-command[0,-2,-1]' : Apply instruction on the first and two latest images."); |
philpem@5 | 4192 | 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)."); |
philpem@5 | 4193 | cimg_help(" '-command[0,2-4,50%--1]' : Apply instruction on images 0,2,3,4 and the second half of the list."); |
philpem@5 | 4194 | cimg_help(" - When no image subset is specified, a G'MIC instruction is applied on all images of the list."); |
philpem@5 | 4195 | cimg_help(" - Native (non-macro) instructions starting with '--' instead of '-' do not act 'in-place' but"); |
philpem@5 | 4196 | cimg_help(" insert their result as a new image at the end of the list."); |
philpem@5 | 4197 | cimg_help(" - On the command line, any item of the form '@indice' or '@{indice}' is replaced"); |
philpem@5 | 4198 | cimg_help(" by the values of the image '[indice]' separated by commas."); |
philpem@5 | 4199 | cimg_help(" - Items '@?' (or '@{?}'), '@{?,max}' or '@{?,min,max}' are replaced by a float random value between [0,1], [0,max] or [min,max]."); |
philpem@5 | 4200 | cimg_help(" - Items '@[?]', '@[?,max]' or '@[?,min,max]' do the same but return integer random values."); |
philpem@5 | 4201 | cimg_help(" - Restrictions to a subset of image values can be specified with '@{indice,subset}' (as in '@{2,0-50%}')."); |
philpem@5 | 4202 | cimg_help(" - Restriction to a particular pixel coordinate can be specified with '@(indice,x[,y[,z[,v[,borders]]]])'."); |
philpem@5 | 4203 | cimg_help(" - On the command line, the item '@#' is replaced by the number of images in the list."); |
philpem@5 | 4204 | cimg_help(" - Input filenames or commands may result to the generation of 3D objects."); |
philpem@5 | 4205 | cimg_help(" - A 3D object viewer, based on software rendering, is included in G'MIC."); |
philpem@5 | 4206 | cimg_help(" - A 3D object is stored as a single-column image containing all object data, in the following order :"); |
philpem@5 | 4207 | cimg_help(" { magic header, vertices, faces, colors, opacities }."); |
philpem@5 | 4208 | cimg_help(" - Custom user-defined G'MIC instructions can be defined with the use of a macro file."); |
philpem@5 | 4209 | cimg_help(" - A macro file is a simple ASCII text file, each line being of the form"); |
philpem@5 | 4210 | cimg_help(" 'instruction_name : substitution' or 'substitution (continuation)' or '# comment'."); |
philpem@5 | 4211 | cimg_help(" - Each invoked macro instruction is substituted as its defined content on the command line."); |
philpem@5 | 4212 | cimg_help(" - A macro file 'gmic_def.raw' is distributed within the G'MIC package."); |
philpem@5 | 4213 | cimg_help(" - The macros defined in 'gmic_def.raw' are included by default in G'MIC."); |
philpem@5 | 4214 | cimg_help(" - Macros arguments, separated by commas, can be added after the invokation of a macro instruction."); |
philpem@5 | 4215 | cimg_help(" - In macros definitions, expressions starting with '$' are used to reference macro arguments :"); |
philpem@5 | 4216 | cimg_help(" $i and ${i} are replaced by the value of the i-th macro argument."); |
philpem@5 | 4217 | cimg_help(" $# and ${#} are replaced by the number of macro arguments."); |
philpem@5 | 4218 | cimg_help(" $* and ${*} are replaced by the entire string of macro arguments."); |
philpem@5 | 4219 | cimg_help(" ${i*} is replaced by all macro arguments following the i-th argument (included)."); |
philpem@5 | 4220 | cimg_help(" ${i=$#} is replaced by $i if defined, or by its new value $# else."); |
philpem@5 | 4221 | cimg_help(" ${i=$j} is replaced by $i if defined, or by its new value $j else."); |
philpem@5 | 4222 | cimg_help(" ${i=default} is replaced by $i if defined, or by its new value 'default' else."); |
philpem@5 | 4223 | cimg_help("\n A list of available native and macro instructions is available below."); |
philpem@5 | 4224 | cimg_help(" A parameter specified in '[]' is optional, except when standing for '[indices]' where it"); |
philpem@5 | 4225 | cimg_help(" corresponds to one or several indices of the image list, as described above. In this case, the '[' and ']'"); |
philpem@5 | 4226 | cimg_help(" characters must explicitly appear when writting the item."); |
philpem@5 | 4227 | |
philpem@5 | 4228 | cimg_help("\n Global options\n" |
philpem@5 | 4229 | " --------------"); |
philpem@5 | 4230 | cimg_option("-help","(no args)","Display this help (eq. to '-h')."); |
philpem@5 | 4231 | cimg_option("-verbose+","(no args)","Increment verbosity level (eq. to '-v+')."); |
philpem@5 | 4232 | cimg_option("-verbose-","(no args)","Decrement verbosity level (eq. to '-v-')."); |
philpem@5 | 4233 | cimg_option("-macros","'filename'","Load macro file from specified filename (eq. to '-m')."); |
philpem@5 | 4234 | cimg_option("-debug","(no args)","Switch debug flag (when on, displays internal infos for debugging)."); |
philpem@5 | 4235 | cimg_option("-fullpath","(no args)","Switch full path flag (when on, displays full filename paths)."); |
philpem@5 | 4236 | |
philpem@5 | 4237 | cimg_help("\n Arithmetic operators\n" |
philpem@5 | 4238 | " --------------------"); |
philpem@5 | 4239 | cimg_option("-add","'value', '[indice]' or (no args)","Add 'value' or '[indice]' to image(s)"); |
philpem@5 | 4240 | cimg_help(" " |
philpem@5 | 4241 | "or add image(s) together (eq. to '-+')."); |
philpem@5 | 4242 | cimg_option("-sub","'value', '[indice]' or (no args)","Substract 'value' or '[indice]' to image(s)"); |
philpem@5 | 4243 | cimg_help(" " |
philpem@5 | 4244 | "or substract image(s) together (eq. to '--')."); |
philpem@5 | 4245 | cimg_option("-mul","'value', '[indice]' or (no args)","Multiply image(s) by 'value' or '[indice]'"); |
philpem@5 | 4246 | cimg_help(" " |
philpem@5 | 4247 | "or multiply image(s) together (eq. to '-*')."); |
philpem@5 | 4248 | cimg_option("-div","'value', '[indice]' or (no args)","Divide image(s) by 'value' or '[indice]'"); |
philpem@5 | 4249 | cimg_help(" " |
philpem@5 | 4250 | "or divide image(s) together (eq. to '-/')."); |
philpem@5 | 4251 | cimg_option("-pow","'value', '[indice]' or (no args)","Compute image(s) to the power of 'value' or '[indice]'"); |
philpem@5 | 4252 | cimg_help(" " |
philpem@5 | 4253 | "or power of the image(s) together (eq. to '-^')."); |
philpem@5 | 4254 | cimg_option("-min","'value', '[indice]' or (no args)","Compute minimum between image(s) and 'value' or '[indice]'"); |
philpem@5 | 4255 | cimg_help(" " |
philpem@5 | 4256 | "or minimum of image(s) together."); |
philpem@5 | 4257 | cimg_option("-max","'value', '[indice]' or (no args)","Compute maximum between image(s) and 'value' or '[indice]'"); |
philpem@5 | 4258 | cimg_help(" " |
philpem@5 | 4259 | "or maximum of image(s) together."); |
philpem@5 | 4260 | cimg_option("-mod","'value', '[indice]' or (no args)","Compute modulo of image(s) with 'value' or '[indice]'"); |
philpem@5 | 4261 | cimg_help(" " |
philpem@5 | 4262 | "or modulo with image(s) together."); |
philpem@5 | 4263 | cimg_option("-and","'value', '[indice]' or (no args)","Compute bitwise AND of image(s) with 'value' or '[indice]'"); |
philpem@5 | 4264 | cimg_help(" " |
philpem@5 | 4265 | "or bitwise AND of image(s) together."); |
philpem@5 | 4266 | cimg_option("-or","'value', '[indice]' or (no args)","Compute bitwise OR of image(s) with 'value' or '[indice]'"); |
philpem@5 | 4267 | cimg_help(" " |
philpem@5 | 4268 | "or bitwise OR of image(s) together."); |
philpem@5 | 4269 | cimg_option("-xor","'value', '[indice]' or (no args)","Compute bitwise XOR of image(s) with 'value' '[indice]'"); |
philpem@5 | 4270 | cimg_help(" " |
philpem@5 | 4271 | "or bitwise XOR of image(s) together."); |
philpem@5 | 4272 | cimg_option("-cos","(no args)","Compute cosine of image(s) values."); |
philpem@5 | 4273 | cimg_option("-sin","(no args)","Compute sine of image(s) values."); |
philpem@5 | 4274 | cimg_option("-tan","(no args)","Compute tangent of image(s) values."); |
philpem@5 | 4275 | cimg_option("-acos","(no args)","Compute arccosine of image(s) values."); |
philpem@5 | 4276 | cimg_option("-asin","(no args)","Compute arcsine of image(s) values."); |
philpem@5 | 4277 | cimg_option("-atan","(no args)","Compute arctangent of image(s) values."); |
philpem@5 | 4278 | cimg_option("-abs","(no args)","Compute absolute value of image(s) values."); |
philpem@5 | 4279 | cimg_option("-sqr","(no args)","Compute square of image(s) values."); |
philpem@5 | 4280 | cimg_option("-sqrt","(no args)","Compute square root of image(s) values."); |
philpem@5 | 4281 | cimg_option("-exp","(no args)","Compute exponential of image(s) values."); |
philpem@5 | 4282 | cimg_option("-log","(no args)","Compute logarithm of image(s) values."); |
philpem@5 | 4283 | cimg_option("-log10","(no args)","Compute logarithm_10 of image(s) values."); |
philpem@5 | 4284 | |
philpem@5 | 4285 | cimg_help("\n Pointwise pixel manipulation\n" |
philpem@5 | 4286 | " ----------------------------"); |
philpem@5 | 4287 | cimg_option("-type","'value_type'","Cast all images into specified value type (eq. to '-t')."); |
philpem@5 | 4288 | cimg_help(" " |
philpem@5 | 4289 | "('value_type' can be 'bool','uchar','char','ushort','short',"); |
philpem@5 | 4290 | cimg_help(" " |
philpem@5 | 4291 | "'uint','int','float','double')."); |
philpem@5 | 4292 | cimg_option("-set","'value[,x[,y[,z[,v]]]]'","Set scalar value in image(s) at specified position (eq. to '-=')."); |
philpem@5 | 4293 | cimg_option("-endian","(no args)","Invert endianness of the image(s) buffers."); |
philpem@5 | 4294 | cimg_option("-fill","'value1,value2,...'","Fill image(s) with scalar values in a repetitive way (eq. to '-f')."); |
philpem@5 | 4295 | cimg_option("-threshold","'value[%][,soft]' or (noargs)","Threshold pixel values ((noargs) for interactive mode)."); |
philpem@5 | 4296 | cimg_option("-cut","'{value1[%],[indice]},{value2[%],[indice]}' or (noargs)","Cut pixel values in specified range "); |
philpem@5 | 4297 | cimg_help(" " |
philpem@5 | 4298 | "((noargs) for interactive mode)."); |
philpem@5 | 4299 | cimg_option("-normalize","'{value1[%],[indice]},{value2[%],[indice]}'", |
philpem@5 | 4300 | "Normalize pixel values in specified range (eq. to '-n')."); |
philpem@5 | 4301 | cimg_option("-round","'round_value[,round_type]'","Round pixel values."); |
philpem@5 | 4302 | cimg_option("-equalize","'nb_levels'","Equalize image(s) histogram(s) using specified number of levels."); |
philpem@5 | 4303 | cimg_option("-quantize","'nb_levels'","Quantize image(s) with 'nb_levels' levels."); |
philpem@5 | 4304 | cimg_option("-noise","'std[%][,noise_type]'","Add noise with specified standard deviation"); |
philpem@5 | 4305 | cimg_help(" " |
philpem@5 | 4306 | "('noise_type' can be '{0=gaussian, 1=uniform, 2=salt&pepper, 3=poisson}'."); |
philpem@5 | 4307 | cimg_option("-norm","(no args)","Compute pointwise L2-norm of vector-valued image(s)."); |
philpem@5 | 4308 | cimg_option("-orientation","(no args)","Compute pointwise orientation of vector-valued image(s)."); |
philpem@5 | 4309 | |
philpem@5 | 4310 | cimg_help("\n Color bases conversions\n" |
philpem@5 | 4311 | " -----------------------"); |
philpem@5 | 4312 | cimg_option("-rgb2hsv","(no args)","Convert image(s) from RGB to HSV colorbases."); |
philpem@5 | 4313 | cimg_option("-rgb2hsl","(no args)","Convert image(s) from RGB to HSL colorbases."); |
philpem@5 | 4314 | cimg_option("-rgb2hsi","(no args)","Convert image(s) from RGB to HSI colorbases."); |
philpem@5 | 4315 | cimg_option("-rgb2yuv","(no args)","Convert image(s) from RGB to YUV colorbases."); |
philpem@5 | 4316 | cimg_option("-rgb2ycbcr","(no args)","Convert image(s) from RGB to YCbCr colorbases."); |
philpem@5 | 4317 | cimg_option("-rgb2xyz","(no args)","Convert image(s) from RGB to XYZ colorbases."); |
philpem@5 | 4318 | cimg_option("-rgb2lab","(no args)","Convert image(s) from RGB to Lab colorbases."); |
philpem@5 | 4319 | cimg_option("-rgb2cmy","(no args)","Convert image(s) from RGB to CMY colorbases."); |
philpem@5 | 4320 | cimg_option("-rgb2cmyk","(no args)","Convert image(s) from RGB to CMYK colorbases."); |
philpem@5 | 4321 | cimg_option("-rgb2lut","'[indice][,dithering]' or 'LUT_type[,dithering]'","Index image(s) with color palette "); |
philpem@5 | 4322 | cimg_help(" " |
philpem@5 | 4323 | "('LUT_type' can be '{0=default, 1=rainbow, 2=contrast}'"); |
philpem@5 | 4324 | cimg_help(" " |
philpem@5 | 4325 | "'dithering' can be '{0=off, 1=on}')."); |
philpem@5 | 4326 | cimg_option("-hsv2rgb","(no args)","Convert image(s) from HSV to RGB colorbases."); |
philpem@5 | 4327 | cimg_option("-hsl2rgb","(no args)","Convert image(s) from HSL to RGB colorbases."); |
philpem@5 | 4328 | cimg_option("-hsi2rgb","(no args)","Convert image(s) from HSI to RGB colorbases."); |
philpem@5 | 4329 | cimg_option("-yuv2rgb","(no args)","Convert image(s) from YUV to RGB colorbases."); |
philpem@5 | 4330 | cimg_option("-ycbcr2rgb","(no args)","Convert image(s) from YCbCr to RGB colorbases."); |
philpem@5 | 4331 | cimg_option("-xyz2rgb","(no args)","Convert image(s) from XYZ to RGB colorbases."); |
philpem@5 | 4332 | cimg_option("-lab2rgb","(no args)","Convert image(s) from Lab to RGB colorbases."); |
philpem@5 | 4333 | cimg_option("-cmy2rgb","(no args)","Convert image(s) from CMY to RGB colorbases."); |
philpem@5 | 4334 | cimg_option("-cmyk2rgb","(no args)","Convert image(s) from CMYK to RGB colorbases."); |
philpem@5 | 4335 | cimg_option("-lut2rgb","'[indice]' or 'LUT_type'","Map color palette to image(s) "); |
philpem@5 | 4336 | cimg_help(" " |
philpem@5 | 4337 | "('LUT_type' can be '{0=default, 1=rainbow, 2=contrast}'."); |
philpem@5 | 4338 | |
philpem@5 | 4339 | cimg_help("\n Geometric manipulation\n" |
philpem@5 | 4340 | " ----------------------"); |
philpem@5 | 4341 | cimg_option("-resize","'[indice][,interpolation[,borders[,center]]]' or ",""); |
philpem@5 | 4342 | cimg_help(" " |
philpem@5 | 4343 | "'{[indice],width[%]}[x{[indice],height[%]}[x{[indice],depth[%]}[x{[indice],dim[%]}[,interpolation[,borders[,center]]]]]]'"); |
philpem@5 | 4344 | cimg_help(" " |
philpem@5 | 4345 | "or (noargs)"); |
philpem@5 | 4346 | cimg_help(" " |
philpem@5 | 4347 | "Resize image(s) to specified geometry ((noargs) for interactive mode) (eq. to '-r')"); |
philpem@5 | 4348 | cimg_help(" " |
philpem@5 | 4349 | "('interpolation' can be '{0=none, 1=nearest, 2=average, 3=linear, 4=grid, 5=cubic}')."); |
philpem@5 | 4350 | cimg_option("-resize2x","(no args)","Resize image(s) with Scale2x."); |
philpem@5 | 4351 | cimg_option("-resize3x","(no args)","Resize image(s) with Scale3x."); |
philpem@5 | 4352 | cimg_option("-crop","'x0[%],x1[%][,border_conditions]' or 'x0[%],y0[%],x1[%],y1[%][,border_conditions]' or ",""); |
philpem@5 | 4353 | cimg_help(" " |
philpem@5 | 4354 | "'x0[%],y0[%],z0[%],x1[%],y1[%],z1[%][,border_conditions]' or "); |
philpem@5 | 4355 | cimg_help(" " |
philpem@5 | 4356 | "'x0[%],y0[%],z0[%],v0[%],x1[%],y1[%],z1[%],v1[%][,border_conditions]' or (noargs)."); |
philpem@5 | 4357 | cimg_help(" " |
philpem@5 | 4358 | "Crop image(s) using specified geometry ((noargs) for interactive mode) (eq. to '-c') "); |
philpem@5 | 4359 | cimg_help(" " |
philpem@5 | 4360 | "('border_conditions' can be '{0=zero, 1=nearest}')"); |
philpem@5 | 4361 | cimg_help(" " |
philpem@5 | 4362 | "((no args) for interactive mode)."); |
philpem@5 | 4363 | cimg_option("-autocrop","'value1,value2,...'","Autocrop image(s) using specified background color."); |
philpem@5 | 4364 | cimg_option("-channels","'{[ind0],v0[%]}[,{[ind1],v1[%]}]'","Select channels v0..v1 of multi-spectral image(s)."); |
philpem@5 | 4365 | cimg_option("-slices","'{[ind0],z0[%]}[,{[ind1],z1[%]}]'","Select slices z0..z1 of volumetric image(s)."); |
philpem@5 | 4366 | cimg_option("-lines","'{[ind0],y0[%]}[,{[ind1],y1[%]}]'","Select lines y0..y1 of image(s)."); |
philpem@5 | 4367 | cimg_option("-columns","'{[ind0],x0[%]}[,{[ind1],x1[%]}]'","Select columns x0..x1 of image(s)."); |
philpem@5 | 4368 | cimg_option("-rotate","'angle[,border_conditions]'","Rotate image(s) with a given angle "); |
philpem@5 | 4369 | cimg_help(" " |
philpem@5 | 4370 | "('border_conditions' can be '{-3=cyclic (in-place), -2=nearest(ip), -1=zero(ip), 0=zero, 1=nearest, 2=cyclic}'"); |
philpem@5 | 4371 | cimg_help(" " |
philpem@5 | 4372 | "and 'interpolation' can be '{0=none, 1=linear, 2=cubic}')."); |
philpem@5 | 4373 | cimg_option("-mirror","'axis'", |
philpem@5 | 4374 | "Mirror image(s) along specified axis ('axis' can be '{x,y,z,v}')."); |
philpem@5 | 4375 | cimg_option("-translate","'tx[%][,ty[%][,tz[%][,tv[%][,border_conditions]]]]'", |
philpem@5 | 4376 | "Translate image(s) by vector (dx,dy,dz,dv)"); |
philpem@5 | 4377 | cimg_help(" " |
philpem@5 | 4378 | "('border_conditions' can be '{0=zero, 1=nearest, 2=cyclic}')."); |
philpem@5 | 4379 | cimg_option("-transpose","(no args)","Transpose image(s)."); |
philpem@5 | 4380 | cimg_option("-invert","(no args)","Compute inverse matrix."); |
philpem@5 | 4381 | cimg_option("-permute","'permutation'","Permute image axes by the specified permutation " |
philpem@5 | 4382 | "('permutation' can be 'yxzv',...)."); |
philpem@5 | 4383 | cimg_option("-unroll","'axis'", |
philpem@5 | 4384 | "Unroll image(s) along specified axis ('axis' can be '{x,y,z,v}')."); |
philpem@5 | 4385 | cimg_option("-split","'axis[,nb_parts]' or 'value[,keep]'", |
philpem@5 | 4386 | "Split image(s) along specified axis or value ('axis' can be '{x,y,z,v}') (eq. to '-s')."); |
philpem@5 | 4387 | cimg_option("-append","'axis,[alignement]'","Append image(s) along specified axis and alignement (eq. to '-a')"); |
philpem@5 | 4388 | cimg_help(" " |
philpem@5 | 4389 | "('axis' can be '{x,y,z,v}' and 'alignement' can be '{p=left, c=center, n=right)'."); |
philpem@5 | 4390 | cimg_option("-warp","'[indice][,relative[,interpolation[,border_conditions[,nb_frames]]]]'", |
philpem@5 | 4391 | "Warp image(s) in 'nb_frames' with field '[indice]' "); |
philpem@5 | 4392 | cimg_help(" " |
philpem@5 | 4393 | "('relative' can be '{0,1}', 'interpolation' can be '{0,1}', " |
philpem@5 | 4394 | "'border_conditions' can be '{0=zero, 1=nearest}')."); |
philpem@5 | 4395 | |
philpem@5 | 4396 | cimg_help("\n Image filtering\n" |
philpem@5 | 4397 | " ---------------"); |
philpem@5 | 4398 | cimg_option("-blur","'std[,border_conditions]'", |
philpem@5 | 4399 | "Apply gaussian blur of specified standard deviation"); |
philpem@5 | 4400 | cimg_help(" " |
philpem@5 | 4401 | "('border_conditions' can be '{0=zero, 1=nearest}')."); |
philpem@5 | 4402 | cimg_option("-bilateral","'stdevs,stdevr'", |
philpem@5 | 4403 | "Apply bilateral filtering with specified standard deviations 'stdevs' and 'stdevr'."); |
philpem@5 | 4404 | cimg_option("-smooth","'amplitude[,sharpness[,anisotropy[,alpha[,sigma[,dl[,da[,prec[,interp[,fast]]]]]]]]]'",""); |
philpem@5 | 4405 | cimg_help(" " |
philpem@5 | 4406 | "Smooth image(s) anisotropically with specified parameters."); |
philpem@5 | 4407 | cimg_option("-denoise","'patch_size[,stdev_p[,stdev_s[,lookup_size]]]'", |
philpem@5 | 4408 | "Denoise image(s) with a patch-averaging procedure."); |
philpem@5 | 4409 | cimg_option("-median","'size'","Apply median filter with specified size."); |
philpem@5 | 4410 | cimg_option("-sharpen","'amplitude[,0]' or 'amplitude,1[,edge[,alpha[,sigma]]]'", |
philpem@5 | 4411 | "Sharpen image(s) with inverse diffusion or shock filters."); |
philpem@5 | 4412 | cimg_option("-convolve","'[indice][,border_conditions]'", |
philpem@5 | 4413 | "Convolve image(s) by the specified mask"); |
philpem@5 | 4414 | cimg_help(" " |
philpem@5 | 4415 | "('border_conditions' can be '{0=zero, 1=nearest}')."); |
philpem@5 | 4416 | cimg_option("-correlate","'[indice][,border_conditions]'", |
philpem@5 | 4417 | "Correlate image(s) by the specified mask (same parameters as above)."); |
philpem@5 | 4418 | cimg_option("-erode","'size[,border_conditions]' or '[indice][,border_conditions]'",""); |
philpem@5 | 4419 | cimg_help(" " |
philpem@5 | 4420 | "Erode image(s) by the specified mask (same parameters as above)')."); |
philpem@5 | 4421 | cimg_option("-dilate","'size[,border_conditions]' or '[indice][,border_conditions]'",""); |
philpem@5 | 4422 | cimg_help(" " |
philpem@5 | 4423 | "Dilate image(s) by the specified mask (same parameters as above)."); |
philpem@5 | 4424 | cimg_option("-gradient","'x', 'xy', 'xyz' or (no args)","Compute image gradient."); |
philpem@5 | 4425 | cimg_option("-hessian","'{xx,xy,xz,yy,yz,zz}' or (no args)","Compute image Hessian."); |
philpem@5 | 4426 | cimg_option("-fft","(no args)","Compute direct Fourier transform."); |
philpem@5 | 4427 | cimg_option("-ifft","(no args)","Compute inverse Fourier transform."); |
philpem@5 | 4428 | |
philpem@5 | 4429 | cimg_help("\n Image creation and drawing\n" |
philpem@5 | 4430 | " --------------------------"); |
philpem@5 | 4431 | cimg_option("-dimensions","(no args)","Get dimensions of the image(s) as a 1x4 vector."); |
philpem@5 | 4432 | cimg_option("-stats","(no args)","Get statistics of the image(s) as a 1x6 vector."); |
philpem@5 | 4433 | cimg_option("-histogram","'nb_values[%]'","Compute histogram of image(s) with 'nb_values' values."); |
philpem@5 | 4434 | cimg_option("-distance","'isovalue'","Compute distance function(s) to specified isovalue."); |
philpem@5 | 4435 | cimg_option("-hamilton","'nb_iter[,band_size]'","Apply Hamilton-Jacobi PDE to compute distance to 0."); |
philpem@5 | 4436 | cimg_option("-label","(no args)","Label connected components of image(s)."); |
philpem@5 | 4437 | cimg_option("-displacement","'[indice][,smoothness[,precision[,nbscales[,itermax]]]]","Estimate smooth displacement field between image(s) " |
philpem@5 | 4438 | "and specified target '[indice]'."); |
philpem@5 | 4439 | cimg_option("-sort","(no args)","Sort values of image(s) in increasing order."); |
philpem@5 | 4440 | cimg_option("-psnr","'max_value' or (noargs)","Compute PSNR between specified image(s)."); |
philpem@5 | 4441 | cimg_option("-point","'x[%],y[%][,z[%][,opacity[,color]]]'","Draw 3D colored point on specified image(s)."); |
philpem@5 | 4442 | cimg_option("-line","'x0[%],y0[%],x1[%],y1[%][,opacity[,color]]'","Draw 2D colored line on specified image(s)."); |
philpem@5 | 4443 | cimg_option("-polygon","'N,x0[%],y0[%],..,xN[%],yN[%][,opacity[,color]]'","Draw a 2D colored N-vertices polygon on specified image(s)."); |
philpem@5 | 4444 | cimg_option("-ellipse","'x[%],y[%],r,R[,u,v[,opacity[,color]]]'","Draw 2D colored ellipse on specified image(s)."); |
philpem@5 | 4445 | cimg_option("-text","text,x[%],y[%],size[,opacity[,color]]'", |
philpem@5 | 4446 | "Draw specified text at position (x,y) and with specified font size."); |
philpem@5 | 4447 | cimg_option("-image","'[indice][,x[%][,y[%][,z[%][,opacity[,ind_mask]]]]]'","Draw sprite image on specified image(s)."); |
philpem@5 | 4448 | cimg_option("-object3d","'[indice][,x[%][,y[%][,z[,opacity]]]]'","Draw 3D object on specified image(s)."); |
philpem@5 | 4449 | cimg_option("-plasma","'alpha[,beta[,opacity]]'","Draw plasma on specified image(s)."); |
philpem@5 | 4450 | cimg_option("-mandelbrot","'z0r,z0i,z1r,z1i[,itermax[,julia,c0r,c0i[,opacity]]]'","Draw Mandelbrot/Julia fractals on specified image(s)."); |
philpem@5 | 4451 | cimg_option("-flood","'x[%][,y[%][,z[%][,tolerance[,opacity[,color]]]]]'", |
philpem@5 | 4452 | "Flood-fill image(s) starting from (x,y,z) with specified tolerance."); |
philpem@5 | 4453 | |
philpem@5 | 4454 | cimg_help("\n List manipulation\n" |
philpem@5 | 4455 | " -----------------"); |
philpem@5 | 4456 | cimg_option("-remove","(no args)","Remove image(s) from list (eq. to '-rm')."); |
philpem@5 | 4457 | cimg_option("-keep","(no args)","Keep only specified image(s) (eq. to '-k')."); |
philpem@5 | 4458 | cimg_option("-move","'position'","Move image(s) at specified position (eq. to '-mv')."); |
philpem@5 | 4459 | cimg_option("-reverse","(no args)","Reverse image(s) order."); |
philpem@5 | 4460 | cimg_option("-name","\"name\"","Set display name of image(s)."); |
philpem@5 | 4461 | |
philpem@5 | 4462 | cimg_help("\n 3D Rendering\n" |
philpem@5 | 4463 | " ------------"); |
philpem@5 | 4464 | cimg_option("-cube3d","'size'","Insert a 3D cube at the end of the list."); |
philpem@5 | 4465 | cimg_option("-cone3d","'radius[,height[,subdivisions]]'","Insert a 3D cube at the end of the list."); |
philpem@5 | 4466 | cimg_option("-cylinder3d","'radius[,height[,subdivisions]]'","Insert a 3D cylinder at the end of the list."); |
philpem@5 | 4467 | cimg_option("-torus3d","'radius1,radius2[,subdivisions1,subdivisions2]'","Insert a 3D torus at the end of the list."); |
philpem@5 | 4468 | cimg_option("-plane3d","'sizex,sizey[,subdivisionsx,subdisivionsy]'","Insert a 3D plane at the end of the list."); |
philpem@5 | 4469 | cimg_option("-sphere3d","'radius[,subdivisions]'","Insert a 3D sphere at the end of the list."); |
philpem@5 | 4470 | cimg_option("-elevation3d","'z-factor' or '[indice]'", |
philpem@5 | 4471 | "Generate 3D elevation(s) of image(s) using specified z-factor or elevation map."); |
philpem@5 | 4472 | cimg_option("-isovalue3d","'value'","Generate 3D object(s) by retrieving isophote or isosurface of image(s)."); |
philpem@5 | 4473 | cimg_option("-center3d","(no args)","Center 3D object(s) (eq. to '-c3d')."); |
philpem@5 | 4474 | cimg_option("-normalize3d","(no args)","Normalize 3D object(s) to a unit size (eq. to '-n3d')."); |
philpem@5 | 4475 | cimg_option("-rotate3d","'u,v,w,angle'","Rotate 3D object(s) around axis (u,v,w) with specified angle (eq. to '-rot3d')."); |
philpem@5 | 4476 | 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')."); |
philpem@5 | 4477 | cimg_option("-sub3d","'tx,ty,tz'","Translate 3D object(s) with the opposite of the specified vector (eq. to '--3d')."); |
philpem@5 | 4478 | cimg_option("-mul3d","'fact' or 'factx,facty[,factz]'","Scale 3D object(s) with specified factor (eq. to '-*3d')."); |
philpem@5 | 4479 | cimg_option("-div3d","'fact' or 'factx,facty[,factz]'","Scale 3D object(s) with specified inverse factor (eq. to '-/3d')."); |
philpem@5 | 4480 | cimg_option("-color3d","'R,G,B[,opacity]'","Set color of 3D object(s) (eq. to '-col3d')."); |
philpem@5 | 4481 | cimg_option("-opacity3d","'opacity'","Set opacity of 3D object(s) (eq. to '-opac3d')."); |
philpem@5 | 4482 | cimg_option("-invert3d","(no args)","Invert primitive orientations of 3D object(s) (eq. to '-i3d')."); |
philpem@5 | 4483 | cimg_option("-split3d","(no args)","Split 3D object data into 6 data vectors 'header,N,vertices,primitives,colors,opacities' (eq. to '-s3d')."); |
philpem@5 | 4484 | cimg_option("-light3d","'posx,posy,posz'","Set the 3D position of the light for 3D rendering (eq. to '-l3d')."); |
philpem@5 | 4485 | cimg_option("-focale3d","'value'","Set focale value for 3D rendering (eq. to '-f3d')."); |
philpem@5 | 4486 | cimg_option("-specl3d","'value'","Set amount of specular light for 3D rendering (eq. to '-sl3d')."); |
philpem@5 | 4487 | cimg_option("-specs3d","'value'","Set shininess of specular light for 3D rendering (eq. to '-ss3d')."); |
philpem@5 | 4488 | cimg_option("-orient3d","(no args)","Switch double-sided mode for 3D rendering (eq. to '-o3d')."); |
philpem@5 | 4489 | cimg_option("-render3d","'mode'","Set 3D rendering mode"); |
philpem@5 | 4490 | cimg_help(" " |
philpem@5 | 4491 | "(can be '{-1=bounding-box, 0=pointwise, 1=linear, 2=flat, 3=flat-shaded, 4=Gouraud-shaded, 5=Phong-shaded}') (eq. to '-r3d')."); |
philpem@5 | 4492 | cimg_option("-renderd3d","'mode'","Set dynamic rendering mode in 3D viewer (same values as above) (eq. to '-rd3d')."); |
philpem@5 | 4493 | cimg_option("-background3d","'R,G,B'","Define background color in 3D viewer (eq. to '-b3d')."); |
philpem@5 | 4494 | |
philpem@5 | 4495 | cimg_help("\n Program controls\n" |
philpem@5 | 4496 | " ----------------"); |
philpem@5 | 4497 | cimg_option("-nop","(no args)","Do nothing."); |
philpem@5 | 4498 | cimg_option("-skip","(any args)","Do nothing but skip the next argument."); |
philpem@5 | 4499 | cimg_option("-echo","'text'","Output specified message (eq. to '-e')."); |
philpem@5 | 4500 | cimg_option("-print","(no args)","Print image(s) informations (eq. to '-p')."); |
philpem@5 | 4501 | cimg_option("-quit","(no args)","Force interpreter to quit (eq. to '-q')."); |
philpem@5 | 4502 | cimg_option("-do","(no args)","Start a 'do-while' code bloc."); |
philpem@5 | 4503 | cimg_option("-while","'cond'","End a 'do-while' code bloc and go back to associated '-do' if 'cond' is a strictly positive value."); |
philpem@5 | 4504 | cimg_option("-if","'cond'","Start a 'if-then-else' code bloc and test if 'cond' is a strictly positive value."); |
philpem@5 | 4505 | cimg_option("-else","(no args)","Execute following commands if previous '-if' condition failed."); |
philpem@5 | 4506 | cimg_option("-endif","(no args)","End a 'if-then-else' code bloc"); |
philpem@5 | 4507 | cimg_option("-repeat","'N'","Start a 'repeat-done' code bloc."); |
philpem@5 | 4508 | cimg_option("-done","(no args)","End a 'repeat-done' code bloc, and go to associated '-repeat' if iterations remain."); |
philpem@5 | 4509 | cimg_option("-int","'arg1,...,argN'","Check if all specified arguments are integer. If not, print an error message and exit."); |
philpem@5 | 4510 | cimg_option("-float","'arg1,...,argN","Check if all specified arguments are float values. If not, print an error message and exit."); |
philpem@5 | 4511 | |
philpem@5 | 4512 | cimg_help("\n Input/output\n" |
philpem@5 | 4513 | " ------------"); |
philpem@5 | 4514 | cimg_option("-input","'filename' or 'width[%][xheight[%][xdepth[%][xdim[%][xN]]]]'",""); |
philpem@5 | 4515 | cimg_help(" " |
philpem@5 | 4516 | "or '[indice][xN]' or '(v11{,;/^}v21...vLM)[xN]'"); |
philpem@5 | 4517 | cimg_help(" " |
philpem@5 | 4518 | "Input filename, empty image, image copy, or image with specified values (eq. to '-i' or (no args))."); |
philpem@5 | 4519 | cimg_option("-output","'filename'","Output image(s) in specified filename (eq. to '-o')."); |
philpem@5 | 4520 | cimg_option("-display","(no args)","Display image(s) (eq. to '-d')."); |
philpem@5 | 4521 | cimg_option("-display3d","(no args)","Display 3D object(s) (eq. to '-d3d')."); |
philpem@5 | 4522 | cimg_option("-plot","'[plot_type[,vertex_type[,xmin[,xmax[,ymin[,ymax]]]]]]'", |
philpem@5 | 4523 | "Display image(s) as 1D plot(s)"); |
philpem@5 | 4524 | cimg_help(" " |
philpem@5 | 4525 | "('plot_type' can be '{0=none, 1=lines, 2=splines, 3=bar}')."); |
philpem@5 | 4526 | cimg_help(" " |
philpem@5 | 4527 | "('vertex_type' can be in '[0-7]')."); |
philpem@5 | 4528 | cimg_option("-select","'select_type'","Select feature from image(s) in an interactive way"); |
philpem@5 | 4529 | cimg_help(" " |
philpem@5 | 4530 | "('select_type' can be in '{0=point, 1=line, 2=rectangle, 3=circle')."); |
philpem@5 | 4531 | |
philpem@5 | 4532 | // Print descriptions of default macros. |
philpem@5 | 4533 | char line[256*1024] = { 0 }, name[4096] = { 0 }, args[4096] = { 0 }, desc[4096] = { 0 }; |
philpem@5 | 4534 | bool first_description = true; |
philpem@5 | 4535 | for (const char *data = data_def; *data; ) { |
philpem@5 | 4536 | if (*data=='\n') ++data; |
philpem@5 | 4537 | else { |
philpem@5 | 4538 | if (std::sscanf(data,"%262143[^\n]",line)>0) data += cimg::strlen(line); |
philpem@5 | 4539 | if (line[0]=='#' && std::sscanf(line,"#@gmic %4095[^:] : %4095[^:] : %4095[^:]",name,args,desc)>0) { |
philpem@5 | 4540 | if (first_description) cimg_help("\n Commands : Default macros\n" |
philpem@5 | 4541 | " -------------------------"); |
philpem@5 | 4542 | std::fprintf(cimg_stdout,"%s %s-%-15s%s %-24s %s%s%s", |
philpem@5 | 4543 | first_description?"":"\n", |
philpem@5 | 4544 | cimg::t_bold,name,cimg::t_normal,args,cimg::t_green,desc,cimg::t_normal); |
philpem@5 | 4545 | first_description = false; |
philpem@5 | 4546 | } |
philpem@5 | 4547 | } |
philpem@5 | 4548 | } |
philpem@5 | 4549 | |
philpem@5 | 4550 | // Print descriptions of use-defined macros. |
philpem@5 | 4551 | first_description = true; |
philpem@5 | 4552 | for (int i = 1; i<argc-1; ++i) if (!cimg::strcmp("-m",argv[i]) || !cimg::strcmp("-macros",argv[i])) { |
philpem@5 | 4553 | std::FILE *file = cimg::fopen(argv[i+1],"r"); |
philpem@5 | 4554 | if (file) { |
philpem@5 | 4555 | int err = 0; |
philpem@5 | 4556 | while ((err=std::fscanf(file,"%262143[^\n] ",line)>=0)) { |
philpem@5 | 4557 | if (err) { // Non empty-line |
philpem@5 | 4558 | name[0] = args[0] = desc[0] = 0; |
philpem@5 | 4559 | if (line[0]=='#' && std::sscanf(line,"#@gmic %4095[^:] : %4095[^:] : %4095[^:]",name,args,desc)>0) { |
philpem@5 | 4560 | if (first_description) cimg_help("\n\n Commands : User-defined macros\n" |
philpem@5 | 4561 | " ------------------------------"); |
philpem@5 | 4562 | std::fprintf(cimg_stdout,"%s %s-%-15s%s %-24s %s%s%s", |
philpem@5 | 4563 | first_description?"":"\n", |
philpem@5 | 4564 | cimg::t_bold,name,cimg::t_normal,args,cimg::t_green,desc,cimg::t_normal); |
philpem@5 | 4565 | first_description = false; |
philpem@5 | 4566 | } |
philpem@5 | 4567 | } |
philpem@5 | 4568 | } |
philpem@5 | 4569 | } |
philpem@5 | 4570 | cimg::fclose(file); |
philpem@5 | 4571 | } |
philpem@5 | 4572 | |
philpem@5 | 4573 | cimg_help("\n\n Viewers shortcuts\n" |
philpem@5 | 4574 | " -----------------"); |
philpem@5 | 4575 | cimg_help(" When displaying image(s) or 3D object(s) with G'MIC, you can use these shortcuts in viewers :"); |
philpem@5 | 4576 | cimg_help(" - CTRL+D : Increase window size."); |
philpem@5 | 4577 | cimg_help(" - CTRL+C : Decrease window size."); |
philpem@5 | 4578 | cimg_help(" - CTRL+R : Reset window size."); |
philpem@5 | 4579 | cimg_help(" - CTRL+F : Toggle fullscreen mode."); |
philpem@5 | 4580 | cimg_help(" - CTRL+S : Save current window snapshot."); |
philpem@5 | 4581 | cimg_help(" - CTRL+O : Save current instance of viewed image or 3D object.\n"); |
philpem@5 | 4582 | cimg_help(" Specific options for the viewer of image(s) :"); |
philpem@5 | 4583 | cimg_help(" - CTRL+P : Play stack of frames as a movie."); |
philpem@5 | 4584 | cimg_help(" - CTRL+(mousewheel) : Zoom in/out."); |
philpem@5 | 4585 | cimg_help(" - SHIFT+(mousewheel) : Go left/right."); |
philpem@5 | 4586 | cimg_help(" - ALT+(mousewheel) : Go up/down."); |
philpem@5 | 4587 | cimg_help(" - Numeric PAD : Zoom in/out (+/-) and move zoomed region (numbers)."); |
philpem@5 | 4588 | cimg_help(" - BACKSPACE : Reset zoom.\n"); |
philpem@5 | 4589 | cimg_help(" Specific options for the viewer of 3D object(s) :"); |
philpem@5 | 4590 | cimg_help(" - (mouse) + (left mouse button) : Rotate object."); |
philpem@5 | 4591 | cimg_help(" - (mouse) + (right mouse button) : Zoom object."); |
philpem@5 | 4592 | cimg_help(" - (mouse) + (middle mouse button) : Translate object."); |
philpem@5 | 4593 | cimg_help(" - (mousewheel) : Zoom in/out."); |
philpem@5 | 4594 | cimg_help(" - CTRL + Z : Enable/disable Z-buffer rendering"); |
philpem@5 | 4595 | |
philpem@5 | 4596 | cimg_help("\n File options\n" |
philpem@5 | 4597 | " ------------"); |
philpem@5 | 4598 | cimg_help(" G'MIC is able to read/write most of the classical image file formats, including :"); |
philpem@5 | 4599 | cimg_help(" - 2D grayscale/color images : PNG,JPEG,GIF,PNM,TIFF,BMP,...."); |
philpem@5 | 4600 | cimg_help(" - 3D volumetric images : DICOM,HDR,NII,PAN,CIMG,INR,...."); |
philpem@5 | 4601 | cimg_help(" - Video files : MPEG,AVI,MOV,OGG,FLV,..."); |
philpem@5 | 4602 | cimg_help(" - Generic data files : DLM,ASC,RAW,TXT."); |
philpem@5 | 4603 | cimg_help(" - 3D objects : OFF.\n"); |
philpem@5 | 4604 | cimg_help(" Specific options :"); |
philpem@5 | 4605 | cimg_help(" - For video files : you can read only sub-frames of the image sequence (recommended) with the expression"); |
philpem@5 | 4606 | cimg_help(" 'video.ext,[first_frame[%][,last_frame[%][,step]]]'."); |
philpem@5 | 4607 | cimg_help(" - For RAW files : you must specify the image dimensions with the expression"); |
philpem@5 | 4608 | cimg_help(" 'file.raw,width[,height[,depth[,dim]]]]'."); |
philpem@5 | 4609 | cimg_help(" - For YUV files : you must specify the image dimensions and can read only sub-frames of the image sequence with the expression"); |
philpem@5 | 4610 | cimg_help(" 'file.yuv,width,height[,first_frame[,last_frame[,step]]]'."); |
philpem@5 | 4611 | cimg_help(" - For JPEG files : you can specify the quality (in %) of an output jpeg file format with the expression"); |
philpem@5 | 4612 | cimg_help(" 'file.jpg,30%'."); |
philpem@5 | 4613 | |
philpem@5 | 4614 | cimg_help("\n Examples of use\n" |
philpem@5 | 4615 | " ---------------"); |
philpem@5 | 4616 | cimg_help(" G'MIC is a simple but quite complete interpreter of image processing instructions, and can be used for a wide variety of"); |
philpem@5 | 4617 | cimg_help(" image processing tasks. Here are (very few) examples of how the command line tool G'MIC can be used :\n"); |
philpem@5 | 4618 | cimg_help(" - View image data : "); |
philpem@5 | 4619 | cimg_help(" gmic file1.bmp file2.jpeg"); |
philpem@5 | 4620 | cimg_help(" - Convert image files : "); |
philpem@5 | 4621 | cimg_help(" gmic input.bmp -o output.jpg"); |
philpem@5 | 4622 | cimg_help(" - Create volumetric image(s) from movie sequence : "); |
philpem@5 | 4623 | cimg_help(" gmic input.mpg -a z -o output.hdr"); |
philpem@5 | 4624 | cimg_help(" - Compute image gradient norm : "); |
philpem@5 | 4625 | cimg_help(" gmic input.bmp -gradient_norm"); |
philpem@5 | 4626 | cimg_help(" - Create G'MIC 3D logo : "); |
philpem@5 | 4627 | cimg_help(" gmic 180x70x1x3 -text G\\'MIC,30,5,50,1,1 -blur 2 -n 0,100 [0] -plasma[1] \\"); |
philpem@5 | 4628 | cimg_help(" -+ -blur 1 -elevation -0.1 -rd3d 4"); |
philpem@5 | 4629 | cimg_help("\n See also the macros defined in the provided macro file 'gmic_def.raw' for other examples."); |
philpem@5 | 4630 | |
philpem@5 | 4631 | cimg_help("\n ** G'MIC comes with ABSOLUTELY NO WARRANTY; " |
philpem@5 | 4632 | "for details visit http://gmic.sourceforge.net **"); |
philpem@5 | 4633 | std::exit(0); |
philpem@5 | 4634 | } |
philpem@5 | 4635 | |
philpem@5 | 4636 | // Launch G'MIC instance. |
philpem@5 | 4637 | //----------------------- |
philpem@5 | 4638 | CImgList<float> images; |
philpem@5 | 4639 | try { |
philpem@5 | 4640 | gmic(argc,argv,images); |
philpem@5 | 4641 | } catch (gmic_exception &e) { |
philpem@5 | 4642 | std::fprintf(cimg_stdout,"\n** Error occurred : %s **\n",e.message); |
philpem@5 | 4643 | } |
philpem@5 | 4644 | return 0; |
philpem@5 | 4645 | } |
philpem@5 | 4646 | #endif |
philpem@5 | 4647 | |
philpem@5 | 4648 | #endif // #ifdef cimg_plugin ... #else ... |