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