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