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