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) \
338 dynamic_number_threads(image,image->columns,image->rows,1)
340 for (y=0; y < (ssize_t) image->rows; y++)
345 register const Quantum
357 if (status == MagickFalse)
359 if (clip_to_self != MagickFalse)
363 if ((y-y_offset) >= (ssize_t) composite_image->rows)
367 If pixels is NULL, y is outside overlay region.
369 pixels=(Quantum *) NULL;
371 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
373 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
374 composite_image->columns,1,exception);
375 if (p == (const Quantum *) NULL)
382 p-=x_offset*GetPixelChannels(composite_image);
384 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
385 if (q == (Quantum *) NULL)
390 for (x=0; x < (ssize_t) image->columns; x++)
403 if (clip_to_self != MagickFalse)
407 q+=GetPixelChannels(image);
410 if ((x-x_offset) >= (ssize_t) composite_image->columns)
413 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
414 ((x-x_offset) >= (ssize_t) composite_image->columns))
417 source[MaxPixelChannels];
422 Dc: destination color.
424 if (GetPixelMask(image,q) != 0)
426 q+=GetPixelChannels(image);
429 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
431 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
440 channel=GetPixelChannelMapChannel(image,i);
441 traits=GetPixelChannelMapTraits(image,channel);
442 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
443 if ((traits == UndefinedPixelTrait) ||
444 (composite_traits == UndefinedPixelTrait))
446 q[i]=source[channel];
448 q+=GetPixelChannels(image);
453 Sa: normalized source alpha.
454 Da: normalized destination alpha.
456 if (GetPixelMask(composite_image,p) != 0)
458 p+=GetPixelChannels(composite_image);
459 channels=GetPixelChannels(composite_image);
460 if (p >= (pixels+channels*composite_image->columns))
462 q+=GetPixelChannels(image);
465 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
466 Da=QuantumScale*GetPixelAlpha(image,q);
467 alpha=Sa*(-Da)+Sa+Da;
468 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
477 channel=GetPixelChannelMapChannel(image,i);
478 traits=GetPixelChannelMapTraits(image,channel);
479 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
480 if ((traits == UndefinedPixelTrait) ||
481 (composite_traits == UndefinedPixelTrait))
483 if ((traits & CopyPixelTrait) != 0)
485 if (channel != AlphaPixelChannel)
490 q[i]=GetPixelChannel(composite_image,channel,p);
496 q[i]=ClampToQuantum(QuantumRange*alpha);
501 Dc: destination color.
503 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
504 Dc=(MagickRealType) q[i];
505 gamma=MagickEpsilonReciprocal(alpha);
506 q[i]=ClampToQuantum(gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc));
508 p+=GetPixelChannels(composite_image);
509 channels=GetPixelChannels(composite_image);
510 if (p >= (pixels+channels*composite_image->columns))
512 q+=GetPixelChannels(image);
514 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
516 if (image->progress_monitor != (MagickProgressMonitor) NULL)
521 #if defined(MAGICKCORE_OPENMP_SUPPORT)
522 #pragma omp critical (MagickCore_CompositeImage)
524 proceed=SetImageProgress(image,CompositeImageTag,progress++,
526 if (proceed == MagickFalse)
530 composite_view=DestroyCacheView(composite_view);
531 image_view=DestroyCacheView(image_view);
535 MagickExport MagickBooleanType CompositeImage(Image *image,
536 const Image *composite_image,const CompositeOperator compose,
537 const MagickBooleanType clip_to_self,const ssize_t x_offset,
538 const ssize_t y_offset,ExceptionInfo *exception)
540 #define CompositeImageTag "Composite/Image"
560 destination_dissolve,
573 assert(image != (Image *) NULL);
574 assert(image->signature == MagickSignature);
575 if (image->debug != MagickFalse)
576 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
577 assert(composite_image != (Image *) NULL);
578 assert(composite_image->signature == MagickSignature);
579 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
581 if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
582 (IsGrayColorspace(composite_image->colorspace) == MagickFalse))
583 (void) TransformImageColorspace(image,sRGBColorspace,exception);
584 if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
586 status=CompositeOverImage(image,composite_image,clip_to_self,x_offset,
590 destination_image=(Image *) NULL;
592 destination_dissolve=1.0;
593 percent_brightness=100.0;
594 percent_saturation=100.0;
599 case CopyCompositeOp:
601 if ((x_offset < 0) || (y_offset < 0))
603 if ((x_offset+(ssize_t) composite_image->columns) >= (ssize_t) image->columns)
605 if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
608 composite_view=AcquireVirtualCacheView(composite_image,exception);
609 image_view=AcquireAuthenticCacheView(image,exception);
610 #if defined(MAGICKCORE_OPENMP_SUPPORT)
611 #pragma omp parallel for schedule(static,4) shared(status) \
612 dynamic_number_threads(image,image->columns,image->rows,1)
614 for (y=0; y < (ssize_t) composite_image->rows; y++)
619 register const Quantum
628 if (status == MagickFalse)
630 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
632 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
633 composite_image->columns,1,exception);
634 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
639 for (x=0; x < (ssize_t) composite_image->columns; x++)
644 if (GetPixelMask(composite_image,p) != 0)
646 p+=GetPixelChannels(composite_image);
647 q+=GetPixelChannels(image);
650 for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
659 channel=GetPixelChannelMapChannel(composite_image,i);
660 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
661 traits=GetPixelChannelMapTraits(image,channel);
662 if ((traits == UndefinedPixelTrait) ||
663 (composite_traits == UndefinedPixelTrait))
665 SetPixelChannel(image,channel,p[i],q);
667 p+=GetPixelChannels(composite_image);
668 q+=GetPixelChannels(image);
670 sync=SyncCacheViewAuthenticPixels(image_view,exception);
671 if (sync == MagickFalse)
673 if (image->progress_monitor != (MagickProgressMonitor) NULL)
678 #if defined(MAGICKCORE_OPENMP_SUPPORT)
679 #pragma omp critical (MagickCore_CompositeImage)
681 proceed=SetImageProgress(image,CompositeImageTag,
682 (MagickOffsetType) y,image->rows);
683 if (proceed == MagickFalse)
687 composite_view=DestroyCacheView(composite_view);
688 image_view=DestroyCacheView(image_view);
691 case CopyAlphaCompositeOp:
692 case ChangeMaskCompositeOp:
693 case IntensityCompositeOp:
696 Modify destination outside the overlaid region and require an alpha
697 channel to exist, to add transparency.
699 if (image->matte == MagickFalse)
700 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
703 case BlurCompositeOp:
728 Blur Image by resampling.
730 Blur Image dictated by an overlay gradient map: X = red_channel;
731 Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
733 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
735 if (destination_image == (Image *) NULL)
738 Gather the maximum blur sigma values from user.
740 SetGeometryInfo(&geometry_info);
742 value=GetImageArtifact(composite_image,"compose:args");
743 if (value != (char *) NULL)
744 flags=ParseGeometry(value,&geometry_info);
745 if ((flags & WidthValue) == 0 ) {
746 (void) ThrowMagickException(exception,GetMagickModule(),
747 OptionWarning,"InvalidSetting","'%s' '%s'",
748 "compose:args",value);
749 destination_image=DestroyImage(destination_image);
753 Users input sigma now needs to be converted to the EWA ellipse size.
754 The filter defaults to a sigma of 0.5 so to make this match the
755 users input the ellipse size needs to be doubled.
757 width=height=geometry_info.rho*2.0;
758 if ((flags & HeightValue) != 0 )
759 height=geometry_info.sigma*2.0;
761 /* default the unrotated ellipse width and height axis vectors */
766 /* rotate vectors if a rotation angle is given */
767 if ((flags & XValue) != 0 )
772 angle=DegreesToRadians(geometry_info.xi);
773 blur.x1=width*cos(angle);
774 blur.x2=width*sin(angle);
775 blur.y1=(-height*sin(angle));
776 blur.y2=height*cos(angle);
778 /* Otherwise lets set a angle range and calculate in the loop */
781 if ((flags & YValue) != 0 )
783 angle_start=DegreesToRadians(geometry_info.xi);
784 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
787 Set up a gaussian cylindrical filter for EWA Bluring.
789 As the minimum ellipse radius of support*1.0 the EWA algorithm
790 can only produce a minimum blur of 0.5 for Gaussian (support=2.0)
791 This means that even 'No Blur' will be still a little blurry!
793 The solution (as well as the problem of preventing any user
794 expert filter settings, is to set our own user settings, then
795 restore them afterwards.
797 resample_filter=AcquireResampleFilter(image,exception);
798 SetResampleFilter(resample_filter,GaussianFilter);
800 /* do the variable blurring of each pixel in image */
801 GetPixelInfo(image,&pixel);
802 composite_view=AcquireVirtualCacheView(composite_image,exception);
803 destination_view=AcquireAuthenticCacheView(destination_image,exception);
804 for (y=0; y < (ssize_t) composite_image->rows; y++)
809 register const Quantum
818 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
820 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
822 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
823 destination_image->columns,1,exception);
824 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
826 for (x=0; x < (ssize_t) composite_image->columns; x++)
828 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
830 p+=GetPixelChannels(composite_image);
833 if (fabs(angle_range) > MagickEpsilon)
838 angle=angle_start+angle_range*QuantumScale*
839 GetPixelBlue(composite_image,p);
840 blur.x1=width*cos(angle);
841 blur.x2=width*sin(angle);
842 blur.y1=(-height*sin(angle));
843 blur.y2=height*cos(angle);
846 if ( x == 10 && y == 60 ) {
847 fprintf(stderr, "blur.x=%lf,%lf, blur.y=%lf,%lf\n",
848 blur.x1, blur.x2, blur.y1, blur.y2);
849 fprintf(stderr, "scaled by=%lf,%lf\n",
850 QuantumScale*GetPixelRed(p), QuantumScale*GetPixelGreen(p));
852 ScaleResampleFilter(resample_filter,
853 blur.x1*QuantumScale*GetPixelRed(composite_image,p),
854 blur.y1*QuantumScale*GetPixelGreen(composite_image,p),
855 blur.x2*QuantumScale*GetPixelRed(composite_image,p),
856 blur.y2*QuantumScale*GetPixelGreen(composite_image,p) );
857 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
858 (double) y_offset+y,&pixel,exception);
859 SetPixelInfoPixel(destination_image,&pixel,q);
860 p+=GetPixelChannels(composite_image);
861 q+=GetPixelChannels(destination_image);
863 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
864 if (sync == MagickFalse)
867 resample_filter=DestroyResampleFilter(resample_filter);
868 composite_view=DestroyCacheView(composite_view);
869 destination_view=DestroyCacheView(destination_view);
870 composite_image=destination_image;
873 case DisplaceCompositeOp:
874 case DistortCompositeOp:
896 Displace/Distort based on overlay gradient map:
897 X = red_channel; Y = green_channel;
898 compose:args = x_scale[,y_scale[,center.x,center.y]]
900 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
902 if (destination_image == (Image *) NULL)
904 SetGeometryInfo(&geometry_info);
906 value=GetImageArtifact(composite_image,"compose:args");
907 if (value != (char *) NULL)
908 flags=ParseGeometry(value,&geometry_info);
909 if ((flags & (WidthValue|HeightValue)) == 0 )
911 if ((flags & AspectValue) == 0)
913 horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
915 vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
919 horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
920 vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
925 horizontal_scale=geometry_info.rho;
926 vertical_scale=geometry_info.sigma;
927 if ((flags & PercentValue) != 0)
929 if ((flags & AspectValue) == 0)
931 horizontal_scale*=(composite_image->columns-1.0)/200.0;
932 vertical_scale*=(composite_image->rows-1.0)/200.0;
936 horizontal_scale*=(image->columns-1.0)/200.0;
937 vertical_scale*=(image->rows-1.0)/200.0;
940 if ((flags & HeightValue) == 0)
941 vertical_scale=horizontal_scale;
944 Determine fixed center point for absolute distortion map
946 Displace offset relative to a fixed absolute point
947 Select that point according to +X+Y user inputs.
948 default = center of overlay image
949 arg flag '!' = locations/percentage relative to background image
951 center.x=(MagickRealType) x_offset;
952 center.y=(MagickRealType) y_offset;
953 if (compose == DistortCompositeOp)
955 if ((flags & XValue) == 0)
956 if ((flags & AspectValue) == 0)
957 center.x=(MagickRealType) x_offset+(composite_image->columns-1)/
960 center.x=((MagickRealType) image->columns-1)/2.0;
962 if ((flags & AspectValue) == 0)
963 center.x=(MagickRealType) x_offset+geometry_info.xi;
965 center.x=geometry_info.xi;
966 if ((flags & YValue) == 0)
967 if ((flags & AspectValue) == 0)
968 center.y=(MagickRealType) y_offset+(composite_image->rows-1)/2.0;
970 center.y=((MagickRealType) image->rows-1)/2.0;
972 if ((flags & AspectValue) == 0)
973 center.y=(MagickRealType) y_offset+geometry_info.psi;
975 center.y=geometry_info.psi;
978 Shift the pixel offset point as defined by the provided,
979 displacement/distortion map. -- Like a lens...
981 GetPixelInfo(image,&pixel);
982 image_view=AcquireVirtualCacheView(image,exception);
983 composite_view=AcquireVirtualCacheView(composite_image,exception);
984 destination_view=AcquireAuthenticCacheView(destination_image,exception);
985 for (y=0; y < (ssize_t) composite_image->rows; y++)
990 register const Quantum
999 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1001 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
1003 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
1004 destination_image->columns,1,exception);
1005 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1007 for (x=0; x < (ssize_t) composite_image->columns; x++)
1009 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1011 p+=GetPixelChannels(composite_image);
1015 Displace the offset.
1017 offset.x=(horizontal_scale*(GetPixelRed(composite_image,p)-
1018 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1019 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
1021 offset.y=(vertical_scale*(GetPixelGreen(composite_image,p)-
1022 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1023 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
1025 (void) InterpolatePixelInfo(image,image_view,
1026 UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1029 Mask with the 'invalid pixel mask' in alpha channel.
1031 pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
1032 pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
1033 SetPixelInfoPixel(destination_image,&pixel,q);
1034 p+=GetPixelChannels(composite_image);
1035 q+=GetPixelChannels(destination_image);
1037 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1038 if (sync == MagickFalse)
1041 destination_view=DestroyCacheView(destination_view);
1042 composite_view=DestroyCacheView(composite_view);
1043 image_view=DestroyCacheView(image_view);
1044 composite_image=destination_image;
1047 case DissolveCompositeOp:
1053 Geometry arguments to dissolve factors.
1055 value=GetImageArtifact(composite_image,"compose:args");
1056 if (value != (char *) NULL)
1058 flags=ParseGeometry(value,&geometry_info);
1059 source_dissolve=geometry_info.rho/100.0;
1060 destination_dissolve=1.0;
1061 if ((source_dissolve-MagickEpsilon) < 0.0)
1062 source_dissolve=0.0;
1063 if ((source_dissolve+MagickEpsilon) > 1.0)
1065 destination_dissolve=2.0-source_dissolve;
1066 source_dissolve=1.0;
1068 if ((flags & SigmaValue) != 0)
1069 destination_dissolve=geometry_info.sigma/100.0;
1070 if ((destination_dissolve-MagickEpsilon) < 0.0)
1071 destination_dissolve=0.0;
1072 /* posible speed up? -- from IMv6 update
1073 clip_to_self=MagickFalse;
1074 if ((destination_dissolve+MagickEpsilon) > 1.0 )
1076 destination_dissolve=1.0;
1077 clip_to_self=MagickTrue;
1083 case BlendCompositeOp:
1088 value=GetImageArtifact(composite_image,"compose:args");
1089 if (value != (char *) NULL)
1091 flags=ParseGeometry(value,&geometry_info);
1092 source_dissolve=geometry_info.rho/100.0;
1093 destination_dissolve=1.0-source_dissolve;
1094 if ((flags & SigmaValue) != 0)
1095 destination_dissolve=geometry_info.sigma/100.0;
1099 case MathematicsCompositeOp:
1105 Just collect the values from "compose:args", setting.
1106 Unused values are set to zero automagically.
1108 Arguments are normally a comma separated list, so this probably should
1109 be changed to some 'general comma list' parser, (with a minimum
1112 SetGeometryInfo(&geometry_info);
1113 value=GetImageArtifact(composite_image,"compose:args");
1114 if (value != (char *) NULL)
1115 (void) ParseGeometry(value,&geometry_info);
1118 case ModulateCompositeOp:
1124 Determine the brightness and saturation scale.
1126 value=GetImageArtifact(composite_image,"compose:args");
1127 if (value != (char *) NULL)
1129 flags=ParseGeometry(value,&geometry_info);
1130 percent_brightness=geometry_info.rho;
1131 if ((flags & SigmaValue) != 0)
1132 percent_saturation=geometry_info.sigma;
1136 case ThresholdCompositeOp:
1142 Determine the amount and threshold.
1144 value=GetImageArtifact(composite_image,"compose:args");
1145 if (value != (char *) NULL)
1147 flags=ParseGeometry(value,&geometry_info);
1148 amount=geometry_info.rho;
1149 threshold=geometry_info.sigma;
1150 if ((flags & SigmaValue) == 0)
1153 threshold*=QuantumRange;
1164 midpoint=((MagickRealType) QuantumRange+1.0)/2;
1165 composite_view=AcquireVirtualCacheView(composite_image,exception);
1166 image_view=AcquireAuthenticCacheView(image,exception);
1167 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1168 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1169 dynamic_number_threads(image,image->columns,image->rows,1)
1171 for (y=0; y < (ssize_t) image->rows; y++)
1188 register const Quantum
1197 if (status == MagickFalse)
1199 if (clip_to_self != MagickFalse)
1203 if ((y-y_offset) >= (ssize_t) composite_image->rows)
1207 If pixels is NULL, y is outside overlay region.
1209 pixels=(Quantum *) NULL;
1211 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
1213 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
1214 composite_image->columns,1,exception);
1215 if (p == (const Quantum *) NULL)
1222 p-=x_offset*GetPixelChannels(composite_image);
1224 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1225 if (q == (Quantum *) NULL)
1233 GetPixelInfo(image,&destination_pixel);
1234 GetPixelInfo(composite_image,&source_pixel);
1235 for (x=0; x < (ssize_t) image->columns; x++)
1253 if (clip_to_self != MagickFalse)
1257 q+=GetPixelChannels(image);
1260 if ((x-x_offset) >= (ssize_t) composite_image->columns)
1263 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1264 ((x-x_offset) >= (ssize_t) composite_image->columns))
1267 source[MaxPixelChannels];
1272 Dc: destination color.
1274 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
1276 if (GetPixelMask(image,q) != 0)
1278 q+=GetPixelChannels(image);
1281 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1293 channel=GetPixelChannelMapChannel(image,i);
1294 traits=GetPixelChannelMapTraits(image,channel);
1295 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
1296 if ((traits == UndefinedPixelTrait) ||
1297 (composite_traits == UndefinedPixelTrait))
1301 case AlphaCompositeOp:
1302 case ChangeMaskCompositeOp:
1303 case CopyAlphaCompositeOp:
1304 case DstAtopCompositeOp:
1305 case DstInCompositeOp:
1307 case IntensityCompositeOp:
1308 case OutCompositeOp:
1309 case SrcInCompositeOp:
1310 case SrcOutCompositeOp:
1312 pixel=(MagickRealType) q[i];
1313 if (channel == AlphaPixelChannel)
1314 pixel=(MagickRealType) TransparentAlpha;
1317 case ClearCompositeOp:
1318 case CopyCompositeOp:
1319 case ReplaceCompositeOp:
1320 case SrcCompositeOp:
1322 if (channel == AlphaPixelChannel)
1324 pixel=(MagickRealType) TransparentAlpha;
1330 case BlendCompositeOp:
1331 case DissolveCompositeOp:
1333 if (channel == AlphaPixelChannel)
1335 pixel=destination_dissolve*GetPixelAlpha(composite_image,
1339 pixel=(MagickRealType) source[channel];
1344 pixel=(MagickRealType) source[channel];
1348 q[i]=ClampToQuantum(pixel);
1350 q+=GetPixelChannels(image);
1354 Authentic composite:
1355 Sa: normalized source alpha.
1356 Da: normalized destination alpha.
1358 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
1359 Da=QuantumScale*GetPixelAlpha(image,q);
1362 case BumpmapCompositeOp:
1364 alpha=GetPixelIntensity(composite_image,p)*Sa;
1367 case ColorBurnCompositeOp:
1368 case ColorDodgeCompositeOp:
1369 case DifferenceCompositeOp:
1370 case DivideDstCompositeOp:
1371 case DivideSrcCompositeOp:
1372 case ExclusionCompositeOp:
1373 case HardLightCompositeOp:
1374 case LinearBurnCompositeOp:
1375 case LinearDodgeCompositeOp:
1376 case LinearLightCompositeOp:
1377 case MathematicsCompositeOp:
1378 case MinusDstCompositeOp:
1379 case MinusSrcCompositeOp:
1380 case ModulusAddCompositeOp:
1381 case ModulusSubtractCompositeOp:
1382 case MultiplyCompositeOp:
1383 case OverlayCompositeOp:
1384 case PegtopLightCompositeOp:
1385 case PinLightCompositeOp:
1386 case ScreenCompositeOp:
1387 case SoftLightCompositeOp:
1388 case VividLightCompositeOp:
1390 alpha=RoundToUnity(Sa+Da-Sa*Da);
1393 case DarkenCompositeOp:
1394 case DstAtopCompositeOp:
1395 case DstInCompositeOp:
1397 case LightenCompositeOp:
1398 case SrcInCompositeOp:
1403 case DissolveCompositeOp:
1405 alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
1406 Sa+destination_dissolve*Da;
1409 case DstOverCompositeOp:
1411 alpha=Da*(-Sa)+Da+Sa;
1414 case DstOutCompositeOp:
1419 case OutCompositeOp:
1420 case SrcOutCompositeOp:
1425 case OverCompositeOp:
1426 case SrcOverCompositeOp:
1428 alpha=Sa*(-Da)+Sa+Da;
1431 case BlendCompositeOp:
1432 case PlusCompositeOp:
1434 alpha=RoundToUnity(Sa+Da);
1437 case XorCompositeOp:
1439 alpha=Sa+Da-2.0*Sa*Da;
1448 if (GetPixelMask(image,p) != 0)
1450 p+=GetPixelChannels(composite_image);
1451 q+=GetPixelChannels(image);
1456 case ColorizeCompositeOp:
1457 case HueCompositeOp:
1458 case LuminizeCompositeOp:
1459 case ModulateCompositeOp:
1460 case SaturateCompositeOp:
1462 GetPixelInfoPixel(composite_image,p,&source_pixel);
1463 GetPixelInfoPixel(image,q,&destination_pixel);
1469 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1484 channel=GetPixelChannelMapChannel(image,i);
1485 traits=GetPixelChannelMapTraits(image,channel);
1486 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
1487 if (traits == UndefinedPixelTrait)
1489 if ((compose != IntensityCompositeOp) &&
1490 (composite_traits == UndefinedPixelTrait))
1494 Dc: destination color.
1496 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
1497 Dc=(MagickRealType) q[i];
1498 if ((traits & CopyPixelTrait) != 0)
1500 if (channel != AlphaPixelChannel)
1505 q[i]=ClampToQuantum(Sc);
1513 case AlphaCompositeOp:
1515 pixel=QuantumRange*Sa;
1518 case AtopCompositeOp:
1519 case CopyBlackCompositeOp:
1520 case CopyBlueCompositeOp:
1521 case CopyCyanCompositeOp:
1522 case CopyGreenCompositeOp:
1523 case CopyMagentaCompositeOp:
1524 case CopyRedCompositeOp:
1525 case CopyYellowCompositeOp:
1526 case SrcAtopCompositeOp:
1527 case DstCompositeOp:
1530 pixel=QuantumRange*Da;
1533 case ChangeMaskCompositeOp:
1538 if (Da > ((MagickRealType) QuantumRange/2.0))
1540 pixel=(MagickRealType) TransparentAlpha;
1543 equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
1544 if (equivalent != MagickFalse)
1546 pixel=(MagickRealType) TransparentAlpha;
1549 pixel=(MagickRealType) OpaqueAlpha;
1552 case ClearCompositeOp:
1554 pixel=(MagickRealType) TransparentAlpha;
1557 case ColorizeCompositeOp:
1558 case HueCompositeOp:
1559 case LuminizeCompositeOp:
1560 case SaturateCompositeOp:
1562 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1564 pixel=QuantumRange*Da;
1567 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1569 pixel=QuantumRange*Sa;
1574 pixel=QuantumRange*Da;
1577 pixel=QuantumRange*Sa;
1580 case CopyAlphaCompositeOp:
1582 pixel=QuantumRange*Sa;
1583 if (composite_image->matte == MagickFalse)
1584 pixel=GetPixelIntensity(composite_image,p);
1587 case CopyCompositeOp:
1588 case DisplaceCompositeOp:
1589 case DistortCompositeOp:
1590 case DstAtopCompositeOp:
1591 case ReplaceCompositeOp:
1592 case SrcCompositeOp:
1594 pixel=QuantumRange*Sa;
1597 case DarkenIntensityCompositeOp:
1599 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1600 (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
1603 case IntensityCompositeOp:
1605 pixel=(MagickRealType) GetPixelIntensity(composite_image,p);
1608 case LightenIntensityCompositeOp:
1610 pixel=Sa*GetPixelIntensity(composite_image,p) >
1611 Da*GetPixelIntensity(image,q) ? Sa : Da;
1614 case ModulateCompositeOp:
1616 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1618 pixel=QuantumRange*Da;
1621 pixel=QuantumRange*Da;
1626 pixel=QuantumRange*alpha;
1630 q[i]=ClampToQuantum(pixel);
1634 Porter-Duff compositions:
1635 Sca: source normalized color multiplied by alpha.
1636 Dca: normalized destination color multiplied by alpha.
1638 Sca=QuantumScale*Sa*Sc;
1639 Dca=QuantumScale*Da*Dc;
1642 case DarkenCompositeOp:
1643 case LightenCompositeOp:
1644 case ModulusSubtractCompositeOp:
1652 gamma=MagickEpsilonReciprocal(alpha);
1656 case AlphaCompositeOp:
1658 pixel=QuantumRange*Sa;
1661 case AtopCompositeOp:
1662 case SrcAtopCompositeOp:
1664 pixel=Sc*Sa+Dc*(1.0-Sa);
1667 case BlendCompositeOp:
1669 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1672 case BlurCompositeOp:
1673 case DisplaceCompositeOp:
1674 case DistortCompositeOp:
1675 case CopyCompositeOp:
1676 case ReplaceCompositeOp:
1677 case SrcCompositeOp:
1682 case BumpmapCompositeOp:
1684 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1689 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1692 case ChangeMaskCompositeOp:
1697 case ClearCompositeOp:
1702 case ColorBurnCompositeOp:
1705 Refer to the March 2009 SVG specification.
1707 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1709 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1712 if (Sca < MagickEpsilon)
1714 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1717 pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
1718 Sca*(1.0-Da)+Dca*(1.0-Sa));
1721 case ColorDodgeCompositeOp:
1723 if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1725 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1728 if (fabs(Sca-Sa) < MagickEpsilon)
1730 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1733 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1737 case ColorizeCompositeOp:
1739 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1744 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1749 CompositeHSB(destination_pixel.red,destination_pixel.green,
1750 destination_pixel.blue,&sans,&sans,&brightness);
1751 CompositeHSB(source_pixel.red,source_pixel.green,source_pixel.blue,
1752 &hue,&saturation,&sans);
1753 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1756 case RedPixelChannel: pixel=red; break;
1757 case GreenPixelChannel: pixel=green; break;
1758 case BluePixelChannel: pixel=blue; break;
1759 default: pixel=Dc; break;
1763 case CopyAlphaCompositeOp:
1764 case IntensityCompositeOp:
1769 case CopyBlackCompositeOp:
1771 if (channel == BlackPixelChannel)
1772 pixel=(MagickRealType) GetPixelBlack(composite_image,p);
1775 case CopyBlueCompositeOp:
1776 case CopyYellowCompositeOp:
1778 if (channel == BluePixelChannel)
1779 pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1782 case CopyGreenCompositeOp:
1783 case CopyMagentaCompositeOp:
1785 if (channel == GreenPixelChannel)
1786 pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1789 case CopyRedCompositeOp:
1790 case CopyCyanCompositeOp:
1792 if (channel == RedPixelChannel)
1793 pixel=(MagickRealType) GetPixelRed(composite_image,p);
1796 case DarkenCompositeOp:
1799 Darken is equivalent to a 'Minimum' method
1800 OR a greyscale version of a binary 'Or'
1801 OR the 'Intersection' of pixel sets.
1805 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1808 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1811 case DarkenIntensityCompositeOp:
1813 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1814 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1817 case DifferenceCompositeOp:
1819 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1822 case DissolveCompositeOp:
1824 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1825 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1828 case DivideDstCompositeOp:
1830 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1832 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1835 if (fabs(Dca) < MagickEpsilon)
1837 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1840 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1843 case DivideSrcCompositeOp:
1845 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1847 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1850 if (fabs(Sca) < MagickEpsilon)
1852 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1855 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1858 case DstAtopCompositeOp:
1860 pixel=Dc*Da+Sc*(1.0-Da);
1863 case DstCompositeOp:
1869 case DstInCompositeOp:
1871 pixel=gamma*(Sa*Dc*Sa);
1874 case DstOutCompositeOp:
1876 pixel=gamma*(Da*Dc*(1.0-Sa));
1879 case DstOverCompositeOp:
1881 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1884 case ExclusionCompositeOp:
1886 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1890 case HardLightCompositeOp:
1894 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1898 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1902 case HueCompositeOp:
1904 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1909 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1914 CompositeHSB(destination_pixel.red,destination_pixel.green,
1915 destination_pixel.blue,&hue,&saturation,&brightness);
1916 CompositeHSB(source_pixel.red,source_pixel.green,source_pixel.blue,
1918 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1921 case RedPixelChannel: pixel=red; break;
1922 case GreenPixelChannel: pixel=green; break;
1923 case BluePixelChannel: pixel=blue; break;
1924 default: pixel=Dc; break;
1929 case SrcInCompositeOp:
1931 pixel=gamma*(Da*Sc*Da);
1934 case LinearBurnCompositeOp:
1937 LinearBurn: as defined by Abode Photoshop, according to
1938 http://www.simplefilter.de/en/basics/mixmods.html is:
1940 f(Sc,Dc) = Sc + Dc - 1
1942 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1945 case LinearDodgeCompositeOp:
1947 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1950 case LinearLightCompositeOp:
1953 LinearLight: as defined by Abode Photoshop, according to
1954 http://www.simplefilter.de/en/basics/mixmods.html is:
1956 f(Sc,Dc) = Dc + 2*Sc - 1
1958 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1961 case LightenCompositeOp:
1965 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1968 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1971 case LightenIntensityCompositeOp:
1974 Lighten is equivalent to a 'Maximum' method
1975 OR a greyscale version of a binary 'And'
1976 OR the 'Union' of pixel sets.
1978 pixel=Sa*GetPixelIntensity(composite_image,p) >
1979 Da*GetPixelIntensity(image,q) ? Sc : Dc;
1982 case LuminizeCompositeOp:
1984 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1989 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1994 CompositeHSB(destination_pixel.red,destination_pixel.green,
1995 destination_pixel.blue,&hue,&saturation,&brightness);
1996 CompositeHSB(source_pixel.red,source_pixel.green,source_pixel.blue,
1997 &sans,&sans,&brightness);
1998 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
2001 case RedPixelChannel: pixel=red; break;
2002 case GreenPixelChannel: pixel=green; break;
2003 case BluePixelChannel: pixel=blue; break;
2004 default: pixel=Dc; break;
2008 case MathematicsCompositeOp:
2011 'Mathematics' a free form user control mathematical composition
2014 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
2016 Where the arguments A,B,C,D are (currently) passed to composite
2017 as a command separated 'geometry' string in "compose:args" image
2020 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
2022 Applying the SVG transparency formula (see above), we get...
2024 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
2026 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
2029 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
2030 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
2031 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
2034 case MinusDstCompositeOp:
2036 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2039 case MinusSrcCompositeOp:
2042 Minus source from destination.
2046 pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2049 case ModulateCompositeOp:
2054 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2059 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
2065 CompositeHSB(destination_pixel.red,destination_pixel.green,
2066 destination_pixel.blue,&hue,&saturation,&brightness);
2067 brightness+=(0.01*percent_brightness*offset)/midpoint;
2068 saturation*=0.01*percent_saturation;
2069 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
2072 case RedPixelChannel: pixel=red; break;
2073 case GreenPixelChannel: pixel=green; break;
2074 case BluePixelChannel: pixel=blue; break;
2075 default: pixel=Dc; break;
2079 case ModulusAddCompositeOp:
2082 if (pixel > QuantumRange)
2083 pixel-=(QuantumRange+1.0);
2084 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2087 case ModulusSubtractCompositeOp:
2091 pixel+=(QuantumRange+1.0);
2092 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2095 case MultiplyCompositeOp:
2097 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2100 case OutCompositeOp:
2101 case SrcOutCompositeOp:
2103 pixel=gamma*(Sa*Sc*(1.0-Da));
2106 case OverCompositeOp:
2107 case SrcOverCompositeOp:
2109 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2112 case OverlayCompositeOp:
2116 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2120 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2124 case PegtopLightCompositeOp:
2127 PegTop: A Soft-Light alternative: A continuous version of the
2128 Softlight function, producing very similar results.
2130 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2132 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2134 if (fabs(Da) < MagickEpsilon)
2136 pixel=QuantumRange*gamma*(Sca);
2139 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2143 case PinLightCompositeOp:
2146 PinLight: A Photoshop 7 composition method
2147 http://www.simplefilter.de/en/basics/mixmods.html
2149 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2151 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2153 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2156 if ((Dca*Sa) > (2.0*Sca*Da))
2158 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2161 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2164 case PlusCompositeOp:
2166 pixel=gamma*(Sa*Sc+Da*Dc);
2169 case SaturateCompositeOp:
2171 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2176 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2181 CompositeHSB(destination_pixel.red,destination_pixel.green,
2182 destination_pixel.blue,&hue,&saturation,&brightness);
2183 CompositeHSB(source_pixel.red,source_pixel.green,source_pixel.blue,
2184 &sans,&saturation,&sans);
2185 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
2188 case RedPixelChannel: pixel=red; break;
2189 case GreenPixelChannel: pixel=green; break;
2190 case BluePixelChannel: pixel=blue; break;
2191 default: pixel=Dc; break;
2195 case ScreenCompositeOp:
2198 Screen: a negated multiply:
2200 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2202 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2205 case SoftLightCompositeOp:
2208 Refer to the March 2009 SVG specification.
2212 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2213 Sca*(1.0-Da)+Dca*(1.0-Sa));
2216 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2218 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2219 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2223 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2224 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2227 case ThresholdCompositeOp:
2233 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2238 pixel=gamma*(Dc+delta*amount);
2241 case VividLightCompositeOp:
2244 VividLight: A Photoshop 7 composition method. See
2245 http://www.simplefilter.de/en/basics/mixmods.html.
2247 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2249 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2251 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2254 if ((2.0*Sca) <= Sa)
2256 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2257 (1.0-Da)+Dca*(1.0-Sa));
2260 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2264 case XorCompositeOp:
2266 pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2275 q[i]=ClampToQuantum(pixel);
2277 p+=GetPixelChannels(composite_image);
2278 channels=GetPixelChannels(composite_image);
2279 if (p >= (pixels+channels*composite_image->columns))
2281 q+=GetPixelChannels(image);
2283 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2285 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2290 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2291 #pragma omp critical (MagickCore_CompositeImage)
2293 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2295 if (proceed == MagickFalse)
2299 composite_view=DestroyCacheView(composite_view);
2300 image_view=DestroyCacheView(image_view);
2301 if (destination_image != (Image * ) NULL)
2302 destination_image=DestroyImage(destination_image);
2307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2311 % T e x t u r e I m a g e %
2315 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2317 % TextureImage() repeatedly tiles the texture image across and down the image
2320 % The format of the TextureImage method is:
2322 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2323 % ExceptionInfo *exception)
2325 % A description of each parameter follows:
2327 % o image: the image.
2329 % o texture_image: This image is the texture to layer on the background.
2332 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
2333 ExceptionInfo *exception)
2335 #define TextureImageTag "Texture/Image"
2350 assert(image != (Image *) NULL);
2351 if (image->debug != MagickFalse)
2352 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2353 assert(image->signature == MagickSignature);
2354 if (texture == (const Image *) NULL)
2355 return(MagickFalse);
2356 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2357 return(MagickFalse);
2358 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2359 if (texture_image == (const Image *) NULL)
2360 return(MagickFalse);
2361 if (IsGrayColorspace(texture_image->colorspace) != MagickFalse)
2362 (void) TransformImageColorspace(texture_image,sRGBColorspace,exception);
2363 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
2366 if ((image->compose != CopyCompositeOp) &&
2367 ((image->compose != OverCompositeOp) || (image->matte != MagickFalse) ||
2368 (texture_image->matte != MagickFalse)))
2371 Tile texture onto the image background.
2373 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2374 #pragma omp parallel for schedule(static) shared(status) \
2375 dynamic_number_threads(image,image->columns,image->rows,1)
2377 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2382 if (status == MagickFalse)
2384 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2389 thread_status=CompositeImage(image,texture_image,image->compose,
2390 MagickFalse,x+texture_image->tile_offset.x,y+
2391 texture_image->tile_offset.y,exception);
2392 if (thread_status == MagickFalse)
2394 status=thread_status;
2398 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2403 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2404 #pragma omp critical (MagickCore_TextureImage)
2406 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2408 if (proceed == MagickFalse)
2412 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2413 image->rows,image->rows);
2414 texture_image=DestroyImage(texture_image);
2418 Tile texture onto the image background (optimized).
2421 texture_view=AcquireVirtualCacheView(texture_image,exception);
2422 image_view=AcquireAuthenticCacheView(image,exception);
2423 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2424 #pragma omp parallel for schedule(static) shared(status) \
2425 dynamic_number_threads(image,image->columns,image->rows,1)
2427 for (y=0; y < (ssize_t) image->rows; y++)
2432 register const Quantum
2445 if (status == MagickFalse)
2447 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2448 (y+texture_image->tile_offset.y) % texture_image->rows,
2449 texture_image->columns,1,exception);
2450 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2451 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2456 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2462 width=texture_image->columns;
2463 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2464 width=image->columns-x;
2465 for (j=0; j < (ssize_t) width; j++)
2470 if (GetPixelMask(image,p) != 0)
2472 p+=GetPixelChannels(texture_image);
2473 q+=GetPixelChannels(image);
2476 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2485 channel=GetPixelChannelMapChannel(texture_image,i);
2486 texture_traits=GetPixelChannelMapTraits(texture_image,channel);
2487 traits=GetPixelChannelMapTraits(image,channel);
2488 if ((traits == UndefinedPixelTrait) ||
2489 (texture_traits == UndefinedPixelTrait))
2491 SetPixelChannel(image,channel,p[i],q);
2493 p+=GetPixelChannels(texture_image);
2494 q+=GetPixelChannels(image);
2497 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2498 if (sync == MagickFalse)
2500 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2505 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2506 #pragma omp critical (MagickCore_TextureImage)
2508 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2510 if (proceed == MagickFalse)
2514 texture_view=DestroyCacheView(texture_view);
2515 image_view=DestroyCacheView(image_view);
2516 texture_image=DestroyImage(texture_image);