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-2012 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/artifact.h"
45 #include "MagickCore/cache.h"
46 #include "MagickCore/cache-private.h"
47 #include "MagickCore/cache-view.h"
48 #include "MagickCore/client.h"
49 #include "MagickCore/color.h"
50 #include "MagickCore/color-private.h"
51 #include "MagickCore/colorspace.h"
52 #include "MagickCore/colorspace-private.h"
53 #include "MagickCore/composite.h"
54 #include "MagickCore/composite-private.h"
55 #include "MagickCore/constitute.h"
56 #include "MagickCore/draw.h"
57 #include "MagickCore/fx.h"
58 #include "MagickCore/gem.h"
59 #include "MagickCore/geometry.h"
60 #include "MagickCore/image.h"
61 #include "MagickCore/image-private.h"
62 #include "MagickCore/list.h"
63 #include "MagickCore/log.h"
64 #include "MagickCore/monitor.h"
65 #include "MagickCore/monitor-private.h"
66 #include "MagickCore/memory_.h"
67 #include "MagickCore/option.h"
68 #include "MagickCore/pixel-accessor.h"
69 #include "MagickCore/property.h"
70 #include "MagickCore/quantum.h"
71 #include "MagickCore/resample.h"
72 #include "MagickCore/resource_.h"
73 #include "MagickCore/string_.h"
74 #include "MagickCore/thread-private.h"
75 #include "MagickCore/token.h"
76 #include "MagickCore/utility.h"
77 #include "MagickCore/utility-private.h"
78 #include "MagickCore/version.h"
81 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
85 % C o m p o s i t e I m a g e %
89 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
91 % CompositeImage() returns the second image composited onto the first
92 % at the specified offset, using the specified composite method.
94 % The format of the CompositeImage method is:
96 % MagickBooleanType CompositeImage(Image *image,
97 % const Image *composite_image,const CompositeOperator compose,
98 % const MagickBooleanType clip_to_self,const ssize_t x_offset,
99 % const ssize_t y_offset,ExceptionInfo *exception)
101 % A description of each parameter follows:
103 % o image: the destination image, modified by he composition
105 % o composite_image: the composite (source) image.
107 % o compose: This operator affects how the composite is applied to
108 % the image. The operators and how they are utilized are listed here
109 % http://www.w3.org/TR/SVG12/#compositing.
111 % o clip_to_self: set to MagickTrue to limit composition to area composed.
113 % o x_offset: the column offset of the composited image.
115 % o y_offset: the row offset of the composited image.
117 % Extra Controls from Image meta-data in 'composite_image' (artifacts)
120 % A string containing extra numerical arguments for specific compose
121 % methods, generally expressed as a 'geometry' or a comma separated list
124 % Compose methods needing such arguments include "BlendCompositeOp" and
125 % "DisplaceCompositeOp".
127 % o exception: return any errors or warnings in this structure.
132 Composition based on the SVG specification:
134 A Composition is defined by...
135 Color Function : f(Sc,Dc) where Sc and Dc are the normizalized colors
136 Blending areas : X = 1 for area of overlap, ie: f(Sc,Dc)
137 Y = 1 for source preserved
138 Z = 1 for destination preserved
140 Conversion to transparency (then optimized)
141 Dca' = f(Sc, Dc)*Sa*Da + Y*Sca*(1-Da) + Z*Dca*(1-Sa)
142 Da' = X*Sa*Da + Y*Sa*(1-Da) + Z*Da*(1-Sa)
145 Sca = Sc*Sa normalized Source color divided by Source alpha
146 Dca = Dc*Da normalized Dest color divided by Dest alpha
147 Dc' = Dca'/Da' the desired color value for this channel.
149 Da' in in the follow formula as 'gamma' The resulting alpla value.
151 Most functions use a blending mode of over (X=1,Y=1,Z=1) this results in
152 the following optimizations...
154 gamma = 1 - QuantiumScale*alpha * QuantiumScale*beta;
155 opacity = QuantiumScale*alpha*beta; // over blend, optimized 1-Gamma
157 The above SVG definitions also definate that Mathematical Composition
158 methods should use a 'Over' blending mode for Alpha Channel.
159 It however was not applied for composition modes of 'Plus', 'Minus',
160 the modulus versions of 'Add' and 'Subtract'.
162 Mathematical operator changes to be applied from IM v6.7...
164 1) Modulus modes 'Add' and 'Subtract' are obsoleted and renamed
165 'ModulusAdd' and 'ModulusSubtract' for clarity.
167 2) All mathematical compositions work as per the SVG specification
168 with regard to blending. This now includes 'ModulusAdd' and
171 3) When the special channel flag 'sync' (syncronize channel updates)
172 is turned off (enabled by default) then mathematical compositions are
173 only performed on the channels specified, and are applied
174 independantally of each other. In other words the mathematics is
175 performed as 'pure' mathematical operations, rather than as image
178 static void CompositeHSB(const double red,const double green,
179 const double blue,double *hue,double *saturation,double *brightness)
187 Convert RGB to HSB colorspace.
189 assert(hue != (double *) NULL);
190 assert(saturation != (double *) NULL);
191 assert(brightness != (double *) NULL);
192 max=(red > green ? red : green);
195 min=(red < green ? red : green);
200 *brightness=(double) (QuantumScale*max);
201 if (fabs((double) max) < MagickEpsilon)
203 *saturation=(double) (1.0-min/max);
204 delta=(MagickRealType) max-min;
205 if (fabs(delta) < MagickEpsilon)
207 if (fabs((double) red-max) < MagickEpsilon)
208 *hue=(double) ((green-blue)/delta);
210 if (fabs((double) green-max) < MagickEpsilon)
211 *hue=(double) (2.0+(blue-red)/delta);
213 if (fabs((double) blue-max) < MagickEpsilon)
214 *hue=(double) (4.0+(red-green)/delta);
220 static void HSBComposite(const double hue,const double saturation,
221 const double brightness,double *red,double *green,double *blue)
231 Convert HSB to RGB colorspace.
233 assert(red != (double *) NULL);
234 assert(green != (double *) NULL);
235 assert(blue != (double *) NULL);
236 if (saturation == 0.0)
238 *red=(double) QuantumRange*brightness;
243 h=6.0*(hue-floor(hue));
244 f=h-floor((double) h);
245 p=brightness*(1.0-saturation);
246 q=brightness*(1.0-saturation*f);
247 t=brightness*(1.0-saturation*(1.0-f));
253 *red=(double) QuantumRange*brightness;
254 *green=(double) QuantumRange*t;
255 *blue=(double) QuantumRange*p;
260 *red=(double) QuantumRange*q;
261 *green=(double) QuantumRange*brightness;
262 *blue=(double) QuantumRange*p;
267 *red=(double) QuantumRange*p;
268 *green=(double) QuantumRange*brightness;
269 *blue=(double) QuantumRange*t;
274 *red=(double) QuantumRange*p;
275 *green=(double) QuantumRange*q;
276 *blue=(double) QuantumRange*brightness;
281 *red=(double) QuantumRange*t;
282 *green=(double) QuantumRange*p;
283 *blue=(double) QuantumRange*brightness;
288 *red=(double) QuantumRange*brightness;
289 *green=(double) QuantumRange*p;
290 *blue=(double) QuantumRange*q;
296 static inline double MagickMin(const double x,const double y)
303 static inline double MagickMax(const double x,const double y)
310 static MagickBooleanType CompositeOverImage(Image *image,
311 const Image *composite_image,const MagickBooleanType clip_to_self,
312 const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
314 #define CompositeImageTag "Composite/Image"
334 composite_view=AcquireVirtualCacheView(composite_image,exception);
335 image_view=AcquireAuthenticCacheView(image,exception);
336 #if defined(MAGICKCORE_OPENMP_SUPPORT)
337 #pragma omp parallel for schedule(static,4) shared(progress,status)
339 for (y=0; y < (ssize_t) image->rows; y++)
344 register const Quantum
356 if (status == MagickFalse)
358 if (clip_to_self != MagickFalse)
362 if ((y-y_offset) >= (ssize_t) composite_image->rows)
366 If pixels is NULL, y is outside overlay region.
368 pixels=(Quantum *) NULL;
370 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
372 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
373 composite_image->columns,1,exception);
374 if (p == (const Quantum *) NULL)
381 p-=x_offset*GetPixelChannels(composite_image);
383 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
384 if (q == (Quantum *) NULL)
389 for (x=0; x < (ssize_t) image->columns; x++)
402 if (clip_to_self != MagickFalse)
406 q+=GetPixelChannels(image);
409 if ((x-x_offset) >= (ssize_t) composite_image->columns)
412 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
413 ((x-x_offset) >= (ssize_t) composite_image->columns))
416 source[MaxPixelChannels];
421 Dc: destination color.
423 if (GetPixelMask(image,q) != 0)
425 q+=GetPixelChannels(image);
428 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
430 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
439 channel=GetPixelChannelMapChannel(image,i);
440 traits=GetPixelChannelMapTraits(image,channel);
441 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
442 if ((traits == UndefinedPixelTrait) ||
443 (composite_traits == UndefinedPixelTrait))
445 q[i]=source[channel];
447 q+=GetPixelChannels(image);
452 Sa: normalized source alpha.
453 Da: normalized destination alpha.
455 if (GetPixelMask(composite_image,p) != 0)
457 p+=GetPixelChannels(composite_image);
458 channels=GetPixelChannels(composite_image);
459 if (p >= (pixels+channels*composite_image->columns))
461 q+=GetPixelChannels(image);
464 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
465 Da=QuantumScale*GetPixelAlpha(image,q);
466 alpha=Sa*(-Da)+Sa+Da;
467 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
476 channel=GetPixelChannelMapChannel(image,i);
477 traits=GetPixelChannelMapTraits(image,channel);
478 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
479 if ((traits == UndefinedPixelTrait) ||
480 (composite_traits == UndefinedPixelTrait))
482 if ((traits & CopyPixelTrait) != 0)
484 if (channel != AlphaPixelChannel)
489 q[i]=GetPixelChannel(composite_image,channel,p);
495 q[i]=ClampToQuantum(QuantumRange*alpha);
500 Dc: destination color.
502 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
503 Dc=(MagickRealType) q[i];
504 gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
505 q[i]=ClampToQuantum(gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc));
507 p+=GetPixelChannels(composite_image);
508 channels=GetPixelChannels(composite_image);
509 if (p >= (pixels+channels*composite_image->columns))
511 q+=GetPixelChannels(image);
513 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
515 if (image->progress_monitor != (MagickProgressMonitor) NULL)
520 #if defined(MAGICKCORE_OPENMP_SUPPORT)
521 #pragma omp critical (MagickCore_CompositeImage)
523 proceed=SetImageProgress(image,CompositeImageTag,progress++,
525 if (proceed == MagickFalse)
529 composite_view=DestroyCacheView(composite_view);
530 image_view=DestroyCacheView(image_view);
534 MagickExport MagickBooleanType CompositeImage(Image *image,
535 const Image *composite_image,const CompositeOperator compose,
536 const MagickBooleanType clip_to_self,const ssize_t x_offset,
537 const ssize_t y_offset,ExceptionInfo *exception)
539 #define CompositeImageTag "Composite/Image"
559 destination_dissolve,
572 assert(image != (Image *) NULL);
573 assert(image->signature == MagickSignature);
574 if (image->debug != MagickFalse)
575 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
576 assert(composite_image != (Image *) NULL);
577 assert(composite_image->signature == MagickSignature);
578 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
580 if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
581 (IsGrayColorspace(composite_image->colorspace) == MagickFalse))
582 (void) TransformImageColorspace(image,sRGBColorspace,exception);
583 if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
585 status=CompositeOverImage(image,composite_image,clip_to_self,x_offset,
589 destination_image=(Image *) NULL;
591 destination_dissolve=1.0;
592 percent_brightness=100.0;
593 percent_saturation=100.0;
598 case CopyCompositeOp:
600 if ((x_offset < 0) || (y_offset < 0))
602 if ((x_offset+(ssize_t) composite_image->columns) >= (ssize_t) image->columns)
604 if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
607 composite_view=AcquireVirtualCacheView(composite_image,exception);
608 image_view=AcquireAuthenticCacheView(image,exception);
609 #if defined(MAGICKCORE_OPENMP_SUPPORT)
610 #pragma omp parallel for schedule(static,4) shared(status)
612 for (y=0; y < (ssize_t) composite_image->rows; y++)
617 register const Quantum
626 if (status == MagickFalse)
628 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
630 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
631 composite_image->columns,1,exception);
632 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
637 for (x=0; x < (ssize_t) composite_image->columns; x++)
642 if (GetPixelMask(image,p) != 0)
644 p+=GetPixelChannels(composite_image);
645 q+=GetPixelChannels(image);
648 for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
657 channel=GetPixelChannelMapChannel(composite_image,i);
658 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
659 traits=GetPixelChannelMapTraits(image,channel);
660 if ((traits == UndefinedPixelTrait) ||
661 (composite_traits == UndefinedPixelTrait))
663 SetPixelChannel(image,channel,p[i],q);
665 p+=GetPixelChannels(composite_image);
666 q+=GetPixelChannels(image);
668 sync=SyncCacheViewAuthenticPixels(image_view,exception);
669 if (sync == MagickFalse)
671 if (image->progress_monitor != (MagickProgressMonitor) NULL)
676 #if defined(MAGICKCORE_OPENMP_SUPPORT)
677 #pragma omp critical (MagickCore_CompositeImage)
679 proceed=SetImageProgress(image,CompositeImageTag,
680 (MagickOffsetType) y,image->rows);
681 if (proceed == MagickFalse)
685 composite_view=DestroyCacheView(composite_view);
686 image_view=DestroyCacheView(image_view);
689 case CopyAlphaCompositeOp:
690 case ChangeMaskCompositeOp:
691 case IntensityCompositeOp:
694 Modify destination outside the overlaid region and require an alpha
695 channel to exist, to add transparency.
697 if (image->matte == MagickFalse)
698 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
701 case BlurCompositeOp:
726 Blur Image dictated by an overlay gradient map: X = red_channel;
727 Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
729 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
731 if (destination_image == (Image *) NULL)
734 Determine the horizontal and vertical maximim blur.
736 SetGeometryInfo(&geometry_info);
738 value=GetImageArtifact(composite_image,"compose:args");
739 if (value != (char *) NULL)
740 flags=ParseGeometry(value,&geometry_info);
741 if ((flags & WidthValue) == 0 )
743 destination_image=DestroyImage(destination_image);
746 width=geometry_info.rho;
747 height=geometry_info.sigma;
748 blur.x1=geometry_info.rho;
751 blur.y2=geometry_info.sigma;
754 if ((flags & HeightValue) == 0)
756 if ((flags & XValue) != 0 )
761 angle=DegreesToRadians(geometry_info.xi);
762 blur.x1=width*cos(angle);
763 blur.x2=width*sin(angle);
764 blur.y1=(-height*sin(angle));
765 blur.y2=height*cos(angle);
767 if ((flags & YValue) != 0 )
769 angle_start=DegreesToRadians(geometry_info.xi);
770 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
773 Blur Image by resampling.
774 FUTURE: this is currently broken, especially for small sigma blurs
775 This needs to be fixed to use a non-user filter setup that provides
776 far more control than currently available.
778 resample_filter=AcquireResampleFilter(image,exception);
779 SetResampleFilter(resample_filter,GaussianFilter); /* was blur*2 */
780 composite_view=AcquireVirtualCacheView(composite_image,exception);
781 destination_view=AcquireAuthenticCacheView(destination_image,exception);
782 for (y=0; y < (ssize_t) composite_image->rows; y++)
787 register const Quantum
796 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
798 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
800 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
801 destination_image->columns,1,exception);
802 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
804 for (x=0; x < (ssize_t) composite_image->columns; x++)
806 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
808 p+=GetPixelChannels(composite_image);
811 if (fabs(angle_range) > MagickEpsilon)
816 angle=angle_start+angle_range*QuantumScale*
817 GetPixelBlue(composite_image,p);
818 blur.x1=width*cos(angle);
819 blur.x2=width*sin(angle);
820 blur.y1=(-height*sin(angle));
821 blur.y2=height*cos(angle);
823 ScaleResampleFilter(resample_filter,blur.x1*QuantumScale*
824 GetPixelRed(composite_image,p),blur.y1*QuantumScale*
825 GetPixelGreen(composite_image,p),blur.x2*QuantumScale*
826 GetPixelRed(composite_image,p),blur.y2*QuantumScale*
827 GetPixelGreen(composite_image,p));
828 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
829 (double) y_offset+y,&pixel,exception);
830 SetPixelInfoPixel(destination_image,&pixel,q);
831 p+=GetPixelChannels(composite_image);
832 q+=GetPixelChannels(destination_image);
834 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
835 if (sync == MagickFalse)
838 resample_filter=DestroyResampleFilter(resample_filter);
839 composite_view=DestroyCacheView(composite_view);
840 destination_view=DestroyCacheView(destination_view);
841 composite_image=destination_image;
844 case DisplaceCompositeOp:
845 case DistortCompositeOp:
867 Displace/Distort based on overlay gradient map:
868 X = red_channel; Y = green_channel;
869 compose:args = x_scale[,y_scale[,center.x,center.y]]
871 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
873 if (destination_image == (Image *) NULL)
875 SetGeometryInfo(&geometry_info);
877 value=GetImageArtifact(composite_image,"compose:args");
878 if (value != (char *) NULL)
879 flags=ParseGeometry(value,&geometry_info);
880 if ((flags & (WidthValue|HeightValue)) == 0 )
882 if ((flags & AspectValue) == 0)
884 horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
886 vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
890 horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
891 vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
896 horizontal_scale=geometry_info.rho;
897 vertical_scale=geometry_info.sigma;
898 if ((flags & PercentValue) != 0)
900 if ((flags & AspectValue) == 0)
902 horizontal_scale*=(composite_image->columns-1.0)/200.0;
903 vertical_scale*=(composite_image->rows-1.0)/200.0;
907 horizontal_scale*=(image->columns-1.0)/200.0;
908 vertical_scale*=(image->rows-1.0)/200.0;
911 if ((flags & HeightValue) == 0)
912 vertical_scale=horizontal_scale;
915 Determine fixed center point for absolute distortion map
917 Displace offset relative to a fixed absolute point
918 Select that point according to +X+Y user inputs.
919 default = center of overlay image
920 arg flag '!' = locations/percentage relative to background image
922 center.x=(MagickRealType) x_offset;
923 center.y=(MagickRealType) y_offset;
924 if (compose == DistortCompositeOp)
926 if ((flags & XValue) == 0)
927 if ((flags & AspectValue) == 0)
928 center.x=(MagickRealType) x_offset+(composite_image->columns-1)/
931 center.x=((MagickRealType) image->columns-1)/2.0;
933 if ((flags & AspectValue) == 0)
934 center.x=(MagickRealType) x_offset+geometry_info.xi;
936 center.x=geometry_info.xi;
937 if ((flags & YValue) == 0)
938 if ((flags & AspectValue) == 0)
939 center.y=(MagickRealType) y_offset+(composite_image->rows-1)/2.0;
941 center.y=((MagickRealType) image->rows-1)/2.0;
943 if ((flags & AspectValue) == 0)
944 center.y=(MagickRealType) y_offset+geometry_info.psi;
946 center.y=geometry_info.psi;
949 Shift the pixel offset point as defined by the provided,
950 displacement/distortion map. -- Like a lens...
952 GetPixelInfo(image,&pixel);
953 image_view=AcquireVirtualCacheView(image,exception);
954 composite_view=AcquireVirtualCacheView(composite_image,exception);
955 destination_view=AcquireAuthenticCacheView(destination_image,exception);
956 for (y=0; y < (ssize_t) composite_image->rows; y++)
961 register const Quantum
970 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
972 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
974 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
975 destination_image->columns,1,exception);
976 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
978 for (x=0; x < (ssize_t) composite_image->columns; x++)
980 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
982 p+=GetPixelChannels(composite_image);
988 offset.x=(horizontal_scale*(GetPixelRed(composite_image,p)-
989 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
990 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
992 offset.y=(vertical_scale*(GetPixelGreen(composite_image,p)-
993 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
994 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
996 (void) InterpolatePixelInfo(image,image_view,
997 UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1000 Mask with the 'invalid pixel mask' in alpha channel.
1002 pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
1003 pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
1004 SetPixelInfoPixel(destination_image,&pixel,q);
1005 p+=GetPixelChannels(composite_image);
1006 q+=GetPixelChannels(destination_image);
1008 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1009 if (sync == MagickFalse)
1012 destination_view=DestroyCacheView(destination_view);
1013 composite_view=DestroyCacheView(composite_view);
1014 image_view=DestroyCacheView(image_view);
1015 composite_image=destination_image;
1018 case DissolveCompositeOp:
1024 Geometry arguments to dissolve factors.
1026 value=GetImageArtifact(composite_image,"compose:args");
1027 if (value != (char *) NULL)
1029 flags=ParseGeometry(value,&geometry_info);
1030 source_dissolve=geometry_info.rho/100.0;
1031 destination_dissolve=1.0;
1032 if ((source_dissolve-MagickEpsilon) < 0.0)
1033 source_dissolve=0.0;
1034 if ((source_dissolve+MagickEpsilon) > 1.0)
1036 destination_dissolve=2.0-source_dissolve;
1037 source_dissolve=1.0;
1039 if ((flags & SigmaValue) != 0)
1040 destination_dissolve=geometry_info.sigma/100.0;
1041 if ((destination_dissolve-MagickEpsilon) < 0.0)
1042 destination_dissolve=0.0;
1046 case BlendCompositeOp:
1051 value=GetImageArtifact(composite_image,"compose:args");
1052 if (value != (char *) NULL)
1054 flags=ParseGeometry(value,&geometry_info);
1055 source_dissolve=geometry_info.rho/100.0;
1056 destination_dissolve=1.0-source_dissolve;
1057 if ((flags & SigmaValue) != 0)
1058 destination_dissolve=geometry_info.sigma/100.0;
1062 case MathematicsCompositeOp:
1068 Just collect the values from "compose:args", setting.
1069 Unused values are set to zero automagically.
1071 Arguments are normally a comma separated list, so this probably should
1072 be changed to some 'general comma list' parser, (with a minimum
1075 SetGeometryInfo(&geometry_info);
1076 value=GetImageArtifact(composite_image,"compose:args");
1077 if (value != (char *) NULL)
1078 (void) ParseGeometry(value,&geometry_info);
1081 case ModulateCompositeOp:
1087 Determine the brightness and saturation scale.
1089 value=GetImageArtifact(composite_image,"compose:args");
1090 if (value != (char *) NULL)
1092 flags=ParseGeometry(value,&geometry_info);
1093 percent_brightness=geometry_info.rho;
1094 if ((flags & SigmaValue) != 0)
1095 percent_saturation=geometry_info.sigma;
1099 case ThresholdCompositeOp:
1105 Determine the amount and threshold.
1107 value=GetImageArtifact(composite_image,"compose:args");
1108 if (value != (char *) NULL)
1110 flags=ParseGeometry(value,&geometry_info);
1111 amount=geometry_info.rho;
1112 threshold=geometry_info.sigma;
1113 if ((flags & SigmaValue) == 0)
1116 threshold*=QuantumRange;
1127 midpoint=((MagickRealType) QuantumRange+1.0)/2;
1128 composite_view=AcquireVirtualCacheView(composite_image,exception);
1129 image_view=AcquireAuthenticCacheView(image,exception);
1130 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1131 #pragma omp parallel for schedule(static,4) shared(progress,status)
1133 for (y=0; y < (ssize_t) image->rows; y++)
1150 register const Quantum
1159 if (status == MagickFalse)
1161 if (clip_to_self != MagickFalse)
1165 if ((y-y_offset) >= (ssize_t) composite_image->rows)
1169 If pixels is NULL, y is outside overlay region.
1171 pixels=(Quantum *) NULL;
1173 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
1175 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
1176 composite_image->columns,1,exception);
1177 if (p == (const Quantum *) NULL)
1184 p-=x_offset*GetPixelChannels(composite_image);
1186 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1187 if (q == (Quantum *) NULL)
1195 GetPixelInfo(image,&destination_pixel);
1196 GetPixelInfo(composite_image,&source_pixel);
1197 for (x=0; x < (ssize_t) image->columns; x++)
1215 if (clip_to_self != MagickFalse)
1219 q+=GetPixelChannels(image);
1222 if ((x-x_offset) >= (ssize_t) composite_image->columns)
1225 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1226 ((x-x_offset) >= (ssize_t) composite_image->columns))
1229 source[MaxPixelChannels];
1234 Dc: destination color.
1236 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
1238 if (GetPixelMask(image,q) != 0)
1240 q+=GetPixelChannels(image);
1243 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1255 channel=GetPixelChannelMapChannel(image,i);
1256 traits=GetPixelChannelMapTraits(image,channel);
1257 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
1258 if ((traits == UndefinedPixelTrait) ||
1259 (composite_traits == UndefinedPixelTrait))
1263 case AlphaCompositeOp:
1264 case ChangeMaskCompositeOp:
1265 case CopyAlphaCompositeOp:
1266 case DstAtopCompositeOp:
1267 case DstInCompositeOp:
1269 case IntensityCompositeOp:
1270 case OutCompositeOp:
1271 case SrcInCompositeOp:
1272 case SrcOutCompositeOp:
1274 pixel=(MagickRealType) q[i];
1275 if (channel == AlphaPixelChannel)
1276 pixel=(MagickRealType) TransparentAlpha;
1279 case ClearCompositeOp:
1280 case CopyCompositeOp:
1281 case ReplaceCompositeOp:
1282 case SrcCompositeOp:
1284 if (channel == AlphaPixelChannel)
1286 pixel=(MagickRealType) TransparentAlpha;
1292 case BlendCompositeOp:
1293 case DissolveCompositeOp:
1295 if (channel == AlphaPixelChannel)
1297 pixel=destination_dissolve*GetPixelAlpha(composite_image,
1301 pixel=(MagickRealType) source[channel];
1306 pixel=(MagickRealType) source[channel];
1310 q[i]=ClampToQuantum(pixel);
1312 q+=GetPixelChannels(image);
1316 Authentic composite:
1317 Sa: normalized source alpha.
1318 Da: normalized destination alpha.
1320 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
1321 Da=QuantumScale*GetPixelAlpha(image,q);
1324 case BumpmapCompositeOp:
1326 alpha=GetPixelIntensity(composite_image,p)*Sa;
1329 case ColorBurnCompositeOp:
1330 case ColorDodgeCompositeOp:
1331 case DifferenceCompositeOp:
1332 case DivideDstCompositeOp:
1333 case DivideSrcCompositeOp:
1334 case ExclusionCompositeOp:
1335 case HardLightCompositeOp:
1336 case LinearBurnCompositeOp:
1337 case LinearDodgeCompositeOp:
1338 case LinearLightCompositeOp:
1339 case MathematicsCompositeOp:
1340 case MinusDstCompositeOp:
1341 case MinusSrcCompositeOp:
1342 case ModulusAddCompositeOp:
1343 case ModulusSubtractCompositeOp:
1344 case MultiplyCompositeOp:
1345 case OverlayCompositeOp:
1346 case PegtopLightCompositeOp:
1347 case PinLightCompositeOp:
1348 case ScreenCompositeOp:
1349 case SoftLightCompositeOp:
1350 case VividLightCompositeOp:
1352 alpha=RoundToUnity(Sa+Da-Sa*Da);
1355 case DarkenCompositeOp:
1356 case DstAtopCompositeOp:
1357 case DstInCompositeOp:
1359 case LightenCompositeOp:
1360 case SrcInCompositeOp:
1365 case DissolveCompositeOp:
1367 alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
1368 Sa+destination_dissolve*Da;
1371 case DstOverCompositeOp:
1373 alpha=Da*(-Sa)+Da+Sa;
1376 case DstOutCompositeOp:
1381 case OutCompositeOp:
1382 case SrcOutCompositeOp:
1387 case OverCompositeOp:
1388 case SrcOverCompositeOp:
1390 alpha=Sa*(-Da)+Sa+Da;
1393 case BlendCompositeOp:
1394 case PlusCompositeOp:
1396 alpha=RoundToUnity(Sa+Da);
1399 case XorCompositeOp:
1401 alpha=Sa+Da-2.0*Sa*Da;
1410 if (GetPixelMask(image,p) != 0)
1412 p+=GetPixelChannels(composite_image);
1413 q+=GetPixelChannels(image);
1418 case ColorizeCompositeOp:
1419 case HueCompositeOp:
1420 case LuminizeCompositeOp:
1421 case ModulateCompositeOp:
1422 case SaturateCompositeOp:
1424 GetPixelInfoPixel(composite_image,p,&source_pixel);
1425 GetPixelInfoPixel(image,q,&destination_pixel);
1431 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1446 channel=GetPixelChannelMapChannel(image,i);
1447 traits=GetPixelChannelMapTraits(image,channel);
1448 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
1449 if (traits == UndefinedPixelTrait)
1451 if ((compose != IntensityCompositeOp) &&
1452 (composite_traits == UndefinedPixelTrait))
1456 Dc: destination color.
1458 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
1459 Dc=(MagickRealType) q[i];
1460 if ((traits & CopyPixelTrait) != 0)
1462 if (channel != AlphaPixelChannel)
1467 q[i]=ClampToQuantum(Sc);
1475 case AlphaCompositeOp:
1477 pixel=QuantumRange*Sa;
1480 case AtopCompositeOp:
1481 case CopyBlackCompositeOp:
1482 case CopyBlueCompositeOp:
1483 case CopyCyanCompositeOp:
1484 case CopyGreenCompositeOp:
1485 case CopyMagentaCompositeOp:
1486 case CopyRedCompositeOp:
1487 case CopyYellowCompositeOp:
1488 case SrcAtopCompositeOp:
1489 case DstCompositeOp:
1492 pixel=QuantumRange*Da;
1495 case ChangeMaskCompositeOp:
1500 if (Da > ((MagickRealType) QuantumRange/2.0))
1502 pixel=(MagickRealType) TransparentAlpha;
1505 equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
1506 if (equivalent != MagickFalse)
1508 pixel=(MagickRealType) TransparentAlpha;
1511 pixel=(MagickRealType) OpaqueAlpha;
1514 case ClearCompositeOp:
1516 pixel=(MagickRealType) TransparentAlpha;
1519 case ColorizeCompositeOp:
1520 case HueCompositeOp:
1521 case LuminizeCompositeOp:
1522 case SaturateCompositeOp:
1524 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1526 pixel=QuantumRange*Da;
1529 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1531 pixel=QuantumRange*Sa;
1536 pixel=QuantumRange*Da;
1539 pixel=QuantumRange*Sa;
1542 case CopyCompositeOp:
1543 case CopyAlphaCompositeOp:
1544 case DisplaceCompositeOp:
1545 case DistortCompositeOp:
1546 case DstAtopCompositeOp:
1547 case ReplaceCompositeOp:
1548 case SrcCompositeOp:
1550 pixel=QuantumRange*Sa;
1553 case DarkenIntensityCompositeOp:
1555 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1556 (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
1559 case IntensityCompositeOp:
1561 pixel=(MagickRealType) GetPixelIntensity(composite_image,p);
1564 case LightenIntensityCompositeOp:
1566 pixel=Sa*GetPixelIntensity(composite_image,p) >
1567 Da*GetPixelIntensity(image,q) ? Sa : Da;
1570 case ModulateCompositeOp:
1572 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1574 pixel=QuantumRange*Da;
1577 pixel=QuantumRange*Da;
1582 pixel=QuantumRange*alpha;
1586 q[i]=ClampToQuantum(pixel);
1590 Porter-Duff compositions:
1591 Sca: source normalized color multiplied by alpha.
1592 Dca: normalized destination color multiplied by alpha.
1594 Sca=QuantumScale*Sa*Sc;
1595 Dca=QuantumScale*Da*Dc;
1598 case DarkenCompositeOp:
1599 case LightenCompositeOp:
1600 case ModulusSubtractCompositeOp:
1608 gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
1612 case AlphaCompositeOp:
1614 pixel=QuantumRange*Sa;
1617 case AtopCompositeOp:
1618 case SrcAtopCompositeOp:
1620 pixel=Sc*Sa+Dc*(1.0-Sa);
1623 case BlendCompositeOp:
1625 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1628 case BlurCompositeOp:
1629 case DisplaceCompositeOp:
1630 case DistortCompositeOp:
1631 case CopyCompositeOp:
1632 case ReplaceCompositeOp:
1633 case SrcCompositeOp:
1638 case BumpmapCompositeOp:
1640 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1645 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1648 case ChangeMaskCompositeOp:
1653 case ClearCompositeOp:
1658 case ColorBurnCompositeOp:
1661 Refer to the March 2009 SVG specification.
1663 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1665 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1668 if (Sca < MagickEpsilon)
1670 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1673 pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
1674 Sca*(1.0-Da)+Dca*(1.0-Sa));
1677 case ColorDodgeCompositeOp:
1679 if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1681 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1684 if (fabs(Sca-Sa) < MagickEpsilon)
1686 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1689 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1693 case ColorizeCompositeOp:
1695 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1700 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1705 CompositeHSB(destination_pixel.red,destination_pixel.green,
1706 destination_pixel.blue,&sans,&sans,&brightness);
1707 CompositeHSB(source_pixel.red,source_pixel.green,source_pixel.blue,
1708 &hue,&saturation,&sans);
1709 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1712 case RedPixelChannel: pixel=red; break;
1713 case GreenPixelChannel: pixel=green; break;
1714 case BluePixelChannel: pixel=blue; break;
1715 default: pixel=Dc; break;
1719 case CopyAlphaCompositeOp:
1720 case IntensityCompositeOp:
1722 if (channel == AlphaPixelChannel)
1723 pixel=(MagickRealType) GetPixelAlpha(composite_image,p);
1726 case CopyBlackCompositeOp:
1728 if (channel == BlackPixelChannel)
1729 pixel=(MagickRealType) GetPixelBlack(composite_image,p);
1732 case CopyBlueCompositeOp:
1733 case CopyYellowCompositeOp:
1735 if (channel == BluePixelChannel)
1736 pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1739 case CopyGreenCompositeOp:
1740 case CopyMagentaCompositeOp:
1742 if (channel == GreenPixelChannel)
1743 pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1746 case CopyRedCompositeOp:
1747 case CopyCyanCompositeOp:
1749 if (channel == RedPixelChannel)
1750 pixel=(MagickRealType) GetPixelRed(composite_image,p);
1753 case DarkenCompositeOp:
1756 Darken is equivalent to a 'Minimum' method
1757 OR a greyscale version of a binary 'Or'
1758 OR the 'Intersection' of pixel sets.
1762 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1765 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1768 case DarkenIntensityCompositeOp:
1770 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1771 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1774 case DifferenceCompositeOp:
1776 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1779 case DissolveCompositeOp:
1781 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1782 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1785 case DivideDstCompositeOp:
1787 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1789 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1792 if (fabs(Dca) < MagickEpsilon)
1794 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1797 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1800 case DivideSrcCompositeOp:
1802 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1804 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1807 if (fabs(Sca) < MagickEpsilon)
1809 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1812 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1815 case DstAtopCompositeOp:
1817 pixel=Dc*Da+Sc*(1.0-Da);
1820 case DstCompositeOp:
1826 case DstInCompositeOp:
1828 pixel=gamma*(Sa*Dc*Sa);
1831 case DstOutCompositeOp:
1833 pixel=gamma*(Da*Dc*(1.0-Sa));
1836 case DstOverCompositeOp:
1838 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1841 case ExclusionCompositeOp:
1843 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1847 case HardLightCompositeOp:
1851 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1855 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1859 case HueCompositeOp:
1861 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1866 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1871 CompositeHSB(destination_pixel.red,destination_pixel.green,
1872 destination_pixel.blue,&hue,&saturation,&brightness);
1873 CompositeHSB(source_pixel.red,source_pixel.green,source_pixel.blue,
1875 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1878 case RedPixelChannel: pixel=red; break;
1879 case GreenPixelChannel: pixel=green; break;
1880 case BluePixelChannel: pixel=blue; break;
1881 default: pixel=Dc; break;
1886 case SrcInCompositeOp:
1888 pixel=gamma*(Da*Sc*Da);
1891 case LinearBurnCompositeOp:
1894 LinearBurn: as defined by Abode Photoshop, according to
1895 http://www.simplefilter.de/en/basics/mixmods.html is:
1897 f(Sc,Dc) = Sc + Dc - 1
1899 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1902 case LinearDodgeCompositeOp:
1904 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1907 case LinearLightCompositeOp:
1910 LinearLight: as defined by Abode Photoshop, according to
1911 http://www.simplefilter.de/en/basics/mixmods.html is:
1913 f(Sc,Dc) = Dc + 2*Sc - 1
1915 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1918 case LightenCompositeOp:
1922 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1925 pixel=QuantumRange*gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1928 case LightenIntensityCompositeOp:
1931 Lighten is equivalent to a 'Maximum' method
1932 OR a greyscale version of a binary 'And'
1933 OR the 'Union' of pixel sets.
1935 pixel=Sa*GetPixelIntensity(composite_image,p) >
1936 Da*GetPixelIntensity(image,q) ? Sc : Dc;
1939 case LuminizeCompositeOp:
1941 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1946 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1951 CompositeHSB(destination_pixel.red,destination_pixel.green,
1952 destination_pixel.blue,&hue,&saturation,&brightness);
1953 CompositeHSB(source_pixel.red,source_pixel.green,source_pixel.blue,
1954 &sans,&sans,&brightness);
1955 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1958 case RedPixelChannel: pixel=red; break;
1959 case GreenPixelChannel: pixel=green; break;
1960 case BluePixelChannel: pixel=blue; break;
1961 default: pixel=Dc; break;
1965 case MathematicsCompositeOp:
1968 'Mathematics' a free form user control mathematical composition
1971 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
1973 Where the arguments A,B,C,D are (currently) passed to composite
1974 as a command separated 'geometry' string in "compose:args" image
1977 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
1979 Applying the SVG transparency formula (see above), we get...
1981 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
1983 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
1986 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
1987 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
1988 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
1991 case MinusDstCompositeOp:
1993 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
1996 case MinusSrcCompositeOp:
1999 Minus source from destination.
2003 pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2006 case ModulateCompositeOp:
2011 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2016 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
2022 CompositeHSB(destination_pixel.red,destination_pixel.green,
2023 destination_pixel.blue,&hue,&saturation,&brightness);
2024 brightness+=(0.01*percent_brightness*offset)/midpoint;
2025 saturation*=0.01*percent_saturation;
2026 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
2029 case RedPixelChannel: pixel=red; break;
2030 case GreenPixelChannel: pixel=green; break;
2031 case BluePixelChannel: pixel=blue; break;
2032 default: pixel=Dc; break;
2036 case ModulusAddCompositeOp:
2039 if (pixel > QuantumRange)
2040 pixel-=(QuantumRange+1.0);
2041 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2044 case ModulusSubtractCompositeOp:
2048 pixel+=(QuantumRange+1.0);
2049 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2052 case MultiplyCompositeOp:
2054 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2057 case OutCompositeOp:
2058 case SrcOutCompositeOp:
2060 pixel=gamma*(Sa*Sc*(1.0-Da));
2063 case OverCompositeOp:
2064 case SrcOverCompositeOp:
2066 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2069 case OverlayCompositeOp:
2073 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2077 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2081 case PegtopLightCompositeOp:
2084 PegTop: A Soft-Light alternative: A continuous version of the
2085 Softlight function, producing very similar results.
2087 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2089 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2091 if (fabs(Da) < MagickEpsilon)
2093 pixel=QuantumRange*gamma*(Sca);
2096 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2100 case PinLightCompositeOp:
2103 PinLight: A Photoshop 7 composition method
2104 http://www.simplefilter.de/en/basics/mixmods.html
2106 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2108 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2110 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2113 if ((Dca*Sa) > (2.0*Sca*Da))
2115 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2118 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2121 case PlusCompositeOp:
2123 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
2126 case SaturateCompositeOp:
2128 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2133 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2138 CompositeHSB(destination_pixel.red,destination_pixel.green,
2139 destination_pixel.blue,&hue,&saturation,&brightness);
2140 CompositeHSB(source_pixel.red,source_pixel.green,source_pixel.blue,
2141 &sans,&saturation,&sans);
2142 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
2145 case RedPixelChannel: pixel=red; break;
2146 case GreenPixelChannel: pixel=green; break;
2147 case BluePixelChannel: pixel=blue; break;
2148 default: pixel=Dc; break;
2152 case ScreenCompositeOp:
2155 Screen: a negated multiply:
2157 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2159 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2162 case SoftLightCompositeOp:
2165 Refer to the March 2009 SVG specification.
2169 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2170 Sca*(1.0-Da)+Dca*(1.0-Sa));
2173 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2175 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2176 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2180 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2181 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2184 case ThresholdCompositeOp:
2190 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2195 pixel=gamma*(Dc+delta*amount);
2198 case VividLightCompositeOp:
2201 VividLight: A Photoshop 7 composition method. See
2202 http://www.simplefilter.de/en/basics/mixmods.html.
2204 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2206 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2208 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2211 if ((2.0*Sca) <= Sa)
2213 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2214 (1.0-Da)+Dca*(1.0-Sa));
2217 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2221 case XorCompositeOp:
2223 pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2232 q[i]=ClampToQuantum(pixel);
2234 p+=GetPixelChannels(composite_image);
2235 channels=GetPixelChannels(composite_image);
2236 if (p >= (pixels+channels*composite_image->columns))
2238 q+=GetPixelChannels(image);
2240 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2242 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2247 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2248 #pragma omp critical (MagickCore_CompositeImage)
2250 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2252 if (proceed == MagickFalse)
2256 composite_view=DestroyCacheView(composite_view);
2257 image_view=DestroyCacheView(image_view);
2258 if (destination_image != (Image * ) NULL)
2259 destination_image=DestroyImage(destination_image);
2264 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2268 % T e x t u r e I m a g e %
2272 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2274 % TextureImage() repeatedly tiles the texture image across and down the image
2277 % The format of the TextureImage method is:
2279 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2280 % ExceptionInfo *exception)
2282 % A description of each parameter follows:
2284 % o image: the image.
2286 % o texture_image: This image is the texture to layer on the background.
2289 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
2290 ExceptionInfo *exception)
2292 #define TextureImageTag "Texture/Image"
2307 assert(image != (Image *) NULL);
2308 if (image->debug != MagickFalse)
2309 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2310 assert(image->signature == MagickSignature);
2311 if (texture == (const Image *) NULL)
2312 return(MagickFalse);
2313 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2314 return(MagickFalse);
2315 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2316 if (texture_image == (const Image *) NULL)
2317 return(MagickFalse);
2318 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
2321 if ((image->compose != CopyCompositeOp) &&
2322 ((image->compose != OverCompositeOp) || (image->matte != MagickFalse) ||
2323 (texture_image->matte != MagickFalse)))
2326 Tile texture onto the image background.
2328 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2329 #pragma omp parallel for schedule(static) shared(status)
2331 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2336 if (status == MagickFalse)
2338 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2343 thread_status=CompositeImage(image,texture_image,image->compose,
2344 MagickFalse,x+texture_image->tile_offset.x,y+
2345 texture_image->tile_offset.y,exception);
2346 if (thread_status == MagickFalse)
2348 status=thread_status;
2352 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2357 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2358 #pragma omp critical (MagickCore_TextureImage)
2360 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2362 if (proceed == MagickFalse)
2366 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2367 image->rows,image->rows);
2368 texture_image=DestroyImage(texture_image);
2372 Tile texture onto the image background (optimized).
2375 texture_view=AcquireVirtualCacheView(texture_image,exception);
2376 image_view=AcquireAuthenticCacheView(image,exception);
2377 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2378 #pragma omp parallel for schedule(static) shared(status)
2380 for (y=0; y < (ssize_t) image->rows; y++)
2385 register const Quantum
2398 if (status == MagickFalse)
2400 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2401 (y+texture_image->tile_offset.y) % texture_image->rows,
2402 texture_image->columns,1,exception);
2403 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2404 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2409 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2415 width=texture_image->columns;
2416 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2417 width=image->columns-x;
2418 for (j=0; j < (ssize_t) width; j++)
2423 if (GetPixelMask(image,p) != 0)
2425 p+=GetPixelChannels(texture_image);
2426 q+=GetPixelChannels(image);
2429 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2438 channel=GetPixelChannelMapChannel(texture_image,i);
2439 texture_traits=GetPixelChannelMapTraits(texture_image,channel);
2440 traits=GetPixelChannelMapTraits(image,channel);
2441 if ((traits == UndefinedPixelTrait) ||
2442 (texture_traits == UndefinedPixelTrait))
2444 SetPixelChannel(image,channel,p[i],q);
2446 p+=GetPixelChannels(texture_image);
2447 q+=GetPixelChannels(image);
2450 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2451 if (sync == MagickFalse)
2453 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2458 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2459 #pragma omp critical (MagickCore_TextureImage)
2461 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2463 if (proceed == MagickFalse)
2467 texture_view=DestroyCacheView(texture_view);
2468 image_view=DestroyCacheView(image_view);
2469 texture_image=DestroyImage(texture_image);