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 if ((image->rows*image->columns) > 8192) \
339 num_threads(GetMagickResourceLimit(ThreadResource))
341 for (y=0; y < (ssize_t) image->rows; y++)
346 register const Quantum
358 if (status == MagickFalse)
360 if (clip_to_self != MagickFalse)
364 if ((y-y_offset) >= (ssize_t) composite_image->rows)
368 If pixels is NULL, y is outside overlay region.
370 pixels=(Quantum *) NULL;
372 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
374 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
375 composite_image->columns,1,exception);
376 if (p == (const Quantum *) NULL)
383 p-=x_offset*GetPixelChannels(composite_image);
385 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
386 if (q == (Quantum *) NULL)
391 for (x=0; x < (ssize_t) image->columns; x++)
404 if (clip_to_self != MagickFalse)
408 q+=GetPixelChannels(image);
411 if ((x-x_offset) >= (ssize_t) composite_image->columns)
414 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
415 ((x-x_offset) >= (ssize_t) composite_image->columns))
418 source[MaxPixelChannels];
423 Dc: destination color.
425 if (GetPixelMask(image,q) != 0)
427 q+=GetPixelChannels(image);
430 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
432 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
441 channel=GetPixelChannelMapChannel(image,i);
442 traits=GetPixelChannelMapTraits(image,channel);
443 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
444 if ((traits == UndefinedPixelTrait) ||
445 (composite_traits == UndefinedPixelTrait))
447 q[i]=source[channel];
449 q+=GetPixelChannels(image);
454 Sa: normalized source alpha.
455 Da: normalized destination alpha.
457 if (GetPixelMask(composite_image,p) != 0)
459 p+=GetPixelChannels(composite_image);
460 channels=GetPixelChannels(composite_image);
461 if (p >= (pixels+channels*composite_image->columns))
463 q+=GetPixelChannels(image);
466 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
467 Da=QuantumScale*GetPixelAlpha(image,q);
468 alpha=Sa*(-Da)+Sa+Da;
469 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
478 channel=GetPixelChannelMapChannel(image,i);
479 traits=GetPixelChannelMapTraits(image,channel);
480 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
481 if ((traits == UndefinedPixelTrait) ||
482 (composite_traits == UndefinedPixelTrait))
484 if ((traits & CopyPixelTrait) != 0)
486 if (channel != AlphaPixelChannel)
491 q[i]=GetPixelChannel(composite_image,channel,p);
497 q[i]=ClampToQuantum(QuantumRange*alpha);
502 Dc: destination color.
504 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
505 Dc=(MagickRealType) q[i];
506 gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
507 q[i]=ClampToQuantum(gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc));
509 p+=GetPixelChannels(composite_image);
510 channels=GetPixelChannels(composite_image);
511 if (p >= (pixels+channels*composite_image->columns))
513 q+=GetPixelChannels(image);
515 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
517 if (image->progress_monitor != (MagickProgressMonitor) NULL)
522 #if defined(MAGICKCORE_OPENMP_SUPPORT)
523 #pragma omp critical (MagickCore_CompositeImage)
525 proceed=SetImageProgress(image,CompositeImageTag,progress++,
527 if (proceed == MagickFalse)
531 composite_view=DestroyCacheView(composite_view);
532 image_view=DestroyCacheView(image_view);
536 MagickExport MagickBooleanType CompositeImage(Image *image,
537 const Image *composite_image,const CompositeOperator compose,
538 const MagickBooleanType clip_to_self,const ssize_t x_offset,
539 const ssize_t y_offset,ExceptionInfo *exception)
541 #define CompositeImageTag "Composite/Image"
561 destination_dissolve,
574 assert(image != (Image *) NULL);
575 assert(image->signature == MagickSignature);
576 if (image->debug != MagickFalse)
577 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
578 assert(composite_image != (Image *) NULL);
579 assert(composite_image->signature == MagickSignature);
580 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
582 if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
583 (IsGrayColorspace(composite_image->colorspace) == MagickFalse))
584 (void) TransformImageColorspace(image,sRGBColorspace,exception);
585 if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
587 status=CompositeOverImage(image,composite_image,clip_to_self,x_offset,
591 destination_image=(Image *) NULL;
593 destination_dissolve=1.0;
594 percent_brightness=100.0;
595 percent_saturation=100.0;
600 case CopyCompositeOp:
602 if ((x_offset < 0) || (y_offset < 0))
604 if ((x_offset+(ssize_t) composite_image->columns) >= (ssize_t) image->columns)
606 if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
609 composite_view=AcquireVirtualCacheView(composite_image,exception);
610 image_view=AcquireAuthenticCacheView(image,exception);
611 #if defined(MAGICKCORE_OPENMP_SUPPORT)
612 #pragma omp parallel for schedule(static,4) shared(status) \
613 if ((composite_image->rows*composite_image->columns) > 8192) \
614 num_threads(GetMagickResourceLimit(ThreadResource))
616 for (y=0; y < (ssize_t) composite_image->rows; y++)
621 register const Quantum
630 if (status == MagickFalse)
632 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
634 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
635 composite_image->columns,1,exception);
636 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
641 for (x=0; x < (ssize_t) composite_image->columns; x++)
646 if (GetPixelMask(image,p) != 0)
648 p+=GetPixelChannels(composite_image);
649 q+=GetPixelChannels(image);
652 for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
661 channel=GetPixelChannelMapChannel(composite_image,i);
662 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
663 traits=GetPixelChannelMapTraits(image,channel);
664 if ((traits == UndefinedPixelTrait) ||
665 (composite_traits == UndefinedPixelTrait))
667 SetPixelChannel(image,channel,p[i],q);
669 p+=GetPixelChannels(composite_image);
670 q+=GetPixelChannels(image);
672 sync=SyncCacheViewAuthenticPixels(image_view,exception);
673 if (sync == MagickFalse)
675 if (image->progress_monitor != (MagickProgressMonitor) NULL)
680 #if defined(MAGICKCORE_OPENMP_SUPPORT)
681 #pragma omp critical (MagickCore_CompositeImage)
683 proceed=SetImageProgress(image,CompositeImageTag,
684 (MagickOffsetType) y,image->rows);
685 if (proceed == MagickFalse)
689 composite_view=DestroyCacheView(composite_view);
690 image_view=DestroyCacheView(image_view);
693 case CopyAlphaCompositeOp:
694 case ChangeMaskCompositeOp:
695 case IntensityCompositeOp:
698 Modify destination outside the overlaid region and require an alpha
699 channel to exist, to add transparency.
701 if (image->matte == MagickFalse)
702 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
705 case BlurCompositeOp:
730 Blur Image by resampling.
732 Blur Image dictated by an overlay gradient map: X = red_channel;
733 Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
735 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
737 if (destination_image == (Image *) NULL)
740 Gather the maximum blur sigma values from user.
742 SetGeometryInfo(&geometry_info);
744 value=GetImageArtifact(composite_image,"compose:args");
745 if (value != (char *) NULL)
746 flags=ParseGeometry(value,&geometry_info);
747 if ((flags & WidthValue) == 0 ) {
748 (void) ThrowMagickException(exception,GetMagickModule(),
749 OptionWarning,"InvalidSetting","'%s' '%s'",
750 "compose:args",value);
751 destination_image=DestroyImage(destination_image);
755 Users input sigma now needs to be converted to the EWA ellipse size.
756 The filter defaults to a sigma of 0.5 so to make this match the
757 users input the ellipse size needs to be doubled.
759 width=height=geometry_info.rho*2.0;
760 if ((flags & HeightValue) != 0 )
761 height=geometry_info.sigma*2.0;
763 /* default the unrotated ellipse width and height axis vectors */
768 /* rotate vectors if a rotation angle is given */
769 if ((flags & XValue) != 0 )
774 angle=DegreesToRadians(geometry_info.xi);
775 blur.x1=width*cos(angle);
776 blur.x2=width*sin(angle);
777 blur.y1=(-height*sin(angle));
778 blur.y2=height*cos(angle);
780 /* Otherwise lets set a angle range and calculate in the loop */
783 if ((flags & YValue) != 0 )
785 angle_start=DegreesToRadians(geometry_info.xi);
786 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
789 Set up a gaussian cylindrical filter for EWA Bluring.
791 As the minimum ellipse radius of support*1.0 the EWA algorithm
792 can only produce a minimum blur of 0.5 for Gaussian (support=2.0)
793 This means that even 'No Blur' will be still a little blurry!
795 The solution (as well as the problem of preventing any user
796 expert filter settings, is to set our own user settings, then
797 restore them afterwards.
799 resample_filter=AcquireResampleFilter(image,exception);
800 SetResampleFilter(resample_filter,GaussianFilter);
802 /* do the variable blurring of each pixel in image */
803 GetPixelInfo(image,&pixel);
804 composite_view=AcquireVirtualCacheView(composite_image,exception);
805 destination_view=AcquireAuthenticCacheView(destination_image,exception);
806 for (y=0; y < (ssize_t) composite_image->rows; y++)
811 register const Quantum
820 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
822 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
824 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
825 destination_image->columns,1,exception);
826 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
828 for (x=0; x < (ssize_t) composite_image->columns; x++)
830 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
832 p+=GetPixelChannels(composite_image);
835 if (fabs(angle_range) > MagickEpsilon)
840 angle=angle_start+angle_range*QuantumScale*
841 GetPixelBlue(composite_image,p);
842 blur.x1=width*cos(angle);
843 blur.x2=width*sin(angle);
844 blur.y1=(-height*sin(angle));
845 blur.y2=height*cos(angle);
848 if ( x == 10 && y == 60 ) {
849 fprintf(stderr, "blur.x=%lf,%lf, blur.y=%lf,%lf\n",
850 blur.x1, blur.x2, blur.y1, blur.y2);
851 fprintf(stderr, "scaled by=%lf,%lf\n",
852 QuantumScale*GetPixelRed(p), QuantumScale*GetPixelGreen(p));
854 ScaleResampleFilter(resample_filter,
855 blur.x1*QuantumScale*GetPixelRed(composite_image,p),
856 blur.y1*QuantumScale*GetPixelGreen(composite_image,p),
857 blur.x2*QuantumScale*GetPixelRed(composite_image,p),
858 blur.y2*QuantumScale*GetPixelGreen(composite_image,p) );
859 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
860 (double) y_offset+y,&pixel,exception);
861 SetPixelInfoPixel(destination_image,&pixel,q);
862 p+=GetPixelChannels(composite_image);
863 q+=GetPixelChannels(destination_image);
865 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
866 if (sync == MagickFalse)
869 resample_filter=DestroyResampleFilter(resample_filter);
870 composite_view=DestroyCacheView(composite_view);
871 destination_view=DestroyCacheView(destination_view);
872 composite_image=destination_image;
875 case DisplaceCompositeOp:
876 case DistortCompositeOp:
898 Displace/Distort based on overlay gradient map:
899 X = red_channel; Y = green_channel;
900 compose:args = x_scale[,y_scale[,center.x,center.y]]
902 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
904 if (destination_image == (Image *) NULL)
906 SetGeometryInfo(&geometry_info);
908 value=GetImageArtifact(composite_image,"compose:args");
909 if (value != (char *) NULL)
910 flags=ParseGeometry(value,&geometry_info);
911 if ((flags & (WidthValue|HeightValue)) == 0 )
913 if ((flags & AspectValue) == 0)
915 horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
917 vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
921 horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
922 vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
927 horizontal_scale=geometry_info.rho;
928 vertical_scale=geometry_info.sigma;
929 if ((flags & PercentValue) != 0)
931 if ((flags & AspectValue) == 0)
933 horizontal_scale*=(composite_image->columns-1.0)/200.0;
934 vertical_scale*=(composite_image->rows-1.0)/200.0;
938 horizontal_scale*=(image->columns-1.0)/200.0;
939 vertical_scale*=(image->rows-1.0)/200.0;
942 if ((flags & HeightValue) == 0)
943 vertical_scale=horizontal_scale;
946 Determine fixed center point for absolute distortion map
948 Displace offset relative to a fixed absolute point
949 Select that point according to +X+Y user inputs.
950 default = center of overlay image
951 arg flag '!' = locations/percentage relative to background image
953 center.x=(MagickRealType) x_offset;
954 center.y=(MagickRealType) y_offset;
955 if (compose == DistortCompositeOp)
957 if ((flags & XValue) == 0)
958 if ((flags & AspectValue) == 0)
959 center.x=(MagickRealType) x_offset+(composite_image->columns-1)/
962 center.x=((MagickRealType) image->columns-1)/2.0;
964 if ((flags & AspectValue) == 0)
965 center.x=(MagickRealType) x_offset+geometry_info.xi;
967 center.x=geometry_info.xi;
968 if ((flags & YValue) == 0)
969 if ((flags & AspectValue) == 0)
970 center.y=(MagickRealType) y_offset+(composite_image->rows-1)/2.0;
972 center.y=((MagickRealType) image->rows-1)/2.0;
974 if ((flags & AspectValue) == 0)
975 center.y=(MagickRealType) y_offset+geometry_info.psi;
977 center.y=geometry_info.psi;
980 Shift the pixel offset point as defined by the provided,
981 displacement/distortion map. -- Like a lens...
983 GetPixelInfo(image,&pixel);
984 image_view=AcquireVirtualCacheView(image,exception);
985 composite_view=AcquireVirtualCacheView(composite_image,exception);
986 destination_view=AcquireAuthenticCacheView(destination_image,exception);
987 for (y=0; y < (ssize_t) composite_image->rows; y++)
992 register const Quantum
1001 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1003 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
1005 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
1006 destination_image->columns,1,exception);
1007 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1009 for (x=0; x < (ssize_t) composite_image->columns; x++)
1011 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1013 p+=GetPixelChannels(composite_image);
1017 Displace the offset.
1019 offset.x=(horizontal_scale*(GetPixelRed(composite_image,p)-
1020 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1021 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
1023 offset.y=(vertical_scale*(GetPixelGreen(composite_image,p)-
1024 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1025 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
1027 (void) InterpolatePixelInfo(image,image_view,
1028 UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1031 Mask with the 'invalid pixel mask' in alpha channel.
1033 pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
1034 pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
1035 SetPixelInfoPixel(destination_image,&pixel,q);
1036 p+=GetPixelChannels(composite_image);
1037 q+=GetPixelChannels(destination_image);
1039 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1040 if (sync == MagickFalse)
1043 destination_view=DestroyCacheView(destination_view);
1044 composite_view=DestroyCacheView(composite_view);
1045 image_view=DestroyCacheView(image_view);
1046 composite_image=destination_image;
1049 case DissolveCompositeOp:
1055 Geometry arguments to dissolve factors.
1057 value=GetImageArtifact(composite_image,"compose:args");
1058 if (value != (char *) NULL)
1060 flags=ParseGeometry(value,&geometry_info);
1061 source_dissolve=geometry_info.rho/100.0;
1062 destination_dissolve=1.0;
1063 if ((source_dissolve-MagickEpsilon) < 0.0)
1064 source_dissolve=0.0;
1065 if ((source_dissolve+MagickEpsilon) > 1.0)
1067 destination_dissolve=2.0-source_dissolve;
1068 source_dissolve=1.0;
1070 if ((flags & SigmaValue) != 0)
1071 destination_dissolve=geometry_info.sigma/100.0;
1072 if ((destination_dissolve-MagickEpsilon) < 0.0)
1073 destination_dissolve=0.0;
1074 /* posible speed up? -- from IMv6 update
1075 clip_to_self=MagickFalse;
1076 if ((destination_dissolve+MagickEpsilon) > 1.0 )
1078 destination_dissolve=1.0;
1079 clip_to_self=MagickTrue;
1085 case BlendCompositeOp:
1090 value=GetImageArtifact(composite_image,"compose:args");
1091 if (value != (char *) NULL)
1093 flags=ParseGeometry(value,&geometry_info);
1094 source_dissolve=geometry_info.rho/100.0;
1095 destination_dissolve=1.0-source_dissolve;
1096 if ((flags & SigmaValue) != 0)
1097 destination_dissolve=geometry_info.sigma/100.0;
1101 case MathematicsCompositeOp:
1107 Just collect the values from "compose:args", setting.
1108 Unused values are set to zero automagically.
1110 Arguments are normally a comma separated list, so this probably should
1111 be changed to some 'general comma list' parser, (with a minimum
1114 SetGeometryInfo(&geometry_info);
1115 value=GetImageArtifact(composite_image,"compose:args");
1116 if (value != (char *) NULL)
1117 (void) ParseGeometry(value,&geometry_info);
1120 case ModulateCompositeOp:
1126 Determine the brightness and saturation scale.
1128 value=GetImageArtifact(composite_image,"compose:args");
1129 if (value != (char *) NULL)
1131 flags=ParseGeometry(value,&geometry_info);
1132 percent_brightness=geometry_info.rho;
1133 if ((flags & SigmaValue) != 0)
1134 percent_saturation=geometry_info.sigma;
1138 case ThresholdCompositeOp:
1144 Determine the amount and threshold.
1146 value=GetImageArtifact(composite_image,"compose:args");
1147 if (value != (char *) NULL)
1149 flags=ParseGeometry(value,&geometry_info);
1150 amount=geometry_info.rho;
1151 threshold=geometry_info.sigma;
1152 if ((flags & SigmaValue) == 0)
1155 threshold*=QuantumRange;
1166 midpoint=((MagickRealType) QuantumRange+1.0)/2;
1167 composite_view=AcquireVirtualCacheView(composite_image,exception);
1168 image_view=AcquireAuthenticCacheView(image,exception);
1169 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1170 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1171 if ((image->rows*image->columns) > 8192) \
1172 num_threads(GetMagickResourceLimit(ThreadResource))
1174 for (y=0; y < (ssize_t) image->rows; y++)
1191 register const Quantum
1200 if (status == MagickFalse)
1202 if (clip_to_self != MagickFalse)
1206 if ((y-y_offset) >= (ssize_t) composite_image->rows)
1210 If pixels is NULL, y is outside overlay region.
1212 pixels=(Quantum *) NULL;
1214 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
1216 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
1217 composite_image->columns,1,exception);
1218 if (p == (const Quantum *) NULL)
1225 p-=x_offset*GetPixelChannels(composite_image);
1227 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1228 if (q == (Quantum *) NULL)
1236 GetPixelInfo(image,&destination_pixel);
1237 GetPixelInfo(composite_image,&source_pixel);
1238 for (x=0; x < (ssize_t) image->columns; x++)
1256 if (clip_to_self != MagickFalse)
1260 q+=GetPixelChannels(image);
1263 if ((x-x_offset) >= (ssize_t) composite_image->columns)
1266 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1267 ((x-x_offset) >= (ssize_t) composite_image->columns))
1270 source[MaxPixelChannels];
1275 Dc: destination color.
1277 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
1279 if (GetPixelMask(image,q) != 0)
1281 q+=GetPixelChannels(image);
1284 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1296 channel=GetPixelChannelMapChannel(image,i);
1297 traits=GetPixelChannelMapTraits(image,channel);
1298 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
1299 if ((traits == UndefinedPixelTrait) ||
1300 (composite_traits == UndefinedPixelTrait))
1304 case AlphaCompositeOp:
1305 case ChangeMaskCompositeOp:
1306 case CopyAlphaCompositeOp:
1307 case DstAtopCompositeOp:
1308 case DstInCompositeOp:
1310 case IntensityCompositeOp:
1311 case OutCompositeOp:
1312 case SrcInCompositeOp:
1313 case SrcOutCompositeOp:
1315 pixel=(MagickRealType) q[i];
1316 if (channel == AlphaPixelChannel)
1317 pixel=(MagickRealType) TransparentAlpha;
1320 case ClearCompositeOp:
1321 case CopyCompositeOp:
1322 case ReplaceCompositeOp:
1323 case SrcCompositeOp:
1325 if (channel == AlphaPixelChannel)
1327 pixel=(MagickRealType) TransparentAlpha;
1333 case BlendCompositeOp:
1334 case DissolveCompositeOp:
1336 if (channel == AlphaPixelChannel)
1338 pixel=destination_dissolve*GetPixelAlpha(composite_image,
1342 pixel=(MagickRealType) source[channel];
1347 pixel=(MagickRealType) source[channel];
1351 q[i]=ClampToQuantum(pixel);
1353 q+=GetPixelChannels(image);
1357 Authentic composite:
1358 Sa: normalized source alpha.
1359 Da: normalized destination alpha.
1361 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
1362 Da=QuantumScale*GetPixelAlpha(image,q);
1365 case BumpmapCompositeOp:
1367 alpha=GetPixelIntensity(composite_image,p)*Sa;
1370 case ColorBurnCompositeOp:
1371 case ColorDodgeCompositeOp:
1372 case DifferenceCompositeOp:
1373 case DivideDstCompositeOp:
1374 case DivideSrcCompositeOp:
1375 case ExclusionCompositeOp:
1376 case HardLightCompositeOp:
1377 case LinearBurnCompositeOp:
1378 case LinearDodgeCompositeOp:
1379 case LinearLightCompositeOp:
1380 case MathematicsCompositeOp:
1381 case MinusDstCompositeOp:
1382 case MinusSrcCompositeOp:
1383 case ModulusAddCompositeOp:
1384 case ModulusSubtractCompositeOp:
1385 case MultiplyCompositeOp:
1386 case OverlayCompositeOp:
1387 case PegtopLightCompositeOp:
1388 case PinLightCompositeOp:
1389 case ScreenCompositeOp:
1390 case SoftLightCompositeOp:
1391 case VividLightCompositeOp:
1393 alpha=RoundToUnity(Sa+Da-Sa*Da);
1396 case DarkenCompositeOp:
1397 case DstAtopCompositeOp:
1398 case DstInCompositeOp:
1400 case LightenCompositeOp:
1401 case SrcInCompositeOp:
1406 case DissolveCompositeOp:
1408 alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
1409 Sa+destination_dissolve*Da;
1412 case DstOverCompositeOp:
1414 alpha=Da*(-Sa)+Da+Sa;
1417 case DstOutCompositeOp:
1422 case OutCompositeOp:
1423 case SrcOutCompositeOp:
1428 case OverCompositeOp:
1429 case SrcOverCompositeOp:
1431 alpha=Sa*(-Da)+Sa+Da;
1434 case BlendCompositeOp:
1435 case PlusCompositeOp:
1437 alpha=RoundToUnity(Sa+Da);
1440 case XorCompositeOp:
1442 alpha=Sa+Da-2.0*Sa*Da;
1451 if (GetPixelMask(image,p) != 0)
1453 p+=GetPixelChannels(composite_image);
1454 q+=GetPixelChannels(image);
1459 case ColorizeCompositeOp:
1460 case HueCompositeOp:
1461 case LuminizeCompositeOp:
1462 case ModulateCompositeOp:
1463 case SaturateCompositeOp:
1465 GetPixelInfoPixel(composite_image,p,&source_pixel);
1466 GetPixelInfoPixel(image,q,&destination_pixel);
1472 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1487 channel=GetPixelChannelMapChannel(image,i);
1488 traits=GetPixelChannelMapTraits(image,channel);
1489 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
1490 if (traits == UndefinedPixelTrait)
1492 if ((compose != IntensityCompositeOp) &&
1493 (composite_traits == UndefinedPixelTrait))
1497 Dc: destination color.
1499 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
1500 Dc=(MagickRealType) q[i];
1501 if ((traits & CopyPixelTrait) != 0)
1503 if (channel != AlphaPixelChannel)
1508 q[i]=ClampToQuantum(Sc);
1516 case AlphaCompositeOp:
1518 pixel=QuantumRange*Sa;
1521 case AtopCompositeOp:
1522 case CopyBlackCompositeOp:
1523 case CopyBlueCompositeOp:
1524 case CopyCyanCompositeOp:
1525 case CopyGreenCompositeOp:
1526 case CopyMagentaCompositeOp:
1527 case CopyRedCompositeOp:
1528 case CopyYellowCompositeOp:
1529 case SrcAtopCompositeOp:
1530 case DstCompositeOp:
1533 pixel=QuantumRange*Da;
1536 case ChangeMaskCompositeOp:
1541 if (Da > ((MagickRealType) QuantumRange/2.0))
1543 pixel=(MagickRealType) TransparentAlpha;
1546 equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
1547 if (equivalent != MagickFalse)
1549 pixel=(MagickRealType) TransparentAlpha;
1552 pixel=(MagickRealType) OpaqueAlpha;
1555 case ClearCompositeOp:
1557 pixel=(MagickRealType) TransparentAlpha;
1560 case ColorizeCompositeOp:
1561 case HueCompositeOp:
1562 case LuminizeCompositeOp:
1563 case SaturateCompositeOp:
1565 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1567 pixel=QuantumRange*Da;
1570 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1572 pixel=QuantumRange*Sa;
1577 pixel=QuantumRange*Da;
1580 pixel=QuantumRange*Sa;
1583 case CopyCompositeOp:
1584 case CopyAlphaCompositeOp:
1585 case DisplaceCompositeOp:
1586 case DistortCompositeOp:
1587 case DstAtopCompositeOp:
1588 case ReplaceCompositeOp:
1589 case SrcCompositeOp:
1591 pixel=QuantumRange*Sa;
1594 case DarkenIntensityCompositeOp:
1596 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1597 (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
1600 case IntensityCompositeOp:
1602 pixel=(MagickRealType) GetPixelIntensity(composite_image,p);
1605 case LightenIntensityCompositeOp:
1607 pixel=Sa*GetPixelIntensity(composite_image,p) >
1608 Da*GetPixelIntensity(image,q) ? Sa : Da;
1611 case ModulateCompositeOp:
1613 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1615 pixel=QuantumRange*Da;
1618 pixel=QuantumRange*Da;
1623 pixel=QuantumRange*alpha;
1627 q[i]=ClampToQuantum(pixel);
1631 Porter-Duff compositions:
1632 Sca: source normalized color multiplied by alpha.
1633 Dca: normalized destination color multiplied by alpha.
1635 Sca=QuantumScale*Sa*Sc;
1636 Dca=QuantumScale*Da*Dc;
1639 case DarkenCompositeOp:
1640 case LightenCompositeOp:
1641 case ModulusSubtractCompositeOp:
1649 gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
1653 case AlphaCompositeOp:
1655 pixel=QuantumRange*Sa;
1658 case AtopCompositeOp:
1659 case SrcAtopCompositeOp:
1661 pixel=Sc*Sa+Dc*(1.0-Sa);
1664 case BlendCompositeOp:
1666 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1669 case BlurCompositeOp:
1670 case DisplaceCompositeOp:
1671 case DistortCompositeOp:
1672 case CopyCompositeOp:
1673 case ReplaceCompositeOp:
1674 case SrcCompositeOp:
1679 case BumpmapCompositeOp:
1681 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1686 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1689 case ChangeMaskCompositeOp:
1694 case ClearCompositeOp:
1699 case ColorBurnCompositeOp:
1702 Refer to the March 2009 SVG specification.
1704 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1706 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1709 if (Sca < MagickEpsilon)
1711 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1714 pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
1715 Sca*(1.0-Da)+Dca*(1.0-Sa));
1718 case ColorDodgeCompositeOp:
1720 if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1722 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1725 if (fabs(Sca-Sa) < MagickEpsilon)
1727 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1730 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1734 case ColorizeCompositeOp:
1736 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1741 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1746 CompositeHSB(destination_pixel.red,destination_pixel.green,
1747 destination_pixel.blue,&sans,&sans,&brightness);
1748 CompositeHSB(source_pixel.red,source_pixel.green,source_pixel.blue,
1749 &hue,&saturation,&sans);
1750 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1753 case RedPixelChannel: pixel=red; break;
1754 case GreenPixelChannel: pixel=green; break;
1755 case BluePixelChannel: pixel=blue; break;
1756 default: pixel=Dc; break;
1760 case CopyAlphaCompositeOp:
1761 case IntensityCompositeOp:
1763 if (channel == AlphaPixelChannel)
1764 pixel=(MagickRealType) GetPixelAlpha(composite_image,p);
1767 case CopyBlackCompositeOp:
1769 if (channel == BlackPixelChannel)
1770 pixel=(MagickRealType) GetPixelBlack(composite_image,p);
1773 case CopyBlueCompositeOp:
1774 case CopyYellowCompositeOp:
1776 if (channel == BluePixelChannel)
1777 pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1780 case CopyGreenCompositeOp:
1781 case CopyMagentaCompositeOp:
1783 if (channel == GreenPixelChannel)
1784 pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1787 case CopyRedCompositeOp:
1788 case CopyCyanCompositeOp:
1790 if (channel == RedPixelChannel)
1791 pixel=(MagickRealType) GetPixelRed(composite_image,p);
1794 case DarkenCompositeOp:
1797 Darken is equivalent to a 'Minimum' method
1798 OR a greyscale version of a binary 'Or'
1799 OR the 'Intersection' of pixel sets.
1803 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1806 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1809 case DarkenIntensityCompositeOp:
1811 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1812 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1815 case DifferenceCompositeOp:
1817 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1820 case DissolveCompositeOp:
1822 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1823 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1826 case DivideDstCompositeOp:
1828 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1830 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1833 if (fabs(Dca) < MagickEpsilon)
1835 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1838 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1841 case DivideSrcCompositeOp:
1843 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1845 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1848 if (fabs(Sca) < MagickEpsilon)
1850 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1853 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1856 case DstAtopCompositeOp:
1858 pixel=Dc*Da+Sc*(1.0-Da);
1861 case DstCompositeOp:
1867 case DstInCompositeOp:
1869 pixel=gamma*(Sa*Dc*Sa);
1872 case DstOutCompositeOp:
1874 pixel=gamma*(Da*Dc*(1.0-Sa));
1877 case DstOverCompositeOp:
1879 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1882 case ExclusionCompositeOp:
1884 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1888 case HardLightCompositeOp:
1892 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1896 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1900 case HueCompositeOp:
1902 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1907 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1912 CompositeHSB(destination_pixel.red,destination_pixel.green,
1913 destination_pixel.blue,&hue,&saturation,&brightness);
1914 CompositeHSB(source_pixel.red,source_pixel.green,source_pixel.blue,
1916 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1919 case RedPixelChannel: pixel=red; break;
1920 case GreenPixelChannel: pixel=green; break;
1921 case BluePixelChannel: pixel=blue; break;
1922 default: pixel=Dc; break;
1927 case SrcInCompositeOp:
1929 pixel=gamma*(Da*Sc*Da);
1932 case LinearBurnCompositeOp:
1935 LinearBurn: as defined by Abode Photoshop, according to
1936 http://www.simplefilter.de/en/basics/mixmods.html is:
1938 f(Sc,Dc) = Sc + Dc - 1
1940 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1943 case LinearDodgeCompositeOp:
1945 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1948 case LinearLightCompositeOp:
1951 LinearLight: as defined by Abode Photoshop, according to
1952 http://www.simplefilter.de/en/basics/mixmods.html is:
1954 f(Sc,Dc) = Dc + 2*Sc - 1
1956 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1959 case LightenCompositeOp:
1963 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1966 pixel=QuantumRange*gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1969 case LightenIntensityCompositeOp:
1972 Lighten is equivalent to a 'Maximum' method
1973 OR a greyscale version of a binary 'And'
1974 OR the 'Union' of pixel sets.
1976 pixel=Sa*GetPixelIntensity(composite_image,p) >
1977 Da*GetPixelIntensity(image,q) ? Sc : Dc;
1980 case LuminizeCompositeOp:
1982 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1987 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1992 CompositeHSB(destination_pixel.red,destination_pixel.green,
1993 destination_pixel.blue,&hue,&saturation,&brightness);
1994 CompositeHSB(source_pixel.red,source_pixel.green,source_pixel.blue,
1995 &sans,&sans,&brightness);
1996 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1999 case RedPixelChannel: pixel=red; break;
2000 case GreenPixelChannel: pixel=green; break;
2001 case BluePixelChannel: pixel=blue; break;
2002 default: pixel=Dc; break;
2006 case MathematicsCompositeOp:
2009 'Mathematics' a free form user control mathematical composition
2012 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
2014 Where the arguments A,B,C,D are (currently) passed to composite
2015 as a command separated 'geometry' string in "compose:args" image
2018 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
2020 Applying the SVG transparency formula (see above), we get...
2022 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
2024 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
2027 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
2028 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
2029 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
2032 case MinusDstCompositeOp:
2034 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2037 case MinusSrcCompositeOp:
2040 Minus source from destination.
2044 pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2047 case ModulateCompositeOp:
2052 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2057 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
2063 CompositeHSB(destination_pixel.red,destination_pixel.green,
2064 destination_pixel.blue,&hue,&saturation,&brightness);
2065 brightness+=(0.01*percent_brightness*offset)/midpoint;
2066 saturation*=0.01*percent_saturation;
2067 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
2070 case RedPixelChannel: pixel=red; break;
2071 case GreenPixelChannel: pixel=green; break;
2072 case BluePixelChannel: pixel=blue; break;
2073 default: pixel=Dc; break;
2077 case ModulusAddCompositeOp:
2080 if (pixel > QuantumRange)
2081 pixel-=(QuantumRange+1.0);
2082 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2085 case ModulusSubtractCompositeOp:
2089 pixel+=(QuantumRange+1.0);
2090 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2093 case MultiplyCompositeOp:
2095 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2098 case OutCompositeOp:
2099 case SrcOutCompositeOp:
2101 pixel=gamma*(Sa*Sc*(1.0-Da));
2104 case OverCompositeOp:
2105 case SrcOverCompositeOp:
2107 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2110 case OverlayCompositeOp:
2114 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2118 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2122 case PegtopLightCompositeOp:
2125 PegTop: A Soft-Light alternative: A continuous version of the
2126 Softlight function, producing very similar results.
2128 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2130 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2132 if (fabs(Da) < MagickEpsilon)
2134 pixel=QuantumRange*gamma*(Sca);
2137 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2141 case PinLightCompositeOp:
2144 PinLight: A Photoshop 7 composition method
2145 http://www.simplefilter.de/en/basics/mixmods.html
2147 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2149 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2151 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2154 if ((Dca*Sa) > (2.0*Sca*Da))
2156 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2159 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2162 case PlusCompositeOp:
2164 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
2167 case SaturateCompositeOp:
2169 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2174 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2179 CompositeHSB(destination_pixel.red,destination_pixel.green,
2180 destination_pixel.blue,&hue,&saturation,&brightness);
2181 CompositeHSB(source_pixel.red,source_pixel.green,source_pixel.blue,
2182 &sans,&saturation,&sans);
2183 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
2186 case RedPixelChannel: pixel=red; break;
2187 case GreenPixelChannel: pixel=green; break;
2188 case BluePixelChannel: pixel=blue; break;
2189 default: pixel=Dc; break;
2193 case ScreenCompositeOp:
2196 Screen: a negated multiply:
2198 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2200 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2203 case SoftLightCompositeOp:
2206 Refer to the March 2009 SVG specification.
2210 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2211 Sca*(1.0-Da)+Dca*(1.0-Sa));
2214 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2216 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2217 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2221 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2222 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2225 case ThresholdCompositeOp:
2231 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2236 pixel=gamma*(Dc+delta*amount);
2239 case VividLightCompositeOp:
2242 VividLight: A Photoshop 7 composition method. See
2243 http://www.simplefilter.de/en/basics/mixmods.html.
2245 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2247 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2249 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2252 if ((2.0*Sca) <= Sa)
2254 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2255 (1.0-Da)+Dca*(1.0-Sa));
2258 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2262 case XorCompositeOp:
2264 pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2273 q[i]=ClampToQuantum(pixel);
2275 p+=GetPixelChannels(composite_image);
2276 channels=GetPixelChannels(composite_image);
2277 if (p >= (pixels+channels*composite_image->columns))
2279 q+=GetPixelChannels(image);
2281 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2283 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2288 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2289 #pragma omp critical (MagickCore_CompositeImage)
2291 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2293 if (proceed == MagickFalse)
2297 composite_view=DestroyCacheView(composite_view);
2298 image_view=DestroyCacheView(image_view);
2299 if (destination_image != (Image * ) NULL)
2300 destination_image=DestroyImage(destination_image);
2305 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2309 % T e x t u r e I m a g e %
2313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2315 % TextureImage() repeatedly tiles the texture image across and down the image
2318 % The format of the TextureImage method is:
2320 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2321 % ExceptionInfo *exception)
2323 % A description of each parameter follows:
2325 % o image: the image.
2327 % o texture_image: This image is the texture to layer on the background.
2330 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
2331 ExceptionInfo *exception)
2333 #define TextureImageTag "Texture/Image"
2348 assert(image != (Image *) NULL);
2349 if (image->debug != MagickFalse)
2350 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2351 assert(image->signature == MagickSignature);
2352 if (texture == (const Image *) NULL)
2353 return(MagickFalse);
2354 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2355 return(MagickFalse);
2356 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2357 if (texture_image == (const Image *) NULL)
2358 return(MagickFalse);
2359 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
2362 if ((image->compose != CopyCompositeOp) &&
2363 ((image->compose != OverCompositeOp) || (image->matte != MagickFalse) ||
2364 (texture_image->matte != MagickFalse)))
2367 Tile texture onto the image background.
2369 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2370 #pragma omp parallel for schedule(static) shared(status) \
2371 if ((image->rows*image->columns) > 8192) \
2372 num_threads(GetMagickResourceLimit(ThreadResource))
2374 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2379 if (status == MagickFalse)
2381 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2386 thread_status=CompositeImage(image,texture_image,image->compose,
2387 MagickFalse,x+texture_image->tile_offset.x,y+
2388 texture_image->tile_offset.y,exception);
2389 if (thread_status == MagickFalse)
2391 status=thread_status;
2395 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2400 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2401 #pragma omp critical (MagickCore_TextureImage)
2403 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2405 if (proceed == MagickFalse)
2409 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2410 image->rows,image->rows);
2411 texture_image=DestroyImage(texture_image);
2415 Tile texture onto the image background (optimized).
2418 texture_view=AcquireVirtualCacheView(texture_image,exception);
2419 image_view=AcquireAuthenticCacheView(image,exception);
2420 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2421 #pragma omp parallel for schedule(static) shared(status) \
2422 if ((image->rows*image->columns) > 8192) \
2423 num_threads(GetMagickResourceLimit(ThreadResource))
2425 for (y=0; y < (ssize_t) image->rows; y++)
2430 register const Quantum
2443 if (status == MagickFalse)
2445 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2446 (y+texture_image->tile_offset.y) % texture_image->rows,
2447 texture_image->columns,1,exception);
2448 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2449 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2454 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2460 width=texture_image->columns;
2461 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2462 width=image->columns-x;
2463 for (j=0; j < (ssize_t) width; j++)
2468 if (GetPixelMask(image,p) != 0)
2470 p+=GetPixelChannels(texture_image);
2471 q+=GetPixelChannels(image);
2474 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2483 channel=GetPixelChannelMapChannel(texture_image,i);
2484 texture_traits=GetPixelChannelMapTraits(texture_image,channel);
2485 traits=GetPixelChannelMapTraits(image,channel);
2486 if ((traits == UndefinedPixelTrait) ||
2487 (texture_traits == UndefinedPixelTrait))
2489 SetPixelChannel(image,channel,p[i],q);
2491 p+=GetPixelChannels(texture_image);
2492 q+=GetPixelChannels(image);
2495 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2496 if (sync == MagickFalse)
2498 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2503 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2504 #pragma omp critical (MagickCore_TextureImage)
2506 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2508 if (proceed == MagickFalse)
2512 texture_view=DestroyCacheView(texture_view);
2513 image_view=DestroyCacheView(image_view);
2514 texture_image=DestroyImage(texture_image);