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