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 HCLComposite(const double hue,const double chroma,const double luma,
211 double *red,double *green,double *blue)
224 Convert HCL to RGB colorspace.
226 assert(red != (double *) NULL);
227 assert(green != (double *) NULL);
228 assert(blue != (double *) NULL);
231 x=c*(1.0-fabs(fmod(h,2.0)-1.0));
235 if ((0.0 <= h) && (h < 1.0))
241 if ((1.0 <= h) && (h < 2.0))
247 if ((2.0 <= h) && (h < 3.0))
253 if ((3.0 <= h) && (h < 4.0))
259 if ((4.0 <= h) && (h < 5.0))
265 if ((5.0 <= h) && (h < 6.0))
270 m=luma-(0.298839f*r+0.586811f*g+0.114350f*b);
272 Choose saturation strategy to clip it into the RGB cube; hue and luma are
273 preserved and chroma may be changed.
284 z=(1.0-luma)/(m+c-luma);
287 *red=QuantumRange*(z*r+m);
288 *green=QuantumRange*(z*g+m);
289 *blue=QuantumRange*(z*b+m);
292 static void CompositeHCL(const double red,const double green,const double blue,
293 double *hue,double *chroma,double *luma)
304 Convert RGB to HCL colorspace.
306 assert(hue != (double *) NULL);
307 assert(chroma != (double *) NULL);
308 assert(luma != (double *) NULL);
312 max=MagickMax(r,MagickMax(g,b));
313 c=max-(double) MagickMin(r,MagickMin(g,b));
319 h=fmod(6.0+(g-b)/c,6.0);
327 *chroma=QuantumScale*c;
328 *luma=QuantumScale*(0.298839f*r+0.586811f*g+0.114350f*b);
331 static MagickBooleanType CompositeOverImage(Image *image,
332 const Image *composite_image,const MagickBooleanType clip_to_self,
333 const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
335 #define CompositeImageTag "Composite/Image"
355 composite_view=AcquireVirtualCacheView(composite_image,exception);
356 image_view=AcquireAuthenticCacheView(image,exception);
357 #if defined(MAGICKCORE_OPENMP_SUPPORT)
358 #pragma omp parallel for schedule(static,4) shared(progress,status) \
359 dynamic_number_threads(image,image->columns,image->rows,1)
361 for (y=0; y < (ssize_t) image->rows; y++)
366 register const Quantum
378 if (status == MagickFalse)
380 if (clip_to_self != MagickFalse)
384 if ((y-y_offset) >= (ssize_t) composite_image->rows)
388 If pixels is NULL, y is outside overlay region.
390 pixels=(Quantum *) NULL;
392 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
394 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
395 composite_image->columns,1,exception);
396 if (p == (const Quantum *) NULL)
403 p-=x_offset*GetPixelChannels(composite_image);
405 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
406 if (q == (Quantum *) NULL)
411 for (x=0; x < (ssize_t) image->columns; x++)
424 if (clip_to_self != MagickFalse)
428 q+=GetPixelChannels(image);
431 if ((x-x_offset) >= (ssize_t) composite_image->columns)
434 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
435 ((x-x_offset) >= (ssize_t) composite_image->columns))
438 source[MaxPixelChannels];
443 Dc: destination color.
445 if (GetPixelMask(image,q) != 0)
447 q+=GetPixelChannels(image);
450 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
452 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
461 channel=GetPixelChannelChannel(image,i);
462 traits=GetPixelChannelTraits(image,channel);
463 composite_traits=GetPixelChannelTraits(composite_image,channel);
464 if ((traits == UndefinedPixelTrait) ||
465 (composite_traits == UndefinedPixelTrait))
467 q[i]=source[channel];
469 q+=GetPixelChannels(image);
474 Sa: normalized source alpha.
475 Da: normalized destination alpha.
477 if (GetPixelMask(composite_image,p) != 0)
479 p+=GetPixelChannels(composite_image);
480 channels=GetPixelChannels(composite_image);
481 if (p >= (pixels+channels*composite_image->columns))
483 q+=GetPixelChannels(image);
486 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
487 Da=QuantumScale*GetPixelAlpha(image,q);
488 alpha=Sa*(-Da)+Sa+Da;
489 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
498 channel=GetPixelChannelChannel(image,i);
499 traits=GetPixelChannelTraits(image,channel);
500 composite_traits=GetPixelChannelTraits(composite_image,channel);
501 if ((traits == UndefinedPixelTrait) ||
502 (composite_traits == UndefinedPixelTrait))
504 if ((traits & CopyPixelTrait) != 0)
506 if (channel != AlphaPixelChannel)
511 q[i]=GetPixelChannel(composite_image,channel,p);
517 q[i]=ClampToQuantum(QuantumRange*alpha);
522 Dc: destination color.
524 Sc=(double) GetPixelChannel(composite_image,channel,p);
526 gamma=MagickEpsilonReciprocal(alpha);
527 q[i]=ClampToQuantum(gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc));
529 p+=GetPixelChannels(composite_image);
530 channels=GetPixelChannels(composite_image);
531 if (p >= (pixels+channels*composite_image->columns))
533 q+=GetPixelChannels(image);
535 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
537 if (image->progress_monitor != (MagickProgressMonitor) NULL)
542 #if defined(MAGICKCORE_OPENMP_SUPPORT)
543 #pragma omp critical (MagickCore_CompositeImage)
545 proceed=SetImageProgress(image,CompositeImageTag,progress++,
547 if (proceed == MagickFalse)
551 composite_view=DestroyCacheView(composite_view);
552 image_view=DestroyCacheView(image_view);
556 MagickExport MagickBooleanType CompositeImage(Image *image,
557 const Image *composite,const CompositeOperator compose,
558 const MagickBooleanType clip_to_self,const ssize_t x_offset,
559 const ssize_t y_offset,ExceptionInfo *exception)
561 #define CompositeImageTag "Composite/Image"
582 destination_dissolve,
595 assert(image != (Image *) NULL);
596 assert(image->signature == MagickSignature);
597 if (image->debug != MagickFalse)
598 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
599 assert(composite!= (Image *) NULL);
600 assert(composite->signature == MagickSignature);
601 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
603 composite_image=CloneImage(composite,0,0,MagickTrue,exception);
604 if (composite_image == (const Image *) NULL)
606 if (IsGrayColorspace(image->colorspace) != MagickFalse)
607 (void) SetImageColorspace(image,RGBColorspace,exception);
608 (void) SetImageColorspace(composite_image,image->colorspace,exception);
609 if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
611 status=CompositeOverImage(image,composite_image,clip_to_self,x_offset,
613 composite_image=DestroyImage(composite_image);
616 destination_image=(Image *) NULL;
618 destination_dissolve=1.0;
620 percent_chroma=100.0;
625 case CopyCompositeOp:
627 if ((x_offset < 0) || (y_offset < 0))
629 if ((x_offset+(ssize_t) composite_image->columns) >= (ssize_t) image->columns)
631 if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
634 composite_view=AcquireVirtualCacheView(composite_image,exception);
635 image_view=AcquireAuthenticCacheView(image,exception);
636 #if defined(MAGICKCORE_OPENMP_SUPPORT)
637 #pragma omp parallel for schedule(static,4) shared(status) \
638 dynamic_number_threads(image,image->columns,image->rows,1)
640 for (y=0; y < (ssize_t) composite_image->rows; y++)
645 register const Quantum
654 if (status == MagickFalse)
656 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
658 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
659 composite_image->columns,1,exception);
660 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
665 for (x=0; x < (ssize_t) composite_image->columns; x++)
670 if (GetPixelMask(composite_image,p) != 0)
672 p+=GetPixelChannels(composite_image);
673 q+=GetPixelChannels(image);
676 for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
685 channel=GetPixelChannelChannel(composite_image,i);
686 composite_traits=GetPixelChannelTraits(composite_image,channel);
687 traits=GetPixelChannelTraits(image,channel);
688 if ((traits == UndefinedPixelTrait) ||
689 (composite_traits == UndefinedPixelTrait))
691 SetPixelChannel(image,channel,p[i],q);
693 p+=GetPixelChannels(composite_image);
694 q+=GetPixelChannels(image);
696 sync=SyncCacheViewAuthenticPixels(image_view,exception);
697 if (sync == MagickFalse)
699 if (image->progress_monitor != (MagickProgressMonitor) NULL)
704 #if defined(MAGICKCORE_OPENMP_SUPPORT)
705 #pragma omp critical (MagickCore_CompositeImage)
707 proceed=SetImageProgress(image,CompositeImageTag,
708 (MagickOffsetType) y,image->rows);
709 if (proceed == MagickFalse)
713 composite_view=DestroyCacheView(composite_view);
714 image_view=DestroyCacheView(image_view);
715 composite_image=DestroyImage(composite_image);
718 case CopyAlphaCompositeOp:
719 case ChangeMaskCompositeOp:
720 case IntensityCompositeOp:
723 Modify destination outside the overlaid region and require an alpha
724 channel to exist, to add transparency.
726 if (image->alpha_trait != BlendPixelTrait)
727 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
730 case BlurCompositeOp:
755 Blur Image by resampling.
757 Blur Image dictated by an overlay gradient map: X = red_channel;
758 Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
760 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
762 if (destination_image == (Image *) NULL)
764 composite_image=DestroyImage(composite_image);
768 Gather the maximum blur sigma values from user.
770 SetGeometryInfo(&geometry_info);
772 value=GetImageArtifact(composite_image,"compose:args");
773 if (value != (char *) NULL)
774 flags=ParseGeometry(value,&geometry_info);
775 if ((flags & WidthValue) == 0 ) {
776 (void) ThrowMagickException(exception,GetMagickModule(),
777 OptionWarning,"InvalidSetting","'%s' '%s'",
778 "compose:args",value);
779 composite_image=DestroyImage(composite_image);
780 destination_image=DestroyImage(destination_image);
784 Users input sigma now needs to be converted to the EWA ellipse size.
785 The filter defaults to a sigma of 0.5 so to make this match the
786 users input the ellipse size needs to be doubled.
788 width=height=geometry_info.rho*2.0;
789 if ((flags & HeightValue) != 0 )
790 height=geometry_info.sigma*2.0;
792 /* default the unrotated ellipse width and height axis vectors */
797 /* rotate vectors if a rotation angle is given */
798 if ((flags & XValue) != 0 )
803 angle=DegreesToRadians(geometry_info.xi);
804 blur.x1=width*cos(angle);
805 blur.x2=width*sin(angle);
806 blur.y1=(-height*sin(angle));
807 blur.y2=height*cos(angle);
809 /* Otherwise lets set a angle range and calculate in the loop */
812 if ((flags & YValue) != 0 )
814 angle_start=DegreesToRadians(geometry_info.xi);
815 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
818 Set up a gaussian cylindrical filter for EWA Bluring.
820 As the minimum ellipse radius of support*1.0 the EWA algorithm
821 can only produce a minimum blur of 0.5 for Gaussian (support=2.0)
822 This means that even 'No Blur' will be still a little blurry!
824 The solution (as well as the problem of preventing any user
825 expert filter settings, is to set our own user settings, then
826 restore them afterwards.
828 resample_filter=AcquireResampleFilter(image,exception);
829 SetResampleFilter(resample_filter,GaussianFilter);
831 /* do the variable blurring of each pixel in image */
832 GetPixelInfo(image,&pixel);
833 composite_view=AcquireVirtualCacheView(composite_image,exception);
834 destination_view=AcquireAuthenticCacheView(destination_image,exception);
835 for (y=0; y < (ssize_t) composite_image->rows; y++)
840 register const Quantum
849 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
851 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
853 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
854 destination_image->columns,1,exception);
855 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
857 for (x=0; x < (ssize_t) composite_image->columns; x++)
859 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
861 p+=GetPixelChannels(composite_image);
864 if (fabs(angle_range) > MagickEpsilon)
869 angle=angle_start+angle_range*QuantumScale*
870 GetPixelBlue(composite_image,p);
871 blur.x1=width*cos(angle);
872 blur.x2=width*sin(angle);
873 blur.y1=(-height*sin(angle));
874 blur.y2=height*cos(angle);
877 if ( x == 10 && y == 60 ) {
878 fprintf(stderr, "blur.x=%lf,%lf, blur.y=%lf,%lf\n",
879 blur.x1, blur.x2, blur.y1, blur.y2);
880 fprintf(stderr, "scaled by=%lf,%lf\n",
881 QuantumScale*GetPixelRed(p), QuantumScale*GetPixelGreen(p));
883 ScaleResampleFilter(resample_filter,
884 blur.x1*QuantumScale*GetPixelRed(composite_image,p),
885 blur.y1*QuantumScale*GetPixelGreen(composite_image,p),
886 blur.x2*QuantumScale*GetPixelRed(composite_image,p),
887 blur.y2*QuantumScale*GetPixelGreen(composite_image,p) );
888 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
889 (double) y_offset+y,&pixel,exception);
890 SetPixelInfoPixel(destination_image,&pixel,q);
891 p+=GetPixelChannels(composite_image);
892 q+=GetPixelChannels(destination_image);
894 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
895 if (sync == MagickFalse)
898 resample_filter=DestroyResampleFilter(resample_filter);
899 composite_view=DestroyCacheView(composite_view);
900 destination_view=DestroyCacheView(destination_view);
901 composite_image=DestroyImage(composite_image);
902 composite_image=destination_image;
905 case DisplaceCompositeOp:
906 case DistortCompositeOp:
928 Displace/Distort based on overlay gradient map:
929 X = red_channel; Y = green_channel;
930 compose:args = x_scale[,y_scale[,center.x,center.y]]
932 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
934 if (destination_image == (Image *) NULL)
936 composite_image=DestroyImage(composite_image);
939 SetGeometryInfo(&geometry_info);
941 value=GetImageArtifact(composite_image,"compose:args");
942 if (value != (char *) NULL)
943 flags=ParseGeometry(value,&geometry_info);
944 if ((flags & (WidthValue|HeightValue)) == 0 )
946 if ((flags & AspectValue) == 0)
948 horizontal_scale=(double) (composite_image->columns-1.0)/
950 vertical_scale=(double) (composite_image->rows-1.0)/2.0;
954 horizontal_scale=(double) (image->columns-1.0)/2.0;
955 vertical_scale=(double) (image->rows-1.0)/2.0;
960 horizontal_scale=geometry_info.rho;
961 vertical_scale=geometry_info.sigma;
962 if ((flags & PercentValue) != 0)
964 if ((flags & AspectValue) == 0)
966 horizontal_scale*=(composite_image->columns-1.0)/200.0;
967 vertical_scale*=(composite_image->rows-1.0)/200.0;
971 horizontal_scale*=(image->columns-1.0)/200.0;
972 vertical_scale*=(image->rows-1.0)/200.0;
975 if ((flags & HeightValue) == 0)
976 vertical_scale=horizontal_scale;
979 Determine fixed center point for absolute distortion map
981 Displace offset relative to a fixed absolute point
982 Select that point according to +X+Y user inputs.
983 default = center of overlay image
984 arg flag '!' = locations/percentage relative to background image
986 center.x=(double) x_offset;
987 center.y=(double) y_offset;
988 if (compose == DistortCompositeOp)
990 if ((flags & XValue) == 0)
991 if ((flags & AspectValue) == 0)
992 center.x=(double) x_offset+(composite_image->columns-1)/
995 center.x=((double) image->columns-1)/2.0;
997 if ((flags & AspectValue) == 0)
998 center.x=(double) x_offset+geometry_info.xi;
1000 center.x=geometry_info.xi;
1001 if ((flags & YValue) == 0)
1002 if ((flags & AspectValue) == 0)
1003 center.y=(double) y_offset+(composite_image->rows-1)/2.0;
1005 center.y=((double) image->rows-1)/2.0;
1007 if ((flags & AspectValue) == 0)
1008 center.y=(double) y_offset+geometry_info.psi;
1010 center.y=geometry_info.psi;
1013 Shift the pixel offset point as defined by the provided,
1014 displacement/distortion map. -- Like a lens...
1016 GetPixelInfo(image,&pixel);
1017 image_view=AcquireVirtualCacheView(image,exception);
1018 composite_view=AcquireVirtualCacheView(composite_image,exception);
1019 destination_view=AcquireAuthenticCacheView(destination_image,exception);
1020 for (y=0; y < (ssize_t) composite_image->rows; y++)
1025 register const Quantum
1034 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1036 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
1038 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
1039 destination_image->columns,1,exception);
1040 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1042 for (x=0; x < (ssize_t) composite_image->columns; x++)
1044 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1046 p+=GetPixelChannels(composite_image);
1050 Displace the offset.
1052 offset.x=(horizontal_scale*(GetPixelRed(composite_image,p)-
1053 (((double) QuantumRange+1.0)/2.0)))/(((double)
1054 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
1056 offset.y=(vertical_scale*(GetPixelGreen(composite_image,p)-
1057 (((double) QuantumRange+1.0)/2.0)))/(((double)
1058 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
1060 (void) InterpolatePixelInfo(image,image_view,
1061 UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1064 Mask with the 'invalid pixel mask' in alpha channel.
1066 pixel.alpha=(double) QuantumRange*(1.0-(1.0-QuantumScale*
1067 pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
1068 SetPixelInfoPixel(destination_image,&pixel,q);
1069 p+=GetPixelChannels(composite_image);
1070 q+=GetPixelChannels(destination_image);
1072 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1073 if (sync == MagickFalse)
1076 destination_view=DestroyCacheView(destination_view);
1077 composite_view=DestroyCacheView(composite_view);
1078 image_view=DestroyCacheView(image_view);
1079 composite_image=DestroyImage(composite_image);
1080 composite_image=destination_image;
1083 case DissolveCompositeOp:
1089 Geometry arguments to dissolve factors.
1091 value=GetImageArtifact(composite_image,"compose:args");
1092 if (value != (char *) NULL)
1094 flags=ParseGeometry(value,&geometry_info);
1095 source_dissolve=geometry_info.rho/100.0;
1096 destination_dissolve=1.0;
1097 if ((source_dissolve-MagickEpsilon) < 0.0)
1098 source_dissolve=0.0;
1099 if ((source_dissolve+MagickEpsilon) > 1.0)
1101 destination_dissolve=2.0-source_dissolve;
1102 source_dissolve=1.0;
1104 if ((flags & SigmaValue) != 0)
1105 destination_dissolve=geometry_info.sigma/100.0;
1106 if ((destination_dissolve-MagickEpsilon) < 0.0)
1107 destination_dissolve=0.0;
1108 /* posible speed up? -- from IMv6 update
1109 clip_to_self=MagickFalse;
1110 if ((destination_dissolve+MagickEpsilon) > 1.0 )
1112 destination_dissolve=1.0;
1113 clip_to_self=MagickTrue;
1119 case BlendCompositeOp:
1124 value=GetImageArtifact(composite_image,"compose:args");
1125 if (value != (char *) NULL)
1127 flags=ParseGeometry(value,&geometry_info);
1128 source_dissolve=geometry_info.rho/100.0;
1129 destination_dissolve=1.0-source_dissolve;
1130 if ((flags & SigmaValue) != 0)
1131 destination_dissolve=geometry_info.sigma/100.0;
1135 case MathematicsCompositeOp:
1141 Just collect the values from "compose:args", setting.
1142 Unused values are set to zero automagically.
1144 Arguments are normally a comma separated list, so this probably should
1145 be changed to some 'general comma list' parser, (with a minimum
1148 SetGeometryInfo(&geometry_info);
1149 value=GetImageArtifact(composite_image,"compose:args");
1150 if (value != (char *) NULL)
1151 (void) ParseGeometry(value,&geometry_info);
1154 case ModulateCompositeOp:
1160 Determine the luma and chroma scale.
1162 value=GetImageArtifact(composite_image,"compose:args");
1163 if (value != (char *) NULL)
1165 flags=ParseGeometry(value,&geometry_info);
1166 percent_luma=geometry_info.rho;
1167 if ((flags & SigmaValue) != 0)
1168 percent_chroma=geometry_info.sigma;
1172 case ThresholdCompositeOp:
1178 Determine the amount and threshold.
1180 value=GetImageArtifact(composite_image,"compose:args");
1181 if (value != (char *) NULL)
1183 flags=ParseGeometry(value,&geometry_info);
1184 amount=geometry_info.rho;
1185 threshold=geometry_info.sigma;
1186 if ((flags & SigmaValue) == 0)
1189 threshold*=QuantumRange;
1200 midpoint=((double) QuantumRange+1.0)/2;
1201 composite_view=AcquireVirtualCacheView(composite_image,exception);
1202 image_view=AcquireAuthenticCacheView(image,exception);
1203 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1204 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1205 dynamic_number_threads(image,image->columns,image->rows,1)
1207 for (y=0; y < (ssize_t) image->rows; y++)
1224 register const Quantum
1233 if (status == MagickFalse)
1235 if (clip_to_self != MagickFalse)
1239 if ((y-y_offset) >= (ssize_t) composite_image->rows)
1243 If pixels is NULL, y is outside overlay region.
1245 pixels=(Quantum *) NULL;
1247 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
1249 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
1250 composite_image->columns,1,exception);
1251 if (p == (const Quantum *) NULL)
1258 p-=x_offset*GetPixelChannels(composite_image);
1260 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1261 if (q == (Quantum *) NULL)
1269 GetPixelInfo(image,&destination_pixel);
1270 GetPixelInfo(composite_image,&source_pixel);
1271 for (x=0; x < (ssize_t) image->columns; x++)
1289 if (clip_to_self != MagickFalse)
1293 q+=GetPixelChannels(image);
1296 if ((x-x_offset) >= (ssize_t) composite_image->columns)
1299 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1300 ((x-x_offset) >= (ssize_t) composite_image->columns))
1303 source[MaxPixelChannels];
1308 Dc: destination color.
1310 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
1312 if (GetPixelMask(image,q) != 0)
1314 q+=GetPixelChannels(image);
1317 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1329 channel=GetPixelChannelChannel(image,i);
1330 traits=GetPixelChannelTraits(image,channel);
1331 composite_traits=GetPixelChannelTraits(composite_image,channel);
1332 if ((traits == UndefinedPixelTrait) ||
1333 (composite_traits == UndefinedPixelTrait))
1337 case AlphaCompositeOp:
1338 case ChangeMaskCompositeOp:
1339 case CopyAlphaCompositeOp:
1340 case DstAtopCompositeOp:
1341 case DstInCompositeOp:
1343 case IntensityCompositeOp:
1344 case OutCompositeOp:
1345 case SrcInCompositeOp:
1346 case SrcOutCompositeOp:
1348 pixel=(double) q[i];
1349 if (channel == AlphaPixelChannel)
1350 pixel=(double) TransparentAlpha;
1353 case ClearCompositeOp:
1354 case CopyCompositeOp:
1355 case ReplaceCompositeOp:
1356 case SrcCompositeOp:
1358 if (channel == AlphaPixelChannel)
1360 pixel=(double) TransparentAlpha;
1366 case BlendCompositeOp:
1367 case DissolveCompositeOp:
1369 if (channel == AlphaPixelChannel)
1371 pixel=destination_dissolve*GetPixelAlpha(composite_image,
1375 pixel=(double) source[channel];
1380 pixel=(double) source[channel];
1384 q[i]=ClampToQuantum(pixel);
1386 q+=GetPixelChannels(image);
1390 Authentic composite:
1391 Sa: normalized source alpha.
1392 Da: normalized destination alpha.
1394 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
1395 Da=QuantumScale*GetPixelAlpha(image,q);
1398 case BumpmapCompositeOp:
1400 alpha=GetPixelIntensity(composite_image,p)*Sa;
1403 case ColorBurnCompositeOp:
1404 case ColorDodgeCompositeOp:
1405 case DifferenceCompositeOp:
1406 case DivideDstCompositeOp:
1407 case DivideSrcCompositeOp:
1408 case ExclusionCompositeOp:
1409 case HardLightCompositeOp:
1410 case LinearBurnCompositeOp:
1411 case LinearDodgeCompositeOp:
1412 case LinearLightCompositeOp:
1413 case MathematicsCompositeOp:
1414 case MinusDstCompositeOp:
1415 case MinusSrcCompositeOp:
1416 case ModulusAddCompositeOp:
1417 case ModulusSubtractCompositeOp:
1418 case MultiplyCompositeOp:
1419 case OverlayCompositeOp:
1420 case PegtopLightCompositeOp:
1421 case PinLightCompositeOp:
1422 case ScreenCompositeOp:
1423 case SoftLightCompositeOp:
1424 case VividLightCompositeOp:
1426 alpha=RoundToUnity(Sa+Da-Sa*Da);
1429 case DarkenCompositeOp:
1430 case DstAtopCompositeOp:
1431 case DstInCompositeOp:
1433 case LightenCompositeOp:
1434 case SrcInCompositeOp:
1439 case DissolveCompositeOp:
1441 alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
1442 Sa+destination_dissolve*Da;
1445 case DstOverCompositeOp:
1447 alpha=Da*(-Sa)+Da+Sa;
1450 case DstOutCompositeOp:
1455 case OutCompositeOp:
1456 case SrcOutCompositeOp:
1461 case OverCompositeOp:
1462 case SrcOverCompositeOp:
1464 alpha=Sa*(-Da)+Sa+Da;
1467 case BlendCompositeOp:
1468 case PlusCompositeOp:
1470 alpha=RoundToUnity(Sa+Da);
1473 case XorCompositeOp:
1475 alpha=Sa+Da-2.0*Sa*Da;
1484 if (GetPixelMask(image,p) != 0)
1486 p+=GetPixelChannels(composite_image);
1487 q+=GetPixelChannels(image);
1492 case ColorizeCompositeOp:
1493 case HueCompositeOp:
1494 case LuminizeCompositeOp:
1495 case ModulateCompositeOp:
1496 case SaturateCompositeOp:
1498 GetPixelInfoPixel(composite_image,p,&source_pixel);
1499 GetPixelInfoPixel(image,q,&destination_pixel);
1505 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1520 channel=GetPixelChannelChannel(image,i);
1521 traits=GetPixelChannelTraits(image,channel);
1522 composite_traits=GetPixelChannelTraits(composite_image,channel);
1523 if (traits == UndefinedPixelTrait)
1525 if ((compose != IntensityCompositeOp) &&
1526 (composite_traits == UndefinedPixelTrait))
1530 Dc: destination color.
1532 Sc=(double) GetPixelChannel(composite_image,channel,p);
1534 if ((traits & CopyPixelTrait) != 0)
1536 if (channel != AlphaPixelChannel)
1541 q[i]=ClampToQuantum(Sc);
1549 case AlphaCompositeOp:
1551 pixel=QuantumRange*Sa;
1554 case AtopCompositeOp:
1555 case CopyBlackCompositeOp:
1556 case CopyBlueCompositeOp:
1557 case CopyCyanCompositeOp:
1558 case CopyGreenCompositeOp:
1559 case CopyMagentaCompositeOp:
1560 case CopyRedCompositeOp:
1561 case CopyYellowCompositeOp:
1562 case SrcAtopCompositeOp:
1563 case DstCompositeOp:
1566 pixel=QuantumRange*Da;
1569 case ChangeMaskCompositeOp:
1574 if (Da > ((double) QuantumRange/2.0))
1576 pixel=(double) TransparentAlpha;
1579 equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
1580 if (equivalent != MagickFalse)
1582 pixel=(double) TransparentAlpha;
1585 pixel=(double) OpaqueAlpha;
1588 case ClearCompositeOp:
1590 pixel=(double) TransparentAlpha;
1593 case ColorizeCompositeOp:
1594 case HueCompositeOp:
1595 case LuminizeCompositeOp:
1596 case SaturateCompositeOp:
1598 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1600 pixel=QuantumRange*Da;
1603 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1605 pixel=QuantumRange*Sa;
1610 pixel=QuantumRange*Da;
1613 pixel=QuantumRange*Sa;
1616 case CopyAlphaCompositeOp:
1618 pixel=QuantumRange*Sa;
1619 if (composite_image->alpha_trait != BlendPixelTrait)
1620 pixel=GetPixelIntensity(composite_image,p);
1623 case CopyCompositeOp:
1624 case DisplaceCompositeOp:
1625 case DistortCompositeOp:
1626 case DstAtopCompositeOp:
1627 case ReplaceCompositeOp:
1628 case SrcCompositeOp:
1630 pixel=QuantumRange*Sa;
1633 case DarkenIntensityCompositeOp:
1635 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1636 (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
1639 case IntensityCompositeOp:
1641 pixel=GetPixelIntensity(composite_image,p);
1644 case LightenIntensityCompositeOp:
1646 pixel=Sa*GetPixelIntensity(composite_image,p) >
1647 Da*GetPixelIntensity(image,q) ? Sa : Da;
1650 case ModulateCompositeOp:
1652 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1654 pixel=QuantumRange*Da;
1657 pixel=QuantumRange*Da;
1662 pixel=QuantumRange*alpha;
1666 q[i]=ClampToQuantum(pixel);
1670 Porter-Duff compositions:
1671 Sca: source normalized color multiplied by alpha.
1672 Dca: normalized destination color multiplied by alpha.
1674 Sca=QuantumScale*Sa*Sc;
1675 Dca=QuantumScale*Da*Dc;
1678 case DarkenCompositeOp:
1679 case LightenCompositeOp:
1680 case ModulusSubtractCompositeOp:
1688 gamma=MagickEpsilonReciprocal(alpha);
1692 case AlphaCompositeOp:
1694 pixel=QuantumRange*Sa;
1697 case AtopCompositeOp:
1698 case SrcAtopCompositeOp:
1700 pixel=Sc*Sa+Dc*(1.0-Sa);
1703 case BlendCompositeOp:
1705 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1708 case BlurCompositeOp:
1709 case DisplaceCompositeOp:
1710 case DistortCompositeOp:
1711 case CopyCompositeOp:
1712 case ReplaceCompositeOp:
1713 case SrcCompositeOp:
1718 case BumpmapCompositeOp:
1720 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1725 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1728 case ChangeMaskCompositeOp:
1733 case ClearCompositeOp:
1738 case ColorBurnCompositeOp:
1741 Refer to the March 2009 SVG specification.
1743 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1745 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1748 if (Sca < MagickEpsilon)
1750 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1753 pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
1754 Sca*(1.0-Da)+Dca*(1.0-Sa));
1757 case ColorDodgeCompositeOp:
1759 if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1761 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1764 if (fabs(Sca-Sa) < MagickEpsilon)
1766 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1769 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1773 case ColorizeCompositeOp:
1775 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1780 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1785 CompositeHCL(destination_pixel.red,destination_pixel.green,
1786 destination_pixel.blue,&sans,&sans,&luma);
1787 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1788 &hue,&chroma,&sans);
1789 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1792 case RedPixelChannel: pixel=red; break;
1793 case GreenPixelChannel: pixel=green; break;
1794 case BluePixelChannel: pixel=blue; break;
1795 default: pixel=Dc; break;
1799 case CopyAlphaCompositeOp:
1800 case IntensityCompositeOp:
1805 case CopyBlackCompositeOp:
1807 if (channel == BlackPixelChannel)
1808 pixel=(double) GetPixelBlack(composite_image,p);
1811 case CopyBlueCompositeOp:
1812 case CopyYellowCompositeOp:
1814 if (channel == BluePixelChannel)
1815 pixel=(double) GetPixelBlue(composite_image,p);
1818 case CopyGreenCompositeOp:
1819 case CopyMagentaCompositeOp:
1821 if (channel == GreenPixelChannel)
1822 pixel=(double) GetPixelGreen(composite_image,p);
1825 case CopyRedCompositeOp:
1826 case CopyCyanCompositeOp:
1828 if (channel == RedPixelChannel)
1829 pixel=(double) GetPixelRed(composite_image,p);
1832 case DarkenCompositeOp:
1835 Darken is equivalent to a 'Minimum' method
1836 OR a greyscale version of a binary 'Or'
1837 OR the 'Intersection' of pixel sets.
1841 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1844 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1847 case DarkenIntensityCompositeOp:
1849 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1850 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1853 case DifferenceCompositeOp:
1855 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1858 case DissolveCompositeOp:
1860 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1861 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1864 case DivideDstCompositeOp:
1866 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1868 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1871 if (fabs(Dca) < MagickEpsilon)
1873 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1876 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1879 case DivideSrcCompositeOp:
1881 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1883 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1886 if (fabs(Sca) < MagickEpsilon)
1888 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1891 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1894 case DstAtopCompositeOp:
1896 pixel=Dc*Da+Sc*(1.0-Da);
1899 case DstCompositeOp:
1905 case DstInCompositeOp:
1907 pixel=gamma*(Sa*Dc*Sa);
1910 case DstOutCompositeOp:
1912 pixel=gamma*(Da*Dc*(1.0-Sa));
1915 case DstOverCompositeOp:
1917 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1920 case ExclusionCompositeOp:
1922 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1926 case HardLightCompositeOp:
1930 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1934 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1938 case HueCompositeOp:
1940 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1945 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1950 CompositeHCL(destination_pixel.red,destination_pixel.green,
1951 destination_pixel.blue,&hue,&chroma,&luma);
1952 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1954 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1957 case RedPixelChannel: pixel=red; break;
1958 case GreenPixelChannel: pixel=green; break;
1959 case BluePixelChannel: pixel=blue; break;
1960 default: pixel=Dc; break;
1965 case SrcInCompositeOp:
1967 pixel=gamma*(Da*Sc*Da);
1970 case LinearBurnCompositeOp:
1973 LinearBurn: as defined by Abode Photoshop, according to
1974 http://www.simplefilter.de/en/basics/mixmods.html is:
1976 f(Sc,Dc) = Sc + Dc - 1
1978 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1981 case LinearDodgeCompositeOp:
1983 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1986 case LinearLightCompositeOp:
1989 LinearLight: as defined by Abode Photoshop, according to
1990 http://www.simplefilter.de/en/basics/mixmods.html is:
1992 f(Sc,Dc) = Dc + 2*Sc - 1
1994 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1997 case LightenCompositeOp:
2001 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2004 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
2007 case LightenIntensityCompositeOp:
2010 Lighten is equivalent to a 'Maximum' method
2011 OR a greyscale version of a binary 'And'
2012 OR the 'Union' of pixel sets.
2014 pixel=Sa*GetPixelIntensity(composite_image,p) >
2015 Da*GetPixelIntensity(image,q) ? Sc : Dc;
2018 case LuminizeCompositeOp:
2020 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2025 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2030 CompositeHCL(destination_pixel.red,destination_pixel.green,
2031 destination_pixel.blue,&hue,&chroma,&luma);
2032 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2034 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2037 case RedPixelChannel: pixel=red; break;
2038 case GreenPixelChannel: pixel=green; break;
2039 case BluePixelChannel: pixel=blue; break;
2040 default: pixel=Dc; break;
2044 case MathematicsCompositeOp:
2047 'Mathematics' a free form user control mathematical composition
2050 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
2052 Where the arguments A,B,C,D are (currently) passed to composite
2053 as a command separated 'geometry' string in "compose:args" image
2056 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
2058 Applying the SVG transparency formula (see above), we get...
2060 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
2062 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
2065 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
2066 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
2067 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
2070 case MinusDstCompositeOp:
2072 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2075 case MinusSrcCompositeOp:
2078 Minus source from destination.
2082 pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2085 case ModulateCompositeOp:
2090 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2095 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
2101 CompositeHCL(destination_pixel.red,destination_pixel.green,
2102 destination_pixel.blue,&hue,&chroma,&luma);
2103 luma+=(0.01*percent_luma*offset)/midpoint;
2104 chroma*=0.01*percent_chroma;
2105 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2108 case RedPixelChannel: pixel=red; break;
2109 case GreenPixelChannel: pixel=green; break;
2110 case BluePixelChannel: pixel=blue; break;
2111 default: pixel=Dc; break;
2115 case ModulusAddCompositeOp:
2118 if (pixel > QuantumRange)
2119 pixel-=(QuantumRange+1.0);
2120 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2123 case ModulusSubtractCompositeOp:
2127 pixel+=(QuantumRange+1.0);
2128 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2131 case MultiplyCompositeOp:
2133 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2136 case OutCompositeOp:
2137 case SrcOutCompositeOp:
2139 pixel=gamma*(Sa*Sc*(1.0-Da));
2142 case OverCompositeOp:
2143 case SrcOverCompositeOp:
2145 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2148 case OverlayCompositeOp:
2152 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2156 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2160 case PegtopLightCompositeOp:
2163 PegTop: A Soft-Light alternative: A continuous version of the
2164 Softlight function, producing very similar results.
2166 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2168 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2170 if (fabs(Da) < MagickEpsilon)
2172 pixel=QuantumRange*gamma*(Sca);
2175 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2179 case PinLightCompositeOp:
2182 PinLight: A Photoshop 7 composition method
2183 http://www.simplefilter.de/en/basics/mixmods.html
2185 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2187 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2189 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2192 if ((Dca*Sa) > (2.0*Sca*Da))
2194 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2197 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2200 case PlusCompositeOp:
2202 pixel=gamma*(Sa*Sc+Da*Dc);
2205 case SaturateCompositeOp:
2207 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2212 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2217 CompositeHCL(destination_pixel.red,destination_pixel.green,
2218 destination_pixel.blue,&hue,&chroma,&luma);
2219 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2220 &sans,&chroma,&sans);
2221 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2224 case RedPixelChannel: pixel=red; break;
2225 case GreenPixelChannel: pixel=green; break;
2226 case BluePixelChannel: pixel=blue; break;
2227 default: pixel=Dc; break;
2231 case ScreenCompositeOp:
2234 Screen: a negated multiply:
2236 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2238 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2241 case SoftLightCompositeOp:
2244 Refer to the March 2009 SVG specification.
2248 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2249 Sca*(1.0-Da)+Dca*(1.0-Sa));
2252 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2254 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2255 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2259 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2260 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2263 case ThresholdCompositeOp:
2269 if ((double) fabs((double) (2.0*delta)) < threshold)
2274 pixel=gamma*(Dc+delta*amount);
2277 case VividLightCompositeOp:
2280 VividLight: A Photoshop 7 composition method. See
2281 http://www.simplefilter.de/en/basics/mixmods.html.
2283 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2285 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2287 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2290 if ((2.0*Sca) <= Sa)
2292 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2293 (1.0-Da)+Dca*(1.0-Sa));
2296 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2300 case XorCompositeOp:
2302 pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2311 q[i]=ClampToQuantum(pixel);
2313 p+=GetPixelChannels(composite_image);
2314 channels=GetPixelChannels(composite_image);
2315 if (p >= (pixels+channels*composite_image->columns))
2317 q+=GetPixelChannels(image);
2319 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2321 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2326 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2327 #pragma omp critical (MagickCore_CompositeImage)
2329 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2331 if (proceed == MagickFalse)
2335 composite_view=DestroyCacheView(composite_view);
2336 image_view=DestroyCacheView(image_view);
2337 if (destination_image != (Image * ) NULL)
2338 destination_image=DestroyImage(destination_image);
2340 composite_image=DestroyImage(composite_image);
2341 if (status != MagickFalse)
2342 (void) ClampImage(image,exception);
2347 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2351 % T e x t u r e I m a g e %
2355 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2357 % TextureImage() repeatedly tiles the texture image across and down the image
2360 % The format of the TextureImage method is:
2362 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2363 % ExceptionInfo *exception)
2365 % A description of each parameter follows:
2367 % o image: the image.
2369 % o texture_image: This image is the texture to layer on the background.
2372 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
2373 ExceptionInfo *exception)
2375 #define TextureImageTag "Texture/Image"
2390 assert(image != (Image *) NULL);
2391 if (image->debug != MagickFalse)
2392 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2393 assert(image->signature == MagickSignature);
2394 if (texture == (const Image *) NULL)
2395 return(MagickFalse);
2396 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2397 return(MagickFalse);
2398 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2399 if (texture_image == (const Image *) NULL)
2400 return(MagickFalse);
2401 (void) TransformImageColorspace(texture_image,image->colorspace,exception);
2402 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
2405 if ((image->compose != CopyCompositeOp) &&
2406 ((image->compose != OverCompositeOp) || (image->alpha_trait == BlendPixelTrait) ||
2407 (texture_image->alpha_trait == BlendPixelTrait)))
2410 Tile texture onto the image background.
2412 #if defined(MAGICKCORE_OPENMP_SUPPORT) && defined(NoBenefitFromParallelism)
2413 #pragma omp parallel for schedule(static,4) shared(status) \
2414 dynamic_number_threads(image,image->columns,image->rows,1)
2416 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2421 if (status == MagickFalse)
2423 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2428 thread_status=CompositeImage(image,texture_image,image->compose,
2429 MagickFalse,x+texture_image->tile_offset.x,y+
2430 texture_image->tile_offset.y,exception);
2431 if (thread_status == MagickFalse)
2433 status=thread_status;
2437 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2442 #if defined(MAGICKCORE_OPENMP_SUPPORT) && defined(NoBenefitFromParallelism)
2443 #pragma omp critical (MagickCore_TextureImage)
2445 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2447 if (proceed == MagickFalse)
2451 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2452 image->rows,image->rows);
2453 texture_image=DestroyImage(texture_image);
2457 Tile texture onto the image background (optimized).
2460 texture_view=AcquireVirtualCacheView(texture_image,exception);
2461 image_view=AcquireAuthenticCacheView(image,exception);
2462 #if defined(MAGICKCORE_OPENMP_SUPPORT) && defined(NoBenefitFromParallelism)
2463 #pragma omp parallel for schedule(static,4) shared(status) \
2464 dynamic_number_threads(image,image->columns,image->rows,1)
2466 for (y=0; y < (ssize_t) image->rows; y++)
2471 register const Quantum
2484 if (status == MagickFalse)
2486 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2487 (y+texture_image->tile_offset.y) % texture_image->rows,
2488 texture_image->columns,1,exception);
2489 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2490 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2495 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2501 width=texture_image->columns;
2502 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2503 width=image->columns-x;
2504 for (j=0; j < (ssize_t) width; j++)
2509 if (GetPixelMask(image,p) != 0)
2511 p+=GetPixelChannels(texture_image);
2512 q+=GetPixelChannels(image);
2515 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2524 channel=GetPixelChannelChannel(texture_image,i);
2525 texture_traits=GetPixelChannelTraits(texture_image,channel);
2526 traits=GetPixelChannelTraits(image,channel);
2527 if ((traits == UndefinedPixelTrait) ||
2528 (texture_traits == UndefinedPixelTrait))
2530 SetPixelChannel(image,channel,p[i],q);
2532 p+=GetPixelChannels(texture_image);
2533 q+=GetPixelChannels(image);
2536 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2537 if (sync == MagickFalse)
2539 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2544 #if defined(MAGICKCORE_OPENMP_SUPPORT) && defined(NoBenefitFromParallelism)
2545 #pragma omp critical (MagickCore_TextureImage)
2547 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2549 if (proceed == MagickFalse)
2553 texture_view=DestroyCacheView(texture_view);
2554 image_view=DestroyCacheView(image_view);
2555 texture_image=DestroyImage(texture_image);