PTdecode/CImg-1.3.0/plugins/draw_gradient.h

Mon, 03 Aug 2009 23:39:53 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Mon, 03 Aug 2009 23:39:53 +0100
changeset 10
604c205d9163
parent 5
1204ebf9340d
permissions
-rwxr-xr-x

add basic test routine for Ptouch library

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