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