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->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=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : 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->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(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->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 CopyCompositeOp:
1581 case CopyAlphaCompositeOp:
1582 case DisplaceCompositeOp:
1583 case DistortCompositeOp:
1584 case DstAtopCompositeOp:
1585 case ReplaceCompositeOp:
1586 case SrcCompositeOp:
1588 pixel=QuantumRange*Sa;
1591 case DarkenIntensityCompositeOp:
1593 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1594 (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
1597 case IntensityCompositeOp:
1599 pixel=(MagickRealType) GetPixelIntensity(composite_image,p);
1602 case LightenIntensityCompositeOp:
1604 pixel=Sa*GetPixelIntensity(composite_image,p) >
1605 Da*GetPixelIntensity(image,q) ? Sa : Da;
1608 case ModulateCompositeOp:
1610 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1612 pixel=QuantumRange*Da;
1615 pixel=QuantumRange*Da;
1620 pixel=QuantumRange*alpha;
1624 q[i]=ClampToQuantum(pixel);
1628 Porter-Duff compositions:
1629 Sca: source normalized color multiplied by alpha.
1630 Dca: normalized destination color multiplied by alpha.
1632 Sca=QuantumScale*Sa*Sc;
1633 Dca=QuantumScale*Da*Dc;
1636 case DarkenCompositeOp:
1637 case LightenCompositeOp:
1638 case ModulusSubtractCompositeOp:
1646 gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
1650 case AlphaCompositeOp:
1652 pixel=QuantumRange*Sa;
1655 case AtopCompositeOp:
1656 case SrcAtopCompositeOp:
1658 pixel=Sc*Sa+Dc*(1.0-Sa);
1661 case BlendCompositeOp:
1663 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1666 case BlurCompositeOp:
1667 case DisplaceCompositeOp:
1668 case DistortCompositeOp:
1669 case CopyCompositeOp:
1670 case ReplaceCompositeOp:
1671 case SrcCompositeOp:
1676 case BumpmapCompositeOp:
1678 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1683 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1686 case ChangeMaskCompositeOp:
1691 case ClearCompositeOp:
1696 case ColorBurnCompositeOp:
1699 Refer to the March 2009 SVG specification.
1701 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1703 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1706 if (Sca < MagickEpsilon)
1708 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1711 pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
1712 Sca*(1.0-Da)+Dca*(1.0-Sa));
1715 case ColorDodgeCompositeOp:
1717 if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1719 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1722 if (fabs(Sca-Sa) < MagickEpsilon)
1724 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1727 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1731 case ColorizeCompositeOp:
1733 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1738 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1743 CompositeHSB(destination_pixel.red,destination_pixel.green,
1744 destination_pixel.blue,&sans,&sans,&brightness);
1745 CompositeHSB(source_pixel.red,source_pixel.green,source_pixel.blue,
1746 &hue,&saturation,&sans);
1747 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1750 case RedPixelChannel: pixel=red; break;
1751 case GreenPixelChannel: pixel=green; break;
1752 case BluePixelChannel: pixel=blue; break;
1753 default: pixel=Dc; break;
1757 case CopyAlphaCompositeOp:
1758 case IntensityCompositeOp:
1760 if (channel == AlphaPixelChannel)
1761 pixel=(MagickRealType) GetPixelAlpha(composite_image,p);
1764 case CopyBlackCompositeOp:
1766 if (channel == BlackPixelChannel)
1767 pixel=(MagickRealType) GetPixelBlack(composite_image,p);
1770 case CopyBlueCompositeOp:
1771 case CopyYellowCompositeOp:
1773 if (channel == BluePixelChannel)
1774 pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1777 case CopyGreenCompositeOp:
1778 case CopyMagentaCompositeOp:
1780 if (channel == GreenPixelChannel)
1781 pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1784 case CopyRedCompositeOp:
1785 case CopyCyanCompositeOp:
1787 if (channel == RedPixelChannel)
1788 pixel=(MagickRealType) GetPixelRed(composite_image,p);
1791 case DarkenCompositeOp:
1794 Darken is equivalent to a 'Minimum' method
1795 OR a greyscale version of a binary 'Or'
1796 OR the 'Intersection' of pixel sets.
1800 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1803 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1806 case DarkenIntensityCompositeOp:
1808 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1809 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1812 case DifferenceCompositeOp:
1814 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1817 case DissolveCompositeOp:
1819 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1820 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1823 case DivideDstCompositeOp:
1825 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1827 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1830 if (fabs(Dca) < MagickEpsilon)
1832 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1835 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1838 case DivideSrcCompositeOp:
1840 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1842 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1845 if (fabs(Sca) < MagickEpsilon)
1847 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1850 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1853 case DstAtopCompositeOp:
1855 pixel=Dc*Da+Sc*(1.0-Da);
1858 case DstCompositeOp:
1864 case DstInCompositeOp:
1866 pixel=gamma*(Sa*Dc*Sa);
1869 case DstOutCompositeOp:
1871 pixel=gamma*(Da*Dc*(1.0-Sa));
1874 case DstOverCompositeOp:
1876 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1879 case ExclusionCompositeOp:
1881 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1885 case HardLightCompositeOp:
1889 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1893 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1897 case HueCompositeOp:
1899 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1904 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1909 CompositeHSB(destination_pixel.red,destination_pixel.green,
1910 destination_pixel.blue,&hue,&saturation,&brightness);
1911 CompositeHSB(source_pixel.red,source_pixel.green,source_pixel.blue,
1913 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1916 case RedPixelChannel: pixel=red; break;
1917 case GreenPixelChannel: pixel=green; break;
1918 case BluePixelChannel: pixel=blue; break;
1919 default: pixel=Dc; break;
1924 case SrcInCompositeOp:
1926 pixel=gamma*(Da*Sc*Da);
1929 case LinearBurnCompositeOp:
1932 LinearBurn: as defined by Abode Photoshop, according to
1933 http://www.simplefilter.de/en/basics/mixmods.html is:
1935 f(Sc,Dc) = Sc + Dc - 1
1937 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1940 case LinearDodgeCompositeOp:
1942 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1945 case LinearLightCompositeOp:
1948 LinearLight: as defined by Abode Photoshop, according to
1949 http://www.simplefilter.de/en/basics/mixmods.html is:
1951 f(Sc,Dc) = Dc + 2*Sc - 1
1953 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1956 case LightenCompositeOp:
1960 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1963 pixel=QuantumRange*gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1966 case LightenIntensityCompositeOp:
1969 Lighten is equivalent to a 'Maximum' method
1970 OR a greyscale version of a binary 'And'
1971 OR the 'Union' of pixel sets.
1973 pixel=Sa*GetPixelIntensity(composite_image,p) >
1974 Da*GetPixelIntensity(image,q) ? Sc : Dc;
1977 case LuminizeCompositeOp:
1979 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1984 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1989 CompositeHSB(destination_pixel.red,destination_pixel.green,
1990 destination_pixel.blue,&hue,&saturation,&brightness);
1991 CompositeHSB(source_pixel.red,source_pixel.green,source_pixel.blue,
1992 &sans,&sans,&brightness);
1993 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1996 case RedPixelChannel: pixel=red; break;
1997 case GreenPixelChannel: pixel=green; break;
1998 case BluePixelChannel: pixel=blue; break;
1999 default: pixel=Dc; break;
2003 case MathematicsCompositeOp:
2006 'Mathematics' a free form user control mathematical composition
2009 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
2011 Where the arguments A,B,C,D are (currently) passed to composite
2012 as a command separated 'geometry' string in "compose:args" image
2015 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
2017 Applying the SVG transparency formula (see above), we get...
2019 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
2021 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
2024 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
2025 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
2026 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
2029 case MinusDstCompositeOp:
2031 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2034 case MinusSrcCompositeOp:
2037 Minus source from destination.
2041 pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2044 case ModulateCompositeOp:
2049 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2054 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
2060 CompositeHSB(destination_pixel.red,destination_pixel.green,
2061 destination_pixel.blue,&hue,&saturation,&brightness);
2062 brightness+=(0.01*percent_brightness*offset)/midpoint;
2063 saturation*=0.01*percent_saturation;
2064 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
2067 case RedPixelChannel: pixel=red; break;
2068 case GreenPixelChannel: pixel=green; break;
2069 case BluePixelChannel: pixel=blue; break;
2070 default: pixel=Dc; break;
2074 case ModulusAddCompositeOp:
2077 if (pixel > QuantumRange)
2078 pixel-=(QuantumRange+1.0);
2079 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2082 case ModulusSubtractCompositeOp:
2086 pixel+=(QuantumRange+1.0);
2087 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2090 case MultiplyCompositeOp:
2092 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2095 case OutCompositeOp:
2096 case SrcOutCompositeOp:
2098 pixel=gamma*(Sa*Sc*(1.0-Da));
2101 case OverCompositeOp:
2102 case SrcOverCompositeOp:
2104 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2107 case OverlayCompositeOp:
2111 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2115 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2119 case PegtopLightCompositeOp:
2122 PegTop: A Soft-Light alternative: A continuous version of the
2123 Softlight function, producing very similar results.
2125 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2127 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2129 if (fabs(Da) < MagickEpsilon)
2131 pixel=QuantumRange*gamma*(Sca);
2134 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2138 case PinLightCompositeOp:
2141 PinLight: A Photoshop 7 composition method
2142 http://www.simplefilter.de/en/basics/mixmods.html
2144 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2146 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2148 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2151 if ((Dca*Sa) > (2.0*Sca*Da))
2153 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2156 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2159 case PlusCompositeOp:
2161 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
2164 case SaturateCompositeOp:
2166 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2171 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2176 CompositeHSB(destination_pixel.red,destination_pixel.green,
2177 destination_pixel.blue,&hue,&saturation,&brightness);
2178 CompositeHSB(source_pixel.red,source_pixel.green,source_pixel.blue,
2179 &sans,&saturation,&sans);
2180 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
2183 case RedPixelChannel: pixel=red; break;
2184 case GreenPixelChannel: pixel=green; break;
2185 case BluePixelChannel: pixel=blue; break;
2186 default: pixel=Dc; break;
2190 case ScreenCompositeOp:
2193 Screen: a negated multiply:
2195 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2197 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2200 case SoftLightCompositeOp:
2203 Refer to the March 2009 SVG specification.
2207 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2208 Sca*(1.0-Da)+Dca*(1.0-Sa));
2211 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2213 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2214 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2218 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2219 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2222 case ThresholdCompositeOp:
2228 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2233 pixel=gamma*(Dc+delta*amount);
2236 case VividLightCompositeOp:
2239 VividLight: A Photoshop 7 composition method. See
2240 http://www.simplefilter.de/en/basics/mixmods.html.
2242 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2244 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2246 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2249 if ((2.0*Sca) <= Sa)
2251 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2252 (1.0-Da)+Dca*(1.0-Sa));
2255 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2259 case XorCompositeOp:
2261 pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2270 q[i]=ClampToQuantum(pixel);
2272 p+=GetPixelChannels(composite_image);
2273 channels=GetPixelChannels(composite_image);
2274 if (p >= (pixels+channels*composite_image->columns))
2276 q+=GetPixelChannels(image);
2278 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2280 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2285 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2286 #pragma omp critical (MagickCore_CompositeImage)
2288 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2290 if (proceed == MagickFalse)
2294 composite_view=DestroyCacheView(composite_view);
2295 image_view=DestroyCacheView(image_view);
2296 if (destination_image != (Image * ) NULL)
2297 destination_image=DestroyImage(destination_image);
2302 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2306 % T e x t u r e I m a g e %
2310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2312 % TextureImage() repeatedly tiles the texture image across and down the image
2315 % The format of the TextureImage method is:
2317 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2318 % ExceptionInfo *exception)
2320 % A description of each parameter follows:
2322 % o image: the image.
2324 % o texture_image: This image is the texture to layer on the background.
2327 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
2328 ExceptionInfo *exception)
2330 #define TextureImageTag "Texture/Image"
2345 assert(image != (Image *) NULL);
2346 if (image->debug != MagickFalse)
2347 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2348 assert(image->signature == MagickSignature);
2349 if (texture == (const Image *) NULL)
2350 return(MagickFalse);
2351 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2352 return(MagickFalse);
2353 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2354 if (texture_image == (const Image *) NULL)
2355 return(MagickFalse);
2356 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
2359 if ((image->compose != CopyCompositeOp) &&
2360 ((image->compose != OverCompositeOp) || (image->matte != MagickFalse) ||
2361 (texture_image->matte != MagickFalse)))
2364 Tile texture onto the image background.
2366 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2367 #pragma omp parallel for schedule(static) shared(status) \
2368 dynamic_number_threads(image->columns,image->rows,1)
2370 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2375 if (status == MagickFalse)
2377 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2382 thread_status=CompositeImage(image,texture_image,image->compose,
2383 MagickFalse,x+texture_image->tile_offset.x,y+
2384 texture_image->tile_offset.y,exception);
2385 if (thread_status == MagickFalse)
2387 status=thread_status;
2391 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2396 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2397 #pragma omp critical (MagickCore_TextureImage)
2399 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2401 if (proceed == MagickFalse)
2405 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2406 image->rows,image->rows);
2407 texture_image=DestroyImage(texture_image);
2411 Tile texture onto the image background (optimized).
2414 texture_view=AcquireVirtualCacheView(texture_image,exception);
2415 image_view=AcquireAuthenticCacheView(image,exception);
2416 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2417 #pragma omp parallel for schedule(static) shared(status) \
2418 dynamic_number_threads(image->columns,image->rows,1)
2420 for (y=0; y < (ssize_t) image->rows; y++)
2425 register const Quantum
2438 if (status == MagickFalse)
2440 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2441 (y+texture_image->tile_offset.y) % texture_image->rows,
2442 texture_image->columns,1,exception);
2443 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2444 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2449 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2455 width=texture_image->columns;
2456 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2457 width=image->columns-x;
2458 for (j=0; j < (ssize_t) width; j++)
2463 if (GetPixelMask(image,p) != 0)
2465 p+=GetPixelChannels(texture_image);
2466 q+=GetPixelChannels(image);
2469 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2478 channel=GetPixelChannelMapChannel(texture_image,i);
2479 texture_traits=GetPixelChannelMapTraits(texture_image,channel);
2480 traits=GetPixelChannelMapTraits(image,channel);
2481 if ((traits == UndefinedPixelTrait) ||
2482 (texture_traits == UndefinedPixelTrait))
2484 SetPixelChannel(image,channel,p[i],q);
2486 p+=GetPixelChannels(texture_image);
2487 q+=GetPixelChannels(image);
2490 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2491 if (sync == MagickFalse)
2493 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2498 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2499 #pragma omp critical (MagickCore_TextureImage)
2501 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2503 if (proceed == MagickFalse)
2507 texture_view=DestroyCacheView(texture_view);
2508 image_view=DestroyCacheView(image_view);
2509 texture_image=DestroyImage(texture_image);