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