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/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) GetPixelBlack(composite_image,p);
1771 case CopyBlueCompositeOp:
1772 case CopyYellowCompositeOp:
1774 if (channel == BluePixelChannel)
1775 pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1778 case CopyGreenCompositeOp:
1779 case CopyMagentaCompositeOp:
1781 if (channel == GreenPixelChannel)
1782 pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1785 case CopyRedCompositeOp:
1786 case CopyCyanCompositeOp:
1788 if (channel == RedPixelChannel)
1789 pixel=(MagickRealType) GetPixelRed(composite_image,p);
1792 case DarkenCompositeOp:
1795 Darken is equivalent to a 'Minimum' method
1796 OR a greyscale version of a binary 'Or'
1797 OR the 'Intersection' of pixel sets.
1801 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1804 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1807 case DarkenIntensityCompositeOp:
1809 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1810 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1813 case DifferenceCompositeOp:
1815 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1818 case DissolveCompositeOp:
1820 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1821 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1824 case DivideDstCompositeOp:
1826 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1828 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1831 if (fabs(Dca) < MagickEpsilon)
1833 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1836 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1839 case DivideSrcCompositeOp:
1841 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1843 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1846 if (fabs(Sca) < MagickEpsilon)
1848 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1851 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1854 case DstAtopCompositeOp:
1856 pixel=Dc*Da+Sc*(1.0-Da);
1859 case DstCompositeOp:
1865 case DstInCompositeOp:
1867 pixel=gamma*(Sa*Dc*Sa);
1870 case DstOutCompositeOp:
1872 pixel=gamma*(Da*Dc*(1.0-Sa));
1875 case DstOverCompositeOp:
1877 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1880 case ExclusionCompositeOp:
1882 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1886 case HardLightCompositeOp:
1890 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1894 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1898 case HueCompositeOp:
1900 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1905 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1910 CompositeHCL(destination_pixel.red,destination_pixel.green,
1911 destination_pixel.blue,&hue,&chroma,&luma);
1912 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1914 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1917 case RedPixelChannel: pixel=red; break;
1918 case GreenPixelChannel: pixel=green; break;
1919 case BluePixelChannel: pixel=blue; break;
1920 default: pixel=Dc; break;
1925 case SrcInCompositeOp:
1927 pixel=gamma*(Da*Sc*Da);
1930 case LinearBurnCompositeOp:
1933 LinearBurn: as defined by Abode Photoshop, according to
1934 http://www.simplefilter.de/en/basics/mixmods.html is:
1936 f(Sc,Dc) = Sc + Dc - 1
1938 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1941 case LinearDodgeCompositeOp:
1943 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1946 case LinearLightCompositeOp:
1949 LinearLight: as defined by Abode Photoshop, according to
1950 http://www.simplefilter.de/en/basics/mixmods.html is:
1952 f(Sc,Dc) = Dc + 2*Sc - 1
1954 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1957 case LightenCompositeOp:
1961 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1964 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1967 case LightenIntensityCompositeOp:
1970 Lighten is equivalent to a 'Maximum' method
1971 OR a greyscale version of a binary 'And'
1972 OR the 'Union' of pixel sets.
1974 pixel=Sa*GetPixelIntensity(composite_image,p) >
1975 Da*GetPixelIntensity(image,q) ? Sc : Dc;
1978 case LuminizeCompositeOp:
1980 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1985 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1990 CompositeHCL(destination_pixel.red,destination_pixel.green,
1991 destination_pixel.blue,&hue,&chroma,&luma);
1992 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1994 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1997 case RedPixelChannel: pixel=red; break;
1998 case GreenPixelChannel: pixel=green; break;
1999 case BluePixelChannel: pixel=blue; break;
2000 default: pixel=Dc; break;
2004 case MathematicsCompositeOp:
2007 'Mathematics' a free form user control mathematical composition
2010 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
2012 Where the arguments A,B,C,D are (currently) passed to composite
2013 as a command separated 'geometry' string in "compose:args" image
2016 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
2018 Applying the SVG transparency formula (see above), we get...
2020 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
2022 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
2025 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
2026 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
2027 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
2030 case MinusDstCompositeOp:
2032 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2035 case MinusSrcCompositeOp:
2038 Minus source from destination.
2042 pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2045 case ModulateCompositeOp:
2050 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2055 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
2061 CompositeHCL(destination_pixel.red,destination_pixel.green,
2062 destination_pixel.blue,&hue,&chroma,&luma);
2063 luma+=(0.01*percent_luma*offset)/midpoint;
2064 chroma*=0.01*percent_chroma;
2065 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2068 case RedPixelChannel: pixel=red; break;
2069 case GreenPixelChannel: pixel=green; break;
2070 case BluePixelChannel: pixel=blue; break;
2071 default: pixel=Dc; break;
2075 case ModulusAddCompositeOp:
2078 if (pixel > QuantumRange)
2079 pixel-=(QuantumRange+1.0);
2080 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2083 case ModulusSubtractCompositeOp:
2087 pixel+=(QuantumRange+1.0);
2088 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2091 case MultiplyCompositeOp:
2093 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2096 case OutCompositeOp:
2097 case SrcOutCompositeOp:
2099 pixel=gamma*(Sa*Sc*(1.0-Da));
2102 case OverCompositeOp:
2103 case SrcOverCompositeOp:
2105 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2108 case OverlayCompositeOp:
2112 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2116 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2120 case PegtopLightCompositeOp:
2123 PegTop: A Soft-Light alternative: A continuous version of the
2124 Softlight function, producing very similar results.
2126 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2128 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2130 if (fabs(Da) < MagickEpsilon)
2132 pixel=QuantumRange*gamma*(Sca);
2135 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2139 case PinLightCompositeOp:
2142 PinLight: A Photoshop 7 composition method
2143 http://www.simplefilter.de/en/basics/mixmods.html
2145 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2147 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2149 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2152 if ((Dca*Sa) > (2.0*Sca*Da))
2154 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2157 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2160 case PlusCompositeOp:
2162 pixel=gamma*(Sa*Sc+Da*Dc);
2165 case SaturateCompositeOp:
2167 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2172 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2177 CompositeHCL(destination_pixel.red,destination_pixel.green,
2178 destination_pixel.blue,&hue,&chroma,&luma);
2179 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2180 &sans,&chroma,&sans);
2181 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2184 case RedPixelChannel: pixel=red; break;
2185 case GreenPixelChannel: pixel=green; break;
2186 case BluePixelChannel: pixel=blue; break;
2187 default: pixel=Dc; break;
2191 case ScreenCompositeOp:
2194 Screen: a negated multiply:
2196 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2198 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2201 case SoftLightCompositeOp:
2204 Refer to the March 2009 SVG specification.
2208 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2209 Sca*(1.0-Da)+Dca*(1.0-Sa));
2212 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2214 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2215 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2219 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2220 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2223 case ThresholdCompositeOp:
2229 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2234 pixel=gamma*(Dc+delta*amount);
2237 case VividLightCompositeOp:
2240 VividLight: A Photoshop 7 composition method. See
2241 http://www.simplefilter.de/en/basics/mixmods.html.
2243 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2245 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2247 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2250 if ((2.0*Sca) <= Sa)
2252 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2253 (1.0-Da)+Dca*(1.0-Sa));
2256 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2260 case XorCompositeOp:
2262 pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2271 q[i]=ClampToQuantum(pixel);
2273 p+=GetPixelChannels(composite_image);
2274 channels=GetPixelChannels(composite_image);
2275 if (p >= (pixels+channels*composite_image->columns))
2277 q+=GetPixelChannels(image);
2279 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2281 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2286 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2287 #pragma omp critical (MagickCore_CompositeImage)
2289 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2291 if (proceed == MagickFalse)
2295 composite_view=DestroyCacheView(composite_view);
2296 image_view=DestroyCacheView(image_view);
2297 if (destination_image != (Image * ) NULL)
2298 destination_image=DestroyImage(destination_image);
2300 composite_image=DestroyImage(composite_image);
2305 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2309 % T e x t u r e I m a g e %
2313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2315 % TextureImage() repeatedly tiles the texture image across and down the image
2318 % The format of the TextureImage method is:
2320 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2321 % ExceptionInfo *exception)
2323 % A description of each parameter follows:
2325 % o image: the image.
2327 % o texture_image: This image is the texture to layer on the background.
2330 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
2331 ExceptionInfo *exception)
2333 #define TextureImageTag "Texture/Image"
2348 assert(image != (Image *) NULL);
2349 if (image->debug != MagickFalse)
2350 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2351 assert(image->signature == MagickSignature);
2352 if (texture == (const Image *) NULL)
2353 return(MagickFalse);
2354 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2355 return(MagickFalse);
2356 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2357 if (texture_image == (const Image *) NULL)
2358 return(MagickFalse);
2359 (void) TransformImageColorspace(texture_image,image->colorspace,exception);
2360 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
2363 if ((image->compose != CopyCompositeOp) &&
2364 ((image->compose != OverCompositeOp) ||
2365 (image->alpha_trait == BlendPixelTrait) ||
2366 (texture_image->alpha_trait == BlendPixelTrait)))
2369 Tile texture onto the image background.
2371 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2376 if (status == MagickFalse)
2378 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2383 thread_status=CompositeImage(image,texture_image,image->compose,
2384 MagickFalse,x+texture_image->tile_offset.x,y+
2385 texture_image->tile_offset.y,exception);
2386 if (thread_status == MagickFalse)
2388 status=thread_status;
2392 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2397 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2399 if (proceed == MagickFalse)
2403 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2404 image->rows,image->rows);
2405 texture_image=DestroyImage(texture_image);
2409 Tile texture onto the image background (optimized).
2412 texture_view=AcquireVirtualCacheView(texture_image,exception);
2413 image_view=AcquireAuthenticCacheView(image,exception);
2414 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2415 #pragma omp parallel for schedule(static,4) shared(status) \
2416 magick_threads(texture_image,image,1,1)
2418 for (y=0; y < (ssize_t) image->rows; y++)
2423 register const Quantum
2436 if (status == MagickFalse)
2438 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2439 (y+texture_image->tile_offset.y) % texture_image->rows,
2440 texture_image->columns,1,exception);
2441 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2442 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2447 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2453 width=texture_image->columns;
2454 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2455 width=image->columns-x;
2456 for (j=0; j < (ssize_t) width; j++)
2461 if (GetPixelReadMask(image,q) == 0)
2463 p+=GetPixelChannels(texture_image);
2464 q+=GetPixelChannels(image);
2467 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2469 PixelChannel channel=GetPixelChannelChannel(texture_image,i);
2470 PixelTrait traits=GetPixelChannelTraits(image,channel);
2471 PixelTrait texture_traits=GetPixelChannelTraits(texture_image,
2473 if ((traits == UndefinedPixelTrait) ||
2474 (texture_traits == UndefinedPixelTrait))
2476 SetPixelChannel(image,channel,p[i],q);
2478 p+=GetPixelChannels(texture_image);
2479 q+=GetPixelChannels(image);
2482 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2483 if (sync == MagickFalse)
2485 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2490 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2492 if (proceed == MagickFalse)
2496 texture_view=DestroyCacheView(texture_view);
2497 image_view=DestroyCacheView(image_view);
2498 texture_image=DestroyImage(texture_image);