PTdecode/CImg-1.3.0/plugins/draw_gradient.h

changeset 5
1204ebf9340d
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/PTdecode/CImg-1.3.0/plugins/draw_gradient.h	Mon Aug 03 14:09:20 2009 +0100
     1.3 @@ -0,0 +1,248 @@
     1.4 +/*
     1.5 + #
     1.6 + #  File        : draw_gradient.h
     1.7 + #                ( C++ header file - CImg plug-in )
     1.8 + #
     1.9 + #  Description : Plugin that can be used to draw color gradient on images.
    1.10 + #                This file is a part of the CImg Library project.
    1.11 + #                ( http://cimg.sourceforge.net )
    1.12 + #
    1.13 + #  Copyright   : Jerome Boulanger
    1.14 + #                ( http://www.ricam.oeaw.ac.at/people/page.cgi?firstn=Jerome;lastn=Boulanger )
    1.15 + #
    1.16 + #  License     : CeCILL v2.0
    1.17 + #                ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
    1.18 + #
    1.19 + #  This software is governed by the CeCILL  license under French law and
    1.20 + #  abiding by the rules of distribution of free software.  You can  use,
    1.21 + #  modify and/ or redistribute the software under the terms of the CeCILL
    1.22 + #  license as circulated by CEA, CNRS and INRIA at the following URL
    1.23 + #  "http://www.cecill.info".
    1.24 + #
    1.25 + #  As a counterpart to the access to the source code and  rights to copy,
    1.26 + #  modify and redistribute granted by the license, users are provided only
    1.27 + #  with a limited warranty  and the software's author,  the holder of the
    1.28 + #  economic rights,  and the successive licensors  have only  limited
    1.29 + #  liability.
    1.30 + #
    1.31 + #  In this respect, the user's attention is drawn to the risks associated
    1.32 + #  with loading,  using,  modifying and/or developing or reproducing the
    1.33 + #  software by the user in light of its specific status of free software,
    1.34 + #  that may mean  that it is complicated to manipulate,  and  that  also
    1.35 + #  therefore means  that it is reserved for developers  and  experienced
    1.36 + #  professionals having in-depth computer knowledge. Users are therefore
    1.37 + #  encouraged to load and test the software's suitability as regards their
    1.38 + #  requirements in conditions enabling the security of their systems and/or
    1.39 + #  data to be ensured and,  more generally, to use and operate it in the
    1.40 + #  same conditions as regards security.
    1.41 + #
    1.42 + #  The fact that you are presently reading this means that you have had
    1.43 + #  knowledge of the CeCILL license and that you accept its terms.
    1.44 + #
    1.45 +*/
    1.46 +
    1.47 +#ifndef cimg_plugin_draw_gradient
    1.48 +#define cimg_plugin_draw_gradient
    1.49 +
    1.50 +// Convert the couple (shape,profile) into a description string
    1.51 +static inline const char *get_gradient_str(const int shape, const int profile) {
    1.52 +  static char buf[128];
    1.53 +  switch(shape) {
    1.54 +  case 0: std::sprintf(buf,"linear shape and");break;
    1.55 +  case 1: std::sprintf(buf,"spheric shape and");break;
    1.56 +  case 2: std::sprintf(buf,"conic shape and");break;
    1.57 +  case 3: std::sprintf(buf,"square shape and");break;
    1.58 +  case 4: std::sprintf(buf,"rectangle (L1) shape and");break;
    1.59 +  case 5: std::sprintf(buf,"rectangle (Linf) shape and");break;
    1.60 +  case 6: std::sprintf(buf,"Gaussian shape and");break;
    1.61 +  default: std::sprintf(buf,"undefined shape and");break;
    1.62 +  }
    1.63 +  switch(profile) {
    1.64 +  case 0: std::strcat(buf," linear profile");break;
    1.65 +  case 1: std::strcat(buf," wave profile");break;
    1.66 +  case 2: std::strcat(buf," ring/bar profile");break;
    1.67 +  case 3: std::strcat(buf," exponential");break;
    1.68 +  case 4: std::strcat(buf," vanishing wave profile");break;
    1.69 +  case 5: std::strcat(buf," vanishing ring/bar profile");break;
    1.70 +  case 6: std::strcat(buf," circ diffraction (Airy) profile");break;
    1.71 +  case 7: std::strcat(buf," rect diffraction (sinc2) profile");break;
    1.72 +  default: std::strcat(buf," undefined profile");break;
    1.73 +  }
    1.74 +  return buf;
    1.75 +}
    1.76 +
    1.77 +template<typename tc>
    1.78 +void _draw_gradient_profile(T *const ptr, const float opacity, const float r,
    1.79 +                            const tc *const color0, const tc *const color1,
    1.80 +                            const int profile) {
    1.81 +  const unsigned int id = (color0?1:0) + (color1?2:0);
    1.82 +  const tc col0 = color0?*color0:0, col1 = color1?*color1:0;
    1.83 +  switch(profile) {
    1.84 +  case 0: { // linear
    1.85 +    switch(id) { // map the 3 cases
    1.86 +    case 3: *ptr = (T)((1-opacity)**ptr + opacity*(col0*(1.f-r)+col1*r)); break;
    1.87 +    case 1: if (r<1) *ptr = (T)((1-opacity*(1-r))**ptr + col0*opacity*(1-r)); break;
    1.88 +    case 2: if (r>0) *ptr = (T)((1-opacity*r)**ptr + col1*opacity*r); break;
    1.89 +    default: break;
    1.90 +    }  break;
    1.91 +  }
    1.92 +  case 1: { // waves
    1.93 +    const float f = (1 - (float)std::cos(4.5f*r*2.f*cimg::valuePI))/2;
    1.94 +    switch(id) { // map the 3 cases
    1.95 +    case 3: *ptr = (T)((1-opacity)**ptr + opacity*(col0*(1.f-f)+col1*f)); break;
    1.96 +    case 1: if (f<1) *ptr = (T)((1-opacity*(1-f))**ptr + col0*opacity*(1-f)); break;
    1.97 +    case 2: if (f>0) *ptr = (T)((1-opacity*f)**ptr + col1*opacity*f); break;
    1.98 +    default: break;
    1.99 +    } break;
   1.100 +  }
   1.101 +  case 2:{ // ring/bar
   1.102 +    const float f = (1 + (float)std::cos(r*2.f*cimg::valuePI))/2;
   1.103 +    switch(id) { // map the 3 cases
   1.104 +    case 3: *ptr = (T)((1-opacity)**ptr + opacity*(col0*(1.f-f)+col1*f)); break;
   1.105 +    case 1: if (f<1) *ptr = (T)((1-opacity*(1-f))**ptr + col0*opacity*(1-f)); break;
   1.106 +    case 2: if (f>0) *ptr = (T)((1-opacity*f)**ptr + col1*opacity*f); break;
   1.107 +    default: break;
   1.108 +    } break;
   1.109 +  }
   1.110 +  case 3: { // exponential
   1.111 +    const float f = 1 - (float)std::exp(-r);
   1.112 +    switch(id) { // map the 3 cases
   1.113 +    case 3: *ptr = (T)((1-opacity)**ptr + opacity*(col0*(1.f-f)+col1*f)); break;
   1.114 +    case 1: if (f<1) *ptr = (T)((1-opacity*(1-f))**ptr + col0*opacity*(1-f)); break;
   1.115 +    case 2: if (f>0) *ptr = (T)((1-opacity*f)**ptr + col1*opacity*f); break;
   1.116 +    default: break;
   1.117 +    } break;
   1.118 +  }
   1.119 +  case 4: { // vanishing wave
   1.120 +    const float f = (1 - (float)std::cos(4.5f*r*2.f*cimg::valuePI))/2, o = r<.9f?(float)std::exp(-.5*r*r*12.f):0;
   1.121 +    switch(id) { // map the 3 cases
   1.122 +    case 3: if (o>0) *ptr = (T)((1-o)**ptr + o*(col0*(1.f-f)+col1*f)); break;
   1.123 +    case 1: if (f<1) *ptr = (T)((1-o*(1-f))**ptr + col0*o*(1-f)); break;
   1.124 +    case 2: if (f>0) *ptr = (T)((1-o*f)**ptr + col1*o*f); break;
   1.125 +    default: break;
   1.126 +    } break;
   1.127 +  }
   1.128 +  case 5: { // vanishing ring/bar
   1.129 +    const float f = (1 + (float)std::cos(r*2.f*cimg::valuePI))/2, o = r<.9?(float)std::exp(-.5*r*r*12.f):0;
   1.130 +    switch(id) { // map the 3 cases
   1.131 +    case 3: if (o>0) *ptr = (T)((1-o)**ptr + o*(col0*(1.f-f)+col1*f)); break;
   1.132 +    case 1: if (f<1) *ptr = (T)((1-o*(1-f))**ptr + col0*o*(1-f)); break;
   1.133 +    case 2: if (f>0) *ptr = (T)((1-o*f)**ptr + col1*o*f); break;
   1.134 +    default: break;
   1.135 +    } break;
   1.136 +  }
   1.137 +  case 6: { // diffraction pattern of a circular aperture (Airy function)
   1.138 +#define myj1(x) (std::sin((x)<3?(x)*2.2/3:(x)-0.8)*std::exp(-std::pow((x)/5.0,1/3.0)))
   1.139 +    const float a = 10*(float)cimg::valuePI*r, tmp = a<0.2?.5f:((float)myj1(a)/a), f = 1-4*tmp*tmp;
   1.140 +#undef myj1
   1.141 +    switch(id) { // map the 3 cases
   1.142 +    case 3: *ptr = (T)((1-opacity)**ptr + opacity*(col0*(1.f-f)+col1*f)); break;
   1.143 +    case 1: if (f<1) *ptr = (T)((1-opacity*(1-f))**ptr + col0*opacity*(1-f)); break;
   1.144 +    case 2: if (f>0) *ptr = (T)((1-opacity*f)**ptr + col1*opacity*f); break;
   1.145 +    default: break;
   1.146 +    }
   1.147 +    break;
   1.148 +  }
   1.149 +  case 7: { // diffraction pattern of a rectangular function (sinc function)
   1.150 +    const float a = 10*(float)cimg::valuePI*r, tmp = a==0?1:(float)std::sin(a)/a, f = 1-tmp*tmp;
   1.151 +    switch(id) { // map the 3 cases
   1.152 +    case 3: *ptr = (T)((1-opacity)**ptr + opacity*(col0*(1.f-f)+col1*f)); break;
   1.153 +    case 1: if (f<1) *ptr = (T)((1-opacity*(1-f))**ptr + col0*opacity*(1-f)); break;
   1.154 +    case 2: if (f>0) *ptr = (T)((1-opacity*f)**ptr + col1*opacity*f); break;
   1.155 +    default: break;
   1.156 +    } break;
   1.157 +  }
   1.158 +  default:
   1.159 +    CImgArgumentException("CImg<%s>::draw_gradient : unknown profile parameter",pixel_type()); break;
   1.160 +  }
   1.161 +}
   1.162 +
   1.163 +//! Draw a gradient with various shape and profile
   1.164 +/**
   1.165 +   \param x0 X-coordinate of the 1st control point
   1.166 +   \param y0 Y-coordinate of the 1st control point
   1.167 +   \param x1 X-coordinate of the 2nd control point
   1.168 +   \param y1 Y-coordinate of the 2nd control point
   1.169 +   \param color0 Array of dimv() values of type \c T, defining the 1st color.
   1.170 +   \param color1 Array of dimv() values of type \c T, defining the 2nd color.
   1.171 +   \param shape shape of the gradient (0,3)
   1.172 +   \param profile  select a profile function (0,7)
   1.173 +   \param opacity Drawing opacity.
   1.174 +   \note
   1.175 +   - if one color is NULL then the gradient is done to transparency
   1.176 +**/
   1.177 +template<typename tc>
   1.178 +CImg<T>& draw_gradient(const int x0, const int y0, const int x1, const int y1,
   1.179 +                       const tc *const color0, const tc *const color1,
   1.180 +                       const int shape=0, const int profile=0, const float opacity=1.0f){
   1.181 +  if (is_empty()) return *this;
   1.182 +  if (!color0 && !color1)
   1.183 +    throw CImgArgumentException("CImg<%s>::draw_gradient : The two specified colors are (null).",
   1.184 +                          pixel_type());
   1.185 +  if (profile<0 || profile>7) { // catch this case before entering in the for loop
   1.186 +    CImgArgumentException("CImg<%s>::draw_gradient : unknown profile parameter",pixel_type());
   1.187 +    return *this;
   1.188 +  }
   1.189 +  const float abx = (float)x1-x0, aby = (float)y1-y0, ab2 = abx*abx + aby*aby; // pt A=(x0,y0), B=(x1,y1)
   1.190 +  const tc *pcol0 = color0, *pcol1 = color1;
   1.191 +  T *ptr = data;
   1.192 +
   1.193 +  switch(shape) {
   1.194 +  case 0: { // linear
   1.195 +    cimg_forV(*this,v) { cimg_forXYZ(*this,x,y,z) { // point M=(x,z)
   1.196 +      const float amx = (float)x-x0, amy = (float)y-y0, r = cimg::max(0.f,cimg::min(1.f,(amx*abx+amy*aby)/ab2));
   1.197 +      _draw_gradient_profile(ptr++,opacity,r,pcol0,pcol1,profile);
   1.198 +    } if (pcol0) ++pcol0; if (pcol1) ++pcol1; }} break;
   1.199 +  case 1:{ // radial
   1.200 +    cimg_forV(*this,v) { cimg_forXYZ(*this,x,y,z) {
   1.201 +      const float amx = (float)x-x0, amy = (float)y-y0, r = cimg::max(0.f,cimg::min(1.f,(amx*amx+amy*amy)/ab2));
   1.202 +      _draw_gradient_profile(ptr++,opacity,r,pcol0,pcol1,profile);
   1.203 +     } if (pcol0) ++pcol0; if (pcol1) ++pcol1; }} break;
   1.204 +  case 2:{ // radial cone
   1.205 +    cimg_forV(*this,v) { cimg_forXYZ(*this,x,y,z) {
   1.206 +      const float amx = (float)x-x0, amy = (float)y-y0, r = cimg::max(0.f,cimg::min(1.f,(float)std::sqrt((amx*amx+amy*amy)/ab2)));
   1.207 +      _draw_gradient_profile(ptr++,opacity,r,pcol0,pcol1,profile);
   1.208 +    } if (pcol0) ++pcol0; if (pcol1) ++pcol1; }} break;
   1.209 +  case 3:{ // square
   1.210 +    cimg_forV(*this,v) { cimg_forXYZ(*this,x,y,z) {
   1.211 +      const float amx = (float)x-x0, amy = (float)y-y0, r=cimg::max(0.f,cimg::min(1.f,(cimg::abs(amx*abx+amy*aby)+cimg::abs(amx*aby-amy*abx))/ab2));
   1.212 +      _draw_gradient_profile(ptr++,opacity,r,pcol0,pcol1,profile);
   1.213 +    } if (pcol0) ++pcol0; if (pcol1) ++pcol1; }} break;
   1.214 +  case 4:{ // rectangle (L1)
   1.215 +    cimg_forV(*this,v) { cimg_forXYZ(*this,x,y,z) {
   1.216 +      const float amx = (float)x-x0, amy = (float)y-y0,
   1.217 +        r = cimg::max(0.f,cimg::min(1.f,(cimg::abs(amx/abx)+cimg::abs(amy/aby))));
   1.218 +      _draw_gradient_profile(ptr++,opacity,r,pcol0,pcol1,profile);
   1.219 +    } if (pcol0) ++pcol0; if (pcol1) ++pcol1; }} break;
   1.220 +   case 5:{ // rectangle (Linf)
   1.221 +    cimg_forV(*this,v) { cimg_forXYZ(*this,x,y,z) {
   1.222 +      const float amx = (float)x-x0, amy = (float)y-y0,
   1.223 +        r=cimg::max(0.f,cimg::min(1.f,cimg::max(cimg::abs(amx/abx),cimg::abs(amy/aby))));
   1.224 +      _draw_gradient_profile(ptr++,opacity,r,pcol0,pcol1,profile);
   1.225 +    } if (pcol0) ++pcol0; if (pcol1) ++pcol1; }} break;
   1.226 +  case 6:{ // gaussian
   1.227 +    cimg_forV(*this,v) { cimg_forXYZ(*this,x,y,z) {
   1.228 +      const float amx = (float)x-x0, amy = (float)y-y0, r = cimg::max(0.f,cimg::min(1.f,1-(float)std::exp(-(amx*amx+amy*amy)/ab2)));
   1.229 +      _draw_gradient_profile(ptr++,opacity,r,pcol0,pcol1,profile);
   1.230 +    } if (pcol0) ++pcol0; if (pcol1) ++pcol1; }} break;
   1.231 +  default:
   1.232 +    CImgArgumentException("CImg<%s>::draw_gradient : unknown shape parameter",pixel_type()); break;
   1.233 +  }
   1.234 +  return *this;
   1.235 +}
   1.236 +
   1.237 +template<typename tc>
   1.238 +CImg<T>& draw_gradient(const int x0, const int y0, const int x1, const int y1,
   1.239 +                       const tc *const color0, const int color1,
   1.240 +                       const int shape=0, const int profile=0, const float opacity=1.0f) {
   1.241 +  return (*this).draw_gradient(x0,y0,x1,y1,color0,(tc*)color1,shape,profile,opacity);
   1.242 +}
   1.243 +
   1.244 +template<typename tc>
   1.245 +CImg<T>& draw_gradient(const int x0, const int y0, const int x1, const int y1,
   1.246 +                       const int color0, const tc *const color1,
   1.247 +                       const int shape=0, const int profile=0, const float opacity=1.0f) {
   1.248 +  return (*this).draw_gradient(x0,y0,x1,y1,(tc*)color0,color1,shape,profile,opacity);
   1.249 +}
   1.250 +
   1.251 +#endif