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