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