]> granicus.if.org Git - imagemagick/blob - MagickCore/decorate.c
(no commit message)
[imagemagick] / MagickCore / decorate.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %            DDDD   EEEEE   CCCC   OOO   RRRR    AAA   TTTTT  EEEEE           %
7 %            D   D  E      C      O   O  R   R  A   A    T    E               %
8 %            D   D  EEE    C      O   O  RRRR   AAAAA    T    EEE             %
9 %            D   D  E      C      O   O  R R    A   A    T    E               %
10 %            DDDD   EEEEE   CCCC   OOO   R  R   A   A    T    EEEEE           %
11 %                                                                             %
12 %                                                                             %
13 %                     MagickCore Image Decoration Methods                     %
14 %                                                                             %
15 %                                Software Design                              %
16 %                                  John Cristy                                %
17 %                                   July 1992                                 %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 %
38 */
39 \f
40 /*
41   Include declarations.
42 */
43 #include "MagickCore/studio.h"
44 #include "MagickCore/cache-view.h"
45 #include "MagickCore/color-private.h"
46 #include "MagickCore/colorspace-private.h"
47 #include "MagickCore/composite.h"
48 #include "MagickCore/decorate.h"
49 #include "MagickCore/exception.h"
50 #include "MagickCore/exception-private.h"
51 #include "MagickCore/image.h"
52 #include "MagickCore/memory_.h"
53 #include "MagickCore/monitor.h"
54 #include "MagickCore/monitor-private.h"
55 #include "MagickCore/pixel-accessor.h"
56 #include "MagickCore/quantum.h"
57 #include "MagickCore/quantum-private.h"
58 #include "MagickCore/thread-private.h"
59 #include "MagickCore/transform.h"
60 \f
61 /*
62   Define declarations.
63 */
64 #define AccentuateModulate  ScaleCharToQuantum(80)
65 #define HighlightModulate  ScaleCharToQuantum(125)
66 #define ShadowModulate  ScaleCharToQuantum(135)
67 #define DepthModulate  ScaleCharToQuantum(185)
68 #define TroughModulate  ScaleCharToQuantum(110)
69 \f
70 /*
71 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72 %                                                                             %
73 %                                                                             %
74 %                                                                             %
75 %   B o r d e r I m a g e                                                     %
76 %                                                                             %
77 %                                                                             %
78 %                                                                             %
79 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80 %
81 %  BorderImage() surrounds the image with a border of the color defined by
82 %  the bordercolor member of the image structure.  The width and height
83 %  of the border are defined by the corresponding members of the border_info
84 %  structure.
85 %
86 %  The format of the BorderImage method is:
87 %
88 %      Image *BorderImage(const Image *image,const RectangleInfo *border_info,
89 %        const CompositeOperator compose,ExceptionInfo *exception)
90 %
91 %  A description of each parameter follows:
92 %
93 %    o image: the image.
94 %
95 %    o border_info:  define the width and height of the border.
96 %
97 %    o compose:  the composite operator.
98 %
99 %    o exception: return any errors or warnings in this structure.
100 %
101 */
102 MagickExport Image *BorderImage(const Image *image,
103   const RectangleInfo *border_info,const CompositeOperator compose,
104   ExceptionInfo *exception)
105 {
106   Image
107     *border_image,
108     *clone_image;
109
110   FrameInfo
111     frame_info;
112
113   assert(image != (const Image *) NULL);
114   assert(image->signature == MagickSignature);
115   if (image->debug != MagickFalse)
116     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
117   assert(border_info != (RectangleInfo *) NULL);
118   frame_info.width=image->columns+(border_info->width << 1);
119   frame_info.height=image->rows+(border_info->height << 1);
120   frame_info.x=(ssize_t) border_info->width;
121   frame_info.y=(ssize_t) border_info->height;
122   frame_info.inner_bevel=0;
123   frame_info.outer_bevel=0;
124   clone_image=CloneImage(image,0,0,MagickTrue,exception);
125   if (clone_image == (Image *) NULL)
126     return((Image *) NULL);
127   clone_image->matte_color=image->border_color;
128   border_image=FrameImage(clone_image,&frame_info,compose,exception);
129   clone_image=DestroyImage(clone_image);
130   if (border_image != (Image *) NULL)
131     border_image->matte_color=image->matte_color;
132   return(border_image);
133 }
134 \f
135 /*
136 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
137 %                                                                             %
138 %                                                                             %
139 %                                                                             %
140 %   F r a m e I m a g e                                                       %
141 %                                                                             %
142 %                                                                             %
143 %                                                                             %
144 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
145 %
146 %  FrameImage() adds a simulated three-dimensional border around the image.
147 %  The color of the border is defined by the matte_color member of image.
148 %  Members width and height of frame_info specify the border width of the
149 %  vertical and horizontal sides of the frame.  Members inner and outer
150 %  indicate the width of the inner and outer shadows of the frame.
151 %
152 %  The format of the FrameImage method is:
153 %
154 %      Image *FrameImage(const Image *image,const FrameInfo *frame_info,
155 %        const CompositeOperator compose,ExceptionInfo *exception)
156 %
157 %  A description of each parameter follows:
158 %
159 %    o image: the image.
160 %
161 %    o frame_info: Define the width and height of the frame and its bevels.
162 %
163 %    o compose: the composite operator.
164 %
165 %    o exception: return any errors or warnings in this structure.
166 %
167 */
168 MagickExport Image *FrameImage(const Image *image,const FrameInfo *frame_info,
169   const CompositeOperator compose,ExceptionInfo *exception)
170 {
171 #define FrameImageTag  "Frame/Image"
172
173   CacheView
174     *image_view,
175     *frame_view;
176
177   Image
178     *frame_image;
179
180   MagickBooleanType
181     status;
182
183   MagickOffsetType
184     progress;
185
186   PixelInfo
187     accentuate,
188     border,
189     highlight,
190     interior,
191     matte,
192     shadow,
193     trough;
194
195   register ssize_t
196     x;
197
198   size_t
199     bevel_width,
200     height,
201     width;
202
203   ssize_t
204     y;
205
206   /*
207     Check frame geometry.
208   */
209   assert(image != (Image *) NULL);
210   assert(image->signature == MagickSignature);
211   if (image->debug != MagickFalse)
212     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
213   assert(frame_info != (FrameInfo *) NULL);
214   if ((frame_info->outer_bevel < 0) || (frame_info->inner_bevel < 0))
215     ThrowImageException(OptionError,"FrameIsLessThanImageSize");
216   bevel_width=(size_t) (frame_info->outer_bevel+frame_info->inner_bevel);
217   width=frame_info->width-frame_info->x-bevel_width;
218   height=frame_info->height-frame_info->y-bevel_width;
219   if ((width < image->columns) || (height < image->rows))
220     ThrowImageException(OptionError,"FrameIsLessThanImageSize");
221   /*
222     Initialize framed image attributes.
223   */
224   frame_image=CloneImage(image,frame_info->width,frame_info->height,MagickTrue,
225     exception);
226   if (frame_image == (Image *) NULL)
227     return((Image *) NULL);
228   if (SetImageStorageClass(frame_image,DirectClass,exception) == MagickFalse)
229     {
230       frame_image=DestroyImage(frame_image);
231       return((Image *) NULL);
232     }
233   if (frame_image->matte_color.alpha != OpaqueAlpha)
234     frame_image->matte=MagickTrue;
235   frame_image->page=image->page;
236   if ((image->page.width != 0) && (image->page.height != 0))
237     {
238       frame_image->page.width+=frame_image->columns-image->columns;
239       frame_image->page.height+=frame_image->rows-image->rows;
240     }
241   /*
242     Initialize 3D effects color.
243   */
244   GetPixelInfo(frame_image,&interior);
245   SetPixelInfoPacket(frame_image,&image->border_color,&interior);
246   GetPixelInfo(frame_image,&matte);
247   matte.colorspace=RGBColorspace;
248   SetPixelInfoPacket(frame_image,&image->matte_color,&matte);
249   GetPixelInfo(frame_image,&border);
250   border.colorspace=RGBColorspace;
251   SetPixelInfoPacket(frame_image,&image->border_color,&border);
252   GetPixelInfo(frame_image,&accentuate);
253   accentuate.red=(MagickRealType) (QuantumScale*((QuantumRange-
254     AccentuateModulate)*matte.red+(QuantumRange*AccentuateModulate)));
255   accentuate.green=(MagickRealType) (QuantumScale*((QuantumRange-
256     AccentuateModulate)*matte.green+(QuantumRange*AccentuateModulate)));
257   accentuate.blue=(MagickRealType) (QuantumScale*((QuantumRange-
258     AccentuateModulate)*matte.blue+(QuantumRange*AccentuateModulate)));
259   accentuate.alpha=matte.alpha;
260   GetPixelInfo(frame_image,&highlight);
261   highlight.red=(MagickRealType) (QuantumScale*((QuantumRange-
262     HighlightModulate)*matte.red+(QuantumRange*HighlightModulate)));
263   highlight.green=(MagickRealType) (QuantumScale*((QuantumRange-
264     HighlightModulate)*matte.green+(QuantumRange*HighlightModulate)));
265   highlight.blue=(MagickRealType) (QuantumScale*((QuantumRange-
266     HighlightModulate)*matte.blue+(QuantumRange*HighlightModulate)));
267   highlight.alpha=matte.alpha;
268   GetPixelInfo(frame_image,&shadow);
269   shadow.red=QuantumScale*matte.red*ShadowModulate;
270   shadow.green=QuantumScale*matte.green*ShadowModulate;
271   shadow.blue=QuantumScale*matte.blue*ShadowModulate;
272   shadow.alpha=matte.alpha;
273   GetPixelInfo(frame_image,&trough);
274   trough.red=QuantumScale*matte.red*TroughModulate;
275   trough.green=QuantumScale*matte.green*TroughModulate;
276   trough.blue=QuantumScale*matte.blue*TroughModulate;
277   trough.alpha=matte.alpha;
278   status=MagickTrue;
279   progress=0;
280   image_view=AcquireCacheView(image);
281   frame_view=AcquireCacheView(frame_image);
282   height=(size_t) (frame_info->outer_bevel+(frame_info->y-bevel_width)+
283     frame_info->inner_bevel);
284   if (height != 0)
285     {
286       register ssize_t
287         x;
288
289       register Quantum
290         *restrict q;
291
292       /*
293         Draw top of ornamental border.
294       */
295       q=QueueCacheViewAuthenticPixels(frame_view,0,0,frame_image->columns,
296         height,exception);
297       if (q != (Quantum *) NULL)
298         {
299           /*
300             Draw top of ornamental border.
301           */
302           for (y=0; y < (ssize_t) frame_info->outer_bevel; y++)
303           {
304             for (x=0; x < (ssize_t) (frame_image->columns-y); x++)
305             {
306               if (x < y)
307                 SetPixelPixelInfo(frame_image,&highlight,q);
308               else
309                 SetPixelPixelInfo(frame_image,&accentuate,q);
310               q+=GetPixelChannels(frame_image);
311             }
312             for ( ; x < (ssize_t) frame_image->columns; x++)
313             {
314               SetPixelPixelInfo(frame_image,&shadow,q);
315               q+=GetPixelChannels(frame_image);
316             }
317           }
318           for (y=0; y < (ssize_t) (frame_info->y-bevel_width); y++)
319           {
320             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
321             {
322               SetPixelPixelInfo(frame_image,&highlight,q);
323               q+=GetPixelChannels(frame_image);
324             }
325             width=frame_image->columns-2*frame_info->outer_bevel;
326             for (x=0; x < (ssize_t) width; x++)
327             {
328               SetPixelPixelInfo(frame_image,&matte,q);
329               q+=GetPixelChannels(frame_image);
330             }
331             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
332             {
333               SetPixelPixelInfo(frame_image,&shadow,q);
334               q+=GetPixelChannels(frame_image);
335             }
336           }
337           for (y=0; y < (ssize_t) frame_info->inner_bevel; y++)
338           {
339             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
340             {
341               SetPixelPixelInfo(frame_image,&highlight,q);
342               q+=GetPixelChannels(frame_image);
343             }
344             for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++)
345             {
346               SetPixelPixelInfo(frame_image,&matte,q);
347               q+=GetPixelChannels(frame_image);
348             }
349             width=image->columns+((size_t) frame_info->inner_bevel << 1)-
350               y;
351             for (x=0; x < (ssize_t) width; x++)
352             {
353               if (x < y)
354                 SetPixelPixelInfo(frame_image,&shadow,q);
355               else
356                 SetPixelPixelInfo(frame_image,&trough,q);
357               q+=GetPixelChannels(frame_image);
358             }
359             for ( ; x < (ssize_t) (image->columns+2*frame_info->inner_bevel); x++)
360             {
361               SetPixelPixelInfo(frame_image,&highlight,q);
362               q+=GetPixelChannels(frame_image);
363             }
364             width=frame_info->width-frame_info->x-image->columns-bevel_width;
365             for (x=0; x < (ssize_t) width; x++)
366             {
367               SetPixelPixelInfo(frame_image,&matte,q);
368               q+=GetPixelChannels(frame_image);
369             }
370             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
371             {
372               SetPixelPixelInfo(frame_image,&shadow,q);
373               q+=GetPixelChannels(frame_image);
374             }
375           }
376           (void) SyncCacheViewAuthenticPixels(frame_view,exception);
377         }
378     }
379   /*
380     Draw sides of ornamental border.
381   */
382 #if defined(MAGICKCORE_OPENMP_SUPPORT) 
383   #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
384 #endif
385   for (y=0; y < (ssize_t) image->rows; y++)
386   {
387     register ssize_t
388       x;
389
390     register Quantum
391       *restrict q;
392
393     /*
394       Initialize scanline with matte color.
395     */
396     if (status == MagickFalse)
397       continue;
398     q=QueueCacheViewAuthenticPixels(frame_view,0,frame_info->y+y,
399       frame_image->columns,1,exception);
400     if (q == (Quantum *) NULL)
401       {
402         status=MagickFalse;
403         continue;
404       }
405     for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
406     {
407       SetPixelPixelInfo(frame_image,&highlight,q);
408       q+=GetPixelChannels(frame_image);
409     }
410     for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++)
411     {
412       SetPixelPixelInfo(frame_image,&matte,q);
413       q+=GetPixelChannels(frame_image);
414     }
415     for (x=0; x < (ssize_t) frame_info->inner_bevel; x++)
416     {
417       SetPixelPixelInfo(frame_image,&shadow,q);
418       q+=GetPixelChannels(frame_image);
419     }
420     /*
421       Set frame interior to interior color.
422     */
423     if ((compose != CopyCompositeOp) && ((compose != OverCompositeOp) ||
424         (image->matte != MagickFalse)))
425       for (x=0; x < (ssize_t) image->columns; x++)
426       {
427         SetPixelPixelInfo(frame_image,&interior,q);
428         q+=GetPixelChannels(frame_image);
429       }
430     else
431       {
432         register const Quantum
433           *p;
434
435         p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
436         if (p == (const Quantum *) NULL)
437           {
438             status=MagickFalse;
439             continue;
440           }
441         for (x=0; x < (ssize_t) image->columns; x++)
442         {
443           if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
444             SetPixelRed(frame_image,GetPixelRed(image,p),q);
445           if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
446             SetPixelGreen(frame_image,GetPixelGreen(image,p),q);
447           if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
448             SetPixelBlue(frame_image,GetPixelBlue(image,p),q);
449           if ((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0)
450             SetPixelBlack(frame_image,GetPixelBlack(image,p),q);
451           if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
452             SetPixelAlpha(frame_image,GetPixelAlpha(image,p),q);
453           p+=GetPixelChannels(image);
454           q+=GetPixelChannels(frame_image);
455         }
456       }
457     for (x=0; x < (ssize_t) frame_info->inner_bevel; x++)
458     {
459       SetPixelPixelInfo(frame_image,&highlight,q);
460       q+=GetPixelChannels(frame_image);
461     }
462     width=frame_info->width-frame_info->x-image->columns-bevel_width;
463     for (x=0; x < (ssize_t) width; x++)
464     {
465       SetPixelPixelInfo(frame_image,&matte,q);
466       q+=GetPixelChannels(frame_image);
467     }
468     for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
469     {
470       SetPixelPixelInfo(frame_image,&shadow,q);
471       q+=GetPixelChannels(frame_image);
472     }
473     if (SyncCacheViewAuthenticPixels(frame_view,exception) == MagickFalse)
474       status=MagickFalse;
475     if (image->progress_monitor != (MagickProgressMonitor) NULL)
476       {
477         MagickBooleanType
478           proceed;
479
480 #if defined(MAGICKCORE_OPENMP_SUPPORT) 
481   #pragma omp critical (MagickCore_FrameImage)
482 #endif
483         proceed=SetImageProgress(image,FrameImageTag,progress++,image->rows);
484         if (proceed == MagickFalse)
485           status=MagickFalse;
486       }
487   }
488   height=(size_t) (frame_info->inner_bevel+frame_info->height-
489     frame_info->y-image->rows-bevel_width+frame_info->outer_bevel);
490   if (height != 0)
491     {
492       register ssize_t
493         x;
494
495       register Quantum
496         *restrict q;
497
498       /*
499         Draw bottom of ornamental border.
500       */
501       q=QueueCacheViewAuthenticPixels(frame_view,0,(ssize_t) (frame_image->rows-
502         height),frame_image->columns,height,exception);
503       if (q != (Quantum *) NULL)
504         {
505           /*
506             Draw bottom of ornamental border.
507           */
508           for (y=frame_info->inner_bevel-1; y >= 0; y--)
509           {
510             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
511             {
512               SetPixelPixelInfo(frame_image,&highlight,q);
513               q+=GetPixelChannels(frame_image);
514             }
515             for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++)
516             {
517               SetPixelPixelInfo(frame_image,&matte,q);
518               q+=GetPixelChannels(frame_image);
519             }
520             for (x=0; x < y; x++)
521             {
522               SetPixelPixelInfo(frame_image,&shadow,q);
523               q+=GetPixelChannels(frame_image);
524             }
525             for ( ; x < (ssize_t) (image->columns+2*frame_info->inner_bevel); x++)
526             {
527               if (x >= (ssize_t) (image->columns+2*frame_info->inner_bevel-y))
528                 SetPixelPixelInfo(frame_image,&highlight,q);
529               else
530                 SetPixelPixelInfo(frame_image,&accentuate,q);
531               q+=GetPixelChannels(frame_image);
532             }
533             width=frame_info->width-frame_info->x-image->columns-bevel_width;
534             for (x=0; x < (ssize_t) width; x++)
535             {
536               SetPixelPixelInfo(frame_image,&matte,q);
537               q+=GetPixelChannels(frame_image);
538             }
539             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
540             {
541               SetPixelPixelInfo(frame_image,&shadow,q);
542               q+=GetPixelChannels(frame_image);
543             }
544           }
545           height=frame_info->height-frame_info->y-image->rows-bevel_width;
546           for (y=0; y < (ssize_t) height; y++)
547           {
548             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
549             {
550               SetPixelPixelInfo(frame_image,&highlight,q);
551               q+=GetPixelChannels(frame_image);
552             }
553             width=frame_image->columns-2*frame_info->outer_bevel;
554             for (x=0; x < (ssize_t) width; x++)
555             {
556               SetPixelPixelInfo(frame_image,&matte,q);
557               q+=GetPixelChannels(frame_image);
558             }
559             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
560             {
561               SetPixelPixelInfo(frame_image,&shadow,q);
562               q+=GetPixelChannels(frame_image);
563             }
564           }
565           for (y=frame_info->outer_bevel-1; y >= 0; y--)
566           {
567             for (x=0; x < y; x++)
568             {
569               SetPixelPixelInfo(frame_image,&highlight,q);
570               q+=GetPixelChannels(frame_image);
571             }
572             for ( ; x < (ssize_t) frame_image->columns; x++)
573             {
574               if (x >= (ssize_t) (frame_image->columns-y))
575                 SetPixelPixelInfo(frame_image,&shadow,q);
576               else
577                 SetPixelPixelInfo(frame_image,&trough,q);
578               q+=GetPixelChannels(frame_image);
579             }
580           }
581           (void) SyncCacheViewAuthenticPixels(frame_view,exception);
582         }
583     }
584   frame_view=DestroyCacheView(frame_view);
585   image_view=DestroyCacheView(image_view);
586   if ((compose != CopyCompositeOp) && ((compose != OverCompositeOp) ||
587       (image->matte != MagickFalse)))
588     {
589       x=(ssize_t) (frame_info->outer_bevel+(frame_info->x-bevel_width)+
590         frame_info->inner_bevel);
591       y=(ssize_t) (frame_info->outer_bevel+(frame_info->y-bevel_width)+
592         frame_info->inner_bevel);
593       (void) CompositeImage(frame_image,compose,image,x,y,exception);
594     }
595   return(frame_image);
596 }
597 \f
598 /*
599 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
600 %                                                                             %
601 %                                                                             %
602 %                                                                             %
603 %   R a i s e I m a g e                                                       %
604 %                                                                             %
605 %                                                                             %
606 %                                                                             %
607 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
608 %
609 %  RaiseImage() creates a simulated three-dimensional button-like effect
610 %  by lightening and darkening the edges of the image.  Members width and
611 %  height of raise_info define the width of the vertical and horizontal
612 %  edge of the effect.
613 %
614 %  The format of the RaiseImage method is:
615 %
616 %      MagickBooleanType RaiseImage(const Image *image,
617 %        const RectangleInfo *raise_info,const MagickBooleanType raise,
618 %        ExceptionInfo *exception)
619 %
620 %  A description of each parameter follows:
621 %
622 %    o image: the image.
623 %
624 %    o raise_info: Define the width and height of the raise area.
625 %
626 %    o raise: A value other than zero creates a 3-D raise effect,
627 %      otherwise it has a lowered effect.
628 %
629 %    o exception: return any errors or warnings in this structure.
630 %
631 */
632 MagickExport MagickBooleanType RaiseImage(Image *image,
633   const RectangleInfo *raise_info,const MagickBooleanType raise,
634   ExceptionInfo *exception)
635 {
636 #define AccentuateFactor  ScaleCharToQuantum(135)
637 #define HighlightFactor  ScaleCharToQuantum(190)
638 #define ShadowFactor  ScaleCharToQuantum(190)
639 #define RaiseImageTag  "Raise/Image"
640 #define TroughFactor  ScaleCharToQuantum(135)
641
642   CacheView
643     *image_view;
644
645   MagickBooleanType
646     status;
647
648   MagickOffsetType
649     progress;
650
651   Quantum
652     foreground,
653     background;
654
655   ssize_t
656     y;
657
658   assert(image != (Image *) NULL);
659   assert(image->signature == MagickSignature);
660   if (image->debug != MagickFalse)
661     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
662   assert(raise_info != (RectangleInfo *) NULL);
663   if ((image->columns <= (raise_info->width << 1)) ||
664       (image->rows <= (raise_info->height << 1)))
665     ThrowBinaryException(OptionError,"ImageSizeMustExceedBevelWidth",
666       image->filename);
667   foreground=(Quantum) QuantumRange;
668   background=(Quantum) 0;
669   if (raise == MagickFalse)
670     {
671       foreground=(Quantum) 0;
672       background=(Quantum) QuantumRange;
673     }
674   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
675     return(MagickFalse);
676   /*
677     Raise image.
678   */
679   status=MagickTrue;
680   progress=0;
681   image_view=AcquireCacheView(image);
682 #if defined(MAGICKCORE_OPENMP_SUPPORT) 
683   #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
684 #endif
685   for (y=0; y < (ssize_t) raise_info->height; y++)
686   {
687     PixelTrait
688       traits;
689
690     register ssize_t
691       i,
692       x;
693
694     register Quantum
695       *restrict q;
696
697     if (status == MagickFalse)
698       continue;
699     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
700     if (q == (Quantum *) NULL)
701       {
702         status=MagickFalse;
703         continue;
704       }
705     for (x=0; x < y; x++)
706     {
707       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
708       {
709         traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
710         if ((traits & UpdatePixelTrait) != 0)
711           q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*
712             HighlightFactor+(MagickRealType) foreground*(QuantumRange-
713             HighlightFactor)));
714       }
715       q+=GetPixelChannels(image);
716     }
717     for ( ; x < (ssize_t) (image->columns-y); x++)
718     {
719       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
720       {
721         traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
722         if ((traits & UpdatePixelTrait) != 0)
723           q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*
724             AccentuateFactor+(MagickRealType) foreground*(QuantumRange-
725             AccentuateFactor)));
726       }
727       q+=GetPixelChannels(image);
728     }
729     for ( ; x < (ssize_t) image->columns; x++)
730     {
731       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
732       {
733         traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
734         if ((traits & UpdatePixelTrait) != 0)
735           q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*
736             ShadowFactor+(MagickRealType) background*(QuantumRange-
737             ShadowFactor)));
738       }
739       q+=GetPixelChannels(image);
740     }
741     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
742       status=MagickFalse;
743     if (image->progress_monitor != (MagickProgressMonitor) NULL)
744       {
745         MagickBooleanType
746           proceed;
747
748         proceed=SetImageProgress(image,RaiseImageTag,progress++,image->rows);
749         if (proceed == MagickFalse)
750           status=MagickFalse;
751       }
752   }
753 #if defined(MAGICKCORE_OPENMP_SUPPORT)
754   #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
755 #endif
756   for (y=(ssize_t) raise_info->height; y < (ssize_t) (image->rows-raise_info->height); y++)
757   {
758     PixelTrait
759       traits;
760
761     register ssize_t
762       i,
763       x;
764
765     register Quantum
766       *restrict q;
767
768     if (status == MagickFalse)
769       continue;
770     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
771     if (q == (Quantum *) NULL)
772       {
773         status=MagickFalse;
774         continue;
775       }
776     for (x=0; x < (ssize_t) raise_info->width; x++)
777     {
778       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
779       {
780         traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
781         if ((traits & UpdatePixelTrait) != 0)
782           q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*
783             HighlightFactor+(MagickRealType) foreground*(QuantumRange-
784             HighlightFactor)));
785       }
786       q+=GetPixelChannels(image);
787     }
788     for ( ; x < (ssize_t) (image->columns-raise_info->width); x++)
789       q+=GetPixelChannels(image);
790     for ( ; x < (ssize_t) image->columns; x++)
791     {
792       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
793       {
794         traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
795         if ((traits & UpdatePixelTrait) != 0)
796           q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*
797             ShadowFactor+(MagickRealType) background*(QuantumRange-
798             ShadowFactor)));
799       }
800       q+=GetPixelChannels(image);
801     }
802     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
803       status=MagickFalse;
804     if (image->progress_monitor != (MagickProgressMonitor) NULL)
805       {
806         MagickBooleanType
807           proceed;
808
809         proceed=SetImageProgress(image,RaiseImageTag,progress++,image->rows);
810         if (proceed == MagickFalse)
811           status=MagickFalse;
812       }
813   }
814 #if defined(MAGICKCORE_OPENMP_SUPPORT) 
815   #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
816 #endif
817   for (y=(ssize_t) (image->rows-raise_info->height); y < (ssize_t) image->rows; y++)
818   {
819     PixelTrait
820       traits;
821
822     register ssize_t
823       i,
824       x;
825
826     register Quantum
827       *restrict q;
828
829     if (status == MagickFalse)
830       continue;
831     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
832     if (q == (Quantum *) NULL)
833       {
834         status=MagickFalse;
835         continue;
836       }
837     for (x=0; x < (ssize_t) (image->rows-y); x++)
838     {
839       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
840       {
841         traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
842         if ((traits & UpdatePixelTrait) != 0)
843           q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*
844             HighlightFactor+(MagickRealType) foreground*(QuantumRange-
845             HighlightFactor)));
846       }
847       q+=GetPixelChannels(image);
848     }
849     for ( ; x < (ssize_t) (image->columns-(image->rows-y)); x++)
850     {
851       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
852       {
853         traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
854         if ((traits & UpdatePixelTrait) != 0)
855           q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*
856             TroughFactor+(MagickRealType) background*(QuantumRange-
857             TroughFactor)));
858       }
859       q+=GetPixelChannels(image);
860     }
861     for ( ; x < (ssize_t) image->columns; x++)
862     {
863       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
864       {
865         traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
866         if ((traits & UpdatePixelTrait) != 0)
867           q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*
868             ShadowFactor+(MagickRealType) background*(QuantumRange-
869             ShadowFactor)));
870       }
871       q+=GetPixelChannels(image);
872     }
873     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
874       status=MagickFalse;
875     if (image->progress_monitor != (MagickProgressMonitor) NULL)
876       {
877         MagickBooleanType
878           proceed;
879
880 #if defined(MAGICKCORE_OPENMP_SUPPORT)
881   #pragma omp critical (MagickCore_RaiseImage)
882 #endif
883         proceed=SetImageProgress(image,RaiseImageTag,progress++,image->rows);
884         if (proceed == MagickFalse)
885           status=MagickFalse;
886       }
887   }
888   image_view=DestroyCacheView(image_view);
889   return(status);
890 }