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 (GetPixelReadMask(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 (GetPixelReadMask(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 (void) SetImageColorspace(composite_image,image->colorspace,exception);
584 if ((image->alpha_trait == BlendPixelTrait) &&
585 (composite_image->alpha_trait != BlendPixelTrait))
586 (void) SetImageAlphaChannel(composite_image,SetAlphaChannel,exception);
587 if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
589 status=CompositeOverImage(image,composite_image,clip_to_self,x_offset,
591 composite_image=DestroyImage(composite_image);
594 destination_image=(Image *) NULL;
596 destination_dissolve=1.0;
598 percent_chroma=100.0;
603 case CopyCompositeOp:
605 if ((x_offset < 0) || (y_offset < 0))
607 if ((x_offset+(ssize_t) composite_image->columns) >= (ssize_t) image->columns)
609 if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
612 composite_view=AcquireVirtualCacheView(composite_image,exception);
613 image_view=AcquireAuthenticCacheView(image,exception);
614 #if defined(MAGICKCORE_OPENMP_SUPPORT)
615 #pragma omp parallel for schedule(static,4) shared(status) \
616 magick_threads(composite_image,image,composite_image->rows,1)
618 for (y=0; y < (ssize_t) composite_image->rows; y++)
623 register const Quantum
632 if (status == MagickFalse)
634 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
636 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
637 composite_image->columns,1,exception);
638 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
643 for (x=0; x < (ssize_t) composite_image->columns; x++)
648 if (GetPixelReadMask(composite_image,p) == 0)
650 p+=GetPixelChannels(composite_image);
651 q+=GetPixelChannels(image);
654 for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
656 PixelChannel channel=GetPixelChannelChannel(composite_image,i);
657 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
659 PixelTrait traits=GetPixelChannelTraits(image,channel);
660 if ((traits == UndefinedPixelTrait) ||
661 (composite_traits == UndefinedPixelTrait))
663 SetPixelChannel(image,channel,p[i],q);
665 p+=GetPixelChannels(composite_image);
666 q+=GetPixelChannels(image);
668 sync=SyncCacheViewAuthenticPixels(image_view,exception);
669 if (sync == MagickFalse)
671 if (image->progress_monitor != (MagickProgressMonitor) NULL)
676 #if defined(MAGICKCORE_OPENMP_SUPPORT)
677 #pragma omp critical (MagickCore_CompositeImage)
679 proceed=SetImageProgress(image,CompositeImageTag,
680 (MagickOffsetType) y,image->rows);
681 if (proceed == MagickFalse)
685 composite_view=DestroyCacheView(composite_view);
686 image_view=DestroyCacheView(image_view);
687 composite_image=DestroyImage(composite_image);
690 case CopyAlphaCompositeOp:
691 case ChangeMaskCompositeOp:
692 case IntensityCompositeOp:
695 Modify destination outside the overlaid region and require an alpha
696 channel to exist, to add transparency.
698 if (image->alpha_trait != BlendPixelTrait)
699 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
702 case BlurCompositeOp:
727 Blur Image by resampling.
729 Blur Image dictated by an overlay gradient map: X = red_channel;
730 Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
732 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
734 if (destination_image == (Image *) NULL)
736 composite_image=DestroyImage(composite_image);
740 Gather the maximum blur sigma values from user.
742 SetGeometryInfo(&geometry_info);
744 value=GetImageArtifact(image,"compose:args");
745 if (value != (const char *) NULL)
746 flags=ParseGeometry(value,&geometry_info);
747 if ((flags & WidthValue) == 0)
749 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
750 "InvalidSetting","'%s' '%s'","compose:args",value);
751 composite_image=DestroyImage(composite_image);
752 destination_image=DestroyImage(destination_image);
756 Users input sigma now needs to be converted to the EWA ellipse size.
757 The filter defaults to a sigma of 0.5 so to make this match the
758 users input the ellipse size needs to be doubled.
760 width=height=geometry_info.rho*2.0;
761 if ((flags & HeightValue) != 0 )
762 height=geometry_info.sigma*2.0;
764 Default the unrotated ellipse width and height axis vectors.
770 /* rotate vectors if a rotation angle is given */
771 if ((flags & XValue) != 0 )
776 angle=DegreesToRadians(geometry_info.xi);
777 blur.x1=width*cos(angle);
778 blur.x2=width*sin(angle);
779 blur.y1=(-height*sin(angle));
780 blur.y2=height*cos(angle);
782 /* Otherwise lets set a angle range and calculate in the loop */
785 if ((flags & YValue) != 0 )
787 angle_start=DegreesToRadians(geometry_info.xi);
788 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
791 Set up a gaussian cylindrical filter for EWA Bluring.
793 As the minimum ellipse radius of support*1.0 the EWA algorithm
794 can only produce a minimum blur of 0.5 for Gaussian (support=2.0)
795 This means that even 'No Blur' will be still a little blurry!
797 The solution (as well as the problem of preventing any user
798 expert filter settings, is to set our own user settings, then
799 restore them afterwards.
801 resample_filter=AcquireResampleFilter(image,exception);
802 SetResampleFilter(resample_filter,GaussianFilter);
804 /* do the variable blurring of each pixel in image */
805 GetPixelInfo(image,&pixel);
806 composite_view=AcquireVirtualCacheView(composite_image,exception);
807 destination_view=AcquireAuthenticCacheView(destination_image,exception);
808 for (y=0; y < (ssize_t) composite_image->rows; y++)
813 register const Quantum
822 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
824 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
826 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
827 destination_image->columns,1,exception);
828 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
830 for (x=0; x < (ssize_t) composite_image->columns; x++)
832 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
834 p+=GetPixelChannels(composite_image);
837 if (fabs(angle_range) > MagickEpsilon)
842 angle=angle_start+angle_range*QuantumScale*
843 GetPixelBlue(composite_image,p);
844 blur.x1=width*cos(angle);
845 blur.x2=width*sin(angle);
846 blur.y1=(-height*sin(angle));
847 blur.y2=height*cos(angle);
850 if ( x == 10 && y == 60 ) {
851 (void) fprintf(stderr, "blur.x=%lf,%lf, blur.y=%lf,%lf\n",blur.x1,
852 blur.x2,blur.y1, blur.y2);
853 (void) fprintf(stderr, "scaled by=%lf,%lf\n",QuantumScale*
854 GetPixelRed(p),QuantumScale*GetPixelGreen(p));
856 ScaleResampleFilter(resample_filter,
857 blur.x1*QuantumScale*GetPixelRed(composite_image,p),
858 blur.y1*QuantumScale*GetPixelGreen(composite_image,p),
859 blur.x2*QuantumScale*GetPixelRed(composite_image,p),
860 blur.y2*QuantumScale*GetPixelGreen(composite_image,p) );
861 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
862 (double) y_offset+y,&pixel,exception);
863 SetPixelInfoPixel(destination_image,&pixel,q);
864 p+=GetPixelChannels(composite_image);
865 q+=GetPixelChannels(destination_image);
867 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
868 if (sync == MagickFalse)
871 resample_filter=DestroyResampleFilter(resample_filter);
872 composite_view=DestroyCacheView(composite_view);
873 destination_view=DestroyCacheView(destination_view);
874 composite_image=DestroyImage(composite_image);
875 composite_image=destination_image;
878 case DisplaceCompositeOp:
879 case DistortCompositeOp:
901 Displace/Distort based on overlay gradient map:
902 X = red_channel; Y = green_channel;
903 compose:args = x_scale[,y_scale[,center.x,center.y]]
905 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
907 if (destination_image == (Image *) NULL)
909 composite_image=DestroyImage(composite_image);
912 SetGeometryInfo(&geometry_info);
914 value=GetImageArtifact(composite_image,"compose:args");
915 if (value != (char *) NULL)
916 flags=ParseGeometry(value,&geometry_info);
917 if ((flags & (WidthValue|HeightValue)) == 0 )
919 if ((flags & AspectValue) == 0)
921 horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
923 vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
927 horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
928 vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
933 horizontal_scale=geometry_info.rho;
934 vertical_scale=geometry_info.sigma;
935 if ((flags & PercentValue) != 0)
937 if ((flags & AspectValue) == 0)
939 horizontal_scale*=(composite_image->columns-1.0)/200.0;
940 vertical_scale*=(composite_image->rows-1.0)/200.0;
944 horizontal_scale*=(image->columns-1.0)/200.0;
945 vertical_scale*=(image->rows-1.0)/200.0;
948 if ((flags & HeightValue) == 0)
949 vertical_scale=horizontal_scale;
952 Determine fixed center point for absolute distortion map
954 Displace offset relative to a fixed absolute point
955 Select that point according to +X+Y user inputs.
956 default = center of overlay image
957 arg flag '!' = locations/percentage relative to background image
959 center.x=(MagickRealType) x_offset;
960 center.y=(MagickRealType) y_offset;
961 if (compose == DistortCompositeOp)
963 if ((flags & XValue) == 0)
964 if ((flags & AspectValue) == 0)
965 center.x=(MagickRealType) (x_offset+(composite_image->columns-1)/
968 center.x=(MagickRealType) ((image->columns-1)/2);
970 if ((flags & AspectValue) == 0)
971 center.x=(MagickRealType) x_offset+geometry_info.xi;
973 center.x=geometry_info.xi;
974 if ((flags & YValue) == 0)
975 if ((flags & AspectValue) == 0)
976 center.y=(MagickRealType) (y_offset+(composite_image->rows-1)/
979 center.y=(MagickRealType) ((image->rows-1)/2);
981 if ((flags & AspectValue) == 0)
982 center.y=(MagickRealType) y_offset+geometry_info.psi;
984 center.y=geometry_info.psi;
987 Shift the pixel offset point as defined by the provided,
988 displacement/distortion map. -- Like a lens...
990 GetPixelInfo(image,&pixel);
991 image_view=AcquireVirtualCacheView(image,exception);
992 composite_view=AcquireVirtualCacheView(composite_image,exception);
993 destination_view=AcquireAuthenticCacheView(destination_image,exception);
994 for (y=0; y < (ssize_t) composite_image->rows; y++)
999 register const Quantum
1008 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1010 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
1012 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
1013 destination_image->columns,1,exception);
1014 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1016 for (x=0; x < (ssize_t) composite_image->columns; x++)
1018 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1020 p+=GetPixelChannels(composite_image);
1024 Displace the offset.
1026 offset.x=(double) (horizontal_scale*(GetPixelRed(composite_image,p)-
1027 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1028 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
1030 offset.y=(double) (vertical_scale*(GetPixelGreen(composite_image,p)-
1031 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1032 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
1034 (void) InterpolatePixelInfo(image,image_view,
1035 UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1038 Mask with the 'invalid pixel mask' in alpha channel.
1040 pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
1041 pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
1042 SetPixelInfoPixel(destination_image,&pixel,q);
1043 p+=GetPixelChannels(composite_image);
1044 q+=GetPixelChannels(destination_image);
1046 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1047 if (sync == MagickFalse)
1050 destination_view=DestroyCacheView(destination_view);
1051 composite_view=DestroyCacheView(composite_view);
1052 image_view=DestroyCacheView(image_view);
1053 composite_image=DestroyImage(composite_image);
1054 composite_image=destination_image;
1057 case DissolveCompositeOp:
1063 Geometry arguments to dissolve factors.
1065 value=GetImageArtifact(composite_image,"compose:args");
1066 if (value != (char *) NULL)
1068 flags=ParseGeometry(value,&geometry_info);
1069 source_dissolve=geometry_info.rho/100.0;
1070 destination_dissolve=1.0;
1071 if ((source_dissolve-MagickEpsilon) < 0.0)
1072 source_dissolve=0.0;
1073 if ((source_dissolve+MagickEpsilon) > 1.0)
1075 destination_dissolve=2.0-source_dissolve;
1076 source_dissolve=1.0;
1078 if ((flags & SigmaValue) != 0)
1079 destination_dissolve=geometry_info.sigma/100.0;
1080 if ((destination_dissolve-MagickEpsilon) < 0.0)
1081 destination_dissolve=0.0;
1082 /* posible speed up? -- from IMv6 update
1083 clip_to_self=MagickFalse;
1084 if ((destination_dissolve+MagickEpsilon) > 1.0 )
1086 destination_dissolve=1.0;
1087 clip_to_self=MagickTrue;
1093 case BlendCompositeOp:
1098 value=GetImageArtifact(composite_image,"compose:args");
1099 if (value != (char *) NULL)
1101 flags=ParseGeometry(value,&geometry_info);
1102 source_dissolve=geometry_info.rho/100.0;
1103 destination_dissolve=1.0-source_dissolve;
1104 if ((flags & SigmaValue) != 0)
1105 destination_dissolve=geometry_info.sigma/100.0;
1109 case MathematicsCompositeOp:
1115 Just collect the values from "compose:args", setting.
1116 Unused values are set to zero automagically.
1118 Arguments are normally a comma separated list, so this probably should
1119 be changed to some 'general comma list' parser, (with a minimum
1122 SetGeometryInfo(&geometry_info);
1123 value=GetImageArtifact(composite_image,"compose:args");
1124 if (value != (char *) NULL)
1125 (void) ParseGeometry(value,&geometry_info);
1128 case ModulateCompositeOp:
1134 Determine the luma and chroma scale.
1136 value=GetImageArtifact(composite_image,"compose:args");
1137 if (value != (char *) NULL)
1139 flags=ParseGeometry(value,&geometry_info);
1140 percent_luma=geometry_info.rho;
1141 if ((flags & SigmaValue) != 0)
1142 percent_chroma=geometry_info.sigma;
1146 case ThresholdCompositeOp:
1152 Determine the amount and threshold.
1154 value=GetImageArtifact(composite_image,"compose:args");
1155 if (value != (char *) NULL)
1157 flags=ParseGeometry(value,&geometry_info);
1158 amount=geometry_info.rho;
1159 threshold=geometry_info.sigma;
1160 if ((flags & SigmaValue) == 0)
1163 threshold*=QuantumRange;
1174 midpoint=((MagickRealType) QuantumRange+1.0)/2;
1175 composite_view=AcquireVirtualCacheView(composite_image,exception);
1176 image_view=AcquireAuthenticCacheView(image,exception);
1177 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1178 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1179 magick_threads(composite_image,image,image->rows,1)
1181 for (y=0; y < (ssize_t) image->rows; y++)
1198 register const Quantum
1207 if (status == MagickFalse)
1209 if (clip_to_self != MagickFalse)
1213 if ((y-y_offset) >= (ssize_t) composite_image->rows)
1217 If pixels is NULL, y is outside overlay region.
1219 pixels=(Quantum *) NULL;
1221 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
1223 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
1224 composite_image->columns,1,exception);
1225 if (p == (const Quantum *) NULL)
1232 p-=x_offset*GetPixelChannels(composite_image);
1234 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1235 if (q == (Quantum *) NULL)
1243 GetPixelInfo(image,&destination_pixel);
1244 GetPixelInfo(composite_image,&source_pixel);
1245 for (x=0; x < (ssize_t) image->columns; x++)
1265 if (clip_to_self != MagickFalse)
1269 q+=GetPixelChannels(image);
1272 if ((x-x_offset) >= (ssize_t) composite_image->columns)
1275 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1276 ((x-x_offset) >= (ssize_t) composite_image->columns))
1279 source[MaxPixelChannels];
1284 Dc: destination color.
1286 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
1288 if (GetPixelReadMask(image,q) == 0)
1290 q+=GetPixelChannels(image);
1293 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1298 PixelChannel channel=GetPixelChannelChannel(image,i);
1299 PixelTrait traits=GetPixelChannelTraits(image,channel);
1300 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
1302 if ((traits == UndefinedPixelTrait) ||
1303 (composite_traits == UndefinedPixelTrait))
1307 case AlphaCompositeOp:
1308 case ChangeMaskCompositeOp:
1309 case CopyAlphaCompositeOp:
1310 case DstAtopCompositeOp:
1311 case DstInCompositeOp:
1313 case IntensityCompositeOp:
1314 case OutCompositeOp:
1315 case SrcInCompositeOp:
1316 case SrcOutCompositeOp:
1318 pixel=(MagickRealType) q[i];
1319 if (channel == AlphaPixelChannel)
1320 pixel=(MagickRealType) TransparentAlpha;
1323 case ClearCompositeOp:
1324 case CopyCompositeOp:
1325 case ReplaceCompositeOp:
1326 case SrcCompositeOp:
1328 if (channel == AlphaPixelChannel)
1330 pixel=(MagickRealType) TransparentAlpha;
1336 case BlendCompositeOp:
1337 case DissolveCompositeOp:
1339 if (channel == AlphaPixelChannel)
1341 pixel=destination_dissolve*GetPixelAlpha(composite_image,
1345 pixel=(MagickRealType) source[channel];
1350 pixel=(MagickRealType) source[channel];
1354 q[i]=ClampToQuantum(pixel);
1356 q+=GetPixelChannels(image);
1360 Authentic composite:
1361 Sa: normalized source alpha.
1362 Da: normalized destination alpha.
1364 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
1365 Da=QuantumScale*GetPixelAlpha(image,q);
1368 case BumpmapCompositeOp:
1370 alpha=GetPixelIntensity(composite_image,p)*Sa;
1373 case ColorBurnCompositeOp:
1374 case ColorDodgeCompositeOp:
1375 case DifferenceCompositeOp:
1376 case DivideDstCompositeOp:
1377 case DivideSrcCompositeOp:
1378 case ExclusionCompositeOp:
1379 case HardLightCompositeOp:
1380 case LinearBurnCompositeOp:
1381 case LinearDodgeCompositeOp:
1382 case LinearLightCompositeOp:
1383 case MathematicsCompositeOp:
1384 case MinusDstCompositeOp:
1385 case MinusSrcCompositeOp:
1386 case ModulusAddCompositeOp:
1387 case ModulusSubtractCompositeOp:
1388 case MultiplyCompositeOp:
1389 case OverlayCompositeOp:
1390 case PegtopLightCompositeOp:
1391 case PinLightCompositeOp:
1392 case ScreenCompositeOp:
1393 case SoftLightCompositeOp:
1394 case VividLightCompositeOp:
1396 alpha=RoundToUnity(Sa+Da-Sa*Da);
1399 case DarkenCompositeOp:
1400 case DstAtopCompositeOp:
1401 case DstInCompositeOp:
1403 case LightenCompositeOp:
1404 case SrcInCompositeOp:
1409 case DissolveCompositeOp:
1411 alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
1412 Sa+destination_dissolve*Da;
1415 case DstOverCompositeOp:
1417 alpha=Da*(-Sa)+Da+Sa;
1420 case DstOutCompositeOp:
1425 case OutCompositeOp:
1426 case SrcOutCompositeOp:
1431 case OverCompositeOp:
1432 case SrcOverCompositeOp:
1434 alpha=Sa*(-Da)+Sa+Da;
1437 case BlendCompositeOp:
1438 case PlusCompositeOp:
1440 alpha=RoundToUnity(Sa+Da);
1443 case XorCompositeOp:
1445 alpha=Sa+Da-2.0*Sa*Da;
1454 if (GetPixelReadMask(image,q) == 0)
1456 p+=GetPixelChannels(composite_image);
1457 q+=GetPixelChannels(image);
1462 case ColorizeCompositeOp:
1463 case HueCompositeOp:
1464 case LuminizeCompositeOp:
1465 case ModulateCompositeOp:
1466 case SaturateCompositeOp:
1468 GetPixelInfoPixel(composite_image,p,&source_pixel);
1469 GetPixelInfoPixel(image,q,&destination_pixel);
1475 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1481 PixelChannel channel=GetPixelChannelChannel(image,i);
1482 PixelTrait traits=GetPixelChannelTraits(image,channel);
1483 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
1485 if (traits == UndefinedPixelTrait)
1487 if ((compose != IntensityCompositeOp) &&
1488 (composite_traits == UndefinedPixelTrait))
1492 Dc: destination color.
1494 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
1495 Dc=(MagickRealType) q[i];
1496 if ((traits & CopyPixelTrait) != 0)
1498 if (channel != AlphaPixelChannel)
1503 q[i]=ClampToQuantum(Sc);
1511 case AlphaCompositeOp:
1513 pixel=QuantumRange*Sa;
1516 case AtopCompositeOp:
1517 case CopyBlackCompositeOp:
1518 case CopyBlueCompositeOp:
1519 case CopyCyanCompositeOp:
1520 case CopyGreenCompositeOp:
1521 case CopyMagentaCompositeOp:
1522 case CopyRedCompositeOp:
1523 case CopyYellowCompositeOp:
1524 case SrcAtopCompositeOp:
1525 case DstCompositeOp:
1528 pixel=QuantumRange*Da;
1531 case ChangeMaskCompositeOp:
1536 if (Da > ((MagickRealType) QuantumRange/2.0))
1538 pixel=(MagickRealType) TransparentAlpha;
1541 equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
1542 if (equivalent != MagickFalse)
1544 pixel=(MagickRealType) TransparentAlpha;
1547 pixel=(MagickRealType) OpaqueAlpha;
1550 case ClearCompositeOp:
1552 pixel=(MagickRealType) TransparentAlpha;
1555 case ColorizeCompositeOp:
1556 case HueCompositeOp:
1557 case LuminizeCompositeOp:
1558 case SaturateCompositeOp:
1560 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1562 pixel=QuantumRange*Da;
1565 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1567 pixel=QuantumRange*Sa;
1572 pixel=QuantumRange*Da;
1575 pixel=QuantumRange*Sa;
1578 case CopyAlphaCompositeOp:
1580 pixel=QuantumRange*Sa;
1581 if (composite_image->alpha_trait == BlendPixelTrait)
1582 pixel=GetPixelIntensity(composite_image,p);
1585 case CopyCompositeOp:
1586 case DisplaceCompositeOp:
1587 case DistortCompositeOp:
1588 case DstAtopCompositeOp:
1589 case ReplaceCompositeOp:
1590 case SrcCompositeOp:
1592 pixel=QuantumRange*Sa;
1595 case DarkenIntensityCompositeOp:
1597 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1598 (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
1601 case IntensityCompositeOp:
1603 pixel=GetPixelIntensity(composite_image,p);
1606 case LightenIntensityCompositeOp:
1608 pixel=Sa*GetPixelIntensity(composite_image,p) >
1609 Da*GetPixelIntensity(image,q) ? Sa : Da;
1612 case ModulateCompositeOp:
1614 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1616 pixel=QuantumRange*Da;
1619 pixel=QuantumRange*Da;
1624 pixel=QuantumRange*alpha;
1628 q[i]=ClampToQuantum(pixel);
1632 Porter-Duff compositions:
1633 Sca: source normalized color multiplied by alpha.
1634 Dca: normalized destination color multiplied by alpha.
1636 Sca=QuantumScale*Sa*Sc;
1637 Dca=QuantumScale*Da*Dc;
1640 case DarkenCompositeOp:
1641 case LightenCompositeOp:
1642 case ModulusSubtractCompositeOp:
1650 gamma=PerceptibleReciprocal(alpha);
1654 case AlphaCompositeOp:
1656 pixel=QuantumRange*Sa;
1659 case AtopCompositeOp:
1660 case SrcAtopCompositeOp:
1662 pixel=Sc*Sa+Dc*(1.0-Sa);
1665 case BlendCompositeOp:
1667 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1670 case BlurCompositeOp:
1671 case DisplaceCompositeOp:
1672 case DistortCompositeOp:
1673 case CopyCompositeOp:
1674 case ReplaceCompositeOp:
1675 case SrcCompositeOp:
1680 case BumpmapCompositeOp:
1682 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1687 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1690 case ChangeMaskCompositeOp:
1695 case ClearCompositeOp:
1700 case ColorBurnCompositeOp:
1703 Refer to the March 2009 SVG specification.
1705 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1707 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1710 if (Sca < MagickEpsilon)
1712 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1715 pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
1716 Sca*(1.0-Da)+Dca*(1.0-Sa));
1719 case ColorDodgeCompositeOp:
1721 if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1723 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1726 if (fabs(Sca-Sa) < MagickEpsilon)
1728 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1731 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1735 case ColorizeCompositeOp:
1737 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1742 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1747 CompositeHCL(destination_pixel.red,destination_pixel.green,
1748 destination_pixel.blue,&sans,&sans,&luma);
1749 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1750 &hue,&chroma,&sans);
1751 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1754 case RedPixelChannel: pixel=red; break;
1755 case GreenPixelChannel: pixel=green; break;
1756 case BluePixelChannel: pixel=blue; break;
1757 default: pixel=Dc; break;
1761 case CopyAlphaCompositeOp:
1762 case IntensityCompositeOp:
1767 case CopyBlackCompositeOp:
1769 if (channel == BlackPixelChannel)
1770 pixel=(MagickRealType) GetPixelBlack(composite_image,p);
1773 case CopyBlueCompositeOp:
1774 case CopyYellowCompositeOp:
1776 if (channel == BluePixelChannel)
1777 pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1780 case CopyGreenCompositeOp:
1781 case CopyMagentaCompositeOp:
1783 if (channel == GreenPixelChannel)
1784 pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1787 case CopyRedCompositeOp:
1788 case CopyCyanCompositeOp:
1790 if (channel == RedPixelChannel)
1791 pixel=(MagickRealType) GetPixelRed(composite_image,p);
1794 case DarkenCompositeOp:
1797 Darken is equivalent to a 'Minimum' method
1798 OR a greyscale version of a binary 'Or'
1799 OR the 'Intersection' of pixel sets.
1803 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1806 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1809 case DarkenIntensityCompositeOp:
1811 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1812 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1815 case DifferenceCompositeOp:
1817 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1820 case DissolveCompositeOp:
1822 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1823 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1826 case DivideDstCompositeOp:
1828 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1830 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1833 if (fabs(Dca) < MagickEpsilon)
1835 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1838 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1841 case DivideSrcCompositeOp:
1843 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1845 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1848 if (fabs(Sca) < MagickEpsilon)
1850 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1853 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1856 case DstAtopCompositeOp:
1858 pixel=Dc*Da+Sc*(1.0-Da);
1861 case DstCompositeOp:
1867 case DstInCompositeOp:
1869 pixel=gamma*(Sa*Dc*Sa);
1872 case DstOutCompositeOp:
1874 pixel=gamma*(Da*Dc*(1.0-Sa));
1877 case DstOverCompositeOp:
1879 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1882 case ExclusionCompositeOp:
1884 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1888 case HardLightCompositeOp:
1892 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1896 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1900 case HueCompositeOp:
1902 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1907 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1912 CompositeHCL(destination_pixel.red,destination_pixel.green,
1913 destination_pixel.blue,&hue,&chroma,&luma);
1914 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1916 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1919 case RedPixelChannel: pixel=red; break;
1920 case GreenPixelChannel: pixel=green; break;
1921 case BluePixelChannel: pixel=blue; break;
1922 default: pixel=Dc; break;
1927 case SrcInCompositeOp:
1929 pixel=gamma*(Da*Sc*Da);
1932 case LinearBurnCompositeOp:
1935 LinearBurn: as defined by Abode Photoshop, according to
1936 http://www.simplefilter.de/en/basics/mixmods.html is:
1938 f(Sc,Dc) = Sc + Dc - 1
1940 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1943 case LinearDodgeCompositeOp:
1945 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1948 case LinearLightCompositeOp:
1951 LinearLight: as defined by Abode Photoshop, according to
1952 http://www.simplefilter.de/en/basics/mixmods.html is:
1954 f(Sc,Dc) = Dc + 2*Sc - 1
1956 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1959 case LightenCompositeOp:
1963 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1966 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1969 case LightenIntensityCompositeOp:
1972 Lighten is equivalent to a 'Maximum' method
1973 OR a greyscale version of a binary 'And'
1974 OR the 'Union' of pixel sets.
1976 pixel=Sa*GetPixelIntensity(composite_image,p) >
1977 Da*GetPixelIntensity(image,q) ? Sc : Dc;
1980 case LuminizeCompositeOp:
1982 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1987 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1992 CompositeHCL(destination_pixel.red,destination_pixel.green,
1993 destination_pixel.blue,&hue,&chroma,&luma);
1994 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1996 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1999 case RedPixelChannel: pixel=red; break;
2000 case GreenPixelChannel: pixel=green; break;
2001 case BluePixelChannel: pixel=blue; break;
2002 default: pixel=Dc; break;
2006 case MathematicsCompositeOp:
2009 'Mathematics' a free form user control mathematical composition
2012 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
2014 Where the arguments A,B,C,D are (currently) passed to composite
2015 as a command separated 'geometry' string in "compose:args" image
2018 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
2020 Applying the SVG transparency formula (see above), we get...
2022 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
2024 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
2027 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
2028 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
2029 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
2032 case MinusDstCompositeOp:
2034 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2037 case MinusSrcCompositeOp:
2040 Minus source from destination.
2044 pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2047 case ModulateCompositeOp:
2052 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2057 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
2063 CompositeHCL(destination_pixel.red,destination_pixel.green,
2064 destination_pixel.blue,&hue,&chroma,&luma);
2065 luma+=(0.01*percent_luma*offset)/midpoint;
2066 chroma*=0.01*percent_chroma;
2067 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2070 case RedPixelChannel: pixel=red; break;
2071 case GreenPixelChannel: pixel=green; break;
2072 case BluePixelChannel: pixel=blue; break;
2073 default: pixel=Dc; break;
2077 case ModulusAddCompositeOp:
2080 if (pixel > QuantumRange)
2081 pixel-=(QuantumRange+1.0);
2082 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2085 case ModulusSubtractCompositeOp:
2089 pixel+=(QuantumRange+1.0);
2090 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2093 case MultiplyCompositeOp:
2095 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2098 case OutCompositeOp:
2099 case SrcOutCompositeOp:
2101 pixel=gamma*(Sa*Sc*(1.0-Da));
2104 case OverCompositeOp:
2105 case SrcOverCompositeOp:
2107 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2110 case OverlayCompositeOp:
2114 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2118 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2122 case PegtopLightCompositeOp:
2125 PegTop: A Soft-Light alternative: A continuous version of the
2126 Softlight function, producing very similar results.
2128 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2130 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2132 if (fabs(Da) < MagickEpsilon)
2134 pixel=QuantumRange*gamma*(Sca);
2137 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2141 case PinLightCompositeOp:
2144 PinLight: A Photoshop 7 composition method
2145 http://www.simplefilter.de/en/basics/mixmods.html
2147 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2149 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2151 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2154 if ((Dca*Sa) > (2.0*Sca*Da))
2156 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2159 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2162 case PlusCompositeOp:
2164 pixel=gamma*(Sa*Sc+Da*Dc);
2167 case SaturateCompositeOp:
2169 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2174 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2179 CompositeHCL(destination_pixel.red,destination_pixel.green,
2180 destination_pixel.blue,&hue,&chroma,&luma);
2181 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2182 &sans,&chroma,&sans);
2183 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2186 case RedPixelChannel: pixel=red; break;
2187 case GreenPixelChannel: pixel=green; break;
2188 case BluePixelChannel: pixel=blue; break;
2189 default: pixel=Dc; break;
2193 case ScreenCompositeOp:
2196 Screen: a negated multiply:
2198 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2200 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2203 case SoftLightCompositeOp:
2206 Refer to the March 2009 SVG specification.
2210 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2211 Sca*(1.0-Da)+Dca*(1.0-Sa));
2214 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2216 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2217 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2221 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2222 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2225 case ThresholdCompositeOp:
2231 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2236 pixel=gamma*(Dc+delta*amount);
2239 case VividLightCompositeOp:
2242 VividLight: A Photoshop 7 composition method. See
2243 http://www.simplefilter.de/en/basics/mixmods.html.
2245 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2247 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2249 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2252 if ((2.0*Sca) <= Sa)
2254 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2255 (1.0-Da)+Dca*(1.0-Sa));
2258 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2262 case XorCompositeOp:
2264 pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2273 q[i]=ClampToQuantum(pixel);
2275 p+=GetPixelChannels(composite_image);
2276 channels=GetPixelChannels(composite_image);
2277 if (p >= (pixels+channels*composite_image->columns))
2279 q+=GetPixelChannels(image);
2281 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2283 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2288 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2289 #pragma omp critical (MagickCore_CompositeImage)
2291 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2293 if (proceed == MagickFalse)
2297 composite_view=DestroyCacheView(composite_view);
2298 image_view=DestroyCacheView(image_view);
2299 if (destination_image != (Image * ) NULL)
2300 destination_image=DestroyImage(destination_image);
2302 composite_image=DestroyImage(composite_image);
2307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2311 % T e x t u r e I m a g e %
2315 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2317 % TextureImage() repeatedly tiles the texture image across and down the image
2320 % The format of the TextureImage method is:
2322 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2323 % ExceptionInfo *exception)
2325 % A description of each parameter follows:
2327 % o image: the image.
2329 % o texture_image: This image is the texture to layer on the background.
2332 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
2333 ExceptionInfo *exception)
2335 #define TextureImageTag "Texture/Image"
2350 assert(image != (Image *) NULL);
2351 if (image->debug != MagickFalse)
2352 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2353 assert(image->signature == MagickSignature);
2354 if (texture == (const Image *) NULL)
2355 return(MagickFalse);
2356 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2357 return(MagickFalse);
2358 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2359 if (texture_image == (const Image *) NULL)
2360 return(MagickFalse);
2361 (void) TransformImageColorspace(texture_image,image->colorspace,exception);
2362 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
2365 if ((image->compose != CopyCompositeOp) &&
2366 ((image->compose != OverCompositeOp) || (image->alpha_trait == BlendPixelTrait) ||
2367 (texture_image->alpha_trait == BlendPixelTrait)))
2370 Tile texture onto the image background.
2372 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2377 if (status == MagickFalse)
2379 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2384 thread_status=CompositeImage(image,texture_image,image->compose,
2385 MagickFalse,x+texture_image->tile_offset.x,y+
2386 texture_image->tile_offset.y,exception);
2387 if (thread_status == MagickFalse)
2389 status=thread_status;
2393 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2398 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2400 if (proceed == MagickFalse)
2404 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2405 image->rows,image->rows);
2406 texture_image=DestroyImage(texture_image);
2410 Tile texture onto the image background (optimized).
2413 texture_view=AcquireVirtualCacheView(texture_image,exception);
2414 image_view=AcquireAuthenticCacheView(image,exception);
2415 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2416 #pragma omp parallel for schedule(static,4) shared(status) \
2417 magick_threads(texture_image,image,1,1)
2419 for (y=0; y < (ssize_t) image->rows; y++)
2424 register const Quantum
2437 if (status == MagickFalse)
2439 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2440 (y+texture_image->tile_offset.y) % texture_image->rows,
2441 texture_image->columns,1,exception);
2442 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2443 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2448 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2454 width=texture_image->columns;
2455 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2456 width=image->columns-x;
2457 for (j=0; j < (ssize_t) width; j++)
2462 if (GetPixelReadMask(image,q) == 0)
2464 p+=GetPixelChannels(texture_image);
2465 q+=GetPixelChannels(image);
2468 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2470 PixelChannel channel=GetPixelChannelChannel(texture_image,i);
2471 PixelTrait traits=GetPixelChannelTraits(image,channel);
2472 PixelTrait texture_traits=GetPixelChannelTraits(texture_image,
2474 if ((traits == UndefinedPixelTrait) ||
2475 (texture_traits == UndefinedPixelTrait))
2477 SetPixelChannel(image,channel,p[i],q);
2479 p+=GetPixelChannels(texture_image);
2480 q+=GetPixelChannels(image);
2483 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2484 if (sync == MagickFalse)
2486 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2491 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2493 if (proceed == MagickFalse)
2497 texture_view=DestroyCacheView(texture_view);
2498 image_view=DestroyCacheView(image_view);
2499 texture_image=DestroyImage(texture_image);