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/utility.h"
76 #include "MagickCore/utility-private.h"
77 #include "MagickCore/version.h"
80 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
84 % C o m p o s i t e I m a g e %
88 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
90 % CompositeImage() returns the second image composited onto the first
91 % at the specified offset, using the specified composite method.
93 % The format of the CompositeImage method is:
95 % MagickBooleanType CompositeImage(Image *image,
96 % const CompositeOperator compose,Image *composite_image,
97 % const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
99 % A description of each parameter follows:
101 % o image: the destination image, modified by he composition
103 % o compose: This operator affects how the composite is applied to
104 % the image. The operators and how they are utilized are listed here
105 % http://www.w3.org/TR/SVG12/#compositing.
107 % o composite_image: the composite (source) image.
109 % o x_offset: the column offset of the composited image.
111 % o y_offset: the row offset of the composited image.
113 % Extra Controls from Image meta-data in 'composite_image' (artifacts)
116 % A string containing extra numerical arguments for specific compose
117 % methods, generally expressed as a 'geometry' or a comma separated list
120 % Compose methods needing such arguments include "BlendCompositeOp" and
121 % "DisplaceCompositeOp".
123 % o "compose:outside-overlay"
124 % Modify how the composition is to effect areas not directly covered
125 % by the 'composite_image' at the offset given. Normally this is
126 % dependant on the 'compose' method, especially Duff-Porter methods.
128 % If set to "false" then disable all normal handling of pixels not
129 % covered by the composite_image. Typically used for repeated tiling
130 % of the composite_image by the calling API.
132 % Previous to IM v6.5.3-3 this was called "modify-outside-overlay"
134 % o exception: return any errors or warnings in this structure.
138 static void CompositeHSB(const Quantum red,const Quantum green,
139 const Quantum blue,double *hue,double *saturation,double *brightness)
149 Convert RGB to HSB colorspace.
151 assert(hue != (double *) NULL);
152 assert(saturation != (double *) NULL);
153 assert(brightness != (double *) NULL);
154 max=(red > green ? red : green);
157 min=(red < green ? red : green);
162 *brightness=(double) (QuantumScale*max);
163 if (fabs((double) max) < MagickEpsilon)
165 *saturation=(double) (1.0-min/max);
166 delta=(MagickRealType) max-min;
167 if (fabs(delta) < MagickEpsilon)
169 if (fabs((double) red-max) < MagickEpsilon)
170 *hue=(double) ((green-blue)/delta);
172 if (fabs((double) green-max) < MagickEpsilon)
173 *hue=(double) (2.0+(blue-red)/delta);
175 if (fabs((double) blue-max) < MagickEpsilon)
176 *hue=(double) (4.0+(red-green)/delta);
182 static void HSBComposite(const double hue,const double saturation,
183 const double brightness,double *red,double *green,double *blue)
193 Convert HSB to RGB colorspace.
195 assert(red != (double *) NULL);
196 assert(green != (double *) NULL);
197 assert(blue != (double *) NULL);
198 if (saturation == 0.0)
200 *red=(double) QuantumRange*brightness;
205 h=6.0*(hue-floor(hue));
206 f=h-floor((double) h);
207 p=brightness*(1.0-saturation);
208 q=brightness*(1.0-saturation*f);
209 t=brightness*(1.0-saturation*(1.0-f));
215 *red=(double) QuantumRange*brightness;
216 *green=(double) QuantumRange*t;
217 *blue=(double) QuantumRange*p;
222 *red=(double) QuantumRange*q;
223 *green=(double) QuantumRange*brightness;
224 *blue=(double) QuantumRange*p;
229 *red=(double) QuantumRange*p;
230 *green=(double) QuantumRange*brightness;
231 *blue=(double) QuantumRange*t;
236 *red=(double) QuantumRange*p;
237 *green=(double) QuantumRange*q;
238 *blue=(double) QuantumRange*brightness;
243 *red=(double) QuantumRange*t;
244 *green=(double) QuantumRange*p;
245 *blue=(double) QuantumRange*brightness;
250 *red=(double) QuantumRange*brightness;
251 *green=(double) QuantumRange*p;
252 *blue=(double) QuantumRange*q;
258 static inline double MagickMin(const double x,const double y)
264 static inline double MagickMax(const double x,const double y)
271 static MagickBooleanType CompositeOverImage(Image *image,
272 const Image *composite_image,const ssize_t x_offset,const ssize_t y_offset,
273 ExceptionInfo *exception)
275 #define CompositeImageTag "Composite/Image"
285 modify_outside_overlay,
298 Prepare composite image.
300 modify_outside_overlay=MagickFalse;
301 value=GetImageArtifact(composite_image,"compose:outside-overlay");
302 if (value != (const char *) NULL)
303 modify_outside_overlay=IsMagickTrue(value);
309 image_view=AcquireCacheView(image);
310 composite_view=AcquireCacheView(composite_image);
311 #if defined(MAGICKCORE_OPENMP_SUPPORT)
312 #pragma omp parallel for schedule(static,4) shared(progress,status)
314 for (y=0; y < (ssize_t) image->rows; y++)
319 register const Quantum
328 if (status == MagickFalse)
330 if (modify_outside_overlay == MagickFalse)
334 if ((y-y_offset) >= (ssize_t) composite_image->rows)
338 If pixels is NULL, y is outside overlay region.
340 pixels=(Quantum *) NULL;
342 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
344 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
345 composite_image->columns,1,exception);
346 if (p == (const Quantum *) NULL)
353 p-=x_offset*GetPixelChannels(composite_image);
355 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
356 if (q == (Quantum *) NULL)
361 for (x=0; x < (ssize_t) image->columns; x++)
374 if (modify_outside_overlay == MagickFalse)
378 q+=GetPixelChannels(image);
381 if ((x-x_offset) >= (ssize_t) composite_image->columns)
384 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
385 ((x-x_offset) >= (ssize_t) composite_image->columns))
388 source[MaxPixelChannels];
393 Dc: destination color.
395 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
397 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
406 channel=GetPixelChannelMapChannel(image,i);
407 traits=GetPixelChannelMapTraits(image,channel);
408 composite_traits=GetPixelChannelMapTraits(composite_image,
410 if ((traits == UndefinedPixelTrait) ||
411 (composite_traits == UndefinedPixelTrait))
413 q[i]=source[channel];
415 q+=GetPixelChannels(image);
420 Sa: normalized source alpha.
421 Da: normalized destination alpha.
423 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
424 Da=QuantumScale*GetPixelAlpha(image,q);
425 alpha=Sa*(-Da)+Sa+Da;
426 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
435 channel=GetPixelChannelMapChannel(image,i);
436 traits=GetPixelChannelMapTraits(image,channel);
437 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
438 if ((traits == UndefinedPixelTrait) ||
439 (composite_traits == UndefinedPixelTrait))
441 if ((traits & CopyPixelTrait) != 0)
443 if (channel != AlphaPixelChannel)
448 q[i]=GetPixelChannel(composite_image,channel,p);
454 q[i]=ClampToQuantum(QuantumRange*alpha);
459 Dc: destination color.
461 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
462 Dc=(MagickRealType) q[i];
463 gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
464 q[i]=ClampToQuantum(gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc));
466 p+=GetPixelChannels(composite_image);
467 channels=GetPixelChannels(composite_image);
468 if (p >= (pixels+channels*composite_image->columns))
470 q+=GetPixelChannels(image);
472 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
474 if (image->progress_monitor != (MagickProgressMonitor) NULL)
479 #if defined(MAGICKCORE_OPENMP_SUPPORT)
480 #pragma omp critical (MagickCore_CompositeImage)
482 proceed=SetImageProgress(image,CompositeImageTag,progress++,
484 if (proceed == MagickFalse)
488 composite_view=DestroyCacheView(composite_view);
489 image_view=DestroyCacheView(image_view);
493 MagickExport MagickBooleanType CompositeImage(Image *image,
494 const CompositeOperator compose,const Image *composite_image,
495 const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
497 #define CompositeImageTag "Composite/Image"
516 modify_outside_overlay,
524 destination_dissolve,
541 Composition based on the SVG specification:
543 A Composition is defined by...
544 Color Function : f(Sc,Dc) where Sc and Dc are the normizalized colors
545 Blending areas : X = 1 for area of overlap, ie: f(Sc,Dc)
546 Y = 1 for source preserved
547 Z = 1 for destination preserved
549 Conversion to transparency (then optimized)
550 Dca' = f(Sc, Dc)*Sa*Da + Y*Sca*(1-Da) + Z*Dca*(1-Sa)
551 Da' = X*Sa*Da + Y*Sa*(1-Da) + Z*Da*(1-Sa)
554 Sca = Sc*Sa normalized Source color divided by Source alpha
555 Dca = Dc*Da normalized Dest color divided by Dest alpha
556 Dc' = Dca'/Da' the desired color value for this channel.
558 Da' in in the follow formula as 'gamma' The resulting alpla value.
560 Most functions use a blending mode of over (X=1,Y=1,Z=1) this results in
561 the following optimizations...
563 gamma = 1 - QuantiumScale*alpha * QuantiumScale*beta;
564 opacity = QuantiumScale*alpha*beta; // over blend, optimized 1-Gamma
566 The above SVG definitions also definate that Mathematical Composition
567 methods should use a 'Over' blending mode for Alpha Channel.
568 It however was not applied for composition modes of 'Plus', 'Minus',
569 the modulus versions of 'Add' and 'Subtract'.
571 Mathematical operator changes to be applied from IM v6.7...
573 1) Modulus modes 'Add' and 'Subtract' are obsoleted and renamed
574 'ModulusAdd' and 'ModulusSubtract' for clarity.
576 2) All mathematical compositions work as per the SVG specification
577 with regard to blending. This now includes 'ModulusAdd' and
580 3) When the special channel flag 'sync' (syncronize channel updates)
581 is turned off (enabled by default) then mathematical compositions are
582 only performed on the channels specified, and are applied
583 independantally of each other. In other words the mathematics is
584 performed as 'pure' mathematical operations, rather than as image
588 assert(image != (Image *) NULL);
589 assert(image->signature == MagickSignature);
590 if (image->debug != MagickFalse)
591 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
592 assert(composite_image != (Image *) NULL);
593 assert(composite_image->signature == MagickSignature);
594 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
596 if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
598 status=CompositeOverImage(image,composite_image,x_offset,y_offset,
602 destination_image=(Image *) NULL;
604 destination_dissolve=1.0;
605 modify_outside_overlay=MagickFalse;
606 percent_brightness=100.0;
607 percent_saturation=100.0;
612 case ClearCompositeOp:
613 case DstAtopCompositeOp:
614 case DstInCompositeOp:
618 case SrcInCompositeOp:
619 case SrcOutCompositeOp:
622 Modify destination outside the overlaid region.
624 modify_outside_overlay=MagickTrue;
627 case CopyCompositeOp:
629 if ((x_offset < 0) || (y_offset < 0))
631 if ((x_offset+(ssize_t) composite_image->columns) >= (ssize_t) image->columns)
633 if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
636 image_view=AcquireCacheView(image);
637 composite_view=AcquireCacheView(composite_image);
638 #if defined(MAGICKCORE_OPENMP_SUPPORT)
639 #pragma omp parallel for schedule(static,4) shared(status)
641 for (y=0; y < (ssize_t) composite_image->rows; y++)
646 register const Quantum
655 if (status == MagickFalse)
657 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
659 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
660 composite_image->columns,1,exception);
661 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
666 for (x=0; x < (ssize_t) composite_image->columns; x++)
671 for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
680 channel=GetPixelChannelMapChannel(composite_image,i);
681 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
682 traits=GetPixelChannelMapTraits(image,channel);
683 if ((traits == UndefinedPixelTrait) ||
684 (composite_traits == UndefinedPixelTrait))
686 SetPixelChannel(image,channel,p[i],q);
688 p+=GetPixelChannels(composite_image);
689 q+=GetPixelChannels(image);
691 sync=SyncCacheViewAuthenticPixels(image_view,exception);
692 if (sync == MagickFalse)
694 if (image->progress_monitor != (MagickProgressMonitor) NULL)
699 #if defined(MAGICKCORE_OPENMP_SUPPORT)
700 #pragma omp critical (MagickCore_CompositeImage)
702 proceed=SetImageProgress(image,CompositeImageTag,
703 (MagickOffsetType) y,image->rows);
704 if (proceed == MagickFalse)
708 composite_view=DestroyCacheView(composite_view);
709 image_view=DestroyCacheView(image_view);
712 case CopyAlphaCompositeOp:
713 case ChangeMaskCompositeOp:
714 case IntensityCompositeOp:
717 Modify destination outside the overlaid region and require an alpha
718 channel to exist, to add transparency.
720 if (image->matte == MagickFalse)
721 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
722 modify_outside_overlay=MagickTrue;
725 case BlurCompositeOp:
747 Blur Image dictated by an overlay gradient map: X = red_channel;
748 Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
750 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
752 if (destination_image == (Image *) NULL)
755 Determine the horizontal and vertical maximim blur.
757 SetGeometryInfo(&geometry_info);
759 value=GetImageArtifact(composite_image,"compose:args");
760 if (value != (char *) NULL)
761 flags=ParseGeometry(value,&geometry_info);
762 if ((flags & WidthValue) == 0 )
764 destination_image=DestroyImage(destination_image);
767 width=geometry_info.rho;
768 height=geometry_info.sigma;
769 blur.x1=geometry_info.rho;
772 blur.y2=geometry_info.sigma;
775 if ((flags & HeightValue) == 0)
777 if ((flags & XValue) != 0 )
782 angle=DegreesToRadians(geometry_info.xi);
783 blur.x1=width*cos(angle);
784 blur.x2=width*sin(angle);
785 blur.y1=(-height*sin(angle));
786 blur.y2=height*cos(angle);
788 if ((flags & YValue) != 0 )
790 angle_start=DegreesToRadians(geometry_info.xi);
791 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
794 Blur Image by resampling.
796 resample_filter=AcquireResampleFilter(image,exception);
797 SetResampleFilter(resample_filter,CubicFilter,2.0);
798 destination_view=AcquireCacheView(destination_image);
799 composite_view=AcquireCacheView(composite_image);
800 for (y=0; y < (ssize_t) composite_image->rows; y++)
805 register const Quantum
814 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
816 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
818 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
819 destination_image->columns,1,exception);
820 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
822 for (x=0; x < (ssize_t) composite_image->columns; x++)
824 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
826 p+=GetPixelChannels(composite_image);
829 if (fabs(angle_range) > MagickEpsilon)
834 angle=angle_start+angle_range*QuantumScale*
835 GetPixelBlue(composite_image,p);
836 blur.x1=width*cos(angle);
837 blur.x2=width*sin(angle);
838 blur.y1=(-height*sin(angle));
839 blur.y2=height*cos(angle);
841 ScaleResampleFilter(resample_filter,blur.x1*QuantumScale*
842 GetPixelRed(composite_image,p),blur.y1*QuantumScale*
843 GetPixelGreen(composite_image,p),blur.x2*QuantumScale*
844 GetPixelRed(composite_image,p),blur.y2*QuantumScale*
845 GetPixelGreen(composite_image,p));
846 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
847 (double) y_offset+y,&pixel);
848 SetPixelInfoPixel(destination_image,&pixel,q);
849 p+=GetPixelChannels(composite_image);
850 q+=GetPixelChannels(destination_image);
852 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
853 if (sync == MagickFalse)
856 resample_filter=DestroyResampleFilter(resample_filter);
857 composite_view=DestroyCacheView(composite_view);
858 destination_view=DestroyCacheView(destination_view);
859 composite_image=destination_image;
862 case DisplaceCompositeOp:
863 case DistortCompositeOp:
882 Displace/Distort based on overlay gradient map:
883 X = red_channel; Y = green_channel;
884 compose:args = x_scale[,y_scale[,center.x,center.y]]
886 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
888 if (destination_image == (Image *) NULL)
890 SetGeometryInfo(&geometry_info);
892 value=GetImageArtifact(composite_image,"compose:args");
893 if (value != (char *) NULL)
894 flags=ParseGeometry(value,&geometry_info);
895 if ((flags & (WidthValue|HeightValue)) == 0 )
897 if ((flags & AspectValue) == 0)
899 horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
901 vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
905 horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
906 vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
911 horizontal_scale=geometry_info.rho;
912 vertical_scale=geometry_info.sigma;
913 if ((flags & PercentValue) != 0)
915 if ((flags & AspectValue) == 0)
917 horizontal_scale*=(composite_image->columns-1.0)/200.0;
918 vertical_scale*=(composite_image->rows-1.0)/200.0;
922 horizontal_scale*=(image->columns-1.0)/200.0;
923 vertical_scale*=(image->rows-1.0)/200.0;
926 if ((flags & HeightValue) == 0)
927 vertical_scale=horizontal_scale;
930 Determine fixed center point for absolute distortion map
932 Displace offset relative to a fixed absolute point
933 Select that point according to +X+Y user inputs.
934 default = center of overlay image
935 arg flag '!' = locations/percentage relative to background image
937 center.x=(MagickRealType) x_offset;
938 center.y=(MagickRealType) y_offset;
939 if (compose == DistortCompositeOp)
941 if ((flags & XValue) == 0)
942 if ((flags & AspectValue) == 0)
943 center.x=(MagickRealType) x_offset+(composite_image->columns-1)/
946 center.x=((MagickRealType) image->columns-1)/2.0;
948 if ((flags & AspectValue) == 0)
949 center.x=(MagickRealType) x_offset+geometry_info.xi;
951 center.x=geometry_info.xi;
952 if ((flags & YValue) == 0)
953 if ((flags & AspectValue) == 0)
954 center.y=(MagickRealType) y_offset+(composite_image->rows-1)/2.0;
956 center.y=((MagickRealType) image->rows-1)/2.0;
958 if ((flags & AspectValue) == 0)
959 center.y=(MagickRealType) y_offset+geometry_info.psi;
961 center.y=geometry_info.psi;
964 Shift the pixel offset point as defined by the provided,
965 displacement/distortion map. -- Like a lens...
967 GetPixelInfo(image,&pixel);
968 image_view=AcquireCacheView(image);
969 destination_view=AcquireCacheView(destination_image);
970 composite_view=AcquireCacheView(composite_image);
971 for (y=0; y < (ssize_t) composite_image->rows; y++)
976 register const Quantum
985 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
987 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
989 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
990 destination_image->columns,1,exception);
991 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
993 for (x=0; x < (ssize_t) composite_image->columns; x++)
995 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
997 p+=GetPixelChannels(composite_image);
1001 Displace the offset.
1003 offset.x=(horizontal_scale*(GetPixelRed(composite_image,p)-
1004 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1005 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
1007 offset.y=(vertical_scale*(GetPixelGreen(composite_image,p)-
1008 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1009 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
1011 (void) InterpolatePixelInfo(image,image_view,
1012 UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1015 Mask with the 'invalid pixel mask' in alpha channel.
1017 pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
1018 pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
1019 SetPixelInfoPixel(destination_image,&pixel,q);
1020 p+=GetPixelChannels(composite_image);
1021 q+=GetPixelChannels(destination_image);
1023 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1024 if (sync == MagickFalse)
1027 destination_view=DestroyCacheView(destination_view);
1028 composite_view=DestroyCacheView(composite_view);
1029 image_view=DestroyCacheView(image_view);
1030 composite_image=destination_image;
1033 case DissolveCompositeOp:
1036 Geometry arguments to dissolve factors.
1038 value=GetImageArtifact(composite_image,"compose:args");
1039 if (value != (char *) NULL)
1041 flags=ParseGeometry(value,&geometry_info);
1042 source_dissolve=geometry_info.rho/100.0;
1043 destination_dissolve=1.0;
1044 if ((source_dissolve-MagickEpsilon) < 0.0)
1045 source_dissolve=0.0;
1046 if ((source_dissolve+MagickEpsilon) > 1.0)
1048 destination_dissolve=2.0-source_dissolve;
1049 source_dissolve=1.0;
1051 if ((flags & SigmaValue) != 0)
1052 destination_dissolve=geometry_info.sigma/100.0;
1053 if ((destination_dissolve-MagickEpsilon) < 0.0)
1054 destination_dissolve=0.0;
1055 modify_outside_overlay=MagickTrue;
1056 if ((destination_dissolve+MagickEpsilon) > 1.0 )
1058 destination_dissolve=1.0;
1059 modify_outside_overlay=MagickFalse;
1064 case BlendCompositeOp:
1066 value=GetImageArtifact(composite_image,"compose:args");
1067 if (value != (char *) NULL)
1069 flags=ParseGeometry(value,&geometry_info);
1070 source_dissolve=geometry_info.rho/100.0;
1071 destination_dissolve=1.0-source_dissolve;
1072 if ((flags & SigmaValue) != 0)
1073 destination_dissolve=geometry_info.sigma/100.0;
1074 modify_outside_overlay=MagickTrue;
1075 if ((destination_dissolve+MagickEpsilon) > 1.0)
1076 modify_outside_overlay=MagickFalse;
1080 case MathematicsCompositeOp:
1083 Just collect the values from "compose:args", setting.
1084 Unused values are set to zero automagically.
1086 Arguments are normally a comma separated list, so this probably should
1087 be changed to some 'general comma list' parser, (with a minimum
1090 SetGeometryInfo(&geometry_info);
1091 value=GetImageArtifact(composite_image,"compose:args");
1092 if (value != (char *) NULL)
1093 (void) ParseGeometry(value,&geometry_info);
1096 case ModulateCompositeOp:
1099 Determine the brightness and saturation scale.
1101 value=GetImageArtifact(composite_image,"compose:args");
1102 if (value != (char *) NULL)
1104 flags=ParseGeometry(value,&geometry_info);
1105 percent_brightness=geometry_info.rho;
1106 if ((flags & SigmaValue) != 0)
1107 percent_saturation=geometry_info.sigma;
1111 case ThresholdCompositeOp:
1114 Determine the amount and threshold.
1116 value=GetImageArtifact(composite_image,"compose:args");
1117 if (value != (char *) NULL)
1119 flags=ParseGeometry(value,&geometry_info);
1120 amount=geometry_info.rho;
1121 threshold=geometry_info.sigma;
1122 if ((flags & SigmaValue) == 0)
1125 threshold*=QuantumRange;
1131 value=GetImageArtifact(composite_image,"compose:outside-overlay");
1132 if (value != (const char *) NULL)
1133 modify_outside_overlay=IsMagickTrue(value);
1139 midpoint=((MagickRealType) QuantumRange+1.0)/2;
1140 image_view=AcquireCacheView(image);
1141 composite_view=AcquireCacheView(composite_image);
1142 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1143 #pragma omp parallel for schedule(static,4) shared(progress,status)
1145 for (y=0; y < (ssize_t) image->rows; y++)
1158 register const Quantum
1167 if (status == MagickFalse)
1169 if (modify_outside_overlay == MagickFalse)
1173 if ((y-y_offset) >= (ssize_t) composite_image->rows)
1177 If pixels is NULL, y is outside overlay region.
1179 pixels=(Quantum *) NULL;
1181 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
1183 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
1184 composite_image->columns,1,exception);
1185 if (p == (const Quantum *) NULL)
1192 p-=x_offset*GetPixelChannels(composite_image);
1194 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1195 if (q == (Quantum *) NULL)
1203 for (x=0; x < (ssize_t) image->columns; x++)
1218 if (modify_outside_overlay == MagickFalse)
1222 q+=GetPixelChannels(image);
1225 if ((x-x_offset) >= (ssize_t) composite_image->columns)
1228 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1229 ((x-x_offset) >= (ssize_t) composite_image->columns))
1232 source[MaxPixelChannels];
1237 Dc: destination color.
1239 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
1241 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1253 channel=GetPixelChannelMapChannel(image,i);
1254 traits=GetPixelChannelMapTraits(image,channel);
1255 composite_traits=GetPixelChannelMapTraits(composite_image,
1257 if ((traits == UndefinedPixelTrait) ||
1258 (composite_traits == UndefinedPixelTrait))
1262 case AlphaCompositeOp:
1263 case ChangeMaskCompositeOp:
1264 case CopyAlphaCompositeOp:
1265 case DstAtopCompositeOp:
1266 case DstInCompositeOp:
1268 case IntensityCompositeOp:
1269 case OutCompositeOp:
1270 case SrcInCompositeOp:
1271 case SrcOutCompositeOp:
1273 pixel=(MagickRealType) q[i];
1274 if (channel == AlphaPixelChannel)
1275 pixel=(MagickRealType) TransparentAlpha;
1278 case ClearCompositeOp:
1279 case CopyCompositeOp:
1280 case ReplaceCompositeOp:
1281 case SrcCompositeOp:
1283 if (channel == AlphaPixelChannel)
1285 pixel=(MagickRealType) TransparentAlpha;
1291 case BlendCompositeOp:
1292 case DissolveCompositeOp:
1294 if (channel == AlphaPixelChannel)
1296 pixel=destination_dissolve*GetPixelAlpha(composite_image,
1300 pixel=(MagickRealType) source[channel];
1305 pixel=(MagickRealType) source[channel];
1309 q[i]=ClampToQuantum(pixel);
1311 q+=GetPixelChannels(image);
1315 Authentic composite:
1316 Sa: normalized source alpha.
1317 Da: normalized destination alpha.
1319 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
1320 Da=QuantumScale*GetPixelAlpha(image,q);
1323 case BumpmapCompositeOp:
1325 alpha=GetPixelIntensity(composite_image,p)*Sa;
1328 case ColorBurnCompositeOp:
1329 case ColorDodgeCompositeOp:
1330 case DifferenceCompositeOp:
1331 case DivideDstCompositeOp:
1332 case DivideSrcCompositeOp:
1333 case ExclusionCompositeOp:
1334 case HardLightCompositeOp:
1335 case LinearBurnCompositeOp:
1336 case LinearDodgeCompositeOp:
1337 case LinearLightCompositeOp:
1338 case MathematicsCompositeOp:
1339 case MinusDstCompositeOp:
1340 case MinusSrcCompositeOp:
1341 case ModulusAddCompositeOp:
1342 case ModulusSubtractCompositeOp:
1343 case MultiplyCompositeOp:
1344 case OverlayCompositeOp:
1345 case PegtopLightCompositeOp:
1346 case PinLightCompositeOp:
1347 case ScreenCompositeOp:
1348 case SoftLightCompositeOp:
1349 case VividLightCompositeOp:
1351 alpha=RoundToUnity(Sa+Da-Sa*Da);
1354 case DarkenCompositeOp:
1355 case DstAtopCompositeOp:
1356 case DstInCompositeOp:
1358 case LightenCompositeOp:
1359 case SrcInCompositeOp:
1364 case DissolveCompositeOp:
1366 alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
1367 Sa+destination_dissolve*Da;
1370 case DstOverCompositeOp:
1372 alpha=Da*(-Sa)+Da+Sa;
1375 case DstOutCompositeOp:
1380 case OutCompositeOp:
1381 case SrcOutCompositeOp:
1386 case OverCompositeOp:
1387 case SrcOverCompositeOp:
1389 alpha=Sa*(-Da)+Sa+Da;
1392 case BlendCompositeOp:
1393 case PlusCompositeOp:
1395 alpha=RoundToUnity(Sa+Da);
1398 case XorCompositeOp:
1400 alpha=Sa+Da-2.0*Sa*Da;
1409 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1421 channel=GetPixelChannelMapChannel(image,i);
1422 traits=GetPixelChannelMapTraits(image,channel);
1423 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
1424 if (traits == UndefinedPixelTrait)
1426 if ((compose != AlphaCompositeOp) &&
1427 (compose != IntensityCompositeOp) &&
1428 (composite_traits == UndefinedPixelTrait))
1432 Dc: destination color.
1434 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
1435 Dc=(MagickRealType) q[i];
1436 if ((traits & CopyPixelTrait) != 0)
1438 if (channel != AlphaPixelChannel)
1443 q[i]=ClampToQuantum(Sc);
1451 case AlphaCompositeOp:
1456 case AtopCompositeOp:
1457 case CopyBlackCompositeOp:
1458 case CopyBlueCompositeOp:
1459 case CopyCyanCompositeOp:
1460 case CopyGreenCompositeOp:
1461 case CopyMagentaCompositeOp:
1462 case CopyRedCompositeOp:
1463 case CopyYellowCompositeOp:
1464 case SrcAtopCompositeOp:
1465 case DstCompositeOp:
1468 pixel=QuantumRange*Da;
1471 case ChangeMaskCompositeOp:
1476 if (Da > ((MagickRealType) QuantumRange/2.0))
1478 pixel=(MagickRealType) TransparentAlpha;
1481 equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
1482 if (equivalent != MagickFalse)
1484 pixel=(MagickRealType) TransparentAlpha;
1487 pixel=(MagickRealType) OpaqueAlpha;
1490 case ClearCompositeOp:
1492 pixel=(MagickRealType) TransparentAlpha;
1495 case ColorizeCompositeOp:
1496 case HueCompositeOp:
1497 case LuminizeCompositeOp:
1498 case SaturateCompositeOp:
1500 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1502 pixel=QuantumRange*Da;
1505 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1507 pixel=QuantumRange*Sa;
1512 pixel=QuantumRange*Da;
1515 pixel=QuantumRange*Sa;
1518 case CopyCompositeOp:
1519 case CopyAlphaCompositeOp:
1520 case DisplaceCompositeOp:
1521 case DistortCompositeOp:
1522 case DstAtopCompositeOp:
1523 case ReplaceCompositeOp:
1524 case SrcCompositeOp:
1526 pixel=QuantumRange*Sa;
1529 case DarkenIntensityCompositeOp:
1531 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1532 (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
1535 case IntensityCompositeOp:
1537 pixel=(MagickRealType) GetPixelIntensity(composite_image,p);
1540 case LightenIntensityCompositeOp:
1542 pixel=Sa*GetPixelIntensity(composite_image,p) >
1543 Da*GetPixelIntensity(image,q) ? Sa : Da;
1546 case ModulateCompositeOp:
1548 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1550 pixel=QuantumRange*Da;
1553 pixel=QuantumRange*Da;
1558 pixel=QuantumRange*alpha;
1562 q[i]=ClampToQuantum(pixel);
1566 Porter-Duff compositions:
1567 Sca: source normalized color multiplied by alpha.
1568 Dca: normalized destination color multiplied by alpha.
1570 Sca=QuantumScale*Sa*Sc;
1571 Dca=QuantumScale*Da*Dc;
1574 case DarkenCompositeOp:
1575 case LightenCompositeOp:
1576 case ModulusSubtractCompositeOp:
1584 gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
1587 case AtopCompositeOp:
1588 case SrcAtopCompositeOp:
1590 pixel=Sc*Sa+Dc*(1.0-Sa);
1593 case BlendCompositeOp:
1595 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1598 case BlurCompositeOp:
1599 case DisplaceCompositeOp:
1600 case DistortCompositeOp:
1601 case CopyCompositeOp:
1602 case ReplaceCompositeOp:
1603 case SrcCompositeOp:
1608 case BumpmapCompositeOp:
1610 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1615 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1618 case ChangeMaskCompositeOp:
1623 case ClearCompositeOp:
1628 case ColorBurnCompositeOp:
1631 Refer to the March 2009 SVG specification.
1633 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1635 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1638 if (Sca < MagickEpsilon)
1640 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1643 pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
1644 Sca*(1.0-Da)+Dca*(1.0-Sa));
1647 case ColorDodgeCompositeOp:
1649 if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1651 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1654 if (fabs(Sca-Sa) < MagickEpsilon)
1656 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1659 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1663 case ColorizeCompositeOp:
1665 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1670 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1675 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1676 GetPixelBlue(image,q),&sans,&sans,&brightness);
1677 CompositeHSB(GetPixelRed(composite_image,p),
1678 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1679 &hue,&saturation,&sans);
1680 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1683 case RedPixelChannel: pixel=red; break;
1684 case GreenPixelChannel: pixel=green; break;
1685 case BluePixelChannel: pixel=blue; break;
1686 default: pixel=Dc; break;
1690 case CopyAlphaCompositeOp:
1691 case IntensityCompositeOp:
1696 case CopyBlackCompositeOp:
1698 pixel=(MagickRealType) GetPixelBlack(composite_image,p);
1701 case CopyBlueCompositeOp:
1702 case CopyYellowCompositeOp:
1704 pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1707 case CopyGreenCompositeOp:
1708 case CopyMagentaCompositeOp:
1710 pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1713 case CopyRedCompositeOp:
1714 case CopyCyanCompositeOp:
1716 pixel=(MagickRealType) GetPixelRed(composite_image,p);
1719 case DarkenCompositeOp:
1722 Darken is equivalent to a 'Minimum' method
1723 OR a greyscale version of a binary 'Or'
1724 OR the 'Intersection' of pixel sets.
1728 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1731 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1734 case DarkenIntensityCompositeOp:
1736 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1737 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1740 case DifferenceCompositeOp:
1742 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1745 case DissolveCompositeOp:
1747 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1748 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1751 case DivideDstCompositeOp:
1753 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1755 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1758 if (fabs(Dca) < MagickEpsilon)
1760 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1763 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1766 case DivideSrcCompositeOp:
1768 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1770 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1773 if (fabs(Sca) < MagickEpsilon)
1775 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1778 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1781 case DstAtopCompositeOp:
1783 pixel=Dc*Da+Sc*(1.0-Da);
1786 case DstCompositeOp:
1792 case DstInCompositeOp:
1794 pixel=gamma*(Sa*Dc*Sa);
1797 case DstOutCompositeOp:
1799 pixel=gamma*(Da*Dc*(1.0-Sa));
1802 case DstOverCompositeOp:
1804 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1807 case ExclusionCompositeOp:
1809 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1813 case HardLightCompositeOp:
1817 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1821 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1825 case HueCompositeOp:
1827 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1832 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1837 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1838 GetPixelBlue(image,q),&hue,&saturation,&brightness);
1839 CompositeHSB(GetPixelRed(composite_image,p),
1840 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1842 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1845 case RedPixelChannel: pixel=red; break;
1846 case GreenPixelChannel: pixel=green; break;
1847 case BluePixelChannel: pixel=blue; break;
1848 default: pixel=Dc; break;
1853 case SrcInCompositeOp:
1855 pixel=gamma*(Da*Sc*Da);
1858 case LinearBurnCompositeOp:
1861 LinearBurn: as defined by Abode Photoshop, according to
1862 http://www.simplefilter.de/en/basics/mixmods.html is:
1864 f(Sc,Dc) = Sc + Dc - 1
1866 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1869 case LinearDodgeCompositeOp:
1871 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1874 case LinearLightCompositeOp:
1877 LinearLight: as defined by Abode Photoshop, according to
1878 http://www.simplefilter.de/en/basics/mixmods.html is:
1880 f(Sc,Dc) = Dc + 2*Sc - 1
1882 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1885 case LightenCompositeOp:
1889 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1892 pixel=QuantumRange*gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1895 case LightenIntensityCompositeOp:
1898 Lighten is equivalent to a 'Maximum' method
1899 OR a greyscale version of a binary 'And'
1900 OR the 'Union' of pixel sets.
1902 pixel=Sa*GetPixelIntensity(composite_image,p) >
1903 Da*GetPixelIntensity(image,q) ? Sc : Dc;
1906 case LuminizeCompositeOp:
1908 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1913 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1918 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1919 GetPixelBlue(image,q),&hue,&saturation,&brightness);
1920 CompositeHSB(GetPixelRed(composite_image,p),
1921 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1922 &sans,&sans,&brightness);
1923 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1926 case RedPixelChannel: pixel=red; break;
1927 case GreenPixelChannel: pixel=green; break;
1928 case BluePixelChannel: pixel=blue; break;
1929 default: pixel=Dc; break;
1933 case MathematicsCompositeOp:
1936 'Mathematics' a free form user control mathematical composition
1939 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
1941 Where the arguments A,B,C,D are (currently) passed to composite
1942 as a command separated 'geometry' string in "compose:args" image
1945 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
1947 Applying the SVG transparency formula (see above), we get...
1949 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
1951 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
1954 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
1955 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
1956 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
1959 case MinusDstCompositeOp:
1961 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
1964 case MinusSrcCompositeOp:
1967 Minus source from destination.
1971 pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
1974 case ModulateCompositeOp:
1979 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1984 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
1990 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1991 GetPixelBlue(image,q),&hue,&saturation,&brightness);
1992 brightness+=(0.01*percent_brightness*offset)/midpoint;
1993 saturation*=0.01*percent_saturation;
1994 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1997 case RedPixelChannel: pixel=red; break;
1998 case GreenPixelChannel: pixel=green; break;
1999 case BluePixelChannel: pixel=blue; break;
2000 default: pixel=Dc; break;
2004 case ModulusAddCompositeOp:
2007 if (pixel > QuantumRange)
2008 pixel-=(QuantumRange+1.0);
2009 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2012 case ModulusSubtractCompositeOp:
2016 pixel+=(QuantumRange+1.0);
2017 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2020 case MultiplyCompositeOp:
2022 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2025 case OutCompositeOp:
2026 case SrcOutCompositeOp:
2028 pixel=gamma*(Sa*Sc*(1.0-Da));
2031 case OverCompositeOp:
2032 case SrcOverCompositeOp:
2034 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2037 case OverlayCompositeOp:
2041 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2045 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2049 case PegtopLightCompositeOp:
2052 PegTop: A Soft-Light alternative: A continuous version of the
2053 Softlight function, producing very similar results.
2055 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2057 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2059 if (fabs(Da) < MagickEpsilon)
2061 pixel=QuantumRange*gamma*(Sca);
2064 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2068 case PinLightCompositeOp:
2071 PinLight: A Photoshop 7 composition method
2072 http://www.simplefilter.de/en/basics/mixmods.html
2074 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2076 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2078 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2081 if ((Dca*Sa) > (2.0*Sca*Da))
2083 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2086 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2089 case PlusCompositeOp:
2091 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
2094 case SaturateCompositeOp:
2096 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2101 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2106 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
2107 GetPixelBlue(image,q),&hue,&saturation,&brightness);
2108 CompositeHSB(GetPixelRed(composite_image,p),
2109 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
2110 &sans,&saturation,&sans);
2111 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
2114 case RedPixelChannel: pixel=red; break;
2115 case GreenPixelChannel: pixel=green; break;
2116 case BluePixelChannel: pixel=blue; break;
2117 default: pixel=Dc; break;
2121 case ScreenCompositeOp:
2124 Screen: a negated multiply:
2126 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2128 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2131 case SoftLightCompositeOp:
2134 Refer to the March 2009 SVG specification.
2138 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2139 Sca*(1.0-Da)+Dca*(1.0-Sa));
2142 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2144 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2145 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2149 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2150 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2153 case ThresholdCompositeOp:
2159 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2164 pixel=gamma*(Dc+delta*amount);
2167 case VividLightCompositeOp:
2170 VividLight: A Photoshop 7 composition method. See
2171 http://www.simplefilter.de/en/basics/mixmods.html.
2173 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2175 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2177 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2180 if ((2.0*Sca) <= Sa)
2182 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2183 (1.0-Da)+Dca*(1.0-Sa));
2186 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2190 case XorCompositeOp:
2192 pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2201 q[i]=ClampToQuantum(pixel);
2203 p+=GetPixelChannels(composite_image);
2204 channels=GetPixelChannels(composite_image);
2205 if (p >= (pixels+channels*composite_image->columns))
2207 q+=GetPixelChannels(image);
2209 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2211 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2216 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2217 #pragma omp critical (MagickCore_CompositeImage)
2219 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2221 if (proceed == MagickFalse)
2225 composite_view=DestroyCacheView(composite_view);
2226 image_view=DestroyCacheView(image_view);
2227 if (destination_image != (Image * ) NULL)
2228 destination_image=DestroyImage(destination_image);
2233 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2237 % T e x t u r e I m a g e %
2241 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2243 % TextureImage() repeatedly tiles the texture image across and down the image
2246 % The format of the TextureImage method is:
2248 % MagickBooleanType TextureImage(Image *image,const Image *texture_image,
2249 % ExceptionInfo *exception)
2251 % A description of each parameter follows:
2253 % o image: the image.
2255 % o texture_image: This image is the texture to layer on the background.
2258 MagickExport MagickBooleanType TextureImage(Image *image,
2259 const Image *texture_image,ExceptionInfo *exception)
2261 #define TextureImageTag "Texture/Image"
2273 assert(image != (Image *) NULL);
2274 if (image->debug != MagickFalse)
2275 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2276 assert(image->signature == MagickSignature);
2277 if (texture_image == (const Image *) NULL)
2278 return(MagickFalse);
2279 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod);
2280 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2281 return(MagickFalse);
2283 if ((image->compose != CopyCompositeOp) &&
2284 ((image->compose != OverCompositeOp) || (image->matte != MagickFalse) ||
2285 (texture_image->matte != MagickFalse)))
2288 Tile texture onto the image background.
2290 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2291 #pragma omp parallel for schedule(static,4) shared(status) omp_throttle(1)
2293 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2298 if (status == MagickFalse)
2300 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2305 thread_status=CompositeImage(image,image->compose,texture_image,x+
2306 texture_image->tile_offset.x,y+texture_image->tile_offset.y,
2308 if (thread_status == MagickFalse)
2310 status=thread_status;
2314 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2319 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2320 #pragma omp critical (MagickCore_TextureImage)
2322 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2324 if (proceed == MagickFalse)
2328 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2329 image->rows,image->rows);
2333 Tile texture onto the image background (optimized).
2336 image_view=AcquireCacheView(image);
2337 texture_view=AcquireCacheView(texture_image);
2338 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2339 #pragma omp parallel for schedule(static,4) shared(status) omp_throttle(1)
2341 for (y=0; y < (ssize_t) image->rows; y++)
2346 register const Quantum
2359 if (status == MagickFalse)
2361 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2362 (y+texture_image->tile_offset.y) % texture_image->rows,
2363 texture_image->columns,1,exception);
2364 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2365 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2370 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2376 width=texture_image->columns;
2377 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2378 width=image->columns-x;
2379 for (j=0; j < (ssize_t) width; j++)
2384 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2393 channel=GetPixelChannelMapChannel(texture_image,i);
2394 texture_traits=GetPixelChannelMapTraits(texture_image,channel);
2395 traits=GetPixelChannelMapTraits(image,channel);
2396 if ((traits == UndefinedPixelTrait) ||
2397 (texture_traits == UndefinedPixelTrait))
2399 SetPixelChannel(image,channel,p[i],q);
2401 p+=GetPixelChannels(texture_image);
2402 q+=GetPixelChannels(image);
2405 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2406 if (sync == MagickFalse)
2408 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2413 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2414 #pragma omp critical (MagickCore_TextureImage)
2416 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2418 if (proceed == MagickFalse)
2422 texture_view=DestroyCacheView(texture_view);
2423 image_view=DestroyCacheView(image_view);