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)
226 Convert HCL to RGB colorspace.
228 assert(red != (MagickRealType *) NULL);
229 assert(green != (MagickRealType *) NULL);
230 assert(blue != (MagickRealType *) NULL);
233 x=c*(1.0-fabs(fmod(h,2.0)-1.0));
237 if ((0.0 <= h) && (h < 1.0))
243 if ((1.0 <= h) && (h < 2.0))
249 if ((2.0 <= h) && (h < 3.0))
255 if ((3.0 <= h) && (h < 4.0))
261 if ((4.0 <= h) && (h < 5.0))
267 if ((5.0 <= h) && (h < 6.0))
272 m=luma-(0.298839f*r+0.586811f*g+0.114350f*b);
273 *red=QuantumRange*(r+m);
274 *green=QuantumRange*(g+m);
275 *blue=QuantumRange*(b+m);
278 static void CompositeHCL(const MagickRealType red,const MagickRealType green,
279 const MagickRealType blue,MagickRealType *hue,MagickRealType *chroma,
280 MagickRealType *luma)
291 Convert RGB to HCL colorspace.
293 assert(hue != (MagickRealType *) NULL);
294 assert(chroma != (MagickRealType *) NULL);
295 assert(luma != (MagickRealType *) NULL);
299 max=MagickMax(r,MagickMax(g,b));
300 c=max-(MagickRealType) MagickMin(r,MagickMin(g,b));
306 h=fmod(6.0+(g-b)/c,6.0);
314 *chroma=QuantumScale*c;
315 *luma=QuantumScale*(0.298839f*r+0.586811f*g+0.114350f*b);
318 static MagickBooleanType CompositeOverImage(Image *image,
319 const Image *composite_image,const MagickBooleanType clip_to_self,
320 const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
322 #define CompositeImageTag "Composite/Image"
342 composite_view=AcquireVirtualCacheView(composite_image,exception);
343 image_view=AcquireAuthenticCacheView(image,exception);
344 #if defined(MAGICKCORE_OPENMP_SUPPORT)
345 #pragma omp parallel for schedule(static,4) shared(progress,status) \
346 magick_threads(composite_image,image,image->rows,1)
348 for (y=0; y < (ssize_t) image->rows; y++)
353 register const Quantum
365 if (status == MagickFalse)
367 if (clip_to_self != MagickFalse)
371 if ((y-y_offset) >= (ssize_t) composite_image->rows)
375 If pixels is NULL, y is outside overlay region.
377 pixels=(Quantum *) NULL;
379 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
381 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
382 composite_image->columns,1,exception);
383 if (p == (const Quantum *) NULL)
390 p-=x_offset*GetPixelChannels(composite_image);
392 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
393 if (q == (Quantum *) NULL)
398 for (x=0; x < (ssize_t) image->columns; x++)
413 if (clip_to_self != MagickFalse)
417 q+=GetPixelChannels(image);
420 if ((x-x_offset) >= (ssize_t) composite_image->columns)
423 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
424 ((x-x_offset) >= (ssize_t) composite_image->columns))
427 source[MaxPixelChannels];
432 Dc: destination color.
434 if (GetPixelMask(image,q) != 0)
436 q+=GetPixelChannels(image);
439 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
441 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
443 PixelChannel channel=GetPixelChannelChannel(image,i);
444 PixelTrait traits=GetPixelChannelTraits(image,channel);
445 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
447 if ((traits == UndefinedPixelTrait) ||
448 (composite_traits == UndefinedPixelTrait))
450 q[i]=source[channel];
452 q+=GetPixelChannels(image);
457 Sa: normalized source alpha.
458 Da: normalized destination alpha.
460 if (GetPixelMask(composite_image,p) != 0)
462 p+=GetPixelChannels(composite_image);
463 channels=GetPixelChannels(composite_image);
464 if (p >= (pixels+channels*composite_image->columns))
466 q+=GetPixelChannels(image);
469 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
470 Da=QuantumScale*GetPixelAlpha(image,q);
471 alpha=Sa*(-Da)+Sa+Da;
472 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
474 PixelChannel channel=GetPixelChannelChannel(image,i);
475 PixelTrait traits=GetPixelChannelTraits(image,channel);
476 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
478 if ((traits == UndefinedPixelTrait) ||
479 (composite_traits == UndefinedPixelTrait))
481 if ((traits & CopyPixelTrait) != 0)
483 if (channel != AlphaPixelChannel)
488 q[i]=GetPixelChannel(composite_image,channel,p);
494 q[i]=ClampToQuantum(QuantumRange*alpha);
499 Dc: destination color.
501 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
502 Dc=(MagickRealType) q[i];
503 gamma=PerceptibleReciprocal(alpha);
504 q[i]=ClampToQuantum(gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc));
506 p+=GetPixelChannels(composite_image);
507 channels=GetPixelChannels(composite_image);
508 if (p >= (pixels+channels*composite_image->columns))
510 q+=GetPixelChannels(image);
512 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
514 if (image->progress_monitor != (MagickProgressMonitor) NULL)
519 #if defined(MAGICKCORE_OPENMP_SUPPORT)
520 #pragma omp critical (MagickCore_CompositeImage)
522 proceed=SetImageProgress(image,CompositeImageTag,progress++,
524 if (proceed == MagickFalse)
528 composite_view=DestroyCacheView(composite_view);
529 image_view=DestroyCacheView(image_view);
533 MagickExport MagickBooleanType CompositeImage(Image *image,
534 const Image *composite,const CompositeOperator compose,
535 const MagickBooleanType clip_to_self,const ssize_t x_offset,
536 const ssize_t y_offset,ExceptionInfo *exception)
538 #define CompositeImageTag "Composite/Image"
559 destination_dissolve,
572 assert(image != (Image *) NULL);
573 assert(image->signature == MagickSignature);
574 if (image->debug != MagickFalse)
575 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
576 assert(composite!= (Image *) NULL);
577 assert(composite->signature == MagickSignature);
578 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
580 composite_image=CloneImage(composite,0,0,MagickTrue,exception);
581 if (composite_image == (const Image *) NULL)
583 if (IsGrayColorspace(image->colorspace) != MagickFalse)
584 (void) SetImageColorspace(image,RGBColorspace,exception);
585 (void) SetImageColorspace(composite_image,image->colorspace,exception);
586 if ((image->alpha_trait == BlendPixelTrait) &&
587 (composite_image->alpha_trait != BlendPixelTrait))
588 (void) SetImageAlphaChannel(composite_image,SetAlphaChannel,exception);
589 if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
591 status=CompositeOverImage(image,composite_image,clip_to_self,x_offset,
593 composite_image=DestroyImage(composite_image);
596 destination_image=(Image *) NULL;
598 destination_dissolve=1.0;
600 percent_chroma=100.0;
605 case CopyCompositeOp:
607 if ((x_offset < 0) || (y_offset < 0))
609 if ((x_offset+(ssize_t) composite_image->columns) >= (ssize_t) image->columns)
611 if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
614 composite_view=AcquireVirtualCacheView(composite_image,exception);
615 image_view=AcquireAuthenticCacheView(image,exception);
616 #if defined(MAGICKCORE_OPENMP_SUPPORT)
617 #pragma omp parallel for schedule(static,4) shared(status) \
618 magick_threads(composite_image,image,composite_image->rows,1)
620 for (y=0; y < (ssize_t) composite_image->rows; y++)
625 register const Quantum
634 if (status == MagickFalse)
636 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
638 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
639 composite_image->columns,1,exception);
640 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
645 for (x=0; x < (ssize_t) composite_image->columns; x++)
650 if (GetPixelMask(composite_image,p) != 0)
652 p+=GetPixelChannels(composite_image);
653 q+=GetPixelChannels(image);
656 for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
658 PixelChannel channel=GetPixelChannelChannel(composite_image,i);
659 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
661 PixelTrait traits=GetPixelChannelTraits(image,channel);
662 if ((traits == UndefinedPixelTrait) ||
663 (composite_traits == UndefinedPixelTrait))
665 SetPixelChannel(image,channel,p[i],q);
667 p+=GetPixelChannels(composite_image);
668 q+=GetPixelChannels(image);
670 sync=SyncCacheViewAuthenticPixels(image_view,exception);
671 if (sync == MagickFalse)
673 if (image->progress_monitor != (MagickProgressMonitor) NULL)
678 #if defined(MAGICKCORE_OPENMP_SUPPORT)
679 #pragma omp critical (MagickCore_CompositeImage)
681 proceed=SetImageProgress(image,CompositeImageTag,
682 (MagickOffsetType) y,image->rows);
683 if (proceed == MagickFalse)
687 composite_view=DestroyCacheView(composite_view);
688 image_view=DestroyCacheView(image_view);
689 composite_image=DestroyImage(composite_image);
692 case CopyAlphaCompositeOp:
693 case ChangeMaskCompositeOp:
694 case IntensityCompositeOp:
697 Modify destination outside the overlaid region and require an alpha
698 channel to exist, to add transparency.
700 if (image->alpha_trait != BlendPixelTrait)
701 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
704 case BlurCompositeOp:
729 Blur Image by resampling.
731 Blur Image dictated by an overlay gradient map: X = red_channel;
732 Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
734 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
736 if (destination_image == (Image *) NULL)
738 composite_image=DestroyImage(composite_image);
742 Gather the maximum blur sigma values from user.
744 SetGeometryInfo(&geometry_info);
746 value=GetImageArtifact(image,"compose:args");
747 if (value != (const char *) NULL)
748 flags=ParseGeometry(value,&geometry_info);
749 if ((flags & WidthValue) == 0)
751 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
752 "InvalidSetting","'%s' '%s'","compose:args",value);
753 composite_image=DestroyImage(composite_image);
754 destination_image=DestroyImage(destination_image);
758 Users input sigma now needs to be converted to the EWA ellipse size.
759 The filter defaults to a sigma of 0.5 so to make this match the
760 users input the ellipse size needs to be doubled.
762 width=height=geometry_info.rho*2.0;
763 if ((flags & HeightValue) != 0 )
764 height=geometry_info.sigma*2.0;
766 Default the unrotated ellipse width and height axis vectors.
772 /* rotate vectors if a rotation angle is given */
773 if ((flags & XValue) != 0 )
778 angle=DegreesToRadians(geometry_info.xi);
779 blur.x1=width*cos(angle);
780 blur.x2=width*sin(angle);
781 blur.y1=(-height*sin(angle));
782 blur.y2=height*cos(angle);
784 /* Otherwise lets set a angle range and calculate in the loop */
787 if ((flags & YValue) != 0 )
789 angle_start=DegreesToRadians(geometry_info.xi);
790 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
793 Set up a gaussian cylindrical filter for EWA Bluring.
795 As the minimum ellipse radius of support*1.0 the EWA algorithm
796 can only produce a minimum blur of 0.5 for Gaussian (support=2.0)
797 This means that even 'No Blur' will be still a little blurry!
799 The solution (as well as the problem of preventing any user
800 expert filter settings, is to set our own user settings, then
801 restore them afterwards.
803 resample_filter=AcquireResampleFilter(image,exception);
804 SetResampleFilter(resample_filter,GaussianFilter);
806 /* do the variable blurring of each pixel in image */
807 GetPixelInfo(image,&pixel);
808 composite_view=AcquireVirtualCacheView(composite_image,exception);
809 destination_view=AcquireAuthenticCacheView(destination_image,exception);
810 for (y=0; y < (ssize_t) composite_image->rows; y++)
815 register const Quantum
824 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
826 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
828 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
829 destination_image->columns,1,exception);
830 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
832 for (x=0; x < (ssize_t) composite_image->columns; x++)
834 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
836 p+=GetPixelChannels(composite_image);
839 if (fabs(angle_range) > MagickEpsilon)
844 angle=angle_start+angle_range*QuantumScale*
845 GetPixelBlue(composite_image,p);
846 blur.x1=width*cos(angle);
847 blur.x2=width*sin(angle);
848 blur.y1=(-height*sin(angle));
849 blur.y2=height*cos(angle);
852 if ( x == 10 && y == 60 ) {
853 (void) fprintf(stderr, "blur.x=%lf,%lf, blur.y=%lf,%lf\n",blur.x1,
854 blur.x2,blur.y1, blur.y2);
855 (void) fprintf(stderr, "scaled by=%lf,%lf\n",QuantumScale*
856 GetPixelRed(p),QuantumScale*GetPixelGreen(p));
858 ScaleResampleFilter(resample_filter,
859 blur.x1*QuantumScale*GetPixelRed(composite_image,p),
860 blur.y1*QuantumScale*GetPixelGreen(composite_image,p),
861 blur.x2*QuantumScale*GetPixelRed(composite_image,p),
862 blur.y2*QuantumScale*GetPixelGreen(composite_image,p) );
863 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
864 (double) y_offset+y,&pixel,exception);
865 SetPixelInfoPixel(destination_image,&pixel,q);
866 p+=GetPixelChannels(composite_image);
867 q+=GetPixelChannels(destination_image);
869 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
870 if (sync == MagickFalse)
873 resample_filter=DestroyResampleFilter(resample_filter);
874 composite_view=DestroyCacheView(composite_view);
875 destination_view=DestroyCacheView(destination_view);
876 composite_image=DestroyImage(composite_image);
877 composite_image=destination_image;
880 case DisplaceCompositeOp:
881 case DistortCompositeOp:
903 Displace/Distort based on overlay gradient map:
904 X = red_channel; Y = green_channel;
905 compose:args = x_scale[,y_scale[,center.x,center.y]]
907 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
909 if (destination_image == (Image *) NULL)
911 composite_image=DestroyImage(composite_image);
914 SetGeometryInfo(&geometry_info);
916 value=GetImageArtifact(composite_image,"compose:args");
917 if (value != (char *) NULL)
918 flags=ParseGeometry(value,&geometry_info);
919 if ((flags & (WidthValue|HeightValue)) == 0 )
921 if ((flags & AspectValue) == 0)
923 horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
925 vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
929 horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
930 vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
935 horizontal_scale=geometry_info.rho;
936 vertical_scale=geometry_info.sigma;
937 if ((flags & PercentValue) != 0)
939 if ((flags & AspectValue) == 0)
941 horizontal_scale*=(composite_image->columns-1.0)/200.0;
942 vertical_scale*=(composite_image->rows-1.0)/200.0;
946 horizontal_scale*=(image->columns-1.0)/200.0;
947 vertical_scale*=(image->rows-1.0)/200.0;
950 if ((flags & HeightValue) == 0)
951 vertical_scale=horizontal_scale;
954 Determine fixed center point for absolute distortion map
956 Displace offset relative to a fixed absolute point
957 Select that point according to +X+Y user inputs.
958 default = center of overlay image
959 arg flag '!' = locations/percentage relative to background image
961 center.x=(MagickRealType) x_offset;
962 center.y=(MagickRealType) y_offset;
963 if (compose == DistortCompositeOp)
965 if ((flags & XValue) == 0)
966 if ((flags & AspectValue) == 0)
967 center.x=(MagickRealType) (x_offset+(composite_image->columns-1)/
970 center.x=(MagickRealType) ((image->columns-1)/2);
972 if ((flags & AspectValue) == 0)
973 center.x=(MagickRealType) x_offset+geometry_info.xi;
975 center.x=geometry_info.xi;
976 if ((flags & YValue) == 0)
977 if ((flags & AspectValue) == 0)
978 center.y=(MagickRealType) (y_offset+(composite_image->rows-1)/
981 center.y=(MagickRealType) ((image->rows-1)/2);
983 if ((flags & AspectValue) == 0)
984 center.y=(MagickRealType) y_offset+geometry_info.psi;
986 center.y=geometry_info.psi;
989 Shift the pixel offset point as defined by the provided,
990 displacement/distortion map. -- Like a lens...
992 GetPixelInfo(image,&pixel);
993 image_view=AcquireVirtualCacheView(image,exception);
994 composite_view=AcquireVirtualCacheView(composite_image,exception);
995 destination_view=AcquireAuthenticCacheView(destination_image,exception);
996 for (y=0; y < (ssize_t) composite_image->rows; y++)
1001 register const Quantum
1010 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1012 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
1014 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
1015 destination_image->columns,1,exception);
1016 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1018 for (x=0; x < (ssize_t) composite_image->columns; x++)
1020 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1022 p+=GetPixelChannels(composite_image);
1026 Displace the offset.
1028 offset.x=(double) (horizontal_scale*(GetPixelRed(composite_image,p)-
1029 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1030 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
1032 offset.y=(double) (vertical_scale*(GetPixelGreen(composite_image,p)-
1033 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1034 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
1036 (void) InterpolatePixelInfo(image,image_view,
1037 UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1040 Mask with the 'invalid pixel mask' in alpha channel.
1042 pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
1043 pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
1044 SetPixelInfoPixel(destination_image,&pixel,q);
1045 p+=GetPixelChannels(composite_image);
1046 q+=GetPixelChannels(destination_image);
1048 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1049 if (sync == MagickFalse)
1052 destination_view=DestroyCacheView(destination_view);
1053 composite_view=DestroyCacheView(composite_view);
1054 image_view=DestroyCacheView(image_view);
1055 composite_image=DestroyImage(composite_image);
1056 composite_image=destination_image;
1059 case DissolveCompositeOp:
1065 Geometry arguments to dissolve factors.
1067 value=GetImageArtifact(composite_image,"compose:args");
1068 if (value != (char *) NULL)
1070 flags=ParseGeometry(value,&geometry_info);
1071 source_dissolve=geometry_info.rho/100.0;
1072 destination_dissolve=1.0;
1073 if ((source_dissolve-MagickEpsilon) < 0.0)
1074 source_dissolve=0.0;
1075 if ((source_dissolve+MagickEpsilon) > 1.0)
1077 destination_dissolve=2.0-source_dissolve;
1078 source_dissolve=1.0;
1080 if ((flags & SigmaValue) != 0)
1081 destination_dissolve=geometry_info.sigma/100.0;
1082 if ((destination_dissolve-MagickEpsilon) < 0.0)
1083 destination_dissolve=0.0;
1084 /* posible speed up? -- from IMv6 update
1085 clip_to_self=MagickFalse;
1086 if ((destination_dissolve+MagickEpsilon) > 1.0 )
1088 destination_dissolve=1.0;
1089 clip_to_self=MagickTrue;
1095 case BlendCompositeOp:
1100 value=GetImageArtifact(composite_image,"compose:args");
1101 if (value != (char *) NULL)
1103 flags=ParseGeometry(value,&geometry_info);
1104 source_dissolve=geometry_info.rho/100.0;
1105 destination_dissolve=1.0-source_dissolve;
1106 if ((flags & SigmaValue) != 0)
1107 destination_dissolve=geometry_info.sigma/100.0;
1111 case MathematicsCompositeOp:
1117 Just collect the values from "compose:args", setting.
1118 Unused values are set to zero automagically.
1120 Arguments are normally a comma separated list, so this probably should
1121 be changed to some 'general comma list' parser, (with a minimum
1124 SetGeometryInfo(&geometry_info);
1125 value=GetImageArtifact(composite_image,"compose:args");
1126 if (value != (char *) NULL)
1127 (void) ParseGeometry(value,&geometry_info);
1130 case ModulateCompositeOp:
1136 Determine the luma and chroma scale.
1138 value=GetImageArtifact(composite_image,"compose:args");
1139 if (value != (char *) NULL)
1141 flags=ParseGeometry(value,&geometry_info);
1142 percent_luma=geometry_info.rho;
1143 if ((flags & SigmaValue) != 0)
1144 percent_chroma=geometry_info.sigma;
1148 case ThresholdCompositeOp:
1154 Determine the amount and threshold.
1156 value=GetImageArtifact(composite_image,"compose:args");
1157 if (value != (char *) NULL)
1159 flags=ParseGeometry(value,&geometry_info);
1160 amount=geometry_info.rho;
1161 threshold=geometry_info.sigma;
1162 if ((flags & SigmaValue) == 0)
1165 threshold*=QuantumRange;
1176 midpoint=((MagickRealType) QuantumRange+1.0)/2;
1177 composite_view=AcquireVirtualCacheView(composite_image,exception);
1178 image_view=AcquireAuthenticCacheView(image,exception);
1179 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1180 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1181 magick_threads(composite_image,image,image->rows,1)
1183 for (y=0; y < (ssize_t) image->rows; y++)
1200 register const Quantum
1209 if (status == MagickFalse)
1211 if (clip_to_self != MagickFalse)
1215 if ((y-y_offset) >= (ssize_t) composite_image->rows)
1219 If pixels is NULL, y is outside overlay region.
1221 pixels=(Quantum *) NULL;
1223 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
1225 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
1226 composite_image->columns,1,exception);
1227 if (p == (const Quantum *) NULL)
1234 p-=x_offset*GetPixelChannels(composite_image);
1236 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1237 if (q == (Quantum *) NULL)
1245 GetPixelInfo(image,&destination_pixel);
1246 GetPixelInfo(composite_image,&source_pixel);
1247 for (x=0; x < (ssize_t) image->columns; x++)
1267 if (clip_to_self != MagickFalse)
1271 q+=GetPixelChannels(image);
1274 if ((x-x_offset) >= (ssize_t) composite_image->columns)
1277 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1278 ((x-x_offset) >= (ssize_t) composite_image->columns))
1281 source[MaxPixelChannels];
1286 Dc: destination color.
1288 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
1290 if (GetPixelMask(image,q) != 0)
1292 q+=GetPixelChannels(image);
1295 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1300 PixelChannel channel=GetPixelChannelChannel(image,i);
1301 PixelTrait traits=GetPixelChannelTraits(image,channel);
1302 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
1304 if ((traits == UndefinedPixelTrait) ||
1305 (composite_traits == UndefinedPixelTrait))
1309 case AlphaCompositeOp:
1310 case ChangeMaskCompositeOp:
1311 case CopyAlphaCompositeOp:
1312 case DstAtopCompositeOp:
1313 case DstInCompositeOp:
1315 case IntensityCompositeOp:
1316 case OutCompositeOp:
1317 case SrcInCompositeOp:
1318 case SrcOutCompositeOp:
1320 pixel=(MagickRealType) q[i];
1321 if (channel == AlphaPixelChannel)
1322 pixel=(MagickRealType) TransparentAlpha;
1325 case ClearCompositeOp:
1326 case CopyCompositeOp:
1327 case ReplaceCompositeOp:
1328 case SrcCompositeOp:
1330 if (channel == AlphaPixelChannel)
1332 pixel=(MagickRealType) TransparentAlpha;
1338 case BlendCompositeOp:
1339 case DissolveCompositeOp:
1341 if (channel == AlphaPixelChannel)
1343 pixel=destination_dissolve*GetPixelAlpha(composite_image,
1347 pixel=(MagickRealType) source[channel];
1352 pixel=(MagickRealType) source[channel];
1356 q[i]=ClampToQuantum(pixel);
1358 q+=GetPixelChannels(image);
1362 Authentic composite:
1363 Sa: normalized source alpha.
1364 Da: normalized destination alpha.
1366 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
1367 Da=QuantumScale*GetPixelAlpha(image,q);
1370 case BumpmapCompositeOp:
1372 alpha=GetPixelIntensity(composite_image,p)*Sa;
1375 case ColorBurnCompositeOp:
1376 case ColorDodgeCompositeOp:
1377 case DifferenceCompositeOp:
1378 case DivideDstCompositeOp:
1379 case DivideSrcCompositeOp:
1380 case ExclusionCompositeOp:
1381 case HardLightCompositeOp:
1382 case LinearBurnCompositeOp:
1383 case LinearDodgeCompositeOp:
1384 case LinearLightCompositeOp:
1385 case MathematicsCompositeOp:
1386 case MinusDstCompositeOp:
1387 case MinusSrcCompositeOp:
1388 case ModulusAddCompositeOp:
1389 case ModulusSubtractCompositeOp:
1390 case MultiplyCompositeOp:
1391 case OverlayCompositeOp:
1392 case PegtopLightCompositeOp:
1393 case PinLightCompositeOp:
1394 case ScreenCompositeOp:
1395 case SoftLightCompositeOp:
1396 case VividLightCompositeOp:
1398 alpha=RoundToUnity(Sa+Da-Sa*Da);
1401 case DarkenCompositeOp:
1402 case DstAtopCompositeOp:
1403 case DstInCompositeOp:
1405 case LightenCompositeOp:
1406 case SrcInCompositeOp:
1411 case DissolveCompositeOp:
1413 alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
1414 Sa+destination_dissolve*Da;
1417 case DstOverCompositeOp:
1419 alpha=Da*(-Sa)+Da+Sa;
1422 case DstOutCompositeOp:
1427 case OutCompositeOp:
1428 case SrcOutCompositeOp:
1433 case OverCompositeOp:
1434 case SrcOverCompositeOp:
1436 alpha=Sa*(-Da)+Sa+Da;
1439 case BlendCompositeOp:
1440 case PlusCompositeOp:
1442 alpha=RoundToUnity(Sa+Da);
1445 case XorCompositeOp:
1447 alpha=Sa+Da-2.0*Sa*Da;
1456 if (GetPixelMask(image,q) != 0)
1458 p+=GetPixelChannels(composite_image);
1459 q+=GetPixelChannels(image);
1464 case ColorizeCompositeOp:
1465 case HueCompositeOp:
1466 case LuminizeCompositeOp:
1467 case ModulateCompositeOp:
1468 case SaturateCompositeOp:
1470 GetPixelInfoPixel(composite_image,p,&source_pixel);
1471 GetPixelInfoPixel(image,q,&destination_pixel);
1477 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1483 PixelChannel channel=GetPixelChannelChannel(image,i);
1484 PixelTrait traits=GetPixelChannelTraits(image,channel);
1485 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
1487 if (traits == UndefinedPixelTrait)
1489 if ((compose != IntensityCompositeOp) &&
1490 (composite_traits == UndefinedPixelTrait))
1494 Dc: destination color.
1496 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
1497 Dc=(MagickRealType) q[i];
1498 if ((traits & CopyPixelTrait) != 0)
1500 if (channel != AlphaPixelChannel)
1505 q[i]=ClampToQuantum(Sc);
1513 case AlphaCompositeOp:
1515 pixel=QuantumRange*Sa;
1518 case AtopCompositeOp:
1519 case CopyBlackCompositeOp:
1520 case CopyBlueCompositeOp:
1521 case CopyCyanCompositeOp:
1522 case CopyGreenCompositeOp:
1523 case CopyMagentaCompositeOp:
1524 case CopyRedCompositeOp:
1525 case CopyYellowCompositeOp:
1526 case SrcAtopCompositeOp:
1527 case DstCompositeOp:
1530 pixel=QuantumRange*Da;
1533 case ChangeMaskCompositeOp:
1538 if (Da > ((MagickRealType) QuantumRange/2.0))
1540 pixel=(MagickRealType) TransparentAlpha;
1543 equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
1544 if (equivalent != MagickFalse)
1546 pixel=(MagickRealType) TransparentAlpha;
1549 pixel=(MagickRealType) OpaqueAlpha;
1552 case ClearCompositeOp:
1554 pixel=(MagickRealType) TransparentAlpha;
1557 case ColorizeCompositeOp:
1558 case HueCompositeOp:
1559 case LuminizeCompositeOp:
1560 case SaturateCompositeOp:
1562 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1564 pixel=QuantumRange*Da;
1567 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1569 pixel=QuantumRange*Sa;
1574 pixel=QuantumRange*Da;
1577 pixel=QuantumRange*Sa;
1580 case CopyAlphaCompositeOp:
1582 pixel=QuantumRange*Sa;
1583 if (composite_image->alpha_trait == BlendPixelTrait)
1584 pixel=GetPixelIntensity(composite_image,p);
1587 case CopyCompositeOp:
1588 case DisplaceCompositeOp:
1589 case DistortCompositeOp:
1590 case DstAtopCompositeOp:
1591 case ReplaceCompositeOp:
1592 case SrcCompositeOp:
1594 pixel=QuantumRange*Sa;
1597 case DarkenIntensityCompositeOp:
1599 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1600 (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
1603 case IntensityCompositeOp:
1605 pixel=GetPixelIntensity(composite_image,p);
1608 case LightenIntensityCompositeOp:
1610 pixel=Sa*GetPixelIntensity(composite_image,p) >
1611 Da*GetPixelIntensity(image,q) ? Sa : Da;
1614 case ModulateCompositeOp:
1616 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1618 pixel=QuantumRange*Da;
1621 pixel=QuantumRange*Da;
1626 pixel=QuantumRange*alpha;
1630 q[i]=ClampToQuantum(pixel);
1634 Porter-Duff compositions:
1635 Sca: source normalized color multiplied by alpha.
1636 Dca: normalized destination color multiplied by alpha.
1638 Sca=QuantumScale*Sa*Sc;
1639 Dca=QuantumScale*Da*Dc;
1642 case DarkenCompositeOp:
1643 case LightenCompositeOp:
1644 case ModulusSubtractCompositeOp:
1652 gamma=PerceptibleReciprocal(alpha);
1656 case AlphaCompositeOp:
1658 pixel=QuantumRange*Sa;
1661 case AtopCompositeOp:
1662 case SrcAtopCompositeOp:
1664 pixel=Sc*Sa+Dc*(1.0-Sa);
1667 case BlendCompositeOp:
1669 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1672 case BlurCompositeOp:
1673 case DisplaceCompositeOp:
1674 case DistortCompositeOp:
1675 case CopyCompositeOp:
1676 case ReplaceCompositeOp:
1677 case SrcCompositeOp:
1682 case BumpmapCompositeOp:
1684 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1689 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1692 case ChangeMaskCompositeOp:
1697 case ClearCompositeOp:
1702 case ColorBurnCompositeOp:
1705 Refer to the March 2009 SVG specification.
1707 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1709 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1712 if (Sca < MagickEpsilon)
1714 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1717 pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
1718 Sca*(1.0-Da)+Dca*(1.0-Sa));
1721 case ColorDodgeCompositeOp:
1723 if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1725 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1728 if (fabs(Sca-Sa) < MagickEpsilon)
1730 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1733 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1737 case ColorizeCompositeOp:
1739 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1744 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1749 CompositeHCL(destination_pixel.red,destination_pixel.green,
1750 destination_pixel.blue,&sans,&sans,&luma);
1751 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1752 &hue,&chroma,&sans);
1753 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1756 case RedPixelChannel: pixel=red; break;
1757 case GreenPixelChannel: pixel=green; break;
1758 case BluePixelChannel: pixel=blue; break;
1759 default: pixel=Dc; break;
1763 case CopyAlphaCompositeOp:
1764 case IntensityCompositeOp:
1769 case CopyBlackCompositeOp:
1771 if (channel == BlackPixelChannel)
1772 pixel=(MagickRealType) GetPixelBlack(composite_image,p);
1775 case CopyBlueCompositeOp:
1776 case CopyYellowCompositeOp:
1778 if (channel == BluePixelChannel)
1779 pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1782 case CopyGreenCompositeOp:
1783 case CopyMagentaCompositeOp:
1785 if (channel == GreenPixelChannel)
1786 pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1789 case CopyRedCompositeOp:
1790 case CopyCyanCompositeOp:
1792 if (channel == RedPixelChannel)
1793 pixel=(MagickRealType) GetPixelRed(composite_image,p);
1796 case DarkenCompositeOp:
1799 Darken is equivalent to a 'Minimum' method
1800 OR a greyscale version of a binary 'Or'
1801 OR the 'Intersection' of pixel sets.
1805 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1808 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1811 case DarkenIntensityCompositeOp:
1813 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1814 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1817 case DifferenceCompositeOp:
1819 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1822 case DissolveCompositeOp:
1824 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1825 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1828 case DivideDstCompositeOp:
1830 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1832 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1835 if (fabs(Dca) < MagickEpsilon)
1837 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1840 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1843 case DivideSrcCompositeOp:
1845 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1847 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1850 if (fabs(Sca) < MagickEpsilon)
1852 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1855 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1858 case DstAtopCompositeOp:
1860 pixel=Dc*Da+Sc*(1.0-Da);
1863 case DstCompositeOp:
1869 case DstInCompositeOp:
1871 pixel=gamma*(Sa*Dc*Sa);
1874 case DstOutCompositeOp:
1876 pixel=gamma*(Da*Dc*(1.0-Sa));
1879 case DstOverCompositeOp:
1881 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1884 case ExclusionCompositeOp:
1886 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1890 case HardLightCompositeOp:
1894 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1898 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1902 case HueCompositeOp:
1904 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1909 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1914 CompositeHCL(destination_pixel.red,destination_pixel.green,
1915 destination_pixel.blue,&hue,&chroma,&luma);
1916 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1918 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1921 case RedPixelChannel: pixel=red; break;
1922 case GreenPixelChannel: pixel=green; break;
1923 case BluePixelChannel: pixel=blue; break;
1924 default: pixel=Dc; break;
1929 case SrcInCompositeOp:
1931 pixel=gamma*(Da*Sc*Da);
1934 case LinearBurnCompositeOp:
1937 LinearBurn: as defined by Abode Photoshop, according to
1938 http://www.simplefilter.de/en/basics/mixmods.html is:
1940 f(Sc,Dc) = Sc + Dc - 1
1942 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1945 case LinearDodgeCompositeOp:
1947 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1950 case LinearLightCompositeOp:
1953 LinearLight: as defined by Abode Photoshop, according to
1954 http://www.simplefilter.de/en/basics/mixmods.html is:
1956 f(Sc,Dc) = Dc + 2*Sc - 1
1958 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1961 case LightenCompositeOp:
1965 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1968 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1971 case LightenIntensityCompositeOp:
1974 Lighten is equivalent to a 'Maximum' method
1975 OR a greyscale version of a binary 'And'
1976 OR the 'Union' of pixel sets.
1978 pixel=Sa*GetPixelIntensity(composite_image,p) >
1979 Da*GetPixelIntensity(image,q) ? Sc : Dc;
1982 case LuminizeCompositeOp:
1984 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1989 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1994 CompositeHCL(destination_pixel.red,destination_pixel.green,
1995 destination_pixel.blue,&hue,&chroma,&luma);
1996 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1998 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2001 case RedPixelChannel: pixel=red; break;
2002 case GreenPixelChannel: pixel=green; break;
2003 case BluePixelChannel: pixel=blue; break;
2004 default: pixel=Dc; break;
2008 case MathematicsCompositeOp:
2011 'Mathematics' a free form user control mathematical composition
2014 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
2016 Where the arguments A,B,C,D are (currently) passed to composite
2017 as a command separated 'geometry' string in "compose:args" image
2020 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
2022 Applying the SVG transparency formula (see above), we get...
2024 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
2026 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
2029 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
2030 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
2031 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
2034 case MinusDstCompositeOp:
2036 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2039 case MinusSrcCompositeOp:
2042 Minus source from destination.
2046 pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2049 case ModulateCompositeOp:
2054 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2059 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
2065 CompositeHCL(destination_pixel.red,destination_pixel.green,
2066 destination_pixel.blue,&hue,&chroma,&luma);
2067 luma+=(0.01*percent_luma*offset)/midpoint;
2068 chroma*=0.01*percent_chroma;
2069 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2072 case RedPixelChannel: pixel=red; break;
2073 case GreenPixelChannel: pixel=green; break;
2074 case BluePixelChannel: pixel=blue; break;
2075 default: pixel=Dc; break;
2079 case ModulusAddCompositeOp:
2082 if (pixel > QuantumRange)
2083 pixel-=(QuantumRange+1.0);
2084 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2087 case ModulusSubtractCompositeOp:
2091 pixel+=(QuantumRange+1.0);
2092 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2095 case MultiplyCompositeOp:
2097 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2100 case OutCompositeOp:
2101 case SrcOutCompositeOp:
2103 pixel=gamma*(Sa*Sc*(1.0-Da));
2106 case OverCompositeOp:
2107 case SrcOverCompositeOp:
2109 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2112 case OverlayCompositeOp:
2116 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2120 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2124 case PegtopLightCompositeOp:
2127 PegTop: A Soft-Light alternative: A continuous version of the
2128 Softlight function, producing very similar results.
2130 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2132 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2134 if (fabs(Da) < MagickEpsilon)
2136 pixel=QuantumRange*gamma*(Sca);
2139 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2143 case PinLightCompositeOp:
2146 PinLight: A Photoshop 7 composition method
2147 http://www.simplefilter.de/en/basics/mixmods.html
2149 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2151 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2153 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2156 if ((Dca*Sa) > (2.0*Sca*Da))
2158 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2161 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2164 case PlusCompositeOp:
2166 pixel=gamma*(Sa*Sc+Da*Dc);
2169 case SaturateCompositeOp:
2171 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2176 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2181 CompositeHCL(destination_pixel.red,destination_pixel.green,
2182 destination_pixel.blue,&hue,&chroma,&luma);
2183 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2184 &sans,&chroma,&sans);
2185 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2188 case RedPixelChannel: pixel=red; break;
2189 case GreenPixelChannel: pixel=green; break;
2190 case BluePixelChannel: pixel=blue; break;
2191 default: pixel=Dc; break;
2195 case ScreenCompositeOp:
2198 Screen: a negated multiply:
2200 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2202 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2205 case SoftLightCompositeOp:
2208 Refer to the March 2009 SVG specification.
2212 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2213 Sca*(1.0-Da)+Dca*(1.0-Sa));
2216 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2218 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2219 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2223 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2224 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2227 case ThresholdCompositeOp:
2233 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2238 pixel=gamma*(Dc+delta*amount);
2241 case VividLightCompositeOp:
2244 VividLight: A Photoshop 7 composition method. See
2245 http://www.simplefilter.de/en/basics/mixmods.html.
2247 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2249 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2251 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2254 if ((2.0*Sca) <= Sa)
2256 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2257 (1.0-Da)+Dca*(1.0-Sa));
2260 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2264 case XorCompositeOp:
2266 pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2275 q[i]=ClampToQuantum(pixel);
2277 p+=GetPixelChannels(composite_image);
2278 channels=GetPixelChannels(composite_image);
2279 if (p >= (pixels+channels*composite_image->columns))
2281 q+=GetPixelChannels(image);
2283 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2285 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2290 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2291 #pragma omp critical (MagickCore_CompositeImage)
2293 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2295 if (proceed == MagickFalse)
2299 composite_view=DestroyCacheView(composite_view);
2300 image_view=DestroyCacheView(image_view);
2301 if (destination_image != (Image * ) NULL)
2302 destination_image=DestroyImage(destination_image);
2304 composite_image=DestroyImage(composite_image);
2309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2313 % T e x t u r e I m a g e %
2317 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2319 % TextureImage() repeatedly tiles the texture image across and down the image
2322 % The format of the TextureImage method is:
2324 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2325 % ExceptionInfo *exception)
2327 % A description of each parameter follows:
2329 % o image: the image.
2331 % o texture_image: This image is the texture to layer on the background.
2334 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
2335 ExceptionInfo *exception)
2337 #define TextureImageTag "Texture/Image"
2352 assert(image != (Image *) NULL);
2353 if (image->debug != MagickFalse)
2354 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2355 assert(image->signature == MagickSignature);
2356 if (texture == (const Image *) NULL)
2357 return(MagickFalse);
2358 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2359 return(MagickFalse);
2360 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2361 if (texture_image == (const Image *) NULL)
2362 return(MagickFalse);
2363 (void) TransformImageColorspace(texture_image,image->colorspace,exception);
2364 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
2367 if ((image->compose != CopyCompositeOp) &&
2368 ((image->compose != OverCompositeOp) || (image->alpha_trait == BlendPixelTrait) ||
2369 (texture_image->alpha_trait == BlendPixelTrait)))
2372 Tile texture onto the image background.
2374 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2379 if (status == MagickFalse)
2381 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2386 thread_status=CompositeImage(image,texture_image,image->compose,
2387 MagickFalse,x+texture_image->tile_offset.x,y+
2388 texture_image->tile_offset.y,exception);
2389 if (thread_status == MagickFalse)
2391 status=thread_status;
2395 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2400 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2402 if (proceed == MagickFalse)
2406 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2407 image->rows,image->rows);
2408 texture_image=DestroyImage(texture_image);
2412 Tile texture onto the image background (optimized).
2415 texture_view=AcquireVirtualCacheView(texture_image,exception);
2416 image_view=AcquireAuthenticCacheView(image,exception);
2417 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2418 #pragma omp parallel for schedule(static,4) shared(status) \
2419 magick_threads(texture_image,image,1,1)
2421 for (y=0; y < (ssize_t) image->rows; y++)
2426 register const Quantum
2439 if (status == MagickFalse)
2441 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2442 (y+texture_image->tile_offset.y) % texture_image->rows,
2443 texture_image->columns,1,exception);
2444 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2445 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2450 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2456 width=texture_image->columns;
2457 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2458 width=image->columns-x;
2459 for (j=0; j < (ssize_t) width; j++)
2464 if (GetPixelMask(image,q) != 0)
2466 p+=GetPixelChannels(texture_image);
2467 q+=GetPixelChannels(image);
2470 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2472 PixelChannel channel=GetPixelChannelChannel(texture_image,i);
2473 PixelTrait traits=GetPixelChannelTraits(image,channel);
2474 PixelTrait texture_traits=GetPixelChannelTraits(texture_image,
2476 if ((traits == UndefinedPixelTrait) ||
2477 (texture_traits == UndefinedPixelTrait))
2479 SetPixelChannel(image,channel,p[i],q);
2481 p+=GetPixelChannels(texture_image);
2482 q+=GetPixelChannels(image);
2485 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2486 if (sync == MagickFalse)
2488 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2493 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2495 if (proceed == MagickFalse)
2499 texture_view=DestroyCacheView(texture_view);
2500 image_view=DestroyCacheView(image_view);
2501 texture_image=DestroyImage(texture_image);