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/token.h"
76 #include "MagickCore/utility.h"
77 #include "MagickCore/utility-private.h"
78 #include "MagickCore/version.h"
81 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
85 % C o m p o s i t e I m a g e %
89 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
91 % CompositeImage() returns the second image composited onto the first
92 % at the specified offset, using the specified composite method.
94 % The format of the CompositeImage method is:
96 % MagickBooleanType CompositeImage(Image *image,
97 % const Image *composite_image,const CompositeOperator compose,
98 % const MagickBooleanType clip_to_self,const ssize_t x_offset,
99 % const ssize_t y_offset,ExceptionInfo *exception)
101 % A description of each parameter follows:
103 % o image: the destination image, modified by he composition
105 % o composite_image: the composite (source) image.
107 % o compose: This operator affects how the composite is applied to
108 % the image. The operators and how they are utilized are listed here
109 % http://www.w3.org/TR/SVG12/#compositing.
111 % o clip_to_self: set to MagickTrue to limit composition to area composed.
113 % o x_offset: the column offset of the composited image.
115 % o y_offset: the row offset of the composited image.
117 % Extra Controls from Image meta-data in 'composite_image' (artifacts)
120 % A string containing extra numerical arguments for specific compose
121 % methods, generally expressed as a 'geometry' or a comma separated list
124 % Compose methods needing such arguments include "BlendCompositeOp" and
125 % "DisplaceCompositeOp".
127 % o exception: return any errors or warnings in this structure.
131 static void CompositeHSB(const Quantum red,const Quantum green,
132 const Quantum blue,double *hue,double *saturation,double *brightness)
142 Convert RGB to HSB colorspace.
144 assert(hue != (double *) NULL);
145 assert(saturation != (double *) NULL);
146 assert(brightness != (double *) NULL);
147 max=(red > green ? red : green);
150 min=(red < green ? red : green);
155 *brightness=(double) (QuantumScale*max);
156 if (fabs((double) max) < MagickEpsilon)
158 *saturation=(double) (1.0-min/max);
159 delta=(MagickRealType) max-min;
160 if (fabs(delta) < MagickEpsilon)
162 if (fabs((double) red-max) < MagickEpsilon)
163 *hue=(double) ((green-blue)/delta);
165 if (fabs((double) green-max) < MagickEpsilon)
166 *hue=(double) (2.0+(blue-red)/delta);
168 if (fabs((double) blue-max) < MagickEpsilon)
169 *hue=(double) (4.0+(red-green)/delta);
175 static void HSBComposite(const double hue,const double saturation,
176 const double brightness,double *red,double *green,double *blue)
186 Convert HSB to RGB colorspace.
188 assert(red != (double *) NULL);
189 assert(green != (double *) NULL);
190 assert(blue != (double *) NULL);
191 if (saturation == 0.0)
193 *red=(double) QuantumRange*brightness;
198 h=6.0*(hue-floor(hue));
199 f=h-floor((double) h);
200 p=brightness*(1.0-saturation);
201 q=brightness*(1.0-saturation*f);
202 t=brightness*(1.0-saturation*(1.0-f));
208 *red=(double) QuantumRange*brightness;
209 *green=(double) QuantumRange*t;
210 *blue=(double) QuantumRange*p;
215 *red=(double) QuantumRange*q;
216 *green=(double) QuantumRange*brightness;
217 *blue=(double) QuantumRange*p;
222 *red=(double) QuantumRange*p;
223 *green=(double) QuantumRange*brightness;
224 *blue=(double) QuantumRange*t;
229 *red=(double) QuantumRange*p;
230 *green=(double) QuantumRange*q;
231 *blue=(double) QuantumRange*brightness;
236 *red=(double) QuantumRange*t;
237 *green=(double) QuantumRange*p;
238 *blue=(double) QuantumRange*brightness;
243 *red=(double) QuantumRange*brightness;
244 *green=(double) QuantumRange*p;
245 *blue=(double) QuantumRange*q;
251 static inline double MagickMin(const double x,const double y)
257 static inline double MagickMax(const double x,const double y)
264 static MagickBooleanType CompositeOverImage(Image *image,
265 const Image *composite_image,const MagickBooleanType clip_to_self,
266 const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
268 #define CompositeImageTag "Composite/Image"
288 image_view=AcquireCacheView(image);
289 composite_view=AcquireCacheView(composite_image);
290 #if defined(MAGICKCORE_OPENMP_SUPPORT)
291 #pragma omp parallel for schedule(static,4) shared(progress,status)
293 for (y=0; y < (ssize_t) image->rows; y++)
298 register const Quantum
310 if (status == MagickFalse)
312 if (clip_to_self != MagickFalse)
316 if ((y-y_offset) >= (ssize_t) composite_image->rows)
320 If pixels is NULL, y is outside overlay region.
322 pixels=(Quantum *) NULL;
324 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
326 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
327 composite_image->columns,1,exception);
328 if (p == (const Quantum *) NULL)
335 p-=x_offset*GetPixelChannels(composite_image);
337 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
338 if (q == (Quantum *) NULL)
343 for (x=0; x < (ssize_t) image->columns; x++)
356 if (clip_to_self != MagickFalse)
360 q+=GetPixelChannels(image);
363 if ((x-x_offset) >= (ssize_t) composite_image->columns)
366 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
367 ((x-x_offset) >= (ssize_t) composite_image->columns))
370 source[MaxPixelChannels];
375 Dc: destination color.
377 if (GetPixelMask(image,q) != 0)
379 q+=GetPixelChannels(image);
382 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
384 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
393 channel=GetPixelChannelMapChannel(image,i);
394 traits=GetPixelChannelMapTraits(image,channel);
395 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
396 if ((traits == UndefinedPixelTrait) ||
397 (composite_traits == UndefinedPixelTrait))
399 q[i]=source[channel];
401 q+=GetPixelChannels(image);
406 Sa: normalized source alpha.
407 Da: normalized destination alpha.
409 if (GetPixelMask(composite_image,p) != 0)
411 p+=GetPixelChannels(composite_image);
412 channels=GetPixelChannels(composite_image);
413 if (p >= (pixels+channels*composite_image->columns))
415 q+=GetPixelChannels(image);
418 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
419 Da=QuantumScale*GetPixelAlpha(image,q);
420 alpha=Sa*(-Da)+Sa+Da;
421 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
430 channel=GetPixelChannelMapChannel(image,i);
431 traits=GetPixelChannelMapTraits(image,channel);
432 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
433 if ((traits == UndefinedPixelTrait) ||
434 (composite_traits == UndefinedPixelTrait))
436 if ((traits & CopyPixelTrait) != 0)
438 if (channel != AlphaPixelChannel)
443 q[i]=GetPixelChannel(composite_image,channel,p);
449 q[i]=ClampToQuantum(QuantumRange*alpha);
454 Dc: destination color.
456 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
457 Dc=(MagickRealType) q[i];
458 gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
459 q[i]=ClampToQuantum(gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc));
461 p+=GetPixelChannels(composite_image);
462 channels=GetPixelChannels(composite_image);
463 if (p >= (pixels+channels*composite_image->columns))
465 q+=GetPixelChannels(image);
467 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
469 if (image->progress_monitor != (MagickProgressMonitor) NULL)
474 #if defined(MAGICKCORE_OPENMP_SUPPORT)
475 #pragma omp critical (MagickCore_CompositeImage)
477 proceed=SetImageProgress(image,CompositeImageTag,progress++,
479 if (proceed == MagickFalse)
483 composite_view=DestroyCacheView(composite_view);
484 image_view=DestroyCacheView(image_view);
488 MagickExport MagickBooleanType CompositeImage(Image *image,
489 const Image *composite_image,const CompositeOperator compose,
490 const MagickBooleanType clip_to_self,const ssize_t x_offset,
491 const ssize_t y_offset,ExceptionInfo *exception)
493 #define CompositeImageTag "Composite/Image"
513 destination_dissolve,
527 Composition based on the SVG specification:
529 A Composition is defined by...
530 Color Function : f(Sc,Dc) where Sc and Dc are the normizalized colors
531 Blending areas : X = 1 for area of overlap, ie: f(Sc,Dc)
532 Y = 1 for source preserved
533 Z = 1 for destination preserved
535 Conversion to transparency (then optimized)
536 Dca' = f(Sc, Dc)*Sa*Da + Y*Sca*(1-Da) + Z*Dca*(1-Sa)
537 Da' = X*Sa*Da + Y*Sa*(1-Da) + Z*Da*(1-Sa)
540 Sca = Sc*Sa normalized Source color divided by Source alpha
541 Dca = Dc*Da normalized Dest color divided by Dest alpha
542 Dc' = Dca'/Da' the desired color value for this channel.
544 Da' in in the follow formula as 'gamma' The resulting alpla value.
546 Most functions use a blending mode of over (X=1,Y=1,Z=1) this results in
547 the following optimizations...
549 gamma = 1 - QuantiumScale*alpha * QuantiumScale*beta;
550 opacity = QuantiumScale*alpha*beta; // over blend, optimized 1-Gamma
552 The above SVG definitions also definate that Mathematical Composition
553 methods should use a 'Over' blending mode for Alpha Channel.
554 It however was not applied for composition modes of 'Plus', 'Minus',
555 the modulus versions of 'Add' and 'Subtract'.
557 Mathematical operator changes to be applied from IM v6.7...
559 1) Modulus modes 'Add' and 'Subtract' are obsoleted and renamed
560 'ModulusAdd' and 'ModulusSubtract' for clarity.
562 2) All mathematical compositions work as per the SVG specification
563 with regard to blending. This now includes 'ModulusAdd' and
566 3) When the special channel flag 'sync' (syncronize channel updates)
567 is turned off (enabled by default) then mathematical compositions are
568 only performed on the channels specified, and are applied
569 independantally of each other. In other words the mathematics is
570 performed as 'pure' mathematical operations, rather than as image
573 assert(image != (Image *) NULL);
574 assert(image->signature == MagickSignature);
575 if (image->debug != MagickFalse)
576 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
577 assert(composite_image != (Image *) NULL);
578 assert(composite_image->signature == MagickSignature);
579 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
581 if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
582 (IsGrayColorspace(composite_image->colorspace) == MagickFalse))
583 (void) TransformImageColorspace(image,sRGBColorspace,exception);
584 if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
586 status=CompositeOverImage(image,composite_image,clip_to_self,x_offset,
590 destination_image=(Image *) NULL;
592 destination_dissolve=1.0;
593 percent_brightness=100.0;
594 percent_saturation=100.0;
599 case CopyCompositeOp:
601 if ((x_offset < 0) || (y_offset < 0))
603 if ((x_offset+(ssize_t) composite_image->columns) >= (ssize_t) image->columns)
605 if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
608 image_view=AcquireCacheView(image);
609 composite_view=AcquireCacheView(composite_image);
610 #if defined(MAGICKCORE_OPENMP_SUPPORT)
611 #pragma omp parallel for schedule(static,4) shared(status)
613 for (y=0; y < (ssize_t) composite_image->rows; y++)
618 register const Quantum
627 if (status == MagickFalse)
629 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
631 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
632 composite_image->columns,1,exception);
633 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
638 for (x=0; x < (ssize_t) composite_image->columns; x++)
643 if (GetPixelMask(image,p) != 0)
645 p+=GetPixelChannels(composite_image);
646 q+=GetPixelChannels(image);
649 for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
658 channel=GetPixelChannelMapChannel(composite_image,i);
659 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
660 traits=GetPixelChannelMapTraits(image,channel);
661 if ((traits == UndefinedPixelTrait) ||
662 (composite_traits == UndefinedPixelTrait))
664 SetPixelChannel(image,channel,p[i],q);
666 p+=GetPixelChannels(composite_image);
667 q+=GetPixelChannels(image);
669 sync=SyncCacheViewAuthenticPixels(image_view,exception);
670 if (sync == MagickFalse)
672 if (image->progress_monitor != (MagickProgressMonitor) NULL)
677 #if defined(MAGICKCORE_OPENMP_SUPPORT)
678 #pragma omp critical (MagickCore_CompositeImage)
680 proceed=SetImageProgress(image,CompositeImageTag,
681 (MagickOffsetType) y,image->rows);
682 if (proceed == MagickFalse)
686 composite_view=DestroyCacheView(composite_view);
687 image_view=DestroyCacheView(image_view);
690 case CopyAlphaCompositeOp:
691 case ChangeMaskCompositeOp:
692 case IntensityCompositeOp:
695 Modify destination outside the overlaid region and require an alpha
696 channel to exist, to add transparency.
698 if (image->matte == MagickFalse)
699 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
702 case BlurCompositeOp:
727 Blur Image dictated by an overlay gradient map: X = red_channel;
728 Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
730 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
732 if (destination_image == (Image *) NULL)
735 Determine the horizontal and vertical maximim blur.
737 SetGeometryInfo(&geometry_info);
739 value=GetImageArtifact(composite_image,"compose:args");
740 if (value != (char *) NULL)
741 flags=ParseGeometry(value,&geometry_info);
742 if ((flags & WidthValue) == 0 )
744 destination_image=DestroyImage(destination_image);
747 width=geometry_info.rho;
748 height=geometry_info.sigma;
749 blur.x1=geometry_info.rho;
752 blur.y2=geometry_info.sigma;
755 if ((flags & HeightValue) == 0)
757 if ((flags & XValue) != 0 )
762 angle=DegreesToRadians(geometry_info.xi);
763 blur.x1=width*cos(angle);
764 blur.x2=width*sin(angle);
765 blur.y1=(-height*sin(angle));
766 blur.y2=height*cos(angle);
768 if ((flags & YValue) != 0 )
770 angle_start=DegreesToRadians(geometry_info.xi);
771 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
774 Blur Image by resampling.
775 FUTURE: this is currently broken, especially for small sigma blurs
776 This needs to be fixed to use a non-user filter setup that provides
777 far more control than currently available.
779 resample_filter=AcquireResampleFilter(image,exception);
780 SetResampleFilter(resample_filter,CubicFilter); /* was blur*2 */
781 destination_view=AcquireCacheView(destination_image);
782 composite_view=AcquireCacheView(composite_image);
783 for (y=0; y < (ssize_t) composite_image->rows; y++)
788 register const Quantum
797 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
799 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
801 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
802 destination_image->columns,1,exception);
803 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
805 for (x=0; x < (ssize_t) composite_image->columns; x++)
807 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
809 p+=GetPixelChannels(composite_image);
812 if (fabs(angle_range) > MagickEpsilon)
817 angle=angle_start+angle_range*QuantumScale*
818 GetPixelBlue(composite_image,p);
819 blur.x1=width*cos(angle);
820 blur.x2=width*sin(angle);
821 blur.y1=(-height*sin(angle));
822 blur.y2=height*cos(angle);
824 ScaleResampleFilter(resample_filter,blur.x1*QuantumScale*
825 GetPixelRed(composite_image,p),blur.y1*QuantumScale*
826 GetPixelGreen(composite_image,p),blur.x2*QuantumScale*
827 GetPixelRed(composite_image,p),blur.y2*QuantumScale*
828 GetPixelGreen(composite_image,p));
829 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
830 (double) y_offset+y,&pixel);
831 SetPixelInfoPixel(destination_image,&pixel,q);
832 p+=GetPixelChannels(composite_image);
833 q+=GetPixelChannels(destination_image);
835 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
836 if (sync == MagickFalse)
839 resample_filter=DestroyResampleFilter(resample_filter);
840 composite_view=DestroyCacheView(composite_view);
841 destination_view=DestroyCacheView(destination_view);
842 composite_image=destination_image;
845 case DisplaceCompositeOp:
846 case DistortCompositeOp:
868 Displace/Distort based on overlay gradient map:
869 X = red_channel; Y = green_channel;
870 compose:args = x_scale[,y_scale[,center.x,center.y]]
872 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
874 if (destination_image == (Image *) NULL)
876 SetGeometryInfo(&geometry_info);
878 value=GetImageArtifact(composite_image,"compose:args");
879 if (value != (char *) NULL)
880 flags=ParseGeometry(value,&geometry_info);
881 if ((flags & (WidthValue|HeightValue)) == 0 )
883 if ((flags & AspectValue) == 0)
885 horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
887 vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
891 horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
892 vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
897 horizontal_scale=geometry_info.rho;
898 vertical_scale=geometry_info.sigma;
899 if ((flags & PercentValue) != 0)
901 if ((flags & AspectValue) == 0)
903 horizontal_scale*=(composite_image->columns-1.0)/200.0;
904 vertical_scale*=(composite_image->rows-1.0)/200.0;
908 horizontal_scale*=(image->columns-1.0)/200.0;
909 vertical_scale*=(image->rows-1.0)/200.0;
912 if ((flags & HeightValue) == 0)
913 vertical_scale=horizontal_scale;
916 Determine fixed center point for absolute distortion map
918 Displace offset relative to a fixed absolute point
919 Select that point according to +X+Y user inputs.
920 default = center of overlay image
921 arg flag '!' = locations/percentage relative to background image
923 center.x=(MagickRealType) x_offset;
924 center.y=(MagickRealType) y_offset;
925 if (compose == DistortCompositeOp)
927 if ((flags & XValue) == 0)
928 if ((flags & AspectValue) == 0)
929 center.x=(MagickRealType) x_offset+(composite_image->columns-1)/
932 center.x=((MagickRealType) image->columns-1)/2.0;
934 if ((flags & AspectValue) == 0)
935 center.x=(MagickRealType) x_offset+geometry_info.xi;
937 center.x=geometry_info.xi;
938 if ((flags & YValue) == 0)
939 if ((flags & AspectValue) == 0)
940 center.y=(MagickRealType) y_offset+(composite_image->rows-1)/2.0;
942 center.y=((MagickRealType) image->rows-1)/2.0;
944 if ((flags & AspectValue) == 0)
945 center.y=(MagickRealType) y_offset+geometry_info.psi;
947 center.y=geometry_info.psi;
950 Shift the pixel offset point as defined by the provided,
951 displacement/distortion map. -- Like a lens...
953 GetPixelInfo(image,&pixel);
954 image_view=AcquireCacheView(image);
955 destination_view=AcquireCacheView(destination_image);
956 composite_view=AcquireCacheView(composite_image);
957 for (y=0; y < (ssize_t) composite_image->rows; y++)
962 register const Quantum
971 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
973 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
975 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
976 destination_image->columns,1,exception);
977 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
979 for (x=0; x < (ssize_t) composite_image->columns; x++)
981 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
983 p+=GetPixelChannels(composite_image);
989 offset.x=(horizontal_scale*(GetPixelRed(composite_image,p)-
990 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
991 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
993 offset.y=(vertical_scale*(GetPixelGreen(composite_image,p)-
994 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
995 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
997 (void) InterpolatePixelInfo(image,image_view,
998 UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1001 Mask with the 'invalid pixel mask' in alpha channel.
1003 pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
1004 pixel.alpha)*(1.0-QuantumScale*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:
1025 Geometry arguments to dissolve factors.
1027 value=GetImageArtifact(composite_image,"compose:args");
1028 if (value != (char *) NULL)
1030 flags=ParseGeometry(value,&geometry_info);
1031 source_dissolve=geometry_info.rho/100.0;
1032 destination_dissolve=1.0;
1033 if ((source_dissolve-MagickEpsilon) < 0.0)
1034 source_dissolve=0.0;
1035 if ((source_dissolve+MagickEpsilon) > 1.0)
1037 destination_dissolve=2.0-source_dissolve;
1038 source_dissolve=1.0;
1040 if ((flags & SigmaValue) != 0)
1041 destination_dissolve=geometry_info.sigma/100.0;
1042 if ((destination_dissolve-MagickEpsilon) < 0.0)
1043 destination_dissolve=0.0;
1047 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;
1063 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:
1088 Determine the brightness and saturation scale.
1090 value=GetImageArtifact(composite_image,"compose:args");
1091 if (value != (char *) NULL)
1093 flags=ParseGeometry(value,&geometry_info);
1094 percent_brightness=geometry_info.rho;
1095 if ((flags & SigmaValue) != 0)
1096 percent_saturation=geometry_info.sigma;
1100 case ThresholdCompositeOp:
1106 Determine the amount and threshold.
1108 value=GetImageArtifact(composite_image,"compose:args");
1109 if (value != (char *) NULL)
1111 flags=ParseGeometry(value,&geometry_info);
1112 amount=geometry_info.rho;
1113 threshold=geometry_info.sigma;
1114 if ((flags & SigmaValue) == 0)
1117 threshold*=QuantumRange;
1128 midpoint=((MagickRealType) QuantumRange+1.0)/2;
1129 image_view=AcquireCacheView(image);
1130 composite_view=AcquireCacheView(composite_image);
1131 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1132 #pragma omp parallel for schedule(static,4) shared(progress,status)
1134 for (y=0; y < (ssize_t) image->rows; y++)
1147 register const Quantum
1156 if (status == MagickFalse)
1158 if (clip_to_self != MagickFalse)
1162 if ((y-y_offset) >= (ssize_t) composite_image->rows)
1166 If pixels is NULL, y is outside overlay region.
1168 pixels=(Quantum *) NULL;
1170 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
1172 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
1173 composite_image->columns,1,exception);
1174 if (p == (const Quantum *) NULL)
1181 p-=x_offset*GetPixelChannels(composite_image);
1183 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1184 if (q == (Quantum *) NULL)
1192 for (x=0; x < (ssize_t) image->columns; x++)
1210 if (clip_to_self != MagickFalse)
1214 q+=GetPixelChannels(image);
1217 if ((x-x_offset) >= (ssize_t) composite_image->columns)
1220 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1221 ((x-x_offset) >= (ssize_t) composite_image->columns))
1224 source[MaxPixelChannels];
1229 Dc: destination color.
1231 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
1233 if (GetPixelMask(image,q) != 0)
1235 q+=GetPixelChannels(image);
1238 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1250 channel=GetPixelChannelMapChannel(image,i);
1251 traits=GetPixelChannelMapTraits(image,channel);
1252 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
1253 if ((traits == UndefinedPixelTrait) ||
1254 (composite_traits == UndefinedPixelTrait))
1258 case AlphaCompositeOp:
1259 case ChangeMaskCompositeOp:
1260 case CopyAlphaCompositeOp:
1261 case DstAtopCompositeOp:
1262 case DstInCompositeOp:
1264 case IntensityCompositeOp:
1265 case OutCompositeOp:
1266 case SrcInCompositeOp:
1267 case SrcOutCompositeOp:
1269 pixel=(MagickRealType) q[i];
1270 if (channel == AlphaPixelChannel)
1271 pixel=(MagickRealType) TransparentAlpha;
1274 case ClearCompositeOp:
1275 case CopyCompositeOp:
1276 case ReplaceCompositeOp:
1277 case SrcCompositeOp:
1279 if (channel == AlphaPixelChannel)
1281 pixel=(MagickRealType) TransparentAlpha;
1287 case BlendCompositeOp:
1288 case DissolveCompositeOp:
1290 if (channel == AlphaPixelChannel)
1292 pixel=destination_dissolve*GetPixelAlpha(composite_image,
1296 pixel=(MagickRealType) source[channel];
1301 pixel=(MagickRealType) source[channel];
1305 q[i]=ClampToQuantum(pixel);
1307 q+=GetPixelChannels(image);
1311 Authentic composite:
1312 Sa: normalized source alpha.
1313 Da: normalized destination alpha.
1315 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
1316 Da=QuantumScale*GetPixelAlpha(image,q);
1319 case BumpmapCompositeOp:
1321 alpha=GetPixelIntensity(composite_image,p)*Sa;
1324 case ColorBurnCompositeOp:
1325 case ColorDodgeCompositeOp:
1326 case DifferenceCompositeOp:
1327 case DivideDstCompositeOp:
1328 case DivideSrcCompositeOp:
1329 case ExclusionCompositeOp:
1330 case HardLightCompositeOp:
1331 case LinearBurnCompositeOp:
1332 case LinearDodgeCompositeOp:
1333 case LinearLightCompositeOp:
1334 case MathematicsCompositeOp:
1335 case MinusDstCompositeOp:
1336 case MinusSrcCompositeOp:
1337 case ModulusAddCompositeOp:
1338 case ModulusSubtractCompositeOp:
1339 case MultiplyCompositeOp:
1340 case OverlayCompositeOp:
1341 case PegtopLightCompositeOp:
1342 case PinLightCompositeOp:
1343 case ScreenCompositeOp:
1344 case SoftLightCompositeOp:
1345 case VividLightCompositeOp:
1347 alpha=RoundToUnity(Sa+Da-Sa*Da);
1350 case DarkenCompositeOp:
1351 case DstAtopCompositeOp:
1352 case DstInCompositeOp:
1354 case LightenCompositeOp:
1355 case SrcInCompositeOp:
1360 case DissolveCompositeOp:
1362 alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
1363 Sa+destination_dissolve*Da;
1366 case DstOverCompositeOp:
1368 alpha=Da*(-Sa)+Da+Sa;
1371 case DstOutCompositeOp:
1376 case OutCompositeOp:
1377 case SrcOutCompositeOp:
1382 case OverCompositeOp:
1383 case SrcOverCompositeOp:
1385 alpha=Sa*(-Da)+Sa+Da;
1388 case BlendCompositeOp:
1389 case PlusCompositeOp:
1391 alpha=RoundToUnity(Sa+Da);
1394 case XorCompositeOp:
1396 alpha=Sa+Da-2.0*Sa*Da;
1405 if (GetPixelMask(image,p) != 0)
1407 p+=GetPixelChannels(composite_image);
1408 q+=GetPixelChannels(image);
1411 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1426 channel=GetPixelChannelMapChannel(image,i);
1427 traits=GetPixelChannelMapTraits(image,channel);
1428 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
1429 if (traits == UndefinedPixelTrait)
1431 if ((compose != IntensityCompositeOp) &&
1432 (composite_traits == UndefinedPixelTrait))
1436 Dc: destination color.
1438 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
1439 Dc=(MagickRealType) q[i];
1440 if ((traits & CopyPixelTrait) != 0)
1442 if (channel != AlphaPixelChannel)
1447 q[i]=ClampToQuantum(Sc);
1455 case AlphaCompositeOp:
1457 pixel=QuantumRange*Sa;
1460 case AtopCompositeOp:
1461 case CopyBlackCompositeOp:
1462 case CopyBlueCompositeOp:
1463 case CopyCyanCompositeOp:
1464 case CopyGreenCompositeOp:
1465 case CopyMagentaCompositeOp:
1466 case CopyRedCompositeOp:
1467 case CopyYellowCompositeOp:
1468 case SrcAtopCompositeOp:
1469 case DstCompositeOp:
1472 pixel=QuantumRange*Da;
1475 case ChangeMaskCompositeOp:
1480 if (Da > ((MagickRealType) QuantumRange/2.0))
1482 pixel=(MagickRealType) TransparentAlpha;
1485 equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
1486 if (equivalent != MagickFalse)
1488 pixel=(MagickRealType) TransparentAlpha;
1491 pixel=(MagickRealType) OpaqueAlpha;
1494 case ClearCompositeOp:
1496 pixel=(MagickRealType) TransparentAlpha;
1499 case ColorizeCompositeOp:
1500 case HueCompositeOp:
1501 case LuminizeCompositeOp:
1502 case SaturateCompositeOp:
1504 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1506 pixel=QuantumRange*Da;
1509 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1511 pixel=QuantumRange*Sa;
1516 pixel=QuantumRange*Da;
1519 pixel=QuantumRange*Sa;
1522 case CopyCompositeOp:
1523 case CopyAlphaCompositeOp:
1524 case DisplaceCompositeOp:
1525 case DistortCompositeOp:
1526 case DstAtopCompositeOp:
1527 case ReplaceCompositeOp:
1528 case SrcCompositeOp:
1530 pixel=QuantumRange*Sa;
1533 case DarkenIntensityCompositeOp:
1535 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1536 (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
1539 case IntensityCompositeOp:
1541 pixel=(MagickRealType) GetPixelIntensity(composite_image,p);
1544 case LightenIntensityCompositeOp:
1546 pixel=Sa*GetPixelIntensity(composite_image,p) >
1547 Da*GetPixelIntensity(image,q) ? Sa : Da;
1550 case ModulateCompositeOp:
1552 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1554 pixel=QuantumRange*Da;
1557 pixel=QuantumRange*Da;
1562 pixel=QuantumRange*alpha;
1566 q[i]=ClampToQuantum(pixel);
1570 Porter-Duff compositions:
1571 Sca: source normalized color multiplied by alpha.
1572 Dca: normalized destination color multiplied by alpha.
1574 Sca=QuantumScale*Sa*Sc;
1575 Dca=QuantumScale*Da*Dc;
1578 case DarkenCompositeOp:
1579 case LightenCompositeOp:
1580 case ModulusSubtractCompositeOp:
1588 gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
1592 case AlphaCompositeOp:
1594 pixel=QuantumRange*Sa;
1597 case AtopCompositeOp:
1598 case SrcAtopCompositeOp:
1600 pixel=Sc*Sa+Dc*(1.0-Sa);
1603 case BlendCompositeOp:
1605 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1608 case BlurCompositeOp:
1609 case DisplaceCompositeOp:
1610 case DistortCompositeOp:
1611 case CopyCompositeOp:
1612 case ReplaceCompositeOp:
1613 case SrcCompositeOp:
1618 case BumpmapCompositeOp:
1620 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1625 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1628 case ChangeMaskCompositeOp:
1633 case ClearCompositeOp:
1638 case ColorBurnCompositeOp:
1641 Refer to the March 2009 SVG specification.
1643 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1645 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1648 if (Sca < MagickEpsilon)
1650 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1653 pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
1654 Sca*(1.0-Da)+Dca*(1.0-Sa));
1657 case ColorDodgeCompositeOp:
1659 if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1661 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1664 if (fabs(Sca-Sa) < MagickEpsilon)
1666 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1669 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1673 case ColorizeCompositeOp:
1675 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1680 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1685 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1686 GetPixelBlue(image,q),&sans,&sans,&brightness);
1687 CompositeHSB(GetPixelRed(composite_image,p),
1688 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1689 &hue,&saturation,&sans);
1690 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1693 case RedPixelChannel: pixel=red; break;
1694 case GreenPixelChannel: pixel=green; break;
1695 case BluePixelChannel: pixel=blue; break;
1696 default: pixel=Dc; break;
1700 case CopyAlphaCompositeOp:
1701 case IntensityCompositeOp:
1703 if (channel == AlphaPixelChannel)
1704 pixel=(MagickRealType) GetPixelAlpha(composite_image,p);
1707 case CopyBlackCompositeOp:
1709 if (channel == BlackPixelChannel)
1710 pixel=(MagickRealType) GetPixelBlack(composite_image,p);
1713 case CopyBlueCompositeOp:
1714 case CopyYellowCompositeOp:
1716 if (channel == BluePixelChannel)
1717 pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1720 case CopyGreenCompositeOp:
1721 case CopyMagentaCompositeOp:
1723 if (channel == GreenPixelChannel)
1724 pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1727 case CopyRedCompositeOp:
1728 case CopyCyanCompositeOp:
1730 if (channel == RedPixelChannel)
1731 pixel=(MagickRealType) GetPixelRed(composite_image,p);
1734 case DarkenCompositeOp:
1737 Darken is equivalent to a 'Minimum' method
1738 OR a greyscale version of a binary 'Or'
1739 OR the 'Intersection' of pixel sets.
1743 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1746 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1749 case DarkenIntensityCompositeOp:
1751 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1752 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1755 case DifferenceCompositeOp:
1757 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1760 case DissolveCompositeOp:
1762 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1763 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1766 case DivideDstCompositeOp:
1768 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1770 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1773 if (fabs(Dca) < MagickEpsilon)
1775 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1778 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1781 case DivideSrcCompositeOp:
1783 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1785 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1788 if (fabs(Sca) < MagickEpsilon)
1790 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1793 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1796 case DstAtopCompositeOp:
1798 pixel=Dc*Da+Sc*(1.0-Da);
1801 case DstCompositeOp:
1807 case DstInCompositeOp:
1809 pixel=gamma*(Sa*Dc*Sa);
1812 case DstOutCompositeOp:
1814 pixel=gamma*(Da*Dc*(1.0-Sa));
1817 case DstOverCompositeOp:
1819 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1822 case ExclusionCompositeOp:
1824 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1828 case HardLightCompositeOp:
1832 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1836 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1840 case HueCompositeOp:
1842 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1847 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1852 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1853 GetPixelBlue(image,q),&hue,&saturation,&brightness);
1854 CompositeHSB(GetPixelRed(composite_image,p),
1855 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1857 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1860 case RedPixelChannel: pixel=red; break;
1861 case GreenPixelChannel: pixel=green; break;
1862 case BluePixelChannel: pixel=blue; break;
1863 default: pixel=Dc; break;
1868 case SrcInCompositeOp:
1870 pixel=gamma*(Da*Sc*Da);
1873 case LinearBurnCompositeOp:
1876 LinearBurn: as defined by Abode Photoshop, according to
1877 http://www.simplefilter.de/en/basics/mixmods.html is:
1879 f(Sc,Dc) = Sc + Dc - 1
1881 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1884 case LinearDodgeCompositeOp:
1886 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1889 case LinearLightCompositeOp:
1892 LinearLight: as defined by Abode Photoshop, according to
1893 http://www.simplefilter.de/en/basics/mixmods.html is:
1895 f(Sc,Dc) = Dc + 2*Sc - 1
1897 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1900 case LightenCompositeOp:
1904 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1907 pixel=QuantumRange*gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1910 case LightenIntensityCompositeOp:
1913 Lighten is equivalent to a 'Maximum' method
1914 OR a greyscale version of a binary 'And'
1915 OR the 'Union' of pixel sets.
1917 pixel=Sa*GetPixelIntensity(composite_image,p) >
1918 Da*GetPixelIntensity(image,q) ? Sc : Dc;
1921 case LuminizeCompositeOp:
1923 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1928 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1933 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1934 GetPixelBlue(image,q),&hue,&saturation,&brightness);
1935 CompositeHSB(GetPixelRed(composite_image,p),
1936 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1937 &sans,&sans,&brightness);
1938 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1941 case RedPixelChannel: pixel=red; break;
1942 case GreenPixelChannel: pixel=green; break;
1943 case BluePixelChannel: pixel=blue; break;
1944 default: pixel=Dc; break;
1948 case MathematicsCompositeOp:
1951 'Mathematics' a free form user control mathematical composition
1954 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
1956 Where the arguments A,B,C,D are (currently) passed to composite
1957 as a command separated 'geometry' string in "compose:args" image
1960 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
1962 Applying the SVG transparency formula (see above), we get...
1964 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
1966 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
1969 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
1970 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
1971 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
1974 case MinusDstCompositeOp:
1976 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
1979 case MinusSrcCompositeOp:
1982 Minus source from destination.
1986 pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
1989 case ModulateCompositeOp:
1994 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1999 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
2005 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
2006 GetPixelBlue(image,q),&hue,&saturation,&brightness);
2007 brightness+=(0.01*percent_brightness*offset)/midpoint;
2008 saturation*=0.01*percent_saturation;
2009 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
2012 case RedPixelChannel: pixel=red; break;
2013 case GreenPixelChannel: pixel=green; break;
2014 case BluePixelChannel: pixel=blue; break;
2015 default: pixel=Dc; break;
2019 case ModulusAddCompositeOp:
2022 if (pixel > QuantumRange)
2023 pixel-=(QuantumRange+1.0);
2024 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2027 case ModulusSubtractCompositeOp:
2031 pixel+=(QuantumRange+1.0);
2032 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2035 case MultiplyCompositeOp:
2037 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2040 case OutCompositeOp:
2041 case SrcOutCompositeOp:
2043 pixel=gamma*(Sa*Sc*(1.0-Da));
2046 case OverCompositeOp:
2047 case SrcOverCompositeOp:
2049 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2052 case OverlayCompositeOp:
2056 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2060 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2064 case PegtopLightCompositeOp:
2067 PegTop: A Soft-Light alternative: A continuous version of the
2068 Softlight function, producing very similar results.
2070 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2072 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2074 if (fabs(Da) < MagickEpsilon)
2076 pixel=QuantumRange*gamma*(Sca);
2079 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2083 case PinLightCompositeOp:
2086 PinLight: A Photoshop 7 composition method
2087 http://www.simplefilter.de/en/basics/mixmods.html
2089 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2091 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2093 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2096 if ((Dca*Sa) > (2.0*Sca*Da))
2098 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2101 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2104 case PlusCompositeOp:
2106 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
2109 case SaturateCompositeOp:
2111 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2116 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2121 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
2122 GetPixelBlue(image,q),&hue,&saturation,&brightness);
2123 CompositeHSB(GetPixelRed(composite_image,p),
2124 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
2125 &sans,&saturation,&sans);
2126 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
2129 case RedPixelChannel: pixel=red; break;
2130 case GreenPixelChannel: pixel=green; break;
2131 case BluePixelChannel: pixel=blue; break;
2132 default: pixel=Dc; break;
2136 case ScreenCompositeOp:
2139 Screen: a negated multiply:
2141 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2143 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2146 case SoftLightCompositeOp:
2149 Refer to the March 2009 SVG specification.
2153 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2154 Sca*(1.0-Da)+Dca*(1.0-Sa));
2157 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2159 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2160 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2164 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2165 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2168 case ThresholdCompositeOp:
2174 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2179 pixel=gamma*(Dc+delta*amount);
2182 case VividLightCompositeOp:
2185 VividLight: A Photoshop 7 composition method. See
2186 http://www.simplefilter.de/en/basics/mixmods.html.
2188 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2190 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2192 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2195 if ((2.0*Sca) <= Sa)
2197 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2198 (1.0-Da)+Dca*(1.0-Sa));
2201 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2205 case XorCompositeOp:
2207 pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2216 q[i]=ClampToQuantum(pixel);
2218 p+=GetPixelChannels(composite_image);
2219 channels=GetPixelChannels(composite_image);
2220 if (p >= (pixels+channels*composite_image->columns))
2222 q+=GetPixelChannels(image);
2224 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2226 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2231 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2232 #pragma omp critical (MagickCore_CompositeImage)
2234 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2236 if (proceed == MagickFalse)
2240 composite_view=DestroyCacheView(composite_view);
2241 image_view=DestroyCacheView(image_view);
2242 if (destination_image != (Image * ) NULL)
2243 destination_image=DestroyImage(destination_image);
2248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2252 % T e x t u r e I m a g e %
2256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2258 % TextureImage() repeatedly tiles the texture image across and down the image
2261 % The format of the TextureImage method is:
2263 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2264 % ExceptionInfo *exception)
2266 % A description of each parameter follows:
2268 % o image: the image.
2270 % o texture_image: This image is the texture to layer on the background.
2273 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
2274 ExceptionInfo *exception)
2276 #define TextureImageTag "Texture/Image"
2291 assert(image != (Image *) NULL);
2292 if (image->debug != MagickFalse)
2293 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2294 assert(image->signature == MagickSignature);
2295 if (texture == (const Image *) NULL)
2296 return(MagickFalse);
2297 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2298 return(MagickFalse);
2299 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2300 if (texture_image == (const Image *) NULL)
2301 return(MagickFalse);
2302 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
2305 if ((image->compose != CopyCompositeOp) &&
2306 ((image->compose != OverCompositeOp) || (image->matte != MagickFalse) ||
2307 (texture_image->matte != MagickFalse)))
2310 Tile texture onto the image background.
2312 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2313 #pragma omp parallel for schedule(static) shared(status)
2315 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2320 if (status == MagickFalse)
2322 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2327 thread_status=CompositeImage(image,texture_image,image->compose,
2328 MagickFalse,x+texture_image->tile_offset.x,y+
2329 texture_image->tile_offset.y,exception);
2330 if (thread_status == MagickFalse)
2332 status=thread_status;
2336 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2341 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2342 #pragma omp critical (MagickCore_TextureImage)
2344 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2346 if (proceed == MagickFalse)
2350 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2351 image->rows,image->rows);
2352 texture_image=DestroyImage(texture_image);
2356 Tile texture onto the image background (optimized).
2359 image_view=AcquireCacheView(image);
2360 texture_view=AcquireCacheView(texture_image);
2361 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2362 #pragma omp parallel for schedule(static) shared(status)
2364 for (y=0; y < (ssize_t) image->rows; y++)
2369 register const Quantum
2382 if (status == MagickFalse)
2384 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2385 (y+texture_image->tile_offset.y) % texture_image->rows,
2386 texture_image->columns,1,exception);
2387 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2388 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2393 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2399 width=texture_image->columns;
2400 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2401 width=image->columns-x;
2402 for (j=0; j < (ssize_t) width; j++)
2407 if (GetPixelMask(image,p) != 0)
2409 p+=GetPixelChannels(texture_image);
2410 q+=GetPixelChannels(image);
2413 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2422 channel=GetPixelChannelMapChannel(texture_image,i);
2423 texture_traits=GetPixelChannelMapTraits(texture_image,channel);
2424 traits=GetPixelChannelMapTraits(image,channel);
2425 if ((traits == UndefinedPixelTrait) ||
2426 (texture_traits == UndefinedPixelTrait))
2428 SetPixelChannel(image,channel,p[i],q);
2430 p+=GetPixelChannels(texture_image);
2431 q+=GetPixelChannels(image);
2434 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2435 if (sync == MagickFalse)
2437 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2442 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2443 #pragma omp critical (MagickCore_TextureImage)
2445 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2447 if (proceed == MagickFalse)
2451 texture_view=DestroyCacheView(texture_view);
2452 image_view=DestroyCacheView(image_view);
2453 texture_image=DestroyImage(texture_image);