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-2013 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/client.h"
49 #include "MagickCore/color.h"
50 #include "MagickCore/color-private.h"
51 #include "MagickCore/colorspace.h"
52 #include "MagickCore/colorspace-private.h"
53 #include "MagickCore/composite.h"
54 #include "MagickCore/composite-private.h"
55 #include "MagickCore/constitute.h"
56 #include "MagickCore/draw.h"
57 #include "MagickCore/fx.h"
58 #include "MagickCore/gem.h"
59 #include "MagickCore/geometry.h"
60 #include "MagickCore/image.h"
61 #include "MagickCore/image-private.h"
62 #include "MagickCore/list.h"
63 #include "MagickCore/log.h"
64 #include "MagickCore/monitor.h"
65 #include "MagickCore/monitor-private.h"
66 #include "MagickCore/memory_.h"
67 #include "MagickCore/option.h"
68 #include "MagickCore/pixel-accessor.h"
69 #include "MagickCore/property.h"
70 #include "MagickCore/quantum.h"
71 #include "MagickCore/resample.h"
72 #include "MagickCore/resource_.h"
73 #include "MagickCore/string_.h"
74 #include "MagickCore/thread-private.h"
75 #include "MagickCore/threshold.h"
76 #include "MagickCore/token.h"
77 #include "MagickCore/utility.h"
78 #include "MagickCore/utility-private.h"
79 #include "MagickCore/version.h"
82 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
86 % C o m p o s i t e I m a g e %
90 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
92 % CompositeImage() returns the second image composited onto the first
93 % at the specified offset, using the specified composite method.
95 % The format of the CompositeImage method is:
97 % MagickBooleanType CompositeImage(Image *image,
98 % const Image *composite_image,const CompositeOperator compose,
99 % const MagickBooleanType clip_to_self,const ssize_t x_offset,
100 % const ssize_t y_offset,ExceptionInfo *exception)
102 % A description of each parameter follows:
104 % o image: the destination image, modified by he composition
106 % o composite_image: the composite (source) image.
108 % o compose: This operator affects how the composite is applied to
109 % the image. The operators and how they are utilized are listed here
110 % http://www.w3.org/TR/SVG12/#compositing.
112 % o clip_to_self: set to MagickTrue to limit composition to area composed.
114 % o x_offset: the column offset of the composited image.
116 % o y_offset: the row offset of the composited image.
118 % Extra Controls from Image meta-data in 'composite_image' (artifacts)
121 % A string containing extra numerical arguments for specific compose
122 % methods, generally expressed as a 'geometry' or a comma separated list
125 % Compose methods needing such arguments include "BlendCompositeOp" and
126 % "DisplaceCompositeOp".
128 % o exception: return any errors or warnings in this structure.
133 Composition based on the SVG specification:
135 A Composition is defined by...
136 Color Function : f(Sc,Dc) where Sc and Dc are the normizalized colors
137 Blending areas : X = 1 for area of overlap, ie: f(Sc,Dc)
138 Y = 1 for source preserved
139 Z = 1 for destination preserved
141 Conversion to transparency (then optimized)
142 Dca' = f(Sc, Dc)*Sa*Da + Y*Sca*(1-Da) + Z*Dca*(1-Sa)
143 Da' = X*Sa*Da + Y*Sa*(1-Da) + Z*Da*(1-Sa)
146 Sca = Sc*Sa normalized Source color divided by Source alpha
147 Dca = Dc*Da normalized Dest color divided by Dest alpha
148 Dc' = Dca'/Da' the desired color value for this channel.
150 Da' in in the follow formula as 'gamma' The resulting alpla value.
152 Most functions use a blending mode of over (X=1,Y=1,Z=1) this results in
153 the following optimizations...
155 gamma = 1 - QuantiumScale*alpha * QuantiumScale*beta;
156 opacity = QuantiumScale*alpha*beta; // over blend, optimized 1-Gamma
158 The above SVG definitions also definate that Mathematical Composition
159 methods should use a 'Over' blending mode for Alpha Channel.
160 It however was not applied for composition modes of 'Plus', 'Minus',
161 the modulus versions of 'Add' and 'Subtract'.
163 Mathematical operator changes to be applied from IM v6.7...
165 1) Modulus modes 'Add' and 'Subtract' are obsoleted and renamed
166 'ModulusAdd' and 'ModulusSubtract' for clarity.
168 2) All mathematical compositions work as per the SVG specification
169 with regard to blending. This now includes 'ModulusAdd' and
172 3) When the special channel flag 'sync' (syncronize channel updates)
173 is turned off (enabled by default) then mathematical compositions are
174 only performed on the channels specified, and are applied
175 independantally of each other. In other words the mathematics is
176 performed as 'pure' mathematical operations, rather than as image
180 static inline MagickRealType MagickMin(const MagickRealType x,
181 const MagickRealType y)
188 static inline MagickRealType MagickMax(const MagickRealType x,
189 const MagickRealType y)
196 static inline MagickRealType ConvertHueToRGB(MagickRealType m1,
197 MagickRealType m2,MagickRealType hue)
204 return(m1+6.0*(m2-m1)*hue);
208 return(m1+6.0*(m2-m1)*(2.0/3.0-hue));
212 static void HCLComposite(const MagickRealType hue,const MagickRealType chroma,
213 const MagickRealType luma,MagickRealType *red,MagickRealType *green,
214 MagickRealType *blue)
227 Convert HCL to RGB colorspace.
229 assert(red != (MagickRealType *) NULL);
230 assert(green != (MagickRealType *) NULL);
231 assert(blue != (MagickRealType *) NULL);
234 x=c*(1.0-fabs(fmod(h,2.0)-1.0));
238 if ((0.0 <= h) && (h < 1.0))
244 if ((1.0 <= h) && (h < 2.0))
250 if ((2.0 <= h) && (h < 3.0))
256 if ((3.0 <= h) && (h < 4.0))
262 if ((4.0 <= h) && (h < 5.0))
268 if ((5.0 <= h) && (h < 6.0))
273 m=luma-(0.298839*r+0.586811*g+0.114350*b);
283 z=(1.0-luma)/(m+c-luma);
286 *red=QuantumRange*(z*r+m);
287 *green=QuantumRange*(z*g+m);
288 *blue=QuantumRange*(z*b+m);
291 static void CompositeHCL(const MagickRealType red,const MagickRealType green,
292 const MagickRealType blue,MagickRealType *hue,MagickRealType *chroma,
293 MagickRealType *luma)
304 Convert RGB to HCL colorspace.
306 assert(hue != (MagickRealType *) NULL);
307 assert(chroma != (MagickRealType *) NULL);
308 assert(luma != (MagickRealType *) NULL);
312 max=MagickMax(r,MagickMax(g,b));
313 c=max-(MagickRealType) MagickMin(r,MagickMin(g,b));
319 h=fmod((g-b)/c+6.0,6.0);
327 *chroma=QuantumScale*c;
328 *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
331 static MagickBooleanType CompositeOverImage(Image *image,
332 const Image *composite_image,const MagickBooleanType clip_to_self,
333 const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
335 #define CompositeImageTag "Composite/Image"
355 composite_view=AcquireVirtualCacheView(composite_image,exception);
356 image_view=AcquireAuthenticCacheView(image,exception);
357 #if defined(MAGICKCORE_OPENMP_SUPPORT)
358 #pragma omp parallel for schedule(static,4) shared(progress,status) \
359 magick_threads(composite_image,image,image->rows,1)
361 for (y=0; y < (ssize_t) image->rows; y++)
366 register const Quantum
378 if (status == MagickFalse)
380 if (clip_to_self != MagickFalse)
384 if ((y-y_offset) >= (ssize_t) composite_image->rows)
388 If pixels is NULL, y is outside overlay region.
390 pixels=(Quantum *) NULL;
392 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
394 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
395 composite_image->columns,1,exception);
396 if (p == (const Quantum *) NULL)
403 p-=x_offset*GetPixelChannels(composite_image);
405 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
406 if (q == (Quantum *) NULL)
411 for (x=0; x < (ssize_t) image->columns; x++)
426 if (clip_to_self != MagickFalse)
430 q+=GetPixelChannels(image);
433 if ((x-x_offset) >= (ssize_t) composite_image->columns)
436 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
437 ((x-x_offset) >= (ssize_t) composite_image->columns))
440 source[MaxPixelChannels];
445 Dc: destination color.
447 if (GetPixelReadMask(image,q) == 0)
449 q+=GetPixelChannels(image);
452 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
454 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
456 PixelChannel channel=GetPixelChannelChannel(image,i);
457 PixelTrait traits=GetPixelChannelTraits(image,channel);
458 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
460 if ((traits == UndefinedPixelTrait) ||
461 (composite_traits == UndefinedPixelTrait))
463 q[i]=source[channel];
465 q+=GetPixelChannels(image);
470 Sa: normalized source alpha.
471 Da: normalized destination alpha.
473 if (GetPixelReadMask(composite_image,p) == 0)
475 p+=GetPixelChannels(composite_image);
476 channels=GetPixelChannels(composite_image);
477 if (p >= (pixels+channels*composite_image->columns))
479 q+=GetPixelChannels(image);
482 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
483 Da=QuantumScale*GetPixelAlpha(image,q);
484 alpha=Sa*(-Da)+Sa+Da;
485 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
487 PixelChannel channel=GetPixelChannelChannel(image,i);
488 PixelTrait traits=GetPixelChannelTraits(image,channel);
489 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
491 if ((traits == UndefinedPixelTrait) ||
492 (composite_traits == UndefinedPixelTrait))
494 if ((traits & CopyPixelTrait) != 0)
496 if (channel != AlphaPixelChannel)
501 q[i]=GetPixelChannel(composite_image,channel,p);
507 q[i]=ClampToQuantum(QuantumRange*alpha);
512 Dc: destination color.
514 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
515 Dc=(MagickRealType) q[i];
516 gamma=PerceptibleReciprocal(alpha);
517 q[i]=ClampToQuantum(gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc));
519 p+=GetPixelChannels(composite_image);
520 channels=GetPixelChannels(composite_image);
521 if (p >= (pixels+channels*composite_image->columns))
523 q+=GetPixelChannels(image);
525 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
527 if (image->progress_monitor != (MagickProgressMonitor) NULL)
532 #if defined(MAGICKCORE_OPENMP_SUPPORT)
533 #pragma omp critical (MagickCore_CompositeImage)
535 proceed=SetImageProgress(image,CompositeImageTag,progress++,
537 if (proceed == MagickFalse)
541 composite_view=DestroyCacheView(composite_view);
542 image_view=DestroyCacheView(image_view);
546 MagickExport MagickBooleanType CompositeImage(Image *image,
547 const Image *composite,const CompositeOperator compose,
548 const MagickBooleanType clip_to_self,const ssize_t x_offset,
549 const ssize_t y_offset,ExceptionInfo *exception)
551 #define CompositeImageTag "Composite/Image"
572 destination_dissolve,
585 assert(image != (Image *) NULL);
586 assert(image->signature == MagickSignature);
587 if (image->debug != MagickFalse)
588 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
589 assert(composite!= (Image *) NULL);
590 assert(composite->signature == MagickSignature);
591 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
593 composite_image=CloneImage(composite,0,0,MagickTrue,exception);
594 if (composite_image == (const Image *) NULL)
596 if (IsGrayColorspace(image->colorspace) != MagickFalse)
597 (void) SetImageColorspace(image,sRGBColorspace,exception);
598 (void) SetImageColorspace(composite_image,image->colorspace,exception);
599 if ((image->alpha_trait == BlendPixelTrait) &&
600 (composite_image->alpha_trait != BlendPixelTrait))
601 (void) SetImageAlphaChannel(composite_image,SetAlphaChannel,exception);
602 if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
604 status=CompositeOverImage(image,composite_image,clip_to_self,x_offset,
606 composite_image=DestroyImage(composite_image);
609 destination_image=(Image *) NULL;
611 destination_dissolve=1.0;
613 percent_chroma=100.0;
618 case CopyCompositeOp:
620 if ((x_offset < 0) || (y_offset < 0))
622 if ((x_offset+(ssize_t) composite_image->columns) >= (ssize_t) image->columns)
624 if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
627 composite_view=AcquireVirtualCacheView(composite_image,exception);
628 image_view=AcquireAuthenticCacheView(image,exception);
629 #if defined(MAGICKCORE_OPENMP_SUPPORT)
630 #pragma omp parallel for schedule(static,4) shared(status) \
631 magick_threads(composite_image,image,composite_image->rows,1)
633 for (y=0; y < (ssize_t) composite_image->rows; y++)
638 register const Quantum
647 if (status == MagickFalse)
649 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
651 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
652 composite_image->columns,1,exception);
653 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
658 for (x=0; x < (ssize_t) composite_image->columns; x++)
663 if (GetPixelReadMask(composite_image,p) == 0)
665 p+=GetPixelChannels(composite_image);
666 q+=GetPixelChannels(image);
669 for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
671 PixelChannel channel=GetPixelChannelChannel(composite_image,i);
672 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
674 PixelTrait traits=GetPixelChannelTraits(image,channel);
675 if ((traits == UndefinedPixelTrait) ||
676 (composite_traits == UndefinedPixelTrait))
678 SetPixelChannel(image,channel,p[i],q);
680 p+=GetPixelChannels(composite_image);
681 q+=GetPixelChannels(image);
683 sync=SyncCacheViewAuthenticPixels(image_view,exception);
684 if (sync == MagickFalse)
686 if (image->progress_monitor != (MagickProgressMonitor) NULL)
691 #if defined(MAGICKCORE_OPENMP_SUPPORT)
692 #pragma omp critical (MagickCore_CompositeImage)
694 proceed=SetImageProgress(image,CompositeImageTag,
695 (MagickOffsetType) y,image->rows);
696 if (proceed == MagickFalse)
700 composite_view=DestroyCacheView(composite_view);
701 image_view=DestroyCacheView(image_view);
702 composite_image=DestroyImage(composite_image);
705 case CopyAlphaCompositeOp:
706 case ChangeMaskCompositeOp:
707 case IntensityCompositeOp:
710 Modify destination outside the overlaid region and require an alpha
711 channel to exist, to add transparency.
713 if (image->alpha_trait != BlendPixelTrait)
714 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
717 case BlurCompositeOp:
742 Blur Image by resampling.
744 Blur Image dictated by an overlay gradient map: X = red_channel;
745 Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
747 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
749 if (destination_image == (Image *) NULL)
751 composite_image=DestroyImage(composite_image);
755 Gather the maximum blur sigma values from user.
757 SetGeometryInfo(&geometry_info);
759 value=GetImageArtifact(image,"compose:args");
760 if (value != (const char *) NULL)
761 flags=ParseGeometry(value,&geometry_info);
762 if ((flags & WidthValue) == 0)
764 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
765 "InvalidSetting","'%s' '%s'","compose:args",value);
766 composite_image=DestroyImage(composite_image);
767 destination_image=DestroyImage(destination_image);
771 Users input sigma now needs to be converted to the EWA ellipse size.
772 The filter defaults to a sigma of 0.5 so to make this match the
773 users input the ellipse size needs to be doubled.
775 width=height=geometry_info.rho*2.0;
776 if ((flags & HeightValue) != 0 )
777 height=geometry_info.sigma*2.0;
779 Default the unrotated ellipse width and height axis vectors.
785 /* rotate vectors if a rotation angle is given */
786 if ((flags & XValue) != 0 )
791 angle=DegreesToRadians(geometry_info.xi);
792 blur.x1=width*cos(angle);
793 blur.x2=width*sin(angle);
794 blur.y1=(-height*sin(angle));
795 blur.y2=height*cos(angle);
797 /* Otherwise lets set a angle range and calculate in the loop */
800 if ((flags & YValue) != 0 )
802 angle_start=DegreesToRadians(geometry_info.xi);
803 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
806 Set up a gaussian cylindrical filter for EWA Bluring.
808 As the minimum ellipse radius of support*1.0 the EWA algorithm
809 can only produce a minimum blur of 0.5 for Gaussian (support=2.0)
810 This means that even 'No Blur' will be still a little blurry!
812 The solution (as well as the problem of preventing any user
813 expert filter settings, is to set our own user settings, then
814 restore them afterwards.
816 resample_filter=AcquireResampleFilter(image,exception);
817 SetResampleFilter(resample_filter,GaussianFilter);
819 /* do the variable blurring of each pixel in image */
820 GetPixelInfo(image,&pixel);
821 composite_view=AcquireVirtualCacheView(composite_image,exception);
822 destination_view=AcquireAuthenticCacheView(destination_image,exception);
823 for (y=0; y < (ssize_t) composite_image->rows; y++)
828 register const Quantum
837 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
839 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
841 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
842 destination_image->columns,1,exception);
843 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
845 for (x=0; x < (ssize_t) composite_image->columns; x++)
847 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
849 p+=GetPixelChannels(composite_image);
852 if (fabs(angle_range) > MagickEpsilon)
857 angle=angle_start+angle_range*QuantumScale*
858 GetPixelBlue(composite_image,p);
859 blur.x1=width*cos(angle);
860 blur.x2=width*sin(angle);
861 blur.y1=(-height*sin(angle));
862 blur.y2=height*cos(angle);
865 if ( x == 10 && y == 60 ) {
866 (void) fprintf(stderr, "blur.x=%lf,%lf, blur.y=%lf,%lf\n",blur.x1,
867 blur.x2,blur.y1, blur.y2);
868 (void) fprintf(stderr, "scaled by=%lf,%lf\n",QuantumScale*
869 GetPixelRed(p),QuantumScale*GetPixelGreen(p));
871 ScaleResampleFilter(resample_filter,
872 blur.x1*QuantumScale*GetPixelRed(composite_image,p),
873 blur.y1*QuantumScale*GetPixelGreen(composite_image,p),
874 blur.x2*QuantumScale*GetPixelRed(composite_image,p),
875 blur.y2*QuantumScale*GetPixelGreen(composite_image,p) );
876 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
877 (double) y_offset+y,&pixel,exception);
878 SetPixelInfoPixel(destination_image,&pixel,q);
879 p+=GetPixelChannels(composite_image);
880 q+=GetPixelChannels(destination_image);
882 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
883 if (sync == MagickFalse)
886 resample_filter=DestroyResampleFilter(resample_filter);
887 composite_view=DestroyCacheView(composite_view);
888 destination_view=DestroyCacheView(destination_view);
889 composite_image=DestroyImage(composite_image);
890 composite_image=destination_image;
893 case DisplaceCompositeOp:
894 case DistortCompositeOp:
916 Displace/Distort based on overlay gradient map:
917 X = red_channel; Y = green_channel;
918 compose:args = x_scale[,y_scale[,center.x,center.y]]
920 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
922 if (destination_image == (Image *) NULL)
924 composite_image=DestroyImage(composite_image);
927 SetGeometryInfo(&geometry_info);
929 value=GetImageArtifact(composite_image,"compose:args");
930 if (value != (char *) NULL)
931 flags=ParseGeometry(value,&geometry_info);
932 if ((flags & (WidthValue|HeightValue)) == 0 )
934 if ((flags & AspectValue) == 0)
936 horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
938 vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
942 horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
943 vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
948 horizontal_scale=geometry_info.rho;
949 vertical_scale=geometry_info.sigma;
950 if ((flags & PercentValue) != 0)
952 if ((flags & AspectValue) == 0)
954 horizontal_scale*=(composite_image->columns-1.0)/200.0;
955 vertical_scale*=(composite_image->rows-1.0)/200.0;
959 horizontal_scale*=(image->columns-1.0)/200.0;
960 vertical_scale*=(image->rows-1.0)/200.0;
963 if ((flags & HeightValue) == 0)
964 vertical_scale=horizontal_scale;
967 Determine fixed center point for absolute distortion map
969 Displace offset relative to a fixed absolute point
970 Select that point according to +X+Y user inputs.
971 default = center of overlay image
972 arg flag '!' = locations/percentage relative to background image
974 center.x=(MagickRealType) x_offset;
975 center.y=(MagickRealType) y_offset;
976 if (compose == DistortCompositeOp)
978 if ((flags & XValue) == 0)
979 if ((flags & AspectValue) == 0)
980 center.x=(MagickRealType) (x_offset+(composite_image->columns-1)/
983 center.x=(MagickRealType) ((image->columns-1)/2);
985 if ((flags & AspectValue) == 0)
986 center.x=(MagickRealType) x_offset+geometry_info.xi;
988 center.x=geometry_info.xi;
989 if ((flags & YValue) == 0)
990 if ((flags & AspectValue) == 0)
991 center.y=(MagickRealType) (y_offset+(composite_image->rows-1)/
994 center.y=(MagickRealType) ((image->rows-1)/2);
996 if ((flags & AspectValue) == 0)
997 center.y=(MagickRealType) y_offset+geometry_info.psi;
999 center.y=geometry_info.psi;
1002 Shift the pixel offset point as defined by the provided,
1003 displacement/distortion map. -- Like a lens...
1005 GetPixelInfo(image,&pixel);
1006 image_view=AcquireVirtualCacheView(image,exception);
1007 composite_view=AcquireVirtualCacheView(composite_image,exception);
1008 destination_view=AcquireAuthenticCacheView(destination_image,exception);
1009 for (y=0; y < (ssize_t) composite_image->rows; y++)
1014 register const Quantum
1023 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1025 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
1027 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
1028 destination_image->columns,1,exception);
1029 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1031 for (x=0; x < (ssize_t) composite_image->columns; x++)
1033 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1035 p+=GetPixelChannels(composite_image);
1039 Displace the offset.
1041 offset.x=(double) (horizontal_scale*(GetPixelRed(composite_image,p)-
1042 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1043 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
1045 offset.y=(double) (vertical_scale*(GetPixelGreen(composite_image,p)-
1046 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1047 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
1049 (void) InterpolatePixelInfo(image,image_view,
1050 UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1053 Mask with the 'invalid pixel mask' in alpha channel.
1055 pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
1056 pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
1057 SetPixelInfoPixel(destination_image,&pixel,q);
1058 p+=GetPixelChannels(composite_image);
1059 q+=GetPixelChannels(destination_image);
1061 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1062 if (sync == MagickFalse)
1065 destination_view=DestroyCacheView(destination_view);
1066 composite_view=DestroyCacheView(composite_view);
1067 image_view=DestroyCacheView(image_view);
1068 composite_image=DestroyImage(composite_image);
1069 composite_image=destination_image;
1072 case DissolveCompositeOp:
1078 Geometry arguments to dissolve factors.
1080 value=GetImageArtifact(composite_image,"compose:args");
1081 if (value != (char *) NULL)
1083 flags=ParseGeometry(value,&geometry_info);
1084 source_dissolve=geometry_info.rho/100.0;
1085 destination_dissolve=1.0;
1086 if ((source_dissolve-MagickEpsilon) < 0.0)
1087 source_dissolve=0.0;
1088 if ((source_dissolve+MagickEpsilon) > 1.0)
1090 destination_dissolve=2.0-source_dissolve;
1091 source_dissolve=1.0;
1093 if ((flags & SigmaValue) != 0)
1094 destination_dissolve=geometry_info.sigma/100.0;
1095 if ((destination_dissolve-MagickEpsilon) < 0.0)
1096 destination_dissolve=0.0;
1097 /* posible speed up? -- from IMv6 update
1098 clip_to_self=MagickFalse;
1099 if ((destination_dissolve+MagickEpsilon) > 1.0 )
1101 destination_dissolve=1.0;
1102 clip_to_self=MagickTrue;
1108 case BlendCompositeOp:
1113 value=GetImageArtifact(composite_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-source_dissolve;
1119 if ((flags & SigmaValue) != 0)
1120 destination_dissolve=geometry_info.sigma/100.0;
1124 case MathematicsCompositeOp:
1130 Just collect the values from "compose:args", setting.
1131 Unused values are set to zero automagically.
1133 Arguments are normally a comma separated list, so this probably should
1134 be changed to some 'general comma list' parser, (with a minimum
1137 SetGeometryInfo(&geometry_info);
1138 value=GetImageArtifact(composite_image,"compose:args");
1139 if (value != (char *) NULL)
1140 (void) ParseGeometry(value,&geometry_info);
1143 case ModulateCompositeOp:
1149 Determine the luma and chroma scale.
1151 value=GetImageArtifact(composite_image,"compose:args");
1152 if (value != (char *) NULL)
1154 flags=ParseGeometry(value,&geometry_info);
1155 percent_luma=geometry_info.rho;
1156 if ((flags & SigmaValue) != 0)
1157 percent_chroma=geometry_info.sigma;
1161 case ThresholdCompositeOp:
1167 Determine the amount and threshold.
1169 value=GetImageArtifact(composite_image,"compose:args");
1170 if (value != (char *) NULL)
1172 flags=ParseGeometry(value,&geometry_info);
1173 amount=geometry_info.rho;
1174 threshold=geometry_info.sigma;
1175 if ((flags & SigmaValue) == 0)
1178 threshold*=QuantumRange;
1189 midpoint=((MagickRealType) QuantumRange+1.0)/2;
1190 composite_view=AcquireVirtualCacheView(composite_image,exception);
1191 image_view=AcquireAuthenticCacheView(image,exception);
1192 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1193 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1194 magick_threads(composite_image,image,image->rows,1)
1196 for (y=0; y < (ssize_t) image->rows; y++)
1213 register const Quantum
1222 if (status == MagickFalse)
1224 if (clip_to_self != MagickFalse)
1228 if ((y-y_offset) >= (ssize_t) composite_image->rows)
1232 If pixels is NULL, y is outside overlay region.
1234 pixels=(Quantum *) NULL;
1236 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
1238 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
1239 composite_image->columns,1,exception);
1240 if (p == (const Quantum *) NULL)
1247 p-=x_offset*GetPixelChannels(composite_image);
1249 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1250 if (q == (Quantum *) NULL)
1258 GetPixelInfo(image,&destination_pixel);
1259 GetPixelInfo(composite_image,&source_pixel);
1260 for (x=0; x < (ssize_t) image->columns; x++)
1280 if (clip_to_self != MagickFalse)
1284 q+=GetPixelChannels(image);
1287 if ((x-x_offset) >= (ssize_t) composite_image->columns)
1290 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1291 ((x-x_offset) >= (ssize_t) composite_image->columns))
1294 source[MaxPixelChannels];
1299 Dc: destination color.
1301 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
1303 if (GetPixelReadMask(image,q) == 0)
1305 q+=GetPixelChannels(image);
1308 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1313 PixelChannel channel=GetPixelChannelChannel(image,i);
1314 PixelTrait traits=GetPixelChannelTraits(image,channel);
1315 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
1317 if ((traits == UndefinedPixelTrait) ||
1318 (composite_traits == UndefinedPixelTrait))
1322 case AlphaCompositeOp:
1323 case ChangeMaskCompositeOp:
1324 case CopyAlphaCompositeOp:
1325 case DstAtopCompositeOp:
1326 case DstInCompositeOp:
1328 case IntensityCompositeOp:
1329 case OutCompositeOp:
1330 case SrcInCompositeOp:
1331 case SrcOutCompositeOp:
1333 pixel=(MagickRealType) q[i];
1334 if (channel == AlphaPixelChannel)
1335 pixel=(MagickRealType) TransparentAlpha;
1338 case ClearCompositeOp:
1339 case CopyCompositeOp:
1340 case ReplaceCompositeOp:
1341 case SrcCompositeOp:
1343 if (channel == AlphaPixelChannel)
1345 pixel=(MagickRealType) TransparentAlpha;
1351 case BlendCompositeOp:
1352 case DissolveCompositeOp:
1354 if (channel == AlphaPixelChannel)
1356 pixel=destination_dissolve*GetPixelAlpha(composite_image,
1360 pixel=(MagickRealType) source[channel];
1365 pixel=(MagickRealType) source[channel];
1369 q[i]=ClampToQuantum(pixel);
1371 q+=GetPixelChannels(image);
1375 Authentic composite:
1376 Sa: normalized source alpha.
1377 Da: normalized destination alpha.
1379 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
1380 Da=QuantumScale*GetPixelAlpha(image,q);
1383 case BumpmapCompositeOp:
1385 alpha=GetPixelIntensity(composite_image,p)*Sa;
1388 case ColorBurnCompositeOp:
1389 case ColorDodgeCompositeOp:
1390 case DifferenceCompositeOp:
1391 case DivideDstCompositeOp:
1392 case DivideSrcCompositeOp:
1393 case ExclusionCompositeOp:
1394 case HardLightCompositeOp:
1395 case LinearBurnCompositeOp:
1396 case LinearDodgeCompositeOp:
1397 case LinearLightCompositeOp:
1398 case MathematicsCompositeOp:
1399 case MinusDstCompositeOp:
1400 case MinusSrcCompositeOp:
1401 case ModulusAddCompositeOp:
1402 case ModulusSubtractCompositeOp:
1403 case MultiplyCompositeOp:
1404 case OverlayCompositeOp:
1405 case PegtopLightCompositeOp:
1406 case PinLightCompositeOp:
1407 case ScreenCompositeOp:
1408 case SoftLightCompositeOp:
1409 case VividLightCompositeOp:
1411 alpha=RoundToUnity(Sa+Da-Sa*Da);
1414 case DarkenCompositeOp:
1415 case DstAtopCompositeOp:
1416 case DstInCompositeOp:
1418 case LightenCompositeOp:
1419 case SrcInCompositeOp:
1424 case DissolveCompositeOp:
1426 alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
1427 Sa+destination_dissolve*Da;
1430 case DstOverCompositeOp:
1432 alpha=Da*(-Sa)+Da+Sa;
1435 case DstOutCompositeOp:
1440 case OutCompositeOp:
1441 case SrcOutCompositeOp:
1446 case OverCompositeOp:
1447 case SrcOverCompositeOp:
1449 alpha=Sa*(-Da)+Sa+Da;
1452 case BlendCompositeOp:
1453 case PlusCompositeOp:
1455 alpha=RoundToUnity(Sa+Da);
1458 case XorCompositeOp:
1460 alpha=Sa+Da-2.0*Sa*Da;
1469 if (GetPixelReadMask(image,q) == 0)
1471 p+=GetPixelChannels(composite_image);
1472 q+=GetPixelChannels(image);
1477 case ColorizeCompositeOp:
1478 case HueCompositeOp:
1479 case LuminizeCompositeOp:
1480 case ModulateCompositeOp:
1481 case SaturateCompositeOp:
1483 GetPixelInfoPixel(composite_image,p,&source_pixel);
1484 GetPixelInfoPixel(image,q,&destination_pixel);
1490 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1496 PixelChannel channel=GetPixelChannelChannel(image,i);
1497 PixelTrait traits=GetPixelChannelTraits(image,channel);
1498 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
1500 if (traits == UndefinedPixelTrait)
1502 if ((compose != IntensityCompositeOp) &&
1503 (composite_traits == UndefinedPixelTrait))
1507 Dc: destination color.
1509 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
1510 Dc=(MagickRealType) q[i];
1511 if ((traits & CopyPixelTrait) != 0)
1513 if (channel != AlphaPixelChannel)
1518 q[i]=ClampToQuantum(Sc);
1526 case AlphaCompositeOp:
1528 pixel=QuantumRange*Sa;
1531 case AtopCompositeOp:
1532 case CopyBlackCompositeOp:
1533 case CopyBlueCompositeOp:
1534 case CopyCyanCompositeOp:
1535 case CopyGreenCompositeOp:
1536 case CopyMagentaCompositeOp:
1537 case CopyRedCompositeOp:
1538 case CopyYellowCompositeOp:
1539 case SrcAtopCompositeOp:
1540 case DstCompositeOp:
1543 pixel=QuantumRange*Da;
1546 case ChangeMaskCompositeOp:
1551 if (Da > ((MagickRealType) QuantumRange/2.0))
1553 pixel=(MagickRealType) TransparentAlpha;
1556 equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
1557 if (equivalent != MagickFalse)
1559 pixel=(MagickRealType) TransparentAlpha;
1562 pixel=(MagickRealType) OpaqueAlpha;
1565 case ClearCompositeOp:
1567 pixel=(MagickRealType) TransparentAlpha;
1570 case ColorizeCompositeOp:
1571 case HueCompositeOp:
1572 case LuminizeCompositeOp:
1573 case SaturateCompositeOp:
1575 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1577 pixel=QuantumRange*Da;
1580 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1582 pixel=QuantumRange*Sa;
1587 pixel=QuantumRange*Da;
1590 pixel=QuantumRange*Sa;
1593 case CopyAlphaCompositeOp:
1595 pixel=QuantumRange*Sa;
1596 if (composite_image->alpha_trait == BlendPixelTrait)
1597 pixel=GetPixelIntensity(composite_image,p);
1600 case CopyCompositeOp:
1601 case DisplaceCompositeOp:
1602 case DistortCompositeOp:
1603 case DstAtopCompositeOp:
1604 case ReplaceCompositeOp:
1605 case SrcCompositeOp:
1607 pixel=QuantumRange*Sa;
1610 case DarkenIntensityCompositeOp:
1612 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1613 (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
1616 case IntensityCompositeOp:
1618 pixel=GetPixelIntensity(composite_image,p);
1621 case LightenIntensityCompositeOp:
1623 pixel=Sa*GetPixelIntensity(composite_image,p) >
1624 Da*GetPixelIntensity(image,q) ? Sa : Da;
1627 case ModulateCompositeOp:
1629 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1631 pixel=QuantumRange*Da;
1634 pixel=QuantumRange*Da;
1639 pixel=QuantumRange*alpha;
1643 q[i]=ClampToQuantum(pixel);
1647 Porter-Duff compositions:
1648 Sca: source normalized color multiplied by alpha.
1649 Dca: normalized destination color multiplied by alpha.
1651 Sca=QuantumScale*Sa*Sc;
1652 Dca=QuantumScale*Da*Dc;
1655 case DarkenCompositeOp:
1656 case LightenCompositeOp:
1657 case ModulusSubtractCompositeOp:
1665 gamma=PerceptibleReciprocal(alpha);
1669 case AlphaCompositeOp:
1671 pixel=QuantumRange*Sa;
1674 case AtopCompositeOp:
1675 case SrcAtopCompositeOp:
1677 pixel=Sc*Sa+Dc*(1.0-Sa);
1680 case BlendCompositeOp:
1682 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1685 case BlurCompositeOp:
1686 case DisplaceCompositeOp:
1687 case DistortCompositeOp:
1688 case CopyCompositeOp:
1689 case ReplaceCompositeOp:
1690 case SrcCompositeOp:
1695 case BumpmapCompositeOp:
1697 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1702 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1705 case ChangeMaskCompositeOp:
1710 case ClearCompositeOp:
1715 case ColorBurnCompositeOp:
1718 Refer to the March 2009 SVG specification.
1720 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1722 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1725 if (Sca < MagickEpsilon)
1727 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1730 pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
1731 Sca*(1.0-Da)+Dca*(1.0-Sa));
1734 case ColorDodgeCompositeOp:
1736 if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1738 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1741 if (fabs(Sca-Sa) < MagickEpsilon)
1743 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1746 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1750 case ColorizeCompositeOp:
1752 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1757 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1762 CompositeHCL(destination_pixel.red,destination_pixel.green,
1763 destination_pixel.blue,&sans,&sans,&luma);
1764 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1765 &hue,&chroma,&sans);
1766 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1769 case RedPixelChannel: pixel=red; break;
1770 case GreenPixelChannel: pixel=green; break;
1771 case BluePixelChannel: pixel=blue; break;
1772 default: pixel=Dc; break;
1776 case CopyAlphaCompositeOp:
1777 case IntensityCompositeOp:
1782 case CopyBlackCompositeOp:
1784 if (channel == BlackPixelChannel)
1785 pixel=(MagickRealType) GetPixelBlack(composite_image,p);
1788 case CopyBlueCompositeOp:
1789 case CopyYellowCompositeOp:
1791 if (channel == BluePixelChannel)
1792 pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1795 case CopyGreenCompositeOp:
1796 case CopyMagentaCompositeOp:
1798 if (channel == GreenPixelChannel)
1799 pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1802 case CopyRedCompositeOp:
1803 case CopyCyanCompositeOp:
1805 if (channel == RedPixelChannel)
1806 pixel=(MagickRealType) GetPixelRed(composite_image,p);
1809 case DarkenCompositeOp:
1812 Darken is equivalent to a 'Minimum' method
1813 OR a greyscale version of a binary 'Or'
1814 OR the 'Intersection' of pixel sets.
1818 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1821 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1824 case DarkenIntensityCompositeOp:
1826 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1827 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1830 case DifferenceCompositeOp:
1832 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1835 case DissolveCompositeOp:
1837 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1838 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1841 case DivideDstCompositeOp:
1843 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1845 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1848 if (fabs(Dca) < MagickEpsilon)
1850 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1853 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1856 case DivideSrcCompositeOp:
1858 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1860 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1863 if (fabs(Sca) < MagickEpsilon)
1865 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1868 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1871 case DstAtopCompositeOp:
1873 pixel=Dc*Da+Sc*(1.0-Da);
1876 case DstCompositeOp:
1882 case DstInCompositeOp:
1884 pixel=gamma*(Sa*Dc*Sa);
1887 case DstOutCompositeOp:
1889 pixel=gamma*(Da*Dc*(1.0-Sa));
1892 case DstOverCompositeOp:
1894 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1897 case ExclusionCompositeOp:
1899 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1903 case HardLightCompositeOp:
1907 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1911 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1915 case HueCompositeOp:
1917 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1922 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1927 CompositeHCL(destination_pixel.red,destination_pixel.green,
1928 destination_pixel.blue,&hue,&chroma,&luma);
1929 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1931 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1934 case RedPixelChannel: pixel=red; break;
1935 case GreenPixelChannel: pixel=green; break;
1936 case BluePixelChannel: pixel=blue; break;
1937 default: pixel=Dc; break;
1942 case SrcInCompositeOp:
1944 pixel=gamma*(Da*Sc*Da);
1947 case LinearBurnCompositeOp:
1950 LinearBurn: as defined by Abode Photoshop, according to
1951 http://www.simplefilter.de/en/basics/mixmods.html is:
1953 f(Sc,Dc) = Sc + Dc - 1
1955 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1958 case LinearDodgeCompositeOp:
1960 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1963 case LinearLightCompositeOp:
1966 LinearLight: as defined by Abode Photoshop, according to
1967 http://www.simplefilter.de/en/basics/mixmods.html is:
1969 f(Sc,Dc) = Dc + 2*Sc - 1
1971 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1974 case LightenCompositeOp:
1978 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1981 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1984 case LightenIntensityCompositeOp:
1987 Lighten is equivalent to a 'Maximum' method
1988 OR a greyscale version of a binary 'And'
1989 OR the 'Union' of pixel sets.
1991 pixel=Sa*GetPixelIntensity(composite_image,p) >
1992 Da*GetPixelIntensity(image,q) ? Sc : Dc;
1995 case LuminizeCompositeOp:
1997 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2002 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2007 CompositeHCL(destination_pixel.red,destination_pixel.green,
2008 destination_pixel.blue,&hue,&chroma,&luma);
2009 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2011 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2014 case RedPixelChannel: pixel=red; break;
2015 case GreenPixelChannel: pixel=green; break;
2016 case BluePixelChannel: pixel=blue; break;
2017 default: pixel=Dc; break;
2021 case MathematicsCompositeOp:
2024 'Mathematics' a free form user control mathematical composition
2027 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
2029 Where the arguments A,B,C,D are (currently) passed to composite
2030 as a command separated 'geometry' string in "compose:args" image
2033 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
2035 Applying the SVG transparency formula (see above), we get...
2037 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
2039 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
2042 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
2043 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
2044 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
2047 case MinusDstCompositeOp:
2049 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2052 case MinusSrcCompositeOp:
2055 Minus source from destination.
2059 pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2062 case ModulateCompositeOp:
2067 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2072 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
2078 CompositeHCL(destination_pixel.red,destination_pixel.green,
2079 destination_pixel.blue,&hue,&chroma,&luma);
2080 luma+=(0.01*percent_luma*offset)/midpoint;
2081 chroma*=0.01*percent_chroma;
2082 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2085 case RedPixelChannel: pixel=red; break;
2086 case GreenPixelChannel: pixel=green; break;
2087 case BluePixelChannel: pixel=blue; break;
2088 default: pixel=Dc; break;
2092 case ModulusAddCompositeOp:
2095 if (pixel > QuantumRange)
2096 pixel-=(QuantumRange+1.0);
2097 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2100 case ModulusSubtractCompositeOp:
2104 pixel+=(QuantumRange+1.0);
2105 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2108 case MultiplyCompositeOp:
2110 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2113 case OutCompositeOp:
2114 case SrcOutCompositeOp:
2116 pixel=gamma*(Sa*Sc*(1.0-Da));
2119 case OverCompositeOp:
2120 case SrcOverCompositeOp:
2122 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2125 case OverlayCompositeOp:
2129 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2133 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2137 case PegtopLightCompositeOp:
2140 PegTop: A Soft-Light alternative: A continuous version of the
2141 Softlight function, producing very similar results.
2143 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2145 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2147 if (fabs(Da) < MagickEpsilon)
2149 pixel=QuantumRange*gamma*(Sca);
2152 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2156 case PinLightCompositeOp:
2159 PinLight: A Photoshop 7 composition method
2160 http://www.simplefilter.de/en/basics/mixmods.html
2162 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2164 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2166 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2169 if ((Dca*Sa) > (2.0*Sca*Da))
2171 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2174 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2177 case PlusCompositeOp:
2179 pixel=gamma*(Sa*Sc+Da*Dc);
2182 case SaturateCompositeOp:
2184 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2189 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2194 CompositeHCL(destination_pixel.red,destination_pixel.green,
2195 destination_pixel.blue,&hue,&chroma,&luma);
2196 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2197 &sans,&chroma,&sans);
2198 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2201 case RedPixelChannel: pixel=red; break;
2202 case GreenPixelChannel: pixel=green; break;
2203 case BluePixelChannel: pixel=blue; break;
2204 default: pixel=Dc; break;
2208 case ScreenCompositeOp:
2211 Screen: a negated multiply:
2213 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2215 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2218 case SoftLightCompositeOp:
2221 Refer to the March 2009 SVG specification.
2225 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2226 Sca*(1.0-Da)+Dca*(1.0-Sa));
2229 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2231 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2232 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2236 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2237 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2240 case ThresholdCompositeOp:
2246 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2251 pixel=gamma*(Dc+delta*amount);
2254 case VividLightCompositeOp:
2257 VividLight: A Photoshop 7 composition method. See
2258 http://www.simplefilter.de/en/basics/mixmods.html.
2260 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2262 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2264 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2267 if ((2.0*Sca) <= Sa)
2269 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2270 (1.0-Da)+Dca*(1.0-Sa));
2273 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2277 case XorCompositeOp:
2279 pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2288 q[i]=ClampToQuantum(pixel);
2290 p+=GetPixelChannels(composite_image);
2291 channels=GetPixelChannels(composite_image);
2292 if (p >= (pixels+channels*composite_image->columns))
2294 q+=GetPixelChannels(image);
2296 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2298 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2303 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2304 #pragma omp critical (MagickCore_CompositeImage)
2306 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2308 if (proceed == MagickFalse)
2312 composite_view=DestroyCacheView(composite_view);
2313 image_view=DestroyCacheView(image_view);
2314 if (destination_image != (Image * ) NULL)
2315 destination_image=DestroyImage(destination_image);
2317 composite_image=DestroyImage(composite_image);
2322 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2326 % T e x t u r e I m a g e %
2330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2332 % TextureImage() repeatedly tiles the texture image across and down the image
2335 % The format of the TextureImage method is:
2337 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2338 % ExceptionInfo *exception)
2340 % A description of each parameter follows:
2342 % o image: the image.
2344 % o texture_image: This image is the texture to layer on the background.
2347 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
2348 ExceptionInfo *exception)
2350 #define TextureImageTag "Texture/Image"
2365 assert(image != (Image *) NULL);
2366 if (image->debug != MagickFalse)
2367 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2368 assert(image->signature == MagickSignature);
2369 if (texture == (const Image *) NULL)
2370 return(MagickFalse);
2371 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2372 return(MagickFalse);
2373 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2374 if (texture_image == (const Image *) NULL)
2375 return(MagickFalse);
2376 (void) TransformImageColorspace(texture_image,image->colorspace,exception);
2377 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
2380 if ((image->compose != CopyCompositeOp) &&
2381 ((image->compose != OverCompositeOp) ||
2382 (image->alpha_trait == BlendPixelTrait) ||
2383 (texture_image->alpha_trait == BlendPixelTrait)))
2386 Tile texture onto the image background.
2388 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2393 if (status == MagickFalse)
2395 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2400 thread_status=CompositeImage(image,texture_image,image->compose,
2401 MagickFalse,x+texture_image->tile_offset.x,y+
2402 texture_image->tile_offset.y,exception);
2403 if (thread_status == MagickFalse)
2405 status=thread_status;
2409 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2414 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2416 if (proceed == MagickFalse)
2420 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2421 image->rows,image->rows);
2422 texture_image=DestroyImage(texture_image);
2426 Tile texture onto the image background (optimized).
2429 texture_view=AcquireVirtualCacheView(texture_image,exception);
2430 image_view=AcquireAuthenticCacheView(image,exception);
2431 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2432 #pragma omp parallel for schedule(static,4) shared(status) \
2433 magick_threads(texture_image,image,1,1)
2435 for (y=0; y < (ssize_t) image->rows; y++)
2440 register const Quantum
2453 if (status == MagickFalse)
2455 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2456 (y+texture_image->tile_offset.y) % texture_image->rows,
2457 texture_image->columns,1,exception);
2458 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2459 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2464 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2470 width=texture_image->columns;
2471 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2472 width=image->columns-x;
2473 for (j=0; j < (ssize_t) width; j++)
2478 if (GetPixelReadMask(image,q) == 0)
2480 p+=GetPixelChannels(texture_image);
2481 q+=GetPixelChannels(image);
2484 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2486 PixelChannel channel=GetPixelChannelChannel(texture_image,i);
2487 PixelTrait traits=GetPixelChannelTraits(image,channel);
2488 PixelTrait texture_traits=GetPixelChannelTraits(texture_image,
2490 if ((traits == UndefinedPixelTrait) ||
2491 (texture_traits == UndefinedPixelTrait))
2493 SetPixelChannel(image,channel,p[i],q);
2495 p+=GetPixelChannels(texture_image);
2496 q+=GetPixelChannels(image);
2499 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2500 if (sync == MagickFalse)
2502 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2507 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2509 if (proceed == MagickFalse)
2513 texture_view=DestroyCacheView(texture_view);
2514 image_view=DestroyCacheView(image_view);
2515 texture_image=DestroyImage(texture_image);