2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % CCCC OOO M M PPPP OOO SSSSS IIIII TTTTT EEEEE %
7 % C O O MM MM P P O O SS I T E %
8 % C O O M M M PPPP O O SSS I T EEE %
9 % C O O M M P O O SS I T E %
10 % CCCC OOO M M P OOO SSSSS IIIII T EEEEE %
13 % MagickCore Image Composite Methods %
20 % Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/artifact.h"
45 #include "MagickCore/cache.h"
46 #include "MagickCore/cache-private.h"
47 #include "MagickCore/cache-view.h"
48 #include "MagickCore/channel.h"
49 #include "MagickCore/client.h"
50 #include "MagickCore/color.h"
51 #include "MagickCore/color-private.h"
52 #include "MagickCore/colorspace.h"
53 #include "MagickCore/colorspace-private.h"
54 #include "MagickCore/composite.h"
55 #include "MagickCore/composite-private.h"
56 #include "MagickCore/constitute.h"
57 #include "MagickCore/draw.h"
58 #include "MagickCore/fx.h"
59 #include "MagickCore/gem.h"
60 #include "MagickCore/geometry.h"
61 #include "MagickCore/image.h"
62 #include "MagickCore/image-private.h"
63 #include "MagickCore/list.h"
64 #include "MagickCore/log.h"
65 #include "MagickCore/monitor.h"
66 #include "MagickCore/monitor-private.h"
67 #include "MagickCore/memory_.h"
68 #include "MagickCore/option.h"
69 #include "MagickCore/pixel-accessor.h"
70 #include "MagickCore/property.h"
71 #include "MagickCore/quantum.h"
72 #include "MagickCore/resample.h"
73 #include "MagickCore/resource_.h"
74 #include "MagickCore/string_.h"
75 #include "MagickCore/thread-private.h"
76 #include "MagickCore/threshold.h"
77 #include "MagickCore/token.h"
78 #include "MagickCore/utility.h"
79 #include "MagickCore/utility-private.h"
80 #include "MagickCore/version.h"
83 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
87 % C o m p o s i t e I m a g e %
91 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
93 % CompositeImage() returns the second image composited onto the first
94 % at the specified offset, using the specified composite method.
96 % The format of the CompositeImage method is:
98 % MagickBooleanType CompositeImage(Image *image,
99 % const Image *composite_image,const CompositeOperator compose,
100 % const MagickBooleanType clip_to_self,const ssize_t x_offset,
101 % const ssize_t y_offset,ExceptionInfo *exception)
103 % A description of each parameter follows:
105 % o image: the destination image, modified by he composition
107 % o composite_image: the composite (source) image.
109 % o compose: This operator affects how the composite is applied to
110 % the image. The operators and how they are utilized are listed here
111 % http://www.w3.org/TR/SVG12/#compositing.
113 % o clip_to_self: set to MagickTrue to limit composition to area composed.
115 % o x_offset: the column offset of the composited image.
117 % o y_offset: the row offset of the composited image.
119 % Extra Controls from Image meta-data in '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 == BlendPixelTrait) &&
572 (composite_image->alpha_trait != BlendPixelTrait))
573 (void) SetImageAlphaChannel(composite_image,SetAlphaChannel,exception);
574 if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
576 status=CompositeOverImage(image,composite_image,clip_to_self,x_offset,
578 composite_image=DestroyImage(composite_image);
581 destination_image=(Image *) NULL;
583 destination_dissolve=1.0;
585 percent_chroma=100.0;
590 case CopyCompositeOp:
592 if ((x_offset < 0) || (y_offset < 0))
594 if ((x_offset+(ssize_t) composite_image->columns) >= (ssize_t) image->columns)
596 if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
599 composite_view=AcquireVirtualCacheView(composite_image,exception);
600 image_view=AcquireAuthenticCacheView(image,exception);
601 #if defined(MAGICKCORE_OPENMP_SUPPORT)
602 #pragma omp parallel for schedule(static,4) shared(status) \
603 magick_threads(composite_image,image,composite_image->rows,1)
605 for (y=0; y < (ssize_t) composite_image->rows; y++)
610 register const Quantum
619 if (status == MagickFalse)
621 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
623 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
624 composite_image->columns,1,exception);
625 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
630 for (x=0; x < (ssize_t) composite_image->columns; x++)
635 if (GetPixelReadMask(composite_image,p) == 0)
637 p+=GetPixelChannels(composite_image);
638 q+=GetPixelChannels(image);
641 for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
643 PixelChannel channel=GetPixelChannelChannel(composite_image,i);
644 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
646 PixelTrait traits=GetPixelChannelTraits(image,channel);
647 if ((traits == UndefinedPixelTrait) ||
648 (composite_traits == UndefinedPixelTrait))
650 SetPixelChannel(image,channel,p[i],q);
652 p+=GetPixelChannels(composite_image);
653 q+=GetPixelChannels(image);
655 sync=SyncCacheViewAuthenticPixels(image_view,exception);
656 if (sync == MagickFalse)
658 if (image->progress_monitor != (MagickProgressMonitor) NULL)
663 #if defined(MAGICKCORE_OPENMP_SUPPORT)
664 #pragma omp critical (MagickCore_CompositeImage)
666 proceed=SetImageProgress(image,CompositeImageTag,
667 (MagickOffsetType) y,image->rows);
668 if (proceed == MagickFalse)
672 composite_view=DestroyCacheView(composite_view);
673 image_view=DestroyCacheView(image_view);
674 composite_image=DestroyImage(composite_image);
677 case CopyAlphaCompositeOp:
678 case ChangeMaskCompositeOp:
679 case IntensityCompositeOp:
682 Modify destination outside the overlaid region and require an alpha
683 channel to exist, to add transparency.
685 if (image->alpha_trait != BlendPixelTrait)
686 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
689 case BlurCompositeOp:
714 Blur Image by resampling.
716 Blur Image dictated by an overlay gradient map: X = red_channel;
717 Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
719 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
721 if (destination_image == (Image *) NULL)
723 composite_image=DestroyImage(composite_image);
727 Gather the maximum blur sigma values from user.
729 SetGeometryInfo(&geometry_info);
731 value=GetImageArtifact(image,"compose:args");
732 if (value != (const char *) NULL)
733 flags=ParseGeometry(value,&geometry_info);
734 if ((flags & WidthValue) == 0)
736 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
737 "InvalidSetting","'%s' '%s'","compose:args",value);
738 composite_image=DestroyImage(composite_image);
739 destination_image=DestroyImage(destination_image);
743 Users input sigma now needs to be converted to the EWA ellipse size.
744 The filter defaults to a sigma of 0.5 so to make this match the
745 users input the ellipse size needs to be doubled.
747 width=height=geometry_info.rho*2.0;
748 if ((flags & HeightValue) != 0 )
749 height=geometry_info.sigma*2.0;
751 Default the unrotated ellipse width and height axis vectors.
757 /* rotate vectors if a rotation angle is given */
758 if ((flags & XValue) != 0 )
763 angle=DegreesToRadians(geometry_info.xi);
764 blur.x1=width*cos(angle);
765 blur.x2=width*sin(angle);
766 blur.y1=(-height*sin(angle));
767 blur.y2=height*cos(angle);
769 /* Otherwise lets set a angle range and calculate in the loop */
772 if ((flags & YValue) != 0 )
774 angle_start=DegreesToRadians(geometry_info.xi);
775 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
778 Set up a gaussian cylindrical filter for EWA Bluring.
780 As the minimum ellipse radius of support*1.0 the EWA algorithm
781 can only produce a minimum blur of 0.5 for Gaussian (support=2.0)
782 This means that even 'No Blur' will be still a little blurry!
784 The solution (as well as the problem of preventing any user
785 expert filter settings, is to set our own user settings, then
786 restore them afterwards.
788 resample_filter=AcquireResampleFilter(image,exception);
789 SetResampleFilter(resample_filter,GaussianFilter);
791 /* do the variable blurring of each pixel in image */
792 GetPixelInfo(image,&pixel);
793 composite_view=AcquireVirtualCacheView(composite_image,exception);
794 destination_view=AcquireAuthenticCacheView(destination_image,exception);
795 for (y=0; y < (ssize_t) composite_image->rows; y++)
800 register const Quantum
809 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
811 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
813 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
814 destination_image->columns,1,exception);
815 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
817 for (x=0; x < (ssize_t) composite_image->columns; x++)
819 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
821 p+=GetPixelChannels(composite_image);
824 if (fabs(angle_range) > MagickEpsilon)
829 angle=angle_start+angle_range*QuantumScale*
830 GetPixelBlue(composite_image,p);
831 blur.x1=width*cos(angle);
832 blur.x2=width*sin(angle);
833 blur.y1=(-height*sin(angle));
834 blur.y2=height*cos(angle);
837 if ( x == 10 && y == 60 ) {
838 (void) fprintf(stderr, "blur.x=%lf,%lf, blur.y=%lf,%lf\n",blur.x1,
839 blur.x2,blur.y1, blur.y2);
840 (void) fprintf(stderr, "scaled by=%lf,%lf\n",QuantumScale*
841 GetPixelRed(p),QuantumScale*GetPixelGreen(p));
843 ScaleResampleFilter(resample_filter,
844 blur.x1*QuantumScale*GetPixelRed(composite_image,p),
845 blur.y1*QuantumScale*GetPixelGreen(composite_image,p),
846 blur.x2*QuantumScale*GetPixelRed(composite_image,p),
847 blur.y2*QuantumScale*GetPixelGreen(composite_image,p) );
848 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
849 (double) y_offset+y,&pixel,exception);
850 SetPixelInfoPixel(destination_image,&pixel,q);
851 p+=GetPixelChannels(composite_image);
852 q+=GetPixelChannels(destination_image);
854 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
855 if (sync == MagickFalse)
858 resample_filter=DestroyResampleFilter(resample_filter);
859 composite_view=DestroyCacheView(composite_view);
860 destination_view=DestroyCacheView(destination_view);
861 composite_image=DestroyImage(composite_image);
862 composite_image=destination_image;
865 case DisplaceCompositeOp:
866 case DistortCompositeOp:
888 Displace/Distort based on overlay gradient map:
889 X = red_channel; Y = green_channel;
890 compose:args = x_scale[,y_scale[,center.x,center.y]]
892 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
894 if (destination_image == (Image *) NULL)
896 composite_image=DestroyImage(composite_image);
899 SetGeometryInfo(&geometry_info);
901 value=GetImageArtifact(image,"compose:args");
902 if (value != (char *) NULL)
903 flags=ParseGeometry(value,&geometry_info);
904 if ((flags & (WidthValue|HeightValue)) == 0 )
906 if ((flags & AspectValue) == 0)
908 horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
910 vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
914 horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
915 vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
920 horizontal_scale=geometry_info.rho;
921 vertical_scale=geometry_info.sigma;
922 if ((flags & PercentValue) != 0)
924 if ((flags & AspectValue) == 0)
926 horizontal_scale*=(composite_image->columns-1.0)/200.0;
927 vertical_scale*=(composite_image->rows-1.0)/200.0;
931 horizontal_scale*=(image->columns-1.0)/200.0;
932 vertical_scale*=(image->rows-1.0)/200.0;
935 if ((flags & HeightValue) == 0)
936 vertical_scale=horizontal_scale;
939 Determine fixed center point for absolute distortion map
941 Displace offset relative to a fixed absolute point
942 Select that point according to +X+Y user inputs.
943 default = center of overlay image
944 arg flag '!' = locations/percentage relative to background image
946 center.x=(MagickRealType) x_offset;
947 center.y=(MagickRealType) y_offset;
948 if (compose == DistortCompositeOp)
950 if ((flags & XValue) == 0)
951 if ((flags & AspectValue) == 0)
952 center.x=(MagickRealType) (x_offset+(composite_image->columns-1)/
955 center.x=(MagickRealType) ((image->columns-1)/2);
957 if ((flags & AspectValue) == 0)
958 center.x=(MagickRealType) x_offset+geometry_info.xi;
960 center.x=geometry_info.xi;
961 if ((flags & YValue) == 0)
962 if ((flags & AspectValue) == 0)
963 center.y=(MagickRealType) (y_offset+(composite_image->rows-1)/
966 center.y=(MagickRealType) ((image->rows-1)/2);
968 if ((flags & AspectValue) == 0)
969 center.y=(MagickRealType) y_offset+geometry_info.psi;
971 center.y=geometry_info.psi;
974 Shift the pixel offset point as defined by the provided,
975 displacement/distortion map. -- Like a lens...
977 GetPixelInfo(image,&pixel);
978 image_view=AcquireVirtualCacheView(image,exception);
979 composite_view=AcquireVirtualCacheView(composite_image,exception);
980 destination_view=AcquireAuthenticCacheView(destination_image,exception);
981 for (y=0; y < (ssize_t) composite_image->rows; y++)
986 register const Quantum
995 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
997 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
999 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
1000 destination_image->columns,1,exception);
1001 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1003 for (x=0; x < (ssize_t) composite_image->columns; x++)
1005 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1007 p+=GetPixelChannels(composite_image);
1011 Displace the offset.
1013 offset.x=(double) (horizontal_scale*(GetPixelRed(composite_image,p)-
1014 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1015 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
1017 offset.y=(double) (vertical_scale*(GetPixelGreen(composite_image,p)-
1018 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1019 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
1021 (void) InterpolatePixelInfo(image,image_view,
1022 UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1025 Mask with the 'invalid pixel mask' in alpha channel.
1027 pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
1028 pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
1029 SetPixelInfoPixel(destination_image,&pixel,q);
1030 p+=GetPixelChannels(composite_image);
1031 q+=GetPixelChannels(destination_image);
1033 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1034 if (sync == MagickFalse)
1037 destination_view=DestroyCacheView(destination_view);
1038 composite_view=DestroyCacheView(composite_view);
1039 image_view=DestroyCacheView(image_view);
1040 composite_image=DestroyImage(composite_image);
1041 composite_image=destination_image;
1044 case DissolveCompositeOp:
1050 Geometry arguments to dissolve factors.
1052 value=GetImageArtifact(image,"compose:args");
1053 if (value != (char *) NULL)
1055 flags=ParseGeometry(value,&geometry_info);
1056 source_dissolve=geometry_info.rho/100.0;
1057 destination_dissolve=1.0;
1058 if ((source_dissolve-MagickEpsilon) < 0.0)
1059 source_dissolve=0.0;
1060 if ((source_dissolve+MagickEpsilon) > 1.0)
1062 destination_dissolve=2.0-source_dissolve;
1063 source_dissolve=1.0;
1065 if ((flags & SigmaValue) != 0)
1066 destination_dissolve=geometry_info.sigma/100.0;
1067 if ((destination_dissolve-MagickEpsilon) < 0.0)
1068 destination_dissolve=0.0;
1072 case BlendCompositeOp:
1077 value=GetImageArtifact(image,"compose:args");
1078 if (value != (char *) NULL)
1080 flags=ParseGeometry(value,&geometry_info);
1081 source_dissolve=geometry_info.rho/100.0;
1082 destination_dissolve=1.0-source_dissolve;
1083 if ((flags & SigmaValue) != 0)
1084 destination_dissolve=geometry_info.sigma/100.0;
1088 case MathematicsCompositeOp:
1094 Just collect the values from "compose:args", setting.
1095 Unused values are set to zero automagically.
1097 Arguments are normally a comma separated list, so this probably should
1098 be changed to some 'general comma list' parser, (with a minimum
1101 SetGeometryInfo(&geometry_info);
1102 value=GetImageArtifact(image,"compose:args");
1103 if (value != (char *) NULL)
1104 (void) ParseGeometry(value,&geometry_info);
1107 case ModulateCompositeOp:
1113 Determine the luma and chroma scale.
1115 value=GetImageArtifact(image,"compose:args");
1116 if (value != (char *) NULL)
1118 flags=ParseGeometry(value,&geometry_info);
1119 percent_luma=geometry_info.rho;
1120 if ((flags & SigmaValue) != 0)
1121 percent_chroma=geometry_info.sigma;
1125 case ThresholdCompositeOp:
1131 Determine the amount and threshold.
1133 value=GetImageArtifact(image,"compose:args");
1134 if (value != (char *) NULL)
1136 flags=ParseGeometry(value,&geometry_info);
1137 amount=geometry_info.rho;
1138 threshold=geometry_info.sigma;
1139 if ((flags & SigmaValue) == 0)
1142 threshold*=QuantumRange;
1153 midpoint=((MagickRealType) QuantumRange+1.0)/2;
1154 composite_view=AcquireVirtualCacheView(composite_image,exception);
1155 image_view=AcquireAuthenticCacheView(image,exception);
1156 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1157 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1158 magick_threads(composite_image,image,image->rows,1)
1160 for (y=0; y < (ssize_t) image->rows; y++)
1177 register const Quantum
1186 if (status == MagickFalse)
1188 if (clip_to_self != MagickFalse)
1192 if ((y-y_offset) >= (ssize_t) composite_image->rows)
1196 If pixels is NULL, y is outside overlay region.
1198 pixels=(Quantum *) NULL;
1200 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
1202 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
1203 composite_image->columns,1,exception);
1204 if (p == (const Quantum *) NULL)
1211 p-=x_offset*GetPixelChannels(composite_image);
1213 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1214 if (q == (Quantum *) NULL)
1222 GetPixelInfo(image,&destination_pixel);
1223 GetPixelInfo(composite_image,&source_pixel);
1224 for (x=0; x < (ssize_t) image->columns; x++)
1244 if (clip_to_self != MagickFalse)
1248 q+=GetPixelChannels(image);
1251 if ((x-x_offset) >= (ssize_t) composite_image->columns)
1254 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1255 ((x-x_offset) >= (ssize_t) composite_image->columns))
1258 source[MaxPixelChannels];
1263 Dc: destination color.
1265 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
1267 if (GetPixelReadMask(image,q) == 0)
1269 q+=GetPixelChannels(image);
1272 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1277 PixelChannel channel=GetPixelChannelChannel(image,i);
1278 PixelTrait traits=GetPixelChannelTraits(image,channel);
1279 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
1281 if ((traits == UndefinedPixelTrait) ||
1282 (composite_traits == UndefinedPixelTrait))
1286 case AlphaCompositeOp:
1287 case ChangeMaskCompositeOp:
1288 case CopyAlphaCompositeOp:
1289 case DstAtopCompositeOp:
1290 case DstInCompositeOp:
1292 case IntensityCompositeOp:
1293 case OutCompositeOp:
1294 case SrcInCompositeOp:
1295 case SrcOutCompositeOp:
1297 pixel=(MagickRealType) q[i];
1298 if (channel == AlphaPixelChannel)
1299 pixel=(MagickRealType) TransparentAlpha;
1302 case ClearCompositeOp:
1303 case CopyCompositeOp:
1304 case ReplaceCompositeOp:
1305 case SrcCompositeOp:
1307 if (channel == AlphaPixelChannel)
1309 pixel=(MagickRealType) TransparentAlpha;
1315 case BlendCompositeOp:
1316 case DissolveCompositeOp:
1318 if (channel == AlphaPixelChannel)
1320 pixel=destination_dissolve*GetPixelAlpha(composite_image,
1324 pixel=(MagickRealType) source[channel];
1329 pixel=(MagickRealType) source[channel];
1333 q[i]=ClampToQuantum(pixel);
1335 q+=GetPixelChannels(image);
1339 Authentic composite:
1340 Sa: normalized source alpha.
1341 Da: normalized destination alpha.
1343 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
1344 Da=QuantumScale*GetPixelAlpha(image,q);
1347 case BumpmapCompositeOp:
1349 alpha=GetPixelIntensity(composite_image,p)*Sa;
1352 case ColorBurnCompositeOp:
1353 case ColorDodgeCompositeOp:
1354 case DifferenceCompositeOp:
1355 case DivideDstCompositeOp:
1356 case DivideSrcCompositeOp:
1357 case ExclusionCompositeOp:
1358 case HardLightCompositeOp:
1359 case HardMixCompositeOp:
1360 case LinearBurnCompositeOp:
1361 case LinearDodgeCompositeOp:
1362 case LinearLightCompositeOp:
1363 case MathematicsCompositeOp:
1364 case MinusDstCompositeOp:
1365 case MinusSrcCompositeOp:
1366 case ModulusAddCompositeOp:
1367 case ModulusSubtractCompositeOp:
1368 case MultiplyCompositeOp:
1369 case OverlayCompositeOp:
1370 case PegtopLightCompositeOp:
1371 case PinLightCompositeOp:
1372 case ScreenCompositeOp:
1373 case SoftLightCompositeOp:
1374 case VividLightCompositeOp:
1376 alpha=RoundToUnity(Sa+Da-Sa*Da);
1379 case DarkenCompositeOp:
1380 case DstAtopCompositeOp:
1381 case DstInCompositeOp:
1383 case LightenCompositeOp:
1384 case SrcInCompositeOp:
1389 case DissolveCompositeOp:
1391 alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
1392 Sa+destination_dissolve*Da;
1395 case DstOverCompositeOp:
1397 alpha=Da*(-Sa)+Da+Sa;
1400 case DstOutCompositeOp:
1405 case OutCompositeOp:
1406 case SrcOutCompositeOp:
1411 case OverCompositeOp:
1412 case SrcOverCompositeOp:
1414 alpha=Sa*(-Da)+Sa+Da;
1417 case BlendCompositeOp:
1418 case PlusCompositeOp:
1420 alpha=RoundToUnity(Sa+Da);
1423 case XorCompositeOp:
1425 alpha=Sa+Da-2.0*Sa*Da;
1434 if (GetPixelReadMask(image,q) == 0)
1436 p+=GetPixelChannels(composite_image);
1437 q+=GetPixelChannels(image);
1442 case ColorizeCompositeOp:
1443 case HueCompositeOp:
1444 case LuminizeCompositeOp:
1445 case ModulateCompositeOp:
1446 case SaturateCompositeOp:
1448 GetPixelInfoPixel(composite_image,p,&source_pixel);
1449 GetPixelInfoPixel(image,q,&destination_pixel);
1455 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1461 PixelChannel channel=GetPixelChannelChannel(image,i);
1462 PixelTrait traits=GetPixelChannelTraits(image,channel);
1463 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
1465 if (traits == UndefinedPixelTrait)
1467 if ((compose != IntensityCompositeOp) &&
1468 (composite_traits == UndefinedPixelTrait))
1472 Dc: destination color.
1474 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
1475 Dc=(MagickRealType) q[i];
1476 if ((traits & CopyPixelTrait) != 0)
1478 if (channel != AlphaPixelChannel)
1483 q[i]=ClampToQuantum(Sc);
1491 case AlphaCompositeOp:
1493 pixel=QuantumRange*Sa;
1496 case AtopCompositeOp:
1497 case CopyBlackCompositeOp:
1498 case CopyBlueCompositeOp:
1499 case CopyCyanCompositeOp:
1500 case CopyGreenCompositeOp:
1501 case CopyMagentaCompositeOp:
1502 case CopyRedCompositeOp:
1503 case CopyYellowCompositeOp:
1504 case SrcAtopCompositeOp:
1505 case DstCompositeOp:
1508 pixel=QuantumRange*Da;
1511 case ChangeMaskCompositeOp:
1516 if (Da > ((MagickRealType) QuantumRange/2.0))
1518 pixel=(MagickRealType) TransparentAlpha;
1521 equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
1522 if (equivalent != MagickFalse)
1524 pixel=(MagickRealType) TransparentAlpha;
1527 pixel=(MagickRealType) OpaqueAlpha;
1530 case ClearCompositeOp:
1532 pixel=(MagickRealType) TransparentAlpha;
1535 case ColorizeCompositeOp:
1536 case HueCompositeOp:
1537 case LuminizeCompositeOp:
1538 case SaturateCompositeOp:
1540 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1542 pixel=QuantumRange*Da;
1545 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1547 pixel=QuantumRange*Sa;
1552 pixel=QuantumRange*Da;
1555 pixel=QuantumRange*Sa;
1558 case CopyAlphaCompositeOp:
1560 pixel=QuantumRange*Sa;
1561 if (composite_image->alpha_trait != BlendPixelTrait)
1562 pixel=GetPixelIntensity(composite_image,p);
1565 case CopyCompositeOp:
1566 case DisplaceCompositeOp:
1567 case DistortCompositeOp:
1568 case DstAtopCompositeOp:
1569 case ReplaceCompositeOp:
1570 case SrcCompositeOp:
1572 pixel=QuantumRange*Sa;
1575 case DarkenIntensityCompositeOp:
1577 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1578 (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
1581 case IntensityCompositeOp:
1583 pixel=GetPixelIntensity(composite_image,p);
1586 case LightenIntensityCompositeOp:
1588 pixel=Sa*GetPixelIntensity(composite_image,p) >
1589 Da*GetPixelIntensity(image,q) ? Sa : Da;
1592 case ModulateCompositeOp:
1594 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1596 pixel=QuantumRange*Da;
1599 pixel=QuantumRange*Da;
1604 pixel=QuantumRange*alpha;
1608 q[i]=ClampToQuantum(pixel);
1612 Porter-Duff compositions:
1613 Sca: source normalized color multiplied by alpha.
1614 Dca: normalized destination color multiplied by alpha.
1616 Sca=QuantumScale*Sa*Sc;
1617 Dca=QuantumScale*Da*Dc;
1620 case DarkenCompositeOp:
1621 case LightenCompositeOp:
1622 case ModulusSubtractCompositeOp:
1630 gamma=PerceptibleReciprocal(alpha);
1634 case AlphaCompositeOp:
1636 pixel=QuantumRange*Sa;
1639 case AtopCompositeOp:
1640 case SrcAtopCompositeOp:
1642 pixel=Sc*Sa+Dc*(1.0-Sa);
1645 case BlendCompositeOp:
1647 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1650 case BlurCompositeOp:
1651 case DisplaceCompositeOp:
1652 case DistortCompositeOp:
1653 case CopyCompositeOp:
1654 case ReplaceCompositeOp:
1655 case SrcCompositeOp:
1660 case BumpmapCompositeOp:
1662 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1667 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1670 case ChangeMaskCompositeOp:
1675 case ClearCompositeOp:
1680 case ColorBurnCompositeOp:
1683 Refer to the March 2009 SVG specification.
1685 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1687 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1690 if (Sca < MagickEpsilon)
1692 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1695 pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
1696 Sca*(1.0-Da)+Dca*(1.0-Sa));
1699 case ColorDodgeCompositeOp:
1701 if ((Sca*Da+Dca*Sa) >= Sa*Da)
1703 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1706 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1710 case ColorizeCompositeOp:
1712 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1717 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1722 CompositeHCL(destination_pixel.red,destination_pixel.green,
1723 destination_pixel.blue,&sans,&sans,&luma);
1724 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1725 &hue,&chroma,&sans);
1726 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1729 case RedPixelChannel: pixel=red; break;
1730 case GreenPixelChannel: pixel=green; break;
1731 case BluePixelChannel: pixel=blue; break;
1732 default: pixel=Dc; break;
1736 case CopyAlphaCompositeOp:
1737 case IntensityCompositeOp:
1742 case CopyBlackCompositeOp:
1744 if (channel == BlackPixelChannel)
1745 pixel=(MagickRealType) (QuantumRange-
1746 GetPixelBlack(composite_image,p));
1749 case CopyBlueCompositeOp:
1750 case CopyYellowCompositeOp:
1752 if (channel == BluePixelChannel)
1753 pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1756 case CopyGreenCompositeOp:
1757 case CopyMagentaCompositeOp:
1759 if (channel == GreenPixelChannel)
1760 pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1763 case CopyRedCompositeOp:
1764 case CopyCyanCompositeOp:
1766 if (channel == RedPixelChannel)
1767 pixel=(MagickRealType) GetPixelRed(composite_image,p);
1770 case DarkenCompositeOp:
1773 Darken is equivalent to a 'Minimum' method
1774 OR a greyscale version of a binary 'Or'
1775 OR the 'Intersection' of pixel sets.
1779 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1782 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1785 case DarkenIntensityCompositeOp:
1787 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1788 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1791 case DifferenceCompositeOp:
1793 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1796 case DissolveCompositeOp:
1798 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1799 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1802 case DivideDstCompositeOp:
1804 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1806 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1809 if (fabs(Dca) < MagickEpsilon)
1811 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1814 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1817 case DivideSrcCompositeOp:
1819 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1821 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1824 if (fabs(Sca) < MagickEpsilon)
1826 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1829 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1832 case DstAtopCompositeOp:
1834 pixel=Dc*Da+Sc*(1.0-Da);
1837 case DstCompositeOp:
1843 case DstInCompositeOp:
1845 pixel=gamma*(Sa*Dc*Sa);
1848 case DstOutCompositeOp:
1850 pixel=gamma*(Da*Dc*(1.0-Sa));
1853 case DstOverCompositeOp:
1855 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1858 case ExclusionCompositeOp:
1860 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1864 case HardLightCompositeOp:
1868 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1872 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1876 case HardMixCompositeOp:
1885 pixel=(gamma*(1.0-Sca)*(1.0-Dca))+Sa*(1.0-Sca)*Dca+Da*(1.0-Dca)*Sca;
1888 case HueCompositeOp:
1890 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1895 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1900 CompositeHCL(destination_pixel.red,destination_pixel.green,
1901 destination_pixel.blue,&hue,&chroma,&luma);
1902 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1904 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1907 case RedPixelChannel: pixel=red; break;
1908 case GreenPixelChannel: pixel=green; break;
1909 case BluePixelChannel: pixel=blue; break;
1910 default: pixel=Dc; break;
1915 case SrcInCompositeOp:
1917 pixel=gamma*(Da*Sc*Da);
1920 case LinearBurnCompositeOp:
1923 LinearBurn: as defined by Abode Photoshop, according to
1924 http://www.simplefilter.de/en/basics/mixmods.html is:
1926 f(Sc,Dc) = Sc + Dc - 1
1928 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1931 case LinearDodgeCompositeOp:
1933 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1936 case LinearLightCompositeOp:
1939 LinearLight: as defined by Abode Photoshop, according to
1940 http://www.simplefilter.de/en/basics/mixmods.html is:
1942 f(Sc,Dc) = Dc + 2*Sc - 1
1944 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1947 case LightenCompositeOp:
1951 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1954 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1957 case LightenIntensityCompositeOp:
1960 Lighten is equivalent to a 'Maximum' method
1961 OR a greyscale version of a binary 'And'
1962 OR the 'Union' of pixel sets.
1964 pixel=Sa*GetPixelIntensity(composite_image,p) >
1965 Da*GetPixelIntensity(image,q) ? Sc : Dc;
1968 case LuminizeCompositeOp:
1970 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1975 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1980 CompositeHCL(destination_pixel.red,destination_pixel.green,
1981 destination_pixel.blue,&hue,&chroma,&luma);
1982 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1984 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1987 case RedPixelChannel: pixel=red; break;
1988 case GreenPixelChannel: pixel=green; break;
1989 case BluePixelChannel: pixel=blue; break;
1990 default: pixel=Dc; break;
1994 case MathematicsCompositeOp:
1997 'Mathematics' a free form user control mathematical composition
2000 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
2002 Where the arguments A,B,C,D are (currently) passed to composite
2003 as a command separated 'geometry' string in "compose:args" image
2006 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
2008 Applying the SVG transparency formula (see above), we get...
2010 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
2012 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
2015 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
2016 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
2017 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
2020 case MinusDstCompositeOp:
2022 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2025 case MinusSrcCompositeOp:
2028 Minus source from destination.
2032 pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2035 case ModulateCompositeOp:
2040 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2045 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
2051 CompositeHCL(destination_pixel.red,destination_pixel.green,
2052 destination_pixel.blue,&hue,&chroma,&luma);
2053 luma+=(0.01*percent_luma*offset)/midpoint;
2054 chroma*=0.01*percent_chroma;
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 ModulusAddCompositeOp:
2068 if (pixel > QuantumRange)
2069 pixel-=QuantumRange;
2070 pixel=gamma*(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2073 case ModulusSubtractCompositeOp:
2077 pixel+=QuantumRange;
2078 pixel=gamma*(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2081 case MultiplyCompositeOp:
2083 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2086 case OutCompositeOp:
2087 case SrcOutCompositeOp:
2089 pixel=gamma*(Sa*Sc*(1.0-Da));
2092 case OverCompositeOp:
2093 case SrcOverCompositeOp:
2095 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2098 case OverlayCompositeOp:
2102 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2106 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2110 case PegtopLightCompositeOp:
2113 PegTop: A Soft-Light alternative: A continuous version of the
2114 Softlight function, producing very similar results.
2116 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2118 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2120 if (fabs(Da) < MagickEpsilon)
2122 pixel=QuantumRange*gamma*(Sca);
2125 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2129 case PinLightCompositeOp:
2132 PinLight: A Photoshop 7 composition method
2133 http://www.simplefilter.de/en/basics/mixmods.html
2135 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2137 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2139 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2142 if ((Dca*Sa) > (2.0*Sca*Da))
2144 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2147 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2150 case PlusCompositeOp:
2152 pixel=gamma*(Sa*Sc+Da*Dc);
2155 case SaturateCompositeOp:
2157 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2162 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2167 CompositeHCL(destination_pixel.red,destination_pixel.green,
2168 destination_pixel.blue,&hue,&chroma,&luma);
2169 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2170 &sans,&chroma,&sans);
2171 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2174 case RedPixelChannel: pixel=red; break;
2175 case GreenPixelChannel: pixel=green; break;
2176 case BluePixelChannel: pixel=blue; break;
2177 default: pixel=Dc; break;
2181 case ScreenCompositeOp:
2184 Screen: a negated multiply:
2186 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2188 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2191 case SoftLightCompositeOp:
2194 Refer to the March 2009 SVG specification.
2198 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2199 Sca*(1.0-Da)+Dca*(1.0-Sa));
2202 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2204 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2205 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2209 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2210 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2213 case ThresholdCompositeOp:
2219 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2224 pixel=gamma*(Dc+delta*amount);
2227 case VividLightCompositeOp:
2230 VividLight: A Photoshop 7 composition method. See
2231 http://www.simplefilter.de/en/basics/mixmods.html.
2233 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2235 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2237 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2240 if ((2.0*Sca) <= Sa)
2242 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2243 (1.0-Da)+Dca*(1.0-Sa));
2246 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2250 case XorCompositeOp:
2252 pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2261 q[i]=ClampToQuantum(pixel);
2263 p+=GetPixelChannels(composite_image);
2264 channels=GetPixelChannels(composite_image);
2265 if (p >= (pixels+channels*composite_image->columns))
2267 q+=GetPixelChannels(image);
2269 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2271 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2276 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2277 #pragma omp critical (MagickCore_CompositeImage)
2279 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2281 if (proceed == MagickFalse)
2285 composite_view=DestroyCacheView(composite_view);
2286 image_view=DestroyCacheView(image_view);
2287 if (destination_image != (Image * ) NULL)
2288 destination_image=DestroyImage(destination_image);
2290 composite_image=DestroyImage(composite_image);
2295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2299 % T e x t u r e I m a g e %
2303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2305 % TextureImage() repeatedly tiles the texture image across and down the image
2308 % The format of the TextureImage method is:
2310 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2311 % ExceptionInfo *exception)
2313 % A description of each parameter follows:
2315 % o image: the image.
2317 % o texture_image: This image is the texture to layer on the background.
2320 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
2321 ExceptionInfo *exception)
2323 #define TextureImageTag "Texture/Image"
2338 assert(image != (Image *) NULL);
2339 if (image->debug != MagickFalse)
2340 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2341 assert(image->signature == MagickSignature);
2342 if (texture == (const Image *) NULL)
2343 return(MagickFalse);
2344 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2345 return(MagickFalse);
2346 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2347 if (texture_image == (const Image *) NULL)
2348 return(MagickFalse);
2349 (void) TransformImageColorspace(texture_image,image->colorspace,exception);
2350 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
2353 if ((image->compose != CopyCompositeOp) &&
2354 ((image->compose != OverCompositeOp) ||
2355 (image->alpha_trait == BlendPixelTrait) ||
2356 (texture_image->alpha_trait == BlendPixelTrait)))
2359 Tile texture onto the image background.
2361 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2366 if (status == MagickFalse)
2368 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2373 thread_status=CompositeImage(image,texture_image,image->compose,
2374 MagickFalse,x+texture_image->tile_offset.x,y+
2375 texture_image->tile_offset.y,exception);
2376 if (thread_status == MagickFalse)
2378 status=thread_status;
2382 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2387 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2389 if (proceed == MagickFalse)
2393 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2394 image->rows,image->rows);
2395 texture_image=DestroyImage(texture_image);
2399 Tile texture onto the image background (optimized).
2402 texture_view=AcquireVirtualCacheView(texture_image,exception);
2403 image_view=AcquireAuthenticCacheView(image,exception);
2404 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2405 #pragma omp parallel for schedule(static,4) shared(status) \
2406 magick_threads(texture_image,image,1,1)
2408 for (y=0; y < (ssize_t) image->rows; y++)
2413 register const Quantum
2426 if (status == MagickFalse)
2428 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2429 (y+texture_image->tile_offset.y) % texture_image->rows,
2430 texture_image->columns,1,exception);
2431 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2432 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2437 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2443 width=texture_image->columns;
2444 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2445 width=image->columns-x;
2446 for (j=0; j < (ssize_t) width; j++)
2451 if (GetPixelReadMask(image,q) == 0)
2453 p+=GetPixelChannels(texture_image);
2454 q+=GetPixelChannels(image);
2457 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2459 PixelChannel channel=GetPixelChannelChannel(texture_image,i);
2460 PixelTrait traits=GetPixelChannelTraits(image,channel);
2461 PixelTrait texture_traits=GetPixelChannelTraits(texture_image,
2463 if ((traits == UndefinedPixelTrait) ||
2464 (texture_traits == UndefinedPixelTrait))
2466 SetPixelChannel(image,channel,p[i],q);
2468 p+=GetPixelChannels(texture_image);
2469 q+=GetPixelChannels(image);
2472 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2473 if (sync == MagickFalse)
2475 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2480 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2482 if (proceed == MagickFalse)
2486 texture_view=DestroyCacheView(texture_view);
2487 image_view=DestroyCacheView(image_view);
2488 texture_image=DestroyImage(texture_image);