2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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 %
13 % MagickCore Image Composite Methods %
20 % Copyright 1999-2015 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
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. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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"
83 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
87 % C o m p o s i t e I m a g e %
91 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
93 % CompositeImage() returns the second image composited onto the first
94 % at the specified offset, using the specified composite method.
96 % The format of the CompositeImage method is:
98 % MagickBooleanType CompositeImage(Image *image,
99 % const Image *composite_image,const CompositeOperator compose,
100 % const MagickBooleanType clip_to_self,const ssize_t x_offset,
101 % const ssize_t y_offset,ExceptionInfo *exception)
103 % A description of each parameter follows:
105 % o image: the destination image, modified by he composition
107 % o composite_image: the composite (source) image.
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.
113 % o clip_to_self: set to MagickTrue to limit composition to area composed.
115 % o x_offset: the column offset of the composited image.
117 % o y_offset: the row offset of the composited image.
119 % Extra Controls from Image meta-data in 'image' (artifacts)
122 % A string containing extra numerical arguments for specific compose
123 % methods, generally expressed as a 'geometry' or a comma separated list
126 % Compose methods needing such arguments include "BlendCompositeOp" and
127 % "DisplaceCompositeOp".
129 % o exception: return any errors or warnings in this structure.
134 Composition based on the SVG specification:
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 destination preserved
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)
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.
151 Da' in in the follow formula as 'gamma' The resulting alpla value.
153 Most functions use a blending mode of over (X=1,Y=1,Z=1) this results in
154 the following optimizations...
156 gamma = 1 - QuantiumScale*alpha * QuantiumScale*beta;
157 opacity = QuantiumScale*alpha*beta; // over blend, optimized 1-Gamma
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'.
164 Mathematical operator changes to be applied from IM v6.7...
166 1) Modulus modes 'Add' and 'Subtract' are obsoleted and renamed
167 'ModulusAdd' and 'ModulusSubtract' for clarity.
169 2) All mathematical compositions work as per the SVG specification
170 with regard to blending. This now includes 'ModulusAdd' and
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
181 static void HCLComposite(const MagickRealType hue,const MagickRealType chroma,
182 const MagickRealType luma,MagickRealType *red,MagickRealType *green,
183 MagickRealType *blue)
195 Convert HCL to RGB colorspace.
197 assert(red != (MagickRealType *) NULL);
198 assert(green != (MagickRealType *) NULL);
199 assert(blue != (MagickRealType *) NULL);
202 x=c*(1.0-fabs(fmod(h,2.0)-1.0));
206 if ((0.0 <= h) && (h < 1.0))
212 if ((1.0 <= h) && (h < 2.0))
218 if ((2.0 <= h) && (h < 3.0))
224 if ((3.0 <= h) && (h < 4.0))
230 if ((4.0 <= h) && (h < 5.0))
236 if ((5.0 <= h) && (h < 6.0))
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);
247 static void CompositeHCL(const MagickRealType red,const MagickRealType green,
248 const MagickRealType blue,MagickRealType *hue,MagickRealType *chroma,
249 MagickRealType *luma)
260 Convert RGB to HCL colorspace.
262 assert(hue != (MagickRealType *) NULL);
263 assert(chroma != (MagickRealType *) NULL);
264 assert(luma != (MagickRealType *) NULL);
268 max=MagickMax(r,MagickMax(g,b));
269 c=max-(MagickRealType) MagickMin(r,MagickMin(g,b));
275 h=fmod((g-b)/c+6.0,6.0);
283 *chroma=QuantumScale*c;
284 *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
287 static MagickBooleanType CompositeOverImage(Image *image,
288 const Image *composite_image,const MagickBooleanType clip_to_self,
289 const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
291 #define CompositeImageTag "Composite/Image"
311 composite_view=AcquireVirtualCacheView(composite_image,exception);
312 image_view=AcquireAuthenticCacheView(image,exception);
313 #if defined(MAGICKCORE_OPENMP_SUPPORT)
314 #pragma omp parallel for schedule(static,4) shared(progress,status) \
315 magick_threads(composite_image,image,image->rows,1)
317 for (y=0; y < (ssize_t) image->rows; y++)
322 register const Quantum
334 if (status == MagickFalse)
336 if (clip_to_self != MagickFalse)
340 if ((y-y_offset) >= (ssize_t) composite_image->rows)
344 If pixels is NULL, y is outside overlay region.
346 pixels=(Quantum *) NULL;
348 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
350 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
351 composite_image->columns,1,exception);
352 if (p == (const Quantum *) NULL)
359 p-=x_offset*GetPixelChannels(composite_image);
361 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
362 if (q == (Quantum *) NULL)
367 for (x=0; x < (ssize_t) image->columns; x++)
380 if (clip_to_self != MagickFalse)
384 q+=GetPixelChannels(image);
387 if ((x-x_offset) >= (ssize_t) composite_image->columns)
390 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
391 ((x-x_offset) >= (ssize_t) composite_image->columns))
394 source[MaxPixelChannels];
399 Dc: destination color.
401 if (GetPixelReadMask(image,q) == 0)
403 q+=GetPixelChannels(image);
406 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
408 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
410 PixelChannel channel=GetPixelChannelChannel(image,i);
411 PixelTrait traits=GetPixelChannelTraits(image,channel);
412 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
414 if ((traits == UndefinedPixelTrait) ||
415 (composite_traits == UndefinedPixelTrait))
417 q[i]=source[channel];
419 q+=GetPixelChannels(image);
424 Sa: normalized source alpha.
425 Da: normalized destination alpha.
427 if (GetPixelReadMask(composite_image,p) == 0)
429 p+=GetPixelChannels(composite_image);
430 channels=GetPixelChannels(composite_image);
431 if (p >= (pixels+channels*composite_image->columns))
433 q+=GetPixelChannels(image);
436 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
437 Da=QuantumScale*GetPixelAlpha(image,q);
438 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
440 PixelChannel channel=GetPixelChannelChannel(image,i);
441 PixelTrait traits=GetPixelChannelTraits(image,channel);
442 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
444 if ((traits == UndefinedPixelTrait) ||
445 (composite_traits == UndefinedPixelTrait))
447 if ((traits & CopyPixelTrait) != 0)
452 q[i]=GetPixelChannel(composite_image,channel,p);
455 if (channel == AlphaPixelChannel)
460 q[i]=ClampToQuantum(QuantumRange*(Sa+Da-Sa*Da));
465 Dc: destination color.
467 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
468 Dc=(MagickRealType) q[i];
469 Sca=QuantumScale*Sa*Sc;
470 Dca=QuantumScale*Da*Dc;
471 q[i]=ClampToQuantum(QuantumRange*(Sca+Dca*(1.0-Sa)));
473 p+=GetPixelChannels(composite_image);
474 channels=GetPixelChannels(composite_image);
475 if (p >= (pixels+channels*composite_image->columns))
477 q+=GetPixelChannels(image);
479 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
481 if (image->progress_monitor != (MagickProgressMonitor) NULL)
486 #if defined(MAGICKCORE_OPENMP_SUPPORT)
487 #pragma omp critical (MagickCore_CompositeImage)
489 proceed=SetImageProgress(image,CompositeImageTag,progress++,
491 if (proceed == MagickFalse)
495 composite_view=DestroyCacheView(composite_view);
496 image_view=DestroyCacheView(image_view);
500 MagickExport MagickBooleanType CompositeImage(Image *image,
501 const Image *composite,const CompositeOperator compose,
502 const MagickBooleanType clip_to_self,const ssize_t x_offset,
503 const ssize_t y_offset,ExceptionInfo *exception)
505 #define CompositeImageTag "Composite/Image"
526 destination_dissolve,
539 assert(image != (Image *) NULL);
540 assert(image->signature == MagickSignature);
541 if (image->debug != MagickFalse)
542 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
543 assert(composite!= (Image *) NULL);
544 assert(composite->signature == MagickSignature);
545 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
547 composite_image=CloneImage(composite,0,0,MagickTrue,exception);
548 if (composite_image == (const Image *) NULL)
550 if (IsGrayColorspace(image->colorspace) != MagickFalse)
551 (void) SetImageColorspace(image,sRGBColorspace,exception);
552 (void) SetImageColorspace(composite_image,image->colorspace,exception);
553 if ((image->alpha_trait != UndefinedPixelTrait) &&
554 (composite_image->alpha_trait == UndefinedPixelTrait))
555 (void) SetImageAlphaChannel(composite_image,SetAlphaChannel,exception);
557 if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
559 status=CompositeOverImage(image,composite_image,clip_to_self,x_offset,
561 composite_image=DestroyImage(composite_image);
564 destination_image=(Image *) NULL;
566 destination_dissolve=1.0;
568 percent_chroma=100.0;
573 case CopyCompositeOp:
575 if ((x_offset < 0) || (y_offset < 0))
577 if ((x_offset+(ssize_t) composite_image->columns) > (ssize_t) image->columns)
579 if ((y_offset+(ssize_t) composite_image->rows) > (ssize_t) image->rows)
582 composite_view=AcquireVirtualCacheView(composite_image,exception);
583 image_view=AcquireAuthenticCacheView(image,exception);
584 #if defined(MAGICKCORE_OPENMP_SUPPORT)
585 #pragma omp parallel for schedule(static,4) shared(status) \
586 magick_threads(composite_image,image,composite_image->rows,1)
588 for (y=0; y < (ssize_t) composite_image->rows; y++)
593 register const Quantum
602 if (status == MagickFalse)
604 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
606 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
607 composite_image->columns,1,exception);
608 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
613 for (x=0; x < (ssize_t) composite_image->columns; x++)
618 if (GetPixelReadMask(composite_image,p) == 0)
620 p+=GetPixelChannels(composite_image);
621 q+=GetPixelChannels(image);
624 for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
626 PixelChannel channel=GetPixelChannelChannel(composite_image,i);
627 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
629 PixelTrait traits=GetPixelChannelTraits(image,channel);
630 if ((traits == UndefinedPixelTrait) ||
631 (composite_traits == UndefinedPixelTrait))
633 SetPixelChannel(image,channel,p[i],q);
635 p+=GetPixelChannels(composite_image);
636 q+=GetPixelChannels(image);
638 sync=SyncCacheViewAuthenticPixels(image_view,exception);
639 if (sync == MagickFalse)
641 if (image->progress_monitor != (MagickProgressMonitor) NULL)
646 #if defined(MAGICKCORE_OPENMP_SUPPORT)
647 #pragma omp critical (MagickCore_CompositeImage)
649 proceed=SetImageProgress(image,CompositeImageTag,
650 (MagickOffsetType) y,image->rows);
651 if (proceed == MagickFalse)
655 composite_view=DestroyCacheView(composite_view);
656 image_view=DestroyCacheView(image_view);
657 composite_image=DestroyImage(composite_image);
660 case IntensityCompositeOp:
662 if ((x_offset < 0) || (y_offset < 0))
664 if ((x_offset+(ssize_t) composite_image->columns) > (ssize_t) image->columns)
666 if ((y_offset+(ssize_t) composite_image->rows) > (ssize_t) image->rows)
669 composite_view=AcquireVirtualCacheView(composite_image,exception);
670 image_view=AcquireAuthenticCacheView(image,exception);
671 #if defined(MAGICKCORE_OPENMP_SUPPORT)
672 #pragma omp parallel for schedule(static,4) shared(status) \
673 magick_threads(composite_image,image,composite_image->rows,1)
675 for (y=0; y < (ssize_t) composite_image->rows; y++)
680 register const Quantum
689 if (status == MagickFalse)
691 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
693 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
694 composite_image->columns,1,exception);
695 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
700 for (x=0; x < (ssize_t) composite_image->columns; x++)
705 if (GetPixelReadMask(composite_image,p) == 0)
707 p+=GetPixelChannels(composite_image);
708 q+=GetPixelChannels(image);
711 for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
712 SetPixelAlpha(image,ClampToQuantum(GetPixelIntensity(
713 composite_image,p)),q);
714 p+=GetPixelChannels(composite_image);
715 q+=GetPixelChannels(image);
717 sync=SyncCacheViewAuthenticPixels(image_view,exception);
718 if (sync == MagickFalse)
720 if (image->progress_monitor != (MagickProgressMonitor) NULL)
725 #if defined(MAGICKCORE_OPENMP_SUPPORT)
726 #pragma omp critical (MagickCore_CompositeImage)
728 proceed=SetImageProgress(image,CompositeImageTag,
729 (MagickOffsetType) y,image->rows);
730 if (proceed == MagickFalse)
734 composite_view=DestroyCacheView(composite_view);
735 image_view=DestroyCacheView(image_view);
736 composite_image=DestroyImage(composite_image);
739 case CopyAlphaCompositeOp:
740 case ChangeMaskCompositeOp:
743 Modify destination outside the overlaid region and require an alpha
744 channel to exist, to add transparency.
746 if (image->alpha_trait == UndefinedPixelTrait)
747 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
750 case BlurCompositeOp:
775 Blur Image by resampling.
777 Blur Image dictated by an overlay gradient map: X = red_channel;
778 Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
780 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
782 if (destination_image == (Image *) NULL)
784 composite_image=DestroyImage(composite_image);
788 Gather the maximum blur sigma values from user.
790 SetGeometryInfo(&geometry_info);
792 value=GetImageArtifact(image,"compose:args");
793 if (value != (const char *) NULL)
794 flags=ParseGeometry(value,&geometry_info);
795 if ((flags & WidthValue) == 0)
797 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
798 "InvalidSetting","'%s' '%s'","compose:args",value);
799 composite_image=DestroyImage(composite_image);
800 destination_image=DestroyImage(destination_image);
804 Users input sigma now needs to be converted to the EWA ellipse size.
805 The filter defaults to a sigma of 0.5 so to make this match the
806 users input the ellipse size needs to be doubled.
808 width=height=geometry_info.rho*2.0;
809 if ((flags & HeightValue) != 0 )
810 height=geometry_info.sigma*2.0;
812 Default the unrotated ellipse width and height axis vectors.
818 /* rotate vectors if a rotation angle is given */
819 if ((flags & XValue) != 0 )
824 angle=DegreesToRadians(geometry_info.xi);
825 blur.x1=width*cos(angle);
826 blur.x2=width*sin(angle);
827 blur.y1=(-height*sin(angle));
828 blur.y2=height*cos(angle);
830 /* Otherwise lets set a angle range and calculate in the loop */
833 if ((flags & YValue) != 0 )
835 angle_start=DegreesToRadians(geometry_info.xi);
836 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
839 Set up a gaussian cylindrical filter for EWA Bluring.
841 As the minimum ellipse radius of support*1.0 the EWA algorithm
842 can only produce a minimum blur of 0.5 for Gaussian (support=2.0)
843 This means that even 'No Blur' will be still a little blurry!
845 The solution (as well as the problem of preventing any user
846 expert filter settings, is to set our own user settings, then
847 restore them afterwards.
849 resample_filter=AcquireResampleFilter(image,exception);
850 SetResampleFilter(resample_filter,GaussianFilter);
852 /* do the variable blurring of each pixel in image */
853 GetPixelInfo(image,&pixel);
854 composite_view=AcquireVirtualCacheView(composite_image,exception);
855 destination_view=AcquireAuthenticCacheView(destination_image,exception);
856 for (y=0; y < (ssize_t) composite_image->rows; y++)
861 register const Quantum
870 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
872 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
874 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
875 destination_image->columns,1,exception);
876 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
878 for (x=0; x < (ssize_t) composite_image->columns; x++)
880 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
882 p+=GetPixelChannels(composite_image);
885 if (fabs((double) angle_range) > MagickEpsilon)
890 angle=angle_start+angle_range*QuantumScale*
891 GetPixelBlue(composite_image,p);
892 blur.x1=width*cos(angle);
893 blur.x2=width*sin(angle);
894 blur.y1=(-height*sin(angle));
895 blur.y2=height*cos(angle);
898 if ( x == 10 && y == 60 ) {
899 (void) fprintf(stderr, "blur.x=%lf,%lf, blur.y=%lf,%lf\n",blur.x1,
900 blur.x2,blur.y1, blur.y2);
901 (void) fprintf(stderr, "scaled by=%lf,%lf\n",QuantumScale*
902 GetPixelRed(p),QuantumScale*GetPixelGreen(p));
904 ScaleResampleFilter(resample_filter,
905 blur.x1*QuantumScale*GetPixelRed(composite_image,p),
906 blur.y1*QuantumScale*GetPixelGreen(composite_image,p),
907 blur.x2*QuantumScale*GetPixelRed(composite_image,p),
908 blur.y2*QuantumScale*GetPixelGreen(composite_image,p) );
909 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
910 (double) y_offset+y,&pixel,exception);
911 SetPixelInfoPixel(destination_image,&pixel,q);
912 p+=GetPixelChannels(composite_image);
913 q+=GetPixelChannels(destination_image);
915 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
916 if (sync == MagickFalse)
919 resample_filter=DestroyResampleFilter(resample_filter);
920 composite_view=DestroyCacheView(composite_view);
921 destination_view=DestroyCacheView(destination_view);
922 composite_image=DestroyImage(composite_image);
923 composite_image=destination_image;
926 case DisplaceCompositeOp:
927 case DistortCompositeOp:
949 Displace/Distort based on overlay gradient map:
950 X = red_channel; Y = green_channel;
951 compose:args = x_scale[,y_scale[,center.x,center.y]]
953 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
955 if (destination_image == (Image *) NULL)
957 composite_image=DestroyImage(composite_image);
960 SetGeometryInfo(&geometry_info);
962 value=GetImageArtifact(image,"compose:args");
963 if (value != (char *) NULL)
964 flags=ParseGeometry(value,&geometry_info);
965 if ((flags & (WidthValue|HeightValue)) == 0 )
967 if ((flags & AspectValue) == 0)
969 horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
971 vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
975 horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
976 vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
981 horizontal_scale=geometry_info.rho;
982 vertical_scale=geometry_info.sigma;
983 if ((flags & PercentValue) != 0)
985 if ((flags & AspectValue) == 0)
987 horizontal_scale*=(composite_image->columns-1.0)/200.0;
988 vertical_scale*=(composite_image->rows-1.0)/200.0;
992 horizontal_scale*=(image->columns-1.0)/200.0;
993 vertical_scale*=(image->rows-1.0)/200.0;
996 if ((flags & HeightValue) == 0)
997 vertical_scale=horizontal_scale;
1000 Determine fixed center point for absolute distortion map
1002 Displace offset relative to a fixed absolute point
1003 Select that point according to +X+Y user inputs.
1004 default = center of overlay image
1005 arg flag '!' = locations/percentage relative to background image
1007 center.x=(MagickRealType) x_offset;
1008 center.y=(MagickRealType) y_offset;
1009 if (compose == DistortCompositeOp)
1011 if ((flags & XValue) == 0)
1012 if ((flags & AspectValue) == 0)
1013 center.x=(MagickRealType) (x_offset+(composite_image->columns-1)/
1016 center.x=(MagickRealType) ((image->columns-1)/2);
1018 if ((flags & AspectValue) == 0)
1019 center.x=(MagickRealType) x_offset+geometry_info.xi;
1021 center.x=geometry_info.xi;
1022 if ((flags & YValue) == 0)
1023 if ((flags & AspectValue) == 0)
1024 center.y=(MagickRealType) (y_offset+(composite_image->rows-1)/
1027 center.y=(MagickRealType) ((image->rows-1)/2);
1029 if ((flags & AspectValue) == 0)
1030 center.y=(MagickRealType) y_offset+geometry_info.psi;
1032 center.y=geometry_info.psi;
1035 Shift the pixel offset point as defined by the provided,
1036 displacement/distortion map. -- Like a lens...
1038 GetPixelInfo(image,&pixel);
1039 image_view=AcquireVirtualCacheView(image,exception);
1040 composite_view=AcquireVirtualCacheView(composite_image,exception);
1041 destination_view=AcquireAuthenticCacheView(destination_image,exception);
1042 for (y=0; y < (ssize_t) composite_image->rows; y++)
1047 register const Quantum
1056 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1058 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
1060 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
1061 destination_image->columns,1,exception);
1062 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1064 for (x=0; x < (ssize_t) composite_image->columns; x++)
1066 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1068 p+=GetPixelChannels(composite_image);
1072 Displace the offset.
1074 offset.x=(double) (horizontal_scale*(GetPixelRed(composite_image,p)-
1075 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1076 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
1078 offset.y=(double) (vertical_scale*(GetPixelGreen(composite_image,p)-
1079 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1080 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
1082 (void) InterpolatePixelInfo(image,image_view,
1083 UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1086 Mask with the 'invalid pixel mask' in alpha channel.
1088 pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
1089 pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
1090 SetPixelInfoPixel(destination_image,&pixel,q);
1091 p+=GetPixelChannels(composite_image);
1092 q+=GetPixelChannels(destination_image);
1094 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1095 if (sync == MagickFalse)
1098 destination_view=DestroyCacheView(destination_view);
1099 composite_view=DestroyCacheView(composite_view);
1100 image_view=DestroyCacheView(image_view);
1101 composite_image=DestroyImage(composite_image);
1102 composite_image=destination_image;
1105 case DissolveCompositeOp:
1111 Geometry arguments to dissolve factors.
1113 value=GetImageArtifact(image,"compose:args");
1114 if (value != (char *) NULL)
1116 flags=ParseGeometry(value,&geometry_info);
1117 source_dissolve=geometry_info.rho/100.0;
1118 destination_dissolve=1.0;
1119 if ((source_dissolve-MagickEpsilon) < 0.0)
1120 source_dissolve=0.0;
1121 if ((source_dissolve+MagickEpsilon) > 1.0)
1123 destination_dissolve=2.0-source_dissolve;
1124 source_dissolve=1.0;
1126 if ((flags & SigmaValue) != 0)
1127 destination_dissolve=geometry_info.sigma/100.0;
1128 if ((destination_dissolve-MagickEpsilon) < 0.0)
1129 destination_dissolve=0.0;
1133 case BlendCompositeOp:
1138 value=GetImageArtifact(image,"compose:args");
1139 if (value != (char *) NULL)
1141 flags=ParseGeometry(value,&geometry_info);
1142 source_dissolve=geometry_info.rho/100.0;
1143 destination_dissolve=1.0-source_dissolve;
1144 if ((flags & SigmaValue) != 0)
1145 destination_dissolve=geometry_info.sigma/100.0;
1149 case MathematicsCompositeOp:
1155 Just collect the values from "compose:args", setting.
1156 Unused values are set to zero automagically.
1158 Arguments are normally a comma separated list, so this probably should
1159 be changed to some 'general comma list' parser, (with a minimum
1162 SetGeometryInfo(&geometry_info);
1163 value=GetImageArtifact(image,"compose:args");
1164 if (value != (char *) NULL)
1165 (void) ParseGeometry(value,&geometry_info);
1168 case ModulateCompositeOp:
1174 Determine the luma and chroma scale.
1176 value=GetImageArtifact(image,"compose:args");
1177 if (value != (char *) NULL)
1179 flags=ParseGeometry(value,&geometry_info);
1180 percent_luma=geometry_info.rho;
1181 if ((flags & SigmaValue) != 0)
1182 percent_chroma=geometry_info.sigma;
1186 case ThresholdCompositeOp:
1192 Determine the amount and threshold.
1194 value=GetImageArtifact(image,"compose:args");
1195 if (value != (char *) NULL)
1197 flags=ParseGeometry(value,&geometry_info);
1198 amount=geometry_info.rho;
1199 threshold=geometry_info.sigma;
1200 if ((flags & SigmaValue) == 0)
1203 threshold*=QuantumRange;
1214 midpoint=((MagickRealType) QuantumRange+1.0)/2;
1215 composite_view=AcquireVirtualCacheView(composite_image,exception);
1216 image_view=AcquireAuthenticCacheView(image,exception);
1217 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1218 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1219 magick_threads(composite_image,image,image->rows,1)
1221 for (y=0; y < (ssize_t) image->rows; y++)
1238 register const Quantum
1247 if (status == MagickFalse)
1249 if (clip_to_self != MagickFalse)
1253 if ((y-y_offset) >= (ssize_t) composite_image->rows)
1257 If pixels is NULL, y is outside overlay region.
1259 pixels=(Quantum *) NULL;
1261 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
1263 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
1264 composite_image->columns,1,exception);
1265 if (p == (const Quantum *) NULL)
1272 p-=x_offset*GetPixelChannels(composite_image);
1274 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1275 if (q == (Quantum *) NULL)
1283 GetPixelInfo(image,&destination_pixel);
1284 GetPixelInfo(composite_image,&source_pixel);
1285 for (x=0; x < (ssize_t) image->columns; x++)
1305 if (clip_to_self != MagickFalse)
1309 q+=GetPixelChannels(image);
1312 if ((x-x_offset) >= (ssize_t) composite_image->columns)
1315 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1316 ((x-x_offset) >= (ssize_t) composite_image->columns))
1319 source[MaxPixelChannels];
1324 Dc: destination color.
1326 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
1328 if (GetPixelReadMask(image,q) == 0)
1330 q+=GetPixelChannels(image);
1333 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1338 PixelChannel channel=GetPixelChannelChannel(image,i);
1339 PixelTrait traits=GetPixelChannelTraits(image,channel);
1340 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
1342 if ((traits == UndefinedPixelTrait) ||
1343 (composite_traits == UndefinedPixelTrait))
1347 case AlphaCompositeOp:
1348 case ChangeMaskCompositeOp:
1349 case CopyAlphaCompositeOp:
1350 case DstAtopCompositeOp:
1351 case DstInCompositeOp:
1353 case OutCompositeOp:
1354 case SrcInCompositeOp:
1355 case SrcOutCompositeOp:
1357 if (channel == AlphaPixelChannel)
1358 pixel=(MagickRealType) TransparentAlpha;
1360 pixel=(MagickRealType) q[i];
1363 case ClearCompositeOp:
1364 case CopyCompositeOp:
1365 case ReplaceCompositeOp:
1366 case SrcCompositeOp:
1368 if (channel == AlphaPixelChannel)
1369 pixel=(MagickRealType) TransparentAlpha;
1374 case BlendCompositeOp:
1375 case DissolveCompositeOp:
1377 if (channel == AlphaPixelChannel)
1378 pixel=destination_dissolve*GetPixelAlpha(composite_image,
1381 pixel=(MagickRealType) source[channel];
1386 pixel=(MagickRealType) source[channel];
1390 q[i]=ClampToQuantum(pixel);
1392 q+=GetPixelChannels(image);
1396 Authentic composite:
1397 Sa: normalized source alpha.
1398 Da: normalized destination alpha.
1400 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
1401 Da=QuantumScale*GetPixelAlpha(image,q);
1404 case BumpmapCompositeOp:
1406 alpha=GetPixelIntensity(composite_image,p)*Sa;
1409 case ColorBurnCompositeOp:
1410 case ColorDodgeCompositeOp:
1411 case DarkenCompositeOp:
1412 case DifferenceCompositeOp:
1413 case DivideDstCompositeOp:
1414 case DivideSrcCompositeOp:
1415 case ExclusionCompositeOp:
1416 case HardLightCompositeOp:
1417 case HardMixCompositeOp:
1418 case LinearBurnCompositeOp:
1419 case LinearDodgeCompositeOp:
1420 case LinearLightCompositeOp:
1421 case LightenCompositeOp:
1422 case MathematicsCompositeOp:
1423 case MinusDstCompositeOp:
1424 case MinusSrcCompositeOp:
1425 case ModulusAddCompositeOp:
1426 case ModulusSubtractCompositeOp:
1427 case MultiplyCompositeOp:
1428 case OverlayCompositeOp:
1429 case PegtopLightCompositeOp:
1430 case PinLightCompositeOp:
1431 case ScreenCompositeOp:
1432 case SoftLightCompositeOp:
1433 case VividLightCompositeOp:
1435 alpha=RoundToUnity(Sa+Da-Sa*Da);
1438 case DstAtopCompositeOp:
1439 case DstInCompositeOp:
1441 case SrcInCompositeOp:
1446 case DissolveCompositeOp:
1448 alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
1449 Sa+destination_dissolve*Da;
1452 case DstOverCompositeOp:
1457 case DstOutCompositeOp:
1462 case OutCompositeOp:
1463 case SrcOutCompositeOp:
1468 case OverCompositeOp:
1469 case SrcOverCompositeOp:
1474 case BlendCompositeOp:
1475 case PlusCompositeOp:
1477 alpha=RoundToUnity(Sa+Da);
1480 case XorCompositeOp:
1482 alpha=Sa+Da-2.0*Sa*Da;
1491 if (GetPixelReadMask(image,q) == 0)
1493 p+=GetPixelChannels(composite_image);
1494 q+=GetPixelChannels(image);
1499 case ColorizeCompositeOp:
1500 case HueCompositeOp:
1501 case LuminizeCompositeOp:
1502 case ModulateCompositeOp:
1503 case SaturateCompositeOp:
1505 GetPixelInfoPixel(composite_image,p,&source_pixel);
1506 GetPixelInfoPixel(image,q,&destination_pixel);
1512 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1518 PixelChannel channel=GetPixelChannelChannel(image,i);
1519 PixelTrait traits=GetPixelChannelTraits(image,channel);
1520 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
1522 if (traits == UndefinedPixelTrait)
1524 if ((composite_traits == UndefinedPixelTrait) &&
1525 (((compose != CopyAlphaCompositeOp) &&
1526 (compose != ChangeMaskCompositeOp)) ||
1527 (channel != AlphaPixelChannel)))
1531 Dc: destination color.
1533 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
1534 Dc=(MagickRealType) q[i];
1535 if ((traits & CopyPixelTrait) != 0)
1540 q[i]=ClampToQuantum(Sc);
1543 if (channel == AlphaPixelChannel)
1550 case AlphaCompositeOp:
1552 pixel=QuantumRange*Sa;
1555 case AtopCompositeOp:
1556 case CopyBlackCompositeOp:
1557 case CopyBlueCompositeOp:
1558 case CopyCyanCompositeOp:
1559 case CopyGreenCompositeOp:
1560 case CopyMagentaCompositeOp:
1561 case CopyRedCompositeOp:
1562 case CopyYellowCompositeOp:
1563 case SrcAtopCompositeOp:
1564 case DstCompositeOp:
1567 pixel=QuantumRange*Da;
1570 case ChangeMaskCompositeOp:
1575 if (Da > ((MagickRealType) QuantumRange/2.0))
1577 pixel=(MagickRealType) TransparentAlpha;
1580 equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
1581 if (equivalent != MagickFalse)
1582 pixel=(MagickRealType) TransparentAlpha;
1584 pixel=(MagickRealType) OpaqueAlpha;
1587 case ClearCompositeOp:
1589 pixel=(MagickRealType) TransparentAlpha;
1592 case ColorizeCompositeOp:
1593 case HueCompositeOp:
1594 case LuminizeCompositeOp:
1595 case SaturateCompositeOp:
1597 if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1599 pixel=QuantumRange*Da;
1602 if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
1604 pixel=QuantumRange*Sa;
1609 pixel=QuantumRange*Da;
1612 pixel=QuantumRange*Sa;
1615 case CopyAlphaCompositeOp:
1617 if (composite_traits == UndefinedPixelTrait)
1618 pixel=GetPixelIntensity(composite_image,p);
1620 pixel=QuantumRange*Sa;
1623 case CopyCompositeOp:
1624 case DisplaceCompositeOp:
1625 case DistortCompositeOp:
1626 case DstAtopCompositeOp:
1627 case ReplaceCompositeOp:
1628 case SrcCompositeOp:
1630 pixel=QuantumRange*Sa;
1633 case DarkenIntensityCompositeOp:
1635 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1636 (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
1639 case LightenIntensityCompositeOp:
1641 pixel=Sa*GetPixelIntensity(composite_image,p) >
1642 Da*GetPixelIntensity(image,q) ? Sa : Da;
1645 case ModulateCompositeOp:
1647 if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1649 pixel=QuantumRange*Da;
1652 pixel=QuantumRange*Da;
1657 pixel=QuantumRange*alpha;
1661 q[i]=ClampToQuantum(pixel);
1665 Porter-Duff compositions:
1666 Sca: source normalized color multiplied by alpha.
1667 Dca: normalized destination color multiplied by alpha.
1669 Sca=QuantumScale*Sa*Sc;
1670 Dca=QuantumScale*Da*Dc;
1673 case DarkenCompositeOp:
1674 case LightenCompositeOp:
1675 case ModulusSubtractCompositeOp:
1683 gamma=PerceptibleReciprocal(alpha);
1687 case AlphaCompositeOp:
1689 pixel=QuantumRange*Sa;
1692 case AtopCompositeOp:
1693 case SrcAtopCompositeOp:
1695 pixel=QuantumRange*(Sca*Da+Dca*(1.0-Sa));
1698 case BlendCompositeOp:
1700 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1703 case BlurCompositeOp:
1704 case DisplaceCompositeOp:
1705 case DistortCompositeOp:
1706 case CopyCompositeOp:
1707 case ReplaceCompositeOp:
1708 case SrcCompositeOp:
1710 pixel=QuantumRange*Sca;
1713 case BumpmapCompositeOp:
1715 if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1720 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1723 case ChangeMaskCompositeOp:
1728 case ClearCompositeOp:
1733 case ColorBurnCompositeOp:
1735 if ((Sca == 0.0) && (Dca == Da))
1737 pixel=QuantumRange*(Sa*Da+Dca*(1.0-Sa));
1742 pixel=QuantumRange*(Dca*(1.0-Sa));
1745 pixel=QuantumRange*(Sa*Da-Sa*Da*MagickMin(1.0,(1.0-Dca/Da)*Sa/Sca)+
1746 Sca*(1.0-Da)+Dca*(1.0-Sa));
1749 case ColorDodgeCompositeOp:
1751 if ((Sca == Sa) && (Dca == 0.0))
1753 pixel=QuantumRange*(Sca*(1.0-Da));
1758 pixel=QuantumRange*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1761 pixel=QuantumRange*(Sa*Da*MagickMin(1.0,Dca/Da*Sa/(Sa-Sca)));
1764 case ColorizeCompositeOp:
1766 if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1771 if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
1776 CompositeHCL(destination_pixel.red,destination_pixel.green,
1777 destination_pixel.blue,&sans,&sans,&luma);
1778 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1779 &hue,&chroma,&sans);
1780 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1783 case RedPixelChannel: pixel=red; break;
1784 case GreenPixelChannel: pixel=green; break;
1785 case BluePixelChannel: pixel=blue; break;
1786 default: pixel=Dc; break;
1790 case CopyAlphaCompositeOp:
1795 case CopyBlackCompositeOp:
1797 if (channel == BlackPixelChannel)
1798 pixel=(MagickRealType) (QuantumRange-
1799 GetPixelBlack(composite_image,p));
1802 case CopyBlueCompositeOp:
1803 case CopyYellowCompositeOp:
1805 if (channel == BluePixelChannel)
1806 pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1809 case CopyGreenCompositeOp:
1810 case CopyMagentaCompositeOp:
1812 if (channel == GreenPixelChannel)
1813 pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1816 case CopyRedCompositeOp:
1817 case CopyCyanCompositeOp:
1819 if (channel == RedPixelChannel)
1820 pixel=(MagickRealType) GetPixelRed(composite_image,p);
1823 case DarkenCompositeOp:
1826 Darken is equivalent to a 'Minimum' method
1827 OR a greyscale version of a binary 'Or'
1828 OR the 'Intersection' of pixel sets.
1830 if ((Sca*Da) < (Dca*Sa))
1832 pixel=QuantumRange*(Sca+Dca*(1.0-Sa));
1835 pixel=QuantumRange*(Dca+Sca*(1.0-Da));
1838 case DarkenIntensityCompositeOp:
1840 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1841 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1844 case DifferenceCompositeOp:
1846 pixel=QuantumRange*(Sca+Dca-2.0*MagickMin(Sca*Da,Dca*Sa));
1849 case DissolveCompositeOp:
1851 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1852 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1855 case DivideDstCompositeOp:
1857 if ((fabs((double) Sca) < MagickEpsilon) &&
1858 (fabs((double) Dca) < MagickEpsilon))
1860 pixel=QuantumRange*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1863 if (fabs((double) Dca) < MagickEpsilon)
1865 pixel=QuantumRange*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1868 pixel=QuantumRange*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1871 case DivideSrcCompositeOp:
1873 if ((fabs((double) Dca) < MagickEpsilon) &&
1874 (fabs((double) Sca) < MagickEpsilon))
1876 pixel=QuantumRange*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1879 if (fabs((double) Sca) < MagickEpsilon)
1881 pixel=QuantumRange*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1884 pixel=QuantumRange*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1887 case DstAtopCompositeOp:
1889 pixel=QuantumRange*(Dca*Sa+Sca*(1.0-Da));
1892 case DstCompositeOp:
1895 pixel=QuantumRange*Dca;
1898 case DstInCompositeOp:
1900 pixel=QuantumRange*(Dca*Sa);
1903 case DstOutCompositeOp:
1905 pixel=QuantumRange*(Dca*(1.0-Sa));
1908 case DstOverCompositeOp:
1910 pixel=QuantumRange*(Dca+Sca*(1.0-Da));
1913 case ExclusionCompositeOp:
1915 pixel=QuantumRange*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1919 case HardLightCompositeOp:
1923 pixel=QuantumRange*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1926 pixel=QuantumRange*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+Dca*
1930 case HardMixCompositeOp:
1939 pixel=(gamma*(1.0-Sca)*(1.0-Dca))+Sa*(1.0-Sca)*Dca+Da*(1.0-Dca)*Sca;
1942 case HueCompositeOp:
1944 if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1949 if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
1954 CompositeHCL(destination_pixel.red,destination_pixel.green,
1955 destination_pixel.blue,&hue,&chroma,&luma);
1956 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1958 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1961 case RedPixelChannel: pixel=red; break;
1962 case GreenPixelChannel: pixel=green; break;
1963 case BluePixelChannel: pixel=blue; break;
1964 default: pixel=Dc; break;
1969 case SrcInCompositeOp:
1971 pixel=QuantumRange*(Sca*Da);
1974 case LinearBurnCompositeOp:
1977 LinearBurn: as defined by Abode Photoshop, according to
1978 http://www.simplefilter.de/en/basics/mixmods.html is:
1980 f(Sc,Dc) = Sc + Dc - 1
1982 pixel=QuantumRange*(Sca+Dca-Sa*Da);
1985 case LinearDodgeCompositeOp:
1987 pixel=QuantumRange*(Sa*Sc+Da*Dc);
1990 case LinearLightCompositeOp:
1993 LinearLight: as defined by Abode Photoshop, according to
1994 http://www.simplefilter.de/en/basics/mixmods.html is:
1996 f(Sc,Dc) = Dc + 2*Sc - 1
1998 pixel=QuantumRange*((Sca-Sa)*Da+Sca+Dca);
2001 case LightenCompositeOp:
2003 if ((Sca*Da) > (Dca*Sa))
2005 pixel=QuantumRange*(Sca+Dca*(1.0-Sa));
2008 pixel=QuantumRange*(Dca+Sca*(1.0-Da));
2011 case LightenIntensityCompositeOp:
2014 Lighten is equivalent to a 'Maximum' method
2015 OR a greyscale version of a binary 'And'
2016 OR the 'Union' of pixel sets.
2018 pixel=Sa*GetPixelIntensity(composite_image,p) >
2019 Da*GetPixelIntensity(image,q) ? Sc : Dc;
2022 case LuminizeCompositeOp:
2024 if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2029 if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
2034 CompositeHCL(destination_pixel.red,destination_pixel.green,
2035 destination_pixel.blue,&hue,&chroma,&luma);
2036 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2038 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2041 case RedPixelChannel: pixel=red; break;
2042 case GreenPixelChannel: pixel=green; break;
2043 case BluePixelChannel: pixel=blue; break;
2044 default: pixel=Dc; break;
2048 case MathematicsCompositeOp:
2051 'Mathematics' a free form user control mathematical composition
2054 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
2056 Where the arguments A,B,C,D are (currently) passed to composite
2057 as a command separated 'geometry' string in "compose:args" image
2060 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
2062 Applying the SVG transparency formula (see above), we get...
2064 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
2066 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
2069 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
2070 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
2071 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
2074 case MinusDstCompositeOp:
2076 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2079 case MinusSrcCompositeOp:
2082 Minus source from destination.
2086 pixel=QuantumRange*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2089 case ModulateCompositeOp:
2094 if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2099 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
2105 CompositeHCL(destination_pixel.red,destination_pixel.green,
2106 destination_pixel.blue,&hue,&chroma,&luma);
2107 luma+=(0.01*percent_luma*offset)/midpoint;
2108 chroma*=0.01*percent_chroma;
2109 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2112 case RedPixelChannel: pixel=red; break;
2113 case GreenPixelChannel: pixel=green; break;
2114 case BluePixelChannel: pixel=blue; break;
2115 default: pixel=Dc; break;
2119 case ModulusAddCompositeOp:
2122 if (pixel > QuantumRange)
2123 pixel-=QuantumRange;
2124 pixel=gamma*(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2127 case ModulusSubtractCompositeOp:
2131 pixel+=QuantumRange;
2132 pixel=gamma*(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2135 case MultiplyCompositeOp:
2137 pixel=QuantumRange*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2140 case OutCompositeOp:
2141 case SrcOutCompositeOp:
2143 pixel=QuantumRange*(Sca*(1.0-Da));
2146 case OverCompositeOp:
2147 case SrcOverCompositeOp:
2149 pixel=QuantumRange*(Sca+Dca*(1.0-Sa));
2152 case OverlayCompositeOp:
2154 if ((2.0*Dca) <= Da)
2156 pixel=QuantumRange*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2159 pixel=QuantumRange*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+Dca*
2163 case PegtopLightCompositeOp:
2166 PegTop: A Soft-Light alternative: A continuous version of the
2167 Softlight function, producing very similar results.
2169 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2171 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2173 if (fabs((double) Da) < MagickEpsilon)
2175 pixel=QuantumRange*(Sca);
2178 pixel=QuantumRange*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-Da)+
2182 case PinLightCompositeOp:
2185 PinLight: A Photoshop 7 composition method
2186 http://www.simplefilter.de/en/basics/mixmods.html
2188 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2190 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2192 pixel=QuantumRange*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2195 if ((Dca*Sa) > (2.0*Sca*Da))
2197 pixel=QuantumRange*(Sca*Da+Sca+Dca*(1.0-Sa));
2200 pixel=QuantumRange*(Sca*(1.0-Da)+Dca);
2203 case PlusCompositeOp:
2205 pixel=QuantumRange*(Sca+Dca);
2208 case SaturateCompositeOp:
2210 if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2215 if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
2220 CompositeHCL(destination_pixel.red,destination_pixel.green,
2221 destination_pixel.blue,&hue,&chroma,&luma);
2222 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2223 &sans,&chroma,&sans);
2224 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2227 case RedPixelChannel: pixel=red; break;
2228 case GreenPixelChannel: pixel=green; break;
2229 case BluePixelChannel: pixel=blue; break;
2230 default: pixel=Dc; break;
2234 case ScreenCompositeOp:
2237 Screen: a negated multiply:
2239 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2241 pixel=QuantumRange*(Sca+Dca-Sca*Dca);
2244 case SoftLightCompositeOp:
2248 pixel=QuantumRange*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+Sca*
2249 (1.0-Da)+Dca*(1.0-Sa));
2252 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2254 pixel=QuantumRange*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*(4.0*
2255 (Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+Dca*
2259 pixel=QuantumRange*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-(Dca/
2260 Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2263 case ThresholdCompositeOp:
2269 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2274 pixel=gamma*(Dc+delta*amount);
2277 case VividLightCompositeOp:
2280 VividLight: A Photoshop 7 composition method. See
2281 http://www.simplefilter.de/en/basics/mixmods.html.
2283 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2285 if ((fabs((double) Sa) < MagickEpsilon) ||
2286 (fabs((double) (Sca-Sa)) < MagickEpsilon))
2288 pixel=QuantumRange*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2291 if ((2.0*Sca) <= Sa)
2293 pixel=QuantumRange*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*(1.0-Da)+
2297 pixel=QuantumRange*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+Dca*
2301 case XorCompositeOp:
2303 pixel=QuantumRange*(Sca*(1.0-Da)+Dca*(1.0-Sa));
2312 q[i]=ClampToQuantum(pixel);
2314 p+=GetPixelChannels(composite_image);
2315 channels=GetPixelChannels(composite_image);
2316 if (p >= (pixels+channels*composite_image->columns))
2318 q+=GetPixelChannels(image);
2320 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2322 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2327 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2328 #pragma omp critical (MagickCore_CompositeImage)
2330 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2332 if (proceed == MagickFalse)
2336 composite_view=DestroyCacheView(composite_view);
2337 image_view=DestroyCacheView(image_view);
2338 if (destination_image != (Image * ) NULL)
2339 destination_image=DestroyImage(destination_image);
2341 composite_image=DestroyImage(composite_image);
2346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2350 % T e x t u r e I m a g e %
2354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2356 % TextureImage() repeatedly tiles the texture image across and down the image
2359 % The format of the TextureImage method is:
2361 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2362 % ExceptionInfo *exception)
2364 % A description of each parameter follows:
2366 % o image: the image.
2368 % o texture_image: This image is the texture to layer on the background.
2371 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
2372 ExceptionInfo *exception)
2374 #define TextureImageTag "Texture/Image"
2389 assert(image != (Image *) NULL);
2390 if (image->debug != MagickFalse)
2391 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2392 assert(image->signature == MagickSignature);
2393 if (texture == (const Image *) NULL)
2394 return(MagickFalse);
2395 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2396 return(MagickFalse);
2397 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2398 if (texture_image == (const Image *) NULL)
2399 return(MagickFalse);
2400 (void) TransformImageColorspace(texture_image,image->colorspace,exception);
2401 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
2404 if ((image->compose != CopyCompositeOp) &&
2405 ((image->compose != OverCompositeOp) ||
2406 (image->alpha_trait != UndefinedPixelTrait) ||
2407 (texture_image->alpha_trait != UndefinedPixelTrait)))
2410 Tile texture onto the image background.
2412 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2417 if (status == MagickFalse)
2419 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2424 thread_status=CompositeImage(image,texture_image,image->compose,
2425 MagickFalse,x+texture_image->tile_offset.x,y+
2426 texture_image->tile_offset.y,exception);
2427 if (thread_status == MagickFalse)
2429 status=thread_status;
2433 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2438 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2440 if (proceed == MagickFalse)
2444 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2445 image->rows,image->rows);
2446 texture_image=DestroyImage(texture_image);
2450 Tile texture onto the image background (optimized).
2453 texture_view=AcquireVirtualCacheView(texture_image,exception);
2454 image_view=AcquireAuthenticCacheView(image,exception);
2455 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2456 #pragma omp parallel for schedule(static,4) shared(status) \
2457 magick_threads(texture_image,image,1,1)
2459 for (y=0; y < (ssize_t) image->rows; y++)
2464 register const Quantum
2477 if (status == MagickFalse)
2479 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2480 (y+texture_image->tile_offset.y) % texture_image->rows,
2481 texture_image->columns,1,exception);
2482 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2483 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2488 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2494 width=texture_image->columns;
2495 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2496 width=image->columns-x;
2497 for (j=0; j < (ssize_t) width; j++)
2502 if (GetPixelReadMask(image,q) == 0)
2504 p+=GetPixelChannels(texture_image);
2505 q+=GetPixelChannels(image);
2508 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2510 PixelChannel channel=GetPixelChannelChannel(texture_image,i);
2511 PixelTrait traits=GetPixelChannelTraits(image,channel);
2512 PixelTrait texture_traits=GetPixelChannelTraits(texture_image,
2514 if ((traits == UndefinedPixelTrait) ||
2515 (texture_traits == UndefinedPixelTrait))
2517 SetPixelChannel(image,channel,p[i],q);
2519 p+=GetPixelChannels(texture_image);
2520 q+=GetPixelChannels(image);
2523 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2524 if (sync == MagickFalse)
2526 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2531 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2533 if (proceed == MagickFalse)
2537 texture_view=DestroyCacheView(texture_view);
2538 image_view=DestroyCacheView(image_view);
2539 texture_image=DestroyImage(texture_image);