]> 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(static) shared(progress,status)
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     size_t
393       width;
394
395     /*
396       Initialize scanline with matte color.
397     */
398     if (status == MagickFalse)
399       continue;
400     q=QueueCacheViewAuthenticPixels(frame_view,0,frame_info->y+y,
401       frame_image->columns,1,exception);
402     if (q == (Quantum *) NULL)
403       {
404         status=MagickFalse;
405         continue;
406       }
407     for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
408     {
409       SetPixelInfoPixel(frame_image,&highlight,q);
410       q+=GetPixelChannels(frame_image);
411     }
412     for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++)
413     {
414       SetPixelInfoPixel(frame_image,&matte,q);
415       q+=GetPixelChannels(frame_image);
416     }
417     for (x=0; x < (ssize_t) frame_info->inner_bevel; x++)
418     {
419       SetPixelInfoPixel(frame_image,&shadow,q);
420       q+=GetPixelChannels(frame_image);
421     }
422     /*
423       Set frame interior to interior color.
424     */
425     if ((compose != CopyCompositeOp) && ((compose != OverCompositeOp) ||
426         (image->matte != MagickFalse)))
427       for (x=0; x < (ssize_t) image->columns; x++)
428       {
429         SetPixelInfoPixel(frame_image,&interior,q);
430         q+=GetPixelChannels(frame_image);
431       }
432     else
433       {
434         register const Quantum
435           *p;
436
437         p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
438         if (p == (const Quantum *) NULL)
439           {
440             status=MagickFalse;
441             continue;
442           }
443         for (x=0; x < (ssize_t) image->columns; x++)
444         {
445           if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
446             SetPixelRed(frame_image,GetPixelRed(image,p),q);
447           if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
448             SetPixelGreen(frame_image,GetPixelGreen(image,p),q);
449           if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
450             SetPixelBlue(frame_image,GetPixelBlue(image,p),q);
451           if ((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0)
452             SetPixelBlack(frame_image,GetPixelBlack(image,p),q);
453           if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
454             SetPixelAlpha(frame_image,GetPixelAlpha(image,p),q);
455           p+=GetPixelChannels(image);
456           q+=GetPixelChannels(frame_image);
457         }
458       }
459     for (x=0; x < (ssize_t) frame_info->inner_bevel; x++)
460     {
461       SetPixelInfoPixel(frame_image,&highlight,q);
462       q+=GetPixelChannels(frame_image);
463     }
464     width=frame_info->width-frame_info->x-image->columns-bevel_width;
465     for (x=0; x < (ssize_t) width; x++)
466     {
467       SetPixelInfoPixel(frame_image,&matte,q);
468       q+=GetPixelChannels(frame_image);
469     }
470     for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
471     {
472       SetPixelInfoPixel(frame_image,&shadow,q);
473       q+=GetPixelChannels(frame_image);
474     }
475     if (SyncCacheViewAuthenticPixels(frame_view,exception) == MagickFalse)
476       status=MagickFalse;
477     if (image->progress_monitor != (MagickProgressMonitor) NULL)
478       {
479         MagickBooleanType
480           proceed;
481
482 #if defined(MAGICKCORE_OPENMP_SUPPORT) 
483         #pragma omp critical (MagickCore_FrameImage)
484 #endif
485         proceed=SetImageProgress(image,FrameImageTag,progress++,image->rows);
486         if (proceed == MagickFalse)
487           status=MagickFalse;
488       }
489   }
490   height=(size_t) (frame_info->inner_bevel+frame_info->height-
491     frame_info->y-image->rows-bevel_width+frame_info->outer_bevel);
492   if (height != 0)
493     {
494       register ssize_t
495         x;
496
497       register Quantum
498         *restrict q;
499
500       /*
501         Draw bottom of ornamental border.
502       */
503       q=QueueCacheViewAuthenticPixels(frame_view,0,(ssize_t) (frame_image->rows-
504         height),frame_image->columns,height,exception);
505       if (q != (Quantum *) NULL)
506         {
507           /*
508             Draw bottom of ornamental border.
509           */
510           for (y=frame_info->inner_bevel-1; y >= 0; y--)
511           {
512             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
513             {
514               SetPixelInfoPixel(frame_image,&highlight,q);
515               q+=GetPixelChannels(frame_image);
516             }
517             for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++)
518             {
519               SetPixelInfoPixel(frame_image,&matte,q);
520               q+=GetPixelChannels(frame_image);
521             }
522             for (x=0; x < y; x++)
523             {
524               SetPixelInfoPixel(frame_image,&shadow,q);
525               q+=GetPixelChannels(frame_image);
526             }
527             for ( ; x < (ssize_t) (image->columns+2*frame_info->inner_bevel); x++)
528             {
529               if (x >= (ssize_t) (image->columns+2*frame_info->inner_bevel-y))
530                 SetPixelInfoPixel(frame_image,&highlight,q);
531               else
532                 SetPixelInfoPixel(frame_image,&accentuate,q);
533               q+=GetPixelChannels(frame_image);
534             }
535             width=frame_info->width-frame_info->x-image->columns-bevel_width;
536             for (x=0; x < (ssize_t) width; x++)
537             {
538               SetPixelInfoPixel(frame_image,&matte,q);
539               q+=GetPixelChannels(frame_image);
540             }
541             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
542             {
543               SetPixelInfoPixel(frame_image,&shadow,q);
544               q+=GetPixelChannels(frame_image);
545             }
546           }
547           height=frame_info->height-frame_info->y-image->rows-bevel_width;
548           for (y=0; y < (ssize_t) height; y++)
549           {
550             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
551             {
552               SetPixelInfoPixel(frame_image,&highlight,q);
553               q+=GetPixelChannels(frame_image);
554             }
555             width=frame_image->columns-2*frame_info->outer_bevel;
556             for (x=0; x < (ssize_t) width; x++)
557             {
558               SetPixelInfoPixel(frame_image,&matte,q);
559               q+=GetPixelChannels(frame_image);
560             }
561             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
562             {
563               SetPixelInfoPixel(frame_image,&shadow,q);
564               q+=GetPixelChannels(frame_image);
565             }
566           }
567           for (y=frame_info->outer_bevel-1; y >= 0; y--)
568           {
569             for (x=0; x < y; x++)
570             {
571               SetPixelInfoPixel(frame_image,&highlight,q);
572               q+=GetPixelChannels(frame_image);
573             }
574             for ( ; x < (ssize_t) frame_image->columns; x++)
575             {
576               if (x >= (ssize_t) (frame_image->columns-y))
577                 SetPixelInfoPixel(frame_image,&shadow,q);
578               else
579                 SetPixelInfoPixel(frame_image,&trough,q);
580               q+=GetPixelChannels(frame_image);
581             }
582           }
583           (void) SyncCacheViewAuthenticPixels(frame_view,exception);
584         }
585     }
586   frame_view=DestroyCacheView(frame_view);
587   image_view=DestroyCacheView(image_view);
588   if ((compose != CopyCompositeOp) && ((compose != OverCompositeOp) ||
589       (image->matte != MagickFalse)))
590     {
591       x=(ssize_t) (frame_info->outer_bevel+(frame_info->x-bevel_width)+
592         frame_info->inner_bevel);
593       y=(ssize_t) (frame_info->outer_bevel+(frame_info->y-bevel_width)+
594         frame_info->inner_bevel);
595       (void) CompositeImage(frame_image,compose,image,x,y,exception);
596     }
597   return(frame_image);
598 }
599 \f
600 /*
601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
602 %                                                                             %
603 %                                                                             %
604 %                                                                             %
605 %   R a i s e I m a g e                                                       %
606 %                                                                             %
607 %                                                                             %
608 %                                                                             %
609 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
610 %
611 %  RaiseImage() creates a simulated three-dimensional button-like effect
612 %  by lightening and darkening the edges of the image.  Members width and
613 %  height of raise_info define the width of the vertical and horizontal
614 %  edge of the effect.
615 %
616 %  The format of the RaiseImage method is:
617 %
618 %      MagickBooleanType RaiseImage(const Image *image,
619 %        const RectangleInfo *raise_info,const MagickBooleanType raise,
620 %        ExceptionInfo *exception)
621 %
622 %  A description of each parameter follows:
623 %
624 %    o image: the image.
625 %
626 %    o raise_info: Define the width and height of the raise area.
627 %
628 %    o raise: A value other than zero creates a 3-D raise effect,
629 %      otherwise it has a lowered effect.
630 %
631 %    o exception: return any errors or warnings in this structure.
632 %
633 */
634 MagickExport MagickBooleanType RaiseImage(Image *image,
635   const RectangleInfo *raise_info,const MagickBooleanType raise,
636   ExceptionInfo *exception)
637 {
638 #define AccentuateFactor  ScaleCharToQuantum(135)
639 #define HighlightFactor  ScaleCharToQuantum(190)
640 #define ShadowFactor  ScaleCharToQuantum(190)
641 #define RaiseImageTag  "Raise/Image"
642 #define TroughFactor  ScaleCharToQuantum(135)
643
644   CacheView
645     *image_view;
646
647   MagickBooleanType
648     status;
649
650   MagickOffsetType
651     progress;
652
653   Quantum
654     foreground,
655     background;
656
657   ssize_t
658     y;
659
660   assert(image != (Image *) NULL);
661   assert(image->signature == MagickSignature);
662   if (image->debug != MagickFalse)
663     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
664   assert(raise_info != (RectangleInfo *) NULL);
665   if ((image->columns <= (raise_info->width << 1)) ||
666       (image->rows <= (raise_info->height << 1)))
667     ThrowBinaryException(OptionError,"ImageSizeMustExceedBevelWidth",
668       image->filename);
669   foreground=(Quantum) QuantumRange;
670   background=(Quantum) 0;
671   if (raise == MagickFalse)
672     {
673       foreground=(Quantum) 0;
674       background=(Quantum) QuantumRange;
675     }
676   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
677     return(MagickFalse);
678   /*
679     Raise image.
680   */
681   status=MagickTrue;
682   progress=0;
683   image_view=AcquireCacheView(image);
684 #if defined(MAGICKCORE_OPENMP_SUPPORT) 
685   #pragma omp parallel for schedule(static) shared(progress,status)
686 #endif
687   for (y=0; y < (ssize_t) raise_info->height; y++)
688   {
689     register ssize_t
690       i,
691       x;
692
693     register Quantum
694       *restrict q;
695
696     if (status == MagickFalse)
697       continue;
698     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
699     if (q == (Quantum *) NULL)
700       {
701         status=MagickFalse;
702         continue;
703       }
704     for (x=0; x < y; x++)
705     {
706       if (GetPixelMask(image,q) != 0)
707         {
708           q+=GetPixelChannels(image);
709           continue;
710         }
711       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
712       {
713         PixelChannel
714           channel;
715
716         PixelTrait
717           traits;
718
719         channel=GetPixelChannelMapChannel(image,i);
720         traits=GetPixelChannelMapTraits(image,channel);
721         if ((traits & UpdatePixelTrait) == 0)
722           continue;
723         q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*HighlightFactor+
724           (MagickRealType) foreground*(QuantumRange-HighlightFactor)));
725       }
726       q+=GetPixelChannels(image);
727     }
728     for ( ; x < (ssize_t) (image->columns-y); x++)
729     {
730       if (GetPixelMask(image,q) != 0)
731         {
732           q+=GetPixelChannels(image);
733           continue;
734         }
735       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
736       {
737         PixelChannel
738           channel;
739
740         PixelTrait
741           traits;
742
743         channel=GetPixelChannelMapChannel(image,i);
744         traits=GetPixelChannelMapTraits(image,channel);
745         if ((traits & UpdatePixelTrait) == 0)
746           continue;
747         q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*
748           AccentuateFactor+(MagickRealType) foreground*(QuantumRange-
749           AccentuateFactor)));
750       }
751       q+=GetPixelChannels(image);
752     }
753     for ( ; x < (ssize_t) image->columns; x++)
754     {
755       if (GetPixelMask(image,q) != 0)
756         {
757           q+=GetPixelChannels(image);
758           continue;
759         }
760       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
761       {
762         PixelChannel
763           channel;
764
765         PixelTrait
766           traits;
767
768         channel=GetPixelChannelMapChannel(image,i);
769         traits=GetPixelChannelMapTraits(image,channel);
770         if ((traits & UpdatePixelTrait) == 0)
771           continue;
772         q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*ShadowFactor+
773           (MagickRealType) background*(QuantumRange-ShadowFactor)));
774       }
775       q+=GetPixelChannels(image);
776     }
777     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
778       status=MagickFalse;
779     if (image->progress_monitor != (MagickProgressMonitor) NULL)
780       {
781         MagickBooleanType
782           proceed;
783
784         proceed=SetImageProgress(image,RaiseImageTag,progress++,image->rows);
785         if (proceed == MagickFalse)
786           status=MagickFalse;
787       }
788   }
789 #if defined(MAGICKCORE_OPENMP_SUPPORT)
790   #pragma omp parallel for schedule(static) shared(progress,status)
791 #endif
792   for (y=(ssize_t) raise_info->height; y < (ssize_t) (image->rows-raise_info->height); y++)
793   {
794     register ssize_t
795       i,
796       x;
797
798     register Quantum
799       *restrict q;
800
801     if (status == MagickFalse)
802       continue;
803     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
804     if (q == (Quantum *) NULL)
805       {
806         status=MagickFalse;
807         continue;
808       }
809     for (x=0; x < (ssize_t) raise_info->width; x++)
810     {
811       if (GetPixelMask(image,q) != 0)
812         {
813           q+=GetPixelChannels(image);
814           continue;
815         }
816       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
817       {
818         PixelChannel
819           channel;
820
821         PixelTrait
822           traits;
823
824         channel=GetPixelChannelMapChannel(image,i);
825         traits=GetPixelChannelMapTraits(image,channel);
826         if ((traits & UpdatePixelTrait) == 0)
827           continue;
828         q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*HighlightFactor+
829           (MagickRealType) foreground*(QuantumRange-HighlightFactor)));
830       }
831       q+=GetPixelChannels(image);
832     }
833     for ( ; x < (ssize_t) (image->columns-raise_info->width); x++)
834       q+=GetPixelChannels(image);
835     for ( ; x < (ssize_t) image->columns; x++)
836     {
837       if (GetPixelMask(image,q) != 0)
838         {
839           q+=GetPixelChannels(image);
840           continue;
841         }
842       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
843       {
844         PixelChannel
845           channel;
846
847         PixelTrait
848           traits;
849
850         channel=GetPixelChannelMapChannel(image,i);
851         traits=GetPixelChannelMapTraits(image,channel);
852         if ((traits & UpdatePixelTrait) == 0)
853           continue;
854         q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*ShadowFactor+
855           (MagickRealType) background*(QuantumRange-ShadowFactor)));
856       }
857       q+=GetPixelChannels(image);
858     }
859     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
860       status=MagickFalse;
861     if (image->progress_monitor != (MagickProgressMonitor) NULL)
862       {
863         MagickBooleanType
864           proceed;
865
866         proceed=SetImageProgress(image,RaiseImageTag,progress++,image->rows);
867         if (proceed == MagickFalse)
868           status=MagickFalse;
869       }
870   }
871 #if defined(MAGICKCORE_OPENMP_SUPPORT) 
872   #pragma omp parallel for schedule(static) shared(progress,status)
873 #endif
874   for (y=(ssize_t) (image->rows-raise_info->height); y < (ssize_t) image->rows; y++)
875   {
876     register ssize_t
877       i,
878       x;
879
880     register Quantum
881       *restrict q;
882
883     if (status == MagickFalse)
884       continue;
885     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
886     if (q == (Quantum *) NULL)
887       {
888         status=MagickFalse;
889         continue;
890       }
891     for (x=0; x < (ssize_t) (image->rows-y); x++)
892     {
893       if (GetPixelMask(image,q) != 0)
894         {
895           q+=GetPixelChannels(image);
896           continue;
897         }
898       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
899       {
900         PixelChannel
901           channel;
902
903         PixelTrait
904           traits;
905
906         channel=GetPixelChannelMapChannel(image,i);
907         traits=GetPixelChannelMapTraits(image,channel);
908         if ((traits & UpdatePixelTrait) == 0)
909           continue;
910         q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*HighlightFactor+
911           (MagickRealType) foreground*(QuantumRange-HighlightFactor)));
912       }
913       q+=GetPixelChannels(image);
914     }
915     for ( ; x < (ssize_t) (image->columns-(image->rows-y)); x++)
916     {
917       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
918       {
919         PixelChannel
920           channel;
921
922         PixelTrait
923           traits;
924
925         channel=GetPixelChannelMapChannel(image,i);
926         traits=GetPixelChannelMapTraits(image,channel);
927         if ((traits & UpdatePixelTrait) == 0)
928           continue;
929         q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*TroughFactor+
930           (MagickRealType) background*(QuantumRange-TroughFactor)));
931       }
932       q+=GetPixelChannels(image);
933     }
934     for ( ; x < (ssize_t) image->columns; x++)
935     {
936       if (GetPixelMask(image,q) != 0)
937         {
938           q+=GetPixelChannels(image);
939           continue;
940         }
941       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
942       {
943         PixelChannel
944           channel;
945
946         PixelTrait
947           traits;
948
949         channel=GetPixelChannelMapChannel(image,i);
950         traits=GetPixelChannelMapTraits(image,channel);
951         if ((traits & UpdatePixelTrait) == 0)
952           continue;
953         q[i]=ClampToQuantum(QuantumScale*((MagickRealType) q[i]*ShadowFactor+
954           (MagickRealType) background*(QuantumRange-ShadowFactor)));
955       }
956       q+=GetPixelChannels(image);
957     }
958     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
959       status=MagickFalse;
960     if (image->progress_monitor != (MagickProgressMonitor) NULL)
961       {
962         MagickBooleanType
963           proceed;
964
965 #if defined(MAGICKCORE_OPENMP_SUPPORT)
966         #pragma omp critical (MagickCore_RaiseImage)
967 #endif
968         proceed=SetImageProgress(image,RaiseImageTag,progress++,image->rows);
969         if (proceed == MagickFalse)
970           status=MagickFalse;
971       }
972   }
973   image_view=DestroyCacheView(image_view);
974   return(status);
975 }