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)
1703 case CopyCompositeOp:
1705 if ((x_offset < 0) || (y_offset < 0))
1707 if ((x_offset+(ssize_t) source_image->columns) >= (ssize_t) image->columns)
1709 if ((y_offset+(ssize_t) source_image->rows) >= (ssize_t) image->rows)
1712 source_view=AcquireVirtualCacheView(source_image,exception);
1713 image_view=AcquireAuthenticCacheView(image,exception);
1714 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1715 #pragma omp parallel for schedule(static) shared(status) \
1716 magick_number_threads(source_image,image,source_image->rows,1)
1718 for (y=0; y < (ssize_t) source_image->rows; y++)
1735 if (status == MagickFalse)
1737 p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,
1739 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
1740 source_image->columns,1,exception);
1746 source_indexes=GetCacheViewVirtualIndexQueue(source_view);
1747 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1748 (void) memcpy(q,p,source_image->columns*
sizeof(*p));
1749 if ((indexes != (IndexPacket *) NULL) &&
1750 (source_indexes != (
const IndexPacket *) NULL))
1751 (
void) memcpy(indexes,source_indexes,
1752 source_image->columns*
sizeof(*indexes));
1753 sync=SyncCacheViewAuthenticPixels(image_view,exception);
1754 if (sync == MagickFalse)
1756 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1761 proceed=SetImageProgress(image,CompositeImageTag,(MagickOffsetType)
1763 if (proceed == MagickFalse)
1767 source_view=DestroyCacheView(source_view);
1768 image_view=DestroyCacheView(image_view);
1769 source_image=DestroyImage(source_image);
1772 case CopyOpacityCompositeOp:
1773 case ChangeMaskCompositeOp:
1779 if (image->matte == MagickFalse)
1780 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
1781 clip_to_self=MagickFalse;
1784 case BlurCompositeOp:
1811 canvas_image=CloneImage(image,0,0,MagickTrue,exception);
1812 if (canvas_image == (
Image *) NULL)
1814 source_image=DestroyImage(source_image);
1815 return(MagickFalse);
1820 SetGeometryInfo(&geometry_info);
1822 value=GetImageArtifact(image,
"compose:args");
1823 if (value != (
char *) NULL)
1824 flags=ParseGeometry(value,&geometry_info);
1825 if ((flags & WidthValue) == 0)
1827 (void) ThrowMagickException(exception,GetMagickModule(),
1828 OptionWarning,
"InvalidGeometry",
"'%s' '%s'",
"compose:args",value);
1829 source_image=DestroyImage(source_image);
1830 canvas_image=DestroyImage(canvas_image);
1831 return(MagickFalse);
1838 width=height=geometry_info.rho*2.0;
1839 if ((flags & HeightValue) != 0 )
1840 height=geometry_info.sigma*2.0;
1848 if ((flags & XValue) != 0 )
1853 angle=DegreesToRadians(geometry_info.xi);
1854 blur.x1=width*cos(angle);
1855 blur.x2=width*sin(angle);
1856 blur.y1=(-height*sin(angle));
1857 blur.y2=height*cos(angle);
1862 if ((flags & YValue) != 0 )
1864 angle_start=DegreesToRadians(geometry_info.xi);
1865 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
1878 resample_filter=AcquireResampleFilter(image,exception);
1879 SetResampleFilter(resample_filter,GaussianFilter,1.0);
1883 source_view=AcquireVirtualCacheView(source_image,exception);
1884 canvas_view=AcquireAuthenticCacheView(canvas_image,exception);
1885 for (y=0; y < (ssize_t) source_image->rows; y++)
1897 *magick_restrict canvas_indexes;
1902 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1904 p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,
1906 r=QueueCacheViewAuthenticPixels(canvas_view,0,y,canvas_image->columns,
1910 canvas_indexes=GetCacheViewAuthenticIndexQueue(canvas_view);
1911 for (x=0; x < (ssize_t) source_image->columns; x++)
1913 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1918 if (fabs((
double) angle_range) > MagickEpsilon)
1923 angle=angle_start+angle_range*QuantumScale*GetPixelBlue(p);
1924 blur.x1=width*cos(angle);
1925 blur.x2=width*sin(angle);
1926 blur.y1=(-height*sin(angle));
1927 blur.y2=height*cos(angle);
1930 if ( x == 10 && y == 60 ) {
1931 fprintf(stderr,
"blur.x=%lf,%lf, blur.y=%lf,%lf\n",
1932 blur.x1, blur.x2, blur.y1, blur.y2);
1933 fprintf(stderr,
"scaled by=%lf,%lf\n",
1934 QuantumScale*GetPixelRed(p), QuantumScale*GetPixelGreen(p));
1937 ScaleResampleFilter(resample_filter,
1938 blur.x1*QuantumScale*GetPixelRed(p),
1939 blur.y1*QuantumScale*GetPixelGreen(p),
1940 blur.x2*QuantumScale*GetPixelRed(p),
1941 blur.y2*QuantumScale*GetPixelGreen(p));
1942 (void) ResamplePixelColor(resample_filter,(
double) x_offset+x,(double)
1944 SetPixelPacket(canvas_image,&pixel,r,canvas_indexes+x);
1948 sync=SyncCacheViewAuthenticPixels(canvas_view,exception);
1949 if (sync == MagickFalse)
1952 resample_filter=DestroyResampleFilter(resample_filter);
1953 source_view=DestroyCacheView(source_view);
1954 canvas_view=DestroyCacheView(canvas_view);
1955 source_image=DestroyImage(source_image);
1956 source_image=canvas_image;
1959 case DisplaceCompositeOp:
1960 case DistortCompositeOp:
1979 *magick_restrict canvas_indexes;
1989 canvas_image=CloneImage(image,0,0,MagickTrue,exception);
1990 if (canvas_image == (
Image *) NULL)
1992 source_image=DestroyImage(source_image);
1993 return(MagickFalse);
1995 SetGeometryInfo(&geometry_info);
1997 value=GetImageArtifact(image,
"compose:args");
1998 if (value != (
char *) NULL)
1999 flags=ParseGeometry(value,&geometry_info);
2000 if ((flags & (WidthValue | HeightValue)) == 0 )
2002 if ((flags & AspectValue) == 0)
2004 horizontal_scale=(MagickRealType) (source_image->columns-1)/2.0;
2005 vertical_scale=(MagickRealType) (source_image->rows-1)/2.0;
2009 horizontal_scale=(MagickRealType) (image->columns-1)/2.0;
2010 vertical_scale=(MagickRealType) (image->rows-1)/2.0;
2015 horizontal_scale=geometry_info.rho;
2016 vertical_scale=geometry_info.sigma;
2017 if ((flags & PercentValue) != 0)
2019 if ((flags & AspectValue) == 0)
2021 horizontal_scale*=(source_image->columns-1)/200.0;
2022 vertical_scale*=(source_image->rows-1)/200.0;
2026 horizontal_scale*=(image->columns-1)/200.0;
2027 vertical_scale*=(image->rows-1)/200.0;
2030 if ((flags & HeightValue) == 0)
2031 vertical_scale=horizontal_scale;
2041 center.x=(MagickRealType) x_offset;
2042 center.y=(MagickRealType) y_offset;
2043 if (compose == DistortCompositeOp)
2045 if ((flags & XValue) == 0)
2046 if ((flags & AspectValue) != 0)
2047 center.x=((MagickRealType) image->columns-1)/2.0;
2049 center.x=(MagickRealType) (x_offset+(source_image->columns-1)/
2052 if ((flags & AspectValue) == 0)
2053 center.x=(MagickRealType) (x_offset+geometry_info.xi);
2055 center.x=geometry_info.xi;
2056 if ((flags & YValue) == 0)
2057 if ((flags & AspectValue) != 0)
2058 center.y=((MagickRealType) image->rows-1)/2.0;
2060 center.y=(MagickRealType) (y_offset+(source_image->rows-1)/2.0);
2062 if ((flags & AspectValue) != 0)
2063 center.y=geometry_info.psi;
2065 center.y=(MagickRealType) (y_offset+geometry_info.psi);
2072 image_view=AcquireVirtualCacheView(image,exception);
2073 source_view=AcquireVirtualCacheView(source_image,exception);
2074 canvas_view=AcquireAuthenticCacheView(canvas_image,exception);
2075 for (y=0; y < (ssize_t) source_image->rows; y++)
2086 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
2088 p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,
2090 r=QueueCacheViewAuthenticPixels(canvas_view,0,y,canvas_image->columns,
2094 canvas_indexes=GetCacheViewAuthenticIndexQueue(canvas_view);
2095 for (x=0; x < (ssize_t) source_image->columns; x++)
2097 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
2105 offset.x=(double) ((horizontal_scale*(GetPixelRed(p)-
2106 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
2107 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
2109 offset.y=(double) ((vertical_scale*(GetPixelGreen(p)-
2110 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
2111 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
2113 status=InterpolateMagickPixelPacket(image,image_view,
2114 UndefinedInterpolatePixel,(
double) offset.x,(
double) offset.y,
2116 if (status == MagickFalse)
2121 pixel.opacity=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
2122 pixel.opacity)*(1.0-QuantumScale*GetPixelOpacity(p)));
2123 SetPixelPacket(canvas_image,&pixel,r,canvas_indexes+x);
2127 if (x < (ssize_t) source_image->columns)
2129 sync=SyncCacheViewAuthenticPixels(canvas_view,exception);
2130 if (sync == MagickFalse)
2133 canvas_view=DestroyCacheView(canvas_view);
2134 source_view=DestroyCacheView(source_view);
2135 image_view=DestroyCacheView(image_view);
2136 source_image=DestroyImage(source_image);
2137 source_image=canvas_image;
2140 case DissolveCompositeOp:
2145 value=GetImageArtifact(image,
"compose:args");
2146 if (value != (
char *) NULL)
2148 flags=ParseGeometry(value,&geometry_info);
2149 source_dissolve=geometry_info.rho/100.0;
2150 canvas_dissolve=1.0;
2151 if ((source_dissolve-MagickEpsilon) < 0.0)
2152 source_dissolve=0.0;
2153 if ((source_dissolve+MagickEpsilon) > 1.0)
2155 canvas_dissolve=2.0-source_dissolve;
2156 source_dissolve=1.0;
2158 if ((flags & SigmaValue) != 0)
2159 canvas_dissolve=geometry_info.sigma/100.0;
2160 if ((canvas_dissolve-MagickEpsilon) < 0.0)
2161 canvas_dissolve=0.0;
2162 clip_to_self=MagickFalse;
2163 if ((canvas_dissolve+MagickEpsilon) > 1.0 )
2165 canvas_dissolve=1.0;
2166 clip_to_self=MagickTrue;
2171 case BlendCompositeOp:
2173 value=GetImageArtifact(image,
"compose:args");
2174 if (value != (
char *) NULL)
2176 flags=ParseGeometry(value,&geometry_info);
2177 source_dissolve=geometry_info.rho/100.0;
2178 canvas_dissolve=1.0-source_dissolve;
2179 if ((flags & SigmaValue) != 0)
2180 canvas_dissolve=geometry_info.sigma/100.0;
2181 clip_to_self=MagickFalse;
2182 if ((canvas_dissolve+MagickEpsilon) > 1.0)
2183 clip_to_self=MagickTrue;
2187 case MathematicsCompositeOp:
2197 SetGeometryInfo(&geometry_info);
2198 value=GetImageArtifact(image,
"compose:args");
2199 if (value != (
char *) NULL)
2201 flags=ParseGeometry(value,&geometry_info);
2202 if (flags == NoValue)
2203 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2204 "InvalidGeometry",
"`%s'",value);
2208 case ModulateCompositeOp:
2213 value=GetImageArtifact(image,
"compose:args");
2214 if (value != (
char *) NULL)
2216 flags=ParseGeometry(value,&geometry_info);
2217 percent_luma=geometry_info.rho;
2218 if ((flags & SigmaValue) != 0)
2219 percent_chroma=geometry_info.sigma;
2223 case ThresholdCompositeOp:
2229 value=GetImageArtifact(image,
"compose:args");
2230 if (value != (
char *) NULL)
2232 flags=ParseGeometry(value,&geometry_info);
2233 amount=geometry_info.rho;
2234 threshold=geometry_info.sigma;
2235 if ((flags & SigmaValue) == 0)
2238 threshold*=QuantumRange;
2244 value=GetImageArtifact(image,
"compose:outside-overlay");
2245 if (value != (
const char *) NULL)
2246 clip_to_self=IsMagickTrue(value) == MagickFalse ? MagickTrue : MagickFalse;
2247 value=GetImageArtifact(image,
"compose:clip-to-self");
2248 if (value != (
const char *) NULL)
2249 clip_to_self=IsMagickTrue(value) != MagickFalse ? MagickTrue : MagickFalse;
2251 value=GetImageArtifact(image,
"compose:clamp");
2252 if (value != (
const char *) NULL)
2253 clamp=IsMagickTrue(value);
2257 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2258 status=AccelerateCompositeImage(image,channel,compose,source_image,
2259 x_offset,y_offset,canvas_dissolve,source_dissolve,exception);
2260 if (status != MagickFalse)
2265 midpoint=((MagickRealType) QuantumRange+1.0)/2;
2266 GetMagickPixelPacket(source_image,&zero);
2267 source_view=AcquireVirtualCacheView(source_image,exception);
2268 image_view=AcquireAuthenticCacheView(image,exception);
2269 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2270 #pragma omp parallel for schedule(static) shared(progress,status) \
2271 magick_number_threads(source_image,image,image->rows,1)
2273 for (y=0; y < (ssize_t) image->rows; y++)
2290 *magick_restrict source_indexes;
2296 *magick_restrict indexes;
2304 if (status == MagickFalse)
2306 if (clip_to_self != MagickFalse)
2310 if ((y-y_offset) >= (ssize_t) source_image->rows)
2318 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) source_image->rows))
2320 p=GetCacheViewVirtualPixels(source_view,0,y-y_offset,
2321 source_image->columns,1,exception);
2331 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2337 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2338 source_indexes=GetCacheViewVirtualIndexQueue(source_view);
2339 GetMagickPixelPacket(source_image,&source);
2340 GetMagickPixelPacket(image,&canvas);
2344 for (x=0; x < (ssize_t) image->columns; x++)
2346 if (clip_to_self != MagickFalse)
2353 if ((x-x_offset) >= (ssize_t) source_image->columns)
2356 canvas.red=(MagickRealType) GetPixelRed(q);
2357 canvas.green=(MagickRealType) GetPixelGreen(q);
2358 canvas.blue=(MagickRealType) GetPixelBlue(q);
2359 if (image->matte != MagickFalse)
2360 canvas.opacity=(MagickRealType) GetPixelOpacity(q);
2361 if (image->colorspace == CMYKColorspace)
2362 canvas.index=(MagickRealType) GetPixelIndex(indexes+x);
2363 if (image->colorspace == CMYKColorspace)
2365 canvas.red=(MagickRealType) QuantumRange-canvas.red;
2366 canvas.green=(MagickRealType) QuantumRange-canvas.green;
2367 canvas.blue=(MagickRealType) QuantumRange-canvas.blue;
2368 canvas.index=(MagickRealType) QuantumRange-canvas.index;
2374 if ((pixels == (
PixelPacket *) NULL) || (x < x_offset) ||
2375 ((x-x_offset) >= (ssize_t) source_image->columns))
2379 case DissolveCompositeOp:
2380 case BlendCompositeOp:
2382 composite.opacity=(MagickRealType) (QuantumRange-canvas_dissolve*
2383 (QuantumRange-composite.opacity));
2386 case ClearCompositeOp:
2387 case SrcCompositeOp:
2389 CompositeClear(&canvas,&composite);
2393 case SrcInCompositeOp:
2394 case OutCompositeOp:
2395 case SrcOutCompositeOp:
2396 case DstInCompositeOp:
2397 case DstAtopCompositeOp:
2398 case CopyOpacityCompositeOp:
2399 case ChangeMaskCompositeOp:
2401 composite.opacity=(MagickRealType) TransparentOpacity;
2406 (void) GetOneVirtualMagickPixel(source_image,x-x_offset,
2407 y-y_offset,&composite,exception);
2411 if (image->colorspace == CMYKColorspace)
2413 composite.red=(MagickRealType) QuantumRange-composite.red;
2414 composite.green=(MagickRealType) QuantumRange-composite.green;
2415 composite.blue=(MagickRealType) QuantumRange-composite.blue;
2416 composite.index=(MagickRealType) QuantumRange-composite.index;
2418 SetPixelRed(q,clamp != MagickFalse ?
2419 ClampPixel(composite.red) : ClampToQuantum(composite.red));
2420 SetPixelGreen(q,clamp != MagickFalse ?
2421 ClampPixel(composite.green) : ClampToQuantum(composite.green));
2422 SetPixelBlue(q,clamp != MagickFalse ?
2423 ClampPixel(composite.blue) : ClampToQuantum(composite.blue));
2424 if (image->matte != MagickFalse)
2425 SetPixelOpacity(q,clamp != MagickFalse ?
2426 ClampPixel(composite.opacity) :
2427 ClampToQuantum(composite.opacity));
2428 if (image->colorspace == CMYKColorspace)
2429 SetPixelIndex(indexes+x,clamp != MagickFalse ?
2430 ClampPixel(composite.index) : ClampToQuantum(composite.index));
2437 source.red=(MagickRealType) GetPixelRed(p);
2438 source.green=(MagickRealType) GetPixelGreen(p);
2439 source.blue=(MagickRealType) GetPixelBlue(p);
2440 if (source_image->matte != MagickFalse)
2441 source.opacity=(MagickRealType) GetPixelOpacity(p);
2442 if (source_image->colorspace == CMYKColorspace)
2443 source.index=(MagickRealType) GetPixelIndex(source_indexes+
2445 if (source_image->colorspace == CMYKColorspace)
2447 source.red=(MagickRealType) QuantumRange-source.red;
2448 source.green=(MagickRealType) QuantumRange-source.green;
2449 source.blue=(MagickRealType) QuantumRange-source.blue;
2450 source.index=(MagickRealType) QuantumRange-source.index;
2455 case ClearCompositeOp:
2457 CompositeClear(&canvas,&composite);
2460 case SrcCompositeOp:
2461 case CopyCompositeOp:
2462 case ReplaceCompositeOp:
2468 case DstCompositeOp:
2470 case OverCompositeOp:
2471 case SrcOverCompositeOp:
2473 MagickPixelCompositeOver(&source,source.opacity,&canvas,
2474 canvas.opacity,&composite);
2477 case DstOverCompositeOp:
2479 MagickPixelCompositeOver(&canvas,canvas.opacity,&source,
2480 source.opacity,&composite);
2483 case SrcInCompositeOp:
2486 CompositeIn(&source,&canvas,&composite);
2489 case DstInCompositeOp:
2491 CompositeIn(&canvas,&source,&composite);
2494 case OutCompositeOp:
2495 case SrcOutCompositeOp:
2497 CompositeOut(&source,&canvas,&composite);
2500 case DstOutCompositeOp:
2502 CompositeOut(&canvas,&source,&composite);
2505 case AtopCompositeOp:
2506 case SrcAtopCompositeOp:
2508 CompositeAtop(&source,&canvas,&composite);
2511 case DstAtopCompositeOp:
2513 CompositeAtop(&canvas,&source,&composite);
2516 case XorCompositeOp:
2518 CompositeXor(&source,&canvas,&composite);
2522 case PlusCompositeOp:
2524 CompositePlus(&source,&canvas,channel,&composite);
2527 case MinusDstCompositeOp:
2529 CompositeMinus(&source,&canvas,channel,&composite);
2532 case MinusSrcCompositeOp:
2534 CompositeMinus(&canvas,&source,channel,&composite);
2537 case ModulusAddCompositeOp:
2539 CompositeModulusAdd(&source,&canvas,channel,&composite);
2542 case ModulusSubtractCompositeOp:
2544 CompositeModulusSubtract(&source,&canvas,channel,&composite);
2547 case DifferenceCompositeOp:
2549 CompositeDifference(&source,&canvas,channel,&composite);
2552 case ExclusionCompositeOp:
2554 CompositeExclusion(&source,&canvas,channel,&composite);
2557 case MultiplyCompositeOp:
2559 CompositeMultiply(&source,&canvas,channel,&composite);
2562 case ScreenCompositeOp:
2564 CompositeScreen(&source,&canvas,channel,&composite);
2567 case DivideDstCompositeOp:
2569 CompositeDivide(&source,&canvas,channel,&composite);
2572 case DivideSrcCompositeOp:
2574 CompositeDivide(&canvas,&source,channel,&composite);
2577 case DarkenCompositeOp:
2579 CompositeDarken(&source,&canvas,channel,&composite);
2582 case LightenCompositeOp:
2584 CompositeLighten(&source,&canvas,channel,&composite);
2587 case DarkenIntensityCompositeOp:
2589 CompositeDarkenIntensity(&source,&canvas,channel,&composite);
2592 case LightenIntensityCompositeOp:
2594 CompositeLightenIntensity(&source,&canvas,channel,&composite);
2597 case MathematicsCompositeOp:
2599 CompositeMathematics(&source,&canvas,channel,&geometry_info,
2604 case ColorDodgeCompositeOp:
2606 CompositeColorDodge(&source,&canvas,&composite);
2609 case ColorBurnCompositeOp:
2611 CompositeColorBurn(&source,&canvas,&composite);
2614 case LinearDodgeCompositeOp:
2616 CompositeLinearDodge(&source,&canvas,&composite);
2619 case LinearBurnCompositeOp:
2621 CompositeLinearBurn(&source,&canvas,&composite);
2624 case HardLightCompositeOp:
2626 CompositeHardLight(&source,&canvas,&composite);
2629 case HardMixCompositeOp:
2631 CompositeHardMix(&source,&canvas,&composite);
2634 case OverlayCompositeOp:
2637 CompositeHardLight(&canvas,&source,&composite);
2640 case SoftLightCompositeOp:
2642 CompositeSoftLight(&source,&canvas,&composite);
2645 case LinearLightCompositeOp:
2647 CompositeLinearLight(&source,&canvas,&composite);
2650 case PegtopLightCompositeOp:
2652 CompositePegtopLight(&source,&canvas,&composite);
2655 case VividLightCompositeOp:
2657 CompositeVividLight(&source,&canvas,&composite);
2660 case PinLightCompositeOp:
2662 CompositePinLight(&source,&canvas,&composite);
2666 case ChangeMaskCompositeOp:
2668 if ((composite.opacity > ((MagickRealType) QuantumRange/2.0)) ||
2669 (IsMagickColorSimilar(&source,&canvas) != MagickFalse))
2670 composite.opacity=(MagickRealType) TransparentOpacity;
2672 composite.opacity=(MagickRealType) OpaqueOpacity;
2675 case BumpmapCompositeOp:
2677 if (source.opacity == TransparentOpacity)
2679 CompositeBumpmap(&source,&canvas,&composite);
2682 case DissolveCompositeOp:
2684 MagickPixelCompositeOver(&source,(MagickRealType) (QuantumRange-
2685 source_dissolve*(QuantumRange-source.opacity)),&canvas,
2686 (MagickRealType) (QuantumRange-canvas_dissolve*(QuantumRange-
2687 canvas.opacity)),&composite);
2690 case BlendCompositeOp:
2692 MagickPixelCompositeBlend(&source,source_dissolve,&canvas,
2693 canvas_dissolve,&composite);
2696 case StereoCompositeOp:
2698 composite.red=(MagickRealType) GetPixelRed(p);
2699 composite.opacity=(composite.opacity+canvas.opacity/2);
2702 case ThresholdCompositeOp:
2704 CompositeThreshold(&source,&canvas,threshold,amount,&composite);
2707 case ModulateCompositeOp:
2712 if (source.opacity == TransparentOpacity)
2714 offset=(ssize_t) (MagickPixelIntensityToQuantum(&source)-midpoint);
2717 CompositeHCL(canvas.red,canvas.green,canvas.blue,&hue,
2719 luma+=(0.01*percent_luma*offset)/midpoint;
2720 chroma*=0.01*percent_chroma;
2721 HCLComposite(hue,chroma,luma,&composite.red,&composite.green,
2725 case HueCompositeOp:
2727 if (source.opacity == TransparentOpacity)
2729 if (canvas.opacity == TransparentOpacity)
2734 CompositeHCL(canvas.red,canvas.green,canvas.blue,&hue,
2736 CompositeHCL(source.red,source.green,source.blue,&hue,&sans,&sans);
2737 HCLComposite(hue,chroma,luma,&composite.red,
2738 &composite.green,&composite.blue);
2739 if (source.opacity < canvas.opacity)
2740 composite.opacity=source.opacity;
2743 case SaturateCompositeOp:
2745 if (source.opacity == TransparentOpacity)
2747 if (canvas.opacity == TransparentOpacity)
2752 CompositeHCL(canvas.red,canvas.green,canvas.blue,&hue,
2754 CompositeHCL(source.red,source.green,source.blue,&sans,&chroma,
2756 HCLComposite(hue,chroma,luma,&composite.red,
2757 &composite.green,&composite.blue);
2758 if (source.opacity < canvas.opacity)
2759 composite.opacity=source.opacity;
2762 case LuminizeCompositeOp:
2764 if (source.opacity == TransparentOpacity)
2766 if (canvas.opacity == TransparentOpacity)
2771 CompositeHCL(canvas.red,canvas.green,canvas.blue,&hue,
2773 CompositeHCL(source.red,source.green,source.blue,&sans,&sans,
2775 HCLComposite(hue,chroma,luma,&composite.red,
2776 &composite.green,&composite.blue);
2777 if (source.opacity < canvas.opacity)
2778 composite.opacity=source.opacity;
2781 case ColorizeCompositeOp:
2783 if (source.opacity == TransparentOpacity)
2785 if (canvas.opacity == TransparentOpacity)
2790 CompositeHCL(canvas.red,canvas.green,canvas.blue,&sans,
2792 CompositeHCL(source.red,source.green,source.blue,&hue,&chroma,&sans);
2793 HCLComposite(hue,chroma,luma,&composite.red,
2794 &composite.green,&composite.blue);
2795 if (source.opacity < canvas.opacity)
2796 composite.opacity=source.opacity;
2799 case CopyRedCompositeOp:
2800 case CopyCyanCompositeOp:
2802 composite.red=source.red;
2805 case CopyGreenCompositeOp:
2806 case CopyMagentaCompositeOp:
2808 composite.green=source.green;
2811 case CopyBlueCompositeOp:
2812 case CopyYellowCompositeOp:
2814 composite.blue=source.blue;
2817 case CopyOpacityCompositeOp:
2819 if (source.matte == MagickFalse)
2820 composite.opacity=(MagickRealType) (QuantumRange-
2821 MagickPixelIntensityToQuantum(&source));
2823 composite.opacity=source.opacity;
2826 case CopyBlackCompositeOp:
2828 if (source.colorspace != CMYKColorspace)
2829 ConvertRGBToCMYK(&source);
2830 composite.index=source.index;
2834 case BlurCompositeOp:
2835 case DisplaceCompositeOp:
2836 case DistortCompositeOp:
2844 if (image->colorspace == CMYKColorspace)
2846 composite.red=(MagickRealType) QuantumRange-composite.red;
2847 composite.green=(MagickRealType) QuantumRange-composite.green;
2848 composite.blue=(MagickRealType) QuantumRange-composite.blue;
2849 composite.index=(MagickRealType) QuantumRange-composite.index;
2851 SetPixelRed(q,clamp != MagickFalse ?
2852 ClampPixel(composite.red) : ClampToQuantum(composite.red));
2853 SetPixelGreen(q,clamp != MagickFalse ?
2854 ClampPixel(composite.green) : ClampToQuantum(composite.green));
2855 SetPixelBlue(q,clamp != MagickFalse ?
2856 ClampPixel(composite.blue) : ClampToQuantum(composite.blue));
2857 SetPixelOpacity(q,clamp != MagickFalse ?
2858 ClampPixel(composite.opacity) : ClampToQuantum(composite.opacity));
2859 if (image->colorspace == CMYKColorspace)
2860 SetPixelIndex(indexes+x,clamp != MagickFalse ?
2861 ClampPixel(composite.index) : ClampToQuantum(composite.index));
2863 if (p >= (pixels+source_image->columns))
2867 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2869 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2874 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2878 proceed=SetImageProgress(image,CompositeImageTag,progress,image->rows);
2879 if (proceed == MagickFalse)
2883 source_view=DestroyCacheView(source_view);
2884 image_view=DestroyCacheView(image_view);
2885 if (canvas_image != (
Image * ) NULL)
2886 canvas_image=DestroyImage(canvas_image);
2888 source_image=DestroyImage(source_image);
2917 MagickExport MagickBooleanType TextureImage(
Image *image,
const Image *texture)
2919 #define TextureImageTag "Texture/Image"
2937 assert(image != (
Image *) NULL);
2938 assert(image->signature == MagickCoreSignature);
2939 if (IsEventLogging() != MagickFalse)
2940 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
2941 if (texture == (
const Image *) NULL)
2942 return(MagickFalse);
2943 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2944 return(MagickFalse);
2945 exception=(&image->exception);
2946 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2947 if (texture_image == (
const Image *) NULL)
2948 return(MagickFalse);
2949 (void) TransformImageColorspace(texture_image,image->colorspace);
2950 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod);
2952 if ((image->compose != CopyCompositeOp) &&
2953 ((image->compose != OverCompositeOp) || (image->matte != MagickFalse) ||
2954 (texture_image->matte != MagickFalse)))
2959 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2964 if (status == MagickFalse)
2966 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2971 thread_status=CompositeImage(image,image->compose,texture_image,x+
2972 texture_image->tile_offset.x,y+texture_image->tile_offset.y);
2973 if (thread_status == MagickFalse)
2975 status=thread_status;
2979 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2984 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2986 if (proceed == MagickFalse)
2990 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2991 image->rows,image->rows);
2992 texture_image=DestroyImage(texture_image);
2999 texture_view=AcquireVirtualCacheView(texture_image,exception);
3000 image_view=AcquireAuthenticCacheView(image,exception);
3001 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3002 #pragma omp parallel for schedule(static) shared(status) \
3003 magick_number_threads(image,texture_image,image->rows,1)
3005 for (y=0; y < (ssize_t) image->rows; y++)
3028 if (status == MagickFalse)
3030 p=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,(y+
3031 texture_image->tile_offset.y) % texture_image->rows,
3032 texture_image->columns,1,exception);
3033 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
3040 texture_indexes=GetCacheViewVirtualIndexQueue(texture_view);
3041 indexes=GetCacheViewAuthenticIndexQueue(image_view);
3042 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
3044 width=texture_image->columns;
3045 if ((x+(ssize_t) width) > (ssize_t) image->columns)
3046 width=image->columns-x;
3047 (void) memcpy(q,p,width*
sizeof(*p));
3048 if ((image->colorspace == CMYKColorspace) &&
3049 (texture_image->colorspace == CMYKColorspace))
3051 (void) memcpy(indexes,texture_indexes,width*
3057 sync=SyncCacheViewAuthenticPixels(image_view,exception);
3058 if (sync == MagickFalse)
3060 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3065 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
3067 if (proceed == MagickFalse)
3071 texture_view=DestroyCacheView(texture_view);
3072 image_view=DestroyCacheView(image_view);
3073 texture_image=DestroyImage(texture_image);