MagickCore  7.1.0
composite.c
Go to the documentation of this file.
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % CCCC OOO M M PPPP OOO SSSSS IIIII TTTTT EEEEE %
7 % C O O MM MM P P O O SS I T E %
8 % C O O M M M PPPP O O SSS I T EEE %
9 % C O O M M P O O SS I T E %
10 % CCCC OOO M M P OOO SSSSS IIIII T EEEEE %
11 % %
12 % %
13 % MagickCore Image Composite Methods %
14 % %
15 % Software Design %
16 % Cristy %
17 % July 1992 %
18 % %
19 % %
20 % Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 %
38 */
39 
40 /*
41  Include declarations.
42 */
43 #include "MagickCore/studio.h"
44 #include "MagickCore/artifact.h"
45 #include "MagickCore/cache.h"
47 #include "MagickCore/cache-view.h"
48 #include "MagickCore/channel.h"
49 #include "MagickCore/client.h"
50 #include "MagickCore/color.h"
52 #include "MagickCore/colorspace.h"
54 #include "MagickCore/composite.h"
56 #include "MagickCore/constitute.h"
57 #include "MagickCore/draw.h"
59 #include "MagickCore/fx.h"
60 #include "MagickCore/gem.h"
61 #include "MagickCore/geometry.h"
62 #include "MagickCore/image.h"
64 #include "MagickCore/list.h"
65 #include "MagickCore/log.h"
66 #include "MagickCore/memory_.h"
67 #include "MagickCore/monitor.h"
69 #include "MagickCore/morphology.h"
70 #include "MagickCore/option.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"
78 #include "MagickCore/threshold.h"
79 #include "MagickCore/token.h"
80 #include "MagickCore/transform.h"
81 #include "MagickCore/utility.h"
83 #include "MagickCore/version.h"
84 
85 /*
86 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
87 % %
88 % %
89 % %
90 % C o m p o s i t e I m a g e %
91 % %
92 % %
93 % %
94 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
95 %
96 % CompositeImage() returns the second image composited onto the first
97 % at the specified offset, using the specified composite method.
98 %
99 % The format of the CompositeImage method is:
100 %
101 % MagickBooleanType CompositeImage(Image *image,
102 % const Image *source_image,const CompositeOperator compose,
103 % const MagickBooleanType clip_to_self,const ssize_t x_offset,
104 % const ssize_t y_offset,ExceptionInfo *exception)
105 %
106 % A description of each parameter follows:
107 %
108 % o image: the canvas image, modified by he composition
109 %
110 % o source_image: the source image.
111 %
112 % o compose: This operator affects how the composite is applied to
113 % the image. The operators and how they are utilized are listed here
114 % http://www.w3.org/TR/SVG12/#compositing.
115 %
116 % o clip_to_self: set to MagickTrue to limit composition to area composed.
117 %
118 % o x_offset: the column offset of the composited image.
119 %
120 % o y_offset: the row offset of the composited image.
121 %
122 % Extra Controls from Image meta-data in 'image' (artifacts)
123 %
124 % o "compose:args"
125 % A string containing extra numerical arguments for specific compose
126 % methods, generally expressed as a 'geometry' or a comma separated list
127 % of numbers.
128 %
129 % Compose methods needing such arguments include "BlendCompositeOp" and
130 % "DisplaceCompositeOp".
131 %
132 % o exception: return any errors or warnings in this structure.
133 %
134 */
135 
136 /*
137  Composition based on the SVG specification:
138 
139  A Composition is defined by...
140  Color Function : f(Sc,Dc) where Sc and Dc are the normizalized colors
141  Blending areas : X = 1 for area of overlap, ie: f(Sc,Dc)
142  Y = 1 for source preserved
143  Z = 1 for canvas preserved
144 
145  Conversion to transparency (then optimized)
146  Dca' = f(Sc, Dc)*Sa*Da + Y*Sca*(1-Da) + Z*Dca*(1-Sa)
147  Da' = X*Sa*Da + Y*Sa*(1-Da) + Z*Da*(1-Sa)
148 
149  Where...
150  Sca = Sc*Sa normalized Source color divided by Source alpha
151  Dca = Dc*Da normalized Dest color divided by Dest alpha
152  Dc' = Dca'/Da' the desired color value for this channel.
153 
154  Da' in in the follow formula as 'gamma' The resulting alpla value.
155 
156  Most functions use a blending mode of over (X=1,Y=1,Z=1) this results in
157  the following optimizations...
158  gamma = Sa+Da-Sa*Da;
159  gamma = 1 - QuantumScale*alpha * QuantumScale*beta;
160  opacity = QuantumScale*alpha*beta; // over blend, optimized 1-Gamma
161 
162  The above SVG definitions also define that Mathematical Composition
163  methods should use a 'Over' blending mode for Alpha Channel.
164  It however was not applied for composition modes of 'Plus', 'Minus',
165  the modulus versions of 'Add' and 'Subtract'.
166 
167  Mathematical operator changes to be applied from IM v6.7...
168 
169  1) Modulus modes 'Add' and 'Subtract' are obsoleted and renamed
170  'ModulusAdd' and 'ModulusSubtract' for clarity.
171 
172  2) All mathematical compositions work as per the SVG specification
173  with regard to blending. This now includes 'ModulusAdd' and
174  'ModulusSubtract'.
175 
176  3) When the special channel flag 'sync' (syncronize channel updates)
177  is turned off (enabled by default) then mathematical compositions are
178  only performed on the channels specified, and are applied
179  independantally of each other. In other words the mathematics is
180  performed as 'pure' mathematical operations, rather than as image
181  operations.
182 */
183 
184 static Image *BlendConvolveImage(const Image *image,const char *kernel,
185  ExceptionInfo *exception)
186 {
187  Image
188  *clone_image,
189  *convolve_image;
190 
191  KernelInfo
192  *kernel_info;
193 
194  /*
195  Convolve image with a kernel.
196  */
197  kernel_info=AcquireKernelInfo(kernel,exception);
198  if (kernel_info == (KernelInfo *) NULL)
199  return((Image *) NULL);
200  clone_image=CloneImage(image,0,0,MagickTrue,exception);
201  if (clone_image == (Image *) NULL)
202  {
203  kernel_info=DestroyKernelInfo(kernel_info);
204  return((Image *) NULL);
205  }
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);
211 }
212 
213 static Image *BlendMagnitudeImage(const Image *dx_image,const Image *dy_image,
214  ExceptionInfo *exception)
215 {
216  CacheView
217  *dx_view,
218  *dy_view,
219  *magnitude_view;
220 
221  Image
222  *magnitude_image;
223 
225  status = MagickTrue;
226 
227  ssize_t
228  y;
229 
230  /*
231  Generate the magnitude between two images.
232  */
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)
242 #endif
243  for (y=0; y < (ssize_t) dx_image->rows; y++)
244  {
245  const Quantum
246  *magick_restrict p,
247  *magick_restrict q;
248 
249  Quantum
250  *magick_restrict r;
251 
252  ssize_t
253  x;
254 
255  if (status == MagickFalse)
256  continue;
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,
260  exception);
261  if ((p == (const Quantum *) NULL) || (q == (const Quantum *) NULL) ||
262  (r == (Quantum *) NULL))
263  {
264  status=MagickFalse;
265  continue;
266  }
267  for (x=0; x < (ssize_t) dx_image->columns; x++)
268  {
269  ssize_t
270  i;
271 
272  for (i=0; i < (ssize_t) GetPixelChannels(dx_image); i++)
273  {
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))
280  continue;
281  r[i]=ClampToQuantum(hypot((double) p[i],(double)
282  GetPixelChannel(dy_image,channel,q)));
283  }
284  p+=GetPixelChannels(dx_image);
285  q+=GetPixelChannels(dy_image);
286  r+=GetPixelChannels(magnitude_image);
287  }
288  if (SyncCacheViewAuthenticPixels(magnitude_view,exception) == MagickFalse)
289  status=MagickFalse;
290  }
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);
297 }
298 
299 static Image *BlendMaxMagnitudeImage(const Image *alpha_image,
300  const Image *beta_image,const Image *dx_image,const Image *dy_image,
301  ExceptionInfo *exception)
302 {
303  CacheView
304  *alpha_view,
305  *beta_view,
306  *dx_view,
307  *dy_view,
308  *magnitude_view;
309 
310  Image
311  *magnitude_image;
312 
314  status = MagickTrue;
315 
316  ssize_t
317  y;
318 
319  /*
320  Select the larger of two magnitudes.
321  */
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)
333 #endif
334  for (y=0; y < (ssize_t) alpha_image->rows; y++)
335  {
336  const Quantum
337  *magick_restrict p,
338  *magick_restrict q,
339  *magick_restrict r,
340  *magick_restrict s;
341 
342  Quantum
343  *magick_restrict t;
344 
345  ssize_t
346  x;
347 
348  if (status == MagickFalse)
349  continue;
350  p=GetCacheViewVirtualPixels(alpha_view,0,y,alpha_image->columns,1,
351  exception);
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,
356  exception);
357  if ((p == (const Quantum *) NULL) || (q == (const Quantum *) NULL) ||
358  (r == (const Quantum *) NULL) || (s == (const Quantum *) NULL) ||
359  (t == (Quantum *) NULL))
360  {
361  status=MagickFalse;
362  continue;
363  }
364  for (x=0; x < (ssize_t) alpha_image->columns; x++)
365  {
366  ssize_t
367  i;
368 
369  for (i=0; i < (ssize_t) GetPixelChannels(alpha_image); i++)
370  {
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))
377  continue;
378  if (p[i] > GetPixelChannel(beta_image,channel,q))
379  t[i]=GetPixelChannel(dx_image,channel,r);
380  else
381  t[i]=GetPixelChannel(dy_image,channel,s);
382  }
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);
388  }
389  if (SyncCacheViewAuthenticPixels(magnitude_view,exception) == MagickFalse)
390  status=MagickFalse;
391  }
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);
400 }
401 
402 static Image *BlendSumImage(const Image *alpha_image,const Image *beta_image,
403  const double attenuate,const double sign,ExceptionInfo *exception)
404 {
405  CacheView
406  *alpha_view,
407  *beta_view,
408  *sum_view;
409 
410  Image
411  *sum_image;
412 
414  status = MagickTrue;
415 
416  ssize_t
417  y;
418 
419  /*
420  Add or subtract and optionally attenuate two images.
421  */
422  sum_image=CloneImage(alpha_image,0,0,MagickTrue,exception);
423  if (sum_image == (Image *) NULL)
424  return(sum_image);
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)
431 #endif
432  for (y=0; y < (ssize_t) alpha_image->rows; y++)
433  {
434  const Quantum
435  *magick_restrict p,
436  *magick_restrict q;
437 
438  Quantum
439  *magick_restrict r;
440 
441  ssize_t
442  x;
443 
444  if (status == MagickFalse)
445  continue;
446  p=GetCacheViewVirtualPixels(alpha_view,0,y,alpha_image->columns,1,
447  exception);
448  q=GetCacheViewVirtualPixels(beta_view,0,y,alpha_image->columns,1,exception);
449  r=GetCacheViewAuthenticPixels(sum_view,0,y,alpha_image->columns,1,
450  exception);
451  if ((p == (const Quantum *) NULL) || (q == (const Quantum *) NULL) ||
452  (r == (Quantum *) NULL))
453  {
454  status=MagickFalse;
455  continue;
456  }
457  for (x=0; x < (ssize_t) alpha_image->columns; x++)
458  {
459  ssize_t
460  i;
461 
462  for (i=0; i < (ssize_t) GetPixelChannels(alpha_image); i++)
463  {
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))
470  continue;
471  r[i]=ClampToQuantum(attenuate*(p[i]+sign*
472  GetPixelChannel(beta_image,channel,q)));
473  }
474  p+=GetPixelChannels(alpha_image);
475  q+=GetPixelChannels(beta_image);
476  r+=GetPixelChannels(sum_image);
477  }
478  if (SyncCacheViewAuthenticPixels(sum_view,exception) == MagickFalse)
479  status=MagickFalse;
480  }
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);
486  return(sum_image);
487 }
488 
489 static Image *BlendDivergentImage(const Image *alpha_image,
490  const Image *beta_image,ExceptionInfo *exception)
491 {
492 #define FreeDivergentResources() \
493 { \
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); \
510 }
511 
512  Image
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;
524 
525  /*
526  Create X and Y gradient images for alpha image and the magnitude.
527  */
528  dx_alpha=BlendConvolveImage(alpha_image,"3x1:-0.5,0.0,0.5",exception);
529  if (dx_alpha == (Image *) NULL)
530  {
532  return((Image *) NULL);
533  }
534  dy_alpha=BlendConvolveImage(alpha_image,"1x3:-0.5,0.0,0.5",exception);
535  if (dy_alpha == (Image *) NULL)
536  {
538  return((Image *) NULL);
539  }
540  magnitude_alpha=BlendMagnitudeImage(dx_alpha,dy_alpha,exception);
541  if (magnitude_alpha == (Image *) NULL)
542  {
544  return((Image *) NULL);
545  }
546  /*
547  Create X and Y gradient images for beta and the magnitude.
548  */
549  dx_beta=BlendConvolveImage(beta_image,"3x1:-0.5,0.0,0.5",exception);
550  if (dx_beta == (Image *) NULL)
551  {
553  return((Image *) NULL);
554  }
555  dy_beta=BlendConvolveImage(beta_image,"1x3:-0.5,0.0,0.5",exception);
556  if (dy_beta == (Image *) NULL)
557  {
559  return((Image *) NULL);
560  }
561  magnitude_beta=BlendMagnitudeImage(dx_beta,dy_beta,exception);
562  if (magnitude_beta == (Image *) NULL)
563  {
565  return((Image *) NULL);
566  }
567  /*
568  Select alpha or beta gradient for larger of two magnitudes.
569  */
570  dx_image=BlendMaxMagnitudeImage(magnitude_alpha,magnitude_beta,dx_alpha,
571  dx_beta,exception);
572  if (dx_image == (Image *) NULL)
573  {
575  return((Image *) NULL);
576  }
577  dy_image=BlendMaxMagnitudeImage(magnitude_alpha,magnitude_beta,dy_alpha,
578  dy_beta,exception);
579  if (dy_image == (Image *) NULL)
580  {
582  return((Image *) NULL);
583  }
584  dx_beta=DestroyImage(dx_beta);
585  dx_alpha=DestroyImage(dx_alpha);
586  magnitude_beta=DestroyImage(magnitude_beta);
587  magnitude_alpha=DestroyImage(magnitude_alpha);
588  /*
589  Create divergence of gradients dx and dy and divide by 4 as guide image.
590  */
591  dx_divergent=BlendConvolveImage(dx_image,"3x1:-0.5,0.0,0.5",exception);
592  if (dx_divergent == (Image *) NULL)
593  {
595  return((Image *) NULL);
596  }
597  dy_divergent=BlendConvolveImage(dy_image,"1x3:-0.5,0.0,0.5",exception);
598  if (dy_divergent == (Image *) NULL)
599  {
601  return((Image *) NULL);
602  }
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)
607  {
609  return((Image *) NULL);
610  }
612  return(divergent_image);
613 }
614 
616  const Image *mask_image,ExceptionInfo *exception)
617 {
618  CacheView
619  *image_view,
620  *mask_view;
621 
623  status = MagickTrue;
624 
625  ssize_t
626  y;
627 
628  /*
629  Threshold the alpha channel.
630  */
631  if (SetImageAlpha(image,OpaqueAlpha,exception) == MagickFalse)
632  return(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)
638 #endif
639  for (y=0; y < (ssize_t) image->rows; y++)
640  {
641  const Quantum
642  *magick_restrict p;
643 
644  Quantum
645  *magick_restrict q;
646 
647  ssize_t
648  x;
649 
650  if (status == MagickFalse)
651  continue;
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))
655  {
656  status=MagickFalse;
657  continue;
658  }
659  for (x=0; x < (ssize_t) image->columns; x++)
660  {
661  Quantum
662  alpha = GetPixelAlpha(mask_image,p);
663 
664  ssize_t
666 
667  if (fabs((double) alpha) >= MagickEpsilon)
668  q[i]=(Quantum) 0;
669  p+=GetPixelChannels(mask_image);
670  q+=GetPixelChannels(image);
671  }
672  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
673  status=MagickFalse;
674  }
675  mask_view=DestroyCacheView(mask_view);
676  image_view=DestroyCacheView(image_view);
677  return(status);
678 }
679 
680 static Image *BlendMeanImage(Image *image,const Image *mask_image,
681  ExceptionInfo *exception)
682 {
683  CacheView
684  *alpha_view,
685  *mask_view,
686  *mean_view;
687 
688  double
689  mean[MaxPixelChannels];
690 
691  Image
692  *mean_image;
693 
695  status = MagickTrue;
696 
697  ssize_t
698  j,
699  y;
700 
701  /*
702  Compute the mean of the image.
703  */
704  (void) memset(mean,0,MaxPixelChannels*sizeof(*mean));
705  alpha_view=AcquireVirtualCacheView(image,exception);
706  for (y=0; y < (ssize_t) image->rows; y++)
707  {
708  const Quantum
709  *magick_restrict p;
710 
711  ssize_t
712  x;
713 
714  p=GetCacheViewVirtualPixels(alpha_view,0,y,image->columns,1,
715  exception);
716  if (p == (const Quantum *) NULL)
717  break;
718  for (x=0; x < (ssize_t) image->columns; x++)
719  {
720  ssize_t
721  i;
722 
723  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
724  {
725  PixelChannel channel = GetPixelChannelChannel(image,i);
726  PixelTrait traits = GetPixelChannelTraits(image,channel);
727  if (traits == UndefinedPixelTrait)
728  continue;
729  mean[i]+=QuantumScale*p[i];
730  }
731  p+=GetPixelChannels(image);
732  }
733  }
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/
739  image->rows;
740  /*
741  Replace any unmasked pixels with the mean pixel.
742  */
743  mean_image=CloneImage(image,0,0,MagickTrue,exception);
744  if (mean_image == (Image *) NULL)
745  return(mean_image);
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)
751 #endif
752  for (y=0; y < (ssize_t) mean_image->rows; y++)
753  {
754  const Quantum
755  *magick_restrict p;
756 
757  Quantum
758  *magick_restrict q;
759 
760  ssize_t
761  x;
762 
763  if (status == MagickFalse)
764  continue;
765  p=GetCacheViewVirtualPixels(mask_view,0,y,mean_image->columns,1,exception);
766  q=GetCacheViewAuthenticPixels(mean_view,0,y,mean_image->columns,1,
767  exception);
768  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
769  {
770  status=MagickFalse;
771  continue;
772  }
773  for (x=0; x < (ssize_t) mean_image->columns; x++)
774  {
775  Quantum
776  alpha = GetPixelAlpha(mask_image,p),
777  mask = GetPixelReadMask(mask_image,p);
778 
779  ssize_t
780  i;
781 
782  for (i=0; i < (ssize_t) GetPixelChannels(mean_image); i++)
783  {
784  PixelChannel channel = GetPixelChannelChannel(mean_image,i);
785  PixelTrait traits = GetPixelChannelTraits(mean_image,channel);
786  if (traits == UndefinedPixelTrait)
787  continue;
788  if (mask <= (QuantumRange/2))
789  q[i]=(Quantum) 0;
790  else
791  if (fabs((double) alpha) >= MagickEpsilon)
792  q[i]=ClampToQuantum(mean[i]);
793  }
794  p+=GetPixelChannels(mask_image);
795  q+=GetPixelChannels(mean_image);
796  }
797  if (SyncCacheViewAuthenticPixels(mean_view,exception) == MagickFalse)
798  status=MagickFalse;
799  }
800  mask_view=DestroyCacheView(mask_view);
801  mean_view=DestroyCacheView(mean_view);
802  if (status == MagickFalse)
803  mean_image=DestroyImage(mean_image);
804  return(mean_image);
805 }
806 
807 static MagickBooleanType BlendRMSEResidual(const Image *alpha_image,
808  const Image *beta_image,double *residual,ExceptionInfo *exception)
809 {
810  CacheView
811  *alpha_view,
812  *beta_view;
813 
814  double
815  area = 0.0;
816 
818  status = MagickTrue;
819 
820  size_t
821  columns = MagickMax(alpha_image->columns,beta_image->columns),
822  rows = MagickMax(alpha_image->rows,beta_image->rows);
823 
824  ssize_t
825  y;
826 
827  *residual=0.0;
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)
833 #endif
834  for (y=0; y < (ssize_t) rows; y++)
835  {
836  const Quantum
837  *magick_restrict p,
838  *magick_restrict q;
839 
840  double
841  channel_residual;
842 
843  size_t
844  local_area = 0;
845 
846  ssize_t
847  x;
848 
849  if (status == MagickFalse)
850  continue;
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))
854  {
855  status=MagickFalse;
856  continue;
857  }
858  channel_residual=0.0;
859  for (x=0; x < (ssize_t) columns; x++)
860  {
861  double
862  Da,
863  Sa;
864 
865  ssize_t
866  i;
867 
868  if ((GetPixelReadMask(alpha_image,p) <= (QuantumRange/2)) ||
869  (GetPixelReadMask(beta_image,q) <= (QuantumRange/2)))
870  {
871  p+=GetPixelChannels(alpha_image);
872  q+=GetPixelChannels(beta_image);
873  continue;
874  }
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++)
878  {
879  double
880  distance;
881 
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))
888  continue;
889  if (channel == AlphaPixelChannel)
890  distance=QuantumScale*(p[i]-GetPixelChannel(beta_image,channel,q));
891  else
892  distance=QuantumScale*(Sa*p[i]-Da*GetPixelChannel(beta_image,channel,
893  q));
894  channel_residual+=distance*distance;
895  }
896  local_area++;
897  p+=GetPixelChannels(alpha_image);
898  q+=GetPixelChannels(beta_image);
899  }
900 #if defined(MAGICKCORE_OPENMP_SUPPORT)
901  #pragma omp critical (MagickCore_BlendRMSEResidual)
902 #endif
903  {
904  area+=local_area;
905  *residual+=channel_residual;
906  }
907  }
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));
912  return(status);
913 }
914 
915 static void CompositeHCL(const MagickRealType red,const MagickRealType green,
916  const MagickRealType blue,MagickRealType *hue,MagickRealType *chroma,
917  MagickRealType *luma)
918 {
920  b,
921  c,
922  g,
923  h,
924  max,
925  r;
926 
927  /*
928  Convert RGB to HCL colorspace.
929  */
930  assert(hue != (MagickRealType *) NULL);
931  assert(chroma != (MagickRealType *) NULL);
932  assert(luma != (MagickRealType *) NULL);
933  r=red;
934  g=green;
935  b=blue;
936  max=MagickMax(r,MagickMax(g,b));
937  c=max-(MagickRealType) MagickMin(r,MagickMin(g,b));
938  h=0.0;
939  if (c == 0)
940  h=0.0;
941  else
942  if (red == max)
943  h=fmod((g-b)/c+6.0,6.0);
944  else
945  if (green == max)
946  h=((b-r)/c)+2.0;
947  else
948  if (blue == max)
949  h=((r-g)/c)+4.0;
950  *hue=(h/6.0);
951  *chroma=QuantumScale*c;
952  *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
953 }
954 
956  const Image *source_image,const MagickBooleanType clip_to_self,
957  const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
958 {
959 #define CompositeImageTag "Composite/Image"
960 
961  CacheView
962  *image_view,
963  *source_view;
964 
965  const char
966  *value;
967 
969  clamp,
970  status;
971 
973  progress;
974 
975  ssize_t
976  y;
977 
978  /*
979  Composite image.
980  */
981  status=MagickTrue;
982  progress=0;
983  clamp=MagickTrue;
984  value=GetImageArtifact(image,"compose:clamp");
985  if (value != (const char *) NULL)
986  clamp=IsStringTrue(value);
987  status=MagickTrue;
988  progress=0;
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)
994 #endif
995  for (y=0; y < (ssize_t) image->rows; y++)
996  {
997  const Quantum
998  *pixels;
999 
1000  PixelInfo
1001  canvas_pixel,
1002  source_pixel;
1003 
1004  const Quantum
1005  *magick_restrict p;
1006 
1007  Quantum
1008  *magick_restrict q;
1009 
1010  ssize_t
1011  x;
1012 
1013  if (status == MagickFalse)
1014  continue;
1015  if (clip_to_self != MagickFalse)
1016  {
1017  if (y < y_offset)
1018  continue;
1019  if ((y-y_offset) >= (ssize_t) source_image->rows)
1020  continue;
1021  }
1022  /*
1023  If pixels is NULL, y is outside overlay region.
1024  */
1025  pixels=(Quantum *) NULL;
1026  p=(Quantum *) NULL;
1027  if ((y >= y_offset) && ((y-y_offset) < (ssize_t) source_image->rows))
1028  {
1029  p=GetCacheViewVirtualPixels(source_view,0,y-y_offset,
1030  source_image->columns,1,exception);
1031  if (p == (const Quantum *) NULL)
1032  {
1033  status=MagickFalse;
1034  continue;
1035  }
1036  pixels=p;
1037  if (x_offset < 0)
1038  p-=x_offset*(ssize_t) GetPixelChannels(source_image);
1039  }
1040  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1041  if (q == (Quantum *) NULL)
1042  {
1043  status=MagickFalse;
1044  continue;
1045  }
1046  GetPixelInfo(image,&canvas_pixel);
1047  GetPixelInfo(source_image,&source_pixel);
1048  for (x=0; x < (ssize_t) image->columns; x++)
1049  {
1050  double
1051  gamma;
1052 
1054  alpha,
1055  Da,
1056  Dc,
1057  Dca,
1058  Sa,
1059  Sc,
1060  Sca;
1061 
1062  ssize_t
1063  i;
1064 
1065  size_t
1066  channels;
1067 
1068  if (clip_to_self != MagickFalse)
1069  {
1070  if (x < x_offset)
1071  {
1072  q+=GetPixelChannels(image);
1073  continue;
1074  }
1075  if ((x-x_offset) >= (ssize_t) source_image->columns)
1076  break;
1077  }
1078  if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1079  ((x-x_offset) >= (ssize_t) source_image->columns))
1080  {
1081  Quantum
1082  source[MaxPixelChannels];
1083 
1084  /*
1085  Virtual composite:
1086  Sc: source color.
1087  Dc: canvas color.
1088  */
1089  (void) GetOneVirtualPixel(source_image,x-x_offset,y-y_offset,source,
1090  exception);
1091  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1092  {
1094  pixel;
1095 
1096  PixelChannel channel = GetPixelChannelChannel(image,i);
1097  PixelTrait traits = GetPixelChannelTraits(image,channel);
1098  PixelTrait source_traits=GetPixelChannelTraits(source_image,
1099  channel);
1100  if ((traits == UndefinedPixelTrait) ||
1101  (source_traits == UndefinedPixelTrait))
1102  continue;
1103  if (channel == AlphaPixelChannel)
1105  else
1106  pixel=(MagickRealType) q[i];
1107  q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
1108  ClampToQuantum(pixel);
1109  }
1110  q+=GetPixelChannels(image);
1111  continue;
1112  }
1113  /*
1114  Authentic composite:
1115  Sa: normalized source alpha.
1116  Da: normalized canvas alpha.
1117  */
1118  Sa=QuantumScale*GetPixelAlpha(source_image,p);
1119  Da=QuantumScale*GetPixelAlpha(image,q);
1120  alpha=Sa+Da-Sa*Da;
1121  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1122  {
1124  pixel;
1125 
1126  PixelChannel channel = GetPixelChannelChannel(image,i);
1127  PixelTrait traits = GetPixelChannelTraits(image,channel);
1128  PixelTrait source_traits=GetPixelChannelTraits(source_image,channel);
1129  if (traits == UndefinedPixelTrait)
1130  continue;
1131  if ((source_traits == UndefinedPixelTrait) &&
1132  (channel != AlphaPixelChannel))
1133  continue;
1134  if (channel == AlphaPixelChannel)
1135  {
1136  /*
1137  Set alpha channel.
1138  */
1139  pixel=QuantumRange*alpha;
1140  q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
1141  ClampToQuantum(pixel);
1142  continue;
1143  }
1144  /*
1145  Sc: source color.
1146  Dc: canvas color.
1147  */
1148  Sc=(MagickRealType) GetPixelChannel(source_image,channel,p);
1149  Dc=(MagickRealType) q[i];
1150  if ((traits & CopyPixelTrait) != 0)
1151  {
1152  /*
1153  Copy channel.
1154  */
1155  q[i]=ClampToQuantum(Sc);
1156  continue;
1157  }
1158  /*
1159  Porter-Duff compositions:
1160  Sca: source normalized color multiplied by alpha.
1161  Dca: normalized canvas color multiplied by alpha.
1162  */
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);
1168  }
1169  p+=GetPixelChannels(source_image);
1170  channels=GetPixelChannels(source_image);
1171  if (p >= (pixels+channels*source_image->columns))
1172  p=pixels;
1173  q+=GetPixelChannels(image);
1174  }
1175  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1176  status=MagickFalse;
1177  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1178  {
1180  proceed;
1181 
1182 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1183  #pragma omp atomic
1184 #endif
1185  progress++;
1186  proceed=SetImageProgress(image,CompositeImageTag,progress,image->rows);
1187  if (proceed == MagickFalse)
1188  status=MagickFalse;
1189  }
1190  }
1191  source_view=DestroyCacheView(source_view);
1192  image_view=DestroyCacheView(image_view);
1193  return(status);
1194 }
1195 
1196 static void HCLComposite(const MagickRealType hue,const MagickRealType chroma,
1197  const MagickRealType luma,MagickRealType *red,MagickRealType *green,
1198  MagickRealType *blue)
1199 {
1201  b,
1202  c,
1203  g,
1204  h,
1205  m,
1206  r,
1207  x;
1208 
1209  /*
1210  Convert HCL to RGB colorspace.
1211  */
1212  assert(red != (MagickRealType *) NULL);
1213  assert(green != (MagickRealType *) NULL);
1214  assert(blue != (MagickRealType *) NULL);
1215  h=6.0*hue;
1216  c=chroma;
1217  x=c*(1.0-fabs(fmod(h,2.0)-1.0));
1218  r=0.0;
1219  g=0.0;
1220  b=0.0;
1221  if ((0.0 <= h) && (h < 1.0))
1222  {
1223  r=c;
1224  g=x;
1225  }
1226  else
1227  if ((1.0 <= h) && (h < 2.0))
1228  {
1229  r=x;
1230  g=c;
1231  }
1232  else
1233  if ((2.0 <= h) && (h < 3.0))
1234  {
1235  g=c;
1236  b=x;
1237  }
1238  else
1239  if ((3.0 <= h) && (h < 4.0))
1240  {
1241  g=x;
1242  b=c;
1243  }
1244  else
1245  if ((4.0 <= h) && (h < 5.0))
1246  {
1247  r=x;
1248  b=c;
1249  }
1250  else
1251  if ((5.0 <= h) && (h < 6.0))
1252  {
1253  r=c;
1254  b=x;
1255  }
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);
1260 }
1261 
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,
1265  ExceptionInfo *exception)
1266 {
1267  Image
1268  *crop_image,
1269  *divergent_image,
1270  *relax_image,
1271  *residual_image = (Image *) NULL;
1272 
1273  KernelInfo
1274  *kernel_info;
1275 
1277  status = MagickTrue,
1278  verbose = MagickFalse;
1279 
1281  crop_info = {
1282  source_image->columns,
1283  source_image->rows,
1284  x_offset,
1285  y_offset
1286  };
1287 
1288  ssize_t
1289  i;
1290 
1291  /*
1292  Saliency blend composite operator.
1293  */
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)
1300  {
1301  crop_image=DestroyImage(crop_image);
1302  return(MagickFalse);
1303  }
1304  (void) ResetImagePage(crop_image,"0x0+0+0");
1305  relax_image=BlendMeanImage(crop_image,source_image,exception);
1306  if (relax_image == (Image *) NULL)
1307  {
1308  crop_image=DestroyImage(crop_image);
1309  divergent_image=DestroyImage(divergent_image);
1310  return(MagickFalse);
1311  }
1312  status=BlendMaskAlphaChannel(crop_image,source_image,exception);
1313  if (status == MagickFalse)
1314  {
1315  crop_image=DestroyImage(crop_image);
1316  divergent_image=DestroyImage(divergent_image);
1317  return(MagickFalse);
1318  }
1319  residual_image=CloneImage(relax_image,0,0,MagickTrue,exception);
1320  if (residual_image == (Image *) NULL)
1321  {
1322  crop_image=DestroyImage(crop_image);
1323  relax_image=DestroyImage(relax_image);
1324  return(MagickFalse);
1325  }
1326  /*
1327  Convolve relaxed image and blur area of interest.
1328  */
1329  kernel_info=AcquireKernelInfo("3x3:0,0.25,0,0.25,0,0.25,0,0.25,0",exception);
1330  if (kernel_info == (KernelInfo *) NULL)
1331  {
1332  crop_image=DestroyImage(crop_image);
1333  residual_image=DestroyImage(residual_image);
1334  relax_image=DestroyImage(relax_image);
1335  return(MagickFalse);
1336  }
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++)
1341  {
1342  double
1343  residual = 1.0;
1344 
1345  Image
1346  *convolve_image,
1347  *sum_image;
1348 
1349  convolve_image=ConvolveImage(relax_image,kernel_info,exception);
1350  if (convolve_image == (Image *) NULL)
1351  break;
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)
1356  break;
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)
1361  break;
1362  status=BlendRMSEResidual(relax_image,residual_image,&residual,exception);
1363  if (status == MagickFalse)
1364  break;
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)
1368  {
1369  if (verbose != MagickFalse)
1370  (void) FormatLocaleFile(stderr," %g: %g\n",(double) i,(double)
1371  residual);
1372  break;
1373  }
1374  residual_image=DestroyImage(residual_image);
1375  residual_image=CloneImage(relax_image,0,0,MagickTrue,exception);
1376  if (residual_image == (Image *) NULL)
1377  break;
1378  }
1379  kernel_info=DestroyKernelInfo(kernel_info);
1380  crop_image=DestroyImage(crop_image);
1381  divergent_image=DestroyImage(divergent_image);
1382  residual_image=DestroyImage(residual_image);
1383  /*
1384  Composite relaxed over the background image.
1385  */
1386  status=CompositeOverImage(image,relax_image,MagickTrue,x_offset,y_offset,
1387  exception);
1388  relax_image=DestroyImage(relax_image);
1389  return(status);
1390 }
1391 
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,
1395  ExceptionInfo *exception)
1396 {
1397  Image
1398  *crop_image,
1399  *foreground_image,
1400  *mean_image,
1401  *relax_image,
1402  *residual_image,
1403  *sum_image;
1404 
1405  KernelInfo
1406  *kernel_info;
1407 
1409  status = MagickTrue,
1410  verbose = MagickFalse;
1411 
1413  crop_info = {
1414  source_image->columns,
1415  source_image->rows,
1416  x_offset,
1417  y_offset
1418  };
1419 
1420  ssize_t
1421  i;
1422 
1423  /*
1424  Seamless blend composite operator.
1425  */
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)
1441  {
1442  mean_image=DestroyImage(mean_image);
1443  return(MagickFalse);
1444  }
1445  status=BlendMaskAlphaChannel(mean_image,source_image,exception);
1446  if (status == MagickFalse)
1447  {
1448  relax_image=DestroyImage(relax_image);
1449  mean_image=DestroyImage(mean_image);
1450  return(MagickFalse);
1451  }
1452  residual_image=CloneImage(relax_image,0,0,MagickTrue,exception);
1453  if (residual_image == (Image *) NULL)
1454  {
1455  relax_image=DestroyImage(relax_image);
1456  mean_image=DestroyImage(mean_image);
1457  return(MagickFalse);
1458  }
1459  /*
1460  Convolve relaxed image and blur area of interest.
1461  */
1462  kernel_info=AcquireKernelInfo("3x3:0,0.25,0,0.25,0,0.25,0,0.25,0",exception);
1463  if (kernel_info == (KernelInfo *) NULL)
1464  {
1465  residual_image=DestroyImage(residual_image);
1466  relax_image=DestroyImage(relax_image);
1467  mean_image=DestroyImage(mean_image);
1468  return(MagickFalse);
1469  }
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++)
1474  {
1475  double
1476  residual = 1.0;
1477 
1478  Image
1479  *convolve_image;
1480 
1481  convolve_image=ConvolveImage(relax_image,kernel_info,exception);
1482  if (convolve_image == (Image *) NULL)
1483  break;
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)
1488  break;
1489  status=BlendRMSEResidual(relax_image,residual_image,&residual,exception);
1490  if (status == MagickFalse)
1491  break;
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)
1495  {
1496  if (verbose != MagickFalse)
1497  (void) FormatLocaleFile(stderr," %g: %g\n",(double) i,(double)
1498  residual);
1499  break;
1500  }
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)
1505  break;
1506  }
1507  kernel_info=DestroyKernelInfo(kernel_info);
1508  mean_image=DestroyImage(mean_image);
1509  residual_image=DestroyImage(residual_image);
1510  /*
1511  Composite the foreground image over the background image.
1512  */
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,
1518  exception);
1519  status=CompositeOverImage(image,foreground_image,MagickTrue,x_offset,y_offset,
1520  exception);
1521  foreground_image=DestroyImage(foreground_image);
1522  return(status);
1523 }
1524 
1526  const Image *composite,const CompositeOperator compose,
1527  const MagickBooleanType clip_to_self,const ssize_t x_offset,
1528  const ssize_t y_offset,ExceptionInfo *exception)
1529 {
1530 #define CompositeImageTag "Composite/Image"
1531 
1532  CacheView
1533  *source_view,
1534  *image_view;
1535 
1536  const char
1537  *value;
1538 
1539  GeometryInfo
1540  geometry_info;
1541 
1542  Image
1543  *canvas_image,
1544  *source_image;
1545 
1547  clamp,
1548  compose_sync,
1549  status;
1550 
1552  progress;
1553 
1555  amount,
1556  canvas_dissolve,
1557  midpoint,
1558  percent_luma,
1559  percent_chroma,
1560  source_dissolve,
1561  threshold;
1562 
1564  flags;
1565 
1566  ssize_t
1567  y;
1568 
1569  assert(image != (Image *) NULL);
1570  assert(image->signature == MagickCoreSignature);
1571  if (image->debug != MagickFalse)
1572  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1573  assert(composite != (Image *) NULL);
1574  assert(composite->signature == MagickCoreSignature);
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))
1582  {
1583  status=CompositeOverImage(image,source_image,clip_to_self,x_offset,
1584  y_offset,exception);
1585  source_image=DestroyImage(source_image);
1586  return(status);
1587  }
1588  amount=0.5;
1589  canvas_image=(Image *) NULL;
1590  canvas_dissolve=1.0;
1591  clamp=MagickTrue;
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);
1600  percent_luma=100.0;
1601  percent_chroma=100.0;
1602  source_dissolve=1.0;
1603  threshold=0.05f;
1604  switch (compose)
1605  {
1606  case CopyCompositeOp:
1607  {
1608  if ((x_offset < 0) || (y_offset < 0))
1609  break;
1610  if ((x_offset+(ssize_t) source_image->columns) > (ssize_t) image->columns)
1611  break;
1612  if ((y_offset+(ssize_t) source_image->rows) > (ssize_t) image->rows)
1613  break;
1614  if ((source_image->alpha_trait == UndefinedPixelTrait) &&
1615  (image->alpha_trait != UndefinedPixelTrait))
1616  (void) SetImageAlphaChannel(source_image,OpaqueAlphaChannel,exception);
1617  status=MagickTrue;
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)
1623 #endif
1624  for (y=0; y < (ssize_t) source_image->rows; y++)
1625  {
1627  sync;
1628 
1629  const Quantum
1630  *p;
1631 
1632  Quantum
1633  *q;
1634 
1635  ssize_t
1636  x;
1637 
1638  if (status == MagickFalse)
1639  continue;
1640  p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
1641  exception);
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))
1645  {
1646  status=MagickFalse;
1647  continue;
1648  }
1649  for (x=0; x < (ssize_t) source_image->columns; x++)
1650  {
1651  ssize_t
1652  i;
1653 
1654  if (GetPixelReadMask(source_image,p) <= (QuantumRange/2))
1655  {
1656  p+=GetPixelChannels(source_image);
1657  q+=GetPixelChannels(image);
1658  continue;
1659  }
1660  for (i=0; i < (ssize_t) GetPixelChannels(source_image); i++)
1661  {
1662  PixelChannel channel = GetPixelChannelChannel(source_image,i);
1663  PixelTrait source_traits = GetPixelChannelTraits(source_image,
1664  channel);
1665  PixelTrait traits = GetPixelChannelTraits(image,channel);
1666  if ((source_traits == UndefinedPixelTrait) ||
1667  (traits == UndefinedPixelTrait))
1668  continue;
1669  SetPixelChannel(image,channel,p[i],q);
1670  }
1671  p+=GetPixelChannels(source_image);
1672  q+=GetPixelChannels(image);
1673  }
1674  sync=SyncCacheViewAuthenticPixels(image_view,exception);
1675  if (sync == MagickFalse)
1676  status=MagickFalse;
1677  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1678  {
1680  proceed;
1681 
1683  y,image->rows);
1684  if (proceed == MagickFalse)
1685  status=MagickFalse;
1686  }
1687  }
1688  source_view=DestroyCacheView(source_view);
1689  image_view=DestroyCacheView(image_view);
1690  source_image=DestroyImage(source_image);
1691  return(status);
1692  }
1693  case IntensityCompositeOp:
1694  {
1695  if ((x_offset < 0) || (y_offset < 0))
1696  break;
1697  if ((x_offset+(ssize_t) source_image->columns) > (ssize_t) image->columns)
1698  break;
1699  if ((y_offset+(ssize_t) source_image->rows) > (ssize_t) image->rows)
1700  break;
1701  status=MagickTrue;
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)
1707 #endif
1708  for (y=0; y < (ssize_t) source_image->rows; y++)
1709  {
1711  sync;
1712 
1713  const Quantum
1714  *p;
1715 
1716  Quantum
1717  *q;
1718 
1719  ssize_t
1720  x;
1721 
1722  if (status == MagickFalse)
1723  continue;
1724  p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
1725  exception);
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))
1729  {
1730  status=MagickFalse;
1731  continue;
1732  }
1733  for (x=0; x < (ssize_t) source_image->columns; x++)
1734  {
1735  if (GetPixelReadMask(source_image,p) <= (QuantumRange/2))
1736  {
1737  p+=GetPixelChannels(source_image);
1738  q+=GetPixelChannels(image);
1739  continue;
1740  }
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);
1746  }
1747  sync=SyncCacheViewAuthenticPixels(image_view,exception);
1748  if (sync == MagickFalse)
1749  status=MagickFalse;
1750  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1751  {
1753  proceed;
1754 
1756  y,image->rows);
1757  if (proceed == MagickFalse)
1758  status=MagickFalse;
1759  }
1760  }
1761  source_view=DestroyCacheView(source_view);
1762  image_view=DestroyCacheView(image_view);
1763  source_image=DestroyImage(source_image);
1764  return(status);
1765  }
1766  case CopyAlphaCompositeOp:
1767  case ChangeMaskCompositeOp:
1768  {
1769  /*
1770  Modify canvas outside the overlaid region and require an alpha
1771  channel to exist, to add transparency.
1772  */
1773  if (image->alpha_trait == UndefinedPixelTrait)
1774  (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1775  break;
1776  }
1777  case BlurCompositeOp:
1778  {
1779  CacheView
1780  *canvas_view;
1781 
1782  double
1783  angle_range,
1784  angle_start,
1785  height,
1786  width;
1787 
1788  PixelInfo
1789  pixel;
1790 
1792  *resample_filter;
1793 
1794  SegmentInfo
1795  blur;
1796 
1797  /*
1798  Blur Image by resampling dictated by an overlay gradient map:
1799  X = red_channel; Y = green_channel; compose:args =
1800  x_scale[,y_scale[,angle]].
1801  */
1802  canvas_image=CloneImage(image,0,0,MagickTrue,exception);
1803  if (canvas_image == (Image *) NULL)
1804  {
1805  source_image=DestroyImage(source_image);
1806  return(MagickFalse);
1807  }
1808  /*
1809  Gather the maximum blur sigma values from user.
1810  */
1811  flags=NoValue;
1812  value=GetImageArtifact(image,"compose:args");
1813  if (value != (const char *) NULL)
1814  flags=ParseGeometry(value,&geometry_info);
1815  if ((flags & WidthValue) == 0)
1816  {
1818  "InvalidSetting","'%s' '%s'","compose:args",value);
1819  source_image=DestroyImage(source_image);
1820  canvas_image=DestroyImage(canvas_image);
1821  return(MagickFalse);
1822  }
1823  /*
1824  Users input sigma now needs to be converted to the EWA ellipse size.
1825  The filter defaults to a sigma of 0.5 so to make this match the users
1826  input the ellipse size needs to be doubled.
1827  */
1828  width=2.0*geometry_info.rho;
1829  height=width;
1830  if ((flags & HeightValue) != 0)
1831  height=2.0*geometry_info.sigma;
1832  /*
1833  Default the unrotated ellipse width and height axis vectors.
1834  */
1835  blur.x1=width;
1836  blur.x2=0.0;
1837  blur.y1=0.0;
1838  blur.y2=height;
1839  if ((flags & XValue) != 0 )
1840  {
1842  angle;
1843 
1844  /*
1845  Rotate vectors if a rotation angle is given.
1846  */
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);
1852  }
1853  angle_start=0.0;
1854  angle_range=0.0;
1855  if ((flags & YValue) != 0 )
1856  {
1857  /*
1858  Lets set a angle range and calculate in the loop.
1859  */
1860  angle_start=DegreesToRadians(geometry_info.xi);
1861  angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
1862  }
1863  /*
1864  Set up a gaussian cylindrical filter for EWA Bluring.
1865 
1866  As the minimum ellipse radius of support*1.0 the EWA algorithm
1867  can only produce a minimum blur of 0.5 for Gaussian (support=2.0)
1868  This means that even 'No Blur' will be still a little blurry! The
1869  solution (as well as the problem of preventing any user expert filter
1870  settings, is to set our own user settings, restore them afterwards.
1871  */
1872  resample_filter=AcquireResampleFilter(image,exception);
1873  SetResampleFilter(resample_filter,GaussianFilter);
1874  /*
1875  Perform the variable blurring of each pixel in image.
1876  */
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++)
1881  {
1883  sync;
1884 
1885  const Quantum
1886  *magick_restrict p;
1887 
1888  Quantum
1889  *magick_restrict q;
1890 
1891  ssize_t
1892  x;
1893 
1894  if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1895  continue;
1896  p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
1897  exception);
1898  q=QueueCacheViewAuthenticPixels(canvas_view,0,y,canvas_image->columns,1,
1899  exception);
1900  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1901  break;
1902  for (x=0; x < (ssize_t) source_image->columns; x++)
1903  {
1904  if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1905  {
1906  p+=GetPixelChannels(source_image);
1907  continue;
1908  }
1909  if (fabs(angle_range) > MagickEpsilon)
1910  {
1912  angle;
1913 
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);
1920  }
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);
1931  }
1932  sync=SyncCacheViewAuthenticPixels(canvas_view,exception);
1933  if (sync == MagickFalse)
1934  break;
1935  }
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;
1941  break;
1942  }
1943  case DisplaceCompositeOp:
1944  case DistortCompositeOp:
1945  {
1946  CacheView
1947  *canvas_view;
1948 
1950  horizontal_scale,
1951  vertical_scale;
1952 
1953  PixelInfo
1954  pixel;
1955 
1956  PointInfo
1957  center,
1958  offset;
1959 
1960  /*
1961  Displace/Distort based on overlay gradient map:
1962  X = red_channel; Y = green_channel;
1963  compose:args = x_scale[,y_scale[,center.x,center.y]]
1964  */
1965  canvas_image=CloneImage(image,0,0,MagickTrue,exception);
1966  if (canvas_image == (Image *) NULL)
1967  {
1968  source_image=DestroyImage(source_image);
1969  return(MagickFalse);
1970  }
1971  SetGeometryInfo(&geometry_info);
1972  flags=NoValue;
1973  value=GetImageArtifact(image,"compose:args");
1974  if (value != (char *) NULL)
1975  flags=ParseGeometry(value,&geometry_info);
1976  if ((flags & (WidthValue | HeightValue)) == 0 )
1977  {
1978  if ((flags & AspectValue) == 0)
1979  {
1980  horizontal_scale=(MagickRealType) (source_image->columns-1)/2.0;
1981  vertical_scale=(MagickRealType) (source_image->rows-1)/2.0;
1982  }
1983  else
1984  {
1985  horizontal_scale=(MagickRealType) (image->columns-1)/2.0;
1986  vertical_scale=(MagickRealType) (image->rows-1)/2.0;
1987  }
1988  }
1989  else
1990  {
1991  horizontal_scale=geometry_info.rho;
1992  vertical_scale=geometry_info.sigma;
1993  if ((flags & PercentValue) != 0)
1994  {
1995  if ((flags & AspectValue) == 0)
1996  {
1997  horizontal_scale*=(source_image->columns-1)/200.0;
1998  vertical_scale*=(source_image->rows-1)/200.0;
1999  }
2000  else
2001  {
2002  horizontal_scale*=(image->columns-1)/200.0;
2003  vertical_scale*=(image->rows-1)/200.0;
2004  }
2005  }
2006  if ((flags & HeightValue) == 0)
2007  vertical_scale=horizontal_scale;
2008  }
2009  /*
2010  Determine fixed center point for absolute distortion map
2011  Absolute distort ==
2012  Displace offset relative to a fixed absolute point
2013  Select that point according to +X+Y user inputs.
2014  default = center of overlay image
2015  arg flag '!' = locations/percentage relative to background image
2016  */
2017  center.x=(MagickRealType) x_offset;
2018  center.y=(MagickRealType) y_offset;
2019  if (compose == DistortCompositeOp)
2020  {
2021  if ((flags & XValue) == 0)
2022  if ((flags & AspectValue) != 0)
2023  center.x=(MagickRealType) ((image->columns-1)/2.0);
2024  else
2025  center.x=(MagickRealType) (x_offset+(source_image->columns-1)/
2026  2.0);
2027  else
2028  if ((flags & AspectValue) != 0)
2029  center.x=geometry_info.xi;
2030  else
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);
2035  else
2036  center.y=(MagickRealType) (y_offset+(source_image->rows-1)/2.0);
2037  else
2038  if ((flags & AspectValue) != 0)
2039  center.y=geometry_info.psi;
2040  else
2041  center.y=(MagickRealType) (y_offset+geometry_info.psi);
2042  }
2043  /*
2044  Shift the pixel offset point as defined by the provided,
2045  displacement/distortion map. -- Like a lens...
2046  */
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++)
2052  {
2054  sync;
2055 
2056  const Quantum
2057  *magick_restrict p;
2058 
2059  Quantum
2060  *magick_restrict q;
2061 
2062  ssize_t
2063  x;
2064 
2065  if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
2066  continue;
2067  p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
2068  exception);
2069  q=QueueCacheViewAuthenticPixels(canvas_view,0,y,canvas_image->columns,1,
2070  exception);
2071  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2072  break;
2073  for (x=0; x < (ssize_t) source_image->columns; x++)
2074  {
2075  if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
2076  {
2077  p+=GetPixelChannels(source_image);
2078  continue;
2079  }
2080  /*
2081  Displace the offset.
2082  */
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) ?
2086  x : 0);
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) ?
2090  y : 0);
2091  status=InterpolatePixelInfo(image,image_view,
2092  UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
2093  &pixel,exception);
2094  if (status == MagickFalse)
2095  break;
2096  /*
2097  Mask with the 'invalid pixel mask' in alpha channel.
2098  */
2100  (QuantumScale*GetPixelAlpha(source_image,p));
2101  SetPixelViaPixelInfo(canvas_image,&pixel,q);
2102  p+=GetPixelChannels(source_image);
2103  q+=GetPixelChannels(canvas_image);
2104  }
2105  if (x < (ssize_t) source_image->columns)
2106  break;
2107  sync=SyncCacheViewAuthenticPixels(canvas_view,exception);
2108  if (sync == MagickFalse)
2109  break;
2110  }
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;
2116  break;
2117  }
2118  case DissolveCompositeOp:
2119  {
2120  /*
2121  Geometry arguments to dissolve factors.
2122  */
2123  value=GetImageArtifact(image,"compose:args");
2124  if (value != (char *) NULL)
2125  {
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)
2132  {
2133  canvas_dissolve=2.0-source_dissolve;
2134  source_dissolve=1.0;
2135  }
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  }
2141  break;
2142  }
2143  case BlendCompositeOp:
2144  {
2145  value=GetImageArtifact(image,"compose:args");
2146  if (value != (char *) NULL)
2147  {
2148  flags=ParseGeometry(value,&geometry_info);
2149  source_dissolve=geometry_info.rho/100.0;
2150  canvas_dissolve=1.0-source_dissolve;
2151  if ((flags & SigmaValue) != 0)
2152  canvas_dissolve=geometry_info.sigma/100.0;
2153  }
2154  break;
2155  }
2157  {
2158  double
2159  residual_threshold = 0.0002,
2160  iterations = 400.0;
2161 
2162  size_t
2163  tick = 100;
2164 
2165  value=GetImageArtifact(image,"compose:args");
2166  if (value != (char *) NULL)
2167  {
2168  flags=ParseGeometry(value,&geometry_info);
2169  iterations=geometry_info.rho;
2170  if ((flags & SigmaValue) != 0)
2171  residual_threshold=geometry_info.sigma;
2172  if ((flags & XiValue) != 0)
2173  tick=(size_t) geometry_info.xi;
2174  }
2175  status=SaliencyBlendImage(image,composite,x_offset,y_offset,iterations,
2176  residual_threshold,tick,exception);
2177  source_image=DestroyImage(source_image);
2178  return(status);
2179  }
2181  {
2182  double
2183  residual_threshold = 0.0002,
2184  iterations = 400.0;
2185 
2186  size_t
2187  tick = 100;
2188 
2189  value=GetImageArtifact(image,"compose:args");
2190  if (value != (char *) NULL)
2191  {
2192  flags=ParseGeometry(value,&geometry_info);
2193  iterations=geometry_info.rho;
2194  if ((flags & SigmaValue) != 0)
2195  residual_threshold=geometry_info.sigma;
2196  if ((flags & XiValue) != 0)
2197  tick=(size_t) geometry_info.xi;
2198  }
2199  status=SeamlessBlendImage(image,composite,x_offset,y_offset,iterations,
2200  residual_threshold,tick,exception);
2201  source_image=DestroyImage(source_image);
2202  return(status);
2203  }
2205  {
2206  /*
2207  Just collect the values from "compose:args", setting.
2208  Unused values are set to zero automagically.
2209 
2210  Arguments are normally a comma separated list, so this probably should
2211  be changed to some 'general comma list' parser, (with a minimum
2212  number of values)
2213  */
2214  SetGeometryInfo(&geometry_info);
2215  value=GetImageArtifact(image,"compose:args");
2216  if (value != (char *) NULL)
2217  {
2218  flags=ParseGeometry(value,&geometry_info);
2219  if (flags == NoValue)
2221  "InvalidGeometry","`%s'",value);
2222  }
2223  break;
2224  }
2225  case ModulateCompositeOp:
2226  {
2227  /*
2228  Determine the luma and chroma scale.
2229  */
2230  value=GetImageArtifact(image,"compose:args");
2231  if (value != (char *) NULL)
2232  {
2233  flags=ParseGeometry(value,&geometry_info);
2234  percent_luma=geometry_info.rho;
2235  if ((flags & SigmaValue) != 0)
2236  percent_chroma=geometry_info.sigma;
2237  }
2238  break;
2239  }
2240  case ThresholdCompositeOp:
2241  {
2242  /*
2243  Determine the amount and threshold.
2244  */
2245  value=GetImageArtifact(image,"compose:args");
2246  if (value != (char *) NULL)
2247  {
2248  flags=ParseGeometry(value,&geometry_info);
2249  amount=geometry_info.rho;
2250  threshold=geometry_info.sigma;
2251  if ((flags & SigmaValue) == 0)
2252  threshold=0.05f;
2253  }
2254  threshold*=QuantumRange;
2255  break;
2256  }
2257  default:
2258  break;
2259  }
2260  /*
2261  Composite image.
2262  */
2263  status=MagickTrue;
2264  progress=0;
2265  midpoint=((MagickRealType) QuantumRange+1.0)/2;
2266  source_view=AcquireVirtualCacheView(source_image,exception);
2267  image_view=AcquireAuthenticCacheView(image,exception);
2268 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2269  #pragma omp parallel for schedule(static) shared(progress,status) \
2270  magick_number_threads(source_image,image,image->rows,1)
2271 #endif
2272  for (y=0; y < (ssize_t) image->rows; y++)
2273  {
2274  const Quantum
2275  *pixels;
2276 
2278  blue,
2279  chroma,
2280  green,
2281  hue,
2282  luma,
2283  red;
2284 
2285  PixelInfo
2286  canvas_pixel,
2287  source_pixel;
2288 
2289  const Quantum
2290  *magick_restrict p;
2291 
2292  Quantum
2293  *magick_restrict q;
2294 
2295  ssize_t
2296  x;
2297 
2298  if (status == MagickFalse)
2299  continue;
2300  if (clip_to_self != MagickFalse)
2301  {
2302  if (y < y_offset)
2303  continue;
2304  if ((y-y_offset) >= (ssize_t) source_image->rows)
2305  continue;
2306  }
2307  /*
2308  If pixels is NULL, y is outside overlay region.
2309  */
2310  pixels=(Quantum *) NULL;
2311  p=(Quantum *) NULL;
2312  if ((y >= y_offset) && ((y-y_offset) < (ssize_t) source_image->rows))
2313  {
2314  p=GetCacheViewVirtualPixels(source_view,0,y-y_offset,
2315  source_image->columns,1,exception);
2316  if (p == (const Quantum *) NULL)
2317  {
2318  status=MagickFalse;
2319  continue;
2320  }
2321  pixels=p;
2322  if (x_offset < 0)
2323  p-=x_offset*(ssize_t) GetPixelChannels(source_image);
2324  }
2325  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2326  if (q == (Quantum *) NULL)
2327  {
2328  status=MagickFalse;
2329  continue;
2330  }
2331  hue=0.0;
2332  chroma=0.0;
2333  luma=0.0;
2334  GetPixelInfo(image,&canvas_pixel);
2335  GetPixelInfo(source_image,&source_pixel);
2336  for (x=0; x < (ssize_t) image->columns; x++)
2337  {
2338  double
2339  gamma;
2340 
2342  alpha,
2343  Da,
2344  Dc,
2345  Dca,
2346  DcaDa,
2347  Sa,
2348  SaSca,
2349  Sc,
2350  Sca;
2351 
2352  ssize_t
2353  i;
2354 
2355  size_t
2356  channels;
2357 
2358  if (clip_to_self != MagickFalse)
2359  {
2360  if (x < x_offset)
2361  {
2362  q+=GetPixelChannels(image);
2363  continue;
2364  }
2365  if ((x-x_offset) >= (ssize_t) source_image->columns)
2366  break;
2367  }
2368  if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
2369  ((x-x_offset) >= (ssize_t) source_image->columns))
2370  {
2371  Quantum
2372  source[MaxPixelChannels];
2373 
2374  /*
2375  Virtual composite:
2376  Sc: source color.
2377  Dc: canvas color.
2378  */
2379  (void) GetOneVirtualPixel(source_image,x-x_offset,y-y_offset,source,
2380  exception);
2381  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2382  {
2384  pixel;
2385 
2386  PixelChannel channel = GetPixelChannelChannel(image,i);
2387  PixelTrait traits = GetPixelChannelTraits(image,channel);
2388  PixelTrait source_traits=GetPixelChannelTraits(source_image,
2389  channel);
2390  if ((traits == UndefinedPixelTrait) ||
2391  (source_traits == UndefinedPixelTrait))
2392  continue;
2393  switch (compose)
2394  {
2395  case AlphaCompositeOp:
2396  case ChangeMaskCompositeOp:
2397  case CopyAlphaCompositeOp:
2398  case DstAtopCompositeOp:
2399  case DstInCompositeOp:
2400  case InCompositeOp:
2401  case OutCompositeOp:
2402  case SrcInCompositeOp:
2403  case SrcOutCompositeOp:
2404  {
2405  if (channel == AlphaPixelChannel)
2407  else
2408  pixel=(MagickRealType) q[i];
2409  break;
2410  }
2411  case ClearCompositeOp:
2412  case CopyCompositeOp:
2413  case ReplaceCompositeOp:
2414  case SrcCompositeOp:
2415  {
2416  if (channel == AlphaPixelChannel)
2418  else
2419  pixel=0.0;
2420  break;
2421  }
2422  case BlendCompositeOp:
2423  case DissolveCompositeOp:
2424  {
2425  if (channel == AlphaPixelChannel)
2426  pixel=canvas_dissolve*GetPixelAlpha(source_image,source);
2427  else
2428  pixel=(MagickRealType) source[channel];
2429  break;
2430  }
2431  default:
2432  {
2433  pixel=(MagickRealType) source[channel];
2434  break;
2435  }
2436  }
2437  q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
2438  ClampToQuantum(pixel);
2439  }
2440  q+=GetPixelChannels(image);
2441  continue;
2442  }
2443  /*
2444  Authentic composite:
2445  Sa: normalized source alpha.
2446  Da: normalized canvas alpha.
2447  */
2448  Sa=QuantumScale*GetPixelAlpha(source_image,p);
2449  Da=QuantumScale*GetPixelAlpha(image,q);
2450  switch (compose)
2451  {
2452  case BumpmapCompositeOp:
2453  case ColorBurnCompositeOp:
2454  case ColorDodgeCompositeOp:
2455  case DarkenCompositeOp:
2456  case DifferenceCompositeOp:
2457  case DivideDstCompositeOp:
2458  case DivideSrcCompositeOp:
2459  case ExclusionCompositeOp:
2460  case FreezeCompositeOp:
2461  case HardLightCompositeOp:
2462  case HardMixCompositeOp:
2464  case LightenCompositeOp:
2465  case LinearBurnCompositeOp:
2469  case MinusDstCompositeOp:
2470  case MinusSrcCompositeOp:
2471  case MultiplyCompositeOp:
2472  case NegateCompositeOp:
2473  case OverlayCompositeOp:
2475  case PinLightCompositeOp:
2476  case ReflectCompositeOp:
2477  case ScreenCompositeOp:
2478  case SoftBurnCompositeOp:
2479  case SoftDodgeCompositeOp:
2480  case SoftLightCompositeOp:
2481  case StampCompositeOp:
2482  case VividLightCompositeOp:
2483  {
2484  alpha=RoundToUnity(Sa+Da-Sa*Da);
2485  break;
2486  }
2487  case DstAtopCompositeOp:
2488  case DstInCompositeOp:
2489  case InCompositeOp:
2490  case SrcInCompositeOp:
2491  {
2492  alpha=Sa*Da;
2493  break;
2494  }
2495  case DissolveCompositeOp:
2496  {
2497  alpha=source_dissolve*Sa*(-canvas_dissolve*Da)+source_dissolve*Sa+
2498  canvas_dissolve*Da;
2499  break;
2500  }
2501  case DstOverCompositeOp:
2502  case OverCompositeOp:
2503  case SrcOverCompositeOp:
2504  {
2505  alpha=Sa+Da-Sa*Da;
2506  break;
2507  }
2508  case DstOutCompositeOp:
2509  {
2510  alpha=Da*(1.0-Sa);
2511  break;
2512  }
2513  case OutCompositeOp:
2514  case SrcOutCompositeOp:
2515  {
2516  alpha=Sa*(1.0-Da);
2517  break;
2518  }
2519  case BlendCompositeOp:
2520  case PlusCompositeOp:
2521  {
2522  alpha=RoundToUnity(source_dissolve*Sa+canvas_dissolve*Da);
2523  break;
2524  }
2525  case XorCompositeOp:
2526  {
2527  alpha=Sa+Da-2.0*Sa*Da;
2528  break;
2529  }
2530  case ModulusAddCompositeOp:
2531  {
2532  if ((Sa+Da) <= 1.0)
2533  {
2534  alpha=(Sa+Da);
2535  break;
2536  }
2537  alpha=((Sa+Da)-1.0);
2538  break;
2539  }
2541  {
2542  if ((Sa-Da) >= 0.0)
2543  {
2544  alpha=(Sa-Da);
2545  break;
2546  }
2547  alpha=((Sa-Da)+1.0);
2548  break;
2549  }
2550  default:
2551  {
2552  alpha=1.0;
2553  break;
2554  }
2555  }
2556  switch (compose)
2557  {
2558  case ColorizeCompositeOp:
2559  case HueCompositeOp:
2560  case LuminizeCompositeOp:
2561  case ModulateCompositeOp:
2562  case RMSECompositeOp:
2563  case SaturateCompositeOp:
2564  {
2565  GetPixelInfoPixel(source_image,p,&source_pixel);
2566  GetPixelInfoPixel(image,q,&canvas_pixel);
2567  break;
2568  }
2569  default:
2570  break;
2571  }
2572  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2573  {
2575  pixel,
2576  sans;
2577 
2578  PixelChannel channel = GetPixelChannelChannel(image,i);
2579  PixelTrait traits = GetPixelChannelTraits(image,channel);
2580  PixelTrait source_traits = GetPixelChannelTraits(source_image,channel);
2581  if (traits == UndefinedPixelTrait)
2582  continue;
2583  if ((channel == AlphaPixelChannel) &&
2584  ((traits & UpdatePixelTrait) != 0))
2585  {
2586  /*
2587  Set alpha channel.
2588  */
2589  switch (compose)
2590  {
2591  case AlphaCompositeOp:
2592  {
2593  pixel=QuantumRange*Sa;
2594  break;
2595  }
2596  case AtopCompositeOp:
2597  case CopyBlackCompositeOp:
2598  case CopyBlueCompositeOp:
2599  case CopyCyanCompositeOp:
2600  case CopyGreenCompositeOp:
2602  case CopyRedCompositeOp:
2603  case CopyYellowCompositeOp:
2604  case SrcAtopCompositeOp:
2605  case DstCompositeOp:
2606  case NoCompositeOp:
2607  {
2608  pixel=QuantumRange*Da;
2609  break;
2610  }
2611  case BumpmapCompositeOp:
2612  {
2613  pixel=GetPixelIntensity(source_image,p)*Da;
2614  break;
2615  }
2616  case ChangeMaskCompositeOp:
2617  {
2618  if (IsFuzzyEquivalencePixel(source_image,p,image,q) != MagickFalse)
2620  else
2621  pixel=QuantumRange*Da;
2622  break;
2623  }
2624  case ClearCompositeOp:
2625  {
2627  break;
2628  }
2629  case ColorizeCompositeOp:
2630  case HueCompositeOp:
2631  case LuminizeCompositeOp:
2632  case RMSECompositeOp:
2633  case SaturateCompositeOp:
2634  {
2635  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2636  {
2637  pixel=QuantumRange*Da;
2638  break;
2639  }
2640  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
2641  {
2642  pixel=QuantumRange*Sa;
2643  break;
2644  }
2645  if (Sa < Da)
2646  {
2647  pixel=QuantumRange*Da;
2648  break;
2649  }
2650  pixel=QuantumRange*Sa;
2651  break;
2652  }
2653  case CopyAlphaCompositeOp:
2654  {
2655  if (source_image->alpha_trait == UndefinedPixelTrait)
2656  pixel=GetPixelIntensity(source_image,p);
2657  else
2658  pixel=QuantumRange*Sa;
2659  break;
2660  }
2661  case BlurCompositeOp:
2662  case CopyCompositeOp:
2663  case DisplaceCompositeOp:
2664  case DistortCompositeOp:
2665  case DstAtopCompositeOp:
2666  case ReplaceCompositeOp:
2667  case SrcCompositeOp:
2668  {
2669  pixel=QuantumRange*Sa;
2670  break;
2671  }
2673  {
2674  if (compose_sync == MagickFalse)
2675  {
2676  pixel=GetPixelIntensity(source_image,p) <
2677  GetPixelIntensity(image,q) ? Sa : Da;
2678  break;
2679  }
2680  pixel=Sa*GetPixelIntensity(source_image,p) <
2681  Da*GetPixelIntensity(image,q) ? Sa : Da;
2682  break;
2683  }
2684  case DifferenceCompositeOp:
2685  {
2686  pixel=QuantumRange*fabs((double) (Sa-Da));
2687  break;
2688  }
2689  case FreezeCompositeOp:
2690  {
2691  pixel=QuantumRange*(1.0-(1.0-Sa)*(1.0-Sa)*
2692  PerceptibleReciprocal(Da));
2693  if (pixel < 0.0)
2694  pixel=0.0;
2695  break;
2696  }
2698  {
2699  pixel=QuantumRange*(0.5-0.25*cos(MagickPI*Sa)-0.25*
2700  cos(MagickPI*Da));
2701  break;
2702  }
2704  {
2705  if (compose_sync == MagickFalse)
2706  {
2707  pixel=GetPixelIntensity(source_image,p) >
2708  GetPixelIntensity(image,q) ? Sa : Da;
2709  break;
2710  }
2711  pixel=Sa*GetPixelIntensity(source_image,p) >
2712  Da*GetPixelIntensity(image,q) ? Sa : Da;
2713  break;
2714  }
2715  case ModulateCompositeOp:
2716  {
2717  pixel=QuantumRange*Da;
2718  break;
2719  }
2720  case MultiplyCompositeOp:
2721  {
2722  if (compose_sync == MagickFalse)
2723  {
2724  pixel=QuantumRange*Sa*Da;
2725  break;
2726  }
2727  pixel=QuantumRange*alpha;
2728  break;
2729  }
2730  case NegateCompositeOp:
2731  {
2732  pixel=QuantumRange*((1.0-Sa-Da));
2733  break;
2734  }
2735  case ReflectCompositeOp:
2736  {
2737  pixel=QuantumRange*(Sa*Sa*PerceptibleReciprocal(1.0-Da));
2738  if (pixel > QuantumRange)
2739  pixel=QuantumRange;
2740  break;
2741  }
2742  case StampCompositeOp:
2743  {
2744  pixel=QuantumRange*(Sa+Da*Da-1.0);
2745  break;
2746  }
2747  case StereoCompositeOp:
2748  {
2749  pixel=QuantumRange*(Sa+Da)/2;
2750  break;
2751  }
2752  default:
2753  {
2754  pixel=QuantumRange*alpha;
2755  break;
2756  }
2757  }
2758  q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
2759  ClampToQuantum(pixel);
2760  continue;
2761  }
2762  if (source_traits == UndefinedPixelTrait)
2763  continue;
2764  /*
2765  Sc: source color.
2766  Dc: canvas color.
2767  */
2768  Sc=(MagickRealType) GetPixelChannel(source_image,channel,p);
2769  Dc=(MagickRealType) q[i];
2770  if ((traits & CopyPixelTrait) != 0)
2771  {
2772  /*
2773  Copy channel.
2774  */
2775  q[i]=ClampToQuantum(Dc);
2776  continue;
2777  }
2778  /*
2779  Porter-Duff compositions:
2780  Sca: source normalized color multiplied by alpha.
2781  Dca: normalized canvas color multiplied by alpha.
2782  */
2783  Sca=QuantumScale*Sa*Sc;
2784  Dca=QuantumScale*Da*Dc;
2785  SaSca=Sa*PerceptibleReciprocal(Sca);
2786  DcaDa=Dca*PerceptibleReciprocal(Da);
2787  switch (compose)
2788  {
2789  case DarkenCompositeOp:
2790  case LightenCompositeOp:
2792  {
2793  gamma=PerceptibleReciprocal(1.0-alpha);
2794  break;
2795  }
2796  default:
2797  {
2798  gamma=PerceptibleReciprocal(alpha);
2799  break;
2800  }
2801  }
2802  pixel=Dc;
2803  switch (compose)
2804  {
2805  case AlphaCompositeOp:
2806  {
2807  pixel=QuantumRange*Sa;
2808  break;
2809  }
2810  case AtopCompositeOp:
2811  case SrcAtopCompositeOp:
2812  {
2813  pixel=QuantumRange*(Sca*Da+Dca*(1.0-Sa));
2814  break;
2815  }
2816  case BlendCompositeOp:
2817  {
2818  pixel=gamma*(source_dissolve*Sa*Sc+canvas_dissolve*Da*Dc);
2819  break;
2820  }
2821  case CopyCompositeOp:
2822  case ReplaceCompositeOp:
2823  case SrcCompositeOp:
2824  {
2825  pixel=QuantumRange*Sca;
2826  break;
2827  }
2828  case BlurCompositeOp:
2829  case DisplaceCompositeOp:
2830  case DistortCompositeOp:
2831  {
2832  pixel=Sc;
2833  break;
2834  }
2835  case BumpmapCompositeOp:
2836  {
2837  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2838  {
2839  pixel=Dc;
2840  break;
2841  }
2842  pixel=QuantumScale*GetPixelIntensity(source_image,p)*Dc;
2843  break;
2844  }
2845  case ChangeMaskCompositeOp:
2846  {
2847  pixel=Dc;
2848  break;
2849  }
2850  case ClearCompositeOp:
2851  {
2852  pixel=0.0;
2853  break;
2854  }
2855  case ColorBurnCompositeOp:
2856  {
2857  if ((Sca == 0.0) && (Dca == Da))
2858  {
2859  pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
2860  break;
2861  }
2862  if (Sca == 0.0)
2863  {
2864  pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
2865  break;
2866  }
2867  pixel=QuantumRange*gamma*(Sa*Da-Sa*Da*MagickMin(1.0,(1.0-DcaDa)*
2868  SaSca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
2869  break;
2870  }
2871  case ColorDodgeCompositeOp:
2872  {
2873  if ((Sca*Da+Dca*Sa) >= Sa*Da)
2874  pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2875  else
2876  pixel=QuantumRange*gamma*(Dca*Sa*Sa*PerceptibleReciprocal(Sa-Sca)+
2877  Sca*(1.0-Da)+Dca*(1.0-Sa));
2878  break;
2879  }
2880  case ColorizeCompositeOp:
2881  {
2882  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2883  {
2884  pixel=Dc;
2885  break;
2886  }
2887  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
2888  {
2889  pixel=Sc;
2890  break;
2891  }
2892  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
2893  &sans,&sans,&luma);
2894  CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2895  &hue,&chroma,&sans);
2896  HCLComposite(hue,chroma,luma,&red,&green,&blue);
2897  switch (channel)
2898  {
2899  case RedPixelChannel: pixel=red; break;
2900  case GreenPixelChannel: pixel=green; break;
2901  case BluePixelChannel: pixel=blue; break;
2902  default: pixel=Dc; break;
2903  }
2904  break;
2905  }
2906  case CopyAlphaCompositeOp:
2907  {
2908  pixel=Dc;
2909  break;
2910  }
2911  case CopyBlackCompositeOp:
2912  {
2913  if (channel == BlackPixelChannel)
2914  pixel=(MagickRealType) GetPixelBlack(source_image,p);
2915  break;
2916  }
2917  case CopyBlueCompositeOp:
2918  case CopyYellowCompositeOp:
2919  {
2920  if (channel == BluePixelChannel)
2921  pixel=(MagickRealType) GetPixelBlue(source_image,p);
2922  break;
2923  }
2924  case CopyGreenCompositeOp:
2926  {
2927  if (channel == GreenPixelChannel)
2928  pixel=(MagickRealType) GetPixelGreen(source_image,p);
2929  break;
2930  }
2931  case CopyRedCompositeOp:
2932  case CopyCyanCompositeOp:
2933  {
2934  if (channel == RedPixelChannel)
2935  pixel=(MagickRealType) GetPixelRed(source_image,p);
2936  break;
2937  }
2938  case DarkenCompositeOp:
2939  {
2940  /*
2941  Darken is equivalent to a 'Minimum' method
2942  OR a greyscale version of a binary 'Or'
2943  OR the 'Intersection' of pixel sets.
2944  */
2945  if (compose_sync == MagickFalse)
2946  {
2947  pixel=MagickMin(Sc,Dc);
2948  break;
2949  }
2950  if ((Sca*Da) < (Dca*Sa))
2951  {
2952  pixel=QuantumRange*(Sca+Dca*(1.0-Sa));
2953  break;
2954  }
2955  pixel=QuantumRange*(Dca+Sca*(1.0-Da));
2956  break;
2957  }
2959  {
2960  if (compose_sync == MagickFalse)
2961  {
2962  pixel=GetPixelIntensity(source_image,p) <
2963  GetPixelIntensity(image,q) ? Sc : Dc;
2964  break;
2965  }
2966  pixel=Sa*GetPixelIntensity(source_image,p) <
2967  Da*GetPixelIntensity(image,q) ? Sc : Dc;
2968  break;
2969  }
2970  case DifferenceCompositeOp:
2971  {
2972  if (compose_sync == MagickFalse)
2973  {
2974  pixel=fabs((double) Sc-Dc);
2975  break;
2976  }
2977  pixel=QuantumRange*gamma*(Sca+Dca-2.0*MagickMin(Sca*Da,Dca*Sa));
2978  break;
2979  }
2980  case DissolveCompositeOp:
2981  {
2982  pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
2983  canvas_dissolve*Da*Dc+canvas_dissolve*Da*Dc);
2984  break;
2985  }
2986  case DivideDstCompositeOp:
2987  {
2988  if (compose_sync == MagickFalse)
2989  {
2990  pixel=QuantumRange*(Sc/PerceptibleReciprocal(Dc));
2991  break;
2992  }
2993  if ((fabs((double) Sca) < MagickEpsilon) &&
2994  (fabs((double) Dca) < MagickEpsilon))
2995  {
2996  pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
2997  break;
2998  }
2999  if (fabs((double) Dca) < MagickEpsilon)
3000  {
3001  pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
3002  break;
3003  }
3004  pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
3005  break;
3006  }
3007  case DivideSrcCompositeOp:
3008  {
3009  if (compose_sync == MagickFalse)
3010  {
3011  pixel=QuantumRange*(Dc/PerceptibleReciprocal(Sc));
3012  break;
3013  }
3014  if ((fabs((double) Dca) < MagickEpsilon) &&
3015  (fabs((double) Sca) < MagickEpsilon))
3016  {
3017  pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
3018  break;
3019  }
3020  if (fabs((double) Sca) < MagickEpsilon)
3021  {
3022  pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
3023  break;
3024  }
3025  pixel=QuantumRange*gamma*(Dca*Sa*SaSca+Dca*(1.0-Sa)+Sca*(1.0-Da));
3026  break;
3027  }
3028  case DstAtopCompositeOp:
3029  {
3030  pixel=QuantumRange*(Dca*Sa+Sca*(1.0-Da));
3031  break;
3032  }
3033  case DstCompositeOp:
3034  case NoCompositeOp:
3035  {
3036  pixel=QuantumRange*Dca;
3037  break;
3038  }
3039  case DstInCompositeOp:
3040  {
3041  pixel=QuantumRange*gamma*(Dca*Sa);
3042  break;
3043  }
3044  case DstOutCompositeOp:
3045  {
3046  pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
3047  break;
3048  }
3049  case DstOverCompositeOp:
3050  {
3051  pixel=QuantumRange*gamma*(Dca+Sca*(1.0-Da));
3052  break;
3053  }
3054  case ExclusionCompositeOp:
3055  {
3056  pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
3057  Dca*(1.0-Sa));
3058  break;
3059  }
3060  case FreezeCompositeOp:
3061  {
3062  pixel=QuantumRange*gamma*(1.0-(1.0-Sca)*(1.0-Sca)*
3063  PerceptibleReciprocal(Dca));
3064  if (pixel < 0.0)
3065  pixel=0.0;
3066  break;
3067  }
3068  case HardLightCompositeOp:
3069  {
3070  if ((2.0*Sca) < Sa)
3071  {
3072  pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-
3073  Sa));
3074  break;
3075  }
3076  pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
3077  Dca*(1.0-Sa));
3078  break;
3079  }
3080  case HardMixCompositeOp:
3081  {
3082  pixel=gamma*(((Sca+Dca) < 1.0) ? 0.0 : QuantumRange);
3083  break;
3084  }
3085  case HueCompositeOp:
3086  {
3087  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
3088  {
3089  pixel=Dc;
3090  break;
3091  }
3092  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
3093  {
3094  pixel=Sc;
3095  break;
3096  }
3097  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
3098  &hue,&chroma,&luma);
3099  CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
3100  &hue,&sans,&sans);
3101  HCLComposite(hue,chroma,luma,&red,&green,&blue);
3102  switch (channel)
3103  {
3104  case RedPixelChannel: pixel=red; break;
3105  case GreenPixelChannel: pixel=green; break;
3106  case BluePixelChannel: pixel=blue; break;
3107  default: pixel=Dc; break;
3108  }
3109  break;
3110  }
3111  case InCompositeOp:
3112  case SrcInCompositeOp:
3113  {
3114  pixel=QuantumRange*(Sca*Da);
3115  break;
3116  }
3118  {
3119  pixel=QuantumRange*(0.5-0.25*cos(MagickPI*Sca)-0.25*
3120  cos(MagickPI*Dca));
3121  break;
3122  }
3123  case LinearBurnCompositeOp:
3124  {
3125  /*
3126  LinearBurn: as defined by Abode Photoshop, according to
3127  http://www.simplefilter.de/en/basics/mixmods.html is:
3128 
3129  f(Sc,Dc) = Sc + Dc - 1
3130  */
3131  pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
3132  break;
3133  }
3135  {
3136  pixel=gamma*(Sa*Sc+Da*Dc);
3137  break;
3138  }
3140  {
3141  /*
3142  LinearLight: as defined by Abode Photoshop, according to
3143  http://www.simplefilter.de/en/basics/mixmods.html is:
3144 
3145  f(Sc,Dc) = Dc + 2*Sc - 1
3146  */
3147  pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
3148  break;
3149  }
3150  case LightenCompositeOp:
3151  {
3152  if (compose_sync == MagickFalse)
3153  {
3154  pixel=MagickMax(Sc,Dc);
3155  break;
3156  }
3157  if ((Sca*Da) > (Dca*Sa))
3158  {
3159  pixel=QuantumRange*(Sca+Dca*(1.0-Sa));
3160  break;
3161  }
3162  pixel=QuantumRange*(Dca+Sca*(1.0-Da));
3163  break;
3164  }
3166  {
3167  /*
3168  Lighten is equivalent to a 'Maximum' method
3169  OR a greyscale version of a binary 'And'
3170  OR the 'Union' of pixel sets.
3171  */
3172  if (compose_sync == MagickFalse)
3173  {
3174  pixel=GetPixelIntensity(source_image,p) >
3175  GetPixelIntensity(image,q) ? Sc : Dc;
3176  break;
3177  }
3178  pixel=Sa*GetPixelIntensity(source_image,p) >
3179  Da*GetPixelIntensity(image,q) ? Sc : Dc;
3180  break;
3181  }
3182  case LuminizeCompositeOp:
3183  {
3184  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
3185  {
3186  pixel=Dc;
3187  break;
3188  }
3189  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
3190  {
3191  pixel=Sc;
3192  break;
3193  }
3194  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
3195  &hue,&chroma,&luma);
3196  CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
3197  &sans,&sans,&luma);
3198  HCLComposite(hue,chroma,luma,&red,&green,&blue);
3199  switch (channel)
3200  {
3201  case RedPixelChannel: pixel=red; break;
3202  case GreenPixelChannel: pixel=green; break;
3203  case BluePixelChannel: pixel=blue; break;
3204  default: pixel=Dc; break;
3205  }
3206  break;
3207  }
3209  {
3210  /*
3211  'Mathematics' a free form user control mathematical composition
3212  is defined as...
3213 
3214  f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
3215 
3216  Where the arguments A,B,C,D are (currently) passed to composite
3217  as a command separated 'geometry' string in "compose:args" image
3218  artifact.
3219 
3220  A = a->rho, B = a->sigma, C = a->xi, D = a->psi
3221 
3222  Applying the SVG transparency formula (see above), we get...
3223 
3224  Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
3225 
3226  Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
3227  Dca*(1.0-Sa)
3228  */
3229  if (compose_sync == MagickFalse)
3230  {
3231  pixel=geometry_info.rho*Sc*Dc+geometry_info.sigma*Sc+
3232  geometry_info.xi*Dc+geometry_info.psi;
3233  break;
3234  }
3235  pixel=QuantumRange*gamma*(geometry_info.rho*Sca*Dca+
3236  geometry_info.sigma*Sca*Da+geometry_info.xi*Dca*Sa+
3237  geometry_info.psi*Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
3238  break;
3239  }
3240  case MinusDstCompositeOp:
3241  {
3242  if (compose_sync == MagickFalse)
3243  {
3244  pixel=Dc-Sc;
3245  break;
3246  }
3247  pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
3248  break;
3249  }
3250  case MinusSrcCompositeOp:
3251  {
3252  /*
3253  Minus source from canvas.
3254 
3255  f(Sc,Dc) = Sc - Dc
3256  */
3257  if (compose_sync == MagickFalse)
3258  {
3259  pixel=Sc-Dc;
3260  break;
3261  }
3262  pixel=gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
3263  break;
3264  }
3265  case ModulateCompositeOp:
3266  {
3267  ssize_t
3268  offset;
3269 
3270  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
3271  {
3272  pixel=Dc;
3273  break;
3274  }
3275  offset=(ssize_t) (GetPixelIntensity(source_image,p)-midpoint);
3276  if (offset == 0)
3277  {
3278  pixel=Dc;
3279  break;
3280  }
3281  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
3282  &hue,&chroma,&luma);
3283  luma+=(0.01*percent_luma*offset)/midpoint;
3284  chroma*=0.01*percent_chroma;
3285  HCLComposite(hue,chroma,luma,&red,&green,&blue);
3286  switch (channel)
3287  {
3288  case RedPixelChannel: pixel=red; break;
3289  case GreenPixelChannel: pixel=green; break;
3290  case BluePixelChannel: pixel=blue; break;
3291  default: pixel=Dc; break;
3292  }
3293  break;
3294  }
3295  case ModulusAddCompositeOp:
3296  {
3297  if (compose_sync == MagickFalse)
3298  {
3299  pixel=(Sc+Dc);
3300  break;
3301  }
3302  if ((Sca+Dca) <= 1.0)
3303  {
3304  pixel=QuantumRange*(Sca+Dca);
3305  break;
3306  }
3307  pixel=QuantumRange*((Sca+Dca)-1.0);
3308  break;
3309  }
3311  {
3312  if (compose_sync == MagickFalse)
3313  {
3314  pixel=(Sc-Dc);
3315  break;
3316  }
3317  if ((Sca-Dca) >= 0.0)
3318  {
3319  pixel=QuantumRange*(Sca-Dca);
3320  break;
3321  }
3322  pixel=QuantumRange*((Sca-Dca)+1.0);
3323  break;
3324  }
3325  case MultiplyCompositeOp:
3326  {
3327  if (compose_sync == MagickFalse)
3328  {
3329  pixel=QuantumScale*Dc*Sc;
3330  break;
3331  }
3332  pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
3333  break;
3334  }
3335  case NegateCompositeOp:
3336  {
3337  pixel=QuantumRange*(1.0-fabs(1.0-Sca-Dca));
3338  break;
3339  }
3340  case OutCompositeOp:
3341  case SrcOutCompositeOp:
3342  {
3343  pixel=QuantumRange*(Sca*(1.0-Da));
3344  break;
3345  }
3346  case OverCompositeOp:
3347  case SrcOverCompositeOp:
3348  {
3349  pixel=QuantumRange*gamma*(Sca+Dca*(1.0-Sa));
3350  break;
3351  }
3352  case OverlayCompositeOp:
3353  {
3354  if ((2.0*Dca) < Da)
3355  {
3356  pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*(1.0-
3357  Da));
3358  break;
3359  }
3360  pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
3361  Sca*(1.0-Da));
3362  break;
3363  }
3365  {
3366  /*
3367  PegTop: A Soft-Light alternative: A continuous version of the
3368  Softlight function, producing very similar results.
3369 
3370  f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
3371 
3372  http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
3373  */
3374  if (fabs((double) Da) < MagickEpsilon)
3375  {
3376  pixel=QuantumRange*gamma*Sca;
3377  break;
3378  }
3379  pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
3380  Da)+Dca*(1.0-Sa));
3381  break;
3382  }
3383  case PinLightCompositeOp:
3384  {
3385  /*
3386  PinLight: A Photoshop 7 composition method
3387  http://www.simplefilter.de/en/basics/mixmods.html
3388 
3389  f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
3390  */
3391  if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
3392  {
3393  pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
3394  break;
3395  }
3396  if ((Dca*Sa) > (2.0*Sca*Da))
3397  {
3398  pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
3399  break;
3400  }
3401  pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
3402  break;
3403  }
3404  case PlusCompositeOp:
3405  {
3406  if (compose_sync == MagickFalse)
3407  {
3408  pixel=(Dc+Sc);
3409  break;
3410  }
3411  pixel=QuantumRange*(Sca+Dca);
3412  break;
3413  }
3414  case ReflectCompositeOp:
3415  {
3416  pixel=QuantumRange*gamma*(Sca*Sca*PerceptibleReciprocal(1.0-Dca));
3417  if (pixel > QuantumRange)
3418  pixel=QuantumRange;
3419  break;
3420  }
3421  case RMSECompositeOp:
3422  {
3423  double
3424  gray;
3425 
3426  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
3427  {
3428  pixel=Dc;
3429  break;
3430  }
3431  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
3432  {
3433  pixel=Sc;
3434  break;
3435  }
3436  gray=sqrt(
3437  (canvas_pixel.red-source_pixel.red)*
3438  (canvas_pixel.red-source_pixel.red)+
3439  (canvas_pixel.green-source_pixel.green)*
3440  (canvas_pixel.green-source_pixel.green)+
3441  (canvas_pixel.blue-source_pixel.blue)*
3442  (canvas_pixel.blue-source_pixel.blue)/3.0);
3443  switch (channel)
3444  {
3445  case RedPixelChannel: pixel=gray; break;
3446  case GreenPixelChannel: pixel=gray; break;
3447  case BluePixelChannel: pixel=gray; break;
3448  default: pixel=Dc; break;
3449  }
3450  break;
3451  }
3452  case SaturateCompositeOp:
3453  {
3454  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
3455  {
3456  pixel=Dc;
3457  break;
3458  }
3459  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
3460  {
3461  pixel=Sc;
3462  break;
3463  }
3464  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
3465  &hue,&chroma,&luma);
3466  CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
3467  &sans,&chroma,&sans);
3468  HCLComposite(hue,chroma,luma,&red,&green,&blue);
3469  switch (channel)
3470  {
3471  case RedPixelChannel: pixel=red; break;
3472  case GreenPixelChannel: pixel=green; break;
3473  case BluePixelChannel: pixel=blue; break;
3474  default: pixel=Dc; break;
3475  }
3476  break;
3477  }
3478  case ScreenCompositeOp:
3479  {
3480  /*
3481  Screen: a negated multiply:
3482 
3483  f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
3484  */
3485  if (compose_sync == MagickFalse)
3486  {
3487  pixel=Sc+Dc-Sc*Dc;
3488  break;
3489  }
3490  pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
3491  break;
3492  }
3493  case SoftBurnCompositeOp:
3494  {
3495  if ((Sca+Dca) < 1.0)
3496  pixel=QuantumRange*gamma*(0.5*Dca*PerceptibleReciprocal(1.0-Sca));
3497  else
3498  pixel=QuantumRange*gamma*(1.0-0.5*(1.0-Sca)*
3499  PerceptibleReciprocal(Dca));
3500  break;
3501  }
3502  case SoftDodgeCompositeOp:
3503  {
3504  if ((Sca+Dca) < 1.0)
3505  pixel=QuantumRange*gamma*(0.5*Sca*PerceptibleReciprocal(1.0-Dca));
3506  else
3507  pixel=QuantumRange*gamma*(1.0-0.5*(1.0-Dca)*
3508  PerceptibleReciprocal(Sca));
3509  break;
3510  }
3511  case SoftLightCompositeOp:
3512  {
3513  if ((2.0*Sca) < Sa)
3514  {
3515  pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-DcaDa))+
3516  Sca*(1.0-Da)+Dca*(1.0-Sa));
3517  break;
3518  }
3519  if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
3520  {
3521  pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*DcaDa*
3522  (4.0*DcaDa+1.0)*(DcaDa-1.0)+7.0*DcaDa)+Sca*(1.0-Da)+
3523  Dca*(1.0-Sa));
3524  break;
3525  }
3526  pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow(DcaDa,0.5)-
3527  DcaDa)+Sca*(1.0-Da)+Dca*(1.0-Sa));
3528  break;
3529  }
3530  case StampCompositeOp:
3531  {
3532  pixel=QuantumRange*(Sca+Dca*Dca-1.0);
3533  break;
3534  }
3535  case StereoCompositeOp:
3536  {
3537  if (channel == RedPixelChannel)
3538  pixel=(MagickRealType) GetPixelRed(source_image,p);
3539  break;
3540  }
3541  case ThresholdCompositeOp:
3542  {
3544  delta;
3545 
3546  delta=Sc-Dc;
3547  if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
3548  {
3549  pixel=gamma*Dc;
3550  break;
3551  }
3552  pixel=gamma*(Dc+delta*amount);
3553  break;
3554  }
3555  case VividLightCompositeOp:
3556  {
3557  /*
3558  VividLight: A Photoshop 7 composition method. See
3559  http://www.simplefilter.de/en/basics/mixmods.html.
3560 
3561  f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
3562  */
3563  if ((fabs((double) Sa) < MagickEpsilon) ||
3564  (fabs((double) (Sca-Sa)) < MagickEpsilon))
3565  {
3566  pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
3567  break;
3568  }
3569  if ((2.0*Sca) <= Sa)
3570  {
3571  pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)*
3572  PerceptibleReciprocal(2.0*Sca))+Sca*(1.0-Da)+Dca*(1.0-Sa));
3573  break;
3574  }
3575  pixel=QuantumRange*gamma*(Dca*Sa*Sa*PerceptibleReciprocal(2.0*
3576  (Sa-Sca))+Sca*(1.0-Da)+Dca*(1.0-Sa));
3577  break;
3578  }
3579  case XorCompositeOp:
3580  {
3581  pixel=QuantumRange*(Sca*(1.0-Da)+Dca*(1.0-Sa));
3582  break;
3583  }
3584  default:
3585  {
3586  pixel=Sc;
3587  break;
3588  }
3589  }
3590  q[i]=clamp != MagickFalse ? ClampPixel(pixel) : ClampToQuantum(pixel);
3591  }
3592  p+=GetPixelChannels(source_image);
3593  channels=GetPixelChannels(source_image);
3594  if (p >= (pixels+channels*source_image->columns))
3595  p=pixels;
3596  q+=GetPixelChannels(image);
3597  }
3598  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3599  status=MagickFalse;
3600  if (image->progress_monitor != (MagickProgressMonitor) NULL)
3601  {
3603  proceed;
3604 
3605 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3606  #pragma omp atomic
3607 #endif
3608  progress++;
3609  proceed=SetImageProgress(image,CompositeImageTag,progress,image->rows);
3610  if (proceed == MagickFalse)
3611  status=MagickFalse;
3612  }
3613  }
3614  source_view=DestroyCacheView(source_view);
3615  image_view=DestroyCacheView(image_view);
3616  if (canvas_image != (Image * ) NULL)
3617  canvas_image=DestroyImage(canvas_image);
3618  else
3619  source_image=DestroyImage(source_image);
3620  return(status);
3621 }
3622 
3623 /*
3624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3625 % %
3626 % %
3627 % %
3628 % T e x t u r e I m a g e %
3629 % %
3630 % %
3631 % %
3632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3633 %
3634 % TextureImage() repeatedly tiles the texture image across and down the image
3635 % canvas.
3636 %
3637 % The format of the TextureImage method is:
3638 %
3639 % MagickBooleanType TextureImage(Image *image,const Image *texture,
3640 % ExceptionInfo *exception)
3641 %
3642 % A description of each parameter follows:
3643 %
3644 % o image: the image.
3645 %
3646 % o texture_image: This image is the texture to layer on the background.
3647 %
3648 */
3650  ExceptionInfo *exception)
3651 {
3652 #define TextureImageTag "Texture/Image"
3653 
3654  CacheView
3655  *image_view,
3656  *texture_view;
3657 
3658  Image
3659  *texture_image;
3660 
3662  status;
3663 
3664  ssize_t
3665  y;
3666 
3667  assert(image != (Image *) NULL);
3668  if (image->debug != MagickFalse)
3669  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3670  assert(image->signature == MagickCoreSignature);
3671  if (texture == (const Image *) NULL)
3672  return(MagickFalse);
3673  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
3674  return(MagickFalse);
3675  texture_image=CloneImage(texture,0,0,MagickTrue,exception);
3676  if (texture_image == (const Image *) NULL)
3677  return(MagickFalse);
3678  (void) TransformImageColorspace(texture_image,image->colorspace,exception);
3680  exception);
3681  status=MagickTrue;
3682  if ((image->compose != CopyCompositeOp) &&
3683  ((image->compose != OverCompositeOp) ||
3684  (image->alpha_trait != UndefinedPixelTrait) ||
3685  (texture_image->alpha_trait != UndefinedPixelTrait)))
3686  {
3687  /*
3688  Tile texture onto the image background.
3689  */
3690  for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
3691  {
3692  ssize_t
3693  x;
3694 
3695  if (status == MagickFalse)
3696  continue;
3697  for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
3698  {
3700  thread_status;
3701 
3702  thread_status=CompositeImage(image,texture_image,image->compose,
3703  MagickTrue,x+texture_image->tile_offset.x,y+
3704  texture_image->tile_offset.y,exception);
3705  if (thread_status == MagickFalse)
3706  {
3707  status=thread_status;
3708  break;
3709  }
3710  }
3711  if (image->progress_monitor != (MagickProgressMonitor) NULL)
3712  {
3714  proceed;
3715 
3717  image->rows);
3718  if (proceed == MagickFalse)
3719  status=MagickFalse;
3720  }
3721  }
3723  image->rows,image->rows);
3724  texture_image=DestroyImage(texture_image);
3725  return(status);
3726  }
3727  /*
3728  Tile texture onto the image background (optimized).
3729  */
3730  status=MagickTrue;
3731  texture_view=AcquireVirtualCacheView(texture_image,exception);
3732  image_view=AcquireAuthenticCacheView(image,exception);
3733 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3734  #pragma omp parallel for schedule(static) shared(status) \
3735  magick_number_threads(texture_image,image,image->rows,1)
3736 #endif
3737  for (y=0; y < (ssize_t) image->rows; y++)
3738  {
3740  sync;
3741 
3742  const Quantum
3743  *p,
3744  *pixels;
3745 
3746  ssize_t
3747  x;
3748 
3749  Quantum
3750  *q;
3751 
3752  size_t
3753  width;
3754 
3755  if (status == MagickFalse)
3756  continue;
3757  pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
3758  (y+texture_image->tile_offset.y) % texture_image->rows,
3759  texture_image->columns,1,exception);
3760  q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3761  if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3762  {
3763  status=MagickFalse;
3764  continue;
3765  }
3766  for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
3767  {
3768  ssize_t
3769  j;
3770 
3771  p=pixels;
3772  width=texture_image->columns;
3773  if ((x+(ssize_t) width) > (ssize_t) image->columns)
3774  width=image->columns-x;
3775  for (j=0; j < (ssize_t) width; j++)
3776  {
3777  ssize_t
3778  i;
3779 
3780  for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
3781  {
3782  PixelChannel channel = GetPixelChannelChannel(texture_image,i);
3783  PixelTrait traits = GetPixelChannelTraits(image,channel);
3784  PixelTrait texture_traits=GetPixelChannelTraits(texture_image,
3785  channel);
3786  if ((traits == UndefinedPixelTrait) ||
3787  (texture_traits == UndefinedPixelTrait))
3788  continue;
3789  SetPixelChannel(image,channel,p[i],q);
3790  }
3791  p+=GetPixelChannels(texture_image);
3792  q+=GetPixelChannels(image);
3793  }
3794  }
3795  sync=SyncCacheViewAuthenticPixels(image_view,exception);
3796  if (sync == MagickFalse)
3797  status=MagickFalse;
3798  if (image->progress_monitor != (MagickProgressMonitor) NULL)
3799  {
3801  proceed;
3802 
3804  image->rows);
3805  if (proceed == MagickFalse)
3806  status=MagickFalse;
3807  }
3808  }
3809  texture_view=DestroyCacheView(texture_view);
3810  image_view=DestroyCacheView(image_view);
3811  texture_image=DestroyImage(texture_image);
3812  return(status);
3813 }
double psi
Definition: geometry.h:108
size_t rows
Definition: image.h:172
#define magick_restrict
Definition: MagickCore.h:41
MagickExport MagickBooleanType TextureImage(Image *image, const Image *texture, ExceptionInfo *exception)
Definition: composite.c:3649
MagickDoubleType MagickRealType
Definition: magick-type.h:124
MagickExport CacheView * DestroyCacheView(CacheView *cache_view)
Definition: cache-view.c:252
#define TransparentAlpha
Definition: image.h:26
static ssize_t GetPixelChannelOffset(const Image *magick_restrict image, const PixelChannel channel)
double x2
Definition: image.h:107
static void HCLComposite(const MagickRealType hue, const MagickRealType chroma, const MagickRealType luma, MagickRealType *red, MagickRealType *green, MagickRealType *blue)
Definition: composite.c:1196
static Image * BlendMeanImage(Image *image, const Image *mask_image, ExceptionInfo *exception)
Definition: composite.c:680
#define FreeDivergentResources()
MagickProgressMonitor progress_monitor
Definition: image.h:303
static Quantum GetPixelAlpha(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
MagickExport MagickBooleanType TransformImageColorspace(Image *image, const ColorspaceType colorspace, ExceptionInfo *exception)
Definition: colorspace.c:1607
static Quantum GetPixelRed(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
MagickExport MagickBooleanType ResamplePixelColor(ResampleFilter *resample_filter, const double u0, const double v0, PixelInfo *pixel, ExceptionInfo *exception)
Definition: resample.c:315
MagickExport KernelInfo * DestroyKernelInfo(KernelInfo *kernel)
Definition: morphology.c:2268
double rho
Definition: geometry.h:108
MagickExport void SetGeometryInfo(GeometryInfo *geometry_info)
Definition: geometry.c:1748
MagickExport MagickBooleanType SetImageArtifact(Image *image, const char *artifact, const char *value)
Definition: artifact.c:448
#define OpaqueAlpha
Definition: image.h:25
static Quantum GetPixelChannel(const Image *magick_restrict image, const PixelChannel channel, const Quantum *magick_restrict pixel)
MagickExport const char * GetImageArtifact(const Image *image, const char *artifact)
Definition: artifact.c:273
MagickRealType red
Definition: pixel.h:193
static Image * BlendMagnitudeImage(const Image *dx_image, const Image *dy_image, ExceptionInfo *exception)
Definition: composite.c:213
MagickExport MagickBooleanType SetImageAlpha(Image *image, const Quantum alpha, ExceptionInfo *exception)
Definition: image.c:2337
static PixelTrait GetPixelChannelTraits(const Image *magick_restrict image, const PixelChannel channel)
MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image, const ssize_t x, const ssize_t y, Quantum *pixel, ExceptionInfo *exception)
Definition: cache.c:1989
#define MagickPI
Definition: image-private.h:42
MagickExport MagickBooleanType InterpolatePixelInfo(const Image *image, const CacheView_ *image_view, const PixelInterpolateMethod method, const double x, const double y, PixelInfo *pixel, ExceptionInfo *exception)
Definition: pixel.c:5484
static void SetPixelViaPixelInfo(const Image *magick_restrict image, const PixelInfo *magick_restrict pixel_info, Quantum *magick_restrict pixel)
static Quantum GetPixelReadMask(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
MagickExport const Quantum * GetCacheViewVirtualPixels(const CacheView *cache_view, const ssize_t x, const ssize_t y, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: cache-view.c:651
MagickRealType alpha
Definition: pixel.h:193
static MagickBooleanType SaliencyBlendImage(Image *image, const Image *source_image, const ssize_t x_offset, const ssize_t y_offset, const double iterations, const double residual_threshold, const size_t tick, ExceptionInfo *exception)
Definition: composite.c:1262
#define MagickEpsilon
Definition: magick-type.h:114
double sigma
Definition: geometry.h:108
static MagickBooleanType BlendMaskAlphaChannel(Image *image, const Image *mask_image, ExceptionInfo *exception)
Definition: composite.c:615
MagickExport MagickBooleanType CompositeImage(Image *image, const Image *composite, const CompositeOperator compose, const MagickBooleanType clip_to_self, const ssize_t x_offset, const ssize_t y_offset, ExceptionInfo *exception)
Definition: composite.c:1525
RectangleInfo tile_offset
Definition: image.h:261
MagickExport ResampleFilter * AcquireResampleFilter(const Image *image, ExceptionInfo *exception)
Definition: resample.c:208
Definition: log.h:52
ssize_t MagickOffsetType
Definition: magick-type.h:133
MagickExport void GetPixelInfo(const Image *image, PixelInfo *pixel)
Definition: pixel.c:2170
static Quantum ClampToQuantum(const MagickRealType quantum)
Definition: quantum.h:85
Definition: image.h:151
MagickExport Image * CropImage(const Image *image, const RectangleInfo *geometry, ExceptionInfo *exception)
Definition: transform.c:537
double x
Definition: geometry.h:125
MagickExport KernelInfo * AcquireKernelInfo(const char *kernel_string, ExceptionInfo *exception)
Definition: morphology.c:485
#define MagickCoreSignature
MagickExport Quantum * GetCacheViewAuthenticPixels(CacheView *cache_view, const ssize_t x, const ssize_t y, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: cache-view.c:299
static Quantum ClampPixel(const MagickRealType pixel)
MagickExport MagickBooleanType SetImageMask(Image *image, const PixelMask type, const Image *mask, ExceptionInfo *exception)
Definition: image.c:3201
MagickExport ssize_t FormatLocaleFile(FILE *file, const char *magick_restrict format,...)
Definition: locale.c:370
MagickExport MagickBooleanType SetImageAlphaChannel(Image *image, const AlphaChannelOption alpha_type, ExceptionInfo *exception)
Definition: channel.c:973
MagickBooleanType
Definition: magick-type.h:161
unsigned int MagickStatusType
Definition: magick-type.h:125
static double PerceptibleReciprocal(const double x)
static void CompositeHCL(const MagickRealType red, const MagickRealType green, const MagickRealType blue, MagickRealType *hue, MagickRealType *chroma, MagickRealType *luma)
Definition: composite.c:915
double x1
Definition: image.h:107
static double DegreesToRadians(const double degrees)
Definition: image-private.h:66
double y
Definition: geometry.h:125
static Quantum GetPixelGreen(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
MagickExport MagickBooleanType IsStringTrue(const char *value)
Definition: string.c:1386
static void GetPixelInfoPixel(const Image *magick_restrict image, const Quantum *magick_restrict pixel, PixelInfo *magick_restrict pixel_info)
PixelTrait alpha_trait
Definition: image.h:280
MagickRealType blue
Definition: pixel.h:193
static Quantum GetPixelBlack(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
MagickExport Quantum * QueueCacheViewAuthenticPixels(CacheView *cache_view, const ssize_t x, const ssize_t y, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: cache-view.c:977
MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(Image *image, const VirtualPixelMethod virtual_pixel_method, ExceptionInfo *exception)
Definition: image.c:3508
double y2
Definition: image.h:107
MagickExport MagickBooleanType ThrowMagickException(ExceptionInfo *exception, const char *module, const char *function, const size_t line, const ExceptionType severity, const char *tag, const char *format,...)
Definition: exception.c:1145
MagickExport MagickBooleanType LogMagickEvent(const LogEventType type, const char *module, const char *function, const size_t line, const char *format,...)
Definition: log.c:1662
size_t signature
Definition: image.h:354
#define QuantumScale
Definition: magick-type.h:119
size_t columns
Definition: image.h:172
ssize_t x
Definition: geometry.h:136
MagickBooleanType(* MagickProgressMonitor)(const char *, const MagickOffsetType, const MagickSizeType, void *)
Definition: monitor.h:26
MagickExport ResampleFilter * DestroyResampleFilter(ResampleFilter *resample_filter)
Definition: resample.c:262
static Image * BlendDivergentImage(const Image *alpha_image, const Image *beta_image, ExceptionInfo *exception)
Definition: composite.c:489
MagickExport MagickBooleanType SetImageStorageClass(Image *image, const ClassType storage_class, ExceptionInfo *exception)
Definition: image.c:2616
static Image * BlendConvolveImage(const Image *image, const char *kernel, ExceptionInfo *exception)
Definition: composite.c:184
MagickExport MagickBooleanType ResetImagePage(Image *image, const char *page)
Definition: image.c:2170
PixelChannel
Definition: pixel.h:70
static double RoundToUnity(const double value)
#define MagickMax(x, y)
Definition: image-private.h:38
MagickExport void SetResampleFilter(ResampleFilter *resample_filter, const FilterType filter)
Definition: resample.c:1241
MagickExport void ScaleResampleFilter(ResampleFilter *resample_filter, const double dux, const double duy, const double dvx, const double dvy)
Definition: resample.c:1038
static size_t GetPixelChannels(const Image *magick_restrict image)
char filename[MagickPathExtent]
Definition: image.h:319
#define GetMagickModule()
Definition: log.h:28
MagickExport MagickBooleanType IsFuzzyEquivalencePixel(const Image *source, const Quantum *p, const Image *destination, const Quantum *q)
Definition: pixel.c:5957
static PixelChannel GetPixelChannelChannel(const Image *magick_restrict image, const ssize_t offset)
MagickExport CacheView * AcquireVirtualCacheView(const Image *image, ExceptionInfo *exception)
Definition: cache-view.c:149
static Image * BlendSumImage(const Image *alpha_image, const Image *beta_image, const double attenuate, const double sign, ExceptionInfo *exception)
Definition: composite.c:402
static MagickBooleanType SeamlessBlendImage(Image *image, const Image *source_image, const ssize_t x_offset, const ssize_t y_offset, const double iterations, const double residual_threshold, const size_t tick, ExceptionInfo *exception)
Definition: composite.c:1392
unsigned short Quantum
Definition: magick-type.h:86
double xi
Definition: geometry.h:108
MagickExport MagickBooleanType SetImageColorspace(Image *image, const ColorspaceType colorspace, ExceptionInfo *exception)
Definition: colorspace.c:1418
static Image * BlendMaxMagnitudeImage(const Image *alpha_image, const Image *beta_image, const Image *dx_image, const Image *dy_image, ExceptionInfo *exception)
Definition: composite.c:299
MagickExport MagickStatusType ParseGeometry(const char *geometry, GeometryInfo *geometry_info)
Definition: geometry.c:866
static void SetPixelChannel(const Image *magick_restrict image, const PixelChannel channel, const Quantum quantum, Quantum *magick_restrict pixel)
#define MagickMin(x, y)
Definition: image-private.h:39
static void SetPixelAlpha(const Image *magick_restrict image, const Quantum alpha, Quantum *magick_restrict pixel)
#define CompositeImageTag
MagickExport Image * ConvolveImage(const Image *image, const KernelInfo *kernel_info, ExceptionInfo *exception)
Definition: effect.c:1173
static MagickBooleanType BlendRMSEResidual(const Image *alpha_image, const Image *beta_image, double *residual, ExceptionInfo *exception)
Definition: composite.c:807
static size_t GetImageChannels(const Image *image)
Definition: image-private.h:71
#define MaxPixelChannels
Definition: pixel.h:27
MagickRealType green
Definition: pixel.h:193
CompositeOperator compose
Definition: image.h:234
#define TextureImageTag
static MagickBooleanType CompositeOverImage(Image *image, const Image *source_image, const MagickBooleanType clip_to_self, const ssize_t x_offset, const ssize_t y_offset, ExceptionInfo *exception)
Definition: composite.c:955
CompositeOperator
Definition: composite.h:25
#define MagickExport
MagickExport MagickBooleanType SyncCacheViewAuthenticPixels(CacheView *magick_restrict cache_view, ExceptionInfo *exception)
Definition: cache-view.c:1100
ssize_t y
Definition: geometry.h:136
MagickExport CacheView * AcquireAuthenticCacheView(const Image *image, ExceptionInfo *exception)
Definition: cache-view.c:112
double y1
Definition: image.h:107
static Quantum GetPixelBlue(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
PixelTrait
Definition: pixel.h:137
MagickExport MagickRealType GetPixelIntensity(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
Definition: pixel.c:2358
MagickExport Image * DestroyImage(Image *image)
Definition: image.c:1179
MagickExport Image * CloneImage(const Image *image, const size_t columns, const size_t rows, const MagickBooleanType detach, ExceptionInfo *exception)
Definition: image.c:787
ColorspaceType colorspace
Definition: image.h:157
#define QuantumRange
Definition: magick-type.h:87
MagickExport MagickBooleanType SetImageProgress(const Image *image, const char *tag, const MagickOffsetType offset, const MagickSizeType extent)
Definition: monitor.c:136
MagickBooleanType debug
Definition: image.h:334