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