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:
716 Modify destination outside the overlaid region and require an alpha
717 channel to exist, to add transparency.
719 if (image->matte == MagickFalse)
720 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
721 modify_outside_overlay=MagickTrue;
724 case BlurCompositeOp:
746 Blur Image dictated by an overlay gradient map: X = red_channel;
747 Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
749 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
751 if (destination_image == (Image *) NULL)
754 Determine the horizontal and vertical maximim blur.
756 SetGeometryInfo(&geometry_info);
758 value=GetImageArtifact(composite_image,"compose:args");
759 if (value != (char *) NULL)
760 flags=ParseGeometry(value,&geometry_info);
761 if ((flags & WidthValue) == 0 )
763 destination_image=DestroyImage(destination_image);
766 width=geometry_info.rho;
767 height=geometry_info.sigma;
768 blur.x1=geometry_info.rho;
771 blur.y2=geometry_info.sigma;
774 if ((flags & HeightValue) == 0)
776 if ((flags & XValue) != 0 )
781 angle=DegreesToRadians(geometry_info.xi);
782 blur.x1=width*cos(angle);
783 blur.x2=width*sin(angle);
784 blur.y1=(-height*sin(angle));
785 blur.y2=height*cos(angle);
787 if ((flags & YValue) != 0 )
789 angle_start=DegreesToRadians(geometry_info.xi);
790 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
793 Blur Image by resampling.
795 resample_filter=AcquireResampleFilter(image,exception);
796 SetResampleFilter(resample_filter,CubicFilter,2.0);
797 destination_view=AcquireCacheView(destination_image);
798 composite_view=AcquireCacheView(composite_image);
799 for (y=0; y < (ssize_t) composite_image->rows; y++)
804 register const Quantum
813 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
815 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
817 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
818 destination_image->columns,1,exception);
819 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
821 for (x=0; x < (ssize_t) composite_image->columns; x++)
823 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
825 p+=GetPixelChannels(composite_image);
828 if (fabs(angle_range) > MagickEpsilon)
833 angle=angle_start+angle_range*QuantumScale*
834 GetPixelBlue(composite_image,p);
835 blur.x1=width*cos(angle);
836 blur.x2=width*sin(angle);
837 blur.y1=(-height*sin(angle));
838 blur.y2=height*cos(angle);
840 ScaleResampleFilter(resample_filter,blur.x1*QuantumScale*
841 GetPixelRed(composite_image,p),blur.y1*QuantumScale*
842 GetPixelGreen(composite_image,p),blur.x2*QuantumScale*
843 GetPixelRed(composite_image,p),blur.y2*QuantumScale*
844 GetPixelGreen(composite_image,p));
845 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
846 (double) y_offset+y,&pixel);
847 SetPixelInfoPixel(destination_image,&pixel,q);
848 p+=GetPixelChannels(composite_image);
849 q+=GetPixelChannels(destination_image);
851 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
852 if (sync == MagickFalse)
855 resample_filter=DestroyResampleFilter(resample_filter);
856 composite_view=DestroyCacheView(composite_view);
857 destination_view=DestroyCacheView(destination_view);
858 composite_image=destination_image;
861 case DisplaceCompositeOp:
862 case DistortCompositeOp:
881 Displace/Distort based on overlay gradient map:
882 X = red_channel; Y = green_channel;
883 compose:args = x_scale[,y_scale[,center.x,center.y]]
885 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
887 if (destination_image == (Image *) NULL)
889 SetGeometryInfo(&geometry_info);
891 value=GetImageArtifact(composite_image,"compose:args");
892 if (value != (char *) NULL)
893 flags=ParseGeometry(value,&geometry_info);
894 if ((flags & (WidthValue|HeightValue)) == 0 )
896 if ((flags & AspectValue) == 0)
898 horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
900 vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
904 horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
905 vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
910 horizontal_scale=geometry_info.rho;
911 vertical_scale=geometry_info.sigma;
912 if ((flags & PercentValue) != 0)
914 if ((flags & AspectValue) == 0)
916 horizontal_scale*=(composite_image->columns-1.0)/200.0;
917 vertical_scale*=(composite_image->rows-1.0)/200.0;
921 horizontal_scale*=(image->columns-1.0)/200.0;
922 vertical_scale*=(image->rows-1.0)/200.0;
925 if ((flags & HeightValue) == 0)
926 vertical_scale=horizontal_scale;
929 Determine fixed center point for absolute distortion map
931 Displace offset relative to a fixed absolute point
932 Select that point according to +X+Y user inputs.
933 default = center of overlay image
934 arg flag '!' = locations/percentage relative to background image
936 center.x=(MagickRealType) x_offset;
937 center.y=(MagickRealType) y_offset;
938 if (compose == DistortCompositeOp)
940 if ((flags & XValue) == 0)
941 if ((flags & AspectValue) == 0)
942 center.x=(MagickRealType) x_offset+(composite_image->columns-1)/
945 center.x=((MagickRealType) image->columns-1)/2.0;
947 if ((flags & AspectValue) == 0)
948 center.x=(MagickRealType) x_offset+geometry_info.xi;
950 center.x=geometry_info.xi;
951 if ((flags & YValue) == 0)
952 if ((flags & AspectValue) == 0)
953 center.y=(MagickRealType) y_offset+(composite_image->rows-1)/2.0;
955 center.y=((MagickRealType) image->rows-1)/2.0;
957 if ((flags & AspectValue) == 0)
958 center.y=(MagickRealType) y_offset+geometry_info.psi;
960 center.y=geometry_info.psi;
963 Shift the pixel offset point as defined by the provided,
964 displacement/distortion map. -- Like a lens...
966 GetPixelInfo(image,&pixel);
967 image_view=AcquireCacheView(image);
968 destination_view=AcquireCacheView(destination_image);
969 composite_view=AcquireCacheView(composite_image);
970 for (y=0; y < (ssize_t) composite_image->rows; y++)
975 register const Quantum
984 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
986 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
988 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
989 destination_image->columns,1,exception);
990 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
992 for (x=0; x < (ssize_t) composite_image->columns; x++)
994 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
996 p+=GetPixelChannels(composite_image);
1000 Displace the offset.
1002 offset.x=(horizontal_scale*(GetPixelRed(composite_image,p)-
1003 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1004 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
1006 offset.y=(vertical_scale*(GetPixelGreen(composite_image,p)-
1007 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1008 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
1010 (void) InterpolatePixelInfo(image,image_view,
1011 UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1014 Mask with the 'invalid pixel mask' in alpha channel.
1016 pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
1017 pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
1018 SetPixelInfoPixel(destination_image,&pixel,q);
1019 p+=GetPixelChannels(composite_image);
1020 q+=GetPixelChannels(destination_image);
1022 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1023 if (sync == MagickFalse)
1026 destination_view=DestroyCacheView(destination_view);
1027 composite_view=DestroyCacheView(composite_view);
1028 image_view=DestroyCacheView(image_view);
1029 composite_image=destination_image;
1032 case DissolveCompositeOp:
1035 Geometry arguments to dissolve factors.
1037 value=GetImageArtifact(composite_image,"compose:args");
1038 if (value != (char *) NULL)
1040 flags=ParseGeometry(value,&geometry_info);
1041 source_dissolve=geometry_info.rho/100.0;
1042 destination_dissolve=1.0;
1043 if ((source_dissolve-MagickEpsilon) < 0.0)
1044 source_dissolve=0.0;
1045 if ((source_dissolve+MagickEpsilon) > 1.0)
1047 destination_dissolve=2.0-source_dissolve;
1048 source_dissolve=1.0;
1050 if ((flags & SigmaValue) != 0)
1051 destination_dissolve=geometry_info.sigma/100.0;
1052 if ((destination_dissolve-MagickEpsilon) < 0.0)
1053 destination_dissolve=0.0;
1054 modify_outside_overlay=MagickTrue;
1055 if ((destination_dissolve+MagickEpsilon) > 1.0 )
1057 destination_dissolve=1.0;
1058 modify_outside_overlay=MagickFalse;
1063 case BlendCompositeOp:
1065 value=GetImageArtifact(composite_image,"compose:args");
1066 if (value != (char *) NULL)
1068 flags=ParseGeometry(value,&geometry_info);
1069 source_dissolve=geometry_info.rho/100.0;
1070 destination_dissolve=1.0-source_dissolve;
1071 if ((flags & SigmaValue) != 0)
1072 destination_dissolve=geometry_info.sigma/100.0;
1073 modify_outside_overlay=MagickTrue;
1074 if ((destination_dissolve+MagickEpsilon) > 1.0)
1075 modify_outside_overlay=MagickFalse;
1079 case MathematicsCompositeOp:
1082 Just collect the values from "compose:args", setting.
1083 Unused values are set to zero automagically.
1085 Arguments are normally a comma separated list, so this probably should
1086 be changed to some 'general comma list' parser, (with a minimum
1089 SetGeometryInfo(&geometry_info);
1090 value=GetImageArtifact(composite_image,"compose:args");
1091 if (value != (char *) NULL)
1092 (void) ParseGeometry(value,&geometry_info);
1095 case ModulateCompositeOp:
1098 Determine the brightness and saturation scale.
1100 value=GetImageArtifact(composite_image,"compose:args");
1101 if (value != (char *) NULL)
1103 flags=ParseGeometry(value,&geometry_info);
1104 percent_brightness=geometry_info.rho;
1105 if ((flags & SigmaValue) != 0)
1106 percent_saturation=geometry_info.sigma;
1110 case ThresholdCompositeOp:
1113 Determine the amount and threshold.
1115 value=GetImageArtifact(composite_image,"compose:args");
1116 if (value != (char *) NULL)
1118 flags=ParseGeometry(value,&geometry_info);
1119 amount=geometry_info.rho;
1120 threshold=geometry_info.sigma;
1121 if ((flags & SigmaValue) == 0)
1124 threshold*=QuantumRange;
1130 value=GetImageArtifact(composite_image,"compose:outside-overlay");
1131 if (value != (const char *) NULL)
1132 modify_outside_overlay=IsMagickTrue(value);
1138 midpoint=((MagickRealType) QuantumRange+1.0)/2;
1139 image_view=AcquireCacheView(image);
1140 composite_view=AcquireCacheView(composite_image);
1141 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1142 #pragma omp parallel for schedule(static,4) shared(progress,status)
1144 for (y=0; y < (ssize_t) image->rows; y++)
1157 register const Quantum
1166 if (status == MagickFalse)
1168 if (modify_outside_overlay == MagickFalse)
1172 if ((y-y_offset) >= (ssize_t) composite_image->rows)
1176 If pixels is NULL, y is outside overlay region.
1178 pixels=(Quantum *) NULL;
1180 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
1182 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
1183 composite_image->columns,1,exception);
1184 if (p == (const Quantum *) NULL)
1191 p-=x_offset*GetPixelChannels(composite_image);
1193 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1194 if (q == (Quantum *) NULL)
1202 for (x=0; x < (ssize_t) image->columns; x++)
1217 if (modify_outside_overlay == MagickFalse)
1221 q+=GetPixelChannels(image);
1224 if ((x-x_offset) >= (ssize_t) composite_image->columns)
1227 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1228 ((x-x_offset) >= (ssize_t) composite_image->columns))
1231 source[MaxPixelChannels];
1236 Dc: destination color.
1238 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
1240 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1252 channel=GetPixelChannelMapChannel(image,i);
1253 traits=GetPixelChannelMapTraits(image,channel);
1254 composite_traits=GetPixelChannelMapTraits(composite_image,
1256 if ((traits == UndefinedPixelTrait) ||
1257 (composite_traits == UndefinedPixelTrait))
1261 case ChangeMaskCompositeOp:
1262 case CopyAlphaCompositeOp:
1263 case DstAtopCompositeOp:
1264 case DstInCompositeOp:
1266 case OutCompositeOp:
1267 case SrcInCompositeOp:
1268 case SrcOutCompositeOp:
1270 pixel=(MagickRealType) q[i];
1271 if (channel == AlphaPixelChannel)
1272 pixel=(MagickRealType) TransparentAlpha;
1275 case ClearCompositeOp:
1276 case CopyCompositeOp:
1277 case ReplaceCompositeOp:
1278 case SrcCompositeOp:
1280 if (channel == AlphaPixelChannel)
1282 pixel=(MagickRealType) TransparentAlpha;
1288 case BlendCompositeOp:
1289 case DissolveCompositeOp:
1291 if (channel == AlphaPixelChannel)
1293 pixel=destination_dissolve*GetPixelAlpha(composite_image,
1297 pixel=(MagickRealType) source[channel];
1302 pixel=(MagickRealType) source[channel];
1306 q[i]=ClampToQuantum(pixel);
1308 q+=GetPixelChannels(image);
1312 Authentic composite:
1313 Sa: normalized source alpha.
1314 Da: normalized destination alpha.
1316 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
1317 Da=QuantumScale*GetPixelAlpha(image,q);
1320 case BumpmapCompositeOp:
1322 alpha=GetPixelIntensity(composite_image,p)*Sa;
1325 case ColorBurnCompositeOp:
1326 case ColorDodgeCompositeOp:
1327 case DifferenceCompositeOp:
1328 case DivideDstCompositeOp:
1329 case DivideSrcCompositeOp:
1330 case ExclusionCompositeOp:
1331 case HardLightCompositeOp:
1332 case LinearBurnCompositeOp:
1333 case LinearDodgeCompositeOp:
1334 case LinearLightCompositeOp:
1335 case MathematicsCompositeOp:
1336 case MinusDstCompositeOp:
1337 case MinusSrcCompositeOp:
1338 case ModulusAddCompositeOp:
1339 case ModulusSubtractCompositeOp:
1340 case MultiplyCompositeOp:
1341 case OverlayCompositeOp:
1342 case PegtopLightCompositeOp:
1343 case PinLightCompositeOp:
1344 case ScreenCompositeOp:
1345 case SoftLightCompositeOp:
1346 case VividLightCompositeOp:
1348 alpha=RoundToUnity(Sa+Da-Sa*Da);
1351 case DarkenCompositeOp:
1352 case DstAtopCompositeOp:
1353 case DstInCompositeOp:
1355 case LightenCompositeOp:
1356 case SrcInCompositeOp:
1361 case DissolveCompositeOp:
1363 alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
1364 Sa+destination_dissolve*Da;
1367 case DstOverCompositeOp:
1369 alpha=Da*(-Sa)+Da+Sa;
1372 case DstOutCompositeOp:
1377 case OutCompositeOp:
1378 case SrcOutCompositeOp:
1383 case OverCompositeOp:
1384 case SrcOverCompositeOp:
1386 alpha=Sa*(-Da)+Sa+Da;
1389 case BlendCompositeOp:
1390 case PlusCompositeOp:
1392 alpha=RoundToUnity(Sa+Da);
1395 case XorCompositeOp:
1397 alpha=Sa+Da-2.0*Sa*Da;
1406 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1418 channel=GetPixelChannelMapChannel(image,i);
1419 traits=GetPixelChannelMapTraits(image,channel);
1420 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
1421 if ((traits == UndefinedPixelTrait) ||
1422 (composite_traits == UndefinedPixelTrait))
1426 Dc: destination color.
1428 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
1429 Dc=(MagickRealType) q[i];
1430 if ((traits & CopyPixelTrait) != 0)
1432 if (channel != AlphaPixelChannel)
1437 q[i]=ClampToQuantum(Sc);
1445 case AtopCompositeOp:
1446 case CopyBlackCompositeOp:
1447 case CopyBlueCompositeOp:
1448 case CopyCyanCompositeOp:
1449 case CopyGreenCompositeOp:
1450 case CopyMagentaCompositeOp:
1451 case CopyRedCompositeOp:
1452 case CopyYellowCompositeOp:
1453 case SrcAtopCompositeOp:
1454 case DstCompositeOp:
1457 pixel=QuantumRange*Da;
1460 case ChangeMaskCompositeOp:
1465 if (Da > ((MagickRealType) QuantumRange/2.0))
1467 pixel=(MagickRealType) TransparentAlpha;
1470 equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
1471 if (equivalent != MagickFalse)
1473 pixel=(MagickRealType) TransparentAlpha;
1476 pixel=(MagickRealType) OpaqueAlpha;
1479 case ClearCompositeOp:
1481 pixel=(MagickRealType) TransparentAlpha;
1484 case ColorizeCompositeOp:
1485 case HueCompositeOp:
1486 case LuminizeCompositeOp:
1487 case SaturateCompositeOp:
1489 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1491 pixel=QuantumRange*Da;
1494 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1496 pixel=QuantumRange*Sa;
1501 pixel=QuantumRange*Da;
1504 pixel=QuantumRange*Sa;
1507 case CopyCompositeOp:
1508 case CopyAlphaCompositeOp:
1509 case DisplaceCompositeOp:
1510 case DistortCompositeOp:
1511 case DstAtopCompositeOp:
1512 case ReplaceCompositeOp:
1513 case SrcCompositeOp:
1515 pixel=QuantumRange*Sa;
1518 case DarkenIntensityCompositeOp:
1520 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1521 (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
1524 case IntensityCompositeOp:
1526 pixel=GetPixelIntensity(composite_image,p);
1529 case LightenIntensityCompositeOp:
1531 pixel=Sa*GetPixelIntensity(composite_image,p) >
1532 Da*GetPixelIntensity(image,q) ? Sa : Da;
1535 case ModulateCompositeOp:
1537 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1539 pixel=QuantumRange*Da;
1542 pixel=QuantumRange*Da;
1547 pixel=QuantumRange*alpha;
1551 q[i]=ClampToQuantum(pixel);
1555 Porter-Duff compositions:
1556 Sca: source normalized color multiplied by alpha.
1557 Dca: normalized destination color multiplied by alpha.
1559 Sca=QuantumScale*Sa*Sc;
1560 Dca=QuantumScale*Da*Dc;
1563 case DarkenCompositeOp:
1564 case LightenCompositeOp:
1565 case ModulusSubtractCompositeOp:
1573 gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
1576 case AtopCompositeOp:
1577 case SrcAtopCompositeOp:
1579 pixel=Sc*Sa+Dc*(1.0-Sa);
1582 case BlendCompositeOp:
1584 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1587 case BlurCompositeOp:
1588 case DisplaceCompositeOp:
1589 case DistortCompositeOp:
1590 case CopyCompositeOp:
1591 case ReplaceCompositeOp:
1592 case SrcCompositeOp:
1597 case BumpmapCompositeOp:
1599 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1604 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1607 case ChangeMaskCompositeOp:
1612 case ClearCompositeOp:
1617 case ColorBurnCompositeOp:
1620 Refer to the March 2009 SVG specification.
1622 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1624 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1627 if (Sca < MagickEpsilon)
1629 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1632 pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
1633 Sca*(1.0-Da)+Dca*(1.0-Sa));
1636 case ColorDodgeCompositeOp:
1638 if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1640 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1643 if (fabs(Sca-Sa) < MagickEpsilon)
1645 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1648 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1652 case ColorizeCompositeOp:
1654 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1659 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1664 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1665 GetPixelBlue(image,q),&sans,&sans,&brightness);
1666 CompositeHSB(GetPixelRed(composite_image,p),
1667 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1668 &hue,&saturation,&sans);
1669 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1672 case RedPixelChannel: pixel=red; break;
1673 case GreenPixelChannel: pixel=green; break;
1674 case BluePixelChannel: pixel=blue; break;
1675 default: pixel=Dc; break;
1679 case CopyAlphaCompositeOp:
1680 case IntensityCompositeOp:
1682 if (channel == AlphaPixelChannel)
1684 if (composite_image->matte != MagickFalse)
1685 pixel=(MagickRealType) GetPixelAlpha(composite_image,p);
1687 pixel=(MagickRealType) GetPixelIntensity(composite_image,p);
1693 case CopyBlackCompositeOp:
1695 pixel=(MagickRealType) GetPixelBlack(composite_image,p);
1698 case CopyBlueCompositeOp:
1699 case CopyYellowCompositeOp:
1701 pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1704 case CopyGreenCompositeOp:
1705 case CopyMagentaCompositeOp:
1707 pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1710 case CopyRedCompositeOp:
1711 case CopyCyanCompositeOp:
1713 pixel=(MagickRealType) GetPixelRed(composite_image,p);
1716 case DarkenCompositeOp:
1719 Darken is equivalent to a 'Minimum' method
1720 OR a greyscale version of a binary 'Or'
1721 OR the 'Intersection' of pixel sets.
1725 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1728 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1731 case DarkenIntensityCompositeOp:
1733 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1734 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1737 case DifferenceCompositeOp:
1739 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1742 case DissolveCompositeOp:
1744 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1745 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1748 case DivideDstCompositeOp:
1750 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1752 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1755 if (fabs(Dca) < MagickEpsilon)
1757 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1760 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1763 case DivideSrcCompositeOp:
1765 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1767 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1770 if (fabs(Sca) < MagickEpsilon)
1772 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1775 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1778 case DstAtopCompositeOp:
1780 pixel=Dc*Da+Sc*(1.0-Da);
1783 case DstCompositeOp:
1789 case DstInCompositeOp:
1791 pixel=gamma*(Sa*Dc*Sa);
1794 case DstOutCompositeOp:
1796 pixel=gamma*(Da*Dc*(1.0-Sa));
1799 case DstOverCompositeOp:
1801 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1804 case ExclusionCompositeOp:
1806 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1810 case HardLightCompositeOp:
1814 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1818 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1822 case HueCompositeOp:
1824 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1829 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1834 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1835 GetPixelBlue(image,q),&hue,&saturation,&brightness);
1836 CompositeHSB(GetPixelRed(composite_image,p),
1837 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1839 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1842 case RedPixelChannel: pixel=red; break;
1843 case GreenPixelChannel: pixel=green; break;
1844 case BluePixelChannel: pixel=blue; break;
1845 default: pixel=Dc; break;
1850 case SrcInCompositeOp:
1852 pixel=gamma*(Da*Sc*Da);
1855 case LinearBurnCompositeOp:
1858 LinearBurn: as defined by Abode Photoshop, according to
1859 http://www.simplefilter.de/en/basics/mixmods.html is:
1861 f(Sc,Dc) = Sc + Dc - 1
1863 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1866 case LinearDodgeCompositeOp:
1868 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1871 case LinearLightCompositeOp:
1874 LinearLight: as defined by Abode Photoshop, according to
1875 http://www.simplefilter.de/en/basics/mixmods.html is:
1877 f(Sc,Dc) = Dc + 2*Sc - 1
1879 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1882 case LightenCompositeOp:
1886 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1889 pixel=QuantumRange*gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1892 case LightenIntensityCompositeOp:
1895 Lighten is equivalent to a 'Maximum' method
1896 OR a greyscale version of a binary 'And'
1897 OR the 'Union' of pixel sets.
1899 pixel=Sa*GetPixelIntensity(composite_image,p) >
1900 Da*GetPixelIntensity(image,q) ? Sc : Dc;
1903 case LuminizeCompositeOp:
1905 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1910 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1915 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1916 GetPixelBlue(image,q),&hue,&saturation,&brightness);
1917 CompositeHSB(GetPixelRed(composite_image,p),
1918 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1919 &sans,&sans,&brightness);
1920 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1923 case RedPixelChannel: pixel=red; break;
1924 case GreenPixelChannel: pixel=green; break;
1925 case BluePixelChannel: pixel=blue; break;
1926 default: pixel=Dc; break;
1930 case MathematicsCompositeOp:
1933 'Mathematics' a free form user control mathematical composition
1936 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
1938 Where the arguments A,B,C,D are (currently) passed to composite
1939 as a command separated 'geometry' string in "compose:args" image
1942 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
1944 Applying the SVG transparency formula (see above), we get...
1946 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
1948 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
1951 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
1952 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
1953 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
1956 case MinusDstCompositeOp:
1958 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
1961 case MinusSrcCompositeOp:
1964 Minus source from destination.
1968 pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
1971 case ModulateCompositeOp:
1976 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1981 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
1987 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1988 GetPixelBlue(image,q),&hue,&saturation,&brightness);
1989 brightness+=(0.01*percent_brightness*offset)/midpoint;
1990 saturation*=0.01*percent_saturation;
1991 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1994 case RedPixelChannel: pixel=red; break;
1995 case GreenPixelChannel: pixel=green; break;
1996 case BluePixelChannel: pixel=blue; break;
1997 default: pixel=Dc; break;
2001 case ModulusAddCompositeOp:
2004 if (pixel > QuantumRange)
2005 pixel-=(QuantumRange+1.0);
2006 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2009 case ModulusSubtractCompositeOp:
2013 pixel+=(QuantumRange+1.0);
2014 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2017 case MultiplyCompositeOp:
2019 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2022 case OutCompositeOp:
2023 case SrcOutCompositeOp:
2025 pixel=gamma*(Sa*Sc*(1.0-Da));
2028 case OverCompositeOp:
2029 case SrcOverCompositeOp:
2031 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2034 case OverlayCompositeOp:
2038 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2042 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2046 case PegtopLightCompositeOp:
2049 PegTop: A Soft-Light alternative: A continuous version of the
2050 Softlight function, producing very similar results.
2052 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2054 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2056 if (fabs(Da) < MagickEpsilon)
2058 pixel=QuantumRange*gamma*(Sca);
2061 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2065 case PinLightCompositeOp:
2068 PinLight: A Photoshop 7 composition method
2069 http://www.simplefilter.de/en/basics/mixmods.html
2071 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2073 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2075 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2078 if ((Dca*Sa) > (2.0*Sca*Da))
2080 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2083 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2086 case PlusCompositeOp:
2088 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
2091 case SaturateCompositeOp:
2093 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2098 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2103 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
2104 GetPixelBlue(image,q),&hue,&saturation,&brightness);
2105 CompositeHSB(GetPixelRed(composite_image,p),
2106 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
2107 &sans,&saturation,&sans);
2108 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
2111 case RedPixelChannel: pixel=red; break;
2112 case GreenPixelChannel: pixel=green; break;
2113 case BluePixelChannel: pixel=blue; break;
2114 default: pixel=Dc; break;
2118 case ScreenCompositeOp:
2121 Screen: a negated multiply:
2123 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2125 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2128 case SoftLightCompositeOp:
2131 Refer to the March 2009 SVG specification.
2135 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2136 Sca*(1.0-Da)+Dca*(1.0-Sa));
2139 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2141 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2142 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2146 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2147 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2150 case ThresholdCompositeOp:
2156 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2161 pixel=gamma*(Dc+delta*amount);
2164 case VividLightCompositeOp:
2167 VividLight: A Photoshop 7 composition method. See
2168 http://www.simplefilter.de/en/basics/mixmods.html.
2170 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2172 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2174 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2177 if ((2.0*Sca) <= Sa)
2179 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2180 (1.0-Da)+Dca*(1.0-Sa));
2183 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2187 case XorCompositeOp:
2189 pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2198 q[i]=ClampToQuantum(pixel);
2200 p+=GetPixelChannels(composite_image);
2201 channels=GetPixelChannels(composite_image);
2202 if (p >= (pixels+channels*composite_image->columns))
2204 q+=GetPixelChannels(image);
2206 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2208 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2213 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2214 #pragma omp critical (MagickCore_CompositeImage)
2216 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2218 if (proceed == MagickFalse)
2222 composite_view=DestroyCacheView(composite_view);
2223 image_view=DestroyCacheView(image_view);
2224 if (destination_image != (Image * ) NULL)
2225 destination_image=DestroyImage(destination_image);
2230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2234 % T e x t u r e I m a g e %
2238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2240 % TextureImage() repeatedly tiles the texture image across and down the image
2243 % The format of the TextureImage method is:
2245 % MagickBooleanType TextureImage(Image *image,const Image *texture_image,
2246 % ExceptionInfo *exception)
2248 % A description of each parameter follows:
2250 % o image: the image.
2252 % o texture_image: This image is the texture to layer on the background.
2255 MagickExport MagickBooleanType TextureImage(Image *image,
2256 const Image *texture_image,ExceptionInfo *exception)
2258 #define TextureImageTag "Texture/Image"
2270 assert(image != (Image *) NULL);
2271 if (image->debug != MagickFalse)
2272 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2273 assert(image->signature == MagickSignature);
2274 if (texture_image == (const Image *) NULL)
2275 return(MagickFalse);
2276 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod);
2277 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2278 return(MagickFalse);
2280 if ((image->compose != CopyCompositeOp) &&
2281 ((image->compose != OverCompositeOp) || (image->matte != MagickFalse) ||
2282 (texture_image->matte != MagickFalse)))
2285 Tile texture onto the image background.
2287 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2288 #pragma omp parallel for schedule(static,4) shared(status) omp_throttle(1)
2290 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2295 if (status == MagickFalse)
2297 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2302 thread_status=CompositeImage(image,image->compose,texture_image,x+
2303 texture_image->tile_offset.x,y+texture_image->tile_offset.y,
2305 if (thread_status == MagickFalse)
2307 status=thread_status;
2311 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2316 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2317 #pragma omp critical (MagickCore_TextureImage)
2319 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2321 if (proceed == MagickFalse)
2325 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2326 image->rows,image->rows);
2330 Tile texture onto the image background (optimized).
2333 image_view=AcquireCacheView(image);
2334 texture_view=AcquireCacheView(texture_image);
2335 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2336 #pragma omp parallel for schedule(static,4) shared(status) omp_throttle(1)
2338 for (y=0; y < (ssize_t) image->rows; y++)
2343 register const Quantum
2356 if (status == MagickFalse)
2358 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2359 (y+texture_image->tile_offset.y) % texture_image->rows,
2360 texture_image->columns,1,exception);
2361 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2362 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2367 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2373 width=texture_image->columns;
2374 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2375 width=image->columns-x;
2376 for (j=0; j < (ssize_t) width; j++)
2381 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2390 channel=GetPixelChannelMapChannel(texture_image,i);
2391 texture_traits=GetPixelChannelMapTraits(texture_image,channel);
2392 traits=GetPixelChannelMapTraits(image,channel);
2393 if ((traits == UndefinedPixelTrait) ||
2394 (texture_traits == UndefinedPixelTrait))
2396 SetPixelChannel(image,channel,p[i],q);
2398 p+=GetPixelChannels(texture_image);
2399 q+=GetPixelChannels(image);
2402 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2403 if (sync == MagickFalse)
2405 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2410 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2411 #pragma omp critical (MagickCore_TextureImage)
2413 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2415 if (proceed == MagickFalse)
2419 texture_view=DestroyCacheView(texture_view);
2420 image_view=DestroyCacheView(image_view);