43 #include "magick/studio.h"
44 #include "magick/accelerate-private.h"
45 #include "magick/artifact.h"
46 #include "magick/cache-view.h"
47 #include "magick/channel.h"
48 #include "magick/client.h"
49 #include "magick/color.h"
50 #include "magick/color-private.h"
51 #include "magick/colorspace.h"
52 #include "magick/colorspace-private.h"
53 #include "magick/composite.h"
54 #include "magick/composite-private.h"
55 #include "magick/constitute.h"
56 #include "magick/draw.h"
57 #include "magick/fx.h"
58 #include "magick/gem.h"
59 #include "magick/geometry.h"
60 #include "magick/image.h"
61 #include "magick/image-private.h"
62 #include "magick/list.h"
63 #include "magick/log.h"
64 #include "magick/monitor.h"
65 #include "magick/monitor-private.h"
66 #include "magick/memory_.h"
67 #include "magick/option.h"
68 #include "magick/pixel-private.h"
69 #include "magick/property.h"
70 #include "magick/quantum.h"
71 #include "magick/resample.h"
72 #include "magick/resource_.h"
73 #include "magick/string_.h"
74 #include "magick/thread-private.h"
75 #include "magick/threshold.h"
76 #include "magick/token.h"
77 #include "magick/utility.h"
78 #include "magick/version.h"
192 static inline MagickRealType Atop(
const MagickRealType p,
193 const MagickRealType Sa,
const MagickRealType q,
194 const MagickRealType magick_unused(Da))
196 magick_unreferenced(Da);
198 return(p*Sa+q*(1.0-Sa));
207 Sa=1.0-QuantumScale*p->opacity;
208 composite->opacity=q->opacity;
209 composite->red=Atop(p->red,Sa,q->red,1.0);
210 composite->green=Atop(p->green,Sa,q->green,1.0);
211 composite->blue=Atop(p->blue,Sa,q->blue,1.0);
212 if (q->colorspace == CMYKColorspace)
213 composite->index=Atop(p->index,Sa,q->index,1.0);
226 intensity=MagickPixelIntensity(p);
227 composite->red=QuantumScale*intensity*q->red;
228 composite->green=QuantumScale*intensity*q->green;
229 composite->blue=QuantumScale*intensity*q->blue;
230 composite->opacity=(MagickRealType) QuantumScale*intensity*p->opacity;
231 if (q->colorspace == CMYKColorspace)
232 composite->index=QuantumScale*intensity*q->index;
238 composite->opacity=(MagickRealType) TransparentOpacity;
240 composite->green=0.0;
242 if (q->colorspace == CMYKColorspace)
243 composite->index=0.0;
246 static MagickRealType ColorBurn(
const MagickRealType Sca,
247 const MagickRealType Sa,
const MagickRealType Dca,
const MagickRealType Da)
252 if ((fabs((
double) Sca) < MagickEpsilon) &&
253 (fabs((
double) (Dca-Da)) < MagickEpsilon))
254 return(Sa*Da+Dca*(1.0-Sa));
255 if (Sca < MagickEpsilon)
256 return(Dca*(1.0-Sa));
257 SaSca=Sa*PerceptibleReciprocal(Sca);
258 return(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*SaSca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
269 Sa=1.0-QuantumScale*p->opacity;
270 Da=1.0-QuantumScale*q->opacity;
271 gamma=RoundToUnity(Sa+Da-Sa*Da);
272 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
273 gamma=QuantumRange/(fabs((
double) gamma) < MagickEpsilon ? MagickEpsilon :
275 composite->red=gamma*ColorBurn(QuantumScale*p->red*Sa,Sa,QuantumScale*
277 composite->green=gamma*ColorBurn(QuantumScale*p->green*Sa,Sa,QuantumScale*
279 composite->blue=gamma*ColorBurn(QuantumScale*p->blue*Sa,Sa,QuantumScale*
281 if (q->colorspace == CMYKColorspace)
282 composite->index=gamma*ColorBurn(QuantumScale*p->index*Sa,Sa,QuantumScale*
287 static MagickRealType ColorDodge(
const MagickRealType Sca,
288 const MagickRealType Sa,
const MagickRealType Dca,
const MagickRealType Da)
293 if ((Sca*Da+Dca*Sa) >= Sa*Da)
294 return(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
295 return(Dca*Sa*Sa*PerceptibleReciprocal(Sa-Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
301 if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
302 return(Sca*(1.0-Da));
303 if (fabs(Sca-Sa) < MagickEpsilon)
304 return(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
305 return(Sa*MagickMin(Da,Dca*Sa/(Sa-Sca)));
316 if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
317 return(Sca*(1.0-Da)+Dca*(1.0-Sa));
318 if (fabs(Sca-Sa) < MagickEpsilon)
319 return(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
320 return(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
332 Sa=1.0-QuantumScale*p->opacity;
333 Da=1.0-QuantumScale*q->opacity;
334 gamma=RoundToUnity(Sa+Da-Sa*Da);
335 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
336 gamma=QuantumRange/(fabs((
double) gamma) < MagickEpsilon ? MagickEpsilon :
338 composite->red=gamma*ColorDodge(QuantumScale*p->red*Sa,Sa,QuantumScale*
340 composite->green=gamma*ColorDodge(QuantumScale*p->green*Sa,Sa,QuantumScale*
342 composite->blue=gamma*ColorDodge(QuantumScale*p->blue*Sa,Sa,QuantumScale*
344 if (q->colorspace == CMYKColorspace)
345 composite->index=gamma*ColorDodge(QuantumScale*p->index*Sa,Sa,QuantumScale*
349 static inline MagickRealType Darken(
const MagickRealType p,
350 const MagickRealType alpha,
const MagickRealType q,
const MagickRealType beta)
353 return(MagickOver_(p,alpha,q,beta));
354 return(MagickOver_(q,beta,p,alpha));
369 if ( (channel & SyncChannels) != 0 ) {
370 composite->opacity=QuantumScale*p->opacity*q->opacity;
371 gamma=1.0-QuantumScale*composite->opacity;
372 gamma=PerceptibleReciprocal(gamma);
373 composite->red=gamma*Darken(p->red,p->opacity,q->red,q->opacity);
374 composite->green=gamma*Darken(p->green,p->opacity,q->green,q->opacity);
375 composite->blue=gamma*Darken(p->blue,p->opacity,q->blue,q->opacity);
376 if (q->colorspace == CMYKColorspace)
377 composite->index=gamma*Darken(p->index,p->opacity,q->index,q->opacity);
380 if ( (channel & AlphaChannel) != 0 )
381 composite->opacity=MagickMax(p->opacity,q->opacity);
382 if ( (channel & RedChannel) != 0 )
383 composite->red=MagickMin(p->red,q->red);
384 if ( (channel & GreenChannel) != 0 )
385 composite->green=MagickMin(p->green,q->green);
386 if ( (channel & BlueChannel) != 0 )
387 composite->blue=MagickMin(p->blue,q->blue);
388 if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
389 composite->index=MagickMin(p->index,q->index);
402 if ( (channel & SyncChannels) != 0 ) {
407 Sa=1.0-QuantumScale*p->opacity;
408 Da=1.0-QuantumScale*q->opacity;
409 *composite = (Sa*MagickPixelIntensity(p) < Da*MagickPixelIntensity(q))
413 int from_p = (MagickPixelIntensity(p) < MagickPixelIntensity(q));
414 if ( (channel & AlphaChannel) != 0 )
415 composite->opacity = from_p ? p->opacity : q->opacity;
416 if ( (channel & RedChannel) != 0 )
417 composite->red = from_p ? p->red : q->red;
418 if ( (channel & GreenChannel) != 0 )
419 composite->green = from_p ? p->green : q->green;
420 if ( (channel & BlueChannel) != 0 )
421 composite->blue = from_p ? p->blue : q->blue;
422 if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
423 composite->index = from_p ? p->index : q->index;
427 static inline MagickRealType Difference(
const MagickRealType p,
428 const MagickRealType Sa,
const MagickRealType q,
const MagickRealType Da)
431 return(Sa*p+Da*q-Sa*Da*2.0*MagickMin(p,q));
445 Sa=1.0-QuantumScale*p->opacity;
446 Da=1.0-QuantumScale*q->opacity;
447 if ( (channel & SyncChannels) != 0 ) {
448 gamma=RoundToUnity(Sa+Da-Sa*Da);
449 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
450 gamma=PerceptibleReciprocal(gamma);
452 composite->red=gamma*Difference(p->red,Sa,q->red,Da);
453 composite->green=gamma*Difference(p->green,Sa,q->green,Da);
454 composite->blue=gamma*Difference(p->blue,Sa,q->blue,Da);
455 if (q->colorspace == CMYKColorspace)
456 composite->index=gamma*Difference(p->index,Sa,q->index,Da);
459 if ( (channel & AlphaChannel) != 0 )
460 composite->opacity=QuantumRange-fabs((
double) (p->opacity-q->opacity));
461 if ( (channel & RedChannel) != 0 )
462 composite->red=fabs((
double) (p->red-q->red));
463 if ( (channel & GreenChannel) != 0 )
464 composite->green=fabs((
double) (p->green-q->green));
465 if ( (channel & BlueChannel) != 0 )
466 composite->blue=fabs((
double) (p->blue-q->blue));
467 if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
468 composite->index=fabs((
double) (p->index-q->index));
472 static MagickRealType Divide(
const MagickRealType Sca,
const MagickRealType Sa,
473 const MagickRealType Dca,
const MagickRealType Da)
485 if ((fabs((
double) Sca) < MagickEpsilon) &&
486 (fabs((
double) Dca) < MagickEpsilon))
487 return(Sca*(1.0-Da)+Dca*(1.0-Sa));
488 if (fabs((
double) Dca) < MagickEpsilon)
489 return(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
490 return(Sca*Da*Da*PerceptibleReciprocal(Dca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
502 Sa=1.0-QuantumScale*p->opacity;
503 Da=1.0-QuantumScale*q->opacity;
504 if ( (channel & SyncChannels) != 0 ) {
505 gamma=RoundToUnity(Sa+Da-Sa*Da);
506 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
507 gamma=QuantumRange/(fabs((
double) gamma) < MagickEpsilon ? MagickEpsilon :
509 composite->red=gamma*Divide(QuantumScale*p->red*Sa,Sa,QuantumScale*
511 composite->green=gamma*Divide(QuantumScale*p->green*Sa,Sa,QuantumScale*
513 composite->blue=gamma*Divide(QuantumScale*p->blue*Sa,Sa,QuantumScale*
515 if (q->colorspace == CMYKColorspace)
516 composite->index=gamma*Divide(QuantumScale*p->index*Sa,Sa,QuantumScale*
520 if ( (channel & AlphaChannel) != 0 )
521 composite->opacity=QuantumRange*(1.0-Divide(Sa,1.0,Da,1.0));
522 if ( (channel & RedChannel) != 0 )
523 composite->red=QuantumRange*
524 Divide(QuantumScale*p->red,1.0,QuantumScale*q->red,1.0);
525 if ( (channel & GreenChannel) != 0 )
526 composite->green=QuantumRange*
527 Divide(QuantumScale*p->green,1.0,QuantumScale*q->green,1.0);
528 if ( (channel & BlueChannel) != 0 )
529 composite->blue=QuantumRange*
530 Divide(QuantumScale*p->blue,1.0,QuantumScale*q->blue,1.0);
531 if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
532 composite->index=QuantumRange*
533 Divide(QuantumScale*p->index,1.0,QuantumScale*q->index,1.0);
537 static MagickRealType Exclusion(
const MagickRealType Sca,
538 const MagickRealType Sa,
const MagickRealType Dca,
const MagickRealType Da)
540 return(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
552 Sa=1.0-QuantumScale*p->opacity;
553 Da=1.0-QuantumScale*q->opacity;
554 if ( (channel & SyncChannels) != 0 ) {
555 gamma=RoundToUnity(Sa+Da-Sa*Da);
556 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
557 gamma=QuantumRange/(fabs((
double) gamma) < MagickEpsilon ? MagickEpsilon :
559 composite->red=gamma*Exclusion(QuantumScale*p->red*Sa,Sa,QuantumScale*
561 composite->green=gamma*Exclusion(QuantumScale*p->green*Sa,Sa,QuantumScale*
563 composite->blue=gamma*Exclusion(QuantumScale*p->blue*Sa,Sa,QuantumScale*
565 if (q->colorspace == CMYKColorspace)
566 composite->index=gamma*Exclusion(QuantumScale*p->index*Sa,Sa,QuantumScale*
570 if ((channel & AlphaChannel) != 0)
571 composite->opacity=QuantumRange*(1.0-Exclusion(Sa,1.0,Da,1.0));
572 if ((channel & RedChannel) != 0)
573 composite->red=QuantumRange*Exclusion(QuantumScale*p->red,1.0,
574 QuantumScale*q->red,1.0);
575 if ((channel & GreenChannel) != 0)
576 composite->green=QuantumRange*Exclusion(QuantumScale*p->green,1.0,
577 QuantumScale*q->green,1.0);
578 if ((channel & BlueChannel) != 0)
579 composite->blue=QuantumRange*Exclusion(QuantumScale*p->blue,1.0,
580 QuantumScale*q->blue,1.0);
581 if (((channel & IndexChannel) != 0) && (q->colorspace == CMYKColorspace))
582 composite->index=QuantumRange*Exclusion(QuantumScale*p->index,1.0,
583 QuantumScale*q->index,1.0);
587 static MagickRealType HardLight(
const MagickRealType Sca,
588 const MagickRealType Sa,
const MagickRealType Dca,
const MagickRealType Da)
591 return(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
592 return(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
603 Sa=1.0-QuantumScale*p->opacity;
604 Da=1.0-QuantumScale*q->opacity;
605 gamma=RoundToUnity(Sa+Da-Sa*Da);
606 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
607 gamma=QuantumRange/(fabs((
double) gamma) < MagickEpsilon ? MagickEpsilon :
609 composite->red=gamma*HardLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
611 composite->green=gamma*HardLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
613 composite->blue=gamma*HardLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
615 if (q->colorspace == CMYKColorspace)
616 composite->index=gamma*HardLight(QuantumScale*p->index*Sa,Sa,QuantumScale*
620 static MagickRealType HardMix(
const MagickRealType Sca,
621 const MagickRealType Dca)
623 if ((Sca+Dca) < QuantumRange)
637 Sa=1.0-QuantumScale*p->opacity;
638 Da=1.0-QuantumScale*q->opacity;
639 gamma=RoundToUnity(Sa+Da-Sa*Da);
640 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
641 gamma=QuantumRange/(fabs((
double) gamma) < MagickEpsilon ? MagickEpsilon :
643 composite->red=gamma*HardMix(p->red*Sa,q->red*Da);
644 composite->green=gamma*HardMix(p->green*Sa,q->green*Da);
645 composite->blue=gamma*HardMix(p->blue*Sa,q->blue*Da);
646 if (q->colorspace == CMYKColorspace)
647 composite->index=gamma*HardMix(p->index*Sa,q->index*Da);
650 static void HCLComposite(
const double hue,
const double chroma,
const double luma,
651 MagickRealType *red,MagickRealType *green,MagickRealType *blue)
665 assert(red != (MagickRealType *) NULL);
666 assert(green != (MagickRealType *) NULL);
667 assert(blue != (MagickRealType *) NULL);
670 x=c*(1.0-fabs(fmod(h,2.0)-1.0));
674 if ((0.0 <= h) && (h < 1.0))
680 if ((1.0 <= h) && (h < 2.0))
686 if ((2.0 <= h) && (h < 3.0))
692 if ((3.0 <= h) && (h < 4.0))
698 if ((4.0 <= h) && (h < 5.0))
704 if ((5.0 <= h) && (h < 6.0))
709 m=luma-(0.298839*r+0.586811*g+0.114350*b);
710 *red=QuantumRange*(r+m);
711 *green=QuantumRange*(g+m);
712 *blue=QuantumRange*(b+m);
715 static void CompositeHCL(
const MagickRealType red,
const MagickRealType green,
716 const MagickRealType blue,
double *hue,
double *chroma,
double *luma)
729 assert(hue != (
double *) NULL);
730 assert(chroma != (
double *) NULL);
731 assert(luma != (
double *) NULL);
735 max=MagickMax(r,MagickMax(g,b));
736 c=max-(double) MagickMin(r,MagickMin(g,b));
741 if (red == (MagickRealType) max)
742 h=fmod((g-b)/c+6.0,6.0);
744 if (green == (MagickRealType) max)
747 if (blue == (MagickRealType) max)
750 *chroma=QuantumScale*c;
751 *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
754 static inline MagickRealType In(
const MagickRealType p,
const MagickRealType Sa,
755 const MagickRealType magick_unused(q),
const MagickRealType Da)
757 magick_unreferenced(q);
772 Sa=1.0-QuantumScale*p->opacity;
773 Da=1.0-QuantumScale*q->opacity;
775 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
776 gamma=PerceptibleReciprocal(gamma);
777 composite->red=gamma*In(p->red,Sa,q->red,Da);
778 composite->green=gamma*In(p->green,Sa,q->green,Da);
779 composite->blue=gamma*In(p->blue,Sa,q->blue,Da);
780 if (q->colorspace == CMYKColorspace)
781 composite->index=gamma*In(p->index,Sa,q->index,Da);
784 static inline MagickRealType Lighten(
const MagickRealType p,
785 const MagickRealType alpha,
const MagickRealType q,
const MagickRealType beta)
788 return(MagickOver_(p,alpha,q,beta));
789 return(MagickOver_(q,beta,p,alpha));
804 if ( (channel & SyncChannels) != 0 ) {
805 composite->opacity=QuantumScale*p->opacity*q->opacity;
806 gamma=1.0-QuantumScale*composite->opacity;
807 gamma=PerceptibleReciprocal(gamma);
808 composite->red=gamma*Lighten(p->red,p->opacity,q->red,q->opacity);
809 composite->green=gamma*Lighten(p->green,p->opacity,q->green,q->opacity);
810 composite->blue=gamma*Lighten(p->blue,p->opacity,q->blue,q->opacity);
811 if (q->colorspace == CMYKColorspace)
812 composite->index=gamma*Lighten(p->index,p->opacity,q->index,q->opacity);
815 if ( (channel & AlphaChannel) != 0 )
816 composite->opacity=MagickMin(p->opacity,q->opacity);
817 if ( (channel & RedChannel) != 0 )
818 composite->red=MagickMax(p->red,q->red);
819 if ( (channel & GreenChannel) != 0 )
820 composite->green=MagickMax(p->green,q->green);
821 if ( (channel & BlueChannel) != 0 )
822 composite->blue=MagickMax(p->blue,q->blue);
823 if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
824 composite->index=MagickMax(p->index,q->index);
837 if ( (channel & SyncChannels) != 0 ) {
842 Sa=1.0-QuantumScale*p->opacity;
843 Da=1.0-QuantumScale*q->opacity;
844 *composite = (Sa*MagickPixelIntensity(p) > Da*MagickPixelIntensity(q))
848 int from_p = (MagickPixelIntensity(p) > MagickPixelIntensity(q));
849 if ( (channel & AlphaChannel) != 0 )
850 composite->opacity = from_p ? p->opacity : q->opacity;
851 if ( (channel & RedChannel) != 0 )
852 composite->red = from_p ? p->red : q->red;
853 if ( (channel & GreenChannel) != 0 )
854 composite->green = from_p ? p->green : q->green;
855 if ( (channel & BlueChannel) != 0 )
856 composite->blue = from_p ? p->blue : q->blue;
857 if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
858 composite->index = from_p ? p->index : q->index;
863 static inline MagickRealType LinearDodge(
const MagickRealType Sca,
864 const MagickRealType Sa,
const MagickRealType Dca,
const MagickRealType Da)
885 Sa=1.0-QuantumScale*p->opacity;
886 Da=1.0-QuantumScale*q->opacity;
887 gamma=RoundToUnity(Sa+Da-Sa*Da);
888 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
889 gamma=PerceptibleReciprocal(gamma);
890 composite->red=gamma*(p->red*Sa+q->red*Da);
891 composite->green=gamma*(p->green*Sa+q->green*Da);
892 composite->blue=gamma*(p->blue*Sa+q->blue*Da);
893 if (q->colorspace == CMYKColorspace)
894 composite->index=gamma*(p->index*Sa+q->index*Da);
898 static inline MagickRealType LinearBurn(
const MagickRealType Sca,
899 const MagickRealType Sa,
const MagickRealType Dca,
const MagickRealType Da)
907 return(Sca+Dca-Sa*Da);
918 Sa=1.0-QuantumScale*p->opacity;
919 Da=1.0-QuantumScale*q->opacity;
920 gamma=RoundToUnity(Sa+Da-Sa*Da);
921 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
922 gamma=QuantumRange/(fabs((
double) gamma) < MagickEpsilon ? MagickEpsilon :
924 composite->red=gamma*LinearBurn(QuantumScale*p->red*Sa,Sa,QuantumScale*
926 composite->green=gamma*LinearBurn(QuantumScale*p->green*Sa,Sa,QuantumScale*
928 composite->blue=gamma*LinearBurn(QuantumScale*p->blue*Sa,Sa,QuantumScale*
930 if (q->colorspace == CMYKColorspace)
931 composite->index=gamma*LinearBurn(QuantumScale*p->index*Sa,Sa,QuantumScale*
935 static inline MagickRealType LinearLight(
const MagickRealType Sca,
936 const MagickRealType Sa,
const MagickRealType Dca,
const MagickRealType Da)
942 return(Dca+2*Sca-1.0);
950 return((Sca-Sa)*Da+Sca+Dca);
962 Sa=1.0-QuantumScale*p->opacity;
963 Da=1.0-QuantumScale*q->opacity;
964 gamma=RoundToUnity(Sa+Da-Sa*Da);
965 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
966 gamma=QuantumRange/(fabs((
double) gamma) < MagickEpsilon ? MagickEpsilon :
968 composite->red=gamma*LinearLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
970 composite->green=gamma*LinearLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
972 composite->blue=gamma*LinearLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
974 if (q->colorspace == CMYKColorspace)
975 composite->index=gamma*LinearLight(QuantumScale*p->index*Sa,Sa,QuantumScale*
979 static inline MagickRealType Mathematics(
const MagickRealType Sca,
980 const MagickRealType Sa,
const MagickRealType Dca,
const MagickRealType Da,
1001 return(geometry_info->rho*Sca*Dca+geometry_info->sigma*Sca*Da+
1002 geometry_info->xi*Dca*Sa+geometry_info->psi*Sa*Da+Sca*(1.0-Da)+
1017 Sa=1.0-QuantumScale*p->opacity;
1018 Da=1.0-QuantumScale*q->opacity;
1019 if ( (channel & SyncChannels) != 0 ) {
1020 gamma=RoundToUnity(Sa+Da-Sa*Da);
1021 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
1022 gamma=QuantumRange/(fabs((
double) gamma) < MagickEpsilon ? MagickEpsilon :
1024 composite->red=gamma*Mathematics(QuantumScale*p->red*Sa,Sa,QuantumScale*
1026 composite->green=gamma*Mathematics(QuantumScale*p->green*Sa,Sa,QuantumScale*
1027 q->green*Da,Da,args);
1028 composite->blue=gamma*Mathematics(QuantumScale*p->blue*Sa,Sa,QuantumScale*
1029 q->blue*Da,Da,args);
1030 if (q->colorspace == CMYKColorspace)
1031 composite->index=gamma*Mathematics(QuantumScale*p->index*Sa,Sa,
1032 QuantumScale*q->index*Da,Da,args);
1035 if ( (channel & AlphaChannel) != 0 )
1036 composite->opacity=QuantumRange*(1.0-Mathematics(Sa,1.0,Da,1.0,args));
1037 if ( (channel & RedChannel) != 0 )
1038 composite->red=QuantumRange*
1039 Mathematics(QuantumScale*p->red,1.0,QuantumScale*q->red,1.0,args);
1040 if ( (channel & GreenChannel) != 0 )
1041 composite->green=QuantumRange*
1042 Mathematics(QuantumScale*p->green,1.0,QuantumScale*q->green,1.0,args);
1043 if ( (channel & BlueChannel) != 0 )
1044 composite->blue=QuantumRange*
1045 Mathematics(QuantumScale*p->blue,1.0,QuantumScale*q->blue,1.0,args);
1046 if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
1047 composite->index=QuantumRange*
1048 Mathematics(QuantumScale*p->index,1.0,QuantumScale*q->index,1.0,args);
1057 if ( (channel & SyncChannels) != 0 ) {
1073 MagickPixelCompositePlus(p,p->opacity,q,q->opacity,composite);
1076 if ( (channel & AlphaChannel) != 0 )
1077 composite->opacity=p->opacity+q->opacity-QuantumRange;
1078 if ( (channel & RedChannel) != 0 )
1079 composite->red=p->red+q->red;
1080 if ( (channel & GreenChannel) != 0 )
1081 composite->green=p->green+q->green;
1082 if ( (channel & BlueChannel) != 0 )
1083 composite->blue=p->blue+q->blue;
1084 if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
1085 composite->index=p->index+q->index;
1089 static inline MagickRealType Minus(
const MagickRealType Sca,
1090 const MagickRealType Sa,
const MagickRealType Dca,
1091 const MagickRealType magick_unused(Da))
1099 magick_unreferenced(Da);
1101 return(Sca+Dca-2*Dca*Sa);
1115 Sa=1.0-QuantumScale*p->opacity;
1116 Da=1.0-QuantumScale*q->opacity;
1117 if ( (channel & SyncChannels) != 0 ) {
1118 gamma=RoundToUnity(Sa+Da-Sa*Da);
1119 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
1120 gamma=PerceptibleReciprocal(gamma);
1121 composite->red=gamma*Minus(p->red*Sa,Sa,q->red*Da,Da);
1122 composite->green=gamma*Minus(p->green*Sa,Sa,q->green*Da,Da);
1123 composite->blue=gamma*Minus(p->blue*Sa,Sa,q->blue*Da,Da);
1124 if (q->colorspace == CMYKColorspace)
1125 composite->index=gamma*Minus(p->index*Sa,Sa,q->index*Da,Da);
1128 if ( (channel & AlphaChannel) != 0 )
1129 composite->opacity=QuantumRange*(1.0-(Sa-Da));
1130 if ( (channel & RedChannel) != 0 )
1131 composite->red=p->red-q->red;
1132 if ( (channel & GreenChannel) != 0 )
1133 composite->green=p->green-q->green;
1134 if ( (channel & BlueChannel) != 0 )
1135 composite->blue=p->blue-q->blue;
1136 if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
1137 composite->index=p->index-q->index;
1141 static inline MagickRealType ModulusAdd(
const MagickRealType Sc,
1142 const MagickRealType Sa,
const MagickRealType Dc,
const MagickRealType Da)
1144 if (((Sc*Sa)+(Dc*Da)) <= QuantumRange)
1145 return((Sc*Sa)+Dc*Da);
1146 return(((Sc*Sa)+Dc*Da)-QuantumRange);
1153 if ( (channel & SyncChannels) != 0 ) {
1161 Sa=1.0-QuantumScale*p->opacity;
1162 Da=1.0-QuantumScale*q->opacity;
1163 gamma=RoundToUnity(Sa+Da-Sa*Da);
1164 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
1165 gamma=PerceptibleReciprocal(gamma);
1166 composite->red=ModulusAdd(p->red,Sa,q->red,Da);
1167 composite->green=ModulusAdd(p->green,Sa,q->green,Da);
1168 composite->blue=ModulusAdd(p->blue,Sa,q->blue,Da);
1169 if (q->colorspace == CMYKColorspace)
1170 composite->index=ModulusAdd(p->index,Sa,q->index,Da);
1173 if ( (channel & AlphaChannel) != 0 )
1174 composite->opacity=QuantumRange-ModulusAdd(QuantumRange-p->opacity,
1175 1.0,QuantumRange-q->opacity,1.0);
1176 if ( (channel & RedChannel) != 0 )
1177 composite->red=ModulusAdd(p->red,1.0,q->red,1.0);
1178 if ( (channel & GreenChannel) != 0 )
1179 composite->green=ModulusAdd(p->green,1.0,q->green,1.0);
1180 if ( (channel & BlueChannel) != 0 )
1181 composite->blue=ModulusAdd(p->blue,1.0,q->blue,1.0);
1182 if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
1183 composite->index=ModulusAdd(p->index,1.0,q->index,1.0);
1187 static inline MagickRealType ModulusSubtract(
const MagickRealType Sc,
1188 const MagickRealType Sa,
const MagickRealType Dc,
const MagickRealType Da)
1190 if (((Sc*Sa)-(Dc*Da)) <= 0.0)
1191 return((Sc*Sa)-Dc*Da);
1192 return(((Sc*Sa)-Dc*Da)+QuantumRange);
1199 if ( (channel & SyncChannels) != 0 ) {
1207 Sa=1.0-QuantumScale*p->opacity;
1208 Da=1.0-QuantumScale*q->opacity;
1209 gamma = RoundToUnity(Sa+Da-Sa*Da);
1210 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
1211 gamma=PerceptibleReciprocal(gamma);
1212 composite->red=ModulusSubtract(p->red,Sa,q->red,Da);
1213 composite->green=ModulusSubtract(p->green,Sa,q->green,Da);
1214 composite->blue=ModulusSubtract(p->blue,Sa,q->blue,Da);
1215 if (q->colorspace == CMYKColorspace)
1216 composite->index=ModulusSubtract(p->index,Sa,q->index,Da);
1219 if ( (channel & AlphaChannel) != 0 )
1220 composite->opacity=QuantumRange-ModulusSubtract(QuantumRange-p->opacity,
1221 1.0,QuantumRange-q->opacity,1.0);
1222 if ( (channel & RedChannel) != 0 )
1223 composite->red=ModulusSubtract(p->red,1.0,q->red,1.0);
1224 if ( (channel & GreenChannel) != 0 )
1225 composite->green=ModulusSubtract(p->green,1.0,q->green,1.0);
1226 if ( (channel & BlueChannel) != 0 )
1227 composite->blue=ModulusSubtract(p->blue,1.0,q->blue,1.0);
1228 if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
1229 composite->index=ModulusSubtract(p->index,1.0,q->index,1.0);
1233 static inline MagickRealType Multiply(
const MagickRealType Sca,
1234 const MagickRealType Sa,
const MagickRealType Dca,
const MagickRealType Da)
1236 return(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1248 Sa=1.0-QuantumScale*p->opacity;
1249 Da=1.0-QuantumScale*q->opacity;
1250 if ( (channel & SyncChannels) != 0 ) {
1251 gamma=RoundToUnity(Sa+Da-Sa*Da);
1252 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
1253 gamma=QuantumRange/(fabs((
double) gamma) < MagickEpsilon ? MagickEpsilon :
1255 composite->red=gamma*Multiply(QuantumScale*p->red*Sa,Sa,QuantumScale*
1257 composite->green=gamma*Multiply(QuantumScale*p->green*Sa,Sa,QuantumScale*
1259 composite->blue=gamma*Multiply(QuantumScale*p->blue*Sa,Sa,QuantumScale*
1261 if (q->colorspace == CMYKColorspace)
1262 composite->index=gamma*Multiply(QuantumScale*p->index*Sa,Sa,QuantumScale*
1266 if ( (channel & AlphaChannel) != 0 )
1267 composite->opacity=QuantumRange*(1.0-Sa*Da);
1268 if ( (channel & RedChannel) != 0 )
1269 composite->red=QuantumScale*p->red*q->red;
1270 if ( (channel & GreenChannel) != 0 )
1271 composite->green=QuantumScale*p->green*q->green;
1272 if ( (channel & BlueChannel) != 0 )
1273 composite->blue=QuantumScale*p->blue*q->blue;
1274 if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
1275 composite->index=QuantumScale*p->index*q->index;
1279 static inline MagickRealType Out(
const MagickRealType p,
1280 const MagickRealType Sa,
const MagickRealType magick_unused(q),
1281 const MagickRealType Da)
1283 magick_unreferenced(q);
1285 return(Sa*p*(1.0-Da));
1298 Sa=1.0-QuantumScale*p->opacity;
1299 Da=1.0-QuantumScale*q->opacity;
1301 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
1302 gamma=PerceptibleReciprocal(gamma);
1303 composite->red=gamma*Out(p->red,Sa,q->red,Da);
1304 composite->green=gamma*Out(p->green,Sa,q->green,Da);
1305 composite->blue=gamma*Out(p->blue,Sa,q->blue,Da);
1306 if (q->colorspace == CMYKColorspace)
1307 composite->index=gamma*Out(p->index,Sa,q->index,Da);
1310 static MagickRealType PegtopLight(
const MagickRealType Sca,
1311 const MagickRealType Sa,
const MagickRealType Dca,
const MagickRealType Da)
1321 if (fabs((
double) Da) < MagickEpsilon)
1323 return(Dca*Dca*(Sa-2.0*Sca)*PerceptibleReciprocal(Da)+Sca*(2.0*Dca+1.0-Da)+Dca*(1.0-Sa));
1334 Sa=1.0-QuantumScale*p->opacity;
1335 Da=1.0-QuantumScale*q->opacity;
1336 gamma=RoundToUnity(Sa+Da-Sa*Da);
1337 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
1338 gamma=QuantumRange/(fabs((
double) gamma) < MagickEpsilon ? MagickEpsilon :
1340 composite->red=gamma*PegtopLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
1342 composite->green=gamma*PegtopLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
1344 composite->blue=gamma*PegtopLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
1346 if (q->colorspace == CMYKColorspace)
1347 composite->index=gamma*PegtopLight(QuantumScale*p->index*Sa,Sa,QuantumScale*
1351 static MagickRealType PinLight(
const MagickRealType Sca,
1352 const MagickRealType Sa,
const MagickRealType Dca,
const MagickRealType Da)
1360 if (Dca*Sa < Da*(2*Sca-Sa))
1361 return(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
1362 if ((Dca*Sa) > (2*Sca*Da))
1363 return(Sca*Da+Sca+Dca*(1.0-Sa));
1364 return(Sca*(1.0-Da)+Dca);
1375 Sa=1.0-QuantumScale*p->opacity;
1376 Da=1.0-QuantumScale*q->opacity;
1377 gamma=RoundToUnity(Sa+Da-Sa*Da);
1378 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
1379 gamma=QuantumRange/(fabs((
double) gamma) < MagickEpsilon ? MagickEpsilon :
1381 composite->red=gamma*PinLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
1383 composite->green=gamma*PinLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
1385 composite->blue=gamma*PinLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
1387 if (q->colorspace == CMYKColorspace)
1388 composite->index=gamma*PinLight(QuantumScale*p->index*Sa,Sa,QuantumScale*
1392 static inline MagickRealType Screen(
const MagickRealType Sca,
1393 const MagickRealType Dca)
1398 return(Sca+Dca-Sca*Dca);
1412 Sa=1.0-QuantumScale*p->opacity;
1413 Da=1.0-QuantumScale*q->opacity;
1414 if ( (channel & SyncChannels) != 0 ) {
1415 gamma=RoundToUnity(Sa+Da-Sa*Da);
1416 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
1417 Sa*=(MagickRealType) QuantumScale;
1418 Da*=(MagickRealType) QuantumScale;
1419 gamma=QuantumRange/(fabs((
double) gamma) < MagickEpsilon ? MagickEpsilon :
1421 composite->red=gamma*Screen(p->red*Sa,q->red*Da);
1422 composite->green=gamma*Screen(p->green*Sa,q->green*Da);
1423 composite->blue=gamma*Screen(p->blue*Sa,q->blue*Da);
1424 if (q->colorspace == CMYKColorspace)
1425 composite->index=gamma*Screen(p->index*Sa,q->index*Da);
1428 if ( (channel & AlphaChannel) != 0 )
1429 composite->opacity=QuantumRange*(1.0-Screen(Sa,Da));
1430 if ( (channel & RedChannel) != 0 )
1431 composite->red=QuantumRange*Screen(QuantumScale*p->red,
1432 QuantumScale*q->red);
1433 if ( (channel & GreenChannel) != 0 )
1434 composite->green=QuantumRange*Screen(QuantumScale*p->green,
1435 QuantumScale*q->green);
1436 if ( (channel & BlueChannel) != 0 )
1437 composite->blue=QuantumRange*Screen(QuantumScale*p->blue,
1438 QuantumScale*q->blue);
1439 if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
1440 composite->index=QuantumRange*Screen(QuantumScale*p->index,
1441 QuantumScale*q->index);
1445 static MagickRealType SoftLight(
const MagickRealType Sca,
1446 const MagickRealType Sa,
const MagickRealType Dca,
const MagickRealType Da)
1452 alpha=Dca*PerceptibleReciprocal(Da);
1454 return(Dca*(Sa+(2.0*Sca-Sa)*(1.0-alpha))+Sca*(1.0-Da)+Dca*(1.0-Sa));
1455 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
1457 beta=Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*alpha*(4.0*alpha+1.0)*(alpha-1.0)+7.0*
1458 alpha)+Sca*(1.0-Da)+Dca*(1.0-Sa);
1461 beta=Dca*Sa+Da*(2.0*Sca-Sa)*(pow(alpha,0.5)-alpha)+Sca*(1.0-Da)+Dca*(1.0-Sa);
1473 Sa=1.0-QuantumScale*p->opacity;
1474 Da=1.0-QuantumScale*q->opacity;
1475 gamma=RoundToUnity(Sa+Da-Sa*Da);
1476 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
1477 gamma=QuantumRange/(fabs((
double) gamma) < MagickEpsilon ? MagickEpsilon :
1479 composite->red=gamma*SoftLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
1481 composite->green=gamma*SoftLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
1483 composite->blue=gamma*SoftLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
1485 if (q->colorspace == CMYKColorspace)
1486 composite->index=gamma*SoftLight(QuantumScale*p->index*Sa,Sa,QuantumScale*
1496 static inline MagickRealType Threshold(
const MagickRealType p,
1497 const MagickRealType q,
const MagickRealType threshold,
1498 const MagickRealType amount)
1504 if ((MagickRealType) fabs((
double) (2.0*delta)) < threshold)
1506 return(q+delta*amount);
1513 composite->red=Threshold(p->red,q->red,threshold,amount);
1514 composite->green=Threshold(p->green,q->green,threshold,amount);
1515 composite->blue=Threshold(p->blue,q->blue,threshold,amount);
1516 composite->opacity=QuantumRange-Threshold(p->opacity,q->opacity,
1518 if (q->colorspace == CMYKColorspace)
1519 composite->index=Threshold(p->index,q->index,threshold,amount);
1523 static MagickRealType VividLight(
const MagickRealType Sca,
1524 const MagickRealType Sa,
const MagickRealType Dca,
const MagickRealType Da)
1532 if ((fabs((
double) Sa) < MagickEpsilon) ||
1533 (fabs((
double) (Sca-Sa)) < MagickEpsilon))
1534 return(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1536 return(Sa*(Da+Sa*(Dca-Da)*PerceptibleReciprocal(2.0*Sca))+Sca*(1.0-Da)+
1538 return(Dca*Sa*Sa*PerceptibleReciprocal(2.0*(Sa-Sca))+Sca*(1.0-Da)+Dca*
1550 Sa=1.0-QuantumScale*p->opacity;
1551 Da=1.0-QuantumScale*q->opacity;
1552 gamma=RoundToUnity(Sa+Da-Sa*Da);
1553 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
1554 gamma=QuantumRange/(fabs((
double) gamma) < MagickEpsilon ? MagickEpsilon :
1556 composite->red=gamma*VividLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
1558 composite->green=gamma*VividLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
1560 composite->blue=gamma*VividLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
1562 if (q->colorspace == CMYKColorspace)
1563 composite->index=gamma*VividLight(QuantumScale*p->index*Sa,Sa,QuantumScale*
1567 static MagickRealType Xor(
const MagickRealType Sca,
const MagickRealType Sa,
1568 const MagickRealType Dca,
const MagickRealType Da)
1570 return(Sca*(1.0-Da)+Dca*(1.0-Sa));
1581 Sa=1.0-QuantumScale*p->opacity;
1582 Da=1.0-QuantumScale*q->opacity;
1583 gamma=Sa+Da-2*Sa*Da;
1584 composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
1585 gamma=PerceptibleReciprocal(gamma);
1586 composite->red=gamma*Xor(p->red*Sa,Sa,q->red*Da,Da);
1587 composite->green=gamma*Xor(p->green*Sa,Sa,q->green*Da,Da);
1588 composite->blue=gamma*Xor(p->blue*Sa,Sa,q->blue*Da,Da);
1589 if (q->colorspace == CMYKColorspace)
1590 composite->index=gamma*Xor(p->index*Sa,Sa,q->index*Da,Da);
1593 MagickExport MagickBooleanType CompositeImage(
Image *image,
1594 const CompositeOperator compose,
const Image *source_image,
1595 const ssize_t x_offset,
const ssize_t y_offset)
1600 status=CompositeImageChannel(image,DefaultChannels,compose,source_image,
1605 MagickExport MagickBooleanType CompositeImageChannel(
Image *image,
1606 const ChannelType channel,
const CompositeOperator compose,
1607 const Image *composite,
const ssize_t x_offset,
const ssize_t y_offset)
1609 #define CompositeImageTag "Composite/Image"
1657 assert(image != (
Image *) NULL);
1658 assert(image->signature == MagickCoreSignature);
1659 assert(composite != (
Image *) NULL);
1660 assert(composite->signature == MagickCoreSignature);
1661 if (IsEventLogging() != MagickFalse)
1662 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1663 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
1664 return(MagickFalse);
1665 exception=(&image->exception);
1666 source_image=CloneImage(composite,0,0,MagickTrue,exception);
1667 if (source_image == (
const Image *) NULL)
1668 return(MagickFalse);
1669 (void) SetImageColorspace(source_image,image->colorspace);
1670 GetMagickPixelPacket(image,&zero);
1671 canvas_image=(
Image *) NULL;
1673 canvas_dissolve=1.0;
1674 clip_to_self=MagickTrue;
1676 percent_chroma=100.0;
1677 source_dissolve=1.0;
1681 case ClearCompositeOp:
1682 case SrcCompositeOp:
1684 case SrcInCompositeOp:
1685 case OutCompositeOp:
1686 case SrcOutCompositeOp:
1687 case DstInCompositeOp:
1688 case DstAtopCompositeOp:
1693 clip_to_self=MagickFalse;
1696 case OverCompositeOp:
1698 if (image->matte != MagickFalse)
1700 if (source_image->matte != MagickFalse)
1704 case CopyCompositeOp:
1706 if ((x_offset < 0) || (y_offset < 0))
1708 if ((x_offset+(ssize_t) source_image->columns) >= (ssize_t) image->columns)
1710 if ((y_offset+(ssize_t) source_image->rows) >= (ssize_t) image->rows)
1713 source_view=AcquireVirtualCacheView(source_image,exception);
1714 image_view=AcquireAuthenticCacheView(image,exception);
1715 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1716 #pragma omp parallel for schedule(static) shared(status) \
1717 magick_number_threads(source_image,image,source_image->rows,1)
1719 for (y=0; y < (ssize_t) source_image->rows; y++)
1736 if (status == MagickFalse)
1738 p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,
1740 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
1741 source_image->columns,1,exception);
1747 source_indexes=GetCacheViewVirtualIndexQueue(source_view);
1748 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1749 (void) memcpy(q,p,source_image->columns*
sizeof(*p));
1750 if ((indexes != (IndexPacket *) NULL) &&
1751 (source_indexes != (
const IndexPacket *) NULL))
1752 (
void) memcpy(indexes,source_indexes,
1753 source_image->columns*
sizeof(*indexes));
1754 sync=SyncCacheViewAuthenticPixels(image_view,exception);
1755 if (sync == MagickFalse)
1757 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1762 proceed=SetImageProgress(image,CompositeImageTag,(MagickOffsetType)
1764 if (proceed == MagickFalse)
1768 source_view=DestroyCacheView(source_view);
1769 image_view=DestroyCacheView(image_view);
1770 source_image=DestroyImage(source_image);
1773 case CopyOpacityCompositeOp:
1774 case ChangeMaskCompositeOp:
1780 if (image->matte == MagickFalse)
1781 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
1782 clip_to_self=MagickFalse;
1785 case BlurCompositeOp:
1812 canvas_image=CloneImage(image,0,0,MagickTrue,exception);
1813 if (canvas_image == (
Image *) NULL)
1815 source_image=DestroyImage(source_image);
1816 return(MagickFalse);
1821 SetGeometryInfo(&geometry_info);
1823 value=GetImageArtifact(image,
"compose:args");
1824 if (value != (
char *) NULL)
1825 flags=ParseGeometry(value,&geometry_info);
1826 if ((flags & WidthValue) == 0)
1828 (void) ThrowMagickException(exception,GetMagickModule(),
1829 OptionWarning,
"InvalidGeometry",
"'%s' '%s'",
"compose:args",value);
1830 source_image=DestroyImage(source_image);
1831 canvas_image=DestroyImage(canvas_image);
1832 return(MagickFalse);
1839 width=height=geometry_info.rho*2.0;
1840 if ((flags & HeightValue) != 0 )
1841 height=geometry_info.sigma*2.0;
1849 if ((flags & XValue) != 0 )
1854 angle=DegreesToRadians(geometry_info.xi);
1855 blur.x1=width*cos(angle);
1856 blur.x2=width*sin(angle);
1857 blur.y1=(-height*sin(angle));
1858 blur.y2=height*cos(angle);
1863 if ((flags & YValue) != 0 )
1865 angle_start=DegreesToRadians(geometry_info.xi);
1866 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
1879 resample_filter=AcquireResampleFilter(image,exception);
1880 SetResampleFilter(resample_filter,GaussianFilter,1.0);
1884 source_view=AcquireVirtualCacheView(source_image,exception);
1885 canvas_view=AcquireAuthenticCacheView(canvas_image,exception);
1886 for (y=0; y < (ssize_t) source_image->rows; y++)
1898 *magick_restrict canvas_indexes;
1903 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1905 p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,
1907 r=QueueCacheViewAuthenticPixels(canvas_view,0,y,canvas_image->columns,
1911 canvas_indexes=GetCacheViewAuthenticIndexQueue(canvas_view);
1912 for (x=0; x < (ssize_t) source_image->columns; x++)
1914 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1919 if (fabs((
double) angle_range) > MagickEpsilon)
1924 angle=angle_start+angle_range*QuantumScale*GetPixelBlue(p);
1925 blur.x1=width*cos(angle);
1926 blur.x2=width*sin(angle);
1927 blur.y1=(-height*sin(angle));
1928 blur.y2=height*cos(angle);
1931 if ( x == 10 && y == 60 ) {
1932 fprintf(stderr,
"blur.x=%lf,%lf, blur.y=%lf,%lf\n",
1933 blur.x1, blur.x2, blur.y1, blur.y2);
1934 fprintf(stderr,
"scaled by=%lf,%lf\n",
1935 QuantumScale*GetPixelRed(p), QuantumScale*GetPixelGreen(p));
1938 ScaleResampleFilter(resample_filter,
1939 blur.x1*QuantumScale*GetPixelRed(p),
1940 blur.y1*QuantumScale*GetPixelGreen(p),
1941 blur.x2*QuantumScale*GetPixelRed(p),
1942 blur.y2*QuantumScale*GetPixelGreen(p));
1943 (void) ResamplePixelColor(resample_filter,(
double) x_offset+x,(double)
1945 SetPixelPacket(canvas_image,&pixel,r,canvas_indexes+x);
1949 sync=SyncCacheViewAuthenticPixels(canvas_view,exception);
1950 if (sync == MagickFalse)
1953 resample_filter=DestroyResampleFilter(resample_filter);
1954 source_view=DestroyCacheView(source_view);
1955 canvas_view=DestroyCacheView(canvas_view);
1956 source_image=DestroyImage(source_image);
1957 source_image=canvas_image;
1960 case DisplaceCompositeOp:
1961 case DistortCompositeOp:
1980 *magick_restrict canvas_indexes;
1990 canvas_image=CloneImage(image,0,0,MagickTrue,exception);
1991 if (canvas_image == (
Image *) NULL)
1993 source_image=DestroyImage(source_image);
1994 return(MagickFalse);
1996 SetGeometryInfo(&geometry_info);
1998 value=GetImageArtifact(image,
"compose:args");
1999 if (value != (
char *) NULL)
2000 flags=ParseGeometry(value,&geometry_info);
2001 if ((flags & (WidthValue | HeightValue)) == 0 )
2003 if ((flags & AspectValue) == 0)
2005 horizontal_scale=(MagickRealType) (source_image->columns-1)/2.0;
2006 vertical_scale=(MagickRealType) (source_image->rows-1)/2.0;
2010 horizontal_scale=(MagickRealType) (image->columns-1)/2.0;
2011 vertical_scale=(MagickRealType) (image->rows-1)/2.0;
2016 horizontal_scale=geometry_info.rho;
2017 vertical_scale=geometry_info.sigma;
2018 if ((flags & PercentValue) != 0)
2020 if ((flags & AspectValue) == 0)
2022 horizontal_scale*=(source_image->columns-1)/200.0;
2023 vertical_scale*=(source_image->rows-1)/200.0;
2027 horizontal_scale*=(image->columns-1)/200.0;
2028 vertical_scale*=(image->rows-1)/200.0;
2031 if ((flags & HeightValue) == 0)
2032 vertical_scale=horizontal_scale;
2042 center.x=(MagickRealType) x_offset;
2043 center.y=(MagickRealType) y_offset;
2044 if (compose == DistortCompositeOp)
2046 if ((flags & XValue) == 0)
2047 if ((flags & AspectValue) != 0)
2048 center.x=((MagickRealType) image->columns-1)/2.0;
2050 center.x=(MagickRealType) (x_offset+(source_image->columns-1)/
2053 if ((flags & AspectValue) == 0)
2054 center.x=(MagickRealType) (x_offset+geometry_info.xi);
2056 center.x=geometry_info.xi;
2057 if ((flags & YValue) == 0)
2058 if ((flags & AspectValue) != 0)
2059 center.y=((MagickRealType) image->rows-1)/2.0;
2061 center.y=(MagickRealType) (y_offset+(source_image->rows-1)/2.0);
2063 if ((flags & AspectValue) != 0)
2064 center.y=geometry_info.psi;
2066 center.y=(MagickRealType) (y_offset+geometry_info.psi);
2073 image_view=AcquireVirtualCacheView(image,exception);
2074 source_view=AcquireVirtualCacheView(source_image,exception);
2075 canvas_view=AcquireAuthenticCacheView(canvas_image,exception);
2076 for (y=0; y < (ssize_t) source_image->rows; y++)
2087 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
2089 p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,
2091 r=QueueCacheViewAuthenticPixels(canvas_view,0,y,canvas_image->columns,
2095 canvas_indexes=GetCacheViewAuthenticIndexQueue(canvas_view);
2096 for (x=0; x < (ssize_t) source_image->columns; x++)
2098 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
2106 offset.x=(double) ((horizontal_scale*(GetPixelRed(p)-
2107 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
2108 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
2110 offset.y=(double) ((vertical_scale*(GetPixelGreen(p)-
2111 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
2112 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
2114 status=InterpolateMagickPixelPacket(image,image_view,
2115 UndefinedInterpolatePixel,(
double) offset.x,(
double) offset.y,
2117 if (status == MagickFalse)
2122 pixel.opacity=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
2123 pixel.opacity)*(1.0-QuantumScale*GetPixelOpacity(p)));
2124 SetPixelPacket(canvas_image,&pixel,r,canvas_indexes+x);
2128 if (x < (ssize_t) source_image->columns)
2130 sync=SyncCacheViewAuthenticPixels(canvas_view,exception);
2131 if (sync == MagickFalse)
2134 canvas_view=DestroyCacheView(canvas_view);
2135 source_view=DestroyCacheView(source_view);
2136 image_view=DestroyCacheView(image_view);
2137 source_image=DestroyImage(source_image);
2138 source_image=canvas_image;
2141 case DissolveCompositeOp:
2146 value=GetImageArtifact(image,
"compose:args");
2147 if (value != (
char *) NULL)
2149 flags=ParseGeometry(value,&geometry_info);
2150 source_dissolve=geometry_info.rho/100.0;
2151 canvas_dissolve=1.0;
2152 if ((source_dissolve-MagickEpsilon) < 0.0)
2153 source_dissolve=0.0;
2154 if ((source_dissolve+MagickEpsilon) > 1.0)
2156 canvas_dissolve=2.0-source_dissolve;
2157 source_dissolve=1.0;
2159 if ((flags & SigmaValue) != 0)
2160 canvas_dissolve=geometry_info.sigma/100.0;
2161 if ((canvas_dissolve-MagickEpsilon) < 0.0)
2162 canvas_dissolve=0.0;
2163 clip_to_self=MagickFalse;
2164 if ((canvas_dissolve+MagickEpsilon) > 1.0 )
2166 canvas_dissolve=1.0;
2167 clip_to_self=MagickTrue;
2172 case BlendCompositeOp:
2174 value=GetImageArtifact(image,
"compose:args");
2175 if (value != (
char *) NULL)
2177 flags=ParseGeometry(value,&geometry_info);
2178 source_dissolve=geometry_info.rho/100.0;
2179 canvas_dissolve=1.0-source_dissolve;
2180 if ((flags & SigmaValue) != 0)
2181 canvas_dissolve=geometry_info.sigma/100.0;
2182 clip_to_self=MagickFalse;
2183 if ((canvas_dissolve+MagickEpsilon) > 1.0)
2184 clip_to_self=MagickTrue;
2188 case MathematicsCompositeOp:
2198 SetGeometryInfo(&geometry_info);
2199 value=GetImageArtifact(image,
"compose:args");
2200 if (value != (
char *) NULL)
2202 flags=ParseGeometry(value,&geometry_info);
2203 if (flags == NoValue)
2204 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2205 "InvalidGeometry",
"`%s'",value);
2209 case ModulateCompositeOp:
2214 value=GetImageArtifact(image,
"compose:args");
2215 if (value != (
char *) NULL)
2217 flags=ParseGeometry(value,&geometry_info);
2218 percent_luma=geometry_info.rho;
2219 if ((flags & SigmaValue) != 0)
2220 percent_chroma=geometry_info.sigma;
2224 case ThresholdCompositeOp:
2230 value=GetImageArtifact(image,
"compose:args");
2231 if (value != (
char *) NULL)
2233 flags=ParseGeometry(value,&geometry_info);
2234 amount=geometry_info.rho;
2235 threshold=geometry_info.sigma;
2236 if ((flags & SigmaValue) == 0)
2239 threshold*=QuantumRange;
2245 value=GetImageArtifact(image,
"compose:outside-overlay");
2246 if (value != (
const char *) NULL)
2247 clip_to_self=IsMagickTrue(value) == MagickFalse ? MagickTrue : MagickFalse;
2248 value=GetImageArtifact(image,
"compose:clip-to-self");
2249 if (value != (
const char *) NULL)
2250 clip_to_self=IsMagickTrue(value) != MagickFalse ? MagickTrue : MagickFalse;
2252 value=GetImageArtifact(image,
"compose:clamp");
2253 if (value != (
const char *) NULL)
2254 clamp=IsMagickTrue(value);
2258 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2259 status=AccelerateCompositeImage(image,channel,compose,source_image,
2260 x_offset,y_offset,canvas_dissolve,source_dissolve,exception);
2261 if (status != MagickFalse)
2266 midpoint=((MagickRealType) QuantumRange+1.0)/2;
2267 GetMagickPixelPacket(source_image,&zero);
2268 source_view=AcquireVirtualCacheView(source_image,exception);
2269 image_view=AcquireAuthenticCacheView(image,exception);
2270 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2271 #pragma omp parallel for schedule(static) shared(progress,status) \
2272 magick_number_threads(source_image,image,image->rows,1)
2274 for (y=0; y < (ssize_t) image->rows; y++)
2291 *magick_restrict source_indexes;
2297 *magick_restrict indexes;
2305 if (status == MagickFalse)
2307 if (clip_to_self != MagickFalse)
2311 if ((y-y_offset) >= (ssize_t) source_image->rows)
2319 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) source_image->rows))
2321 p=GetCacheViewVirtualPixels(source_view,0,y-y_offset,
2322 source_image->columns,1,exception);
2332 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2338 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2339 source_indexes=GetCacheViewVirtualIndexQueue(source_view);
2340 GetMagickPixelPacket(source_image,&source);
2341 GetMagickPixelPacket(image,&canvas);
2345 for (x=0; x < (ssize_t) image->columns; x++)
2347 if (clip_to_self != MagickFalse)
2354 if ((x-x_offset) >= (ssize_t) source_image->columns)
2357 canvas.red=(MagickRealType) GetPixelRed(q);
2358 canvas.green=(MagickRealType) GetPixelGreen(q);
2359 canvas.blue=(MagickRealType) GetPixelBlue(q);
2360 if (image->matte != MagickFalse)
2361 canvas.opacity=(MagickRealType) GetPixelOpacity(q);
2362 if (image->colorspace == CMYKColorspace)
2363 canvas.index=(MagickRealType) GetPixelIndex(indexes+x);
2364 if (image->colorspace == CMYKColorspace)
2366 canvas.red=(MagickRealType) QuantumRange-canvas.red;
2367 canvas.green=(MagickRealType) QuantumRange-canvas.green;
2368 canvas.blue=(MagickRealType) QuantumRange-canvas.blue;
2369 canvas.index=(MagickRealType) QuantumRange-canvas.index;
2375 if ((pixels == (
PixelPacket *) NULL) || (x < x_offset) ||
2376 ((x-x_offset) >= (ssize_t) source_image->columns))
2380 case DissolveCompositeOp:
2381 case BlendCompositeOp:
2383 composite.opacity=(MagickRealType) (QuantumRange-canvas_dissolve*
2384 (QuantumRange-composite.opacity));
2387 case ClearCompositeOp:
2388 case SrcCompositeOp:
2390 CompositeClear(&canvas,&composite);
2394 case SrcInCompositeOp:
2395 case OutCompositeOp:
2396 case SrcOutCompositeOp:
2397 case DstInCompositeOp:
2398 case DstAtopCompositeOp:
2399 case CopyOpacityCompositeOp:
2400 case ChangeMaskCompositeOp:
2402 composite.opacity=(MagickRealType) TransparentOpacity;
2407 (void) GetOneVirtualMagickPixel(source_image,x-x_offset,
2408 y-y_offset,&composite,exception);
2412 if (image->colorspace == CMYKColorspace)
2414 composite.red=(MagickRealType) QuantumRange-composite.red;
2415 composite.green=(MagickRealType) QuantumRange-composite.green;
2416 composite.blue=(MagickRealType) QuantumRange-composite.blue;
2417 composite.index=(MagickRealType) QuantumRange-composite.index;
2419 SetPixelRed(q,clamp != MagickFalse ?
2420 ClampPixel(composite.red) : ClampToQuantum(composite.red));
2421 SetPixelGreen(q,clamp != MagickFalse ?
2422 ClampPixel(composite.green) : ClampToQuantum(composite.green));
2423 SetPixelBlue(q,clamp != MagickFalse ?
2424 ClampPixel(composite.blue) : ClampToQuantum(composite.blue));
2425 if (image->matte != MagickFalse)
2426 SetPixelOpacity(q,clamp != MagickFalse ?
2427 ClampPixel(composite.opacity) :
2428 ClampToQuantum(composite.opacity));
2429 if (image->colorspace == CMYKColorspace)
2430 SetPixelIndex(indexes+x,clamp != MagickFalse ?
2431 ClampPixel(composite.index) : ClampToQuantum(composite.index));
2438 source.red=(MagickRealType) GetPixelRed(p);
2439 source.green=(MagickRealType) GetPixelGreen(p);
2440 source.blue=(MagickRealType) GetPixelBlue(p);
2441 if (source_image->matte != MagickFalse)
2442 source.opacity=(MagickRealType) GetPixelOpacity(p);
2443 if (source_image->colorspace == CMYKColorspace)
2444 source.index=(MagickRealType) GetPixelIndex(source_indexes+
2446 if (source_image->colorspace == CMYKColorspace)
2448 source.red=(MagickRealType) QuantumRange-source.red;
2449 source.green=(MagickRealType) QuantumRange-source.green;
2450 source.blue=(MagickRealType) QuantumRange-source.blue;
2451 source.index=(MagickRealType) QuantumRange-source.index;
2456 case ClearCompositeOp:
2458 CompositeClear(&canvas,&composite);
2461 case SrcCompositeOp:
2462 case CopyCompositeOp:
2463 case ReplaceCompositeOp:
2469 case DstCompositeOp:
2471 case OverCompositeOp:
2472 case SrcOverCompositeOp:
2474 MagickPixelCompositeOver(&source,source.opacity,&canvas,
2475 canvas.opacity,&composite);
2478 case DstOverCompositeOp:
2480 MagickPixelCompositeOver(&canvas,canvas.opacity,&source,
2481 source.opacity,&composite);
2484 case SrcInCompositeOp:
2487 CompositeIn(&source,&canvas,&composite);
2490 case DstInCompositeOp:
2492 CompositeIn(&canvas,&source,&composite);
2495 case OutCompositeOp:
2496 case SrcOutCompositeOp:
2498 CompositeOut(&source,&canvas,&composite);
2501 case DstOutCompositeOp:
2503 CompositeOut(&canvas,&source,&composite);
2506 case AtopCompositeOp:
2507 case SrcAtopCompositeOp:
2509 CompositeAtop(&source,&canvas,&composite);
2512 case DstAtopCompositeOp:
2514 CompositeAtop(&canvas,&source,&composite);
2517 case XorCompositeOp:
2519 CompositeXor(&source,&canvas,&composite);
2523 case PlusCompositeOp:
2525 CompositePlus(&source,&canvas,channel,&composite);
2528 case MinusDstCompositeOp:
2530 CompositeMinus(&source,&canvas,channel,&composite);
2533 case MinusSrcCompositeOp:
2535 CompositeMinus(&canvas,&source,channel,&composite);
2538 case ModulusAddCompositeOp:
2540 CompositeModulusAdd(&source,&canvas,channel,&composite);
2543 case ModulusSubtractCompositeOp:
2545 CompositeModulusSubtract(&source,&canvas,channel,&composite);
2548 case DifferenceCompositeOp:
2550 CompositeDifference(&source,&canvas,channel,&composite);
2553 case ExclusionCompositeOp:
2555 CompositeExclusion(&source,&canvas,channel,&composite);
2558 case MultiplyCompositeOp:
2560 CompositeMultiply(&source,&canvas,channel,&composite);
2563 case ScreenCompositeOp:
2565 CompositeScreen(&source,&canvas,channel,&composite);
2568 case DivideDstCompositeOp:
2570 CompositeDivide(&source,&canvas,channel,&composite);
2573 case DivideSrcCompositeOp:
2575 CompositeDivide(&canvas,&source,channel,&composite);
2578 case DarkenCompositeOp:
2580 CompositeDarken(&source,&canvas,channel,&composite);
2583 case LightenCompositeOp:
2585 CompositeLighten(&source,&canvas,channel,&composite);
2588 case DarkenIntensityCompositeOp:
2590 CompositeDarkenIntensity(&source,&canvas,channel,&composite);
2593 case LightenIntensityCompositeOp:
2595 CompositeLightenIntensity(&source,&canvas,channel,&composite);
2598 case MathematicsCompositeOp:
2600 CompositeMathematics(&source,&canvas,channel,&geometry_info,
2605 case ColorDodgeCompositeOp:
2607 CompositeColorDodge(&source,&canvas,&composite);
2610 case ColorBurnCompositeOp:
2612 CompositeColorBurn(&source,&canvas,&composite);
2615 case LinearDodgeCompositeOp:
2617 CompositeLinearDodge(&source,&canvas,&composite);
2620 case LinearBurnCompositeOp:
2622 CompositeLinearBurn(&source,&canvas,&composite);
2625 case HardLightCompositeOp:
2627 CompositeHardLight(&source,&canvas,&composite);
2630 case HardMixCompositeOp:
2632 CompositeHardMix(&source,&canvas,&composite);
2635 case OverlayCompositeOp:
2638 CompositeHardLight(&canvas,&source,&composite);
2641 case SoftLightCompositeOp:
2643 CompositeSoftLight(&source,&canvas,&composite);
2646 case LinearLightCompositeOp:
2648 CompositeLinearLight(&source,&canvas,&composite);
2651 case PegtopLightCompositeOp:
2653 CompositePegtopLight(&source,&canvas,&composite);
2656 case VividLightCompositeOp:
2658 CompositeVividLight(&source,&canvas,&composite);
2661 case PinLightCompositeOp:
2663 CompositePinLight(&source,&canvas,&composite);
2667 case ChangeMaskCompositeOp:
2669 if ((composite.opacity > ((MagickRealType) QuantumRange/2.0)) ||
2670 (IsMagickColorSimilar(&source,&canvas) != MagickFalse))
2671 composite.opacity=(MagickRealType) TransparentOpacity;
2673 composite.opacity=(MagickRealType) OpaqueOpacity;
2676 case BumpmapCompositeOp:
2678 if (source.opacity == TransparentOpacity)
2680 CompositeBumpmap(&source,&canvas,&composite);
2683 case DissolveCompositeOp:
2685 MagickPixelCompositeOver(&source,(MagickRealType) (QuantumRange-
2686 source_dissolve*(QuantumRange-source.opacity)),&canvas,
2687 (MagickRealType) (QuantumRange-canvas_dissolve*(QuantumRange-
2688 canvas.opacity)),&composite);
2691 case BlendCompositeOp:
2693 MagickPixelCompositeBlend(&source,source_dissolve,&canvas,
2694 canvas_dissolve,&composite);
2697 case StereoCompositeOp:
2699 composite.red=(MagickRealType) GetPixelRed(p);
2700 composite.opacity=(composite.opacity+canvas.opacity/2);
2703 case ThresholdCompositeOp:
2705 CompositeThreshold(&source,&canvas,threshold,amount,&composite);
2708 case ModulateCompositeOp:
2713 if (source.opacity == TransparentOpacity)
2715 offset=(ssize_t) (MagickPixelIntensityToQuantum(&source)-midpoint);
2718 CompositeHCL(canvas.red,canvas.green,canvas.blue,&hue,
2720 luma+=(0.01*percent_luma*offset)/midpoint;
2721 chroma*=0.01*percent_chroma;
2722 HCLComposite(hue,chroma,luma,&composite.red,&composite.green,
2726 case HueCompositeOp:
2728 if (source.opacity == TransparentOpacity)
2730 if (canvas.opacity == TransparentOpacity)
2735 CompositeHCL(canvas.red,canvas.green,canvas.blue,&hue,
2737 CompositeHCL(source.red,source.green,source.blue,&hue,&sans,&sans);
2738 HCLComposite(hue,chroma,luma,&composite.red,
2739 &composite.green,&composite.blue);
2740 if (source.opacity < canvas.opacity)
2741 composite.opacity=source.opacity;
2744 case SaturateCompositeOp:
2746 if (source.opacity == TransparentOpacity)
2748 if (canvas.opacity == TransparentOpacity)
2753 CompositeHCL(canvas.red,canvas.green,canvas.blue,&hue,
2755 CompositeHCL(source.red,source.green,source.blue,&sans,&chroma,
2757 HCLComposite(hue,chroma,luma,&composite.red,
2758 &composite.green,&composite.blue);
2759 if (source.opacity < canvas.opacity)
2760 composite.opacity=source.opacity;
2763 case LuminizeCompositeOp:
2765 if (source.opacity == TransparentOpacity)
2767 if (canvas.opacity == TransparentOpacity)
2772 CompositeHCL(canvas.red,canvas.green,canvas.blue,&hue,
2774 CompositeHCL(source.red,source.green,source.blue,&sans,&sans,
2776 HCLComposite(hue,chroma,luma,&composite.red,
2777 &composite.green,&composite.blue);
2778 if (source.opacity < canvas.opacity)
2779 composite.opacity=source.opacity;
2782 case ColorizeCompositeOp:
2784 if (source.opacity == TransparentOpacity)
2786 if (canvas.opacity == TransparentOpacity)
2791 CompositeHCL(canvas.red,canvas.green,canvas.blue,&sans,
2793 CompositeHCL(source.red,source.green,source.blue,&hue,&chroma,&sans);
2794 HCLComposite(hue,chroma,luma,&composite.red,
2795 &composite.green,&composite.blue);
2796 if (source.opacity < canvas.opacity)
2797 composite.opacity=source.opacity;
2800 case CopyRedCompositeOp:
2801 case CopyCyanCompositeOp:
2803 composite.red=source.red;
2806 case CopyGreenCompositeOp:
2807 case CopyMagentaCompositeOp:
2809 composite.green=source.green;
2812 case CopyBlueCompositeOp:
2813 case CopyYellowCompositeOp:
2815 composite.blue=source.blue;
2818 case CopyOpacityCompositeOp:
2820 if (source.matte == MagickFalse)
2821 composite.opacity=(MagickRealType) (QuantumRange-
2822 MagickPixelIntensityToQuantum(&source));
2824 composite.opacity=source.opacity;
2827 case CopyBlackCompositeOp:
2829 if (source.colorspace != CMYKColorspace)
2830 ConvertRGBToCMYK(&source);
2831 composite.index=source.index;
2835 case BlurCompositeOp:
2836 case DisplaceCompositeOp:
2837 case DistortCompositeOp:
2845 if (image->colorspace == CMYKColorspace)
2847 composite.red=(MagickRealType) QuantumRange-composite.red;
2848 composite.green=(MagickRealType) QuantumRange-composite.green;
2849 composite.blue=(MagickRealType) QuantumRange-composite.blue;
2850 composite.index=(MagickRealType) QuantumRange-composite.index;
2852 SetPixelRed(q,clamp != MagickFalse ?
2853 ClampPixel(composite.red) : ClampToQuantum(composite.red));
2854 SetPixelGreen(q,clamp != MagickFalse ?
2855 ClampPixel(composite.green) : ClampToQuantum(composite.green));
2856 SetPixelBlue(q,clamp != MagickFalse ?
2857 ClampPixel(composite.blue) : ClampToQuantum(composite.blue));
2858 SetPixelOpacity(q,clamp != MagickFalse ?
2859 ClampPixel(composite.opacity) : ClampToQuantum(composite.opacity));
2860 if (image->colorspace == CMYKColorspace)
2861 SetPixelIndex(indexes+x,clamp != MagickFalse ?
2862 ClampPixel(composite.index) : ClampToQuantum(composite.index));
2864 if (p >= (pixels+source_image->columns))
2868 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2870 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2875 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2879 proceed=SetImageProgress(image,CompositeImageTag,progress,image->rows);
2880 if (proceed == MagickFalse)
2884 source_view=DestroyCacheView(source_view);
2885 image_view=DestroyCacheView(image_view);
2886 if (canvas_image != (
Image * ) NULL)
2887 canvas_image=DestroyImage(canvas_image);
2889 source_image=DestroyImage(source_image);
2918 MagickExport MagickBooleanType TextureImage(
Image *image,
const Image *texture)
2920 #define TextureImageTag "Texture/Image"
2938 assert(image != (
Image *) NULL);
2939 assert(image->signature == MagickCoreSignature);
2940 if (IsEventLogging() != MagickFalse)
2941 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
2942 if (texture == (
const Image *) NULL)
2943 return(MagickFalse);
2944 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2945 return(MagickFalse);
2946 exception=(&image->exception);
2947 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2948 if (texture_image == (
const Image *) NULL)
2949 return(MagickFalse);
2950 (void) TransformImageColorspace(texture_image,image->colorspace);
2951 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod);
2953 if ((image->compose != CopyCompositeOp) &&
2954 ((image->compose != OverCompositeOp) || (image->matte != MagickFalse) ||
2955 (texture_image->matte != MagickFalse)))
2960 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2965 if (status == MagickFalse)
2967 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2972 thread_status=CompositeImage(image,image->compose,texture_image,x+
2973 texture_image->tile_offset.x,y+texture_image->tile_offset.y);
2974 if (thread_status == MagickFalse)
2976 status=thread_status;
2980 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2985 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2987 if (proceed == MagickFalse)
2991 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2992 image->rows,image->rows);
2993 texture_image=DestroyImage(texture_image);
3000 texture_view=AcquireVirtualCacheView(texture_image,exception);
3001 image_view=AcquireAuthenticCacheView(image,exception);
3002 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3003 #pragma omp parallel for schedule(static) shared(status) \
3004 magick_number_threads(image,texture_image,image->rows,1)
3006 for (y=0; y < (ssize_t) image->rows; y++)
3029 if (status == MagickFalse)
3031 p=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,(y+
3032 texture_image->tile_offset.y) % texture_image->rows,
3033 texture_image->columns,1,exception);
3034 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
3041 texture_indexes=GetCacheViewVirtualIndexQueue(texture_view);
3042 indexes=GetCacheViewAuthenticIndexQueue(image_view);
3043 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
3045 width=texture_image->columns;
3046 if ((x+(ssize_t) width) > (ssize_t) image->columns)
3047 width=image->columns-x;
3048 (void) memcpy(q,p,width*
sizeof(*p));
3049 if ((image->colorspace == CMYKColorspace) &&
3050 (texture_image->colorspace == CMYKColorspace))
3052 (void) memcpy(indexes,texture_indexes,width*
3058 sync=SyncCacheViewAuthenticPixels(image_view,exception);
3059 if (sync == MagickFalse)
3061 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3066 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
3068 if (proceed == MagickFalse)
3072 texture_view=DestroyCacheView(texture_view);
3073 image_view=DestroyCacheView(image_view);
3074 texture_image=DestroyImage(texture_image);