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 CompositeOperator compose,Image *composite_image,
98 % const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
100 % A description of each parameter follows:
102 % o image: the destination image, modified by he composition
104 % o compose: This operator affects how the composite is applied to
105 % the image. The operators and how they are utilized are listed here
106 % http://www.w3.org/TR/SVG12/#compositing.
108 % o composite_image: the composite (source) image.
110 % o x_offset: the column offset of the composited image.
112 % o y_offset: the row offset of the composited image.
114 % Extra Controls from Image meta-data in 'composite_image' (artifacts)
117 % A string containing extra numerical arguments for specific compose
118 % methods, generally expressed as a 'geometry' or a comma separated list
121 % Compose methods needing such arguments include "BlendCompositeOp" and
122 % "DisplaceCompositeOp".
124 % o "compose:outside-overlay"
125 % Modify how the composition is to effect areas not directly covered
126 % by the 'composite_image' at the offset given. Normally this is
127 % dependant on the 'compose' method, especially Duff-Porter methods.
129 % If set to "false" then disable all normal handling of pixels not
130 % covered by the composite_image. Typically used for repeated tiling
131 % of the composite_image by the calling API.
133 % Previous to IM v6.5.3-3 this was called "modify-outside-overlay"
135 % o exception: return any errors or warnings in this structure.
139 static void CompositeHSB(const Quantum red,const Quantum green,
140 const Quantum blue,double *hue,double *saturation,double *brightness)
150 Convert RGB to HSB colorspace.
152 assert(hue != (double *) NULL);
153 assert(saturation != (double *) NULL);
154 assert(brightness != (double *) NULL);
155 max=(red > green ? red : green);
158 min=(red < green ? red : green);
163 *brightness=(double) (QuantumScale*max);
164 if (fabs((double) max) < MagickEpsilon)
166 *saturation=(double) (1.0-min/max);
167 delta=(MagickRealType) max-min;
168 if (fabs(delta) < MagickEpsilon)
170 if (fabs((double) red-max) < MagickEpsilon)
171 *hue=(double) ((green-blue)/delta);
173 if (fabs((double) green-max) < MagickEpsilon)
174 *hue=(double) (2.0+(blue-red)/delta);
176 if (fabs((double) blue-max) < MagickEpsilon)
177 *hue=(double) (4.0+(red-green)/delta);
183 static void HSBComposite(const double hue,const double saturation,
184 const double brightness,double *red,double *green,double *blue)
194 Convert HSB to RGB colorspace.
196 assert(red != (double *) NULL);
197 assert(green != (double *) NULL);
198 assert(blue != (double *) NULL);
199 if (saturation == 0.0)
201 *red=(double) QuantumRange*brightness;
206 h=6.0*(hue-floor(hue));
207 f=h-floor((double) h);
208 p=brightness*(1.0-saturation);
209 q=brightness*(1.0-saturation*f);
210 t=brightness*(1.0-saturation*(1.0-f));
216 *red=(double) QuantumRange*brightness;
217 *green=(double) QuantumRange*t;
218 *blue=(double) QuantumRange*p;
223 *red=(double) QuantumRange*q;
224 *green=(double) QuantumRange*brightness;
225 *blue=(double) QuantumRange*p;
230 *red=(double) QuantumRange*p;
231 *green=(double) QuantumRange*brightness;
232 *blue=(double) QuantumRange*t;
237 *red=(double) QuantumRange*p;
238 *green=(double) QuantumRange*q;
239 *blue=(double) QuantumRange*brightness;
244 *red=(double) QuantumRange*t;
245 *green=(double) QuantumRange*p;
246 *blue=(double) QuantumRange*brightness;
251 *red=(double) QuantumRange*brightness;
252 *green=(double) QuantumRange*p;
253 *blue=(double) QuantumRange*q;
259 static inline double MagickMin(const double x,const double y)
265 static inline double MagickMax(const double x,const double y)
272 static MagickBooleanType CompositeOverImage(Image *image,
273 const Image *composite_image,const ssize_t x_offset,const ssize_t y_offset,
274 ExceptionInfo *exception)
276 #define CompositeImageTag "Composite/Image"
286 modify_outside_overlay,
296 Prepare composite image.
298 modify_outside_overlay=MagickFalse;
299 value=GetImageArtifact(composite_image,"compose:outside-overlay");
300 if (value != (const char *) NULL)
301 modify_outside_overlay=IsMagickTrue(value);
307 image_view=AcquireCacheView(image);
308 composite_view=AcquireCacheView(composite_image);
309 #if defined(MAGICKCORE_OPENMP_SUPPORT)
310 #pragma omp parallel for schedule(static,4) shared(progress,status)
312 for (y=0; y < (ssize_t) image->rows; y++)
317 register const Quantum
329 if (status == MagickFalse)
331 if (modify_outside_overlay == MagickFalse)
335 if ((y-y_offset) >= (ssize_t) composite_image->rows)
339 If pixels is NULL, y is outside overlay region.
341 pixels=(Quantum *) NULL;
343 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
345 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
346 composite_image->columns,1,exception);
347 if (p == (const Quantum *) NULL)
354 p-=x_offset*GetPixelChannels(composite_image);
356 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
357 if (q == (Quantum *) NULL)
362 for (x=0; x < (ssize_t) image->columns; x++)
375 if (modify_outside_overlay == MagickFalse)
379 q+=GetPixelChannels(image);
382 if ((x-x_offset) >= (ssize_t) composite_image->columns)
385 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
386 ((x-x_offset) >= (ssize_t) composite_image->columns))
389 source[MaxPixelChannels];
394 Dc: destination color.
396 if (GetPixelMask(image,q) != 0)
398 q+=GetPixelChannels(image);
401 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
403 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
412 channel=GetPixelChannelMapChannel(image,i);
413 traits=GetPixelChannelMapTraits(image,channel);
414 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
415 if ((traits == UndefinedPixelTrait) ||
416 (composite_traits == UndefinedPixelTrait))
418 q[i]=source[channel];
420 q+=GetPixelChannels(image);
425 Sa: normalized source alpha.
426 Da: normalized destination alpha.
428 if (GetPixelMask(composite_image,p) != 0)
430 p+=GetPixelChannels(composite_image);
431 channels=GetPixelChannels(composite_image);
432 if (p >= (pixels+channels*composite_image->columns))
434 q+=GetPixelChannels(image);
437 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
438 Da=QuantumScale*GetPixelAlpha(image,q);
439 alpha=Sa*(-Da)+Sa+Da;
440 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
449 channel=GetPixelChannelMapChannel(image,i);
450 traits=GetPixelChannelMapTraits(image,channel);
451 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
452 if ((traits == UndefinedPixelTrait) ||
453 (composite_traits == UndefinedPixelTrait))
455 if ((traits & CopyPixelTrait) != 0)
457 if (channel != AlphaPixelChannel)
462 q[i]=GetPixelChannel(composite_image,channel,p);
468 q[i]=ClampToQuantum(QuantumRange*alpha);
473 Dc: destination color.
475 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
476 Dc=(MagickRealType) q[i];
477 gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
478 q[i]=ClampToQuantum(gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc));
480 p+=GetPixelChannels(composite_image);
481 channels=GetPixelChannels(composite_image);
482 if (p >= (pixels+channels*composite_image->columns))
484 q+=GetPixelChannels(image);
486 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
488 if (image->progress_monitor != (MagickProgressMonitor) NULL)
493 #if defined(MAGICKCORE_OPENMP_SUPPORT)
494 #pragma omp critical (MagickCore_CompositeImage)
496 proceed=SetImageProgress(image,CompositeImageTag,progress++,
498 if (proceed == MagickFalse)
502 composite_view=DestroyCacheView(composite_view);
503 image_view=DestroyCacheView(image_view);
507 MagickExport MagickBooleanType CompositeImage(Image *image,
508 const CompositeOperator compose,const Image *composite_image,
509 const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
511 #define CompositeImageTag "Composite/Image"
527 modify_outside_overlay,
535 destination_dissolve,
549 Composition based on the SVG specification:
551 A Composition is defined by...
552 Color Function : f(Sc,Dc) where Sc and Dc are the normizalized colors
553 Blending areas : X = 1 for area of overlap, ie: f(Sc,Dc)
554 Y = 1 for source preserved
555 Z = 1 for destination preserved
557 Conversion to transparency (then optimized)
558 Dca' = f(Sc, Dc)*Sa*Da + Y*Sca*(1-Da) + Z*Dca*(1-Sa)
559 Da' = X*Sa*Da + Y*Sa*(1-Da) + Z*Da*(1-Sa)
562 Sca = Sc*Sa normalized Source color divided by Source alpha
563 Dca = Dc*Da normalized Dest color divided by Dest alpha
564 Dc' = Dca'/Da' the desired color value for this channel.
566 Da' in in the follow formula as 'gamma' The resulting alpla value.
568 Most functions use a blending mode of over (X=1,Y=1,Z=1) this results in
569 the following optimizations...
571 gamma = 1 - QuantiumScale*alpha * QuantiumScale*beta;
572 opacity = QuantiumScale*alpha*beta; // over blend, optimized 1-Gamma
574 The above SVG definitions also definate that Mathematical Composition
575 methods should use a 'Over' blending mode for Alpha Channel.
576 It however was not applied for composition modes of 'Plus', 'Minus',
577 the modulus versions of 'Add' and 'Subtract'.
579 Mathematical operator changes to be applied from IM v6.7...
581 1) Modulus modes 'Add' and 'Subtract' are obsoleted and renamed
582 'ModulusAdd' and 'ModulusSubtract' for clarity.
584 2) All mathematical compositions work as per the SVG specification
585 with regard to blending. This now includes 'ModulusAdd' and
588 3) When the special channel flag 'sync' (syncronize channel updates)
589 is turned off (enabled by default) then mathematical compositions are
590 only performed on the channels specified, and are applied
591 independantally of each other. In other words the mathematics is
592 performed as 'pure' mathematical operations, rather than as image
595 assert(image != (Image *) NULL);
596 assert(image->signature == MagickSignature);
597 if (image->debug != MagickFalse)
598 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
599 assert(composite_image != (Image *) NULL);
600 assert(composite_image->signature == MagickSignature);
601 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
603 if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
605 status=CompositeOverImage(image,composite_image,x_offset,y_offset,
609 destination_image=(Image *) NULL;
611 destination_dissolve=1.0;
612 modify_outside_overlay=MagickFalse;
613 percent_brightness=100.0;
614 percent_saturation=100.0;
619 case ClearCompositeOp:
620 case DstAtopCompositeOp:
621 case DstInCompositeOp:
625 case SrcInCompositeOp:
626 case SrcOutCompositeOp:
629 Modify destination outside the overlaid region.
631 modify_outside_overlay=MagickTrue;
634 case CopyCompositeOp:
636 if ((x_offset < 0) || (y_offset < 0))
638 if ((x_offset+(ssize_t) composite_image->columns) >= (ssize_t) image->columns)
640 if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
643 image_view=AcquireCacheView(image);
644 composite_view=AcquireCacheView(composite_image);
645 #if defined(MAGICKCORE_OPENMP_SUPPORT)
646 #pragma omp parallel for schedule(static,4) shared(status)
648 for (y=0; y < (ssize_t) composite_image->rows; y++)
653 register const Quantum
662 if (status == MagickFalse)
664 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
666 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
667 composite_image->columns,1,exception);
668 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
673 for (x=0; x < (ssize_t) composite_image->columns; x++)
678 if (GetPixelMask(image,p) != 0)
680 p+=GetPixelChannels(composite_image);
681 q+=GetPixelChannels(image);
684 for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
693 channel=GetPixelChannelMapChannel(composite_image,i);
694 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
695 traits=GetPixelChannelMapTraits(image,channel);
696 if ((traits == UndefinedPixelTrait) ||
697 (composite_traits == UndefinedPixelTrait))
699 SetPixelChannel(image,channel,p[i],q);
701 p+=GetPixelChannels(composite_image);
702 q+=GetPixelChannels(image);
704 sync=SyncCacheViewAuthenticPixels(image_view,exception);
705 if (sync == MagickFalse)
707 if (image->progress_monitor != (MagickProgressMonitor) NULL)
712 #if defined(MAGICKCORE_OPENMP_SUPPORT)
713 #pragma omp critical (MagickCore_CompositeImage)
715 proceed=SetImageProgress(image,CompositeImageTag,
716 (MagickOffsetType) y,image->rows);
717 if (proceed == MagickFalse)
721 composite_view=DestroyCacheView(composite_view);
722 image_view=DestroyCacheView(image_view);
725 case CopyAlphaCompositeOp:
726 case ChangeMaskCompositeOp:
727 case IntensityCompositeOp:
730 Modify destination outside the overlaid region and require an alpha
731 channel to exist, to add transparency.
733 if (image->matte == MagickFalse)
734 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
735 modify_outside_overlay=MagickTrue;
738 case BlurCompositeOp:
760 Blur Image dictated by an overlay gradient map: X = red_channel;
761 Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
763 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
765 if (destination_image == (Image *) NULL)
768 Determine the horizontal and vertical maximim blur.
770 SetGeometryInfo(&geometry_info);
772 value=GetImageArtifact(composite_image,"compose:args");
773 if (value != (char *) NULL)
774 flags=ParseGeometry(value,&geometry_info);
775 if ((flags & WidthValue) == 0 )
777 destination_image=DestroyImage(destination_image);
780 width=geometry_info.rho;
781 height=geometry_info.sigma;
782 blur.x1=geometry_info.rho;
785 blur.y2=geometry_info.sigma;
788 if ((flags & HeightValue) == 0)
790 if ((flags & XValue) != 0 )
795 angle=DegreesToRadians(geometry_info.xi);
796 blur.x1=width*cos(angle);
797 blur.x2=width*sin(angle);
798 blur.y1=(-height*sin(angle));
799 blur.y2=height*cos(angle);
801 if ((flags & YValue) != 0 )
803 angle_start=DegreesToRadians(geometry_info.xi);
804 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
807 Blur Image by resampling.
808 FUTURE: this is currently broken, especially for small sigma blurs
809 This needs to be fixed to use a non-user filter setup that provides
810 far more control than currently available.
812 resample_filter=AcquireResampleFilter(image,exception);
813 SetResampleFilter(resample_filter,CubicFilter); /* was blur*2 */
814 destination_view=AcquireCacheView(destination_image);
815 composite_view=AcquireCacheView(composite_image);
816 for (y=0; y < (ssize_t) composite_image->rows; y++)
821 register const Quantum
830 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
832 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
834 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
835 destination_image->columns,1,exception);
836 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
838 for (x=0; x < (ssize_t) composite_image->columns; x++)
840 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
842 p+=GetPixelChannels(composite_image);
845 if (fabs(angle_range) > MagickEpsilon)
850 angle=angle_start+angle_range*QuantumScale*
851 GetPixelBlue(composite_image,p);
852 blur.x1=width*cos(angle);
853 blur.x2=width*sin(angle);
854 blur.y1=(-height*sin(angle));
855 blur.y2=height*cos(angle);
857 ScaleResampleFilter(resample_filter,blur.x1*QuantumScale*
858 GetPixelRed(composite_image,p),blur.y1*QuantumScale*
859 GetPixelGreen(composite_image,p),blur.x2*QuantumScale*
860 GetPixelRed(composite_image,p),blur.y2*QuantumScale*
861 GetPixelGreen(composite_image,p));
862 (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
863 (double) y_offset+y,&pixel);
864 SetPixelInfoPixel(destination_image,&pixel,q);
865 p+=GetPixelChannels(composite_image);
866 q+=GetPixelChannels(destination_image);
868 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
869 if (sync == MagickFalse)
872 resample_filter=DestroyResampleFilter(resample_filter);
873 composite_view=DestroyCacheView(composite_view);
874 destination_view=DestroyCacheView(destination_view);
875 composite_image=destination_image;
878 case DisplaceCompositeOp:
879 case DistortCompositeOp:
898 Displace/Distort based on overlay gradient map:
899 X = red_channel; Y = green_channel;
900 compose:args = x_scale[,y_scale[,center.x,center.y]]
902 destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
904 if (destination_image == (Image *) NULL)
906 SetGeometryInfo(&geometry_info);
908 value=GetImageArtifact(composite_image,"compose:args");
909 if (value != (char *) NULL)
910 flags=ParseGeometry(value,&geometry_info);
911 if ((flags & (WidthValue|HeightValue)) == 0 )
913 if ((flags & AspectValue) == 0)
915 horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
917 vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
921 horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
922 vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
927 horizontal_scale=geometry_info.rho;
928 vertical_scale=geometry_info.sigma;
929 if ((flags & PercentValue) != 0)
931 if ((flags & AspectValue) == 0)
933 horizontal_scale*=(composite_image->columns-1.0)/200.0;
934 vertical_scale*=(composite_image->rows-1.0)/200.0;
938 horizontal_scale*=(image->columns-1.0)/200.0;
939 vertical_scale*=(image->rows-1.0)/200.0;
942 if ((flags & HeightValue) == 0)
943 vertical_scale=horizontal_scale;
946 Determine fixed center point for absolute distortion map
948 Displace offset relative to a fixed absolute point
949 Select that point according to +X+Y user inputs.
950 default = center of overlay image
951 arg flag '!' = locations/percentage relative to background image
953 center.x=(MagickRealType) x_offset;
954 center.y=(MagickRealType) y_offset;
955 if (compose == DistortCompositeOp)
957 if ((flags & XValue) == 0)
958 if ((flags & AspectValue) == 0)
959 center.x=(MagickRealType) x_offset+(composite_image->columns-1)/
962 center.x=((MagickRealType) image->columns-1)/2.0;
964 if ((flags & AspectValue) == 0)
965 center.x=(MagickRealType) x_offset+geometry_info.xi;
967 center.x=geometry_info.xi;
968 if ((flags & YValue) == 0)
969 if ((flags & AspectValue) == 0)
970 center.y=(MagickRealType) y_offset+(composite_image->rows-1)/2.0;
972 center.y=((MagickRealType) image->rows-1)/2.0;
974 if ((flags & AspectValue) == 0)
975 center.y=(MagickRealType) y_offset+geometry_info.psi;
977 center.y=geometry_info.psi;
980 Shift the pixel offset point as defined by the provided,
981 displacement/distortion map. -- Like a lens...
983 GetPixelInfo(image,&pixel);
984 image_view=AcquireCacheView(image);
985 destination_view=AcquireCacheView(destination_image);
986 composite_view=AcquireCacheView(composite_image);
987 for (y=0; y < (ssize_t) composite_image->rows; y++)
992 register const Quantum
1001 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1003 p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
1005 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
1006 destination_image->columns,1,exception);
1007 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1009 for (x=0; x < (ssize_t) composite_image->columns; x++)
1011 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1013 p+=GetPixelChannels(composite_image);
1017 Displace the offset.
1019 offset.x=(horizontal_scale*(GetPixelRed(composite_image,p)-
1020 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1021 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
1023 offset.y=(vertical_scale*(GetPixelGreen(composite_image,p)-
1024 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1025 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
1027 (void) InterpolatePixelInfo(image,image_view,
1028 UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1031 Mask with the 'invalid pixel mask' in alpha channel.
1033 pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
1034 pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
1035 SetPixelInfoPixel(destination_image,&pixel,q);
1036 p+=GetPixelChannels(composite_image);
1037 q+=GetPixelChannels(destination_image);
1039 sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1040 if (sync == MagickFalse)
1043 destination_view=DestroyCacheView(destination_view);
1044 composite_view=DestroyCacheView(composite_view);
1045 image_view=DestroyCacheView(image_view);
1046 composite_image=destination_image;
1049 case DissolveCompositeOp:
1052 Geometry arguments to dissolve factors.
1054 value=GetImageArtifact(composite_image,"compose:args");
1055 if (value != (char *) NULL)
1057 flags=ParseGeometry(value,&geometry_info);
1058 source_dissolve=geometry_info.rho/100.0;
1059 destination_dissolve=1.0;
1060 if ((source_dissolve-MagickEpsilon) < 0.0)
1061 source_dissolve=0.0;
1062 if ((source_dissolve+MagickEpsilon) > 1.0)
1064 destination_dissolve=2.0-source_dissolve;
1065 source_dissolve=1.0;
1067 if ((flags & SigmaValue) != 0)
1068 destination_dissolve=geometry_info.sigma/100.0;
1069 if ((destination_dissolve-MagickEpsilon) < 0.0)
1070 destination_dissolve=0.0;
1071 modify_outside_overlay=MagickTrue;
1072 if ((destination_dissolve+MagickEpsilon) > 1.0 )
1074 destination_dissolve=1.0;
1075 modify_outside_overlay=MagickFalse;
1080 case BlendCompositeOp:
1082 value=GetImageArtifact(composite_image,"compose:args");
1083 if (value != (char *) NULL)
1085 flags=ParseGeometry(value,&geometry_info);
1086 source_dissolve=geometry_info.rho/100.0;
1087 destination_dissolve=1.0-source_dissolve;
1088 if ((flags & SigmaValue) != 0)
1089 destination_dissolve=geometry_info.sigma/100.0;
1090 modify_outside_overlay=MagickTrue;
1091 if ((destination_dissolve+MagickEpsilon) > 1.0)
1092 modify_outside_overlay=MagickFalse;
1096 case MathematicsCompositeOp:
1099 Just collect the values from "compose:args", setting.
1100 Unused values are set to zero automagically.
1102 Arguments are normally a comma separated list, so this probably should
1103 be changed to some 'general comma list' parser, (with a minimum
1106 SetGeometryInfo(&geometry_info);
1107 value=GetImageArtifact(composite_image,"compose:args");
1108 if (value != (char *) NULL)
1109 (void) ParseGeometry(value,&geometry_info);
1112 case ModulateCompositeOp:
1115 Determine the brightness and saturation scale.
1117 value=GetImageArtifact(composite_image,"compose:args");
1118 if (value != (char *) NULL)
1120 flags=ParseGeometry(value,&geometry_info);
1121 percent_brightness=geometry_info.rho;
1122 if ((flags & SigmaValue) != 0)
1123 percent_saturation=geometry_info.sigma;
1127 case ThresholdCompositeOp:
1130 Determine the amount and threshold.
1132 value=GetImageArtifact(composite_image,"compose:args");
1133 if (value != (char *) NULL)
1135 flags=ParseGeometry(value,&geometry_info);
1136 amount=geometry_info.rho;
1137 threshold=geometry_info.sigma;
1138 if ((flags & SigmaValue) == 0)
1141 threshold*=QuantumRange;
1147 value=GetImageArtifact(composite_image,"compose:outside-overlay");
1148 if (value != (const char *) NULL)
1149 modify_outside_overlay=IsMagickTrue(value);
1155 midpoint=((MagickRealType) QuantumRange+1.0)/2;
1156 image_view=AcquireCacheView(image);
1157 composite_view=AcquireCacheView(composite_image);
1158 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1159 #pragma omp parallel for schedule(static,4) shared(progress,status)
1161 for (y=0; y < (ssize_t) image->rows; y++)
1174 register const Quantum
1183 if (status == MagickFalse)
1185 if (modify_outside_overlay == MagickFalse)
1189 if ((y-y_offset) >= (ssize_t) composite_image->rows)
1193 If pixels is NULL, y is outside overlay region.
1195 pixels=(Quantum *) NULL;
1197 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
1199 p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
1200 composite_image->columns,1,exception);
1201 if (p == (const Quantum *) NULL)
1208 p-=x_offset*GetPixelChannels(composite_image);
1210 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1211 if (q == (Quantum *) NULL)
1219 for (x=0; x < (ssize_t) image->columns; x++)
1237 if (modify_outside_overlay == MagickFalse)
1241 q+=GetPixelChannels(image);
1244 if ((x-x_offset) >= (ssize_t) composite_image->columns)
1247 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1248 ((x-x_offset) >= (ssize_t) composite_image->columns))
1251 source[MaxPixelChannels];
1256 Dc: destination color.
1258 (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
1260 if (GetPixelMask(image,q) != 0)
1262 q+=GetPixelChannels(image);
1265 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1277 channel=GetPixelChannelMapChannel(image,i);
1278 traits=GetPixelChannelMapTraits(image,channel);
1279 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
1280 if ((traits == UndefinedPixelTrait) ||
1281 (composite_traits == UndefinedPixelTrait))
1285 case AlphaCompositeOp:
1286 case ChangeMaskCompositeOp:
1287 case CopyAlphaCompositeOp:
1288 case DstAtopCompositeOp:
1289 case DstInCompositeOp:
1291 case IntensityCompositeOp:
1292 case OutCompositeOp:
1293 case SrcInCompositeOp:
1294 case SrcOutCompositeOp:
1296 pixel=(MagickRealType) q[i];
1297 if (channel == AlphaPixelChannel)
1298 pixel=(MagickRealType) TransparentAlpha;
1301 case ClearCompositeOp:
1302 case CopyCompositeOp:
1303 case ReplaceCompositeOp:
1304 case SrcCompositeOp:
1306 if (channel == AlphaPixelChannel)
1308 pixel=(MagickRealType) TransparentAlpha;
1314 case BlendCompositeOp:
1315 case DissolveCompositeOp:
1317 if (channel == AlphaPixelChannel)
1319 pixel=destination_dissolve*GetPixelAlpha(composite_image,
1323 pixel=(MagickRealType) source[channel];
1328 pixel=(MagickRealType) source[channel];
1332 q[i]=ClampToQuantum(pixel);
1334 q+=GetPixelChannels(image);
1338 Authentic composite:
1339 Sa: normalized source alpha.
1340 Da: normalized destination alpha.
1342 Sa=QuantumScale*GetPixelAlpha(composite_image,p);
1343 Da=QuantumScale*GetPixelAlpha(image,q);
1346 case BumpmapCompositeOp:
1348 alpha=GetPixelIntensity(composite_image,p)*Sa;
1351 case ColorBurnCompositeOp:
1352 case ColorDodgeCompositeOp:
1353 case DifferenceCompositeOp:
1354 case DivideDstCompositeOp:
1355 case DivideSrcCompositeOp:
1356 case ExclusionCompositeOp:
1357 case HardLightCompositeOp:
1358 case LinearBurnCompositeOp:
1359 case LinearDodgeCompositeOp:
1360 case LinearLightCompositeOp:
1361 case MathematicsCompositeOp:
1362 case MinusDstCompositeOp:
1363 case MinusSrcCompositeOp:
1364 case ModulusAddCompositeOp:
1365 case ModulusSubtractCompositeOp:
1366 case MultiplyCompositeOp:
1367 case OverlayCompositeOp:
1368 case PegtopLightCompositeOp:
1369 case PinLightCompositeOp:
1370 case ScreenCompositeOp:
1371 case SoftLightCompositeOp:
1372 case VividLightCompositeOp:
1374 alpha=RoundToUnity(Sa+Da-Sa*Da);
1377 case DarkenCompositeOp:
1378 case DstAtopCompositeOp:
1379 case DstInCompositeOp:
1381 case LightenCompositeOp:
1382 case SrcInCompositeOp:
1387 case DissolveCompositeOp:
1389 alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
1390 Sa+destination_dissolve*Da;
1393 case DstOverCompositeOp:
1395 alpha=Da*(-Sa)+Da+Sa;
1398 case DstOutCompositeOp:
1403 case OutCompositeOp:
1404 case SrcOutCompositeOp:
1409 case OverCompositeOp:
1410 case SrcOverCompositeOp:
1412 alpha=Sa*(-Da)+Sa+Da;
1415 case BlendCompositeOp:
1416 case PlusCompositeOp:
1418 alpha=RoundToUnity(Sa+Da);
1421 case XorCompositeOp:
1423 alpha=Sa+Da-2.0*Sa*Da;
1432 if (GetPixelMask(image,p) != 0)
1434 p+=GetPixelChannels(composite_image);
1435 q+=GetPixelChannels(image);
1438 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1453 channel=GetPixelChannelMapChannel(image,i);
1454 traits=GetPixelChannelMapTraits(image,channel);
1455 composite_traits=GetPixelChannelMapTraits(composite_image,channel);
1456 if (traits == UndefinedPixelTrait)
1458 if ((compose != IntensityCompositeOp) &&
1459 (composite_traits == UndefinedPixelTrait))
1463 Dc: destination color.
1465 Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
1466 Dc=(MagickRealType) q[i];
1467 if ((traits & CopyPixelTrait) != 0)
1469 if (channel != AlphaPixelChannel)
1474 q[i]=ClampToQuantum(Sc);
1482 case AlphaCompositeOp:
1484 pixel=QuantumRange*Sa;
1487 case AtopCompositeOp:
1488 case CopyBlackCompositeOp:
1489 case CopyBlueCompositeOp:
1490 case CopyCyanCompositeOp:
1491 case CopyGreenCompositeOp:
1492 case CopyMagentaCompositeOp:
1493 case CopyRedCompositeOp:
1494 case CopyYellowCompositeOp:
1495 case SrcAtopCompositeOp:
1496 case DstCompositeOp:
1499 pixel=QuantumRange*Da;
1502 case ChangeMaskCompositeOp:
1507 if (Da > ((MagickRealType) QuantumRange/2.0))
1509 pixel=(MagickRealType) TransparentAlpha;
1512 equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
1513 if (equivalent != MagickFalse)
1515 pixel=(MagickRealType) TransparentAlpha;
1518 pixel=(MagickRealType) OpaqueAlpha;
1521 case ClearCompositeOp:
1523 pixel=(MagickRealType) TransparentAlpha;
1526 case ColorizeCompositeOp:
1527 case HueCompositeOp:
1528 case LuminizeCompositeOp:
1529 case SaturateCompositeOp:
1531 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1533 pixel=QuantumRange*Da;
1536 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1538 pixel=QuantumRange*Sa;
1543 pixel=QuantumRange*Da;
1546 pixel=QuantumRange*Sa;
1549 case CopyCompositeOp:
1550 case CopyAlphaCompositeOp:
1551 case DisplaceCompositeOp:
1552 case DistortCompositeOp:
1553 case DstAtopCompositeOp:
1554 case ReplaceCompositeOp:
1555 case SrcCompositeOp:
1557 pixel=QuantumRange*Sa;
1560 case DarkenIntensityCompositeOp:
1562 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1563 (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
1566 case IntensityCompositeOp:
1568 pixel=(MagickRealType) GetPixelIntensity(composite_image,p);
1571 case LightenIntensityCompositeOp:
1573 pixel=Sa*GetPixelIntensity(composite_image,p) >
1574 Da*GetPixelIntensity(image,q) ? Sa : Da;
1577 case ModulateCompositeOp:
1579 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1581 pixel=QuantumRange*Da;
1584 pixel=QuantumRange*Da;
1589 pixel=QuantumRange*alpha;
1593 q[i]=ClampToQuantum(pixel);
1597 Porter-Duff compositions:
1598 Sca: source normalized color multiplied by alpha.
1599 Dca: normalized destination color multiplied by alpha.
1601 Sca=QuantumScale*Sa*Sc;
1602 Dca=QuantumScale*Da*Dc;
1605 case DarkenCompositeOp:
1606 case LightenCompositeOp:
1607 case ModulusSubtractCompositeOp:
1615 gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
1619 case AlphaCompositeOp:
1621 pixel=QuantumRange*Sa;
1624 case AtopCompositeOp:
1625 case SrcAtopCompositeOp:
1627 pixel=Sc*Sa+Dc*(1.0-Sa);
1630 case BlendCompositeOp:
1632 pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1635 case BlurCompositeOp:
1636 case DisplaceCompositeOp:
1637 case DistortCompositeOp:
1638 case CopyCompositeOp:
1639 case ReplaceCompositeOp:
1640 case SrcCompositeOp:
1645 case BumpmapCompositeOp:
1647 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1652 pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1655 case ChangeMaskCompositeOp:
1660 case ClearCompositeOp:
1665 case ColorBurnCompositeOp:
1668 Refer to the March 2009 SVG specification.
1670 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1672 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1675 if (Sca < MagickEpsilon)
1677 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1680 pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
1681 Sca*(1.0-Da)+Dca*(1.0-Sa));
1684 case ColorDodgeCompositeOp:
1686 if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1688 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1691 if (fabs(Sca-Sa) < MagickEpsilon)
1693 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1696 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1700 case ColorizeCompositeOp:
1702 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1707 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1712 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1713 GetPixelBlue(image,q),&sans,&sans,&brightness);
1714 CompositeHSB(GetPixelRed(composite_image,p),
1715 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1716 &hue,&saturation,&sans);
1717 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1720 case RedPixelChannel: pixel=red; break;
1721 case GreenPixelChannel: pixel=green; break;
1722 case BluePixelChannel: pixel=blue; break;
1723 default: pixel=Dc; break;
1727 case CopyAlphaCompositeOp:
1728 case IntensityCompositeOp:
1730 if (channel == AlphaPixelChannel)
1731 pixel=(MagickRealType) GetPixelAlpha(composite_image,p);
1734 case CopyBlackCompositeOp:
1736 if (channel == BlackPixelChannel)
1737 pixel=(MagickRealType) GetPixelBlack(composite_image,p);
1740 case CopyBlueCompositeOp:
1741 case CopyYellowCompositeOp:
1743 if (channel == BluePixelChannel)
1744 pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1747 case CopyGreenCompositeOp:
1748 case CopyMagentaCompositeOp:
1750 if (channel == GreenPixelChannel)
1751 pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1754 case CopyRedCompositeOp:
1755 case CopyCyanCompositeOp:
1757 if (channel == RedPixelChannel)
1758 pixel=(MagickRealType) GetPixelRed(composite_image,p);
1761 case DarkenCompositeOp:
1764 Darken is equivalent to a 'Minimum' method
1765 OR a greyscale version of a binary 'Or'
1766 OR the 'Intersection' of pixel sets.
1770 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1773 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1776 case DarkenIntensityCompositeOp:
1778 pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1779 (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1782 case DifferenceCompositeOp:
1784 pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1787 case DissolveCompositeOp:
1789 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1790 destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1793 case DivideDstCompositeOp:
1795 if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1797 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1800 if (fabs(Dca) < MagickEpsilon)
1802 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1805 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1808 case DivideSrcCompositeOp:
1810 if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1812 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1815 if (fabs(Sca) < MagickEpsilon)
1817 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1820 pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1823 case DstAtopCompositeOp:
1825 pixel=Dc*Da+Sc*(1.0-Da);
1828 case DstCompositeOp:
1834 case DstInCompositeOp:
1836 pixel=gamma*(Sa*Dc*Sa);
1839 case DstOutCompositeOp:
1841 pixel=gamma*(Da*Dc*(1.0-Sa));
1844 case DstOverCompositeOp:
1846 pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1849 case ExclusionCompositeOp:
1851 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1855 case HardLightCompositeOp:
1859 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1863 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1867 case HueCompositeOp:
1869 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1874 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1879 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1880 GetPixelBlue(image,q),&hue,&saturation,&brightness);
1881 CompositeHSB(GetPixelRed(composite_image,p),
1882 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1884 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1887 case RedPixelChannel: pixel=red; break;
1888 case GreenPixelChannel: pixel=green; break;
1889 case BluePixelChannel: pixel=blue; break;
1890 default: pixel=Dc; break;
1895 case SrcInCompositeOp:
1897 pixel=gamma*(Da*Sc*Da);
1900 case LinearBurnCompositeOp:
1903 LinearBurn: as defined by Abode Photoshop, according to
1904 http://www.simplefilter.de/en/basics/mixmods.html is:
1906 f(Sc,Dc) = Sc + Dc - 1
1908 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1911 case LinearDodgeCompositeOp:
1913 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1916 case LinearLightCompositeOp:
1919 LinearLight: as defined by Abode Photoshop, according to
1920 http://www.simplefilter.de/en/basics/mixmods.html is:
1922 f(Sc,Dc) = Dc + 2*Sc - 1
1924 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1927 case LightenCompositeOp:
1931 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1934 pixel=QuantumRange*gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1937 case LightenIntensityCompositeOp:
1940 Lighten is equivalent to a 'Maximum' method
1941 OR a greyscale version of a binary 'And'
1942 OR the 'Union' of pixel sets.
1944 pixel=Sa*GetPixelIntensity(composite_image,p) >
1945 Da*GetPixelIntensity(image,q) ? Sc : Dc;
1948 case LuminizeCompositeOp:
1950 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1955 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1960 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1961 GetPixelBlue(image,q),&hue,&saturation,&brightness);
1962 CompositeHSB(GetPixelRed(composite_image,p),
1963 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1964 &sans,&sans,&brightness);
1965 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1968 case RedPixelChannel: pixel=red; break;
1969 case GreenPixelChannel: pixel=green; break;
1970 case BluePixelChannel: pixel=blue; break;
1971 default: pixel=Dc; break;
1975 case MathematicsCompositeOp:
1978 'Mathematics' a free form user control mathematical composition
1981 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
1983 Where the arguments A,B,C,D are (currently) passed to composite
1984 as a command separated 'geometry' string in "compose:args" image
1987 A = a->rho, B = a->sigma, C = a->xi, D = a->psi
1989 Applying the SVG transparency formula (see above), we get...
1991 Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
1993 Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
1996 pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
1997 Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
1998 Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
2001 case MinusDstCompositeOp:
2003 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2006 case MinusSrcCompositeOp:
2009 Minus source from destination.
2013 pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2016 case ModulateCompositeOp:
2021 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2026 offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
2032 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
2033 GetPixelBlue(image,q),&hue,&saturation,&brightness);
2034 brightness+=(0.01*percent_brightness*offset)/midpoint;
2035 saturation*=0.01*percent_saturation;
2036 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
2039 case RedPixelChannel: pixel=red; break;
2040 case GreenPixelChannel: pixel=green; break;
2041 case BluePixelChannel: pixel=blue; break;
2042 default: pixel=Dc; break;
2046 case ModulusAddCompositeOp:
2049 if (pixel > QuantumRange)
2050 pixel-=(QuantumRange+1.0);
2051 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2054 case ModulusSubtractCompositeOp:
2058 pixel+=(QuantumRange+1.0);
2059 pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2062 case MultiplyCompositeOp:
2064 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2067 case OutCompositeOp:
2068 case SrcOutCompositeOp:
2070 pixel=gamma*(Sa*Sc*(1.0-Da));
2073 case OverCompositeOp:
2074 case SrcOverCompositeOp:
2076 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2079 case OverlayCompositeOp:
2083 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2087 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2091 case PegtopLightCompositeOp:
2094 PegTop: A Soft-Light alternative: A continuous version of the
2095 Softlight function, producing very similar results.
2097 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2099 http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2101 if (fabs(Da) < MagickEpsilon)
2103 pixel=QuantumRange*gamma*(Sca);
2106 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2110 case PinLightCompositeOp:
2113 PinLight: A Photoshop 7 composition method
2114 http://www.simplefilter.de/en/basics/mixmods.html
2116 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2118 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2120 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2123 if ((Dca*Sa) > (2.0*Sca*Da))
2125 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2128 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2131 case PlusCompositeOp:
2133 pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
2136 case SaturateCompositeOp:
2138 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2143 if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2148 CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
2149 GetPixelBlue(image,q),&hue,&saturation,&brightness);
2150 CompositeHSB(GetPixelRed(composite_image,p),
2151 GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
2152 &sans,&saturation,&sans);
2153 HSBComposite(hue,saturation,brightness,&red,&green,&blue);
2156 case RedPixelChannel: pixel=red; break;
2157 case GreenPixelChannel: pixel=green; break;
2158 case BluePixelChannel: pixel=blue; break;
2159 default: pixel=Dc; break;
2163 case ScreenCompositeOp:
2166 Screen: a negated multiply:
2168 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2170 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2173 case SoftLightCompositeOp:
2176 Refer to the March 2009 SVG specification.
2180 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2181 Sca*(1.0-Da)+Dca*(1.0-Sa));
2184 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2186 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2187 (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2191 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2192 (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2195 case ThresholdCompositeOp:
2201 if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2206 pixel=gamma*(Dc+delta*amount);
2209 case VividLightCompositeOp:
2212 VividLight: A Photoshop 7 composition method. See
2213 http://www.simplefilter.de/en/basics/mixmods.html.
2215 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2217 if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2219 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2222 if ((2.0*Sca) <= Sa)
2224 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2225 (1.0-Da)+Dca*(1.0-Sa));
2228 pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2232 case XorCompositeOp:
2234 pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2243 q[i]=ClampToQuantum(pixel);
2245 p+=GetPixelChannels(composite_image);
2246 channels=GetPixelChannels(composite_image);
2247 if (p >= (pixels+channels*composite_image->columns))
2249 q+=GetPixelChannels(image);
2251 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2253 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2258 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2259 #pragma omp critical (MagickCore_CompositeImage)
2261 proceed=SetImageProgress(image,CompositeImageTag,progress++,
2263 if (proceed == MagickFalse)
2267 composite_view=DestroyCacheView(composite_view);
2268 image_view=DestroyCacheView(image_view);
2269 if (destination_image != (Image * ) NULL)
2270 destination_image=DestroyImage(destination_image);
2275 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2279 % T e x t u r e I m a g e %
2283 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2285 % TextureImage() repeatedly tiles the texture image across and down the image
2288 % The format of the TextureImage method is:
2290 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2291 % ExceptionInfo *exception)
2293 % A description of each parameter follows:
2295 % o image: the image.
2297 % o texture_image: This image is the texture to layer on the background.
2300 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
2301 ExceptionInfo *exception)
2303 #define TextureImageTag "Texture/Image"
2318 assert(image != (Image *) NULL);
2319 if (image->debug != MagickFalse)
2320 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2321 assert(image->signature == MagickSignature);
2322 if (texture == (const Image *) NULL)
2323 return(MagickFalse);
2324 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2325 return(MagickFalse);
2326 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2327 if (texture_image == (const Image *) NULL)
2328 return(MagickFalse);
2329 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
2332 if ((image->compose != CopyCompositeOp) &&
2333 ((image->compose != OverCompositeOp) || (image->matte != MagickFalse) ||
2334 (texture_image->matte != MagickFalse)))
2337 Tile texture onto the image background.
2339 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2340 #pragma omp parallel for schedule(static) shared(status)
2342 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2347 if (status == MagickFalse)
2349 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2354 thread_status=CompositeImage(image,image->compose,texture_image,x+
2355 texture_image->tile_offset.x,y+texture_image->tile_offset.y,
2357 if (thread_status == MagickFalse)
2359 status=thread_status;
2363 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2368 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2369 #pragma omp critical (MagickCore_TextureImage)
2371 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2373 if (proceed == MagickFalse)
2377 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2378 image->rows,image->rows);
2379 texture_image=DestroyImage(texture_image);
2383 Tile texture onto the image background (optimized).
2386 image_view=AcquireCacheView(image);
2387 texture_view=AcquireCacheView(texture_image);
2388 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2389 #pragma omp parallel for schedule(static) shared(status)
2391 for (y=0; y < (ssize_t) image->rows; y++)
2396 register const Quantum
2409 if (status == MagickFalse)
2411 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2412 (y+texture_image->tile_offset.y) % texture_image->rows,
2413 texture_image->columns,1,exception);
2414 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2415 if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2420 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2426 width=texture_image->columns;
2427 if ((x+(ssize_t) width) > (ssize_t) image->columns)
2428 width=image->columns-x;
2429 for (j=0; j < (ssize_t) width; j++)
2434 if (GetPixelMask(image,p) != 0)
2436 p+=GetPixelChannels(texture_image);
2437 q+=GetPixelChannels(image);
2440 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2449 channel=GetPixelChannelMapChannel(texture_image,i);
2450 texture_traits=GetPixelChannelMapTraits(texture_image,channel);
2451 traits=GetPixelChannelMapTraits(image,channel);
2452 if ((traits == UndefinedPixelTrait) ||
2453 (texture_traits == UndefinedPixelTrait))
2455 SetPixelChannel(image,channel,p[i],q);
2457 p+=GetPixelChannels(texture_image);
2458 q+=GetPixelChannels(image);
2461 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2462 if (sync == MagickFalse)
2464 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2469 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2470 #pragma omp critical (MagickCore_TextureImage)
2472 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2474 if (proceed == MagickFalse)
2478 texture_view=DestroyCacheView(texture_view);
2479 image_view=DestroyCacheView(image_view);
2480 texture_image=DestroyImage(texture_image);