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-2014 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/channel.h"
49 #include "MagickCore/client.h"
50 #include "MagickCore/color.h"
51 #include "MagickCore/color-private.h"
52 #include "MagickCore/colorspace.h"
53 #include "MagickCore/colorspace-private.h"
54 #include "MagickCore/composite.h"
55 #include "MagickCore/composite-private.h"
56 #include "MagickCore/constitute.h"
57 #include "MagickCore/draw.h"
58 #include "MagickCore/fx.h"
59 #include "MagickCore/gem.h"
60 #include "MagickCore/geometry.h"
61 #include "MagickCore/image.h"
62 #include "MagickCore/image-private.h"
63 #include "MagickCore/list.h"
64 #include "MagickCore/log.h"
65 #include "MagickCore/monitor.h"
66 #include "MagickCore/monitor-private.h"
67 #include "MagickCore/memory_.h"
68 #include "MagickCore/option.h"
69 #include "MagickCore/pixel-accessor.h"
70 #include "MagickCore/property.h"
71 #include "MagickCore/quantum.h"
72 #include "MagickCore/resample.h"
73 #include "MagickCore/resource_.h"
74 #include "MagickCore/string_.h"
75 #include "MagickCore/thread-private.h"
76 #include "MagickCore/threshold.h"
77 #include "MagickCore/token.h"
78 #include "MagickCore/utility.h"
79 #include "MagickCore/utility-private.h"
80 #include "MagickCore/version.h"
83 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
87 % C o m p o s i t e I m a g e %
91 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
93 % CompositeImage() returns the second image composited onto the first
94 % at the specified offset, using the specified composite method.
96 % The format of the CompositeImage method is:
98 % MagickBooleanType CompositeImage(Image *image,
99 % const Image *composite_image,const CompositeOperator compose,
100 % const MagickBooleanType clip_to_self,const ssize_t x_offset,
101 % const ssize_t y_offset,ExceptionInfo *exception)
103 % A description of each parameter follows:
105 % o image: the destination image, modified by he composition
107 % o composite_image: the composite (source) image.
109 % o compose: This operator affects how the composite is applied to
110 % the image. The operators and how they are utilized are listed here
111 % http://www.w3.org/TR/SVG12/#compositing.
113 % o clip_to_self: set to MagickTrue to limit composition to area composed.
115 % o x_offset: the column offset of the composited image.
117 % o y_offset: the row offset of the composited image.
119 % Extra Controls from Image meta-data in 'composite_image' (artifacts)
122 % A string containing extra numerical arguments for specific compose
123 % methods, generally expressed as a 'geometry' or a comma separated list
126 % Compose methods needing such arguments include "BlendCompositeOp" and
127 % "DisplaceCompositeOp".
129 % o exception: return any errors or warnings in this structure.
134 Composition based on the SVG specification:
136 A Composition is defined by...
137 Color Function : f(Sc,Dc) where Sc and Dc are the normizalized colors
138 Blending areas : X = 1 for area of overlap, ie: f(Sc,Dc)
139 Y = 1 for source preserved
140 Z = 1 for destination preserved
142 Conversion to transparency (then optimized)
143 Dca' = f(Sc, Dc)*Sa*Da + Y*Sca*(1-Da) + Z*Dca*(1-Sa)
144 Da' = X*Sa*Da + Y*Sa*(1-Da) + Z*Da*(1-Sa)
147 Sca = Sc*Sa normalized Source color divided by Source alpha
148 Dca = Dc*Da normalized Dest color divided by Dest alpha
149 Dc' = Dca'/Da' the desired color value for this channel.
151 Da' in in the follow formula as 'gamma' The resulting alpla value.
153 Most functions use a blending mode of over (X=1,Y=1,Z=1) this results in
154 the following optimizations...
156 gamma = 1 - QuantiumScale*alpha * QuantiumScale*beta;
157 opacity = QuantiumScale*alpha*beta; // over blend, optimized 1-Gamma
159 The above SVG definitions also definate that Mathematical Composition
160 methods should use a 'Over' blending mode for Alpha Channel.
161 It however was not applied for composition modes of 'Plus', 'Minus',
162 the modulus versions of 'Add' and 'Subtract'.
164 Mathematical operator changes to be applied from IM v6.7...
166 1) Modulus modes 'Add' and 'Subtract' are obsoleted and renamed
167 'ModulusAdd' and 'ModulusSubtract' for clarity.
169 2) All mathematical compositions work as per the SVG specification
170 with regard to blending. This now includes 'ModulusAdd' and
173 3) When the special channel flag 'sync' (syncronize channel updates)
174 is turned off (enabled by default) then mathematical compositions are
175 only performed on the channels specified, and are applied
176 independantally of each other. In other words the mathematics is
177 performed as 'pure' mathematical operations, rather than as image
181 static inline MagickRealType MagickMin(const MagickRealType x,
182 const MagickRealType y)
189 static inline MagickRealType MagickMax(const MagickRealType x,
190 const MagickRealType y)
197 static inline MagickRealType ConvertHueToRGB(MagickRealType m1,
198 MagickRealType m2,MagickRealType hue)
205 return(m1+6.0*(m2-m1)*hue);
209 return(m1+6.0*(m2-m1)*(2.0/3.0-hue));
213 static void HCLComposite(const MagickRealType hue,const MagickRealType chroma,
214 const MagickRealType luma,MagickRealType *red,MagickRealType *green,
215 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.298839*r+0.586811*g+0.114350*b);
274 *red=QuantumRange*(r+m);
275 *green=QuantumRange*(g+m);
276 *blue=QuantumRange*(b+m);
279 static void CompositeHCL(const MagickRealType red,const MagickRealType green,
280 const MagickRealType blue,MagickRealType *hue,MagickRealType *chroma,
281 MagickRealType *luma)
292 Convert RGB to HCL colorspace.
294 assert(hue != (MagickRealType *) NULL);
295 assert(chroma != (MagickRealType *) NULL);
296 assert(luma != (MagickRealType *) NULL);
300 max=MagickMax(r,MagickMax(g,b));
301 c=max-(MagickRealType) MagickMin(r,MagickMin(g,b));
307 h=fmod((g-b)/c+6.0,6.0);
315 *chroma=QuantumScale*c;
316 *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
319 static MagickBooleanType CompositeOverImage(Image *image,
320 const Image *composite_image,const MagickBooleanType clip_to_self,
321 const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
323 #define CompositeImageTag "Composite/Image"
343 composite_view=AcquireVirtualCacheView(composite_image,exception);
344 image_view=AcquireAuthenticCacheView(image,exception);
345 #if defined(MAGICKCORE_OPENMP_SUPPORT)
346 #pragma omp parallel for schedule(static,4) shared(progress,status) \
347 magick_threads(composite_image,image,image->rows,1)
349 for (y=0; y < (ssize_t) image->rows; y++)
354 register const Quantum
366 if (status == MagickFalse)
368 if (clip_to_self != MagickFalse)
372 if ((y-y_offset) >= (ssize_t) composite_image->rows)
376 If pixels is NULL, y is outside overlay region.
378 pixels=(Quantum *) NULL;
380 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
382 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
383 composite_image->columns,1,exception);
384 if (p == (const Quantum *) NULL)
391 p-=x_offset*GetPixelChannels(composite_image);
393 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
394 if (q == (Quantum *) NULL)
399 for (x=0; x < (ssize_t) image->columns; x++)
414 if (clip_to_self != MagickFalse)
418 q+=GetPixelChannels(image);
421 if ((x-x_offset) >= (ssize_t) composite_image->columns)
424 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
425 ((x-x_offset) >= (ssize_t) composite_image->columns))
428 source[MaxPixelChannels];
433 Dc: destination color.
435 if (GetPixelReadMask(image,q) == 0)
437 q+=GetPixelChannels(image);
440 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
442 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
444 PixelChannel channel=GetPixelChannelChannel(image,i);
445 PixelTrait traits=GetPixelChannelTraits(image,channel);
446 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
448 if ((traits == UndefinedPixelTrait) ||
449 (composite_traits == UndefinedPixelTrait))
451 q[i]=source[channel];
453 q+=GetPixelChannels(image);
458 Sa: normalized source alpha.
459 Da: normalized destination alpha.
461 if (GetPixelReadMask(composite_image,p) == 0)
463 p+=GetPixelChannels(composite_image);
464 channels=GetPixelChannels(composite_image);
465 if (p >= (pixels+channels*composite_image->columns))
467 q+=GetPixelChannels(image);
470 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
471 Da=QuantumScale*GetPixelAlpha(image,q);
472 alpha=Sa*(-Da)+Sa+Da;
473 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
475 PixelChannel channel=GetPixelChannelChannel(image,i);
476 PixelTrait traits=GetPixelChannelTraits(image,channel);
477 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
479 if ((traits == UndefinedPixelTrait) ||
480 (composite_traits == UndefinedPixelTrait))
482 if ((traits & CopyPixelTrait) != 0)
484 if (channel != AlphaPixelChannel)
489 q[i]=GetPixelChannel(composite_image,channel,p);
495 q[i]=ClampToQuantum(QuantumRange*alpha);
500 Dc: destination color.
502 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
503 Dc=(MagickRealType) q[i];
504 gamma=PerceptibleReciprocal(alpha);
505 q[i]=ClampToQuantum(gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc));
507 p+=GetPixelChannels(composite_image);
508 channels=GetPixelChannels(composite_image);
509 if (p >= (pixels+channels*composite_image->columns))
511 q+=GetPixelChannels(image);
513 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
515 if (image->progress_monitor != (MagickProgressMonitor) NULL)
520 #if defined(MAGICKCORE_OPENMP_SUPPORT)
521 #pragma omp critical (MagickCore_CompositeImage)
523 proceed=SetImageProgress(image,CompositeImageTag,progress++,
525 if (proceed == MagickFalse)
529 composite_view=DestroyCacheView(composite_view);
530 image_view=DestroyCacheView(image_view);
534 MagickExport MagickBooleanType CompositeImage(Image *image,
535 const Image *composite,const CompositeOperator compose,
536 const MagickBooleanType clip_to_self,const ssize_t x_offset,
537 const ssize_t y_offset,ExceptionInfo *exception)
539 #define CompositeImageTag "Composite/Image"
560 destination_dissolve,
573 assert(image != (Image *) NULL);
574 assert(image->signature == MagickSignature);
575 if (image->debug != MagickFalse)
576 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
577 assert(composite!= (Image *) NULL);
578 assert(composite->signature == MagickSignature);
579 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
581 composite_image=CloneImage(composite,0,0,MagickTrue,exception);
582 if (composite_image == (const Image *) NULL)
584 if (IsGrayColorspace(image->colorspace) != MagickFalse)
585 (void) SetImageColorspace(image,sRGBColorspace,exception);
586 (void) SetImageColorspace(composite_image,image->colorspace,exception);
587 if ((image->alpha_trait == BlendPixelTrait) &&
588 (composite_image->alpha_trait != BlendPixelTrait))
589 (void) SetImageAlphaChannel(composite_image,SetAlphaChannel,exception);
590 if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
592 status=CompositeOverImage(image,composite_image,clip_to_self,x_offset,
594 composite_image=DestroyImage(composite_image);
597 destination_image=(Image *) NULL;
599 destination_dissolve=1.0;
601 percent_chroma=100.0;
606 case CopyCompositeOp:
608 if ((x_offset < 0) || (y_offset < 0))
610 if ((x_offset+(ssize_t) composite_image->columns) >= (ssize_t) image->columns)
612 if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
615 composite_view=AcquireVirtualCacheView(composite_image,exception);
616 image_view=AcquireAuthenticCacheView(image,exception);
617 #if defined(MAGICKCORE_OPENMP_SUPPORT)
618 #pragma omp parallel for schedule(static,4) shared(status) \
619 magick_threads(composite_image,image,composite_image->rows,1)
621 for (y=0; y < (ssize_t) composite_image->rows; y++)
626 register const Quantum
635 if (status == MagickFalse)
637 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
639 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
640 composite_image->columns,1,exception);
641 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
646 for (x=0; x < (ssize_t) composite_image->columns; x++)
651 if (GetPixelReadMask(composite_image,p) == 0)
653 p+=GetPixelChannels(composite_image);
654 q+=GetPixelChannels(image);
657 for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
659 PixelChannel channel=GetPixelChannelChannel(composite_image,i);
660 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
662 PixelTrait traits=GetPixelChannelTraits(image,channel);
663 if ((traits == UndefinedPixelTrait) ||
664 (composite_traits == UndefinedPixelTrait))
666 SetPixelChannel(image,channel,p[i],q);
668 p+=GetPixelChannels(composite_image);
669 q+=GetPixelChannels(image);
671 sync=SyncCacheViewAuthenticPixels(image_view,exception);
672 if (sync == MagickFalse)
674 if (image->progress_monitor != (MagickProgressMonitor) NULL)
679 #if defined(MAGICKCORE_OPENMP_SUPPORT)
680 #pragma omp critical (MagickCore_CompositeImage)
682 proceed=SetImageProgress(image,CompositeImageTag,
683 (MagickOffsetType) y,image->rows);
684 if (proceed == MagickFalse)
688 composite_view=DestroyCacheView(composite_view);
689 image_view=DestroyCacheView(image_view);
690 composite_image=DestroyImage(composite_image);
693 case CopyAlphaCompositeOp:
694 case ChangeMaskCompositeOp:
695 case IntensityCompositeOp:
698 Modify destination outside the overlaid region and require an alpha
699 channel to exist, to add transparency.
701 if (image->alpha_trait != BlendPixelTrait)
702 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
705 case BlurCompositeOp:
730 Blur Image by resampling.
732 Blur Image dictated by an overlay gradient map: X = red_channel;
733 Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
735 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
737 if (destination_image == (Image *) NULL)
739 composite_image=DestroyImage(composite_image);
743 Gather the maximum blur sigma values from user.
745 SetGeometryInfo(&geometry_info);
747 value=GetImageArtifact(image,"compose:args");
748 if (value != (const char *) NULL)
749 flags=ParseGeometry(value,&geometry_info);
750 if ((flags & WidthValue) == 0)
752 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
753 "InvalidSetting","'%s' '%s'","compose:args",value);
754 composite_image=DestroyImage(composite_image);
755 destination_image=DestroyImage(destination_image);
759 Users input sigma now needs to be converted to the EWA ellipse size.
760 The filter defaults to a sigma of 0.5 so to make this match the
761 users input the ellipse size needs to be doubled.
763 width=height=geometry_info.rho*2.0;
764 if ((flags & HeightValue) != 0 )
765 height=geometry_info.sigma*2.0;
767 Default the unrotated ellipse width and height axis vectors.
773 /* rotate vectors if a rotation angle is given */
774 if ((flags & XValue) != 0 )
779 angle=DegreesToRadians(geometry_info.xi);
780 blur.x1=width*cos(angle);
781 blur.x2=width*sin(angle);
782 blur.y1=(-height*sin(angle));
783 blur.y2=height*cos(angle);
785 /* Otherwise lets set a angle range and calculate in the loop */
788 if ((flags & YValue) != 0 )
790 angle_start=DegreesToRadians(geometry_info.xi);
791 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
794 Set up a gaussian cylindrical filter for EWA Bluring.
796 As the minimum ellipse radius of support*1.0 the EWA algorithm
797 can only produce a minimum blur of 0.5 for Gaussian (support=2.0)
798 This means that even 'No Blur' will be still a little blurry!
800 The solution (as well as the problem of preventing any user
801 expert filter settings, is to set our own user settings, then
802 restore them afterwards.
804 resample_filter=AcquireResampleFilter(image,exception);
805 SetResampleFilter(resample_filter,GaussianFilter);
807 /* do the variable blurring of each pixel in image */
808 GetPixelInfo(image,&pixel);
809 composite_view=AcquireVirtualCacheView(composite_image,exception);
810 destination_view=AcquireAuthenticCacheView(destination_image,exception);
811 for (y=0; y < (ssize_t) composite_image->rows; y++)
816 register const Quantum
825 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
827 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
829 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
830 destination_image->columns,1,exception);
831 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
833 for (x=0; x < (ssize_t) composite_image->columns; x++)
835 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
837 p+=GetPixelChannels(composite_image);
840 if (fabs(angle_range) > MagickEpsilon)
845 angle=angle_start+angle_range*QuantumScale*
846 GetPixelBlue(composite_image,p);
847 blur.x1=width*cos(angle);
848 blur.x2=width*sin(angle);
849 blur.y1=(-height*sin(angle));
850 blur.y2=height*cos(angle);
853 if ( x == 10 && y == 60 ) {
854 (void) fprintf(stderr, "blur.x=%lf,%lf, blur.y=%lf,%lf\n",blur.x1,
855 blur.x2,blur.y1, blur.y2);
856 (void) fprintf(stderr, "scaled by=%lf,%lf\n",QuantumScale*
857 GetPixelRed(p),QuantumScale*GetPixelGreen(p));
859 ScaleResampleFilter(resample_filter,
860 blur.x1*QuantumScale*GetPixelRed(composite_image,p),
861 blur.y1*QuantumScale*GetPixelGreen(composite_image,p),
862 blur.x2*QuantumScale*GetPixelRed(composite_image,p),
863 blur.y2*QuantumScale*GetPixelGreen(composite_image,p) );
864 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
865 (double) y_offset+y,&pixel,exception);
866 SetPixelInfoPixel(destination_image,&pixel,q);
867 p+=GetPixelChannels(composite_image);
868 q+=GetPixelChannels(destination_image);
870 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
871 if (sync == MagickFalse)
874 resample_filter=DestroyResampleFilter(resample_filter);
875 composite_view=DestroyCacheView(composite_view);
876 destination_view=DestroyCacheView(destination_view);
877 composite_image=DestroyImage(composite_image);
878 composite_image=destination_image;
881 case DisplaceCompositeOp:
882 case DistortCompositeOp:
904 Displace/Distort based on overlay gradient map:
905 X = red_channel; Y = green_channel;
906 compose:args = x_scale[,y_scale[,center.x,center.y]]
908 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
910 if (destination_image == (Image *) NULL)
912 composite_image=DestroyImage(composite_image);
915 SetGeometryInfo(&geometry_info);
917 value=GetImageArtifact(composite_image,"compose:args");
918 if (value != (char *) NULL)
919 flags=ParseGeometry(value,&geometry_info);
920 if ((flags & (WidthValue|HeightValue)) == 0 )
922 if ((flags & AspectValue) == 0)
924 horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
926 vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
930 horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
931 vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
936 horizontal_scale=geometry_info.rho;
937 vertical_scale=geometry_info.sigma;
938 if ((flags & PercentValue) != 0)
940 if ((flags & AspectValue) == 0)
942 horizontal_scale*=(composite_image->columns-1.0)/200.0;
943 vertical_scale*=(composite_image->rows-1.0)/200.0;
947 horizontal_scale*=(image->columns-1.0)/200.0;
948 vertical_scale*=(image->rows-1.0)/200.0;
951 if ((flags & HeightValue) == 0)
952 vertical_scale=horizontal_scale;
955 Determine fixed center point for absolute distortion map
957 Displace offset relative to a fixed absolute point
958 Select that point according to +X+Y user inputs.
959 default = center of overlay image
960 arg flag '!' = locations/percentage relative to background image
962 center.x=(MagickRealType) x_offset;
963 center.y=(MagickRealType) y_offset;
964 if (compose == DistortCompositeOp)
966 if ((flags & XValue) == 0)
967 if ((flags & AspectValue) == 0)
968 center.x=(MagickRealType) (x_offset+(composite_image->columns-1)/
971 center.x=(MagickRealType) ((image->columns-1)/2);
973 if ((flags & AspectValue) == 0)
974 center.x=(MagickRealType) x_offset+geometry_info.xi;
976 center.x=geometry_info.xi;
977 if ((flags & YValue) == 0)
978 if ((flags & AspectValue) == 0)
979 center.y=(MagickRealType) (y_offset+(composite_image->rows-1)/
982 center.y=(MagickRealType) ((image->rows-1)/2);
984 if ((flags & AspectValue) == 0)
985 center.y=(MagickRealType) y_offset+geometry_info.psi;
987 center.y=geometry_info.psi;
990 Shift the pixel offset point as defined by the provided,
991 displacement/distortion map. -- Like a lens...
993 GetPixelInfo(image,&pixel);
994 image_view=AcquireVirtualCacheView(image,exception);
995 composite_view=AcquireVirtualCacheView(composite_image,exception);
996 destination_view=AcquireAuthenticCacheView(destination_image,exception);
997 for (y=0; y < (ssize_t) composite_image->rows; y++)
1002 register const Quantum
1011 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1013 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
1015 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
1016 destination_image->columns,1,exception);
1017 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1019 for (x=0; x < (ssize_t) composite_image->columns; x++)
1021 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1023 p+=GetPixelChannels(composite_image);
1027 Displace the offset.
1029 offset.x=(double) (horizontal_scale*(GetPixelRed(composite_image,p)-
1030 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1031 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
1033 offset.y=(double) (vertical_scale*(GetPixelGreen(composite_image,p)-
1034 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1035 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
1037 (void) InterpolatePixelInfo(image,image_view,
1038 UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1041 Mask with the 'invalid pixel mask' in alpha channel.
1043 pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
1044 pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
1045 SetPixelInfoPixel(destination_image,&pixel,q);
1046 p+=GetPixelChannels(composite_image);
1047 q+=GetPixelChannels(destination_image);
1049 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1050 if (sync == MagickFalse)
1053 destination_view=DestroyCacheView(destination_view);
1054 composite_view=DestroyCacheView(composite_view);
1055 image_view=DestroyCacheView(image_view);
1056 composite_image=DestroyImage(composite_image);
1057 composite_image=destination_image;
1060 case DissolveCompositeOp:
1066 Geometry arguments to dissolve factors.
1068 value=GetImageArtifact(composite_image,"compose:args");
1069 if (value != (char *) NULL)
1071 flags=ParseGeometry(value,&geometry_info);
1072 source_dissolve=geometry_info.rho/100.0;
1073 destination_dissolve=1.0;
1074 if ((source_dissolve-MagickEpsilon) < 0.0)
1075 source_dissolve=0.0;
1076 if ((source_dissolve+MagickEpsilon) > 1.0)
1078 destination_dissolve=2.0-source_dissolve;
1079 source_dissolve=1.0;
1081 if ((flags & SigmaValue) != 0)
1082 destination_dissolve=geometry_info.sigma/100.0;
1083 if ((destination_dissolve-MagickEpsilon) < 0.0)
1084 destination_dissolve=0.0;
1085 /* posible speed up? -- from IMv6 update
1086 clip_to_self=MagickFalse;
1087 if ((destination_dissolve+MagickEpsilon) > 1.0 )
1089 destination_dissolve=1.0;
1090 clip_to_self=MagickTrue;
1096 case BlendCompositeOp:
1101 value=GetImageArtifact(composite_image,"compose:args");
1102 if (value != (char *) NULL)
1104 flags=ParseGeometry(value,&geometry_info);
1105 source_dissolve=geometry_info.rho/100.0;
1106 destination_dissolve=1.0-source_dissolve;
1107 if ((flags & SigmaValue) != 0)
1108 destination_dissolve=geometry_info.sigma/100.0;
1112 case MathematicsCompositeOp:
1118 Just collect the values from "compose:args", setting.
1119 Unused values are set to zero automagically.
1121 Arguments are normally a comma separated list, so this probably should
1122 be changed to some 'general comma list' parser, (with a minimum
1125 SetGeometryInfo(&geometry_info);
1126 value=GetImageArtifact(composite_image,"compose:args");
1127 if (value != (char *) NULL)
1128 (void) ParseGeometry(value,&geometry_info);
1131 case ModulateCompositeOp:
1137 Determine the luma and chroma scale.
1139 value=GetImageArtifact(composite_image,"compose:args");
1140 if (value != (char *) NULL)
1142 flags=ParseGeometry(value,&geometry_info);
1143 percent_luma=geometry_info.rho;
1144 if ((flags & SigmaValue) != 0)
1145 percent_chroma=geometry_info.sigma;
1149 case ThresholdCompositeOp:
1155 Determine the amount and threshold.
1157 value=GetImageArtifact(composite_image,"compose:args");
1158 if (value != (char *) NULL)
1160 flags=ParseGeometry(value,&geometry_info);
1161 amount=geometry_info.rho;
1162 threshold=geometry_info.sigma;
1163 if ((flags & SigmaValue) == 0)
1166 threshold*=QuantumRange;
1177 midpoint=((MagickRealType) QuantumRange+1.0)/2;
1178 composite_view=AcquireVirtualCacheView(composite_image,exception);
1179 image_view=AcquireAuthenticCacheView(image,exception);
1180 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1181 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1182 magick_threads(composite_image,image,image->rows,1)
1184 for (y=0; y < (ssize_t) image->rows; y++)
1201 register const Quantum
1210 if (status == MagickFalse)
1212 if (clip_to_self != MagickFalse)
1216 if ((y-y_offset) >= (ssize_t) composite_image->rows)
1220 If pixels is NULL, y is outside overlay region.
1222 pixels=(Quantum *) NULL;
1224 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
1226 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
1227 composite_image->columns,1,exception);
1228 if (p == (const Quantum *) NULL)
1235 p-=x_offset*GetPixelChannels(composite_image);
1237 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1238 if (q == (Quantum *) NULL)
1246 GetPixelInfo(image,&destination_pixel);
1247 GetPixelInfo(composite_image,&source_pixel);
1248 for (x=0; x < (ssize_t) image->columns; x++)
1268 if (clip_to_self != MagickFalse)
1272 q+=GetPixelChannels(image);
1275 if ((x-x_offset) >= (ssize_t) composite_image->columns)
1278 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1279 ((x-x_offset) >= (ssize_t) composite_image->columns))
1282 source[MaxPixelChannels];
1287 Dc: destination color.
1289 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
1291 if (GetPixelReadMask(image,q) == 0)
1293 q+=GetPixelChannels(image);
1296 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1301 PixelChannel channel=GetPixelChannelChannel(image,i);
1302 PixelTrait traits=GetPixelChannelTraits(image,channel);
1303 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
1305 if ((traits == UndefinedPixelTrait) ||
1306 (composite_traits == UndefinedPixelTrait))
1310 case AlphaCompositeOp:
1311 case ChangeMaskCompositeOp:
1312 case CopyAlphaCompositeOp:
1313 case DstAtopCompositeOp:
1314 case DstInCompositeOp:
1316 case IntensityCompositeOp:
1317 case OutCompositeOp:
1318 case SrcInCompositeOp:
1319 case SrcOutCompositeOp:
1321 pixel=(MagickRealType) q[i];
1322 if (channel == AlphaPixelChannel)
1323 pixel=(MagickRealType) TransparentAlpha;
1326 case ClearCompositeOp:
1327 case CopyCompositeOp:
1328 case ReplaceCompositeOp:
1329 case SrcCompositeOp:
1331 if (channel == AlphaPixelChannel)
1333 pixel=(MagickRealType) TransparentAlpha;
1339 case BlendCompositeOp:
1340 case DissolveCompositeOp:
1342 if (channel == AlphaPixelChannel)
1344 pixel=destination_dissolve*GetPixelAlpha(composite_image,
1348 pixel=(MagickRealType) source[channel];
1353 pixel=(MagickRealType) source[channel];
1357 q[i]=ClampToQuantum(pixel);
1359 q+=GetPixelChannels(image);
1363 Authentic composite:
1364 Sa: normalized source alpha.
1365 Da: normalized destination alpha.
1367 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
1368 Da=QuantumScale*GetPixelAlpha(image,q);
1371 case BumpmapCompositeOp:
1373 alpha=GetPixelIntensity(composite_image,p)*Sa;
1376 case ColorBurnCompositeOp:
1377 case ColorDodgeCompositeOp:
1378 case DifferenceCompositeOp:
1379 case DivideDstCompositeOp:
1380 case DivideSrcCompositeOp:
1381 case ExclusionCompositeOp:
1382 case HardLightCompositeOp:
1383 case LinearBurnCompositeOp:
1384 case LinearDodgeCompositeOp:
1385 case LinearLightCompositeOp:
1386 case MathematicsCompositeOp:
1387 case MinusDstCompositeOp:
1388 case MinusSrcCompositeOp:
1389 case ModulusAddCompositeOp:
1390 case ModulusSubtractCompositeOp:
1391 case MultiplyCompositeOp:
1392 case OverlayCompositeOp:
1393 case PegtopLightCompositeOp:
1394 case PinLightCompositeOp:
1395 case ScreenCompositeOp:
1396 case SoftLightCompositeOp:
1397 case VividLightCompositeOp:
1399 alpha=RoundToUnity(Sa+Da-Sa*Da);
1402 case DarkenCompositeOp:
1403 case DstAtopCompositeOp:
1404 case DstInCompositeOp:
1406 case LightenCompositeOp:
1407 case SrcInCompositeOp:
1412 case DissolveCompositeOp:
1414 alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
1415 Sa+destination_dissolve*Da;
1418 case DstOverCompositeOp:
1420 alpha=Da*(-Sa)+Da+Sa;
1423 case DstOutCompositeOp:
1428 case OutCompositeOp:
1429 case SrcOutCompositeOp:
1434 case OverCompositeOp:
1435 case SrcOverCompositeOp:
1437 alpha=Sa*(-Da)+Sa+Da;
1440 case BlendCompositeOp:
1441 case PlusCompositeOp:
1443 alpha=RoundToUnity(Sa+Da);
1446 case XorCompositeOp:
1448 alpha=Sa+Da-2.0*Sa*Da;
1457 if (GetPixelReadMask(image,q) == 0)
1459 p+=GetPixelChannels(composite_image);
1460 q+=GetPixelChannels(image);
1465 case ColorizeCompositeOp:
1466 case HueCompositeOp:
1467 case LuminizeCompositeOp:
1468 case ModulateCompositeOp:
1469 case SaturateCompositeOp:
1471 GetPixelInfoPixel(composite_image,p,&source_pixel);
1472 GetPixelInfoPixel(image,q,&destination_pixel);
1478 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1484 PixelChannel channel=GetPixelChannelChannel(image,i);
1485 PixelTrait traits=GetPixelChannelTraits(image,channel);
1486 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
1488 if (traits == UndefinedPixelTrait)
1490 if ((compose != IntensityCompositeOp) &&
1491 (composite_traits == UndefinedPixelTrait))
1495 Dc: destination color.
1497 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
1498 Dc=(MagickRealType) q[i];
1499 if ((traits & CopyPixelTrait) != 0)
1501 if (channel != AlphaPixelChannel)
1506 q[i]=ClampToQuantum(Sc);
1514 case AlphaCompositeOp:
1516 pixel=QuantumRange*Sa;
1519 case AtopCompositeOp:
1520 case CopyBlackCompositeOp:
1521 case CopyBlueCompositeOp:
1522 case CopyCyanCompositeOp:
1523 case CopyGreenCompositeOp:
1524 case CopyMagentaCompositeOp:
1525 case CopyRedCompositeOp:
1526 case CopyYellowCompositeOp:
1527 case SrcAtopCompositeOp:
1528 case DstCompositeOp:
1531 pixel=QuantumRange*Da;
1534 case ChangeMaskCompositeOp:
1539 if (Da > ((MagickRealType) QuantumRange/2.0))
1541 pixel=(MagickRealType) TransparentAlpha;
1544 equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
1545 if (equivalent != MagickFalse)
1547 pixel=(MagickRealType) TransparentAlpha;
1550 pixel=(MagickRealType) OpaqueAlpha;
1553 case ClearCompositeOp:
1555 pixel=(MagickRealType) TransparentAlpha;
1558 case ColorizeCompositeOp:
1559 case HueCompositeOp:
1560 case LuminizeCompositeOp:
1561 case SaturateCompositeOp:
1563 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1565 pixel=QuantumRange*Da;
1568 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1570 pixel=QuantumRange*Sa;
1575 pixel=QuantumRange*Da;
1578 pixel=QuantumRange*Sa;
1581 case CopyAlphaCompositeOp:
1583 pixel=QuantumRange*Sa;
1584 if (composite_image->alpha_trait == BlendPixelTrait)
1585 pixel=GetPixelIntensity(composite_image,p);
1588 case CopyCompositeOp:
1589 case DisplaceCompositeOp:
1590 case DistortCompositeOp:
1591 case DstAtopCompositeOp:
1592 case ReplaceCompositeOp:
1593 case SrcCompositeOp:
1595 pixel=QuantumRange*Sa;
1598 case DarkenIntensityCompositeOp:
1600 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1601 (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
1604 case IntensityCompositeOp:
1606 pixel=GetPixelIntensity(composite_image,p);
1609 case LightenIntensityCompositeOp:
1611 pixel=Sa*GetPixelIntensity(composite_image,p) >
1612 Da*GetPixelIntensity(image,q) ? Sa : Da;
1615 case ModulateCompositeOp:
1617 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1619 pixel=QuantumRange*Da;
1622 pixel=QuantumRange*Da;
1627 pixel=QuantumRange*alpha;
1631 q[i]=ClampToQuantum(pixel);
1635 Porter-Duff compositions:
1636 Sca: source normalized color multiplied by alpha.
1637 Dca: normalized destination color multiplied by alpha.
1639 Sca=QuantumScale*Sa*Sc;
1640 Dca=QuantumScale*Da*Dc;
1643 case DarkenCompositeOp:
1644 case LightenCompositeOp:
1645 case ModulusSubtractCompositeOp:
1653 gamma=PerceptibleReciprocal(alpha);
1657 case AlphaCompositeOp:
1659 pixel=QuantumRange*Sa;
1662 case AtopCompositeOp:
1663 case SrcAtopCompositeOp:
1665 pixel=Sc*Sa+Dc*(1.0-Sa);
1668 case BlendCompositeOp:
1670 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1673 case BlurCompositeOp:
1674 case DisplaceCompositeOp:
1675 case DistortCompositeOp:
1676 case CopyCompositeOp:
1677 case ReplaceCompositeOp:
1678 case SrcCompositeOp:
1683 case BumpmapCompositeOp:
1685 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1690 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1693 case ChangeMaskCompositeOp:
1698 case ClearCompositeOp:
1703 case ColorBurnCompositeOp:
1706 Refer to the March 2009 SVG specification.
1708 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1710 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1713 if (Sca < MagickEpsilon)
1715 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1718 pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
1719 Sca*(1.0-Da)+Dca*(1.0-Sa));
1722 case ColorDodgeCompositeOp:
1724 if ((Sca*Da+Dca*Sa) >= Sa*Da)
1726 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1729 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1733 case ColorizeCompositeOp:
1735 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1740 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1745 CompositeHCL(destination_pixel.red,destination_pixel.green,
1746 destination_pixel.blue,&sans,&sans,&luma);
1747 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1748 &hue,&chroma,&sans);
1749 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1752 case RedPixelChannel: pixel=red; break;
1753 case GreenPixelChannel: pixel=green; break;
1754 case BluePixelChannel: pixel=blue; break;
1755 default: pixel=Dc; break;
1759 case CopyAlphaCompositeOp:
1760 case IntensityCompositeOp:
1765 case CopyBlackCompositeOp:
1767 if (channel == BlackPixelChannel)
1768 pixel=(MagickRealType) (QuantumRange-
1769 GetPixelBlack(composite_image,p));
1772 case CopyBlueCompositeOp:
1773 case CopyYellowCompositeOp:
1775 if (channel == BluePixelChannel)
1776 pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1779 case CopyGreenCompositeOp:
1780 case CopyMagentaCompositeOp:
1782 if (channel == GreenPixelChannel)
1783 pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1786 case CopyRedCompositeOp:
1787 case CopyCyanCompositeOp:
1789 if (channel == RedPixelChannel)
1790 pixel=(MagickRealType) GetPixelRed(composite_image,p);
1793 case DarkenCompositeOp:
1796 Darken is equivalent to a 'Minimum' method
1797 OR a greyscale version of a binary 'Or'
1798 OR the 'Intersection' of pixel sets.
1802 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1805 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1808 case DarkenIntensityCompositeOp:
1810 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1811 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1814 case DifferenceCompositeOp:
1816 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1819 case DissolveCompositeOp:
1821 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1822 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1825 case DivideDstCompositeOp:
1827 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1829 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1832 if (fabs(Dca) < MagickEpsilon)
1834 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1837 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1840 case DivideSrcCompositeOp:
1842 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1844 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1847 if (fabs(Sca) < MagickEpsilon)
1849 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1852 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1855 case DstAtopCompositeOp:
1857 pixel=Dc*Da+Sc*(1.0-Da);
1860 case DstCompositeOp:
1866 case DstInCompositeOp:
1868 pixel=gamma*(Sa*Dc*Sa);
1871 case DstOutCompositeOp:
1873 pixel=gamma*(Da*Dc*(1.0-Sa));
1876 case DstOverCompositeOp:
1878 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1881 case ExclusionCompositeOp:
1883 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1887 case HardLightCompositeOp:
1891 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1895 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1899 case HueCompositeOp:
1901 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1906 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1911 CompositeHCL(destination_pixel.red,destination_pixel.green,
1912 destination_pixel.blue,&hue,&chroma,&luma);
1913 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1915 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1918 case RedPixelChannel: pixel=red; break;
1919 case GreenPixelChannel: pixel=green; break;
1920 case BluePixelChannel: pixel=blue; break;
1921 default: pixel=Dc; break;
1926 case SrcInCompositeOp:
1928 pixel=gamma*(Da*Sc*Da);
1931 case LinearBurnCompositeOp:
1934 LinearBurn: as defined by Abode Photoshop, according to
1935 http://www.simplefilter.de/en/basics/mixmods.html is:
1937 f(Sc,Dc) = Sc + Dc - 1
1939 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1942 case LinearDodgeCompositeOp:
1944 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1947 case LinearLightCompositeOp:
1950 LinearLight: as defined by Abode Photoshop, according to
1951 http://www.simplefilter.de/en/basics/mixmods.html is:
1953 f(Sc,Dc) = Dc + 2*Sc - 1
1955 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1958 case LightenCompositeOp:
1962 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1965 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1968 case LightenIntensityCompositeOp:
1971 Lighten is equivalent to a 'Maximum' method
1972 OR a greyscale version of a binary 'And'
1973 OR the 'Union' of pixel sets.
1975 pixel=Sa*GetPixelIntensity(composite_image,p) >
1976 Da*GetPixelIntensity(image,q) ? Sc : Dc;
1979 case LuminizeCompositeOp:
1981 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1986 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1991 CompositeHCL(destination_pixel.red,destination_pixel.green,
1992 destination_pixel.blue,&hue,&chroma,&luma);
1993 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1995 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1998 case RedPixelChannel: pixel=red; break;
1999 case GreenPixelChannel: pixel=green; break;
2000 case BluePixelChannel: pixel=blue; break;
2001 default: pixel=Dc; break;
2005 case MathematicsCompositeOp:
2008 'Mathematics' a free form user control mathematical composition
2011 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
2013 Where the arguments A,B,C,D are (currently) passed to composite
2014 as a command separated 'geometry' string in "compose:args" image
2017 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
2019 Applying the SVG transparency formula (see above), we get...
2021 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
2023 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
2026 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
2027 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
2028 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
2031 case MinusDstCompositeOp:
2033 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2036 case MinusSrcCompositeOp:
2039 Minus source from destination.
2043 pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2046 case ModulateCompositeOp:
2051 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2056 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
2062 CompositeHCL(destination_pixel.red,destination_pixel.green,
2063 destination_pixel.blue,&hue,&chroma,&luma);
2064 luma+=(0.01*percent_luma*offset)/midpoint;
2065 chroma*=0.01*percent_chroma;
2066 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2069 case RedPixelChannel: pixel=red; break;
2070 case GreenPixelChannel: pixel=green; break;
2071 case BluePixelChannel: pixel=blue; break;
2072 default: pixel=Dc; break;
2076 case ModulusAddCompositeOp:
2079 if (pixel > QuantumRange)
2080 pixel-=QuantumRange;
2081 pixel=gamma*(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2084 case ModulusSubtractCompositeOp:
2088 pixel+=QuantumRange;
2089 pixel=gamma*(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2092 case MultiplyCompositeOp:
2094 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2097 case OutCompositeOp:
2098 case SrcOutCompositeOp:
2100 pixel=gamma*(Sa*Sc*(1.0-Da));
2103 case OverCompositeOp:
2104 case SrcOverCompositeOp:
2106 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2109 case OverlayCompositeOp:
2113 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2117 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2121 case PegtopLightCompositeOp:
2124 PegTop: A Soft-Light alternative: A continuous version of the
2125 Softlight function, producing very similar results.
2127 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2129 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2131 if (fabs(Da) < MagickEpsilon)
2133 pixel=QuantumRange*gamma*(Sca);
2136 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2140 case PinLightCompositeOp:
2143 PinLight: A Photoshop 7 composition method
2144 http://www.simplefilter.de/en/basics/mixmods.html
2146 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2148 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2150 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2153 if ((Dca*Sa) > (2.0*Sca*Da))
2155 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2158 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2161 case PlusCompositeOp:
2163 pixel=gamma*(Sa*Sc+Da*Dc);
2166 case SaturateCompositeOp:
2168 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2173 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2178 CompositeHCL(destination_pixel.red,destination_pixel.green,
2179 destination_pixel.blue,&hue,&chroma,&luma);
2180 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2181 &sans,&chroma,&sans);
2182 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2185 case RedPixelChannel: pixel=red; break;
2186 case GreenPixelChannel: pixel=green; break;
2187 case BluePixelChannel: pixel=blue; break;
2188 default: pixel=Dc; break;
2192 case ScreenCompositeOp:
2195 Screen: a negated multiply:
2197 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2199 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2202 case SoftLightCompositeOp:
2205 Refer to the March 2009 SVG specification.
2209 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2210 Sca*(1.0-Da)+Dca*(1.0-Sa));
2213 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2215 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2216 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2220 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2221 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2224 case ThresholdCompositeOp:
2230 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2235 pixel=gamma*(Dc+delta*amount);
2238 case VividLightCompositeOp:
2241 VividLight: A Photoshop 7 composition method. See
2242 http://www.simplefilter.de/en/basics/mixmods.html.
2244 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2246 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2248 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2251 if ((2.0*Sca) <= Sa)
2253 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2254 (1.0-Da)+Dca*(1.0-Sa));
2257 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2261 case XorCompositeOp:
2263 pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2272 q[i]=ClampToQuantum(pixel);
2274 p+=GetPixelChannels(composite_image);
2275 channels=GetPixelChannels(composite_image);
2276 if (p >= (pixels+channels*composite_image->columns))
2278 q+=GetPixelChannels(image);
2280 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2282 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2287 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2288 #pragma omp critical (MagickCore_CompositeImage)
2290 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2292 if (proceed == MagickFalse)
2296 composite_view=DestroyCacheView(composite_view);
2297 image_view=DestroyCacheView(image_view);
2298 if (destination_image != (Image * ) NULL)
2299 destination_image=DestroyImage(destination_image);
2301 composite_image=DestroyImage(composite_image);
2306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2310 % T e x t u r e I m a g e %
2314 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2316 % TextureImage() repeatedly tiles the texture image across and down the image
2319 % The format of the TextureImage method is:
2321 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2322 % ExceptionInfo *exception)
2324 % A description of each parameter follows:
2326 % o image: the image.
2328 % o texture_image: This image is the texture to layer on the background.
2331 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
2332 ExceptionInfo *exception)
2334 #define TextureImageTag "Texture/Image"
2349 assert(image != (Image *) NULL);
2350 if (image->debug != MagickFalse)
2351 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2352 assert(image->signature == MagickSignature);
2353 if (texture == (const Image *) NULL)
2354 return(MagickFalse);
2355 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2356 return(MagickFalse);
2357 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2358 if (texture_image == (const Image *) NULL)
2359 return(MagickFalse);
2360 (void) TransformImageColorspace(texture_image,image->colorspace,exception);
2361 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
2364 if ((image->compose != CopyCompositeOp) &&
2365 ((image->compose != OverCompositeOp) ||
2366 (image->alpha_trait == BlendPixelTrait) ||
2367 (texture_image->alpha_trait == BlendPixelTrait)))
2370 Tile texture onto the image background.
2372 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2377 if (status == MagickFalse)
2379 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2384 thread_status=CompositeImage(image,texture_image,image->compose,
2385 MagickFalse,x+texture_image->tile_offset.x,y+
2386 texture_image->tile_offset.y,exception);
2387 if (thread_status == MagickFalse)
2389 status=thread_status;
2393 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2398 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2400 if (proceed == MagickFalse)
2404 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2405 image->rows,image->rows);
2406 texture_image=DestroyImage(texture_image);
2410 Tile texture onto the image background (optimized).
2413 texture_view=AcquireVirtualCacheView(texture_image,exception);
2414 image_view=AcquireAuthenticCacheView(image,exception);
2415 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2416 #pragma omp parallel for schedule(static,4) shared(status) \
2417 magick_threads(texture_image,image,1,1)
2419 for (y=0; y < (ssize_t) image->rows; y++)
2424 register const Quantum
2437 if (status == MagickFalse)
2439 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2440 (y+texture_image->tile_offset.y) % texture_image->rows,
2441 texture_image->columns,1,exception);
2442 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2443 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2448 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2454 width=texture_image->columns;
2455 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2456 width=image->columns-x;
2457 for (j=0; j < (ssize_t) width; j++)
2462 if (GetPixelReadMask(image,q) == 0)
2464 p+=GetPixelChannels(texture_image);
2465 q+=GetPixelChannels(image);
2468 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2470 PixelChannel channel=GetPixelChannelChannel(texture_image,i);
2471 PixelTrait traits=GetPixelChannelTraits(image,channel);
2472 PixelTrait texture_traits=GetPixelChannelTraits(texture_image,
2474 if ((traits == UndefinedPixelTrait) ||
2475 (texture_traits == UndefinedPixelTrait))
2477 SetPixelChannel(image,channel,p[i],q);
2479 p+=GetPixelChannels(texture_image);
2480 q+=GetPixelChannels(image);
2483 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2484 if (sync == MagickFalse)
2486 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2491 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2493 if (proceed == MagickFalse)
2497 texture_view=DestroyCacheView(texture_view);
2498 image_view=DestroyCacheView(image_view);
2499 texture_image=DestroyImage(texture_image);