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-2012 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 double MagickMin(const double x,const double y)
187 static inline double MagickMax(const double x,const double y)
194 static inline double ConvertHueToRGB(double m1,
195 double m2,double hue)
202 return(m1+6.0*(m2-m1)*hue);
206 return(m1+6.0*(m2-m1)*(2.0/3.0-hue));
210 static void HSLComposite(const double hue,const double saturation,
211 const double lightness,double *red,double *green,double *blue)
221 Convert HSL to RGB colorspace.
223 assert(red != (double *) NULL);
224 assert(green != (double *) NULL);
225 assert(blue != (double *) NULL);
228 *red=(double) QuantumRange*lightness;
234 m2=lightness*(saturation+1.0);
236 m2=(lightness+saturation)-(lightness*saturation);
238 r=ConvertHueToRGB(m1,m2,hue+1.0/3.0);
239 g=ConvertHueToRGB(m1,m2,hue);
240 b=ConvertHueToRGB(m1,m2,hue-1.0/3.0);
241 *red=(double) QuantumRange*r;
242 *green=(double) QuantumRange*g;
243 *blue=(double) QuantumRange*b;
246 static void CompositeHSL(const double red,const double green,const double blue,
247 double *hue,double *saturation,double *lightness)
258 Convert RGB to HSL colorspace.
260 assert(hue != (double *) NULL);
261 assert(saturation != (double *) NULL);
262 assert(lightness != (double *) NULL);
264 g=QuantumScale*green;
266 max=MagickMax(r,MagickMax(g,b));
267 min=MagickMin(r,MagickMin(g,b));
268 *lightness=(double) ((min+max)/2.0);
276 if (*lightness < 0.5)
277 *saturation=(double) (delta/(min+max));
279 *saturation=(double) (delta/(2.0-max-min));
281 *hue=((((max-b)/6.0)+(delta/2.0))-(((max-g)/6.0)+(delta/2.0)))/delta;
284 *hue=(1.0/3.0)+((((max-r)/6.0)+(delta/2.0))-(((max-b)/6.0)+(delta/2.0)))/
288 *hue=(2.0/3.0)+((((max-g)/6.0)+(delta/2.0))-(((max-r)/6.0)+
296 static MagickBooleanType CompositeOverImage(Image *image,
297 const Image *composite_image,const MagickBooleanType clip_to_self,
298 const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
300 #define CompositeImageTag "Composite/Image"
320 composite_view=AcquireVirtualCacheView(composite_image,exception);
321 image_view=AcquireAuthenticCacheView(image,exception);
322 #if defined(MAGICKCORE_OPENMP_SUPPORT)
323 #pragma omp parallel for schedule(static,4) shared(progress,status) \
324 dynamic_number_threads(image,image->columns,image->rows,1)
326 for (y=0; y < (ssize_t) image->rows; y++)
331 register const Quantum
343 if (status == MagickFalse)
345 if (clip_to_self != MagickFalse)
349 if ((y-y_offset) >= (ssize_t) composite_image->rows)
353 If pixels is NULL, y is outside overlay region.
355 pixels=(Quantum *) NULL;
357 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
359 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
360 composite_image->columns,1,exception);
361 if (p == (const Quantum *) NULL)
368 p-=x_offset*GetPixelChannels(composite_image);
370 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
371 if (q == (Quantum *) NULL)
376 for (x=0; x < (ssize_t) image->columns; x++)
389 if (clip_to_self != MagickFalse)
393 q+=GetPixelChannels(image);
396 if ((x-x_offset) >= (ssize_t) composite_image->columns)
399 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
400 ((x-x_offset) >= (ssize_t) composite_image->columns))
403 source[MaxPixelChannels];
408 Dc: destination color.
410 if (GetPixelMask(image,q) != 0)
412 q+=GetPixelChannels(image);
415 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
417 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
426 channel=GetPixelChannelMapChannel(image,i);
427 traits=GetPixelChannelMapTraits(image,channel);
428 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
429 if ((traits == UndefinedPixelTrait) ||
430 (composite_traits == UndefinedPixelTrait))
432 q[i]=source[channel];
434 q+=GetPixelChannels(image);
439 Sa: normalized source alpha.
440 Da: normalized destination alpha.
442 if (GetPixelMask(composite_image,p) != 0)
444 p+=GetPixelChannels(composite_image);
445 channels=GetPixelChannels(composite_image);
446 if (p >= (pixels+channels*composite_image->columns))
448 q+=GetPixelChannels(image);
451 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
452 Da=QuantumScale*GetPixelAlpha(image,q);
453 alpha=Sa*(-Da)+Sa+Da;
454 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
463 channel=GetPixelChannelMapChannel(image,i);
464 traits=GetPixelChannelMapTraits(image,channel);
465 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
466 if ((traits == UndefinedPixelTrait) ||
467 (composite_traits == UndefinedPixelTrait))
469 if ((traits & CopyPixelTrait) != 0)
471 if (channel != AlphaPixelChannel)
476 q[i]=GetPixelChannel(composite_image,channel,p);
482 q[i]=ClampToQuantum(QuantumRange*alpha);
487 Dc: destination color.
489 Sc=(double) GetPixelChannel(composite_image,channel,p);
491 gamma=MagickEpsilonReciprocal(alpha);
492 q[i]=ClampToQuantum(gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc));
494 p+=GetPixelChannels(composite_image);
495 channels=GetPixelChannels(composite_image);
496 if (p >= (pixels+channels*composite_image->columns))
498 q+=GetPixelChannels(image);
500 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
502 if (image->progress_monitor != (MagickProgressMonitor) NULL)
507 #if defined(MAGICKCORE_OPENMP_SUPPORT)
508 #pragma omp critical (MagickCore_CompositeImage)
510 proceed=SetImageProgress(image,CompositeImageTag,progress++,
512 if (proceed == MagickFalse)
516 composite_view=DestroyCacheView(composite_view);
517 image_view=DestroyCacheView(image_view);
521 MagickExport MagickBooleanType CompositeImage(Image *image,
522 const Image *composite,const CompositeOperator compose,
523 const MagickBooleanType clip_to_self,const ssize_t x_offset,
524 const ssize_t y_offset,ExceptionInfo *exception)
526 #define CompositeImageTag "Composite/Image"
547 destination_dissolve,
560 assert(image != (Image *) NULL);
561 assert(image->signature == MagickSignature);
562 if (image->debug != MagickFalse)
563 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
564 assert(composite!= (Image *) NULL);
565 assert(composite->signature == MagickSignature);
566 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
568 composite_image=CloneImage(composite,0,0,MagickTrue,exception);
569 if (composite_image == (const Image *) NULL)
571 (void) SetImageColorspace(composite_image,image->colorspace,exception);
572 if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
574 status=CompositeOverImage(image,composite_image,clip_to_self,x_offset,
576 composite_image=DestroyImage(composite_image);
579 destination_image=(Image *) NULL;
581 destination_dissolve=1.0;
582 percent_brightness=100.0;
583 percent_saturation=100.0;
588 case CopyCompositeOp:
590 if ((x_offset < 0) || (y_offset < 0))
592 if ((x_offset+(ssize_t) composite_image->columns) >= (ssize_t) image->columns)
594 if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
597 composite_view=AcquireVirtualCacheView(composite_image,exception);
598 image_view=AcquireAuthenticCacheView(image,exception);
599 #if defined(MAGICKCORE_OPENMP_SUPPORT)
600 #pragma omp parallel for schedule(static,4) shared(status) \
601 dynamic_number_threads(image,image->columns,image->rows,1)
603 for (y=0; y < (ssize_t) composite_image->rows; y++)
608 register const Quantum
617 if (status == MagickFalse)
619 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
621 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
622 composite_image->columns,1,exception);
623 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
628 for (x=0; x < (ssize_t) composite_image->columns; x++)
633 if (GetPixelMask(composite_image,p) != 0)
635 p+=GetPixelChannels(composite_image);
636 q+=GetPixelChannels(image);
639 for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
648 channel=GetPixelChannelMapChannel(composite_image,i);
649 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
650 traits=GetPixelChannelMapTraits(image,channel);
651 if ((traits == UndefinedPixelTrait) ||
652 (composite_traits == UndefinedPixelTrait))
654 SetPixelChannel(image,channel,p[i],q);
656 p+=GetPixelChannels(composite_image);
657 q+=GetPixelChannels(image);
659 sync=SyncCacheViewAuthenticPixels(image_view,exception);
660 if (sync == MagickFalse)
662 if (image->progress_monitor != (MagickProgressMonitor) NULL)
667 #if defined(MAGICKCORE_OPENMP_SUPPORT)
668 #pragma omp critical (MagickCore_CompositeImage)
670 proceed=SetImageProgress(image,CompositeImageTag,
671 (MagickOffsetType) y,image->rows);
672 if (proceed == MagickFalse)
676 composite_view=DestroyCacheView(composite_view);
677 image_view=DestroyCacheView(image_view);
678 composite_image=DestroyImage(composite_image);
681 case CopyAlphaCompositeOp:
682 case ChangeMaskCompositeOp:
683 case IntensityCompositeOp:
686 Modify destination outside the overlaid region and require an alpha
687 channel to exist, to add transparency.
689 if (image->matte == MagickFalse)
690 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
693 case BlurCompositeOp:
718 Blur Image by resampling.
720 Blur Image dictated by an overlay gradient map: X = red_channel;
721 Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
723 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
725 if (destination_image == (Image *) NULL)
727 composite_image=DestroyImage(composite_image);
731 Gather the maximum blur sigma values from user.
733 SetGeometryInfo(&geometry_info);
735 value=GetImageArtifact(composite_image,"compose:args");
736 if (value != (char *) NULL)
737 flags=ParseGeometry(value,&geometry_info);
738 if ((flags & WidthValue) == 0 ) {
739 (void) ThrowMagickException(exception,GetMagickModule(),
740 OptionWarning,"InvalidSetting","'%s' '%s'",
741 "compose:args",value);
742 composite_image=DestroyImage(composite_image);
743 destination_image=DestroyImage(destination_image);
747 Users input sigma now needs to be converted to the EWA ellipse size.
748 The filter defaults to a sigma of 0.5 so to make this match the
749 users input the ellipse size needs to be doubled.
751 width=height=geometry_info.rho*2.0;
752 if ((flags & HeightValue) != 0 )
753 height=geometry_info.sigma*2.0;
755 /* default the unrotated ellipse width and height axis vectors */
760 /* rotate vectors if a rotation angle is given */
761 if ((flags & XValue) != 0 )
766 angle=DegreesToRadians(geometry_info.xi);
767 blur.x1=width*cos(angle);
768 blur.x2=width*sin(angle);
769 blur.y1=(-height*sin(angle));
770 blur.y2=height*cos(angle);
772 /* Otherwise lets set a angle range and calculate in the loop */
775 if ((flags & YValue) != 0 )
777 angle_start=DegreesToRadians(geometry_info.xi);
778 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
781 Set up a gaussian cylindrical filter for EWA Bluring.
783 As the minimum ellipse radius of support*1.0 the EWA algorithm
784 can only produce a minimum blur of 0.5 for Gaussian (support=2.0)
785 This means that even 'No Blur' will be still a little blurry!
787 The solution (as well as the problem of preventing any user
788 expert filter settings, is to set our own user settings, then
789 restore them afterwards.
791 resample_filter=AcquireResampleFilter(image,exception);
792 SetResampleFilter(resample_filter,GaussianFilter);
794 /* do the variable blurring of each pixel in image */
795 GetPixelInfo(image,&pixel);
796 composite_view=AcquireVirtualCacheView(composite_image,exception);
797 destination_view=AcquireAuthenticCacheView(destination_image,exception);
798 for (y=0; y < (ssize_t) composite_image->rows; y++)
803 register const Quantum
812 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
814 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
816 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
817 destination_image->columns,1,exception);
818 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
820 for (x=0; x < (ssize_t) composite_image->columns; x++)
822 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
824 p+=GetPixelChannels(composite_image);
827 if (fabs(angle_range) > MagickEpsilon)
832 angle=angle_start+angle_range*QuantumScale*
833 GetPixelBlue(composite_image,p);
834 blur.x1=width*cos(angle);
835 blur.x2=width*sin(angle);
836 blur.y1=(-height*sin(angle));
837 blur.y2=height*cos(angle);
840 if ( x == 10 && y == 60 ) {
841 fprintf(stderr, "blur.x=%lf,%lf, blur.y=%lf,%lf\n",
842 blur.x1, blur.x2, blur.y1, blur.y2);
843 fprintf(stderr, "scaled by=%lf,%lf\n",
844 QuantumScale*GetPixelRed(p), QuantumScale*GetPixelGreen(p));
846 ScaleResampleFilter(resample_filter,
847 blur.x1*QuantumScale*GetPixelRed(composite_image,p),
848 blur.y1*QuantumScale*GetPixelGreen(composite_image,p),
849 blur.x2*QuantumScale*GetPixelRed(composite_image,p),
850 blur.y2*QuantumScale*GetPixelGreen(composite_image,p) );
851 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
852 (double) y_offset+y,&pixel,exception);
853 SetPixelInfoPixel(destination_image,&pixel,q);
854 p+=GetPixelChannels(composite_image);
855 q+=GetPixelChannels(destination_image);
857 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
858 if (sync == MagickFalse)
861 resample_filter=DestroyResampleFilter(resample_filter);
862 composite_view=DestroyCacheView(composite_view);
863 destination_view=DestroyCacheView(destination_view);
864 composite_image=DestroyImage(composite_image);
865 composite_image=destination_image;
868 case DisplaceCompositeOp:
869 case DistortCompositeOp:
891 Displace/Distort based on overlay gradient map:
892 X = red_channel; Y = green_channel;
893 compose:args = x_scale[,y_scale[,center.x,center.y]]
895 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
897 if (destination_image == (Image *) NULL)
899 composite_image=DestroyImage(composite_image);
902 SetGeometryInfo(&geometry_info);
904 value=GetImageArtifact(composite_image,"compose:args");
905 if (value != (char *) NULL)
906 flags=ParseGeometry(value,&geometry_info);
907 if ((flags & (WidthValue|HeightValue)) == 0 )
909 if ((flags & AspectValue) == 0)
911 horizontal_scale=(double) (composite_image->columns-1.0)/
913 vertical_scale=(double) (composite_image->rows-1.0)/2.0;
917 horizontal_scale=(double) (image->columns-1.0)/2.0;
918 vertical_scale=(double) (image->rows-1.0)/2.0;
923 horizontal_scale=geometry_info.rho;
924 vertical_scale=geometry_info.sigma;
925 if ((flags & PercentValue) != 0)
927 if ((flags & AspectValue) == 0)
929 horizontal_scale*=(composite_image->columns-1.0)/200.0;
930 vertical_scale*=(composite_image->rows-1.0)/200.0;
934 horizontal_scale*=(image->columns-1.0)/200.0;
935 vertical_scale*=(image->rows-1.0)/200.0;
938 if ((flags & HeightValue) == 0)
939 vertical_scale=horizontal_scale;
942 Determine fixed center point for absolute distortion map
944 Displace offset relative to a fixed absolute point
945 Select that point according to +X+Y user inputs.
946 default = center of overlay image
947 arg flag '!' = locations/percentage relative to background image
949 center.x=(double) x_offset;
950 center.y=(double) y_offset;
951 if (compose == DistortCompositeOp)
953 if ((flags & XValue) == 0)
954 if ((flags & AspectValue) == 0)
955 center.x=(double) x_offset+(composite_image->columns-1)/
958 center.x=((double) image->columns-1)/2.0;
960 if ((flags & AspectValue) == 0)
961 center.x=(double) x_offset+geometry_info.xi;
963 center.x=geometry_info.xi;
964 if ((flags & YValue) == 0)
965 if ((flags & AspectValue) == 0)
966 center.y=(double) y_offset+(composite_image->rows-1)/2.0;
968 center.y=((double) image->rows-1)/2.0;
970 if ((flags & AspectValue) == 0)
971 center.y=(double) y_offset+geometry_info.psi;
973 center.y=geometry_info.psi;
976 Shift the pixel offset point as defined by the provided,
977 displacement/distortion map. -- Like a lens...
979 GetPixelInfo(image,&pixel);
980 image_view=AcquireVirtualCacheView(image,exception);
981 composite_view=AcquireVirtualCacheView(composite_image,exception);
982 destination_view=AcquireAuthenticCacheView(destination_image,exception);
983 for (y=0; y < (ssize_t) composite_image->rows; y++)
988 register const Quantum
997 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
999 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
1001 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
1002 destination_image->columns,1,exception);
1003 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1005 for (x=0; x < (ssize_t) composite_image->columns; x++)
1007 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1009 p+=GetPixelChannels(composite_image);
1013 Displace the offset.
1015 offset.x=(horizontal_scale*(GetPixelRed(composite_image,p)-
1016 (((double) QuantumRange+1.0)/2.0)))/(((double)
1017 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
1019 offset.y=(vertical_scale*(GetPixelGreen(composite_image,p)-
1020 (((double) QuantumRange+1.0)/2.0)))/(((double)
1021 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
1023 (void) InterpolatePixelInfo(image,image_view,
1024 UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1027 Mask with the 'invalid pixel mask' in alpha channel.
1029 pixel.alpha=(double) QuantumRange*(1.0-(1.0-QuantumScale*
1030 pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
1031 SetPixelInfoPixel(destination_image,&pixel,q);
1032 p+=GetPixelChannels(composite_image);
1033 q+=GetPixelChannels(destination_image);
1035 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1036 if (sync == MagickFalse)
1039 destination_view=DestroyCacheView(destination_view);
1040 composite_view=DestroyCacheView(composite_view);
1041 image_view=DestroyCacheView(image_view);
1042 composite_image=DestroyImage(composite_image);
1043 composite_image=destination_image;
1046 case DissolveCompositeOp:
1052 Geometry arguments to dissolve factors.
1054 value=GetImageArtifact(composite_image,"compose:args");
1055 if (value != (char *) NULL)
1057 flags=ParseGeometry(value,&geometry_info);
1058 source_dissolve=geometry_info.rho/100.0;
1059 destination_dissolve=1.0;
1060 if ((source_dissolve-MagickEpsilon) < 0.0)
1061 source_dissolve=0.0;
1062 if ((source_dissolve+MagickEpsilon) > 1.0)
1064 destination_dissolve=2.0-source_dissolve;
1065 source_dissolve=1.0;
1067 if ((flags & SigmaValue) != 0)
1068 destination_dissolve=geometry_info.sigma/100.0;
1069 if ((destination_dissolve-MagickEpsilon) < 0.0)
1070 destination_dissolve=0.0;
1071 /* posible speed up? -- from IMv6 update
1072 clip_to_self=MagickFalse;
1073 if ((destination_dissolve+MagickEpsilon) > 1.0 )
1075 destination_dissolve=1.0;
1076 clip_to_self=MagickTrue;
1082 case BlendCompositeOp:
1087 value=GetImageArtifact(composite_image,"compose:args");
1088 if (value != (char *) NULL)
1090 flags=ParseGeometry(value,&geometry_info);
1091 source_dissolve=geometry_info.rho/100.0;
1092 destination_dissolve=1.0-source_dissolve;
1093 if ((flags & SigmaValue) != 0)
1094 destination_dissolve=geometry_info.sigma/100.0;
1098 case MathematicsCompositeOp:
1104 Just collect the values from "compose:args", setting.
1105 Unused values are set to zero automagically.
1107 Arguments are normally a comma separated list, so this probably should
1108 be changed to some 'general comma list' parser, (with a minimum
1111 SetGeometryInfo(&geometry_info);
1112 value=GetImageArtifact(composite_image,"compose:args");
1113 if (value != (char *) NULL)
1114 (void) ParseGeometry(value,&geometry_info);
1117 case ModulateCompositeOp:
1123 Determine the brightness and saturation scale.
1125 value=GetImageArtifact(composite_image,"compose:args");
1126 if (value != (char *) NULL)
1128 flags=ParseGeometry(value,&geometry_info);
1129 percent_brightness=geometry_info.rho;
1130 if ((flags & SigmaValue) != 0)
1131 percent_saturation=geometry_info.sigma;
1135 case ThresholdCompositeOp:
1141 Determine the amount and threshold.
1143 value=GetImageArtifact(composite_image,"compose:args");
1144 if (value != (char *) NULL)
1146 flags=ParseGeometry(value,&geometry_info);
1147 amount=geometry_info.rho;
1148 threshold=geometry_info.sigma;
1149 if ((flags & SigmaValue) == 0)
1152 threshold*=QuantumRange;
1163 midpoint=((double) QuantumRange+1.0)/2;
1164 composite_view=AcquireVirtualCacheView(composite_image,exception);
1165 image_view=AcquireAuthenticCacheView(image,exception);
1166 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1167 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1168 dynamic_number_threads(image,image->columns,image->rows,1)
1170 for (y=0; y < (ssize_t) image->rows; y++)
1187 register const Quantum
1196 if (status == MagickFalse)
1198 if (clip_to_self != MagickFalse)
1202 if ((y-y_offset) >= (ssize_t) composite_image->rows)
1206 If pixels is NULL, y is outside overlay region.
1208 pixels=(Quantum *) NULL;
1210 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
1212 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
1213 composite_image->columns,1,exception);
1214 if (p == (const Quantum *) NULL)
1221 p-=x_offset*GetPixelChannels(composite_image);
1223 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1224 if (q == (Quantum *) NULL)
1232 GetPixelInfo(image,&destination_pixel);
1233 GetPixelInfo(composite_image,&source_pixel);
1234 for (x=0; x < (ssize_t) image->columns; x++)
1252 if (clip_to_self != MagickFalse)
1256 q+=GetPixelChannels(image);
1259 if ((x-x_offset) >= (ssize_t) composite_image->columns)
1262 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1263 ((x-x_offset) >= (ssize_t) composite_image->columns))
1266 source[MaxPixelChannels];
1271 Dc: destination color.
1273 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
1275 if (GetPixelMask(image,q) != 0)
1277 q+=GetPixelChannels(image);
1280 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1292 channel=GetPixelChannelMapChannel(image,i);
1293 traits=GetPixelChannelMapTraits(image,channel);
1294 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
1295 if ((traits == UndefinedPixelTrait) ||
1296 (composite_traits == UndefinedPixelTrait))
1300 case AlphaCompositeOp:
1301 case ChangeMaskCompositeOp:
1302 case CopyAlphaCompositeOp:
1303 case DstAtopCompositeOp:
1304 case DstInCompositeOp:
1306 case IntensityCompositeOp:
1307 case OutCompositeOp:
1308 case SrcInCompositeOp:
1309 case SrcOutCompositeOp:
1311 pixel=(double) q[i];
1312 if (channel == AlphaPixelChannel)
1313 pixel=(double) TransparentAlpha;
1316 case ClearCompositeOp:
1317 case CopyCompositeOp:
1318 case ReplaceCompositeOp:
1319 case SrcCompositeOp:
1321 if (channel == AlphaPixelChannel)
1323 pixel=(double) TransparentAlpha;
1329 case BlendCompositeOp:
1330 case DissolveCompositeOp:
1332 if (channel == AlphaPixelChannel)
1334 pixel=destination_dissolve*GetPixelAlpha(composite_image,
1338 pixel=(double) source[channel];
1343 pixel=(double) source[channel];
1347 q[i]=ClampToQuantum(pixel);
1349 q+=GetPixelChannels(image);
1353 Authentic composite:
1354 Sa: normalized source alpha.
1355 Da: normalized destination alpha.
1357 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
1358 Da=QuantumScale*GetPixelAlpha(image,q);
1361 case BumpmapCompositeOp:
1363 alpha=GetPixelIntensity(composite_image,p)*Sa;
1366 case ColorBurnCompositeOp:
1367 case ColorDodgeCompositeOp:
1368 case DifferenceCompositeOp:
1369 case DivideDstCompositeOp:
1370 case DivideSrcCompositeOp:
1371 case ExclusionCompositeOp:
1372 case HardLightCompositeOp:
1373 case LinearBurnCompositeOp:
1374 case LinearDodgeCompositeOp:
1375 case LinearLightCompositeOp:
1376 case MathematicsCompositeOp:
1377 case MinusDstCompositeOp:
1378 case MinusSrcCompositeOp:
1379 case ModulusAddCompositeOp:
1380 case ModulusSubtractCompositeOp:
1381 case MultiplyCompositeOp:
1382 case OverlayCompositeOp:
1383 case PegtopLightCompositeOp:
1384 case PinLightCompositeOp:
1385 case ScreenCompositeOp:
1386 case SoftLightCompositeOp:
1387 case VividLightCompositeOp:
1389 alpha=RoundToUnity(Sa+Da-Sa*Da);
1392 case DarkenCompositeOp:
1393 case DstAtopCompositeOp:
1394 case DstInCompositeOp:
1396 case LightenCompositeOp:
1397 case SrcInCompositeOp:
1402 case DissolveCompositeOp:
1404 alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
1405 Sa+destination_dissolve*Da;
1408 case DstOverCompositeOp:
1410 alpha=Da*(-Sa)+Da+Sa;
1413 case DstOutCompositeOp:
1418 case OutCompositeOp:
1419 case SrcOutCompositeOp:
1424 case OverCompositeOp:
1425 case SrcOverCompositeOp:
1427 alpha=Sa*(-Da)+Sa+Da;
1430 case BlendCompositeOp:
1431 case PlusCompositeOp:
1433 alpha=RoundToUnity(Sa+Da);
1436 case XorCompositeOp:
1438 alpha=Sa+Da-2.0*Sa*Da;
1447 if (GetPixelMask(image,p) != 0)
1449 p+=GetPixelChannels(composite_image);
1450 q+=GetPixelChannels(image);
1455 case ColorizeCompositeOp:
1456 case HueCompositeOp:
1457 case LuminizeCompositeOp:
1458 case ModulateCompositeOp:
1459 case SaturateCompositeOp:
1461 GetPixelInfoPixel(composite_image,p,&source_pixel);
1462 GetPixelInfoPixel(image,q,&destination_pixel);
1468 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1483 channel=GetPixelChannelMapChannel(image,i);
1484 traits=GetPixelChannelMapTraits(image,channel);
1485 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
1486 if (traits == UndefinedPixelTrait)
1488 if ((compose != IntensityCompositeOp) &&
1489 (composite_traits == UndefinedPixelTrait))
1493 Dc: destination color.
1495 Sc=(double) GetPixelChannel(composite_image,channel,p);
1497 if ((traits & CopyPixelTrait) != 0)
1499 if (channel != AlphaPixelChannel)
1504 q[i]=ClampToQuantum(Sc);
1512 case AlphaCompositeOp:
1514 pixel=QuantumRange*Sa;
1517 case AtopCompositeOp:
1518 case CopyBlackCompositeOp:
1519 case CopyBlueCompositeOp:
1520 case CopyCyanCompositeOp:
1521 case CopyGreenCompositeOp:
1522 case CopyMagentaCompositeOp:
1523 case CopyRedCompositeOp:
1524 case CopyYellowCompositeOp:
1525 case SrcAtopCompositeOp:
1526 case DstCompositeOp:
1529 pixel=QuantumRange*Da;
1532 case ChangeMaskCompositeOp:
1537 if (Da > ((double) QuantumRange/2.0))
1539 pixel=(double) TransparentAlpha;
1542 equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
1543 if (equivalent != MagickFalse)
1545 pixel=(double) TransparentAlpha;
1548 pixel=(double) OpaqueAlpha;
1551 case ClearCompositeOp:
1553 pixel=(double) TransparentAlpha;
1556 case ColorizeCompositeOp:
1557 case HueCompositeOp:
1558 case LuminizeCompositeOp:
1559 case SaturateCompositeOp:
1561 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1563 pixel=QuantumRange*Da;
1566 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1568 pixel=QuantumRange*Sa;
1573 pixel=QuantumRange*Da;
1576 pixel=QuantumRange*Sa;
1579 case CopyAlphaCompositeOp:
1581 pixel=QuantumRange*Sa;
1582 if (composite_image->matte == MagickFalse)
1583 pixel=GetPixelIntensity(composite_image,p);
1586 case CopyCompositeOp:
1587 case DisplaceCompositeOp:
1588 case DistortCompositeOp:
1589 case DstAtopCompositeOp:
1590 case ReplaceCompositeOp:
1591 case SrcCompositeOp:
1593 pixel=QuantumRange*Sa;
1596 case DarkenIntensityCompositeOp:
1598 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1599 (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
1602 case IntensityCompositeOp:
1604 pixel=GetPixelIntensity(composite_image,p);
1607 case LightenIntensityCompositeOp:
1609 pixel=Sa*GetPixelIntensity(composite_image,p) >
1610 Da*GetPixelIntensity(image,q) ? Sa : Da;
1613 case ModulateCompositeOp:
1615 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1617 pixel=QuantumRange*Da;
1620 pixel=QuantumRange*Da;
1625 pixel=QuantumRange*alpha;
1629 q[i]=ClampToQuantum(pixel);
1633 Porter-Duff compositions:
1634 Sca: source normalized color multiplied by alpha.
1635 Dca: normalized destination color multiplied by alpha.
1637 Sca=QuantumScale*Sa*Sc;
1638 Dca=QuantumScale*Da*Dc;
1641 case DarkenCompositeOp:
1642 case LightenCompositeOp:
1643 case ModulusSubtractCompositeOp:
1651 gamma=MagickEpsilonReciprocal(alpha);
1655 case AlphaCompositeOp:
1657 pixel=QuantumRange*Sa;
1660 case AtopCompositeOp:
1661 case SrcAtopCompositeOp:
1663 pixel=Sc*Sa+Dc*(1.0-Sa);
1666 case BlendCompositeOp:
1668 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1671 case BlurCompositeOp:
1672 case DisplaceCompositeOp:
1673 case DistortCompositeOp:
1674 case CopyCompositeOp:
1675 case ReplaceCompositeOp:
1676 case SrcCompositeOp:
1681 case BumpmapCompositeOp:
1683 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1688 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1691 case ChangeMaskCompositeOp:
1696 case ClearCompositeOp:
1701 case ColorBurnCompositeOp:
1704 Refer to the March 2009 SVG specification.
1706 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1708 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1711 if (Sca < MagickEpsilon)
1713 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1716 pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
1717 Sca*(1.0-Da)+Dca*(1.0-Sa));
1720 case ColorDodgeCompositeOp:
1722 if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1724 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1727 if (fabs(Sca-Sa) < MagickEpsilon)
1729 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1732 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1736 case ColorizeCompositeOp:
1738 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1743 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1748 CompositeHSL(destination_pixel.red,destination_pixel.green,
1749 destination_pixel.blue,&sans,&sans,&brightness);
1750 CompositeHSL(source_pixel.red,source_pixel.green,source_pixel.blue,
1751 &hue,&saturation,&sans);
1752 HSLComposite(hue,saturation,brightness,&red,&green,&blue);
1755 case RedPixelChannel: pixel=red; break;
1756 case GreenPixelChannel: pixel=green; break;
1757 case BluePixelChannel: pixel=blue; break;
1758 default: pixel=Dc; break;
1762 case CopyAlphaCompositeOp:
1763 case IntensityCompositeOp:
1768 case CopyBlackCompositeOp:
1770 if (channel == BlackPixelChannel)
1771 pixel=(double) GetPixelBlack(composite_image,p);
1774 case CopyBlueCompositeOp:
1775 case CopyYellowCompositeOp:
1777 if (channel == BluePixelChannel)
1778 pixel=(double) GetPixelBlue(composite_image,p);
1781 case CopyGreenCompositeOp:
1782 case CopyMagentaCompositeOp:
1784 if (channel == GreenPixelChannel)
1785 pixel=(double) GetPixelGreen(composite_image,p);
1788 case CopyRedCompositeOp:
1789 case CopyCyanCompositeOp:
1791 if (channel == RedPixelChannel)
1792 pixel=(double) GetPixelRed(composite_image,p);
1795 case DarkenCompositeOp:
1798 Darken is equivalent to a 'Minimum' method
1799 OR a greyscale version of a binary 'Or'
1800 OR the 'Intersection' of pixel sets.
1804 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1807 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1810 case DarkenIntensityCompositeOp:
1812 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1813 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1816 case DifferenceCompositeOp:
1818 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1821 case DissolveCompositeOp:
1823 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1824 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1827 case DivideDstCompositeOp:
1829 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1831 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1834 if (fabs(Dca) < MagickEpsilon)
1836 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1839 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1842 case DivideSrcCompositeOp:
1844 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1846 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1849 if (fabs(Sca) < MagickEpsilon)
1851 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1854 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1857 case DstAtopCompositeOp:
1859 pixel=Dc*Da+Sc*(1.0-Da);
1862 case DstCompositeOp:
1868 case DstInCompositeOp:
1870 pixel=gamma*(Sa*Dc*Sa);
1873 case DstOutCompositeOp:
1875 pixel=gamma*(Da*Dc*(1.0-Sa));
1878 case DstOverCompositeOp:
1880 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1883 case ExclusionCompositeOp:
1885 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1889 case HardLightCompositeOp:
1893 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1897 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1901 case HueCompositeOp:
1903 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1908 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1913 CompositeHSL(destination_pixel.red,destination_pixel.green,
1914 destination_pixel.blue,&hue,&saturation,&brightness);
1915 CompositeHSL(source_pixel.red,source_pixel.green,source_pixel.blue,
1917 HSLComposite(hue,saturation,brightness,&red,&green,&blue);
1920 case RedPixelChannel: pixel=red; break;
1921 case GreenPixelChannel: pixel=green; break;
1922 case BluePixelChannel: pixel=blue; break;
1923 default: pixel=Dc; break;
1928 case SrcInCompositeOp:
1930 pixel=gamma*(Da*Sc*Da);
1933 case LinearBurnCompositeOp:
1936 LinearBurn: as defined by Abode Photoshop, according to
1937 http://www.simplefilter.de/en/basics/mixmods.html is:
1939 f(Sc,Dc) = Sc + Dc - 1
1941 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1944 case LinearDodgeCompositeOp:
1946 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1949 case LinearLightCompositeOp:
1952 LinearLight: as defined by Abode Photoshop, according to
1953 http://www.simplefilter.de/en/basics/mixmods.html is:
1955 f(Sc,Dc) = Dc + 2*Sc - 1
1957 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1960 case LightenCompositeOp:
1964 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1967 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1970 case LightenIntensityCompositeOp:
1973 Lighten is equivalent to a 'Maximum' method
1974 OR a greyscale version of a binary 'And'
1975 OR the 'Union' of pixel sets.
1977 pixel=Sa*GetPixelIntensity(composite_image,p) >
1978 Da*GetPixelIntensity(image,q) ? Sc : Dc;
1981 case LuminizeCompositeOp:
1983 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1988 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1993 CompositeHSL(destination_pixel.red,destination_pixel.green,
1994 destination_pixel.blue,&hue,&saturation,&brightness);
1995 CompositeHSL(source_pixel.red,source_pixel.green,source_pixel.blue,
1996 &sans,&sans,&brightness);
1997 HSLComposite(hue,saturation,brightness,&red,&green,&blue);
2000 case RedPixelChannel: pixel=red; break;
2001 case GreenPixelChannel: pixel=green; break;
2002 case BluePixelChannel: pixel=blue; break;
2003 default: pixel=Dc; break;
2007 case MathematicsCompositeOp:
2010 'Mathematics' a free form user control mathematical composition
2013 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
2015 Where the arguments A,B,C,D are (currently) passed to composite
2016 as a command separated 'geometry' string in "compose:args" image
2019 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
2021 Applying the SVG transparency formula (see above), we get...
2023 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
2025 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
2028 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
2029 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
2030 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
2033 case MinusDstCompositeOp:
2035 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2038 case MinusSrcCompositeOp:
2041 Minus source from destination.
2045 pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2048 case ModulateCompositeOp:
2053 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2058 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
2064 CompositeHSL(destination_pixel.red,destination_pixel.green,
2065 destination_pixel.blue,&hue,&saturation,&brightness);
2066 brightness+=(0.01*percent_brightness*offset)/midpoint;
2067 saturation*=0.01*percent_saturation;
2068 HSLComposite(hue,saturation,brightness,&red,&green,&blue);
2071 case RedPixelChannel: pixel=red; break;
2072 case GreenPixelChannel: pixel=green; break;
2073 case BluePixelChannel: pixel=blue; break;
2074 default: pixel=Dc; break;
2078 case ModulusAddCompositeOp:
2081 if (pixel > QuantumRange)
2082 pixel-=(QuantumRange+1.0);
2083 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2086 case ModulusSubtractCompositeOp:
2090 pixel+=(QuantumRange+1.0);
2091 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2094 case MultiplyCompositeOp:
2096 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2099 case OutCompositeOp:
2100 case SrcOutCompositeOp:
2102 pixel=gamma*(Sa*Sc*(1.0-Da));
2105 case OverCompositeOp:
2106 case SrcOverCompositeOp:
2108 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2111 case OverlayCompositeOp:
2115 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2119 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2123 case PegtopLightCompositeOp:
2126 PegTop: A Soft-Light alternative: A continuous version of the
2127 Softlight function, producing very similar results.
2129 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2131 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2133 if (fabs(Da) < MagickEpsilon)
2135 pixel=QuantumRange*gamma*(Sca);
2138 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2142 case PinLightCompositeOp:
2145 PinLight: A Photoshop 7 composition method
2146 http://www.simplefilter.de/en/basics/mixmods.html
2148 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2150 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2152 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2155 if ((Dca*Sa) > (2.0*Sca*Da))
2157 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2160 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2163 case PlusCompositeOp:
2165 pixel=gamma*(Sa*Sc+Da*Dc);
2168 case SaturateCompositeOp:
2170 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2175 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2180 CompositeHSL(destination_pixel.red,destination_pixel.green,
2181 destination_pixel.blue,&hue,&saturation,&brightness);
2182 CompositeHSL(source_pixel.red,source_pixel.green,source_pixel.blue,
2183 &sans,&saturation,&sans);
2184 HSLComposite(hue,saturation,brightness,&red,&green,&blue);
2187 case RedPixelChannel: pixel=red; break;
2188 case GreenPixelChannel: pixel=green; break;
2189 case BluePixelChannel: pixel=blue; break;
2190 default: pixel=Dc; break;
2194 case ScreenCompositeOp:
2197 Screen: a negated multiply:
2199 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2201 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2204 case SoftLightCompositeOp:
2207 Refer to the March 2009 SVG specification.
2211 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2212 Sca*(1.0-Da)+Dca*(1.0-Sa));
2215 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2217 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2218 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2222 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2223 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2226 case ThresholdCompositeOp:
2232 if ((double) fabs((double) (2.0*delta)) < threshold)
2237 pixel=gamma*(Dc+delta*amount);
2240 case VividLightCompositeOp:
2243 VividLight: A Photoshop 7 composition method. See
2244 http://www.simplefilter.de/en/basics/mixmods.html.
2246 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2248 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2250 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2253 if ((2.0*Sca) <= Sa)
2255 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2256 (1.0-Da)+Dca*(1.0-Sa));
2259 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2263 case XorCompositeOp:
2265 pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2274 q[i]=ClampToQuantum(pixel);
2276 p+=GetPixelChannels(composite_image);
2277 channels=GetPixelChannels(composite_image);
2278 if (p >= (pixels+channels*composite_image->columns))
2280 q+=GetPixelChannels(image);
2282 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2284 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2289 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2290 #pragma omp critical (MagickCore_CompositeImage)
2292 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2294 if (proceed == MagickFalse)
2298 composite_view=DestroyCacheView(composite_view);
2299 image_view=DestroyCacheView(image_view);
2300 if (destination_image != (Image * ) NULL)
2301 destination_image=DestroyImage(destination_image);
2303 composite_image=DestroyImage(composite_image);
2304 if (status != MagickFalse)
2305 (void) ClampImage(image,exception);
2310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2314 % T e x t u r e I m a g e %
2318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2320 % TextureImage() repeatedly tiles the texture image across and down the image
2323 % The format of the TextureImage method is:
2325 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2326 % ExceptionInfo *exception)
2328 % A description of each parameter follows:
2330 % o image: the image.
2332 % o texture_image: This image is the texture to layer on the background.
2335 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
2336 ExceptionInfo *exception)
2338 #define TextureImageTag "Texture/Image"
2353 assert(image != (Image *) NULL);
2354 if (image->debug != MagickFalse)
2355 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2356 assert(image->signature == MagickSignature);
2357 if (texture == (const Image *) NULL)
2358 return(MagickFalse);
2359 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2360 return(MagickFalse);
2361 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2362 if (texture_image == (const Image *) NULL)
2363 return(MagickFalse);
2364 (void) TransformImageColorspace(texture_image,image->colorspace,exception);
2365 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
2368 if ((image->compose != CopyCompositeOp) &&
2369 ((image->compose != OverCompositeOp) || (image->matte != MagickFalse) ||
2370 (texture_image->matte != MagickFalse)))
2373 Tile texture onto the image background.
2375 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2376 #pragma omp parallel for schedule(static) shared(status) \
2377 dynamic_number_threads(image,image->columns,image->rows,1)
2379 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2384 if (status == MagickFalse)
2386 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2391 thread_status=CompositeImage(image,texture_image,image->compose,
2392 MagickFalse,x+texture_image->tile_offset.x,y+
2393 texture_image->tile_offset.y,exception);
2394 if (thread_status == MagickFalse)
2396 status=thread_status;
2400 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2405 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2406 #pragma omp critical (MagickCore_TextureImage)
2408 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2410 if (proceed == MagickFalse)
2414 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2415 image->rows,image->rows);
2416 texture_image=DestroyImage(texture_image);
2420 Tile texture onto the image background (optimized).
2423 texture_view=AcquireVirtualCacheView(texture_image,exception);
2424 image_view=AcquireAuthenticCacheView(image,exception);
2425 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2426 #pragma omp parallel for schedule(static) shared(status) \
2427 dynamic_number_threads(image,image->columns,image->rows,1)
2429 for (y=0; y < (ssize_t) image->rows; y++)
2434 register const Quantum
2447 if (status == MagickFalse)
2449 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2450 (y+texture_image->tile_offset.y) % texture_image->rows,
2451 texture_image->columns,1,exception);
2452 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2453 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2458 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2464 width=texture_image->columns;
2465 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2466 width=image->columns-x;
2467 for (j=0; j < (ssize_t) width; j++)
2472 if (GetPixelMask(image,p) != 0)
2474 p+=GetPixelChannels(texture_image);
2475 q+=GetPixelChannels(image);
2478 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2487 channel=GetPixelChannelMapChannel(texture_image,i);
2488 texture_traits=GetPixelChannelMapTraits(texture_image,channel);
2489 traits=GetPixelChannelMapTraits(image,channel);
2490 if ((traits == UndefinedPixelTrait) ||
2491 (texture_traits == UndefinedPixelTrait))
2493 SetPixelChannel(image,channel,p[i],q);
2495 p+=GetPixelChannels(texture_image);
2496 q+=GetPixelChannels(image);
2499 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2500 if (sync == MagickFalse)
2502 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2507 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2508 #pragma omp critical (MagickCore_TextureImage)
2510 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2512 if (proceed == MagickFalse)
2516 texture_view=DestroyCacheView(texture_view);
2517 image_view=DestroyCacheView(image_view);
2518 texture_image=DestroyImage(texture_image);