2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % CCCC OOO M M PPPP OOO SSSSS IIIII TTTTT EEEEE %
7 % C O O MM MM P P O O SS I T E %
8 % C O O M M M PPPP O O SSS I T EEE %
9 % C O O M M P O O SS I T E %
10 % CCCC OOO M M P OOO SSSSS IIIII T EEEEE %
13 % MagickCore Image Composite Methods %
20 % Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/artifact.h"
45 #include "MagickCore/cache.h"
46 #include "MagickCore/cache-private.h"
47 #include "MagickCore/cache-view.h"
48 #include "MagickCore/channel.h"
49 #include "MagickCore/client.h"
50 #include "MagickCore/color.h"
51 #include "MagickCore/color-private.h"
52 #include "MagickCore/colorspace.h"
53 #include "MagickCore/colorspace-private.h"
54 #include "MagickCore/composite.h"
55 #include "MagickCore/composite-private.h"
56 #include "MagickCore/constitute.h"
57 #include "MagickCore/draw.h"
58 #include "MagickCore/fx.h"
59 #include "MagickCore/gem.h"
60 #include "MagickCore/geometry.h"
61 #include "MagickCore/image.h"
62 #include "MagickCore/image-private.h"
63 #include "MagickCore/list.h"
64 #include "MagickCore/log.h"
65 #include "MagickCore/monitor.h"
66 #include "MagickCore/monitor-private.h"
67 #include "MagickCore/memory_.h"
68 #include "MagickCore/option.h"
69 #include "MagickCore/pixel-accessor.h"
70 #include "MagickCore/property.h"
71 #include "MagickCore/quantum.h"
72 #include "MagickCore/resample.h"
73 #include "MagickCore/resource_.h"
74 #include "MagickCore/string_.h"
75 #include "MagickCore/thread-private.h"
76 #include "MagickCore/threshold.h"
77 #include "MagickCore/token.h"
78 #include "MagickCore/utility.h"
79 #include "MagickCore/utility-private.h"
80 #include "MagickCore/version.h"
83 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
87 % C o m p o s i t e I m a g e %
91 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
93 % CompositeImage() returns the second image composited onto the first
94 % at the specified offset, using the specified composite method.
96 % The format of the CompositeImage method is:
98 % MagickBooleanType CompositeImage(Image *image,
99 % const Image *composite_image,const CompositeOperator compose,
100 % const MagickBooleanType clip_to_self,const ssize_t x_offset,
101 % const ssize_t y_offset,ExceptionInfo *exception)
103 % A description of each parameter follows:
105 % o image: the destination image, modified by he composition
107 % o composite_image: the composite (source) image.
109 % o compose: This operator affects how the composite is applied to
110 % the image. The operators and how they are utilized are listed here
111 % http://www.w3.org/TR/SVG12/#compositing.
113 % o clip_to_self: set to MagickTrue to limit composition to area composed.
115 % o x_offset: the column offset of the composited image.
117 % o y_offset: the row offset of the composited image.
119 % Extra Controls from Image meta-data in 'image' (artifacts)
122 % A string containing extra numerical arguments for specific compose
123 % methods, generally expressed as a 'geometry' or a comma separated list
126 % Compose methods needing such arguments include "BlendCompositeOp" and
127 % "DisplaceCompositeOp".
129 % o exception: return any errors or warnings in this structure.
134 Composition based on the SVG specification:
136 A Composition is defined by...
137 Color Function : f(Sc,Dc) where Sc and Dc are the normizalized colors
138 Blending areas : X = 1 for area of overlap, ie: f(Sc,Dc)
139 Y = 1 for source preserved
140 Z = 1 for destination preserved
142 Conversion to transparency (then optimized)
143 Dca' = f(Sc, Dc)*Sa*Da + Y*Sca*(1-Da) + Z*Dca*(1-Sa)
144 Da' = X*Sa*Da + Y*Sa*(1-Da) + Z*Da*(1-Sa)
147 Sca = Sc*Sa normalized Source color divided by Source alpha
148 Dca = Dc*Da normalized Dest color divided by Dest alpha
149 Dc' = Dca'/Da' the desired color value for this channel.
151 Da' in in the follow formula as 'gamma' The resulting alpla value.
153 Most functions use a blending mode of over (X=1,Y=1,Z=1) this results in
154 the following optimizations...
156 gamma = 1 - QuantiumScale*alpha * QuantiumScale*beta;
157 opacity = QuantiumScale*alpha*beta; // over blend, optimized 1-Gamma
159 The above SVG definitions also definate that Mathematical Composition
160 methods should use a 'Over' blending mode for Alpha Channel.
161 It however was not applied for composition modes of 'Plus', 'Minus',
162 the modulus versions of 'Add' and 'Subtract'.
164 Mathematical operator changes to be applied from IM v6.7...
166 1) Modulus modes 'Add' and 'Subtract' are obsoleted and renamed
167 'ModulusAdd' and 'ModulusSubtract' for clarity.
169 2) All mathematical compositions work as per the SVG specification
170 with regard to blending. This now includes 'ModulusAdd' and
173 3) When the special channel flag 'sync' (syncronize channel updates)
174 is turned off (enabled by default) then mathematical compositions are
175 only performed on the channels specified, and are applied
176 independantally of each other. In other words the mathematics is
177 performed as 'pure' mathematical operations, rather than as image
181 static inline MagickRealType MagickMin(const MagickRealType x,
182 const MagickRealType y)
189 static inline MagickRealType MagickMax(const MagickRealType x,
190 const MagickRealType y)
197 static void HCLComposite(const MagickRealType hue,const MagickRealType chroma,
198 const MagickRealType luma,MagickRealType *red,MagickRealType *green,
199 MagickRealType *blue)
211 Convert HCL to RGB colorspace.
213 assert(red != (MagickRealType *) NULL);
214 assert(green != (MagickRealType *) NULL);
215 assert(blue != (MagickRealType *) NULL);
218 x=c*(1.0-fabs(fmod(h,2.0)-1.0));
222 if ((0.0 <= h) && (h < 1.0))
228 if ((1.0 <= h) && (h < 2.0))
234 if ((2.0 <= h) && (h < 3.0))
240 if ((3.0 <= h) && (h < 4.0))
246 if ((4.0 <= h) && (h < 5.0))
252 if ((5.0 <= h) && (h < 6.0))
257 m=luma-(0.298839*r+0.586811*g+0.114350*b);
258 *red=QuantumRange*(r+m);
259 *green=QuantumRange*(g+m);
260 *blue=QuantumRange*(b+m);
263 static void CompositeHCL(const MagickRealType red,const MagickRealType green,
264 const MagickRealType blue,MagickRealType *hue,MagickRealType *chroma,
265 MagickRealType *luma)
276 Convert RGB to HCL colorspace.
278 assert(hue != (MagickRealType *) NULL);
279 assert(chroma != (MagickRealType *) NULL);
280 assert(luma != (MagickRealType *) NULL);
284 max=MagickMax(r,MagickMax(g,b));
285 c=max-(MagickRealType) MagickMin(r,MagickMin(g,b));
291 h=fmod((g-b)/c+6.0,6.0);
299 *chroma=QuantumScale*c;
300 *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
303 static MagickBooleanType CompositeOverImage(Image *image,
304 const Image *composite_image,const MagickBooleanType clip_to_self,
305 const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
307 #define CompositeImageTag "Composite/Image"
327 composite_view=AcquireVirtualCacheView(composite_image,exception);
328 image_view=AcquireAuthenticCacheView(image,exception);
329 #if defined(MAGICKCORE_OPENMP_SUPPORT)
330 #pragma omp parallel for schedule(static,4) shared(progress,status) \
331 magick_threads(composite_image,image,image->rows,1)
333 for (y=0; y < (ssize_t) image->rows; y++)
338 register const Quantum
350 if (status == MagickFalse)
352 if (clip_to_self != MagickFalse)
356 if ((y-y_offset) >= (ssize_t) composite_image->rows)
360 If pixels is NULL, y is outside overlay region.
362 pixels=(Quantum *) NULL;
364 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
366 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
367 composite_image->columns,1,exception);
368 if (p == (const Quantum *) NULL)
375 p-=x_offset*GetPixelChannels(composite_image);
377 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
378 if (q == (Quantum *) NULL)
383 for (x=0; x < (ssize_t) image->columns; x++)
398 if (clip_to_self != MagickFalse)
402 q+=GetPixelChannels(image);
405 if ((x-x_offset) >= (ssize_t) composite_image->columns)
408 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
409 ((x-x_offset) >= (ssize_t) composite_image->columns))
412 source[MaxPixelChannels];
417 Dc: destination color.
419 if (GetPixelReadMask(image,q) == 0)
421 q+=GetPixelChannels(image);
424 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
426 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
428 PixelChannel channel=GetPixelChannelChannel(image,i);
429 PixelTrait traits=GetPixelChannelTraits(image,channel);
430 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
432 if ((traits == UndefinedPixelTrait) ||
433 (composite_traits == UndefinedPixelTrait))
435 q[i]=source[channel];
437 q+=GetPixelChannels(image);
442 Sa: normalized source alpha.
443 Da: normalized destination alpha.
445 if (GetPixelReadMask(composite_image,p) == 0)
447 p+=GetPixelChannels(composite_image);
448 channels=GetPixelChannels(composite_image);
449 if (p >= (pixels+channels*composite_image->columns))
451 q+=GetPixelChannels(image);
454 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
455 Da=QuantumScale*GetPixelAlpha(image,q);
456 alpha=Sa*(-Da)+Sa+Da;
457 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
459 PixelChannel channel=GetPixelChannelChannel(image,i);
460 PixelTrait traits=GetPixelChannelTraits(image,channel);
461 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
463 if ((traits == UndefinedPixelTrait) ||
464 (composite_traits == UndefinedPixelTrait))
466 if ((traits & CopyPixelTrait) != 0)
468 if (channel != AlphaPixelChannel)
473 q[i]=GetPixelChannel(composite_image,channel,p);
479 q[i]=ClampToQuantum(QuantumRange*alpha);
484 Dc: destination color.
486 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
487 Dc=(MagickRealType) q[i];
488 gamma=PerceptibleReciprocal(alpha);
489 q[i]=ClampToQuantum(gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc));
491 p+=GetPixelChannels(composite_image);
492 channels=GetPixelChannels(composite_image);
493 if (p >= (pixels+channels*composite_image->columns))
495 q+=GetPixelChannels(image);
497 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
499 if (image->progress_monitor != (MagickProgressMonitor) NULL)
504 #if defined(MAGICKCORE_OPENMP_SUPPORT)
505 #pragma omp critical (MagickCore_CompositeImage)
507 proceed=SetImageProgress(image,CompositeImageTag,progress++,
509 if (proceed == MagickFalse)
513 composite_view=DestroyCacheView(composite_view);
514 image_view=DestroyCacheView(image_view);
518 MagickExport MagickBooleanType CompositeImage(Image *image,
519 const Image *composite,const CompositeOperator compose,
520 const MagickBooleanType clip_to_self,const ssize_t x_offset,
521 const ssize_t y_offset,ExceptionInfo *exception)
523 #define CompositeImageTag "Composite/Image"
544 destination_dissolve,
557 assert(image != (Image *) NULL);
558 assert(image->signature == MagickSignature);
559 if (image->debug != MagickFalse)
560 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
561 assert(composite!= (Image *) NULL);
562 assert(composite->signature == MagickSignature);
563 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
565 composite_image=CloneImage(composite,0,0,MagickTrue,exception);
566 if (composite_image == (const Image *) NULL)
568 if (IsGrayColorspace(image->colorspace) != MagickFalse)
569 (void) SetImageColorspace(image,sRGBColorspace,exception);
570 (void) SetImageColorspace(composite_image,image->colorspace,exception);
571 if ((image->alpha_trait == BlendPixelTrait) &&
572 (composite_image->alpha_trait != BlendPixelTrait))
573 (void) SetImageAlphaChannel(composite_image,SetAlphaChannel,exception);
574 if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
576 status=CompositeOverImage(image,composite_image,clip_to_self,x_offset,
578 composite_image=DestroyImage(composite_image);
581 destination_image=(Image *) NULL;
583 destination_dissolve=1.0;
585 percent_chroma=100.0;
590 case CopyCompositeOp:
592 if ((x_offset < 0) || (y_offset < 0))
594 if ((x_offset+(ssize_t) composite_image->columns) >= (ssize_t) image->columns)
596 if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
599 composite_view=AcquireVirtualCacheView(composite_image,exception);
600 image_view=AcquireAuthenticCacheView(image,exception);
601 #if defined(MAGICKCORE_OPENMP_SUPPORT)
602 #pragma omp parallel for schedule(static,4) shared(status) \
603 magick_threads(composite_image,image,composite_image->rows,1)
605 for (y=0; y < (ssize_t) composite_image->rows; y++)
610 register const Quantum
619 if (status == MagickFalse)
621 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
623 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
624 composite_image->columns,1,exception);
625 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
630 for (x=0; x < (ssize_t) composite_image->columns; x++)
635 if (GetPixelReadMask(composite_image,p) == 0)
637 p+=GetPixelChannels(composite_image);
638 q+=GetPixelChannels(image);
641 for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
643 PixelChannel channel=GetPixelChannelChannel(composite_image,i);
644 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
646 PixelTrait traits=GetPixelChannelTraits(image,channel);
647 if ((traits == UndefinedPixelTrait) ||
648 (composite_traits == UndefinedPixelTrait))
650 SetPixelChannel(image,channel,p[i],q);
652 p+=GetPixelChannels(composite_image);
653 q+=GetPixelChannels(image);
655 sync=SyncCacheViewAuthenticPixels(image_view,exception);
656 if (sync == MagickFalse)
658 if (image->progress_monitor != (MagickProgressMonitor) NULL)
663 #if defined(MAGICKCORE_OPENMP_SUPPORT)
664 #pragma omp critical (MagickCore_CompositeImage)
666 proceed=SetImageProgress(image,CompositeImageTag,
667 (MagickOffsetType) y,image->rows);
668 if (proceed == MagickFalse)
672 composite_view=DestroyCacheView(composite_view);
673 image_view=DestroyCacheView(image_view);
674 composite_image=DestroyImage(composite_image);
677 case CopyAlphaCompositeOp:
678 case ChangeMaskCompositeOp:
679 case IntensityCompositeOp:
682 Modify destination outside the overlaid region and require an alpha
683 channel to exist, to add transparency.
685 if (image->alpha_trait != BlendPixelTrait)
686 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
687 SetPixelAlphaTraits(image,CopyPixelTrait);
690 case BlurCompositeOp:
715 Blur Image by resampling.
717 Blur Image dictated by an overlay gradient map: X = red_channel;
718 Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
720 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
722 if (destination_image == (Image *) NULL)
724 composite_image=DestroyImage(composite_image);
728 Gather the maximum blur sigma values from user.
730 SetGeometryInfo(&geometry_info);
732 value=GetImageArtifact(image,"compose:args");
733 if (value != (const char *) NULL)
734 flags=ParseGeometry(value,&geometry_info);
735 if ((flags & WidthValue) == 0)
737 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
738 "InvalidSetting","'%s' '%s'","compose:args",value);
739 composite_image=DestroyImage(composite_image);
740 destination_image=DestroyImage(destination_image);
744 Users input sigma now needs to be converted to the EWA ellipse size.
745 The filter defaults to a sigma of 0.5 so to make this match the
746 users input the ellipse size needs to be doubled.
748 width=height=geometry_info.rho*2.0;
749 if ((flags & HeightValue) != 0 )
750 height=geometry_info.sigma*2.0;
752 Default the unrotated ellipse width and height axis vectors.
758 /* rotate vectors if a rotation angle is given */
759 if ((flags & XValue) != 0 )
764 angle=DegreesToRadians(geometry_info.xi);
765 blur.x1=width*cos(angle);
766 blur.x2=width*sin(angle);
767 blur.y1=(-height*sin(angle));
768 blur.y2=height*cos(angle);
770 /* Otherwise lets set a angle range and calculate in the loop */
773 if ((flags & YValue) != 0 )
775 angle_start=DegreesToRadians(geometry_info.xi);
776 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
779 Set up a gaussian cylindrical filter for EWA Bluring.
781 As the minimum ellipse radius of support*1.0 the EWA algorithm
782 can only produce a minimum blur of 0.5 for Gaussian (support=2.0)
783 This means that even 'No Blur' will be still a little blurry!
785 The solution (as well as the problem of preventing any user
786 expert filter settings, is to set our own user settings, then
787 restore them afterwards.
789 resample_filter=AcquireResampleFilter(image,exception);
790 SetResampleFilter(resample_filter,GaussianFilter);
792 /* do the variable blurring of each pixel in image */
793 GetPixelInfo(image,&pixel);
794 composite_view=AcquireVirtualCacheView(composite_image,exception);
795 destination_view=AcquireAuthenticCacheView(destination_image,exception);
796 for (y=0; y < (ssize_t) composite_image->rows; y++)
801 register const Quantum
810 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
812 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
814 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
815 destination_image->columns,1,exception);
816 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
818 for (x=0; x < (ssize_t) composite_image->columns; x++)
820 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
822 p+=GetPixelChannels(composite_image);
825 if (fabs(angle_range) > MagickEpsilon)
830 angle=angle_start+angle_range*QuantumScale*
831 GetPixelBlue(composite_image,p);
832 blur.x1=width*cos(angle);
833 blur.x2=width*sin(angle);
834 blur.y1=(-height*sin(angle));
835 blur.y2=height*cos(angle);
838 if ( x == 10 && y == 60 ) {
839 (void) fprintf(stderr, "blur.x=%lf,%lf, blur.y=%lf,%lf\n",blur.x1,
840 blur.x2,blur.y1, blur.y2);
841 (void) fprintf(stderr, "scaled by=%lf,%lf\n",QuantumScale*
842 GetPixelRed(p),QuantumScale*GetPixelGreen(p));
844 ScaleResampleFilter(resample_filter,
845 blur.x1*QuantumScale*GetPixelRed(composite_image,p),
846 blur.y1*QuantumScale*GetPixelGreen(composite_image,p),
847 blur.x2*QuantumScale*GetPixelRed(composite_image,p),
848 blur.y2*QuantumScale*GetPixelGreen(composite_image,p) );
849 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
850 (double) y_offset+y,&pixel,exception);
851 SetPixelInfoPixel(destination_image,&pixel,q);
852 p+=GetPixelChannels(composite_image);
853 q+=GetPixelChannels(destination_image);
855 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
856 if (sync == MagickFalse)
859 resample_filter=DestroyResampleFilter(resample_filter);
860 composite_view=DestroyCacheView(composite_view);
861 destination_view=DestroyCacheView(destination_view);
862 composite_image=DestroyImage(composite_image);
863 composite_image=destination_image;
866 case DisplaceCompositeOp:
867 case DistortCompositeOp:
889 Displace/Distort based on overlay gradient map:
890 X = red_channel; Y = green_channel;
891 compose:args = x_scale[,y_scale[,center.x,center.y]]
893 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
895 if (destination_image == (Image *) NULL)
897 composite_image=DestroyImage(composite_image);
900 SetGeometryInfo(&geometry_info);
902 value=GetImageArtifact(image,"compose:args");
903 if (value != (char *) NULL)
904 flags=ParseGeometry(value,&geometry_info);
905 if ((flags & (WidthValue|HeightValue)) == 0 )
907 if ((flags & AspectValue) == 0)
909 horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
911 vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
915 horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
916 vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
921 horizontal_scale=geometry_info.rho;
922 vertical_scale=geometry_info.sigma;
923 if ((flags & PercentValue) != 0)
925 if ((flags & AspectValue) == 0)
927 horizontal_scale*=(composite_image->columns-1.0)/200.0;
928 vertical_scale*=(composite_image->rows-1.0)/200.0;
932 horizontal_scale*=(image->columns-1.0)/200.0;
933 vertical_scale*=(image->rows-1.0)/200.0;
936 if ((flags & HeightValue) == 0)
937 vertical_scale=horizontal_scale;
940 Determine fixed center point for absolute distortion map
942 Displace offset relative to a fixed absolute point
943 Select that point according to +X+Y user inputs.
944 default = center of overlay image
945 arg flag '!' = locations/percentage relative to background image
947 center.x=(MagickRealType) x_offset;
948 center.y=(MagickRealType) y_offset;
949 if (compose == DistortCompositeOp)
951 if ((flags & XValue) == 0)
952 if ((flags & AspectValue) == 0)
953 center.x=(MagickRealType) (x_offset+(composite_image->columns-1)/
956 center.x=(MagickRealType) ((image->columns-1)/2);
958 if ((flags & AspectValue) == 0)
959 center.x=(MagickRealType) x_offset+geometry_info.xi;
961 center.x=geometry_info.xi;
962 if ((flags & YValue) == 0)
963 if ((flags & AspectValue) == 0)
964 center.y=(MagickRealType) (y_offset+(composite_image->rows-1)/
967 center.y=(MagickRealType) ((image->rows-1)/2);
969 if ((flags & AspectValue) == 0)
970 center.y=(MagickRealType) y_offset+geometry_info.psi;
972 center.y=geometry_info.psi;
975 Shift the pixel offset point as defined by the provided,
976 displacement/distortion map. -- Like a lens...
978 GetPixelInfo(image,&pixel);
979 image_view=AcquireVirtualCacheView(image,exception);
980 composite_view=AcquireVirtualCacheView(composite_image,exception);
981 destination_view=AcquireAuthenticCacheView(destination_image,exception);
982 for (y=0; y < (ssize_t) composite_image->rows; y++)
987 register const Quantum
996 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
998 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
1000 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
1001 destination_image->columns,1,exception);
1002 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1004 for (x=0; x < (ssize_t) composite_image->columns; x++)
1006 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1008 p+=GetPixelChannels(composite_image);
1012 Displace the offset.
1014 offset.x=(double) (horizontal_scale*(GetPixelRed(composite_image,p)-
1015 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1016 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
1018 offset.y=(double) (vertical_scale*(GetPixelGreen(composite_image,p)-
1019 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1020 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
1022 (void) InterpolatePixelInfo(image,image_view,
1023 UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1026 Mask with the 'invalid pixel mask' in alpha channel.
1028 pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
1029 pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
1030 SetPixelInfoPixel(destination_image,&pixel,q);
1031 p+=GetPixelChannels(composite_image);
1032 q+=GetPixelChannels(destination_image);
1034 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1035 if (sync == MagickFalse)
1038 destination_view=DestroyCacheView(destination_view);
1039 composite_view=DestroyCacheView(composite_view);
1040 image_view=DestroyCacheView(image_view);
1041 composite_image=DestroyImage(composite_image);
1042 composite_image=destination_image;
1045 case DissolveCompositeOp:
1051 Geometry arguments to dissolve factors.
1053 value=GetImageArtifact(image,"compose:args");
1054 if (value != (char *) NULL)
1056 flags=ParseGeometry(value,&geometry_info);
1057 source_dissolve=geometry_info.rho/100.0;
1058 destination_dissolve=1.0;
1059 if ((source_dissolve-MagickEpsilon) < 0.0)
1060 source_dissolve=0.0;
1061 if ((source_dissolve+MagickEpsilon) > 1.0)
1063 destination_dissolve=2.0-source_dissolve;
1064 source_dissolve=1.0;
1066 if ((flags & SigmaValue) != 0)
1067 destination_dissolve=geometry_info.sigma/100.0;
1068 if ((destination_dissolve-MagickEpsilon) < 0.0)
1069 destination_dissolve=0.0;
1073 case BlendCompositeOp:
1078 value=GetImageArtifact(image,"compose:args");
1079 if (value != (char *) NULL)
1081 flags=ParseGeometry(value,&geometry_info);
1082 source_dissolve=geometry_info.rho/100.0;
1083 destination_dissolve=1.0-source_dissolve;
1084 if ((flags & SigmaValue) != 0)
1085 destination_dissolve=geometry_info.sigma/100.0;
1089 case MathematicsCompositeOp:
1095 Just collect the values from "compose:args", setting.
1096 Unused values are set to zero automagically.
1098 Arguments are normally a comma separated list, so this probably should
1099 be changed to some 'general comma list' parser, (with a minimum
1102 SetGeometryInfo(&geometry_info);
1103 value=GetImageArtifact(image,"compose:args");
1104 if (value != (char *) NULL)
1105 (void) ParseGeometry(value,&geometry_info);
1108 case ModulateCompositeOp:
1114 Determine the luma and chroma scale.
1116 value=GetImageArtifact(image,"compose:args");
1117 if (value != (char *) NULL)
1119 flags=ParseGeometry(value,&geometry_info);
1120 percent_luma=geometry_info.rho;
1121 if ((flags & SigmaValue) != 0)
1122 percent_chroma=geometry_info.sigma;
1126 case ThresholdCompositeOp:
1132 Determine the amount and threshold.
1134 value=GetImageArtifact(image,"compose:args");
1135 if (value != (char *) NULL)
1137 flags=ParseGeometry(value,&geometry_info);
1138 amount=geometry_info.rho;
1139 threshold=geometry_info.sigma;
1140 if ((flags & SigmaValue) == 0)
1143 threshold*=QuantumRange;
1154 midpoint=((MagickRealType) QuantumRange+1.0)/2;
1155 composite_view=AcquireVirtualCacheView(composite_image,exception);
1156 image_view=AcquireAuthenticCacheView(image,exception);
1157 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1158 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1159 magick_threads(composite_image,image,image->rows,1)
1161 for (y=0; y < (ssize_t) image->rows; y++)
1178 register const Quantum
1187 if (status == MagickFalse)
1189 if (clip_to_self != MagickFalse)
1193 if ((y-y_offset) >= (ssize_t) composite_image->rows)
1197 If pixels is NULL, y is outside overlay region.
1199 pixels=(Quantum *) NULL;
1201 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
1203 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
1204 composite_image->columns,1,exception);
1205 if (p == (const Quantum *) NULL)
1212 p-=x_offset*GetPixelChannels(composite_image);
1214 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1215 if (q == (Quantum *) NULL)
1223 GetPixelInfo(image,&destination_pixel);
1224 GetPixelInfo(composite_image,&source_pixel);
1225 for (x=0; x < (ssize_t) image->columns; x++)
1245 if (clip_to_self != MagickFalse)
1249 q+=GetPixelChannels(image);
1252 if ((x-x_offset) >= (ssize_t) composite_image->columns)
1255 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1256 ((x-x_offset) >= (ssize_t) composite_image->columns))
1259 source[MaxPixelChannels];
1264 Dc: destination color.
1266 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
1268 if (GetPixelReadMask(image,q) == 0)
1270 q+=GetPixelChannels(image);
1273 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1278 PixelChannel channel=GetPixelChannelChannel(image,i);
1279 PixelTrait traits=GetPixelChannelTraits(image,channel);
1280 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
1282 if ((traits == UndefinedPixelTrait) ||
1283 (composite_traits == UndefinedPixelTrait))
1287 case AlphaCompositeOp:
1288 case ChangeMaskCompositeOp:
1289 case CopyAlphaCompositeOp:
1290 case DstAtopCompositeOp:
1291 case DstInCompositeOp:
1293 case IntensityCompositeOp:
1294 case OutCompositeOp:
1295 case SrcInCompositeOp:
1296 case SrcOutCompositeOp:
1298 pixel=(MagickRealType) q[i];
1299 if (channel == AlphaPixelChannel)
1300 pixel=(MagickRealType) TransparentAlpha;
1303 case ClearCompositeOp:
1304 case CopyCompositeOp:
1305 case ReplaceCompositeOp:
1306 case SrcCompositeOp:
1308 if (channel == AlphaPixelChannel)
1310 pixel=(MagickRealType) TransparentAlpha;
1316 case BlendCompositeOp:
1317 case DissolveCompositeOp:
1319 if (channel == AlphaPixelChannel)
1321 pixel=destination_dissolve*GetPixelAlpha(composite_image,
1325 pixel=(MagickRealType) source[channel];
1330 pixel=(MagickRealType) source[channel];
1334 q[i]=ClampToQuantum(pixel);
1336 q+=GetPixelChannels(image);
1340 Authentic composite:
1341 Sa: normalized source alpha.
1342 Da: normalized destination alpha.
1344 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
1345 Da=QuantumScale*GetPixelAlpha(image,q);
1348 case BumpmapCompositeOp:
1350 alpha=GetPixelIntensity(composite_image,p)*Sa;
1353 case ColorBurnCompositeOp:
1354 case ColorDodgeCompositeOp:
1355 case DifferenceCompositeOp:
1356 case DivideDstCompositeOp:
1357 case DivideSrcCompositeOp:
1358 case ExclusionCompositeOp:
1359 case HardLightCompositeOp:
1360 case HardMixCompositeOp:
1361 case LinearBurnCompositeOp:
1362 case LinearDodgeCompositeOp:
1363 case LinearLightCompositeOp:
1364 case MathematicsCompositeOp:
1365 case MinusDstCompositeOp:
1366 case MinusSrcCompositeOp:
1367 case ModulusAddCompositeOp:
1368 case ModulusSubtractCompositeOp:
1369 case MultiplyCompositeOp:
1370 case OverlayCompositeOp:
1371 case PegtopLightCompositeOp:
1372 case PinLightCompositeOp:
1373 case ScreenCompositeOp:
1374 case SoftLightCompositeOp:
1375 case VividLightCompositeOp:
1377 alpha=RoundToUnity(Sa+Da-Sa*Da);
1380 case DarkenCompositeOp:
1381 case DstAtopCompositeOp:
1382 case DstInCompositeOp:
1384 case LightenCompositeOp:
1385 case SrcInCompositeOp:
1390 case DissolveCompositeOp:
1392 alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
1393 Sa+destination_dissolve*Da;
1396 case DstOverCompositeOp:
1398 alpha=Da*(-Sa)+Da+Sa;
1401 case DstOutCompositeOp:
1406 case OutCompositeOp:
1407 case SrcOutCompositeOp:
1412 case OverCompositeOp:
1413 case SrcOverCompositeOp:
1415 alpha=Sa*(-Da)+Sa+Da;
1418 case BlendCompositeOp:
1419 case PlusCompositeOp:
1421 alpha=RoundToUnity(Sa+Da);
1424 case XorCompositeOp:
1426 alpha=Sa+Da-2.0*Sa*Da;
1435 if (GetPixelReadMask(image,q) == 0)
1437 p+=GetPixelChannels(composite_image);
1438 q+=GetPixelChannels(image);
1443 case ColorizeCompositeOp:
1444 case HueCompositeOp:
1445 case LuminizeCompositeOp:
1446 case ModulateCompositeOp:
1447 case SaturateCompositeOp:
1449 GetPixelInfoPixel(composite_image,p,&source_pixel);
1450 GetPixelInfoPixel(image,q,&destination_pixel);
1456 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1462 PixelChannel channel=GetPixelChannelChannel(image,i);
1463 PixelTrait traits=GetPixelChannelTraits(image,channel);
1464 PixelTrait composite_traits=GetPixelChannelTraits(composite_image,
1466 if (traits == UndefinedPixelTrait)
1468 if ((compose != IntensityCompositeOp) &&
1469 (composite_traits == UndefinedPixelTrait))
1473 Dc: destination color.
1475 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
1476 Dc=(MagickRealType) q[i];
1477 if ((traits & CopyPixelTrait) != 0)
1479 if (channel != AlphaPixelChannel)
1484 q[i]=ClampToQuantum(Sc);
1492 case AlphaCompositeOp:
1494 pixel=QuantumRange*Sa;
1497 case AtopCompositeOp:
1498 case CopyBlackCompositeOp:
1499 case CopyBlueCompositeOp:
1500 case CopyCyanCompositeOp:
1501 case CopyGreenCompositeOp:
1502 case CopyMagentaCompositeOp:
1503 case CopyRedCompositeOp:
1504 case CopyYellowCompositeOp:
1505 case SrcAtopCompositeOp:
1506 case DstCompositeOp:
1509 pixel=QuantumRange*Da;
1512 case ChangeMaskCompositeOp:
1517 if (Da > ((MagickRealType) QuantumRange/2.0))
1519 pixel=(MagickRealType) TransparentAlpha;
1522 equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
1523 if (equivalent != MagickFalse)
1525 pixel=(MagickRealType) TransparentAlpha;
1528 pixel=(MagickRealType) OpaqueAlpha;
1531 case ClearCompositeOp:
1533 pixel=(MagickRealType) TransparentAlpha;
1536 case ColorizeCompositeOp:
1537 case HueCompositeOp:
1538 case LuminizeCompositeOp:
1539 case SaturateCompositeOp:
1541 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1543 pixel=QuantumRange*Da;
1546 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1548 pixel=QuantumRange*Sa;
1553 pixel=QuantumRange*Da;
1556 pixel=QuantumRange*Sa;
1559 case CopyAlphaCompositeOp:
1561 pixel=QuantumRange*Sa;
1562 if (composite_image->alpha_trait != BlendPixelTrait)
1563 pixel=GetPixelIntensity(composite_image,p);
1566 case CopyCompositeOp:
1567 case DisplaceCompositeOp:
1568 case DistortCompositeOp:
1569 case DstAtopCompositeOp:
1570 case ReplaceCompositeOp:
1571 case SrcCompositeOp:
1573 pixel=QuantumRange*Sa;
1576 case DarkenIntensityCompositeOp:
1578 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1579 (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
1582 case IntensityCompositeOp:
1584 pixel=GetPixelIntensity(composite_image,p);
1587 case LightenIntensityCompositeOp:
1589 pixel=Sa*GetPixelIntensity(composite_image,p) >
1590 Da*GetPixelIntensity(image,q) ? Sa : Da;
1593 case ModulateCompositeOp:
1595 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1597 pixel=QuantumRange*Da;
1600 pixel=QuantumRange*Da;
1605 pixel=QuantumRange*alpha;
1609 q[i]=ClampToQuantum(pixel);
1613 Porter-Duff compositions:
1614 Sca: source normalized color multiplied by alpha.
1615 Dca: normalized destination color multiplied by alpha.
1617 Sca=QuantumScale*Sa*Sc;
1618 Dca=QuantumScale*Da*Dc;
1621 case DarkenCompositeOp:
1622 case LightenCompositeOp:
1623 case ModulusSubtractCompositeOp:
1631 gamma=PerceptibleReciprocal(alpha);
1635 case AlphaCompositeOp:
1637 pixel=QuantumRange*Sa;
1640 case AtopCompositeOp:
1641 case SrcAtopCompositeOp:
1643 pixel=Sc*Sa+Dc*(1.0-Sa);
1646 case BlendCompositeOp:
1648 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1651 case BlurCompositeOp:
1652 case DisplaceCompositeOp:
1653 case DistortCompositeOp:
1654 case CopyCompositeOp:
1655 case ReplaceCompositeOp:
1656 case SrcCompositeOp:
1661 case BumpmapCompositeOp:
1663 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1668 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1671 case ChangeMaskCompositeOp:
1676 case ClearCompositeOp:
1681 case ColorBurnCompositeOp:
1684 Refer to the March 2009 SVG specification.
1686 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1688 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1691 if (Sca < MagickEpsilon)
1693 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1696 pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
1697 Sca*(1.0-Da)+Dca*(1.0-Sa));
1700 case ColorDodgeCompositeOp:
1702 if ((Sca*Da+Dca*Sa) >= Sa*Da)
1704 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1707 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1711 case ColorizeCompositeOp:
1713 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1718 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1723 CompositeHCL(destination_pixel.red,destination_pixel.green,
1724 destination_pixel.blue,&sans,&sans,&luma);
1725 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1726 &hue,&chroma,&sans);
1727 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1730 case RedPixelChannel: pixel=red; break;
1731 case GreenPixelChannel: pixel=green; break;
1732 case BluePixelChannel: pixel=blue; break;
1733 default: pixel=Dc; break;
1737 case CopyAlphaCompositeOp:
1738 case IntensityCompositeOp:
1743 case CopyBlackCompositeOp:
1745 if (channel == BlackPixelChannel)
1746 pixel=(MagickRealType) (QuantumRange-
1747 GetPixelBlack(composite_image,p));
1750 case CopyBlueCompositeOp:
1751 case CopyYellowCompositeOp:
1753 if (channel == BluePixelChannel)
1754 pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1757 case CopyGreenCompositeOp:
1758 case CopyMagentaCompositeOp:
1760 if (channel == GreenPixelChannel)
1761 pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1764 case CopyRedCompositeOp:
1765 case CopyCyanCompositeOp:
1767 if (channel == RedPixelChannel)
1768 pixel=(MagickRealType) GetPixelRed(composite_image,p);
1771 case DarkenCompositeOp:
1774 Darken is equivalent to a 'Minimum' method
1775 OR a greyscale version of a binary 'Or'
1776 OR the 'Intersection' of pixel sets.
1780 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1783 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1786 case DarkenIntensityCompositeOp:
1788 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1789 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1792 case DifferenceCompositeOp:
1794 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1797 case DissolveCompositeOp:
1799 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1800 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1803 case DivideDstCompositeOp:
1805 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1807 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1810 if (fabs(Dca) < MagickEpsilon)
1812 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1815 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1818 case DivideSrcCompositeOp:
1820 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1822 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1825 if (fabs(Sca) < MagickEpsilon)
1827 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1830 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1833 case DstAtopCompositeOp:
1835 pixel=Dc*Da+Sc*(1.0-Da);
1838 case DstCompositeOp:
1844 case DstInCompositeOp:
1846 pixel=gamma*(Sa*Dc*Sa);
1849 case DstOutCompositeOp:
1851 pixel=gamma*(Da*Dc*(1.0-Sa));
1854 case DstOverCompositeOp:
1856 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1859 case ExclusionCompositeOp:
1861 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1865 case HardLightCompositeOp:
1869 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1873 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1877 case HardMixCompositeOp:
1886 pixel=(gamma*(1.0-Sca)*(1.0-Dca))+Sa*(1.0-Sca)*Dca+Da*(1.0-Dca)*Sca;
1889 case HueCompositeOp:
1891 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1896 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1901 CompositeHCL(destination_pixel.red,destination_pixel.green,
1902 destination_pixel.blue,&hue,&chroma,&luma);
1903 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1905 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1908 case RedPixelChannel: pixel=red; break;
1909 case GreenPixelChannel: pixel=green; break;
1910 case BluePixelChannel: pixel=blue; break;
1911 default: pixel=Dc; break;
1916 case SrcInCompositeOp:
1918 pixel=gamma*(Da*Sc*Da);
1921 case LinearBurnCompositeOp:
1924 LinearBurn: as defined by Abode Photoshop, according to
1925 http://www.simplefilter.de/en/basics/mixmods.html is:
1927 f(Sc,Dc) = Sc + Dc - 1
1929 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1932 case LinearDodgeCompositeOp:
1934 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1937 case LinearLightCompositeOp:
1940 LinearLight: as defined by Abode Photoshop, according to
1941 http://www.simplefilter.de/en/basics/mixmods.html is:
1943 f(Sc,Dc) = Dc + 2*Sc - 1
1945 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1948 case LightenCompositeOp:
1952 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1955 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1958 case LightenIntensityCompositeOp:
1961 Lighten is equivalent to a 'Maximum' method
1962 OR a greyscale version of a binary 'And'
1963 OR the 'Union' of pixel sets.
1965 pixel=Sa*GetPixelIntensity(composite_image,p) >
1966 Da*GetPixelIntensity(image,q) ? Sc : Dc;
1969 case LuminizeCompositeOp:
1971 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1976 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1981 CompositeHCL(destination_pixel.red,destination_pixel.green,
1982 destination_pixel.blue,&hue,&chroma,&luma);
1983 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1985 HCLComposite(hue,chroma,luma,&red,&green,&blue);
1988 case RedPixelChannel: pixel=red; break;
1989 case GreenPixelChannel: pixel=green; break;
1990 case BluePixelChannel: pixel=blue; break;
1991 default: pixel=Dc; break;
1995 case MathematicsCompositeOp:
1998 'Mathematics' a free form user control mathematical composition
2001 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
2003 Where the arguments A,B,C,D are (currently) passed to composite
2004 as a command separated 'geometry' string in "compose:args" image
2007 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
2009 Applying the SVG transparency formula (see above), we get...
2011 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
2013 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
2016 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
2017 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
2018 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
2021 case MinusDstCompositeOp:
2023 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2026 case MinusSrcCompositeOp:
2029 Minus source from destination.
2033 pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2036 case ModulateCompositeOp:
2041 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2046 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
2052 CompositeHCL(destination_pixel.red,destination_pixel.green,
2053 destination_pixel.blue,&hue,&chroma,&luma);
2054 luma+=(0.01*percent_luma*offset)/midpoint;
2055 chroma*=0.01*percent_chroma;
2056 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2059 case RedPixelChannel: pixel=red; break;
2060 case GreenPixelChannel: pixel=green; break;
2061 case BluePixelChannel: pixel=blue; break;
2062 default: pixel=Dc; break;
2066 case ModulusAddCompositeOp:
2069 if (pixel > QuantumRange)
2070 pixel-=QuantumRange;
2071 pixel=gamma*(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2074 case ModulusSubtractCompositeOp:
2078 pixel+=QuantumRange;
2079 pixel=gamma*(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2082 case MultiplyCompositeOp:
2084 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2087 case OutCompositeOp:
2088 case SrcOutCompositeOp:
2090 pixel=gamma*(Sa*Sc*(1.0-Da));
2093 case OverCompositeOp:
2094 case SrcOverCompositeOp:
2096 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2099 case OverlayCompositeOp:
2103 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2107 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2111 case PegtopLightCompositeOp:
2114 PegTop: A Soft-Light alternative: A continuous version of the
2115 Softlight function, producing very similar results.
2117 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2119 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2121 if (fabs(Da) < MagickEpsilon)
2123 pixel=QuantumRange*gamma*(Sca);
2126 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2130 case PinLightCompositeOp:
2133 PinLight: A Photoshop 7 composition method
2134 http://www.simplefilter.de/en/basics/mixmods.html
2136 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2138 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2140 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2143 if ((Dca*Sa) > (2.0*Sca*Da))
2145 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2148 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2151 case PlusCompositeOp:
2153 pixel=gamma*(Sa*Sc+Da*Dc);
2156 case SaturateCompositeOp:
2158 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2163 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2168 CompositeHCL(destination_pixel.red,destination_pixel.green,
2169 destination_pixel.blue,&hue,&chroma,&luma);
2170 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2171 &sans,&chroma,&sans);
2172 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2175 case RedPixelChannel: pixel=red; break;
2176 case GreenPixelChannel: pixel=green; break;
2177 case BluePixelChannel: pixel=blue; break;
2178 default: pixel=Dc; break;
2182 case ScreenCompositeOp:
2185 Screen: a negated multiply:
2187 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2189 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2192 case SoftLightCompositeOp:
2195 Refer to the March 2009 SVG specification.
2199 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2200 Sca*(1.0-Da)+Dca*(1.0-Sa));
2203 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2205 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2206 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2210 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2211 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2214 case ThresholdCompositeOp:
2220 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2225 pixel=gamma*(Dc+delta*amount);
2228 case VividLightCompositeOp:
2231 VividLight: A Photoshop 7 composition method. See
2232 http://www.simplefilter.de/en/basics/mixmods.html.
2234 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2236 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2238 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2241 if ((2.0*Sca) <= Sa)
2243 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2244 (1.0-Da)+Dca*(1.0-Sa));
2247 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2251 case XorCompositeOp:
2253 pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2262 q[i]=ClampToQuantum(pixel);
2264 p+=GetPixelChannels(composite_image);
2265 channels=GetPixelChannels(composite_image);
2266 if (p >= (pixels+channels*composite_image->columns))
2268 q+=GetPixelChannels(image);
2270 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2272 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2277 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2278 #pragma omp critical (MagickCore_CompositeImage)
2280 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2282 if (proceed == MagickFalse)
2286 composite_view=DestroyCacheView(composite_view);
2287 image_view=DestroyCacheView(image_view);
2288 if (destination_image != (Image * ) NULL)
2289 destination_image=DestroyImage(destination_image);
2291 composite_image=DestroyImage(composite_image);
2296 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2300 % T e x t u r e I m a g e %
2304 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2306 % TextureImage() repeatedly tiles the texture image across and down the image
2309 % The format of the TextureImage method is:
2311 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2312 % ExceptionInfo *exception)
2314 % A description of each parameter follows:
2316 % o image: the image.
2318 % o texture_image: This image is the texture to layer on the background.
2321 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
2322 ExceptionInfo *exception)
2324 #define TextureImageTag "Texture/Image"
2339 assert(image != (Image *) NULL);
2340 if (image->debug != MagickFalse)
2341 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2342 assert(image->signature == MagickSignature);
2343 if (texture == (const Image *) NULL)
2344 return(MagickFalse);
2345 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2346 return(MagickFalse);
2347 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2348 if (texture_image == (const Image *) NULL)
2349 return(MagickFalse);
2350 (void) TransformImageColorspace(texture_image,image->colorspace,exception);
2351 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
2354 if ((image->compose != CopyCompositeOp) &&
2355 ((image->compose != OverCompositeOp) ||
2356 (image->alpha_trait == BlendPixelTrait) ||
2357 (texture_image->alpha_trait == BlendPixelTrait)))
2360 Tile texture onto the image background.
2362 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2367 if (status == MagickFalse)
2369 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2374 thread_status=CompositeImage(image,texture_image,image->compose,
2375 MagickFalse,x+texture_image->tile_offset.x,y+
2376 texture_image->tile_offset.y,exception);
2377 if (thread_status == MagickFalse)
2379 status=thread_status;
2383 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2388 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2390 if (proceed == MagickFalse)
2394 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2395 image->rows,image->rows);
2396 texture_image=DestroyImage(texture_image);
2400 Tile texture onto the image background (optimized).
2403 texture_view=AcquireVirtualCacheView(texture_image,exception);
2404 image_view=AcquireAuthenticCacheView(image,exception);
2405 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2406 #pragma omp parallel for schedule(static,4) shared(status) \
2407 magick_threads(texture_image,image,1,1)
2409 for (y=0; y < (ssize_t) image->rows; y++)
2414 register const Quantum
2427 if (status == MagickFalse)
2429 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2430 (y+texture_image->tile_offset.y) % texture_image->rows,
2431 texture_image->columns,1,exception);
2432 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2433 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2438 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2444 width=texture_image->columns;
2445 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2446 width=image->columns-x;
2447 for (j=0; j < (ssize_t) width; j++)
2452 if (GetPixelReadMask(image,q) == 0)
2454 p+=GetPixelChannels(texture_image);
2455 q+=GetPixelChannels(image);
2458 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2460 PixelChannel channel=GetPixelChannelChannel(texture_image,i);
2461 PixelTrait traits=GetPixelChannelTraits(image,channel);
2462 PixelTrait texture_traits=GetPixelChannelTraits(texture_image,
2464 if ((traits == UndefinedPixelTrait) ||
2465 (texture_traits == UndefinedPixelTrait))
2467 SetPixelChannel(image,channel,p[i],q);
2469 p+=GetPixelChannels(texture_image);
2470 q+=GetPixelChannels(image);
2473 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2474 if (sync == MagickFalse)
2476 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2481 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2483 if (proceed == MagickFalse)
2487 texture_view=DestroyCacheView(texture_view);
2488 image_view=DestroyCacheView(image_view);
2489 texture_image=DestroyImage(texture_image);