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