PTdecode/CImg-1.3.0/plugins/draw_gradient.h

Wed, 05 Aug 2009 15:00:54 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Wed, 05 Aug 2009 15:00:54 +0100
changeset 12
96e1df9bd27c
parent 5
1204ebf9340d
permissions
-rwxr-xr-x

small changes to hexdump code to stop a gcc warning on platforms where sizeof(int) != sizeof(int*) e.g. x86_64

     1 /*
     2  #
     3  #  File        : draw_gradient.h
     4  #                ( C++ header file - CImg plug-in )
     5  #
     6  #  Description : Plugin that can be used to draw color gradient on images.
     7  #                This file is a part of the CImg Library project.
     8  #                ( http://cimg.sourceforge.net )
     9  #
    10  #  Copyright   : Jerome Boulanger
    11  #                ( http://www.ricam.oeaw.ac.at/people/page.cgi?firstn=Jerome;lastn=Boulanger )
    12  #
    13  #  License     : CeCILL v2.0
    14  #                ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
    15  #
    16  #  This software is governed by the CeCILL  license under French law and
    17  #  abiding by the rules of distribution of free software.  You can  use,
    18  #  modify and/ or redistribute the software under the terms of the CeCILL
    19  #  license as circulated by CEA, CNRS and INRIA at the following URL
    20  #  "http://www.cecill.info".
    21  #
    22  #  As a counterpart to the access to the source code and  rights to copy,
    23  #  modify and redistribute granted by the license, users are provided only
    24  #  with a limited warranty  and the software's author,  the holder of the
    25  #  economic rights,  and the successive licensors  have only  limited
    26  #  liability.
    27  #
    28  #  In this respect, the user's attention is drawn to the risks associated
    29  #  with loading,  using,  modifying and/or developing or reproducing the
    30  #  software by the user in light of its specific status of free software,
    31  #  that may mean  that it is complicated to manipulate,  and  that  also
    32  #  therefore means  that it is reserved for developers  and  experienced
    33  #  professionals having in-depth computer knowledge. Users are therefore
    34  #  encouraged to load and test the software's suitability as regards their
    35  #  requirements in conditions enabling the security of their systems and/or
    36  #  data to be ensured and,  more generally, to use and operate it in the
    37  #  same conditions as regards security.
    38  #
    39  #  The fact that you are presently reading this means that you have had
    40  #  knowledge of the CeCILL license and that you accept its terms.
    41  #
    42 */
    44 #ifndef cimg_plugin_draw_gradient
    45 #define cimg_plugin_draw_gradient
    47 // Convert the couple (shape,profile) into a description string
    48 static inline const char *get_gradient_str(const int shape, const int profile) {
    49   static char buf[128];
    50   switch(shape) {
    51   case 0: std::sprintf(buf,"linear shape and");break;
    52   case 1: std::sprintf(buf,"spheric shape and");break;
    53   case 2: std::sprintf(buf,"conic shape and");break;
    54   case 3: std::sprintf(buf,"square shape and");break;
    55   case 4: std::sprintf(buf,"rectangle (L1) shape and");break;
    56   case 5: std::sprintf(buf,"rectangle (Linf) shape and");break;
    57   case 6: std::sprintf(buf,"Gaussian shape and");break;
    58   default: std::sprintf(buf,"undefined shape and");break;
    59   }
    60   switch(profile) {
    61   case 0: std::strcat(buf," linear profile");break;
    62   case 1: std::strcat(buf," wave profile");break;
    63   case 2: std::strcat(buf," ring/bar profile");break;
    64   case 3: std::strcat(buf," exponential");break;
    65   case 4: std::strcat(buf," vanishing wave profile");break;
    66   case 5: std::strcat(buf," vanishing ring/bar profile");break;
    67   case 6: std::strcat(buf," circ diffraction (Airy) profile");break;
    68   case 7: std::strcat(buf," rect diffraction (sinc2) profile");break;
    69   default: std::strcat(buf," undefined profile");break;
    70   }
    71   return buf;
    72 }
    74 template<typename tc>
    75 void _draw_gradient_profile(T *const ptr, const float opacity, const float r,
    76                             const tc *const color0, const tc *const color1,
    77                             const int profile) {
    78   const unsigned int id = (color0?1:0) + (color1?2:0);
    79   const tc col0 = color0?*color0:0, col1 = color1?*color1:0;
    80   switch(profile) {
    81   case 0: { // linear
    82     switch(id) { // map the 3 cases
    83     case 3: *ptr = (T)((1-opacity)**ptr + opacity*(col0*(1.f-r)+col1*r)); break;
    84     case 1: if (r<1) *ptr = (T)((1-opacity*(1-r))**ptr + col0*opacity*(1-r)); break;
    85     case 2: if (r>0) *ptr = (T)((1-opacity*r)**ptr + col1*opacity*r); break;
    86     default: break;
    87     }  break;
    88   }
    89   case 1: { // waves
    90     const float f = (1 - (float)std::cos(4.5f*r*2.f*cimg::valuePI))/2;
    91     switch(id) { // map the 3 cases
    92     case 3: *ptr = (T)((1-opacity)**ptr + opacity*(col0*(1.f-f)+col1*f)); break;
    93     case 1: if (f<1) *ptr = (T)((1-opacity*(1-f))**ptr + col0*opacity*(1-f)); break;
    94     case 2: if (f>0) *ptr = (T)((1-opacity*f)**ptr + col1*opacity*f); break;
    95     default: break;
    96     } break;
    97   }
    98   case 2:{ // ring/bar
    99     const float f = (1 + (float)std::cos(r*2.f*cimg::valuePI))/2;
   100     switch(id) { // map the 3 cases
   101     case 3: *ptr = (T)((1-opacity)**ptr + opacity*(col0*(1.f-f)+col1*f)); break;
   102     case 1: if (f<1) *ptr = (T)((1-opacity*(1-f))**ptr + col0*opacity*(1-f)); break;
   103     case 2: if (f>0) *ptr = (T)((1-opacity*f)**ptr + col1*opacity*f); break;
   104     default: break;
   105     } break;
   106   }
   107   case 3: { // exponential
   108     const float f = 1 - (float)std::exp(-r);
   109     switch(id) { // map the 3 cases
   110     case 3: *ptr = (T)((1-opacity)**ptr + opacity*(col0*(1.f-f)+col1*f)); break;
   111     case 1: if (f<1) *ptr = (T)((1-opacity*(1-f))**ptr + col0*opacity*(1-f)); break;
   112     case 2: if (f>0) *ptr = (T)((1-opacity*f)**ptr + col1*opacity*f); break;
   113     default: break;
   114     } break;
   115   }
   116   case 4: { // vanishing wave
   117     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;
   118     switch(id) { // map the 3 cases
   119     case 3: if (o>0) *ptr = (T)((1-o)**ptr + o*(col0*(1.f-f)+col1*f)); break;
   120     case 1: if (f<1) *ptr = (T)((1-o*(1-f))**ptr + col0*o*(1-f)); break;
   121     case 2: if (f>0) *ptr = (T)((1-o*f)**ptr + col1*o*f); break;
   122     default: break;
   123     } break;
   124   }
   125   case 5: { // vanishing ring/bar
   126     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;
   127     switch(id) { // map the 3 cases
   128     case 3: if (o>0) *ptr = (T)((1-o)**ptr + o*(col0*(1.f-f)+col1*f)); break;
   129     case 1: if (f<1) *ptr = (T)((1-o*(1-f))**ptr + col0*o*(1-f)); break;
   130     case 2: if (f>0) *ptr = (T)((1-o*f)**ptr + col1*o*f); break;
   131     default: break;
   132     } break;
   133   }
   134   case 6: { // diffraction pattern of a circular aperture (Airy function)
   135 #define myj1(x) (std::sin((x)<3?(x)*2.2/3:(x)-0.8)*std::exp(-std::pow((x)/5.0,1/3.0)))
   136     const float a = 10*(float)cimg::valuePI*r, tmp = a<0.2?.5f:((float)myj1(a)/a), f = 1-4*tmp*tmp;
   137 #undef myj1
   138     switch(id) { // map the 3 cases
   139     case 3: *ptr = (T)((1-opacity)**ptr + opacity*(col0*(1.f-f)+col1*f)); break;
   140     case 1: if (f<1) *ptr = (T)((1-opacity*(1-f))**ptr + col0*opacity*(1-f)); break;
   141     case 2: if (f>0) *ptr = (T)((1-opacity*f)**ptr + col1*opacity*f); break;
   142     default: break;
   143     }
   144     break;
   145   }
   146   case 7: { // diffraction pattern of a rectangular function (sinc function)
   147     const float a = 10*(float)cimg::valuePI*r, tmp = a==0?1:(float)std::sin(a)/a, f = 1-tmp*tmp;
   148     switch(id) { // map the 3 cases
   149     case 3: *ptr = (T)((1-opacity)**ptr + opacity*(col0*(1.f-f)+col1*f)); break;
   150     case 1: if (f<1) *ptr = (T)((1-opacity*(1-f))**ptr + col0*opacity*(1-f)); break;
   151     case 2: if (f>0) *ptr = (T)((1-opacity*f)**ptr + col1*opacity*f); break;
   152     default: break;
   153     } break;
   154   }
   155   default:
   156     CImgArgumentException("CImg<%s>::draw_gradient : unknown profile parameter",pixel_type()); break;
   157   }
   158 }
   160 //! Draw a gradient with various shape and profile
   161 /**
   162    \param x0 X-coordinate of the 1st control point
   163    \param y0 Y-coordinate of the 1st control point
   164    \param x1 X-coordinate of the 2nd control point
   165    \param y1 Y-coordinate of the 2nd control point
   166    \param color0 Array of dimv() values of type \c T, defining the 1st color.
   167    \param color1 Array of dimv() values of type \c T, defining the 2nd color.
   168    \param shape shape of the gradient (0,3)
   169    \param profile  select a profile function (0,7)
   170    \param opacity Drawing opacity.
   171    \note
   172    - if one color is NULL then the gradient is done to transparency
   173 **/
   174 template<typename tc>
   175 CImg<T>& draw_gradient(const int x0, const int y0, const int x1, const int y1,
   176                        const tc *const color0, const tc *const color1,
   177                        const int shape=0, const int profile=0, const float opacity=1.0f){
   178   if (is_empty()) return *this;
   179   if (!color0 && !color1)
   180     throw CImgArgumentException("CImg<%s>::draw_gradient : The two specified colors are (null).",
   181                           pixel_type());
   182   if (profile<0 || profile>7) { // catch this case before entering in the for loop
   183     CImgArgumentException("CImg<%s>::draw_gradient : unknown profile parameter",pixel_type());
   184     return *this;
   185   }
   186   const float abx = (float)x1-x0, aby = (float)y1-y0, ab2 = abx*abx + aby*aby; // pt A=(x0,y0), B=(x1,y1)
   187   const tc *pcol0 = color0, *pcol1 = color1;
   188   T *ptr = data;
   190   switch(shape) {
   191   case 0: { // linear
   192     cimg_forV(*this,v) { cimg_forXYZ(*this,x,y,z) { // point M=(x,z)
   193       const float amx = (float)x-x0, amy = (float)y-y0, r = cimg::max(0.f,cimg::min(1.f,(amx*abx+amy*aby)/ab2));
   194       _draw_gradient_profile(ptr++,opacity,r,pcol0,pcol1,profile);
   195     } if (pcol0) ++pcol0; if (pcol1) ++pcol1; }} break;
   196   case 1:{ // radial
   197     cimg_forV(*this,v) { cimg_forXYZ(*this,x,y,z) {
   198       const float amx = (float)x-x0, amy = (float)y-y0, r = cimg::max(0.f,cimg::min(1.f,(amx*amx+amy*amy)/ab2));
   199       _draw_gradient_profile(ptr++,opacity,r,pcol0,pcol1,profile);
   200      } if (pcol0) ++pcol0; if (pcol1) ++pcol1; }} break;
   201   case 2:{ // radial cone
   202     cimg_forV(*this,v) { cimg_forXYZ(*this,x,y,z) {
   203       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)));
   204       _draw_gradient_profile(ptr++,opacity,r,pcol0,pcol1,profile);
   205     } if (pcol0) ++pcol0; if (pcol1) ++pcol1; }} break;
   206   case 3:{ // square
   207     cimg_forV(*this,v) { cimg_forXYZ(*this,x,y,z) {
   208       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));
   209       _draw_gradient_profile(ptr++,opacity,r,pcol0,pcol1,profile);
   210     } if (pcol0) ++pcol0; if (pcol1) ++pcol1; }} break;
   211   case 4:{ // rectangle (L1)
   212     cimg_forV(*this,v) { cimg_forXYZ(*this,x,y,z) {
   213       const float amx = (float)x-x0, amy = (float)y-y0,
   214         r = cimg::max(0.f,cimg::min(1.f,(cimg::abs(amx/abx)+cimg::abs(amy/aby))));
   215       _draw_gradient_profile(ptr++,opacity,r,pcol0,pcol1,profile);
   216     } if (pcol0) ++pcol0; if (pcol1) ++pcol1; }} break;
   217    case 5:{ // rectangle (Linf)
   218     cimg_forV(*this,v) { cimg_forXYZ(*this,x,y,z) {
   219       const float amx = (float)x-x0, amy = (float)y-y0,
   220         r=cimg::max(0.f,cimg::min(1.f,cimg::max(cimg::abs(amx/abx),cimg::abs(amy/aby))));
   221       _draw_gradient_profile(ptr++,opacity,r,pcol0,pcol1,profile);
   222     } if (pcol0) ++pcol0; if (pcol1) ++pcol1; }} break;
   223   case 6:{ // gaussian
   224     cimg_forV(*this,v) { cimg_forXYZ(*this,x,y,z) {
   225       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)));
   226       _draw_gradient_profile(ptr++,opacity,r,pcol0,pcol1,profile);
   227     } if (pcol0) ++pcol0; if (pcol1) ++pcol1; }} break;
   228   default:
   229     CImgArgumentException("CImg<%s>::draw_gradient : unknown shape parameter",pixel_type()); break;
   230   }
   231   return *this;
   232 }
   234 template<typename tc>
   235 CImg<T>& draw_gradient(const int x0, const int y0, const int x1, const int y1,
   236                        const tc *const color0, const int color1,
   237                        const int shape=0, const int profile=0, const float opacity=1.0f) {
   238   return (*this).draw_gradient(x0,y0,x1,y1,color0,(tc*)color1,shape,profile,opacity);
   239 }
   241 template<typename tc>
   242 CImg<T>& draw_gradient(const int x0, const int y0, const int x1, const int y1,
   243                        const int color0, const tc *const color1,
   244                        const int shape=0, const int profile=0, const float opacity=1.0f) {
   245   return (*this).draw_gradient(x0,y0,x1,y1,(tc*)color0,color1,shape,profile,opacity);
   246 }
   248 #endif