]> 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-2012 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     highlight,
189     interior,
190     matte,
191     shadow,
192     trough;
193
194   register ssize_t
195     x;
196
197   size_t
198     bevel_width,
199     height,
200     width;
201
202   ssize_t
203     y;
204
205   /*
206     Check frame geometry.
207   */
208   assert(image != (Image *) NULL);
209   assert(image->signature == MagickSignature);
210   if (image->debug != MagickFalse)
211     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
212   assert(frame_info != (FrameInfo *) NULL);
213   if ((frame_info->outer_bevel < 0) || (frame_info->inner_bevel < 0))
214     ThrowImageException(OptionError,"FrameIsLessThanImageSize");
215   bevel_width=(size_t) (frame_info->outer_bevel+frame_info->inner_bevel);
216   width=frame_info->width-frame_info->x-bevel_width;
217   height=frame_info->height-frame_info->y-bevel_width;
218   if ((width < image->columns) || (height < image->rows))
219     ThrowImageException(OptionError,"FrameIsLessThanImageSize");
220   /*
221     Initialize framed image attributes.
222   */
223   frame_image=CloneImage(image,frame_info->width,frame_info->height,MagickTrue,
224     exception);
225   if (frame_image == (Image *) NULL)
226     return((Image *) NULL);
227   if (SetImageStorageClass(frame_image,DirectClass,exception) == MagickFalse)
228     {
229       frame_image=DestroyImage(frame_image);
230       return((Image *) NULL);
231     }
232   if (frame_image->matte_color.alpha != OpaqueAlpha)
233     frame_image->matte=MagickTrue;
234   frame_image->page=image->page;
235   if ((image->page.width != 0) && (image->page.height != 0))
236     {
237       frame_image->page.width+=frame_image->columns-image->columns;
238       frame_image->page.height+=frame_image->rows-image->rows;
239     }
240   /*
241     Initialize 3D effects color.
242   */
243   interior=image->border_color;
244   matte=image->matte_color;
245   accentuate=matte;
246   accentuate.red=(MagickRealType) (QuantumScale*((QuantumRange-
247     AccentuateModulate)*matte.red+(QuantumRange*AccentuateModulate)));
248   accentuate.green=(MagickRealType) (QuantumScale*((QuantumRange-
249     AccentuateModulate)*matte.green+(QuantumRange*AccentuateModulate)));
250   accentuate.blue=(MagickRealType) (QuantumScale*((QuantumRange-
251     AccentuateModulate)*matte.blue+(QuantumRange*AccentuateModulate)));
252   accentuate.black=(MagickRealType) (QuantumScale*((QuantumRange-
253     AccentuateModulate)*matte.black+(QuantumRange*AccentuateModulate)));
254   accentuate.alpha=matte.alpha;
255   highlight=matte;
256   highlight.red=(MagickRealType) (QuantumScale*((QuantumRange-
257     HighlightModulate)*matte.red+(QuantumRange*HighlightModulate)));
258   highlight.green=(MagickRealType) (QuantumScale*((QuantumRange-
259     HighlightModulate)*matte.green+(QuantumRange*HighlightModulate)));
260   highlight.blue=(MagickRealType) (QuantumScale*((QuantumRange-
261     HighlightModulate)*matte.blue+(QuantumRange*HighlightModulate)));
262   highlight.black=(MagickRealType) (QuantumScale*((QuantumRange-
263     HighlightModulate)*matte.black+(QuantumRange*HighlightModulate)));
264   highlight.alpha=matte.alpha;
265   shadow=matte;
266   shadow.red=QuantumScale*matte.red*ShadowModulate;
267   shadow.green=QuantumScale*matte.green*ShadowModulate;
268   shadow.blue=QuantumScale*matte.blue*ShadowModulate;
269   shadow.black=QuantumScale*matte.black*ShadowModulate;
270   shadow.alpha=matte.alpha;
271   trough=matte;
272   trough.red=QuantumScale*matte.red*TroughModulate;
273   trough.green=QuantumScale*matte.green*TroughModulate;
274   trough.blue=QuantumScale*matte.blue*TroughModulate;
275   trough.black=QuantumScale*matte.black*TroughModulate;
276   trough.alpha=matte.alpha;
277   status=MagickTrue;
278   progress=0;
279   image_view=AcquireCacheView(image);
280   frame_view=AcquireCacheView(frame_image);
281   height=(size_t) (frame_info->outer_bevel+(frame_info->y-bevel_width)+
282     frame_info->inner_bevel);
283   if (height != 0)
284     {
285       register ssize_t
286         x;
287
288       register Quantum
289         *restrict q;
290
291       /*
292         Draw top of ornamental border.
293       */
294       q=QueueCacheViewAuthenticPixels(frame_view,0,0,frame_image->columns,
295         height,exception);
296       if (q != (Quantum *) NULL)
297         {
298           /*
299             Draw top of ornamental border.
300           */
301           for (y=0; y < (ssize_t) frame_info->outer_bevel; y++)
302           {
303             for (x=0; x < (ssize_t) (frame_image->columns-y); x++)
304             {
305               if (x < y)
306                 SetPixelInfoPixel(frame_image,&highlight,q);
307               else
308                 SetPixelInfoPixel(frame_image,&accentuate,q);
309               q+=GetPixelChannels(frame_image);
310             }
311             for ( ; x < (ssize_t) frame_image->columns; x++)
312             {
313               SetPixelInfoPixel(frame_image,&shadow,q);
314               q+=GetPixelChannels(frame_image);
315             }
316           }
317           for (y=0; y < (ssize_t) (frame_info->y-bevel_width); y++)
318           {
319             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
320             {
321               SetPixelInfoPixel(frame_image,&highlight,q);
322               q+=GetPixelChannels(frame_image);
323             }
324             width=frame_image->columns-2*frame_info->outer_bevel;
325             for (x=0; x < (ssize_t) width; x++)
326             {
327               SetPixelInfoPixel(frame_image,&matte,q);
328               q+=GetPixelChannels(frame_image);
329             }
330             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
331             {
332               SetPixelInfoPixel(frame_image,&shadow,q);
333               q+=GetPixelChannels(frame_image);
334             }
335           }
336           for (y=0; y < (ssize_t) frame_info->inner_bevel; y++)
337           {
338             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
339             {
340               SetPixelInfoPixel(frame_image,&highlight,q);
341               q+=GetPixelChannels(frame_image);
342             }
343             for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++)
344             {
345               SetPixelInfoPixel(frame_image,&matte,q);
346               q+=GetPixelChannels(frame_image);
347             }
348             width=image->columns+((size_t) frame_info->inner_bevel << 1)-
349               y;
350             for (x=0; x < (ssize_t) width; x++)
351             {
352               if (x < y)
353                 SetPixelInfoPixel(frame_image,&shadow,q);
354               else
355                 SetPixelInfoPixel(frame_image,&trough,q);
356               q+=GetPixelChannels(frame_image);
357             }
358             for ( ; x < (ssize_t) (image->columns+2*frame_info->inner_bevel); x++)
359             {
360               SetPixelInfoPixel(frame_image,&highlight,q);
361               q+=GetPixelChannels(frame_image);
362             }
363             width=frame_info->width-frame_info->x-image->columns-bevel_width;
364             for (x=0; x < (ssize_t) width; x++)
365             {
366               SetPixelInfoPixel(frame_image,&matte,q);
367               q+=GetPixelChannels(frame_image);
368             }
369             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
370             {
371               SetPixelInfoPixel(frame_image,&shadow,q);
372               q+=GetPixelChannels(frame_image);
373             }
374           }
375           (void) SyncCacheViewAuthenticPixels(frame_view,exception);
376         }
377     }
378   /*
379     Draw sides of ornamental border.
380   */
381 #if defined(MAGICKCORE_OPENMP_SUPPORT) 
382   #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
383 #endif
384   for (y=0; y < (ssize_t) image->rows; y++)
385   {
386     register ssize_t
387       x;
388
389     register Quantum
390       *restrict q;
391
392     /*
393       Initialize scanline with matte color.
394     */
395     if (status == MagickFalse)
396       continue;
397     q=QueueCacheViewAuthenticPixels(frame_view,0,frame_info->y+y,
398       frame_image->columns,1,exception);
399     if (q == (Quantum *) NULL)
400       {
401         status=MagickFalse;
402         continue;
403       }
404     for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
405     {
406       SetPixelInfoPixel(frame_image,&highlight,q);
407       q+=GetPixelChannels(frame_image);
408     }
409     for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++)
410     {
411       SetPixelInfoPixel(frame_image,&matte,q);
412       q+=GetPixelChannels(frame_image);
413     }
414     for (x=0; x < (ssize_t) frame_info->inner_bevel; x++)
415     {
416       SetPixelInfoPixel(frame_image,&shadow,q);
417       q+=GetPixelChannels(frame_image);
418     }
419     /*
420       Set frame interior to interior color.
421     */
422     if ((compose != CopyCompositeOp) && ((compose != OverCompositeOp) ||
423         (image->matte != MagickFalse)))
424       for (x=0; x < (ssize_t) image->columns; x++)
425       {
426         SetPixelInfoPixel(frame_image,&interior,q);
427         q+=GetPixelChannels(frame_image);
428       }
429     else
430       {
431         register const Quantum
432           *p;
433
434         p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
435         if (p == (const Quantum *) NULL)
436           {
437             status=MagickFalse;
438             continue;
439           }
440         for (x=0; x < (ssize_t) image->columns; x++)
441         {
442           if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
443             SetPixelRed(frame_image,GetPixelRed(image,p),q);
444           if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
445             SetPixelGreen(frame_image,GetPixelGreen(image,p),q);
446           if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
447             SetPixelBlue(frame_image,GetPixelBlue(image,p),q);
448           if ((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0)
449             SetPixelBlack(frame_image,GetPixelBlack(image,p),q);
450           if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
451             SetPixelAlpha(frame_image,GetPixelAlpha(image,p),q);
452           p+=GetPixelChannels(image);
453           q+=GetPixelChannels(frame_image);
454         }
455       }
456     for (x=0; x < (ssize_t) frame_info->inner_bevel; x++)
457     {
458       SetPixelInfoPixel(frame_image,&highlight,q);
459       q+=GetPixelChannels(frame_image);
460     }
461     width=frame_info->width-frame_info->x-image->columns-bevel_width;
462     for (x=0; x < (ssize_t) width; x++)
463     {
464       SetPixelInfoPixel(frame_image,&matte,q);
465       q+=GetPixelChannels(frame_image);
466     }
467     for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
468     {
469       SetPixelInfoPixel(frame_image,&shadow,q);
470       q+=GetPixelChannels(frame_image);
471     }
472     if (SyncCacheViewAuthenticPixels(frame_view,exception) == MagickFalse)
473       status=MagickFalse;
474     if (image->progress_monitor != (MagickProgressMonitor) NULL)
475       {
476         MagickBooleanType
477           proceed;
478
479 #if defined(MAGICKCORE_OPENMP_SUPPORT) 
480   #pragma omp critical (MagickCore_FrameImage)
481 #endif
482         proceed=SetImageProgress(image,FrameImageTag,progress++,image->rows);
483         if (proceed == MagickFalse)
484           status=MagickFalse;
485       }
486   }
487   height=(size_t) (frame_info->inner_bevel+frame_info->height-
488     frame_info->y-image->rows-bevel_width+frame_info->outer_bevel);
489   if (height != 0)
490     {
491       register ssize_t
492         x;
493
494       register Quantum
495         *restrict q;
496
497       /*
498         Draw bottom of ornamental border.
499       */
500       q=QueueCacheViewAuthenticPixels(frame_view,0,(ssize_t) (frame_image->rows-
501         height),frame_image->columns,height,exception);
502       if (q != (Quantum *) NULL)
503         {
504           /*
505             Draw bottom of ornamental border.
506           */
507           for (y=frame_info->inner_bevel-1; y >= 0; y--)
508           {
509             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
510             {
511               SetPixelInfoPixel(frame_image,&highlight,q);
512               q+=GetPixelChannels(frame_image);
513             }
514             for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++)
515             {
516               SetPixelInfoPixel(frame_image,&matte,q);
517               q+=GetPixelChannels(frame_image);
518             }
519             for (x=0; x < y; x++)
520             {
521               SetPixelInfoPixel(frame_image,&shadow,q);
522               q+=GetPixelChannels(frame_image);
523             }
524             for ( ; x < (ssize_t) (image->columns+2*frame_info->inner_bevel); x++)
525             {
526               if (x >= (ssize_t) (image->columns+2*frame_info->inner_bevel-y))
527                 SetPixelInfoPixel(frame_image,&highlight,q);
528               else
529                 SetPixelInfoPixel(frame_image,&accentuate,q);
530               q+=GetPixelChannels(frame_image);
531             }
532             width=frame_info->width-frame_info->x-image->columns-bevel_width;
533             for (x=0; x < (ssize_t) width; x++)
534             {
535               SetPixelInfoPixel(frame_image,&matte,q);
536               q+=GetPixelChannels(frame_image);
537             }
538             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
539             {
540               SetPixelInfoPixel(frame_image,&shadow,q);
541               q+=GetPixelChannels(frame_image);
542             }
543           }
544           height=frame_info->height-frame_info->y-image->rows-bevel_width;
545           for (y=0; y < (ssize_t) height; y++)
546           {
547             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
548             {
549               SetPixelInfoPixel(frame_image,&highlight,q);
550               q+=GetPixelChannels(frame_image);
551             }
552             width=frame_image->columns-2*frame_info->outer_bevel;
553             for (x=0; x < (ssize_t) width; x++)
554             {
555               SetPixelInfoPixel(frame_image,&matte,q);
556               q+=GetPixelChannels(frame_image);
557             }
558             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
559             {
560               SetPixelInfoPixel(frame_image,&shadow,q);
561               q+=GetPixelChannels(frame_image);
562             }
563           }
564           for (y=frame_info->outer_bevel-1; y >= 0; y--)
565           {
566             for (x=0; x < y; x++)
567             {
568               SetPixelInfoPixel(frame_image,&highlight,q);
569               q+=GetPixelChannels(frame_image);
570             }
571             for ( ; x < (ssize_t) frame_image->columns; x++)
572             {
573               if (x >= (ssize_t) (frame_image->columns-y))
574                 SetPixelInfoPixel(frame_image,&shadow,q);
575               else
576                 SetPixelInfoPixel(frame_image,&trough,q);
577               q+=GetPixelChannels(frame_image);
578             }
579           }
580           (void) SyncCacheViewAuthenticPixels(frame_view,exception);
581         }
582     }
583   frame_view=DestroyCacheView(frame_view);
584   image_view=DestroyCacheView(image_view);
585   if ((compose != CopyCompositeOp) && ((compose != OverCompositeOp) ||
586       (image->matte != MagickFalse)))
587     {
588       x=(ssize_t) (frame_info->outer_bevel+(frame_info->x-bevel_width)+
589         frame_info->inner_bevel);
590       y=(ssize_t) (frame_info->outer_bevel+(frame_info->y-bevel_width)+
591         frame_info->inner_bevel);
592       (void) CompositeImage(frame_image,compose,image,x,y,exception);
593     }
594   return(frame_image);
595 }
596 \f
597 /*
598 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
599 %                                                                             %
600 %                                                                             %
601 %                                                                             %
602 %   R a i s e I m a g e                                                       %
603 %                                                                             %
604 %                                                                             %
605 %                                                                             %
606 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
607 %
608 %  RaiseImage() creates a simulated three-dimensional button-like effect
609 %  by lightening and darkening the edges of the image.  Members width and
610 %  height of raise_info define the width of the vertical and horizontal
611 %  edge of the effect.
612 %
613 %  The format of the RaiseImage method is:
614 %
615 %      MagickBooleanType RaiseImage(const Image *image,
616 %        const RectangleInfo *raise_info,const MagickBooleanType raise,
617 %        ExceptionInfo *exception)
618 %
619 %  A description of each parameter follows:
620 %
621 %    o image: the image.
622 %
623 %    o raise_info: Define the width and height of the raise area.
624 %
625 %    o raise: A value other than zero creates a 3-D raise effect,
626 %      otherwise it has a lowered effect.
627 %
628 %    o exception: return any errors or warnings in this structure.
629 %
630 */
631 MagickExport MagickBooleanType RaiseImage(Image *image,
632   const RectangleInfo *raise_info,const MagickBooleanType raise,
633   ExceptionInfo *exception)
634 {
635 #define AccentuateFactor  ScaleCharToQuantum(135)
636 #define HighlightFactor  ScaleCharToQuantum(190)
637 #define ShadowFactor  ScaleCharToQuantum(190)
638 #define RaiseImageTag  "Raise/Image"
639 #define TroughFactor  ScaleCharToQuantum(135)
640
641   CacheView
642     *image_view;
643
644   MagickBooleanType
645     status;
646
647   MagickOffsetType
648     progress;
649
650   Quantum
651     foreground,
652     background;
653
654   ssize_t
655     y;
656
657   assert(image != (Image *) NULL);
658   assert(image->signature == MagickSignature);
659   if (image->debug != MagickFalse)
660     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
661   assert(raise_info != (RectangleInfo *) NULL);
662   if ((image->columns <= (raise_info->width << 1)) ||
663       (image->rows <= (raise_info->height << 1)))
664     ThrowBinaryException(OptionError,"ImageSizeMustExceedBevelWidth",
665       image->filename);
666   foreground=(Quantum) QuantumRange;
667   background=(Quantum) 0;
668   if (raise == MagickFalse)
669     {
670       foreground=(Quantum) 0;
671       background=(Quantum) QuantumRange;
672     }
673   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
674     return(MagickFalse);
675   /*
676     Raise image.
677   */
678   status=MagickTrue;
679   progress=0;
680   image_view=AcquireCacheView(image);
681 #if defined(MAGICKCORE_OPENMP_SUPPORT) 
682   #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
683 #endif
684   for (y=0; y < (ssize_t) raise_info->height; y++)
685   {
686     register ssize_t
687       i,
688       x;
689
690     register Quantum
691       *restrict q;
692
693     if (status == MagickFalse)
694       continue;
695     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
696     if (q == (Quantum *) NULL)
697       {
698         status=MagickFalse;
699         continue;
700       }
701     for (x=0; x < y; x++)
702     {
703       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
704       {
705         PixelChannel
706           channel;
707
708         PixelTrait
709           traits;
710
711         channel=GetPixelChannelMapChannel(image,i);
712         traits=GetPixelChannelMapTraits(image,channel);
713         if ((traits & UpdatePixelTrait) != 0)
714           q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*
715             HighlightFactor+(MagickRealType) foreground*(QuantumRange-
716             HighlightFactor)));
717       }
718       q+=GetPixelChannels(image);
719     }
720     for ( ; x < (ssize_t) (image->columns-y); x++)
721     {
722       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
723       {
724         PixelChannel
725           channel;
726
727         PixelTrait
728           traits;
729
730         channel=GetPixelChannelMapChannel(image,i);
731         traits=GetPixelChannelMapTraits(image,channel);
732         if ((traits & UpdatePixelTrait) != 0)
733           q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*
734             AccentuateFactor+(MagickRealType) foreground*(QuantumRange-
735             AccentuateFactor)));
736       }
737       q+=GetPixelChannels(image);
738     }
739     for ( ; x < (ssize_t) image->columns; x++)
740     {
741       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
742       {
743         PixelChannel
744           channel;
745
746         PixelTrait
747           traits;
748
749         channel=GetPixelChannelMapChannel(image,i);
750         traits=GetPixelChannelMapTraits(image,channel);
751         if ((traits & UpdatePixelTrait) != 0)
752           q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*
753             ShadowFactor+(MagickRealType) background*(QuantumRange-
754             ShadowFactor)));
755       }
756       q+=GetPixelChannels(image);
757     }
758     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
759       status=MagickFalse;
760     if (image->progress_monitor != (MagickProgressMonitor) NULL)
761       {
762         MagickBooleanType
763           proceed;
764
765         proceed=SetImageProgress(image,RaiseImageTag,progress++,image->rows);
766         if (proceed == MagickFalse)
767           status=MagickFalse;
768       }
769   }
770 #if defined(MAGICKCORE_OPENMP_SUPPORT)
771   #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
772 #endif
773   for (y=(ssize_t) raise_info->height; y < (ssize_t) (image->rows-raise_info->height); y++)
774   {
775     register ssize_t
776       i,
777       x;
778
779     register Quantum
780       *restrict q;
781
782     if (status == MagickFalse)
783       continue;
784     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
785     if (q == (Quantum *) NULL)
786       {
787         status=MagickFalse;
788         continue;
789       }
790     for (x=0; x < (ssize_t) raise_info->width; x++)
791     {
792       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
793       {
794         PixelChannel
795           channel;
796
797         PixelTrait
798           traits;
799
800         channel=GetPixelChannelMapChannel(image,i);
801         traits=GetPixelChannelMapTraits(image,channel);
802         if ((traits & UpdatePixelTrait) != 0)
803           q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*
804             HighlightFactor+(MagickRealType) foreground*(QuantumRange-
805             HighlightFactor)));
806       }
807       q+=GetPixelChannels(image);
808     }
809     for ( ; x < (ssize_t) (image->columns-raise_info->width); x++)
810       q+=GetPixelChannels(image);
811     for ( ; x < (ssize_t) image->columns; x++)
812     {
813       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
814       {
815         PixelChannel
816           channel;
817
818         PixelTrait
819           traits;
820
821         channel=GetPixelChannelMapChannel(image,i);
822         traits=GetPixelChannelMapTraits(image,channel);
823         if ((traits & UpdatePixelTrait) != 0)
824           q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*
825             ShadowFactor+(MagickRealType) background*(QuantumRange-
826             ShadowFactor)));
827       }
828       q+=GetPixelChannels(image);
829     }
830     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
831       status=MagickFalse;
832     if (image->progress_monitor != (MagickProgressMonitor) NULL)
833       {
834         MagickBooleanType
835           proceed;
836
837         proceed=SetImageProgress(image,RaiseImageTag,progress++,image->rows);
838         if (proceed == MagickFalse)
839           status=MagickFalse;
840       }
841   }
842 #if defined(MAGICKCORE_OPENMP_SUPPORT) 
843   #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
844 #endif
845   for (y=(ssize_t) (image->rows-raise_info->height); y < (ssize_t) image->rows; y++)
846   {
847     register ssize_t
848       i,
849       x;
850
851     register Quantum
852       *restrict q;
853
854     if (status == MagickFalse)
855       continue;
856     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
857     if (q == (Quantum *) NULL)
858       {
859         status=MagickFalse;
860         continue;
861       }
862     for (x=0; x < (ssize_t) (image->rows-y); x++)
863     {
864       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
865       {
866         PixelChannel
867           channel;
868
869         PixelTrait
870           traits;
871
872         channel=GetPixelChannelMapChannel(image,i);
873         traits=GetPixelChannelMapTraits(image,channel);
874         if ((traits & UpdatePixelTrait) != 0)
875           q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*
876             HighlightFactor+(MagickRealType) foreground*(QuantumRange-
877             HighlightFactor)));
878       }
879       q+=GetPixelChannels(image);
880     }
881     for ( ; x < (ssize_t) (image->columns-(image->rows-y)); x++)
882     {
883       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
884       {
885         PixelChannel
886           channel;
887
888         PixelTrait
889           traits;
890
891         channel=GetPixelChannelMapChannel(image,i);
892         traits=GetPixelChannelMapTraits(image,channel);
893         if ((traits & UpdatePixelTrait) != 0)
894           q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*
895             TroughFactor+(MagickRealType) background*(QuantumRange-
896             TroughFactor)));
897       }
898       q+=GetPixelChannels(image);
899     }
900     for ( ; x < (ssize_t) image->columns; x++)
901     {
902       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
903       {
904         PixelChannel
905           channel;
906
907         PixelTrait
908           traits;
909
910         channel=GetPixelChannelMapChannel(image,i);
911         traits=GetPixelChannelMapTraits(image,channel);
912         if ((traits & UpdatePixelTrait) != 0)
913           q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*
914             ShadowFactor+(MagickRealType) background*(QuantumRange-
915             ShadowFactor)));
916       }
917       q+=GetPixelChannels(image);
918     }
919     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
920       status=MagickFalse;
921     if (image->progress_monitor != (MagickProgressMonitor) NULL)
922       {
923         MagickBooleanType
924           proceed;
925
926 #if defined(MAGICKCORE_OPENMP_SUPPORT)
927   #pragma omp critical (MagickCore_RaiseImage)
928 #endif
929         proceed=SetImageProgress(image,RaiseImageTag,progress++,image->rows);
930         if (proceed == MagickFalse)
931           status=MagickFalse;
932       }
933   }
934   image_view=DestroyCacheView(image_view);
935   return(status);
936 }