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