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