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-2015 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 '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 void HCLComposite(const MagickRealType hue,const MagickRealType chroma,
198 const MagickRealType luma,MagickRealType *red,MagickRealType *green,
199 MagickRealType *blue)
211 Convert HCL to RGB colorspace.
213 assert(red != (MagickRealType *) NULL);
214 assert(green != (MagickRealType *) NULL);
215 assert(blue != (MagickRealType *) NULL);
218 x=c*(1.0-fabs(fmod(h,2.0)-1.0));
222 if ((0.0 <= h) && (h < 1.0))
228 if ((1.0 <= h) && (h < 2.0))
234 if ((2.0 <= h) && (h < 3.0))
240 if ((3.0 <= h) && (h < 4.0))
246 if ((4.0 <= h) && (h < 5.0))
252 if ((5.0 <= h) && (h < 6.0))
257 m=luma-(0.298839*r+0.586811*g+0.114350*b);
258 *red=QuantumRange*(r+m);
259 *green=QuantumRange*(g+m);
260 *blue=QuantumRange*(b+m);
263 static void CompositeHCL(const MagickRealType red,const MagickRealType green,
264 const MagickRealType blue,MagickRealType *hue,MagickRealType *chroma,
265 MagickRealType *luma)
276 Convert RGB to HCL colorspace.
278 assert(hue != (MagickRealType *) NULL);
279 assert(chroma != (MagickRealType *) NULL);
280 assert(luma != (MagickRealType *) NULL);
284 max=MagickMax(r,MagickMax(g,b));
285 c=max-(MagickRealType) MagickMin(r,MagickMin(g,b));
291 h=fmod((g-b)/c+6.0,6.0);
299 *chroma=QuantumScale*c;
300 *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
303 static MagickBooleanType CompositeOverImage(Image *image,
304 const Image *composite_image,const MagickBooleanType clip_to_self,
305 const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
307 #define CompositeImageTag "Composite/Image"
327 composite_view=AcquireVirtualCacheView(composite_image,exception);
328 image_view=AcquireAuthenticCacheView(image,exception);
329 #if defined(MAGICKCORE_OPENMP_SUPPORT)
330 #pragma omp parallel for schedule(static,4) shared(progress,status) \
331 magick_threads(composite_image,image,image->rows,1)
333 for (y=0; y < (ssize_t) image->rows; y++)
338 register const Quantum
350 if (status == MagickFalse)
352 if (clip_to_self != MagickFalse)
356 if ((y-y_offset) >= (ssize_t) composite_image->rows)
360 If pixels is NULL, y is outside overlay region.
362 pixels=(Quantum *) NULL;
364 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
366 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
367 composite_image->columns,1,exception);
368 if (p == (const Quantum *) NULL)
375 p-=x_offset*GetPixelChannels(composite_image);
377 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
378 if (q == (Quantum *) NULL)
383 for (x=0; x < (ssize_t) image->columns; x++)
398 if (clip_to_self != MagickFalse)
402 q+=GetPixelChannels(image);
405 if ((x-x_offset) >= (ssize_t) composite_image->columns)
408 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
409 ((x-x_offset) >= (ssize_t) composite_image->columns))
412 source[MaxPixelChannels];
417 Dc: destination color.
419 if (GetPixelReadMask(image,q) == 0)
421 q+=GetPixelChannels(image);
424 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
426 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
428 PixelChannel channel=GetPixelChannelChannel(image,i);
429 PixelTrait traits=GetPixelChannelTraits(image,channel);
430 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
432 if ((traits == UndefinedPixelTrait) ||
433 (composite_traits == UndefinedPixelTrait))
435 q[i]=source[channel];
437 q+=GetPixelChannels(image);
442 Sa: normalized source alpha.
443 Da: normalized destination alpha.
445 if (GetPixelReadMask(composite_image,p) == 0)
447 p+=GetPixelChannels(composite_image);
448 channels=GetPixelChannels(composite_image);
449 if (p >= (pixels+channels*composite_image->columns))
451 q+=GetPixelChannels(image);
454 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
455 Da=QuantumScale*GetPixelAlpha(image,q);
456 alpha=Sa*(-Da)+Sa+Da;
457 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
459 PixelChannel channel=GetPixelChannelChannel(image,i);
460 PixelTrait traits=GetPixelChannelTraits(image,channel);
461 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
463 if ((traits == UndefinedPixelTrait) ||
464 (composite_traits == UndefinedPixelTrait))
466 if ((traits & CopyPixelTrait) != 0)
468 if (channel != AlphaPixelChannel)
473 q[i]=GetPixelChannel(composite_image,channel,p);
479 q[i]=ClampToQuantum(QuantumRange*alpha);
484 Dc: destination color.
486 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
487 Dc=(MagickRealType) q[i];
488 gamma=PerceptibleReciprocal(alpha);
489 q[i]=ClampToQuantum(gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc));
491 p+=GetPixelChannels(composite_image);
492 channels=GetPixelChannels(composite_image);
493 if (p >= (pixels+channels*composite_image->columns))
495 q+=GetPixelChannels(image);
497 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
499 if (image->progress_monitor != (MagickProgressMonitor) NULL)
504 #if defined(MAGICKCORE_OPENMP_SUPPORT)
505 #pragma omp critical (MagickCore_CompositeImage)
507 proceed=SetImageProgress(image,CompositeImageTag,progress++,
509 if (proceed == MagickFalse)
513 composite_view=DestroyCacheView(composite_view);
514 image_view=DestroyCacheView(image_view);
518 MagickExport MagickBooleanType CompositeImage(Image *image,
519 const Image *composite,const CompositeOperator compose,
520 const MagickBooleanType clip_to_self,const ssize_t x_offset,
521 const ssize_t y_offset,ExceptionInfo *exception)
523 #define CompositeImageTag "Composite/Image"
544 destination_dissolve,
557 assert(image != (Image *) NULL);
558 assert(image->signature == MagickSignature);
559 if (image->debug != MagickFalse)
560 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
561 assert(composite!= (Image *) NULL);
562 assert(composite->signature == MagickSignature);
563 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
565 composite_image=CloneImage(composite,0,0,MagickTrue,exception);
566 if (composite_image == (const Image *) NULL)
568 if (IsGrayColorspace(image->colorspace) != MagickFalse)
569 (void) SetImageColorspace(image,sRGBColorspace,exception);
570 (void) SetImageColorspace(composite_image,image->colorspace,exception);
571 if (image->alpha_trait == UndefinedPixelTrait)
572 (void) SetImageAlphaChannel(image,SetAlphaChannel,exception);
573 if (composite_image->alpha_trait == UndefinedPixelTrait)
574 (void) SetImageAlphaChannel(composite_image,SetAlphaChannel,exception);
575 if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
577 status=CompositeOverImage(image,composite_image,clip_to_self,x_offset,
579 composite_image=DestroyImage(composite_image);
582 destination_image=(Image *) NULL;
584 destination_dissolve=1.0;
586 percent_chroma=100.0;
591 case CopyCompositeOp:
593 if ((x_offset < 0) || (y_offset < 0))
595 if ((x_offset+(ssize_t) composite_image->columns) > (ssize_t) image->columns)
597 if ((y_offset+(ssize_t) composite_image->rows) > (ssize_t) image->rows)
600 composite_view=AcquireVirtualCacheView(composite_image,exception);
601 image_view=AcquireAuthenticCacheView(image,exception);
602 #if defined(MAGICKCORE_OPENMP_SUPPORT)
603 #pragma omp parallel for schedule(static,4) shared(status) \
604 magick_threads(composite_image,image,composite_image->rows,1)
606 for (y=0; y < (ssize_t) composite_image->rows; y++)
611 register const Quantum
620 if (status == MagickFalse)
622 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
624 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
625 composite_image->columns,1,exception);
626 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
631 for (x=0; x < (ssize_t) composite_image->columns; x++)
636 if (GetPixelReadMask(composite_image,p) == 0)
638 p+=GetPixelChannels(composite_image);
639 q+=GetPixelChannels(image);
642 for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
644 PixelChannel channel=GetPixelChannelChannel(composite_image,i);
645 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
647 PixelTrait traits=GetPixelChannelTraits(image,channel);
648 if ((traits == UndefinedPixelTrait) ||
649 (composite_traits == UndefinedPixelTrait))
651 SetPixelChannel(image,channel,p[i],q);
653 p+=GetPixelChannels(composite_image);
654 q+=GetPixelChannels(image);
656 sync=SyncCacheViewAuthenticPixels(image_view,exception);
657 if (sync == MagickFalse)
659 if (image->progress_monitor != (MagickProgressMonitor) NULL)
664 #if defined(MAGICKCORE_OPENMP_SUPPORT)
665 #pragma omp critical (MagickCore_CompositeImage)
667 proceed=SetImageProgress(image,CompositeImageTag,
668 (MagickOffsetType) y,image->rows);
669 if (proceed == MagickFalse)
673 composite_view=DestroyCacheView(composite_view);
674 image_view=DestroyCacheView(image_view);
675 composite_image=DestroyImage(composite_image);
678 case IntensityCompositeOp:
680 if ((x_offset < 0) || (y_offset < 0))
682 if ((x_offset+(ssize_t) composite_image->columns) > (ssize_t) image->columns)
684 if ((y_offset+(ssize_t) composite_image->rows) > (ssize_t) image->rows)
687 composite_view=AcquireVirtualCacheView(composite_image,exception);
688 image_view=AcquireAuthenticCacheView(image,exception);
689 #if defined(MAGICKCORE_OPENMP_SUPPORT)
690 #pragma omp parallel for schedule(static,4) shared(status) \
691 magick_threads(composite_image,image,composite_image->rows,1)
693 for (y=0; y < (ssize_t) composite_image->rows; y++)
698 register const Quantum
707 if (status == MagickFalse)
709 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
711 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
712 composite_image->columns,1,exception);
713 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
718 for (x=0; x < (ssize_t) composite_image->columns; x++)
723 if (GetPixelReadMask(composite_image,p) == 0)
725 p+=GetPixelChannels(composite_image);
726 q+=GetPixelChannels(image);
729 for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
730 SetPixelAlpha(image,GetPixelIntensity(composite_image,p),q);
731 p+=GetPixelChannels(composite_image);
732 q+=GetPixelChannels(image);
734 sync=SyncCacheViewAuthenticPixels(image_view,exception);
735 if (sync == MagickFalse)
737 if (image->progress_monitor != (MagickProgressMonitor) NULL)
742 #if defined(MAGICKCORE_OPENMP_SUPPORT)
743 #pragma omp critical (MagickCore_CompositeImage)
745 proceed=SetImageProgress(image,CompositeImageTag,
746 (MagickOffsetType) y,image->rows);
747 if (proceed == MagickFalse)
751 composite_view=DestroyCacheView(composite_view);
752 image_view=DestroyCacheView(image_view);
753 composite_image=DestroyImage(composite_image);
756 case CopyAlphaCompositeOp:
757 case ChangeMaskCompositeOp:
760 Modify destination outside the overlaid region and require an alpha
761 channel to exist, to add transparency.
763 if (image->alpha_trait != BlendPixelTrait)
764 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
765 SetPixelAlphaTraits(image,CopyPixelTrait);
768 case BlurCompositeOp:
793 Blur Image by resampling.
795 Blur Image dictated by an overlay gradient map: X = red_channel;
796 Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
798 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
800 if (destination_image == (Image *) NULL)
802 composite_image=DestroyImage(composite_image);
806 Gather the maximum blur sigma values from user.
808 SetGeometryInfo(&geometry_info);
810 value=GetImageArtifact(image,"compose:args");
811 if (value != (const char *) NULL)
812 flags=ParseGeometry(value,&geometry_info);
813 if ((flags & WidthValue) == 0)
815 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
816 "InvalidSetting","'%s' '%s'","compose:args",value);
817 composite_image=DestroyImage(composite_image);
818 destination_image=DestroyImage(destination_image);
822 Users input sigma now needs to be converted to the EWA ellipse size.
823 The filter defaults to a sigma of 0.5 so to make this match the
824 users input the ellipse size needs to be doubled.
826 width=height=geometry_info.rho*2.0;
827 if ((flags & HeightValue) != 0 )
828 height=geometry_info.sigma*2.0;
830 Default the unrotated ellipse width and height axis vectors.
836 /* rotate vectors if a rotation angle is given */
837 if ((flags & XValue) != 0 )
842 angle=DegreesToRadians(geometry_info.xi);
843 blur.x1=width*cos(angle);
844 blur.x2=width*sin(angle);
845 blur.y1=(-height*sin(angle));
846 blur.y2=height*cos(angle);
848 /* Otherwise lets set a angle range and calculate in the loop */
851 if ((flags & YValue) != 0 )
853 angle_start=DegreesToRadians(geometry_info.xi);
854 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
857 Set up a gaussian cylindrical filter for EWA Bluring.
859 As the minimum ellipse radius of support*1.0 the EWA algorithm
860 can only produce a minimum blur of 0.5 for Gaussian (support=2.0)
861 This means that even 'No Blur' will be still a little blurry!
863 The solution (as well as the problem of preventing any user
864 expert filter settings, is to set our own user settings, then
865 restore them afterwards.
867 resample_filter=AcquireResampleFilter(image,exception);
868 SetResampleFilter(resample_filter,GaussianFilter);
870 /* do the variable blurring of each pixel in image */
871 GetPixelInfo(image,&pixel);
872 composite_view=AcquireVirtualCacheView(composite_image,exception);
873 destination_view=AcquireAuthenticCacheView(destination_image,exception);
874 for (y=0; y < (ssize_t) composite_image->rows; y++)
879 register const Quantum
888 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
890 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
892 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
893 destination_image->columns,1,exception);
894 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
896 for (x=0; x < (ssize_t) composite_image->columns; x++)
898 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
900 p+=GetPixelChannels(composite_image);
903 if (fabs(angle_range) > MagickEpsilon)
908 angle=angle_start+angle_range*QuantumScale*
909 GetPixelBlue(composite_image,p);
910 blur.x1=width*cos(angle);
911 blur.x2=width*sin(angle);
912 blur.y1=(-height*sin(angle));
913 blur.y2=height*cos(angle);
916 if ( x == 10 && y == 60 ) {
917 (void) fprintf(stderr, "blur.x=%lf,%lf, blur.y=%lf,%lf\n",blur.x1,
918 blur.x2,blur.y1, blur.y2);
919 (void) fprintf(stderr, "scaled by=%lf,%lf\n",QuantumScale*
920 GetPixelRed(p),QuantumScale*GetPixelGreen(p));
922 ScaleResampleFilter(resample_filter,
923 blur.x1*QuantumScale*GetPixelRed(composite_image,p),
924 blur.y1*QuantumScale*GetPixelGreen(composite_image,p),
925 blur.x2*QuantumScale*GetPixelRed(composite_image,p),
926 blur.y2*QuantumScale*GetPixelGreen(composite_image,p) );
927 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
928 (double) y_offset+y,&pixel,exception);
929 SetPixelInfoPixel(destination_image,&pixel,q);
930 p+=GetPixelChannels(composite_image);
931 q+=GetPixelChannels(destination_image);
933 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
934 if (sync == MagickFalse)
937 resample_filter=DestroyResampleFilter(resample_filter);
938 composite_view=DestroyCacheView(composite_view);
939 destination_view=DestroyCacheView(destination_view);
940 composite_image=DestroyImage(composite_image);
941 composite_image=destination_image;
944 case DisplaceCompositeOp:
945 case DistortCompositeOp:
967 Displace/Distort based on overlay gradient map:
968 X = red_channel; Y = green_channel;
969 compose:args = x_scale[,y_scale[,center.x,center.y]]
971 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
973 if (destination_image == (Image *) NULL)
975 composite_image=DestroyImage(composite_image);
978 SetGeometryInfo(&geometry_info);
980 value=GetImageArtifact(image,"compose:args");
981 if (value != (char *) NULL)
982 flags=ParseGeometry(value,&geometry_info);
983 if ((flags & (WidthValue|HeightValue)) == 0 )
985 if ((flags & AspectValue) == 0)
987 horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
989 vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
993 horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
994 vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
999 horizontal_scale=geometry_info.rho;
1000 vertical_scale=geometry_info.sigma;
1001 if ((flags & PercentValue) != 0)
1003 if ((flags & AspectValue) == 0)
1005 horizontal_scale*=(composite_image->columns-1.0)/200.0;
1006 vertical_scale*=(composite_image->rows-1.0)/200.0;
1010 horizontal_scale*=(image->columns-1.0)/200.0;
1011 vertical_scale*=(image->rows-1.0)/200.0;
1014 if ((flags & HeightValue) == 0)
1015 vertical_scale=horizontal_scale;
1018 Determine fixed center point for absolute distortion map
1020 Displace offset relative to a fixed absolute point
1021 Select that point according to +X+Y user inputs.
1022 default = center of overlay image
1023 arg flag '!' = locations/percentage relative to background image
1025 center.x=(MagickRealType) x_offset;
1026 center.y=(MagickRealType) y_offset;
1027 if (compose == DistortCompositeOp)
1029 if ((flags & XValue) == 0)
1030 if ((flags & AspectValue) == 0)
1031 center.x=(MagickRealType) (x_offset+(composite_image->columns-1)/
1034 center.x=(MagickRealType) ((image->columns-1)/2);
1036 if ((flags & AspectValue) == 0)
1037 center.x=(MagickRealType) x_offset+geometry_info.xi;
1039 center.x=geometry_info.xi;
1040 if ((flags & YValue) == 0)
1041 if ((flags & AspectValue) == 0)
1042 center.y=(MagickRealType) (y_offset+(composite_image->rows-1)/
1045 center.y=(MagickRealType) ((image->rows-1)/2);
1047 if ((flags & AspectValue) == 0)
1048 center.y=(MagickRealType) y_offset+geometry_info.psi;
1050 center.y=geometry_info.psi;
1053 Shift the pixel offset point as defined by the provided,
1054 displacement/distortion map. -- Like a lens...
1056 GetPixelInfo(image,&pixel);
1057 image_view=AcquireVirtualCacheView(image,exception);
1058 composite_view=AcquireVirtualCacheView(composite_image,exception);
1059 destination_view=AcquireAuthenticCacheView(destination_image,exception);
1060 for (y=0; y < (ssize_t) composite_image->rows; y++)
1065 register const Quantum
1074 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1076 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
1078 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
1079 destination_image->columns,1,exception);
1080 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1082 for (x=0; x < (ssize_t) composite_image->columns; x++)
1084 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1086 p+=GetPixelChannels(composite_image);
1090 Displace the offset.
1092 offset.x=(double) (horizontal_scale*(GetPixelRed(composite_image,p)-
1093 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1094 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
1096 offset.y=(double) (vertical_scale*(GetPixelGreen(composite_image,p)-
1097 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1098 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
1100 (void) InterpolatePixelInfo(image,image_view,
1101 UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1104 Mask with the 'invalid pixel mask' in alpha channel.
1106 pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
1107 pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
1108 SetPixelInfoPixel(destination_image,&pixel,q);
1109 p+=GetPixelChannels(composite_image);
1110 q+=GetPixelChannels(destination_image);
1112 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1113 if (sync == MagickFalse)
1116 destination_view=DestroyCacheView(destination_view);
1117 composite_view=DestroyCacheView(composite_view);
1118 image_view=DestroyCacheView(image_view);
1119 composite_image=DestroyImage(composite_image);
1120 composite_image=destination_image;
1123 case DissolveCompositeOp:
1129 Geometry arguments to dissolve factors.
1131 value=GetImageArtifact(image,"compose:args");
1132 if (value != (char *) NULL)
1134 flags=ParseGeometry(value,&geometry_info);
1135 source_dissolve=geometry_info.rho/100.0;
1136 destination_dissolve=1.0;
1137 if ((source_dissolve-MagickEpsilon) < 0.0)
1138 source_dissolve=0.0;
1139 if ((source_dissolve+MagickEpsilon) > 1.0)
1141 destination_dissolve=2.0-source_dissolve;
1142 source_dissolve=1.0;
1144 if ((flags & SigmaValue) != 0)
1145 destination_dissolve=geometry_info.sigma/100.0;
1146 if ((destination_dissolve-MagickEpsilon) < 0.0)
1147 destination_dissolve=0.0;
1151 case BlendCompositeOp:
1156 value=GetImageArtifact(image,"compose:args");
1157 if (value != (char *) NULL)
1159 flags=ParseGeometry(value,&geometry_info);
1160 source_dissolve=geometry_info.rho/100.0;
1161 destination_dissolve=1.0-source_dissolve;
1162 if ((flags & SigmaValue) != 0)
1163 destination_dissolve=geometry_info.sigma/100.0;
1167 case MathematicsCompositeOp:
1173 Just collect the values from "compose:args", setting.
1174 Unused values are set to zero automagically.
1176 Arguments are normally a comma separated list, so this probably should
1177 be changed to some 'general comma list' parser, (with a minimum
1180 SetGeometryInfo(&geometry_info);
1181 value=GetImageArtifact(image,"compose:args");
1182 if (value != (char *) NULL)
1183 (void) ParseGeometry(value,&geometry_info);
1186 case ModulateCompositeOp:
1192 Determine the luma and chroma scale.
1194 value=GetImageArtifact(image,"compose:args");
1195 if (value != (char *) NULL)
1197 flags=ParseGeometry(value,&geometry_info);
1198 percent_luma=geometry_info.rho;
1199 if ((flags & SigmaValue) != 0)
1200 percent_chroma=geometry_info.sigma;
1204 case ThresholdCompositeOp:
1210 Determine the amount and threshold.
1212 value=GetImageArtifact(image,"compose:args");
1213 if (value != (char *) NULL)
1215 flags=ParseGeometry(value,&geometry_info);
1216 amount=geometry_info.rho;
1217 threshold=geometry_info.sigma;
1218 if ((flags & SigmaValue) == 0)
1221 threshold*=QuantumRange;
1232 midpoint=((MagickRealType) QuantumRange+1.0)/2;
1233 composite_view=AcquireVirtualCacheView(composite_image,exception);
1234 image_view=AcquireAuthenticCacheView(image,exception);
1235 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1236 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1237 magick_threads(composite_image,image,image->rows,1)
1239 for (y=0; y < (ssize_t) image->rows; y++)
1256 register const Quantum
1265 if (status == MagickFalse)
1267 if (clip_to_self != MagickFalse)
1271 if ((y-y_offset) >= (ssize_t) composite_image->rows)
1275 If pixels is NULL, y is outside overlay region.
1277 pixels=(Quantum *) NULL;
1279 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
1281 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
1282 composite_image->columns,1,exception);
1283 if (p == (const Quantum *) NULL)
1290 p-=x_offset*GetPixelChannels(composite_image);
1292 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1293 if (q == (Quantum *) NULL)
1301 GetPixelInfo(image,&destination_pixel);
1302 GetPixelInfo(composite_image,&source_pixel);
1303 for (x=0; x < (ssize_t) image->columns; x++)
1323 if (clip_to_self != MagickFalse)
1327 q+=GetPixelChannels(image);
1330 if ((x-x_offset) >= (ssize_t) composite_image->columns)
1333 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1334 ((x-x_offset) >= (ssize_t) composite_image->columns))
1337 source[MaxPixelChannels];
1342 Dc: destination color.
1344 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
1346 if (GetPixelReadMask(image,q) == 0)
1348 q+=GetPixelChannels(image);
1351 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1356 PixelChannel channel=GetPixelChannelChannel(image,i);
1357 PixelTrait traits=GetPixelChannelTraits(image,channel);
1358 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
1360 if ((traits == UndefinedPixelTrait) ||
1361 (composite_traits == UndefinedPixelTrait))
1365 case AlphaCompositeOp:
1366 case ChangeMaskCompositeOp:
1367 case CopyAlphaCompositeOp:
1368 case DstAtopCompositeOp:
1369 case DstInCompositeOp:
1371 case OutCompositeOp:
1372 case SrcInCompositeOp:
1373 case SrcOutCompositeOp:
1375 pixel=(MagickRealType) q[i];
1376 if (channel == AlphaPixelChannel)
1377 pixel=(MagickRealType) TransparentAlpha;
1380 case ClearCompositeOp:
1381 case CopyCompositeOp:
1382 case ReplaceCompositeOp:
1383 case SrcCompositeOp:
1385 if (channel == AlphaPixelChannel)
1387 pixel=(MagickRealType) TransparentAlpha;
1393 case BlendCompositeOp:
1394 case DissolveCompositeOp:
1396 if (channel == AlphaPixelChannel)
1398 pixel=destination_dissolve*GetPixelAlpha(composite_image,
1402 pixel=(MagickRealType) source[channel];
1407 pixel=(MagickRealType) source[channel];
1411 q[i]=ClampToQuantum(pixel);
1413 q+=GetPixelChannels(image);
1417 Authentic composite:
1418 Sa: normalized source alpha.
1419 Da: normalized destination alpha.
1421 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
1422 Da=QuantumScale*GetPixelAlpha(image,q);
1425 case BumpmapCompositeOp:
1427 alpha=GetPixelIntensity(composite_image,p)*Sa;
1430 case ColorBurnCompositeOp:
1431 case ColorDodgeCompositeOp:
1432 case DifferenceCompositeOp:
1433 case DivideDstCompositeOp:
1434 case DivideSrcCompositeOp:
1435 case ExclusionCompositeOp:
1436 case HardLightCompositeOp:
1437 case HardMixCompositeOp:
1438 case LinearBurnCompositeOp:
1439 case LinearDodgeCompositeOp:
1440 case LinearLightCompositeOp:
1441 case MathematicsCompositeOp:
1442 case MinusDstCompositeOp:
1443 case MinusSrcCompositeOp:
1444 case ModulusAddCompositeOp:
1445 case ModulusSubtractCompositeOp:
1446 case MultiplyCompositeOp:
1447 case OverlayCompositeOp:
1448 case PegtopLightCompositeOp:
1449 case PinLightCompositeOp:
1450 case ScreenCompositeOp:
1451 case SoftLightCompositeOp:
1452 case VividLightCompositeOp:
1454 alpha=RoundToUnity(Sa+Da-Sa*Da);
1457 case DarkenCompositeOp:
1458 case DstAtopCompositeOp:
1459 case DstInCompositeOp:
1461 case LightenCompositeOp:
1462 case SrcInCompositeOp:
1467 case DissolveCompositeOp:
1469 alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
1470 Sa+destination_dissolve*Da;
1473 case DstOverCompositeOp:
1475 alpha=Da*(-Sa)+Da+Sa;
1478 case DstOutCompositeOp:
1483 case OutCompositeOp:
1484 case SrcOutCompositeOp:
1489 case OverCompositeOp:
1490 case SrcOverCompositeOp:
1492 alpha=Sa*(-Da)+Sa+Da;
1495 case BlendCompositeOp:
1496 case PlusCompositeOp:
1498 alpha=RoundToUnity(Sa+Da);
1501 case XorCompositeOp:
1503 alpha=Sa+Da-2.0*Sa*Da;
1512 if (GetPixelReadMask(image,q) == 0)
1514 p+=GetPixelChannels(composite_image);
1515 q+=GetPixelChannels(image);
1520 case ColorizeCompositeOp:
1521 case HueCompositeOp:
1522 case LuminizeCompositeOp:
1523 case ModulateCompositeOp:
1524 case SaturateCompositeOp:
1526 GetPixelInfoPixel(composite_image,p,&source_pixel);
1527 GetPixelInfoPixel(image,q,&destination_pixel);
1533 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1539 PixelChannel channel=GetPixelChannelChannel(image,i);
1540 PixelTrait traits=GetPixelChannelTraits(image,channel);
1541 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
1543 if (traits == UndefinedPixelTrait)
1545 if (composite_traits == UndefinedPixelTrait)
1549 Dc: destination color.
1551 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
1552 Dc=(MagickRealType) q[i];
1553 if ((traits & CopyPixelTrait) != 0)
1555 if (channel != AlphaPixelChannel)
1560 q[i]=ClampToQuantum(Sc);
1568 case AlphaCompositeOp:
1570 pixel=QuantumRange*Sa;
1573 case AtopCompositeOp:
1574 case CopyBlackCompositeOp:
1575 case CopyBlueCompositeOp:
1576 case CopyCyanCompositeOp:
1577 case CopyGreenCompositeOp:
1578 case CopyMagentaCompositeOp:
1579 case CopyRedCompositeOp:
1580 case CopyYellowCompositeOp:
1581 case SrcAtopCompositeOp:
1582 case DstCompositeOp:
1585 pixel=QuantumRange*Da;
1588 case ChangeMaskCompositeOp:
1593 if (Da > ((MagickRealType) QuantumRange/2.0))
1595 pixel=(MagickRealType) TransparentAlpha;
1598 equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
1599 if (equivalent != MagickFalse)
1601 pixel=(MagickRealType) TransparentAlpha;
1604 pixel=(MagickRealType) OpaqueAlpha;
1607 case ClearCompositeOp:
1609 pixel=(MagickRealType) TransparentAlpha;
1612 case ColorizeCompositeOp:
1613 case HueCompositeOp:
1614 case LuminizeCompositeOp:
1615 case SaturateCompositeOp:
1617 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1619 pixel=QuantumRange*Da;
1622 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1624 pixel=QuantumRange*Sa;
1629 pixel=QuantumRange*Da;
1632 pixel=QuantumRange*Sa;
1635 case CopyAlphaCompositeOp:
1637 pixel=QuantumRange*Sa;
1638 if (composite_image->alpha_trait != BlendPixelTrait)
1639 pixel=GetPixelIntensity(composite_image,p);
1642 case CopyCompositeOp:
1643 case DisplaceCompositeOp:
1644 case DistortCompositeOp:
1645 case DstAtopCompositeOp:
1646 case ReplaceCompositeOp:
1647 case SrcCompositeOp:
1649 pixel=QuantumRange*Sa;
1652 case DarkenIntensityCompositeOp:
1654 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1655 (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
1658 case LightenIntensityCompositeOp:
1660 pixel=Sa*GetPixelIntensity(composite_image,p) >
1661 Da*GetPixelIntensity(image,q) ? Sa : Da;
1664 case ModulateCompositeOp:
1666 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1668 pixel=QuantumRange*Da;
1671 pixel=QuantumRange*Da;
1676 pixel=QuantumRange*alpha;
1680 q[i]=ClampToQuantum(pixel);
1684 Porter-Duff compositions:
1685 Sca: source normalized color multiplied by alpha.
1686 Dca: normalized destination color multiplied by alpha.
1688 Sca=QuantumScale*Sa*Sc;
1689 Dca=QuantumScale*Da*Dc;
1692 case DarkenCompositeOp:
1693 case LightenCompositeOp:
1694 case ModulusSubtractCompositeOp:
1702 gamma=PerceptibleReciprocal(alpha);
1706 case AlphaCompositeOp:
1708 pixel=QuantumRange*Sa;
1711 case AtopCompositeOp:
1712 case SrcAtopCompositeOp:
1714 pixel=Sc*Sa+Dc*(1.0-Sa);
1717 case BlendCompositeOp:
1719 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1722 case BlurCompositeOp:
1723 case DisplaceCompositeOp:
1724 case DistortCompositeOp:
1725 case CopyCompositeOp:
1726 case ReplaceCompositeOp:
1727 case SrcCompositeOp:
1732 case BumpmapCompositeOp:
1734 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1739 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1742 case ChangeMaskCompositeOp:
1747 case ClearCompositeOp:
1752 case ColorBurnCompositeOp:
1755 Refer to the March 2009 SVG specification.
1757 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1759 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1762 if (Sca < MagickEpsilon)
1764 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1767 pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
1768 Sca*(1.0-Da)+Dca*(1.0-Sa));
1771 case ColorDodgeCompositeOp:
1773 if ((Sca*Da+Dca*Sa) >= Sa*Da)
1775 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1778 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1782 case ColorizeCompositeOp:
1784 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1789 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1794 CompositeHCL(destination_pixel.red,destination_pixel.green,
1795 destination_pixel.blue,&sans,&sans,&luma);
1796 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1797 &hue,&chroma,&sans);
1798 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1801 case RedPixelChannel: pixel=red; break;
1802 case GreenPixelChannel: pixel=green; break;
1803 case BluePixelChannel: pixel=blue; break;
1804 default: pixel=Dc; break;
1808 case CopyAlphaCompositeOp:
1813 case CopyBlackCompositeOp:
1815 if (channel == BlackPixelChannel)
1816 pixel=(MagickRealType) (QuantumRange-
1817 GetPixelBlack(composite_image,p));
1820 case CopyBlueCompositeOp:
1821 case CopyYellowCompositeOp:
1823 if (channel == BluePixelChannel)
1824 pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1827 case CopyGreenCompositeOp:
1828 case CopyMagentaCompositeOp:
1830 if (channel == GreenPixelChannel)
1831 pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1834 case CopyRedCompositeOp:
1835 case CopyCyanCompositeOp:
1837 if (channel == RedPixelChannel)
1838 pixel=(MagickRealType) GetPixelRed(composite_image,p);
1841 case DarkenCompositeOp:
1844 Darken is equivalent to a 'Minimum' method
1845 OR a greyscale version of a binary 'Or'
1846 OR the 'Intersection' of pixel sets.
1850 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1853 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1856 case DarkenIntensityCompositeOp:
1858 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1859 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1862 case DifferenceCompositeOp:
1864 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1867 case DissolveCompositeOp:
1869 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1870 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1873 case DivideDstCompositeOp:
1875 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1877 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1880 if (fabs(Dca) < MagickEpsilon)
1882 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1885 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1888 case DivideSrcCompositeOp:
1890 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1892 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1895 if (fabs(Sca) < MagickEpsilon)
1897 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1900 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1903 case DstAtopCompositeOp:
1905 pixel=Dc*Da+Sc*(1.0-Da);
1908 case DstCompositeOp:
1914 case DstInCompositeOp:
1916 pixel=gamma*(Sa*Dc*Sa);
1919 case DstOutCompositeOp:
1921 pixel=gamma*(Da*Dc*(1.0-Sa));
1924 case DstOverCompositeOp:
1926 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1929 case ExclusionCompositeOp:
1931 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1935 case HardLightCompositeOp:
1939 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1943 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1947 case HardMixCompositeOp:
1956 pixel=(gamma*(1.0-Sca)*(1.0-Dca))+Sa*(1.0-Sca)*Dca+Da*(1.0-Dca)*Sca;
1959 case HueCompositeOp:
1961 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1966 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1971 CompositeHCL(destination_pixel.red,destination_pixel.green,
1972 destination_pixel.blue,&hue,&chroma,&luma);
1973 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1975 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1978 case RedPixelChannel: pixel=red; break;
1979 case GreenPixelChannel: pixel=green; break;
1980 case BluePixelChannel: pixel=blue; break;
1981 default: pixel=Dc; break;
1986 case SrcInCompositeOp:
1988 pixel=gamma*(Da*Sc*Da);
1991 case LinearBurnCompositeOp:
1994 LinearBurn: as defined by Abode Photoshop, according to
1995 http://www.simplefilter.de/en/basics/mixmods.html is:
1997 f(Sc,Dc) = Sc + Dc - 1
1999 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
2002 case LinearDodgeCompositeOp:
2004 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
2007 case LinearLightCompositeOp:
2010 LinearLight: as defined by Abode Photoshop, according to
2011 http://www.simplefilter.de/en/basics/mixmods.html is:
2013 f(Sc,Dc) = Dc + 2*Sc - 1
2015 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
2018 case LightenCompositeOp:
2022 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2025 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
2028 case LightenIntensityCompositeOp:
2031 Lighten is equivalent to a 'Maximum' method
2032 OR a greyscale version of a binary 'And'
2033 OR the 'Union' of pixel sets.
2035 pixel=Sa*GetPixelIntensity(composite_image,p) >
2036 Da*GetPixelIntensity(image,q) ? Sc : Dc;
2039 case LuminizeCompositeOp:
2041 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2046 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2051 CompositeHCL(destination_pixel.red,destination_pixel.green,
2052 destination_pixel.blue,&hue,&chroma,&luma);
2053 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2055 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2058 case RedPixelChannel: pixel=red; break;
2059 case GreenPixelChannel: pixel=green; break;
2060 case BluePixelChannel: pixel=blue; break;
2061 default: pixel=Dc; break;
2065 case MathematicsCompositeOp:
2068 'Mathematics' a free form user control mathematical composition
2071 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
2073 Where the arguments A,B,C,D are (currently) passed to composite
2074 as a command separated 'geometry' string in "compose:args" image
2077 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
2079 Applying the SVG transparency formula (see above), we get...
2081 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
2083 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
2086 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
2087 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
2088 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
2091 case MinusDstCompositeOp:
2093 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2096 case MinusSrcCompositeOp:
2099 Minus source from destination.
2103 pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2106 case ModulateCompositeOp:
2111 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2116 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
2122 CompositeHCL(destination_pixel.red,destination_pixel.green,
2123 destination_pixel.blue,&hue,&chroma,&luma);
2124 luma+=(0.01*percent_luma*offset)/midpoint;
2125 chroma*=0.01*percent_chroma;
2126 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2129 case RedPixelChannel: pixel=red; break;
2130 case GreenPixelChannel: pixel=green; break;
2131 case BluePixelChannel: pixel=blue; break;
2132 default: pixel=Dc; break;
2136 case ModulusAddCompositeOp:
2139 if (pixel > QuantumRange)
2140 pixel-=QuantumRange;
2141 pixel=gamma*(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2144 case ModulusSubtractCompositeOp:
2148 pixel+=QuantumRange;
2149 pixel=gamma*(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2152 case MultiplyCompositeOp:
2154 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2157 case OutCompositeOp:
2158 case SrcOutCompositeOp:
2160 pixel=gamma*(Sa*Sc*(1.0-Da));
2163 case OverCompositeOp:
2164 case SrcOverCompositeOp:
2166 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2169 case OverlayCompositeOp:
2173 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2177 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2181 case PegtopLightCompositeOp:
2184 PegTop: A Soft-Light alternative: A continuous version of the
2185 Softlight function, producing very similar results.
2187 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2189 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2191 if (fabs(Da) < MagickEpsilon)
2193 pixel=QuantumRange*gamma*(Sca);
2196 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2200 case PinLightCompositeOp:
2203 PinLight: A Photoshop 7 composition method
2204 http://www.simplefilter.de/en/basics/mixmods.html
2206 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2208 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2210 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2213 if ((Dca*Sa) > (2.0*Sca*Da))
2215 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2218 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2221 case PlusCompositeOp:
2223 pixel=gamma*(Sa*Sc+Da*Dc);
2226 case SaturateCompositeOp:
2228 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2233 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2238 CompositeHCL(destination_pixel.red,destination_pixel.green,
2239 destination_pixel.blue,&hue,&chroma,&luma);
2240 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2241 &sans,&chroma,&sans);
2242 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2245 case RedPixelChannel: pixel=red; break;
2246 case GreenPixelChannel: pixel=green; break;
2247 case BluePixelChannel: pixel=blue; break;
2248 default: pixel=Dc; break;
2252 case ScreenCompositeOp:
2255 Screen: a negated multiply:
2257 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2259 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2262 case SoftLightCompositeOp:
2265 Refer to the March 2009 SVG specification.
2269 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2270 Sca*(1.0-Da)+Dca*(1.0-Sa));
2273 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2275 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2276 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2280 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2281 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2284 case ThresholdCompositeOp:
2290 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2295 pixel=gamma*(Dc+delta*amount);
2298 case VividLightCompositeOp:
2301 VividLight: A Photoshop 7 composition method. See
2302 http://www.simplefilter.de/en/basics/mixmods.html.
2304 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2306 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2308 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2311 if ((2.0*Sca) <= Sa)
2313 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2314 (1.0-Da)+Dca*(1.0-Sa));
2317 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2321 case XorCompositeOp:
2323 pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2332 q[i]=ClampToQuantum(pixel);
2334 p+=GetPixelChannels(composite_image);
2335 channels=GetPixelChannels(composite_image);
2336 if (p >= (pixels+channels*composite_image->columns))
2338 q+=GetPixelChannels(image);
2340 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2342 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2347 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2348 #pragma omp critical (MagickCore_CompositeImage)
2350 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2352 if (proceed == MagickFalse)
2356 composite_view=DestroyCacheView(composite_view);
2357 image_view=DestroyCacheView(image_view);
2358 if (destination_image != (Image * ) NULL)
2359 destination_image=DestroyImage(destination_image);
2361 composite_image=DestroyImage(composite_image);
2366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2370 % T e x t u r e I m a g e %
2374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2376 % TextureImage() repeatedly tiles the texture image across and down the image
2379 % The format of the TextureImage method is:
2381 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2382 % ExceptionInfo *exception)
2384 % A description of each parameter follows:
2386 % o image: the image.
2388 % o texture_image: This image is the texture to layer on the background.
2391 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
2392 ExceptionInfo *exception)
2394 #define TextureImageTag "Texture/Image"
2409 assert(image != (Image *) NULL);
2410 if (image->debug != MagickFalse)
2411 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2412 assert(image->signature == MagickSignature);
2413 if (texture == (const Image *) NULL)
2414 return(MagickFalse);
2415 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2416 return(MagickFalse);
2417 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2418 if (texture_image == (const Image *) NULL)
2419 return(MagickFalse);
2420 (void) TransformImageColorspace(texture_image,image->colorspace,exception);
2421 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
2424 if ((image->compose != CopyCompositeOp) &&
2425 ((image->compose != OverCompositeOp) ||
2426 (image->alpha_trait == BlendPixelTrait) ||
2427 (texture_image->alpha_trait == BlendPixelTrait)))
2430 Tile texture onto the image background.
2432 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2437 if (status == MagickFalse)
2439 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2444 thread_status=CompositeImage(image,texture_image,image->compose,
2445 MagickFalse,x+texture_image->tile_offset.x,y+
2446 texture_image->tile_offset.y,exception);
2447 if (thread_status == MagickFalse)
2449 status=thread_status;
2453 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2458 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2460 if (proceed == MagickFalse)
2464 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2465 image->rows,image->rows);
2466 texture_image=DestroyImage(texture_image);
2470 Tile texture onto the image background (optimized).
2473 texture_view=AcquireVirtualCacheView(texture_image,exception);
2474 image_view=AcquireAuthenticCacheView(image,exception);
2475 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2476 #pragma omp parallel for schedule(static,4) shared(status) \
2477 magick_threads(texture_image,image,1,1)
2479 for (y=0; y < (ssize_t) image->rows; y++)
2484 register const Quantum
2497 if (status == MagickFalse)
2499 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2500 (y+texture_image->tile_offset.y) % texture_image->rows,
2501 texture_image->columns,1,exception);
2502 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2503 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2508 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2514 width=texture_image->columns;
2515 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2516 width=image->columns-x;
2517 for (j=0; j < (ssize_t) width; j++)
2522 if (GetPixelReadMask(image,q) == 0)
2524 p+=GetPixelChannels(texture_image);
2525 q+=GetPixelChannels(image);
2528 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2530 PixelChannel channel=GetPixelChannelChannel(texture_image,i);
2531 PixelTrait traits=GetPixelChannelTraits(image,channel);
2532 PixelTrait texture_traits=GetPixelChannelTraits(texture_image,
2534 if ((traits == UndefinedPixelTrait) ||
2535 (texture_traits == UndefinedPixelTrait))
2537 SetPixelChannel(image,channel,p[i],q);
2539 p+=GetPixelChannels(texture_image);
2540 q+=GetPixelChannels(image);
2543 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2544 if (sync == MagickFalse)
2546 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2551 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2553 if (proceed == MagickFalse)
2557 texture_view=DestroyCacheView(texture_view);
2558 image_view=DestroyCacheView(image_view);
2559 texture_image=DestroyImage(texture_image);