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/channel.h"
49 #include "MagickCore/client.h"
50 #include "MagickCore/color.h"
51 #include "MagickCore/color-private.h"
52 #include "MagickCore/colorspace.h"
53 #include "MagickCore/colorspace-private.h"
54 #include "MagickCore/composite.h"
55 #include "MagickCore/composite-private.h"
56 #include "MagickCore/constitute.h"
57 #include "MagickCore/draw.h"
58 #include "MagickCore/fx.h"
59 #include "MagickCore/gem.h"
60 #include "MagickCore/geometry.h"
61 #include "MagickCore/image.h"
62 #include "MagickCore/image-private.h"
63 #include "MagickCore/list.h"
64 #include "MagickCore/log.h"
65 #include "MagickCore/monitor.h"
66 #include "MagickCore/monitor-private.h"
67 #include "MagickCore/memory_.h"
68 #include "MagickCore/option.h"
69 #include "MagickCore/pixel-accessor.h"
70 #include "MagickCore/property.h"
71 #include "MagickCore/quantum.h"
72 #include "MagickCore/resample.h"
73 #include "MagickCore/resource_.h"
74 #include "MagickCore/string_.h"
75 #include "MagickCore/thread-private.h"
76 #include "MagickCore/threshold.h"
77 #include "MagickCore/token.h"
78 #include "MagickCore/utility.h"
79 #include "MagickCore/utility-private.h"
80 #include "MagickCore/version.h"
83 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
87 % C o m p o s i t e I m a g e %
91 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
93 % CompositeImage() returns the second image composited onto the first
94 % at the specified offset, using the specified composite method.
96 % The format of the CompositeImage method is:
98 % MagickBooleanType CompositeImage(Image *image,
99 % const Image *composite_image,const CompositeOperator compose,
100 % const MagickBooleanType clip_to_self,const ssize_t x_offset,
101 % const ssize_t y_offset,ExceptionInfo *exception)
103 % A description of each parameter follows:
105 % o image: the destination image, modified by he composition
107 % o composite_image: the composite (source) image.
109 % o compose: This operator affects how the composite is applied to
110 % the image. The operators and how they are utilized are listed here
111 % http://www.w3.org/TR/SVG12/#compositing.
113 % o clip_to_self: set to MagickTrue to limit composition to area composed.
115 % o x_offset: the column offset of the composited image.
117 % o y_offset: the row offset of the composited image.
119 % Extra Controls from Image meta-data in 'composite_image' (artifacts)
122 % A string containing extra numerical arguments for specific compose
123 % methods, generally expressed as a 'geometry' or a comma separated list
126 % Compose methods needing such arguments include "BlendCompositeOp" and
127 % "DisplaceCompositeOp".
129 % o exception: return any errors or warnings in this structure.
134 Composition based on the SVG specification:
136 A Composition is defined by...
137 Color Function : f(Sc,Dc) where Sc and Dc are the normizalized colors
138 Blending areas : X = 1 for area of overlap, ie: f(Sc,Dc)
139 Y = 1 for source preserved
140 Z = 1 for destination preserved
142 Conversion to transparency (then optimized)
143 Dca' = f(Sc, Dc)*Sa*Da + Y*Sca*(1-Da) + Z*Dca*(1-Sa)
144 Da' = X*Sa*Da + Y*Sa*(1-Da) + Z*Da*(1-Sa)
147 Sca = Sc*Sa normalized Source color divided by Source alpha
148 Dca = Dc*Da normalized Dest color divided by Dest alpha
149 Dc' = Dca'/Da' the desired color value for this channel.
151 Da' in in the follow formula as 'gamma' The resulting alpla value.
153 Most functions use a blending mode of over (X=1,Y=1,Z=1) this results in
154 the following optimizations...
156 gamma = 1 - QuantiumScale*alpha * QuantiumScale*beta;
157 opacity = QuantiumScale*alpha*beta; // over blend, optimized 1-Gamma
159 The above SVG definitions also definate that Mathematical Composition
160 methods should use a 'Over' blending mode for Alpha Channel.
161 It however was not applied for composition modes of 'Plus', 'Minus',
162 the modulus versions of 'Add' and 'Subtract'.
164 Mathematical operator changes to be applied from IM v6.7...
166 1) Modulus modes 'Add' and 'Subtract' are obsoleted and renamed
167 'ModulusAdd' and 'ModulusSubtract' for clarity.
169 2) All mathematical compositions work as per the SVG specification
170 with regard to blending. This now includes 'ModulusAdd' and
173 3) When the special channel flag 'sync' (syncronize channel updates)
174 is turned off (enabled by default) then mathematical compositions are
175 only performed on the channels specified, and are applied
176 independantally of each other. In other words the mathematics is
177 performed as 'pure' mathematical operations, rather than as image
181 static inline MagickRealType MagickMin(const MagickRealType x,
182 const MagickRealType y)
189 static inline MagickRealType MagickMax(const MagickRealType x,
190 const MagickRealType y)
197 static inline MagickRealType ConvertHueToRGB(MagickRealType m1,
198 MagickRealType m2,MagickRealType hue)
205 return(m1+6.0*(m2-m1)*hue);
209 return(m1+6.0*(m2-m1)*(2.0/3.0-hue));
213 static void HCLComposite(const MagickRealType hue,const MagickRealType chroma,
214 const MagickRealType luma,MagickRealType *red,MagickRealType *green,
215 MagickRealType *blue)
228 Convert HCL to RGB colorspace.
230 assert(red != (MagickRealType *) NULL);
231 assert(green != (MagickRealType *) NULL);
232 assert(blue != (MagickRealType *) NULL);
235 x=c*(1.0-fabs(fmod(h,2.0)-1.0));
239 if ((0.0 <= h) && (h < 1.0))
245 if ((1.0 <= h) && (h < 2.0))
251 if ((2.0 <= h) && (h < 3.0))
257 if ((3.0 <= h) && (h < 4.0))
263 if ((4.0 <= h) && (h < 5.0))
269 if ((5.0 <= h) && (h < 6.0))
274 m=luma-(0.298839*r+0.586811*g+0.114350*b);
284 z=(1.0-luma)/(m+c-luma);
287 *red=QuantumRange*(z*r+m);
288 *green=QuantumRange*(z*g+m);
289 *blue=QuantumRange*(z*b+m);
292 static void CompositeHCL(const MagickRealType red,const MagickRealType green,
293 const MagickRealType blue,MagickRealType *hue,MagickRealType *chroma,
294 MagickRealType *luma)
305 Convert RGB to HCL colorspace.
307 assert(hue != (MagickRealType *) NULL);
308 assert(chroma != (MagickRealType *) NULL);
309 assert(luma != (MagickRealType *) NULL);
313 max=MagickMax(r,MagickMax(g,b));
314 c=max-(MagickRealType) MagickMin(r,MagickMin(g,b));
320 h=fmod((g-b)/c+6.0,6.0);
328 *chroma=QuantumScale*c;
329 *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
332 static MagickBooleanType CompositeOverImage(Image *image,
333 const Image *composite_image,const MagickBooleanType clip_to_self,
334 const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
336 #define CompositeImageTag "Composite/Image"
356 composite_view=AcquireVirtualCacheView(composite_image,exception);
357 image_view=AcquireAuthenticCacheView(image,exception);
358 #if defined(MAGICKCORE_OPENMP_SUPPORT)
359 #pragma omp parallel for schedule(static,4) shared(progress,status) \
360 magick_threads(composite_image,image,image->rows,1)
362 for (y=0; y < (ssize_t) image->rows; y++)
367 register const Quantum
379 if (status == MagickFalse)
381 if (clip_to_self != MagickFalse)
385 if ((y-y_offset) >= (ssize_t) composite_image->rows)
389 If pixels is NULL, y is outside overlay region.
391 pixels=(Quantum *) NULL;
393 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
395 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
396 composite_image->columns,1,exception);
397 if (p == (const Quantum *) NULL)
404 p-=x_offset*GetPixelChannels(composite_image);
406 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
407 if (q == (Quantum *) NULL)
412 for (x=0; x < (ssize_t) image->columns; x++)
427 if (clip_to_self != MagickFalse)
431 q+=GetPixelChannels(image);
434 if ((x-x_offset) >= (ssize_t) composite_image->columns)
437 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
438 ((x-x_offset) >= (ssize_t) composite_image->columns))
441 source[MaxPixelChannels];
446 Dc: destination color.
448 if (GetPixelReadMask(image,q) == 0)
450 q+=GetPixelChannels(image);
453 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
455 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
457 PixelChannel channel=GetPixelChannelChannel(image,i);
458 PixelTrait traits=GetPixelChannelTraits(image,channel);
459 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
461 if ((traits == UndefinedPixelTrait) ||
462 (composite_traits == UndefinedPixelTrait))
464 q[i]=source[channel];
466 q+=GetPixelChannels(image);
471 Sa: normalized source alpha.
472 Da: normalized destination alpha.
474 if (GetPixelReadMask(composite_image,p) == 0)
476 p+=GetPixelChannels(composite_image);
477 channels=GetPixelChannels(composite_image);
478 if (p >= (pixels+channels*composite_image->columns))
480 q+=GetPixelChannels(image);
483 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
484 Da=QuantumScale*GetPixelAlpha(image,q);
485 alpha=Sa*(-Da)+Sa+Da;
486 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
488 PixelChannel channel=GetPixelChannelChannel(image,i);
489 PixelTrait traits=GetPixelChannelTraits(image,channel);
490 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
492 if ((traits == UndefinedPixelTrait) ||
493 (composite_traits == UndefinedPixelTrait))
495 if ((traits & CopyPixelTrait) != 0)
497 if (channel != AlphaPixelChannel)
502 q[i]=GetPixelChannel(composite_image,channel,p);
508 q[i]=ClampToQuantum(QuantumRange*alpha);
513 Dc: destination color.
515 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
516 Dc=(MagickRealType) q[i];
517 gamma=PerceptibleReciprocal(alpha);
518 q[i]=ClampToQuantum(gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc));
520 p+=GetPixelChannels(composite_image);
521 channels=GetPixelChannels(composite_image);
522 if (p >= (pixels+channels*composite_image->columns))
524 q+=GetPixelChannels(image);
526 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
528 if (image->progress_monitor != (MagickProgressMonitor) NULL)
533 #if defined(MAGICKCORE_OPENMP_SUPPORT)
534 #pragma omp critical (MagickCore_CompositeImage)
536 proceed=SetImageProgress(image,CompositeImageTag,progress++,
538 if (proceed == MagickFalse)
542 composite_view=DestroyCacheView(composite_view);
543 image_view=DestroyCacheView(image_view);
547 MagickExport MagickBooleanType CompositeImage(Image *image,
548 const Image *composite,const CompositeOperator compose,
549 const MagickBooleanType clip_to_self,const ssize_t x_offset,
550 const ssize_t y_offset,ExceptionInfo *exception)
552 #define CompositeImageTag "Composite/Image"
573 destination_dissolve,
586 assert(image != (Image *) NULL);
587 assert(image->signature == MagickSignature);
588 if (image->debug != MagickFalse)
589 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
590 assert(composite!= (Image *) NULL);
591 assert(composite->signature == MagickSignature);
592 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
594 composite_image=CloneImage(composite,0,0,MagickTrue,exception);
595 if (composite_image == (const Image *) NULL)
597 if (IsGrayColorspace(image->colorspace) != MagickFalse)
598 (void) SetImageColorspace(image,sRGBColorspace,exception);
599 (void) SetImageColorspace(composite_image,image->colorspace,exception);
600 if ((image->alpha_trait == BlendPixelTrait) &&
601 (composite_image->alpha_trait != BlendPixelTrait))
602 (void) SetImageAlphaChannel(composite_image,SetAlphaChannel,exception);
603 if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
605 status=CompositeOverImage(image,composite_image,clip_to_self,x_offset,
607 composite_image=DestroyImage(composite_image);
610 destination_image=(Image *) NULL;
612 destination_dissolve=1.0;
614 percent_chroma=100.0;
619 case CopyCompositeOp:
621 if ((x_offset < 0) || (y_offset < 0))
623 if ((x_offset+(ssize_t) composite_image->columns) >= (ssize_t) image->columns)
625 if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
628 composite_view=AcquireVirtualCacheView(composite_image,exception);
629 image_view=AcquireAuthenticCacheView(image,exception);
630 #if defined(MAGICKCORE_OPENMP_SUPPORT)
631 #pragma omp parallel for schedule(static,4) shared(status) \
632 magick_threads(composite_image,image,composite_image->rows,1)
634 for (y=0; y < (ssize_t) composite_image->rows; y++)
639 register const Quantum
648 if (status == MagickFalse)
650 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
652 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
653 composite_image->columns,1,exception);
654 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
659 for (x=0; x < (ssize_t) composite_image->columns; x++)
664 if (GetPixelReadMask(composite_image,p) == 0)
666 p+=GetPixelChannels(composite_image);
667 q+=GetPixelChannels(image);
670 for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
672 PixelChannel channel=GetPixelChannelChannel(composite_image,i);
673 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
675 PixelTrait traits=GetPixelChannelTraits(image,channel);
676 if ((traits == UndefinedPixelTrait) ||
677 (composite_traits == UndefinedPixelTrait))
679 SetPixelChannel(image,channel,p[i],q);
681 p+=GetPixelChannels(composite_image);
682 q+=GetPixelChannels(image);
684 sync=SyncCacheViewAuthenticPixels(image_view,exception);
685 if (sync == MagickFalse)
687 if (image->progress_monitor != (MagickProgressMonitor) NULL)
692 #if defined(MAGICKCORE_OPENMP_SUPPORT)
693 #pragma omp critical (MagickCore_CompositeImage)
695 proceed=SetImageProgress(image,CompositeImageTag,
696 (MagickOffsetType) y,image->rows);
697 if (proceed == MagickFalse)
701 composite_view=DestroyCacheView(composite_view);
702 image_view=DestroyCacheView(image_view);
703 composite_image=DestroyImage(composite_image);
706 case CopyAlphaCompositeOp:
707 case ChangeMaskCompositeOp:
708 case IntensityCompositeOp:
711 Modify destination outside the overlaid region and require an alpha
712 channel to exist, to add transparency.
714 if (image->alpha_trait != BlendPixelTrait)
715 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
718 case BlurCompositeOp:
743 Blur Image by resampling.
745 Blur Image dictated by an overlay gradient map: X = red_channel;
746 Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
748 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
750 if (destination_image == (Image *) NULL)
752 composite_image=DestroyImage(composite_image);
756 Gather the maximum blur sigma values from user.
758 SetGeometryInfo(&geometry_info);
760 value=GetImageArtifact(image,"compose:args");
761 if (value != (const char *) NULL)
762 flags=ParseGeometry(value,&geometry_info);
763 if ((flags & WidthValue) == 0)
765 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
766 "InvalidSetting","'%s' '%s'","compose:args",value);
767 composite_image=DestroyImage(composite_image);
768 destination_image=DestroyImage(destination_image);
772 Users input sigma now needs to be converted to the EWA ellipse size.
773 The filter defaults to a sigma of 0.5 so to make this match the
774 users input the ellipse size needs to be doubled.
776 width=height=geometry_info.rho*2.0;
777 if ((flags & HeightValue) != 0 )
778 height=geometry_info.sigma*2.0;
780 Default the unrotated ellipse width and height axis vectors.
786 /* rotate vectors if a rotation angle is given */
787 if ((flags & XValue) != 0 )
792 angle=DegreesToRadians(geometry_info.xi);
793 blur.x1=width*cos(angle);
794 blur.x2=width*sin(angle);
795 blur.y1=(-height*sin(angle));
796 blur.y2=height*cos(angle);
798 /* Otherwise lets set a angle range and calculate in the loop */
801 if ((flags & YValue) != 0 )
803 angle_start=DegreesToRadians(geometry_info.xi);
804 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
807 Set up a gaussian cylindrical filter for EWA Bluring.
809 As the minimum ellipse radius of support*1.0 the EWA algorithm
810 can only produce a minimum blur of 0.5 for Gaussian (support=2.0)
811 This means that even 'No Blur' will be still a little blurry!
813 The solution (as well as the problem of preventing any user
814 expert filter settings, is to set our own user settings, then
815 restore them afterwards.
817 resample_filter=AcquireResampleFilter(image,exception);
818 SetResampleFilter(resample_filter,GaussianFilter);
820 /* do the variable blurring of each pixel in image */
821 GetPixelInfo(image,&pixel);
822 composite_view=AcquireVirtualCacheView(composite_image,exception);
823 destination_view=AcquireAuthenticCacheView(destination_image,exception);
824 for (y=0; y < (ssize_t) composite_image->rows; y++)
829 register const Quantum
838 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
840 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
842 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
843 destination_image->columns,1,exception);
844 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
846 for (x=0; x < (ssize_t) composite_image->columns; x++)
848 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
850 p+=GetPixelChannels(composite_image);
853 if (fabs(angle_range) > MagickEpsilon)
858 angle=angle_start+angle_range*QuantumScale*
859 GetPixelBlue(composite_image,p);
860 blur.x1=width*cos(angle);
861 blur.x2=width*sin(angle);
862 blur.y1=(-height*sin(angle));
863 blur.y2=height*cos(angle);
866 if ( x == 10 && y == 60 ) {
867 (void) fprintf(stderr, "blur.x=%lf,%lf, blur.y=%lf,%lf\n",blur.x1,
868 blur.x2,blur.y1, blur.y2);
869 (void) fprintf(stderr, "scaled by=%lf,%lf\n",QuantumScale*
870 GetPixelRed(p),QuantumScale*GetPixelGreen(p));
872 ScaleResampleFilter(resample_filter,
873 blur.x1*QuantumScale*GetPixelRed(composite_image,p),
874 blur.y1*QuantumScale*GetPixelGreen(composite_image,p),
875 blur.x2*QuantumScale*GetPixelRed(composite_image,p),
876 blur.y2*QuantumScale*GetPixelGreen(composite_image,p) );
877 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
878 (double) y_offset+y,&pixel,exception);
879 SetPixelInfoPixel(destination_image,&pixel,q);
880 p+=GetPixelChannels(composite_image);
881 q+=GetPixelChannels(destination_image);
883 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
884 if (sync == MagickFalse)
887 resample_filter=DestroyResampleFilter(resample_filter);
888 composite_view=DestroyCacheView(composite_view);
889 destination_view=DestroyCacheView(destination_view);
890 composite_image=DestroyImage(composite_image);
891 composite_image=destination_image;
894 case DisplaceCompositeOp:
895 case DistortCompositeOp:
917 Displace/Distort based on overlay gradient map:
918 X = red_channel; Y = green_channel;
919 compose:args = x_scale[,y_scale[,center.x,center.y]]
921 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
923 if (destination_image == (Image *) NULL)
925 composite_image=DestroyImage(composite_image);
928 SetGeometryInfo(&geometry_info);
930 value=GetImageArtifact(composite_image,"compose:args");
931 if (value != (char *) NULL)
932 flags=ParseGeometry(value,&geometry_info);
933 if ((flags & (WidthValue|HeightValue)) == 0 )
935 if ((flags & AspectValue) == 0)
937 horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
939 vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
943 horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
944 vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
949 horizontal_scale=geometry_info.rho;
950 vertical_scale=geometry_info.sigma;
951 if ((flags & PercentValue) != 0)
953 if ((flags & AspectValue) == 0)
955 horizontal_scale*=(composite_image->columns-1.0)/200.0;
956 vertical_scale*=(composite_image->rows-1.0)/200.0;
960 horizontal_scale*=(image->columns-1.0)/200.0;
961 vertical_scale*=(image->rows-1.0)/200.0;
964 if ((flags & HeightValue) == 0)
965 vertical_scale=horizontal_scale;
968 Determine fixed center point for absolute distortion map
970 Displace offset relative to a fixed absolute point
971 Select that point according to +X+Y user inputs.
972 default = center of overlay image
973 arg flag '!' = locations/percentage relative to background image
975 center.x=(MagickRealType) x_offset;
976 center.y=(MagickRealType) y_offset;
977 if (compose == DistortCompositeOp)
979 if ((flags & XValue) == 0)
980 if ((flags & AspectValue) == 0)
981 center.x=(MagickRealType) (x_offset+(composite_image->columns-1)/
984 center.x=(MagickRealType) ((image->columns-1)/2);
986 if ((flags & AspectValue) == 0)
987 center.x=(MagickRealType) x_offset+geometry_info.xi;
989 center.x=geometry_info.xi;
990 if ((flags & YValue) == 0)
991 if ((flags & AspectValue) == 0)
992 center.y=(MagickRealType) (y_offset+(composite_image->rows-1)/
995 center.y=(MagickRealType) ((image->rows-1)/2);
997 if ((flags & AspectValue) == 0)
998 center.y=(MagickRealType) y_offset+geometry_info.psi;
1000 center.y=geometry_info.psi;
1003 Shift the pixel offset point as defined by the provided,
1004 displacement/distortion map. -- Like a lens...
1006 GetPixelInfo(image,&pixel);
1007 image_view=AcquireVirtualCacheView(image,exception);
1008 composite_view=AcquireVirtualCacheView(composite_image,exception);
1009 destination_view=AcquireAuthenticCacheView(destination_image,exception);
1010 for (y=0; y < (ssize_t) composite_image->rows; y++)
1015 register const Quantum
1024 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1026 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
1028 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
1029 destination_image->columns,1,exception);
1030 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1032 for (x=0; x < (ssize_t) composite_image->columns; x++)
1034 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1036 p+=GetPixelChannels(composite_image);
1040 Displace the offset.
1042 offset.x=(double) (horizontal_scale*(GetPixelRed(composite_image,p)-
1043 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1044 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
1046 offset.y=(double) (vertical_scale*(GetPixelGreen(composite_image,p)-
1047 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1048 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
1050 (void) InterpolatePixelInfo(image,image_view,
1051 UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1054 Mask with the 'invalid pixel mask' in alpha channel.
1056 pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
1057 pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
1058 SetPixelInfoPixel(destination_image,&pixel,q);
1059 p+=GetPixelChannels(composite_image);
1060 q+=GetPixelChannels(destination_image);
1062 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1063 if (sync == MagickFalse)
1066 destination_view=DestroyCacheView(destination_view);
1067 composite_view=DestroyCacheView(composite_view);
1068 image_view=DestroyCacheView(image_view);
1069 composite_image=DestroyImage(composite_image);
1070 composite_image=destination_image;
1073 case DissolveCompositeOp:
1079 Geometry arguments to dissolve factors.
1081 value=GetImageArtifact(composite_image,"compose:args");
1082 if (value != (char *) NULL)
1084 flags=ParseGeometry(value,&geometry_info);
1085 source_dissolve=geometry_info.rho/100.0;
1086 destination_dissolve=1.0;
1087 if ((source_dissolve-MagickEpsilon) < 0.0)
1088 source_dissolve=0.0;
1089 if ((source_dissolve+MagickEpsilon) > 1.0)
1091 destination_dissolve=2.0-source_dissolve;
1092 source_dissolve=1.0;
1094 if ((flags & SigmaValue) != 0)
1095 destination_dissolve=geometry_info.sigma/100.0;
1096 if ((destination_dissolve-MagickEpsilon) < 0.0)
1097 destination_dissolve=0.0;
1098 /* posible speed up? -- from IMv6 update
1099 clip_to_self=MagickFalse;
1100 if ((destination_dissolve+MagickEpsilon) > 1.0 )
1102 destination_dissolve=1.0;
1103 clip_to_self=MagickTrue;
1109 case BlendCompositeOp:
1114 value=GetImageArtifact(composite_image,"compose:args");
1115 if (value != (char *) NULL)
1117 flags=ParseGeometry(value,&geometry_info);
1118 source_dissolve=geometry_info.rho/100.0;
1119 destination_dissolve=1.0-source_dissolve;
1120 if ((flags & SigmaValue) != 0)
1121 destination_dissolve=geometry_info.sigma/100.0;
1125 case MathematicsCompositeOp:
1131 Just collect the values from "compose:args", setting.
1132 Unused values are set to zero automagically.
1134 Arguments are normally a comma separated list, so this probably should
1135 be changed to some 'general comma list' parser, (with a minimum
1138 SetGeometryInfo(&geometry_info);
1139 value=GetImageArtifact(composite_image,"compose:args");
1140 if (value != (char *) NULL)
1141 (void) ParseGeometry(value,&geometry_info);
1144 case ModulateCompositeOp:
1150 Determine the luma and chroma scale.
1152 value=GetImageArtifact(composite_image,"compose:args");
1153 if (value != (char *) NULL)
1155 flags=ParseGeometry(value,&geometry_info);
1156 percent_luma=geometry_info.rho;
1157 if ((flags & SigmaValue) != 0)
1158 percent_chroma=geometry_info.sigma;
1162 case ThresholdCompositeOp:
1168 Determine the amount and threshold.
1170 value=GetImageArtifact(composite_image,"compose:args");
1171 if (value != (char *) NULL)
1173 flags=ParseGeometry(value,&geometry_info);
1174 amount=geometry_info.rho;
1175 threshold=geometry_info.sigma;
1176 if ((flags & SigmaValue) == 0)
1179 threshold*=QuantumRange;
1190 midpoint=((MagickRealType) QuantumRange+1.0)/2;
1191 composite_view=AcquireVirtualCacheView(composite_image,exception);
1192 image_view=AcquireAuthenticCacheView(image,exception);
1193 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1194 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1195 magick_threads(composite_image,image,image->rows,1)
1197 for (y=0; y < (ssize_t) image->rows; y++)
1214 register const Quantum
1223 if (status == MagickFalse)
1225 if (clip_to_self != MagickFalse)
1229 if ((y-y_offset) >= (ssize_t) composite_image->rows)
1233 If pixels is NULL, y is outside overlay region.
1235 pixels=(Quantum *) NULL;
1237 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
1239 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
1240 composite_image->columns,1,exception);
1241 if (p == (const Quantum *) NULL)
1248 p-=x_offset*GetPixelChannels(composite_image);
1250 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1251 if (q == (Quantum *) NULL)
1259 GetPixelInfo(image,&destination_pixel);
1260 GetPixelInfo(composite_image,&source_pixel);
1261 for (x=0; x < (ssize_t) image->columns; x++)
1281 if (clip_to_self != MagickFalse)
1285 q+=GetPixelChannels(image);
1288 if ((x-x_offset) >= (ssize_t) composite_image->columns)
1291 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1292 ((x-x_offset) >= (ssize_t) composite_image->columns))
1295 source[MaxPixelChannels];
1300 Dc: destination color.
1302 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
1304 if (GetPixelReadMask(image,q) == 0)
1306 q+=GetPixelChannels(image);
1309 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1314 PixelChannel channel=GetPixelChannelChannel(image,i);
1315 PixelTrait traits=GetPixelChannelTraits(image,channel);
1316 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
1318 if ((traits == UndefinedPixelTrait) ||
1319 (composite_traits == UndefinedPixelTrait))
1323 case AlphaCompositeOp:
1324 case ChangeMaskCompositeOp:
1325 case CopyAlphaCompositeOp:
1326 case DstAtopCompositeOp:
1327 case DstInCompositeOp:
1329 case IntensityCompositeOp:
1330 case OutCompositeOp:
1331 case SrcInCompositeOp:
1332 case SrcOutCompositeOp:
1334 pixel=(MagickRealType) q[i];
1335 if (channel == AlphaPixelChannel)
1336 pixel=(MagickRealType) TransparentAlpha;
1339 case ClearCompositeOp:
1340 case CopyCompositeOp:
1341 case ReplaceCompositeOp:
1342 case SrcCompositeOp:
1344 if (channel == AlphaPixelChannel)
1346 pixel=(MagickRealType) TransparentAlpha;
1352 case BlendCompositeOp:
1353 case DissolveCompositeOp:
1355 if (channel == AlphaPixelChannel)
1357 pixel=destination_dissolve*GetPixelAlpha(composite_image,
1361 pixel=(MagickRealType) source[channel];
1366 pixel=(MagickRealType) source[channel];
1370 q[i]=ClampToQuantum(pixel);
1372 q+=GetPixelChannels(image);
1376 Authentic composite:
1377 Sa: normalized source alpha.
1378 Da: normalized destination alpha.
1380 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
1381 Da=QuantumScale*GetPixelAlpha(image,q);
1384 case BumpmapCompositeOp:
1386 alpha=GetPixelIntensity(composite_image,p)*Sa;
1389 case ColorBurnCompositeOp:
1390 case ColorDodgeCompositeOp:
1391 case DifferenceCompositeOp:
1392 case DivideDstCompositeOp:
1393 case DivideSrcCompositeOp:
1394 case ExclusionCompositeOp:
1395 case HardLightCompositeOp:
1396 case LinearBurnCompositeOp:
1397 case LinearDodgeCompositeOp:
1398 case LinearLightCompositeOp:
1399 case MathematicsCompositeOp:
1400 case MinusDstCompositeOp:
1401 case MinusSrcCompositeOp:
1402 case ModulusAddCompositeOp:
1403 case ModulusSubtractCompositeOp:
1404 case MultiplyCompositeOp:
1405 case OverlayCompositeOp:
1406 case PegtopLightCompositeOp:
1407 case PinLightCompositeOp:
1408 case ScreenCompositeOp:
1409 case SoftLightCompositeOp:
1410 case VividLightCompositeOp:
1412 alpha=RoundToUnity(Sa+Da-Sa*Da);
1415 case DarkenCompositeOp:
1416 case DstAtopCompositeOp:
1417 case DstInCompositeOp:
1419 case LightenCompositeOp:
1420 case SrcInCompositeOp:
1425 case DissolveCompositeOp:
1427 alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
1428 Sa+destination_dissolve*Da;
1431 case DstOverCompositeOp:
1433 alpha=Da*(-Sa)+Da+Sa;
1436 case DstOutCompositeOp:
1441 case OutCompositeOp:
1442 case SrcOutCompositeOp:
1447 case OverCompositeOp:
1448 case SrcOverCompositeOp:
1450 alpha=Sa*(-Da)+Sa+Da;
1453 case BlendCompositeOp:
1454 case PlusCompositeOp:
1456 alpha=RoundToUnity(Sa+Da);
1459 case XorCompositeOp:
1461 alpha=Sa+Da-2.0*Sa*Da;
1470 if (GetPixelReadMask(image,q) == 0)
1472 p+=GetPixelChannels(composite_image);
1473 q+=GetPixelChannels(image);
1478 case ColorizeCompositeOp:
1479 case HueCompositeOp:
1480 case LuminizeCompositeOp:
1481 case ModulateCompositeOp:
1482 case SaturateCompositeOp:
1484 GetPixelInfoPixel(composite_image,p,&source_pixel);
1485 GetPixelInfoPixel(image,q,&destination_pixel);
1491 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1497 PixelChannel channel=GetPixelChannelChannel(image,i);
1498 PixelTrait traits=GetPixelChannelTraits(image,channel);
1499 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
1501 if (traits == UndefinedPixelTrait)
1503 if ((compose != IntensityCompositeOp) &&
1504 (composite_traits == UndefinedPixelTrait))
1508 Dc: destination color.
1510 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
1511 Dc=(MagickRealType) q[i];
1512 if ((traits & CopyPixelTrait) != 0)
1514 if (channel != AlphaPixelChannel)
1519 q[i]=ClampToQuantum(Sc);
1527 case AlphaCompositeOp:
1529 pixel=QuantumRange*Sa;
1532 case AtopCompositeOp:
1533 case CopyBlackCompositeOp:
1534 case CopyBlueCompositeOp:
1535 case CopyCyanCompositeOp:
1536 case CopyGreenCompositeOp:
1537 case CopyMagentaCompositeOp:
1538 case CopyRedCompositeOp:
1539 case CopyYellowCompositeOp:
1540 case SrcAtopCompositeOp:
1541 case DstCompositeOp:
1544 pixel=QuantumRange*Da;
1547 case ChangeMaskCompositeOp:
1552 if (Da > ((MagickRealType) QuantumRange/2.0))
1554 pixel=(MagickRealType) TransparentAlpha;
1557 equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
1558 if (equivalent != MagickFalse)
1560 pixel=(MagickRealType) TransparentAlpha;
1563 pixel=(MagickRealType) OpaqueAlpha;
1566 case ClearCompositeOp:
1568 pixel=(MagickRealType) TransparentAlpha;
1571 case ColorizeCompositeOp:
1572 case HueCompositeOp:
1573 case LuminizeCompositeOp:
1574 case SaturateCompositeOp:
1576 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1578 pixel=QuantumRange*Da;
1581 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1583 pixel=QuantumRange*Sa;
1588 pixel=QuantumRange*Da;
1591 pixel=QuantumRange*Sa;
1594 case CopyAlphaCompositeOp:
1596 pixel=QuantumRange*Sa;
1597 if (composite_image->alpha_trait == BlendPixelTrait)
1598 pixel=GetPixelIntensity(composite_image,p);
1601 case CopyCompositeOp:
1602 case DisplaceCompositeOp:
1603 case DistortCompositeOp:
1604 case DstAtopCompositeOp:
1605 case ReplaceCompositeOp:
1606 case SrcCompositeOp:
1608 pixel=QuantumRange*Sa;
1611 case DarkenIntensityCompositeOp:
1613 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1614 (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
1617 case IntensityCompositeOp:
1619 pixel=GetPixelIntensity(composite_image,p);
1622 case LightenIntensityCompositeOp:
1624 pixel=Sa*GetPixelIntensity(composite_image,p) >
1625 Da*GetPixelIntensity(image,q) ? Sa : Da;
1628 case ModulateCompositeOp:
1630 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1632 pixel=QuantumRange*Da;
1635 pixel=QuantumRange*Da;
1640 pixel=QuantumRange*alpha;
1644 q[i]=ClampToQuantum(pixel);
1648 Porter-Duff compositions:
1649 Sca: source normalized color multiplied by alpha.
1650 Dca: normalized destination color multiplied by alpha.
1652 Sca=QuantumScale*Sa*Sc;
1653 Dca=QuantumScale*Da*Dc;
1656 case DarkenCompositeOp:
1657 case LightenCompositeOp:
1658 case ModulusSubtractCompositeOp:
1666 gamma=PerceptibleReciprocal(alpha);
1670 case AlphaCompositeOp:
1672 pixel=QuantumRange*Sa;
1675 case AtopCompositeOp:
1676 case SrcAtopCompositeOp:
1678 pixel=Sc*Sa+Dc*(1.0-Sa);
1681 case BlendCompositeOp:
1683 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1686 case BlurCompositeOp:
1687 case DisplaceCompositeOp:
1688 case DistortCompositeOp:
1689 case CopyCompositeOp:
1690 case ReplaceCompositeOp:
1691 case SrcCompositeOp:
1696 case BumpmapCompositeOp:
1698 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1703 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1706 case ChangeMaskCompositeOp:
1711 case ClearCompositeOp:
1716 case ColorBurnCompositeOp:
1719 Refer to the March 2009 SVG specification.
1721 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1723 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1726 if (Sca < MagickEpsilon)
1728 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1731 pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
1732 Sca*(1.0-Da)+Dca*(1.0-Sa));
1735 case ColorDodgeCompositeOp:
1737 if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1739 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1742 if (fabs(Sca-Sa) < MagickEpsilon)
1744 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1747 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1751 case ColorizeCompositeOp:
1753 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1758 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1763 CompositeHCL(destination_pixel.red,destination_pixel.green,
1764 destination_pixel.blue,&sans,&sans,&luma);
1765 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1766 &hue,&chroma,&sans);
1767 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1770 case RedPixelChannel: pixel=red; break;
1771 case GreenPixelChannel: pixel=green; break;
1772 case BluePixelChannel: pixel=blue; break;
1773 default: pixel=Dc; break;
1777 case CopyAlphaCompositeOp:
1778 case IntensityCompositeOp:
1783 case CopyBlackCompositeOp:
1785 if (channel == BlackPixelChannel)
1786 pixel=(MagickRealType) GetPixelBlack(composite_image,p);
1789 case CopyBlueCompositeOp:
1790 case CopyYellowCompositeOp:
1792 if (channel == BluePixelChannel)
1793 pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1796 case CopyGreenCompositeOp:
1797 case CopyMagentaCompositeOp:
1799 if (channel == GreenPixelChannel)
1800 pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1803 case CopyRedCompositeOp:
1804 case CopyCyanCompositeOp:
1806 if (channel == RedPixelChannel)
1807 pixel=(MagickRealType) GetPixelRed(composite_image,p);
1810 case DarkenCompositeOp:
1813 Darken is equivalent to a 'Minimum' method
1814 OR a greyscale version of a binary 'Or'
1815 OR the 'Intersection' of pixel sets.
1819 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1822 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1825 case DarkenIntensityCompositeOp:
1827 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1828 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1831 case DifferenceCompositeOp:
1833 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1836 case DissolveCompositeOp:
1838 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1839 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1842 case DivideDstCompositeOp:
1844 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1846 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1849 if (fabs(Dca) < MagickEpsilon)
1851 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1854 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1857 case DivideSrcCompositeOp:
1859 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1861 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1864 if (fabs(Sca) < MagickEpsilon)
1866 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1869 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1872 case DstAtopCompositeOp:
1874 pixel=Dc*Da+Sc*(1.0-Da);
1877 case DstCompositeOp:
1883 case DstInCompositeOp:
1885 pixel=gamma*(Sa*Dc*Sa);
1888 case DstOutCompositeOp:
1890 pixel=gamma*(Da*Dc*(1.0-Sa));
1893 case DstOverCompositeOp:
1895 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1898 case ExclusionCompositeOp:
1900 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1904 case HardLightCompositeOp:
1908 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1912 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1916 case HueCompositeOp:
1918 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1923 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1928 CompositeHCL(destination_pixel.red,destination_pixel.green,
1929 destination_pixel.blue,&hue,&chroma,&luma);
1930 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1932 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1935 case RedPixelChannel: pixel=red; break;
1936 case GreenPixelChannel: pixel=green; break;
1937 case BluePixelChannel: pixel=blue; break;
1938 default: pixel=Dc; break;
1943 case SrcInCompositeOp:
1945 pixel=gamma*(Da*Sc*Da);
1948 case LinearBurnCompositeOp:
1951 LinearBurn: as defined by Abode Photoshop, according to
1952 http://www.simplefilter.de/en/basics/mixmods.html is:
1954 f(Sc,Dc) = Sc + Dc - 1
1956 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1959 case LinearDodgeCompositeOp:
1961 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1964 case LinearLightCompositeOp:
1967 LinearLight: as defined by Abode Photoshop, according to
1968 http://www.simplefilter.de/en/basics/mixmods.html is:
1970 f(Sc,Dc) = Dc + 2*Sc - 1
1972 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1975 case LightenCompositeOp:
1979 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1982 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1985 case LightenIntensityCompositeOp:
1988 Lighten is equivalent to a 'Maximum' method
1989 OR a greyscale version of a binary 'And'
1990 OR the 'Union' of pixel sets.
1992 pixel=Sa*GetPixelIntensity(composite_image,p) >
1993 Da*GetPixelIntensity(image,q) ? Sc : Dc;
1996 case LuminizeCompositeOp:
1998 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2003 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2008 CompositeHCL(destination_pixel.red,destination_pixel.green,
2009 destination_pixel.blue,&hue,&chroma,&luma);
2010 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2012 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2015 case RedPixelChannel: pixel=red; break;
2016 case GreenPixelChannel: pixel=green; break;
2017 case BluePixelChannel: pixel=blue; break;
2018 default: pixel=Dc; break;
2022 case MathematicsCompositeOp:
2025 'Mathematics' a free form user control mathematical composition
2028 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
2030 Where the arguments A,B,C,D are (currently) passed to composite
2031 as a command separated 'geometry' string in "compose:args" image
2034 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
2036 Applying the SVG transparency formula (see above), we get...
2038 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
2040 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
2043 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
2044 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
2045 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
2048 case MinusDstCompositeOp:
2050 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2053 case MinusSrcCompositeOp:
2056 Minus source from destination.
2060 pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2063 case ModulateCompositeOp:
2068 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2073 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
2079 CompositeHCL(destination_pixel.red,destination_pixel.green,
2080 destination_pixel.blue,&hue,&chroma,&luma);
2081 luma+=(0.01*percent_luma*offset)/midpoint;
2082 chroma*=0.01*percent_chroma;
2083 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2086 case RedPixelChannel: pixel=red; break;
2087 case GreenPixelChannel: pixel=green; break;
2088 case BluePixelChannel: pixel=blue; break;
2089 default: pixel=Dc; break;
2093 case ModulusAddCompositeOp:
2096 if (pixel > QuantumRange)
2097 pixel-=(QuantumRange+1.0);
2098 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2101 case ModulusSubtractCompositeOp:
2105 pixel+=(QuantumRange+1.0);
2106 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2109 case MultiplyCompositeOp:
2111 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2114 case OutCompositeOp:
2115 case SrcOutCompositeOp:
2117 pixel=gamma*(Sa*Sc*(1.0-Da));
2120 case OverCompositeOp:
2121 case SrcOverCompositeOp:
2123 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2126 case OverlayCompositeOp:
2130 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2134 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2138 case PegtopLightCompositeOp:
2141 PegTop: A Soft-Light alternative: A continuous version of the
2142 Softlight function, producing very similar results.
2144 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2146 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2148 if (fabs(Da) < MagickEpsilon)
2150 pixel=QuantumRange*gamma*(Sca);
2153 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2157 case PinLightCompositeOp:
2160 PinLight: A Photoshop 7 composition method
2161 http://www.simplefilter.de/en/basics/mixmods.html
2163 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2165 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2167 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2170 if ((Dca*Sa) > (2.0*Sca*Da))
2172 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2175 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2178 case PlusCompositeOp:
2180 pixel=gamma*(Sa*Sc+Da*Dc);
2183 case SaturateCompositeOp:
2185 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2190 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2195 CompositeHCL(destination_pixel.red,destination_pixel.green,
2196 destination_pixel.blue,&hue,&chroma,&luma);
2197 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2198 &sans,&chroma,&sans);
2199 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2202 case RedPixelChannel: pixel=red; break;
2203 case GreenPixelChannel: pixel=green; break;
2204 case BluePixelChannel: pixel=blue; break;
2205 default: pixel=Dc; break;
2209 case ScreenCompositeOp:
2212 Screen: a negated multiply:
2214 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2216 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2219 case SoftLightCompositeOp:
2222 Refer to the March 2009 SVG specification.
2226 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2227 Sca*(1.0-Da)+Dca*(1.0-Sa));
2230 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2232 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2233 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2237 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2238 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2241 case ThresholdCompositeOp:
2247 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2252 pixel=gamma*(Dc+delta*amount);
2255 case VividLightCompositeOp:
2258 VividLight: A Photoshop 7 composition method. See
2259 http://www.simplefilter.de/en/basics/mixmods.html.
2261 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2263 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2265 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2268 if ((2.0*Sca) <= Sa)
2270 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2271 (1.0-Da)+Dca*(1.0-Sa));
2274 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2278 case XorCompositeOp:
2280 pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2289 q[i]=ClampToQuantum(pixel);
2291 p+=GetPixelChannels(composite_image);
2292 channels=GetPixelChannels(composite_image);
2293 if (p >= (pixels+channels*composite_image->columns))
2295 q+=GetPixelChannels(image);
2297 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2299 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2304 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2305 #pragma omp critical (MagickCore_CompositeImage)
2307 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2309 if (proceed == MagickFalse)
2313 composite_view=DestroyCacheView(composite_view);
2314 image_view=DestroyCacheView(image_view);
2315 if (destination_image != (Image * ) NULL)
2316 destination_image=DestroyImage(destination_image);
2318 composite_image=DestroyImage(composite_image);
2323 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2327 % T e x t u r e I m a g e %
2331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2333 % TextureImage() repeatedly tiles the texture image across and down the image
2336 % The format of the TextureImage method is:
2338 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2339 % ExceptionInfo *exception)
2341 % A description of each parameter follows:
2343 % o image: the image.
2345 % o texture_image: This image is the texture to layer on the background.
2348 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
2349 ExceptionInfo *exception)
2351 #define TextureImageTag "Texture/Image"
2366 assert(image != (Image *) NULL);
2367 if (image->debug != MagickFalse)
2368 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2369 assert(image->signature == MagickSignature);
2370 if (texture == (const Image *) NULL)
2371 return(MagickFalse);
2372 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2373 return(MagickFalse);
2374 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2375 if (texture_image == (const Image *) NULL)
2376 return(MagickFalse);
2377 (void) TransformImageColorspace(texture_image,image->colorspace,exception);
2378 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
2381 if ((image->compose != CopyCompositeOp) &&
2382 ((image->compose != OverCompositeOp) ||
2383 (image->alpha_trait == BlendPixelTrait) ||
2384 (texture_image->alpha_trait == BlendPixelTrait)))
2387 Tile texture onto the image background.
2389 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2394 if (status == MagickFalse)
2396 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2401 thread_status=CompositeImage(image,texture_image,image->compose,
2402 MagickFalse,x+texture_image->tile_offset.x,y+
2403 texture_image->tile_offset.y,exception);
2404 if (thread_status == MagickFalse)
2406 status=thread_status;
2410 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2415 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2417 if (proceed == MagickFalse)
2421 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2422 image->rows,image->rows);
2423 texture_image=DestroyImage(texture_image);
2427 Tile texture onto the image background (optimized).
2430 texture_view=AcquireVirtualCacheView(texture_image,exception);
2431 image_view=AcquireAuthenticCacheView(image,exception);
2432 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2433 #pragma omp parallel for schedule(static,4) shared(status) \
2434 magick_threads(texture_image,image,1,1)
2436 for (y=0; y < (ssize_t) image->rows; y++)
2441 register const Quantum
2454 if (status == MagickFalse)
2456 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2457 (y+texture_image->tile_offset.y) % texture_image->rows,
2458 texture_image->columns,1,exception);
2459 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2460 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2465 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2471 width=texture_image->columns;
2472 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2473 width=image->columns-x;
2474 for (j=0; j < (ssize_t) width; j++)
2479 if (GetPixelReadMask(image,q) == 0)
2481 p+=GetPixelChannels(texture_image);
2482 q+=GetPixelChannels(image);
2485 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2487 PixelChannel channel=GetPixelChannelChannel(texture_image,i);
2488 PixelTrait traits=GetPixelChannelTraits(image,channel);
2489 PixelTrait texture_traits=GetPixelChannelTraits(texture_image,
2491 if ((traits == UndefinedPixelTrait) ||
2492 (texture_traits == UndefinedPixelTrait))
2494 SetPixelChannel(image,channel,p[i],q);
2496 p+=GetPixelChannels(texture_image);
2497 q+=GetPixelChannels(image);
2500 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2501 if (sync == MagickFalse)
2503 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2508 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2510 if (proceed == MagickFalse)
2514 texture_view=DestroyCacheView(texture_view);
2515 image_view=DestroyCacheView(image_view);
2516 texture_image=DestroyImage(texture_image);