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