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 *source_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 canvas image, modified by he composition
107 % o source_image: the 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 canvas 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 *source_image,const MagickBooleanType clip_to_self,
289 const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
291 #define CompositeImageTag "Composite/Image"
316 value=GetImageArtifact(image,"compose:clamp");
317 if (value != (const char *) NULL)
318 clamp=IsStringTrue(value);
319 source_view=AcquireVirtualCacheView(source_image,exception);
320 image_view=AcquireAuthenticCacheView(image,exception);
321 #if defined(MAGICKCORE_OPENMP_SUPPORT)
322 #pragma omp parallel for schedule(static,4) shared(progress,status) \
323 magick_threads(source_image,image,image->rows,1)
325 for (y=0; y < (ssize_t) image->rows; y++)
330 register const Quantum
342 if (status == MagickFalse)
344 if (clip_to_self != MagickFalse)
348 if ((y-y_offset) >= (ssize_t) source_image->rows)
352 If pixels is NULL, y is outside overlay region.
354 pixels=(Quantum *) NULL;
356 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) source_image->rows))
358 p=GetCacheViewVirtualPixels(source_view,0,y-y_offset,
359 source_image->columns,1,exception);
360 if (p == (const Quantum *) NULL)
367 p-=x_offset*GetPixelChannels(source_image);
369 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
370 if (q == (Quantum *) NULL)
375 for (x=0; x < (ssize_t) image->columns; x++)
389 if (clip_to_self != MagickFalse)
393 q+=GetPixelChannels(image);
396 if ((x-x_offset) >= (ssize_t) source_image->columns)
399 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
400 ((x-x_offset) >= (ssize_t) source_image->columns))
403 source[MaxPixelChannels];
410 if (GetPixelReadMask(image,q) == 0)
412 q+=GetPixelChannels(image);
415 (void) GetOneVirtualPixel(source_image,x-x_offset,y-y_offset,
417 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
419 PixelChannel channel=GetPixelChannelChannel(image,i);
420 PixelTrait traits=GetPixelChannelTraits(image,channel);
421 PixelTrait source_traits=GetPixelChannelTraits(source_image,
423 if ((traits == UndefinedPixelTrait) ||
424 (source_traits == UndefinedPixelTrait))
426 q[i]=source[channel];
428 q+=GetPixelChannels(image);
433 Sa: normalized source alpha.
434 Da: normalized canvas alpha.
436 if (GetPixelReadMask(source_image,p) == 0)
438 p+=GetPixelChannels(source_image);
439 channels=GetPixelChannels(source_image);
440 if (p >= (pixels+channels*source_image->columns))
442 q+=GetPixelChannels(image);
445 Sa=QuantumScale*GetPixelAlpha(source_image,p);
446 Da=QuantumScale*GetPixelAlpha(image,q);
448 gamma=PerceptibleReciprocal(gamma);
449 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
451 PixelChannel channel=GetPixelChannelChannel(image,i);
452 PixelTrait traits=GetPixelChannelTraits(image,channel);
453 PixelTrait source_traits=GetPixelChannelTraits(source_image,
455 if ((traits == UndefinedPixelTrait) ||
456 (source_traits == UndefinedPixelTrait))
458 if ((traits & CopyPixelTrait) != 0)
463 q[i]=GetPixelChannel(source_image,channel,p);
466 if (channel == AlphaPixelChannel)
471 q[i]=clamp != MagickFalse ?
472 ClampPixel(QuantumRange*(Sa+Da-Sa*Da)) :
473 ClampToQuantum(QuantumRange*(Sa+Da-Sa*Da));
480 Sc=(MagickRealType) GetPixelChannel(source_image,channel,p);
481 Dc=(MagickRealType) q[i];
482 Sca=QuantumScale*Sa*Sc;
483 Dca=QuantumScale*Da*Dc;
484 q[i]=clamp != MagickFalse ?
485 ClampPixel(gamma*QuantumRange*(Sca+Dca*(1.0-Sa))) :
486 ClampToQuantum(gamma*QuantumRange*(Sca+Dca*(1.0-Sa)));
488 p+=GetPixelChannels(source_image);
489 channels=GetPixelChannels(source_image);
490 if (p >= (pixels+channels*source_image->columns))
492 q+=GetPixelChannels(image);
494 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
496 if (image->progress_monitor != (MagickProgressMonitor) NULL)
501 #if defined(MAGICKCORE_OPENMP_SUPPORT)
502 #pragma omp critical (MagickCore_CompositeImage)
504 proceed=SetImageProgress(image,CompositeImageTag,progress++,
506 if (proceed == MagickFalse)
510 source_view=DestroyCacheView(source_view);
511 image_view=DestroyCacheView(image_view);
515 MagickExport MagickBooleanType CompositeImage(Image *image,
516 const Image *composite,const CompositeOperator compose,
517 const MagickBooleanType clip_to_self,const ssize_t x_offset,
518 const ssize_t y_offset,ExceptionInfo *exception)
520 #define CompositeImageTag "Composite/Image"
558 assert(image != (Image *) NULL);
559 assert(image->signature == MagickCoreSignature);
560 if (image->debug != MagickFalse)
561 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
562 assert(composite!= (Image *) NULL);
563 assert(composite->signature == MagickCoreSignature);
564 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
566 source_image=CloneImage(composite,0,0,MagickTrue,exception);
567 if (source_image == (const Image *) NULL)
569 if (IsGrayColorspace(image->colorspace) != MagickFalse)
570 (void) SetImageColorspace(image,sRGBColorspace,exception);
571 (void) SetImageColorspace(source_image,image->colorspace,exception);
572 if ((image->alpha_trait != UndefinedPixelTrait) &&
573 (source_image->alpha_trait == UndefinedPixelTrait))
574 (void) SetImageAlphaChannel(source_image,SetAlphaChannel,exception);
575 if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
577 status=CompositeOverImage(image,source_image,clip_to_self,x_offset,
579 source_image=DestroyImage(source_image);
583 canvas_image=(Image *) NULL;
586 value=GetImageArtifact(image,"compose:clamp");
587 if (value != (const char *) NULL)
588 clamp=IsStringTrue(value);
589 SetGeometryInfo(&geometry_info);
591 percent_chroma=100.0;
596 case CopyCompositeOp:
598 if ((x_offset < 0) || (y_offset < 0))
600 if ((x_offset+(ssize_t) source_image->columns) > (ssize_t) image->columns)
602 if ((y_offset+(ssize_t) source_image->rows) > (ssize_t) image->rows)
605 source_view=AcquireVirtualCacheView(source_image,exception);
606 image_view=AcquireAuthenticCacheView(image,exception);
607 #if defined(MAGICKCORE_OPENMP_SUPPORT)
608 #pragma omp parallel for schedule(static,4) shared(status) \
609 magick_threads(source_image,image,source_image->rows,1)
611 for (y=0; y < (ssize_t) source_image->rows; y++)
616 register const Quantum
625 if (status == MagickFalse)
627 p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
629 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
630 source_image->columns,1,exception);
631 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
636 for (x=0; x < (ssize_t) source_image->columns; x++)
641 if (GetPixelReadMask(source_image,p) == 0)
643 p+=GetPixelChannels(source_image);
644 q+=GetPixelChannels(image);
647 for (i=0; i < (ssize_t) GetPixelChannels(source_image); i++)
649 PixelChannel channel=GetPixelChannelChannel(source_image,i);
650 PixelTrait source_traits=GetPixelChannelTraits(source_image,
652 PixelTrait traits=GetPixelChannelTraits(image,channel);
653 if ((traits == UndefinedPixelTrait) ||
654 (source_traits == UndefinedPixelTrait))
656 SetPixelChannel(image,channel,p[i],q);
658 p+=GetPixelChannels(source_image);
659 q+=GetPixelChannels(image);
661 sync=SyncCacheViewAuthenticPixels(image_view,exception);
662 if (sync == MagickFalse)
664 if (image->progress_monitor != (MagickProgressMonitor) NULL)
669 #if defined(MAGICKCORE_OPENMP_SUPPORT)
670 #pragma omp critical (MagickCore_CompositeImage)
672 proceed=SetImageProgress(image,CompositeImageTag,
673 (MagickOffsetType) y,image->rows);
674 if (proceed == MagickFalse)
678 source_view=DestroyCacheView(source_view);
679 image_view=DestroyCacheView(image_view);
680 source_image=DestroyImage(source_image);
683 case IntensityCompositeOp:
685 if ((x_offset < 0) || (y_offset < 0))
687 if ((x_offset+(ssize_t) source_image->columns) > (ssize_t) image->columns)
689 if ((y_offset+(ssize_t) source_image->rows) > (ssize_t) image->rows)
692 source_view=AcquireVirtualCacheView(source_image,exception);
693 image_view=AcquireAuthenticCacheView(image,exception);
694 #if defined(MAGICKCORE_OPENMP_SUPPORT)
695 #pragma omp parallel for schedule(static,4) shared(status) \
696 magick_threads(source_image,image,source_image->rows,1)
698 for (y=0; y < (ssize_t) source_image->rows; y++)
703 register const Quantum
712 if (status == MagickFalse)
714 p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
716 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
717 source_image->columns,1,exception);
718 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
723 for (x=0; x < (ssize_t) source_image->columns; x++)
725 if (GetPixelReadMask(source_image,p) == 0)
727 p+=GetPixelChannels(source_image);
728 q+=GetPixelChannels(image);
731 SetPixelAlpha(image,clamp != MagickFalse ?
732 ClampPixel(GetPixelIntensity(source_image,p)) :
733 ClampToQuantum(GetPixelIntensity(source_image,p)),q);
734 p+=GetPixelChannels(source_image);
735 q+=GetPixelChannels(image);
737 sync=SyncCacheViewAuthenticPixels(image_view,exception);
738 if (sync == MagickFalse)
740 if (image->progress_monitor != (MagickProgressMonitor) NULL)
745 #if defined(MAGICKCORE_OPENMP_SUPPORT)
746 #pragma omp critical (MagickCore_CompositeImage)
748 proceed=SetImageProgress(image,CompositeImageTag,
749 (MagickOffsetType) y,image->rows);
750 if (proceed == MagickFalse)
754 source_view=DestroyCacheView(source_view);
755 image_view=DestroyCacheView(image_view);
756 source_image=DestroyImage(source_image);
759 case CopyAlphaCompositeOp:
760 case ChangeMaskCompositeOp:
763 Modify canvas outside the overlaid region and require an alpha
764 channel to exist, to add transparency.
766 if (image->alpha_trait == UndefinedPixelTrait)
767 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
770 case BlurCompositeOp:
795 Blur Image by resampling.
797 Blur Image dictated by an overlay gradient map: X = red_channel;
798 Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
800 canvas_image=CloneImage(image,image->columns,image->rows,MagickTrue,
802 if (canvas_image == (Image *) NULL)
804 source_image=DestroyImage(source_image);
808 Gather the maximum blur sigma values from user.
811 value=GetImageArtifact(image,"compose:args");
812 if (value != (const char *) NULL)
813 flags=ParseGeometry(value,&geometry_info);
814 if ((flags & WidthValue) == 0)
816 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
817 "InvalidSetting","'%s' '%s'","compose:args",value);
818 source_image=DestroyImage(source_image);
819 canvas_image=DestroyImage(canvas_image);
823 Users input sigma now needs to be converted to the EWA ellipse size.
824 The filter defaults to a sigma of 0.5 so to make this match the
825 users input the ellipse size needs to be doubled.
827 width=height=geometry_info.rho*2.0;
828 if ((flags & HeightValue) != 0 )
829 height=geometry_info.sigma*2.0;
831 Default the unrotated ellipse width and height axis vectors.
837 /* rotate vectors if a rotation angle is given */
838 if ((flags & XValue) != 0 )
843 angle=DegreesToRadians(geometry_info.xi);
844 blur.x1=width*cos(angle);
845 blur.x2=width*sin(angle);
846 blur.y1=(-height*sin(angle));
847 blur.y2=height*cos(angle);
849 /* Otherwise lets set a angle range and calculate in the loop */
852 if ((flags & YValue) != 0 )
854 angle_start=DegreesToRadians(geometry_info.xi);
855 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
858 Set up a gaussian cylindrical filter for EWA Bluring.
860 As the minimum ellipse radius of support*1.0 the EWA algorithm
861 can only produce a minimum blur of 0.5 for Gaussian (support=2.0)
862 This means that even 'No Blur' will be still a little blurry!
864 The solution (as well as the problem of preventing any user
865 expert filter settings, is to set our own user settings, then
866 restore them afterwards.
868 resample_filter=AcquireResampleFilter(image,exception);
869 SetResampleFilter(resample_filter,GaussianFilter);
871 /* do the variable blurring of each pixel in image */
872 GetPixelInfo(image,&pixel);
873 source_view=AcquireVirtualCacheView(source_image,exception);
874 canvas_view=AcquireAuthenticCacheView(canvas_image,exception);
875 for (y=0; y < (ssize_t) source_image->rows; y++)
880 register const Quantum
889 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
891 p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
893 q=QueueCacheViewAuthenticPixels(canvas_view,0,y,canvas_image->columns,1,
895 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
897 for (x=0; x < (ssize_t) source_image->columns; x++)
899 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
901 p+=GetPixelChannels(source_image);
904 if (fabs((double) angle_range) > MagickEpsilon)
909 angle=angle_start+angle_range*QuantumScale*
910 GetPixelBlue(source_image,p);
911 blur.x1=width*cos(angle);
912 blur.x2=width*sin(angle);
913 blur.y1=(-height*sin(angle));
914 blur.y2=height*cos(angle);
917 if ( x == 10 && y == 60 ) {
918 (void) fprintf(stderr, "blur.x=%lf,%lf, blur.y=%lf,%lf\n",blur.x1,
919 blur.x2,blur.y1, blur.y2);
920 (void) fprintf(stderr, "scaled by=%lf,%lf\n",QuantumScale*
921 GetPixelRed(p),QuantumScale*GetPixelGreen(p));
923 ScaleResampleFilter(resample_filter,
924 blur.x1*QuantumScale*GetPixelRed(source_image,p),
925 blur.y1*QuantumScale*GetPixelGreen(source_image,p),
926 blur.x2*QuantumScale*GetPixelRed(source_image,p),
927 blur.y2*QuantumScale*GetPixelGreen(source_image,p) );
928 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
929 (double) y_offset+y,&pixel,exception);
930 SetPixelViaPixelInfo(canvas_image,&pixel,q);
931 p+=GetPixelChannels(source_image);
932 q+=GetPixelChannels(canvas_image);
934 sync=SyncCacheViewAuthenticPixels(canvas_view,exception);
935 if (sync == MagickFalse)
938 resample_filter=DestroyResampleFilter(resample_filter);
939 source_view=DestroyCacheView(source_view);
940 canvas_view=DestroyCacheView(canvas_view);
941 source_image=DestroyImage(source_image);
942 source_image=canvas_image;
945 case DisplaceCompositeOp:
946 case DistortCompositeOp:
968 Displace/Distort based on overlay gradient map:
969 X = red_channel; Y = green_channel;
970 compose:args = x_scale[,y_scale[,center.x,center.y]]
972 canvas_image=CloneImage(image,image->columns,image->rows,MagickTrue,
974 if (canvas_image == (Image *) NULL)
976 source_image=DestroyImage(source_image);
979 SetGeometryInfo(&geometry_info);
981 value=GetImageArtifact(image,"compose:args");
982 if (value != (char *) NULL)
983 flags=ParseGeometry(value,&geometry_info);
984 if ((flags & (WidthValue | HeightValue)) == 0 )
986 if ((flags & AspectValue) == 0)
988 horizontal_scale=(MagickRealType) (source_image->columns-1)/2.0;
989 vertical_scale=(MagickRealType) (source_image->rows-1)/2.0;
993 horizontal_scale=(MagickRealType) (image->columns-1)/2.0;
994 vertical_scale=(MagickRealType) (image->rows-1)/2.0;
999 horizontal_scale=geometry_info.rho;
1000 vertical_scale=geometry_info.sigma;
1001 if ((flags & PercentValue) != 0)
1003 if ((flags & AspectValue) == 0)
1005 horizontal_scale*=(source_image->columns-1)/200.0;
1006 vertical_scale*=(source_image->rows-1)/200.0;
1010 horizontal_scale*=(image->columns-1)/200.0;
1011 vertical_scale*=(image->rows-1)/200.0;
1014 if ((flags & HeightValue) == 0)
1015 vertical_scale=horizontal_scale;
1018 Determine fixed center point for absolute distortion map
1020 Displace offset relative to a fixed absolute point
1021 Select that point according to +X+Y user inputs.
1022 default = center of overlay image
1023 arg flag '!' = locations/percentage relative to background image
1025 center.x=(MagickRealType) x_offset;
1026 center.y=(MagickRealType) y_offset;
1027 if (compose == DistortCompositeOp)
1029 if ((flags & XValue) == 0)
1030 if ((flags & AspectValue) != 0)
1031 center.x=(MagickRealType) ((image->columns-1)/2.0);
1033 center.x=(MagickRealType) (x_offset+(source_image->columns-1)/
1036 if ((flags & AspectValue) != 0)
1037 center.x=geometry_info.xi;
1039 center.x=(MagickRealType) (x_offset+geometry_info.xi);
1040 if ((flags & YValue) == 0)
1041 if ((flags & AspectValue) != 0)
1042 center.y=(MagickRealType) ((image->rows-1)/2.0);
1044 center.y=(MagickRealType) (y_offset+(source_image->rows-1)/2.0);
1046 if ((flags & AspectValue) != 0)
1047 center.y=geometry_info.psi;
1049 center.y=(MagickRealType) (y_offset+geometry_info.psi);
1052 Shift the pixel offset point as defined by the provided,
1053 displacement/distortion map. -- Like a lens...
1055 GetPixelInfo(image,&pixel);
1056 image_view=AcquireVirtualCacheView(image,exception);
1057 source_view=AcquireVirtualCacheView(source_image,exception);
1058 canvas_view=AcquireAuthenticCacheView(canvas_image,exception);
1059 for (y=0; y < (ssize_t) source_image->rows; y++)
1064 register const Quantum
1073 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1075 p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
1077 q=QueueCacheViewAuthenticPixels(canvas_view,0,y,canvas_image->columns,1,
1079 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1081 for (x=0; x < (ssize_t) source_image->columns; x++)
1083 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1085 p+=GetPixelChannels(source_image);
1089 Displace the offset.
1091 offset.x=(double) (horizontal_scale*(GetPixelRed(source_image,p)-
1092 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1093 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
1095 offset.y=(double) (vertical_scale*(GetPixelGreen(source_image,p)-
1096 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1097 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
1099 (void) InterpolatePixelInfo(image,image_view,
1100 UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1103 Mask with the 'invalid pixel mask' in alpha channel.
1105 pixel.alpha=(MagickRealType) QuantumRange*(QuantumScale*pixel.alpha)*
1106 (QuantumScale*GetPixelAlpha(source_image,p));
1107 SetPixelViaPixelInfo(canvas_image,&pixel,q);
1108 p+=GetPixelChannels(source_image);
1109 q+=GetPixelChannels(canvas_image);
1111 sync=SyncCacheViewAuthenticPixels(canvas_view,exception);
1112 if (sync == MagickFalse)
1115 canvas_view=DestroyCacheView(canvas_view);
1116 source_view=DestroyCacheView(source_view);
1117 image_view=DestroyCacheView(image_view);
1118 source_image=DestroyImage(source_image);
1119 source_image=canvas_image;
1122 case DissolveCompositeOp:
1128 Geometry arguments to dissolve factors.
1130 value=GetImageArtifact(image,"compose:args");
1131 if (value != (char *) NULL)
1133 flags=ParseGeometry(value,&geometry_info);
1134 source_dissolve=geometry_info.rho/100.0;
1135 canvas_dissolve=1.0;
1136 if ((source_dissolve-MagickEpsilon) < 0.0)
1137 source_dissolve=0.0;
1138 if ((source_dissolve+MagickEpsilon) > 1.0)
1140 canvas_dissolve=2.0-source_dissolve;
1141 source_dissolve=1.0;
1143 if ((flags & SigmaValue) != 0)
1144 canvas_dissolve=geometry_info.sigma/100.0;
1145 if ((canvas_dissolve-MagickEpsilon) < 0.0)
1146 canvas_dissolve=0.0;
1150 case BlendCompositeOp:
1155 value=GetImageArtifact(image,"compose:args");
1156 if (value != (char *) NULL)
1158 flags=ParseGeometry(value,&geometry_info);
1159 source_dissolve=geometry_info.rho/100.0;
1160 canvas_dissolve=1.0-source_dissolve;
1161 if ((flags & SigmaValue) != 0)
1162 canvas_dissolve=geometry_info.sigma/100.0;
1166 case MathematicsCompositeOp:
1172 Just collect the values from "compose:args", setting.
1173 Unused values are set to zero automagically.
1175 Arguments are normally a comma separated list, so this probably should
1176 be changed to some 'general comma list' parser, (with a minimum
1179 SetGeometryInfo(&geometry_info);
1180 value=GetImageArtifact(image,"compose:args");
1181 if (value != (char *) NULL)
1182 (void) ParseGeometry(value,&geometry_info);
1185 case ModulateCompositeOp:
1191 Determine the luma and chroma scale.
1193 value=GetImageArtifact(image,"compose:args");
1194 if (value != (char *) NULL)
1196 flags=ParseGeometry(value,&geometry_info);
1197 percent_luma=geometry_info.rho;
1198 if ((flags & SigmaValue) != 0)
1199 percent_chroma=geometry_info.sigma;
1203 case ThresholdCompositeOp:
1209 Determine the amount and threshold.
1211 value=GetImageArtifact(image,"compose:args");
1212 if (value != (char *) NULL)
1214 flags=ParseGeometry(value,&geometry_info);
1215 amount=geometry_info.rho;
1216 threshold=geometry_info.sigma;
1217 if ((flags & SigmaValue) == 0)
1220 threshold*=QuantumRange;
1231 midpoint=((MagickRealType) QuantumRange+1.0)/2;
1232 source_view=AcquireVirtualCacheView(source_image,exception);
1233 image_view=AcquireAuthenticCacheView(image,exception);
1234 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1235 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1236 magick_threads(source_image,image,image->rows,1)
1238 for (y=0; y < (ssize_t) image->rows; y++)
1255 register const Quantum
1264 if (status == MagickFalse)
1266 if (clip_to_self != MagickFalse)
1270 if ((y-y_offset) >= (ssize_t) source_image->rows)
1274 If pixels is NULL, y is outside overlay region.
1276 pixels=(Quantum *) NULL;
1278 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) source_image->rows))
1280 p=GetCacheViewVirtualPixels(source_view,0,y-y_offset,
1281 source_image->columns,1,exception);
1282 if (p == (const Quantum *) NULL)
1289 p-=x_offset*GetPixelChannels(source_image);
1291 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1292 if (q == (Quantum *) NULL)
1300 GetPixelInfo(image,&canvas_pixel);
1301 GetPixelInfo(source_image,&source_pixel);
1302 for (x=0; x < (ssize_t) image->columns; x++)
1322 if (clip_to_self != MagickFalse)
1326 q+=GetPixelChannels(image);
1329 if ((x-x_offset) >= (ssize_t) source_image->columns)
1332 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1333 ((x-x_offset) >= (ssize_t) source_image->columns))
1336 source[MaxPixelChannels];
1343 (void) GetOneVirtualPixel(source_image,x-x_offset,y-y_offset,source,
1345 if (GetPixelReadMask(image,q) == 0)
1347 q+=GetPixelChannels(image);
1350 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1355 PixelChannel channel=GetPixelChannelChannel(image,i);
1356 PixelTrait traits=GetPixelChannelTraits(image,channel);
1357 PixelTrait source_traits=GetPixelChannelTraits(source_image,
1359 if ((traits == UndefinedPixelTrait) ||
1360 (source_traits == UndefinedPixelTrait))
1364 case AlphaCompositeOp:
1365 case ChangeMaskCompositeOp:
1366 case CopyAlphaCompositeOp:
1367 case DstAtopCompositeOp:
1368 case DstInCompositeOp:
1370 case OutCompositeOp:
1371 case SrcInCompositeOp:
1372 case SrcOutCompositeOp:
1374 if (channel == AlphaPixelChannel)
1375 pixel=(MagickRealType) TransparentAlpha;
1377 pixel=(MagickRealType) q[i];
1380 case ClearCompositeOp:
1381 case CopyCompositeOp:
1382 case ReplaceCompositeOp:
1383 case SrcCompositeOp:
1385 if (channel == AlphaPixelChannel)
1386 pixel=(MagickRealType) TransparentAlpha;
1391 case BlendCompositeOp:
1392 case DissolveCompositeOp:
1394 if (channel == AlphaPixelChannel)
1395 pixel=canvas_dissolve*GetPixelAlpha(source_image,source);
1397 pixel=(MagickRealType) source[channel];
1402 pixel=(MagickRealType) source[channel];
1406 q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
1407 ClampToQuantum(pixel);
1409 q+=GetPixelChannels(image);
1413 Authentic composite:
1414 Sa: normalized source alpha.
1415 Da: normalized canvas alpha.
1417 Sa=QuantumScale*GetPixelAlpha(source_image,p);
1418 Da=QuantumScale*GetPixelAlpha(image,q);
1421 case BumpmapCompositeOp:
1423 alpha=GetPixelIntensity(source_image,p)*Sa;
1426 case ColorBurnCompositeOp:
1427 case ColorDodgeCompositeOp:
1428 case DarkenCompositeOp:
1429 case DifferenceCompositeOp:
1430 case DivideDstCompositeOp:
1431 case DivideSrcCompositeOp:
1432 case ExclusionCompositeOp:
1433 case HardLightCompositeOp:
1434 case HardMixCompositeOp:
1435 case LinearBurnCompositeOp:
1436 case LinearDodgeCompositeOp:
1437 case LinearLightCompositeOp:
1438 case LightenCompositeOp:
1439 case MathematicsCompositeOp:
1440 case MinusDstCompositeOp:
1441 case MinusSrcCompositeOp:
1442 case ModulusAddCompositeOp:
1443 case ModulusSubtractCompositeOp:
1444 case MultiplyCompositeOp:
1445 case OverlayCompositeOp:
1446 case PegtopLightCompositeOp:
1447 case PinLightCompositeOp:
1448 case ScreenCompositeOp:
1449 case SoftLightCompositeOp:
1450 case VividLightCompositeOp:
1452 alpha=RoundToUnity(Sa+Da-Sa*Da);
1455 case DstAtopCompositeOp:
1456 case DstInCompositeOp:
1458 case SrcInCompositeOp:
1463 case DissolveCompositeOp:
1465 alpha=source_dissolve*Sa*(-canvas_dissolve*Da)+source_dissolve*Sa+
1469 case DstOverCompositeOp:
1470 case OverCompositeOp:
1471 case SrcOverCompositeOp:
1476 case DstOutCompositeOp:
1481 case OutCompositeOp:
1482 case SrcOutCompositeOp:
1487 case BlendCompositeOp:
1488 case PlusCompositeOp:
1490 alpha=RoundToUnity(source_dissolve*Sa+canvas_dissolve*Da);
1493 case XorCompositeOp:
1495 alpha=Sa+Da-2.0*Sa*Da;
1504 if (GetPixelReadMask(image,q) == 0)
1506 p+=GetPixelChannels(source_image);
1507 q+=GetPixelChannels(image);
1512 case ColorizeCompositeOp:
1513 case HueCompositeOp:
1514 case LuminizeCompositeOp:
1515 case ModulateCompositeOp:
1516 case SaturateCompositeOp:
1518 GetPixelInfoPixel(source_image,p,&source_pixel);
1519 GetPixelInfoPixel(image,q,&canvas_pixel);
1525 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1531 PixelChannel channel=GetPixelChannelChannel(image,i);
1532 PixelTrait traits=GetPixelChannelTraits(image,channel);
1533 PixelTrait source_traits=GetPixelChannelTraits(source_image,channel);
1534 if (traits == UndefinedPixelTrait)
1536 if ((source_traits == UndefinedPixelTrait) &&
1537 (((compose != CopyAlphaCompositeOp) &&
1538 (compose != ChangeMaskCompositeOp)) ||
1539 (channel != AlphaPixelChannel)))
1545 Sc=(MagickRealType) GetPixelChannel(source_image,channel,p);
1546 Dc=(MagickRealType) q[i];
1547 if ((traits & CopyPixelTrait) != 0)
1555 if (channel == AlphaPixelChannel)
1562 case AlphaCompositeOp:
1564 pixel=QuantumRange*Sa;
1567 case AtopCompositeOp:
1568 case CopyBlackCompositeOp:
1569 case CopyBlueCompositeOp:
1570 case CopyCyanCompositeOp:
1571 case CopyGreenCompositeOp:
1572 case CopyMagentaCompositeOp:
1573 case CopyRedCompositeOp:
1574 case CopyYellowCompositeOp:
1575 case SrcAtopCompositeOp:
1576 case DstCompositeOp:
1579 pixel=QuantumRange*Da;
1582 case ChangeMaskCompositeOp:
1587 if (Da > ((MagickRealType) QuantumRange/2.0))
1589 pixel=(MagickRealType) TransparentAlpha;
1592 equivalent=IsFuzzyEquivalencePixel(source_image,p,image,q);
1593 if (equivalent != MagickFalse)
1594 pixel=(MagickRealType) TransparentAlpha;
1596 pixel=(MagickRealType) OpaqueAlpha;
1599 case ClearCompositeOp:
1601 pixel=(MagickRealType) TransparentAlpha;
1604 case ColorizeCompositeOp:
1605 case HueCompositeOp:
1606 case LuminizeCompositeOp:
1607 case SaturateCompositeOp:
1609 if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1611 pixel=QuantumRange*Da;
1614 if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
1616 pixel=QuantumRange*Sa;
1621 pixel=QuantumRange*Da;
1624 pixel=QuantumRange*Sa;
1627 case CopyAlphaCompositeOp:
1629 if ((source_traits & BlendPixelTrait) == 0)
1630 pixel=GetPixelIntensity(source_image,p);
1632 pixel=QuantumRange*Sa;
1635 case CopyCompositeOp:
1636 case DisplaceCompositeOp:
1637 case DistortCompositeOp:
1638 case DstAtopCompositeOp:
1639 case ReplaceCompositeOp:
1640 case SrcCompositeOp:
1642 pixel=QuantumRange*Sa;
1645 case DarkenIntensityCompositeOp:
1647 pixel=Sa*GetPixelIntensity(source_image,p) <
1648 Da*GetPixelIntensity(image,q) ? Sa : Da;
1651 case LightenIntensityCompositeOp:
1653 pixel=Sa*GetPixelIntensity(source_image,p) >
1654 Da*GetPixelIntensity(image,q) ? Sa : Da;
1657 case ModulateCompositeOp:
1659 pixel=QuantumRange*Da;
1664 pixel=QuantumRange*alpha;
1668 q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
1669 ClampToQuantum(pixel);
1673 Porter-Duff compositions:
1674 Sca: source normalized color multiplied by alpha.
1675 Dca: normalized canvas color multiplied by alpha.
1677 Sca=QuantumScale*Sa*Sc;
1678 Dca=QuantumScale*Da*Dc;
1681 case DarkenCompositeOp:
1682 case LightenCompositeOp:
1683 case ModulusSubtractCompositeOp:
1685 gamma=PerceptibleReciprocal(1.0-alpha);
1690 gamma=PerceptibleReciprocal(alpha);
1697 case AlphaCompositeOp:
1699 pixel=QuantumRange*Sa;
1702 case AtopCompositeOp:
1703 case SrcAtopCompositeOp:
1705 pixel=QuantumRange*(Sca*Da+Dca*(1.0-Sa));
1708 case BlendCompositeOp:
1710 pixel=gamma*(source_dissolve*Sa*Sc+canvas_dissolve*Da*Dc);
1713 case BlurCompositeOp:
1714 case CopyCompositeOp:
1715 case ReplaceCompositeOp:
1716 case SrcCompositeOp:
1718 pixel=QuantumRange*Sca;
1721 case DisplaceCompositeOp:
1722 case DistortCompositeOp:
1727 case BumpmapCompositeOp:
1729 if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1734 pixel=QuantumScale*GetPixelIntensity(source_image,p)*Dc;
1737 case ChangeMaskCompositeOp:
1742 case ClearCompositeOp:
1747 case ColorBurnCompositeOp:
1749 if ((Sca == 0.0) && (Dca == Da))
1751 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1756 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1759 pixel=QuantumRange*gamma*(Sa*Da-Sa*Da*MagickMin(1.0,(1.0-Dca/Da)*Sa/
1760 Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
1763 case ColorDodgeCompositeOp:
1765 if ((Sca == Sa) && (Dca == 0.0))
1767 pixel=QuantumRange*gamma*(Sca*(1.0-Da));
1772 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1775 pixel=QuantumRange*gamma*(Sa*Da*MagickMin(1.0,Dca/Da*Sa/(Sa-Sca)));
1778 case ColorizeCompositeOp:
1780 if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1785 if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
1790 CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
1792 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1793 &hue,&chroma,&sans);
1794 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1797 case RedPixelChannel: pixel=red; break;
1798 case GreenPixelChannel: pixel=green; break;
1799 case BluePixelChannel: pixel=blue; break;
1800 default: pixel=Dc; break;
1804 case CopyAlphaCompositeOp:
1809 case CopyBlackCompositeOp:
1811 if (channel == BlackPixelChannel)
1812 pixel=(MagickRealType) (QuantumRange-
1813 GetPixelBlack(source_image,p));
1816 case CopyBlueCompositeOp:
1817 case CopyYellowCompositeOp:
1819 if (channel == BluePixelChannel)
1820 pixel=(MagickRealType) GetPixelBlue(source_image,p);
1823 case CopyGreenCompositeOp:
1824 case CopyMagentaCompositeOp:
1826 if (channel == GreenPixelChannel)
1827 pixel=(MagickRealType) GetPixelGreen(source_image,p);
1830 case CopyRedCompositeOp:
1831 case CopyCyanCompositeOp:
1833 if (channel == RedPixelChannel)
1834 pixel=(MagickRealType) GetPixelRed(source_image,p);
1837 case DarkenCompositeOp:
1840 Darken is equivalent to a 'Minimum' method
1841 OR a greyscale version of a binary 'Or'
1842 OR the 'Intersection' of pixel sets.
1844 if ((Sca*Da) < (Dca*Sa))
1846 pixel=QuantumRange*(Sca+Dca*(1.0-Sa));
1849 pixel=QuantumRange*(Dca+Sca*(1.0-Da));
1852 case DarkenIntensityCompositeOp:
1854 pixel=Sa*GetPixelIntensity(source_image,p) <
1855 Da*GetPixelIntensity(image,q) ? Sc : Dc;
1858 case DifferenceCompositeOp:
1860 pixel=QuantumRange*gamma*(Sca+Dca-2.0*MagickMin(Sca*Da,Dca*Sa));
1863 case DissolveCompositeOp:
1865 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1866 canvas_dissolve*Da*Dc+canvas_dissolve*Da*Dc);
1869 case DivideDstCompositeOp:
1871 if ((fabs((double) Sca) < MagickEpsilon) &&
1872 (fabs((double) Dca) < MagickEpsilon))
1874 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1877 if (fabs((double) Dca) < MagickEpsilon)
1879 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1882 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1885 case DivideSrcCompositeOp:
1887 if ((fabs((double) Dca) < MagickEpsilon) &&
1888 (fabs((double) Sca) < MagickEpsilon))
1890 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1893 if (fabs((double) Sca) < MagickEpsilon)
1895 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1898 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1901 case DstAtopCompositeOp:
1903 pixel=QuantumRange*(Dca*Sa+Sca*(1.0-Da));
1906 case DstCompositeOp:
1909 pixel=QuantumRange*Dca;
1912 case DstInCompositeOp:
1914 pixel=QuantumRange*(Dca*Sa);
1917 case DstOutCompositeOp:
1919 pixel=QuantumRange*(Dca*(1.0-Sa));
1922 case DstOverCompositeOp:
1924 pixel=QuantumRange*gamma*(Dca+Sca*(1.0-Da));
1927 case ExclusionCompositeOp:
1929 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1933 case HardLightCompositeOp:
1937 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-
1941 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1945 case HardMixCompositeOp:
1947 pixel=gamma*(((Sca+Dca) < 1.0) ? 0.0 : QuantumRange);
1950 case HueCompositeOp:
1952 if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1957 if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
1962 CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
1963 &hue,&chroma,&luma);
1964 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1966 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1969 case RedPixelChannel: pixel=red; break;
1970 case GreenPixelChannel: pixel=green; break;
1971 case BluePixelChannel: pixel=blue; break;
1972 default: pixel=Dc; break;
1977 case SrcInCompositeOp:
1979 pixel=QuantumRange*(Sca*Da);
1982 case LinearBurnCompositeOp:
1985 LinearBurn: as defined by Abode Photoshop, according to
1986 http://www.simplefilter.de/en/basics/mixmods.html is:
1988 f(Sc,Dc) = Sc + Dc - 1
1990 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1993 case LinearDodgeCompositeOp:
1995 pixel=gamma*(Sa*Sc+Da*Dc);
1998 case LinearLightCompositeOp:
2001 LinearLight: as defined by Abode Photoshop, according to
2002 http://www.simplefilter.de/en/basics/mixmods.html is:
2004 f(Sc,Dc) = Dc + 2*Sc - 1
2006 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
2009 case LightenCompositeOp:
2011 if ((Sca*Da) > (Dca*Sa))
2013 pixel=QuantumRange*(Sca+Dca*(1.0-Sa));
2016 pixel=QuantumRange*(Dca+Sca*(1.0-Da));
2019 case LightenIntensityCompositeOp:
2022 Lighten is equivalent to a 'Maximum' method
2023 OR a greyscale version of a binary 'And'
2024 OR the 'Union' of pixel sets.
2026 pixel=Sa*GetPixelIntensity(source_image,p) >
2027 Da*GetPixelIntensity(image,q) ? Sc : Dc;
2030 case LuminizeCompositeOp:
2032 if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2037 if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
2042 CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
2043 &hue,&chroma,&luma);
2044 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2046 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2049 case RedPixelChannel: pixel=red; break;
2050 case GreenPixelChannel: pixel=green; break;
2051 case BluePixelChannel: pixel=blue; break;
2052 default: pixel=Dc; break;
2056 case MathematicsCompositeOp:
2059 'Mathematics' a free form user control mathematical composition
2062 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
2064 Where the arguments A,B,C,D are (currently) passed to composite
2065 as a command separated 'geometry' string in "compose:args" image
2068 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
2070 Applying the SVG transparency formula (see above), we get...
2072 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
2074 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
2077 pixel=gamma*(geometry_info.rho*Sca*Dca+
2078 geometry_info.sigma*Sca*Da+geometry_info.xi*Dca*Sa+
2079 geometry_info.psi*Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2082 case MinusDstCompositeOp:
2084 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2087 case MinusSrcCompositeOp:
2090 Minus source from canvas.
2094 pixel=gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2097 case ModulateCompositeOp:
2102 if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2107 offset=(ssize_t) (GetPixelIntensity(source_image,p)-midpoint);
2113 CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
2114 &hue,&chroma,&luma);
2115 luma+=(0.01*percent_luma*offset)/midpoint;
2116 chroma*=0.01*percent_chroma;
2117 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2120 case RedPixelChannel: pixel=red; break;
2121 case GreenPixelChannel: pixel=green; break;
2122 case BluePixelChannel: pixel=blue; break;
2123 default: pixel=Dc; break;
2127 case ModulusAddCompositeOp:
2130 if (pixel > QuantumRange)
2131 pixel-=QuantumRange;
2132 pixel=(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2135 case ModulusSubtractCompositeOp:
2139 pixel+=QuantumRange;
2140 pixel=(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2143 case MultiplyCompositeOp:
2145 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2148 case OutCompositeOp:
2149 case SrcOutCompositeOp:
2151 pixel=QuantumRange*(Sca*(1.0-Da));
2154 case OverCompositeOp:
2155 case SrcOverCompositeOp:
2157 pixel=QuantumRange*gamma*(Sca+Dca*(1.0-Sa));
2160 case OverlayCompositeOp:
2162 if ((2.0*Dca) <= Da)
2164 pixel=QuantumRange*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2167 pixel=QuantumRange*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+Dca*
2171 case PegtopLightCompositeOp:
2174 PegTop: A Soft-Light alternative: A continuous version of the
2175 Softlight function, producing very similar results.
2177 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2179 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2181 if (fabs((double) Da) < MagickEpsilon)
2183 pixel=QuantumRange*gamma*(Sca);
2186 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2190 case PinLightCompositeOp:
2193 PinLight: A Photoshop 7 composition method
2194 http://www.simplefilter.de/en/basics/mixmods.html
2196 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2198 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2200 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2203 if ((Dca*Sa) > (2.0*Sca*Da))
2205 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2208 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2211 case PlusCompositeOp:
2213 pixel=QuantumRange*(Sca+Dca);
2216 case SaturateCompositeOp:
2218 if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2223 if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
2228 CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
2229 &hue,&chroma,&luma);
2230 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2231 &sans,&chroma,&sans);
2232 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2235 case RedPixelChannel: pixel=red; break;
2236 case GreenPixelChannel: pixel=green; break;
2237 case BluePixelChannel: pixel=blue; break;
2238 default: pixel=Dc; break;
2242 case ScreenCompositeOp:
2245 Screen: a negated multiply:
2247 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2249 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2252 case SoftLightCompositeOp:
2256 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2257 Sca*(1.0-Da)+Dca*(1.0-Sa));
2260 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2262 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2263 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2267 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2268 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2271 case ThresholdCompositeOp:
2277 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2282 pixel=gamma*(Dc+delta*amount);
2285 case VividLightCompositeOp:
2288 VividLight: A Photoshop 7 composition method. See
2289 http://www.simplefilter.de/en/basics/mixmods.html.
2291 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2293 if ((fabs((double) Sa) < MagickEpsilon) ||
2294 (fabs((double) (Sca-Sa)) < MagickEpsilon))
2296 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2299 if ((2.0*Sca) <= Sa)
2301 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2302 (1.0-Da)+Dca*(1.0-Sa));
2305 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+Dca*
2309 case XorCompositeOp:
2311 pixel=QuantumRange*(Sca*(1.0-Da)+Dca*(1.0-Sa));
2320 q[i]=clamp != MagickFalse ? ClampPixel(pixel) : ClampToQuantum(pixel);
2322 p+=GetPixelChannels(source_image);
2323 channels=GetPixelChannels(source_image);
2324 if (p >= (pixels+channels*source_image->columns))
2326 q+=GetPixelChannels(image);
2328 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2330 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2335 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2336 #pragma omp critical (MagickCore_CompositeImage)
2338 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2340 if (proceed == MagickFalse)
2344 source_view=DestroyCacheView(source_view);
2345 image_view=DestroyCacheView(image_view);
2346 if (canvas_image != (Image * ) NULL)
2347 canvas_image=DestroyImage(canvas_image);
2349 source_image=DestroyImage(source_image);
2354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2358 % T e x t u r e I m a g e %
2362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2364 % TextureImage() repeatedly tiles the texture image across and down the image
2367 % The format of the TextureImage method is:
2369 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2370 % ExceptionInfo *exception)
2372 % A description of each parameter follows:
2374 % o image: the image.
2376 % o texture_image: This image is the texture to layer on the background.
2379 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
2380 ExceptionInfo *exception)
2382 #define TextureImageTag "Texture/Image"
2397 assert(image != (Image *) NULL);
2398 if (image->debug != MagickFalse)
2399 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2400 assert(image->signature == MagickCoreSignature);
2401 if (texture == (const Image *) NULL)
2402 return(MagickFalse);
2403 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2404 return(MagickFalse);
2405 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2406 if (texture_image == (const Image *) NULL)
2407 return(MagickFalse);
2408 (void) TransformImageColorspace(texture_image,image->colorspace,exception);
2409 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
2412 if ((image->compose != CopyCompositeOp) &&
2413 ((image->compose != OverCompositeOp) ||
2414 (image->alpha_trait != UndefinedPixelTrait) ||
2415 (texture_image->alpha_trait != UndefinedPixelTrait)))
2418 Tile texture onto the image background.
2420 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2425 if (status == MagickFalse)
2427 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2432 thread_status=CompositeImage(image,texture_image,image->compose,
2433 MagickFalse,x+texture_image->tile_offset.x,y+
2434 texture_image->tile_offset.y,exception);
2435 if (thread_status == MagickFalse)
2437 status=thread_status;
2441 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2446 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2448 if (proceed == MagickFalse)
2452 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2453 image->rows,image->rows);
2454 texture_image=DestroyImage(texture_image);
2458 Tile texture onto the image background (optimized).
2461 texture_view=AcquireVirtualCacheView(texture_image,exception);
2462 image_view=AcquireAuthenticCacheView(image,exception);
2463 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2464 #pragma omp parallel for schedule(static,4) shared(status) \
2465 magick_threads(texture_image,image,1,1)
2467 for (y=0; y < (ssize_t) image->rows; y++)
2472 register const Quantum
2485 if (status == MagickFalse)
2487 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2488 (y+texture_image->tile_offset.y) % texture_image->rows,
2489 texture_image->columns,1,exception);
2490 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2491 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2496 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2502 width=texture_image->columns;
2503 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2504 width=image->columns-x;
2505 for (j=0; j < (ssize_t) width; j++)
2510 if (GetPixelReadMask(image,q) == 0)
2512 p+=GetPixelChannels(texture_image);
2513 q+=GetPixelChannels(image);
2516 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2518 PixelChannel channel=GetPixelChannelChannel(texture_image,i);
2519 PixelTrait traits=GetPixelChannelTraits(image,channel);
2520 PixelTrait texture_traits=GetPixelChannelTraits(texture_image,
2522 if ((traits == UndefinedPixelTrait) ||
2523 (texture_traits == UndefinedPixelTrait))
2525 SetPixelChannel(image,channel,p[i],q);
2527 p+=GetPixelChannels(texture_image);
2528 q+=GetPixelChannels(image);
2531 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2532 if (sync == MagickFalse)
2534 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2539 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2541 if (proceed == MagickFalse)
2545 texture_view=DestroyCacheView(texture_view);
2546 image_view=DestroyCacheView(image_view);
2547 texture_image=DestroyImage(texture_image);