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,
295 Prepare composite image.
297 modify_outside_overlay=MagickFalse;
298 value=GetImageArtifact(composite_image,"compose:outside-overlay");
299 if (value != (const char *) NULL)
300 modify_outside_overlay=IsMagickTrue(value);
306 image_view=AcquireCacheView(image);
307 composite_view=AcquireCacheView(composite_image);
308 #if defined(MAGICKCORE_OPENMP_SUPPORT)
309 #pragma omp parallel for schedule(static,4) shared(progress,status)
311 for (y=0; y < (ssize_t) image->rows; y++)
316 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 if (GetPixelMask(image,q) != 0)
397 q+=GetPixelChannels(image);
400 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
402 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
411 channel=GetPixelChannelMapChannel(image,i);
412 traits=GetPixelChannelMapTraits(image,channel);
413 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
414 if ((traits == UndefinedPixelTrait) ||
415 (composite_traits == UndefinedPixelTrait))
417 q[i]=source[channel];
419 q+=GetPixelChannels(image);
424 Sa: normalized source alpha.
425 Da: normalized destination alpha.
427 if (GetPixelMask(composite_image,p) != 0)
429 p+=GetPixelChannels(composite_image);
430 channels=GetPixelChannels(composite_image);
431 if (p >= (pixels+channels*composite_image->columns))
433 q+=GetPixelChannels(image);
436 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
437 Da=QuantumScale*GetPixelAlpha(image,q);
438 alpha=Sa*(-Da)+Sa+Da;
439 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
448 channel=GetPixelChannelMapChannel(image,i);
449 traits=GetPixelChannelMapTraits(image,channel);
450 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
451 if ((traits == UndefinedPixelTrait) ||
452 (composite_traits == UndefinedPixelTrait))
454 if ((traits & CopyPixelTrait) != 0)
456 if (channel != AlphaPixelChannel)
461 q[i]=GetPixelChannel(composite_image,channel,p);
467 q[i]=ClampToQuantum(QuantumRange*alpha);
472 Dc: destination color.
474 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
475 Dc=(MagickRealType) q[i];
476 gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
477 q[i]=ClampToQuantum(gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc));
479 p+=GetPixelChannels(composite_image);
480 channels=GetPixelChannels(composite_image);
481 if (p >= (pixels+channels*composite_image->columns))
483 q+=GetPixelChannels(image);
485 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
487 if (image->progress_monitor != (MagickProgressMonitor) NULL)
492 #if defined(MAGICKCORE_OPENMP_SUPPORT)
493 #pragma omp critical (MagickCore_CompositeImage)
495 proceed=SetImageProgress(image,CompositeImageTag,progress++,
497 if (proceed == MagickFalse)
501 composite_view=DestroyCacheView(composite_view);
502 image_view=DestroyCacheView(image_view);
506 MagickExport MagickBooleanType CompositeImage(Image *image,
507 const CompositeOperator compose,const Image *composite_image,
508 const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
510 #define CompositeImageTag "Composite/Image"
526 modify_outside_overlay,
534 destination_dissolve,
548 Composition based on the SVG specification:
550 A Composition is defined by...
551 Color Function : f(Sc,Dc) where Sc and Dc are the normizalized colors
552 Blending areas : X = 1 for area of overlap, ie: f(Sc,Dc)
553 Y = 1 for source preserved
554 Z = 1 for destination preserved
556 Conversion to transparency (then optimized)
557 Dca' = f(Sc, Dc)*Sa*Da + Y*Sca*(1-Da) + Z*Dca*(1-Sa)
558 Da' = X*Sa*Da + Y*Sa*(1-Da) + Z*Da*(1-Sa)
561 Sca = Sc*Sa normalized Source color divided by Source alpha
562 Dca = Dc*Da normalized Dest color divided by Dest alpha
563 Dc' = Dca'/Da' the desired color value for this channel.
565 Da' in in the follow formula as 'gamma' The resulting alpla value.
567 Most functions use a blending mode of over (X=1,Y=1,Z=1) this results in
568 the following optimizations...
570 gamma = 1 - QuantiumScale*alpha * QuantiumScale*beta;
571 opacity = QuantiumScale*alpha*beta; // over blend, optimized 1-Gamma
573 The above SVG definitions also definate that Mathematical Composition
574 methods should use a 'Over' blending mode for Alpha Channel.
575 It however was not applied for composition modes of 'Plus', 'Minus',
576 the modulus versions of 'Add' and 'Subtract'.
578 Mathematical operator changes to be applied from IM v6.7...
580 1) Modulus modes 'Add' and 'Subtract' are obsoleted and renamed
581 'ModulusAdd' and 'ModulusSubtract' for clarity.
583 2) All mathematical compositions work as per the SVG specification
584 with regard to blending. This now includes 'ModulusAdd' and
587 3) When the special channel flag 'sync' (syncronize channel updates)
588 is turned off (enabled by default) then mathematical compositions are
589 only performed on the channels specified, and are applied
590 independantally of each other. In other words the mathematics is
591 performed as 'pure' mathematical operations, rather than as image
594 assert(image != (Image *) NULL);
595 assert(image->signature == MagickSignature);
596 if (image->debug != MagickFalse)
597 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
598 assert(composite_image != (Image *) NULL);
599 assert(composite_image->signature == MagickSignature);
600 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
602 if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
604 status=CompositeOverImage(image,composite_image,x_offset,y_offset,
608 destination_image=(Image *) NULL;
610 destination_dissolve=1.0;
611 modify_outside_overlay=MagickFalse;
612 percent_brightness=100.0;
613 percent_saturation=100.0;
618 case ClearCompositeOp:
619 case DstAtopCompositeOp:
620 case DstInCompositeOp:
624 case SrcInCompositeOp:
625 case SrcOutCompositeOp:
628 Modify destination outside the overlaid region.
630 modify_outside_overlay=MagickTrue;
633 case CopyCompositeOp:
635 if ((x_offset < 0) || (y_offset < 0))
637 if ((x_offset+(ssize_t) composite_image->columns) >= (ssize_t) image->columns)
639 if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
642 image_view=AcquireCacheView(image);
643 composite_view=AcquireCacheView(composite_image);
644 #if defined(MAGICKCORE_OPENMP_SUPPORT)
645 #pragma omp parallel for schedule(static,4) shared(status)
647 for (y=0; y < (ssize_t) composite_image->rows; y++)
652 register const Quantum
661 if (status == MagickFalse)
663 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
665 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
666 composite_image->columns,1,exception);
667 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
672 for (x=0; x < (ssize_t) composite_image->columns; x++)
677 if (GetPixelMask(image,p) != 0)
679 p+=GetPixelChannels(composite_image);
680 q+=GetPixelChannels(image);
683 for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
692 channel=GetPixelChannelMapChannel(composite_image,i);
693 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
694 traits=GetPixelChannelMapTraits(image,channel);
695 if ((traits == UndefinedPixelTrait) ||
696 (composite_traits == UndefinedPixelTrait))
698 SetPixelChannel(image,channel,p[i],q);
700 p+=GetPixelChannels(composite_image);
701 q+=GetPixelChannels(image);
703 sync=SyncCacheViewAuthenticPixels(image_view,exception);
704 if (sync == MagickFalse)
706 if (image->progress_monitor != (MagickProgressMonitor) NULL)
711 #if defined(MAGICKCORE_OPENMP_SUPPORT)
712 #pragma omp critical (MagickCore_CompositeImage)
714 proceed=SetImageProgress(image,CompositeImageTag,
715 (MagickOffsetType) y,image->rows);
716 if (proceed == MagickFalse)
720 composite_view=DestroyCacheView(composite_view);
721 image_view=DestroyCacheView(image_view);
724 case CopyAlphaCompositeOp:
725 case ChangeMaskCompositeOp:
726 case IntensityCompositeOp:
729 Modify destination outside the overlaid region and require an alpha
730 channel to exist, to add transparency.
732 if (image->matte == MagickFalse)
733 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
734 modify_outside_overlay=MagickTrue;
737 case BlurCompositeOp:
759 Blur Image dictated by an overlay gradient map: X = red_channel;
760 Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
762 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
764 if (destination_image == (Image *) NULL)
767 Determine the horizontal and vertical maximim blur.
769 SetGeometryInfo(&geometry_info);
771 value=GetImageArtifact(composite_image,"compose:args");
772 if (value != (char *) NULL)
773 flags=ParseGeometry(value,&geometry_info);
774 if ((flags & WidthValue) == 0 )
776 destination_image=DestroyImage(destination_image);
779 width=geometry_info.rho;
780 height=geometry_info.sigma;
781 blur.x1=geometry_info.rho;
784 blur.y2=geometry_info.sigma;
787 if ((flags & HeightValue) == 0)
789 if ((flags & XValue) != 0 )
794 angle=DegreesToRadians(geometry_info.xi);
795 blur.x1=width*cos(angle);
796 blur.x2=width*sin(angle);
797 blur.y1=(-height*sin(angle));
798 blur.y2=height*cos(angle);
800 if ((flags & YValue) != 0 )
802 angle_start=DegreesToRadians(geometry_info.xi);
803 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
806 Blur Image by resampling.
808 resample_filter=AcquireResampleFilter(image,exception);
809 SetResampleFilter(resample_filter,CubicFilter,2.0);
810 destination_view=AcquireCacheView(destination_image);
811 composite_view=AcquireCacheView(composite_image);
812 for (y=0; y < (ssize_t) composite_image->rows; y++)
817 register const Quantum
826 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
828 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
830 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
831 destination_image->columns,1,exception);
832 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
834 for (x=0; x < (ssize_t) composite_image->columns; x++)
836 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
838 p+=GetPixelChannels(composite_image);
841 if (fabs(angle_range) > MagickEpsilon)
846 angle=angle_start+angle_range*QuantumScale*
847 GetPixelBlue(composite_image,p);
848 blur.x1=width*cos(angle);
849 blur.x2=width*sin(angle);
850 blur.y1=(-height*sin(angle));
851 blur.y2=height*cos(angle);
853 ScaleResampleFilter(resample_filter,blur.x1*QuantumScale*
854 GetPixelRed(composite_image,p),blur.y1*QuantumScale*
855 GetPixelGreen(composite_image,p),blur.x2*QuantumScale*
856 GetPixelRed(composite_image,p),blur.y2*QuantumScale*
857 GetPixelGreen(composite_image,p));
858 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
859 (double) y_offset+y,&pixel);
860 SetPixelInfoPixel(destination_image,&pixel,q);
861 p+=GetPixelChannels(composite_image);
862 q+=GetPixelChannels(destination_image);
864 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
865 if (sync == MagickFalse)
868 resample_filter=DestroyResampleFilter(resample_filter);
869 composite_view=DestroyCacheView(composite_view);
870 destination_view=DestroyCacheView(destination_view);
871 composite_image=destination_image;
874 case DisplaceCompositeOp:
875 case DistortCompositeOp:
894 Displace/Distort based on overlay gradient map:
895 X = red_channel; Y = green_channel;
896 compose:args = x_scale[,y_scale[,center.x,center.y]]
898 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
900 if (destination_image == (Image *) NULL)
902 SetGeometryInfo(&geometry_info);
904 value=GetImageArtifact(composite_image,"compose:args");
905 if (value != (char *) NULL)
906 flags=ParseGeometry(value,&geometry_info);
907 if ((flags & (WidthValue|HeightValue)) == 0 )
909 if ((flags & AspectValue) == 0)
911 horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
913 vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
917 horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
918 vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
923 horizontal_scale=geometry_info.rho;
924 vertical_scale=geometry_info.sigma;
925 if ((flags & PercentValue) != 0)
927 if ((flags & AspectValue) == 0)
929 horizontal_scale*=(composite_image->columns-1.0)/200.0;
930 vertical_scale*=(composite_image->rows-1.0)/200.0;
934 horizontal_scale*=(image->columns-1.0)/200.0;
935 vertical_scale*=(image->rows-1.0)/200.0;
938 if ((flags & HeightValue) == 0)
939 vertical_scale=horizontal_scale;
942 Determine fixed center point for absolute distortion map
944 Displace offset relative to a fixed absolute point
945 Select that point according to +X+Y user inputs.
946 default = center of overlay image
947 arg flag '!' = locations/percentage relative to background image
949 center.x=(MagickRealType) x_offset;
950 center.y=(MagickRealType) y_offset;
951 if (compose == DistortCompositeOp)
953 if ((flags & XValue) == 0)
954 if ((flags & AspectValue) == 0)
955 center.x=(MagickRealType) x_offset+(composite_image->columns-1)/
958 center.x=((MagickRealType) image->columns-1)/2.0;
960 if ((flags & AspectValue) == 0)
961 center.x=(MagickRealType) x_offset+geometry_info.xi;
963 center.x=geometry_info.xi;
964 if ((flags & YValue) == 0)
965 if ((flags & AspectValue) == 0)
966 center.y=(MagickRealType) y_offset+(composite_image->rows-1)/2.0;
968 center.y=((MagickRealType) image->rows-1)/2.0;
970 if ((flags & AspectValue) == 0)
971 center.y=(MagickRealType) y_offset+geometry_info.psi;
973 center.y=geometry_info.psi;
976 Shift the pixel offset point as defined by the provided,
977 displacement/distortion map. -- Like a lens...
979 GetPixelInfo(image,&pixel);
980 image_view=AcquireCacheView(image);
981 destination_view=AcquireCacheView(destination_image);
982 composite_view=AcquireCacheView(composite_image);
983 for (y=0; y < (ssize_t) composite_image->rows; y++)
988 register const Quantum
997 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
999 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
1001 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
1002 destination_image->columns,1,exception);
1003 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1005 for (x=0; x < (ssize_t) composite_image->columns; x++)
1007 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1009 p+=GetPixelChannels(composite_image);
1013 Displace the offset.
1015 offset.x=(horizontal_scale*(GetPixelRed(composite_image,p)-
1016 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1017 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
1019 offset.y=(vertical_scale*(GetPixelGreen(composite_image,p)-
1020 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1021 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
1023 (void) InterpolatePixelInfo(image,image_view,
1024 UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1027 Mask with the 'invalid pixel mask' in alpha channel.
1029 pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
1030 pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
1031 SetPixelInfoPixel(destination_image,&pixel,q);
1032 p+=GetPixelChannels(composite_image);
1033 q+=GetPixelChannels(destination_image);
1035 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1036 if (sync == MagickFalse)
1039 destination_view=DestroyCacheView(destination_view);
1040 composite_view=DestroyCacheView(composite_view);
1041 image_view=DestroyCacheView(image_view);
1042 composite_image=destination_image;
1045 case DissolveCompositeOp:
1048 Geometry arguments to dissolve factors.
1050 value=GetImageArtifact(composite_image,"compose:args");
1051 if (value != (char *) NULL)
1053 flags=ParseGeometry(value,&geometry_info);
1054 source_dissolve=geometry_info.rho/100.0;
1055 destination_dissolve=1.0;
1056 if ((source_dissolve-MagickEpsilon) < 0.0)
1057 source_dissolve=0.0;
1058 if ((source_dissolve+MagickEpsilon) > 1.0)
1060 destination_dissolve=2.0-source_dissolve;
1061 source_dissolve=1.0;
1063 if ((flags & SigmaValue) != 0)
1064 destination_dissolve=geometry_info.sigma/100.0;
1065 if ((destination_dissolve-MagickEpsilon) < 0.0)
1066 destination_dissolve=0.0;
1067 modify_outside_overlay=MagickTrue;
1068 if ((destination_dissolve+MagickEpsilon) > 1.0 )
1070 destination_dissolve=1.0;
1071 modify_outside_overlay=MagickFalse;
1076 case BlendCompositeOp:
1078 value=GetImageArtifact(composite_image,"compose:args");
1079 if (value != (char *) NULL)
1081 flags=ParseGeometry(value,&geometry_info);
1082 source_dissolve=geometry_info.rho/100.0;
1083 destination_dissolve=1.0-source_dissolve;
1084 if ((flags & SigmaValue) != 0)
1085 destination_dissolve=geometry_info.sigma/100.0;
1086 modify_outside_overlay=MagickTrue;
1087 if ((destination_dissolve+MagickEpsilon) > 1.0)
1088 modify_outside_overlay=MagickFalse;
1092 case MathematicsCompositeOp:
1095 Just collect the values from "compose:args", setting.
1096 Unused values are set to zero automagically.
1098 Arguments are normally a comma separated list, so this probably should
1099 be changed to some 'general comma list' parser, (with a minimum
1102 SetGeometryInfo(&geometry_info);
1103 value=GetImageArtifact(composite_image,"compose:args");
1104 if (value != (char *) NULL)
1105 (void) ParseGeometry(value,&geometry_info);
1108 case ModulateCompositeOp:
1111 Determine the brightness and saturation scale.
1113 value=GetImageArtifact(composite_image,"compose:args");
1114 if (value != (char *) NULL)
1116 flags=ParseGeometry(value,&geometry_info);
1117 percent_brightness=geometry_info.rho;
1118 if ((flags & SigmaValue) != 0)
1119 percent_saturation=geometry_info.sigma;
1123 case ThresholdCompositeOp:
1126 Determine the amount and threshold.
1128 value=GetImageArtifact(composite_image,"compose:args");
1129 if (value != (char *) NULL)
1131 flags=ParseGeometry(value,&geometry_info);
1132 amount=geometry_info.rho;
1133 threshold=geometry_info.sigma;
1134 if ((flags & SigmaValue) == 0)
1137 threshold*=QuantumRange;
1143 value=GetImageArtifact(composite_image,"compose:outside-overlay");
1144 if (value != (const char *) NULL)
1145 modify_outside_overlay=IsMagickTrue(value);
1151 midpoint=((MagickRealType) QuantumRange+1.0)/2;
1152 image_view=AcquireCacheView(image);
1153 composite_view=AcquireCacheView(composite_image);
1154 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1155 #pragma omp parallel for schedule(static,4) shared(progress,status)
1157 for (y=0; y < (ssize_t) image->rows; y++)
1170 register const Quantum
1179 if (status == MagickFalse)
1181 if (modify_outside_overlay == MagickFalse)
1185 if ((y-y_offset) >= (ssize_t) composite_image->rows)
1189 If pixels is NULL, y is outside overlay region.
1191 pixels=(Quantum *) NULL;
1193 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
1195 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
1196 composite_image->columns,1,exception);
1197 if (p == (const Quantum *) NULL)
1204 p-=x_offset*GetPixelChannels(composite_image);
1206 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1207 if (q == (Quantum *) NULL)
1215 for (x=0; x < (ssize_t) image->columns; x++)
1233 if (modify_outside_overlay == MagickFalse)
1237 q+=GetPixelChannels(image);
1240 if ((x-x_offset) >= (ssize_t) composite_image->columns)
1243 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1244 ((x-x_offset) >= (ssize_t) composite_image->columns))
1247 source[MaxPixelChannels];
1252 Dc: destination color.
1254 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
1256 if (GetPixelMask(image,q) != 0)
1258 q+=GetPixelChannels(image);
1261 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1273 channel=GetPixelChannelMapChannel(image,i);
1274 traits=GetPixelChannelMapTraits(image,channel);
1275 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
1276 if ((traits == UndefinedPixelTrait) ||
1277 (composite_traits == UndefinedPixelTrait))
1281 case AlphaCompositeOp:
1282 case ChangeMaskCompositeOp:
1283 case CopyAlphaCompositeOp:
1284 case DstAtopCompositeOp:
1285 case DstInCompositeOp:
1287 case IntensityCompositeOp:
1288 case OutCompositeOp:
1289 case SrcInCompositeOp:
1290 case SrcOutCompositeOp:
1292 pixel=(MagickRealType) q[i];
1293 if (channel == AlphaPixelChannel)
1294 pixel=(MagickRealType) TransparentAlpha;
1297 case ClearCompositeOp:
1298 case CopyCompositeOp:
1299 case ReplaceCompositeOp:
1300 case SrcCompositeOp:
1302 if (channel == AlphaPixelChannel)
1304 pixel=(MagickRealType) TransparentAlpha;
1310 case BlendCompositeOp:
1311 case DissolveCompositeOp:
1313 if (channel == AlphaPixelChannel)
1315 pixel=destination_dissolve*GetPixelAlpha(composite_image,
1319 pixel=(MagickRealType) source[channel];
1324 pixel=(MagickRealType) source[channel];
1328 q[i]=ClampToQuantum(pixel);
1330 q+=GetPixelChannels(image);
1334 Authentic composite:
1335 Sa: normalized source alpha.
1336 Da: normalized destination alpha.
1338 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
1339 Da=QuantumScale*GetPixelAlpha(image,q);
1342 case BumpmapCompositeOp:
1344 alpha=GetPixelIntensity(composite_image,p)*Sa;
1347 case ColorBurnCompositeOp:
1348 case ColorDodgeCompositeOp:
1349 case DifferenceCompositeOp:
1350 case DivideDstCompositeOp:
1351 case DivideSrcCompositeOp:
1352 case ExclusionCompositeOp:
1353 case HardLightCompositeOp:
1354 case LinearBurnCompositeOp:
1355 case LinearDodgeCompositeOp:
1356 case LinearLightCompositeOp:
1357 case MathematicsCompositeOp:
1358 case MinusDstCompositeOp:
1359 case MinusSrcCompositeOp:
1360 case ModulusAddCompositeOp:
1361 case ModulusSubtractCompositeOp:
1362 case MultiplyCompositeOp:
1363 case OverlayCompositeOp:
1364 case PegtopLightCompositeOp:
1365 case PinLightCompositeOp:
1366 case ScreenCompositeOp:
1367 case SoftLightCompositeOp:
1368 case VividLightCompositeOp:
1370 alpha=RoundToUnity(Sa+Da-Sa*Da);
1373 case DarkenCompositeOp:
1374 case DstAtopCompositeOp:
1375 case DstInCompositeOp:
1377 case LightenCompositeOp:
1378 case SrcInCompositeOp:
1383 case DissolveCompositeOp:
1385 alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
1386 Sa+destination_dissolve*Da;
1389 case DstOverCompositeOp:
1391 alpha=Da*(-Sa)+Da+Sa;
1394 case DstOutCompositeOp:
1399 case OutCompositeOp:
1400 case SrcOutCompositeOp:
1405 case OverCompositeOp:
1406 case SrcOverCompositeOp:
1408 alpha=Sa*(-Da)+Sa+Da;
1411 case BlendCompositeOp:
1412 case PlusCompositeOp:
1414 alpha=RoundToUnity(Sa+Da);
1417 case XorCompositeOp:
1419 alpha=Sa+Da-2.0*Sa*Da;
1428 if (GetPixelMask(image,p) != 0)
1430 p+=GetPixelChannels(composite_image);
1431 q+=GetPixelChannels(image);
1434 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1449 channel=GetPixelChannelMapChannel(image,i);
1450 traits=GetPixelChannelMapTraits(image,channel);
1451 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
1452 if (traits == UndefinedPixelTrait)
1454 if ((compose != IntensityCompositeOp) &&
1455 (composite_traits == UndefinedPixelTrait))
1459 Dc: destination color.
1461 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
1462 Dc=(MagickRealType) q[i];
1463 if ((traits & CopyPixelTrait) != 0)
1465 if (channel != AlphaPixelChannel)
1470 q[i]=ClampToQuantum(Sc);
1478 case AlphaCompositeOp:
1480 pixel=QuantumRange*Sa;
1483 case AtopCompositeOp:
1484 case CopyBlackCompositeOp:
1485 case CopyBlueCompositeOp:
1486 case CopyCyanCompositeOp:
1487 case CopyGreenCompositeOp:
1488 case CopyMagentaCompositeOp:
1489 case CopyRedCompositeOp:
1490 case CopyYellowCompositeOp:
1491 case SrcAtopCompositeOp:
1492 case DstCompositeOp:
1495 pixel=QuantumRange*Da;
1498 case ChangeMaskCompositeOp:
1503 if (Da > ((MagickRealType) QuantumRange/2.0))
1505 pixel=(MagickRealType) TransparentAlpha;
1508 equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
1509 if (equivalent != MagickFalse)
1511 pixel=(MagickRealType) TransparentAlpha;
1514 pixel=(MagickRealType) OpaqueAlpha;
1517 case ClearCompositeOp:
1519 pixel=(MagickRealType) TransparentAlpha;
1522 case ColorizeCompositeOp:
1523 case HueCompositeOp:
1524 case LuminizeCompositeOp:
1525 case SaturateCompositeOp:
1527 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1529 pixel=QuantumRange*Da;
1532 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1534 pixel=QuantumRange*Sa;
1539 pixel=QuantumRange*Da;
1542 pixel=QuantumRange*Sa;
1545 case CopyCompositeOp:
1546 case CopyAlphaCompositeOp:
1547 case DisplaceCompositeOp:
1548 case DistortCompositeOp:
1549 case DstAtopCompositeOp:
1550 case ReplaceCompositeOp:
1551 case SrcCompositeOp:
1553 pixel=QuantumRange*Sa;
1556 case DarkenIntensityCompositeOp:
1558 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1559 (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
1562 case IntensityCompositeOp:
1564 pixel=(MagickRealType) GetPixelIntensity(composite_image,p);
1567 case LightenIntensityCompositeOp:
1569 pixel=Sa*GetPixelIntensity(composite_image,p) >
1570 Da*GetPixelIntensity(image,q) ? Sa : Da;
1573 case ModulateCompositeOp:
1575 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1577 pixel=QuantumRange*Da;
1580 pixel=QuantumRange*Da;
1585 pixel=QuantumRange*alpha;
1589 q[i]=ClampToQuantum(pixel);
1593 Porter-Duff compositions:
1594 Sca: source normalized color multiplied by alpha.
1595 Dca: normalized destination color multiplied by alpha.
1597 Sca=QuantumScale*Sa*Sc;
1598 Dca=QuantumScale*Da*Dc;
1601 case DarkenCompositeOp:
1602 case LightenCompositeOp:
1603 case ModulusSubtractCompositeOp:
1611 gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
1615 case AlphaCompositeOp:
1617 pixel=QuantumRange*Sa;
1620 case AtopCompositeOp:
1621 case SrcAtopCompositeOp:
1623 pixel=Sc*Sa+Dc*(1.0-Sa);
1626 case BlendCompositeOp:
1628 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1631 case BlurCompositeOp:
1632 case DisplaceCompositeOp:
1633 case DistortCompositeOp:
1634 case CopyCompositeOp:
1635 case ReplaceCompositeOp:
1636 case SrcCompositeOp:
1641 case BumpmapCompositeOp:
1643 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1648 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1651 case ChangeMaskCompositeOp:
1656 case ClearCompositeOp:
1661 case ColorBurnCompositeOp:
1664 Refer to the March 2009 SVG specification.
1666 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1668 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1671 if (Sca < MagickEpsilon)
1673 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1676 pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
1677 Sca*(1.0-Da)+Dca*(1.0-Sa));
1680 case ColorDodgeCompositeOp:
1682 if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1684 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1687 if (fabs(Sca-Sa) < MagickEpsilon)
1689 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1692 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1696 case ColorizeCompositeOp:
1698 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1703 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1708 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1709 GetPixelBlue(image,q),&sans,&sans,&brightness);
1710 CompositeHSB(GetPixelRed(composite_image,p),
1711 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1712 &hue,&saturation,&sans);
1713 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1716 case RedPixelChannel: pixel=red; break;
1717 case GreenPixelChannel: pixel=green; break;
1718 case BluePixelChannel: pixel=blue; break;
1719 default: pixel=Dc; break;
1723 case CopyAlphaCompositeOp:
1724 case IntensityCompositeOp:
1726 if (channel == AlphaPixelChannel)
1727 pixel=(MagickRealType) GetPixelAlpha(composite_image,p);
1730 case CopyBlackCompositeOp:
1732 if (channel == BlackPixelChannel)
1733 pixel=(MagickRealType) GetPixelBlack(composite_image,p);
1736 case CopyBlueCompositeOp:
1737 case CopyYellowCompositeOp:
1739 if (channel == BluePixelChannel)
1740 pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1743 case CopyGreenCompositeOp:
1744 case CopyMagentaCompositeOp:
1746 if (channel == GreenPixelChannel)
1747 pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1750 case CopyRedCompositeOp:
1751 case CopyCyanCompositeOp:
1753 if (channel == RedPixelChannel)
1754 pixel=(MagickRealType) GetPixelRed(composite_image,p);
1757 case DarkenCompositeOp:
1760 Darken is equivalent to a 'Minimum' method
1761 OR a greyscale version of a binary 'Or'
1762 OR the 'Intersection' of pixel sets.
1766 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1769 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1772 case DarkenIntensityCompositeOp:
1774 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1775 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1778 case DifferenceCompositeOp:
1780 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1783 case DissolveCompositeOp:
1785 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1786 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1789 case DivideDstCompositeOp:
1791 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1793 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1796 if (fabs(Dca) < MagickEpsilon)
1798 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1801 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1804 case DivideSrcCompositeOp:
1806 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1808 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1811 if (fabs(Sca) < MagickEpsilon)
1813 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1816 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1819 case DstAtopCompositeOp:
1821 pixel=Dc*Da+Sc*(1.0-Da);
1824 case DstCompositeOp:
1830 case DstInCompositeOp:
1832 pixel=gamma*(Sa*Dc*Sa);
1835 case DstOutCompositeOp:
1837 pixel=gamma*(Da*Dc*(1.0-Sa));
1840 case DstOverCompositeOp:
1842 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1845 case ExclusionCompositeOp:
1847 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1851 case HardLightCompositeOp:
1855 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1859 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1863 case HueCompositeOp:
1865 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1870 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1875 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1876 GetPixelBlue(image,q),&hue,&saturation,&brightness);
1877 CompositeHSB(GetPixelRed(composite_image,p),
1878 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1880 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1883 case RedPixelChannel: pixel=red; break;
1884 case GreenPixelChannel: pixel=green; break;
1885 case BluePixelChannel: pixel=blue; break;
1886 default: pixel=Dc; break;
1891 case SrcInCompositeOp:
1893 pixel=gamma*(Da*Sc*Da);
1896 case LinearBurnCompositeOp:
1899 LinearBurn: as defined by Abode Photoshop, according to
1900 http://www.simplefilter.de/en/basics/mixmods.html is:
1902 f(Sc,Dc) = Sc + Dc - 1
1904 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1907 case LinearDodgeCompositeOp:
1909 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1912 case LinearLightCompositeOp:
1915 LinearLight: as defined by Abode Photoshop, according to
1916 http://www.simplefilter.de/en/basics/mixmods.html is:
1918 f(Sc,Dc) = Dc + 2*Sc - 1
1920 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1923 case LightenCompositeOp:
1927 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1930 pixel=QuantumRange*gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1933 case LightenIntensityCompositeOp:
1936 Lighten is equivalent to a 'Maximum' method
1937 OR a greyscale version of a binary 'And'
1938 OR the 'Union' of pixel sets.
1940 pixel=Sa*GetPixelIntensity(composite_image,p) >
1941 Da*GetPixelIntensity(image,q) ? Sc : Dc;
1944 case LuminizeCompositeOp:
1946 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1951 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1956 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1957 GetPixelBlue(image,q),&hue,&saturation,&brightness);
1958 CompositeHSB(GetPixelRed(composite_image,p),
1959 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1960 &sans,&sans,&brightness);
1961 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1964 case RedPixelChannel: pixel=red; break;
1965 case GreenPixelChannel: pixel=green; break;
1966 case BluePixelChannel: pixel=blue; break;
1967 default: pixel=Dc; break;
1971 case MathematicsCompositeOp:
1974 'Mathematics' a free form user control mathematical composition
1977 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
1979 Where the arguments A,B,C,D are (currently) passed to composite
1980 as a command separated 'geometry' string in "compose:args" image
1983 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
1985 Applying the SVG transparency formula (see above), we get...
1987 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
1989 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
1992 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
1993 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
1994 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
1997 case MinusDstCompositeOp:
1999 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2002 case MinusSrcCompositeOp:
2005 Minus source from destination.
2009 pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2012 case ModulateCompositeOp:
2017 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2022 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
2028 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
2029 GetPixelBlue(image,q),&hue,&saturation,&brightness);
2030 brightness+=(0.01*percent_brightness*offset)/midpoint;
2031 saturation*=0.01*percent_saturation;
2032 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
2035 case RedPixelChannel: pixel=red; break;
2036 case GreenPixelChannel: pixel=green; break;
2037 case BluePixelChannel: pixel=blue; break;
2038 default: pixel=Dc; break;
2042 case ModulusAddCompositeOp:
2045 if (pixel > QuantumRange)
2046 pixel-=(QuantumRange+1.0);
2047 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2050 case ModulusSubtractCompositeOp:
2054 pixel+=(QuantumRange+1.0);
2055 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2058 case MultiplyCompositeOp:
2060 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2063 case OutCompositeOp:
2064 case SrcOutCompositeOp:
2066 pixel=gamma*(Sa*Sc*(1.0-Da));
2069 case OverCompositeOp:
2070 case SrcOverCompositeOp:
2072 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2075 case OverlayCompositeOp:
2079 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2083 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2087 case PegtopLightCompositeOp:
2090 PegTop: A Soft-Light alternative: A continuous version of the
2091 Softlight function, producing very similar results.
2093 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2095 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2097 if (fabs(Da) < MagickEpsilon)
2099 pixel=QuantumRange*gamma*(Sca);
2102 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2106 case PinLightCompositeOp:
2109 PinLight: A Photoshop 7 composition method
2110 http://www.simplefilter.de/en/basics/mixmods.html
2112 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2114 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2116 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2119 if ((Dca*Sa) > (2.0*Sca*Da))
2121 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2124 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2127 case PlusCompositeOp:
2129 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
2132 case SaturateCompositeOp:
2134 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2139 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2144 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
2145 GetPixelBlue(image,q),&hue,&saturation,&brightness);
2146 CompositeHSB(GetPixelRed(composite_image,p),
2147 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
2148 &sans,&saturation,&sans);
2149 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
2152 case RedPixelChannel: pixel=red; break;
2153 case GreenPixelChannel: pixel=green; break;
2154 case BluePixelChannel: pixel=blue; break;
2155 default: pixel=Dc; break;
2159 case ScreenCompositeOp:
2162 Screen: a negated multiply:
2164 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2166 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2169 case SoftLightCompositeOp:
2172 Refer to the March 2009 SVG specification.
2176 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2177 Sca*(1.0-Da)+Dca*(1.0-Sa));
2180 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2182 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2183 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2187 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2188 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2191 case ThresholdCompositeOp:
2197 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2202 pixel=gamma*(Dc+delta*amount);
2205 case VividLightCompositeOp:
2208 VividLight: A Photoshop 7 composition method. See
2209 http://www.simplefilter.de/en/basics/mixmods.html.
2211 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2213 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2215 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2218 if ((2.0*Sca) <= Sa)
2220 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2221 (1.0-Da)+Dca*(1.0-Sa));
2224 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2228 case XorCompositeOp:
2230 pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2239 q[i]=ClampToQuantum(pixel);
2241 p+=GetPixelChannels(composite_image);
2242 channels=GetPixelChannels(composite_image);
2243 if (p >= (pixels+channels*composite_image->columns))
2245 q+=GetPixelChannels(image);
2247 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2249 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2254 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2255 #pragma omp critical (MagickCore_CompositeImage)
2257 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2259 if (proceed == MagickFalse)
2263 composite_view=DestroyCacheView(composite_view);
2264 image_view=DestroyCacheView(image_view);
2265 if (destination_image != (Image * ) NULL)
2266 destination_image=DestroyImage(destination_image);
2271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2275 % T e x t u r e I m a g e %
2279 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2281 % TextureImage() repeatedly tiles the texture image across and down the image
2284 % The format of the TextureImage method is:
2286 % MagickBooleanType TextureImage(Image *image,const Image *texture_image,
2287 % ExceptionInfo *exception)
2289 % A description of each parameter follows:
2291 % o image: the image.
2293 % o texture_image: This image is the texture to layer on the background.
2296 MagickExport MagickBooleanType TextureImage(Image *image,
2297 const Image *texture_image,ExceptionInfo *exception)
2299 #define TextureImageTag "Texture/Image"
2311 assert(image != (Image *) NULL);
2312 if (image->debug != MagickFalse)
2313 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2314 assert(image->signature == MagickSignature);
2315 if (texture_image == (const Image *) NULL)
2316 return(MagickFalse);
2317 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod);
2318 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2319 return(MagickFalse);
2321 if ((image->compose != CopyCompositeOp) &&
2322 ((image->compose != OverCompositeOp) || (image->matte != MagickFalse) ||
2323 (texture_image->matte != MagickFalse)))
2326 Tile texture onto the image background.
2328 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2329 #pragma omp parallel for schedule(static) shared(status)
2331 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2336 if (status == MagickFalse)
2338 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2343 thread_status=CompositeImage(image,image->compose,texture_image,x+
2344 texture_image->tile_offset.x,y+texture_image->tile_offset.y,
2346 if (thread_status == MagickFalse)
2348 status=thread_status;
2352 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2357 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2358 #pragma omp critical (MagickCore_TextureImage)
2360 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2362 if (proceed == MagickFalse)
2366 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2367 image->rows,image->rows);
2371 Tile texture onto the image background (optimized).
2374 image_view=AcquireCacheView(image);
2375 texture_view=AcquireCacheView(texture_image);
2376 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2377 #pragma omp parallel for schedule(static) shared(status)
2379 for (y=0; y < (ssize_t) image->rows; y++)
2384 register const Quantum
2397 if (status == MagickFalse)
2399 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2400 (y+texture_image->tile_offset.y) % texture_image->rows,
2401 texture_image->columns,1,exception);
2402 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2403 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2408 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2414 width=texture_image->columns;
2415 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2416 width=image->columns-x;
2417 for (j=0; j < (ssize_t) width; j++)
2422 if (GetPixelMask(image,p) != 0)
2424 p+=GetPixelChannels(texture_image);
2425 q+=GetPixelChannels(image);
2428 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2437 channel=GetPixelChannelMapChannel(texture_image,i);
2438 texture_traits=GetPixelChannelMapTraits(texture_image,channel);
2439 traits=GetPixelChannelMapTraits(image,channel);
2440 if ((traits == UndefinedPixelTrait) ||
2441 (texture_traits == UndefinedPixelTrait))
2443 SetPixelChannel(image,channel,p[i],q);
2445 p+=GetPixelChannels(texture_image);
2446 q+=GetPixelChannels(image);
2449 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2450 if (sync == MagickFalse)
2452 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2457 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2458 #pragma omp critical (MagickCore_TextureImage)
2460 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2462 if (proceed == MagickFalse)
2466 texture_view=DestroyCacheView(texture_view);
2467 image_view=DestroyCacheView(image_view);