]> granicus.if.org Git - imagemagick/blob - MagickCore/decorate.c
Must support -mattecolor option for IMv6 compatibility.
[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 %                                     Cristy                                  %
17 %                                   July 1992                                 %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2017 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 == MagickCoreSignature);
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     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 == MagickCoreSignature);
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   x=(ssize_t) frame_info->width-frame_info->x-bevel_width;
217   y=(ssize_t) frame_info->height-frame_info->y-bevel_width;
218   if ((x < (ssize_t) image->columns) |  (y < (ssize_t) 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 ((IsPixelInfoGray(&frame_image->border_color) == MagickFalse) &&
233       (IsGrayColorspace(frame_image->colorspace) != MagickFalse))
234     (void) SetImageColorspace(frame_image,sRGBColorspace,exception);
235   if ((frame_image->matte_color.alpha_trait != UndefinedPixelTrait) &&
236       (frame_image->alpha_trait == UndefinedPixelTrait))
237     (void) SetImageAlpha(frame_image,OpaqueAlpha,exception);
238   frame_image->page=image->page;
239   if ((image->page.width != 0) && (image->page.height != 0))
240     {
241       frame_image->page.width+=frame_image->columns-image->columns;
242       frame_image->page.height+=frame_image->rows-image->rows;
243     }
244   /*
245     Initialize 3D effects color.
246   */
247   matte=image->matte_color;
248   accentuate=matte;
249   accentuate.red=(double) (QuantumScale*((QuantumRange-
250     AccentuateModulate)*matte.red+(QuantumRange*AccentuateModulate)));
251   accentuate.green=(double) (QuantumScale*((QuantumRange-
252     AccentuateModulate)*matte.green+(QuantumRange*AccentuateModulate)));
253   accentuate.blue=(double) (QuantumScale*((QuantumRange-
254     AccentuateModulate)*matte.blue+(QuantumRange*AccentuateModulate)));
255   accentuate.black=(double) (QuantumScale*((QuantumRange-
256     AccentuateModulate)*matte.black+(QuantumRange*AccentuateModulate)));
257   accentuate.alpha=matte.alpha;
258   highlight=matte;
259   highlight.red=(double) (QuantumScale*((QuantumRange-
260     HighlightModulate)*matte.red+(QuantumRange*HighlightModulate)));
261   highlight.green=(double) (QuantumScale*((QuantumRange-
262     HighlightModulate)*matte.green+(QuantumRange*HighlightModulate)));
263   highlight.blue=(double) (QuantumScale*((QuantumRange-
264     HighlightModulate)*matte.blue+(QuantumRange*HighlightModulate)));
265   highlight.black=(double) (QuantumScale*((QuantumRange-
266     HighlightModulate)*matte.black+(QuantumRange*HighlightModulate)));
267   highlight.alpha=matte.alpha;
268   shadow=matte;
269   shadow.red=QuantumScale*matte.red*ShadowModulate;
270   shadow.green=QuantumScale*matte.green*ShadowModulate;
271   shadow.blue=QuantumScale*matte.blue*ShadowModulate;
272   shadow.black=QuantumScale*matte.black*ShadowModulate;
273   shadow.alpha=matte.alpha;
274   trough=matte;
275   trough.red=QuantumScale*matte.red*TroughModulate;
276   trough.green=QuantumScale*matte.green*TroughModulate;
277   trough.blue=QuantumScale*matte.blue*TroughModulate;
278   trough.black=QuantumScale*matte.black*TroughModulate;
279   trough.alpha=matte.alpha;
280   status=MagickTrue;
281   progress=0;
282   image_view=AcquireVirtualCacheView(image,exception);
283   frame_view=AcquireAuthenticCacheView(frame_image,exception);
284   height=(size_t) (frame_info->outer_bevel+(frame_info->y-bevel_width)+
285     frame_info->inner_bevel);
286   if (height != 0)
287     {
288       register ssize_t
289         x;
290
291       register Quantum
292         *magick_restrict q;
293
294       /*
295         Draw top of ornamental border.
296       */
297       q=QueueCacheViewAuthenticPixels(frame_view,0,0,frame_image->columns,
298         height,exception);
299       if (q != (Quantum *) NULL)
300         {
301           /*
302             Draw top of ornamental border.
303           */
304           for (y=0; y < (ssize_t) frame_info->outer_bevel; y++)
305           {
306             for (x=0; x < (ssize_t) (frame_image->columns-y); x++)
307             {
308               if (x < y)
309                 SetPixelViaPixelInfo(frame_image,&highlight,q);
310               else
311                 SetPixelViaPixelInfo(frame_image,&accentuate,q);
312               q+=GetPixelChannels(frame_image);
313             }
314             for ( ; x < (ssize_t) frame_image->columns; x++)
315             {
316               SetPixelViaPixelInfo(frame_image,&shadow,q);
317               q+=GetPixelChannels(frame_image);
318             }
319           }
320           for (y=0; y < (ssize_t) (frame_info->y-bevel_width); y++)
321           {
322             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
323             {
324               SetPixelViaPixelInfo(frame_image,&highlight,q);
325               q+=GetPixelChannels(frame_image);
326             }
327             width=frame_image->columns-2*frame_info->outer_bevel;
328             for (x=0; x < (ssize_t) width; x++)
329             {
330               SetPixelViaPixelInfo(frame_image,&matte,q);
331               q+=GetPixelChannels(frame_image);
332             }
333             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
334             {
335               SetPixelViaPixelInfo(frame_image,&shadow,q);
336               q+=GetPixelChannels(frame_image);
337             }
338           }
339           for (y=0; y < (ssize_t) frame_info->inner_bevel; y++)
340           {
341             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
342             {
343               SetPixelViaPixelInfo(frame_image,&highlight,q);
344               q+=GetPixelChannels(frame_image);
345             }
346             for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++)
347             {
348               SetPixelViaPixelInfo(frame_image,&matte,q);
349               q+=GetPixelChannels(frame_image);
350             }
351             width=image->columns+((size_t) frame_info->inner_bevel << 1)-
352               y;
353             for (x=0; x < (ssize_t) width; x++)
354             {
355               if (x < y)
356                 SetPixelViaPixelInfo(frame_image,&shadow,q);
357               else
358                 SetPixelViaPixelInfo(frame_image,&trough,q);
359               q+=GetPixelChannels(frame_image);
360             }
361             for ( ; x < (ssize_t) (image->columns+2*frame_info->inner_bevel); x++)
362             {
363               SetPixelViaPixelInfo(frame_image,&highlight,q);
364               q+=GetPixelChannels(frame_image);
365             }
366             width=frame_info->width-frame_info->x-image->columns-bevel_width;
367             for (x=0; x < (ssize_t) width; x++)
368             {
369               SetPixelViaPixelInfo(frame_image,&matte,q);
370               q+=GetPixelChannels(frame_image);
371             }
372             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
373             {
374               SetPixelViaPixelInfo(frame_image,&shadow,q);
375               q+=GetPixelChannels(frame_image);
376             }
377           }
378           (void) SyncCacheViewAuthenticPixels(frame_view,exception);
379         }
380     }
381   /*
382     Draw sides of ornamental border.
383   */
384 #if defined(MAGICKCORE_OPENMP_SUPPORT)
385   #pragma omp parallel for schedule(static,4) shared(progress,status) \
386     magick_threads(image,frame_image,1,1)
387 #endif
388   for (y=0; y < (ssize_t) image->rows; y++)
389   {
390     register ssize_t
391       x;
392
393     register Quantum
394       *magick_restrict q;
395
396     size_t
397       width;
398
399     /*
400       Initialize scanline with matte color.
401     */
402     if (status == MagickFalse)
403       continue;
404     q=QueueCacheViewAuthenticPixels(frame_view,0,frame_info->y+y,
405       frame_image->columns,1,exception);
406     if (q == (Quantum *) NULL)
407       {
408         status=MagickFalse;
409         continue;
410       }
411     for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
412     {
413       SetPixelViaPixelInfo(frame_image,&highlight,q);
414       q+=GetPixelChannels(frame_image);
415     }
416     for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++)
417     {
418       SetPixelViaPixelInfo(frame_image,&matte,q);
419       q+=GetPixelChannels(frame_image);
420     }
421     for (x=0; x < (ssize_t) frame_info->inner_bevel; x++)
422     {
423       SetPixelViaPixelInfo(frame_image,&shadow,q);
424       q+=GetPixelChannels(frame_image);
425     }
426     /*
427       Set frame interior pixels.
428     */
429     {
430       register const Quantum
431         *p;
432
433       p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
434       if (p == (const Quantum *) NULL)
435         {
436           status=MagickFalse;
437           continue;
438         }
439       for (x=0; x < (ssize_t) image->columns; x++)
440       {
441         register ssize_t
442           i;
443
444         if (GetPixelWriteMask(image,q) == 0)
445           {
446             SetPixelBackgoundColor(frame_image,q);
447             p+=GetPixelChannels(image);
448             q+=GetPixelChannels(frame_image);
449             continue;
450           }
451         for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
452         {
453           PixelChannel channel=GetPixelChannelChannel(image,i);
454           PixelTrait traits=GetPixelChannelTraits(image,channel);
455           PixelTrait frame_traits=GetPixelChannelTraits(frame_image,channel);
456           if ((traits == UndefinedPixelTrait) ||
457               (frame_traits == UndefinedPixelTrait))
458             continue;
459           SetPixelChannel(frame_image,channel,p[i],q);
460         }
461         SetPixelRed(frame_image,GetPixelRed(image,p),q);
462         SetPixelGreen(frame_image,GetPixelGreen(image,p),q);
463         SetPixelBlue(frame_image,GetPixelBlue(image,p),q);
464         SetPixelAlpha(frame_image,GetPixelAlpha(image,p),q);
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       SetPixelViaPixelInfo(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       SetPixelViaPixelInfo(frame_image,&matte,q);
478       q+=GetPixelChannels(frame_image);
479     }
480     for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
481     {
482       SetPixelViaPixelInfo(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         *magick_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               SetPixelViaPixelInfo(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               SetPixelViaPixelInfo(frame_image,&matte,q);
530               q+=GetPixelChannels(frame_image);
531             }
532             for (x=0; x < y; x++)
533             {
534               SetPixelViaPixelInfo(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                 SetPixelViaPixelInfo(frame_image,&highlight,q);
541               else
542                 SetPixelViaPixelInfo(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               SetPixelViaPixelInfo(frame_image,&matte,q);
549               q+=GetPixelChannels(frame_image);
550             }
551             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
552             {
553               SetPixelViaPixelInfo(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               SetPixelViaPixelInfo(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               SetPixelViaPixelInfo(frame_image,&matte,q);
569               q+=GetPixelChannels(frame_image);
570             }
571             for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
572             {
573               SetPixelViaPixelInfo(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               SetPixelViaPixelInfo(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                 SetPixelViaPixelInfo(frame_image,&shadow,q);
588               else
589                 SetPixelViaPixelInfo(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   x=(ssize_t) (frame_info->outer_bevel+(frame_info->x-bevel_width)+
599     frame_info->inner_bevel);
600   y=(ssize_t) (frame_info->outer_bevel+(frame_info->y-bevel_width)+
601     frame_info->inner_bevel);
602   if (status != MagickFalse)
603     status=CompositeImage(frame_image,image,compose,MagickTrue,x,y,
604       exception);
605   if (status == MagickFalse)
606     frame_image=DestroyImage(frame_image);
607   return(frame_image);
608 }
609 \f
610 /*
611 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
612 %                                                                             %
613 %                                                                             %
614 %                                                                             %
615 %   R a i s e I m a g e                                                       %
616 %                                                                             %
617 %                                                                             %
618 %                                                                             %
619 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
620 %
621 %  RaiseImage() creates a simulated three-dimensional button-like effect
622 %  by lightening and darkening the edges of the image.  Members width and
623 %  height of raise_info define the width of the vertical and horizontal
624 %  edge of the effect.
625 %
626 %  The format of the RaiseImage method is:
627 %
628 %      MagickBooleanType RaiseImage(const Image *image,
629 %        const RectangleInfo *raise_info,const MagickBooleanType raise,
630 %        ExceptionInfo *exception)
631 %
632 %  A description of each parameter follows:
633 %
634 %    o image: the image.
635 %
636 %    o raise_info: Define the width and height of the raise area.
637 %
638 %    o raise: A value other than zero creates a 3-D raise effect,
639 %      otherwise it has a lowered effect.
640 %
641 %    o exception: return any errors or warnings in this structure.
642 %
643 */
644 MagickExport MagickBooleanType RaiseImage(Image *image,
645   const RectangleInfo *raise_info,const MagickBooleanType raise,
646   ExceptionInfo *exception)
647 {
648 #define AccentuateFactor  ScaleCharToQuantum(135)
649 #define HighlightFactor  ScaleCharToQuantum(190)
650 #define ShadowFactor  ScaleCharToQuantum(190)
651 #define RaiseImageTag  "Raise/Image"
652 #define TroughFactor  ScaleCharToQuantum(135)
653
654   CacheView
655     *image_view;
656
657   MagickBooleanType
658     status;
659
660   MagickOffsetType
661     progress;
662
663   Quantum
664     foreground,
665     background;
666
667   ssize_t
668     y;
669
670   assert(image != (Image *) NULL);
671   assert(image->signature == MagickCoreSignature);
672   if (image->debug != MagickFalse)
673     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
674   assert(raise_info != (RectangleInfo *) NULL);
675   if ((image->columns <= (raise_info->width << 1)) ||
676       (image->rows <= (raise_info->height << 1)))
677     ThrowBinaryException(OptionError,"ImageSizeMustExceedBevelWidth",
678       image->filename);
679   foreground=QuantumRange;
680   background=(Quantum) 0;
681   if (raise == MagickFalse)
682     {
683       foreground=(Quantum) 0;
684       background=QuantumRange;
685     }
686   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
687     return(MagickFalse);
688   /*
689     Raise image.
690   */
691   status=MagickTrue;
692   progress=0;
693   image_view=AcquireAuthenticCacheView(image,exception);
694 #if defined(MAGICKCORE_OPENMP_SUPPORT)
695   #pragma omp parallel for schedule(static,4) shared(progress,status) \
696     magick_threads(image,image,1,1)
697 #endif
698   for (y=0; y < (ssize_t) raise_info->height; y++)
699   {
700     register ssize_t
701       i,
702       x;
703
704     register Quantum
705       *magick_restrict q;
706
707     if (status == MagickFalse)
708       continue;
709     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
710     if (q == (Quantum *) NULL)
711       {
712         status=MagickFalse;
713         continue;
714       }
715     for (x=0; x < y; x++)
716     {
717       if (GetPixelWriteMask(image,q) == 0)
718         {
719           q+=GetPixelChannels(image);
720           continue;
721         }
722       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
723       {
724         PixelChannel channel=GetPixelChannelChannel(image,i);
725         PixelTrait traits=GetPixelChannelTraits(image,channel);
726         if ((traits & UpdatePixelTrait) == 0)
727           continue;
728         q[i]=ClampToQuantum(QuantumScale*((double) q[i]*HighlightFactor+(double)
729           foreground*(QuantumRange-HighlightFactor)));
730       }
731       q+=GetPixelChannels(image);
732     }
733     for ( ; x < (ssize_t) (image->columns-y); x++)
734     {
735       if (GetPixelWriteMask(image,q) == 0)
736         {
737           q+=GetPixelChannels(image);
738           continue;
739         }
740       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
741       {
742         PixelChannel channel=GetPixelChannelChannel(image,i);
743         PixelTrait traits=GetPixelChannelTraits(image,channel);
744         if ((traits & UpdatePixelTrait) == 0)
745           continue;
746         q[i]=ClampToQuantum(QuantumScale*((double) q[i]*AccentuateFactor+
747           (double) foreground*(QuantumRange-AccentuateFactor)));
748       }
749       q+=GetPixelChannels(image);
750     }
751     for ( ; x < (ssize_t) image->columns; x++)
752     {
753       if (GetPixelWriteMask(image,q) == 0)
754         {
755           q+=GetPixelChannels(image);
756           continue;
757         }
758       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
759       {
760         PixelChannel channel=GetPixelChannelChannel(image,i);
761         PixelTrait traits=GetPixelChannelTraits(image,channel);
762         if ((traits & UpdatePixelTrait) == 0)
763           continue;
764         q[i]=ClampToQuantum(QuantumScale*((double) q[i]*ShadowFactor+(double)
765           background*(QuantumRange-ShadowFactor)));
766       }
767       q+=GetPixelChannels(image);
768     }
769     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
770       status=MagickFalse;
771     if (image->progress_monitor != (MagickProgressMonitor) NULL)
772       {
773         MagickBooleanType
774           proceed;
775
776 #if defined(MAGICKCORE_OPENMP_SUPPORT)
777         #pragma omp critical (MagickCore_RaiseImage)
778 #endif
779         proceed=SetImageProgress(image,RaiseImageTag,progress++,image->rows);
780         if (proceed == MagickFalse)
781           status=MagickFalse;
782       }
783   }
784 #if defined(MAGICKCORE_OPENMP_SUPPORT)
785   #pragma omp parallel for schedule(static,4) shared(progress,status) \
786     magick_threads(image,image,1,1)
787 #endif
788   for (y=(ssize_t) raise_info->height; y < (ssize_t) (image->rows-raise_info->height); y++)
789   {
790     register ssize_t
791       i,
792       x;
793
794     register Quantum
795       *magick_restrict q;
796
797     if (status == MagickFalse)
798       continue;
799     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
800     if (q == (Quantum *) NULL)
801       {
802         status=MagickFalse;
803         continue;
804       }
805     for (x=0; x < (ssize_t) raise_info->width; x++)
806     {
807       if (GetPixelWriteMask(image,q) == 0)
808         {
809           q+=GetPixelChannels(image);
810           continue;
811         }
812       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
813       {
814         PixelChannel channel=GetPixelChannelChannel(image,i);
815         PixelTrait traits=GetPixelChannelTraits(image,channel);
816         if ((traits & UpdatePixelTrait) == 0)
817           continue;
818         q[i]=ClampToQuantum(QuantumScale*((double) q[i]*HighlightFactor+(double)
819           foreground*(QuantumRange-HighlightFactor)));
820       }
821       q+=GetPixelChannels(image);
822     }
823     for ( ; x < (ssize_t) (image->columns-raise_info->width); x++)
824       q+=GetPixelChannels(image);
825     for ( ; x < (ssize_t) image->columns; x++)
826     {
827       if (GetPixelWriteMask(image,q) == 0)
828         {
829           q+=GetPixelChannels(image);
830           continue;
831         }
832       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
833       {
834         PixelChannel channel=GetPixelChannelChannel(image,i);
835         PixelTrait traits=GetPixelChannelTraits(image,channel);
836         if ((traits & UpdatePixelTrait) == 0)
837           continue;
838         q[i]=ClampToQuantum(QuantumScale*((double) q[i]*ShadowFactor+(double)
839           background*(QuantumRange-ShadowFactor)));
840       }
841       q+=GetPixelChannels(image);
842     }
843     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
844       status=MagickFalse;
845     if (image->progress_monitor != (MagickProgressMonitor) NULL)
846       {
847         MagickBooleanType
848           proceed;
849
850 #if defined(MAGICKCORE_OPENMP_SUPPORT)
851         #pragma omp critical (MagickCore_RaiseImage)
852 #endif
853         proceed=SetImageProgress(image,RaiseImageTag,progress++,image->rows);
854         if (proceed == MagickFalse)
855           status=MagickFalse;
856       }
857   }
858 #if defined(MAGICKCORE_OPENMP_SUPPORT)
859   #pragma omp parallel for schedule(static,4) shared(progress,status) \
860     magick_threads(image,image,1,1)
861 #endif
862   for (y=(ssize_t) (image->rows-raise_info->height); y < (ssize_t) image->rows; y++)
863   {
864     register ssize_t
865       i,
866       x;
867
868     register Quantum
869       *magick_restrict q;
870
871     if (status == MagickFalse)
872       continue;
873     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
874     if (q == (Quantum *) NULL)
875       {
876         status=MagickFalse;
877         continue;
878       }
879     for (x=0; x < (ssize_t) (image->rows-y); x++)
880     {
881       if (GetPixelWriteMask(image,q) == 0)
882         {
883           q+=GetPixelChannels(image);
884           continue;
885         }
886       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
887       {
888         PixelChannel channel=GetPixelChannelChannel(image,i);
889         PixelTrait traits=GetPixelChannelTraits(image,channel);
890         if ((traits & UpdatePixelTrait) == 0)
891           continue;
892         q[i]=ClampToQuantum(QuantumScale*((double) q[i]*HighlightFactor+(double)
893           foreground*(QuantumRange-HighlightFactor)));
894       }
895       q+=GetPixelChannels(image);
896     }
897     for ( ; x < (ssize_t) (image->columns-(image->rows-y)); x++)
898     {
899       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
900       {
901         PixelChannel channel=GetPixelChannelChannel(image,i);
902         PixelTrait traits=GetPixelChannelTraits(image,channel);
903         if ((traits & UpdatePixelTrait) == 0)
904           continue;
905         q[i]=ClampToQuantum(QuantumScale*((double) q[i]*TroughFactor+
906           (double) background*(QuantumRange-TroughFactor)));
907       }
908       q+=GetPixelChannels(image);
909     }
910     for ( ; x < (ssize_t) image->columns; x++)
911     {
912       if (GetPixelWriteMask(image,q) == 0)
913         {
914           q+=GetPixelChannels(image);
915           continue;
916         }
917       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
918       {
919         PixelChannel channel=GetPixelChannelChannel(image,i);
920         PixelTrait traits=GetPixelChannelTraits(image,channel);
921         if ((traits & UpdatePixelTrait) == 0)
922           continue;
923         q[i]=ClampToQuantum(QuantumScale*((double) q[i]*ShadowFactor+(double)
924           background*(QuantumRange-ShadowFactor)));
925       }
926       q+=GetPixelChannels(image);
927     }
928     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
929       status=MagickFalse;
930     if (image->progress_monitor != (MagickProgressMonitor) NULL)
931       {
932         MagickBooleanType
933           proceed;
934
935 #if defined(MAGICKCORE_OPENMP_SUPPORT)
936         #pragma omp critical (MagickCore_RaiseImage)
937 #endif
938         proceed=SetImageProgress(image,RaiseImageTag,progress++,image->rows);
939         if (proceed == MagickFalse)
940           status=MagickFalse;
941       }
942   }
943   image_view=DestroyCacheView(image_view);
944   return(status);
945 }