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 ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
583 status=CompositeOverImage(image,composite_image,clip_to_self,x_offset,
587 destination_image=(Image *) NULL;
589 destination_dissolve=1.0;
590 percent_brightness=100.0;
591 percent_saturation=100.0;
596 case CopyCompositeOp:
598 if ((x_offset < 0) || (y_offset < 0))
600 if ((x_offset+(ssize_t) composite_image->columns) >= (ssize_t) image->columns)
602 if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
605 image_view=AcquireCacheView(image);
606 composite_view=AcquireCacheView(composite_image);
607 #if defined(MAGICKCORE_OPENMP_SUPPORT)
608 #pragma omp parallel for schedule(static,4) shared(status)
610 for (y=0; y < (ssize_t) composite_image->rows; y++)
615 register const Quantum
624 if (status == MagickFalse)
626 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
628 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
629 composite_image->columns,1,exception);
630 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
635 for (x=0; x < (ssize_t) composite_image->columns; x++)
640 if (GetPixelMask(image,p) != 0)
642 p+=GetPixelChannels(composite_image);
643 q+=GetPixelChannels(image);
646 for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
655 channel=GetPixelChannelMapChannel(composite_image,i);
656 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
657 traits=GetPixelChannelMapTraits(image,channel);
658 if ((traits == UndefinedPixelTrait) ||
659 (composite_traits == UndefinedPixelTrait))
661 SetPixelChannel(image,channel,p[i],q);
663 p+=GetPixelChannels(composite_image);
664 q+=GetPixelChannels(image);
666 sync=SyncCacheViewAuthenticPixels(image_view,exception);
667 if (sync == MagickFalse)
669 if (image->progress_monitor != (MagickProgressMonitor) NULL)
674 #if defined(MAGICKCORE_OPENMP_SUPPORT)
675 #pragma omp critical (MagickCore_CompositeImage)
677 proceed=SetImageProgress(image,CompositeImageTag,
678 (MagickOffsetType) y,image->rows);
679 if (proceed == MagickFalse)
683 composite_view=DestroyCacheView(composite_view);
684 image_view=DestroyCacheView(image_view);
687 case CopyAlphaCompositeOp:
688 case ChangeMaskCompositeOp:
689 case IntensityCompositeOp:
692 Modify destination outside the overlaid region and require an alpha
693 channel to exist, to add transparency.
695 if (image->matte == MagickFalse)
696 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
699 case BlurCompositeOp:
724 Blur Image dictated by an overlay gradient map: X = red_channel;
725 Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
727 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
729 if (destination_image == (Image *) NULL)
732 Determine the horizontal and vertical maximim blur.
734 SetGeometryInfo(&geometry_info);
736 value=GetImageArtifact(composite_image,"compose:args");
737 if (value != (char *) NULL)
738 flags=ParseGeometry(value,&geometry_info);
739 if ((flags & WidthValue) == 0 )
741 destination_image=DestroyImage(destination_image);
744 width=geometry_info.rho;
745 height=geometry_info.sigma;
746 blur.x1=geometry_info.rho;
749 blur.y2=geometry_info.sigma;
752 if ((flags & HeightValue) == 0)
754 if ((flags & XValue) != 0 )
759 angle=DegreesToRadians(geometry_info.xi);
760 blur.x1=width*cos(angle);
761 blur.x2=width*sin(angle);
762 blur.y1=(-height*sin(angle));
763 blur.y2=height*cos(angle);
765 if ((flags & YValue) != 0 )
767 angle_start=DegreesToRadians(geometry_info.xi);
768 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
771 Blur Image by resampling.
772 FUTURE: this is currently broken, especially for small sigma blurs
773 This needs to be fixed to use a non-user filter setup that provides
774 far more control than currently available.
776 resample_filter=AcquireResampleFilter(image,exception);
777 SetResampleFilter(resample_filter,CubicFilter); /* was blur*2 */
778 destination_view=AcquireCacheView(destination_image);
779 composite_view=AcquireCacheView(composite_image);
780 for (y=0; y < (ssize_t) composite_image->rows; y++)
785 register const Quantum
794 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
796 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
798 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
799 destination_image->columns,1,exception);
800 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
802 for (x=0; x < (ssize_t) composite_image->columns; x++)
804 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
806 p+=GetPixelChannels(composite_image);
809 if (fabs(angle_range) > MagickEpsilon)
814 angle=angle_start+angle_range*QuantumScale*
815 GetPixelBlue(composite_image,p);
816 blur.x1=width*cos(angle);
817 blur.x2=width*sin(angle);
818 blur.y1=(-height*sin(angle));
819 blur.y2=height*cos(angle);
821 ScaleResampleFilter(resample_filter,blur.x1*QuantumScale*
822 GetPixelRed(composite_image,p),blur.y1*QuantumScale*
823 GetPixelGreen(composite_image,p),blur.x2*QuantumScale*
824 GetPixelRed(composite_image,p),blur.y2*QuantumScale*
825 GetPixelGreen(composite_image,p));
826 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
827 (double) y_offset+y,&pixel);
828 SetPixelInfoPixel(destination_image,&pixel,q);
829 p+=GetPixelChannels(composite_image);
830 q+=GetPixelChannels(destination_image);
832 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
833 if (sync == MagickFalse)
836 resample_filter=DestroyResampleFilter(resample_filter);
837 composite_view=DestroyCacheView(composite_view);
838 destination_view=DestroyCacheView(destination_view);
839 composite_image=destination_image;
842 case DisplaceCompositeOp:
843 case DistortCompositeOp:
865 Displace/Distort based on overlay gradient map:
866 X = red_channel; Y = green_channel;
867 compose:args = x_scale[,y_scale[,center.x,center.y]]
869 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
871 if (destination_image == (Image *) NULL)
873 SetGeometryInfo(&geometry_info);
875 value=GetImageArtifact(composite_image,"compose:args");
876 if (value != (char *) NULL)
877 flags=ParseGeometry(value,&geometry_info);
878 if ((flags & (WidthValue|HeightValue)) == 0 )
880 if ((flags & AspectValue) == 0)
882 horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
884 vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
888 horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
889 vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
894 horizontal_scale=geometry_info.rho;
895 vertical_scale=geometry_info.sigma;
896 if ((flags & PercentValue) != 0)
898 if ((flags & AspectValue) == 0)
900 horizontal_scale*=(composite_image->columns-1.0)/200.0;
901 vertical_scale*=(composite_image->rows-1.0)/200.0;
905 horizontal_scale*=(image->columns-1.0)/200.0;
906 vertical_scale*=(image->rows-1.0)/200.0;
909 if ((flags & HeightValue) == 0)
910 vertical_scale=horizontal_scale;
913 Determine fixed center point for absolute distortion map
915 Displace offset relative to a fixed absolute point
916 Select that point according to +X+Y user inputs.
917 default = center of overlay image
918 arg flag '!' = locations/percentage relative to background image
920 center.x=(MagickRealType) x_offset;
921 center.y=(MagickRealType) y_offset;
922 if (compose == DistortCompositeOp)
924 if ((flags & XValue) == 0)
925 if ((flags & AspectValue) == 0)
926 center.x=(MagickRealType) x_offset+(composite_image->columns-1)/
929 center.x=((MagickRealType) image->columns-1)/2.0;
931 if ((flags & AspectValue) == 0)
932 center.x=(MagickRealType) x_offset+geometry_info.xi;
934 center.x=geometry_info.xi;
935 if ((flags & YValue) == 0)
936 if ((flags & AspectValue) == 0)
937 center.y=(MagickRealType) y_offset+(composite_image->rows-1)/2.0;
939 center.y=((MagickRealType) image->rows-1)/2.0;
941 if ((flags & AspectValue) == 0)
942 center.y=(MagickRealType) y_offset+geometry_info.psi;
944 center.y=geometry_info.psi;
947 Shift the pixel offset point as defined by the provided,
948 displacement/distortion map. -- Like a lens...
950 GetPixelInfo(image,&pixel);
951 image_view=AcquireCacheView(image);
952 destination_view=AcquireCacheView(destination_image);
953 composite_view=AcquireCacheView(composite_image);
954 for (y=0; y < (ssize_t) composite_image->rows; y++)
959 register const Quantum
968 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
970 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
972 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
973 destination_image->columns,1,exception);
974 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
976 for (x=0; x < (ssize_t) composite_image->columns; x++)
978 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
980 p+=GetPixelChannels(composite_image);
986 offset.x=(horizontal_scale*(GetPixelRed(composite_image,p)-
987 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
988 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
990 offset.y=(vertical_scale*(GetPixelGreen(composite_image,p)-
991 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
992 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
994 (void) InterpolatePixelInfo(image,image_view,
995 UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
998 Mask with the 'invalid pixel mask' in alpha channel.
1000 pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
1001 pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
1002 SetPixelInfoPixel(destination_image,&pixel,q);
1003 p+=GetPixelChannels(composite_image);
1004 q+=GetPixelChannels(destination_image);
1006 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1007 if (sync == MagickFalse)
1010 destination_view=DestroyCacheView(destination_view);
1011 composite_view=DestroyCacheView(composite_view);
1012 image_view=DestroyCacheView(image_view);
1013 composite_image=destination_image;
1016 case DissolveCompositeOp:
1022 Geometry arguments to dissolve factors.
1024 value=GetImageArtifact(composite_image,"compose:args");
1025 if (value != (char *) NULL)
1027 flags=ParseGeometry(value,&geometry_info);
1028 source_dissolve=geometry_info.rho/100.0;
1029 destination_dissolve=1.0;
1030 if ((source_dissolve-MagickEpsilon) < 0.0)
1031 source_dissolve=0.0;
1032 if ((source_dissolve+MagickEpsilon) > 1.0)
1034 destination_dissolve=2.0-source_dissolve;
1035 source_dissolve=1.0;
1037 if ((flags & SigmaValue) != 0)
1038 destination_dissolve=geometry_info.sigma/100.0;
1039 if ((destination_dissolve-MagickEpsilon) < 0.0)
1040 destination_dissolve=0.0;
1044 case BlendCompositeOp:
1049 value=GetImageArtifact(composite_image,"compose:args");
1050 if (value != (char *) NULL)
1052 flags=ParseGeometry(value,&geometry_info);
1053 source_dissolve=geometry_info.rho/100.0;
1054 destination_dissolve=1.0-source_dissolve;
1055 if ((flags & SigmaValue) != 0)
1056 destination_dissolve=geometry_info.sigma/100.0;
1060 case MathematicsCompositeOp:
1066 Just collect the values from "compose:args", setting.
1067 Unused values are set to zero automagically.
1069 Arguments are normally a comma separated list, so this probably should
1070 be changed to some 'general comma list' parser, (with a minimum
1073 SetGeometryInfo(&geometry_info);
1074 value=GetImageArtifact(composite_image,"compose:args");
1075 if (value != (char *) NULL)
1076 (void) ParseGeometry(value,&geometry_info);
1079 case ModulateCompositeOp:
1085 Determine the brightness and saturation scale.
1087 value=GetImageArtifact(composite_image,"compose:args");
1088 if (value != (char *) NULL)
1090 flags=ParseGeometry(value,&geometry_info);
1091 percent_brightness=geometry_info.rho;
1092 if ((flags & SigmaValue) != 0)
1093 percent_saturation=geometry_info.sigma;
1097 case ThresholdCompositeOp:
1103 Determine the amount and threshold.
1105 value=GetImageArtifact(composite_image,"compose:args");
1106 if (value != (char *) NULL)
1108 flags=ParseGeometry(value,&geometry_info);
1109 amount=geometry_info.rho;
1110 threshold=geometry_info.sigma;
1111 if ((flags & SigmaValue) == 0)
1114 threshold*=QuantumRange;
1125 midpoint=((MagickRealType) QuantumRange+1.0)/2;
1126 image_view=AcquireCacheView(image);
1127 composite_view=AcquireCacheView(composite_image);
1128 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1129 #pragma omp parallel for schedule(static,4) shared(progress,status)
1131 for (y=0; y < (ssize_t) image->rows; y++)
1144 register const Quantum
1153 if (status == MagickFalse)
1155 if (clip_to_self != MagickFalse)
1159 if ((y-y_offset) >= (ssize_t) composite_image->rows)
1163 If pixels is NULL, y is outside overlay region.
1165 pixels=(Quantum *) NULL;
1167 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
1169 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
1170 composite_image->columns,1,exception);
1171 if (p == (const Quantum *) NULL)
1178 p-=x_offset*GetPixelChannels(composite_image);
1180 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1181 if (q == (Quantum *) NULL)
1189 for (x=0; x < (ssize_t) image->columns; x++)
1207 if (clip_to_self != MagickFalse)
1211 q+=GetPixelChannels(image);
1214 if ((x-x_offset) >= (ssize_t) composite_image->columns)
1217 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1218 ((x-x_offset) >= (ssize_t) composite_image->columns))
1221 source[MaxPixelChannels];
1226 Dc: destination color.
1228 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
1230 if (GetPixelMask(image,q) != 0)
1232 q+=GetPixelChannels(image);
1235 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1247 channel=GetPixelChannelMapChannel(image,i);
1248 traits=GetPixelChannelMapTraits(image,channel);
1249 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
1250 if ((traits == UndefinedPixelTrait) ||
1251 (composite_traits == UndefinedPixelTrait))
1255 case AlphaCompositeOp:
1256 case ChangeMaskCompositeOp:
1257 case CopyAlphaCompositeOp:
1258 case DstAtopCompositeOp:
1259 case DstInCompositeOp:
1261 case IntensityCompositeOp:
1262 case OutCompositeOp:
1263 case SrcInCompositeOp:
1264 case SrcOutCompositeOp:
1266 pixel=(MagickRealType) q[i];
1267 if (channel == AlphaPixelChannel)
1268 pixel=(MagickRealType) TransparentAlpha;
1271 case ClearCompositeOp:
1272 case CopyCompositeOp:
1273 case ReplaceCompositeOp:
1274 case SrcCompositeOp:
1276 if (channel == AlphaPixelChannel)
1278 pixel=(MagickRealType) TransparentAlpha;
1284 case BlendCompositeOp:
1285 case DissolveCompositeOp:
1287 if (channel == AlphaPixelChannel)
1289 pixel=destination_dissolve*GetPixelAlpha(composite_image,
1293 pixel=(MagickRealType) source[channel];
1298 pixel=(MagickRealType) source[channel];
1302 q[i]=ClampToQuantum(pixel);
1304 q+=GetPixelChannels(image);
1308 Authentic composite:
1309 Sa: normalized source alpha.
1310 Da: normalized destination alpha.
1312 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
1313 Da=QuantumScale*GetPixelAlpha(image,q);
1316 case BumpmapCompositeOp:
1318 alpha=GetPixelIntensity(composite_image,p)*Sa;
1321 case ColorBurnCompositeOp:
1322 case ColorDodgeCompositeOp:
1323 case DifferenceCompositeOp:
1324 case DivideDstCompositeOp:
1325 case DivideSrcCompositeOp:
1326 case ExclusionCompositeOp:
1327 case HardLightCompositeOp:
1328 case LinearBurnCompositeOp:
1329 case LinearDodgeCompositeOp:
1330 case LinearLightCompositeOp:
1331 case MathematicsCompositeOp:
1332 case MinusDstCompositeOp:
1333 case MinusSrcCompositeOp:
1334 case ModulusAddCompositeOp:
1335 case ModulusSubtractCompositeOp:
1336 case MultiplyCompositeOp:
1337 case OverlayCompositeOp:
1338 case PegtopLightCompositeOp:
1339 case PinLightCompositeOp:
1340 case ScreenCompositeOp:
1341 case SoftLightCompositeOp:
1342 case VividLightCompositeOp:
1344 alpha=RoundToUnity(Sa+Da-Sa*Da);
1347 case DarkenCompositeOp:
1348 case DstAtopCompositeOp:
1349 case DstInCompositeOp:
1351 case LightenCompositeOp:
1352 case SrcInCompositeOp:
1357 case DissolveCompositeOp:
1359 alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
1360 Sa+destination_dissolve*Da;
1363 case DstOverCompositeOp:
1365 alpha=Da*(-Sa)+Da+Sa;
1368 case DstOutCompositeOp:
1373 case OutCompositeOp:
1374 case SrcOutCompositeOp:
1379 case OverCompositeOp:
1380 case SrcOverCompositeOp:
1382 alpha=Sa*(-Da)+Sa+Da;
1385 case BlendCompositeOp:
1386 case PlusCompositeOp:
1388 alpha=RoundToUnity(Sa+Da);
1391 case XorCompositeOp:
1393 alpha=Sa+Da-2.0*Sa*Da;
1402 if (GetPixelMask(image,p) != 0)
1404 p+=GetPixelChannels(composite_image);
1405 q+=GetPixelChannels(image);
1408 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1423 channel=GetPixelChannelMapChannel(image,i);
1424 traits=GetPixelChannelMapTraits(image,channel);
1425 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
1426 if (traits == UndefinedPixelTrait)
1428 if ((compose != IntensityCompositeOp) &&
1429 (composite_traits == UndefinedPixelTrait))
1433 Dc: destination color.
1435 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
1436 Dc=(MagickRealType) q[i];
1437 if ((traits & CopyPixelTrait) != 0)
1439 if (channel != AlphaPixelChannel)
1444 q[i]=ClampToQuantum(Sc);
1452 case AlphaCompositeOp:
1454 pixel=QuantumRange*Sa;
1457 case AtopCompositeOp:
1458 case CopyBlackCompositeOp:
1459 case CopyBlueCompositeOp:
1460 case CopyCyanCompositeOp:
1461 case CopyGreenCompositeOp:
1462 case CopyMagentaCompositeOp:
1463 case CopyRedCompositeOp:
1464 case CopyYellowCompositeOp:
1465 case SrcAtopCompositeOp:
1466 case DstCompositeOp:
1469 pixel=QuantumRange*Da;
1472 case ChangeMaskCompositeOp:
1477 if (Da > ((MagickRealType) QuantumRange/2.0))
1479 pixel=(MagickRealType) TransparentAlpha;
1482 equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
1483 if (equivalent != MagickFalse)
1485 pixel=(MagickRealType) TransparentAlpha;
1488 pixel=(MagickRealType) OpaqueAlpha;
1491 case ClearCompositeOp:
1493 pixel=(MagickRealType) TransparentAlpha;
1496 case ColorizeCompositeOp:
1497 case HueCompositeOp:
1498 case LuminizeCompositeOp:
1499 case SaturateCompositeOp:
1501 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1503 pixel=QuantumRange*Da;
1506 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1508 pixel=QuantumRange*Sa;
1513 pixel=QuantumRange*Da;
1516 pixel=QuantumRange*Sa;
1519 case CopyCompositeOp:
1520 case CopyAlphaCompositeOp:
1521 case DisplaceCompositeOp:
1522 case DistortCompositeOp:
1523 case DstAtopCompositeOp:
1524 case ReplaceCompositeOp:
1525 case SrcCompositeOp:
1527 pixel=QuantumRange*Sa;
1530 case DarkenIntensityCompositeOp:
1532 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1533 (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
1536 case IntensityCompositeOp:
1538 pixel=(MagickRealType) GetPixelIntensity(composite_image,p);
1541 case LightenIntensityCompositeOp:
1543 pixel=Sa*GetPixelIntensity(composite_image,p) >
1544 Da*GetPixelIntensity(image,q) ? Sa : Da;
1547 case ModulateCompositeOp:
1549 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1551 pixel=QuantumRange*Da;
1554 pixel=QuantumRange*Da;
1559 pixel=QuantumRange*alpha;
1563 q[i]=ClampToQuantum(pixel);
1567 Porter-Duff compositions:
1568 Sca: source normalized color multiplied by alpha.
1569 Dca: normalized destination color multiplied by alpha.
1571 Sca=QuantumScale*Sa*Sc;
1572 Dca=QuantumScale*Da*Dc;
1575 case DarkenCompositeOp:
1576 case LightenCompositeOp:
1577 case ModulusSubtractCompositeOp:
1585 gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
1589 case AlphaCompositeOp:
1591 pixel=QuantumRange*Sa;
1594 case AtopCompositeOp:
1595 case SrcAtopCompositeOp:
1597 pixel=Sc*Sa+Dc*(1.0-Sa);
1600 case BlendCompositeOp:
1602 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1605 case BlurCompositeOp:
1606 case DisplaceCompositeOp:
1607 case DistortCompositeOp:
1608 case CopyCompositeOp:
1609 case ReplaceCompositeOp:
1610 case SrcCompositeOp:
1615 case BumpmapCompositeOp:
1617 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1622 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1625 case ChangeMaskCompositeOp:
1630 case ClearCompositeOp:
1635 case ColorBurnCompositeOp:
1638 Refer to the March 2009 SVG specification.
1640 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1642 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1645 if (Sca < MagickEpsilon)
1647 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1650 pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
1651 Sca*(1.0-Da)+Dca*(1.0-Sa));
1654 case ColorDodgeCompositeOp:
1656 if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1658 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1661 if (fabs(Sca-Sa) < MagickEpsilon)
1663 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1666 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1670 case ColorizeCompositeOp:
1672 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1677 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1682 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1683 GetPixelBlue(image,q),&sans,&sans,&brightness);
1684 CompositeHSB(GetPixelRed(composite_image,p),
1685 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1686 &hue,&saturation,&sans);
1687 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1690 case RedPixelChannel: pixel=red; break;
1691 case GreenPixelChannel: pixel=green; break;
1692 case BluePixelChannel: pixel=blue; break;
1693 default: pixel=Dc; break;
1697 case CopyAlphaCompositeOp:
1698 case IntensityCompositeOp:
1700 if (channel == AlphaPixelChannel)
1701 pixel=(MagickRealType) GetPixelAlpha(composite_image,p);
1704 case CopyBlackCompositeOp:
1706 if (channel == BlackPixelChannel)
1707 pixel=(MagickRealType) GetPixelBlack(composite_image,p);
1710 case CopyBlueCompositeOp:
1711 case CopyYellowCompositeOp:
1713 if (channel == BluePixelChannel)
1714 pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1717 case CopyGreenCompositeOp:
1718 case CopyMagentaCompositeOp:
1720 if (channel == GreenPixelChannel)
1721 pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1724 case CopyRedCompositeOp:
1725 case CopyCyanCompositeOp:
1727 if (channel == RedPixelChannel)
1728 pixel=(MagickRealType) GetPixelRed(composite_image,p);
1731 case DarkenCompositeOp:
1734 Darken is equivalent to a 'Minimum' method
1735 OR a greyscale version of a binary 'Or'
1736 OR the 'Intersection' of pixel sets.
1740 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1743 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1746 case DarkenIntensityCompositeOp:
1748 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1749 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1752 case DifferenceCompositeOp:
1754 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1757 case DissolveCompositeOp:
1759 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1760 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1763 case DivideDstCompositeOp:
1765 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1767 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1770 if (fabs(Dca) < MagickEpsilon)
1772 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1775 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1778 case DivideSrcCompositeOp:
1780 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1782 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1785 if (fabs(Sca) < MagickEpsilon)
1787 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1790 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1793 case DstAtopCompositeOp:
1795 pixel=Dc*Da+Sc*(1.0-Da);
1798 case DstCompositeOp:
1804 case DstInCompositeOp:
1806 pixel=gamma*(Sa*Dc*Sa);
1809 case DstOutCompositeOp:
1811 pixel=gamma*(Da*Dc*(1.0-Sa));
1814 case DstOverCompositeOp:
1816 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1819 case ExclusionCompositeOp:
1821 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1825 case HardLightCompositeOp:
1829 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1833 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1837 case HueCompositeOp:
1839 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1844 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1849 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1850 GetPixelBlue(image,q),&hue,&saturation,&brightness);
1851 CompositeHSB(GetPixelRed(composite_image,p),
1852 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1854 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1857 case RedPixelChannel: pixel=red; break;
1858 case GreenPixelChannel: pixel=green; break;
1859 case BluePixelChannel: pixel=blue; break;
1860 default: pixel=Dc; break;
1865 case SrcInCompositeOp:
1867 pixel=gamma*(Da*Sc*Da);
1870 case LinearBurnCompositeOp:
1873 LinearBurn: as defined by Abode Photoshop, according to
1874 http://www.simplefilter.de/en/basics/mixmods.html is:
1876 f(Sc,Dc) = Sc + Dc - 1
1878 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1881 case LinearDodgeCompositeOp:
1883 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1886 case LinearLightCompositeOp:
1889 LinearLight: as defined by Abode Photoshop, according to
1890 http://www.simplefilter.de/en/basics/mixmods.html is:
1892 f(Sc,Dc) = Dc + 2*Sc - 1
1894 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1897 case LightenCompositeOp:
1901 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1904 pixel=QuantumRange*gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1907 case LightenIntensityCompositeOp:
1910 Lighten is equivalent to a 'Maximum' method
1911 OR a greyscale version of a binary 'And'
1912 OR the 'Union' of pixel sets.
1914 pixel=Sa*GetPixelIntensity(composite_image,p) >
1915 Da*GetPixelIntensity(image,q) ? Sc : Dc;
1918 case LuminizeCompositeOp:
1920 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1925 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1930 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1931 GetPixelBlue(image,q),&hue,&saturation,&brightness);
1932 CompositeHSB(GetPixelRed(composite_image,p),
1933 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1934 &sans,&sans,&brightness);
1935 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1938 case RedPixelChannel: pixel=red; break;
1939 case GreenPixelChannel: pixel=green; break;
1940 case BluePixelChannel: pixel=blue; break;
1941 default: pixel=Dc; break;
1945 case MathematicsCompositeOp:
1948 'Mathematics' a free form user control mathematical composition
1951 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
1953 Where the arguments A,B,C,D are (currently) passed to composite
1954 as a command separated 'geometry' string in "compose:args" image
1957 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
1959 Applying the SVG transparency formula (see above), we get...
1961 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
1963 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
1966 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
1967 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
1968 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
1971 case MinusDstCompositeOp:
1973 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
1976 case MinusSrcCompositeOp:
1979 Minus source from destination.
1983 pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
1986 case ModulateCompositeOp:
1991 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1996 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
2002 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
2003 GetPixelBlue(image,q),&hue,&saturation,&brightness);
2004 brightness+=(0.01*percent_brightness*offset)/midpoint;
2005 saturation*=0.01*percent_saturation;
2006 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
2009 case RedPixelChannel: pixel=red; break;
2010 case GreenPixelChannel: pixel=green; break;
2011 case BluePixelChannel: pixel=blue; break;
2012 default: pixel=Dc; break;
2016 case ModulusAddCompositeOp:
2019 if (pixel > QuantumRange)
2020 pixel-=(QuantumRange+1.0);
2021 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2024 case ModulusSubtractCompositeOp:
2028 pixel+=(QuantumRange+1.0);
2029 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2032 case MultiplyCompositeOp:
2034 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2037 case OutCompositeOp:
2038 case SrcOutCompositeOp:
2040 pixel=gamma*(Sa*Sc*(1.0-Da));
2043 case OverCompositeOp:
2044 case SrcOverCompositeOp:
2046 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2049 case OverlayCompositeOp:
2053 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2057 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2061 case PegtopLightCompositeOp:
2064 PegTop: A Soft-Light alternative: A continuous version of the
2065 Softlight function, producing very similar results.
2067 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2069 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2071 if (fabs(Da) < MagickEpsilon)
2073 pixel=QuantumRange*gamma*(Sca);
2076 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2080 case PinLightCompositeOp:
2083 PinLight: A Photoshop 7 composition method
2084 http://www.simplefilter.de/en/basics/mixmods.html
2086 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2088 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2090 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2093 if ((Dca*Sa) > (2.0*Sca*Da))
2095 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2098 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2101 case PlusCompositeOp:
2103 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
2106 case SaturateCompositeOp:
2108 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2113 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2118 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
2119 GetPixelBlue(image,q),&hue,&saturation,&brightness);
2120 CompositeHSB(GetPixelRed(composite_image,p),
2121 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
2122 &sans,&saturation,&sans);
2123 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
2126 case RedPixelChannel: pixel=red; break;
2127 case GreenPixelChannel: pixel=green; break;
2128 case BluePixelChannel: pixel=blue; break;
2129 default: pixel=Dc; break;
2133 case ScreenCompositeOp:
2136 Screen: a negated multiply:
2138 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2140 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2143 case SoftLightCompositeOp:
2146 Refer to the March 2009 SVG specification.
2150 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2151 Sca*(1.0-Da)+Dca*(1.0-Sa));
2154 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2156 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2157 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2161 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2162 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2165 case ThresholdCompositeOp:
2171 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2176 pixel=gamma*(Dc+delta*amount);
2179 case VividLightCompositeOp:
2182 VividLight: A Photoshop 7 composition method. See
2183 http://www.simplefilter.de/en/basics/mixmods.html.
2185 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2187 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2189 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2192 if ((2.0*Sca) <= Sa)
2194 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2195 (1.0-Da)+Dca*(1.0-Sa));
2198 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2202 case XorCompositeOp:
2204 pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2213 q[i]=ClampToQuantum(pixel);
2215 p+=GetPixelChannels(composite_image);
2216 channels=GetPixelChannels(composite_image);
2217 if (p >= (pixels+channels*composite_image->columns))
2219 q+=GetPixelChannels(image);
2221 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2223 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2228 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2229 #pragma omp critical (MagickCore_CompositeImage)
2231 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2233 if (proceed == MagickFalse)
2237 composite_view=DestroyCacheView(composite_view);
2238 image_view=DestroyCacheView(image_view);
2239 if (destination_image != (Image * ) NULL)
2240 destination_image=DestroyImage(destination_image);
2245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2249 % T e x t u r e I m a g e %
2253 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2255 % TextureImage() repeatedly tiles the texture image across and down the image
2258 % The format of the TextureImage method is:
2260 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2261 % ExceptionInfo *exception)
2263 % A description of each parameter follows:
2265 % o image: the image.
2267 % o texture_image: This image is the texture to layer on the background.
2270 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
2271 ExceptionInfo *exception)
2273 #define TextureImageTag "Texture/Image"
2288 assert(image != (Image *) NULL);
2289 if (image->debug != MagickFalse)
2290 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2291 assert(image->signature == MagickSignature);
2292 if (texture == (const Image *) NULL)
2293 return(MagickFalse);
2294 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2295 return(MagickFalse);
2296 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2297 if (texture_image == (const Image *) NULL)
2298 return(MagickFalse);
2299 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
2302 if ((image->compose != CopyCompositeOp) &&
2303 ((image->compose != OverCompositeOp) || (image->matte != MagickFalse) ||
2304 (texture_image->matte != MagickFalse)))
2307 Tile texture onto the image background.
2309 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2310 #pragma omp parallel for schedule(static) shared(status)
2312 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2317 if (status == MagickFalse)
2319 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2324 thread_status=CompositeImage(image,texture_image,image->compose,
2325 MagickFalse,x+texture_image->tile_offset.x,y+
2326 texture_image->tile_offset.y,exception);
2327 if (thread_status == MagickFalse)
2329 status=thread_status;
2333 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2338 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2339 #pragma omp critical (MagickCore_TextureImage)
2341 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2343 if (proceed == MagickFalse)
2347 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2348 image->rows,image->rows);
2349 texture_image=DestroyImage(texture_image);
2353 Tile texture onto the image background (optimized).
2356 image_view=AcquireCacheView(image);
2357 texture_view=AcquireCacheView(texture_image);
2358 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2359 #pragma omp parallel for schedule(static) shared(status)
2361 for (y=0; y < (ssize_t) image->rows; y++)
2366 register const Quantum
2379 if (status == MagickFalse)
2381 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2382 (y+texture_image->tile_offset.y) % texture_image->rows,
2383 texture_image->columns,1,exception);
2384 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2385 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2390 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2396 width=texture_image->columns;
2397 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2398 width=image->columns-x;
2399 for (j=0; j < (ssize_t) width; j++)
2404 if (GetPixelMask(image,p) != 0)
2406 p+=GetPixelChannels(texture_image);
2407 q+=GetPixelChannels(image);
2410 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2419 channel=GetPixelChannelMapChannel(texture_image,i);
2420 texture_traits=GetPixelChannelMapTraits(texture_image,channel);
2421 traits=GetPixelChannelMapTraits(image,channel);
2422 if ((traits == UndefinedPixelTrait) ||
2423 (texture_traits == UndefinedPixelTrait))
2425 SetPixelChannel(image,channel,p[i],q);
2427 p+=GetPixelChannels(texture_image);
2428 q+=GetPixelChannels(image);
2431 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2432 if (sync == MagickFalse)
2434 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2439 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2440 #pragma omp critical (MagickCore_TextureImage)
2442 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2444 if (proceed == MagickFalse)
2448 texture_view=DestroyCacheView(texture_view);
2449 image_view=DestroyCacheView(image_view);
2450 texture_image=DestroyImage(texture_image);