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