MagickCore  7.1.2-29
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/license/ %
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  channel_residual = 0.0;
818 
819  MagickBooleanType
820  status = MagickTrue;
821 
822  size_t
823  columns = MagickMax(alpha_image->columns,beta_image->columns),
824  rows = MagickMax(alpha_image->rows,beta_image->rows);
825 
826  ssize_t
827  y;
828 
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  reduction(+:area) reduction(+:channel_residual) \
834  magick_number_threads(alpha_image,alpha_image,rows,1)
835 #endif
836  for (y=0; y < (ssize_t) rows; y++)
837  {
838  const Quantum
839  *magick_restrict p,
840  *magick_restrict q;
841 
842  ssize_t
843  x;
844 
845  if (status == MagickFalse)
846  continue;
847  p=GetCacheViewVirtualPixels(alpha_view,0,y,columns,1,exception);
848  q=GetCacheViewVirtualPixels(beta_view,0,y,columns,1,exception);
849  if ((p == (const Quantum *) NULL) || (q == (const Quantum *) NULL))
850  {
851  status=MagickFalse;
852  continue;
853  }
854  channel_residual=0.0;
855  for (x=0; x < (ssize_t) columns; x++)
856  {
857  double
858  Da,
859  Sa;
860 
861  ssize_t
862  i;
863 
864  if ((GetPixelReadMask(alpha_image,p) <= (QuantumRange/2)) ||
865  (GetPixelReadMask(beta_image,q) <= (QuantumRange/2)))
866  {
867  p+=(ptrdiff_t) GetPixelChannels(alpha_image);
868  q+=(ptrdiff_t) GetPixelChannels(beta_image);
869  continue;
870  }
871  Sa=QuantumScale*(double) GetPixelAlpha(alpha_image,p);
872  Da=QuantumScale*(double) GetPixelAlpha(beta_image,q);
873  for (i=0; i < (ssize_t) GetPixelChannels(alpha_image); i++)
874  {
875  double
876  distance;
877 
878  PixelChannel channel = GetPixelChannelChannel(alpha_image,i);
879  PixelTrait traits = GetPixelChannelTraits(alpha_image,channel);
880  PixelTrait beta_traits = GetPixelChannelTraits(beta_image,channel);
881  if ((traits == UndefinedPixelTrait) ||
882  (beta_traits == UndefinedPixelTrait) ||
883  ((beta_traits & UpdatePixelTrait) == 0))
884  continue;
885  if (channel == AlphaPixelChannel)
886  distance=QuantumScale*((double) p[i]-(double) GetPixelChannel(
887  beta_image,channel,q));
888  else
889  distance=QuantumScale*(Sa*(double) p[i]-Da*(double) GetPixelChannel(
890  beta_image,channel,q));
891  channel_residual+=distance*distance;
892  }
893  area++;
894  p+=(ptrdiff_t) GetPixelChannels(alpha_image);
895  q+=(ptrdiff_t) GetPixelChannels(beta_image);
896  }
897  }
898  beta_view=DestroyCacheView(beta_view);
899  alpha_view=DestroyCacheView(alpha_view);
900  area=MagickSafeReciprocal(area);
901  *residual=sqrt(area*channel_residual/(double) GetImageChannels(alpha_image));
902  return(status);
903 }
904 
905 static MagickBooleanType CompositeOverImage(Image *image,
906  const Image *source_image,const MagickBooleanType clip_to_self,
907  const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
908 {
909 #define CompositeImageTag "Composite/Image"
910 
911  CacheView
912  *image_view,
913  *source_view;
914 
915  const char
916  *value;
917 
918  MagickBooleanType
919  clamp,
920  status;
921 
922  MagickOffsetType
923  progress;
924 
925  ssize_t
926  y;
927 
928  /*
929  Composite image.
930  */
931  status=MagickTrue;
932  progress=0;
933  clamp=MagickTrue;
934  value=GetImageArtifact(image,"compose:clamp");
935  if (value != (const char *) NULL)
936  clamp=IsStringTrue(value);
937  status=MagickTrue;
938  progress=0;
939  source_view=AcquireVirtualCacheView(source_image,exception);
940  image_view=AcquireAuthenticCacheView(image,exception);
941 #if defined(MAGICKCORE_OPENMP_SUPPORT)
942  #pragma omp parallel for schedule(static) shared(progress,status) \
943  magick_number_threads(source_image,image,image->rows,1)
944 #endif
945  for (y=0; y < (ssize_t) image->rows; y++)
946  {
947  const Quantum
948  *pixels;
949 
950  PixelInfo
951  canvas_pixel,
952  source_pixel;
953 
954  const Quantum
955  *magick_restrict p;
956 
957  Quantum
958  *magick_restrict q;
959 
960  ssize_t
961  x;
962 
963  if (status == MagickFalse)
964  continue;
965  if (clip_to_self != MagickFalse)
966  {
967  if (y < y_offset)
968  continue;
969  if ((y-y_offset) >= (ssize_t) source_image->rows)
970  continue;
971  }
972  /*
973  If pixels is NULL, y is outside overlay region.
974  */
975  pixels=(Quantum *) NULL;
976  p=(Quantum *) NULL;
977  if ((y >= y_offset) &&
978  ((y-y_offset) < (ssize_t) source_image->rows))
979  {
980  p=GetCacheViewVirtualPixels(source_view,0,CastDoubleToSsizeT((double) y-
981  y_offset),source_image->columns,1,exception);
982  if (p == (const Quantum *) NULL)
983  {
984  status=MagickFalse;
985  continue;
986  }
987  pixels=p;
988  if (x_offset < 0)
989  p-=(ptrdiff_t) CastDoubleToSsizeT((double) x_offset*
990  GetPixelChannels(source_image));
991  }
992  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
993  if (q == (Quantum *) NULL)
994  {
995  status=MagickFalse;
996  continue;
997  }
998  GetPixelInfo(image,&canvas_pixel);
999  GetPixelInfo(source_image,&source_pixel);
1000  for (x=0; x < (ssize_t) image->columns; x++)
1001  {
1002  double
1003  gamma;
1004 
1005  MagickRealType
1006  alpha,
1007  Da,
1008  Dc,
1009  Dca,
1010  Sa,
1011  Sc,
1012  Sca;
1013 
1014  ssize_t
1015  i;
1016 
1017  size_t
1018  channels;
1019 
1020  if (clip_to_self != MagickFalse)
1021  {
1022  if (x < x_offset)
1023  {
1024  q+=(ptrdiff_t) GetPixelChannels(image);
1025  continue;
1026  }
1027  if ((x-x_offset) >= (ssize_t) source_image->columns)
1028  break;
1029  }
1030  if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1031  ((x-x_offset) >= (ssize_t) source_image->columns))
1032  {
1033  Quantum
1034  source[MaxPixelChannels];
1035 
1036  /*
1037  Virtual composite:
1038  Sc: source color.
1039  Dc: canvas color.
1040  */
1041  (void) GetOneVirtualPixel(source_image,
1042  CastDoubleToSsizeT((double) x-x_offset),
1043  CastDoubleToSsizeT((double) y-y_offset),source,exception);
1044  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1045  {
1046  MagickRealType
1047  pixel;
1048 
1049  PixelChannel channel = GetPixelChannelChannel(image,i);
1050  PixelTrait traits = GetPixelChannelTraits(image,channel);
1051  PixelTrait source_traits=GetPixelChannelTraits(source_image,
1052  channel);
1053  if ((traits == UndefinedPixelTrait) ||
1054  (source_traits == UndefinedPixelTrait))
1055  continue;
1056  if (channel == AlphaPixelChannel)
1057  pixel=(MagickRealType) TransparentAlpha;
1058  else
1059  pixel=(MagickRealType) q[i];
1060  q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
1061  ClampToQuantum(pixel);
1062  }
1063  q+=(ptrdiff_t) GetPixelChannels(image);
1064  continue;
1065  }
1066  /*
1067  Authentic composite:
1068  Sa: normalized source alpha.
1069  Da: normalized canvas alpha.
1070  */
1071  Sa=QuantumScale*(double) GetPixelAlpha(source_image,p);
1072  Da=QuantumScale*(double) GetPixelAlpha(image,q);
1073  alpha=Sa+Da-Sa*Da;
1074  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1075  {
1076  MagickRealType
1077  pixel;
1078 
1079  PixelChannel channel = GetPixelChannelChannel(image,i);
1080  PixelTrait traits = GetPixelChannelTraits(image,channel);
1081  PixelTrait source_traits=GetPixelChannelTraits(source_image,channel);
1082  if (traits == UndefinedPixelTrait)
1083  continue;
1084  if ((source_traits == UndefinedPixelTrait) &&
1085  (channel != AlphaPixelChannel))
1086  continue;
1087  if (channel == AlphaPixelChannel)
1088  {
1089  /*
1090  Set alpha channel.
1091  */
1092  pixel=(double) QuantumRange*alpha;
1093  q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
1094  ClampToQuantum(pixel);
1095  continue;
1096  }
1097  /*
1098  Sc: source color.
1099  Dc: canvas color.
1100  */
1101  Sc=(MagickRealType) GetPixelChannel(source_image,channel,p);
1102  Dc=(MagickRealType) q[i];
1103  if ((traits & CopyPixelTrait) != 0)
1104  {
1105  /*
1106  Copy channel.
1107  */
1108  q[i]=ClampToQuantum(Sc);
1109  continue;
1110  }
1111  /*
1112  Porter-Duff compositions:
1113  Sca: source normalized color multiplied by alpha.
1114  Dca: normalized canvas color multiplied by alpha.
1115  */
1116  Sca=QuantumScale*Sa*Sc;
1117  Dca=QuantumScale*Da*Dc;
1118  gamma=MagickSafeReciprocal(alpha);
1119  pixel=(double) QuantumRange*gamma*(Sca+Dca*(1.0-Sa));
1120  q[i]=clamp != MagickFalse ? ClampPixel(pixel) : ClampToQuantum(pixel);
1121  }
1122  p+=(ptrdiff_t) GetPixelChannels(source_image);
1123  channels=GetPixelChannels(source_image);
1124  if (p >= (pixels+channels*source_image->columns))
1125  p=pixels;
1126  q+=(ptrdiff_t) GetPixelChannels(image);
1127  }
1128  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1129  status=MagickFalse;
1130  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1131  {
1132  MagickBooleanType
1133  proceed;
1134 
1135 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1136  #pragma omp atomic
1137 #endif
1138  progress++;
1139  proceed=SetImageProgress(image,CompositeImageTag,progress,image->rows);
1140  if (proceed == MagickFalse)
1141  status=MagickFalse;
1142  }
1143  }
1144  source_view=DestroyCacheView(source_view);
1145  image_view=DestroyCacheView(image_view);
1146  return(status);
1147 }
1148 
1149 static MagickBooleanType SaliencyBlendImage(Image *image,
1150  const Image *source_image,const ssize_t x_offset,const ssize_t y_offset,
1151  const double iterations,const double residual_threshold,const size_t tick,
1152  ExceptionInfo *exception)
1153 {
1154  Image
1155  *crop_image,
1156  *divergent_image,
1157  *relax_image,
1158  *residual_image = (Image *) NULL;
1159 
1160  KernelInfo
1161  *kernel_info;
1162 
1163  MagickBooleanType
1164  status = MagickTrue,
1165  verbose = MagickFalse;
1166 
1168  crop_info = {
1169  source_image->columns,
1170  source_image->rows,
1171  x_offset,
1172  y_offset
1173  };
1174 
1175  ssize_t
1176  i;
1177 
1178  /*
1179  Saliency blend composite operator.
1180  */
1181  crop_image=CropImage(image,&crop_info,exception);
1182  if (crop_image == (Image *) NULL)
1183  return(MagickFalse);
1184  DisableCompositeClampUnlessSpecified(crop_image);
1185  divergent_image=BlendDivergentImage(crop_image,source_image,exception);
1186  if (divergent_image == (Image *) NULL)
1187  {
1188  crop_image=DestroyImage(crop_image);
1189  return(MagickFalse);
1190  }
1191  (void) ResetImagePage(crop_image,"0x0+0+0");
1192  relax_image=BlendMeanImage(crop_image,source_image,exception);
1193  if (relax_image == (Image *) NULL)
1194  {
1195  crop_image=DestroyImage(crop_image);
1196  divergent_image=DestroyImage(divergent_image);
1197  return(MagickFalse);
1198  }
1199  status=BlendMaskAlphaChannel(crop_image,source_image,exception);
1200  if (status == MagickFalse)
1201  {
1202  crop_image=DestroyImage(crop_image);
1203  divergent_image=DestroyImage(divergent_image);
1204  return(MagickFalse);
1205  }
1206  residual_image=CloneImage(relax_image,0,0,MagickTrue,exception);
1207  if (residual_image == (Image *) NULL)
1208  {
1209  crop_image=DestroyImage(crop_image);
1210  relax_image=DestroyImage(relax_image);
1211  return(MagickFalse);
1212  }
1213  /*
1214  Convolve relaxed image and blur area of interest.
1215  */
1216  kernel_info=AcquireKernelInfo("3x3:0,0.25,0,0.25,0,0.25,0,0.25,0",exception);
1217  if (kernel_info == (KernelInfo *) NULL)
1218  {
1219  crop_image=DestroyImage(crop_image);
1220  residual_image=DestroyImage(residual_image);
1221  relax_image=DestroyImage(relax_image);
1222  return(MagickFalse);
1223  }
1224  verbose=IsStringTrue(GetImageArtifact(image,"verbose"));
1225  if (verbose != MagickFalse)
1226  (void) FormatLocaleFile(stderr,"saliency blending:\n");
1227  for (i=0; i < (ssize_t) iterations; i++)
1228  {
1229  double
1230  residual = 1.0;
1231 
1232  Image
1233  *convolve_image,
1234  *sum_image;
1235 
1236  convolve_image=ConvolveImage(relax_image,kernel_info,exception);
1237  if (convolve_image == (Image *) NULL)
1238  break;
1239  relax_image=DestroyImage(relax_image);
1240  relax_image=convolve_image;
1241  sum_image=BlendSumImage(relax_image,divergent_image,1.0,-1.0,exception);
1242  if (sum_image == (Image *) NULL)
1243  break;
1244  relax_image=DestroyImage(relax_image);
1245  relax_image=sum_image;
1246  status=CompositeOverImage(relax_image,crop_image,MagickTrue,0,0,exception);
1247  if (status == MagickFalse)
1248  break;
1249  status=BlendRMSEResidual(relax_image,residual_image,&residual,exception);
1250  if (status == MagickFalse)
1251  break;
1252  if ((verbose != MagickFalse) && ((i % MagickMax(tick,1)) == 0))
1253  (void) FormatLocaleFile(stderr," %g: %g\n",(double) i,(double) residual);
1254  if (residual < residual_threshold)
1255  {
1256  if (verbose != MagickFalse)
1257  (void) FormatLocaleFile(stderr," %g: %g\n",(double) i,(double)
1258  residual);
1259  break;
1260  }
1261  residual_image=DestroyImage(residual_image);
1262  residual_image=CloneImage(relax_image,0,0,MagickTrue,exception);
1263  if (residual_image == (Image *) NULL)
1264  break;
1265  }
1266  kernel_info=DestroyKernelInfo(kernel_info);
1267  crop_image=DestroyImage(crop_image);
1268  divergent_image=DestroyImage(divergent_image);
1269  residual_image=DestroyImage(residual_image);
1270  /*
1271  Composite relaxed over the background image.
1272  */
1273  status=CompositeOverImage(image,relax_image,MagickTrue,x_offset,y_offset,
1274  exception);
1275  relax_image=DestroyImage(relax_image);
1276  return(status);
1277 }
1278 
1279 static MagickBooleanType SeamlessBlendImage(Image *image,
1280  const Image *source_image,const ssize_t x_offset,const ssize_t y_offset,
1281  const double iterations,const double residual_threshold,const size_t tick,
1282  ExceptionInfo *exception)
1283 {
1284  Image
1285  *crop_image,
1286  *foreground_image,
1287  *mean_image,
1288  *relax_image,
1289  *residual_image,
1290  *sum_image;
1291 
1292  KernelInfo
1293  *kernel_info;
1294 
1295  MagickBooleanType
1296  status = MagickTrue,
1297  verbose = MagickFalse;
1298 
1300  crop_info = {
1301  source_image->columns,
1302  source_image->rows,
1303  x_offset,
1304  y_offset
1305  };
1306 
1307  ssize_t
1308  i;
1309 
1310  /*
1311  Seamless blend composite operator.
1312  */
1313  crop_image=CropImage(image,&crop_info,exception);
1314  if (crop_image == (Image *) NULL)
1315  return(MagickFalse);
1316  DisableCompositeClampUnlessSpecified(crop_image);
1317  (void) ResetImagePage(crop_image,"0x0+0+0");
1318  sum_image=BlendSumImage(crop_image,source_image,1.0,-1.0,exception);
1319  crop_image=DestroyImage(crop_image);
1320  if (sum_image == (Image *) NULL)
1321  return(MagickFalse);
1322  mean_image=BlendMeanImage(sum_image,source_image,exception);
1323  sum_image=DestroyImage(sum_image);
1324  if (mean_image == (Image *) NULL)
1325  return(MagickFalse);
1326  relax_image=CloneImage(mean_image,0,0,MagickTrue,exception);
1327  if (relax_image == (Image *) NULL)
1328  {
1329  mean_image=DestroyImage(mean_image);
1330  return(MagickFalse);
1331  }
1332  status=BlendMaskAlphaChannel(mean_image,source_image,exception);
1333  if (status == MagickFalse)
1334  {
1335  relax_image=DestroyImage(relax_image);
1336  mean_image=DestroyImage(mean_image);
1337  return(MagickFalse);
1338  }
1339  residual_image=CloneImage(relax_image,0,0,MagickTrue,exception);
1340  if (residual_image == (Image *) NULL)
1341  {
1342  relax_image=DestroyImage(relax_image);
1343  mean_image=DestroyImage(mean_image);
1344  return(MagickFalse);
1345  }
1346  /*
1347  Convolve relaxed image and blur area of interest.
1348  */
1349  kernel_info=AcquireKernelInfo("3x3:0,0.25,0,0.25,0,0.25,0,0.25,0",exception);
1350  if (kernel_info == (KernelInfo *) NULL)
1351  {
1352  residual_image=DestroyImage(residual_image);
1353  relax_image=DestroyImage(relax_image);
1354  mean_image=DestroyImage(mean_image);
1355  return(MagickFalse);
1356  }
1357  verbose=IsStringTrue(GetImageArtifact(image,"verbose"));
1358  if (verbose != MagickFalse)
1359  (void) FormatLocaleFile(stderr,"seamless blending:\n");
1360  for (i=0; i < (ssize_t) iterations; i++)
1361  {
1362  double
1363  residual = 1.0;
1364 
1365  Image
1366  *convolve_image;
1367 
1368  convolve_image=ConvolveImage(relax_image,kernel_info,exception);
1369  if (convolve_image == (Image *) NULL)
1370  break;
1371  relax_image=DestroyImage(relax_image);
1372  relax_image=convolve_image;
1373  status=CompositeOverImage(relax_image,mean_image,MagickTrue,0,0,exception);
1374  if (status == MagickFalse)
1375  break;
1376  status=BlendRMSEResidual(relax_image,residual_image,&residual,exception);
1377  if (status == MagickFalse)
1378  break;
1379  if ((verbose != MagickFalse) && ((i % MagickMax(tick,1)) == 0))
1380  (void) FormatLocaleFile(stderr," %g: %g\n",(double) i,(double) residual);
1381  if (residual < residual_threshold)
1382  {
1383  if (verbose != MagickFalse)
1384  (void) FormatLocaleFile(stderr," %g: %g\n",(double) i,(double)
1385  residual);
1386  break;
1387  }
1388  if (residual_image != (Image *) NULL)
1389  residual_image=DestroyImage(residual_image);
1390  residual_image=CloneImage(relax_image,0,0,MagickTrue,exception);
1391  if (residual_image == (Image *) NULL)
1392  break;
1393  }
1394  kernel_info=DestroyKernelInfo(kernel_info);
1395  mean_image=DestroyImage(mean_image);
1396  residual_image=DestroyImage(residual_image);
1397  /*
1398  Composite the foreground image over the background image.
1399  */
1400  foreground_image=BlendSumImage(source_image,relax_image,1.0,1.0,exception);
1401  relax_image=DestroyImage(relax_image);
1402  if (foreground_image == (Image *) NULL)
1403  return(MagickFalse);
1404  (void) SetImageMask(foreground_image,ReadPixelMask,(const Image *) NULL,
1405  exception);
1406  status=CompositeOverImage(image,foreground_image,MagickTrue,x_offset,y_offset,
1407  exception);
1408  foreground_image=DestroyImage(foreground_image);
1409  return(status);
1410 }
1411 
1412 MagickExport MagickBooleanType CompositeImage(Image *image,
1413  const Image *composite,const CompositeOperator compose,
1414  const MagickBooleanType clip_to_self,const ssize_t x_offset,
1415  const ssize_t y_offset,ExceptionInfo *exception)
1416 {
1417 #define CompositeImageTag "Composite/Image"
1418 
1419  CacheView
1420  *source_view,
1421  *image_view;
1422 
1423  ColorspaceType
1424  colorspace = HCLColorspace;
1425 
1426  const char
1427  *artifact;
1428 
1429  double
1430  white_luminance = 10000.0;
1431 
1432  GeometryInfo
1433  geometry_info;
1434 
1435  IlluminantType
1436  illuminant = D65Illuminant;
1437 
1438  Image
1439  *canvas_image,
1440  *source_image;
1441 
1442  MagickBooleanType
1443  clamp,
1444  compose_sync,
1445  status;
1446 
1447  MagickOffsetType
1448  progress;
1449 
1450  MagickRealType
1451  amount,
1452  canvas_dissolve,
1453  midpoint,
1454  percent_luma,
1455  percent_chroma,
1456  source_dissolve,
1457  threshold;
1458 
1459  MagickStatusType
1460  flags;
1461 
1462  ssize_t
1463  y;
1464 
1465  assert(image != (Image *) NULL);
1466  assert(image->signature == MagickCoreSignature);
1467  assert(composite != (Image *) NULL);
1468  assert(composite->signature == MagickCoreSignature);
1469  if (IsEventLogging() != MagickFalse)
1470  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1471  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1472  return(MagickFalse);
1473  source_image=CloneImage(composite,0,0,MagickTrue,exception);
1474  if (source_image == (const Image *) NULL)
1475  return(MagickFalse);
1476  (void) SetImageColorspace(source_image,image->colorspace,exception);
1477  if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
1478  {
1479  status=CompositeOverImage(image,source_image,clip_to_self,x_offset,
1480  y_offset,exception);
1481  source_image=DestroyImage(source_image);
1482  return(status);
1483  }
1484  amount=0.5;
1485  canvas_image=(Image *) NULL;
1486  canvas_dissolve=1.0;
1487  white_luminance=10000.0;
1488  artifact=GetImageArtifact(image,"compose:white-luminance");
1489  if (artifact != (const char *) NULL)
1490  white_luminance=StringToDouble(artifact,(char **) NULL);
1491  artifact=GetImageArtifact(image,"compose:illuminant");
1492  if (artifact != (const char *) NULL)
1493  {
1494  ssize_t
1495  illuminant_type;
1496 
1497  illuminant_type=ParseCommandOption(MagickIlluminantOptions,MagickFalse,
1498  artifact);
1499  if (illuminant_type < 0)
1500  illuminant=UndefinedIlluminant;
1501  else
1502  illuminant=(IlluminantType) illuminant_type;
1503  }
1504  artifact=GetImageArtifact(image,"compose:colorspace");
1505  if (artifact != (const char *) NULL)
1506  {
1507  ssize_t
1508  colorspace_type;
1509 
1510  colorspace_type=ParseCommandOption(MagickColorspaceOptions,MagickFalse,
1511  artifact);
1512  if (colorspace_type < 0)
1513  colorspace=UndefinedColorspace;
1514  else
1515  colorspace=(ColorspaceType) colorspace_type;
1516  }
1517  clamp=MagickTrue;
1518  artifact=GetImageArtifact(image,"compose:clamp");
1519  if (artifact != (const char *) NULL)
1520  clamp=IsStringTrue(artifact);
1521  compose_sync=MagickTrue;
1522  artifact=GetImageArtifact(image,"compose:sync");
1523  if (artifact != (const char *) NULL)
1524  compose_sync=IsStringTrue(artifact);
1525  SetGeometryInfo(&geometry_info);
1526  percent_luma=100.0;
1527  percent_chroma=100.0;
1528  source_dissolve=1.0;
1529  threshold=0.05f;
1530  switch (compose)
1531  {
1532  case CopyCompositeOp:
1533  {
1534  if ((x_offset < 0) || (y_offset < 0))
1535  break;
1536  if ((x_offset+(ssize_t) source_image->columns) > (ssize_t) image->columns)
1537  break;
1538  if ((y_offset+(ssize_t) source_image->rows) > (ssize_t) image->rows)
1539  break;
1540  if ((source_image->alpha_trait == UndefinedPixelTrait) &&
1541  (image->alpha_trait != UndefinedPixelTrait))
1542  (void) SetImageAlphaChannel(source_image,OpaqueAlphaChannel,exception);
1543  status=MagickTrue;
1544  source_view=AcquireVirtualCacheView(source_image,exception);
1545  image_view=AcquireAuthenticCacheView(image,exception);
1546 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1547  #pragma omp parallel for schedule(static) shared(status) \
1548  magick_number_threads(source_image,image,source_image->rows,4)
1549 #endif
1550  for (y=0; y < (ssize_t) source_image->rows; y++)
1551  {
1552  MagickBooleanType
1553  sync;
1554 
1555  const Quantum
1556  *p;
1557 
1558  Quantum
1559  *q;
1560 
1561  ssize_t
1562  x;
1563 
1564  if (status == MagickFalse)
1565  continue;
1566  p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
1567  exception);
1568  q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
1569  source_image->columns,1,exception);
1570  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1571  {
1572  status=MagickFalse;
1573  continue;
1574  }
1575  for (x=0; x < (ssize_t) source_image->columns; x++)
1576  {
1577  ssize_t
1578  i;
1579 
1580  if (GetPixelReadMask(source_image,p) <= (QuantumRange/2))
1581  {
1582  p+=(ptrdiff_t) GetPixelChannels(source_image);
1583  q+=(ptrdiff_t) GetPixelChannels(image);
1584  continue;
1585  }
1586  for (i=0; i < (ssize_t) GetPixelChannels(source_image); i++)
1587  {
1588  PixelChannel channel = GetPixelChannelChannel(source_image,i);
1589  PixelTrait source_traits = GetPixelChannelTraits(source_image,
1590  channel);
1591  PixelTrait traits = GetPixelChannelTraits(image,channel);
1592  if ((source_traits == UndefinedPixelTrait) ||
1593  (traits == UndefinedPixelTrait))
1594  continue;
1595  SetPixelChannel(image,channel,p[i],q);
1596  }
1597  p+=(ptrdiff_t) GetPixelChannels(source_image);
1598  q+=(ptrdiff_t) GetPixelChannels(image);
1599  }
1600  sync=SyncCacheViewAuthenticPixels(image_view,exception);
1601  if (sync == MagickFalse)
1602  status=MagickFalse;
1603  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1604  {
1605  MagickBooleanType
1606  proceed;
1607 
1608  proceed=SetImageProgress(image,CompositeImageTag,(MagickOffsetType)
1609  y,image->rows);
1610  if (proceed == MagickFalse)
1611  status=MagickFalse;
1612  }
1613  }
1614  source_view=DestroyCacheView(source_view);
1615  image_view=DestroyCacheView(image_view);
1616  source_image=DestroyImage(source_image);
1617  return(status);
1618  }
1619  case IntensityCompositeOp:
1620  {
1621  if ((x_offset < 0) || (y_offset < 0))
1622  break;
1623  if ((x_offset+(ssize_t) source_image->columns) > (ssize_t) image->columns)
1624  break;
1625  if ((y_offset+(ssize_t) source_image->rows) > (ssize_t) image->rows)
1626  break;
1627  status=MagickTrue;
1628  source_view=AcquireVirtualCacheView(source_image,exception);
1629  image_view=AcquireAuthenticCacheView(image,exception);
1630 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1631  #pragma omp parallel for schedule(static) shared(status) \
1632  magick_number_threads(source_image,image,source_image->rows,4)
1633 #endif
1634  for (y=0; y < (ssize_t) source_image->rows; y++)
1635  {
1636  MagickBooleanType
1637  sync;
1638 
1639  const Quantum
1640  *p;
1641 
1642  Quantum
1643  *q;
1644 
1645  ssize_t
1646  x;
1647 
1648  if (status == MagickFalse)
1649  continue;
1650  p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
1651  exception);
1652  q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
1653  source_image->columns,1,exception);
1654  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1655  {
1656  status=MagickFalse;
1657  continue;
1658  }
1659  for (x=0; x < (ssize_t) source_image->columns; x++)
1660  {
1661  if (GetPixelReadMask(source_image,p) <= (QuantumRange/2))
1662  {
1663  p+=(ptrdiff_t) GetPixelChannels(source_image);
1664  q+=(ptrdiff_t) GetPixelChannels(image);
1665  continue;
1666  }
1667  SetPixelAlpha(image,clamp != MagickFalse ?
1668  ClampPixel(GetPixelIntensity(source_image,p)) :
1669  ClampToQuantum(GetPixelIntensity(source_image,p)),q);
1670  p+=(ptrdiff_t) GetPixelChannels(source_image);
1671  q+=(ptrdiff_t) GetPixelChannels(image);
1672  }
1673  sync=SyncCacheViewAuthenticPixels(image_view,exception);
1674  if (sync == MagickFalse)
1675  status=MagickFalse;
1676  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1677  {
1678  MagickBooleanType
1679  proceed;
1680 
1681  proceed=SetImageProgress(image,CompositeImageTag,(MagickOffsetType)
1682  y,image->rows);
1683  if (proceed == MagickFalse)
1684  status=MagickFalse;
1685  }
1686  }
1687  source_view=DestroyCacheView(source_view);
1688  image_view=DestroyCacheView(image_view);
1689  source_image=DestroyImage(source_image);
1690  return(status);
1691  }
1692  case CopyAlphaCompositeOp:
1693  case ChangeMaskCompositeOp:
1694  {
1695  /*
1696  Modify canvas outside the overlaid region and require an alpha
1697  channel to exist, to add transparency.
1698  */
1699  if ((image->alpha_trait & BlendPixelTrait) == 0)
1700  (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1701  break;
1702  }
1703  case BlurCompositeOp:
1704  {
1705  CacheView
1706  *canvas_view;
1707 
1708  double
1709  angle_range,
1710  angle_start,
1711  height,
1712  width;
1713 
1714  PixelInfo
1715  pixel;
1716 
1718  *resample_filter;
1719 
1720  SegmentInfo
1721  blur;
1722 
1723  /*
1724  Blur Image by resampling dictated by an overlay gradient map:
1725  X = red_channel; Y = green_channel; compose:args =
1726  x_scale[,y_scale[,angle]].
1727  */
1728  canvas_image=CloneImage(image,0,0,MagickTrue,exception);
1729  if (canvas_image == (Image *) NULL)
1730  {
1731  source_image=DestroyImage(source_image);
1732  return(MagickFalse);
1733  }
1734  /*
1735  Gather the maximum blur sigma values from user.
1736  */
1737  flags=NoValue;
1738  artifact=GetImageArtifact(image,"compose:args");
1739  if (artifact != (const char *) NULL)
1740  flags=ParseGeometry(artifact,&geometry_info);
1741  if ((flags & WidthValue) == 0)
1742  {
1743  (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
1744  "InvalidSetting","'%s' '%s'","compose:args",artifact);
1745  source_image=DestroyImage(source_image);
1746  canvas_image=DestroyImage(canvas_image);
1747  return(MagickFalse);
1748  }
1749  /*
1750  Users input sigma now needs to be converted to the EWA ellipse size.
1751  The filter defaults to a sigma of 0.5 so to make this match the users
1752  input the ellipse size needs to be doubled.
1753  */
1754  width=2.0*geometry_info.rho;
1755  height=width;
1756  if ((flags & HeightValue) != 0)
1757  height=2.0*geometry_info.sigma;
1758  /*
1759  Default the unrotated ellipse width and height axis vectors.
1760  */
1761  blur.x1=width;
1762  blur.x2=0.0;
1763  blur.y1=0.0;
1764  blur.y2=height;
1765  if ((flags & XValue) != 0 )
1766  {
1767  MagickRealType
1768  angle;
1769 
1770  /*
1771  Rotate vectors if a rotation angle is given.
1772  */
1773  angle=DegreesToRadians(geometry_info.xi);
1774  blur.x1=width*cos(angle);
1775  blur.x2=width*sin(angle);
1776  blur.y1=(-height*sin(angle));
1777  blur.y2=height*cos(angle);
1778  }
1779  angle_start=0.0;
1780  angle_range=0.0;
1781  if ((flags & YValue) != 0 )
1782  {
1783  /*
1784  Lets set a angle range and calculate in the loop.
1785  */
1786  angle_start=DegreesToRadians(geometry_info.xi);
1787  angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
1788  }
1789  /*
1790  Set up a gaussian cylindrical filter for EWA Blurring.
1791 
1792  As the minimum ellipse radius of support*1.0 the EWA algorithm
1793  can only produce a minimum blur of 0.5 for Gaussian (support=2.0)
1794  This means that even 'No Blur' will be still a little blurry! The
1795  solution (as well as the problem of preventing any user expert filter
1796  settings, is to set our own user settings, restore them afterwards.
1797  */
1798  resample_filter=AcquireResampleFilter(image,exception);
1799  SetResampleFilter(resample_filter,GaussianFilter);
1800  /*
1801  Perform the variable blurring of each pixel in image.
1802  */
1803  GetPixelInfo(image,&pixel);
1804  source_view=AcquireVirtualCacheView(source_image,exception);
1805  canvas_view=AcquireAuthenticCacheView(canvas_image,exception);
1806  for (y=0; y < (ssize_t) source_image->rows; y++)
1807  {
1808  MagickBooleanType
1809  sync;
1810 
1811  const Quantum
1812  *magick_restrict p;
1813 
1814  Quantum
1815  *magick_restrict q;
1816 
1817  ssize_t
1818  x;
1819 
1820  if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1821  continue;
1822  p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
1823  exception);
1824  q=QueueCacheViewAuthenticPixels(canvas_view,0,y,canvas_image->columns,1,
1825  exception);
1826  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1827  break;
1828  for (x=0; x < (ssize_t) source_image->columns; x++)
1829  {
1830  if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1831  {
1832  p+=(ptrdiff_t) GetPixelChannels(source_image);
1833  continue;
1834  }
1835  if (fabs(angle_range) > MagickEpsilon)
1836  {
1837  MagickRealType
1838  angle;
1839 
1840  angle=angle_start+angle_range*QuantumScale*(double)
1841  GetPixelBlue(source_image,p);
1842  blur.x1=width*cos(angle);
1843  blur.x2=width*sin(angle);
1844  blur.y1=(-height*sin(angle));
1845  blur.y2=height*cos(angle);
1846  }
1847  ScaleResampleFilter(resample_filter,
1848  blur.x1*QuantumScale*(double) GetPixelRed(source_image,p),
1849  blur.y1*QuantumScale*(double) GetPixelGreen(source_image,p),
1850  blur.x2*QuantumScale*(double) GetPixelRed(source_image,p),
1851  blur.y2*QuantumScale*(double) GetPixelGreen(source_image,p) );
1852  (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
1853  (double) y_offset+y,&pixel,exception);
1854  SetPixelViaPixelInfo(canvas_image,&pixel,q);
1855  p+=(ptrdiff_t) GetPixelChannels(source_image);
1856  q+=(ptrdiff_t) GetPixelChannels(canvas_image);
1857  }
1858  sync=SyncCacheViewAuthenticPixels(canvas_view,exception);
1859  if (sync == MagickFalse)
1860  break;
1861  }
1862  resample_filter=DestroyResampleFilter(resample_filter);
1863  source_view=DestroyCacheView(source_view);
1864  canvas_view=DestroyCacheView(canvas_view);
1865  source_image=DestroyImage(source_image);
1866  source_image=canvas_image;
1867  break;
1868  }
1869  case DisplaceCompositeOp:
1870  case DistortCompositeOp:
1871  {
1872  CacheView
1873  *canvas_view;
1874 
1875  MagickRealType
1876  horizontal_scale,
1877  vertical_scale;
1878 
1879  PixelInfo
1880  pixel;
1881 
1882  PointInfo
1883  center,
1884  offset;
1885 
1886  /*
1887  Displace/Distort based on overlay gradient map:
1888  X = red_channel; Y = green_channel;
1889  compose:args = x_scale[,y_scale[,center.x,center.y]]
1890  */
1891  canvas_image=CloneImage(image,0,0,MagickTrue,exception);
1892  if (canvas_image == (Image *) NULL)
1893  {
1894  source_image=DestroyImage(source_image);
1895  return(MagickFalse);
1896  }
1897  SetGeometryInfo(&geometry_info);
1898  flags=NoValue;
1899  artifact=GetImageArtifact(image,"compose:args");
1900  if (artifact != (char *) NULL)
1901  flags=ParseGeometry(artifact,&geometry_info);
1902  if ((flags & (WidthValue | HeightValue)) == 0 )
1903  {
1904  if ((flags & AspectValue) == 0)
1905  {
1906  horizontal_scale=(MagickRealType) (source_image->columns-1)/2.0;
1907  vertical_scale=(MagickRealType) (source_image->rows-1)/2.0;
1908  }
1909  else
1910  {
1911  horizontal_scale=(MagickRealType) (image->columns-1)/2.0;
1912  vertical_scale=(MagickRealType) (image->rows-1)/2.0;
1913  }
1914  }
1915  else
1916  {
1917  horizontal_scale=geometry_info.rho;
1918  vertical_scale=geometry_info.sigma;
1919  if ((flags & PercentValue) != 0)
1920  {
1921  if ((flags & AspectValue) == 0)
1922  {
1923  horizontal_scale*=(source_image->columns-1)/200.0;
1924  vertical_scale*=(source_image->rows-1)/200.0;
1925  }
1926  else
1927  {
1928  horizontal_scale*=(image->columns-1)/200.0;
1929  vertical_scale*=(image->rows-1)/200.0;
1930  }
1931  }
1932  if ((flags & HeightValue) == 0)
1933  vertical_scale=horizontal_scale;
1934  }
1935  /*
1936  Determine fixed center point for absolute distortion map
1937  Absolute distort ==
1938  Displace offset relative to a fixed absolute point
1939  Select that point according to +X+Y user inputs.
1940  default = center of overlay image
1941  arg flag '!' = locations/percentage relative to background image
1942  */
1943  center.x=(MagickRealType) x_offset;
1944  center.y=(MagickRealType) y_offset;
1945  if (compose == DistortCompositeOp)
1946  {
1947  if ((flags & XValue) == 0)
1948  if ((flags & AspectValue) != 0)
1949  center.x=(MagickRealType) ((image->columns-1)/2.0);
1950  else
1951  center.x=(MagickRealType) (x_offset+(source_image->columns-1)/
1952  2.0);
1953  else
1954  if ((flags & AspectValue) != 0)
1955  center.x=geometry_info.xi;
1956  else
1957  center.x=(MagickRealType) (x_offset+geometry_info.xi);
1958  if ((flags & YValue) == 0)
1959  if ((flags & AspectValue) != 0)
1960  center.y=(MagickRealType) ((image->rows-1)/2.0);
1961  else
1962  center.y=(MagickRealType) (y_offset+(source_image->rows-1)/2.0);
1963  else
1964  if ((flags & AspectValue) != 0)
1965  center.y=geometry_info.psi;
1966  else
1967  center.y=(MagickRealType) (y_offset+geometry_info.psi);
1968  }
1969  /*
1970  Shift the pixel offset point as defined by the provided,
1971  displacement/distortion map. -- Like a lens...
1972  */
1973  GetPixelInfo(image,&pixel);
1974  image_view=AcquireVirtualCacheView(image,exception);
1975  source_view=AcquireVirtualCacheView(source_image,exception);
1976  canvas_view=AcquireAuthenticCacheView(canvas_image,exception);
1977  for (y=0; y < (ssize_t) source_image->rows; y++)
1978  {
1979  MagickBooleanType
1980  sync;
1981 
1982  const Quantum
1983  *magick_restrict p;
1984 
1985  Quantum
1986  *magick_restrict q;
1987 
1988  ssize_t
1989  x;
1990 
1991  if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1992  continue;
1993  p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
1994  exception);
1995  q=QueueCacheViewAuthenticPixels(canvas_view,0,y,canvas_image->columns,1,
1996  exception);
1997  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1998  break;
1999  for (x=0; x < (ssize_t) source_image->columns; x++)
2000  {
2001  if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
2002  {
2003  p+=(ptrdiff_t) GetPixelChannels(source_image);
2004  continue;
2005  }
2006  /*
2007  Displace the offset.
2008  */
2009  offset.x=(double) (horizontal_scale*((double) GetPixelRed(
2010  source_image,p)-(((MagickRealType) QuantumRange+1.0)/2.0)))/
2011  (((MagickRealType) QuantumRange+1.0)/2.0)+center.x+
2012  ((compose == DisplaceCompositeOp) ? x : 0);
2013  offset.y=(double) (vertical_scale*((double) GetPixelGreen(
2014  source_image,p)-(((MagickRealType) QuantumRange+1.0)/2.0)))/
2015  (((MagickRealType) QuantumRange+1.0)/2.0)+center.y+
2016  ((compose == DisplaceCompositeOp) ? y : 0);
2017  status=InterpolatePixelInfo(image,image_view,
2018  UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
2019  &pixel,exception);
2020  if (status == MagickFalse)
2021  break;
2022  /*
2023  Mask with the 'invalid pixel mask' in alpha channel.
2024  */
2025  pixel.alpha=(MagickRealType) QuantumRange*(QuantumScale*pixel.alpha)*
2026  (QuantumScale*(double) GetPixelAlpha(source_image,p));
2027  SetPixelViaPixelInfo(canvas_image,&pixel,q);
2028  p+=(ptrdiff_t) GetPixelChannels(source_image);
2029  q+=(ptrdiff_t) GetPixelChannels(canvas_image);
2030  }
2031  if (x < (ssize_t) source_image->columns)
2032  break;
2033  sync=SyncCacheViewAuthenticPixels(canvas_view,exception);
2034  if (sync == MagickFalse)
2035  break;
2036  }
2037  canvas_view=DestroyCacheView(canvas_view);
2038  source_view=DestroyCacheView(source_view);
2039  image_view=DestroyCacheView(image_view);
2040  source_image=DestroyImage(source_image);
2041  source_image=canvas_image;
2042  break;
2043  }
2044  case DissolveCompositeOp:
2045  {
2046  /*
2047  Geometry arguments to dissolve factors.
2048  */
2049  artifact=GetImageArtifact(image,"compose:args");
2050  if (artifact != (char *) NULL)
2051  {
2052  flags=ParseGeometry(artifact,&geometry_info);
2053  source_dissolve=geometry_info.rho/100.0;
2054  canvas_dissolve=1.0;
2055  if ((source_dissolve-MagickEpsilon) < 0.0)
2056  source_dissolve=0.0;
2057  if ((source_dissolve+MagickEpsilon) > 1.0)
2058  {
2059  canvas_dissolve=2.0-source_dissolve;
2060  source_dissolve=1.0;
2061  }
2062  if ((flags & SigmaValue) != 0)
2063  canvas_dissolve=geometry_info.sigma/100.0;
2064  if ((canvas_dissolve-MagickEpsilon) < 0.0)
2065  canvas_dissolve=0.0;
2066  if ((canvas_dissolve+MagickEpsilon) > 1.0)
2067  canvas_dissolve=1.0;
2068  }
2069  break;
2070  }
2071  case BlendCompositeOp:
2072  {
2073  artifact=GetImageArtifact(image,"compose:args");
2074  if (artifact != (char *) NULL)
2075  {
2076  flags=ParseGeometry(artifact,&geometry_info);
2077  source_dissolve=geometry_info.rho/100.0;
2078  canvas_dissolve=1.0-source_dissolve;
2079  if ((flags & SigmaValue) != 0)
2080  canvas_dissolve=geometry_info.sigma/100.0;
2081  }
2082  break;
2083  }
2084  case SaliencyBlendCompositeOp:
2085  {
2086  double
2087  residual_threshold = 0.0002,
2088  iterations = 400.0;
2089 
2090  size_t
2091  tick = 100;
2092 
2093  artifact=GetImageArtifact(image,"compose:args");
2094  if (artifact != (char *) NULL)
2095  {
2096  flags=ParseGeometry(artifact,&geometry_info);
2097  iterations=geometry_info.rho;
2098  if ((flags & SigmaValue) != 0)
2099  residual_threshold=geometry_info.sigma;
2100  if ((flags & XiValue) != 0)
2101  tick=(size_t) geometry_info.xi;
2102  }
2103  status=SaliencyBlendImage(image,composite,x_offset,y_offset,iterations,
2104  residual_threshold,tick,exception);
2105  source_image=DestroyImage(source_image);
2106  return(status);
2107  }
2108  case SeamlessBlendCompositeOp:
2109  {
2110  double
2111  residual_threshold = 0.0002,
2112  iterations = 400.0;
2113 
2114  size_t
2115  tick = 100;
2116 
2117  artifact=GetImageArtifact(image,"compose:args");
2118  if (artifact != (char *) NULL)
2119  {
2120  flags=ParseGeometry(artifact,&geometry_info);
2121  iterations=geometry_info.rho;
2122  if ((flags & SigmaValue) != 0)
2123  residual_threshold=geometry_info.sigma;
2124  if ((flags & XiValue) != 0)
2125  tick=(size_t) geometry_info.xi;
2126  }
2127  status=SeamlessBlendImage(image,composite,x_offset,y_offset,iterations,
2128  residual_threshold,tick,exception);
2129  source_image=DestroyImage(source_image);
2130  return(status);
2131  }
2132  case MathematicsCompositeOp:
2133  {
2134  /*
2135  Just collect the values from "compose:args", setting.
2136  Unused values are set to zero automagically.
2137 
2138  Arguments are normally a comma separated list, so this probably should
2139  be changed to some 'general comma list' parser, (with a minimum
2140  number of values)
2141  */
2142  SetGeometryInfo(&geometry_info);
2143  artifact=GetImageArtifact(image,"compose:args");
2144  if (artifact != (char *) NULL)
2145  {
2146  flags=ParseGeometry(artifact,&geometry_info);
2147  if (flags == NoValue)
2148  (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2149  "InvalidGeometry","`%s'",artifact);
2150  }
2151  break;
2152  }
2153  case ModulateCompositeOp:
2154  {
2155  /*
2156  Determine the luma and chroma scale.
2157  */
2158  artifact=GetImageArtifact(image,"compose:args");
2159  if (artifact != (char *) NULL)
2160  {
2161  flags=ParseGeometry(artifact,&geometry_info);
2162  percent_luma=geometry_info.rho;
2163  if ((flags & SigmaValue) != 0)
2164  percent_chroma=geometry_info.sigma;
2165  }
2166  break;
2167  }
2168  case ThresholdCompositeOp:
2169  {
2170  /*
2171  Determine the amount and threshold.
2172  */
2173  artifact=GetImageArtifact(image,"compose:args");
2174  if (artifact != (char *) NULL)
2175  {
2176  flags=ParseGeometry(artifact,&geometry_info);
2177  amount=geometry_info.rho;
2178  threshold=geometry_info.sigma;
2179  if ((flags & SigmaValue) == 0)
2180  threshold=0.05f;
2181  }
2182  threshold*=(double) QuantumRange;
2183  break;
2184  }
2185  default:
2186  break;
2187  }
2188  /*
2189  Composite image.
2190  */
2191  status=MagickTrue;
2192  progress=0;
2193  midpoint=((MagickRealType) QuantumRange+1.0)/2;
2194  source_view=AcquireVirtualCacheView(source_image,exception);
2195  image_view=AcquireAuthenticCacheView(image,exception);
2196 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2197  #pragma omp parallel for schedule(static) shared(progress,status) \
2198  magick_number_threads(source_image,image,image->rows,1)
2199 #endif
2200  for (y=0; y < (ssize_t) image->rows; y++)
2201  {
2202  const Quantum
2203  *magick_restrict p,
2204  *pixels;
2205 
2206  MagickRealType
2207  blue = 0.0,
2208  chroma = 0.0,
2209  green = 0.0,
2210  hue = 0.0,
2211  luma = 0.0,
2212  red = 0.0;
2213 
2214  PixelInfo
2215  canvas_pixel,
2216  source_pixel;
2217 
2218  Quantum
2219  *magick_restrict q;
2220 
2221  ssize_t
2222  x;
2223 
2224  if (status == MagickFalse)
2225  continue;
2226  if (clip_to_self != MagickFalse)
2227  {
2228  if (y < y_offset)
2229  continue;
2230  if ((y-y_offset) >= (ssize_t) source_image->rows)
2231  continue;
2232  }
2233  /*
2234  If pixels is NULL, y is outside overlay region.
2235  */
2236  pixels=(Quantum *) NULL;
2237  p=(Quantum *) NULL;
2238  if ((y >= y_offset) &&
2239  ((y-y_offset) < (ssize_t) source_image->rows))
2240  {
2241  p=GetCacheViewVirtualPixels(source_view,0,
2242  CastDoubleToSsizeT((double) y-y_offset),source_image->columns,1,
2243  exception);
2244  if (p == (const Quantum *) NULL)
2245  {
2246  status=MagickFalse;
2247  continue;
2248  }
2249  pixels=p;
2250  if (x_offset < 0)
2251  p-=(ptrdiff_t) CastDoubleToSsizeT((double) x_offset*
2252  GetPixelChannels(source_image));
2253  }
2254  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2255  if (q == (Quantum *) NULL)
2256  {
2257  status=MagickFalse;
2258  continue;
2259  }
2260  GetPixelInfo(image,&canvas_pixel);
2261  GetPixelInfo(source_image,&source_pixel);
2262  for (x=0; x < (ssize_t) image->columns; x++)
2263  {
2264  double
2265  gamma = 0.0;
2266 
2267  MagickRealType
2268  alpha = 0.0,
2269  blend = 0.0,
2270  D = 0.0,
2271  Da = 0.0,
2272  Dc = 0.0,
2273  Dca = 0.0,
2274  Di = 0.0,
2275  S = 0.0,
2276  Sa = 0.0,
2277  Sc = 0.0,
2278  Sca = 0.0,
2279  Si = 0.0;
2280 
2281  size_t
2282  channels;
2283 
2284  ssize_t
2285  i;
2286 
2287  if (clip_to_self != MagickFalse)
2288  {
2289  if (x < x_offset)
2290  {
2291  q+=(ptrdiff_t) GetPixelChannels(image);
2292  continue;
2293  }
2294  if ((x-x_offset) >= (ssize_t) source_image->columns)
2295  break;
2296  }
2297  if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
2298  ((x-x_offset) >= (ssize_t) source_image->columns))
2299  {
2300  Quantum
2301  source[MaxPixelChannels];
2302 
2303  /*
2304  Virtual composite:
2305  Sc: source color.
2306  Dc: canvas color.
2307  */
2308  (void) GetOneVirtualPixel(source_image,
2309  CastDoubleToSsizeT((double) x-x_offset),
2310  CastDoubleToSsizeT((double) y-y_offset),source,exception);
2311  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2312  {
2313  MagickRealType
2314  pixel = 0.0;
2315 
2316  PixelChannel channel = GetPixelChannelChannel(image,i);
2317  PixelTrait traits = GetPixelChannelTraits(image,channel);
2318  PixelTrait source_traits = GetPixelChannelTraits(source_image,
2319  channel);
2320  if ((traits == UndefinedPixelTrait) ||
2321  (source_traits == UndefinedPixelTrait))
2322  continue;
2323  switch (compose)
2324  {
2325  case AlphaCompositeOp:
2326  case ChangeMaskCompositeOp:
2327  case CopyAlphaCompositeOp:
2328  case DstAtopCompositeOp:
2329  case DstInCompositeOp:
2330  case InCompositeOp:
2331  case OutCompositeOp:
2332  case SrcInCompositeOp:
2333  case SrcOutCompositeOp:
2334  {
2335  if (channel == AlphaPixelChannel)
2336  pixel=(MagickRealType) TransparentAlpha;
2337  else
2338  pixel=(MagickRealType) q[i];
2339  break;
2340  }
2341  case ClearCompositeOp:
2342  case CopyCompositeOp:
2343  case ReplaceCompositeOp:
2344  {
2345  if (channel == AlphaPixelChannel)
2346  pixel=(MagickRealType) TransparentAlpha;
2347  else
2348  pixel=0.0;
2349  break;
2350  }
2351  case BlendCompositeOp:
2352  case DissolveCompositeOp:
2353  {
2354  if (channel == AlphaPixelChannel)
2355  pixel=canvas_dissolve*(double) GetPixelAlpha(source_image,
2356  source);
2357  else
2358  pixel=(MagickRealType) source[channel];
2359  break;
2360  }
2361  default:
2362  {
2363  pixel=(MagickRealType) source[channel];
2364  break;
2365  }
2366  }
2367  q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
2368  ClampToQuantum(pixel);
2369  }
2370  q+=(ptrdiff_t) GetPixelChannels(image);
2371  continue;
2372  }
2373  /*
2374  Authentic composite:
2375  Sa: normalized source alpha.
2376  Da: normalized canvas alpha.
2377  */
2378  Sa=QuantumScale*(double) GetPixelAlpha(source_image,p);
2379  Da=QuantumScale*(double) GetPixelAlpha(image,q);
2380  switch (compose)
2381  {
2382  case BumpmapCompositeOp:
2383  case ColorBurnCompositeOp:
2384  case ColorDodgeCompositeOp:
2385  case DarkenCompositeOp:
2386  case DifferenceCompositeOp:
2387  case DivideCompositeOp:
2388  case DivideDstCompositeOp:
2389  case DivideSrcCompositeOp:
2390  case ExclusionCompositeOp:
2391  case FreezeCompositeOp:
2392  case HardLightCompositeOp:
2393  case HardMixCompositeOp:
2394  case InterpolateCompositeOp:
2395  case LightenCompositeOp:
2396  case LinearBurnCompositeOp:
2397  case LinearDodgeCompositeOp:
2398  case LinearLightCompositeOp:
2399  case MathematicsCompositeOp:
2400  case MinusDstCompositeOp:
2401  case MinusSrcCompositeOp:
2402  case MultiplyCompositeOp:
2403  case NegateCompositeOp:
2404  case OverlayCompositeOp:
2405  case PegtopLightCompositeOp:
2406  case PinLightCompositeOp:
2407  case ReflectCompositeOp:
2408  case ScreenCompositeOp:
2409  case SoftBurnCompositeOp:
2410  case SoftDodgeCompositeOp:
2411  case SoftLightCompositeOp:
2412  case StampCompositeOp:
2413  case VividLightCompositeOp:
2414  {
2415  alpha=RoundToUnity(Sa+Da-Sa*Da);
2416  break;
2417  }
2418  case DstAtopCompositeOp:
2419  case DstInCompositeOp:
2420  case InCompositeOp:
2421  case SrcInCompositeOp:
2422  {
2423  alpha=Sa*Da;
2424  break;
2425  }
2426  case DissolveCompositeOp:
2427  {
2428  alpha=source_dissolve*Sa*(-canvas_dissolve*Da)+source_dissolve*Sa+
2429  canvas_dissolve*Da;
2430  break;
2431  }
2432  case DstOverCompositeOp:
2433  case OverCompositeOp:
2434  case SrcOverCompositeOp:
2435  {
2436  alpha=Sa+Da-Sa*Da;
2437  break;
2438  }
2439  case DstOutCompositeOp:
2440  {
2441  alpha=Da*(1.0-Sa);
2442  break;
2443  }
2444  case OutCompositeOp:
2445  case SrcOutCompositeOp:
2446  {
2447  alpha=Sa*(1.0-Da);
2448  break;
2449  }
2450  case BlendCompositeOp:
2451  case PlusCompositeOp:
2452  {
2453  alpha=RoundToUnity(source_dissolve*Sa+canvas_dissolve*Da);
2454  break;
2455  }
2456  case XorCompositeOp:
2457  {
2458  alpha=Sa+Da-2.0*Sa*Da;
2459  break;
2460  }
2461  case ModulusAddCompositeOp:
2462  {
2463  if ((Sa+Da) <= 1.0)
2464  {
2465  alpha=(Sa+Da);
2466  break;
2467  }
2468  alpha=((Sa+Da)-1.0);
2469  break;
2470  }
2471  case ModulusSubtractCompositeOp:
2472  {
2473  if ((Sa-Da) >= 0.0)
2474  {
2475  alpha=(Sa-Da);
2476  break;
2477  }
2478  alpha=((Sa-Da)+1.0);
2479  break;
2480  }
2481  default:
2482  {
2483  alpha=1.0;
2484  break;
2485  }
2486  }
2487  switch (compose)
2488  {
2489  case ColorizeCompositeOp:
2490  case HueCompositeOp:
2491  case LuminizeCompositeOp:
2492  case ModulateCompositeOp:
2493  case RMSECompositeOp:
2494  case SaturateCompositeOp:
2495  {
2496  Si=GetPixelIntensity(source_image,p);
2497  GetPixelInfoPixel(source_image,p,&source_pixel);
2498  GetPixelInfoPixel(image,q,&canvas_pixel);
2499  break;
2500  }
2501  case BumpmapCompositeOp:
2502  case CopyAlphaCompositeOp:
2503  case DarkenIntensityCompositeOp:
2504  case LightenIntensityCompositeOp:
2505  {
2506  Si=GetPixelIntensity(source_image,p);
2507  Di=GetPixelIntensity(image,q);
2508  break;
2509  }
2510  default:
2511  break;
2512  }
2513  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2514  {
2515  MagickRealType
2516  pixel = 0.0,
2517  sans = 0.0;
2518 
2519  PixelChannel channel = GetPixelChannelChannel(image,i);
2520  PixelTrait traits = GetPixelChannelTraits(image,channel);
2521  PixelTrait source_traits = GetPixelChannelTraits(source_image,channel);
2522  if (traits == UndefinedPixelTrait)
2523  continue;
2524  if ((channel == AlphaPixelChannel) &&
2525  ((traits & UpdatePixelTrait) != 0))
2526  {
2527  /*
2528  Set alpha channel.
2529  */
2530  switch (compose)
2531  {
2532  case AlphaCompositeOp:
2533  {
2534  pixel=(double) QuantumRange*Sa;
2535  break;
2536  }
2537  case AtopCompositeOp:
2538  case CopyBlackCompositeOp:
2539  case CopyBlueCompositeOp:
2540  case CopyCyanCompositeOp:
2541  case CopyGreenCompositeOp:
2542  case CopyMagentaCompositeOp:
2543  case CopyRedCompositeOp:
2544  case CopyYellowCompositeOp:
2545  case SrcAtopCompositeOp:
2546  case DstCompositeOp:
2547  case NoCompositeOp:
2548  {
2549  pixel=(double) QuantumRange*Da;
2550  break;
2551  }
2552  case BumpmapCompositeOp:
2553  {
2554  pixel=Si*Da;
2555  break;
2556  }
2557  case ChangeMaskCompositeOp:
2558  {
2559  if (IsFuzzyEquivalencePixel(source_image,p,image,q) != MagickFalse)
2560  pixel=(MagickRealType) TransparentAlpha;
2561  else
2562  pixel=(double) QuantumRange*Da;
2563  break;
2564  }
2565  case ClearCompositeOp:
2566  {
2567  pixel=(MagickRealType) TransparentAlpha;
2568  break;
2569  }
2570  case ColorizeCompositeOp:
2571  case HueCompositeOp:
2572  case LuminizeCompositeOp:
2573  case RMSECompositeOp:
2574  case SaturateCompositeOp:
2575  {
2576  if (fabs((double) QuantumRange*Sa-(double) TransparentAlpha) < MagickEpsilon)
2577  {
2578  pixel=(double) QuantumRange*Da;
2579  break;
2580  }
2581  if (fabs((double) QuantumRange*Da-(double) TransparentAlpha) < MagickEpsilon)
2582  {
2583  pixel=(double) QuantumRange*Sa;
2584  break;
2585  }
2586  if (Sa < Da)
2587  {
2588  pixel=(double) QuantumRange*Da;
2589  break;
2590  }
2591  pixel=(double) QuantumRange*Sa;
2592  break;
2593  }
2594  case CopyAlphaCompositeOp:
2595  {
2596  if (source_image->alpha_trait == UndefinedPixelTrait)
2597  pixel=Si;
2598  else
2599  pixel=(double) QuantumRange*Sa;
2600  break;
2601  }
2602  case BlurCompositeOp:
2603  case CopyCompositeOp:
2604  case DisplaceCompositeOp:
2605  case DistortCompositeOp:
2606  case DstAtopCompositeOp:
2607  case ReplaceCompositeOp:
2608  case SrcCompositeOp:
2609  {
2610  pixel=(double) QuantumRange*Sa;
2611  break;
2612  }
2613  case DarkenIntensityCompositeOp:
2614  {
2615  if (compose_sync == MagickFalse)
2616  {
2617  pixel=Si < Di ? Sa : Da;
2618  break;
2619  }
2620  pixel=Sa*Si < Da*Di ? Sa : Da;
2621  break;
2622  }
2623  case DifferenceCompositeOp:
2624  {
2625  pixel=(double) QuantumRange*fabs((double) (Sa-Da));
2626  break;
2627  }
2628  case FreezeCompositeOp:
2629  {
2630  pixel=(double) QuantumRange*(1.0-(1.0-Sa)*(1.0-Sa)*
2631  MagickSafeReciprocal(Da));
2632  if (pixel < 0.0)
2633  pixel=0.0;
2634  break;
2635  }
2636  case InterpolateCompositeOp:
2637  {
2638  pixel=(double) QuantumRange*(0.5-0.25*cos(MagickPI*Sa)-0.25*
2639  cos(MagickPI*Da));
2640  break;
2641  }
2642  case LightenIntensityCompositeOp:
2643  {
2644  if (compose_sync == MagickFalse)
2645  {
2646  pixel=Si > Di ? Sa : Da;
2647  break;
2648  }
2649  pixel=Sa*Si > Da*Di ? Sa : Da;
2650  break;
2651  }
2652  case ModulateCompositeOp:
2653  {
2654  pixel=(double) QuantumRange*Da;
2655  break;
2656  }
2657  case MultiplyCompositeOp:
2658  {
2659  if (compose_sync == MagickFalse)
2660  {
2661  pixel=(double) QuantumRange*Sa*Da;
2662  break;
2663  }
2664  pixel=(double) QuantumRange*alpha;
2665  break;
2666  }
2667  case NegateCompositeOp:
2668  {
2669  pixel=(double) QuantumRange*((1.0-Sa-Da));
2670  break;
2671  }
2672  case ReflectCompositeOp:
2673  {
2674  pixel=(double) QuantumRange*(Sa*Sa*
2675  MagickSafeReciprocal(1.0-Da));
2676  if (pixel > (double) QuantumRange)
2677  pixel=(double) QuantumRange;
2678  break;
2679  }
2680  case StampCompositeOp:
2681  {
2682  pixel=(double) QuantumRange*(Sa+Da*Da-1.0);
2683  break;
2684  }
2685  case StereoCompositeOp:
2686  {
2687  pixel=(double) QuantumRange*(Sa+Da)/2;
2688  break;
2689  }
2690  default:
2691  {
2692  pixel=(double) QuantumRange*alpha;
2693  break;
2694  }
2695  }
2696  q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
2697  ClampToQuantum(pixel);
2698  continue;
2699  }
2700  if (source_traits == UndefinedPixelTrait)
2701  continue;
2702  /*
2703  Sc: source color.
2704  Dc: canvas color.
2705  */
2706  Sc=(MagickRealType) GetPixelChannel(source_image,channel,p);
2707  Dc=(MagickRealType) q[i];
2708  if ((traits & CopyPixelTrait) != 0)
2709  {
2710  /*
2711  Copy channel.
2712  */
2713  q[i]=ClampToQuantum(Dc);
2714  continue;
2715  }
2716  /*
2717  Porter-Duff compositions:
2718  Sca: source normalized color multiplied by alpha.
2719  Dca: normalized canvas color multiplied by alpha.
2720  */
2721  Sca=QuantumScale*Sa*Sc;
2722  Dca=QuantumScale*Da*Dc;
2723  switch (compose)
2724  {
2725  case DarkenCompositeOp:
2726  case LightenCompositeOp:
2727  case ModulusSubtractCompositeOp:
2728  {
2729  gamma=MagickSafeReciprocal(1.0-alpha);
2730  break;
2731  }
2732  default:
2733  {
2734  gamma=MagickSafeReciprocal(alpha);
2735  break;
2736  }
2737  }
2738  pixel=Dc;
2739  switch (compose)
2740  {
2741  case AlphaCompositeOp:
2742  {
2743  pixel=(double) QuantumRange*Sa;
2744  break;
2745  }
2746  case AtopCompositeOp:
2747  case SrcAtopCompositeOp:
2748  {
2749  pixel=(double) QuantumRange*(Sca*Da+Dca*(1.0-Sa));
2750  break;
2751  }
2752  case BlendCompositeOp:
2753  {
2754  pixel=gamma*(source_dissolve*Sa*Sc+canvas_dissolve*Da*Dc);
2755  break;
2756  }
2757  case CopyCompositeOp:
2758  case ReplaceCompositeOp:
2759  {
2760  pixel=(double) QuantumRange*Sca;
2761  break;
2762  }
2763  case BlurCompositeOp:
2764  case DisplaceCompositeOp:
2765  case DistortCompositeOp:
2766  case SrcCompositeOp:
2767  {
2768  pixel=Sc;
2769  break;
2770  }
2771  case BumpmapCompositeOp:
2772  {
2773  if (fabs((double) QuantumRange*Sa-(double) TransparentAlpha) < MagickEpsilon)
2774  {
2775  pixel=Dc;
2776  break;
2777  }
2778  pixel=(QuantumScale*Si)*Dc;
2779  break;
2780  }
2781  case ChangeMaskCompositeOp:
2782  {
2783  pixel=Dc;
2784  break;
2785  }
2786  case ClearCompositeOp:
2787  {
2788  pixel=0.0;
2789  break;
2790  }
2791  case ColorBurnCompositeOp:
2792  {
2793  D=(Da > 0.0) ? RoundToUnity(Dca/Da) : 0.0;
2794  S=(Sa > 0.0) ? RoundToUnity(Sca/Sa) : 0.0;
2795  if (fabs(S) < MagickEpsilon)
2796  blend=0.0;
2797  else
2798  blend=MagickMin(1.0,MagickMax(0.0,1.0-(1.0-D)/S));
2799  pixel=(double) QuantumRange*gamma*RoundToUnity(Sa*Da*blend+Sa*
2800  (1.0-Da)*S+Da*(1.0-Sa)*D);
2801  break;
2802  }
2803  case ColorDodgeCompositeOp:
2804  {
2805  if (Sa > 0.0)
2806  S=RoundToUnity(Sca/Sa);
2807  else
2808  S=0.0;
2809  if (Da > 0.0)
2810  D=RoundToUnity(Dca/Da);
2811  else
2812  D=0.0;
2813  if (S >= 1.0)
2814  blend=1.0;
2815  else
2816  if (D <= 0.0)
2817  blend=0.0;
2818  else
2819  {
2820  if ((1.0-S) <= 0.0)
2821  blend=1.0;
2822  else
2823  blend=MagickMin(1.0,D/(1.0-S));
2824  }
2825  pixel=(double) QuantumRange*gamma*(Sa*Da*blend+Sca*(1.0-Da)+Dca*
2826  (1.0-Sa));
2827  break;
2828  }
2829  case ColorizeCompositeOp:
2830  {
2831  if (fabs((double) QuantumRange*Sa-(double) TransparentAlpha) < MagickEpsilon)
2832  {
2833  pixel=Dc;
2834  break;
2835  }
2836  if (fabs((double) QuantumRange*Da-(double) TransparentAlpha) < MagickEpsilon)
2837  {
2838  pixel=Sc;
2839  break;
2840  }
2841  ConvertRGBToGeneric(colorspace,(double) canvas_pixel.red,
2842  (double) canvas_pixel.green,(double) canvas_pixel.blue,
2843  white_luminance,illuminant,&sans,&sans,&luma);
2844  ConvertRGBToGeneric(colorspace,(double) source_pixel.red,
2845  (double) source_pixel.green,(double) source_pixel.blue,
2846  white_luminance,illuminant,&hue,&chroma,&sans);
2847  ConvertGenericToRGB(colorspace,hue,chroma,luma,
2848  white_luminance,illuminant,&red,&green,&blue);
2849  switch (channel)
2850  {
2851  case RedPixelChannel: pixel=red; break;
2852  case GreenPixelChannel: pixel=green; break;
2853  case BluePixelChannel: pixel=blue; break;
2854  default: pixel=Dc; break;
2855  }
2856  break;
2857  }
2858  case CopyAlphaCompositeOp:
2859  case DstCompositeOp:
2860  {
2861  pixel=Dc;
2862  break;
2863  }
2864  case CopyBlackCompositeOp:
2865  {
2866  if (channel == BlackPixelChannel)
2867  pixel=(MagickRealType) GetPixelBlack(source_image,p);
2868  break;
2869  }
2870  case CopyBlueCompositeOp:
2871  case CopyYellowCompositeOp:
2872  {
2873  if (channel == BluePixelChannel)
2874  pixel=(MagickRealType) GetPixelBlue(source_image,p);
2875  break;
2876  }
2877  case CopyGreenCompositeOp:
2878  case CopyMagentaCompositeOp:
2879  {
2880  if (channel == GreenPixelChannel)
2881  pixel=(MagickRealType) GetPixelGreen(source_image,p);
2882  break;
2883  }
2884  case CopyRedCompositeOp:
2885  case CopyCyanCompositeOp:
2886  {
2887  if (channel == RedPixelChannel)
2888  pixel=(MagickRealType) GetPixelRed(source_image,p);
2889  break;
2890  }
2891  case DarkenCompositeOp:
2892  {
2893  if (compose_sync == MagickFalse)
2894  {
2895  pixel=RoundToUnity(MagickMin(Sca,Dca)+Sca*(1.0-Da)+Dca*
2896  (1.0-Sa));
2897  break;
2898  }
2899  pixel=(double) QuantumRange*RoundToUnity(MagickMin(Sca,Dca)+Sca*
2900  (1.0-Da)+Dca*(1.0-Sa));
2901  break;
2902  }
2903  case DarkenIntensityCompositeOp:
2904  {
2905  if (compose_sync == MagickFalse)
2906  {
2907  pixel=RoundToUnity(MagickMin(Sca,Dca)+Sca*(1.0-Di)+Dca*
2908  (1.0-Si));
2909  break;
2910  }
2911  pixel=(double) QuantumRange*RoundToUnity(MagickMin(Sca,Dca)+Sca*
2912  (1.0-Di)+Dca*(1.0-Si));
2913  break;
2914  }
2915  case DifferenceCompositeOp:
2916  {
2917  if (compose_sync == MagickFalse)
2918  {
2919  pixel=(double) QuantumRange*RoundToUnity(fabs((double) Sc-
2920  (double) Dc));
2921  break;
2922  }
2923  S=(Sa > 0.0) ? (Sca/Sa) : 0.0;
2924  D=(Da > 0.0) ? (Dca/Da) : 0.0;
2925  pixel=(double) QuantumRange*RoundToUnity(fabs(S-D));
2926  break;
2927  }
2928  case DissolveCompositeOp:
2929  {
2930  pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
2931  canvas_dissolve*Da*Dc+canvas_dissolve*Da*Dc);
2932  break;
2933  }
2934  case DivideCompositeOp:
2935  {
2936  D=(Da > 0.0) ? (Dca/Da) : 0.0;
2937  S=(Sa > 0.0) ? (Sca/Sa) : 0.0;
2938  if (fabs(S) < MagickEpsilon)
2939  blend=1.0;
2940  else
2941  blend=RoundToUnity(D/S);
2942  pixel=(double) QuantumRange*RoundToUnity(Sca*(1.0-Da)+Dca*(1.0-Sa)+
2943  Sa*Da*blend);
2944  break;
2945  }
2946  case DivideDstCompositeOp:
2947  {
2948  if (compose_sync == MagickFalse)
2949  {
2950  if (fabs(Dc) < MagickEpsilon)
2951  pixel=(double) QuantumRange;
2952  else
2953  pixel=(double) QuantumRange*(Sc/Dc);
2954  break;
2955  }
2956  if (fabs(Dca) < MagickEpsilon)
2957  pixel=(double) QuantumRange*(Sca+(1.0-Sa));
2958  else
2959  pixel=(double) QuantumRange*(Sca/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2960  break;
2961  }
2962  case DivideSrcCompositeOp:
2963  {
2964  if (compose_sync == MagickFalse)
2965  {
2966  if (fabs(Sc) < MagickEpsilon)
2967  pixel=(double) QuantumRange;
2968  else
2969  pixel=(double) QuantumRange*(Dc/Sc);
2970  break;
2971  }
2972  if (fabs(Dca) < MagickEpsilon)
2973  pixel=(double) QuantumRange*(Dca+(1.0-Da));
2974  else
2975  pixel=(double) QuantumRange*(Dca/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
2976  break;
2977  }
2978  case DstAtopCompositeOp:
2979  {
2980  pixel=(double) QuantumRange*(Dca*Sa+Sca*(1.0-Da));
2981  break;
2982  }
2983  case DstInCompositeOp:
2984  {
2985  pixel=(double) QuantumRange*gamma*(Dca*Sa);
2986  break;
2987  }
2988  case DstOutCompositeOp:
2989  {
2990  pixel=(double) QuantumRange*gamma*(Dca*(1.0-Sa));
2991  break;
2992  }
2993  case DstOverCompositeOp:
2994  {
2995  pixel=(double) QuantumRange*gamma*(Dca+Sca*(1.0-Da));
2996  break;
2997  }
2998  case ExclusionCompositeOp:
2999  {
3000  S=(Sa > 0.0) ? RoundToUnity(Sca/Sa) : 0.0;
3001  D=(Da > 0.0) ? RoundToUnity(Dca/Da) : 0.0;
3002  blend=RoundToUnity(S+D-2.0*S*D);
3003  pixel=(double) QuantumRange*RoundToUnity((blend*Sa+D*(1.0-Sa))*
3004  (Sa+Da-Sa*Da));
3005  break;
3006  }
3007  case FreezeCompositeOp:
3008  {
3009  if (Dca != 0.0)
3010  blend=1.0-(1.0-Sca)*(1.0-Sca)/Dca;
3011  else
3012  blend=0.0;
3013  pixel=(double) QuantumRange*gamma*RoundToUnity(blend);
3014  break;
3015  }
3016  case HardLightCompositeOp:
3017  {
3018  D=(Da > 0.0) ? RoundToUnity(Dca/Da) : 0.0;
3019  S=(Sa > 0.0) ? RoundToUnity(Sca/Sa) : 0.0;
3020  if (S <= 0.5)
3021  blend=2.0*S*D;
3022  else
3023  blend=1.0-2.0*(1.0-S)*(1.0-D);
3024  pixel=(double) QuantumRange*gamma*RoundToUnity((1.0-Da)*Sca+
3025  (1.0-Sa)*Dca+blend*Sa*Da);
3026  break;
3027  }
3028  case HardMixCompositeOp:
3029  {
3030  double
3031  hardmix,
3032  vivid;
3033 
3034  S=(Sa > 0.0) ? RoundToUnity(Sca/Sa) : 0.0;
3035  D=(Da > 0.0) ? RoundToUnity(Dca/Da) : 0.0;
3036  if (S <= 0.5)
3037  {
3038  if (S <= MagickEpsilon)
3039  vivid=0.0;
3040  else
3041  vivid=1.0-(1.0-D)/(2.0*S);
3042  }
3043  else
3044  {
3045  if ((1.0-(2.0*S-1.0)) <= MagickEpsilon)
3046  vivid=1.0;
3047  else
3048  vivid=D/(1.0-(2.0*S-1.0));
3049  }
3050  hardmix=(vivid < 0.5) ? 0.0 : 1.0;
3051  pixel=(double) QuantumRange*gamma*RoundToUnity(Sa*Da*hardmix+Sca*
3052  (1.0-Da)+Dca*(1.0-Sa));
3053  break;
3054  }
3055  case HueCompositeOp:
3056  {
3057  if (fabs((double) QuantumRange*Sa-(double) TransparentAlpha) < MagickEpsilon)
3058  {
3059  pixel=Dc;
3060  break;
3061  }
3062  if (fabs((double) QuantumRange*Da-(double) TransparentAlpha) < MagickEpsilon)
3063  {
3064  pixel=Sc;
3065  break;
3066  }
3067  ConvertRGBToGeneric(colorspace,(double) canvas_pixel.red,
3068  (double) canvas_pixel.green,(double) canvas_pixel.blue,
3069  white_luminance,illuminant,&hue,&chroma,&luma);
3070  ConvertRGBToGeneric(colorspace,(double) source_pixel.red,
3071  (double) source_pixel.green,(double) source_pixel.blue,
3072  white_luminance,illuminant,&hue,&sans,&sans);
3073  ConvertGenericToRGB(colorspace,hue,chroma,luma,
3074  white_luminance,illuminant,&red,&green,&blue);
3075  switch (channel)
3076  {
3077  case RedPixelChannel: pixel=red; break;
3078  case GreenPixelChannel: pixel=green; break;
3079  case BluePixelChannel: pixel=blue; break;
3080  default: pixel=Dc; break;
3081  }
3082  break;
3083  }
3084  case InCompositeOp:
3085  case SrcInCompositeOp:
3086  {
3087  pixel=(double) QuantumRange*(Sca*Da);
3088  break;
3089  }
3090  case InterpolateCompositeOp:
3091  {
3092  pixel=(double) QuantumRange*(0.5-0.25*cos(MagickPI*Sca)-0.25*
3093  cos(MagickPI*Dca));
3094  break;
3095  }
3096  case LinearBurnCompositeOp:
3097  {
3098  /*
3099  LinearBurn: as defined by Abode Photoshop, according to
3100  http://www.simplefilter.de/en/basics/mixmods.html is:
3101 
3102  f(Sc,Dc) = Sc + Dc - 1
3103  */
3104  S=(Sa > 0.0) ? RoundToUnity(Sca/Sa) : 0.0;
3105  D=(Da > 0.0) ? RoundToUnity(Dca/Da) : 0.0;
3106  blend=RoundToUnity(S+D-1.0);
3107  pixel=(double) QuantumRange*RoundToUnity(Sa*Da*blend+Sca*(1.0-Da)+
3108  Dca*(1.0-Sa));
3109  break;
3110  }
3111  case LinearDodgeCompositeOp:
3112  {
3113  S=(Sa > 0.0) ? RoundToUnity(Sca/Sa) : 0.0;
3114  D=(Da > 0.0) ? RoundToUnity(Dca/Da) : 0.0;
3115  blend=RoundToUnity(S+D);
3116  pixel=(double) QuantumRange*gamma*RoundToUnity(Sa*Da*blend+
3117  Sca*(1.0-Da)+Dca*(1.0-Sa));
3118  break;
3119  }
3120  case LinearLightCompositeOp:
3121  {
3122  /*
3123  Linear Light (Adobe standard):
3124  f(Sc, Dc) = Dc + 2*Sc - 1
3125  Applied in linear (HDRI) space with clamping.
3126  */
3127  S=(Sa > 0.0) ? RoundToUnity(Sca/Sa) : 0.0;
3128  D=(Da > 0.0) ? RoundToUnity(Dca/Da) : 0.0;
3129  blend=RoundToUnity(D+2.0*S-1.0);
3130  pixel=(double) QuantumRange*gamma*RoundToUnity(Sa*Da*blend+Sca*
3131  (1.0-Da)+Dca*(1.0-Sa));
3132  break;
3133  }
3134  case LightenCompositeOp:
3135  {
3136  if (compose_sync == MagickFalse)
3137  {
3138  pixel=MagickMax(Sc,Dc);
3139  break;
3140  }
3141  S=(Sa > 0.0) ? RoundToUnity(Sca/Sa) : 0.0;
3142  D=(Da > 0.0) ? RoundToUnity(Dca/Da) : 0.0;
3143  pixel=(double) QuantumRange*RoundToUnity(Sca*(1.0-Da)+Dca*(1.0-Sa)+
3144  MagickMax(S,D)*Sa*Da);
3145  break;
3146  }
3147  case LightenIntensityCompositeOp:
3148  {
3149  pixel=Si > Di ? Sc : Dc;
3150  break;
3151  }
3152  case LuminizeCompositeOp:
3153  {
3154  if (fabs((double) QuantumRange*Sa-(double) TransparentAlpha) < MagickEpsilon)
3155  {
3156  pixel=Dc;
3157  break;
3158  }
3159  if (fabs((double) QuantumRange*Da-(double) TransparentAlpha) < MagickEpsilon)
3160  {
3161  pixel=Sc;
3162  break;
3163  }
3164  ConvertRGBToGeneric(colorspace,(double) canvas_pixel.red,
3165  (double) canvas_pixel.green,(double) canvas_pixel.blue,
3166  white_luminance,illuminant,&hue,&chroma,&luma);
3167  ConvertRGBToGeneric(colorspace,(double) source_pixel.red,
3168  (double) source_pixel.green,(double) source_pixel.blue,
3169  white_luminance,illuminant,&sans,&sans,&luma);
3170  ConvertGenericToRGB(colorspace,hue,chroma,luma,
3171  white_luminance,illuminant,&red,&green,&blue);
3172  switch (channel)
3173  {
3174  case RedPixelChannel: pixel=red; break;
3175  case GreenPixelChannel: pixel=green; break;
3176  case BluePixelChannel: pixel=blue; break;
3177  default: pixel=Dc; break;
3178  }
3179  break;
3180  }
3181  case MathematicsCompositeOp:
3182  {
3183  /*
3184  'Mathematics' a free form user control mathematical composition
3185  is defined as...
3186 
3187  f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
3188 
3189  Where the arguments A,B,C,D are (currently) passed to composite
3190  as a command separated 'geometry' string in "compose:args" image
3191  artifact.
3192 
3193  A = a->rho, B = a->sigma, C = a->xi, D = a->psi
3194 
3195  Applying the SVG transparency formula (see above), we get...
3196 
3197  Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
3198 
3199  Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
3200  Dca*(1.0-Sa)
3201  */
3202  if (compose_sync == MagickFalse)
3203  {
3204  pixel=geometry_info.rho*Sc*Dc+geometry_info.sigma*Sc+
3205  geometry_info.xi*Dc+geometry_info.psi;
3206  break;
3207  }
3208  pixel=(double) QuantumRange*gamma*(geometry_info.rho*Sca*Dca+
3209  geometry_info.sigma*Sca*Da+geometry_info.xi*Dca*Sa+
3210  geometry_info.psi*Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
3211  break;
3212  }
3213  case MinusDstCompositeOp:
3214  {
3215  if (compose_sync == MagickFalse)
3216  {
3217  pixel=Dc-Sc;
3218  break;
3219  }
3220  pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
3221  break;
3222  }
3223  case MinusSrcCompositeOp:
3224  {
3225  if (compose_sync == MagickFalse)
3226  {
3227  pixel=Sc-Dc;
3228  break;
3229  }
3230  pixel=gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
3231  break;
3232  }
3233  case ModulateCompositeOp:
3234  {
3235  ssize_t
3236  offset;
3237 
3238  if (fabs((double) QuantumRange*Sa-(double) TransparentAlpha) < MagickEpsilon)
3239  {
3240  pixel=Dc;
3241  break;
3242  }
3243  offset=(ssize_t) (Si-midpoint);
3244  if (offset == 0)
3245  {
3246  pixel=Dc;
3247  break;
3248  }
3249  ConvertRGBToGeneric(colorspace,(double) canvas_pixel.red,
3250  (double) canvas_pixel.green,(double) canvas_pixel.blue,
3251  white_luminance,illuminant,&hue,&chroma,&luma);
3252  luma+=(0.01*percent_luma*offset)/midpoint;
3253  chroma*=0.01*percent_chroma;
3254  ConvertGenericToRGB(colorspace,hue,chroma,luma,
3255  white_luminance,illuminant,&red,&green,&blue);
3256  switch (channel)
3257  {
3258  case RedPixelChannel: pixel=red; break;
3259  case GreenPixelChannel: pixel=green; break;
3260  case BluePixelChannel: pixel=blue; break;
3261  default: pixel=Dc; break;
3262  }
3263  break;
3264  }
3265  case ModulusAddCompositeOp:
3266  {
3267  if (compose_sync == MagickFalse)
3268  {
3269  pixel=(Quantum) QuantumRange*((Sc+Dc)-floor(Sc+Dc));
3270  break;
3271  }
3272  pixel=(Quantum) QuantumRange*((Sca+Dca)-floor(Sca+Dca));
3273  break;
3274  }
3275  case ModulusSubtractCompositeOp:
3276  {
3277  if (compose_sync == MagickFalse)
3278  {
3279  pixel=(Quantum) QuantumRange*((Sc-Dc)-floor(Sc-Dc));
3280  break;
3281  }
3282  pixel=(Quantum) QuantumRange*((Sca-Dca)-floor(Sca-Dca));
3283  break;
3284  }
3285  case MultiplyCompositeOp:
3286  {
3287  if (compose_sync == MagickFalse)
3288  {
3289  pixel=(double) QuantumRange*Sc*Dc;
3290  break;
3291  }
3292  pixel=(double) QuantumRange*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
3293  break;
3294  }
3295  case NegateCompositeOp:
3296  {
3297  D=(Da > 0.0) ? Dca/Da : 0.0;
3298  S=(Sa > 0.0) ? Sca/Sa : 0.0;
3299  pixel=(double) QuantumRange*((1.0-fabs(1.0-S-D))*Da);
3300  break;
3301  }
3302  case NoCompositeOp:
3303  {
3304  pixel=(double) QuantumRange*Dca;
3305  break;
3306  }
3307  case OutCompositeOp:
3308  case SrcOutCompositeOp:
3309  {
3310  pixel=(double) QuantumRange*(Sca*(1.0-Da));
3311  break;
3312  }
3313  case OverCompositeOp:
3314  case SrcOverCompositeOp:
3315  {
3316  if ((Sa+Da*(1.0-Sa)) <= MagickEpsilon)
3317  pixel=0.0;
3318  else
3319  pixel=(double) QuantumRange*gamma*((Sca+Dca*(1.0-Sa))/
3320  (Sa+Da*(1.0-Sa)));
3321  break;
3322  }
3323  case OverlayCompositeOp:
3324  {
3325  if ((2.0*Dca) < Da)
3326  {
3327  pixel=(double) QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+
3328  Sca*(1.0-Da));
3329  break;
3330  }
3331  pixel=(double) QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*
3332  (1.0-Sa)+Sca*(1.0-Da));
3333  break;
3334  }
3335  case PegtopLightCompositeOp:
3336  {
3337  if (fabs((double) Da) < MagickEpsilon)
3338  {
3339  pixel=(double) QuantumRange*gamma*Sca;
3340  break;
3341  }
3342  if (RoundToUnity(Sca) <= 0.5)
3343  blend=RoundToUnity(Dca/Da)-(1.0-2.0*RoundToUnity(Sca))*
3344  RoundToUnity(Dca/Da)*(1.0-RoundToUnity(Dca/Da));
3345  else
3346  {
3347  if (RoundToUnity(Dca/Da) <= 0.25)
3348  blend=((16.0*RoundToUnity(Dca/Da)-12.0)*RoundToUnity(Dca/Da)+
3349  4.0)*RoundToUnity(Dca/Da);
3350  else
3351  blend=sqrt(RoundToUnity(Dca/Da));
3352  blend=RoundToUnity(Dca/Da)+(2.0*RoundToUnity(Sca)-1.0)*
3353  (blend-RoundToUnity(Dca/Da));
3354  }
3355  pixel=(double) QuantumRange*gamma*(RoundToUnity(blend)*Da*Sa+Dca*
3356  (1.0-Sa));
3357  break;
3358  }
3359  case PinLightCompositeOp:
3360  {
3361  /*
3362  Adobe Pin Light (colors in [0,1]):
3363 
3364  if (Cs <= 0.5)
3365  f = min(Cd, 2*Cs);
3366  else
3367  f = max(Cd, 2*Cs - 1);
3368  */
3369  D=(Da > 0.0) ? RoundToUnity(Dca/Da) : 0.0;
3370  S=(Sa > 0.0) ? RoundToUnity(Sca/Sa) : 0.0;
3371  if (S <= 0.5)
3372  blend=MagickMin(D,2.0*S);
3373  else
3374  blend=MagickMax(D,2.0*S-1.0);
3375  pixel=(double) QuantumRange*gamma*RoundToUnity(Sa*Da*blend+Sca*
3376  (1.0-Da)+Dca*(1.0-Sa));
3377  break;
3378  }
3379  case PlusCompositeOp:
3380  {
3381  if (compose_sync == MagickFalse)
3382  {
3383  pixel=(double) QuantumRange*(Sc+Dc);
3384  break;
3385  }
3386  pixel=(double) QuantumRange*(Sca+Dca);
3387  break;
3388  }
3389  case ReflectCompositeOp:
3390  {
3391  if (compose_sync == MagickFalse)
3392  {
3393  if (Dc < 1.0)
3394  blend=(Sc*Sc)/(1.0-Dc);
3395  else
3396  blend=1.0;
3397  pixel=(double) QuantumRange*RoundToUnity(blend);
3398  break;
3399  }
3400  if (Sa > 0.0)
3401  S=Sca/Sa;
3402  else
3403  S=0.0;
3404  if (Da > 0.0)
3405  D=Dca/Da;
3406  else
3407  D=0.0;
3408  if (D < 1.0)
3409  blend=(S*S)/(1.0-D);
3410  else
3411  blend=1.0;
3412  pixel=(double) QuantumRange*RoundToUnity((Sa+Da-Sa*Da)*blend);
3413  break;
3414  }
3415  case RMSECompositeOp:
3416  {
3417  double
3418  gray;
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  gray=sqrt(
3431  (canvas_pixel.red-source_pixel.red)*
3432  (canvas_pixel.red-source_pixel.red)+
3433  (canvas_pixel.green-source_pixel.green)*
3434  (canvas_pixel.green-source_pixel.green)+
3435  (canvas_pixel.blue-source_pixel.blue)*
3436  (canvas_pixel.blue-source_pixel.blue)/3.0);
3437  switch (channel)
3438  {
3439  case RedPixelChannel: pixel=gray; break;
3440  case GreenPixelChannel: pixel=gray; break;
3441  case BluePixelChannel: pixel=gray; break;
3442  default: pixel=Dc; break;
3443  }
3444  break;
3445  }
3446  case SaturateCompositeOp:
3447  {
3448  if (fabs((double) QuantumRange*Sa-(double) TransparentAlpha) < MagickEpsilon)
3449  {
3450  pixel=Dc;
3451  break;
3452  }
3453  if (fabs((double) QuantumRange*Da-(double) TransparentAlpha) < MagickEpsilon)
3454  {
3455  pixel=Sc;
3456  break;
3457  }
3458  ConvertRGBToGeneric(colorspace,(double) canvas_pixel.red,
3459  (double) canvas_pixel.green,(double) canvas_pixel.blue,
3460  white_luminance,illuminant,&hue,&chroma,&luma);
3461  ConvertRGBToGeneric(colorspace,(double) source_pixel.red,
3462  (double) source_pixel.green,(double) source_pixel.blue,
3463  white_luminance,illuminant,&sans,&chroma,&sans);
3464  ConvertGenericToRGB(colorspace,hue,chroma,luma,
3465  white_luminance,illuminant,&red,&green,&blue);
3466  switch (channel)
3467  {
3468  case RedPixelChannel: pixel=red; break;
3469  case GreenPixelChannel: pixel=green; break;
3470  case BluePixelChannel: pixel=blue; break;
3471  default: pixel=Dc; break;
3472  }
3473  break;
3474  }
3475  case ScreenCompositeOp:
3476  {
3477  if (compose_sync == MagickFalse)
3478  {
3479  pixel=(double) QuantumRange*RoundToUnity(Sc+Dc-Sc*Dc);
3480  break;
3481  }
3482  S=(Sa > 0.0) ? RoundToUnity(Sca/Sa) : 0.0;
3483  D=(Da > 0.0) ? RoundToUnity(Dca/Da) : 0.0;
3484  blend=RoundToUnity(S+D-S*D);
3485  pixel=(double) QuantumRange*RoundToUnity(Sa*Da*blend+Sca*(1.0-Da)+
3486  Dca*(1.0-Sa));
3487  break;
3488  }
3489  case SoftBurnCompositeOp:
3490  {
3491  if (RoundToUnity(Dca) <= 0.0)
3492  blend = 0.0;
3493  else
3494  if (RoundToUnity(Sca) >= 1.0)
3495  blend = 1.0;
3496  else
3497  blend=1.0-MagickMin(1.0,(1.0-RoundToUnity(Dca))/
3498  RoundToUnity(Sca));
3499  pixel=(double) QuantumRange*gamma*RoundToUnity(blend);
3500  break;
3501  }
3502  case SoftDodgeCompositeOp:
3503  {
3504  if (RoundToUnity(Sca) <= 0.0)
3505  blend=RoundToUnity(Dca);
3506  else
3507  if (RoundToUnity(Dca) >= 1.0)
3508  blend=1.0;
3509  else
3510  blend=MagickMin(1.0,RoundToUnity(Dca)/(1.0-RoundToUnity(Sca)));
3511  pixel=(double) QuantumRange*gamma*RoundToUnity(blend);
3512  break;
3513  }
3514  case SoftLightCompositeOp:
3515  {
3516  if (RoundToUnity(Sca) <= 0.5)
3517  {
3518  pixel=(double) QuantumRange*gamma*(RoundToUnity(Dca)*Sa+Da*
3519  (RoundToUnity(Dca)-(1.0-2.0*RoundToUnity(Sca))*
3520  RoundToUnity(Dca)*(1.0-RoundToUnity(Dca)))+RoundToUnity(Sca)*
3521  (1.0-Da)+RoundToUnity(Dca)*(1.0-Sa));
3522  break;
3523  }
3524  if (RoundToUnity(Dca) > 0.25)
3525  blend=sqrt(RoundToUnity(Dca));
3526  else
3527  blend=((16.0*RoundToUnity(Dca)-12.0)*RoundToUnity(Dca)+4.0)*
3528  RoundToUnity(Dca);
3529  pixel=(double) QuantumRange*gamma*(RoundToUnity(Dca)*Sa+Da*
3530  (RoundToUnity(Dca)+(2.0*RoundToUnity(Sca)-1.0)*
3531  (RoundToUnity(blend)-RoundToUnity(Dca)))+RoundToUnity(Sca)*
3532  (1.0-Da)+RoundToUnity(Dca)*(1.0-Sa));
3533  break;
3534  }
3535  case StampCompositeOp:
3536  {
3537  pixel=(double) QuantumRange*RoundToUnity(Sca+Dca-1.0);
3538  break;
3539  }
3540  case StereoCompositeOp:
3541  {
3542  if (channel == RedPixelChannel)
3543  pixel=(MagickRealType) GetPixelRed(source_image,p);
3544  break;
3545  }
3546  case ThresholdCompositeOp:
3547  {
3548  S=(Sa > 0.0) ? (Sca/Sa) : 0.0;
3549  D=(Da > 0.0) ? (Dca/Da) : 0.0;
3550  if (fabs(2.0*(S-D)) < threshold)
3551  blend=D;
3552  else
3553  blend=D+(S-D)*amount;
3554  pixel=(double) QuantumRange*(Sa*Da*RoundToUnity(blend)+Sca*
3555  (1.0-Da)+Dca*(1.0-Sa));
3556  break;
3557  }
3558  case VividLightCompositeOp:
3559  {
3560  if ((fabs((double) Sa) < MagickEpsilon) ||
3561  (fabs((double) Da) < MagickEpsilon))
3562  {
3563  pixel=(double) QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*
3564  (1.0-Sa));
3565  break;
3566  }
3567  if (RoundToUnity(Sca/Sa) <= 0.0)
3568  blend=0.0;
3569  else
3570  if (RoundToUnity(Sca/Sa) < 0.5)
3571  blend=1.0-(1.0-RoundToUnity(Dca/Da))/(2.0*RoundToUnity(Sca/Sa));
3572  else
3573  if (RoundToUnity(Sca/Sa) < 1.0)
3574  blend=RoundToUnity(Dca/Da)/(2.0*(1.0-RoundToUnity(Sca/Sa)));
3575  else
3576  blend=1.0;
3577  pixel=(double) QuantumRange*gamma*(Sa*Da*RoundToUnity(blend)+Sca*
3578  (1.0-Da)+Dca*(1.0-Sa));
3579  break;
3580  }
3581  case XorCompositeOp:
3582  {
3583  pixel=(double) QuantumRange*(Sca*(1.0-Da)+Dca*(1.0-Sa));
3584  break;
3585  }
3586  default:
3587  {
3588  pixel=Sc;
3589  break;
3590  }
3591  }
3592  q[i]=clamp != MagickFalse ? ClampPixel(pixel) : ClampToQuantum(pixel);
3593  }
3594  p+=(ptrdiff_t) GetPixelChannels(source_image);
3595  channels=GetPixelChannels(source_image);
3596  if (p >= (pixels+channels*source_image->columns))
3597  p=pixels;
3598  q+=(ptrdiff_t) GetPixelChannels(image);
3599  }
3600  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3601  status=MagickFalse;
3602  if (image->progress_monitor != (MagickProgressMonitor) NULL)
3603  {
3604  MagickBooleanType
3605  proceed;
3606 
3607 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3608  #pragma omp atomic
3609 #endif
3610  progress++;
3611  proceed=SetImageProgress(image,CompositeImageTag,progress,image->rows);
3612  if (proceed == MagickFalse)
3613  status=MagickFalse;
3614  }
3615  }
3616  source_view=DestroyCacheView(source_view);
3617  image_view=DestroyCacheView(image_view);
3618  if (canvas_image != (Image * ) NULL)
3619  canvas_image=DestroyImage(canvas_image);
3620  else
3621  source_image=DestroyImage(source_image);
3622  return(status);
3623 }
3624 ␌
3625 /*
3626 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3627 % %
3628 % %
3629 % %
3630 % T e x t u r e I m a g e %
3631 % %
3632 % %
3633 % %
3634 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3635 %
3636 % TextureImage() repeatedly tiles the texture image across and down the image
3637 % canvas.
3638 %
3639 % The format of the TextureImage method is:
3640 %
3641 % MagickBooleanType TextureImage(Image *image,const Image *texture,
3642 % ExceptionInfo *exception)
3643 %
3644 % A description of each parameter follows:
3645 %
3646 % o image: the image.
3647 %
3648 % o texture_image: This image is the texture to layer on the background.
3649 %
3650 */
3651 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
3652  ExceptionInfo *exception)
3653 {
3654 #define TextureImageTag "Texture/Image"
3655 
3656  CacheView
3657  *image_view,
3658  *texture_view;
3659 
3660  Image
3661  *texture_image;
3662 
3663  MagickBooleanType
3664  status;
3665 
3666  ssize_t
3667  y;
3668 
3669  assert(image != (Image *) NULL);
3670  assert(image->signature == MagickCoreSignature);
3671  if (IsEventLogging() != MagickFalse)
3672  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3673  if (texture == (const Image *) NULL)
3674  return(MagickFalse);
3675  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
3676  return(MagickFalse);
3677  texture_image=CloneImage(texture,0,0,MagickTrue,exception);
3678  if (texture_image == (const Image *) NULL)
3679  return(MagickFalse);
3680  (void) TransformImageColorspace(texture_image,image->colorspace,exception);
3681  (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
3682  exception);
3683  status=MagickTrue;
3684  if ((image->compose != CopyCompositeOp) &&
3685  ((image->compose != OverCompositeOp) ||
3686  (image->alpha_trait != UndefinedPixelTrait) ||
3687  (texture_image->alpha_trait != UndefinedPixelTrait)))
3688  {
3689  /*
3690  Tile texture onto the image background.
3691  */
3692  for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
3693  {
3694  ssize_t
3695  x;
3696 
3697  if (status == MagickFalse)
3698  continue;
3699  for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
3700  {
3701  MagickBooleanType
3702  thread_status;
3703 
3704  thread_status=CompositeImage(image,texture_image,image->compose,
3705  MagickTrue,x+texture_image->tile_offset.x,y+
3706  texture_image->tile_offset.y,exception);
3707  if (thread_status == MagickFalse)
3708  {
3709  status=thread_status;
3710  break;
3711  }
3712  }
3713  if (image->progress_monitor != (MagickProgressMonitor) NULL)
3714  {
3715  MagickBooleanType
3716  proceed;
3717 
3718  proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
3719  image->rows);
3720  if (proceed == MagickFalse)
3721  status=MagickFalse;
3722  }
3723  }
3724  (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
3725  image->rows,image->rows);
3726  texture_image=DestroyImage(texture_image);
3727  return(status);
3728  }
3729  /*
3730  Tile texture onto the image background (optimized).
3731  */
3732  status=MagickTrue;
3733  texture_view=AcquireVirtualCacheView(texture_image,exception);
3734  image_view=AcquireAuthenticCacheView(image,exception);
3735 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3736  #pragma omp parallel for schedule(static) shared(status) \
3737  magick_number_threads(texture_image,image,image->rows,2)
3738 #endif
3739  for (y=0; y < (ssize_t) image->rows; y++)
3740  {
3741  MagickBooleanType
3742  sync;
3743 
3744  const Quantum
3745  *p,
3746  *pixels;
3747 
3748  ssize_t
3749  x;
3750 
3751  Quantum
3752  *q;
3753 
3754  size_t
3755  width;
3756 
3757  if (status == MagickFalse)
3758  continue;
3759  pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
3760  (y+texture_image->tile_offset.y) % (ssize_t) texture_image->rows,
3761  texture_image->columns,1,exception);
3762  q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3763  if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3764  {
3765  status=MagickFalse;
3766  continue;
3767  }
3768  for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
3769  {
3770  ssize_t
3771  j;
3772 
3773  p=pixels;
3774  width=texture_image->columns;
3775  if ((x+(ssize_t) width) > (ssize_t) image->columns)
3776  width=image->columns-(size_t) x;
3777  for (j=0; j < (ssize_t) width; j++)
3778  {
3779  ssize_t
3780  i;
3781 
3782  for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
3783  {
3784  PixelChannel channel = GetPixelChannelChannel(texture_image,i);
3785  PixelTrait traits = GetPixelChannelTraits(image,channel);
3786  PixelTrait texture_traits=GetPixelChannelTraits(texture_image,
3787  channel);
3788  if ((traits == UndefinedPixelTrait) ||
3789  (texture_traits == UndefinedPixelTrait))
3790  continue;
3791  SetPixelChannel(image,channel,p[i],q);
3792  }
3793  p+=(ptrdiff_t) GetPixelChannels(texture_image);
3794  q+=(ptrdiff_t) GetPixelChannels(image);
3795  }
3796  }
3797  sync=SyncCacheViewAuthenticPixels(image_view,exception);
3798  if (sync == MagickFalse)
3799  status=MagickFalse;
3800  if (image->progress_monitor != (MagickProgressMonitor) NULL)
3801  {
3802  MagickBooleanType
3803  proceed;
3804 
3805  proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
3806  image->rows);
3807  if (proceed == MagickFalse)
3808  status=MagickFalse;
3809  }
3810  }
3811  texture_view=DestroyCacheView(texture_view);
3812  image_view=DestroyCacheView(image_view);
3813  texture_image=DestroyImage(texture_image);
3814  return(status);
3815 }
Definition: image.h:132