43 #include "MagickCore/studio.h"
44 #include "MagickCore/artifact.h"
45 #include "MagickCore/cache.h"
46 #include "MagickCore/cache-private.h"
47 #include "MagickCore/cache-view.h"
48 #include "MagickCore/channel.h"
49 #include "MagickCore/client.h"
50 #include "MagickCore/color.h"
51 #include "MagickCore/color-private.h"
52 #include "MagickCore/colorspace.h"
53 #include "MagickCore/colorspace-private.h"
54 #include "MagickCore/composite.h"
55 #include "MagickCore/composite-private.h"
56 #include "MagickCore/constitute.h"
57 #include "MagickCore/draw.h"
58 #include "MagickCore/exception-private.h"
59 #include "MagickCore/fx.h"
60 #include "MagickCore/gem.h"
61 #include "MagickCore/geometry.h"
62 #include "MagickCore/image.h"
63 #include "MagickCore/image-private.h"
64 #include "MagickCore/list.h"
65 #include "MagickCore/log.h"
66 #include "MagickCore/memory_.h"
67 #include "MagickCore/monitor.h"
68 #include "MagickCore/monitor-private.h"
69 #include "MagickCore/morphology.h"
70 #include "MagickCore/option.h"
71 #include "MagickCore/pixel-accessor.h"
72 #include "MagickCore/property.h"
73 #include "MagickCore/quantum.h"
74 #include "MagickCore/resample.h"
75 #include "MagickCore/resource_.h"
76 #include "MagickCore/string_.h"
77 #include "MagickCore/thread-private.h"
78 #include "MagickCore/threshold.h"
79 #include "MagickCore/token.h"
80 #include "MagickCore/transform.h"
81 #include "MagickCore/utility.h"
82 #include "MagickCore/utility-private.h"
83 #include "MagickCore/version.h"
184 static Image *BlendConvolveImage(
const Image *image,
const char *kernel,
197 kernel_info=AcquireKernelInfo(kernel,exception);
199 return((
Image *) NULL);
200 clone_image=CloneImage(image,0,0,MagickTrue,exception);
201 if (clone_image == (
Image *) NULL)
203 kernel_info=DestroyKernelInfo(kernel_info);
204 return((
Image *) NULL);
206 (void) SetImageAlphaChannel(clone_image,OffAlphaChannel,exception);
207 convolve_image=ConvolveImage(clone_image,kernel_info,exception);
208 kernel_info=DestroyKernelInfo(kernel_info);
209 clone_image=DestroyImage(clone_image);
210 return(convolve_image);
213 static Image *BlendMagnitudeImage(
const Image *dx_image,
const Image *dy_image,
233 magnitude_image=CloneImage(dx_image,0,0,MagickTrue,exception);
234 if (magnitude_image == (
Image *) NULL)
235 return(magnitude_image);
236 dx_view=AcquireVirtualCacheView(dx_image,exception);
237 dy_view=AcquireVirtualCacheView(dy_image,exception);
238 magnitude_view=AcquireAuthenticCacheView(magnitude_image,exception);
239 #if defined(MAGICKCORE_OPENMP_SUPPORT)
240 #pragma omp parallel for schedule(static) shared(status) \
241 magick_number_threads(dx_image,magnitude_image,dx_image->rows,1)
243 for (y=0; y < (ssize_t) dx_image->rows; y++)
255 if (status == MagickFalse)
257 p=GetCacheViewVirtualPixels(dx_view,0,y,dx_image->columns,1,exception);
258 q=GetCacheViewVirtualPixels(dy_view,0,y,dx_image->columns,1,exception);
259 r=GetCacheViewAuthenticPixels(magnitude_view,0,y,dx_image->columns,1,
261 if ((p == (
const Quantum *) NULL) || (q == (
const Quantum *) NULL) ||
262 (r == (Quantum *) NULL))
267 for (x=0; x < (ssize_t) dx_image->columns; x++)
272 for (i=0; i < (ssize_t) GetPixelChannels(dx_image); i++)
274 PixelChannel channel = GetPixelChannelChannel(dx_image,i);
275 PixelTrait traits = GetPixelChannelTraits(dx_image,channel);
276 PixelTrait dy_traits = GetPixelChannelTraits(dy_image,channel);
277 if ((traits == UndefinedPixelTrait) ||
278 (dy_traits == UndefinedPixelTrait) ||
279 ((dy_traits & UpdatePixelTrait) == 0))
281 r[i]=ClampToQuantum(hypot((
double) p[i],(
double)
282 GetPixelChannel(dy_image,channel,q)));
284 p+=GetPixelChannels(dx_image);
285 q+=GetPixelChannels(dy_image);
286 r+=GetPixelChannels(magnitude_image);
288 if (SyncCacheViewAuthenticPixels(magnitude_view,exception) == MagickFalse)
291 magnitude_view=DestroyCacheView(magnitude_view);
292 dy_view=DestroyCacheView(dy_view);
293 dx_view=DestroyCacheView(dx_view);
294 if (status == MagickFalse)
295 magnitude_image=DestroyImage(magnitude_image);
296 return(magnitude_image);
299 static Image *BlendMaxMagnitudeImage(
const Image *alpha_image,
322 magnitude_image=CloneImage(alpha_image,0,0,MagickTrue,exception);
323 if (magnitude_image == (
Image *) NULL)
324 return(magnitude_image);
325 alpha_view=AcquireVirtualCacheView(alpha_image,exception);
326 beta_view=AcquireVirtualCacheView(beta_image,exception);
327 dx_view=AcquireVirtualCacheView(dx_image,exception);
328 dy_view=AcquireVirtualCacheView(dy_image,exception);
329 magnitude_view=AcquireAuthenticCacheView(magnitude_image,exception);
330 #if defined(MAGICKCORE_OPENMP_SUPPORT)
331 #pragma omp parallel for schedule(static) shared(status) \
332 magick_number_threads(alpha_image,magnitude_image,alpha_image->rows,1)
334 for (y=0; y < (ssize_t) alpha_image->rows; y++)
348 if (status == MagickFalse)
350 p=GetCacheViewVirtualPixels(alpha_view,0,y,alpha_image->columns,1,
352 q=GetCacheViewVirtualPixels(beta_view,0,y,alpha_image->columns,1,exception);
353 r=GetCacheViewVirtualPixels(dx_view,0,y,alpha_image->columns,1,exception);
354 s=GetCacheViewVirtualPixels(dy_view,0,y,alpha_image->columns,1,exception);
355 t=GetCacheViewAuthenticPixels(magnitude_view,0,y,alpha_image->columns,1,
357 if ((p == (
const Quantum *) NULL) || (q == (
const Quantum *) NULL) ||
358 (r == (
const Quantum *) NULL) || (s == (
const Quantum *) NULL) ||
359 (t == (Quantum *) NULL))
364 for (x=0; x < (ssize_t) alpha_image->columns; x++)
369 for (i=0; i < (ssize_t) GetPixelChannels(alpha_image); i++)
371 PixelChannel channel = GetPixelChannelChannel(alpha_image,i);
372 PixelTrait traits = GetPixelChannelTraits(alpha_image,channel);
373 PixelTrait beta_traits = GetPixelChannelTraits(beta_image,channel);
374 if ((traits == UndefinedPixelTrait) ||
375 (beta_traits == UndefinedPixelTrait) ||
376 ((beta_traits & UpdatePixelTrait) == 0))
378 if (p[i] > GetPixelChannel(beta_image,channel,q))
379 t[i]=GetPixelChannel(dx_image,channel,r);
381 t[i]=GetPixelChannel(dy_image,channel,s);
383 p+=GetPixelChannels(alpha_image);
384 q+=GetPixelChannels(beta_image);
385 r+=GetPixelChannels(dx_image);
386 s+=GetPixelChannels(dy_image);
387 t+=GetPixelChannels(magnitude_image);
389 if (SyncCacheViewAuthenticPixels(magnitude_view,exception) == MagickFalse)
392 magnitude_view=DestroyCacheView(magnitude_view);
393 dy_view=DestroyCacheView(dy_view);
394 dx_view=DestroyCacheView(dx_view);
395 beta_view=DestroyCacheView(beta_view);
396 alpha_view=DestroyCacheView(alpha_view);
397 if (status == MagickFalse)
398 magnitude_image=DestroyImage(magnitude_image);
399 return(magnitude_image);
402 static Image *BlendSumImage(
const Image *alpha_image,
const Image *beta_image,
403 const double attenuate,
const double sign,
ExceptionInfo *exception)
422 sum_image=CloneImage(alpha_image,0,0,MagickTrue,exception);
423 if (sum_image == (
Image *) NULL)
425 alpha_view=AcquireVirtualCacheView(alpha_image,exception);
426 beta_view=AcquireVirtualCacheView(beta_image,exception);
427 sum_view=AcquireAuthenticCacheView(sum_image,exception);
428 #if defined(MAGICKCORE_OPENMP_SUPPORT)
429 #pragma omp parallel for schedule(static) shared(status) \
430 magick_number_threads(alpha_image,sum_image,alpha_image->rows,1)
432 for (y=0; y < (ssize_t) alpha_image->rows; y++)
444 if (status == MagickFalse)
446 p=GetCacheViewVirtualPixels(alpha_view,0,y,alpha_image->columns,1,
448 q=GetCacheViewVirtualPixels(beta_view,0,y,alpha_image->columns,1,exception);
449 r=GetCacheViewAuthenticPixels(sum_view,0,y,alpha_image->columns,1,
451 if ((p == (
const Quantum *) NULL) || (q == (
const Quantum *) NULL) ||
452 (r == (Quantum *) NULL))
457 for (x=0; x < (ssize_t) alpha_image->columns; x++)
462 for (i=0; i < (ssize_t) GetPixelChannels(alpha_image); i++)
464 PixelChannel channel = GetPixelChannelChannel(alpha_image,i);
465 PixelTrait traits = GetPixelChannelTraits(alpha_image,channel);
466 PixelTrait beta_traits = GetPixelChannelTraits(beta_image,channel);
467 if ((traits == UndefinedPixelTrait) ||
468 (beta_traits == UndefinedPixelTrait) ||
469 ((beta_traits & UpdatePixelTrait) == 0))
471 r[i]=ClampToQuantum(attenuate*(p[i]+sign*
472 GetPixelChannel(beta_image,channel,q)));
474 p+=GetPixelChannels(alpha_image);
475 q+=GetPixelChannels(beta_image);
476 r+=GetPixelChannels(sum_image);
478 if (SyncCacheViewAuthenticPixels(sum_view,exception) == MagickFalse)
481 sum_view=DestroyCacheView(sum_view);
482 beta_view=DestroyCacheView(beta_view);
483 alpha_view=DestroyCacheView(alpha_view);
484 if (status == MagickFalse)
485 sum_image=DestroyImage(sum_image);
489 static Image *BlendDivergentImage(
const Image *alpha_image,
492 #define FreeDivergentResources() \
494 if (dy_image != (Image *) NULL) \
495 dy_image=DestroyImage(dy_image); \
496 if (dx_image != (Image *) NULL) \
497 dx_image=DestroyImage(dx_image); \
498 if (magnitude_beta != (Image *) NULL) \
499 magnitude_beta=DestroyImage(magnitude_beta); \
500 if (dy_beta != (Image *) NULL) \
501 dy_beta=DestroyImage(dy_beta); \
502 if (dx_beta != (Image *) NULL) \
503 dx_beta=DestroyImage(dx_beta); \
504 if (magnitude_alpha != (Image *) NULL) \
505 magnitude_alpha=DestroyImage(magnitude_alpha); \
506 if (dy_alpha != (Image *) NULL) \
507 dy_alpha=DestroyImage(dy_alpha); \
508 if (dx_alpha != (Image *) NULL) \
509 dx_alpha=DestroyImage(dx_alpha); \
513 *divergent_image = (
Image *) NULL,
514 *dx_alpha = (
Image *) NULL,
515 *dx_beta = (
Image *) NULL,
516 *dx_divergent = (
Image *) NULL,
517 *dx_image = (
Image *) NULL,
518 *dy_alpha = (
Image *) NULL,
519 *dy_beta = (
Image *) NULL,
520 *dy_divergent = (
Image *) NULL,
521 *dy_image = (
Image *) NULL,
522 *magnitude_alpha = (
Image *) NULL,
523 *magnitude_beta = (
Image *) NULL;
528 dx_alpha=BlendConvolveImage(alpha_image,
"3x1:-0.5,0.0,0.5",exception);
529 if (dx_alpha == (
Image *) NULL)
531 FreeDivergentResources();
532 return((
Image *) NULL);
534 dy_alpha=BlendConvolveImage(alpha_image,
"1x3:-0.5,0.0,0.5",exception);
535 if (dy_alpha == (
Image *) NULL)
537 FreeDivergentResources();
538 return((
Image *) NULL);
540 magnitude_alpha=BlendMagnitudeImage(dx_alpha,dy_alpha,exception);
541 if (magnitude_alpha == (
Image *) NULL)
543 FreeDivergentResources();
544 return((
Image *) NULL);
549 dx_beta=BlendConvolveImage(beta_image,
"3x1:-0.5,0.0,0.5",exception);
550 if (dx_beta == (
Image *) NULL)
552 FreeDivergentResources();
553 return((
Image *) NULL);
555 dy_beta=BlendConvolveImage(beta_image,
"1x3:-0.5,0.0,0.5",exception);
556 if (dy_beta == (
Image *) NULL)
558 FreeDivergentResources();
559 return((
Image *) NULL);
561 magnitude_beta=BlendMagnitudeImage(dx_beta,dy_beta,exception);
562 if (magnitude_beta == (
Image *) NULL)
564 FreeDivergentResources();
565 return((
Image *) NULL);
570 dx_image=BlendMaxMagnitudeImage(magnitude_alpha,magnitude_beta,dx_alpha,
572 if (dx_image == (
Image *) NULL)
574 FreeDivergentResources();
575 return((
Image *) NULL);
577 dy_image=BlendMaxMagnitudeImage(magnitude_alpha,magnitude_beta,dy_alpha,
579 if (dy_image == (
Image *) NULL)
581 FreeDivergentResources();
582 return((
Image *) NULL);
584 dx_beta=DestroyImage(dx_beta);
585 dx_alpha=DestroyImage(dx_alpha);
586 magnitude_beta=DestroyImage(magnitude_beta);
587 magnitude_alpha=DestroyImage(magnitude_alpha);
591 dx_divergent=BlendConvolveImage(dx_image,
"3x1:-0.5,0.0,0.5",exception);
592 if (dx_divergent == (
Image *) NULL)
594 FreeDivergentResources();
595 return((
Image *) NULL);
597 dy_divergent=BlendConvolveImage(dy_image,
"1x3:-0.5,0.0,0.5",exception);
598 if (dy_divergent == (
Image *) NULL)
600 FreeDivergentResources();
601 return((
Image *) NULL);
603 divergent_image=BlendSumImage(dx_divergent,dy_divergent,0.25,1.0,exception);
604 dy_divergent=DestroyImage(dy_divergent);
605 dx_divergent=DestroyImage(dx_divergent);
606 if (divergent_image == (
Image *) NULL)
608 FreeDivergentResources();
609 return((
Image *) NULL);
611 FreeDivergentResources();
612 return(divergent_image);
615 static MagickBooleanType BlendMaskAlphaChannel(
Image *image,
631 if (SetImageAlpha(image,OpaqueAlpha,exception) == MagickFalse)
633 image_view=AcquireAuthenticCacheView(image,exception);
634 mask_view=AcquireVirtualCacheView(mask_image,exception);
635 #if defined(MAGICKCORE_OPENMP_SUPPORT)
636 #pragma omp parallel for schedule(static) shared(status) \
637 magick_number_threads(image,image,image->rows,1)
639 for (y=0; y < (ssize_t) image->rows; y++)
650 if (status == MagickFalse)
652 p=GetCacheViewVirtualPixels(mask_view,0,y,image->columns,1,exception);
653 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
654 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
659 for (x=0; x < (ssize_t) image->columns; x++)
662 alpha = GetPixelAlpha(mask_image,p);
665 i = GetPixelChannelOffset(image,AlphaPixelChannel);
667 if (fabs((
double) alpha) >= MagickEpsilon)
669 p+=GetPixelChannels(mask_image);
670 q+=GetPixelChannels(image);
672 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
675 mask_view=DestroyCacheView(mask_view);
676 image_view=DestroyCacheView(image_view);
689 mean[MaxPixelChannels];
704 (void) memset(mean,0,MaxPixelChannels*
sizeof(*mean));
705 alpha_view=AcquireVirtualCacheView(image,exception);
706 for (y=0; y < (ssize_t) image->rows; y++)
714 p=GetCacheViewVirtualPixels(alpha_view,0,y,image->columns,1,
716 if (p == (
const Quantum *) NULL)
718 for (x=0; x < (ssize_t) image->columns; x++)
723 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
725 PixelChannel channel = GetPixelChannelChannel(image,i);
726 PixelTrait traits = GetPixelChannelTraits(image,channel);
727 if (traits == UndefinedPixelTrait)
729 mean[i]+=QuantumScale*p[i];
731 p+=GetPixelChannels(image);
734 alpha_view=DestroyCacheView(alpha_view);
735 if (y < (ssize_t) image->rows)
736 return((
Image *) NULL);
737 for (j=0; j < (ssize_t) GetPixelChannels(image); j++)
738 mean[j]=(
double) QuantumRange*mean[j]/image->columns/
743 mean_image=CloneImage(image,0,0,MagickTrue,exception);
744 if (mean_image == (
Image *) NULL)
746 mask_view=AcquireVirtualCacheView(mask_image,exception);
747 mean_view=AcquireAuthenticCacheView(mean_image,exception);
748 #if defined(MAGICKCORE_OPENMP_SUPPORT)
749 #pragma omp parallel for schedule(static) shared(status) \
750 magick_number_threads(mask_image,mean_image,mean_image->rows,1)
752 for (y=0; y < (ssize_t) mean_image->rows; y++)
763 if (status == MagickFalse)
765 p=GetCacheViewVirtualPixels(mask_view,0,y,mean_image->columns,1,exception);
766 q=GetCacheViewAuthenticPixels(mean_view,0,y,mean_image->columns,1,
768 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
773 for (x=0; x < (ssize_t) mean_image->columns; x++)
776 alpha = GetPixelAlpha(mask_image,p),
777 mask = GetPixelReadMask(mask_image,p);
782 for (i=0; i < (ssize_t) GetPixelChannels(mean_image); i++)
784 PixelChannel channel = GetPixelChannelChannel(mean_image,i);
785 PixelTrait traits = GetPixelChannelTraits(mean_image,channel);
786 if (traits == UndefinedPixelTrait)
788 if (mask <= (QuantumRange/2))
791 if (fabs((
double) alpha) >= MagickEpsilon)
792 q[i]=ClampToQuantum(mean[i]);
794 p+=GetPixelChannels(mask_image);
795 q+=GetPixelChannels(mean_image);
797 if (SyncCacheViewAuthenticPixels(mean_view,exception) == MagickFalse)
800 mask_view=DestroyCacheView(mask_view);
801 mean_view=DestroyCacheView(mean_view);
802 if (status == MagickFalse)
803 mean_image=DestroyImage(mean_image);
807 static MagickBooleanType BlendRMSEResidual(
const Image *alpha_image,
821 columns = MagickMax(alpha_image->columns,beta_image->columns),
822 rows = MagickMax(alpha_image->rows,beta_image->rows);
828 alpha_view=AcquireVirtualCacheView(alpha_image,exception);
829 beta_view=AcquireVirtualCacheView(beta_image,exception);
830 #if defined(MAGICKCORE_OPENMP_SUPPORT)
831 #pragma omp parallel for schedule(static) shared(status) \
832 magick_number_threads(alpha_image,alpha_image,rows,1)
834 for (y=0; y < (ssize_t) rows; y++)
849 if (status == MagickFalse)
851 p=GetCacheViewVirtualPixels(alpha_view,0,y,columns,1,exception);
852 q=GetCacheViewVirtualPixels(beta_view,0,y,columns,1,exception);
853 if ((p == (
const Quantum *) NULL) || (q == (
const Quantum *) NULL))
858 channel_residual=0.0;
859 for (x=0; x < (ssize_t) columns; x++)
868 if ((GetPixelReadMask(alpha_image,p) <= (QuantumRange/2)) ||
869 (GetPixelReadMask(beta_image,q) <= (QuantumRange/2)))
871 p+=GetPixelChannels(alpha_image);
872 q+=GetPixelChannels(beta_image);
875 Sa=QuantumScale*GetPixelAlpha(alpha_image,p);
876 Da=QuantumScale*GetPixelAlpha(beta_image,q);
877 for (i=0; i < (ssize_t) GetPixelChannels(alpha_image); i++)
882 PixelChannel channel = GetPixelChannelChannel(alpha_image,i);
883 PixelTrait traits = GetPixelChannelTraits(alpha_image,channel);
884 PixelTrait beta_traits = GetPixelChannelTraits(beta_image,channel);
885 if ((traits == UndefinedPixelTrait) ||
886 (beta_traits == UndefinedPixelTrait) ||
887 ((beta_traits & UpdatePixelTrait) == 0))
889 if (channel == AlphaPixelChannel)
890 distance=QuantumScale*(p[i]-GetPixelChannel(beta_image,channel,q));
892 distance=QuantumScale*(Sa*p[i]-Da*GetPixelChannel(beta_image,channel,
894 channel_residual+=distance*distance;
897 p+=GetPixelChannels(alpha_image);
898 q+=GetPixelChannels(beta_image);
900 #if defined(MAGICKCORE_OPENMP_SUPPORT)
901 #pragma omp critical (MagickCore_BlendRMSEResidual)
905 *residual+=channel_residual;
908 area=PerceptibleReciprocal(area);
909 beta_view=DestroyCacheView(beta_view);
910 alpha_view=DestroyCacheView(alpha_view);
911 *residual=sqrt(*residual*area/(
double) GetImageChannels(alpha_image));
915 static void CompositeHCL(
const MagickRealType red,
const MagickRealType green,
916 const MagickRealType blue,MagickRealType *hue,MagickRealType *chroma,
917 MagickRealType *luma)
930 assert(hue != (MagickRealType *) NULL);
931 assert(chroma != (MagickRealType *) NULL);
932 assert(luma != (MagickRealType *) NULL);
936 max=MagickMax(r,MagickMax(g,b));
937 c=max-(MagickRealType) MagickMin(r,MagickMin(g,b));
943 h=fmod((g-b)/c+6.0,6.0);
951 *chroma=QuantumScale*c;
952 *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
955 static MagickBooleanType CompositeOverImage(
Image *image,
956 const Image *source_image,
const MagickBooleanType clip_to_self,
957 const ssize_t x_offset,
const ssize_t y_offset,
ExceptionInfo *exception)
959 #define CompositeImageTag "Composite/Image"
984 value=GetImageArtifact(image,
"compose:clamp");
985 if (value != (
const char *) NULL)
986 clamp=IsStringTrue(value);
989 source_view=AcquireVirtualCacheView(source_image,exception);
990 image_view=AcquireAuthenticCacheView(image,exception);
991 #if defined(MAGICKCORE_OPENMP_SUPPORT)
992 #pragma omp parallel for schedule(static) shared(progress,status) \
993 magick_number_threads(source_image,image,image->rows,1)
995 for (y=0; y < (ssize_t) image->rows; y++)
1013 if (status == MagickFalse)
1015 if (clip_to_self != MagickFalse)
1019 if ((y-y_offset) >= (ssize_t) source_image->rows)
1025 pixels=(Quantum *) NULL;
1027 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) source_image->rows))
1029 p=GetCacheViewVirtualPixels(source_view,0,y-y_offset,
1030 source_image->columns,1,exception);
1031 if (p == (
const Quantum *) NULL)
1038 p-=x_offset*(ssize_t) GetPixelChannels(source_image);
1040 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1041 if (q == (Quantum *) NULL)
1046 GetPixelInfo(image,&canvas_pixel);
1047 GetPixelInfo(source_image,&source_pixel);
1048 for (x=0; x < (ssize_t) image->columns; x++)
1068 if (clip_to_self != MagickFalse)
1072 q+=GetPixelChannels(image);
1075 if ((x-x_offset) >= (ssize_t) source_image->columns)
1078 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1079 ((x-x_offset) >= (ssize_t) source_image->columns))
1082 source[MaxPixelChannels];
1089 (void) GetOneVirtualPixel(source_image,x-x_offset,y-y_offset,source,
1091 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1096 PixelChannel channel = GetPixelChannelChannel(image,i);
1097 PixelTrait traits = GetPixelChannelTraits(image,channel);
1098 PixelTrait source_traits=GetPixelChannelTraits(source_image,
1100 if ((traits == UndefinedPixelTrait) ||
1101 (source_traits == UndefinedPixelTrait))
1103 if (channel == AlphaPixelChannel)
1104 pixel=(MagickRealType) TransparentAlpha;
1106 pixel=(MagickRealType) q[i];
1107 q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
1108 ClampToQuantum(pixel);
1110 q+=GetPixelChannels(image);
1118 Sa=QuantumScale*GetPixelAlpha(source_image,p);
1119 Da=QuantumScale*GetPixelAlpha(image,q);
1121 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1126 PixelChannel channel = GetPixelChannelChannel(image,i);
1127 PixelTrait traits = GetPixelChannelTraits(image,channel);
1128 PixelTrait source_traits=GetPixelChannelTraits(source_image,channel);
1129 if (traits == UndefinedPixelTrait)
1131 if ((source_traits == UndefinedPixelTrait) &&
1132 (channel != AlphaPixelChannel))
1134 if (channel == AlphaPixelChannel)
1139 pixel=QuantumRange*alpha;
1140 q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
1141 ClampToQuantum(pixel);
1148 Sc=(MagickRealType) GetPixelChannel(source_image,channel,p);
1149 Dc=(MagickRealType) q[i];
1150 if ((traits & CopyPixelTrait) != 0)
1155 q[i]=ClampToQuantum(Sc);
1163 Sca=QuantumScale*Sa*Sc;
1164 Dca=QuantumScale*Da*Dc;
1165 gamma=PerceptibleReciprocal(alpha);
1166 pixel=QuantumRange*gamma*(Sca+Dca*(1.0-Sa));
1167 q[i]=clamp != MagickFalse ? ClampPixel(pixel) : ClampToQuantum(pixel);
1169 p+=GetPixelChannels(source_image);
1170 channels=GetPixelChannels(source_image);
1171 if (p >= (pixels+channels*source_image->columns))
1173 q+=GetPixelChannels(image);
1175 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1177 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1182 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1186 proceed=SetImageProgress(image,CompositeImageTag,progress,image->rows);
1187 if (proceed == MagickFalse)
1191 source_view=DestroyCacheView(source_view);
1192 image_view=DestroyCacheView(image_view);
1196 static void HCLComposite(
const MagickRealType hue,
const MagickRealType chroma,
1197 const MagickRealType luma,MagickRealType *red,MagickRealType *green,
1198 MagickRealType *blue)
1212 assert(red != (MagickRealType *) NULL);
1213 assert(green != (MagickRealType *) NULL);
1214 assert(blue != (MagickRealType *) NULL);
1217 x=c*(1.0-fabs(fmod(h,2.0)-1.0));
1221 if ((0.0 <= h) && (h < 1.0))
1227 if ((1.0 <= h) && (h < 2.0))
1233 if ((2.0 <= h) && (h < 3.0))
1239 if ((3.0 <= h) && (h < 4.0))
1245 if ((4.0 <= h) && (h < 5.0))
1251 if ((5.0 <= h) && (h < 6.0))
1256 m=luma-(0.298839*r+0.586811*g+0.114350*b);
1257 *red=QuantumRange*(r+m);
1258 *green=QuantumRange*(g+m);
1259 *blue=QuantumRange*(b+m);
1262 static MagickBooleanType SaliencyBlendImage(
Image *image,
1263 const Image *source_image,
const ssize_t x_offset,
const ssize_t y_offset,
1264 const double iterations,
const double residual_threshold,
const size_t tick,
1271 *residual_image = (
Image *) NULL;
1277 status = MagickTrue,
1278 verbose = MagickFalse;
1282 source_image->columns,
1294 crop_image=CropImage(image,&crop_info,exception);
1295 if (crop_image == (
Image *) NULL)
1296 return(MagickFalse);
1297 (void) SetImageArtifact(crop_image,
"compose:clamp",
"off");
1298 divergent_image=BlendDivergentImage(crop_image,source_image,exception);
1299 if (divergent_image == (
Image *) NULL)
1301 crop_image=DestroyImage(crop_image);
1302 return(MagickFalse);
1304 (void) ResetImagePage(crop_image,
"0x0+0+0");
1305 relax_image=BlendMeanImage(crop_image,source_image,exception);
1306 if (relax_image == (
Image *) NULL)
1308 crop_image=DestroyImage(crop_image);
1309 divergent_image=DestroyImage(divergent_image);
1310 return(MagickFalse);
1312 status=BlendMaskAlphaChannel(crop_image,source_image,exception);
1313 if (status == MagickFalse)
1315 crop_image=DestroyImage(crop_image);
1316 divergent_image=DestroyImage(divergent_image);
1317 return(MagickFalse);
1319 residual_image=CloneImage(relax_image,0,0,MagickTrue,exception);
1320 if (residual_image == (
Image *) NULL)
1322 crop_image=DestroyImage(crop_image);
1323 relax_image=DestroyImage(relax_image);
1324 return(MagickFalse);
1329 kernel_info=AcquireKernelInfo(
"3x3:0,0.25,0,0.25,0,0.25,0,0.25,0",exception);
1332 crop_image=DestroyImage(crop_image);
1333 residual_image=DestroyImage(residual_image);
1334 relax_image=DestroyImage(relax_image);
1335 return(MagickFalse);
1337 verbose=IsStringTrue(GetImageArtifact(image,
"verbose"));
1338 if (verbose != MagickFalse)
1339 (void) FormatLocaleFile(stderr,
"saliency blending:\n");
1340 for (i=0; i < (ssize_t) iterations; i++)
1349 convolve_image=ConvolveImage(relax_image,kernel_info,exception);
1350 if (convolve_image == (
Image *) NULL)
1352 relax_image=DestroyImage(relax_image);
1353 relax_image=convolve_image;
1354 sum_image=BlendSumImage(relax_image,divergent_image,1.0,-1.0,exception);
1355 if (sum_image == (
Image *) NULL)
1357 relax_image=DestroyImage(relax_image);
1358 relax_image=sum_image;
1359 status=CompositeOverImage(relax_image,crop_image,MagickTrue,0,0,exception);
1360 if (status == MagickFalse)
1362 status=BlendRMSEResidual(relax_image,residual_image,&residual,exception);
1363 if (status == MagickFalse)
1365 if ((verbose != MagickFalse) && ((i % MagickMax(tick,1)) == 0))
1366 (void) FormatLocaleFile(stderr,
" %g: %g\n",(
double) i,(double) residual);
1367 if (residual < residual_threshold)
1369 if (verbose != MagickFalse)
1370 (void) FormatLocaleFile(stderr,
" %g: %g\n",(
double) i,(double)
1374 residual_image=DestroyImage(residual_image);
1375 residual_image=CloneImage(relax_image,0,0,MagickTrue,exception);
1376 if (residual_image == (
Image *) NULL)
1379 kernel_info=DestroyKernelInfo(kernel_info);
1380 crop_image=DestroyImage(crop_image);
1381 divergent_image=DestroyImage(divergent_image);
1382 residual_image=DestroyImage(residual_image);
1386 status=CompositeOverImage(image,relax_image,MagickTrue,x_offset,y_offset,
1388 relax_image=DestroyImage(relax_image);
1392 static MagickBooleanType SeamlessBlendImage(
Image *image,
1393 const Image *source_image,
const ssize_t x_offset,
const ssize_t y_offset,
1394 const double iterations,
const double residual_threshold,
const size_t tick,
1409 status = MagickTrue,
1410 verbose = MagickFalse;
1414 source_image->columns,
1426 crop_image=CropImage(image,&crop_info,exception);
1427 if (crop_image == (
Image *) NULL)
1428 return(MagickFalse);
1429 (void) SetImageArtifact(crop_image,
"compose:clamp",
"off");
1430 (void) ResetImagePage(crop_image,
"0x0+0+0");
1431 sum_image=BlendSumImage(crop_image,source_image,1.0,-1.0,exception);
1432 crop_image=DestroyImage(crop_image);
1433 if (sum_image == (
Image *) NULL)
1434 return(MagickFalse);
1435 mean_image=BlendMeanImage(sum_image,source_image,exception);
1436 sum_image=DestroyImage(sum_image);
1437 if (mean_image == (
Image *) NULL)
1438 return(MagickFalse);
1439 relax_image=CloneImage(mean_image,0,0,MagickTrue,exception);
1440 if (relax_image == (
Image *) NULL)
1442 mean_image=DestroyImage(mean_image);
1443 return(MagickFalse);
1445 status=BlendMaskAlphaChannel(mean_image,source_image,exception);
1446 if (status == MagickFalse)
1448 relax_image=DestroyImage(relax_image);
1449 mean_image=DestroyImage(mean_image);
1450 return(MagickFalse);
1452 residual_image=CloneImage(relax_image,0,0,MagickTrue,exception);
1453 if (residual_image == (
Image *) NULL)
1455 relax_image=DestroyImage(relax_image);
1456 mean_image=DestroyImage(mean_image);
1457 return(MagickFalse);
1462 kernel_info=AcquireKernelInfo(
"3x3:0,0.25,0,0.25,0,0.25,0,0.25,0",exception);
1465 residual_image=DestroyImage(residual_image);
1466 relax_image=DestroyImage(relax_image);
1467 mean_image=DestroyImage(mean_image);
1468 return(MagickFalse);
1470 verbose=IsStringTrue(GetImageArtifact(image,
"verbose"));
1471 if (verbose != MagickFalse)
1472 (void) FormatLocaleFile(stderr,
"seamless blending:\n");
1473 for (i=0; i < (ssize_t) iterations; i++)
1481 convolve_image=ConvolveImage(relax_image,kernel_info,exception);
1482 if (convolve_image == (
Image *) NULL)
1484 relax_image=DestroyImage(relax_image);
1485 relax_image=convolve_image;
1486 status=CompositeOverImage(relax_image,mean_image,MagickTrue,0,0,exception);
1487 if (status == MagickFalse)
1489 status=BlendRMSEResidual(relax_image,residual_image,&residual,exception);
1490 if (status == MagickFalse)
1492 if ((verbose != MagickFalse) && ((i % MagickMax(tick,1)) == 0))
1493 (void) FormatLocaleFile(stderr,
" %g: %g\n",(
double) i,(double) residual);
1494 if (residual < residual_threshold)
1496 if (verbose != MagickFalse)
1497 (void) FormatLocaleFile(stderr,
" %g: %g\n",(
double) i,(double)
1501 if (residual_image != (
Image *) NULL)
1502 residual_image=DestroyImage(residual_image);
1503 residual_image=CloneImage(relax_image,0,0,MagickTrue,exception);
1504 if (residual_image == (
Image *) NULL)
1507 kernel_info=DestroyKernelInfo(kernel_info);
1508 mean_image=DestroyImage(mean_image);
1509 residual_image=DestroyImage(residual_image);
1513 foreground_image=BlendSumImage(source_image,relax_image,1.0,1.0,exception);
1514 relax_image=DestroyImage(relax_image);
1515 if (foreground_image == (
Image *) NULL)
1516 return(MagickFalse);
1517 (void) SetImageMask(foreground_image,ReadPixelMask,(
const Image *) NULL,
1519 status=CompositeOverImage(image,foreground_image,MagickTrue,x_offset,y_offset,
1521 foreground_image=DestroyImage(foreground_image);
1525 MagickExport MagickBooleanType CompositeImage(
Image *image,
1526 const Image *composite,
const CompositeOperator compose,
1527 const MagickBooleanType clip_to_self,
const ssize_t x_offset,
1530 #define CompositeImageTag "Composite/Image"
1569 assert(image != (
Image *) NULL);
1570 assert(image->signature == MagickCoreSignature);
1571 assert(composite != (
Image *) NULL);
1572 assert(composite->signature == MagickCoreSignature);
1573 if (IsEventLogging() != MagickFalse)
1574 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1575 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1576 return(MagickFalse);
1577 source_image=CloneImage(composite,0,0,MagickTrue,exception);
1578 if (source_image == (
const Image *) NULL)
1579 return(MagickFalse);
1580 (void) SetImageColorspace(source_image,image->colorspace,exception);
1581 if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
1583 status=CompositeOverImage(image,source_image,clip_to_self,x_offset,
1584 y_offset,exception);
1585 source_image=DestroyImage(source_image);
1589 canvas_image=(
Image *) NULL;
1590 canvas_dissolve=1.0;
1592 value=GetImageArtifact(image,
"compose:clamp");
1593 if (value != (
const char *) NULL)
1594 clamp=IsStringTrue(value);
1595 compose_sync=MagickTrue;
1596 value=GetImageArtifact(image,
"compose:sync");
1597 if (value != (
const char *) NULL)
1598 compose_sync=IsStringTrue(value);
1599 SetGeometryInfo(&geometry_info);
1601 percent_chroma=100.0;
1602 source_dissolve=1.0;
1606 case CopyCompositeOp:
1608 if ((x_offset < 0) || (y_offset < 0))
1610 if ((x_offset+(ssize_t) source_image->columns) > (ssize_t) image->columns)
1612 if ((y_offset+(ssize_t) source_image->rows) > (ssize_t) image->rows)
1614 if ((source_image->alpha_trait == UndefinedPixelTrait) &&
1615 (image->alpha_trait != UndefinedPixelTrait))
1616 (void) SetImageAlphaChannel(source_image,OpaqueAlphaChannel,exception);
1618 source_view=AcquireVirtualCacheView(source_image,exception);
1619 image_view=AcquireAuthenticCacheView(image,exception);
1620 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1621 #pragma omp parallel for schedule(static) shared(status) \
1622 magick_number_threads(source_image,image,source_image->rows,1)
1624 for (y=0; y < (ssize_t) source_image->rows; y++)
1638 if (status == MagickFalse)
1640 p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
1642 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
1643 source_image->columns,1,exception);
1644 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
1649 for (x=0; x < (ssize_t) source_image->columns; x++)
1654 if (GetPixelReadMask(source_image,p) <= (QuantumRange/2))
1656 p+=GetPixelChannels(source_image);
1657 q+=GetPixelChannels(image);
1660 for (i=0; i < (ssize_t) GetPixelChannels(source_image); i++)
1662 PixelChannel channel = GetPixelChannelChannel(source_image,i);
1663 PixelTrait source_traits = GetPixelChannelTraits(source_image,
1665 PixelTrait traits = GetPixelChannelTraits(image,channel);
1666 if ((source_traits == UndefinedPixelTrait) ||
1667 (traits == UndefinedPixelTrait))
1669 SetPixelChannel(image,channel,p[i],q);
1671 p+=GetPixelChannels(source_image);
1672 q+=GetPixelChannels(image);
1674 sync=SyncCacheViewAuthenticPixels(image_view,exception);
1675 if (sync == MagickFalse)
1677 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1682 proceed=SetImageProgress(image,CompositeImageTag,(MagickOffsetType)
1684 if (proceed == MagickFalse)
1688 source_view=DestroyCacheView(source_view);
1689 image_view=DestroyCacheView(image_view);
1690 source_image=DestroyImage(source_image);
1693 case IntensityCompositeOp:
1695 if ((x_offset < 0) || (y_offset < 0))
1697 if ((x_offset+(ssize_t) source_image->columns) > (ssize_t) image->columns)
1699 if ((y_offset+(ssize_t) source_image->rows) > (ssize_t) image->rows)
1702 source_view=AcquireVirtualCacheView(source_image,exception);
1703 image_view=AcquireAuthenticCacheView(image,exception);
1704 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1705 #pragma omp parallel for schedule(static) shared(status) \
1706 magick_number_threads(source_image,image,source_image->rows,1)
1708 for (y=0; y < (ssize_t) source_image->rows; y++)
1722 if (status == MagickFalse)
1724 p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
1726 q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
1727 source_image->columns,1,exception);
1728 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
1733 for (x=0; x < (ssize_t) source_image->columns; x++)
1735 if (GetPixelReadMask(source_image,p) <= (QuantumRange/2))
1737 p+=GetPixelChannels(source_image);
1738 q+=GetPixelChannels(image);
1741 SetPixelAlpha(image,clamp != MagickFalse ?
1742 ClampPixel(GetPixelIntensity(source_image,p)) :
1743 ClampToQuantum(GetPixelIntensity(source_image,p)),q);
1744 p+=GetPixelChannels(source_image);
1745 q+=GetPixelChannels(image);
1747 sync=SyncCacheViewAuthenticPixels(image_view,exception);
1748 if (sync == MagickFalse)
1750 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1755 proceed=SetImageProgress(image,CompositeImageTag,(MagickOffsetType)
1757 if (proceed == MagickFalse)
1761 source_view=DestroyCacheView(source_view);
1762 image_view=DestroyCacheView(image_view);
1763 source_image=DestroyImage(source_image);
1766 case CopyAlphaCompositeOp:
1767 case ChangeMaskCompositeOp:
1773 if (image->alpha_trait == UndefinedPixelTrait)
1774 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1777 case BlurCompositeOp:
1802 canvas_image=CloneImage(image,0,0,MagickTrue,exception);
1803 if (canvas_image == (
Image *) NULL)
1805 source_image=DestroyImage(source_image);
1806 return(MagickFalse);
1812 value=GetImageArtifact(image,
"compose:args");
1813 if (value != (
const char *) NULL)
1814 flags=ParseGeometry(value,&geometry_info);
1815 if ((flags & WidthValue) == 0)
1817 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
1818 "InvalidSetting",
"'%s' '%s'",
"compose:args",value);
1819 source_image=DestroyImage(source_image);
1820 canvas_image=DestroyImage(canvas_image);
1821 return(MagickFalse);
1828 width=2.0*geometry_info.rho;
1830 if ((flags & HeightValue) != 0)
1831 height=2.0*geometry_info.sigma;
1839 if ((flags & XValue) != 0 )
1847 angle=DegreesToRadians(geometry_info.xi);
1848 blur.x1=width*cos(angle);
1849 blur.x2=width*sin(angle);
1850 blur.y1=(-height*sin(angle));
1851 blur.y2=height*cos(angle);
1855 if ((flags & YValue) != 0 )
1860 angle_start=DegreesToRadians(geometry_info.xi);
1861 angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
1872 resample_filter=AcquireResampleFilter(image,exception);
1873 SetResampleFilter(resample_filter,GaussianFilter);
1877 GetPixelInfo(image,&pixel);
1878 source_view=AcquireVirtualCacheView(source_image,exception);
1879 canvas_view=AcquireAuthenticCacheView(canvas_image,exception);
1880 for (y=0; y < (ssize_t) source_image->rows; y++)
1894 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1896 p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
1898 q=QueueCacheViewAuthenticPixels(canvas_view,0,y,canvas_image->columns,1,
1900 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
1902 for (x=0; x < (ssize_t) source_image->columns; x++)
1904 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1906 p+=GetPixelChannels(source_image);
1909 if (fabs(angle_range) > MagickEpsilon)
1914 angle=angle_start+angle_range*QuantumScale*
1915 GetPixelBlue(source_image,p);
1916 blur.x1=width*cos(angle);
1917 blur.x2=width*sin(angle);
1918 blur.y1=(-height*sin(angle));
1919 blur.y2=height*cos(angle);
1921 ScaleResampleFilter(resample_filter,
1922 blur.x1*QuantumScale*GetPixelRed(source_image,p),
1923 blur.y1*QuantumScale*GetPixelGreen(source_image,p),
1924 blur.x2*QuantumScale*GetPixelRed(source_image,p),
1925 blur.y2*QuantumScale*GetPixelGreen(source_image,p) );
1926 (void) ResamplePixelColor(resample_filter,(
double) x_offset+x,
1927 (double) y_offset+y,&pixel,exception);
1928 SetPixelViaPixelInfo(canvas_image,&pixel,q);
1929 p+=GetPixelChannels(source_image);
1930 q+=GetPixelChannels(canvas_image);
1932 sync=SyncCacheViewAuthenticPixels(canvas_view,exception);
1933 if (sync == MagickFalse)
1936 resample_filter=DestroyResampleFilter(resample_filter);
1937 source_view=DestroyCacheView(source_view);
1938 canvas_view=DestroyCacheView(canvas_view);
1939 source_image=DestroyImage(source_image);
1940 source_image=canvas_image;
1943 case DisplaceCompositeOp:
1944 case DistortCompositeOp:
1965 canvas_image=CloneImage(image,0,0,MagickTrue,exception);
1966 if (canvas_image == (
Image *) NULL)
1968 source_image=DestroyImage(source_image);
1969 return(MagickFalse);
1971 SetGeometryInfo(&geometry_info);
1973 value=GetImageArtifact(image,
"compose:args");
1974 if (value != (
char *) NULL)
1975 flags=ParseGeometry(value,&geometry_info);
1976 if ((flags & (WidthValue | HeightValue)) == 0 )
1978 if ((flags & AspectValue) == 0)
1980 horizontal_scale=(MagickRealType) (source_image->columns-1)/2.0;
1981 vertical_scale=(MagickRealType) (source_image->rows-1)/2.0;
1985 horizontal_scale=(MagickRealType) (image->columns-1)/2.0;
1986 vertical_scale=(MagickRealType) (image->rows-1)/2.0;
1991 horizontal_scale=geometry_info.rho;
1992 vertical_scale=geometry_info.sigma;
1993 if ((flags & PercentValue) != 0)
1995 if ((flags & AspectValue) == 0)
1997 horizontal_scale*=(source_image->columns-1)/200.0;
1998 vertical_scale*=(source_image->rows-1)/200.0;
2002 horizontal_scale*=(image->columns-1)/200.0;
2003 vertical_scale*=(image->rows-1)/200.0;
2006 if ((flags & HeightValue) == 0)
2007 vertical_scale=horizontal_scale;
2017 center.x=(MagickRealType) x_offset;
2018 center.y=(MagickRealType) y_offset;
2019 if (compose == DistortCompositeOp)
2021 if ((flags & XValue) == 0)
2022 if ((flags & AspectValue) != 0)
2023 center.x=(MagickRealType) ((image->columns-1)/2.0);
2025 center.x=(MagickRealType) (x_offset+(source_image->columns-1)/
2028 if ((flags & AspectValue) != 0)
2029 center.x=geometry_info.xi;
2031 center.x=(MagickRealType) (x_offset+geometry_info.xi);
2032 if ((flags & YValue) == 0)
2033 if ((flags & AspectValue) != 0)
2034 center.y=(MagickRealType) ((image->rows-1)/2.0);
2036 center.y=(MagickRealType) (y_offset+(source_image->rows-1)/2.0);
2038 if ((flags & AspectValue) != 0)
2039 center.y=geometry_info.psi;
2041 center.y=(MagickRealType) (y_offset+geometry_info.psi);
2047 GetPixelInfo(image,&pixel);
2048 image_view=AcquireVirtualCacheView(image,exception);
2049 source_view=AcquireVirtualCacheView(source_image,exception);
2050 canvas_view=AcquireAuthenticCacheView(canvas_image,exception);
2051 for (y=0; y < (ssize_t) source_image->rows; y++)
2065 if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
2067 p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
2069 q=QueueCacheViewAuthenticPixels(canvas_view,0,y,canvas_image->columns,1,
2071 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
2073 for (x=0; x < (ssize_t) source_image->columns; x++)
2075 if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
2077 p+=GetPixelChannels(source_image);
2083 offset.x=(double) (horizontal_scale*(GetPixelRed(source_image,p)-
2084 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
2085 QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
2087 offset.y=(double) (vertical_scale*(GetPixelGreen(source_image,p)-
2088 (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
2089 QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
2091 status=InterpolatePixelInfo(image,image_view,
2092 UndefinedInterpolatePixel,(
double) offset.x,(
double) offset.y,
2094 if (status == MagickFalse)
2099 pixel.alpha=(MagickRealType) QuantumRange*(QuantumScale*pixel.alpha)*
2100 (QuantumScale*GetPixelAlpha(source_image,p));
2101 SetPixelViaPixelInfo(canvas_image,&pixel,q);
2102 p+=GetPixelChannels(source_image);
2103 q+=GetPixelChannels(canvas_image);
2105 if (x < (ssize_t) source_image->columns)
2107 sync=SyncCacheViewAuthenticPixels(canvas_view,exception);
2108 if (sync == MagickFalse)
2111 canvas_view=DestroyCacheView(canvas_view);
2112 source_view=DestroyCacheView(source_view);
2113 image_view=DestroyCacheView(image_view);
2114 source_image=DestroyImage(source_image);
2115 source_image=canvas_image;
2118 case DissolveCompositeOp:
2123 value=GetImageArtifact(image,
"compose:args");
2124 if (value != (
char *) NULL)
2126 flags=ParseGeometry(value,&geometry_info);
2127 source_dissolve=geometry_info.rho/100.0;
2128 canvas_dissolve=1.0;
2129 if ((source_dissolve-MagickEpsilon) < 0.0)
2130 source_dissolve=0.0;
2131 if ((source_dissolve+MagickEpsilon) > 1.0)
2133 canvas_dissolve=2.0-source_dissolve;
2134 source_dissolve=1.0;
2136 if ((flags & SigmaValue) != 0)
2137 canvas_dissolve=geometry_info.sigma/100.0;
2138 if ((canvas_dissolve-MagickEpsilon) < 0.0)
2139 canvas_dissolve=0.0;
2140 if ((canvas_dissolve+MagickEpsilon) > 1.0)
2141 canvas_dissolve=1.0;
2145 case BlendCompositeOp:
2147 value=GetImageArtifact(image,
"compose:args");
2148 if (value != (
char *) NULL)
2150 flags=ParseGeometry(value,&geometry_info);
2151 source_dissolve=geometry_info.rho/100.0;
2152 canvas_dissolve=1.0-source_dissolve;
2153 if ((flags & SigmaValue) != 0)
2154 canvas_dissolve=geometry_info.sigma/100.0;
2158 case SaliencyBlendCompositeOp:
2161 residual_threshold = 0.0002,
2167 value=GetImageArtifact(image,
"compose:args");
2168 if (value != (
char *) NULL)
2170 flags=ParseGeometry(value,&geometry_info);
2171 iterations=geometry_info.rho;
2172 if ((flags & SigmaValue) != 0)
2173 residual_threshold=geometry_info.sigma;
2174 if ((flags & XiValue) != 0)
2175 tick=(size_t) geometry_info.xi;
2177 status=SaliencyBlendImage(image,composite,x_offset,y_offset,iterations,
2178 residual_threshold,tick,exception);
2179 source_image=DestroyImage(source_image);
2182 case SeamlessBlendCompositeOp:
2185 residual_threshold = 0.0002,
2191 value=GetImageArtifact(image,
"compose:args");
2192 if (value != (
char *) NULL)
2194 flags=ParseGeometry(value,&geometry_info);
2195 iterations=geometry_info.rho;
2196 if ((flags & SigmaValue) != 0)
2197 residual_threshold=geometry_info.sigma;
2198 if ((flags & XiValue) != 0)
2199 tick=(size_t) geometry_info.xi;
2201 status=SeamlessBlendImage(image,composite,x_offset,y_offset,iterations,
2202 residual_threshold,tick,exception);
2203 source_image=DestroyImage(source_image);
2206 case MathematicsCompositeOp:
2216 SetGeometryInfo(&geometry_info);
2217 value=GetImageArtifact(image,
"compose:args");
2218 if (value != (
char *) NULL)
2220 flags=ParseGeometry(value,&geometry_info);
2221 if (flags == NoValue)
2222 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2223 "InvalidGeometry",
"`%s'",value);
2227 case ModulateCompositeOp:
2232 value=GetImageArtifact(image,
"compose:args");
2233 if (value != (
char *) NULL)
2235 flags=ParseGeometry(value,&geometry_info);
2236 percent_luma=geometry_info.rho;
2237 if ((flags & SigmaValue) != 0)
2238 percent_chroma=geometry_info.sigma;
2242 case ThresholdCompositeOp:
2247 value=GetImageArtifact(image,
"compose:args");
2248 if (value != (
char *) NULL)
2250 flags=ParseGeometry(value,&geometry_info);
2251 amount=geometry_info.rho;
2252 threshold=geometry_info.sigma;
2253 if ((flags & SigmaValue) == 0)
2256 threshold*=QuantumRange;
2267 midpoint=((MagickRealType) QuantumRange+1.0)/2;
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++)
2300 if (status == MagickFalse)
2302 if (clip_to_self != MagickFalse)
2306 if ((y-y_offset) >= (ssize_t) source_image->rows)
2312 pixels=(Quantum *) NULL;
2314 if ((y >= y_offset) && ((y-y_offset) < (ssize_t) source_image->rows))
2316 p=GetCacheViewVirtualPixels(source_view,0,y-y_offset,
2317 source_image->columns,1,exception);
2318 if (p == (
const Quantum *) NULL)
2325 p-=x_offset*(ssize_t) GetPixelChannels(source_image);
2327 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2328 if (q == (Quantum *) NULL)
2333 GetPixelInfo(image,&canvas_pixel);
2334 GetPixelInfo(source_image,&source_pixel);
2335 for (x=0; x < (ssize_t) image->columns; x++)
2359 if (clip_to_self != MagickFalse)
2363 q+=GetPixelChannels(image);
2366 if ((x-x_offset) >= (ssize_t) source_image->columns)
2369 if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
2370 ((x-x_offset) >= (ssize_t) source_image->columns))
2373 source[MaxPixelChannels];
2380 (void) GetOneVirtualPixel(source_image,x-x_offset,y-y_offset,source,
2382 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2387 PixelChannel channel = GetPixelChannelChannel(image,i);
2388 PixelTrait traits = GetPixelChannelTraits(image,channel);
2389 PixelTrait source_traits = GetPixelChannelTraits(source_image,
2391 if ((traits == UndefinedPixelTrait) ||
2392 (source_traits == UndefinedPixelTrait))
2396 case AlphaCompositeOp:
2397 case ChangeMaskCompositeOp:
2398 case CopyAlphaCompositeOp:
2399 case DstAtopCompositeOp:
2400 case DstInCompositeOp:
2402 case OutCompositeOp:
2403 case SrcInCompositeOp:
2404 case SrcOutCompositeOp:
2406 if (channel == AlphaPixelChannel)
2407 pixel=(MagickRealType) TransparentAlpha;
2409 pixel=(MagickRealType) q[i];
2412 case ClearCompositeOp:
2413 case CopyCompositeOp:
2414 case ReplaceCompositeOp:
2415 case SrcCompositeOp:
2417 if (channel == AlphaPixelChannel)
2418 pixel=(MagickRealType) TransparentAlpha;
2423 case BlendCompositeOp:
2424 case DissolveCompositeOp:
2426 if (channel == AlphaPixelChannel)
2427 pixel=canvas_dissolve*GetPixelAlpha(source_image,source);
2429 pixel=(MagickRealType) source[channel];
2434 pixel=(MagickRealType) source[channel];
2438 q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
2439 ClampToQuantum(pixel);
2441 q+=GetPixelChannels(image);
2449 Sa=QuantumScale*GetPixelAlpha(source_image,p);
2450 Da=QuantumScale*GetPixelAlpha(image,q);
2453 case BumpmapCompositeOp:
2454 case ColorBurnCompositeOp:
2455 case ColorDodgeCompositeOp:
2456 case DarkenCompositeOp:
2457 case DifferenceCompositeOp:
2458 case DivideDstCompositeOp:
2459 case DivideSrcCompositeOp:
2460 case ExclusionCompositeOp:
2461 case FreezeCompositeOp:
2462 case HardLightCompositeOp:
2463 case HardMixCompositeOp:
2464 case InterpolateCompositeOp:
2465 case LightenCompositeOp:
2466 case LinearBurnCompositeOp:
2467 case LinearDodgeCompositeOp:
2468 case LinearLightCompositeOp:
2469 case MathematicsCompositeOp:
2470 case MinusDstCompositeOp:
2471 case MinusSrcCompositeOp:
2472 case MultiplyCompositeOp:
2473 case NegateCompositeOp:
2474 case OverlayCompositeOp:
2475 case PegtopLightCompositeOp:
2476 case PinLightCompositeOp:
2477 case ReflectCompositeOp:
2478 case ScreenCompositeOp:
2479 case SoftBurnCompositeOp:
2480 case SoftDodgeCompositeOp:
2481 case SoftLightCompositeOp:
2482 case StampCompositeOp:
2483 case VividLightCompositeOp:
2485 alpha=RoundToUnity(Sa+Da-Sa*Da);
2488 case DstAtopCompositeOp:
2489 case DstInCompositeOp:
2491 case SrcInCompositeOp:
2496 case DissolveCompositeOp:
2498 alpha=source_dissolve*Sa*(-canvas_dissolve*Da)+source_dissolve*Sa+
2502 case DstOverCompositeOp:
2503 case OverCompositeOp:
2504 case SrcOverCompositeOp:
2509 case DstOutCompositeOp:
2514 case OutCompositeOp:
2515 case SrcOutCompositeOp:
2520 case BlendCompositeOp:
2521 case PlusCompositeOp:
2523 alpha=RoundToUnity(source_dissolve*Sa+canvas_dissolve*Da);
2526 case XorCompositeOp:
2528 alpha=Sa+Da-2.0*Sa*Da;
2531 case ModulusAddCompositeOp:
2538 alpha=((Sa+Da)-1.0);
2541 case ModulusSubtractCompositeOp:
2548 alpha=((Sa-Da)+1.0);
2559 case ColorizeCompositeOp:
2560 case HueCompositeOp:
2561 case LuminizeCompositeOp:
2562 case ModulateCompositeOp:
2563 case RMSECompositeOp:
2564 case SaturateCompositeOp:
2566 Si=GetPixelIntensity(source_image,p);
2567 GetPixelInfoPixel(source_image,p,&source_pixel);
2568 GetPixelInfoPixel(image,q,&canvas_pixel);
2571 case BumpmapCompositeOp:
2572 case CopyAlphaCompositeOp:
2573 case DarkenIntensityCompositeOp:
2574 case LightenIntensityCompositeOp:
2576 Si=GetPixelIntensity(source_image,p);
2577 Di=GetPixelIntensity(image,q);
2583 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2589 PixelChannel channel = GetPixelChannelChannel(image,i);
2590 PixelTrait traits = GetPixelChannelTraits(image,channel);
2591 PixelTrait source_traits = GetPixelChannelTraits(source_image,channel);
2592 if (traits == UndefinedPixelTrait)
2594 if ((channel == AlphaPixelChannel) &&
2595 ((traits & UpdatePixelTrait) != 0))
2602 case AlphaCompositeOp:
2604 pixel=QuantumRange*Sa;
2607 case AtopCompositeOp:
2608 case CopyBlackCompositeOp:
2609 case CopyBlueCompositeOp:
2610 case CopyCyanCompositeOp:
2611 case CopyGreenCompositeOp:
2612 case CopyMagentaCompositeOp:
2613 case CopyRedCompositeOp:
2614 case CopyYellowCompositeOp:
2615 case SrcAtopCompositeOp:
2616 case DstCompositeOp:
2619 pixel=QuantumRange*Da;
2622 case BumpmapCompositeOp:
2627 case ChangeMaskCompositeOp:
2629 if (IsFuzzyEquivalencePixel(source_image,p,image,q) != MagickFalse)
2630 pixel=(MagickRealType) TransparentAlpha;
2632 pixel=QuantumRange*Da;
2635 case ClearCompositeOp:
2637 pixel=(MagickRealType) TransparentAlpha;
2640 case ColorizeCompositeOp:
2641 case HueCompositeOp:
2642 case LuminizeCompositeOp:
2643 case RMSECompositeOp:
2644 case SaturateCompositeOp:
2646 if (fabs((
double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2648 pixel=QuantumRange*Da;
2651 if (fabs((
double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
2653 pixel=QuantumRange*Sa;
2658 pixel=QuantumRange*Da;
2661 pixel=QuantumRange*Sa;
2664 case CopyAlphaCompositeOp:
2666 if (source_image->alpha_trait == UndefinedPixelTrait)
2669 pixel=QuantumRange*Sa;
2672 case BlurCompositeOp:
2673 case CopyCompositeOp:
2674 case DisplaceCompositeOp:
2675 case DistortCompositeOp:
2676 case DstAtopCompositeOp:
2677 case ReplaceCompositeOp:
2678 case SrcCompositeOp:
2680 pixel=QuantumRange*Sa;
2683 case DarkenIntensityCompositeOp:
2685 if (compose_sync == MagickFalse)
2687 pixel=Si < Di? Sa : Da;
2690 pixel=Sa*Si < Da*Di ? Sa : Da;
2693 case DifferenceCompositeOp:
2695 pixel=QuantumRange*fabs((
double) (Sa-Da));
2698 case FreezeCompositeOp:
2700 pixel=QuantumRange*(1.0-(1.0-Sa)*(1.0-Sa)*
2701 PerceptibleReciprocal(Da));
2706 case InterpolateCompositeOp:
2708 pixel=QuantumRange*(0.5-0.25*cos(MagickPI*Sa)-0.25*
2712 case LightenIntensityCompositeOp:
2714 if (compose_sync == MagickFalse)
2716 pixel=Si > Di ? Sa : Da;
2719 pixel=Sa*Si > Da*Di ? Sa : Da;
2722 case ModulateCompositeOp:
2724 pixel=QuantumRange*Da;
2727 case MultiplyCompositeOp:
2729 if (compose_sync == MagickFalse)
2731 pixel=QuantumRange*Sa*Da;
2734 pixel=QuantumRange*alpha;
2737 case NegateCompositeOp:
2739 pixel=QuantumRange*((1.0-Sa-Da));
2742 case ReflectCompositeOp:
2744 pixel=QuantumRange*(Sa*Sa*PerceptibleReciprocal(1.0-Da));
2745 if (pixel > QuantumRange)
2749 case StampCompositeOp:
2751 pixel=QuantumRange*(Sa+Da*Da-1.0);
2754 case StereoCompositeOp:
2756 pixel=QuantumRange*(Sa+Da)/2;
2761 pixel=QuantumRange*alpha;
2765 q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
2766 ClampToQuantum(pixel);
2769 if (source_traits == UndefinedPixelTrait)
2775 Sc=(MagickRealType) GetPixelChannel(source_image,channel,p);
2776 Dc=(MagickRealType) q[i];
2777 if ((traits & CopyPixelTrait) != 0)
2782 q[i]=ClampToQuantum(Dc);
2790 Sca=QuantumScale*Sa*Sc;
2791 Dca=QuantumScale*Da*Dc;
2792 SaSca=Sa*PerceptibleReciprocal(Sca);
2793 DcaDa=Dca*PerceptibleReciprocal(Da);
2796 case DarkenCompositeOp:
2797 case LightenCompositeOp:
2798 case ModulusSubtractCompositeOp:
2800 gamma=PerceptibleReciprocal(1.0-alpha);
2805 gamma=PerceptibleReciprocal(alpha);
2812 case AlphaCompositeOp:
2814 pixel=QuantumRange*Sa;
2817 case AtopCompositeOp:
2818 case SrcAtopCompositeOp:
2820 pixel=QuantumRange*(Sca*Da+Dca*(1.0-Sa));
2823 case BlendCompositeOp:
2825 pixel=gamma*(source_dissolve*Sa*Sc+canvas_dissolve*Da*Dc);
2828 case CopyCompositeOp:
2829 case ReplaceCompositeOp:
2830 case SrcCompositeOp:
2832 pixel=QuantumRange*Sca;
2835 case BlurCompositeOp:
2836 case DisplaceCompositeOp:
2837 case DistortCompositeOp:
2842 case BumpmapCompositeOp:
2844 if (fabs((
double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2849 pixel=QuantumScale*Si*Dc;
2852 case ChangeMaskCompositeOp:
2857 case ClearCompositeOp:
2862 case ColorBurnCompositeOp:
2864 if ((Sca == 0.0) && (Dca == Da))
2866 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
2871 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
2874 pixel=QuantumRange*gamma*(Sa*Da-Sa*Da*MagickMin(1.0,(1.0-DcaDa)*
2875 SaSca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
2878 case ColorDodgeCompositeOp:
2880 if ((Sca*Da+Dca*Sa) >= Sa*Da)
2881 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2883 pixel=QuantumRange*gamma*(Dca*Sa*Sa*PerceptibleReciprocal(Sa-Sca)+
2884 Sca*(1.0-Da)+Dca*(1.0-Sa));
2887 case ColorizeCompositeOp:
2889 if (fabs((
double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2894 if (fabs((
double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
2899 CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
2901 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2902 &hue,&chroma,&sans);
2903 HCLComposite(hue,chroma,luma,&red,&green,&blue);
2906 case RedPixelChannel: pixel=red;
break;
2907 case GreenPixelChannel: pixel=green;
break;
2908 case BluePixelChannel: pixel=blue;
break;
2909 default: pixel=Dc;
break;
2913 case CopyAlphaCompositeOp:
2918 case CopyBlackCompositeOp:
2920 if (channel == BlackPixelChannel)
2921 pixel=(MagickRealType) GetPixelBlack(source_image,p);
2924 case CopyBlueCompositeOp:
2925 case CopyYellowCompositeOp:
2927 if (channel == BluePixelChannel)
2928 pixel=(MagickRealType) GetPixelBlue(source_image,p);
2931 case CopyGreenCompositeOp:
2932 case CopyMagentaCompositeOp:
2934 if (channel == GreenPixelChannel)
2935 pixel=(MagickRealType) GetPixelGreen(source_image,p);
2938 case CopyRedCompositeOp:
2939 case CopyCyanCompositeOp:
2941 if (channel == RedPixelChannel)
2942 pixel=(MagickRealType) GetPixelRed(source_image,p);
2945 case DarkenCompositeOp:
2952 if (compose_sync == MagickFalse)
2954 pixel=MagickMin(Sc,Dc);
2957 if ((Sca*Da) < (Dca*Sa))
2959 pixel=QuantumRange*(Sca+Dca*(1.0-Sa));
2962 pixel=QuantumRange*(Dca+Sca*(1.0-Da));
2965 case DarkenIntensityCompositeOp:
2967 if (compose_sync == MagickFalse)
2969 pixel=Si < Di ? Sc : Dc;
2972 pixel=Sa*Si < Da*Di ? Sc : Dc;
2975 case DifferenceCompositeOp:
2977 if (compose_sync == MagickFalse)
2979 pixel=fabs((
double) Sc-Dc);
2982 pixel=QuantumRange*gamma*(Sca+Dca-2.0*MagickMin(Sca*Da,Dca*Sa));
2985 case DissolveCompositeOp:
2987 pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
2988 canvas_dissolve*Da*Dc+canvas_dissolve*Da*Dc);
2991 case DivideDstCompositeOp:
2993 if (compose_sync == MagickFalse)
2995 pixel=QuantumRange*(Sc/PerceptibleReciprocal(Dc));
2998 if ((fabs((
double) Sca) < MagickEpsilon) &&
2999 (fabs((
double) Dca) < MagickEpsilon))
3001 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
3004 if (fabs((
double) Dca) < MagickEpsilon)
3006 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
3009 pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
3012 case DivideSrcCompositeOp:
3014 if (compose_sync == MagickFalse)
3016 pixel=QuantumRange*(Dc/PerceptibleReciprocal(Sc));
3019 if ((fabs((
double) Dca) < MagickEpsilon) &&
3020 (fabs((
double) Sca) < MagickEpsilon))
3022 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
3025 if (fabs((
double) Sca) < MagickEpsilon)
3027 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
3030 pixel=QuantumRange*gamma*(Dca*Sa*SaSca+Dca*(1.0-Sa)+Sca*(1.0-Da));
3033 case DstAtopCompositeOp:
3035 pixel=QuantumRange*(Dca*Sa+Sca*(1.0-Da));
3038 case DstCompositeOp:
3041 pixel=QuantumRange*Dca;
3044 case DstInCompositeOp:
3046 pixel=QuantumRange*gamma*(Dca*Sa);
3049 case DstOutCompositeOp:
3051 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
3054 case DstOverCompositeOp:
3056 pixel=QuantumRange*gamma*(Dca+Sca*(1.0-Da));
3059 case ExclusionCompositeOp:
3061 pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
3065 case FreezeCompositeOp:
3067 pixel=QuantumRange*gamma*(1.0-(1.0-Sca)*(1.0-Sca)*
3068 PerceptibleReciprocal(Dca));
3073 case HardLightCompositeOp:
3077 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-
3081 pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
3085 case HardMixCompositeOp:
3087 pixel=gamma*(((Sca+Dca) < 1.0) ? 0.0 : QuantumRange);
3090 case HueCompositeOp:
3092 if (fabs((
double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
3097 if (fabs((
double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
3102 CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
3103 &hue,&chroma,&luma);
3104 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
3106 HCLComposite(hue,chroma,luma,&red,&green,&blue);
3109 case RedPixelChannel: pixel=red;
break;
3110 case GreenPixelChannel: pixel=green;
break;
3111 case BluePixelChannel: pixel=blue;
break;
3112 default: pixel=Dc;
break;
3117 case SrcInCompositeOp:
3119 pixel=QuantumRange*(Sca*Da);
3122 case InterpolateCompositeOp:
3124 pixel=QuantumRange*(0.5-0.25*cos(MagickPI*Sca)-0.25*
3128 case LinearBurnCompositeOp:
3136 pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
3139 case LinearDodgeCompositeOp:
3141 pixel=gamma*(Sa*Sc+Da*Dc);
3144 case LinearLightCompositeOp:
3152 pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
3155 case LightenCompositeOp:
3157 if (compose_sync == MagickFalse)
3159 pixel=MagickMax(Sc,Dc);
3162 if ((Sca*Da) > (Dca*Sa))
3164 pixel=QuantumRange*(Sca+Dca*(1.0-Sa));
3167 pixel=QuantumRange*(Dca+Sca*(1.0-Da));
3170 case LightenIntensityCompositeOp:
3177 if (compose_sync == MagickFalse)
3179 pixel=Si > Di ? Sc : Dc;
3182 pixel=Sa*Si > Da*Di ? Sc : Dc;
3185 case LuminizeCompositeOp:
3187 if (fabs((
double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
3192 if (fabs((
double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
3197 CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
3198 &hue,&chroma,&luma);
3199 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
3201 HCLComposite(hue,chroma,luma,&red,&green,&blue);
3204 case RedPixelChannel: pixel=red;
break;
3205 case GreenPixelChannel: pixel=green;
break;
3206 case BluePixelChannel: pixel=blue;
break;
3207 default: pixel=Dc;
break;
3211 case MathematicsCompositeOp:
3232 if (compose_sync == MagickFalse)
3234 pixel=geometry_info.rho*Sc*Dc+geometry_info.sigma*Sc+
3235 geometry_info.xi*Dc+geometry_info.psi;
3238 pixel=QuantumRange*gamma*(geometry_info.rho*Sca*Dca+
3239 geometry_info.sigma*Sca*Da+geometry_info.xi*Dca*Sa+
3240 geometry_info.psi*Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
3243 case MinusDstCompositeOp:
3245 if (compose_sync == MagickFalse)
3250 pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
3253 case MinusSrcCompositeOp:
3260 if (compose_sync == MagickFalse)
3265 pixel=gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
3268 case ModulateCompositeOp:
3273 if (fabs((
double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
3278 offset=(ssize_t) (Si-midpoint);
3284 CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
3285 &hue,&chroma,&luma);
3286 luma+=(0.01*percent_luma*offset)/midpoint;
3287 chroma*=0.01*percent_chroma;
3288 HCLComposite(hue,chroma,luma,&red,&green,&blue);
3291 case RedPixelChannel: pixel=red;
break;
3292 case GreenPixelChannel: pixel=green;
break;
3293 case BluePixelChannel: pixel=blue;
break;
3294 default: pixel=Dc;
break;
3298 case ModulusAddCompositeOp:
3300 if (compose_sync == MagickFalse)
3305 if ((Sca+Dca) <= 1.0)
3307 pixel=QuantumRange*(Sca+Dca);
3310 pixel=QuantumRange*((Sca+Dca)-1.0);
3313 case ModulusSubtractCompositeOp:
3315 if (compose_sync == MagickFalse)
3320 if ((Sca-Dca) >= 0.0)
3322 pixel=QuantumRange*(Sca-Dca);
3325 pixel=QuantumRange*((Sca-Dca)+1.0);
3328 case MultiplyCompositeOp:
3330 if (compose_sync == MagickFalse)
3332 pixel=QuantumScale*Dc*Sc;
3335 pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
3338 case NegateCompositeOp:
3340 pixel=QuantumRange*(1.0-fabs(1.0-Sca-Dca));
3343 case OutCompositeOp:
3344 case SrcOutCompositeOp:
3346 pixel=QuantumRange*(Sca*(1.0-Da));
3349 case OverCompositeOp:
3350 case SrcOverCompositeOp:
3352 pixel=QuantumRange*gamma*(Sca+Dca*(1.0-Sa));
3355 case OverlayCompositeOp:
3359 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*(1.0-
3363 pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
3367 case PegtopLightCompositeOp:
3377 if (fabs((
double) Da) < MagickEpsilon)
3379 pixel=QuantumRange*gamma*Sca;
3382 pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
3386 case PinLightCompositeOp:
3394 if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
3396 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
3399 if ((Dca*Sa) > (2.0*Sca*Da))
3401 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
3404 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
3407 case PlusCompositeOp:
3409 if (compose_sync == MagickFalse)
3414 pixel=QuantumRange*(Sca+Dca);
3417 case ReflectCompositeOp:
3419 pixel=QuantumRange*gamma*(Sca*Sca*PerceptibleReciprocal(1.0-Dca));
3420 if (pixel > QuantumRange)
3424 case RMSECompositeOp:
3429 if (fabs((
double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
3434 if (fabs((
double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
3440 (canvas_pixel.red-source_pixel.red)*
3441 (canvas_pixel.red-source_pixel.red)+
3442 (canvas_pixel.green-source_pixel.green)*
3443 (canvas_pixel.green-source_pixel.green)+
3444 (canvas_pixel.blue-source_pixel.blue)*
3445 (canvas_pixel.blue-source_pixel.blue)/3.0);
3448 case RedPixelChannel: pixel=gray;
break;
3449 case GreenPixelChannel: pixel=gray;
break;
3450 case BluePixelChannel: pixel=gray;
break;
3451 default: pixel=Dc;
break;
3455 case SaturateCompositeOp:
3457 if (fabs((
double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
3462 if (fabs((
double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
3467 CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
3468 &hue,&chroma,&luma);
3469 CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
3470 &sans,&chroma,&sans);
3471 HCLComposite(hue,chroma,luma,&red,&green,&blue);
3474 case RedPixelChannel: pixel=red;
break;
3475 case GreenPixelChannel: pixel=green;
break;
3476 case BluePixelChannel: pixel=blue;
break;
3477 default: pixel=Dc;
break;
3481 case ScreenCompositeOp:
3488 if (compose_sync == MagickFalse)
3493 pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
3496 case SoftBurnCompositeOp:
3498 if ((Sca+Dca) < 1.0)
3499 pixel=QuantumRange*gamma*(0.5*Dca*PerceptibleReciprocal(1.0-Sca));
3501 pixel=QuantumRange*gamma*(1.0-0.5*(1.0-Sca)*
3502 PerceptibleReciprocal(Dca));
3505 case SoftDodgeCompositeOp:
3507 if ((Sca+Dca) < 1.0)
3508 pixel=QuantumRange*gamma*(0.5*Sca*PerceptibleReciprocal(1.0-Dca));
3510 pixel=QuantumRange*gamma*(1.0-0.5*(1.0-Dca)*
3511 PerceptibleReciprocal(Sca));
3514 case SoftLightCompositeOp:
3518 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-DcaDa))+
3519 Sca*(1.0-Da)+Dca*(1.0-Sa));
3522 if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
3524 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*DcaDa*
3525 (4.0*DcaDa+1.0)*(DcaDa-1.0)+7.0*DcaDa)+Sca*(1.0-Da)+
3529 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow(DcaDa,0.5)-
3530 DcaDa)+Sca*(1.0-Da)+Dca*(1.0-Sa));
3533 case StampCompositeOp:
3535 pixel=QuantumRange*(Sca+Dca*Dca-1.0);
3538 case StereoCompositeOp:
3540 if (channel == RedPixelChannel)
3541 pixel=(MagickRealType) GetPixelRed(source_image,p);
3544 case ThresholdCompositeOp:
3550 if ((MagickRealType) fabs((
double) (2.0*delta)) < threshold)
3555 pixel=gamma*(Dc+delta*amount);
3558 case VividLightCompositeOp:
3566 if ((fabs((
double) Sa) < MagickEpsilon) ||
3567 (fabs((
double) (Sca-Sa)) < MagickEpsilon))
3569 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
3572 if ((2.0*Sca) <= Sa)
3574 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)*
3575 PerceptibleReciprocal(2.0*Sca))+Sca*(1.0-Da)+Dca*(1.0-Sa));
3578 pixel=QuantumRange*gamma*(Dca*Sa*Sa*PerceptibleReciprocal(2.0*
3579 (Sa-Sca))+Sca*(1.0-Da)+Dca*(1.0-Sa));
3582 case XorCompositeOp:
3584 pixel=QuantumRange*(Sca*(1.0-Da)+Dca*(1.0-Sa));
3593 q[i]=clamp != MagickFalse ? ClampPixel(pixel) : ClampToQuantum(pixel);
3595 p+=GetPixelChannels(source_image);
3596 channels=GetPixelChannels(source_image);
3597 if (p >= (pixels+channels*source_image->columns))
3599 q+=GetPixelChannels(image);
3601 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3603 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3608 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3612 proceed=SetImageProgress(image,CompositeImageTag,progress,image->rows);
3613 if (proceed == MagickFalse)
3617 source_view=DestroyCacheView(source_view);
3618 image_view=DestroyCacheView(image_view);
3619 if (canvas_image != (
Image * ) NULL)
3620 canvas_image=DestroyImage(canvas_image);
3622 source_image=DestroyImage(source_image);
3652 MagickExport MagickBooleanType TextureImage(
Image *image,
const Image *texture,
3655 #define TextureImageTag "Texture/Image"
3670 assert(image != (
Image *) NULL);
3671 assert(image->signature == MagickCoreSignature);
3672 if (IsEventLogging() != MagickFalse)
3673 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
3674 if (texture == (
const Image *) NULL)
3675 return(MagickFalse);
3676 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
3677 return(MagickFalse);
3678 texture_image=CloneImage(texture,0,0,MagickTrue,exception);
3679 if (texture_image == (
const Image *) NULL)
3680 return(MagickFalse);
3681 (void) TransformImageColorspace(texture_image,image->colorspace,exception);
3682 (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
3685 if ((image->compose != CopyCompositeOp) &&
3686 ((image->compose != OverCompositeOp) ||
3687 (image->alpha_trait != UndefinedPixelTrait) ||
3688 (texture_image->alpha_trait != UndefinedPixelTrait)))
3693 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
3698 if (status == MagickFalse)
3700 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
3705 thread_status=CompositeImage(image,texture_image,image->compose,
3706 MagickTrue,x+texture_image->tile_offset.x,y+
3707 texture_image->tile_offset.y,exception);
3708 if (thread_status == MagickFalse)
3710 status=thread_status;
3714 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3719 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
3721 if (proceed == MagickFalse)
3725 (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
3726 image->rows,image->rows);
3727 texture_image=DestroyImage(texture_image);
3734 texture_view=AcquireVirtualCacheView(texture_image,exception);
3735 image_view=AcquireAuthenticCacheView(image,exception);
3736 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3737 #pragma omp parallel for schedule(static) shared(status) \
3738 magick_number_threads(texture_image,image,image->rows,1)
3740 for (y=0; y < (ssize_t) image->rows; y++)
3758 if (status == MagickFalse)
3760 pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
3761 (y+texture_image->tile_offset.y) % texture_image->rows,
3762 texture_image->columns,1,exception);
3763 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3764 if ((pixels == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3769 for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
3775 width=texture_image->columns;
3776 if ((x+(ssize_t) width) > (ssize_t) image->columns)
3777 width=image->columns-x;
3778 for (j=0; j < (ssize_t) width; j++)
3783 for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
3785 PixelChannel channel = GetPixelChannelChannel(texture_image,i);
3786 PixelTrait traits = GetPixelChannelTraits(image,channel);
3787 PixelTrait texture_traits=GetPixelChannelTraits(texture_image,
3789 if ((traits == UndefinedPixelTrait) ||
3790 (texture_traits == UndefinedPixelTrait))
3792 SetPixelChannel(image,channel,p[i],q);
3794 p+=GetPixelChannels(texture_image);
3795 q+=GetPixelChannels(image);
3798 sync=SyncCacheViewAuthenticPixels(image_view,exception);
3799 if (sync == MagickFalse)
3801 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3806 proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
3808 if (proceed == MagickFalse)
3812 texture_view=DestroyCacheView(texture_view);
3813 image_view=DestroyCacheView(image_view);
3814 texture_image=DestroyImage(texture_image);