Home | History | Annotate | Download | only in MagickCore
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %        CCCC   OOO   M   M  PPPP    OOO   SSSSS  IIIII  TTTTT  EEEEE         %
      7 %       C      O   O  MM MM  P   P  O   O  SS       I      T    E             %
      8 %       C      O   O  M M M  PPPP   O   O   SSS     I      T    EEE           %
      9 %       C      O   O  M   M  P      O   O     SS    I      T    E             %
     10 %        CCCC   OOO   M   M  P       OOO   SSSSS  IIIII    T    EEEEE         %
     11 %                                                                             %
     12 %                                                                             %
     13 %                     MagickCore Image Composite 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/artifact.h"
     46 #include "MagickCore/cache.h"
     47 #include "MagickCore/cache-private.h"
     48 #include "MagickCore/cache-view.h"
     49 #include "MagickCore/channel.h"
     50 #include "MagickCore/client.h"
     51 #include "MagickCore/color.h"
     52 #include "MagickCore/color-private.h"
     53 #include "MagickCore/colorspace.h"
     54 #include "MagickCore/colorspace-private.h"
     55 #include "MagickCore/composite.h"
     56 #include "MagickCore/composite-private.h"
     57 #include "MagickCore/constitute.h"
     58 #include "MagickCore/draw.h"
     59 #include "MagickCore/fx.h"
     60 #include "MagickCore/gem.h"
     61 #include "MagickCore/geometry.h"
     62 #include "MagickCore/image.h"
     63 #include "MagickCore/image-private.h"
     64 #include "MagickCore/list.h"
     65 #include "MagickCore/log.h"
     66 #include "MagickCore/monitor.h"
     67 #include "MagickCore/monitor-private.h"
     68 #include "MagickCore/memory_.h"
     69 #include "MagickCore/option.h"
     70 #include "MagickCore/pixel-accessor.h"
     71 #include "MagickCore/property.h"
     72 #include "MagickCore/quantum.h"
     73 #include "MagickCore/resample.h"
     74 #include "MagickCore/resource_.h"
     75 #include "MagickCore/string_.h"
     76 #include "MagickCore/thread-private.h"
     77 #include "MagickCore/threshold.h"
     78 #include "MagickCore/token.h"
     79 #include "MagickCore/utility.h"
     80 #include "MagickCore/utility-private.h"
     81 #include "MagickCore/version.h"
     82 
     83 /*
     85 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     86 %                                                                             %
     87 %                                                                             %
     88 %                                                                             %
     89 %   C o m p o s i t e I m a g e                                               %
     90 %                                                                             %
     91 %                                                                             %
     92 %                                                                             %
     93 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     94 %
     95 %  CompositeImage() returns the second image composited onto the first
     96 %  at the specified offset, using the specified composite method.
     97 %
     98 %  The format of the CompositeImage method is:
     99 %
    100 %      MagickBooleanType CompositeImage(Image *image,
    101 %        const Image *source_image,const CompositeOperator compose,
    102 %        const MagickBooleanType clip_to_self,const ssize_t x_offset,
    103 %        const ssize_t y_offset,ExceptionInfo *exception)
    104 %
    105 %  A description of each parameter follows:
    106 %
    107 %    o image: the canvas image, modified by he composition
    108 %
    109 %    o source_image: the source image.
    110 %
    111 %    o compose: This operator affects how the composite is applied to
    112 %      the image.  The operators and how they are utilized are listed here
    113 %      http://www.w3.org/TR/SVG12/#compositing.
    114 %
    115 %    o clip_to_self: set to MagickTrue to limit composition to area composed.
    116 %
    117 %    o x_offset: the column offset of the composited image.
    118 %
    119 %    o y_offset: the row offset of the composited image.
    120 %
    121 %  Extra Controls from Image meta-data in 'image' (artifacts)
    122 %
    123 %    o "compose:args"
    124 %        A string containing extra numerical arguments for specific compose
    125 %        methods, generally expressed as a 'geometry' or a comma separated list
    126 %        of numbers.
    127 %
    128 %        Compose methods needing such arguments include "BlendCompositeOp" and
    129 %        "DisplaceCompositeOp".
    130 %
    131 %    o exception: return any errors or warnings in this structure.
    132 %
    133 */
    134 
    135 /*
    136    Composition based on the SVG specification:
    137 
    138    A Composition is defined by...
    139       Color Function :  f(Sc,Dc)  where Sc and Dc are the normizalized colors
    140       Blending areas :  X = 1     for area of overlap, ie: f(Sc,Dc)
    141                         Y = 1     for source preserved
    142                         Z = 1     for canvas preserved
    143 
    144    Conversion to transparency (then optimized)
    145       Dca' = f(Sc, Dc)*Sa*Da + Y*Sca*(1-Da) + Z*Dca*(1-Sa)
    146       Da'  = X*Sa*Da + Y*Sa*(1-Da) + Z*Da*(1-Sa)
    147 
    148    Where...
    149       Sca = Sc*Sa     normalized Source color divided by Source alpha
    150       Dca = Dc*Da     normalized Dest color divided by Dest alpha
    151       Dc' = Dca'/Da'  the desired color value for this channel.
    152 
    153    Da' in in the follow formula as 'gamma'  The resulting alpla value.
    154 
    155    Most functions use a blending mode of over (X=1,Y=1,Z=1) this results in
    156    the following optimizations...
    157       gamma = Sa+Da-Sa*Da;
    158       gamma = 1 - QuantiumScale*alpha * QuantiumScale*beta;
    159       opacity = QuantiumScale*alpha*beta;  // over blend, optimized 1-Gamma
    160 
    161    The above SVG definitions also definate that Mathematical Composition
    162    methods should use a 'Over' blending mode for Alpha Channel.
    163    It however was not applied for composition modes of 'Plus', 'Minus',
    164    the modulus versions of 'Add' and 'Subtract'.
    165 
    166    Mathematical operator changes to be applied from IM v6.7...
    167 
    168     1) Modulus modes 'Add' and 'Subtract' are obsoleted and renamed
    169        'ModulusAdd' and 'ModulusSubtract' for clarity.
    170 
    171     2) All mathematical compositions work as per the SVG specification
    172        with regard to blending.  This now includes 'ModulusAdd' and
    173        'ModulusSubtract'.
    174 
    175     3) When the special channel flag 'sync' (syncronize channel updates)
    176        is turned off (enabled by default) then mathematical compositions are
    177        only performed on the channels specified, and are applied
    178        independantally of each other.  In other words the mathematics is
    179        performed as 'pure' mathematical operations, rather than as image
    180        operations.
    181 */
    182 
    183 static void HCLComposite(const MagickRealType hue,const MagickRealType chroma,
    184   const MagickRealType luma,MagickRealType *red,MagickRealType *green,
    185   MagickRealType *blue)
    186 {
    187   MagickRealType
    188     b,
    189     c,
    190     g,
    191     h,
    192     m,
    193     r,
    194     x;
    195 
    196   /*
    197     Convert HCL to RGB colorspace.
    198   */
    199   assert(red != (MagickRealType *) NULL);
    200   assert(green != (MagickRealType *) NULL);
    201   assert(blue != (MagickRealType *) NULL);
    202   h=6.0*hue;
    203   c=chroma;
    204   x=c*(1.0-fabs(fmod(h,2.0)-1.0));
    205   r=0.0;
    206   g=0.0;
    207   b=0.0;
    208   if ((0.0 <= h) && (h < 1.0))
    209     {
    210       r=c;
    211       g=x;
    212     }
    213   else
    214     if ((1.0 <= h) && (h < 2.0))
    215       {
    216         r=x;
    217         g=c;
    218       }
    219     else
    220       if ((2.0 <= h) && (h < 3.0))
    221         {
    222           g=c;
    223           b=x;
    224         }
    225       else
    226         if ((3.0 <= h) && (h < 4.0))
    227           {
    228             g=x;
    229             b=c;
    230           }
    231         else
    232           if ((4.0 <= h) && (h < 5.0))
    233             {
    234               r=x;
    235               b=c;
    236             }
    237           else
    238             if ((5.0 <= h) && (h < 6.0))
    239               {
    240                 r=c;
    241                 b=x;
    242               }
    243   m=luma-(0.298839*r+0.586811*g+0.114350*b);
    244   *red=QuantumRange*(r+m);
    245   *green=QuantumRange*(g+m);
    246   *blue=QuantumRange*(b+m);
    247 }
    248 
    249 static void CompositeHCL(const MagickRealType red,const MagickRealType green,
    250   const MagickRealType blue,MagickRealType *hue,MagickRealType *chroma,
    251   MagickRealType *luma)
    252 {
    253   MagickRealType
    254     b,
    255     c,
    256     g,
    257     h,
    258     max,
    259     r;
    260 
    261   /*
    262     Convert RGB to HCL colorspace.
    263   */
    264   assert(hue != (MagickRealType *) NULL);
    265   assert(chroma != (MagickRealType *) NULL);
    266   assert(luma != (MagickRealType *) NULL);
    267   r=red;
    268   g=green;
    269   b=blue;
    270   max=MagickMax(r,MagickMax(g,b));
    271   c=max-(MagickRealType) MagickMin(r,MagickMin(g,b));
    272   h=0.0;
    273   if (c == 0)
    274     h=0.0;
    275   else
    276     if (red == max)
    277       h=fmod((g-b)/c+6.0,6.0);
    278     else
    279       if (green == max)
    280         h=((b-r)/c)+2.0;
    281       else
    282         if (blue == max)
    283           h=((r-g)/c)+4.0;
    284   *hue=(h/6.0);
    285   *chroma=QuantumScale*c;
    286   *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
    287 }
    288 
    289 static MagickBooleanType CompositeOverImage(Image *image,
    290   const Image *source_image,const MagickBooleanType clip_to_self,
    291   const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
    292 {
    293 #define CompositeImageTag  "Composite/Image"
    294 
    295   CacheView
    296     *image_view,
    297     *source_view;
    298 
    299   const char
    300     *value;
    301 
    302   MagickBooleanType
    303     clamp,
    304     status;
    305 
    306   MagickOffsetType
    307     progress;
    308 
    309   ssize_t
    310     y;
    311 
    312   /*
    313     Composite image.
    314   */
    315   status=MagickTrue;
    316   progress=0;
    317   clamp=MagickTrue;
    318   value=GetImageArtifact(image,"compose:clamp");
    319   if (value != (const char *) NULL)
    320     clamp=IsStringTrue(value);
    321   source_view=AcquireVirtualCacheView(source_image,exception);
    322   image_view=AcquireAuthenticCacheView(image,exception);
    323 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    324   #pragma omp parallel for schedule(static,4) shared(progress,status) \
    325     magick_threads(source_image,image,image->rows,1)
    326 #endif
    327   for (y=0; y < (ssize_t) image->rows; y++)
    328   {
    329     const Quantum
    330       *pixels;
    331 
    332     register const Quantum
    333       *magick_restrict p;
    334 
    335     register Quantum
    336       *magick_restrict q;
    337 
    338     register ssize_t
    339       x;
    340 
    341     size_t
    342       channels;
    343 
    344     if (status == MagickFalse)
    345       continue;
    346     if (clip_to_self != MagickFalse)
    347       {
    348         if (y < y_offset)
    349           continue;
    350         if ((y-y_offset) >= (ssize_t) source_image->rows)
    351           continue;
    352       }
    353     /*
    354       If pixels is NULL, y is outside overlay region.
    355     */
    356     pixels=(Quantum *) NULL;
    357     p=(Quantum *) NULL;
    358     if ((y >= y_offset) && ((y-y_offset) < (ssize_t) source_image->rows))
    359       {
    360         p=GetCacheViewVirtualPixels(source_view,0,y-y_offset,
    361           source_image->columns,1,exception);
    362         if (p == (const Quantum *) NULL)
    363           {
    364             status=MagickFalse;
    365             continue;
    366           }
    367         pixels=p;
    368         if (x_offset < 0)
    369           p-=x_offset*GetPixelChannels(source_image);
    370       }
    371     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
    372     if (q == (Quantum *) NULL)
    373       {
    374         status=MagickFalse;
    375         continue;
    376       }
    377     for (x=0; x < (ssize_t) image->columns; x++)
    378     {
    379       MagickRealType
    380         Da,
    381         Dc,
    382         Dca,
    383         gamma,
    384         Sa,
    385         Sc,
    386         Sca;
    387 
    388       register ssize_t
    389         i;
    390 
    391       if (clip_to_self != MagickFalse)
    392         {
    393           if (x < x_offset)
    394             {
    395               q+=GetPixelChannels(image);
    396               continue;
    397             }
    398           if ((x-x_offset) >= (ssize_t) source_image->columns)
    399             break;
    400         }
    401       if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
    402           ((x-x_offset) >= (ssize_t) source_image->columns))
    403         {
    404           Quantum
    405             source[MaxPixelChannels];
    406 
    407           /*
    408             Virtual composite:
    409               Sc: source color.
    410               Dc: canvas color.
    411           */
    412           if (GetPixelReadMask(image,q) == 0)
    413             {
    414               q+=GetPixelChannels(image);
    415               continue;
    416             }
    417           (void) GetOneVirtualPixel(source_image,x-x_offset,y-y_offset,
    418             source,exception);
    419           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
    420           {
    421             PixelChannel channel=GetPixelChannelChannel(image,i);
    422             PixelTrait traits=GetPixelChannelTraits(image,channel);
    423             PixelTrait source_traits=GetPixelChannelTraits(source_image,
    424               channel);
    425             if ((traits == UndefinedPixelTrait) ||
    426                 (source_traits == UndefinedPixelTrait))
    427               continue;
    428             q[i]=source[channel];
    429           }
    430           q+=GetPixelChannels(image);
    431           continue;
    432         }
    433       /*
    434         Authentic composite:
    435           Sa:  normalized source alpha.
    436           Da:  normalized canvas alpha.
    437       */
    438       if (GetPixelReadMask(source_image,p) == 0)
    439         {
    440           p+=GetPixelChannels(source_image);
    441           channels=GetPixelChannels(source_image);
    442           if (p >= (pixels+channels*source_image->columns))
    443             p=pixels;
    444           q+=GetPixelChannels(image);
    445           continue;
    446         }
    447       Sa=QuantumScale*GetPixelAlpha(source_image,p);
    448       Da=QuantumScale*GetPixelAlpha(image,q);
    449       gamma=Sa+Da-Sa*Da;
    450       gamma=PerceptibleReciprocal(gamma);
    451       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
    452       {
    453         PixelChannel channel=GetPixelChannelChannel(image,i);
    454         PixelTrait traits=GetPixelChannelTraits(image,channel);
    455         PixelTrait source_traits=GetPixelChannelTraits(source_image,
    456           channel);
    457         if ((traits == UndefinedPixelTrait) ||
    458             (source_traits == UndefinedPixelTrait))
    459           continue;
    460         if ((traits & CopyPixelTrait) != 0)
    461           {
    462             /*
    463               Copy channel.
    464             */
    465             q[i]=GetPixelChannel(source_image,channel,p);
    466             continue;
    467           }
    468         if (channel == AlphaPixelChannel)
    469           {
    470             /*
    471               Set alpha channel.
    472             */
    473             q[i]=clamp != MagickFalse ?
    474               ClampPixel(QuantumRange*(Sa+Da-Sa*Da)) :
    475               ClampToQuantum(QuantumRange*(Sa+Da-Sa*Da));
    476             continue;
    477           }
    478         /*
    479           Sc: source color.
    480           Dc: canvas color.
    481         */
    482         Sc=(MagickRealType) GetPixelChannel(source_image,channel,p);
    483         Dc=(MagickRealType) q[i];
    484         Sca=QuantumScale*Sa*Sc;
    485         Dca=QuantumScale*Da*Dc;
    486         q[i]=clamp != MagickFalse ?
    487           ClampPixel(gamma*QuantumRange*(Sca+Dca*(1.0-Sa))) :
    488           ClampToQuantum(gamma*QuantumRange*(Sca+Dca*(1.0-Sa)));
    489       }
    490       p+=GetPixelChannels(source_image);
    491       channels=GetPixelChannels(source_image);
    492       if (p >= (pixels+channels*source_image->columns))
    493         p=pixels;
    494       q+=GetPixelChannels(image);
    495     }
    496     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
    497       status=MagickFalse;
    498     if (image->progress_monitor != (MagickProgressMonitor) NULL)
    499       {
    500         MagickBooleanType
    501           proceed;
    502 
    503 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    504         #pragma omp critical (MagickCore_CompositeImage)
    505 #endif
    506         proceed=SetImageProgress(image,CompositeImageTag,progress++,
    507           image->rows);
    508         if (proceed == MagickFalse)
    509           status=MagickFalse;
    510       }
    511   }
    512   source_view=DestroyCacheView(source_view);
    513   image_view=DestroyCacheView(image_view);
    514   return(status);
    515 }
    516 
    517 MagickExport MagickBooleanType CompositeImage(Image *image,
    518   const Image *composite,const CompositeOperator compose,
    519   const MagickBooleanType clip_to_self,const ssize_t x_offset,
    520   const ssize_t y_offset,ExceptionInfo *exception)
    521 {
    522 #define CompositeImageTag  "Composite/Image"
    523 
    524   CacheView
    525     *source_view,
    526     *image_view;
    527 
    528   const char
    529     *value;
    530 
    531   GeometryInfo
    532     geometry_info;
    533 
    534   Image
    535     *canvas_image,
    536     *source_image;
    537 
    538   MagickBooleanType
    539     clamp,
    540     status;
    541 
    542   MagickOffsetType
    543     progress;
    544 
    545   MagickRealType
    546     amount,
    547     canvas_dissolve,
    548     midpoint,
    549     percent_luma,
    550     percent_chroma,
    551     source_dissolve,
    552     threshold;
    553 
    554   MagickStatusType
    555     flags;
    556 
    557   ssize_t
    558     y;
    559 
    560   assert(image != (Image *) NULL);
    561   assert(image->signature == MagickCoreSignature);
    562   if (image->debug != MagickFalse)
    563     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    564   assert(composite!= (Image *) NULL);
    565   assert(composite->signature == MagickCoreSignature);
    566   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
    567     return(MagickFalse);
    568   source_image=CloneImage(composite,0,0,MagickTrue,exception);
    569   if (source_image == (const Image *) NULL)
    570     return(MagickFalse);
    571   if (IsGrayColorspace(image->colorspace) != MagickFalse)
    572     (void) SetImageColorspace(image,sRGBColorspace,exception);
    573   (void) SetImageColorspace(source_image,image->colorspace,exception);
    574   if ((image->alpha_trait != UndefinedPixelTrait) &&
    575       (source_image->alpha_trait == UndefinedPixelTrait))
    576     (void) SetImageAlphaChannel(source_image,SetAlphaChannel,exception);
    577   if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
    578     {
    579       status=CompositeOverImage(image,source_image,clip_to_self,x_offset,
    580         y_offset,exception);
    581       source_image=DestroyImage(source_image);
    582       return(status);
    583     }
    584   amount=0.5;
    585   canvas_image=(Image *) NULL;
    586   canvas_dissolve=1.0;
    587   clamp=MagickTrue;
    588   value=GetImageArtifact(image,"compose:clamp");
    589   if (value != (const char *) NULL)
    590     clamp=IsStringTrue(value);
    591   SetGeometryInfo(&geometry_info);
    592   percent_luma=100.0;
    593   percent_chroma=100.0;
    594   source_dissolve=1.0;
    595   threshold=0.05f;
    596   switch (compose)
    597   {
    598     case CopyCompositeOp:
    599     {
    600       if ((x_offset < 0) || (y_offset < 0))
    601         break;
    602       if ((x_offset+(ssize_t) source_image->columns) > (ssize_t) image->columns)
    603         break;
    604       if ((y_offset+(ssize_t) source_image->rows) > (ssize_t) image->rows)
    605         break;
    606       status=MagickTrue;
    607       source_view=AcquireVirtualCacheView(source_image,exception);
    608       image_view=AcquireAuthenticCacheView(image,exception);
    609 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    610       #pragma omp parallel for schedule(static,4) shared(status) \
    611         magick_threads(source_image,image,source_image->rows,1)
    612 #endif
    613       for (y=0; y < (ssize_t) source_image->rows; y++)
    614       {
    615         MagickBooleanType
    616           sync;
    617 
    618         register const Quantum
    619           *p;
    620 
    621         register Quantum
    622           *q;
    623 
    624         register ssize_t
    625           x;
    626 
    627         if (status == MagickFalse)
    628           continue;
    629         p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
    630           exception);
    631         q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
    632           source_image->columns,1,exception);
    633         if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
    634           {
    635             status=MagickFalse;
    636             continue;
    637           }
    638         for (x=0; x < (ssize_t) source_image->columns; x++)
    639         {
    640           register ssize_t
    641             i;
    642 
    643           if (GetPixelReadMask(source_image,p) == 0)
    644             {
    645               p+=GetPixelChannels(source_image);
    646               q+=GetPixelChannels(image);
    647               continue;
    648             }
    649           for (i=0; i < (ssize_t) GetPixelChannels(source_image); i++)
    650           {
    651             PixelChannel channel=GetPixelChannelChannel(source_image,i);
    652             PixelTrait source_traits=GetPixelChannelTraits(source_image,
    653               channel);
    654             PixelTrait traits=GetPixelChannelTraits(image,channel);
    655             if ((traits == UndefinedPixelTrait) ||
    656                 (source_traits == UndefinedPixelTrait))
    657               continue;
    658             SetPixelChannel(image,channel,p[i],q);
    659           }
    660           p+=GetPixelChannels(source_image);
    661           q+=GetPixelChannels(image);
    662         }
    663         sync=SyncCacheViewAuthenticPixels(image_view,exception);
    664         if (sync == MagickFalse)
    665           status=MagickFalse;
    666         if (image->progress_monitor != (MagickProgressMonitor) NULL)
    667           {
    668             MagickBooleanType
    669               proceed;
    670 
    671 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    672             #pragma omp critical (MagickCore_CompositeImage)
    673 #endif
    674             proceed=SetImageProgress(image,CompositeImageTag,
    675               (MagickOffsetType) y,image->rows);
    676             if (proceed == MagickFalse)
    677               status=MagickFalse;
    678           }
    679       }
    680       source_view=DestroyCacheView(source_view);
    681       image_view=DestroyCacheView(image_view);
    682       source_image=DestroyImage(source_image);
    683       return(status);
    684     }
    685     case IntensityCompositeOp:
    686     {
    687       if ((x_offset < 0) || (y_offset < 0))
    688         break;
    689       if ((x_offset+(ssize_t) source_image->columns) > (ssize_t) image->columns)
    690         break;
    691       if ((y_offset+(ssize_t) source_image->rows) > (ssize_t) image->rows)
    692         break;
    693       status=MagickTrue;
    694       source_view=AcquireVirtualCacheView(source_image,exception);
    695       image_view=AcquireAuthenticCacheView(image,exception);
    696 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    697       #pragma omp parallel for schedule(static,4) shared(status) \
    698         magick_threads(source_image,image,source_image->rows,1)
    699 #endif
    700       for (y=0; y < (ssize_t) source_image->rows; y++)
    701       {
    702         MagickBooleanType
    703           sync;
    704 
    705         register const Quantum
    706           *p;
    707 
    708         register Quantum
    709           *q;
    710 
    711         register ssize_t
    712           x;
    713 
    714         if (status == MagickFalse)
    715           continue;
    716         p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
    717           exception);
    718         q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
    719           source_image->columns,1,exception);
    720         if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
    721           {
    722             status=MagickFalse;
    723             continue;
    724           }
    725         for (x=0; x < (ssize_t) source_image->columns; x++)
    726         {
    727           if (GetPixelReadMask(source_image,p) == 0)
    728             {
    729               p+=GetPixelChannels(source_image);
    730               q+=GetPixelChannels(image);
    731               continue;
    732             }
    733           SetPixelAlpha(image,clamp != MagickFalse ?
    734             ClampPixel(GetPixelIntensity(source_image,p)) :
    735             ClampToQuantum(GetPixelIntensity(source_image,p)),q);
    736           p+=GetPixelChannels(source_image);
    737           q+=GetPixelChannels(image);
    738         }
    739         sync=SyncCacheViewAuthenticPixels(image_view,exception);
    740         if (sync == MagickFalse)
    741           status=MagickFalse;
    742         if (image->progress_monitor != (MagickProgressMonitor) NULL)
    743           {
    744             MagickBooleanType
    745               proceed;
    746 
    747 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    748             #pragma omp critical (MagickCore_CompositeImage)
    749 #endif
    750             proceed=SetImageProgress(image,CompositeImageTag,
    751               (MagickOffsetType) y,image->rows);
    752             if (proceed == MagickFalse)
    753               status=MagickFalse;
    754           }
    755       }
    756       source_view=DestroyCacheView(source_view);
    757       image_view=DestroyCacheView(image_view);
    758       source_image=DestroyImage(source_image);
    759       return(status);
    760     }
    761     case CopyAlphaCompositeOp:
    762     case ChangeMaskCompositeOp:
    763     {
    764       /*
    765         Modify canvas outside the overlaid region and require an alpha
    766         channel to exist, to add transparency.
    767       */
    768       if (image->alpha_trait == UndefinedPixelTrait)
    769         (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
    770       break;
    771     }
    772     case BlurCompositeOp:
    773     {
    774       CacheView
    775         *canvas_view;
    776 
    777       MagickRealType
    778         angle_range,
    779         angle_start,
    780         height,
    781         width;
    782 
    783       PixelInfo
    784         pixel;
    785 
    786       ResampleFilter
    787         *resample_filter;
    788 
    789       SegmentInfo
    790         blur;
    791 
    792       /*
    793         Blur Image by resampling.
    794 
    795         Blur Image dictated by an overlay gradient map: X = red_channel;
    796           Y = green_channel; compose:args =  x_scale[,y_scale[,angle]].
    797       */
    798       canvas_image=CloneImage(image,image->columns,image->rows,MagickTrue,
    799         exception);
    800       if (canvas_image == (Image *) NULL)
    801         {
    802           source_image=DestroyImage(source_image);
    803           return(MagickFalse);
    804         }
    805       /*
    806         Gather the maximum blur sigma values from user.
    807       */
    808       flags=NoValue;
    809       value=GetImageArtifact(image,"compose:args");
    810       if (value != (const char *) NULL)
    811         flags=ParseGeometry(value,&geometry_info);
    812       if ((flags & WidthValue) == 0)
    813         {
    814           (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
    815             "InvalidSetting","'%s' '%s'","compose:args",value);
    816           source_image=DestroyImage(source_image);
    817           canvas_image=DestroyImage(canvas_image);
    818           return(MagickFalse);
    819         }
    820       /*
    821         Users input sigma now needs to be converted to the EWA ellipse size.
    822         The filter defaults to a sigma of 0.5 so to make this match the
    823         users input the ellipse size needs to be doubled.
    824       */
    825       width=height=geometry_info.rho*2.0;
    826       if ((flags & HeightValue) != 0 )
    827         height=geometry_info.sigma*2.0;
    828       /*
    829         Default the unrotated ellipse width and height axis vectors.
    830       */
    831       blur.x1=width;
    832       blur.x2=0.0;
    833       blur.y1=0.0;
    834       blur.y2=height;
    835       /* rotate vectors if a rotation angle is given */
    836       if ((flags & XValue) != 0 )
    837         {
    838           MagickRealType
    839             angle;
    840 
    841           angle=DegreesToRadians(geometry_info.xi);
    842           blur.x1=width*cos(angle);
    843           blur.x2=width*sin(angle);
    844           blur.y1=(-height*sin(angle));
    845           blur.y2=height*cos(angle);
    846         }
    847       /* Otherwise lets set a angle range and calculate in the loop */
    848       angle_start=0.0;
    849       angle_range=0.0;
    850       if ((flags & YValue) != 0 )
    851         {
    852           angle_start=DegreesToRadians(geometry_info.xi);
    853           angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
    854         }
    855       /*
    856         Set up a gaussian cylindrical filter for EWA Bluring.
    857 
    858         As the minimum ellipse radius of support*1.0 the EWA algorithm
    859         can only produce a minimum blur of 0.5 for Gaussian (support=2.0)
    860         This means that even 'No Blur' will be still a little blurry!
    861 
    862         The solution (as well as the problem of preventing any user
    863         expert filter settings, is to set our own user settings, then
    864         restore them afterwards.
    865       */
    866       resample_filter=AcquireResampleFilter(image,exception);
    867       SetResampleFilter(resample_filter,GaussianFilter);
    868 
    869       /* do the variable blurring of each pixel in image */
    870       GetPixelInfo(image,&pixel);
    871       source_view=AcquireVirtualCacheView(source_image,exception);
    872       canvas_view=AcquireAuthenticCacheView(canvas_image,exception);
    873       for (y=0; y < (ssize_t) source_image->rows; y++)
    874       {
    875         MagickBooleanType
    876           sync;
    877 
    878         register const Quantum
    879           *magick_restrict p;
    880 
    881         register Quantum
    882           *magick_restrict q;
    883 
    884         register ssize_t
    885           x;
    886 
    887         if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
    888           continue;
    889         p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
    890           exception);
    891         q=QueueCacheViewAuthenticPixels(canvas_view,0,y,canvas_image->columns,1,
    892           exception);
    893         if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
    894           break;
    895         for (x=0; x < (ssize_t) source_image->columns; x++)
    896         {
    897           if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
    898             {
    899               p+=GetPixelChannels(source_image);
    900               continue;
    901             }
    902           if (fabs((double) angle_range) > MagickEpsilon)
    903             {
    904               MagickRealType
    905                 angle;
    906 
    907               angle=angle_start+angle_range*QuantumScale*
    908                 GetPixelBlue(source_image,p);
    909               blur.x1=width*cos(angle);
    910               blur.x2=width*sin(angle);
    911               blur.y1=(-height*sin(angle));
    912               blur.y2=height*cos(angle);
    913             }
    914 #if 0
    915           if ( x == 10 && y == 60 ) {
    916             (void) fprintf(stderr, "blur.x=%lf,%lf, blur.y=%lf,%lf\n",blur.x1,
    917               blur.x2,blur.y1, blur.y2);
    918             (void) fprintf(stderr, "scaled by=%lf,%lf\n",QuantumScale*
    919               GetPixelRed(p),QuantumScale*GetPixelGreen(p));
    920 #endif
    921           ScaleResampleFilter(resample_filter,
    922             blur.x1*QuantumScale*GetPixelRed(source_image,p),
    923             blur.y1*QuantumScale*GetPixelGreen(source_image,p),
    924             blur.x2*QuantumScale*GetPixelRed(source_image,p),
    925             blur.y2*QuantumScale*GetPixelGreen(source_image,p) );
    926           (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
    927             (double) y_offset+y,&pixel,exception);
    928           SetPixelViaPixelInfo(canvas_image,&pixel,q);
    929           p+=GetPixelChannels(source_image);
    930           q+=GetPixelChannels(canvas_image);
    931         }
    932         sync=SyncCacheViewAuthenticPixels(canvas_view,exception);
    933         if (sync == MagickFalse)
    934           break;
    935       }
    936       resample_filter=DestroyResampleFilter(resample_filter);
    937       source_view=DestroyCacheView(source_view);
    938       canvas_view=DestroyCacheView(canvas_view);
    939       source_image=DestroyImage(source_image);
    940       source_image=canvas_image;
    941       break;
    942     }
    943     case DisplaceCompositeOp:
    944     case DistortCompositeOp:
    945     {
    946       CacheView
    947         *canvas_view;
    948 
    949       MagickRealType
    950         horizontal_scale,
    951         vertical_scale;
    952 
    953       PixelInfo
    954         pixel;
    955 
    956       PointInfo
    957         center,
    958         offset;
    959 
    960       /*
    961         Displace/Distort based on overlay gradient map:
    962           X = red_channel;  Y = green_channel;
    963           compose:args = x_scale[,y_scale[,center.x,center.y]]
    964       */
    965       canvas_image=CloneImage(image,image->columns,image->rows,MagickTrue,
    966         exception);
    967       if (canvas_image == (Image *) NULL)
    968         {
    969           source_image=DestroyImage(source_image);
    970           return(MagickFalse);
    971         }
    972       SetGeometryInfo(&geometry_info);
    973       flags=NoValue;
    974       value=GetImageArtifact(image,"compose:args");
    975       if (value != (char *) NULL)
    976         flags=ParseGeometry(value,&geometry_info);
    977       if ((flags & (WidthValue | HeightValue)) == 0 )
    978         {
    979           if ((flags & AspectValue) == 0)
    980             {
    981               horizontal_scale=(MagickRealType) (source_image->columns-1)/2.0;
    982               vertical_scale=(MagickRealType) (source_image->rows-1)/2.0;
    983             }
    984           else
    985             {
    986               horizontal_scale=(MagickRealType) (image->columns-1)/2.0;
    987               vertical_scale=(MagickRealType) (image->rows-1)/2.0;
    988             }
    989         }
    990       else
    991         {
    992           horizontal_scale=geometry_info.rho;
    993           vertical_scale=geometry_info.sigma;
    994           if ((flags & PercentValue) != 0)
    995             {
    996               if ((flags & AspectValue) == 0)
    997                 {
    998                   horizontal_scale*=(source_image->columns-1)/200.0;
    999                   vertical_scale*=(source_image->rows-1)/200.0;
   1000                 }
   1001               else
   1002                 {
   1003                   horizontal_scale*=(image->columns-1)/200.0;
   1004                   vertical_scale*=(image->rows-1)/200.0;
   1005                 }
   1006             }
   1007           if ((flags & HeightValue) == 0)
   1008             vertical_scale=horizontal_scale;
   1009         }
   1010       /*
   1011         Determine fixed center point for absolute distortion map
   1012          Absolute distort ==
   1013            Displace offset relative to a fixed absolute point
   1014            Select that point according to +X+Y user inputs.
   1015            default = center of overlay image
   1016            arg flag '!' = locations/percentage relative to background image
   1017       */
   1018       center.x=(MagickRealType) x_offset;
   1019       center.y=(MagickRealType) y_offset;
   1020       if (compose == DistortCompositeOp)
   1021         {
   1022           if ((flags & XValue) == 0)
   1023             if ((flags & AspectValue) != 0)
   1024               center.x=(MagickRealType) ((image->columns-1)/2.0);
   1025             else
   1026               center.x=(MagickRealType) (x_offset+(source_image->columns-1)/
   1027                 2.0);
   1028           else
   1029             if ((flags & AspectValue) != 0)
   1030               center.x=geometry_info.xi;
   1031             else
   1032               center.x=(MagickRealType) (x_offset+geometry_info.xi);
   1033           if ((flags & YValue) == 0)
   1034             if ((flags & AspectValue) != 0)
   1035               center.y=(MagickRealType) ((image->rows-1)/2.0);
   1036             else
   1037               center.y=(MagickRealType) (y_offset+(source_image->rows-1)/2.0);
   1038           else
   1039             if ((flags & AspectValue) != 0)
   1040               center.y=geometry_info.psi;
   1041             else
   1042               center.y=(MagickRealType) (y_offset+geometry_info.psi);
   1043         }
   1044       /*
   1045         Shift the pixel offset point as defined by the provided,
   1046         displacement/distortion map.  -- Like a lens...
   1047       */
   1048       GetPixelInfo(image,&pixel);
   1049       image_view=AcquireVirtualCacheView(image,exception);
   1050       source_view=AcquireVirtualCacheView(source_image,exception);
   1051       canvas_view=AcquireAuthenticCacheView(canvas_image,exception);
   1052       for (y=0; y < (ssize_t) source_image->rows; y++)
   1053       {
   1054         MagickBooleanType
   1055           sync;
   1056 
   1057         register const Quantum
   1058           *magick_restrict p;
   1059 
   1060         register Quantum
   1061           *magick_restrict q;
   1062 
   1063         register ssize_t
   1064           x;
   1065 
   1066         if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
   1067           continue;
   1068         p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
   1069           exception);
   1070         q=QueueCacheViewAuthenticPixels(canvas_view,0,y,canvas_image->columns,1,
   1071           exception);
   1072         if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
   1073           break;
   1074         for (x=0; x < (ssize_t) source_image->columns; x++)
   1075         {
   1076           if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
   1077             {
   1078               p+=GetPixelChannels(source_image);
   1079               continue;
   1080             }
   1081           /*
   1082             Displace the offset.
   1083           */
   1084           offset.x=(double) (horizontal_scale*(GetPixelRed(source_image,p)-
   1085             (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
   1086             QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
   1087             x : 0);
   1088           offset.y=(double) (vertical_scale*(GetPixelGreen(source_image,p)-
   1089             (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
   1090             QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
   1091             y : 0);
   1092           (void) InterpolatePixelInfo(image,image_view,
   1093             UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
   1094             &pixel,exception);
   1095           /*
   1096             Mask with the 'invalid pixel mask' in alpha channel.
   1097           */
   1098           pixel.alpha=(MagickRealType) QuantumRange*(QuantumScale*pixel.alpha)*
   1099             (QuantumScale*GetPixelAlpha(source_image,p));
   1100           SetPixelViaPixelInfo(canvas_image,&pixel,q);
   1101           p+=GetPixelChannels(source_image);
   1102           q+=GetPixelChannels(canvas_image);
   1103         }
   1104         sync=SyncCacheViewAuthenticPixels(canvas_view,exception);
   1105         if (sync == MagickFalse)
   1106           break;
   1107       }
   1108       canvas_view=DestroyCacheView(canvas_view);
   1109       source_view=DestroyCacheView(source_view);
   1110       image_view=DestroyCacheView(image_view);
   1111       source_image=DestroyImage(source_image);
   1112       source_image=canvas_image;
   1113       break;
   1114     }
   1115     case DissolveCompositeOp:
   1116     {
   1117       /*
   1118         Geometry arguments to dissolve factors.
   1119       */
   1120       value=GetImageArtifact(image,"compose:args");
   1121       if (value != (char *) NULL)
   1122         {
   1123           flags=ParseGeometry(value,&geometry_info);
   1124           source_dissolve=geometry_info.rho/100.0;
   1125           canvas_dissolve=1.0;
   1126           if ((source_dissolve-MagickEpsilon) < 0.0)
   1127             source_dissolve=0.0;
   1128           if ((source_dissolve+MagickEpsilon) > 1.0)
   1129             {
   1130               canvas_dissolve=2.0-source_dissolve;
   1131               source_dissolve=1.0;
   1132             }
   1133           if ((flags & SigmaValue) != 0)
   1134             canvas_dissolve=geometry_info.sigma/100.0;
   1135           if ((canvas_dissolve-MagickEpsilon) < 0.0)
   1136             canvas_dissolve=0.0;
   1137         }
   1138       break;
   1139     }
   1140     case BlendCompositeOp:
   1141     {
   1142       value=GetImageArtifact(image,"compose:args");
   1143       if (value != (char *) NULL)
   1144         {
   1145           flags=ParseGeometry(value,&geometry_info);
   1146           source_dissolve=geometry_info.rho/100.0;
   1147           canvas_dissolve=1.0-source_dissolve;
   1148           if ((flags & SigmaValue) != 0)
   1149             canvas_dissolve=geometry_info.sigma/100.0;
   1150         }
   1151       break;
   1152     }
   1153     case MathematicsCompositeOp:
   1154     {
   1155       /*
   1156         Just collect the values from "compose:args", setting.
   1157         Unused values are set to zero automagically.
   1158 
   1159         Arguments are normally a comma separated list, so this probably should
   1160         be changed to some 'general comma list' parser, (with a minimum
   1161         number of values)
   1162       */
   1163       SetGeometryInfo(&geometry_info);
   1164       value=GetImageArtifact(image,"compose:args");
   1165       if (value != (char *) NULL)
   1166         (void) ParseGeometry(value,&geometry_info);
   1167       break;
   1168     }
   1169     case ModulateCompositeOp:
   1170     {
   1171       /*
   1172         Determine the luma and chroma scale.
   1173       */
   1174       value=GetImageArtifact(image,"compose:args");
   1175       if (value != (char *) NULL)
   1176         {
   1177           flags=ParseGeometry(value,&geometry_info);
   1178           percent_luma=geometry_info.rho;
   1179           if ((flags & SigmaValue) != 0)
   1180             percent_chroma=geometry_info.sigma;
   1181         }
   1182       break;
   1183     }
   1184     case ThresholdCompositeOp:
   1185     {
   1186       /*
   1187         Determine the amount and threshold.
   1188       */
   1189       value=GetImageArtifact(image,"compose:args");
   1190       if (value != (char *) NULL)
   1191         {
   1192           flags=ParseGeometry(value,&geometry_info);
   1193           amount=geometry_info.rho;
   1194           threshold=geometry_info.sigma;
   1195           if ((flags & SigmaValue) == 0)
   1196             threshold=0.05f;
   1197         }
   1198       threshold*=QuantumRange;
   1199       break;
   1200     }
   1201     default:
   1202       break;
   1203   }
   1204   /*
   1205     Composite image.
   1206   */
   1207   status=MagickTrue;
   1208   progress=0;
   1209   midpoint=((MagickRealType) QuantumRange+1.0)/2;
   1210   source_view=AcquireVirtualCacheView(source_image,exception);
   1211   image_view=AcquireAuthenticCacheView(image,exception);
   1212 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   1213   #pragma omp parallel for schedule(static,4) shared(progress,status) \
   1214     magick_threads(source_image,image,image->rows,1)
   1215 #endif
   1216   for (y=0; y < (ssize_t) image->rows; y++)
   1217   {
   1218     const Quantum
   1219       *pixels;
   1220 
   1221     MagickRealType
   1222       blue,
   1223       chroma,
   1224       green,
   1225       hue,
   1226       luma,
   1227       red;
   1228 
   1229     PixelInfo
   1230       canvas_pixel,
   1231       source_pixel;
   1232 
   1233     register const Quantum
   1234       *magick_restrict p;
   1235 
   1236     register Quantum
   1237       *magick_restrict q;
   1238 
   1239     register ssize_t
   1240       x;
   1241 
   1242     if (status == MagickFalse)
   1243       continue;
   1244     if (clip_to_self != MagickFalse)
   1245       {
   1246         if (y < y_offset)
   1247           continue;
   1248         if ((y-y_offset) >= (ssize_t) source_image->rows)
   1249           continue;
   1250       }
   1251     /*
   1252       If pixels is NULL, y is outside overlay region.
   1253     */
   1254     pixels=(Quantum *) NULL;
   1255     p=(Quantum *) NULL;
   1256     if ((y >= y_offset) && ((y-y_offset) < (ssize_t) source_image->rows))
   1257       {
   1258         p=GetCacheViewVirtualPixels(source_view,0,y-y_offset,
   1259           source_image->columns,1,exception);
   1260         if (p == (const Quantum *) NULL)
   1261           {
   1262             status=MagickFalse;
   1263             continue;
   1264           }
   1265         pixels=p;
   1266         if (x_offset < 0)
   1267           p-=x_offset*GetPixelChannels(source_image);
   1268       }
   1269     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
   1270     if (q == (Quantum *) NULL)
   1271       {
   1272         status=MagickFalse;
   1273         continue;
   1274       }
   1275     hue=0.0;
   1276     chroma=0.0;
   1277     luma=0.0;
   1278     GetPixelInfo(image,&canvas_pixel);
   1279     GetPixelInfo(source_image,&source_pixel);
   1280     for (x=0; x < (ssize_t) image->columns; x++)
   1281     {
   1282       double
   1283         gamma;
   1284 
   1285       MagickRealType
   1286         alpha,
   1287         Da,
   1288         Dc,
   1289         Dca,
   1290         Sa,
   1291         Sc,
   1292         Sca;
   1293 
   1294       register ssize_t
   1295         i;
   1296 
   1297       size_t
   1298         channels;
   1299 
   1300       if (clip_to_self != MagickFalse)
   1301         {
   1302           if (x < x_offset)
   1303             {
   1304               q+=GetPixelChannels(image);
   1305               continue;
   1306             }
   1307           if ((x-x_offset) >= (ssize_t) source_image->columns)
   1308             break;
   1309         }
   1310       if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
   1311           ((x-x_offset) >= (ssize_t) source_image->columns))
   1312         {
   1313           Quantum
   1314             source[MaxPixelChannels];
   1315 
   1316           /*
   1317             Virtual composite:
   1318               Sc: source color.
   1319               Dc: canvas color.
   1320           */
   1321           (void) GetOneVirtualPixel(source_image,x-x_offset,y-y_offset,source,
   1322             exception);
   1323           if (GetPixelReadMask(image,q) == 0)
   1324             {
   1325               q+=GetPixelChannels(image);
   1326               continue;
   1327             }
   1328           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   1329           {
   1330             MagickRealType
   1331               pixel;
   1332 
   1333             PixelChannel channel=GetPixelChannelChannel(image,i);
   1334             PixelTrait traits=GetPixelChannelTraits(image,channel);
   1335             PixelTrait source_traits=GetPixelChannelTraits(source_image,
   1336               channel);
   1337             if ((traits == UndefinedPixelTrait) ||
   1338                 (source_traits == UndefinedPixelTrait))
   1339               continue;
   1340             switch (compose)
   1341             {
   1342               case AlphaCompositeOp:
   1343               case ChangeMaskCompositeOp:
   1344               case CopyAlphaCompositeOp:
   1345               case DstAtopCompositeOp:
   1346               case DstInCompositeOp:
   1347               case InCompositeOp:
   1348               case OutCompositeOp:
   1349               case SrcInCompositeOp:
   1350               case SrcOutCompositeOp:
   1351               {
   1352                 if (channel == AlphaPixelChannel)
   1353                   pixel=(MagickRealType) TransparentAlpha;
   1354                 else
   1355                   pixel=(MagickRealType) q[i];
   1356                 break;
   1357               }
   1358               case ClearCompositeOp:
   1359               case CopyCompositeOp:
   1360               case ReplaceCompositeOp:
   1361               case SrcCompositeOp:
   1362               {
   1363                 if (channel == AlphaPixelChannel)
   1364                   pixel=(MagickRealType) TransparentAlpha;
   1365                 else
   1366                   pixel=0.0;
   1367                 break;
   1368               }
   1369               case BlendCompositeOp:
   1370               case DissolveCompositeOp:
   1371               {
   1372                 if (channel == AlphaPixelChannel)
   1373                   pixel=canvas_dissolve*GetPixelAlpha(source_image,source);
   1374                 else
   1375                   pixel=(MagickRealType) source[channel];
   1376                 break;
   1377               }
   1378               default:
   1379               {
   1380                 pixel=(MagickRealType) source[channel];
   1381                 break;
   1382               }
   1383             }
   1384             q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
   1385               ClampToQuantum(pixel);
   1386           }
   1387           q+=GetPixelChannels(image);
   1388           continue;
   1389         }
   1390       /*
   1391         Authentic composite:
   1392           Sa:  normalized source alpha.
   1393           Da:  normalized canvas alpha.
   1394       */
   1395       Sa=QuantumScale*GetPixelAlpha(source_image,p);
   1396       Da=QuantumScale*GetPixelAlpha(image,q);
   1397       switch (compose)
   1398       {
   1399         case BumpmapCompositeOp:
   1400         {
   1401           alpha=GetPixelIntensity(source_image,p)*Sa;
   1402           break;
   1403         }
   1404         case ColorBurnCompositeOp:
   1405         case ColorDodgeCompositeOp:
   1406         case DarkenCompositeOp:
   1407         case DifferenceCompositeOp:
   1408         case DivideDstCompositeOp:
   1409         case DivideSrcCompositeOp:
   1410         case ExclusionCompositeOp:
   1411         case HardLightCompositeOp:
   1412         case HardMixCompositeOp:
   1413         case LinearBurnCompositeOp:
   1414         case LinearDodgeCompositeOp:
   1415         case LinearLightCompositeOp:
   1416         case LightenCompositeOp:
   1417         case MathematicsCompositeOp:
   1418         case MinusDstCompositeOp:
   1419         case MinusSrcCompositeOp:
   1420         case ModulusAddCompositeOp:
   1421         case ModulusSubtractCompositeOp:
   1422         case MultiplyCompositeOp:
   1423         case OverlayCompositeOp:
   1424         case PegtopLightCompositeOp:
   1425         case PinLightCompositeOp:
   1426         case ScreenCompositeOp:
   1427         case SoftLightCompositeOp:
   1428         case VividLightCompositeOp:
   1429         {
   1430           alpha=RoundToUnity(Sa+Da-Sa*Da);
   1431           break;
   1432         }
   1433         case DstAtopCompositeOp:
   1434         case DstInCompositeOp:
   1435         case InCompositeOp:
   1436         case SrcInCompositeOp:
   1437         {
   1438           alpha=Sa*Da;
   1439           break;
   1440         }
   1441         case DissolveCompositeOp:
   1442         {
   1443           alpha=source_dissolve*Sa*(-canvas_dissolve*Da)+source_dissolve*Sa+
   1444             canvas_dissolve*Da;
   1445           break;
   1446         }
   1447         case DstOverCompositeOp:
   1448         case OverCompositeOp:
   1449         case SrcOverCompositeOp:
   1450         {
   1451           alpha=Sa+Da-Sa*Da;
   1452           break;
   1453         }
   1454         case DstOutCompositeOp:
   1455         {
   1456           alpha=Da*(1.0-Sa);
   1457           break;
   1458         }
   1459         case OutCompositeOp:
   1460         case SrcOutCompositeOp:
   1461         {
   1462           alpha=Sa*(1.0-Da);
   1463           break;
   1464         }
   1465         case BlendCompositeOp:
   1466         case PlusCompositeOp:
   1467         {
   1468           alpha=RoundToUnity(source_dissolve*Sa+canvas_dissolve*Da);
   1469           break;
   1470         }
   1471         case XorCompositeOp:
   1472         {
   1473           alpha=Sa+Da-2.0*Sa*Da;
   1474           break;
   1475         }
   1476         default:
   1477         {
   1478           alpha=1.0;
   1479           break;
   1480         }
   1481       }
   1482       if (GetPixelReadMask(image,q) == 0)
   1483         {
   1484           p+=GetPixelChannels(source_image);
   1485           q+=GetPixelChannels(image);
   1486           continue;
   1487         }
   1488       switch (compose)
   1489       {
   1490         case ColorizeCompositeOp:
   1491         case HueCompositeOp:
   1492         case LuminizeCompositeOp:
   1493         case ModulateCompositeOp:
   1494         case SaturateCompositeOp:
   1495         {
   1496           GetPixelInfoPixel(source_image,p,&source_pixel);
   1497           GetPixelInfoPixel(image,q,&canvas_pixel);
   1498           break;
   1499         }
   1500         default:
   1501           break;
   1502       }
   1503       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   1504       {
   1505         MagickRealType
   1506           pixel,
   1507           sans;
   1508 
   1509         PixelChannel channel=GetPixelChannelChannel(image,i);
   1510         PixelTrait traits=GetPixelChannelTraits(image,channel);
   1511         PixelTrait source_traits=GetPixelChannelTraits(source_image,channel);
   1512         if (traits == UndefinedPixelTrait)
   1513           continue;
   1514         if ((source_traits == UndefinedPixelTrait) &&
   1515              (((compose != CopyAlphaCompositeOp) &&
   1516                (compose != ChangeMaskCompositeOp)) ||
   1517                (channel != AlphaPixelChannel)))
   1518             continue;
   1519         /*
   1520           Sc: source color.
   1521           Dc: canvas color.
   1522         */
   1523         Sc=(MagickRealType) GetPixelChannel(source_image,channel,p);
   1524         Dc=(MagickRealType) q[i];
   1525         if ((traits & CopyPixelTrait) != 0)
   1526           {
   1527             /*
   1528               Copy channel.
   1529             */
   1530             q[i]=Sc;
   1531             continue;
   1532           }
   1533         if (channel == AlphaPixelChannel)
   1534           {
   1535             /*
   1536               Set alpha channel.
   1537             */
   1538             switch (compose)
   1539             {
   1540               case AlphaCompositeOp:
   1541               {
   1542                 pixel=QuantumRange*Sa;
   1543                 break;
   1544               }
   1545               case AtopCompositeOp:
   1546               case CopyBlackCompositeOp:
   1547               case CopyBlueCompositeOp:
   1548               case CopyCyanCompositeOp:
   1549               case CopyGreenCompositeOp:
   1550               case CopyMagentaCompositeOp:
   1551               case CopyRedCompositeOp:
   1552               case CopyYellowCompositeOp:
   1553               case SrcAtopCompositeOp:
   1554               case DstCompositeOp:
   1555               case NoCompositeOp:
   1556               {
   1557                 pixel=QuantumRange*Da;
   1558                 break;
   1559               }
   1560               case ChangeMaskCompositeOp:
   1561               {
   1562                 MagickBooleanType
   1563                   equivalent;
   1564 
   1565                 if (Da < 0.5)
   1566                   {
   1567                     pixel=(MagickRealType) TransparentAlpha;
   1568                     break;
   1569                   }
   1570                 equivalent=IsFuzzyEquivalencePixel(source_image,p,image,q);
   1571                 if (equivalent != MagickFalse)
   1572                   pixel=(MagickRealType) TransparentAlpha;
   1573                 else
   1574                   pixel=(MagickRealType) OpaqueAlpha;
   1575                 break;
   1576               }
   1577               case ClearCompositeOp:
   1578               {
   1579                 pixel=(MagickRealType) TransparentAlpha;
   1580                 break;
   1581               }
   1582               case ColorizeCompositeOp:
   1583               case HueCompositeOp:
   1584               case LuminizeCompositeOp:
   1585               case SaturateCompositeOp:
   1586               {
   1587                 if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
   1588                   {
   1589                     pixel=QuantumRange*Da;
   1590                     break;
   1591                   }
   1592                 if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
   1593                   {
   1594                     pixel=QuantumRange*Sa;
   1595                     break;
   1596                   }
   1597                 if (Sa < Da)
   1598                   {
   1599                     pixel=QuantumRange*Da;
   1600                     break;
   1601                   }
   1602                 pixel=QuantumRange*Sa;
   1603                 break;
   1604               }
   1605               case CopyAlphaCompositeOp:
   1606               {
   1607                 if ((source_traits & BlendPixelTrait) == 0)
   1608                   pixel=GetPixelIntensity(source_image,p);
   1609                 else
   1610                   pixel=QuantumRange*Sa;
   1611                 break;
   1612               }
   1613               case CopyCompositeOp:
   1614               case DisplaceCompositeOp:
   1615               case DistortCompositeOp:
   1616               case DstAtopCompositeOp:
   1617               case ReplaceCompositeOp:
   1618               case SrcCompositeOp:
   1619               {
   1620                 pixel=QuantumRange*Sa;
   1621                 break;
   1622               }
   1623               case DarkenIntensityCompositeOp:
   1624               {
   1625                 pixel=Sa*GetPixelIntensity(source_image,p) <
   1626                   Da*GetPixelIntensity(image,q) ? Sa : Da;
   1627                 break;
   1628               }
   1629               case LightenIntensityCompositeOp:
   1630               {
   1631                 pixel=Sa*GetPixelIntensity(source_image,p) >
   1632                   Da*GetPixelIntensity(image,q) ? Sa : Da;
   1633                 break;
   1634               }
   1635               case ModulateCompositeOp:
   1636               {
   1637                 pixel=QuantumRange*Da;
   1638                 break;
   1639               }
   1640               default:
   1641               {
   1642                 pixel=QuantumRange*alpha;
   1643                 break;
   1644               }
   1645             }
   1646             q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
   1647               ClampToQuantum(pixel);
   1648             continue;
   1649           }
   1650         /*
   1651           Porter-Duff compositions:
   1652             Sca: source normalized color multiplied by alpha.
   1653             Dca: normalized canvas color multiplied by alpha.
   1654         */
   1655         Sca=QuantumScale*Sa*Sc;
   1656         Dca=QuantumScale*Da*Dc;
   1657         switch (compose)
   1658         {
   1659           case DarkenCompositeOp:
   1660           case LightenCompositeOp:
   1661           case ModulusSubtractCompositeOp:
   1662           {
   1663             gamma=PerceptibleReciprocal(1.0-alpha);
   1664             break;
   1665           }
   1666           default:
   1667           {
   1668             gamma=PerceptibleReciprocal(alpha);
   1669             break;
   1670           }
   1671         }
   1672         pixel=Dc;
   1673         switch (compose)
   1674         {
   1675           case AlphaCompositeOp:
   1676           {
   1677             pixel=QuantumRange*Sa;
   1678             break;
   1679           }
   1680           case AtopCompositeOp:
   1681           case SrcAtopCompositeOp:
   1682           {
   1683             pixel=QuantumRange*(Sca*Da+Dca*(1.0-Sa));
   1684             break;
   1685           }
   1686           case BlendCompositeOp:
   1687           {
   1688             pixel=gamma*(source_dissolve*Sa*Sc+canvas_dissolve*Da*Dc);
   1689             break;
   1690           }
   1691           case BlurCompositeOp:
   1692           case CopyCompositeOp:
   1693           case ReplaceCompositeOp:
   1694           case SrcCompositeOp:
   1695           {
   1696             pixel=QuantumRange*Sca;
   1697             break;
   1698           }
   1699           case DisplaceCompositeOp:
   1700           case DistortCompositeOp:
   1701           {
   1702             pixel=Sc;
   1703             break;
   1704           }
   1705           case BumpmapCompositeOp:
   1706           {
   1707             if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
   1708               {
   1709                 pixel=Dc;
   1710                 break;
   1711               }
   1712             pixel=QuantumScale*GetPixelIntensity(source_image,p)*Dc;
   1713             break;
   1714           }
   1715           case ChangeMaskCompositeOp:
   1716           {
   1717             pixel=Dc;
   1718             break;
   1719           }
   1720           case ClearCompositeOp:
   1721           {
   1722             pixel=0.0;
   1723             break;
   1724           }
   1725           case ColorBurnCompositeOp:
   1726           {
   1727             if ((Sca == 0.0) && (Dca == Da))
   1728               {
   1729                 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
   1730                 break;
   1731               }
   1732             if (Sca == 0.0)
   1733               {
   1734                 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
   1735                 break;
   1736               }
   1737             pixel=QuantumRange*gamma*(Sa*Da-Sa*Da*MagickMin(1.0,(1.0-Dca/Da)*Sa/
   1738               Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
   1739             break;
   1740           }
   1741           case ColorDodgeCompositeOp:
   1742           {
   1743             if ((Sca*Da+Dca*Sa) >= Sa*Da)
   1744               pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
   1745             else
   1746               pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
   1747                 (1.0-Sa));
   1748             break;
   1749           }
   1750           case ColorizeCompositeOp:
   1751           {
   1752             if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
   1753               {
   1754                 pixel=Dc;
   1755                 break;
   1756               }
   1757             if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
   1758               {
   1759                 pixel=Sc;
   1760                 break;
   1761               }
   1762             CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
   1763               &sans,&sans,&luma);
   1764             CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
   1765               &hue,&chroma,&sans);
   1766             HCLComposite(hue,chroma,luma,&red,&green,&blue);
   1767             switch (channel)
   1768             {
   1769               case RedPixelChannel: pixel=red; break;
   1770               case GreenPixelChannel: pixel=green; break;
   1771               case BluePixelChannel: pixel=blue; break;
   1772               default: pixel=Dc; break;
   1773             }
   1774             break;
   1775           }
   1776           case CopyAlphaCompositeOp:
   1777           {
   1778             pixel=Dc;
   1779             break;
   1780           }
   1781           case CopyBlackCompositeOp:
   1782           {
   1783             if (channel == BlackPixelChannel)
   1784               pixel=(MagickRealType) (QuantumRange-
   1785                 GetPixelBlack(source_image,p));
   1786             break;
   1787           }
   1788           case CopyBlueCompositeOp:
   1789           case CopyYellowCompositeOp:
   1790           {
   1791             if (channel == BluePixelChannel)
   1792               pixel=(MagickRealType) GetPixelBlue(source_image,p);
   1793             break;
   1794           }
   1795           case CopyGreenCompositeOp:
   1796           case CopyMagentaCompositeOp:
   1797           {
   1798             if (channel == GreenPixelChannel)
   1799               pixel=(MagickRealType) GetPixelGreen(source_image,p);
   1800             break;
   1801           }
   1802           case CopyRedCompositeOp:
   1803           case CopyCyanCompositeOp:
   1804           {
   1805             if (channel == RedPixelChannel)
   1806               pixel=(MagickRealType) GetPixelRed(source_image,p);
   1807             break;
   1808           }
   1809           case DarkenCompositeOp:
   1810           {
   1811             /*
   1812               Darken is equivalent to a 'Minimum' method
   1813                 OR a greyscale version of a binary 'Or'
   1814                 OR the 'Intersection' of pixel sets.
   1815             */
   1816             if ((Sca*Da) < (Dca*Sa))
   1817               {
   1818                 pixel=QuantumRange*(Sca+Dca*(1.0-Sa));
   1819                 break;
   1820               }
   1821             pixel=QuantumRange*(Dca+Sca*(1.0-Da));
   1822             break;
   1823           }
   1824           case DarkenIntensityCompositeOp:
   1825           {
   1826             pixel=Sa*GetPixelIntensity(source_image,p) <
   1827               Da*GetPixelIntensity(image,q) ? Sc : Dc;
   1828             break;
   1829           }
   1830           case DifferenceCompositeOp:
   1831           {
   1832             pixel=QuantumRange*gamma*(Sca+Dca-2.0*MagickMin(Sca*Da,Dca*Sa));
   1833             break;
   1834           }
   1835           case DissolveCompositeOp:
   1836           {
   1837             pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
   1838               canvas_dissolve*Da*Dc+canvas_dissolve*Da*Dc);
   1839             break;
   1840           }
   1841           case DivideDstCompositeOp:
   1842           {
   1843             if ((fabs((double) Sca) < MagickEpsilon) &&
   1844                 (fabs((double) Dca) < MagickEpsilon))
   1845               {
   1846                 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
   1847                 break;
   1848               }
   1849             if (fabs((double) Dca) < MagickEpsilon)
   1850               {
   1851                 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
   1852                 break;
   1853               }
   1854             pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
   1855             break;
   1856           }
   1857           case DivideSrcCompositeOp:
   1858           {
   1859             if ((fabs((double) Dca) < MagickEpsilon) &&
   1860                 (fabs((double) Sca) < MagickEpsilon))
   1861               {
   1862                 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
   1863                 break;
   1864               }
   1865             if (fabs((double) Sca) < MagickEpsilon)
   1866               {
   1867                 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
   1868                 break;
   1869               }
   1870             pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
   1871             break;
   1872           }
   1873           case DstAtopCompositeOp:
   1874           {
   1875             pixel=QuantumRange*(Dca*Sa+Sca*(1.0-Da));
   1876             break;
   1877           }
   1878           case DstCompositeOp:
   1879           case NoCompositeOp:
   1880           {
   1881             pixel=QuantumRange*Dca;
   1882             break;
   1883           }
   1884           case DstInCompositeOp:
   1885           {
   1886             pixel=QuantumRange*(Dca*Sa);
   1887             break;
   1888           }
   1889           case DstOutCompositeOp:
   1890           {
   1891             pixel=QuantumRange*(Dca*(1.0-Sa));
   1892             break;
   1893           }
   1894           case DstOverCompositeOp:
   1895           {
   1896             pixel=QuantumRange*gamma*(Dca+Sca*(1.0-Da));
   1897             break;
   1898           }
   1899           case ExclusionCompositeOp:
   1900           {
   1901             pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
   1902               Dca*(1.0-Sa));
   1903             break;
   1904           }
   1905           case HardLightCompositeOp:
   1906           {
   1907             if ((2.0*Sca) < Sa)
   1908               {
   1909                 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-
   1910                   Sa));
   1911                 break;
   1912               }
   1913             pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
   1914               Dca*(1.0-Sa));
   1915             break;
   1916           }
   1917           case HardMixCompositeOp:
   1918           {
   1919             pixel=gamma*(((Sca+Dca) < 1.0) ? 0.0 : QuantumRange);
   1920             break;
   1921           }
   1922           case HueCompositeOp:
   1923           {
   1924             if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
   1925               {
   1926                 pixel=Dc;
   1927                 break;
   1928               }
   1929             if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
   1930               {
   1931                 pixel=Sc;
   1932                 break;
   1933               }
   1934             CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
   1935               &hue,&chroma,&luma);
   1936             CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
   1937               &hue,&sans,&sans);
   1938             HCLComposite(hue,chroma,luma,&red,&green,&blue);
   1939             switch (channel)
   1940             {
   1941               case RedPixelChannel: pixel=red; break;
   1942               case GreenPixelChannel: pixel=green; break;
   1943               case BluePixelChannel: pixel=blue; break;
   1944               default: pixel=Dc; break;
   1945             }
   1946             break;
   1947           }
   1948           case InCompositeOp:
   1949           case SrcInCompositeOp:
   1950           {
   1951             pixel=QuantumRange*(Sca*Da);
   1952             break;
   1953           }
   1954           case LinearBurnCompositeOp:
   1955           {
   1956             /*
   1957               LinearBurn: as defined by Abode Photoshop, according to
   1958               http://www.simplefilter.de/en/basics/mixmods.html is:
   1959 
   1960                 f(Sc,Dc) = Sc + Dc - 1
   1961             */
   1962             pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
   1963             break;
   1964           }
   1965           case LinearDodgeCompositeOp:
   1966           {
   1967             pixel=gamma*(Sa*Sc+Da*Dc);
   1968             break;
   1969           }
   1970           case LinearLightCompositeOp:
   1971           {
   1972             /*
   1973               LinearLight: as defined by Abode Photoshop, according to
   1974               http://www.simplefilter.de/en/basics/mixmods.html is:
   1975 
   1976                 f(Sc,Dc) = Dc + 2*Sc - 1
   1977             */
   1978             pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
   1979             break;
   1980           }
   1981           case LightenCompositeOp:
   1982           {
   1983             if ((Sca*Da) > (Dca*Sa))
   1984               {
   1985                 pixel=QuantumRange*(Sca+Dca*(1.0-Sa));
   1986                 break;
   1987               }
   1988             pixel=QuantumRange*(Dca+Sca*(1.0-Da));
   1989             break;
   1990           }
   1991           case LightenIntensityCompositeOp:
   1992           {
   1993             /*
   1994               Lighten is equivalent to a 'Maximum' method
   1995                 OR a greyscale version of a binary 'And'
   1996                 OR the 'Union' of pixel sets.
   1997             */
   1998             pixel=Sa*GetPixelIntensity(source_image,p) >
   1999               Da*GetPixelIntensity(image,q) ? Sc : Dc;
   2000             break;
   2001           }
   2002           case LuminizeCompositeOp:
   2003           {
   2004             if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
   2005               {
   2006                 pixel=Dc;
   2007                 break;
   2008               }
   2009             if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
   2010               {
   2011                 pixel=Sc;
   2012                 break;
   2013               }
   2014             CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
   2015               &hue,&chroma,&luma);
   2016             CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
   2017               &sans,&sans,&luma);
   2018             HCLComposite(hue,chroma,luma,&red,&green,&blue);
   2019             switch (channel)
   2020             {
   2021               case RedPixelChannel: pixel=red; break;
   2022               case GreenPixelChannel: pixel=green; break;
   2023               case BluePixelChannel: pixel=blue; break;
   2024               default: pixel=Dc; break;
   2025             }
   2026             break;
   2027           }
   2028           case MathematicsCompositeOp:
   2029           {
   2030             /*
   2031               'Mathematics' a free form user control mathematical composition
   2032               is defined as...
   2033 
   2034                 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
   2035 
   2036               Where the arguments A,B,C,D are (currently) passed to composite
   2037               as a command separated 'geometry' string in "compose:args" image
   2038               artifact.
   2039 
   2040                  A = a->rho,   B = a->sigma,  C = a->xi,  D = a->psi
   2041 
   2042               Applying the SVG transparency formula (see above), we get...
   2043 
   2044                Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
   2045 
   2046                Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
   2047                  Dca*(1.0-Sa)
   2048             */
   2049             pixel=QuantumRange*gamma*(geometry_info.rho*Sca*Dca+
   2050               geometry_info.sigma*Sca*Da+geometry_info.xi*Dca*Sa+
   2051               geometry_info.psi*Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
   2052             break;
   2053           }
   2054           case MinusDstCompositeOp:
   2055           {
   2056             pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
   2057             break;
   2058           }
   2059           case MinusSrcCompositeOp:
   2060           {
   2061             /*
   2062               Minus source from canvas.
   2063 
   2064                 f(Sc,Dc) = Sc - Dc
   2065             */
   2066             pixel=gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
   2067             break;
   2068           }
   2069           case ModulateCompositeOp:
   2070           {
   2071             ssize_t
   2072               offset;
   2073 
   2074             if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
   2075               {
   2076                 pixel=Dc;
   2077                 break;
   2078               }
   2079             offset=(ssize_t) (GetPixelIntensity(source_image,p)-midpoint);
   2080             if (offset == 0)
   2081               {
   2082                 pixel=Dc;
   2083                 break;
   2084               }
   2085             CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
   2086               &hue,&chroma,&luma);
   2087             luma+=(0.01*percent_luma*offset)/midpoint;
   2088             chroma*=0.01*percent_chroma;
   2089             HCLComposite(hue,chroma,luma,&red,&green,&blue);
   2090             switch (channel)
   2091             {
   2092               case RedPixelChannel: pixel=red; break;
   2093               case GreenPixelChannel: pixel=green; break;
   2094               case BluePixelChannel: pixel=blue; break;
   2095               default: pixel=Dc; break;
   2096             }
   2097             break;
   2098           }
   2099           case ModulusAddCompositeOp:
   2100           {
   2101             pixel=Sc+Dc;
   2102             while (pixel > QuantumRange)
   2103               pixel-=QuantumRange;
   2104             while (pixel < 0.0)
   2105               pixel+=QuantumRange;
   2106             pixel=(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
   2107             break;
   2108           }
   2109           case ModulusSubtractCompositeOp:
   2110           {
   2111             pixel=Sc-Dc;
   2112             while (pixel > QuantumRange)
   2113               pixel-=QuantumRange;
   2114             while (pixel < 0.0)
   2115               pixel+=QuantumRange;
   2116             pixel=(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
   2117             break;
   2118           }
   2119           case MultiplyCompositeOp:
   2120           {
   2121             pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
   2122             break;
   2123           }
   2124           case OutCompositeOp:
   2125           case SrcOutCompositeOp:
   2126           {
   2127             pixel=QuantumRange*(Sca*(1.0-Da));
   2128             break;
   2129           }
   2130           case OverCompositeOp:
   2131           case SrcOverCompositeOp:
   2132           {
   2133             pixel=QuantumRange*gamma*(Sca+Dca*(1.0-Sa));
   2134             break;
   2135           }
   2136           case OverlayCompositeOp:
   2137           {
   2138             if ((2.0*Dca) < Da)
   2139               {
   2140                 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*(1.0-
   2141                   Da));
   2142                 break;
   2143               }
   2144             pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
   2145               Sca*(1.0-Da));
   2146             break;
   2147           }
   2148           case PegtopLightCompositeOp:
   2149           {
   2150             /*
   2151               PegTop: A Soft-Light alternative: A continuous version of the
   2152               Softlight function, producing very similar results.
   2153 
   2154                 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
   2155 
   2156               http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
   2157             */
   2158             if (fabs((double) Da) < MagickEpsilon)
   2159               {
   2160                 pixel=QuantumRange*gamma*(Sca);
   2161                 break;
   2162               }
   2163             pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
   2164               Da)+Dca*(1.0-Sa));
   2165             break;
   2166           }
   2167           case PinLightCompositeOp:
   2168           {
   2169             /*
   2170               PinLight: A Photoshop 7 composition method
   2171               http://www.simplefilter.de/en/basics/mixmods.html
   2172 
   2173                 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc   ? 2*Sc : Dc
   2174             */
   2175             if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
   2176               {
   2177                 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
   2178                 break;
   2179               }
   2180             if ((Dca*Sa) > (2.0*Sca*Da))
   2181               {
   2182                 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
   2183                 break;
   2184               }
   2185             pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
   2186             break;
   2187           }
   2188           case PlusCompositeOp:
   2189           {
   2190             pixel=QuantumRange*(Sca+Dca);
   2191             break;
   2192           }
   2193           case SaturateCompositeOp:
   2194           {
   2195             if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
   2196               {
   2197                 pixel=Dc;
   2198                 break;
   2199               }
   2200             if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
   2201               {
   2202                 pixel=Sc;
   2203                 break;
   2204               }
   2205             CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
   2206               &hue,&chroma,&luma);
   2207             CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
   2208               &sans,&chroma,&sans);
   2209             HCLComposite(hue,chroma,luma,&red,&green,&blue);
   2210             switch (channel)
   2211             {
   2212               case RedPixelChannel: pixel=red; break;
   2213               case GreenPixelChannel: pixel=green; break;
   2214               case BluePixelChannel: pixel=blue; break;
   2215               default: pixel=Dc; break;
   2216             }
   2217             break;
   2218           }
   2219           case ScreenCompositeOp:
   2220           {
   2221             /*
   2222               Screen:  a negated multiply:
   2223 
   2224                 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
   2225             */
   2226             pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
   2227             break;
   2228           }
   2229           case SoftLightCompositeOp:
   2230           {
   2231             if ((2.0*Sca) < Sa)
   2232               {
   2233                 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
   2234                   Sca*(1.0-Da)+Dca*(1.0-Sa));
   2235                 break;
   2236               }
   2237             if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
   2238               {
   2239                 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
   2240                   (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
   2241                   Dca*(1.0-Sa));
   2242                 break;
   2243               }
   2244             pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
   2245               (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
   2246             break;
   2247           }
   2248           case ThresholdCompositeOp:
   2249           {
   2250             MagickRealType
   2251               delta;
   2252 
   2253             delta=Sc-Dc;
   2254             if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
   2255               {
   2256                 pixel=gamma*Dc;
   2257                 break;
   2258               }
   2259             pixel=gamma*(Dc+delta*amount);
   2260             break;
   2261           }
   2262           case VividLightCompositeOp:
   2263           {
   2264             /*
   2265               VividLight: A Photoshop 7 composition method.  See
   2266               http://www.simplefilter.de/en/basics/mixmods.html.
   2267 
   2268                 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
   2269             */
   2270             if ((fabs((double) Sa) < MagickEpsilon) ||
   2271                 (fabs((double) (Sca-Sa)) < MagickEpsilon))
   2272               {
   2273                 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
   2274                 break;
   2275               }
   2276             if ((2.0*Sca) <= Sa)
   2277               {
   2278                 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
   2279                   (1.0-Da)+Dca*(1.0-Sa));
   2280                 break;
   2281               }
   2282             pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+Dca*
   2283               (1.0-Sa));
   2284             break;
   2285           }
   2286           case XorCompositeOp:
   2287           {
   2288             pixel=QuantumRange*(Sca*(1.0-Da)+Dca*(1.0-Sa));
   2289             break;
   2290           }
   2291           default:
   2292           {
   2293             pixel=Sc;
   2294             break;
   2295           }
   2296         }
   2297         q[i]=clamp != MagickFalse ? ClampPixel(pixel) : ClampToQuantum(pixel);
   2298       }
   2299       p+=GetPixelChannels(source_image);
   2300       channels=GetPixelChannels(source_image);
   2301       if (p >= (pixels+channels*source_image->columns))
   2302         p=pixels;
   2303       q+=GetPixelChannels(image);
   2304     }
   2305     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
   2306       status=MagickFalse;
   2307     if (image->progress_monitor != (MagickProgressMonitor) NULL)
   2308       {
   2309         MagickBooleanType
   2310           proceed;
   2311 
   2312 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   2313         #pragma omp critical (MagickCore_CompositeImage)
   2314 #endif
   2315         proceed=SetImageProgress(image,CompositeImageTag,progress++,
   2316           image->rows);
   2317         if (proceed == MagickFalse)
   2318           status=MagickFalse;
   2319       }
   2320   }
   2321   source_view=DestroyCacheView(source_view);
   2322   image_view=DestroyCacheView(image_view);
   2323   if (canvas_image != (Image * ) NULL)
   2324     canvas_image=DestroyImage(canvas_image);
   2325   else
   2326     source_image=DestroyImage(source_image);
   2327   return(status);
   2328 }
   2329 
   2330 /*
   2332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   2333 %                                                                             %
   2334 %                                                                             %
   2335 %                                                                             %
   2336 %     T e x t u r e I m a g e                                                 %
   2337 %                                                                             %
   2338 %                                                                             %
   2339 %                                                                             %
   2340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   2341 %
   2342 %  TextureImage() repeatedly tiles the texture image across and down the image
   2343 %  canvas.
   2344 %
   2345 %  The format of the TextureImage method is:
   2346 %
   2347 %      MagickBooleanType TextureImage(Image *image,const Image *texture,
   2348 %        ExceptionInfo *exception)
   2349 %
   2350 %  A description of each parameter follows:
   2351 %
   2352 %    o image: the image.
   2353 %
   2354 %    o texture_image: This image is the texture to layer on the background.
   2355 %
   2356 */
   2357 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
   2358   ExceptionInfo *exception)
   2359 {
   2360 #define TextureImageTag  "Texture/Image"
   2361 
   2362   CacheView
   2363     *image_view,
   2364     *texture_view;
   2365 
   2366   Image
   2367     *texture_image;
   2368 
   2369   MagickBooleanType
   2370     status;
   2371 
   2372   ssize_t
   2373     y;
   2374 
   2375   assert(image != (Image *) NULL);
   2376   if (image->debug != MagickFalse)
   2377     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
   2378   assert(image->signature == MagickCoreSignature);
   2379   if (texture == (const Image *) NULL)
   2380     return(MagickFalse);
   2381   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
   2382     return(MagickFalse);
   2383   texture_image=CloneImage(texture,0,0,MagickTrue,exception);
   2384   if (texture_image == (const Image *) NULL)
   2385     return(MagickFalse);
   2386   (void) TransformImageColorspace(texture_image,image->colorspace,exception);
   2387   (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
   2388     exception);
   2389   status=MagickTrue;
   2390   if ((image->compose != CopyCompositeOp) &&
   2391       ((image->compose != OverCompositeOp) ||
   2392        (image->alpha_trait != UndefinedPixelTrait) ||
   2393        (texture_image->alpha_trait != UndefinedPixelTrait)))
   2394     {
   2395       /*
   2396         Tile texture onto the image background.
   2397       */
   2398       for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
   2399       {
   2400         register ssize_t
   2401           x;
   2402 
   2403         if (status == MagickFalse)
   2404           continue;
   2405         for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
   2406         {
   2407           MagickBooleanType
   2408             thread_status;
   2409 
   2410           thread_status=CompositeImage(image,texture_image,image->compose,
   2411             MagickTrue,x+texture_image->tile_offset.x,y+
   2412             texture_image->tile_offset.y,exception);
   2413           if (thread_status == MagickFalse)
   2414             {
   2415               status=thread_status;
   2416               break;
   2417             }
   2418         }
   2419         if (image->progress_monitor != (MagickProgressMonitor) NULL)
   2420           {
   2421             MagickBooleanType
   2422               proceed;
   2423 
   2424             proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
   2425               image->rows);
   2426             if (proceed == MagickFalse)
   2427               status=MagickFalse;
   2428           }
   2429       }
   2430       (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
   2431         image->rows,image->rows);
   2432       texture_image=DestroyImage(texture_image);
   2433       return(status);
   2434     }
   2435   /*
   2436     Tile texture onto the image background (optimized).
   2437   */
   2438   status=MagickTrue;
   2439   texture_view=AcquireVirtualCacheView(texture_image,exception);
   2440   image_view=AcquireAuthenticCacheView(image,exception);
   2441 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   2442   #pragma omp parallel for schedule(static,4) shared(status) \
   2443     magick_threads(texture_image,image,1,1)
   2444 #endif
   2445   for (y=0; y < (ssize_t) image->rows; y++)
   2446   {
   2447     MagickBooleanType
   2448       sync;
   2449 
   2450     register const Quantum
   2451       *p,
   2452       *pixels;
   2453 
   2454     register ssize_t
   2455       x;
   2456 
   2457     register Quantum
   2458       *q;
   2459 
   2460     size_t
   2461       width;
   2462 
   2463     if (status == MagickFalse)
   2464       continue;
   2465     pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
   2466       (y+texture_image->tile_offset.y) % texture_image->rows,
   2467       texture_image->columns,1,exception);
   2468     q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
   2469     if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
   2470       {
   2471         status=MagickFalse;
   2472         continue;
   2473       }
   2474     for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
   2475     {
   2476       register ssize_t
   2477         j;
   2478 
   2479       p=pixels;
   2480       width=texture_image->columns;
   2481       if ((x+(ssize_t) width) > (ssize_t) image->columns)
   2482         width=image->columns-x;
   2483       for (j=0; j < (ssize_t) width; j++)
   2484       {
   2485         register ssize_t
   2486           i;
   2487 
   2488         if (GetPixelReadMask(image,q) == 0)
   2489           {
   2490             p+=GetPixelChannels(texture_image);
   2491             q+=GetPixelChannels(image);
   2492             continue;
   2493           }
   2494         for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
   2495         {
   2496           PixelChannel channel=GetPixelChannelChannel(texture_image,i);
   2497           PixelTrait traits=GetPixelChannelTraits(image,channel);
   2498           PixelTrait texture_traits=GetPixelChannelTraits(texture_image,
   2499             channel);
   2500           if ((traits == UndefinedPixelTrait) ||
   2501               (texture_traits == UndefinedPixelTrait))
   2502             continue;
   2503           SetPixelChannel(image,channel,p[i],q);
   2504         }
   2505         p+=GetPixelChannels(texture_image);
   2506         q+=GetPixelChannels(image);
   2507       }
   2508     }
   2509     sync=SyncCacheViewAuthenticPixels(image_view,exception);
   2510     if (sync == MagickFalse)
   2511       status=MagickFalse;
   2512     if (image->progress_monitor != (MagickProgressMonitor) NULL)
   2513       {
   2514         MagickBooleanType
   2515           proceed;
   2516 
   2517         proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
   2518           image->rows);
   2519         if (proceed == MagickFalse)
   2520           status=MagickFalse;
   2521       }
   2522   }
   2523   texture_view=DestroyCacheView(texture_view);
   2524   image_view=DestroyCacheView(image_view);
   2525   texture_image=DestroyImage(texture_image);
   2526   return(status);
   2527 }
   2528