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