MagickCore  7.0.7
Convert, Edit, Or Compose Bitmap Images
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-2018 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://www.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 - QuantiumScale*alpha * QuantiumScale*beta;
157  opacity = QuantiumScale*alpha*beta; // over blend, optimized 1-Gamma
158 
159  The above SVG definitions also definate 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,4) 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  if (GetPixelWriteMask(image,q) <= (QuantumRange/2))
424  {
425  q+=GetPixelChannels(image);
426  continue;
427  }
428  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
429  {
431  pixel;
432 
433  PixelChannel channel = GetPixelChannelChannel(image,i);
434  PixelTrait traits = GetPixelChannelTraits(image,channel);
435  PixelTrait source_traits=GetPixelChannelTraits(source_image,
436  channel);
437  if ((traits == UndefinedPixelTrait) ||
438  (source_traits == UndefinedPixelTrait))
439  continue;
440  if (channel == AlphaPixelChannel)
442  else
443  pixel=(MagickRealType) q[i];
444  q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
445  ClampToQuantum(pixel);
446  }
447  q+=GetPixelChannels(image);
448  continue;
449  }
450  /*
451  Authentic composite:
452  Sa: normalized source alpha.
453  Da: normalized canvas alpha.
454  */
455  Sa=QuantumScale*GetPixelAlpha(source_image,p);
456  Da=QuantumScale*GetPixelAlpha(image,q);
457  alpha=Sa+Da-Sa*Da;
458  if (GetPixelWriteMask(image,q) <= (QuantumRange/2))
459  {
460  p+=GetPixelChannels(source_image);
461  q+=GetPixelChannels(image);
462  continue;
463  }
464  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
465  {
467  pixel;
468 
469  PixelChannel channel = GetPixelChannelChannel(image,i);
470  PixelTrait traits = GetPixelChannelTraits(image,channel);
471  PixelTrait source_traits=GetPixelChannelTraits(source_image,channel);
472  if (traits == UndefinedPixelTrait)
473  continue;
474  if ((source_traits == UndefinedPixelTrait) &&
475  (channel != AlphaPixelChannel))
476  continue;
477  if (channel == AlphaPixelChannel)
478  {
479  /*
480  Set alpha channel.
481  */
482  pixel=QuantumRange*alpha;
483  q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
484  ClampToQuantum(pixel);
485  continue;
486  }
487  /*
488  Sc: source color.
489  Dc: canvas color.
490  */
491  Sc=(MagickRealType) GetPixelChannel(source_image,channel,p);
492  Dc=(MagickRealType) q[i];
493  if ((traits & CopyPixelTrait) != 0)
494  {
495  /*
496  Copy channel.
497  */
498  q[i]=Sc;
499  continue;
500  }
501  /*
502  Porter-Duff compositions:
503  Sca: source normalized color multiplied by alpha.
504  Dca: normalized canvas color multiplied by alpha.
505  */
506  Sca=QuantumScale*Sa*Sc;
507  Dca=QuantumScale*Da*Dc;
508  gamma=PerceptibleReciprocal(alpha);
509  pixel=QuantumRange*gamma*(Sca+Dca*(1.0-Sa));
510  q[i]=clamp != MagickFalse ? ClampPixel(pixel) : ClampToQuantum(pixel);
511  }
512  p+=GetPixelChannels(source_image);
513  channels=GetPixelChannels(source_image);
514  if (p >= (pixels+channels*source_image->columns))
515  p=pixels;
516  q+=GetPixelChannels(image);
517  }
518  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
519  status=MagickFalse;
520  if (image->progress_monitor != (MagickProgressMonitor) NULL)
521  {
523  proceed;
524 
525 #if defined(MAGICKCORE_OPENMP_SUPPORT)
526  #pragma omp critical (MagickCore_CompositeImage)
527 #endif
528  proceed=SetImageProgress(image,CompositeImageTag,progress++,
529  image->rows);
530  if (proceed == MagickFalse)
531  status=MagickFalse;
532  }
533  }
534  source_view=DestroyCacheView(source_view);
535  image_view=DestroyCacheView(image_view);
536  return(status);
537 }
538 
540  const Image *composite,const CompositeOperator compose,
541  const MagickBooleanType clip_to_self,const ssize_t x_offset,
542  const ssize_t y_offset,ExceptionInfo *exception)
543 {
544 #define CompositeImageTag "Composite/Image"
545 
546  CacheView
547  *source_view,
548  *image_view;
549 
550  const char
551  *value;
552 
554  geometry_info;
555 
556  Image
557  *canvas_image,
558  *source_image;
559 
561  clamp,
562  status;
563 
565  progress;
566 
568  amount,
569  canvas_dissolve,
570  midpoint,
571  percent_luma,
572  percent_chroma,
573  source_dissolve,
574  threshold;
575 
577  flags;
578 
579  ssize_t
580  y;
581 
582  assert(image != (Image *) NULL);
583  assert(image->signature == MagickCoreSignature);
584  if (image->debug != MagickFalse)
585  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
586  assert(composite != (Image *) NULL);
587  assert(composite->signature == MagickCoreSignature);
588  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
589  return(MagickFalse);
590  source_image=CloneImage(composite,0,0,MagickTrue,exception);
591  if (source_image == (const Image *) NULL)
592  return(MagickFalse);
593  if (IsGrayColorspace(image->colorspace) != MagickFalse)
594  (void) SetImageColorspace(image,sRGBColorspace,exception);
595  (void) SetImageColorspace(source_image,image->colorspace,exception);
596  if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
597  {
598  status=CompositeOverImage(image,source_image,clip_to_self,x_offset,
599  y_offset,exception);
600  source_image=DestroyImage(source_image);
601  return(status);
602  }
603  amount=0.5;
604  canvas_image=(Image *) NULL;
605  canvas_dissolve=1.0;
606  clamp=MagickTrue;
607  value=GetImageArtifact(image,"compose:clamp");
608  if (value != (const char *) NULL)
609  clamp=IsStringTrue(value);
610  SetGeometryInfo(&geometry_info);
611  percent_luma=100.0;
612  percent_chroma=100.0;
613  source_dissolve=1.0;
614  threshold=0.05f;
615  switch (compose)
616  {
617  case CopyCompositeOp:
618  {
619  if ((x_offset < 0) || (y_offset < 0))
620  break;
621  if ((x_offset+(ssize_t) source_image->columns) > (ssize_t) image->columns)
622  break;
623  if ((y_offset+(ssize_t) source_image->rows) > (ssize_t) image->rows)
624  break;
625  status=MagickTrue;
626  source_view=AcquireVirtualCacheView(source_image,exception);
627  image_view=AcquireAuthenticCacheView(image,exception);
628 #if defined(MAGICKCORE_OPENMP_SUPPORT)
629  #pragma omp parallel for schedule(static,4) shared(status) \
630  magick_number_threads(source_image,image,source_image->rows,1)
631 #endif
632  for (y=0; y < (ssize_t) source_image->rows; y++)
633  {
635  sync;
636 
637  register const Quantum
638  *p;
639 
640  register Quantum
641  *q;
642 
643  register ssize_t
644  x;
645 
646  if (status == MagickFalse)
647  continue;
648  p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
649  exception);
650  q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
651  source_image->columns,1,exception);
652  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
653  {
654  status=MagickFalse;
655  continue;
656  }
657  for (x=0; x < (ssize_t) source_image->columns; x++)
658  {
659  register ssize_t
660  i;
661 
662  if (GetPixelReadMask(source_image,p) <= (QuantumRange/2))
663  {
664  p+=GetPixelChannels(source_image);
665  q+=GetPixelChannels(image);
666  continue;
667  }
668  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
669  {
670  PixelChannel channel = GetPixelChannelChannel(image,i);
671  PixelTrait traits = GetPixelChannelTraits(image,channel);
672  PixelTrait source_traits=GetPixelChannelTraits(source_image,
673  channel);
674  if (traits == UndefinedPixelTrait)
675  continue;
676  if (source_traits != UndefinedPixelTrait)
677  SetPixelChannel(image,channel,p[i],q);
678  else if (channel == AlphaPixelChannel)
679  SetPixelChannel(image,channel,OpaqueAlpha,q);
680  }
681  p+=GetPixelChannels(source_image);
682  q+=GetPixelChannels(image);
683  }
684  sync=SyncCacheViewAuthenticPixels(image_view,exception);
685  if (sync == MagickFalse)
686  status=MagickFalse;
687  if (image->progress_monitor != (MagickProgressMonitor) NULL)
688  {
690  proceed;
691 
692 #if defined(MAGICKCORE_OPENMP_SUPPORT)
693  #pragma omp critical (MagickCore_CompositeImage)
694 #endif
695  proceed=SetImageProgress(image,CompositeImageTag,
696  (MagickOffsetType) y,image->rows);
697  if (proceed == MagickFalse)
698  status=MagickFalse;
699  }
700  }
701  source_view=DestroyCacheView(source_view);
702  image_view=DestroyCacheView(image_view);
703  source_image=DestroyImage(source_image);
704  return(status);
705  }
707  {
708  if ((x_offset < 0) || (y_offset < 0))
709  break;
710  if ((x_offset+(ssize_t) source_image->columns) > (ssize_t) image->columns)
711  break;
712  if ((y_offset+(ssize_t) source_image->rows) > (ssize_t) image->rows)
713  break;
714  status=MagickTrue;
715  source_view=AcquireVirtualCacheView(source_image,exception);
716  image_view=AcquireAuthenticCacheView(image,exception);
717 #if defined(MAGICKCORE_OPENMP_SUPPORT)
718  #pragma omp parallel for schedule(static,4) shared(status) \
719  magick_number_threads(source_image,image,source_image->rows,1)
720 #endif
721  for (y=0; y < (ssize_t) source_image->rows; y++)
722  {
724  sync;
725 
726  register const Quantum
727  *p;
728 
729  register Quantum
730  *q;
731 
732  register ssize_t
733  x;
734 
735  if (status == MagickFalse)
736  continue;
737  p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
738  exception);
739  q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
740  source_image->columns,1,exception);
741  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
742  {
743  status=MagickFalse;
744  continue;
745  }
746  for (x=0; x < (ssize_t) source_image->columns; x++)
747  {
748  if (GetPixelReadMask(source_image,p) <= (QuantumRange/2))
749  {
750  p+=GetPixelChannels(source_image);
751  q+=GetPixelChannels(image);
752  continue;
753  }
754  SetPixelAlpha(image,clamp != MagickFalse ?
755  ClampPixel(GetPixelIntensity(source_image,p)) :
756  ClampToQuantum(GetPixelIntensity(source_image,p)),q);
757  p+=GetPixelChannels(source_image);
758  q+=GetPixelChannels(image);
759  }
760  sync=SyncCacheViewAuthenticPixels(image_view,exception);
761  if (sync == MagickFalse)
762  status=MagickFalse;
763  if (image->progress_monitor != (MagickProgressMonitor) NULL)
764  {
766  proceed;
767 
768 #if defined(MAGICKCORE_OPENMP_SUPPORT)
769  #pragma omp critical (MagickCore_CompositeImage)
770 #endif
771  proceed=SetImageProgress(image,CompositeImageTag,
772  (MagickOffsetType) y,image->rows);
773  if (proceed == MagickFalse)
774  status=MagickFalse;
775  }
776  }
777  source_view=DestroyCacheView(source_view);
778  image_view=DestroyCacheView(image_view);
779  source_image=DestroyImage(source_image);
780  return(status);
781  }
784  {
785  /*
786  Modify canvas outside the overlaid region and require an alpha
787  channel to exist, to add transparency.
788  */
789  if (image->alpha_trait == UndefinedPixelTrait)
790  (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
791  break;
792  }
793  case BlurCompositeOp:
794  {
795  CacheView
796  *canvas_view;
797 
799  angle_range,
800  angle_start,
801  height,
802  width;
803 
804  PixelInfo
805  pixel;
806 
808  *resample_filter;
809 
811  blur;
812 
813  /*
814  Blur Image by resampling.
815 
816  Blur Image dictated by an overlay gradient map: X = red_channel;
817  Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
818  */
819  canvas_image=CloneImage(image,image->columns,image->rows,MagickTrue,
820  exception);
821  if (canvas_image == (Image *) NULL)
822  {
823  source_image=DestroyImage(source_image);
824  return(MagickFalse);
825  }
826  /*
827  Gather the maximum blur sigma values from user.
828  */
829  flags=NoValue;
830  value=GetImageArtifact(image,"compose:args");
831  if (value != (const char *) NULL)
832  flags=ParseGeometry(value,&geometry_info);
833  if ((flags & WidthValue) == 0)
834  {
836  "InvalidSetting","'%s' '%s'","compose:args",value);
837  source_image=DestroyImage(source_image);
838  canvas_image=DestroyImage(canvas_image);
839  return(MagickFalse);
840  }
841  /*
842  Users input sigma now needs to be converted to the EWA ellipse size.
843  The filter defaults to a sigma of 0.5 so to make this match the
844  users input the ellipse size needs to be doubled.
845  */
846  width=height=geometry_info.rho*2.0;
847  if ((flags & HeightValue) != 0 )
848  height=geometry_info.sigma*2.0;
849  /*
850  Default the unrotated ellipse width and height axis vectors.
851  */
852  blur.x1=width;
853  blur.x2=0.0;
854  blur.y1=0.0;
855  blur.y2=height;
856  /* rotate vectors if a rotation angle is given */
857  if ((flags & XValue) != 0 )
858  {
860  angle;
861 
862  angle=DegreesToRadians(geometry_info.xi);
863  blur.x1=width*cos(angle);
864  blur.x2=width*sin(angle);
865  blur.y1=(-height*sin(angle));
866  blur.y2=height*cos(angle);
867  }
868  /* Otherwise lets set a angle range and calculate in the loop */
869  angle_start=0.0;
870  angle_range=0.0;
871  if ((flags & YValue) != 0 )
872  {
873  angle_start=DegreesToRadians(geometry_info.xi);
874  angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
875  }
876  /*
877  Set up a gaussian cylindrical filter for EWA Bluring.
878 
879  As the minimum ellipse radius of support*1.0 the EWA algorithm
880  can only produce a minimum blur of 0.5 for Gaussian (support=2.0)
881  This means that even 'No Blur' will be still a little blurry!
882 
883  The solution (as well as the problem of preventing any user
884  expert filter settings, is to set our own user settings, then
885  restore them afterwards.
886  */
887  resample_filter=AcquireResampleFilter(image,exception);
888  SetResampleFilter(resample_filter,GaussianFilter);
889 
890  /* do the variable blurring of each pixel in image */
891  GetPixelInfo(image,&pixel);
892  source_view=AcquireVirtualCacheView(source_image,exception);
893  canvas_view=AcquireAuthenticCacheView(canvas_image,exception);
894  for (y=0; y < (ssize_t) source_image->rows; y++)
895  {
897  sync;
898 
899  register const Quantum
900  *magick_restrict p;
901 
902  register Quantum
903  *magick_restrict q;
904 
905  register ssize_t
906  x;
907 
908  if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
909  continue;
910  p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
911  exception);
912  q=QueueCacheViewAuthenticPixels(canvas_view,0,y,canvas_image->columns,1,
913  exception);
914  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
915  break;
916  for (x=0; x < (ssize_t) source_image->columns; x++)
917  {
918  if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
919  {
920  p+=GetPixelChannels(source_image);
921  continue;
922  }
923  if (fabs((double) angle_range) > MagickEpsilon)
924  {
926  angle;
927 
928  angle=angle_start+angle_range*QuantumScale*
929  GetPixelBlue(source_image,p);
930  blur.x1=width*cos(angle);
931  blur.x2=width*sin(angle);
932  blur.y1=(-height*sin(angle));
933  blur.y2=height*cos(angle);
934  }
935 #if 0
936  if ( x == 10 && y == 60 ) {
937  (void) fprintf(stderr, "blur.x=%lf,%lf, blur.y=%lf,%lf\n",blur.x1,
938  blur.x2,blur.y1, blur.y2);
939  (void) fprintf(stderr, "scaled by=%lf,%lf\n",QuantumScale*
941 #endif
942  ScaleResampleFilter(resample_filter,
943  blur.x1*QuantumScale*GetPixelRed(source_image,p),
944  blur.y1*QuantumScale*GetPixelGreen(source_image,p),
945  blur.x2*QuantumScale*GetPixelRed(source_image,p),
946  blur.y2*QuantumScale*GetPixelGreen(source_image,p) );
947  (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
948  (double) y_offset+y,&pixel,exception);
949  SetPixelViaPixelInfo(canvas_image,&pixel,q);
950  p+=GetPixelChannels(source_image);
951  q+=GetPixelChannels(canvas_image);
952  }
953  sync=SyncCacheViewAuthenticPixels(canvas_view,exception);
954  if (sync == MagickFalse)
955  break;
956  }
957  resample_filter=DestroyResampleFilter(resample_filter);
958  source_view=DestroyCacheView(source_view);
959  canvas_view=DestroyCacheView(canvas_view);
960  source_image=DestroyImage(source_image);
961  source_image=canvas_image;
962  break;
963  }
964  case DisplaceCompositeOp:
965  case DistortCompositeOp:
966  {
967  CacheView
968  *canvas_view;
969 
971  horizontal_scale,
972  vertical_scale;
973 
974  PixelInfo
975  pixel;
976 
977  PointInfo
978  center,
979  offset;
980 
981  /*
982  Displace/Distort based on overlay gradient map:
983  X = red_channel; Y = green_channel;
984  compose:args = x_scale[,y_scale[,center.x,center.y]]
985  */
986  canvas_image=CloneImage(image,image->columns,image->rows,MagickTrue,
987  exception);
988  if (canvas_image == (Image *) NULL)
989  {
990  source_image=DestroyImage(source_image);
991  return(MagickFalse);
992  }
993  SetGeometryInfo(&geometry_info);
994  flags=NoValue;
995  value=GetImageArtifact(image,"compose:args");
996  if (value != (char *) NULL)
997  flags=ParseGeometry(value,&geometry_info);
998  if ((flags & (WidthValue | HeightValue)) == 0 )
999  {
1000  if ((flags & AspectValue) == 0)
1001  {
1002  horizontal_scale=(MagickRealType) (source_image->columns-1)/2.0;
1003  vertical_scale=(MagickRealType) (source_image->rows-1)/2.0;
1004  }
1005  else
1006  {
1007  horizontal_scale=(MagickRealType) (image->columns-1)/2.0;
1008  vertical_scale=(MagickRealType) (image->rows-1)/2.0;
1009  }
1010  }
1011  else
1012  {
1013  horizontal_scale=geometry_info.rho;
1014  vertical_scale=geometry_info.sigma;
1015  if ((flags & PercentValue) != 0)
1016  {
1017  if ((flags & AspectValue) == 0)
1018  {
1019  horizontal_scale*=(source_image->columns-1)/200.0;
1020  vertical_scale*=(source_image->rows-1)/200.0;
1021  }
1022  else
1023  {
1024  horizontal_scale*=(image->columns-1)/200.0;
1025  vertical_scale*=(image->rows-1)/200.0;
1026  }
1027  }
1028  if ((flags & HeightValue) == 0)
1029  vertical_scale=horizontal_scale;
1030  }
1031  /*
1032  Determine fixed center point for absolute distortion map
1033  Absolute distort ==
1034  Displace offset relative to a fixed absolute point
1035  Select that point according to +X+Y user inputs.
1036  default = center of overlay image
1037  arg flag '!' = locations/percentage relative to background image
1038  */
1039  center.x=(MagickRealType) x_offset;
1040  center.y=(MagickRealType) y_offset;
1041  if (compose == DistortCompositeOp)
1042  {
1043  if ((flags & XValue) == 0)
1044  if ((flags & AspectValue) != 0)
1045  center.x=(MagickRealType) ((image->columns-1)/2.0);
1046  else
1047  center.x=(MagickRealType) (x_offset+(source_image->columns-1)/
1048  2.0);
1049  else
1050  if ((flags & AspectValue) != 0)
1051  center.x=geometry_info.xi;
1052  else
1053  center.x=(MagickRealType) (x_offset+geometry_info.xi);
1054  if ((flags & YValue) == 0)
1055  if ((flags & AspectValue) != 0)
1056  center.y=(MagickRealType) ((image->rows-1)/2.0);
1057  else
1058  center.y=(MagickRealType) (y_offset+(source_image->rows-1)/2.0);
1059  else
1060  if ((flags & AspectValue) != 0)
1061  center.y=geometry_info.psi;
1062  else
1063  center.y=(MagickRealType) (y_offset+geometry_info.psi);
1064  }
1065  /*
1066  Shift the pixel offset point as defined by the provided,
1067  displacement/distortion map. -- Like a lens...
1068  */
1069  GetPixelInfo(image,&pixel);
1070  image_view=AcquireVirtualCacheView(image,exception);
1071  source_view=AcquireVirtualCacheView(source_image,exception);
1072  canvas_view=AcquireAuthenticCacheView(canvas_image,exception);
1073  for (y=0; y < (ssize_t) source_image->rows; y++)
1074  {
1076  sync;
1077 
1078  register const Quantum
1079  *magick_restrict p;
1080 
1081  register Quantum
1082  *magick_restrict q;
1083 
1084  register ssize_t
1085  x;
1086 
1087  if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1088  continue;
1089  p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
1090  exception);
1091  q=QueueCacheViewAuthenticPixels(canvas_view,0,y,canvas_image->columns,1,
1092  exception);
1093  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1094  break;
1095  for (x=0; x < (ssize_t) source_image->columns; x++)
1096  {
1097  if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1098  {
1099  p+=GetPixelChannels(source_image);
1100  continue;
1101  }
1102  /*
1103  Displace the offset.
1104  */
1105  offset.x=(double) (horizontal_scale*(GetPixelRed(source_image,p)-
1106  (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1107  QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
1108  x : 0);
1109  offset.y=(double) (vertical_scale*(GetPixelGreen(source_image,p)-
1110  (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1111  QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
1112  y : 0);
1113  (void) InterpolatePixelInfo(image,image_view,
1114  UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1115  &pixel,exception);
1116  /*
1117  Mask with the 'invalid pixel mask' in alpha channel.
1118  */
1120  (QuantumScale*GetPixelAlpha(source_image,p));
1121  SetPixelViaPixelInfo(canvas_image,&pixel,q);
1122  p+=GetPixelChannels(source_image);
1123  q+=GetPixelChannels(canvas_image);
1124  }
1125  sync=SyncCacheViewAuthenticPixels(canvas_view,exception);
1126  if (sync == MagickFalse)
1127  break;
1128  }
1129  canvas_view=DestroyCacheView(canvas_view);
1130  source_view=DestroyCacheView(source_view);
1131  image_view=DestroyCacheView(image_view);
1132  source_image=DestroyImage(source_image);
1133  source_image=canvas_image;
1134  break;
1135  }
1136  case DissolveCompositeOp:
1137  {
1138  /*
1139  Geometry arguments to dissolve factors.
1140  */
1141  value=GetImageArtifact(image,"compose:args");
1142  if (value != (char *) NULL)
1143  {
1144  flags=ParseGeometry(value,&geometry_info);
1145  source_dissolve=geometry_info.rho/100.0;
1146  canvas_dissolve=1.0;
1147  if ((source_dissolve-MagickEpsilon) < 0.0)
1148  source_dissolve=0.0;
1149  if ((source_dissolve+MagickEpsilon) > 1.0)
1150  {
1151  canvas_dissolve=2.0-source_dissolve;
1152  source_dissolve=1.0;
1153  }
1154  if ((flags & SigmaValue) != 0)
1155  canvas_dissolve=geometry_info.sigma/100.0;
1156  if ((canvas_dissolve-MagickEpsilon) < 0.0)
1157  canvas_dissolve=0.0;
1158  }
1159  break;
1160  }
1161  case BlendCompositeOp:
1162  {
1163  value=GetImageArtifact(image,"compose:args");
1164  if (value != (char *) NULL)
1165  {
1166  flags=ParseGeometry(value,&geometry_info);
1167  source_dissolve=geometry_info.rho/100.0;
1168  canvas_dissolve=1.0-source_dissolve;
1169  if ((flags & SigmaValue) != 0)
1170  canvas_dissolve=geometry_info.sigma/100.0;
1171  }
1172  break;
1173  }
1175  {
1176  /*
1177  Just collect the values from "compose:args", setting.
1178  Unused values are set to zero automagically.
1179 
1180  Arguments are normally a comma separated list, so this probably should
1181  be changed to some 'general comma list' parser, (with a minimum
1182  number of values)
1183  */
1184  SetGeometryInfo(&geometry_info);
1185  value=GetImageArtifact(image,"compose:args");
1186  if (value != (char *) NULL)
1187  (void) ParseGeometry(value,&geometry_info);
1188  break;
1189  }
1190  case ModulateCompositeOp:
1191  {
1192  /*
1193  Determine the luma and chroma scale.
1194  */
1195  value=GetImageArtifact(image,"compose:args");
1196  if (value != (char *) NULL)
1197  {
1198  flags=ParseGeometry(value,&geometry_info);
1199  percent_luma=geometry_info.rho;
1200  if ((flags & SigmaValue) != 0)
1201  percent_chroma=geometry_info.sigma;
1202  }
1203  break;
1204  }
1205  case ThresholdCompositeOp:
1206  {
1207  /*
1208  Determine the amount and threshold.
1209  */
1210  value=GetImageArtifact(image,"compose:args");
1211  if (value != (char *) NULL)
1212  {
1213  flags=ParseGeometry(value,&geometry_info);
1214  amount=geometry_info.rho;
1215  threshold=geometry_info.sigma;
1216  if ((flags & SigmaValue) == 0)
1217  threshold=0.05f;
1218  }
1219  threshold*=QuantumRange;
1220  break;
1221  }
1222  default:
1223  break;
1224  }
1225  /*
1226  Composite image.
1227  */
1228  status=MagickTrue;
1229  progress=0;
1230  midpoint=((MagickRealType) QuantumRange+1.0)/2;
1231  source_view=AcquireVirtualCacheView(source_image,exception);
1232  image_view=AcquireAuthenticCacheView(image,exception);
1233 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1234  #pragma omp parallel for schedule(static,4) shared(progress,status) \
1235  magick_number_threads(source_image,image,image->rows,1)
1236 #endif
1237  for (y=0; y < (ssize_t) image->rows; y++)
1238  {
1239  const Quantum
1240  *pixels;
1241 
1243  blue,
1244  chroma,
1245  green,
1246  hue,
1247  luma,
1248  red;
1249 
1250  PixelInfo
1251  canvas_pixel,
1252  source_pixel;
1253 
1254  register const Quantum
1255  *magick_restrict p;
1256 
1257  register Quantum
1258  *magick_restrict q;
1259 
1260  register ssize_t
1261  x;
1262 
1263  if (status == MagickFalse)
1264  continue;
1265  if (clip_to_self != MagickFalse)
1266  {
1267  if (y < y_offset)
1268  continue;
1269  if ((y-y_offset) >= (ssize_t) source_image->rows)
1270  continue;
1271  }
1272  /*
1273  If pixels is NULL, y is outside overlay region.
1274  */
1275  pixels=(Quantum *) NULL;
1276  p=(Quantum *) NULL;
1277  if ((y >= y_offset) && ((y-y_offset) < (ssize_t) source_image->rows))
1278  {
1279  p=GetCacheViewVirtualPixels(source_view,0,y-y_offset,
1280  source_image->columns,1,exception);
1281  if (p == (const Quantum *) NULL)
1282  {
1283  status=MagickFalse;
1284  continue;
1285  }
1286  pixels=p;
1287  if (x_offset < 0)
1288  p-=x_offset*GetPixelChannels(source_image);
1289  }
1290  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1291  if (q == (Quantum *) NULL)
1292  {
1293  status=MagickFalse;
1294  continue;
1295  }
1296  hue=0.0;
1297  chroma=0.0;
1298  luma=0.0;
1299  GetPixelInfo(image,&canvas_pixel);
1300  GetPixelInfo(source_image,&source_pixel);
1301  for (x=0; x < (ssize_t) image->columns; x++)
1302  {
1303  double
1304  gamma;
1305 
1307  alpha,
1308  Da,
1309  Dc,
1310  Dca,
1311  Sa,
1312  Sc,
1313  Sca;
1314 
1315  register ssize_t
1316  i;
1317 
1318  size_t
1319  channels;
1320 
1321  if (clip_to_self != MagickFalse)
1322  {
1323  if (x < x_offset)
1324  {
1325  q+=GetPixelChannels(image);
1326  continue;
1327  }
1328  if ((x-x_offset) >= (ssize_t) source_image->columns)
1329  break;
1330  }
1331  if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1332  ((x-x_offset) >= (ssize_t) source_image->columns))
1333  {
1334  Quantum
1335  source[MaxPixelChannels];
1336 
1337  /*
1338  Virtual composite:
1339  Sc: source color.
1340  Dc: canvas color.
1341  */
1342  (void) GetOneVirtualPixel(source_image,x-x_offset,y-y_offset,source,
1343  exception);
1344  if (GetPixelWriteMask(image,q) <= (QuantumRange/2))
1345  {
1346  q+=GetPixelChannels(image);
1347  continue;
1348  }
1349  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1350  {
1352  pixel;
1353 
1354  PixelChannel channel = GetPixelChannelChannel(image,i);
1355  PixelTrait traits = GetPixelChannelTraits(image,channel);
1356  PixelTrait source_traits=GetPixelChannelTraits(source_image,
1357  channel);
1358  if ((traits == UndefinedPixelTrait) ||
1359  (source_traits == UndefinedPixelTrait))
1360  continue;
1361  switch (compose)
1362  {
1363  case AlphaCompositeOp:
1364  case ChangeMaskCompositeOp:
1365  case CopyAlphaCompositeOp:
1366  case DstAtopCompositeOp:
1367  case DstInCompositeOp:
1368  case InCompositeOp:
1369  case OutCompositeOp:
1370  case SrcInCompositeOp:
1371  case SrcOutCompositeOp:
1372  {
1373  if (channel == AlphaPixelChannel)
1375  else
1376  pixel=(MagickRealType) q[i];
1377  break;
1378  }
1379  case ClearCompositeOp:
1380  case CopyCompositeOp:
1381  case ReplaceCompositeOp:
1382  case SrcCompositeOp:
1383  {
1384  if (channel == AlphaPixelChannel)
1386  else
1387  pixel=0.0;
1388  break;
1389  }
1390  case BlendCompositeOp:
1391  case DissolveCompositeOp:
1392  {
1393  if (channel == AlphaPixelChannel)
1394  pixel=canvas_dissolve*GetPixelAlpha(source_image,source);
1395  else
1396  pixel=(MagickRealType) source[channel];
1397  break;
1398  }
1399  default:
1400  {
1401  pixel=(MagickRealType) source[channel];
1402  break;
1403  }
1404  }
1405  q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
1406  ClampToQuantum(pixel);
1407  }
1408  q+=GetPixelChannels(image);
1409  continue;
1410  }
1411  /*
1412  Authentic composite:
1413  Sa: normalized source alpha.
1414  Da: normalized canvas alpha.
1415  */
1416  Sa=QuantumScale*GetPixelAlpha(source_image,p);
1417  Da=QuantumScale*GetPixelAlpha(image,q);
1418  switch (compose)
1419  {
1420  case BumpmapCompositeOp:
1421  {
1422  alpha=GetPixelIntensity(source_image,p)*Sa;
1423  break;
1424  }
1425  case ColorBurnCompositeOp:
1426  case ColorDodgeCompositeOp:
1427  case DarkenCompositeOp:
1428  case DifferenceCompositeOp:
1429  case DivideDstCompositeOp:
1430  case DivideSrcCompositeOp:
1431  case ExclusionCompositeOp:
1432  case HardLightCompositeOp:
1433  case HardMixCompositeOp:
1434  case LinearBurnCompositeOp:
1437  case LightenCompositeOp:
1439  case MinusDstCompositeOp:
1440  case MinusSrcCompositeOp:
1441  case ModulusAddCompositeOp:
1443  case MultiplyCompositeOp:
1444  case OverlayCompositeOp:
1446  case PinLightCompositeOp:
1447  case ScreenCompositeOp:
1448  case SoftLightCompositeOp:
1449  case VividLightCompositeOp:
1450  {
1451  alpha=RoundToUnity(Sa+Da-Sa*Da);
1452  break;
1453  }
1454  case DstAtopCompositeOp:
1455  case DstInCompositeOp:
1456  case InCompositeOp:
1457  case SrcInCompositeOp:
1458  {
1459  alpha=Sa*Da;
1460  break;
1461  }
1462  case DissolveCompositeOp:
1463  {
1464  alpha=source_dissolve*Sa*(-canvas_dissolve*Da)+source_dissolve*Sa+
1465  canvas_dissolve*Da;
1466  break;
1467  }
1468  case DstOverCompositeOp:
1469  case OverCompositeOp:
1470  case SrcOverCompositeOp:
1471  {
1472  alpha=Sa+Da-Sa*Da;
1473  break;
1474  }
1475  case DstOutCompositeOp:
1476  {
1477  alpha=Da*(1.0-Sa);
1478  break;
1479  }
1480  case OutCompositeOp:
1481  case SrcOutCompositeOp:
1482  {
1483  alpha=Sa*(1.0-Da);
1484  break;
1485  }
1486  case BlendCompositeOp:
1487  case PlusCompositeOp:
1488  {
1489  alpha=RoundToUnity(source_dissolve*Sa+canvas_dissolve*Da);
1490  break;
1491  }
1492  case XorCompositeOp:
1493  {
1494  alpha=Sa+Da-2.0*Sa*Da;
1495  break;
1496  }
1497  default:
1498  {
1499  alpha=1.0;
1500  break;
1501  }
1502  }
1503  if (GetPixelWriteMask(image,q) <= (QuantumRange/2))
1504  {
1505  p+=GetPixelChannels(source_image);
1506  q+=GetPixelChannels(image);
1507  continue;
1508  }
1509  switch (compose)
1510  {
1511  case ColorizeCompositeOp:
1512  case HueCompositeOp:
1513  case LuminizeCompositeOp:
1514  case ModulateCompositeOp:
1515  case SaturateCompositeOp:
1516  {
1517  GetPixelInfoPixel(source_image,p,&source_pixel);
1518  GetPixelInfoPixel(image,q,&canvas_pixel);
1519  break;
1520  }
1521  default:
1522  break;
1523  }
1524  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1525  {
1527  pixel,
1528  sans;
1529 
1530  PixelChannel channel = GetPixelChannelChannel(image,i);
1531  PixelTrait traits = GetPixelChannelTraits(image,channel);
1532  PixelTrait source_traits=GetPixelChannelTraits(source_image,channel);
1533  if (traits == UndefinedPixelTrait)
1534  continue;
1535  if (channel == AlphaPixelChannel)
1536  {
1537  /*
1538  Set alpha channel.
1539  */
1540  switch (compose)
1541  {
1542  case AlphaCompositeOp:
1543  {
1544  pixel=QuantumRange*Sa;
1545  break;
1546  }
1547  case AtopCompositeOp:
1548  case CopyBlackCompositeOp:
1549  case CopyBlueCompositeOp:
1550  case CopyCyanCompositeOp:
1551  case CopyGreenCompositeOp:
1553  case CopyRedCompositeOp:
1554  case CopyYellowCompositeOp:
1555  case SrcAtopCompositeOp:
1556  case DstCompositeOp:
1557  case NoCompositeOp:
1558  {
1559  pixel=QuantumRange*Da;
1560  break;
1561  }
1562  case ChangeMaskCompositeOp:
1563  {
1565  equivalent;
1566 
1567  if (Da < 0.5)
1568  {
1570  break;
1571  }
1572  equivalent=IsFuzzyEquivalencePixel(source_image,p,image,q);
1573  if (equivalent != MagickFalse)
1575  else
1576  pixel=(MagickRealType) OpaqueAlpha;
1577  break;
1578  }
1579  case ClearCompositeOp:
1580  {
1582  break;
1583  }
1584  case ColorizeCompositeOp:
1585  case HueCompositeOp:
1586  case LuminizeCompositeOp:
1587  case SaturateCompositeOp:
1588  {
1589  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1590  {
1591  pixel=QuantumRange*Da;
1592  break;
1593  }
1594  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
1595  {
1596  pixel=QuantumRange*Sa;
1597  break;
1598  }
1599  if (Sa < Da)
1600  {
1601  pixel=QuantumRange*Da;
1602  break;
1603  }
1604  pixel=QuantumRange*Sa;
1605  break;
1606  }
1607  case CopyAlphaCompositeOp:
1608  {
1609  if (source_image->alpha_trait == UndefinedPixelTrait)
1610  pixel=GetPixelIntensity(source_image,p);
1611  else
1612  pixel=QuantumRange*Sa;
1613  break;
1614  }
1615  case CopyCompositeOp:
1616  case DisplaceCompositeOp:
1617  case DistortCompositeOp:
1618  case DstAtopCompositeOp:
1619  case ReplaceCompositeOp:
1620  case SrcCompositeOp:
1621  {
1622  pixel=QuantumRange*Sa;
1623  break;
1624  }
1626  {
1627  pixel=Sa*GetPixelIntensity(source_image,p) <
1628  Da*GetPixelIntensity(image,q) ? Sa : Da;
1629  break;
1630  }
1632  {
1633  pixel=Sa*GetPixelIntensity(source_image,p) >
1634  Da*GetPixelIntensity(image,q) ? Sa : Da;
1635  break;
1636  }
1637  case ModulateCompositeOp:
1638  {
1639  pixel=QuantumRange*Da;
1640  break;
1641  }
1642  case MultiplyCompositeOp:
1643  {
1644  pixel=QuantumRange*Sa*Da;
1645  break;
1646  }
1647  default:
1648  {
1649  pixel=QuantumRange*alpha;
1650  break;
1651  }
1652  }
1653  q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
1654  ClampToQuantum(pixel);
1655  continue;
1656  }
1657  if (source_traits == UndefinedPixelTrait)
1658  continue;
1659  /*
1660  Sc: source color.
1661  Dc: canvas color.
1662  */
1663  Sc=(MagickRealType) GetPixelChannel(source_image,channel,p);
1664  Dc=(MagickRealType) q[i];
1665  if ((traits & CopyPixelTrait) != 0)
1666  {
1667  /*
1668  Copy channel.
1669  */
1670  q[i]=Dc;
1671  continue;
1672  }
1673  /*
1674  Porter-Duff compositions:
1675  Sca: source normalized color multiplied by alpha.
1676  Dca: normalized canvas color multiplied by alpha.
1677  */
1678  Sca=QuantumScale*Sa*Sc;
1679  Dca=QuantumScale*Da*Dc;
1680  switch (compose)
1681  {
1682  case DarkenCompositeOp:
1683  case LightenCompositeOp:
1685  {
1686  gamma=PerceptibleReciprocal(1.0-alpha);
1687  break;
1688  }
1689  default:
1690  {
1691  gamma=PerceptibleReciprocal(alpha);
1692  break;
1693  }
1694  }
1695  pixel=Dc;
1696  switch (compose)
1697  {
1698  case AlphaCompositeOp:
1699  {
1700  pixel=QuantumRange*Sa;
1701  break;
1702  }
1703  case AtopCompositeOp:
1704  case SrcAtopCompositeOp:
1705  {
1706  pixel=QuantumRange*(Sca*Da+Dca*(1.0-Sa));
1707  break;
1708  }
1709  case BlendCompositeOp:
1710  {
1711  pixel=gamma*(source_dissolve*Sa*Sc+canvas_dissolve*Da*Dc);
1712  break;
1713  }
1714  case BlurCompositeOp:
1715  case CopyCompositeOp:
1716  case ReplaceCompositeOp:
1717  case SrcCompositeOp:
1718  {
1719  pixel=QuantumRange*Sca;
1720  break;
1721  }
1722  case DisplaceCompositeOp:
1723  case DistortCompositeOp:
1724  {
1725  pixel=Sc;
1726  break;
1727  }
1728  case BumpmapCompositeOp:
1729  {
1730  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1731  {
1732  pixel=Dc;
1733  break;
1734  }
1735  pixel=QuantumScale*GetPixelIntensity(source_image,p)*Dc;
1736  break;
1737  }
1738  case ChangeMaskCompositeOp:
1739  {
1740  pixel=Dc;
1741  break;
1742  }
1743  case ClearCompositeOp:
1744  {
1745  pixel=0.0;
1746  break;
1747  }
1748  case ColorBurnCompositeOp:
1749  {
1750  if ((Sca == 0.0) && (Dca == Da))
1751  {
1752  pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1753  break;
1754  }
1755  if (Sca == 0.0)
1756  {
1757  pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1758  break;
1759  }
1760  pixel=QuantumRange*gamma*(Sa*Da-Sa*Da*MagickMin(1.0,(1.0-Dca/Da)*Sa/
1761  Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
1762  break;
1763  }
1764  case ColorDodgeCompositeOp:
1765  {
1766  if ((Sca*Da+Dca*Sa) >= Sa*Da)
1767  pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1768  else
1769  pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1770  (1.0-Sa));
1771  break;
1772  }
1773  case ColorizeCompositeOp:
1774  {
1775  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1776  {
1777  pixel=Dc;
1778  break;
1779  }
1780  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
1781  {
1782  pixel=Sc;
1783  break;
1784  }
1785  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
1786  &sans,&sans,&luma);
1787  CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1788  &hue,&chroma,&sans);
1789  HCLComposite(hue,chroma,luma,&red,&green,&blue);
1790  switch (channel)
1791  {
1792  case RedPixelChannel: pixel=red; break;
1793  case GreenPixelChannel: pixel=green; break;
1794  case BluePixelChannel: pixel=blue; break;
1795  default: pixel=Dc; break;
1796  }
1797  break;
1798  }
1799  case CopyAlphaCompositeOp:
1800  {
1801  pixel=Dc;
1802  break;
1803  }
1804  case CopyBlackCompositeOp:
1805  {
1806  if (channel == BlackPixelChannel)
1807  pixel=(MagickRealType) (QuantumRange-
1808  GetPixelBlack(source_image,p));
1809  break;
1810  }
1811  case CopyBlueCompositeOp:
1812  case CopyYellowCompositeOp:
1813  {
1814  if (channel == BluePixelChannel)
1815  pixel=(MagickRealType) GetPixelBlue(source_image,p);
1816  break;
1817  }
1818  case CopyGreenCompositeOp:
1820  {
1821  if (channel == GreenPixelChannel)
1822  pixel=(MagickRealType) GetPixelGreen(source_image,p);
1823  break;
1824  }
1825  case CopyRedCompositeOp:
1826  case CopyCyanCompositeOp:
1827  {
1828  if (channel == RedPixelChannel)
1829  pixel=(MagickRealType) GetPixelRed(source_image,p);
1830  break;
1831  }
1832  case DarkenCompositeOp:
1833  {
1834  /*
1835  Darken is equivalent to a 'Minimum' method
1836  OR a greyscale version of a binary 'Or'
1837  OR the 'Intersection' of pixel sets.
1838  */
1839  if ((Sca*Da) < (Dca*Sa))
1840  {
1841  pixel=QuantumRange*(Sca+Dca*(1.0-Sa));
1842  break;
1843  }
1844  pixel=QuantumRange*(Dca+Sca*(1.0-Da));
1845  break;
1846  }
1848  {
1849  pixel=Sa*GetPixelIntensity(source_image,p) <
1850  Da*GetPixelIntensity(image,q) ? Sc : Dc;
1851  break;
1852  }
1853  case DifferenceCompositeOp:
1854  {
1855  pixel=QuantumRange*gamma*(Sca+Dca-2.0*MagickMin(Sca*Da,Dca*Sa));
1856  break;
1857  }
1858  case DissolveCompositeOp:
1859  {
1860  pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1861  canvas_dissolve*Da*Dc+canvas_dissolve*Da*Dc);
1862  break;
1863  }
1864  case DivideDstCompositeOp:
1865  {
1866  if ((fabs((double) Sca) < MagickEpsilon) &&
1867  (fabs((double) Dca) < MagickEpsilon))
1868  {
1869  pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1870  break;
1871  }
1872  if (fabs((double) Dca) < MagickEpsilon)
1873  {
1874  pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1875  break;
1876  }
1877  pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1878  break;
1879  }
1880  case DivideSrcCompositeOp:
1881  {
1882  if ((fabs((double) Dca) < MagickEpsilon) &&
1883  (fabs((double) Sca) < MagickEpsilon))
1884  {
1885  pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1886  break;
1887  }
1888  if (fabs((double) Sca) < MagickEpsilon)
1889  {
1890  pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1891  break;
1892  }
1893  pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1894  break;
1895  }
1896  case DstAtopCompositeOp:
1897  {
1898  pixel=QuantumRange*(Dca*Sa+Sca*(1.0-Da));
1899  break;
1900  }
1901  case DstCompositeOp:
1902  case NoCompositeOp:
1903  {
1904  pixel=QuantumRange*Dca;
1905  break;
1906  }
1907  case DstInCompositeOp:
1908  {
1909  pixel=QuantumRange*(Dca*Sa);
1910  break;
1911  }
1912  case DstOutCompositeOp:
1913  {
1914  pixel=QuantumRange*(Dca*(1.0-Sa));
1915  break;
1916  }
1917  case DstOverCompositeOp:
1918  {
1919  pixel=QuantumRange*gamma*(Dca+Sca*(1.0-Da));
1920  break;
1921  }
1922  case ExclusionCompositeOp:
1923  {
1924  pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1925  Dca*(1.0-Sa));
1926  break;
1927  }
1928  case HardLightCompositeOp:
1929  {
1930  if ((2.0*Sca) < Sa)
1931  {
1932  pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-
1933  Sa));
1934  break;
1935  }
1936  pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1937  Dca*(1.0-Sa));
1938  break;
1939  }
1940  case HardMixCompositeOp:
1941  {
1942  pixel=gamma*(((Sca+Dca) < 1.0) ? 0.0 : QuantumRange);
1943  break;
1944  }
1945  case HueCompositeOp:
1946  {
1947  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1948  {
1949  pixel=Dc;
1950  break;
1951  }
1952  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
1953  {
1954  pixel=Sc;
1955  break;
1956  }
1957  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
1958  &hue,&chroma,&luma);
1959  CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1960  &hue,&sans,&sans);
1961  HCLComposite(hue,chroma,luma,&red,&green,&blue);
1962  switch (channel)
1963  {
1964  case RedPixelChannel: pixel=red; break;
1965  case GreenPixelChannel: pixel=green; break;
1966  case BluePixelChannel: pixel=blue; break;
1967  default: pixel=Dc; break;
1968  }
1969  break;
1970  }
1971  case InCompositeOp:
1972  case SrcInCompositeOp:
1973  {
1974  pixel=QuantumRange*(Sca*Da);
1975  break;
1976  }
1977  case LinearBurnCompositeOp:
1978  {
1979  /*
1980  LinearBurn: as defined by Abode Photoshop, according to
1981  http://www.simplefilter.de/en/basics/mixmods.html is:
1982 
1983  f(Sc,Dc) = Sc + Dc - 1
1984  */
1985  pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1986  break;
1987  }
1989  {
1990  pixel=gamma*(Sa*Sc+Da*Dc);
1991  break;
1992  }
1994  {
1995  /*
1996  LinearLight: as defined by Abode Photoshop, according to
1997  http://www.simplefilter.de/en/basics/mixmods.html is:
1998 
1999  f(Sc,Dc) = Dc + 2*Sc - 1
2000  */
2001  pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
2002  break;
2003  }
2004  case LightenCompositeOp:
2005  {
2006  if ((Sca*Da) > (Dca*Sa))
2007  {
2008  pixel=QuantumRange*(Sca+Dca*(1.0-Sa));
2009  break;
2010  }
2011  pixel=QuantumRange*(Dca+Sca*(1.0-Da));
2012  break;
2013  }
2015  {
2016  /*
2017  Lighten is equivalent to a 'Maximum' method
2018  OR a greyscale version of a binary 'And'
2019  OR the 'Union' of pixel sets.
2020  */
2021  pixel=Sa*GetPixelIntensity(source_image,p) >
2022  Da*GetPixelIntensity(image,q) ? Sc : Dc;
2023  break;
2024  }
2025  case LuminizeCompositeOp:
2026  {
2027  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2028  {
2029  pixel=Dc;
2030  break;
2031  }
2032  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
2033  {
2034  pixel=Sc;
2035  break;
2036  }
2037  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
2038  &hue,&chroma,&luma);
2039  CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2040  &sans,&sans,&luma);
2041  HCLComposite(hue,chroma,luma,&red,&green,&blue);
2042  switch (channel)
2043  {
2044  case RedPixelChannel: pixel=red; break;
2045  case GreenPixelChannel: pixel=green; break;
2046  case BluePixelChannel: pixel=blue; break;
2047  default: pixel=Dc; break;
2048  }
2049  break;
2050  }
2052  {
2053  /*
2054  'Mathematics' a free form user control mathematical composition
2055  is defined as...
2056 
2057  f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
2058 
2059  Where the arguments A,B,C,D are (currently) passed to composite
2060  as a command separated 'geometry' string in "compose:args" image
2061  artifact.
2062 
2063  A = a->rho, B = a->sigma, C = a->xi, D = a->psi
2064 
2065  Applying the SVG transparency formula (see above), we get...
2066 
2067  Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
2068 
2069  Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
2070  Dca*(1.0-Sa)
2071  */
2072  pixel=QuantumRange*gamma*(geometry_info.rho*Sca*Dca+
2073  geometry_info.sigma*Sca*Da+geometry_info.xi*Dca*Sa+
2074  geometry_info.psi*Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2075  break;
2076  }
2077  case MinusDstCompositeOp:
2078  {
2079  pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2080  break;
2081  }
2082  case MinusSrcCompositeOp:
2083  {
2084  /*
2085  Minus source from canvas.
2086 
2087  f(Sc,Dc) = Sc - Dc
2088  */
2089  pixel=gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2090  break;
2091  }
2092  case ModulateCompositeOp:
2093  {
2094  ssize_t
2095  offset;
2096 
2097  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2098  {
2099  pixel=Dc;
2100  break;
2101  }
2102  offset=(ssize_t) (GetPixelIntensity(source_image,p)-midpoint);
2103  if (offset == 0)
2104  {
2105  pixel=Dc;
2106  break;
2107  }
2108  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
2109  &hue,&chroma,&luma);
2110  luma+=(0.01*percent_luma*offset)/midpoint;
2111  chroma*=0.01*percent_chroma;
2112  HCLComposite(hue,chroma,luma,&red,&green,&blue);
2113  switch (channel)
2114  {
2115  case RedPixelChannel: pixel=red; break;
2116  case GreenPixelChannel: pixel=green; break;
2117  case BluePixelChannel: pixel=blue; break;
2118  default: pixel=Dc; break;
2119  }
2120  break;
2121  }
2122  case ModulusAddCompositeOp:
2123  {
2124  pixel=Sc+Dc;
2125  while (pixel > QuantumRange)
2126  pixel-=QuantumRange;
2127  while (pixel < 0.0)
2128  pixel+=QuantumRange;
2129  pixel=(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2130  break;
2131  }
2133  {
2134  pixel=Sc-Dc;
2135  while (pixel > QuantumRange)
2136  pixel-=QuantumRange;
2137  while (pixel < 0.0)
2138  pixel+=QuantumRange;
2139  pixel=(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2140  break;
2141  }
2142  case MultiplyCompositeOp:
2143  {
2144  pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2145  break;
2146  }
2147  case OutCompositeOp:
2148  case SrcOutCompositeOp:
2149  {
2150  pixel=QuantumRange*(Sca*(1.0-Da));
2151  break;
2152  }
2153  case OverCompositeOp:
2154  case SrcOverCompositeOp:
2155  {
2156  pixel=QuantumRange*gamma*(Sca+Dca*(1.0-Sa));
2157  break;
2158  }
2159  case OverlayCompositeOp:
2160  {
2161  if ((2.0*Dca) < Da)
2162  {
2163  pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*(1.0-
2164  Da));
2165  break;
2166  }
2167  pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2168  Sca*(1.0-Da));
2169  break;
2170  }
2172  {
2173  /*
2174  PegTop: A Soft-Light alternative: A continuous version of the
2175  Softlight function, producing very similar results.
2176 
2177  f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2178 
2179  http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2180  */
2181  if (fabs((double) Da) < MagickEpsilon)
2182  {
2183  pixel=QuantumRange*gamma*(Sca);
2184  break;
2185  }
2186  pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2187  Da)+Dca*(1.0-Sa));
2188  break;
2189  }
2190  case PinLightCompositeOp:
2191  {
2192  /*
2193  PinLight: A Photoshop 7 composition method
2194  http://www.simplefilter.de/en/basics/mixmods.html
2195 
2196  f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2197  */
2198  if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2199  {
2200  pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2201  break;
2202  }
2203  if ((Dca*Sa) > (2.0*Sca*Da))
2204  {
2205  pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2206  break;
2207  }
2208  pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2209  break;
2210  }
2211  case PlusCompositeOp:
2212  {
2213  pixel=QuantumRange*(Sca+Dca);
2214  break;
2215  }
2216  case SaturateCompositeOp:
2217  {
2218  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2219  {
2220  pixel=Dc;
2221  break;
2222  }
2223  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
2224  {
2225  pixel=Sc;
2226  break;
2227  }
2228  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
2229  &hue,&chroma,&luma);
2230  CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2231  &sans,&chroma,&sans);
2232  HCLComposite(hue,chroma,luma,&red,&green,&blue);
2233  switch (channel)
2234  {
2235  case RedPixelChannel: pixel=red; break;
2236  case GreenPixelChannel: pixel=green; break;
2237  case BluePixelChannel: pixel=blue; break;
2238  default: pixel=Dc; break;
2239  }
2240  break;
2241  }
2242  case ScreenCompositeOp:
2243  {
2244  /*
2245  Screen: a negated multiply:
2246 
2247  f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2248  */
2249  pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2250  break;
2251  }
2252  case SoftLightCompositeOp:
2253  {
2254  if ((2.0*Sca) < Sa)
2255  {
2256  pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2257  Sca*(1.0-Da)+Dca*(1.0-Sa));
2258  break;
2259  }
2260  if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2261  {
2262  pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2263  (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2264  Dca*(1.0-Sa));
2265  break;
2266  }
2267  pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2268  (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2269  break;
2270  }
2271  case StereoCompositeOp:
2272  {
2273  if (channel == RedPixelChannel)
2274  pixel=(MagickRealType) GetPixelRed(source_image,p);
2275  break;
2276  }
2277  case ThresholdCompositeOp:
2278  {
2280  delta;
2281 
2282  delta=Sc-Dc;
2283  if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2284  {
2285  pixel=gamma*Dc;
2286  break;
2287  }
2288  pixel=gamma*(Dc+delta*amount);
2289  break;
2290  }
2291  case VividLightCompositeOp:
2292  {
2293  /*
2294  VividLight: A Photoshop 7 composition method. See
2295  http://www.simplefilter.de/en/basics/mixmods.html.
2296 
2297  f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2298  */
2299  if ((fabs((double) Sa) < MagickEpsilon) ||
2300  (fabs((double) (Sca-Sa)) < MagickEpsilon))
2301  {
2302  pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2303  break;
2304  }
2305  if ((2.0*Sca) <= Sa)
2306  {
2307  pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2308  (1.0-Da)+Dca*(1.0-Sa));
2309  break;
2310  }
2311  pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+Dca*
2312  (1.0-Sa));
2313  break;
2314  }
2315  case XorCompositeOp:
2316  {
2317  pixel=QuantumRange*(Sca*(1.0-Da)+Dca*(1.0-Sa));
2318  break;
2319  }
2320  default:
2321  {
2322  pixel=Sc;
2323  break;
2324  }
2325  }
2326  q[i]=clamp != MagickFalse ? ClampPixel(pixel) : ClampToQuantum(pixel);
2327  }
2328  p+=GetPixelChannels(source_image);
2329  channels=GetPixelChannels(source_image);
2330  if (p >= (pixels+channels*source_image->columns))
2331  p=pixels;
2332  q+=GetPixelChannels(image);
2333  }
2334  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2335  status=MagickFalse;
2336  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2337  {
2339  proceed;
2340 
2341 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2342  #pragma omp critical (MagickCore_CompositeImage)
2343 #endif
2344  proceed=SetImageProgress(image,CompositeImageTag,progress++,
2345  image->rows);
2346  if (proceed == MagickFalse)
2347  status=MagickFalse;
2348  }
2349  }
2350  source_view=DestroyCacheView(source_view);
2351  image_view=DestroyCacheView(image_view);
2352  if (canvas_image != (Image * ) NULL)
2353  canvas_image=DestroyImage(canvas_image);
2354  else
2355  source_image=DestroyImage(source_image);
2356  return(status);
2357 }
2358 
2359 /*
2360 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2361 % %
2362 % %
2363 % %
2364 % T e x t u r e I m a g e %
2365 % %
2366 % %
2367 % %
2368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2369 %
2370 % TextureImage() repeatedly tiles the texture image across and down the image
2371 % canvas.
2372 %
2373 % The format of the TextureImage method is:
2374 %
2375 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2376 % ExceptionInfo *exception)
2377 %
2378 % A description of each parameter follows:
2379 %
2380 % o image: the image.
2381 %
2382 % o texture_image: This image is the texture to layer on the background.
2383 %
2384 */
2386  ExceptionInfo *exception)
2387 {
2388 #define TextureImageTag "Texture/Image"
2389 
2390  CacheView
2391  *image_view,
2392  *texture_view;
2393 
2394  Image
2395  *texture_image;
2396 
2398  status;
2399 
2400  ssize_t
2401  y;
2402 
2403  assert(image != (Image *) NULL);
2404  if (image->debug != MagickFalse)
2405  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2406  assert(image->signature == MagickCoreSignature);
2407  if (texture == (const Image *) NULL)
2408  return(MagickFalse);
2409  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2410  return(MagickFalse);
2411  texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2412  if (texture_image == (const Image *) NULL)
2413  return(MagickFalse);
2414  (void) TransformImageColorspace(texture_image,image->colorspace,exception);
2416  exception);
2417  status=MagickTrue;
2418  if ((image->compose != CopyCompositeOp) &&
2419  ((image->compose != OverCompositeOp) ||
2420  (image->alpha_trait != UndefinedPixelTrait) ||
2421  (texture_image->alpha_trait != UndefinedPixelTrait)))
2422  {
2423  /*
2424  Tile texture onto the image background.
2425  */
2426  for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2427  {
2428  register ssize_t
2429  x;
2430 
2431  if (status == MagickFalse)
2432  continue;
2433  for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2434  {
2436  thread_status;
2437 
2438  thread_status=CompositeImage(image,texture_image,image->compose,
2439  MagickTrue,x+texture_image->tile_offset.x,y+
2440  texture_image->tile_offset.y,exception);
2441  if (thread_status == MagickFalse)
2442  {
2443  status=thread_status;
2444  break;
2445  }
2446  }
2447  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2448  {
2450  proceed;
2451 
2453  image->rows);
2454  if (proceed == MagickFalse)
2455  status=MagickFalse;
2456  }
2457  }
2459  image->rows,image->rows);
2460  texture_image=DestroyImage(texture_image);
2461  return(status);
2462  }
2463  /*
2464  Tile texture onto the image background (optimized).
2465  */
2466  status=MagickTrue;
2467  texture_view=AcquireVirtualCacheView(texture_image,exception);
2468  image_view=AcquireAuthenticCacheView(image,exception);
2469 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2470  #pragma omp parallel for schedule(static,4) shared(status) \
2471  magick_number_threads(texture_image,image,image->rows,1)
2472 #endif
2473  for (y=0; y < (ssize_t) image->rows; y++)
2474  {
2476  sync;
2477 
2478  register const Quantum
2479  *p,
2480  *pixels;
2481 
2482  register ssize_t
2483  x;
2484 
2485  register Quantum
2486  *q;
2487 
2488  size_t
2489  width;
2490 
2491  if (status == MagickFalse)
2492  continue;
2493  pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2494  (y+texture_image->tile_offset.y) % texture_image->rows,
2495  texture_image->columns,1,exception);
2496  q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2497  if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2498  {
2499  status=MagickFalse;
2500  continue;
2501  }
2502  for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2503  {
2504  register ssize_t
2505  j;
2506 
2507  p=pixels;
2508  width=texture_image->columns;
2509  if ((x+(ssize_t) width) > (ssize_t) image->columns)
2510  width=image->columns-x;
2511  for (j=0; j < (ssize_t) width; j++)
2512  {
2513  register ssize_t
2514  i;
2515 
2516  if (GetPixelWriteMask(image,q) <= (QuantumRange/2))
2517  {
2518  p+=GetPixelChannels(texture_image);
2519  q+=GetPixelChannels(image);
2520  continue;
2521  }
2522  for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2523  {
2524  PixelChannel channel = GetPixelChannelChannel(texture_image,i);
2525  PixelTrait traits = GetPixelChannelTraits(image,channel);
2526  PixelTrait texture_traits=GetPixelChannelTraits(texture_image,
2527  channel);
2528  if ((traits == UndefinedPixelTrait) ||
2529  (texture_traits == UndefinedPixelTrait))
2530  continue;
2531  SetPixelChannel(image,channel,p[i],q);
2532  }
2533  p+=GetPixelChannels(texture_image);
2534  q+=GetPixelChannels(image);
2535  }
2536  }
2537  sync=SyncCacheViewAuthenticPixels(image_view,exception);
2538  if (sync == MagickFalse)
2539  status=MagickFalse;
2540  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2541  {
2543  proceed;
2544 
2546  image->rows);
2547  if (proceed == MagickFalse)
2548  status=MagickFalse;
2549  }
2550  }
2551  texture_view=DestroyCacheView(texture_view);
2552  image_view=DestroyCacheView(image_view);
2553  texture_image=DestroyImage(texture_image);
2554  return(status);
2555 }
double psi
Definition: geometry.h:105
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:2385
MagickDoubleType MagickRealType
Definition: magick-type.h:118
MagickExport CacheView * DestroyCacheView(CacheView *cache_view)
Definition: cache-view.c:252
#define TransparentAlpha
Definition: image.h:26
double x2
Definition: image.h:107
static MagickBooleanType SetImageProgress(const Image *image, const char *tag, const MagickOffsetType offset, const MagickSizeType extent)
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:1273
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:105
MagickExport void SetGeometryInfo(GeometryInfo *geometry_info)
Definition: geometry.c:1605
#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:188
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:1875
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:5460
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:188
#define MagickEpsilon
Definition: magick-type.h:110
double sigma
Definition: geometry.h:105
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:539
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:127
MagickExport void GetPixelInfo(const Image *image, PixelInfo *pixel)
Definition: pixel.c:2161
Definition: image.h:151
double x
Definition: geometry.h:122
#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:966
MagickBooleanType
Definition: magick-type.h:156
unsigned int MagickStatusType
Definition: magick-type.h:119
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 Quantum GetPixelWriteMask(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
static double DegreesToRadians(const double degrees)
Definition: image-private.h:56
double y
Definition: geometry.h:122
static Quantum GetPixelGreen(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
MagickExport MagickBooleanType IsStringTrue(const char *value)
Definition: string.c:1464
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:188
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:3315
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:1058
MagickExport MagickBooleanType LogMagickEvent(const LogEventType type, const char *module, const char *function, const size_t line, const char *format,...)
Definition: log.c:1397
size_t signature
Definition: image.h:354
size_t columns
Definition: image.h:172
#define QuantumScale
Definition: magick-type.h:113
ssize_t x
Definition: geometry.h:133
MagickBooleanType(* MagickProgressMonitor)(const char *, const MagickOffsetType, const MagickSizeType, void *)
Definition: monitor.h:26
MagickExport ResampleFilter * DestroyResampleFilter(ResampleFilter *resample_filter)
Definition: resample.c:262
MagickExport MagickBooleanType SetImageStorageClass(Image *image, const ClassType storage_class, ExceptionInfo *exception)
Definition: image.c:2508
PixelChannel
Definition: pixel.h:66
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:5937
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:105
MagickExport MagickBooleanType SetImageColorspace(Image *image, const ColorspaceType colorspace, ExceptionInfo *exception)
Definition: colorspace.c:1081
MagickExport MagickStatusType ParseGeometry(const char *geometry, GeometryInfo *geometry_info)
Definition: geometry.c:836
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:188
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:133
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:132
MagickExport MagickRealType GetPixelIntensity(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
Definition: pixel.c:2355
MagickExport Image * DestroyImage(Image *image)
Definition: image.c:1182
MagickExport Image * CloneImage(const Image *image, const size_t columns, const size_t rows, const MagickBooleanType detach, ExceptionInfo *exception)
Definition: image.c:799
ColorspaceType colorspace
Definition: image.h:157
#define QuantumRange
Definition: magick-type.h:83
MagickBooleanType debug
Definition: image.h:334