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++)
668 SetPixelRed(image,GetPixelRed(composite_image,p),q);
669 SetPixelGreen(image,GetPixelGreen(composite_image,p),q);
670 SetPixelBlue(image,GetPixelBlue(composite_image,p),q);
671 SetPixelAlpha(image,GetPixelAlpha(composite_image,p),q);
672 if (image->colorspace == CMYKColorspace)
673 SetPixelBlack(image,GetPixelBlack(composite_image,p),q);
674 p+=GetPixelChannels(composite_image);
675 q+=GetPixelChannels(image);
677 sync=SyncCacheViewAuthenticPixels(image_view,exception);
678 if (sync == MagickFalse)
680 if (image->progress_monitor != (MagickProgressMonitor) NULL)
685 #if defined(MAGICKCORE_OPENMP_SUPPORT)
686 #pragma omp critical (MagickCore_CompositeImage)
688 proceed=SetImageProgress(image,CompositeImageTag,
689 (MagickOffsetType) y,image->rows);
690 if (proceed == MagickFalse)
694 composite_view=DestroyCacheView(composite_view);
695 image_view=DestroyCacheView(image_view);
698 case CopyAlphaCompositeOp:
699 case ChangeMaskCompositeOp:
702 Modify destination outside the overlaid region and require an alpha
703 channel to exist, to add transparency.
705 if (image->matte == MagickFalse)
706 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
707 modify_outside_overlay=MagickTrue;
710 case BlurCompositeOp:
732 Blur Image dictated by an overlay gradient map: X = red_channel;
733 Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
735 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
737 if (destination_image == (Image *) NULL)
740 Determine the horizontal and vertical maximim blur.
742 SetGeometryInfo(&geometry_info);
744 value=GetImageArtifact(composite_image,"compose:args");
745 if (value != (char *) NULL)
746 flags=ParseGeometry(value,&geometry_info);
747 if ((flags & WidthValue) == 0 )
749 destination_image=DestroyImage(destination_image);
752 width=geometry_info.rho;
753 height=geometry_info.sigma;
754 blur.x1=geometry_info.rho;
757 blur.y2=geometry_info.sigma;
760 if ((flags & HeightValue) == 0)
762 if ((flags & XValue) != 0 )
767 angle=DegreesToRadians(geometry_info.xi);
768 blur.x1=width*cos(angle);
769 blur.x2=width*sin(angle);
770 blur.y1=(-height*sin(angle));
771 blur.y2=height*cos(angle);
773 if ((flags & YValue) != 0 )
775 angle_start=DegreesToRadians(geometry_info.xi);
776 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
779 Blur Image by resampling.
781 resample_filter=AcquireResampleFilter(image,exception);
782 SetResampleFilter(resample_filter,CubicFilter,2.0);
783 destination_view=AcquireCacheView(destination_image);
784 composite_view=AcquireCacheView(composite_image);
785 for (y=0; y < (ssize_t) composite_image->rows; y++)
790 register const Quantum
799 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
801 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
803 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
804 destination_image->columns,1,exception);
805 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
807 for (x=0; x < (ssize_t) composite_image->columns; x++)
809 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
811 p+=GetPixelChannels(composite_image);
814 if (fabs(angle_range) > MagickEpsilon)
819 angle=angle_start+angle_range*QuantumScale*
820 GetPixelBlue(composite_image,p);
821 blur.x1=width*cos(angle);
822 blur.x2=width*sin(angle);
823 blur.y1=(-height*sin(angle));
824 blur.y2=height*cos(angle);
826 ScaleResampleFilter(resample_filter,blur.x1*QuantumScale*
827 GetPixelRed(composite_image,p),blur.y1*QuantumScale*
828 GetPixelGreen(composite_image,p),blur.x2*QuantumScale*
829 GetPixelRed(composite_image,p),blur.y2*QuantumScale*
830 GetPixelGreen(composite_image,p));
831 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
832 (double) y_offset+y,&pixel);
833 SetPixelInfoPixel(destination_image,&pixel,q);
834 p+=GetPixelChannels(composite_image);
835 q+=GetPixelChannels(destination_image);
837 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
838 if (sync == MagickFalse)
841 resample_filter=DestroyResampleFilter(resample_filter);
842 composite_view=DestroyCacheView(composite_view);
843 destination_view=DestroyCacheView(destination_view);
844 composite_image=destination_image;
847 case DisplaceCompositeOp:
848 case DistortCompositeOp:
867 Displace/Distort based on overlay gradient map:
868 X = red_channel; Y = green_channel;
869 compose:args = x_scale[,y_scale[,center.x,center.y]]
871 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
873 if (destination_image == (Image *) NULL)
875 SetGeometryInfo(&geometry_info);
877 value=GetImageArtifact(composite_image,"compose:args");
878 if (value != (char *) NULL)
879 flags=ParseGeometry(value,&geometry_info);
880 if ((flags & (WidthValue|HeightValue)) == 0 )
882 if ((flags & AspectValue) == 0)
884 horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
886 vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
890 horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
891 vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
896 horizontal_scale=geometry_info.rho;
897 vertical_scale=geometry_info.sigma;
898 if ((flags & PercentValue) != 0)
900 if ((flags & AspectValue) == 0)
902 horizontal_scale*=(composite_image->columns-1.0)/200.0;
903 vertical_scale*=(composite_image->rows-1.0)/200.0;
907 horizontal_scale*=(image->columns-1.0)/200.0;
908 vertical_scale*=(image->rows-1.0)/200.0;
911 if ((flags & HeightValue) == 0)
912 vertical_scale=horizontal_scale;
915 Determine fixed center point for absolute distortion map
917 Displace offset relative to a fixed absolute point
918 Select that point according to +X+Y user inputs.
919 default = center of overlay image
920 arg flag '!' = locations/percentage relative to background image
922 center.x=(MagickRealType) x_offset;
923 center.y=(MagickRealType) y_offset;
924 if (compose == DistortCompositeOp)
926 if ((flags & XValue) == 0)
927 if ((flags & AspectValue) == 0)
928 center.x=(MagickRealType) x_offset+(composite_image->columns-1)/
931 center.x=((MagickRealType) image->columns-1)/2.0;
933 if ((flags & AspectValue) == 0)
934 center.x=(MagickRealType) x_offset+geometry_info.xi;
936 center.x=geometry_info.xi;
937 if ((flags & YValue) == 0)
938 if ((flags & AspectValue) == 0)
939 center.y=(MagickRealType) y_offset+(composite_image->rows-1)/2.0;
941 center.y=((MagickRealType) image->rows-1)/2.0;
943 if ((flags & AspectValue) == 0)
944 center.y=(MagickRealType) y_offset+geometry_info.psi;
946 center.y=geometry_info.psi;
949 Shift the pixel offset point as defined by the provided,
950 displacement/distortion map. -- Like a lens...
952 GetPixelInfo(image,&pixel);
953 image_view=AcquireCacheView(image);
954 destination_view=AcquireCacheView(destination_image);
955 composite_view=AcquireCacheView(composite_image);
956 for (y=0; y < (ssize_t) composite_image->rows; y++)
961 register const Quantum
970 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
972 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
974 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
975 destination_image->columns,1,exception);
976 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
978 for (x=0; x < (ssize_t) composite_image->columns; x++)
980 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
982 p+=GetPixelChannels(composite_image);
988 offset.x=(horizontal_scale*(GetPixelRed(composite_image,p)-
989 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
990 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
992 offset.y=(vertical_scale*(GetPixelGreen(composite_image,p)-
993 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
994 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
996 (void) InterpolatePixelInfo(image,image_view,
997 UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1000 Mask with the 'invalid pixel mask' in alpha channel.
1002 pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
1003 pixel.alpha)*(1.0-QuantumScale*
1004 GetPixelAlpha(composite_image,p)));
1005 SetPixelInfoPixel(destination_image,&pixel,q);
1006 p+=GetPixelChannels(composite_image);
1007 q+=GetPixelChannels(destination_image);
1009 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1010 if (sync == MagickFalse)
1013 destination_view=DestroyCacheView(destination_view);
1014 composite_view=DestroyCacheView(composite_view);
1015 image_view=DestroyCacheView(image_view);
1016 composite_image=destination_image;
1019 case DissolveCompositeOp:
1022 Geometry arguments to dissolve factors.
1024 value=GetImageArtifact(composite_image,"compose:args");
1025 if (value != (char *) NULL)
1027 flags=ParseGeometry(value,&geometry_info);
1028 source_dissolve=geometry_info.rho/100.0;
1029 destination_dissolve=1.0;
1030 if ((source_dissolve-MagickEpsilon) < 0.0)
1031 source_dissolve=0.0;
1032 if ((source_dissolve+MagickEpsilon) > 1.0)
1034 destination_dissolve=2.0-source_dissolve;
1035 source_dissolve=1.0;
1037 if ((flags & SigmaValue) != 0)
1038 destination_dissolve=geometry_info.sigma/100.0;
1039 if ((destination_dissolve-MagickEpsilon) < 0.0)
1040 destination_dissolve=0.0;
1041 modify_outside_overlay=MagickTrue;
1042 if ((destination_dissolve+MagickEpsilon) > 1.0 )
1044 destination_dissolve=1.0;
1045 modify_outside_overlay=MagickFalse;
1050 case BlendCompositeOp:
1052 value=GetImageArtifact(composite_image,"compose:args");
1053 if (value != (char *) NULL)
1055 flags=ParseGeometry(value,&geometry_info);
1056 source_dissolve=geometry_info.rho/100.0;
1057 destination_dissolve=1.0-source_dissolve;
1058 if ((flags & SigmaValue) != 0)
1059 destination_dissolve=geometry_info.sigma/100.0;
1060 modify_outside_overlay=MagickTrue;
1061 if ((destination_dissolve+MagickEpsilon) > 1.0)
1062 modify_outside_overlay=MagickFalse;
1066 case MathematicsCompositeOp:
1069 Just collect the values from "compose:args", setting.
1070 Unused values are set to zero automagically.
1072 Arguments are normally a comma separated list, so this probably should
1073 be changed to some 'general comma list' parser, (with a minimum
1076 SetGeometryInfo(&geometry_info);
1077 value=GetImageArtifact(composite_image,"compose:args");
1078 if (value != (char *) NULL)
1079 (void) ParseGeometry(value,&geometry_info);
1082 case ModulateCompositeOp:
1085 Determine the brightness and saturation scale.
1087 value=GetImageArtifact(composite_image,"compose:args");
1088 if (value != (char *) NULL)
1090 flags=ParseGeometry(value,&geometry_info);
1091 percent_brightness=geometry_info.rho;
1092 if ((flags & SigmaValue) != 0)
1093 percent_saturation=geometry_info.sigma;
1097 case ThresholdCompositeOp:
1100 Determine the amount and threshold.
1102 value=GetImageArtifact(composite_image,"compose:args");
1103 if (value != (char *) NULL)
1105 flags=ParseGeometry(value,&geometry_info);
1106 amount=geometry_info.rho;
1107 threshold=geometry_info.sigma;
1108 if ((flags & SigmaValue) == 0)
1111 threshold*=QuantumRange;
1117 value=GetImageArtifact(composite_image,"compose:outside-overlay");
1118 if (value != (const char *) NULL)
1119 modify_outside_overlay=IsMagickTrue(value);
1125 midpoint=((MagickRealType) QuantumRange+1.0)/2;
1126 image_view=AcquireCacheView(image);
1127 composite_view=AcquireCacheView(composite_image);
1128 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1129 #pragma omp parallel for schedule(static,4) shared(progress,status)
1131 for (y=0; y < (ssize_t) image->rows; y++)
1144 register const Quantum
1153 if (status == MagickFalse)
1155 if (modify_outside_overlay == MagickFalse)
1159 if ((y-y_offset) >= (ssize_t) composite_image->rows)
1163 If pixels is NULL, y is outside overlay region.
1165 pixels=(Quantum *) NULL;
1167 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
1169 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
1170 composite_image->columns,1,exception);
1171 if (p == (const Quantum *) NULL)
1178 p-=x_offset*GetPixelChannels(composite_image);
1180 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1181 if (q == (Quantum *) NULL)
1189 for (x=0; x < (ssize_t) image->columns; x++)
1204 if (modify_outside_overlay == MagickFalse)
1208 q+=GetPixelChannels(image);
1211 if ((x-x_offset) >= (ssize_t) composite_image->columns)
1214 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1215 ((x-x_offset) >= (ssize_t) composite_image->columns))
1218 source[MaxPixelChannels];
1223 Dc: destination color.
1225 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
1227 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1239 channel=GetPixelChannelMapChannel(image,i);
1240 traits=GetPixelChannelMapTraits(image,channel);
1241 composite_traits=GetPixelChannelMapTraits(composite_image,
1243 if ((traits == UndefinedPixelTrait) ||
1244 (composite_traits == UndefinedPixelTrait))
1248 case ChangeMaskCompositeOp:
1249 case CopyAlphaCompositeOp:
1250 case DstAtopCompositeOp:
1251 case DstInCompositeOp:
1253 case OutCompositeOp:
1254 case SrcInCompositeOp:
1255 case SrcOutCompositeOp:
1257 pixel=(MagickRealType) q[i];
1258 if (channel == AlphaPixelChannel)
1259 pixel=(MagickRealType) TransparentAlpha;
1262 case ClearCompositeOp:
1263 case CopyCompositeOp:
1264 case ReplaceCompositeOp:
1265 case SrcCompositeOp:
1267 if (channel == AlphaPixelChannel)
1269 pixel=(MagickRealType) TransparentAlpha;
1275 case DissolveCompositeOp:
1277 if (channel == AlphaPixelChannel)
1279 pixel=destination_dissolve*GetPixelAlpha(composite_image,
1283 pixel=(MagickRealType) source[channel];
1288 pixel=(MagickRealType) source[channel];
1292 q[i]=ClampToQuantum(pixel);
1294 q+=GetPixelChannels(image);
1298 Authentic composite:
1299 Sa: normalized source alpha.
1300 Da: normalized destination alpha.
1302 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
1303 Da=QuantumScale*GetPixelAlpha(image,q);
1306 case BlendCompositeOp:
1308 alpha=RoundToUnity(source_dissolve*Sa+destination_dissolve*Da);
1311 case BumpmapCompositeOp:
1313 alpha=GetPixelIntensity(composite_image,p)*Sa;
1316 case ColorBurnCompositeOp:
1317 case ColorDodgeCompositeOp:
1318 case DifferenceCompositeOp:
1319 case DivideDstCompositeOp:
1320 case DivideSrcCompositeOp:
1321 case ExclusionCompositeOp:
1322 case HardLightCompositeOp:
1323 case LinearBurnCompositeOp:
1324 case LinearDodgeCompositeOp:
1325 case LinearLightCompositeOp:
1326 case LuminizeCompositeOp:
1327 case MathematicsCompositeOp:
1328 case MinusDstCompositeOp:
1329 case MinusSrcCompositeOp:
1330 case ModulusAddCompositeOp:
1331 case ModulusSubtractCompositeOp:
1332 case MultiplyCompositeOp:
1333 case OverlayCompositeOp:
1334 case PegtopLightCompositeOp:
1335 case PinLightCompositeOp:
1336 case ScreenCompositeOp:
1337 case SoftLightCompositeOp:
1338 case VividLightCompositeOp:
1340 alpha=RoundToUnity(Sa+Da-Sa*Da);
1343 case DarkenCompositeOp:
1344 case DstAtopCompositeOp:
1345 case DstInCompositeOp:
1347 case LightenCompositeOp:
1348 case SrcInCompositeOp:
1353 case DissolveCompositeOp:
1355 alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
1356 Sa+destination_dissolve*Da;
1359 case DstOverCompositeOp:
1361 alpha=Da*(-Sa)+Da+Sa;
1364 case DstOutCompositeOp:
1369 case OutCompositeOp:
1370 case SrcOutCompositeOp:
1375 case OverCompositeOp:
1376 case SrcOverCompositeOp:
1378 alpha=Sa*(-Da)+Sa+Da;
1381 case PlusCompositeOp:
1383 alpha=RoundToUnity(Sa+Da);
1386 case XorCompositeOp:
1388 alpha=Sa+Da-2.0*Sa*Da;
1397 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1409 channel=GetPixelChannelMapChannel(image,i);
1410 traits=GetPixelChannelMapTraits(image,channel);
1411 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
1412 if ((traits == UndefinedPixelTrait) ||
1413 (composite_traits == UndefinedPixelTrait))
1417 Sca: source normalized color multiplied by alpha.
1418 Dc: destination color.
1419 Dca: normalized destination color multiplied by alpha.
1421 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
1422 Sca=QuantumScale*Sa*Sc;
1423 Dc=(MagickRealType) q[i];
1424 Dca=QuantumScale*Da*Dc;
1425 if ((traits & CopyPixelTrait) != 0)
1427 if (channel != AlphaPixelChannel)
1432 q[i]=ClampToQuantum(Sc);
1440 case AtopCompositeOp:
1441 case SrcAtopCompositeOp:
1442 case DstCompositeOp:
1445 pixel=QuantumRange*Da;
1448 case ChangeMaskCompositeOp:
1453 equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
1454 if ((Da > ((MagickRealType) QuantumRange/2.0)) ||
1455 (equivalent != MagickFalse))
1457 pixel=(MagickRealType) TransparentAlpha;
1460 pixel=(MagickRealType) OpaqueAlpha;
1463 case CopyCompositeOp:
1464 case DstAtopCompositeOp:
1465 case ReplaceCompositeOp:
1466 case SrcCompositeOp:
1468 pixel=QuantumRange*Sa;
1471 case DarkenIntensityCompositeOp:
1473 pixel=Sa*GetPixelIntensity(composite_image,p) <
1474 Da*GetPixelIntensity(image,q) ? Sa : Da;
1477 case LightenIntensityCompositeOp:
1479 pixel=Sa*GetPixelIntensity(composite_image,p) >
1480 Da*GetPixelIntensity(image,q) ? Sa : Da;
1485 pixel=QuantumRange*alpha;
1489 q[i]=ClampToQuantum(pixel);
1493 Porter-Duff compositions.
1497 case DarkenCompositeOp:
1498 case LightenCompositeOp:
1500 gamma=1.0-QuantumScale*Dc;
1506 gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
1509 case AtopCompositeOp:
1510 case SrcAtopCompositeOp:
1512 pixel=Sc*Sa+Dc*(1.0-Sa);
1515 case BlendCompositeOp:
1517 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1520 case BlurCompositeOp:
1521 case DisplaceCompositeOp:
1522 case DistortCompositeOp:
1523 case CopyCompositeOp:
1524 case ReplaceCompositeOp:
1525 case SrcCompositeOp:
1530 case BumpmapCompositeOp:
1532 if ((QuantumRange*Sa) == TransparentAlpha)
1537 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1540 case ColorBurnCompositeOp:
1543 Refer to the March 2009 SVG specification.
1545 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1547 pixel=gamma*(Sa*Da+Dca*(1.0-Sa));
1550 if (Sca < MagickEpsilon)
1552 pixel=gamma*(Dca*(1.0-Sa));
1555 pixel=gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+Sca*(1.0-Da)+
1559 case ColorDodgeCompositeOp:
1561 if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1563 pixel=gamma*QuantumRange*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1566 if (fabs(Sca-Sa) < MagickEpsilon)
1568 pixel=gamma*QuantumRange*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1571 pixel=gamma*QuantumRange*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1575 case ColorizeCompositeOp:
1577 if (GetPixelAlpha(composite_image,p) == TransparentAlpha)
1582 if (GetPixelAlpha(image,q) == TransparentAlpha)
1587 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1588 GetPixelBlue(image,q),&hue,&saturation,&brightness);
1589 CompositeHSB(GetPixelRed(composite_image,p),
1590 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1591 &hue,&saturation,&sans);
1592 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1595 case RedPixelChannel: pixel=red; break;
1596 case GreenPixelChannel: pixel=green; break;
1597 case BluePixelChannel: pixel=blue; break;
1598 case AlphaPixelChannel:
1602 pixel=(MagickRealType) GetPixelAlpha(composite_image,p);
1605 default: pixel=Dc; break;
1609 case DarkenCompositeOp:
1612 Darken is equivalent to a 'Minimum' method
1613 OR a greyscale version of a binary 'Or'
1614 OR the 'Intersection' of pixel sets.
1618 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1621 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1624 case CopyAlphaCompositeOp:
1626 if (channel == AlphaPixelChannel)
1628 if (composite_image->matte != MagickFalse)
1629 pixel=(MagickRealType) GetPixelAlpha(composite_image,p);
1631 pixel=(MagickRealType) GetPixelIntensity(composite_image,p);
1637 case CopyBlackCompositeOp:
1639 pixel=(MagickRealType) GetPixelBlack(composite_image,p);
1642 case CopyBlueCompositeOp:
1643 case CopyYellowCompositeOp:
1645 pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1648 case CopyGreenCompositeOp:
1649 case CopyMagentaCompositeOp:
1651 pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1654 case CopyRedCompositeOp:
1655 case CopyCyanCompositeOp:
1657 pixel=(MagickRealType) GetPixelRed(composite_image,p);
1660 case DarkenIntensityCompositeOp:
1662 pixel=Sa*GetPixelIntensity(composite_image,p) <
1663 Da*GetPixelIntensity(image,q) ? Sc : Dc;
1666 case DifferenceCompositeOp:
1668 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1671 case DissolveCompositeOp:
1673 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1674 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1677 case DivideDstCompositeOp:
1679 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1681 pixel=gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1684 if (fabs(Dca) < MagickEpsilon)
1686 pixel=gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1689 pixel=gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1692 case DivideSrcCompositeOp:
1694 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1696 pixel=gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1699 if (fabs(Sca) < MagickEpsilon)
1701 pixel=gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1704 pixel=gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1707 case DstAtopCompositeOp:
1709 pixel=Dc*Da+Sc*(1.0-Da);
1712 case DstCompositeOp:
1718 case DstInCompositeOp:
1720 pixel=gamma*(Sa*Dc*Sa);
1723 case DstOutCompositeOp:
1725 pixel=gamma*(Da*Dc*(1.0-Sa));
1728 case DstOverCompositeOp:
1730 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1733 case ExclusionCompositeOp:
1735 pixel=gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1738 case HardLightCompositeOp:
1742 pixel=gamma*QuantumRange*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1746 pixel=gamma*QuantumRange*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1750 case HueCompositeOp:
1752 if (GetPixelAlpha(composite_image,p) == TransparentAlpha)
1757 if (GetPixelAlpha(image,q) == TransparentAlpha)
1762 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1763 GetPixelBlue(image,q),&hue,&saturation,&brightness);
1764 CompositeHSB(GetPixelRed(composite_image,p),
1765 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1767 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1770 case RedPixelChannel: pixel=red; break;
1771 case GreenPixelChannel: pixel=green; break;
1772 case BluePixelChannel: pixel=blue; break;
1773 case AlphaPixelChannel:
1777 pixel=(MagickRealType) GetPixelAlpha(composite_image,p);
1780 default: pixel=Dc; break;
1785 case SrcInCompositeOp:
1787 pixel=gamma*(Da*Sc*Da);
1790 case LightenIntensityCompositeOp:
1793 Lighten is equivalent to a 'Maximum' method
1794 OR a greyscale version of a binary 'And'
1795 OR the 'Union' of pixel sets.
1797 pixel=Sa*GetPixelIntensity(composite_image,p) >
1798 Da*GetPixelIntensity(image,q) ? Sc : Dc;
1801 case LinearBurnCompositeOp:
1804 LinearBurn: as defined by Abode Photoshop, according to
1805 http://www.simplefilter.de/en/basics/mixmods.html is:
1807 f(Sc,Dc) = Sc + Dc - 1
1809 pixel=gamma*(Sca+Dca-Sa*Da);
1812 case LinearDodgeCompositeOp:
1814 pixel=gamma*(Sa*Sc+Da*Dc);
1817 case LinearLightCompositeOp:
1820 LinearLight: as defined by Abode Photoshop, according to
1821 http://www.simplefilter.de/en/basics/mixmods.html is:
1823 f(Sc,Dc) = Dc + 2*Sc - 1
1825 pixel=gamma*((Sca-Sa)*Da+Sca+Dca);
1828 case LightenCompositeOp:
1832 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1835 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1838 case LuminizeCompositeOp:
1840 if (GetPixelAlpha(composite_image,p) == TransparentAlpha)
1845 if (GetPixelAlpha(image,q) == TransparentAlpha)
1850 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1851 GetPixelBlue(image,q),&hue,&saturation,&brightness);
1852 CompositeHSB(GetPixelRed(composite_image,p),
1853 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1854 &sans,&sans,&brightness);
1855 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1858 case RedPixelChannel: pixel=red; break;
1859 case GreenPixelChannel: pixel=green; break;
1860 case BluePixelChannel: pixel=blue; break;
1861 case AlphaPixelChannel:
1865 pixel=(MagickRealType) GetPixelAlpha(composite_image,p);
1868 default: pixel=Dc; break;
1872 case MathematicsCompositeOp:
1875 'Mathematics' a free form user control mathematical composition
1878 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
1880 Where the arguments A,B,C,D are (currently) passed to composite
1881 as a command separated 'geometry' string in "compose:args" image
1884 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
1886 Applying the SVG transparency formula (see above), we get...
1888 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
1890 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
1893 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
1894 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
1895 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
1898 case MinusDstCompositeOp:
1900 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
1903 case MinusSrcCompositeOp:
1906 Minus source from destination.
1910 pixel=gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
1913 case ModulateCompositeOp:
1918 if (GetPixelAlpha(composite_image,p) == TransparentAlpha)
1923 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
1929 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1930 GetPixelBlue(image,q),&hue,&saturation,&brightness);
1931 brightness+=(0.01*percent_brightness*offset)/midpoint;
1932 saturation*=0.01*percent_saturation;
1933 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1936 case RedPixelChannel: pixel=red; break;
1937 case GreenPixelChannel: pixel=green; break;
1938 case BluePixelChannel: pixel=blue; break;
1939 default: pixel=Dc; break;
1943 case ModulusAddCompositeOp:
1946 if (pixel > QuantumRange)
1947 pixel-=(QuantumRange+1.0);
1948 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
1951 case ModulusSubtractCompositeOp:
1955 pixel+=(QuantumRange+1.0);
1956 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
1959 case MultiplyCompositeOp:
1961 pixel=gamma*QuantumRange*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1964 case OutCompositeOp:
1965 case SrcOutCompositeOp:
1967 pixel=gamma*(Sa*Sc*(1.0-Da));
1970 case OverCompositeOp:
1971 case SrcOverCompositeOp:
1973 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1976 case OverlayCompositeOp:
1979 pixel=gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1980 pixel=gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+Sca*(1.0-Da));
1983 case PegtopLightCompositeOp:
1986 PegTop: A Soft-Light alternative: A continuous version of the
1987 Softlight function, producing very similar results.
1989 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
1991 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
1993 if (fabs(Da) < MagickEpsilon)
1998 pixel=gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-Da)+Dca*
2002 case PinLightCompositeOp:
2005 PinLight: A Photoshop 7 composition method
2006 http://www.simplefilter.de/en/basics/mixmods.html
2008 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2010 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2012 pixel=gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2015 if ((Dca*Sa) > (2.0*Sca*Da))
2017 pixel=gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2020 pixel=gamma*(Sca*(1.0-Da)+Dca);
2023 case PlusCompositeOp:
2025 pixel=gamma*(Sa*Sc+Da*Dc);
2028 case SaturateCompositeOp:
2030 if (GetPixelAlpha(composite_image,p) == TransparentAlpha)
2035 if (GetPixelAlpha(image,q) == TransparentAlpha)
2040 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
2041 GetPixelBlue(image,q),&hue,&saturation,&brightness);
2042 CompositeHSB(GetPixelRed(composite_image,p),
2043 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
2044 &sans,&saturation,&sans);
2045 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
2048 case RedPixelChannel: pixel=red; break;
2049 case GreenPixelChannel: pixel=green; break;
2050 case BluePixelChannel: pixel=blue; break;
2051 case AlphaPixelChannel:
2055 pixel=(MagickRealType) GetPixelAlpha(composite_image,p);
2058 default: pixel=Dc; break;
2062 case ScreenCompositeOp:
2065 Screen: a negated multiply:
2067 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2069 pixel=gamma*QuantumRange*(Sca+Dca-Sca*Dca);
2072 case SoftLightCompositeOp:
2075 Refer to the March 2009 SVG specification.
2079 pixel=gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+Sca*(1.0-Da)+
2083 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2085 pixel=gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*(4.0*(Dca/Da)+
2086 1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2089 pixel=gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-(Dca/Da))+
2090 Sca*(1.0-Da)+Dca*(1.0-Sa));
2093 case ThresholdCompositeOp:
2099 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2104 pixel=gamma*(Dc+delta*amount);
2107 case VividLightCompositeOp:
2110 VividLight: A Photoshop 7 composition method. See
2111 http://www.simplefilter.de/en/basics/mixmods.html.
2113 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2115 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2117 pixel=gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2120 if ((2.0*Sca) <= Sa)
2122 pixel=gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*(1.0-Da)+Dca*
2126 pixel=gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2129 case XorCompositeOp:
2131 pixel=gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2140 q[i]=ClampToQuantum(pixel);
2142 p+=GetPixelChannels(composite_image);
2143 channels=GetPixelChannels(composite_image);
2144 if (p >= (pixels+channels*composite_image->columns))
2146 q+=GetPixelChannels(image);
2148 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2150 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2155 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2156 #pragma omp critical (MagickCore_CompositeImage)
2158 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2160 if (proceed == MagickFalse)
2164 composite_view=DestroyCacheView(composite_view);
2165 image_view=DestroyCacheView(image_view);
2166 if (destination_image != (Image * ) NULL)
2167 destination_image=DestroyImage(destination_image);
2172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2176 % T e x t u r e I m a g e %
2180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2182 % TextureImage() repeatedly tiles the texture image across and down the image
2185 % The format of the TextureImage method is:
2187 % MagickBooleanType TextureImage(Image *image,const Image *texture_image,
2188 % ExceptionInfo *exception)
2190 % A description of each parameter follows:
2192 % o image: the image.
2194 % o texture_image: This image is the texture to layer on the background.
2197 MagickExport MagickBooleanType TextureImage(Image *image,
2198 const Image *texture_image,ExceptionInfo *exception)
2200 #define TextureImageTag "Texture/Image"
2212 assert(image != (Image *) NULL);
2213 if (image->debug != MagickFalse)
2214 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2215 assert(image->signature == MagickSignature);
2216 if (texture_image == (const Image *) NULL)
2217 return(MagickFalse);
2218 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod);
2219 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2220 return(MagickFalse);
2222 if ((image->compose != CopyCompositeOp) &&
2223 ((image->compose != OverCompositeOp) || (image->matte != MagickFalse) ||
2224 (texture_image->matte != MagickFalse)))
2227 Tile texture onto the image background.
2229 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2230 #pragma omp parallel for schedule(static,4) shared(status) omp_throttle(1)
2232 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2237 if (status == MagickFalse)
2239 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2244 thread_status=CompositeImage(image,image->compose,texture_image,x+
2245 texture_image->tile_offset.x,y+texture_image->tile_offset.y,
2247 if (thread_status == MagickFalse)
2249 status=thread_status;
2253 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2258 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2259 #pragma omp critical (MagickCore_TextureImage)
2261 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2263 if (proceed == MagickFalse)
2267 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2268 image->rows,image->rows);
2272 Tile texture onto the image background (optimized).
2275 image_view=AcquireCacheView(image);
2276 texture_view=AcquireCacheView(texture_image);
2277 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2278 #pragma omp parallel for schedule(static,4) shared(status) omp_throttle(1)
2280 for (y=0; y < (ssize_t) image->rows; y++)
2285 register const Quantum
2298 if (status == MagickFalse)
2300 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2301 (y+texture_image->tile_offset.y) % texture_image->rows,
2302 texture_image->columns,1,exception);
2303 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2304 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2309 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2315 width=texture_image->columns;
2316 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2317 width=image->columns-x;
2318 for (j=0; j < (ssize_t) width; j++)
2323 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2332 channel=GetPixelChannelMapChannel(texture_image,i);
2333 texture_traits=GetPixelChannelMapTraits(texture_image,channel);
2334 traits=GetPixelChannelMapTraits(image,channel);
2335 if ((traits == UndefinedPixelTrait) ||
2336 (texture_traits == UndefinedPixelTrait))
2338 SetPixelChannel(image,channel,p[i],q);
2340 p+=GetPixelChannels(texture_image);
2341 q+=GetPixelChannels(image);
2344 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2345 if (sync == MagickFalse)
2347 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2352 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2353 #pragma omp critical (MagickCore_TextureImage)
2355 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2357 if (proceed == MagickFalse)
2361 texture_view=DestroyCacheView(texture_view);
2362 image_view=DestroyCacheView(image_view);