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 ChangeMaskCompositeOp:
1263 case CopyAlphaCompositeOp:
1264 case DstAtopCompositeOp:
1265 case DstInCompositeOp:
1267 case IntensityCompositeOp:
1268 case OutCompositeOp:
1269 case SrcInCompositeOp:
1270 case SrcOutCompositeOp:
1272 pixel=(MagickRealType) q[i];
1273 if (channel == AlphaPixelChannel)
1274 pixel=(MagickRealType) TransparentAlpha;
1277 case ClearCompositeOp:
1278 case CopyCompositeOp:
1279 case ReplaceCompositeOp:
1280 case SrcCompositeOp:
1282 if (channel == AlphaPixelChannel)
1284 pixel=(MagickRealType) TransparentAlpha;
1290 case BlendCompositeOp:
1291 case DissolveCompositeOp:
1293 if (channel == AlphaPixelChannel)
1295 pixel=destination_dissolve*GetPixelAlpha(composite_image,
1299 pixel=(MagickRealType) source[channel];
1304 pixel=(MagickRealType) source[channel];
1308 q[i]=ClampToQuantum(pixel);
1310 q+=GetPixelChannels(image);
1314 Authentic composite:
1315 Sa: normalized source alpha.
1316 Da: normalized destination alpha.
1318 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
1319 Da=QuantumScale*GetPixelAlpha(image,q);
1322 case BumpmapCompositeOp:
1324 alpha=GetPixelIntensity(composite_image,p)*Sa;
1327 case ColorBurnCompositeOp:
1328 case ColorDodgeCompositeOp:
1329 case DifferenceCompositeOp:
1330 case DivideDstCompositeOp:
1331 case DivideSrcCompositeOp:
1332 case ExclusionCompositeOp:
1333 case HardLightCompositeOp:
1334 case LinearBurnCompositeOp:
1335 case LinearDodgeCompositeOp:
1336 case LinearLightCompositeOp:
1337 case MathematicsCompositeOp:
1338 case MinusDstCompositeOp:
1339 case MinusSrcCompositeOp:
1340 case ModulusAddCompositeOp:
1341 case ModulusSubtractCompositeOp:
1342 case MultiplyCompositeOp:
1343 case OverlayCompositeOp:
1344 case PegtopLightCompositeOp:
1345 case PinLightCompositeOp:
1346 case ScreenCompositeOp:
1347 case SoftLightCompositeOp:
1348 case VividLightCompositeOp:
1350 alpha=RoundToUnity(Sa+Da-Sa*Da);
1353 case DarkenCompositeOp:
1354 case DstAtopCompositeOp:
1355 case DstInCompositeOp:
1357 case LightenCompositeOp:
1358 case SrcInCompositeOp:
1363 case DissolveCompositeOp:
1365 alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
1366 Sa+destination_dissolve*Da;
1369 case DstOverCompositeOp:
1371 alpha=Da*(-Sa)+Da+Sa;
1374 case DstOutCompositeOp:
1379 case OutCompositeOp:
1380 case SrcOutCompositeOp:
1385 case OverCompositeOp:
1386 case SrcOverCompositeOp:
1388 alpha=Sa*(-Da)+Sa+Da;
1391 case BlendCompositeOp:
1392 case PlusCompositeOp:
1394 alpha=RoundToUnity(Sa+Da);
1397 case XorCompositeOp:
1399 alpha=Sa+Da-2.0*Sa*Da;
1408 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1420 channel=GetPixelChannelMapChannel(image,i);
1421 traits=GetPixelChannelMapTraits(image,channel);
1422 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
1423 if (traits == UndefinedPixelTrait)
1425 if ((compose != IntensityCompositeOp) &&
1426 (composite_traits == UndefinedPixelTrait))
1430 Dc: destination color.
1432 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
1433 Dc=(MagickRealType) q[i];
1434 if ((traits & CopyPixelTrait) != 0)
1436 if (channel != AlphaPixelChannel)
1441 q[i]=ClampToQuantum(Sc);
1449 case AtopCompositeOp:
1450 case CopyBlackCompositeOp:
1451 case CopyBlueCompositeOp:
1452 case CopyCyanCompositeOp:
1453 case CopyGreenCompositeOp:
1454 case CopyMagentaCompositeOp:
1455 case CopyRedCompositeOp:
1456 case CopyYellowCompositeOp:
1457 case SrcAtopCompositeOp:
1458 case DstCompositeOp:
1461 pixel=QuantumRange*Da;
1464 case ChangeMaskCompositeOp:
1469 if (Da > ((MagickRealType) QuantumRange/2.0))
1471 pixel=(MagickRealType) TransparentAlpha;
1474 equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
1475 if (equivalent != MagickFalse)
1477 pixel=(MagickRealType) TransparentAlpha;
1480 pixel=(MagickRealType) OpaqueAlpha;
1483 case ClearCompositeOp:
1485 pixel=(MagickRealType) TransparentAlpha;
1488 case ColorizeCompositeOp:
1489 case HueCompositeOp:
1490 case LuminizeCompositeOp:
1491 case SaturateCompositeOp:
1493 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1495 pixel=QuantumRange*Da;
1498 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1500 pixel=QuantumRange*Sa;
1505 pixel=QuantumRange*Da;
1508 pixel=QuantumRange*Sa;
1511 case CopyCompositeOp:
1512 case CopyAlphaCompositeOp:
1513 case DisplaceCompositeOp:
1514 case DistortCompositeOp:
1515 case DstAtopCompositeOp:
1516 case ReplaceCompositeOp:
1517 case SrcCompositeOp:
1519 pixel=QuantumRange*Sa;
1522 case DarkenIntensityCompositeOp:
1524 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1525 (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
1528 case IntensityCompositeOp:
1530 pixel=GetPixelIntensity(composite_image,p);
1533 case LightenIntensityCompositeOp:
1535 pixel=Sa*GetPixelIntensity(composite_image,p) >
1536 Da*GetPixelIntensity(image,q) ? Sa : Da;
1539 case ModulateCompositeOp:
1541 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1543 pixel=QuantumRange*Da;
1546 pixel=QuantumRange*Da;
1551 pixel=QuantumRange*alpha;
1555 q[i]=ClampToQuantum(pixel);
1559 Porter-Duff compositions:
1560 Sca: source normalized color multiplied by alpha.
1561 Dca: normalized destination color multiplied by alpha.
1563 Sca=QuantumScale*Sa*Sc;
1564 Dca=QuantumScale*Da*Dc;
1567 case DarkenCompositeOp:
1568 case LightenCompositeOp:
1569 case ModulusSubtractCompositeOp:
1577 gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
1580 case AtopCompositeOp:
1581 case SrcAtopCompositeOp:
1583 pixel=Sc*Sa+Dc*(1.0-Sa);
1586 case BlendCompositeOp:
1588 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1591 case BlurCompositeOp:
1592 case DisplaceCompositeOp:
1593 case DistortCompositeOp:
1594 case CopyCompositeOp:
1595 case ReplaceCompositeOp:
1596 case SrcCompositeOp:
1601 case BumpmapCompositeOp:
1603 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1608 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1611 case ChangeMaskCompositeOp:
1616 case ClearCompositeOp:
1621 case ColorBurnCompositeOp:
1624 Refer to the March 2009 SVG specification.
1626 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1628 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1631 if (Sca < MagickEpsilon)
1633 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1636 pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
1637 Sca*(1.0-Da)+Dca*(1.0-Sa));
1640 case ColorDodgeCompositeOp:
1642 if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1644 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1647 if (fabs(Sca-Sa) < MagickEpsilon)
1649 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1652 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1656 case ColorizeCompositeOp:
1658 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1663 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1668 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1669 GetPixelBlue(image,q),&sans,&sans,&brightness);
1670 CompositeHSB(GetPixelRed(composite_image,p),
1671 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1672 &hue,&saturation,&sans);
1673 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1676 case RedPixelChannel: pixel=red; break;
1677 case GreenPixelChannel: pixel=green; break;
1678 case BluePixelChannel: pixel=blue; break;
1679 default: pixel=Dc; break;
1683 case CopyAlphaCompositeOp:
1684 case IntensityCompositeOp:
1689 case CopyBlackCompositeOp:
1691 pixel=(MagickRealType) GetPixelBlack(composite_image,p);
1694 case CopyBlueCompositeOp:
1695 case CopyYellowCompositeOp:
1697 pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1700 case CopyGreenCompositeOp:
1701 case CopyMagentaCompositeOp:
1703 pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1706 case CopyRedCompositeOp:
1707 case CopyCyanCompositeOp:
1709 pixel=(MagickRealType) GetPixelRed(composite_image,p);
1712 case DarkenCompositeOp:
1715 Darken is equivalent to a 'Minimum' method
1716 OR a greyscale version of a binary 'Or'
1717 OR the 'Intersection' of pixel sets.
1721 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1724 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1727 case DarkenIntensityCompositeOp:
1729 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1730 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1733 case DifferenceCompositeOp:
1735 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1738 case DissolveCompositeOp:
1740 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1741 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1744 case DivideDstCompositeOp:
1746 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1748 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1751 if (fabs(Dca) < MagickEpsilon)
1753 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1756 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1759 case DivideSrcCompositeOp:
1761 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1763 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1766 if (fabs(Sca) < MagickEpsilon)
1768 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1771 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1774 case DstAtopCompositeOp:
1776 pixel=Dc*Da+Sc*(1.0-Da);
1779 case DstCompositeOp:
1785 case DstInCompositeOp:
1787 pixel=gamma*(Sa*Dc*Sa);
1790 case DstOutCompositeOp:
1792 pixel=gamma*(Da*Dc*(1.0-Sa));
1795 case DstOverCompositeOp:
1797 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1800 case ExclusionCompositeOp:
1802 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1806 case HardLightCompositeOp:
1810 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1814 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1818 case HueCompositeOp:
1820 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1825 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1830 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1831 GetPixelBlue(image,q),&hue,&saturation,&brightness);
1832 CompositeHSB(GetPixelRed(composite_image,p),
1833 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1835 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1838 case RedPixelChannel: pixel=red; break;
1839 case GreenPixelChannel: pixel=green; break;
1840 case BluePixelChannel: pixel=blue; break;
1841 default: pixel=Dc; break;
1846 case SrcInCompositeOp:
1848 pixel=gamma*(Da*Sc*Da);
1851 case LinearBurnCompositeOp:
1854 LinearBurn: as defined by Abode Photoshop, according to
1855 http://www.simplefilter.de/en/basics/mixmods.html is:
1857 f(Sc,Dc) = Sc + Dc - 1
1859 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1862 case LinearDodgeCompositeOp:
1864 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1867 case LinearLightCompositeOp:
1870 LinearLight: as defined by Abode Photoshop, according to
1871 http://www.simplefilter.de/en/basics/mixmods.html is:
1873 f(Sc,Dc) = Dc + 2*Sc - 1
1875 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1878 case LightenCompositeOp:
1882 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1885 pixel=QuantumRange*gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1888 case LightenIntensityCompositeOp:
1891 Lighten is equivalent to a 'Maximum' method
1892 OR a greyscale version of a binary 'And'
1893 OR the 'Union' of pixel sets.
1895 pixel=Sa*GetPixelIntensity(composite_image,p) >
1896 Da*GetPixelIntensity(image,q) ? Sc : Dc;
1899 case LuminizeCompositeOp:
1901 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1906 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1911 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1912 GetPixelBlue(image,q),&hue,&saturation,&brightness);
1913 CompositeHSB(GetPixelRed(composite_image,p),
1914 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1915 &sans,&sans,&brightness);
1916 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1919 case RedPixelChannel: pixel=red; break;
1920 case GreenPixelChannel: pixel=green; break;
1921 case BluePixelChannel: pixel=blue; break;
1922 default: pixel=Dc; break;
1926 case MathematicsCompositeOp:
1929 'Mathematics' a free form user control mathematical composition
1932 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
1934 Where the arguments A,B,C,D are (currently) passed to composite
1935 as a command separated 'geometry' string in "compose:args" image
1938 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
1940 Applying the SVG transparency formula (see above), we get...
1942 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
1944 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
1947 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
1948 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
1949 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
1952 case MinusDstCompositeOp:
1954 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
1957 case MinusSrcCompositeOp:
1960 Minus source from destination.
1964 pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
1967 case ModulateCompositeOp:
1972 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1977 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
1983 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1984 GetPixelBlue(image,q),&hue,&saturation,&brightness);
1985 brightness+=(0.01*percent_brightness*offset)/midpoint;
1986 saturation*=0.01*percent_saturation;
1987 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1990 case RedPixelChannel: pixel=red; break;
1991 case GreenPixelChannel: pixel=green; break;
1992 case BluePixelChannel: pixel=blue; break;
1993 default: pixel=Dc; break;
1997 case ModulusAddCompositeOp:
2000 if (pixel > QuantumRange)
2001 pixel-=(QuantumRange+1.0);
2002 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2005 case ModulusSubtractCompositeOp:
2009 pixel+=(QuantumRange+1.0);
2010 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2013 case MultiplyCompositeOp:
2015 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2018 case OutCompositeOp:
2019 case SrcOutCompositeOp:
2021 pixel=gamma*(Sa*Sc*(1.0-Da));
2024 case OverCompositeOp:
2025 case SrcOverCompositeOp:
2027 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2030 case OverlayCompositeOp:
2034 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2038 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2042 case PegtopLightCompositeOp:
2045 PegTop: A Soft-Light alternative: A continuous version of the
2046 Softlight function, producing very similar results.
2048 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2050 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2052 if (fabs(Da) < MagickEpsilon)
2054 pixel=QuantumRange*gamma*(Sca);
2057 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2061 case PinLightCompositeOp:
2064 PinLight: A Photoshop 7 composition method
2065 http://www.simplefilter.de/en/basics/mixmods.html
2067 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2069 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2071 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2074 if ((Dca*Sa) > (2.0*Sca*Da))
2076 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2079 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2082 case PlusCompositeOp:
2084 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
2087 case SaturateCompositeOp:
2089 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2094 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2099 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
2100 GetPixelBlue(image,q),&hue,&saturation,&brightness);
2101 CompositeHSB(GetPixelRed(composite_image,p),
2102 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
2103 &sans,&saturation,&sans);
2104 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
2107 case RedPixelChannel: pixel=red; break;
2108 case GreenPixelChannel: pixel=green; break;
2109 case BluePixelChannel: pixel=blue; break;
2110 default: pixel=Dc; break;
2114 case ScreenCompositeOp:
2117 Screen: a negated multiply:
2119 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2121 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2124 case SoftLightCompositeOp:
2127 Refer to the March 2009 SVG specification.
2131 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2132 Sca*(1.0-Da)+Dca*(1.0-Sa));
2135 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2137 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2138 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2142 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2143 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2146 case ThresholdCompositeOp:
2152 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2157 pixel=gamma*(Dc+delta*amount);
2160 case VividLightCompositeOp:
2163 VividLight: A Photoshop 7 composition method. See
2164 http://www.simplefilter.de/en/basics/mixmods.html.
2166 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2168 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2170 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2173 if ((2.0*Sca) <= Sa)
2175 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2176 (1.0-Da)+Dca*(1.0-Sa));
2179 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2183 case XorCompositeOp:
2185 pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2194 q[i]=ClampToQuantum(pixel);
2196 p+=GetPixelChannels(composite_image);
2197 channels=GetPixelChannels(composite_image);
2198 if (p >= (pixels+channels*composite_image->columns))
2200 q+=GetPixelChannels(image);
2202 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2204 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2209 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2210 #pragma omp critical (MagickCore_CompositeImage)
2212 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2214 if (proceed == MagickFalse)
2218 composite_view=DestroyCacheView(composite_view);
2219 image_view=DestroyCacheView(image_view);
2220 if (destination_image != (Image * ) NULL)
2221 destination_image=DestroyImage(destination_image);
2226 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2230 % T e x t u r e I m a g e %
2234 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2236 % TextureImage() repeatedly tiles the texture image across and down the image
2239 % The format of the TextureImage method is:
2241 % MagickBooleanType TextureImage(Image *image,const Image *texture_image,
2242 % ExceptionInfo *exception)
2244 % A description of each parameter follows:
2246 % o image: the image.
2248 % o texture_image: This image is the texture to layer on the background.
2251 MagickExport MagickBooleanType TextureImage(Image *image,
2252 const Image *texture_image,ExceptionInfo *exception)
2254 #define TextureImageTag "Texture/Image"
2266 assert(image != (Image *) NULL);
2267 if (image->debug != MagickFalse)
2268 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2269 assert(image->signature == MagickSignature);
2270 if (texture_image == (const Image *) NULL)
2271 return(MagickFalse);
2272 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod);
2273 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2274 return(MagickFalse);
2276 if ((image->compose != CopyCompositeOp) &&
2277 ((image->compose != OverCompositeOp) || (image->matte != MagickFalse) ||
2278 (texture_image->matte != MagickFalse)))
2281 Tile texture onto the image background.
2283 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2284 #pragma omp parallel for schedule(static,4) shared(status) omp_throttle(1)
2286 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2291 if (status == MagickFalse)
2293 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2298 thread_status=CompositeImage(image,image->compose,texture_image,x+
2299 texture_image->tile_offset.x,y+texture_image->tile_offset.y,
2301 if (thread_status == MagickFalse)
2303 status=thread_status;
2307 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2312 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2313 #pragma omp critical (MagickCore_TextureImage)
2315 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2317 if (proceed == MagickFalse)
2321 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2322 image->rows,image->rows);
2326 Tile texture onto the image background (optimized).
2329 image_view=AcquireCacheView(image);
2330 texture_view=AcquireCacheView(texture_image);
2331 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2332 #pragma omp parallel for schedule(static,4) shared(status) omp_throttle(1)
2334 for (y=0; y < (ssize_t) image->rows; y++)
2339 register const Quantum
2352 if (status == MagickFalse)
2354 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2355 (y+texture_image->tile_offset.y) % texture_image->rows,
2356 texture_image->columns,1,exception);
2357 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2358 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2363 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2369 width=texture_image->columns;
2370 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2371 width=image->columns-x;
2372 for (j=0; j < (ssize_t) width; j++)
2377 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2386 channel=GetPixelChannelMapChannel(texture_image,i);
2387 texture_traits=GetPixelChannelMapTraits(texture_image,channel);
2388 traits=GetPixelChannelMapTraits(image,channel);
2389 if ((traits == UndefinedPixelTrait) ||
2390 (texture_traits == UndefinedPixelTrait))
2392 SetPixelChannel(image,channel,p[i],q);
2394 p+=GetPixelChannels(texture_image);
2395 q+=GetPixelChannels(image);
2398 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2399 if (sync == MagickFalse)
2401 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2406 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2407 #pragma omp critical (MagickCore_TextureImage)
2409 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2411 if (proceed == MagickFalse)
2415 texture_view=DestroyCacheView(texture_view);
2416 image_view=DestroyCacheView(image_view);