2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % CCCC OOO M M PPPP OOO SSSSS IIIII TTTTT EEEEE %
7 % C O O MM MM P P O O SS I T E %
8 % C O O M M M PPPP O O SSS I T EEE %
9 % C O O M M P O O SS I T E %
10 % CCCC OOO M M P OOO SSSSS IIIII T EEEEE %
13 % MagickCore Image Composite Methods %
20 % Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/artifact.h"
45 #include "MagickCore/cache.h"
46 #include "MagickCore/cache-private.h"
47 #include "MagickCore/cache-view.h"
48 #include "MagickCore/client.h"
49 #include "MagickCore/color.h"
50 #include "MagickCore/color-private.h"
51 #include "MagickCore/colorspace.h"
52 #include "MagickCore/colorspace-private.h"
53 #include "MagickCore/composite.h"
54 #include "MagickCore/composite-private.h"
55 #include "MagickCore/constitute.h"
56 #include "MagickCore/draw.h"
57 #include "MagickCore/fx.h"
58 #include "MagickCore/gem.h"
59 #include "MagickCore/geometry.h"
60 #include "MagickCore/image.h"
61 #include "MagickCore/image-private.h"
62 #include "MagickCore/list.h"
63 #include "MagickCore/log.h"
64 #include "MagickCore/monitor.h"
65 #include "MagickCore/monitor-private.h"
66 #include "MagickCore/memory_.h"
67 #include "MagickCore/option.h"
68 #include "MagickCore/pixel-accessor.h"
69 #include "MagickCore/property.h"
70 #include "MagickCore/quantum.h"
71 #include "MagickCore/resample.h"
72 #include "MagickCore/resource_.h"
73 #include "MagickCore/string_.h"
74 #include "MagickCore/thread-private.h"
75 #include "MagickCore/threshold.h"
76 #include "MagickCore/token.h"
77 #include "MagickCore/utility.h"
78 #include "MagickCore/utility-private.h"
79 #include "MagickCore/version.h"
82 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
86 % C o m p o s i t e I m a g e %
90 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
92 % CompositeImage() returns the second image composited onto the first
93 % at the specified offset, using the specified composite method.
95 % The format of the CompositeImage method is:
97 % MagickBooleanType CompositeImage(Image *image,
98 % const Image *composite_image,const CompositeOperator compose,
99 % const MagickBooleanType clip_to_self,const ssize_t x_offset,
100 % const ssize_t y_offset,ExceptionInfo *exception)
102 % A description of each parameter follows:
104 % o image: the destination image, modified by he composition
106 % o composite_image: the composite (source) image.
108 % o compose: This operator affects how the composite is applied to
109 % the image. The operators and how they are utilized are listed here
110 % http://www.w3.org/TR/SVG12/#compositing.
112 % o clip_to_self: set to MagickTrue to limit composition to area composed.
114 % o x_offset: the column offset of the composited image.
116 % o y_offset: the row offset of the composited image.
118 % Extra Controls from Image meta-data in 'composite_image' (artifacts)
121 % A string containing extra numerical arguments for specific compose
122 % methods, generally expressed as a 'geometry' or a comma separated list
125 % Compose methods needing such arguments include "BlendCompositeOp" and
126 % "DisplaceCompositeOp".
128 % o exception: return any errors or warnings in this structure.
133 Composition based on the SVG specification:
135 A Composition is defined by...
136 Color Function : f(Sc,Dc) where Sc and Dc are the normizalized colors
137 Blending areas : X = 1 for area of overlap, ie: f(Sc,Dc)
138 Y = 1 for source preserved
139 Z = 1 for destination preserved
141 Conversion to transparency (then optimized)
142 Dca' = f(Sc, Dc)*Sa*Da + Y*Sca*(1-Da) + Z*Dca*(1-Sa)
143 Da' = X*Sa*Da + Y*Sa*(1-Da) + Z*Da*(1-Sa)
146 Sca = Sc*Sa normalized Source color divided by Source alpha
147 Dca = Dc*Da normalized Dest color divided by Dest alpha
148 Dc' = Dca'/Da' the desired color value for this channel.
150 Da' in in the follow formula as 'gamma' The resulting alpla value.
152 Most functions use a blending mode of over (X=1,Y=1,Z=1) this results in
153 the following optimizations...
155 gamma = 1 - QuantiumScale*alpha * QuantiumScale*beta;
156 opacity = QuantiumScale*alpha*beta; // over blend, optimized 1-Gamma
158 The above SVG definitions also definate that Mathematical Composition
159 methods should use a 'Over' blending mode for Alpha Channel.
160 It however was not applied for composition modes of 'Plus', 'Minus',
161 the modulus versions of 'Add' and 'Subtract'.
163 Mathematical operator changes to be applied from IM v6.7...
165 1) Modulus modes 'Add' and 'Subtract' are obsoleted and renamed
166 'ModulusAdd' and 'ModulusSubtract' for clarity.
168 2) All mathematical compositions work as per the SVG specification
169 with regard to blending. This now includes 'ModulusAdd' and
172 3) When the special channel flag 'sync' (syncronize channel updates)
173 is turned off (enabled by default) then mathematical compositions are
174 only performed on the channels specified, and are applied
175 independantally of each other. In other words the mathematics is
176 performed as 'pure' mathematical operations, rather than as image
180 static inline MagickRealType MagickMin(const MagickRealType x,
181 const MagickRealType y)
188 static inline MagickRealType MagickMax(const MagickRealType x,
189 const MagickRealType y)
196 static inline MagickRealType ConvertHueToRGB(MagickRealType m1,
197 MagickRealType m2,MagickRealType hue)
204 return(m1+6.0*(m2-m1)*hue);
208 return(m1+6.0*(m2-m1)*(2.0/3.0-hue));
212 static void HCLComposite(const MagickRealType hue,const MagickRealType chroma,
213 const MagickRealType luma,MagickRealType *red,MagickRealType *green,
214 MagickRealType *blue)
227 Convert HCL to RGB colorspace.
229 assert(red != (MagickRealType *) NULL);
230 assert(green != (MagickRealType *) NULL);
231 assert(blue != (MagickRealType *) NULL);
234 x=c*(1.0-fabs(fmod(h,2.0)-1.0));
238 if ((0.0 <= h) && (h < 1.0))
244 if ((1.0 <= h) && (h < 2.0))
250 if ((2.0 <= h) && (h < 3.0))
256 if ((3.0 <= h) && (h < 4.0))
262 if ((4.0 <= h) && (h < 5.0))
268 if ((5.0 <= h) && (h < 6.0))
273 m=luma-(0.298839f*r+0.586811f*g+0.114350f*b);
275 Choose saturation strategy to clip it into the RGB cube; hue and luma are
276 preserved and chroma may be changed.
287 z=(1.0-luma)/(m+c-luma);
290 *red=QuantumRange*(z*r+m);
291 *green=QuantumRange*(z*g+m);
292 *blue=QuantumRange*(z*b+m);
295 static void CompositeHCL(const MagickRealType red,const MagickRealType green,
296 const MagickRealType blue,MagickRealType *hue,MagickRealType *chroma,
297 MagickRealType *luma)
308 Convert RGB to HCL colorspace.
310 assert(hue != (MagickRealType *) NULL);
311 assert(chroma != (MagickRealType *) NULL);
312 assert(luma != (MagickRealType *) NULL);
316 max=MagickMax(r,MagickMax(g,b));
317 c=max-(MagickRealType) MagickMin(r,MagickMin(g,b));
323 h=fmod(6.0+(g-b)/c,6.0);
331 *chroma=QuantumScale*c;
332 *luma=QuantumScale*(0.298839f*r+0.586811f*g+0.114350f*b);
335 static MagickBooleanType CompositeOverImage(Image *image,
336 const Image *composite_image,const MagickBooleanType clip_to_self,
337 const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
339 #define CompositeImageTag "Composite/Image"
359 composite_view=AcquireVirtualCacheView(composite_image,exception);
360 image_view=AcquireAuthenticCacheView(image,exception);
361 #if defined(MAGICKCORE_OPENMP_SUPPORT)
362 #pragma omp parallel for schedule(static,4) shared(progress,status) \
363 dynamic_number_threads(composite_image,image,image->rows,1)
365 for (y=0; y < (ssize_t) image->rows; y++)
370 register const Quantum
382 if (status == MagickFalse)
384 if (clip_to_self != MagickFalse)
388 if ((y-y_offset) >= (ssize_t) composite_image->rows)
392 If pixels is NULL, y is outside overlay region.
394 pixels=(Quantum *) NULL;
396 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
398 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
399 composite_image->columns,1,exception);
400 if (p == (const Quantum *) NULL)
407 p-=x_offset*GetPixelChannels(composite_image);
409 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
410 if (q == (Quantum *) NULL)
415 for (x=0; x < (ssize_t) image->columns; x++)
428 if (clip_to_self != MagickFalse)
432 q+=GetPixelChannels(image);
435 if ((x-x_offset) >= (ssize_t) composite_image->columns)
438 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
439 ((x-x_offset) >= (ssize_t) composite_image->columns))
442 source[MaxPixelChannels];
447 Dc: destination color.
449 if (GetPixelMask(image,q) != 0)
451 q+=GetPixelChannels(image);
454 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
456 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
465 channel=GetPixelChannelChannel(image,i);
466 traits=GetPixelChannelTraits(image,channel);
467 composite_traits=GetPixelChannelTraits(composite_image,channel);
468 if ((traits == UndefinedPixelTrait) ||
469 (composite_traits == UndefinedPixelTrait))
471 q[i]=source[channel];
473 q+=GetPixelChannels(image);
478 Sa: normalized source alpha.
479 Da: normalized destination alpha.
481 if (GetPixelMask(composite_image,p) != 0)
483 p+=GetPixelChannels(composite_image);
484 channels=GetPixelChannels(composite_image);
485 if (p >= (pixels+channels*composite_image->columns))
487 q+=GetPixelChannels(image);
490 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
491 Da=QuantumScale*GetPixelAlpha(image,q);
492 alpha=Sa*(-Da)+Sa+Da;
493 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
502 channel=GetPixelChannelChannel(image,i);
503 traits=GetPixelChannelTraits(image,channel);
504 composite_traits=GetPixelChannelTraits(composite_image,channel);
505 if ((traits == UndefinedPixelTrait) ||
506 (composite_traits == UndefinedPixelTrait))
508 if ((traits & CopyPixelTrait) != 0)
510 if (channel != AlphaPixelChannel)
515 q[i]=GetPixelChannel(composite_image,channel,p);
521 q[i]=ClampToQuantum(QuantumRange*alpha);
526 Dc: destination color.
528 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
529 Dc=(MagickRealType) q[i];
530 gamma=PerceptibleReciprocal(alpha);
531 q[i]=ClampToQuantum(gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc));
533 p+=GetPixelChannels(composite_image);
534 channels=GetPixelChannels(composite_image);
535 if (p >= (pixels+channels*composite_image->columns))
537 q+=GetPixelChannels(image);
539 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
541 if (image->progress_monitor != (MagickProgressMonitor) NULL)
546 #if defined(MAGICKCORE_OPENMP_SUPPORT)
547 #pragma omp critical (MagickCore_CompositeImage)
549 proceed=SetImageProgress(image,CompositeImageTag,progress++,
551 if (proceed == MagickFalse)
555 composite_view=DestroyCacheView(composite_view);
556 image_view=DestroyCacheView(image_view);
560 MagickExport MagickBooleanType CompositeImage(Image *image,
561 const Image *composite,const CompositeOperator compose,
562 const MagickBooleanType clip_to_self,const ssize_t x_offset,
563 const ssize_t y_offset,ExceptionInfo *exception)
565 #define CompositeImageTag "Composite/Image"
586 destination_dissolve,
599 assert(image != (Image *) NULL);
600 assert(image->signature == MagickSignature);
601 if (image->debug != MagickFalse)
602 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
603 assert(composite!= (Image *) NULL);
604 assert(composite->signature == MagickSignature);
605 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
607 composite_image=CloneImage(composite,0,0,MagickTrue,exception);
608 if (composite_image == (const Image *) NULL)
610 if (IsGrayColorspace(image->colorspace) != MagickFalse)
611 (void) SetImageColorspace(image,RGBColorspace,exception);
612 (void) SetImageColorspace(composite_image,image->colorspace,exception);
613 if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
615 status=CompositeOverImage(image,composite_image,clip_to_self,x_offset,
617 composite_image=DestroyImage(composite_image);
620 destination_image=(Image *) NULL;
622 destination_dissolve=1.0;
624 percent_chroma=100.0;
629 case CopyCompositeOp:
631 if ((x_offset < 0) || (y_offset < 0))
633 if ((x_offset+(ssize_t) composite_image->columns) >= (ssize_t) image->columns)
635 if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
638 composite_view=AcquireVirtualCacheView(composite_image,exception);
639 image_view=AcquireAuthenticCacheView(image,exception);
640 #if defined(MAGICKCORE_OPENMP_SUPPORT)
641 #pragma omp parallel for schedule(static,4) shared(status) \
642 dynamic_number_threads(composite_image,image,composite_image->rows,1)
644 for (y=0; y < (ssize_t) composite_image->rows; y++)
649 register const Quantum
658 if (status == MagickFalse)
660 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
662 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
663 composite_image->columns,1,exception);
664 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
669 for (x=0; x < (ssize_t) composite_image->columns; x++)
674 if (GetPixelMask(composite_image,p) != 0)
676 p+=GetPixelChannels(composite_image);
677 q+=GetPixelChannels(image);
680 for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
689 channel=GetPixelChannelChannel(composite_image,i);
690 composite_traits=GetPixelChannelTraits(composite_image,channel);
691 traits=GetPixelChannelTraits(image,channel);
692 if ((traits == UndefinedPixelTrait) ||
693 (composite_traits == UndefinedPixelTrait))
695 SetPixelChannel(image,channel,p[i],q);
697 p+=GetPixelChannels(composite_image);
698 q+=GetPixelChannels(image);
700 sync=SyncCacheViewAuthenticPixels(image_view,exception);
701 if (sync == MagickFalse)
703 if (image->progress_monitor != (MagickProgressMonitor) NULL)
708 #if defined(MAGICKCORE_OPENMP_SUPPORT)
709 #pragma omp critical (MagickCore_CompositeImage)
711 proceed=SetImageProgress(image,CompositeImageTag,
712 (MagickOffsetType) y,image->rows);
713 if (proceed == MagickFalse)
717 composite_view=DestroyCacheView(composite_view);
718 image_view=DestroyCacheView(image_view);
719 composite_image=DestroyImage(composite_image);
722 case CopyAlphaCompositeOp:
723 case ChangeMaskCompositeOp:
724 case IntensityCompositeOp:
727 Modify destination outside the overlaid region and require an alpha
728 channel to exist, to add transparency.
730 if (image->alpha_trait != BlendPixelTrait)
731 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
734 case BlurCompositeOp:
759 Blur Image by resampling.
761 Blur Image dictated by an overlay gradient map: X = red_channel;
762 Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
764 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
766 if (destination_image == (Image *) NULL)
768 composite_image=DestroyImage(composite_image);
772 Gather the maximum blur sigma values from user.
774 SetGeometryInfo(&geometry_info);
776 value=GetImageArtifact(composite_image,"compose:args");
777 if (value != (char *) NULL)
778 flags=ParseGeometry(value,&geometry_info);
779 if ((flags & WidthValue) == 0 ) {
780 (void) ThrowMagickException(exception,GetMagickModule(),
781 OptionWarning,"InvalidSetting","'%s' '%s'",
782 "compose:args",value);
783 composite_image=DestroyImage(composite_image);
784 destination_image=DestroyImage(destination_image);
788 Users input sigma now needs to be converted to the EWA ellipse size.
789 The filter defaults to a sigma of 0.5 so to make this match the
790 users input the ellipse size needs to be doubled.
792 width=height=geometry_info.rho*2.0;
793 if ((flags & HeightValue) != 0 )
794 height=geometry_info.sigma*2.0;
796 Default the unrotated ellipse width and height axis vectors.
802 /* rotate vectors if a rotation angle is given */
803 if ((flags & XValue) != 0 )
808 angle=DegreesToRadians(geometry_info.xi);
809 blur.x1=width*cos(angle);
810 blur.x2=width*sin(angle);
811 blur.y1=(-height*sin(angle));
812 blur.y2=height*cos(angle);
814 /* Otherwise lets set a angle range and calculate in the loop */
817 if ((flags & YValue) != 0 )
819 angle_start=DegreesToRadians(geometry_info.xi);
820 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
823 Set up a gaussian cylindrical filter for EWA Bluring.
825 As the minimum ellipse radius of support*1.0 the EWA algorithm
826 can only produce a minimum blur of 0.5 for Gaussian (support=2.0)
827 This means that even 'No Blur' will be still a little blurry!
829 The solution (as well as the problem of preventing any user
830 expert filter settings, is to set our own user settings, then
831 restore them afterwards.
833 resample_filter=AcquireResampleFilter(image,exception);
834 SetResampleFilter(resample_filter,GaussianFilter);
836 /* do the variable blurring of each pixel in image */
837 GetPixelInfo(image,&pixel);
838 composite_view=AcquireVirtualCacheView(composite_image,exception);
839 destination_view=AcquireAuthenticCacheView(destination_image,exception);
840 for (y=0; y < (ssize_t) composite_image->rows; y++)
845 register const Quantum
854 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
856 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
858 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
859 destination_image->columns,1,exception);
860 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
862 for (x=0; x < (ssize_t) composite_image->columns; x++)
864 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
866 p+=GetPixelChannels(composite_image);
869 if (fabs(angle_range) > MagickEpsilon)
874 angle=angle_start+angle_range*QuantumScale*
875 GetPixelBlue(composite_image,p);
876 blur.x1=width*cos(angle);
877 blur.x2=width*sin(angle);
878 blur.y1=(-height*sin(angle));
879 blur.y2=height*cos(angle);
882 if ( x == 10 && y == 60 ) {
883 (void) fprintf(stderr, "blur.x=%lf,%lf, blur.y=%lf,%lf\n",blur.x1,
884 blur.x2,blur.y1, blur.y2);
885 (void) fprintf(stderr, "scaled by=%lf,%lf\n",QuantumScale*
886 GetPixelRed(p),QuantumScale*GetPixelGreen(p));
888 ScaleResampleFilter(resample_filter,
889 blur.x1*QuantumScale*GetPixelRed(composite_image,p),
890 blur.y1*QuantumScale*GetPixelGreen(composite_image,p),
891 blur.x2*QuantumScale*GetPixelRed(composite_image,p),
892 blur.y2*QuantumScale*GetPixelGreen(composite_image,p) );
893 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
894 (double) y_offset+y,&pixel,exception);
895 SetPixelInfoPixel(destination_image,&pixel,q);
896 p+=GetPixelChannels(composite_image);
897 q+=GetPixelChannels(destination_image);
899 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
900 if (sync == MagickFalse)
903 resample_filter=DestroyResampleFilter(resample_filter);
904 composite_view=DestroyCacheView(composite_view);
905 destination_view=DestroyCacheView(destination_view);
906 composite_image=DestroyImage(composite_image);
907 composite_image=destination_image;
910 case DisplaceCompositeOp:
911 case DistortCompositeOp:
933 Displace/Distort based on overlay gradient map:
934 X = red_channel; Y = green_channel;
935 compose:args = x_scale[,y_scale[,center.x,center.y]]
937 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
939 if (destination_image == (Image *) NULL)
941 composite_image=DestroyImage(composite_image);
944 SetGeometryInfo(&geometry_info);
946 value=GetImageArtifact(composite_image,"compose:args");
947 if (value != (char *) NULL)
948 flags=ParseGeometry(value,&geometry_info);
949 if ((flags & (WidthValue|HeightValue)) == 0 )
951 if ((flags & AspectValue) == 0)
953 horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
955 vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
959 horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
960 vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
965 horizontal_scale=geometry_info.rho;
966 vertical_scale=geometry_info.sigma;
967 if ((flags & PercentValue) != 0)
969 if ((flags & AspectValue) == 0)
971 horizontal_scale*=(composite_image->columns-1.0)/200.0;
972 vertical_scale*=(composite_image->rows-1.0)/200.0;
976 horizontal_scale*=(image->columns-1.0)/200.0;
977 vertical_scale*=(image->rows-1.0)/200.0;
980 if ((flags & HeightValue) == 0)
981 vertical_scale=horizontal_scale;
984 Determine fixed center point for absolute distortion map
986 Displace offset relative to a fixed absolute point
987 Select that point according to +X+Y user inputs.
988 default = center of overlay image
989 arg flag '!' = locations/percentage relative to background image
991 center.x=(MagickRealType) x_offset;
992 center.y=(MagickRealType) y_offset;
993 if (compose == DistortCompositeOp)
995 if ((flags & XValue) == 0)
996 if ((flags & AspectValue) == 0)
997 center.x=(MagickRealType) (x_offset+(composite_image->columns-1)/
1000 center.x=(MagickRealType) ((image->columns-1)/2);
1002 if ((flags & AspectValue) == 0)
1003 center.x=(MagickRealType) x_offset+geometry_info.xi;
1005 center.x=geometry_info.xi;
1006 if ((flags & YValue) == 0)
1007 if ((flags & AspectValue) == 0)
1008 center.y=(MagickRealType) (y_offset+(composite_image->rows-1)/
1011 center.y=(MagickRealType) ((image->rows-1)/2);
1013 if ((flags & AspectValue) == 0)
1014 center.y=(MagickRealType) y_offset+geometry_info.psi;
1016 center.y=geometry_info.psi;
1019 Shift the pixel offset point as defined by the provided,
1020 displacement/distortion map. -- Like a lens...
1022 GetPixelInfo(image,&pixel);
1023 image_view=AcquireVirtualCacheView(image,exception);
1024 composite_view=AcquireVirtualCacheView(composite_image,exception);
1025 destination_view=AcquireAuthenticCacheView(destination_image,exception);
1026 for (y=0; y < (ssize_t) composite_image->rows; y++)
1031 register const Quantum
1040 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1042 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
1044 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
1045 destination_image->columns,1,exception);
1046 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1048 for (x=0; x < (ssize_t) composite_image->columns; x++)
1050 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1052 p+=GetPixelChannels(composite_image);
1056 Displace the offset.
1058 offset.x=(double) (horizontal_scale*(GetPixelRed(composite_image,p)-
1059 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1060 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
1062 offset.y=(double) (vertical_scale*(GetPixelGreen(composite_image,p)-
1063 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1064 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
1066 (void) InterpolatePixelInfo(image,image_view,
1067 UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1070 Mask with the 'invalid pixel mask' in alpha channel.
1072 pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
1073 pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
1074 SetPixelInfoPixel(destination_image,&pixel,q);
1075 p+=GetPixelChannels(composite_image);
1076 q+=GetPixelChannels(destination_image);
1078 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1079 if (sync == MagickFalse)
1082 destination_view=DestroyCacheView(destination_view);
1083 composite_view=DestroyCacheView(composite_view);
1084 image_view=DestroyCacheView(image_view);
1085 composite_image=DestroyImage(composite_image);
1086 composite_image=destination_image;
1089 case DissolveCompositeOp:
1095 Geometry arguments to dissolve factors.
1097 value=GetImageArtifact(composite_image,"compose:args");
1098 if (value != (char *) NULL)
1100 flags=ParseGeometry(value,&geometry_info);
1101 source_dissolve=geometry_info.rho/100.0;
1102 destination_dissolve=1.0;
1103 if ((source_dissolve-MagickEpsilon) < 0.0)
1104 source_dissolve=0.0;
1105 if ((source_dissolve+MagickEpsilon) > 1.0)
1107 destination_dissolve=2.0-source_dissolve;
1108 source_dissolve=1.0;
1110 if ((flags & SigmaValue) != 0)
1111 destination_dissolve=geometry_info.sigma/100.0;
1112 if ((destination_dissolve-MagickEpsilon) < 0.0)
1113 destination_dissolve=0.0;
1114 /* posible speed up? -- from IMv6 update
1115 clip_to_self=MagickFalse;
1116 if ((destination_dissolve+MagickEpsilon) > 1.0 )
1118 destination_dissolve=1.0;
1119 clip_to_self=MagickTrue;
1125 case BlendCompositeOp:
1130 value=GetImageArtifact(composite_image,"compose:args");
1131 if (value != (char *) NULL)
1133 flags=ParseGeometry(value,&geometry_info);
1134 source_dissolve=geometry_info.rho/100.0;
1135 destination_dissolve=1.0-source_dissolve;
1136 if ((flags & SigmaValue) != 0)
1137 destination_dissolve=geometry_info.sigma/100.0;
1141 case MathematicsCompositeOp:
1147 Just collect the values from "compose:args", setting.
1148 Unused values are set to zero automagically.
1150 Arguments are normally a comma separated list, so this probably should
1151 be changed to some 'general comma list' parser, (with a minimum
1154 SetGeometryInfo(&geometry_info);
1155 value=GetImageArtifact(composite_image,"compose:args");
1156 if (value != (char *) NULL)
1157 (void) ParseGeometry(value,&geometry_info);
1160 case ModulateCompositeOp:
1166 Determine the luma and chroma scale.
1168 value=GetImageArtifact(composite_image,"compose:args");
1169 if (value != (char *) NULL)
1171 flags=ParseGeometry(value,&geometry_info);
1172 percent_luma=geometry_info.rho;
1173 if ((flags & SigmaValue) != 0)
1174 percent_chroma=geometry_info.sigma;
1178 case ThresholdCompositeOp:
1184 Determine the amount and threshold.
1186 value=GetImageArtifact(composite_image,"compose:args");
1187 if (value != (char *) NULL)
1189 flags=ParseGeometry(value,&geometry_info);
1190 amount=geometry_info.rho;
1191 threshold=geometry_info.sigma;
1192 if ((flags & SigmaValue) == 0)
1195 threshold*=QuantumRange;
1206 midpoint=((MagickRealType) QuantumRange+1.0)/2;
1207 composite_view=AcquireVirtualCacheView(composite_image,exception);
1208 image_view=AcquireAuthenticCacheView(image,exception);
1209 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1210 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1211 dynamic_number_threads(composite_image,image,image->rows,1)
1213 for (y=0; y < (ssize_t) image->rows; y++)
1230 register const Quantum
1239 if (status == MagickFalse)
1241 if (clip_to_self != MagickFalse)
1245 if ((y-y_offset) >= (ssize_t) composite_image->rows)
1249 If pixels is NULL, y is outside overlay region.
1251 pixels=(Quantum *) NULL;
1253 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
1255 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
1256 composite_image->columns,1,exception);
1257 if (p == (const Quantum *) NULL)
1264 p-=x_offset*GetPixelChannels(composite_image);
1266 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1267 if (q == (Quantum *) NULL)
1275 GetPixelInfo(image,&destination_pixel);
1276 GetPixelInfo(composite_image,&source_pixel);
1277 for (x=0; x < (ssize_t) image->columns; x++)
1295 if (clip_to_self != MagickFalse)
1299 q+=GetPixelChannels(image);
1302 if ((x-x_offset) >= (ssize_t) composite_image->columns)
1305 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1306 ((x-x_offset) >= (ssize_t) composite_image->columns))
1309 source[MaxPixelChannels];
1314 Dc: destination color.
1316 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
1318 if (GetPixelMask(image,q) != 0)
1320 q+=GetPixelChannels(image);
1323 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1335 channel=GetPixelChannelChannel(image,i);
1336 traits=GetPixelChannelTraits(image,channel);
1337 composite_traits=GetPixelChannelTraits(composite_image,channel);
1338 if ((traits == UndefinedPixelTrait) ||
1339 (composite_traits == UndefinedPixelTrait))
1343 case AlphaCompositeOp:
1344 case ChangeMaskCompositeOp:
1345 case CopyAlphaCompositeOp:
1346 case DstAtopCompositeOp:
1347 case DstInCompositeOp:
1349 case IntensityCompositeOp:
1350 case OutCompositeOp:
1351 case SrcInCompositeOp:
1352 case SrcOutCompositeOp:
1354 pixel=(MagickRealType) q[i];
1355 if (channel == AlphaPixelChannel)
1356 pixel=(MagickRealType) TransparentAlpha;
1359 case ClearCompositeOp:
1360 case CopyCompositeOp:
1361 case ReplaceCompositeOp:
1362 case SrcCompositeOp:
1364 if (channel == AlphaPixelChannel)
1366 pixel=(MagickRealType) TransparentAlpha;
1372 case BlendCompositeOp:
1373 case DissolveCompositeOp:
1375 if (channel == AlphaPixelChannel)
1377 pixel=destination_dissolve*GetPixelAlpha(composite_image,
1381 pixel=(MagickRealType) source[channel];
1386 pixel=(MagickRealType) source[channel];
1390 q[i]=ClampToQuantum(pixel);
1392 q+=GetPixelChannels(image);
1396 Authentic composite:
1397 Sa: normalized source alpha.
1398 Da: normalized destination alpha.
1400 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
1401 Da=QuantumScale*GetPixelAlpha(image,q);
1404 case BumpmapCompositeOp:
1406 alpha=GetPixelIntensity(composite_image,p)*Sa;
1409 case ColorBurnCompositeOp:
1410 case ColorDodgeCompositeOp:
1411 case DifferenceCompositeOp:
1412 case DivideDstCompositeOp:
1413 case DivideSrcCompositeOp:
1414 case ExclusionCompositeOp:
1415 case HardLightCompositeOp:
1416 case LinearBurnCompositeOp:
1417 case LinearDodgeCompositeOp:
1418 case LinearLightCompositeOp:
1419 case MathematicsCompositeOp:
1420 case MinusDstCompositeOp:
1421 case MinusSrcCompositeOp:
1422 case ModulusAddCompositeOp:
1423 case ModulusSubtractCompositeOp:
1424 case MultiplyCompositeOp:
1425 case OverlayCompositeOp:
1426 case PegtopLightCompositeOp:
1427 case PinLightCompositeOp:
1428 case ScreenCompositeOp:
1429 case SoftLightCompositeOp:
1430 case VividLightCompositeOp:
1432 alpha=RoundToUnity(Sa+Da-Sa*Da);
1435 case DarkenCompositeOp:
1436 case DstAtopCompositeOp:
1437 case DstInCompositeOp:
1439 case LightenCompositeOp:
1440 case SrcInCompositeOp:
1445 case DissolveCompositeOp:
1447 alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
1448 Sa+destination_dissolve*Da;
1451 case DstOverCompositeOp:
1453 alpha=Da*(-Sa)+Da+Sa;
1456 case DstOutCompositeOp:
1461 case OutCompositeOp:
1462 case SrcOutCompositeOp:
1467 case OverCompositeOp:
1468 case SrcOverCompositeOp:
1470 alpha=Sa*(-Da)+Sa+Da;
1473 case BlendCompositeOp:
1474 case PlusCompositeOp:
1476 alpha=RoundToUnity(Sa+Da);
1479 case XorCompositeOp:
1481 alpha=Sa+Da-2.0*Sa*Da;
1490 if (GetPixelMask(image,p) != 0)
1492 p+=GetPixelChannels(composite_image);
1493 q+=GetPixelChannels(image);
1498 case ColorizeCompositeOp:
1499 case HueCompositeOp:
1500 case LuminizeCompositeOp:
1501 case ModulateCompositeOp:
1502 case SaturateCompositeOp:
1504 GetPixelInfoPixel(composite_image,p,&source_pixel);
1505 GetPixelInfoPixel(image,q,&destination_pixel);
1511 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1524 channel=GetPixelChannelChannel(image,i);
1525 traits=GetPixelChannelTraits(image,channel);
1526 composite_traits=GetPixelChannelTraits(composite_image,channel);
1527 if (traits == UndefinedPixelTrait)
1529 if ((compose != IntensityCompositeOp) &&
1530 (composite_traits == UndefinedPixelTrait))
1534 Dc: destination color.
1536 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
1537 Dc=(MagickRealType) q[i];
1538 if ((traits & CopyPixelTrait) != 0)
1540 if (channel != AlphaPixelChannel)
1545 q[i]=ClampToQuantum(Sc);
1553 case AlphaCompositeOp:
1555 pixel=QuantumRange*Sa;
1558 case AtopCompositeOp:
1559 case CopyBlackCompositeOp:
1560 case CopyBlueCompositeOp:
1561 case CopyCyanCompositeOp:
1562 case CopyGreenCompositeOp:
1563 case CopyMagentaCompositeOp:
1564 case CopyRedCompositeOp:
1565 case CopyYellowCompositeOp:
1566 case SrcAtopCompositeOp:
1567 case DstCompositeOp:
1570 pixel=QuantumRange*Da;
1573 case ChangeMaskCompositeOp:
1578 if (Da > ((MagickRealType) QuantumRange/2.0))
1580 pixel=(MagickRealType) TransparentAlpha;
1583 equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
1584 if (equivalent != MagickFalse)
1586 pixel=(MagickRealType) TransparentAlpha;
1589 pixel=(MagickRealType) OpaqueAlpha;
1592 case ClearCompositeOp:
1594 pixel=(MagickRealType) TransparentAlpha;
1597 case ColorizeCompositeOp:
1598 case HueCompositeOp:
1599 case LuminizeCompositeOp:
1600 case SaturateCompositeOp:
1602 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1604 pixel=QuantumRange*Da;
1607 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1609 pixel=QuantumRange*Sa;
1614 pixel=QuantumRange*Da;
1617 pixel=QuantumRange*Sa;
1620 case CopyAlphaCompositeOp:
1622 pixel=QuantumRange*Sa;
1623 if (composite_image->alpha_trait != BlendPixelTrait)
1624 pixel=GetPixelIntensity(composite_image,p);
1627 case CopyCompositeOp:
1628 case DisplaceCompositeOp:
1629 case DistortCompositeOp:
1630 case DstAtopCompositeOp:
1631 case ReplaceCompositeOp:
1632 case SrcCompositeOp:
1634 pixel=QuantumRange*Sa;
1637 case DarkenIntensityCompositeOp:
1639 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1640 (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
1643 case IntensityCompositeOp:
1645 pixel=GetPixelIntensity(composite_image,p);
1648 case LightenIntensityCompositeOp:
1650 pixel=Sa*GetPixelIntensity(composite_image,p) >
1651 Da*GetPixelIntensity(image,q) ? Sa : Da;
1654 case ModulateCompositeOp:
1656 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1658 pixel=QuantumRange*Da;
1661 pixel=QuantumRange*Da;
1666 pixel=QuantumRange*alpha;
1670 q[i]=ClampToQuantum(pixel);
1674 Porter-Duff compositions:
1675 Sca: source normalized color multiplied by alpha.
1676 Dca: normalized destination color multiplied by alpha.
1678 Sca=QuantumScale*Sa*Sc;
1679 Dca=QuantumScale*Da*Dc;
1682 case DarkenCompositeOp:
1683 case LightenCompositeOp:
1684 case ModulusSubtractCompositeOp:
1692 gamma=PerceptibleReciprocal(alpha);
1696 case AlphaCompositeOp:
1698 pixel=QuantumRange*Sa;
1701 case AtopCompositeOp:
1702 case SrcAtopCompositeOp:
1704 pixel=Sc*Sa+Dc*(1.0-Sa);
1707 case BlendCompositeOp:
1709 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1712 case BlurCompositeOp:
1713 case DisplaceCompositeOp:
1714 case DistortCompositeOp:
1715 case CopyCompositeOp:
1716 case ReplaceCompositeOp:
1717 case SrcCompositeOp:
1722 case BumpmapCompositeOp:
1724 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1729 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1732 case ChangeMaskCompositeOp:
1737 case ClearCompositeOp:
1742 case ColorBurnCompositeOp:
1745 Refer to the March 2009 SVG specification.
1747 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1749 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1752 if (Sca < MagickEpsilon)
1754 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1757 pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
1758 Sca*(1.0-Da)+Dca*(1.0-Sa));
1761 case ColorDodgeCompositeOp:
1763 if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1765 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1768 if (fabs(Sca-Sa) < MagickEpsilon)
1770 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1773 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1777 case ColorizeCompositeOp:
1779 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1784 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1789 CompositeHCL(destination_pixel.red,destination_pixel.green,
1790 destination_pixel.blue,&sans,&sans,&luma);
1791 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1792 &hue,&chroma,&sans);
1793 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1796 case RedPixelChannel: pixel=red; break;
1797 case GreenPixelChannel: pixel=green; break;
1798 case BluePixelChannel: pixel=blue; break;
1799 default: pixel=Dc; break;
1803 case CopyAlphaCompositeOp:
1804 case IntensityCompositeOp:
1809 case CopyBlackCompositeOp:
1811 if (channel == BlackPixelChannel)
1812 pixel=(MagickRealType) GetPixelBlack(composite_image,p);
1815 case CopyBlueCompositeOp:
1816 case CopyYellowCompositeOp:
1818 if (channel == BluePixelChannel)
1819 pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1822 case CopyGreenCompositeOp:
1823 case CopyMagentaCompositeOp:
1825 if (channel == GreenPixelChannel)
1826 pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1829 case CopyRedCompositeOp:
1830 case CopyCyanCompositeOp:
1832 if (channel == RedPixelChannel)
1833 pixel=(MagickRealType) GetPixelRed(composite_image,p);
1836 case DarkenCompositeOp:
1839 Darken is equivalent to a 'Minimum' method
1840 OR a greyscale version of a binary 'Or'
1841 OR the 'Intersection' of pixel sets.
1845 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1848 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1851 case DarkenIntensityCompositeOp:
1853 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1854 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1857 case DifferenceCompositeOp:
1859 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1862 case DissolveCompositeOp:
1864 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1865 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1868 case DivideDstCompositeOp:
1870 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1872 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1875 if (fabs(Dca) < MagickEpsilon)
1877 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1880 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1883 case DivideSrcCompositeOp:
1885 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1887 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1890 if (fabs(Sca) < MagickEpsilon)
1892 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1895 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1898 case DstAtopCompositeOp:
1900 pixel=Dc*Da+Sc*(1.0-Da);
1903 case DstCompositeOp:
1909 case DstInCompositeOp:
1911 pixel=gamma*(Sa*Dc*Sa);
1914 case DstOutCompositeOp:
1916 pixel=gamma*(Da*Dc*(1.0-Sa));
1919 case DstOverCompositeOp:
1921 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1924 case ExclusionCompositeOp:
1926 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1930 case HardLightCompositeOp:
1934 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1938 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1942 case HueCompositeOp:
1944 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1949 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1954 CompositeHCL(destination_pixel.red,destination_pixel.green,
1955 destination_pixel.blue,&hue,&chroma,&luma);
1956 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1958 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1961 case RedPixelChannel: pixel=red; break;
1962 case GreenPixelChannel: pixel=green; break;
1963 case BluePixelChannel: pixel=blue; break;
1964 default: pixel=Dc; break;
1969 case SrcInCompositeOp:
1971 pixel=gamma*(Da*Sc*Da);
1974 case LinearBurnCompositeOp:
1977 LinearBurn: as defined by Abode Photoshop, according to
1978 http://www.simplefilter.de/en/basics/mixmods.html is:
1980 f(Sc,Dc) = Sc + Dc - 1
1982 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1985 case LinearDodgeCompositeOp:
1987 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1990 case LinearLightCompositeOp:
1993 LinearLight: as defined by Abode Photoshop, according to
1994 http://www.simplefilter.de/en/basics/mixmods.html is:
1996 f(Sc,Dc) = Dc + 2*Sc - 1
1998 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
2001 case LightenCompositeOp:
2005 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2008 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
2011 case LightenIntensityCompositeOp:
2014 Lighten is equivalent to a 'Maximum' method
2015 OR a greyscale version of a binary 'And'
2016 OR the 'Union' of pixel sets.
2018 pixel=Sa*GetPixelIntensity(composite_image,p) >
2019 Da*GetPixelIntensity(image,q) ? Sc : Dc;
2022 case LuminizeCompositeOp:
2024 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2029 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2034 CompositeHCL(destination_pixel.red,destination_pixel.green,
2035 destination_pixel.blue,&hue,&chroma,&luma);
2036 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2038 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2041 case RedPixelChannel: pixel=red; break;
2042 case GreenPixelChannel: pixel=green; break;
2043 case BluePixelChannel: pixel=blue; break;
2044 default: pixel=Dc; break;
2048 case MathematicsCompositeOp:
2051 'Mathematics' a free form user control mathematical composition
2054 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
2056 Where the arguments A,B,C,D are (currently) passed to composite
2057 as a command separated 'geometry' string in "compose:args" image
2060 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
2062 Applying the SVG transparency formula (see above), we get...
2064 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
2066 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
2069 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
2070 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
2071 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
2074 case MinusDstCompositeOp:
2076 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2079 case MinusSrcCompositeOp:
2082 Minus source from destination.
2086 pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2089 case ModulateCompositeOp:
2094 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2099 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
2105 CompositeHCL(destination_pixel.red,destination_pixel.green,
2106 destination_pixel.blue,&hue,&chroma,&luma);
2107 luma+=(0.01*percent_luma*offset)/midpoint;
2108 chroma*=0.01*percent_chroma;
2109 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2112 case RedPixelChannel: pixel=red; break;
2113 case GreenPixelChannel: pixel=green; break;
2114 case BluePixelChannel: pixel=blue; break;
2115 default: pixel=Dc; break;
2119 case ModulusAddCompositeOp:
2122 if (pixel > QuantumRange)
2123 pixel-=(QuantumRange+1.0);
2124 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2127 case ModulusSubtractCompositeOp:
2131 pixel+=(QuantumRange+1.0);
2132 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2135 case MultiplyCompositeOp:
2137 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2140 case OutCompositeOp:
2141 case SrcOutCompositeOp:
2143 pixel=gamma*(Sa*Sc*(1.0-Da));
2146 case OverCompositeOp:
2147 case SrcOverCompositeOp:
2149 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2152 case OverlayCompositeOp:
2156 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2160 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2164 case PegtopLightCompositeOp:
2167 PegTop: A Soft-Light alternative: A continuous version of the
2168 Softlight function, producing very similar results.
2170 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2172 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2174 if (fabs(Da) < MagickEpsilon)
2176 pixel=QuantumRange*gamma*(Sca);
2179 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2183 case PinLightCompositeOp:
2186 PinLight: A Photoshop 7 composition method
2187 http://www.simplefilter.de/en/basics/mixmods.html
2189 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2191 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2193 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2196 if ((Dca*Sa) > (2.0*Sca*Da))
2198 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2201 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2204 case PlusCompositeOp:
2206 pixel=gamma*(Sa*Sc+Da*Dc);
2209 case SaturateCompositeOp:
2211 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2216 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2221 CompositeHCL(destination_pixel.red,destination_pixel.green,
2222 destination_pixel.blue,&hue,&chroma,&luma);
2223 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2224 &sans,&chroma,&sans);
2225 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2228 case RedPixelChannel: pixel=red; break;
2229 case GreenPixelChannel: pixel=green; break;
2230 case BluePixelChannel: pixel=blue; break;
2231 default: pixel=Dc; break;
2235 case ScreenCompositeOp:
2238 Screen: a negated multiply:
2240 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2242 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2245 case SoftLightCompositeOp:
2248 Refer to the March 2009 SVG specification.
2252 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2253 Sca*(1.0-Da)+Dca*(1.0-Sa));
2256 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2258 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2259 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2263 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2264 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2267 case ThresholdCompositeOp:
2273 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2278 pixel=gamma*(Dc+delta*amount);
2281 case VividLightCompositeOp:
2284 VividLight: A Photoshop 7 composition method. See
2285 http://www.simplefilter.de/en/basics/mixmods.html.
2287 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2289 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2291 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2294 if ((2.0*Sca) <= Sa)
2296 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2297 (1.0-Da)+Dca*(1.0-Sa));
2300 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2304 case XorCompositeOp:
2306 pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2315 q[i]=ClampToQuantum(pixel);
2317 p+=GetPixelChannels(composite_image);
2318 channels=GetPixelChannels(composite_image);
2319 if (p >= (pixels+channels*composite_image->columns))
2321 q+=GetPixelChannels(image);
2323 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2325 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2330 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2331 #pragma omp critical (MagickCore_CompositeImage)
2333 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2335 if (proceed == MagickFalse)
2339 composite_view=DestroyCacheView(composite_view);
2340 image_view=DestroyCacheView(image_view);
2341 if (destination_image != (Image * ) NULL)
2342 destination_image=DestroyImage(destination_image);
2344 composite_image=DestroyImage(composite_image);
2349 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2353 % T e x t u r e I m a g e %
2357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2359 % TextureImage() repeatedly tiles the texture image across and down the image
2362 % The format of the TextureImage method is:
2364 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2365 % ExceptionInfo *exception)
2367 % A description of each parameter follows:
2369 % o image: the image.
2371 % o texture_image: This image is the texture to layer on the background.
2374 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
2375 ExceptionInfo *exception)
2377 #define TextureImageTag "Texture/Image"
2392 assert(image != (Image *) NULL);
2393 if (image->debug != MagickFalse)
2394 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2395 assert(image->signature == MagickSignature);
2396 if (texture == (const Image *) NULL)
2397 return(MagickFalse);
2398 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2399 return(MagickFalse);
2400 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2401 if (texture_image == (const Image *) NULL)
2402 return(MagickFalse);
2403 (void) TransformImageColorspace(texture_image,image->colorspace,exception);
2404 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
2407 if ((image->compose != CopyCompositeOp) &&
2408 ((image->compose != OverCompositeOp) || (image->alpha_trait == BlendPixelTrait) ||
2409 (texture_image->alpha_trait == BlendPixelTrait)))
2412 Tile texture onto the image background.
2414 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2419 if (status == MagickFalse)
2421 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2426 thread_status=CompositeImage(image,texture_image,image->compose,
2427 MagickFalse,x+texture_image->tile_offset.x,y+
2428 texture_image->tile_offset.y,exception);
2429 if (thread_status == MagickFalse)
2431 status=thread_status;
2435 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2440 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2442 if (proceed == MagickFalse)
2446 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2447 image->rows,image->rows);
2448 texture_image=DestroyImage(texture_image);
2452 Tile texture onto the image background (optimized).
2455 texture_view=AcquireVirtualCacheView(texture_image,exception);
2456 image_view=AcquireAuthenticCacheView(image,exception);
2457 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2458 #pragma omp parallel for schedule(static,256) shared(status) \
2459 dynamic_number_threads(texture_image,image,image->rows,1)
2461 for (y=0; y < (ssize_t) image->rows; y++)
2466 register const Quantum
2479 if (status == MagickFalse)
2481 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2482 (y+texture_image->tile_offset.y) % texture_image->rows,
2483 texture_image->columns,1,exception);
2484 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2485 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2490 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2496 width=texture_image->columns;
2497 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2498 width=image->columns-x;
2499 for (j=0; j < (ssize_t) width; j++)
2504 if (GetPixelMask(image,p) != 0)
2506 p+=GetPixelChannels(texture_image);
2507 q+=GetPixelChannels(image);
2510 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2519 channel=GetPixelChannelChannel(texture_image,i);
2520 texture_traits=GetPixelChannelTraits(texture_image,channel);
2521 traits=GetPixelChannelTraits(image,channel);
2522 if ((traits == UndefinedPixelTrait) ||
2523 (texture_traits == UndefinedPixelTrait))
2525 SetPixelChannel(image,channel,p[i],q);
2527 p+=GetPixelChannels(texture_image);
2528 q+=GetPixelChannels(image);
2531 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2532 if (sync == MagickFalse)
2534 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2539 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2541 if (proceed == MagickFalse)
2545 texture_view=DestroyCacheView(texture_view);
2546 image_view=DestroyCacheView(image_view);
2547 texture_image=DestroyImage(texture_image);