MagickCore  7.0.3
composite.c
Go to the documentation of this file.
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % CCCC OOO M M PPPP OOO SSSSS IIIII TTTTT EEEEE %
7 % C O O MM MM P P O O SS I T E %
8 % C O O M M M PPPP O O SSS I T EEE %
9 % C O O M M P O O SS I T E %
10 % CCCC OOO M M P OOO SSSSS IIIII T EEEEE %
11 % %
12 % %
13 % MagickCore Image Composite Methods %
14 % %
15 % Software Design %
16 % Cristy %
17 % July 1992 %
18 % %
19 % %
20 % Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 %
38 */
39 
40 /*
41  Include declarations.
42 */
43 #include "MagickCore/studio.h"
44 #include "MagickCore/artifact.h"
45 #include "MagickCore/cache.h"
47 #include "MagickCore/cache-view.h"
48 #include "MagickCore/channel.h"
49 #include "MagickCore/client.h"
50 #include "MagickCore/color.h"
52 #include "MagickCore/colorspace.h"
54 #include "MagickCore/composite.h"
56 #include "MagickCore/constitute.h"
57 #include "MagickCore/draw.h"
58 #include "MagickCore/fx.h"
59 #include "MagickCore/gem.h"
60 #include "MagickCore/geometry.h"
61 #include "MagickCore/image.h"
63 #include "MagickCore/list.h"
64 #include "MagickCore/log.h"
65 #include "MagickCore/monitor.h"
67 #include "MagickCore/memory_.h"
68 #include "MagickCore/option.h"
70 #include "MagickCore/property.h"
71 #include "MagickCore/quantum.h"
72 #include "MagickCore/resample.h"
73 #include "MagickCore/resource_.h"
74 #include "MagickCore/string_.h"
76 #include "MagickCore/threshold.h"
77 #include "MagickCore/token.h"
78 #include "MagickCore/utility.h"
80 #include "MagickCore/version.h"
81 
82 /*
83 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
84 % %
85 % %
86 % %
87 % C o m p o s i t e I m a g e %
88 % %
89 % %
90 % %
91 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
92 %
93 % CompositeImage() returns the second image composited onto the first
94 % at the specified offset, using the specified composite method.
95 %
96 % The format of the CompositeImage method is:
97 %
98 % MagickBooleanType CompositeImage(Image *image,
99 % const Image *source_image,const CompositeOperator compose,
100 % const MagickBooleanType clip_to_self,const ssize_t x_offset,
101 % const ssize_t y_offset,ExceptionInfo *exception)
102 %
103 % A description of each parameter follows:
104 %
105 % o image: the canvas image, modified by he composition
106 %
107 % o source_image: the source image.
108 %
109 % o compose: This operator affects how the composite is applied to
110 % the image. The operators and how they are utilized are listed here
111 % http://www.w3.org/TR/SVG12/#compositing.
112 %
113 % o clip_to_self: set to MagickTrue to limit composition to area composed.
114 %
115 % o x_offset: the column offset of the composited image.
116 %
117 % o y_offset: the row offset of the composited image.
118 %
119 % Extra Controls from Image meta-data in 'image' (artifacts)
120 %
121 % o "compose:args"
122 % A string containing extra numerical arguments for specific compose
123 % methods, generally expressed as a 'geometry' or a comma separated list
124 % of numbers.
125 %
126 % Compose methods needing such arguments include "BlendCompositeOp" and
127 % "DisplaceCompositeOp".
128 %
129 % o exception: return any errors or warnings in this structure.
130 %
131 */
132 
133 /*
134  Composition based on the SVG specification:
135 
136  A Composition is defined by...
137  Color Function : f(Sc,Dc) where Sc and Dc are the normizalized colors
138  Blending areas : X = 1 for area of overlap, ie: f(Sc,Dc)
139  Y = 1 for source preserved
140  Z = 1 for canvas preserved
141 
142  Conversion to transparency (then optimized)
143  Dca' = f(Sc, Dc)*Sa*Da + Y*Sca*(1-Da) + Z*Dca*(1-Sa)
144  Da' = X*Sa*Da + Y*Sa*(1-Da) + Z*Da*(1-Sa)
145 
146  Where...
147  Sca = Sc*Sa normalized Source color divided by Source alpha
148  Dca = Dc*Da normalized Dest color divided by Dest alpha
149  Dc' = Dca'/Da' the desired color value for this channel.
150 
151  Da' in in the follow formula as 'gamma' The resulting alpla value.
152 
153  Most functions use a blending mode of over (X=1,Y=1,Z=1) this results in
154  the following optimizations...
155  gamma = Sa+Da-Sa*Da;
156  gamma = 1 - QuantumScale*alpha * QuantumScale*beta;
157  opacity = QuantumScale*alpha*beta; // over blend, optimized 1-Gamma
158 
159  The above SVG definitions also define that Mathematical Composition
160  methods should use a 'Over' blending mode for Alpha Channel.
161  It however was not applied for composition modes of 'Plus', 'Minus',
162  the modulus versions of 'Add' and 'Subtract'.
163 
164  Mathematical operator changes to be applied from IM v6.7...
165 
166  1) Modulus modes 'Add' and 'Subtract' are obsoleted and renamed
167  'ModulusAdd' and 'ModulusSubtract' for clarity.
168 
169  2) All mathematical compositions work as per the SVG specification
170  with regard to blending. This now includes 'ModulusAdd' and
171  'ModulusSubtract'.
172 
173  3) When the special channel flag 'sync' (syncronize channel updates)
174  is turned off (enabled by default) then mathematical compositions are
175  only performed on the channels specified, and are applied
176  independantally of each other. In other words the mathematics is
177  performed as 'pure' mathematical operations, rather than as image
178  operations.
179 */
180 
181 static void HCLComposite(const MagickRealType hue,const MagickRealType chroma,
182  const MagickRealType luma,MagickRealType *red,MagickRealType *green,
183  MagickRealType *blue)
184 {
186  b,
187  c,
188  g,
189  h,
190  m,
191  r,
192  x;
193 
194  /*
195  Convert HCL to RGB colorspace.
196  */
197  assert(red != (MagickRealType *) NULL);
198  assert(green != (MagickRealType *) NULL);
199  assert(blue != (MagickRealType *) NULL);
200  h=6.0*hue;
201  c=chroma;
202  x=c*(1.0-fabs(fmod(h,2.0)-1.0));
203  r=0.0;
204  g=0.0;
205  b=0.0;
206  if ((0.0 <= h) && (h < 1.0))
207  {
208  r=c;
209  g=x;
210  }
211  else
212  if ((1.0 <= h) && (h < 2.0))
213  {
214  r=x;
215  g=c;
216  }
217  else
218  if ((2.0 <= h) && (h < 3.0))
219  {
220  g=c;
221  b=x;
222  }
223  else
224  if ((3.0 <= h) && (h < 4.0))
225  {
226  g=x;
227  b=c;
228  }
229  else
230  if ((4.0 <= h) && (h < 5.0))
231  {
232  r=x;
233  b=c;
234  }
235  else
236  if ((5.0 <= h) && (h < 6.0))
237  {
238  r=c;
239  b=x;
240  }
241  m=luma-(0.298839*r+0.586811*g+0.114350*b);
242  *red=QuantumRange*(r+m);
243  *green=QuantumRange*(g+m);
244  *blue=QuantumRange*(b+m);
245 }
246 
247 static void CompositeHCL(const MagickRealType red,const MagickRealType green,
248  const MagickRealType blue,MagickRealType *hue,MagickRealType *chroma,
249  MagickRealType *luma)
250 {
252  b,
253  c,
254  g,
255  h,
256  max,
257  r;
258 
259  /*
260  Convert RGB to HCL colorspace.
261  */
262  assert(hue != (MagickRealType *) NULL);
263  assert(chroma != (MagickRealType *) NULL);
264  assert(luma != (MagickRealType *) NULL);
265  r=red;
266  g=green;
267  b=blue;
268  max=MagickMax(r,MagickMax(g,b));
269  c=max-(MagickRealType) MagickMin(r,MagickMin(g,b));
270  h=0.0;
271  if (c == 0)
272  h=0.0;
273  else
274  if (red == max)
275  h=fmod((g-b)/c+6.0,6.0);
276  else
277  if (green == max)
278  h=((b-r)/c)+2.0;
279  else
280  if (blue == max)
281  h=((r-g)/c)+4.0;
282  *hue=(h/6.0);
283  *chroma=QuantumScale*c;
284  *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
285 }
286 
288  const Image *source_image,const MagickBooleanType clip_to_self,
289  const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
290 {
291 #define CompositeImageTag "Composite/Image"
292 
293  CacheView
294  *image_view,
295  *source_view;
296 
297  const char
298  *value;
299 
301  clamp,
302  status;
303 
305  progress;
306 
307  ssize_t
308  y;
309 
310  /*
311  Composite image.
312  */
313  status=MagickTrue;
314  progress=0;
315  clamp=MagickTrue;
316  value=GetImageArtifact(image,"compose:clamp");
317  if (value != (const char *) NULL)
318  clamp=IsStringTrue(value);
319  status=MagickTrue;
320  progress=0;
321  source_view=AcquireVirtualCacheView(source_image,exception);
322  image_view=AcquireAuthenticCacheView(image,exception);
323 #if defined(MAGICKCORE_OPENMP_SUPPORT)
324  #pragma omp parallel for schedule(static) shared(progress,status) \
325  magick_number_threads(source_image,image,image->rows,1)
326 #endif
327  for (y=0; y < (ssize_t) image->rows; y++)
328  {
329  const Quantum
330  *pixels;
331 
332  PixelInfo
333  canvas_pixel,
334  source_pixel;
335 
336  register const Quantum
337  *magick_restrict p;
338 
339  register Quantum
340  *magick_restrict q;
341 
342  register ssize_t
343  x;
344 
345  if (status == MagickFalse)
346  continue;
347  if (clip_to_self != MagickFalse)
348  {
349  if (y < y_offset)
350  continue;
351  if ((y-y_offset) >= (ssize_t) source_image->rows)
352  continue;
353  }
354  /*
355  If pixels is NULL, y is outside overlay region.
356  */
357  pixels=(Quantum *) NULL;
358  p=(Quantum *) NULL;
359  if ((y >= y_offset) && ((y-y_offset) < (ssize_t) source_image->rows))
360  {
361  p=GetCacheViewVirtualPixels(source_view,0,y-y_offset,
362  source_image->columns,1,exception);
363  if (p == (const Quantum *) NULL)
364  {
365  status=MagickFalse;
366  continue;
367  }
368  pixels=p;
369  if (x_offset < 0)
370  p-=x_offset*GetPixelChannels(source_image);
371  }
372  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
373  if (q == (Quantum *) NULL)
374  {
375  status=MagickFalse;
376  continue;
377  }
378  GetPixelInfo(image,&canvas_pixel);
379  GetPixelInfo(source_image,&source_pixel);
380  for (x=0; x < (ssize_t) image->columns; x++)
381  {
382  double
383  gamma;
384 
386  alpha,
387  Da,
388  Dc,
389  Dca,
390  Sa,
391  Sc,
392  Sca;
393 
394  register ssize_t
395  i;
396 
397  size_t
398  channels;
399 
400  if (clip_to_self != MagickFalse)
401  {
402  if (x < x_offset)
403  {
404  q+=GetPixelChannels(image);
405  continue;
406  }
407  if ((x-x_offset) >= (ssize_t) source_image->columns)
408  break;
409  }
410  if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
411  ((x-x_offset) >= (ssize_t) source_image->columns))
412  {
413  Quantum
414  source[MaxPixelChannels];
415 
416  /*
417  Virtual composite:
418  Sc: source color.
419  Dc: canvas color.
420  */
421  (void) GetOneVirtualPixel(source_image,x-x_offset,y-y_offset,source,
422  exception);
423  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
424  {
426  pixel;
427 
428  PixelChannel channel = GetPixelChannelChannel(image,i);
429  PixelTrait traits = GetPixelChannelTraits(image,channel);
430  PixelTrait source_traits=GetPixelChannelTraits(source_image,
431  channel);
432  if ((traits == UndefinedPixelTrait) ||
433  (source_traits == UndefinedPixelTrait))
434  continue;
435  if (channel == AlphaPixelChannel)
437  else
438  pixel=(MagickRealType) q[i];
439  q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
440  ClampToQuantum(pixel);
441  }
442  q+=GetPixelChannels(image);
443  continue;
444  }
445  /*
446  Authentic composite:
447  Sa: normalized source alpha.
448  Da: normalized canvas alpha.
449  */
450  Sa=QuantumScale*GetPixelAlpha(source_image,p);
451  Da=QuantumScale*GetPixelAlpha(image,q);
452  alpha=Sa+Da-Sa*Da;
453  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
454  {
456  pixel;
457 
458  PixelChannel channel = GetPixelChannelChannel(image,i);
459  PixelTrait traits = GetPixelChannelTraits(image,channel);
460  PixelTrait source_traits=GetPixelChannelTraits(source_image,channel);
461  if (traits == UndefinedPixelTrait)
462  continue;
463  if ((source_traits == UndefinedPixelTrait) &&
464  (channel != AlphaPixelChannel))
465  continue;
466  if (channel == AlphaPixelChannel)
467  {
468  /*
469  Set alpha channel.
470  */
471  pixel=QuantumRange*alpha;
472  q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
473  ClampToQuantum(pixel);
474  continue;
475  }
476  /*
477  Sc: source color.
478  Dc: canvas color.
479  */
480  Sc=(MagickRealType) GetPixelChannel(source_image,channel,p);
481  Dc=(MagickRealType) q[i];
482  if ((traits & CopyPixelTrait) != 0)
483  {
484  /*
485  Copy channel.
486  */
487  q[i]=ClampToQuantum(Sc);
488  continue;
489  }
490  /*
491  Porter-Duff compositions:
492  Sca: source normalized color multiplied by alpha.
493  Dca: normalized canvas color multiplied by alpha.
494  */
495  Sca=QuantumScale*Sa*Sc;
496  Dca=QuantumScale*Da*Dc;
497  gamma=PerceptibleReciprocal(alpha);
498  pixel=QuantumRange*gamma*(Sca+Dca*(1.0-Sa));
499  q[i]=clamp != MagickFalse ? ClampPixel(pixel) : ClampToQuantum(pixel);
500  }
501  p+=GetPixelChannels(source_image);
502  channels=GetPixelChannels(source_image);
503  if (p >= (pixels+channels*source_image->columns))
504  p=pixels;
505  q+=GetPixelChannels(image);
506  }
507  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
508  status=MagickFalse;
509  if (image->progress_monitor != (MagickProgressMonitor) NULL)
510  {
512  proceed;
513 
514 #if defined(MAGICKCORE_OPENMP_SUPPORT)
515  #pragma omp atomic
516 #endif
517  progress++;
518  proceed=SetImageProgress(image,CompositeImageTag,progress,image->rows);
519  if (proceed == MagickFalse)
520  status=MagickFalse;
521  }
522  }
523  source_view=DestroyCacheView(source_view);
524  image_view=DestroyCacheView(image_view);
525  return(status);
526 }
527 
529  const Image *composite,const CompositeOperator compose,
530  const MagickBooleanType clip_to_self,const ssize_t x_offset,
531  const ssize_t y_offset,ExceptionInfo *exception)
532 {
533 #define CompositeImageTag "Composite/Image"
534 
535  CacheView
536  *source_view,
537  *image_view;
538 
539  const char
540  *value;
541 
543  geometry_info;
544 
545  Image
546  *canvas_image,
547  *source_image;
548 
550  clamp,
551  status;
552 
554  progress;
555 
557  amount,
558  canvas_dissolve,
559  midpoint,
560  percent_luma,
561  percent_chroma,
562  source_dissolve,
563  threshold;
564 
566  flags;
567 
568  ssize_t
569  y;
570 
571  assert(image != (Image *) NULL);
572  assert(image->signature == MagickCoreSignature);
573  if (image->debug != MagickFalse)
574  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
575  assert(composite != (Image *) NULL);
576  assert(composite->signature == MagickCoreSignature);
577  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
578  return(MagickFalse);
579  source_image=CloneImage(composite,0,0,MagickTrue,exception);
580  if (source_image == (const Image *) NULL)
581  return(MagickFalse);
582  if (IsGrayColorspace(image->colorspace) != MagickFalse)
583  (void) SetImageColorspace(image,sRGBColorspace,exception);
584  (void) SetImageColorspace(source_image,image->colorspace,exception);
585  if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
586  {
587  status=CompositeOverImage(image,source_image,clip_to_self,x_offset,
588  y_offset,exception);
589  source_image=DestroyImage(source_image);
590  return(status);
591  }
592  amount=0.5;
593  canvas_image=(Image *) NULL;
594  canvas_dissolve=1.0;
595  clamp=MagickTrue;
596  value=GetImageArtifact(image,"compose:clamp");
597  if (value != (const char *) NULL)
598  clamp=IsStringTrue(value);
599  SetGeometryInfo(&geometry_info);
600  percent_luma=100.0;
601  percent_chroma=100.0;
602  source_dissolve=1.0;
603  threshold=0.05f;
604  switch (compose)
605  {
606  case CopyCompositeOp:
607  {
608  if ((x_offset < 0) || (y_offset < 0))
609  break;
610  if ((x_offset+(ssize_t) source_image->columns) > (ssize_t) image->columns)
611  break;
612  if ((y_offset+(ssize_t) source_image->rows) > (ssize_t) image->rows)
613  break;
614  if ((source_image->alpha_trait == UndefinedPixelTrait) &&
615  (image->alpha_trait != UndefinedPixelTrait))
616  (void) SetImageAlphaChannel(source_image,OpaqueAlphaChannel,exception);
617  status=MagickTrue;
618  source_view=AcquireVirtualCacheView(source_image,exception);
619  image_view=AcquireAuthenticCacheView(image,exception);
620 #if defined(MAGICKCORE_OPENMP_SUPPORT)
621  #pragma omp parallel for schedule(static) shared(status) \
622  magick_number_threads(source_image,image,source_image->rows,1)
623 #endif
624  for (y=0; y < (ssize_t) source_image->rows; y++)
625  {
627  sync;
628 
629  register const Quantum
630  *p;
631 
632  register Quantum
633  *q;
634 
635  register ssize_t
636  x;
637 
638  if (status == MagickFalse)
639  continue;
640  p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
641  exception);
642  q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
643  source_image->columns,1,exception);
644  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
645  {
646  status=MagickFalse;
647  continue;
648  }
649  for (x=0; x < (ssize_t) source_image->columns; x++)
650  {
651  register ssize_t
652  i;
653 
654  if (GetPixelReadMask(source_image,p) <= (QuantumRange/2))
655  {
656  p+=GetPixelChannels(source_image);
657  q+=GetPixelChannels(image);
658  continue;
659  }
660  for (i=0; i < (ssize_t) GetPixelChannels(source_image); i++)
661  {
662  PixelChannel channel = GetPixelChannelChannel(source_image,i);
663  PixelTrait source_traits = GetPixelChannelTraits(source_image,
664  channel);
665  PixelTrait traits = GetPixelChannelTraits(image,channel);
666  if ((source_traits == UndefinedPixelTrait) ||
667  (traits == UndefinedPixelTrait))
668  continue;
669  SetPixelChannel(image,channel,p[i],q);
670  }
671  p+=GetPixelChannels(source_image);
672  q+=GetPixelChannels(image);
673  }
674  sync=SyncCacheViewAuthenticPixels(image_view,exception);
675  if (sync == MagickFalse)
676  status=MagickFalse;
677  if (image->progress_monitor != (MagickProgressMonitor) NULL)
678  {
680  proceed;
681 
683  y,image->rows);
684  if (proceed == MagickFalse)
685  status=MagickFalse;
686  }
687  }
688  source_view=DestroyCacheView(source_view);
689  image_view=DestroyCacheView(image_view);
690  source_image=DestroyImage(source_image);
691  return(status);
692  }
694  {
695  if ((x_offset < 0) || (y_offset < 0))
696  break;
697  if ((x_offset+(ssize_t) source_image->columns) > (ssize_t) image->columns)
698  break;
699  if ((y_offset+(ssize_t) source_image->rows) > (ssize_t) image->rows)
700  break;
701  status=MagickTrue;
702  source_view=AcquireVirtualCacheView(source_image,exception);
703  image_view=AcquireAuthenticCacheView(image,exception);
704 #if defined(MAGICKCORE_OPENMP_SUPPORT)
705  #pragma omp parallel for schedule(static) shared(status) \
706  magick_number_threads(source_image,image,source_image->rows,1)
707 #endif
708  for (y=0; y < (ssize_t) source_image->rows; y++)
709  {
711  sync;
712 
713  register const Quantum
714  *p;
715 
716  register Quantum
717  *q;
718 
719  register ssize_t
720  x;
721 
722  if (status == MagickFalse)
723  continue;
724  p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
725  exception);
726  q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
727  source_image->columns,1,exception);
728  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
729  {
730  status=MagickFalse;
731  continue;
732  }
733  for (x=0; x < (ssize_t) source_image->columns; x++)
734  {
735  if (GetPixelReadMask(source_image,p) <= (QuantumRange/2))
736  {
737  p+=GetPixelChannels(source_image);
738  q+=GetPixelChannels(image);
739  continue;
740  }
741  SetPixelAlpha(image,clamp != MagickFalse ?
742  ClampPixel(GetPixelIntensity(source_image,p)) :
743  ClampToQuantum(GetPixelIntensity(source_image,p)),q);
744  p+=GetPixelChannels(source_image);
745  q+=GetPixelChannels(image);
746  }
747  sync=SyncCacheViewAuthenticPixels(image_view,exception);
748  if (sync == MagickFalse)
749  status=MagickFalse;
750  if (image->progress_monitor != (MagickProgressMonitor) NULL)
751  {
753  proceed;
754 
756  y,image->rows);
757  if (proceed == MagickFalse)
758  status=MagickFalse;
759  }
760  }
761  source_view=DestroyCacheView(source_view);
762  image_view=DestroyCacheView(image_view);
763  source_image=DestroyImage(source_image);
764  return(status);
765  }
768  {
769  /*
770  Modify canvas outside the overlaid region and require an alpha
771  channel to exist, to add transparency.
772  */
773  if (image->alpha_trait == UndefinedPixelTrait)
774  (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
775  break;
776  }
777  case BlurCompositeOp:
778  {
779  CacheView
780  *canvas_view;
781 
783  angle_range,
784  angle_start,
785  height,
786  width;
787 
788  PixelInfo
789  pixel;
790 
792  *resample_filter;
793 
795  blur;
796 
797  /*
798  Blur Image by resampling.
799 
800  Blur Image dictated by an overlay gradient map: X = red_channel;
801  Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
802  */
803  canvas_image=CloneImage(image,0,0,MagickTrue,
804  exception);
805  if (canvas_image == (Image *) NULL)
806  {
807  source_image=DestroyImage(source_image);
808  return(MagickFalse);
809  }
810  /*
811  Gather the maximum blur sigma values from user.
812  */
813  flags=NoValue;
814  value=GetImageArtifact(image,"compose:args");
815  if (value != (const char *) NULL)
816  flags=ParseGeometry(value,&geometry_info);
817  if ((flags & WidthValue) == 0)
818  {
820  "InvalidSetting","'%s' '%s'","compose:args",value);
821  source_image=DestroyImage(source_image);
822  canvas_image=DestroyImage(canvas_image);
823  return(MagickFalse);
824  }
825  /*
826  Users input sigma now needs to be converted to the EWA ellipse size.
827  The filter defaults to a sigma of 0.5 so to make this match the
828  users input the ellipse size needs to be doubled.
829  */
830  width=height=geometry_info.rho*2.0;
831  if ((flags & HeightValue) != 0 )
832  height=geometry_info.sigma*2.0;
833  /*
834  Default the unrotated ellipse width and height axis vectors.
835  */
836  blur.x1=width;
837  blur.x2=0.0;
838  blur.y1=0.0;
839  blur.y2=height;
840  /* rotate vectors if a rotation angle is given */
841  if ((flags & XValue) != 0 )
842  {
844  angle;
845 
846  angle=DegreesToRadians(geometry_info.xi);
847  blur.x1=width*cos(angle);
848  blur.x2=width*sin(angle);
849  blur.y1=(-height*sin(angle));
850  blur.y2=height*cos(angle);
851  }
852  /* Otherwise lets set a angle range and calculate in the loop */
853  angle_start=0.0;
854  angle_range=0.0;
855  if ((flags & YValue) != 0 )
856  {
857  angle_start=DegreesToRadians(geometry_info.xi);
858  angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
859  }
860  /*
861  Set up a gaussian cylindrical filter for EWA Bluring.
862 
863  As the minimum ellipse radius of support*1.0 the EWA algorithm
864  can only produce a minimum blur of 0.5 for Gaussian (support=2.0)
865  This means that even 'No Blur' will be still a little blurry!
866 
867  The solution (as well as the problem of preventing any user
868  expert filter settings, is to set our own user settings, then
869  restore them afterwards.
870  */
871  resample_filter=AcquireResampleFilter(image,exception);
872  SetResampleFilter(resample_filter,GaussianFilter);
873 
874  /* do the variable blurring of each pixel in image */
875  GetPixelInfo(image,&pixel);
876  source_view=AcquireVirtualCacheView(source_image,exception);
877  canvas_view=AcquireAuthenticCacheView(canvas_image,exception);
878  for (y=0; y < (ssize_t) source_image->rows; y++)
879  {
881  sync;
882 
883  register const Quantum
884  *magick_restrict p;
885 
886  register Quantum
887  *magick_restrict q;
888 
889  register ssize_t
890  x;
891 
892  if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
893  continue;
894  p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
895  exception);
896  q=QueueCacheViewAuthenticPixels(canvas_view,0,y,canvas_image->columns,1,
897  exception);
898  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
899  break;
900  for (x=0; x < (ssize_t) source_image->columns; x++)
901  {
902  if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
903  {
904  p+=GetPixelChannels(source_image);
905  continue;
906  }
907  if (fabs((double) angle_range) > MagickEpsilon)
908  {
910  angle;
911 
912  angle=angle_start+angle_range*QuantumScale*
913  GetPixelBlue(source_image,p);
914  blur.x1=width*cos(angle);
915  blur.x2=width*sin(angle);
916  blur.y1=(-height*sin(angle));
917  blur.y2=height*cos(angle);
918  }
919 #if 0
920  if ( x == 10 && y == 60 ) {
921  (void) fprintf(stderr, "blur.x=%lf,%lf, blur.y=%lf,%lf\n",blur.x1,
922  blur.x2,blur.y1, blur.y2);
923  (void) fprintf(stderr, "scaled by=%lf,%lf\n",QuantumScale*
925 #endif
926  ScaleResampleFilter(resample_filter,
927  blur.x1*QuantumScale*GetPixelRed(source_image,p),
928  blur.y1*QuantumScale*GetPixelGreen(source_image,p),
929  blur.x2*QuantumScale*GetPixelRed(source_image,p),
930  blur.y2*QuantumScale*GetPixelGreen(source_image,p) );
931  (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
932  (double) y_offset+y,&pixel,exception);
933  SetPixelViaPixelInfo(canvas_image,&pixel,q);
934  p+=GetPixelChannels(source_image);
935  q+=GetPixelChannels(canvas_image);
936  }
937  sync=SyncCacheViewAuthenticPixels(canvas_view,exception);
938  if (sync == MagickFalse)
939  break;
940  }
941  resample_filter=DestroyResampleFilter(resample_filter);
942  source_view=DestroyCacheView(source_view);
943  canvas_view=DestroyCacheView(canvas_view);
944  source_image=DestroyImage(source_image);
945  source_image=canvas_image;
946  break;
947  }
948  case DisplaceCompositeOp:
949  case DistortCompositeOp:
950  {
951  CacheView
952  *canvas_view;
953 
955  horizontal_scale,
956  vertical_scale;
957 
958  PixelInfo
959  pixel;
960 
961  PointInfo
962  center,
963  offset;
964 
965  /*
966  Displace/Distort based on overlay gradient map:
967  X = red_channel; Y = green_channel;
968  compose:args = x_scale[,y_scale[,center.x,center.y]]
969  */
970  canvas_image=CloneImage(image,0,0,MagickTrue,
971  exception);
972  if (canvas_image == (Image *) NULL)
973  {
974  source_image=DestroyImage(source_image);
975  return(MagickFalse);
976  }
977  SetGeometryInfo(&geometry_info);
978  flags=NoValue;
979  value=GetImageArtifact(image,"compose:args");
980  if (value != (char *) NULL)
981  flags=ParseGeometry(value,&geometry_info);
982  if ((flags & (WidthValue | HeightValue)) == 0 )
983  {
984  if ((flags & AspectValue) == 0)
985  {
986  horizontal_scale=(MagickRealType) (source_image->columns-1)/2.0;
987  vertical_scale=(MagickRealType) (source_image->rows-1)/2.0;
988  }
989  else
990  {
991  horizontal_scale=(MagickRealType) (image->columns-1)/2.0;
992  vertical_scale=(MagickRealType) (image->rows-1)/2.0;
993  }
994  }
995  else
996  {
997  horizontal_scale=geometry_info.rho;
998  vertical_scale=geometry_info.sigma;
999  if ((flags & PercentValue) != 0)
1000  {
1001  if ((flags & AspectValue) == 0)
1002  {
1003  horizontal_scale*=(source_image->columns-1)/200.0;
1004  vertical_scale*=(source_image->rows-1)/200.0;
1005  }
1006  else
1007  {
1008  horizontal_scale*=(image->columns-1)/200.0;
1009  vertical_scale*=(image->rows-1)/200.0;
1010  }
1011  }
1012  if ((flags & HeightValue) == 0)
1013  vertical_scale=horizontal_scale;
1014  }
1015  /*
1016  Determine fixed center point for absolute distortion map
1017  Absolute distort ==
1018  Displace offset relative to a fixed absolute point
1019  Select that point according to +X+Y user inputs.
1020  default = center of overlay image
1021  arg flag '!' = locations/percentage relative to background image
1022  */
1023  center.x=(MagickRealType) x_offset;
1024  center.y=(MagickRealType) y_offset;
1025  if (compose == DistortCompositeOp)
1026  {
1027  if ((flags & XValue) == 0)
1028  if ((flags & AspectValue) != 0)
1029  center.x=(MagickRealType) ((image->columns-1)/2.0);
1030  else
1031  center.x=(MagickRealType) (x_offset+(source_image->columns-1)/
1032  2.0);
1033  else
1034  if ((flags & AspectValue) != 0)
1035  center.x=geometry_info.xi;
1036  else
1037  center.x=(MagickRealType) (x_offset+geometry_info.xi);
1038  if ((flags & YValue) == 0)
1039  if ((flags & AspectValue) != 0)
1040  center.y=(MagickRealType) ((image->rows-1)/2.0);
1041  else
1042  center.y=(MagickRealType) (y_offset+(source_image->rows-1)/2.0);
1043  else
1044  if ((flags & AspectValue) != 0)
1045  center.y=geometry_info.psi;
1046  else
1047  center.y=(MagickRealType) (y_offset+geometry_info.psi);
1048  }
1049  /*
1050  Shift the pixel offset point as defined by the provided,
1051  displacement/distortion map. -- Like a lens...
1052  */
1053  GetPixelInfo(image,&pixel);
1054  image_view=AcquireVirtualCacheView(image,exception);
1055  source_view=AcquireVirtualCacheView(source_image,exception);
1056  canvas_view=AcquireAuthenticCacheView(canvas_image,exception);
1057  for (y=0; y < (ssize_t) source_image->rows; y++)
1058  {
1060  sync;
1061 
1062  register const Quantum
1063  *magick_restrict p;
1064 
1065  register Quantum
1066  *magick_restrict q;
1067 
1068  register ssize_t
1069  x;
1070 
1071  if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1072  continue;
1073  p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
1074  exception);
1075  q=QueueCacheViewAuthenticPixels(canvas_view,0,y,canvas_image->columns,1,
1076  exception);
1077  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1078  break;
1079  for (x=0; x < (ssize_t) source_image->columns; x++)
1080  {
1081  if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1082  {
1083  p+=GetPixelChannels(source_image);
1084  continue;
1085  }
1086  /*
1087  Displace the offset.
1088  */
1089  offset.x=(double) (horizontal_scale*(GetPixelRed(source_image,p)-
1090  (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1091  QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
1092  x : 0);
1093  offset.y=(double) (vertical_scale*(GetPixelGreen(source_image,p)-
1094  (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1095  QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
1096  y : 0);
1097  status=InterpolatePixelInfo(image,image_view,
1098  UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1099  &pixel,exception);
1100  if (status == MagickFalse)
1101  break;
1102  /*
1103  Mask with the 'invalid pixel mask' in alpha channel.
1104  */
1106  (QuantumScale*GetPixelAlpha(source_image,p));
1107  SetPixelViaPixelInfo(canvas_image,&pixel,q);
1108  p+=GetPixelChannels(source_image);
1109  q+=GetPixelChannels(canvas_image);
1110  }
1111  if (x < (ssize_t) source_image->columns)
1112  break;
1113  sync=SyncCacheViewAuthenticPixels(canvas_view,exception);
1114  if (sync == MagickFalse)
1115  break;
1116  }
1117  canvas_view=DestroyCacheView(canvas_view);
1118  source_view=DestroyCacheView(source_view);
1119  image_view=DestroyCacheView(image_view);
1120  source_image=DestroyImage(source_image);
1121  source_image=canvas_image;
1122  break;
1123  }
1124  case DissolveCompositeOp:
1125  {
1126  /*
1127  Geometry arguments to dissolve factors.
1128  */
1129  value=GetImageArtifact(image,"compose:args");
1130  if (value != (char *) NULL)
1131  {
1132  flags=ParseGeometry(value,&geometry_info);
1133  source_dissolve=geometry_info.rho/100.0;
1134  canvas_dissolve=1.0;
1135  if ((source_dissolve-MagickEpsilon) < 0.0)
1136  source_dissolve=0.0;
1137  if ((source_dissolve+MagickEpsilon) > 1.0)
1138  {
1139  canvas_dissolve=2.0-source_dissolve;
1140  source_dissolve=1.0;
1141  }
1142  if ((flags & SigmaValue) != 0)
1143  canvas_dissolve=geometry_info.sigma/100.0;
1144  if ((canvas_dissolve-MagickEpsilon) < 0.0)
1145  canvas_dissolve=0.0;
1146  }
1147  break;
1148  }
1149  case BlendCompositeOp:
1150  {
1151  value=GetImageArtifact(image,"compose:args");
1152  if (value != (char *) NULL)
1153  {
1154  flags=ParseGeometry(value,&geometry_info);
1155  source_dissolve=geometry_info.rho/100.0;
1156  canvas_dissolve=1.0-source_dissolve;
1157  if ((flags & SigmaValue) != 0)
1158  canvas_dissolve=geometry_info.sigma/100.0;
1159  }
1160  break;
1161  }
1163  {
1164  /*
1165  Just collect the values from "compose:args", setting.
1166  Unused values are set to zero automagically.
1167 
1168  Arguments are normally a comma separated list, so this probably should
1169  be changed to some 'general comma list' parser, (with a minimum
1170  number of values)
1171  */
1172  SetGeometryInfo(&geometry_info);
1173  value=GetImageArtifact(image,"compose:args");
1174  if (value != (char *) NULL)
1175  (void) ParseGeometry(value,&geometry_info);
1176  break;
1177  }
1178  case ModulateCompositeOp:
1179  {
1180  /*
1181  Determine the luma and chroma scale.
1182  */
1183  value=GetImageArtifact(image,"compose:args");
1184  if (value != (char *) NULL)
1185  {
1186  flags=ParseGeometry(value,&geometry_info);
1187  percent_luma=geometry_info.rho;
1188  if ((flags & SigmaValue) != 0)
1189  percent_chroma=geometry_info.sigma;
1190  }
1191  break;
1192  }
1193  case ThresholdCompositeOp:
1194  {
1195  /*
1196  Determine the amount and threshold.
1197  */
1198  value=GetImageArtifact(image,"compose:args");
1199  if (value != (char *) NULL)
1200  {
1201  flags=ParseGeometry(value,&geometry_info);
1202  amount=geometry_info.rho;
1203  threshold=geometry_info.sigma;
1204  if ((flags & SigmaValue) == 0)
1205  threshold=0.05f;
1206  }
1207  threshold*=QuantumRange;
1208  break;
1209  }
1210  default:
1211  break;
1212  }
1213  /*
1214  Composite image.
1215  */
1216  status=MagickTrue;
1217  progress=0;
1218  midpoint=((MagickRealType) QuantumRange+1.0)/2;
1219  source_view=AcquireVirtualCacheView(source_image,exception);
1220  image_view=AcquireAuthenticCacheView(image,exception);
1221 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1222  #pragma omp parallel for schedule(static) shared(progress,status) \
1223  magick_number_threads(source_image,image,image->rows,1)
1224 #endif
1225  for (y=0; y < (ssize_t) image->rows; y++)
1226  {
1227  const Quantum
1228  *pixels;
1229 
1231  blue,
1232  chroma,
1233  green,
1234  hue,
1235  luma,
1236  red;
1237 
1238  PixelInfo
1239  canvas_pixel,
1240  source_pixel;
1241 
1242  register const Quantum
1243  *magick_restrict p;
1244 
1245  register Quantum
1246  *magick_restrict q;
1247 
1248  register ssize_t
1249  x;
1250 
1251  if (status == MagickFalse)
1252  continue;
1253  if (clip_to_self != MagickFalse)
1254  {
1255  if (y < y_offset)
1256  continue;
1257  if ((y-y_offset) >= (ssize_t) source_image->rows)
1258  continue;
1259  }
1260  /*
1261  If pixels is NULL, y is outside overlay region.
1262  */
1263  pixels=(Quantum *) NULL;
1264  p=(Quantum *) NULL;
1265  if ((y >= y_offset) && ((y-y_offset) < (ssize_t) source_image->rows))
1266  {
1267  p=GetCacheViewVirtualPixels(source_view,0,y-y_offset,
1268  source_image->columns,1,exception);
1269  if (p == (const Quantum *) NULL)
1270  {
1271  status=MagickFalse;
1272  continue;
1273  }
1274  pixels=p;
1275  if (x_offset < 0)
1276  p-=x_offset*GetPixelChannels(source_image);
1277  }
1278  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1279  if (q == (Quantum *) NULL)
1280  {
1281  status=MagickFalse;
1282  continue;
1283  }
1284  hue=0.0;
1285  chroma=0.0;
1286  luma=0.0;
1287  GetPixelInfo(image,&canvas_pixel);
1288  GetPixelInfo(source_image,&source_pixel);
1289  for (x=0; x < (ssize_t) image->columns; x++)
1290  {
1291  double
1292  gamma;
1293 
1295  alpha,
1296  Da,
1297  Dc,
1298  Dca,
1299  DcaDa,
1300  Sa,
1301  SaSca,
1302  Sc,
1303  Sca;
1304 
1305  register ssize_t
1306  i;
1307 
1308  size_t
1309  channels;
1310 
1311  if (clip_to_self != MagickFalse)
1312  {
1313  if (x < x_offset)
1314  {
1315  q+=GetPixelChannels(image);
1316  continue;
1317  }
1318  if ((x-x_offset) >= (ssize_t) source_image->columns)
1319  break;
1320  }
1321  if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1322  ((x-x_offset) >= (ssize_t) source_image->columns))
1323  {
1324  Quantum
1325  source[MaxPixelChannels];
1326 
1327  /*
1328  Virtual composite:
1329  Sc: source color.
1330  Dc: canvas color.
1331  */
1332  (void) GetOneVirtualPixel(source_image,x-x_offset,y-y_offset,source,
1333  exception);
1334  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1335  {
1337  pixel;
1338 
1339  PixelChannel channel = GetPixelChannelChannel(image,i);
1340  PixelTrait traits = GetPixelChannelTraits(image,channel);
1341  PixelTrait source_traits=GetPixelChannelTraits(source_image,
1342  channel);
1343  if ((traits == UndefinedPixelTrait) ||
1344  (source_traits == UndefinedPixelTrait))
1345  continue;
1346  switch (compose)
1347  {
1348  case AlphaCompositeOp:
1349  case ChangeMaskCompositeOp:
1350  case CopyAlphaCompositeOp:
1351  case DstAtopCompositeOp:
1352  case DstInCompositeOp:
1353  case InCompositeOp:
1354  case OutCompositeOp:
1355  case SrcInCompositeOp:
1356  case SrcOutCompositeOp:
1357  {
1358  if (channel == AlphaPixelChannel)
1360  else
1361  pixel=(MagickRealType) q[i];
1362  break;
1363  }
1364  case ClearCompositeOp:
1365  case CopyCompositeOp:
1366  case ReplaceCompositeOp:
1367  case SrcCompositeOp:
1368  {
1369  if (channel == AlphaPixelChannel)
1371  else
1372  pixel=0.0;
1373  break;
1374  }
1375  case BlendCompositeOp:
1376  case DissolveCompositeOp:
1377  {
1378  if (channel == AlphaPixelChannel)
1379  pixel=canvas_dissolve*GetPixelAlpha(source_image,source);
1380  else
1381  pixel=(MagickRealType) source[channel];
1382  break;
1383  }
1384  default:
1385  {
1386  pixel=(MagickRealType) source[channel];
1387  break;
1388  }
1389  }
1390  q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
1391  ClampToQuantum(pixel);
1392  }
1393  q+=GetPixelChannels(image);
1394  continue;
1395  }
1396  /*
1397  Authentic composite:
1398  Sa: normalized source alpha.
1399  Da: normalized canvas alpha.
1400  */
1401  Sa=QuantumScale*GetPixelAlpha(source_image,p);
1402  Da=QuantumScale*GetPixelAlpha(image,q);
1403  switch (compose)
1404  {
1405  case BumpmapCompositeOp:
1406  {
1407  alpha=GetPixelIntensity(source_image,p)*Sa;
1408  break;
1409  }
1410  case ColorBurnCompositeOp:
1411  case ColorDodgeCompositeOp:
1412  case DarkenCompositeOp:
1413  case DifferenceCompositeOp:
1414  case DivideDstCompositeOp:
1415  case DivideSrcCompositeOp:
1416  case ExclusionCompositeOp:
1417  case HardLightCompositeOp:
1418  case HardMixCompositeOp:
1419  case LinearBurnCompositeOp:
1422  case LightenCompositeOp:
1424  case MinusDstCompositeOp:
1425  case MinusSrcCompositeOp:
1426  case ModulusAddCompositeOp:
1428  case MultiplyCompositeOp:
1429  case OverlayCompositeOp:
1431  case PinLightCompositeOp:
1432  case ScreenCompositeOp:
1433  case SoftLightCompositeOp:
1434  case VividLightCompositeOp:
1435  {
1436  alpha=RoundToUnity(Sa+Da-Sa*Da);
1437  break;
1438  }
1439  case DstAtopCompositeOp:
1440  case DstInCompositeOp:
1441  case InCompositeOp:
1442  case SrcInCompositeOp:
1443  {
1444  alpha=Sa*Da;
1445  break;
1446  }
1447  case DissolveCompositeOp:
1448  {
1449  alpha=source_dissolve*Sa*(-canvas_dissolve*Da)+source_dissolve*Sa+
1450  canvas_dissolve*Da;
1451  break;
1452  }
1453  case DstOverCompositeOp:
1454  case OverCompositeOp:
1455  case SrcOverCompositeOp:
1456  {
1457  alpha=Sa+Da-Sa*Da;
1458  break;
1459  }
1460  case DstOutCompositeOp:
1461  {
1462  alpha=Da*(1.0-Sa);
1463  break;
1464  }
1465  case OutCompositeOp:
1466  case SrcOutCompositeOp:
1467  {
1468  alpha=Sa*(1.0-Da);
1469  break;
1470  }
1471  case BlendCompositeOp:
1472  case PlusCompositeOp:
1473  {
1474  alpha=RoundToUnity(source_dissolve*Sa+canvas_dissolve*Da);
1475  break;
1476  }
1477  case XorCompositeOp:
1478  {
1479  alpha=Sa+Da-2.0*Sa*Da;
1480  break;
1481  }
1482  default:
1483  {
1484  alpha=1.0;
1485  break;
1486  }
1487  }
1488  switch (compose)
1489  {
1490  case ColorizeCompositeOp:
1491  case HueCompositeOp:
1492  case LuminizeCompositeOp:
1493  case ModulateCompositeOp:
1494  case SaturateCompositeOp:
1495  {
1496  GetPixelInfoPixel(source_image,p,&source_pixel);
1497  GetPixelInfoPixel(image,q,&canvas_pixel);
1498  break;
1499  }
1500  default:
1501  break;
1502  }
1503  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1504  {
1506  pixel,
1507  sans;
1508 
1509  PixelChannel channel = GetPixelChannelChannel(image,i);
1510  PixelTrait traits = GetPixelChannelTraits(image,channel);
1511  PixelTrait source_traits = GetPixelChannelTraits(source_image,channel);
1512  if (traits == UndefinedPixelTrait)
1513  continue;
1514  if ((channel == AlphaPixelChannel) &&
1515  ((traits & UpdatePixelTrait) != 0))
1516  {
1517  /*
1518  Set alpha channel.
1519  */
1520  switch (compose)
1521  {
1522  case AlphaCompositeOp:
1523  {
1524  pixel=QuantumRange*Sa;
1525  break;
1526  }
1527  case AtopCompositeOp:
1528  case CopyBlackCompositeOp:
1529  case CopyBlueCompositeOp:
1530  case CopyCyanCompositeOp:
1531  case CopyGreenCompositeOp:
1533  case CopyRedCompositeOp:
1534  case CopyYellowCompositeOp:
1535  case SrcAtopCompositeOp:
1536  case DstCompositeOp:
1537  case NoCompositeOp:
1538  {
1539  pixel=QuantumRange*Da;
1540  break;
1541  }
1542  case ChangeMaskCompositeOp:
1543  {
1545  equivalent;
1546 
1547  if (Da < 0.5)
1548  {
1550  break;
1551  }
1552  equivalent=IsFuzzyEquivalencePixel(source_image,p,image,q);
1553  if (equivalent != MagickFalse)
1555  else
1556  pixel=(MagickRealType) OpaqueAlpha;
1557  break;
1558  }
1559  case ClearCompositeOp:
1560  {
1562  break;
1563  }
1564  case ColorizeCompositeOp:
1565  case HueCompositeOp:
1566  case LuminizeCompositeOp:
1567  case SaturateCompositeOp:
1568  {
1569  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1570  {
1571  pixel=QuantumRange*Da;
1572  break;
1573  }
1574  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
1575  {
1576  pixel=QuantumRange*Sa;
1577  break;
1578  }
1579  if (Sa < Da)
1580  {
1581  pixel=QuantumRange*Da;
1582  break;
1583  }
1584  pixel=QuantumRange*Sa;
1585  break;
1586  }
1587  case CopyAlphaCompositeOp:
1588  {
1589  if (source_image->alpha_trait == UndefinedPixelTrait)
1590  pixel=GetPixelIntensity(source_image,p);
1591  else
1592  pixel=QuantumRange*Sa;
1593  break;
1594  }
1595  case CopyCompositeOp:
1596  case DisplaceCompositeOp:
1597  case DistortCompositeOp:
1598  case DstAtopCompositeOp:
1599  case ReplaceCompositeOp:
1600  case SrcCompositeOp:
1601  {
1602  pixel=QuantumRange*Sa;
1603  break;
1604  }
1606  {
1607  pixel=Sa*GetPixelIntensity(source_image,p) <
1608  Da*GetPixelIntensity(image,q) ? Sa : Da;
1609  break;
1610  }
1611  case DifferenceCompositeOp:
1612  {
1613  pixel=QuantumRange*fabs(Sa-Da);
1614  break;
1615  }
1617  {
1618  pixel=Sa*GetPixelIntensity(source_image,p) >
1619  Da*GetPixelIntensity(image,q) ? Sa : Da;
1620  break;
1621  }
1622  case ModulateCompositeOp:
1623  {
1624  pixel=QuantumRange*Da;
1625  break;
1626  }
1627  case MultiplyCompositeOp:
1628  {
1629  pixel=QuantumRange*Sa*Da;
1630  break;
1631  }
1632  case StereoCompositeOp:
1633  {
1634  pixel=QuantumRange*(Sa+Da)/2;
1635  break;
1636  }
1637  default:
1638  {
1639  pixel=QuantumRange*alpha;
1640  break;
1641  }
1642  }
1643  q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
1644  ClampToQuantum(pixel);
1645  continue;
1646  }
1647  if (source_traits == UndefinedPixelTrait)
1648  continue;
1649  /*
1650  Sc: source color.
1651  Dc: canvas color.
1652  */
1653  Sc=(MagickRealType) GetPixelChannel(source_image,channel,p);
1654  Dc=(MagickRealType) q[i];
1655  if ((traits & CopyPixelTrait) != 0)
1656  {
1657  /*
1658  Copy channel.
1659  */
1660  q[i]=ClampToQuantum(Dc);
1661  continue;
1662  }
1663  /*
1664  Porter-Duff compositions:
1665  Sca: source normalized color multiplied by alpha.
1666  Dca: normalized canvas color multiplied by alpha.
1667  */
1668  Sca=QuantumScale*Sa*Sc;
1669  Dca=QuantumScale*Da*Dc;
1670  SaSca=Sa*PerceptibleReciprocal(Sca);
1671  DcaDa=Dca*PerceptibleReciprocal(Da);
1672  switch (compose)
1673  {
1674  case DarkenCompositeOp:
1675  case LightenCompositeOp:
1677  {
1678  gamma=PerceptibleReciprocal(1.0-alpha);
1679  break;
1680  }
1681  default:
1682  {
1683  gamma=PerceptibleReciprocal(alpha);
1684  break;
1685  }
1686  }
1687  pixel=Dc;
1688  switch (compose)
1689  {
1690  case AlphaCompositeOp:
1691  {
1692  pixel=QuantumRange*Sa;
1693  break;
1694  }
1695  case AtopCompositeOp:
1696  case SrcAtopCompositeOp:
1697  {
1698  pixel=QuantumRange*(Sca*Da+Dca*(1.0-Sa));
1699  break;
1700  }
1701  case BlendCompositeOp:
1702  {
1703  pixel=gamma*(source_dissolve*Sa*Sc+canvas_dissolve*Da*Dc);
1704  break;
1705  }
1706  case BlurCompositeOp:
1707  case CopyCompositeOp:
1708  case ReplaceCompositeOp:
1709  case SrcCompositeOp:
1710  {
1711  pixel=QuantumRange*Sca;
1712  break;
1713  }
1714  case DisplaceCompositeOp:
1715  case DistortCompositeOp:
1716  {
1717  pixel=Sc;
1718  break;
1719  }
1720  case BumpmapCompositeOp:
1721  {
1722  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1723  {
1724  pixel=Dc;
1725  break;
1726  }
1727  pixel=QuantumScale*GetPixelIntensity(source_image,p)*Dc;
1728  break;
1729  }
1730  case ChangeMaskCompositeOp:
1731  {
1732  pixel=Dc;
1733  break;
1734  }
1735  case ClearCompositeOp:
1736  {
1737  pixel=0.0;
1738  break;
1739  }
1740  case ColorBurnCompositeOp:
1741  {
1742  if ((Sca == 0.0) && (Dca == Da))
1743  {
1744  pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1745  break;
1746  }
1747  if (Sca == 0.0)
1748  {
1749  pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1750  break;
1751  }
1752  pixel=QuantumRange*gamma*(Sa*Da-Sa*Da*MagickMin(1.0,(1.0-DcaDa)*
1753  SaSca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
1754  break;
1755  }
1756  case ColorDodgeCompositeOp:
1757  {
1758  if ((Sca*Da+Dca*Sa) >= Sa*Da)
1759  pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1760  else
1761  pixel=QuantumRange*gamma*(Dca*Sa*Sa*PerceptibleReciprocal(Sa-Sca)+
1762  Sca*(1.0-Da)+Dca*(1.0-Sa));
1763  break;
1764  }
1765  case ColorizeCompositeOp:
1766  {
1767  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1768  {
1769  pixel=Dc;
1770  break;
1771  }
1772  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
1773  {
1774  pixel=Sc;
1775  break;
1776  }
1777  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
1778  &sans,&sans,&luma);
1779  CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1780  &hue,&chroma,&sans);
1781  HCLComposite(hue,chroma,luma,&red,&green,&blue);
1782  switch (channel)
1783  {
1784  case RedPixelChannel: pixel=red; break;
1785  case GreenPixelChannel: pixel=green; break;
1786  case BluePixelChannel: pixel=blue; break;
1787  default: pixel=Dc; break;
1788  }
1789  break;
1790  }
1791  case CopyAlphaCompositeOp:
1792  {
1793  pixel=Dc;
1794  break;
1795  }
1796  case CopyBlackCompositeOp:
1797  {
1798  if (channel == BlackPixelChannel)
1799  pixel=(MagickRealType) (QuantumRange-
1800  GetPixelBlack(source_image,p));
1801  break;
1802  }
1803  case CopyBlueCompositeOp:
1804  case CopyYellowCompositeOp:
1805  {
1806  if (channel == BluePixelChannel)
1807  pixel=(MagickRealType) GetPixelBlue(source_image,p);
1808  break;
1809  }
1810  case CopyGreenCompositeOp:
1812  {
1813  if (channel == GreenPixelChannel)
1814  pixel=(MagickRealType) GetPixelGreen(source_image,p);
1815  break;
1816  }
1817  case CopyRedCompositeOp:
1818  case CopyCyanCompositeOp:
1819  {
1820  if (channel == RedPixelChannel)
1821  pixel=(MagickRealType) GetPixelRed(source_image,p);
1822  break;
1823  }
1824  case DarkenCompositeOp:
1825  {
1826  /*
1827  Darken is equivalent to a 'Minimum' method
1828  OR a greyscale version of a binary 'Or'
1829  OR the 'Intersection' of pixel sets.
1830  */
1831  if ((Sca*Da) < (Dca*Sa))
1832  {
1833  pixel=QuantumRange*(Sca+Dca*(1.0-Sa));
1834  break;
1835  }
1836  pixel=QuantumRange*(Dca+Sca*(1.0-Da));
1837  break;
1838  }
1840  {
1841  pixel=Sa*GetPixelIntensity(source_image,p) <
1842  Da*GetPixelIntensity(image,q) ? Sc : Dc;
1843  break;
1844  }
1845  case DifferenceCompositeOp:
1846  {
1847  pixel=QuantumRange*gamma*(Sca+Dca-2.0*MagickMin(Sca*Da,Dca*Sa));
1848  break;
1849  }
1850  case DissolveCompositeOp:
1851  {
1852  pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1853  canvas_dissolve*Da*Dc+canvas_dissolve*Da*Dc);
1854  break;
1855  }
1856  case DivideDstCompositeOp:
1857  {
1858  if ((fabs((double) Sca) < MagickEpsilon) &&
1859  (fabs((double) Dca) < MagickEpsilon))
1860  {
1861  pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1862  break;
1863  }
1864  if (fabs((double) Dca) < MagickEpsilon)
1865  {
1866  pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1867  break;
1868  }
1869  pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1870  break;
1871  }
1872  case DivideSrcCompositeOp:
1873  {
1874  if ((fabs((double) Dca) < MagickEpsilon) &&
1875  (fabs((double) Sca) < MagickEpsilon))
1876  {
1877  pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1878  break;
1879  }
1880  if (fabs((double) Sca) < MagickEpsilon)
1881  {
1882  pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1883  break;
1884  }
1885  pixel=QuantumRange*gamma*(Dca*Sa*SaSca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1886  break;
1887  }
1888  case DstAtopCompositeOp:
1889  {
1890  pixel=QuantumRange*(Dca*Sa+Sca*(1.0-Da));
1891  break;
1892  }
1893  case DstCompositeOp:
1894  case NoCompositeOp:
1895  {
1896  pixel=QuantumRange*Dca;
1897  break;
1898  }
1899  case DstInCompositeOp:
1900  {
1901  pixel=QuantumRange*(Dca*Sa);
1902  break;
1903  }
1904  case DstOutCompositeOp:
1905  {
1906  pixel=QuantumRange*(Dca*(1.0-Sa));
1907  break;
1908  }
1909  case DstOverCompositeOp:
1910  {
1911  pixel=QuantumRange*gamma*(Dca+Sca*(1.0-Da));
1912  break;
1913  }
1914  case ExclusionCompositeOp:
1915  {
1916  pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1917  Dca*(1.0-Sa));
1918  break;
1919  }
1920  case HardLightCompositeOp:
1921  {
1922  if ((2.0*Sca) < Sa)
1923  {
1924  pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-
1925  Sa));
1926  break;
1927  }
1928  pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1929  Dca*(1.0-Sa));
1930  break;
1931  }
1932  case HardMixCompositeOp:
1933  {
1934  pixel=gamma*(((Sca+Dca) < 1.0) ? 0.0 : QuantumRange);
1935  break;
1936  }
1937  case HueCompositeOp:
1938  {
1939  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1940  {
1941  pixel=Dc;
1942  break;
1943  }
1944  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
1945  {
1946  pixel=Sc;
1947  break;
1948  }
1949  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
1950  &hue,&chroma,&luma);
1951  CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1952  &hue,&sans,&sans);
1953  HCLComposite(hue,chroma,luma,&red,&green,&blue);
1954  switch (channel)
1955  {
1956  case RedPixelChannel: pixel=red; break;
1957  case GreenPixelChannel: pixel=green; break;
1958  case BluePixelChannel: pixel=blue; break;
1959  default: pixel=Dc; break;
1960  }
1961  break;
1962  }
1963  case InCompositeOp:
1964  case SrcInCompositeOp:
1965  {
1966  pixel=QuantumRange*(Sca*Da);
1967  break;
1968  }
1969  case LinearBurnCompositeOp:
1970  {
1971  /*
1972  LinearBurn: as defined by Abode Photoshop, according to
1973  http://www.simplefilter.de/en/basics/mixmods.html is:
1974 
1975  f(Sc,Dc) = Sc + Dc - 1
1976  */
1977  pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1978  break;
1979  }
1981  {
1982  pixel=gamma*(Sa*Sc+Da*Dc);
1983  break;
1984  }
1986  {
1987  /*
1988  LinearLight: as defined by Abode Photoshop, according to
1989  http://www.simplefilter.de/en/basics/mixmods.html is:
1990 
1991  f(Sc,Dc) = Dc + 2*Sc - 1
1992  */
1993  pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1994  break;
1995  }
1996  case LightenCompositeOp:
1997  {
1998  if ((Sca*Da) > (Dca*Sa))
1999  {
2000  pixel=QuantumRange*(Sca+Dca*(1.0-Sa));
2001  break;
2002  }
2003  pixel=QuantumRange*(Dca+Sca*(1.0-Da));
2004  break;
2005  }
2007  {
2008  /*
2009  Lighten is equivalent to a 'Maximum' method
2010  OR a greyscale version of a binary 'And'
2011  OR the 'Union' of pixel sets.
2012  */
2013  pixel=Sa*GetPixelIntensity(source_image,p) >
2014  Da*GetPixelIntensity(image,q) ? Sc : Dc;
2015  break;
2016  }
2017  case LuminizeCompositeOp:
2018  {
2019  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2020  {
2021  pixel=Dc;
2022  break;
2023  }
2024  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
2025  {
2026  pixel=Sc;
2027  break;
2028  }
2029  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
2030  &hue,&chroma,&luma);
2031  CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2032  &sans,&sans,&luma);
2033  HCLComposite(hue,chroma,luma,&red,&green,&blue);
2034  switch (channel)
2035  {
2036  case RedPixelChannel: pixel=red; break;
2037  case GreenPixelChannel: pixel=green; break;
2038  case BluePixelChannel: pixel=blue; break;
2039  default: pixel=Dc; break;
2040  }
2041  break;
2042  }
2044  {
2045  /*
2046  'Mathematics' a free form user control mathematical composition
2047  is defined as...
2048 
2049  f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
2050 
2051  Where the arguments A,B,C,D are (currently) passed to composite
2052  as a command separated 'geometry' string in "compose:args" image
2053  artifact.
2054 
2055  A = a->rho, B = a->sigma, C = a->xi, D = a->psi
2056 
2057  Applying the SVG transparency formula (see above), we get...
2058 
2059  Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
2060 
2061  Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
2062  Dca*(1.0-Sa)
2063  */
2064  pixel=QuantumRange*gamma*(geometry_info.rho*Sca*Dca+
2065  geometry_info.sigma*Sca*Da+geometry_info.xi*Dca*Sa+
2066  geometry_info.psi*Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2067  break;
2068  }
2069  case MinusDstCompositeOp:
2070  {
2071  pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2072  break;
2073  }
2074  case MinusSrcCompositeOp:
2075  {
2076  /*
2077  Minus source from canvas.
2078 
2079  f(Sc,Dc) = Sc - Dc
2080  */
2081  pixel=gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2082  break;
2083  }
2084  case ModulateCompositeOp:
2085  {
2086  ssize_t
2087  offset;
2088 
2089  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2090  {
2091  pixel=Dc;
2092  break;
2093  }
2094  offset=(ssize_t) (GetPixelIntensity(source_image,p)-midpoint);
2095  if (offset == 0)
2096  {
2097  pixel=Dc;
2098  break;
2099  }
2100  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
2101  &hue,&chroma,&luma);
2102  luma+=(0.01*percent_luma*offset)/midpoint;
2103  chroma*=0.01*percent_chroma;
2104  HCLComposite(hue,chroma,luma,&red,&green,&blue);
2105  switch (channel)
2106  {
2107  case RedPixelChannel: pixel=red; break;
2108  case GreenPixelChannel: pixel=green; break;
2109  case BluePixelChannel: pixel=blue; break;
2110  default: pixel=Dc; break;
2111  }
2112  break;
2113  }
2114  case ModulusAddCompositeOp:
2115  {
2116  pixel=Sc+Dc;
2117  while (pixel > QuantumRange)
2118  pixel-=QuantumRange;
2119  while (pixel < 0.0)
2120  pixel+=QuantumRange;
2121  pixel=(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2122  break;
2123  }
2125  {
2126  pixel=Sc-Dc;
2127  while (pixel > QuantumRange)
2128  pixel-=QuantumRange;
2129  while (pixel < 0.0)
2130  pixel+=QuantumRange;
2131  pixel=(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2132  break;
2133  }
2134  case MultiplyCompositeOp:
2135  {
2136  pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2137  break;
2138  }
2139  case OutCompositeOp:
2140  case SrcOutCompositeOp:
2141  {
2142  pixel=QuantumRange*(Sca*(1.0-Da));
2143  break;
2144  }
2145  case OverCompositeOp:
2146  case SrcOverCompositeOp:
2147  {
2148  pixel=QuantumRange*gamma*(Sca+Dca*(1.0-Sa));
2149  break;
2150  }
2151  case OverlayCompositeOp:
2152  {
2153  if ((2.0*Dca) < Da)
2154  {
2155  pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*(1.0-
2156  Da));
2157  break;
2158  }
2159  pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2160  Sca*(1.0-Da));
2161  break;
2162  }
2164  {
2165  /*
2166  PegTop: A Soft-Light alternative: A continuous version of the
2167  Softlight function, producing very similar results.
2168 
2169  f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2170 
2171  http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2172  */
2173  if (fabs((double) Da) < MagickEpsilon)
2174  {
2175  pixel=QuantumRange*gamma*(Sca);
2176  break;
2177  }
2178  pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2179  Da)+Dca*(1.0-Sa));
2180  break;
2181  }
2182  case PinLightCompositeOp:
2183  {
2184  /*
2185  PinLight: A Photoshop 7 composition method
2186  http://www.simplefilter.de/en/basics/mixmods.html
2187 
2188  f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2189  */
2190  if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2191  {
2192  pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2193  break;
2194  }
2195  if ((Dca*Sa) > (2.0*Sca*Da))
2196  {
2197  pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2198  break;
2199  }
2200  pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2201  break;
2202  }
2203  case PlusCompositeOp:
2204  {
2205  pixel=QuantumRange*(Sca+Dca);
2206  break;
2207  }
2208  case SaturateCompositeOp:
2209  {
2210  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2211  {
2212  pixel=Dc;
2213  break;
2214  }
2215  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
2216  {
2217  pixel=Sc;
2218  break;
2219  }
2220  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
2221  &hue,&chroma,&luma);
2222  CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2223  &sans,&chroma,&sans);
2224  HCLComposite(hue,chroma,luma,&red,&green,&blue);
2225  switch (channel)
2226  {
2227  case RedPixelChannel: pixel=red; break;
2228  case GreenPixelChannel: pixel=green; break;
2229  case BluePixelChannel: pixel=blue; break;
2230  default: pixel=Dc; break;
2231  }
2232  break;
2233  }
2234  case ScreenCompositeOp:
2235  {
2236  /*
2237  Screen: a negated multiply:
2238 
2239  f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2240  */
2241  pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2242  break;
2243  }
2244  case SoftLightCompositeOp:
2245  {
2246  if ((2.0*Sca) < Sa)
2247  {
2248  pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-DcaDa))+
2249  Sca*(1.0-Da)+Dca*(1.0-Sa));
2250  break;
2251  }
2252  if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2253  {
2254  pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*DcaDa*
2255  (4.0*DcaDa+1.0)*(DcaDa-1.0)+7.0*DcaDa)+Sca*(1.0-Da)+
2256  Dca*(1.0-Sa));
2257  break;
2258  }
2259  pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow(DcaDa,0.5)-
2260  DcaDa)+Sca*(1.0-Da)+Dca*(1.0-Sa));
2261  break;
2262  }
2263  case StereoCompositeOp:
2264  {
2265  if (channel == RedPixelChannel)
2266  pixel=(MagickRealType) GetPixelRed(source_image,p);
2267  break;
2268  }
2269  case ThresholdCompositeOp:
2270  {
2272  delta;
2273 
2274  delta=Sc-Dc;
2275  if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2276  {
2277  pixel=gamma*Dc;
2278  break;
2279  }
2280  pixel=gamma*(Dc+delta*amount);
2281  break;
2282  }
2283  case VividLightCompositeOp:
2284  {
2285  /*
2286  VividLight: A Photoshop 7 composition method. See
2287  http://www.simplefilter.de/en/basics/mixmods.html.
2288 
2289  f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2290  */
2291  if ((fabs((double) Sa) < MagickEpsilon) ||
2292  (fabs((double) (Sca-Sa)) < MagickEpsilon))
2293  {
2294  pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2295  break;
2296  }
2297  if ((2.0*Sca) <= Sa)
2298  {
2299  pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)*
2300  PerceptibleReciprocal(2.0*Sca))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2301  break;
2302  }
2303  pixel=QuantumRange*gamma*(Dca*Sa*Sa*PerceptibleReciprocal(2.0*
2304  (Sa-Sca))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2305  break;
2306  }
2307  case XorCompositeOp:
2308  {
2309  pixel=QuantumRange*(Sca*(1.0-Da)+Dca*(1.0-Sa));
2310  break;
2311  }
2312  default:
2313  {
2314  pixel=Sc;
2315  break;
2316  }
2317  }
2318  q[i]=clamp != MagickFalse ? ClampPixel(pixel) : ClampToQuantum(pixel);
2319  }
2320  p+=GetPixelChannels(source_image);
2321  channels=GetPixelChannels(source_image);
2322  if (p >= (pixels+channels*source_image->columns))
2323  p=pixels;
2324  q+=GetPixelChannels(image);
2325  }
2326  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2327  status=MagickFalse;
2328  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2329  {
2331  proceed;
2332 
2333 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2334  #pragma omp atomic
2335 #endif
2336  progress++;
2337  proceed=SetImageProgress(image,CompositeImageTag,progress,image->rows);
2338  if (proceed == MagickFalse)
2339  status=MagickFalse;
2340  }
2341  }
2342  source_view=DestroyCacheView(source_view);
2343  image_view=DestroyCacheView(image_view);
2344  if (canvas_image != (Image * ) NULL)
2345  canvas_image=DestroyImage(canvas_image);
2346  else
2347  source_image=DestroyImage(source_image);
2348  return(status);
2349 }
2350 
2351 /*
2352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2353 % %
2354 % %
2355 % %
2356 % T e x t u r e I m a g e %
2357 % %
2358 % %
2359 % %
2360 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2361 %
2362 % TextureImage() repeatedly tiles the texture image across and down the image
2363 % canvas.
2364 %
2365 % The format of the TextureImage method is:
2366 %
2367 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2368 % ExceptionInfo *exception)
2369 %
2370 % A description of each parameter follows:
2371 %
2372 % o image: the image.
2373 %
2374 % o texture_image: This image is the texture to layer on the background.
2375 %
2376 */
2378  ExceptionInfo *exception)
2379 {
2380 #define TextureImageTag "Texture/Image"
2381 
2382  CacheView
2383  *image_view,
2384  *texture_view;
2385 
2386  Image
2387  *texture_image;
2388 
2390  status;
2391 
2392  ssize_t
2393  y;
2394 
2395  assert(image != (Image *) NULL);
2396  if (image->debug != MagickFalse)
2397  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2398  assert(image->signature == MagickCoreSignature);
2399  if (texture == (const Image *) NULL)
2400  return(MagickFalse);
2401  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2402  return(MagickFalse);
2403  texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2404  if (texture_image == (const Image *) NULL)
2405  return(MagickFalse);
2406  (void) TransformImageColorspace(texture_image,image->colorspace,exception);
2408  exception);
2409  status=MagickTrue;
2410  if ((image->compose != CopyCompositeOp) &&
2411  ((image->compose != OverCompositeOp) ||
2412  (image->alpha_trait != UndefinedPixelTrait) ||
2413  (texture_image->alpha_trait != UndefinedPixelTrait)))
2414  {
2415  /*
2416  Tile texture onto the image background.
2417  */
2418  for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2419  {
2420  register ssize_t
2421  x;
2422 
2423  if (status == MagickFalse)
2424  continue;
2425  for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2426  {
2428  thread_status;
2429 
2430  thread_status=CompositeImage(image,texture_image,image->compose,
2431  MagickTrue,x+texture_image->tile_offset.x,y+
2432  texture_image->tile_offset.y,exception);
2433  if (thread_status == MagickFalse)
2434  {
2435  status=thread_status;
2436  break;
2437  }
2438  }
2439  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2440  {
2442  proceed;
2443 
2445  image->rows);
2446  if (proceed == MagickFalse)
2447  status=MagickFalse;
2448  }
2449  }
2451  image->rows,image->rows);
2452  texture_image=DestroyImage(texture_image);
2453  return(status);
2454  }
2455  /*
2456  Tile texture onto the image background (optimized).
2457  */
2458  status=MagickTrue;
2459  texture_view=AcquireVirtualCacheView(texture_image,exception);
2460  image_view=AcquireAuthenticCacheView(image,exception);
2461 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2462  #pragma omp parallel for schedule(static) shared(status) \
2463  magick_number_threads(texture_image,image,image->rows,1)
2464 #endif
2465  for (y=0; y < (ssize_t) image->rows; y++)
2466  {
2468  sync;
2469 
2470  register const Quantum
2471  *p,
2472  *pixels;
2473 
2474  register ssize_t
2475  x;
2476 
2477  register Quantum
2478  *q;
2479 
2480  size_t
2481  width;
2482 
2483  if (status == MagickFalse)
2484  continue;
2485  pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2486  (y+texture_image->tile_offset.y) % texture_image->rows,
2487  texture_image->columns,1,exception);
2488  q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2489  if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2490  {
2491  status=MagickFalse;
2492  continue;
2493  }
2494  for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2495  {
2496  register ssize_t
2497  j;
2498 
2499  p=pixels;
2500  width=texture_image->columns;
2501  if ((x+(ssize_t) width) > (ssize_t) image->columns)
2502  width=image->columns-x;
2503  for (j=0; j < (ssize_t) width; j++)
2504  {
2505  register ssize_t
2506  i;
2507 
2508  for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2509  {
2510  PixelChannel channel = GetPixelChannelChannel(texture_image,i);
2511  PixelTrait traits = GetPixelChannelTraits(image,channel);
2512  PixelTrait texture_traits=GetPixelChannelTraits(texture_image,
2513  channel);
2514  if ((traits == UndefinedPixelTrait) ||
2515  (texture_traits == UndefinedPixelTrait))
2516  continue;
2517  SetPixelChannel(image,channel,p[i],q);
2518  }
2519  p+=GetPixelChannels(texture_image);
2520  q+=GetPixelChannels(image);
2521  }
2522  }
2523  sync=SyncCacheViewAuthenticPixels(image_view,exception);
2524  if (sync == MagickFalse)
2525  status=MagickFalse;
2526  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2527  {
2529  proceed;
2530 
2532  image->rows);
2533  if (proceed == MagickFalse)
2534  status=MagickFalse;
2535  }
2536  }
2537  texture_view=DestroyCacheView(texture_view);
2538  image_view=DestroyCacheView(image_view);
2539  texture_image=DestroyImage(texture_image);
2540  return(status);
2541 }
double psi
Definition: geometry.h:106
size_t rows
Definition: image.h:172
#define magick_restrict
Definition: MagickCore.h:41
MagickExport MagickBooleanType TextureImage(Image *image, const Image *texture, ExceptionInfo *exception)
Definition: composite.c:2377
MagickDoubleType MagickRealType
Definition: magick-type.h:120
MagickExport CacheView * DestroyCacheView(CacheView *cache_view)
Definition: cache-view.c:252
#define TransparentAlpha
Definition: image.h:26
double x2
Definition: image.h:107
static void HCLComposite(const MagickRealType hue, const MagickRealType chroma, const MagickRealType luma, MagickRealType *red, MagickRealType *green, MagickRealType *blue)
Definition: composite.c:181
MagickProgressMonitor progress_monitor
Definition: image.h:303
static Quantum GetPixelAlpha(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
MagickExport MagickBooleanType TransformImageColorspace(Image *image, const ColorspaceType colorspace, ExceptionInfo *exception)
Definition: colorspace.c:1326
static Quantum GetPixelRed(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
MagickExport MagickBooleanType ResamplePixelColor(ResampleFilter *resample_filter, const double u0, const double v0, PixelInfo *pixel, ExceptionInfo *exception)
Definition: resample.c:315
double rho
Definition: geometry.h:106
MagickExport void SetGeometryInfo(GeometryInfo *geometry_info)
Definition: geometry.c:1720
#define OpaqueAlpha
Definition: image.h:25
static Quantum GetPixelChannel(const Image *magick_restrict image, const PixelChannel channel, const Quantum *magick_restrict pixel)
MagickExport const char * GetImageArtifact(const Image *image, const char *artifact)
Definition: artifact.c:273
MagickRealType red
Definition: pixel.h:190
static PixelTrait GetPixelChannelTraits(const Image *magick_restrict image, const PixelChannel channel)
MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image, const ssize_t x, const ssize_t y, Quantum *pixel, ExceptionInfo *exception)
Definition: cache.c:1969
MagickExport MagickBooleanType InterpolatePixelInfo(const Image *image, const CacheView_ *image_view, const PixelInterpolateMethod method, const double x, const double y, PixelInfo *pixel, ExceptionInfo *exception)
Definition: pixel.c:5477
static void SetPixelViaPixelInfo(const Image *magick_restrict image, const PixelInfo *magick_restrict pixel_info, Quantum *magick_restrict pixel)
static MagickBooleanType IsGrayColorspace(const ColorspaceType colorspace)
static Quantum GetPixelReadMask(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
MagickExport const Quantum * GetCacheViewVirtualPixels(const CacheView *cache_view, const ssize_t x, const ssize_t y, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: cache-view.c:651
MagickRealType alpha
Definition: pixel.h:190
#define MagickEpsilon
Definition: magick-type.h:110
double sigma
Definition: geometry.h:106
MagickExport MagickBooleanType CompositeImage(Image *image, const Image *composite, const CompositeOperator compose, const MagickBooleanType clip_to_self, const ssize_t x_offset, const ssize_t y_offset, ExceptionInfo *exception)
Definition: composite.c:528
RectangleInfo tile_offset
Definition: image.h:261
MagickExport ResampleFilter * AcquireResampleFilter(const Image *image, ExceptionInfo *exception)
Definition: resample.c:208
Definition: log.h:52
ssize_t MagickOffsetType
Definition: magick-type.h:129
MagickExport void GetPixelInfo(const Image *image, PixelInfo *pixel)
Definition: pixel.c:2170
Definition: image.h:151
double x
Definition: geometry.h:123
#define MagickCoreSignature
MagickExport Quantum * GetCacheViewAuthenticPixels(CacheView *cache_view, const ssize_t x, const ssize_t y, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: cache-view.c:299
static Quantum ClampPixel(const MagickRealType pixel)
MagickExport MagickBooleanType SetImageAlphaChannel(Image *image, const AlphaChannelOption alpha_type, ExceptionInfo *exception)
Definition: channel.c:974
MagickBooleanType
Definition: magick-type.h:158
unsigned int MagickStatusType
Definition: magick-type.h:121
static double PerceptibleReciprocal(const double x)
static void CompositeHCL(const MagickRealType red, const MagickRealType green, const MagickRealType blue, MagickRealType *hue, MagickRealType *chroma, MagickRealType *luma)
Definition: composite.c:247
double x1
Definition: image.h:107
static double DegreesToRadians(const double degrees)
Definition: image-private.h:56
double y
Definition: geometry.h:123
static Quantum GetPixelGreen(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
MagickExport MagickBooleanType IsStringTrue(const char *value)
Definition: string.c:1425
static void GetPixelInfoPixel(const Image *magick_restrict image, const Quantum *magick_restrict pixel, PixelInfo *magick_restrict pixel_info)
PixelTrait alpha_trait
Definition: image.h:280
MagickRealType blue
Definition: pixel.h:190
static Quantum GetPixelBlack(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
MagickExport Quantum * QueueCacheViewAuthenticPixels(CacheView *cache_view, const ssize_t x, const ssize_t y, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: cache-view.c:977
MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(Image *image, const VirtualPixelMethod virtual_pixel_method, ExceptionInfo *exception)
Definition: image.c:3492
double y2
Definition: image.h:107
MagickExport MagickBooleanType ThrowMagickException(ExceptionInfo *exception, const char *module, const char *function, const size_t line, const ExceptionType severity, const char *tag, const char *format,...)
Definition: exception.c:1145
MagickExport MagickBooleanType LogMagickEvent(const LogEventType type, const char *module, const char *function, const size_t line, const char *format,...)
Definition: log.c:1413
size_t signature
Definition: image.h:354
size_t columns
Definition: image.h:172
#define QuantumScale
Definition: magick-type.h:115
ssize_t x
Definition: geometry.h:134
MagickExport ResampleFilter * DestroyResampleFilter(ResampleFilter *resample_filter)
Definition: resample.c:262
MagickExport MagickBooleanType SetImageStorageClass(Image *image, const ClassType storage_class, ExceptionInfo *exception)
Definition: image.c:2617
PixelChannel
Definition: pixel.h:67
static double RoundToUnity(const double value)
#define MagickMax(x, y)
Definition: image-private.h:26
MagickExport void SetResampleFilter(ResampleFilter *resample_filter, const FilterType filter)
Definition: resample.c:1241
MagickExport void ScaleResampleFilter(ResampleFilter *resample_filter, const double dux, const double duy, const double dvx, const double dvy)
Definition: resample.c:1038
static size_t GetPixelChannels(const Image *magick_restrict image)
char filename[MagickPathExtent]
Definition: image.h:319
#define GetMagickModule()
Definition: log.h:28
MagickExport MagickBooleanType IsFuzzyEquivalencePixel(const Image *source, const Quantum *p, const Image *destination, const Quantum *q)
Definition: pixel.c:5950
static Quantum ClampToQuantum(const MagickRealType value)
Definition: quantum.h:84
static PixelChannel GetPixelChannelChannel(const Image *magick_restrict image, const ssize_t offset)
MagickExport CacheView * AcquireVirtualCacheView(const Image *image, ExceptionInfo *exception)
Definition: cache-view.c:149
unsigned short Quantum
Definition: magick-type.h:82
double xi
Definition: geometry.h:106
MagickExport MagickBooleanType SetImageColorspace(Image *image, const ColorspaceType colorspace, ExceptionInfo *exception)
Definition: colorspace.c:1135
MagickExport MagickStatusType ParseGeometry(const char *geometry, GeometryInfo *geometry_info)
Definition: geometry.c:853
static void SetPixelChannel(const Image *magick_restrict image, const PixelChannel channel, const Quantum quantum, Quantum *magick_restrict pixel)
#define MagickMin(x, y)
Definition: image-private.h:27
static void SetPixelAlpha(const Image *magick_restrict image, const Quantum alpha, Quantum *magick_restrict pixel)
#define CompositeImageTag
#define MaxPixelChannels
Definition: pixel.h:27
MagickRealType green
Definition: pixel.h:190
MagickBooleanType(* MagickProgressMonitor)(const char *, const MagickOffsetType, const MagickSizeType, void *)
Definition: monitor.h:26
CompositeOperator compose
Definition: image.h:234
#define TextureImageTag
static MagickBooleanType CompositeOverImage(Image *image, const Image *source_image, const MagickBooleanType clip_to_self, const ssize_t x_offset, const ssize_t y_offset, ExceptionInfo *exception)
Definition: composite.c:287
CompositeOperator
Definition: composite.h:25
#define MagickExport
MagickExport MagickBooleanType SyncCacheViewAuthenticPixels(CacheView *magick_restrict cache_view, ExceptionInfo *exception)
Definition: cache-view.c:1100
ssize_t y
Definition: geometry.h:134
MagickExport CacheView * AcquireAuthenticCacheView(const Image *image, ExceptionInfo *exception)
Definition: cache-view.c:112
double y1
Definition: image.h:107
static Quantum GetPixelBlue(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
PixelTrait
Definition: pixel.h:134
MagickExport MagickRealType GetPixelIntensity(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
Definition: pixel.c:2358
MagickExport Image * DestroyImage(Image *image)
Definition: image.c:1181
MagickExport Image * CloneImage(const Image *image, const size_t columns, const size_t rows, const MagickBooleanType detach, ExceptionInfo *exception)
Definition: image.c:796
ColorspaceType colorspace
Definition: image.h:157
#define QuantumRange
Definition: magick-type.h:83
MagickExport MagickBooleanType SetImageProgress(const Image *image, const char *tag, const MagickOffsetType offset, const MagickSizeType extent)
Definition: monitor.c:136
MagickBooleanType debug
Definition: image.h:334