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