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 - 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  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]=ClampToQuantum(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) 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) 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  status=InterpolatePixelInfo(image,image_view,
1114  UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1115  &pixel,exception);
1116  if (status == MagickFalse)
1117  break;
1118  /*
1119  Mask with the 'invalid pixel mask' in alpha channel.
1120  */
1122  (QuantumScale*GetPixelAlpha(source_image,p));
1123  SetPixelViaPixelInfo(canvas_image,&pixel,q);
1124  p+=GetPixelChannels(source_image);
1125  q+=GetPixelChannels(canvas_image);
1126  }
1127  if (x < (ssize_t) source_image->columns)
1128  break;
1129  sync=SyncCacheViewAuthenticPixels(canvas_view,exception);
1130  if (sync == MagickFalse)
1131  break;
1132  }
1133  canvas_view=DestroyCacheView(canvas_view);
1134  source_view=DestroyCacheView(source_view);
1135  image_view=DestroyCacheView(image_view);
1136  source_image=DestroyImage(source_image);
1137  source_image=canvas_image;
1138  break;
1139  }
1140  case DissolveCompositeOp:
1141  {
1142  /*
1143  Geometry arguments to dissolve factors.
1144  */
1145  value=GetImageArtifact(image,"compose:args");
1146  if (value != (char *) NULL)
1147  {
1148  flags=ParseGeometry(value,&geometry_info);
1149  source_dissolve=geometry_info.rho/100.0;
1150  canvas_dissolve=1.0;
1151  if ((source_dissolve-MagickEpsilon) < 0.0)
1152  source_dissolve=0.0;
1153  if ((source_dissolve+MagickEpsilon) > 1.0)
1154  {
1155  canvas_dissolve=2.0-source_dissolve;
1156  source_dissolve=1.0;
1157  }
1158  if ((flags & SigmaValue) != 0)
1159  canvas_dissolve=geometry_info.sigma/100.0;
1160  if ((canvas_dissolve-MagickEpsilon) < 0.0)
1161  canvas_dissolve=0.0;
1162  }
1163  break;
1164  }
1165  case BlendCompositeOp:
1166  {
1167  value=GetImageArtifact(image,"compose:args");
1168  if (value != (char *) NULL)
1169  {
1170  flags=ParseGeometry(value,&geometry_info);
1171  source_dissolve=geometry_info.rho/100.0;
1172  canvas_dissolve=1.0-source_dissolve;
1173  if ((flags & SigmaValue) != 0)
1174  canvas_dissolve=geometry_info.sigma/100.0;
1175  }
1176  break;
1177  }
1179  {
1180  /*
1181  Just collect the values from "compose:args", setting.
1182  Unused values are set to zero automagically.
1183 
1184  Arguments are normally a comma separated list, so this probably should
1185  be changed to some 'general comma list' parser, (with a minimum
1186  number of values)
1187  */
1188  SetGeometryInfo(&geometry_info);
1189  value=GetImageArtifact(image,"compose:args");
1190  if (value != (char *) NULL)
1191  (void) ParseGeometry(value,&geometry_info);
1192  break;
1193  }
1194  case ModulateCompositeOp:
1195  {
1196  /*
1197  Determine the luma and chroma scale.
1198  */
1199  value=GetImageArtifact(image,"compose:args");
1200  if (value != (char *) NULL)
1201  {
1202  flags=ParseGeometry(value,&geometry_info);
1203  percent_luma=geometry_info.rho;
1204  if ((flags & SigmaValue) != 0)
1205  percent_chroma=geometry_info.sigma;
1206  }
1207  break;
1208  }
1209  case ThresholdCompositeOp:
1210  {
1211  /*
1212  Determine the amount and threshold.
1213  */
1214  value=GetImageArtifact(image,"compose:args");
1215  if (value != (char *) NULL)
1216  {
1217  flags=ParseGeometry(value,&geometry_info);
1218  amount=geometry_info.rho;
1219  threshold=geometry_info.sigma;
1220  if ((flags & SigmaValue) == 0)
1221  threshold=0.05f;
1222  }
1223  threshold*=QuantumRange;
1224  break;
1225  }
1226  default:
1227  break;
1228  }
1229  /*
1230  Composite image.
1231  */
1232  status=MagickTrue;
1233  progress=0;
1234  midpoint=((MagickRealType) QuantumRange+1.0)/2;
1235  source_view=AcquireVirtualCacheView(source_image,exception);
1236  image_view=AcquireAuthenticCacheView(image,exception);
1237 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1238  #pragma omp parallel for schedule(static) shared(progress,status) \
1239  magick_number_threads(source_image,image,image->rows,1)
1240 #endif
1241  for (y=0; y < (ssize_t) image->rows; y++)
1242  {
1243  const Quantum
1244  *pixels;
1245 
1247  blue,
1248  chroma,
1249  green,
1250  hue,
1251  luma,
1252  red;
1253 
1254  PixelInfo
1255  canvas_pixel,
1256  source_pixel;
1257 
1258  register const Quantum
1259  *magick_restrict p;
1260 
1261  register Quantum
1262  *magick_restrict q;
1263 
1264  register ssize_t
1265  x;
1266 
1267  if (status == MagickFalse)
1268  continue;
1269  if (clip_to_self != MagickFalse)
1270  {
1271  if (y < y_offset)
1272  continue;
1273  if ((y-y_offset) >= (ssize_t) source_image->rows)
1274  continue;
1275  }
1276  /*
1277  If pixels is NULL, y is outside overlay region.
1278  */
1279  pixels=(Quantum *) NULL;
1280  p=(Quantum *) NULL;
1281  if ((y >= y_offset) && ((y-y_offset) < (ssize_t) source_image->rows))
1282  {
1283  p=GetCacheViewVirtualPixels(source_view,0,y-y_offset,
1284  source_image->columns,1,exception);
1285  if (p == (const Quantum *) NULL)
1286  {
1287  status=MagickFalse;
1288  continue;
1289  }
1290  pixels=p;
1291  if (x_offset < 0)
1292  p-=x_offset*GetPixelChannels(source_image);
1293  }
1294  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1295  if (q == (Quantum *) NULL)
1296  {
1297  status=MagickFalse;
1298  continue;
1299  }
1300  hue=0.0;
1301  chroma=0.0;
1302  luma=0.0;
1303  GetPixelInfo(image,&canvas_pixel);
1304  GetPixelInfo(source_image,&source_pixel);
1305  for (x=0; x < (ssize_t) image->columns; x++)
1306  {
1307  double
1308  gamma;
1309 
1311  alpha,
1312  Da,
1313  Dc,
1314  Dca,
1315  DcaDa,
1316  Sa,
1317  SaSca,
1318  Sc,
1319  Sca;
1320 
1321  register ssize_t
1322  i;
1323 
1324  size_t
1325  channels;
1326 
1327  if (clip_to_self != MagickFalse)
1328  {
1329  if (x < x_offset)
1330  {
1331  q+=GetPixelChannels(image);
1332  continue;
1333  }
1334  if ((x-x_offset) >= (ssize_t) source_image->columns)
1335  break;
1336  }
1337  if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1338  ((x-x_offset) >= (ssize_t) source_image->columns))
1339  {
1340  Quantum
1341  source[MaxPixelChannels];
1342 
1343  /*
1344  Virtual composite:
1345  Sc: source color.
1346  Dc: canvas color.
1347  */
1348  (void) GetOneVirtualPixel(source_image,x-x_offset,y-y_offset,source,
1349  exception);
1350  if (GetPixelWriteMask(image,q) <= (QuantumRange/2))
1351  {
1352  q+=GetPixelChannels(image);
1353  continue;
1354  }
1355  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1356  {
1358  pixel;
1359 
1360  PixelChannel channel = GetPixelChannelChannel(image,i);
1361  PixelTrait traits = GetPixelChannelTraits(image,channel);
1362  PixelTrait source_traits=GetPixelChannelTraits(source_image,
1363  channel);
1364  if ((traits == UndefinedPixelTrait) ||
1365  (source_traits == UndefinedPixelTrait))
1366  continue;
1367  switch (compose)
1368  {
1369  case AlphaCompositeOp:
1370  case ChangeMaskCompositeOp:
1371  case CopyAlphaCompositeOp:
1372  case DstAtopCompositeOp:
1373  case DstInCompositeOp:
1374  case InCompositeOp:
1375  case OutCompositeOp:
1376  case SrcInCompositeOp:
1377  case SrcOutCompositeOp:
1378  {
1379  if (channel == AlphaPixelChannel)
1381  else
1382  pixel=(MagickRealType) q[i];
1383  break;
1384  }
1385  case ClearCompositeOp:
1386  case CopyCompositeOp:
1387  case ReplaceCompositeOp:
1388  case SrcCompositeOp:
1389  {
1390  if (channel == AlphaPixelChannel)
1392  else
1393  pixel=0.0;
1394  break;
1395  }
1396  case BlendCompositeOp:
1397  case DissolveCompositeOp:
1398  {
1399  if (channel == AlphaPixelChannel)
1400  pixel=canvas_dissolve*GetPixelAlpha(source_image,source);
1401  else
1402  pixel=(MagickRealType) source[channel];
1403  break;
1404  }
1405  default:
1406  {
1407  pixel=(MagickRealType) source[channel];
1408  break;
1409  }
1410  }
1411  q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
1412  ClampToQuantum(pixel);
1413  }
1414  q+=GetPixelChannels(image);
1415  continue;
1416  }
1417  /*
1418  Authentic composite:
1419  Sa: normalized source alpha.
1420  Da: normalized canvas alpha.
1421  */
1422  Sa=QuantumScale*GetPixelAlpha(source_image,p);
1423  Da=QuantumScale*GetPixelAlpha(image,q);
1424  switch (compose)
1425  {
1426  case BumpmapCompositeOp:
1427  {
1428  alpha=GetPixelIntensity(source_image,p)*Sa;
1429  break;
1430  }
1431  case ColorBurnCompositeOp:
1432  case ColorDodgeCompositeOp:
1433  case DarkenCompositeOp:
1434  case DifferenceCompositeOp:
1435  case DivideDstCompositeOp:
1436  case DivideSrcCompositeOp:
1437  case ExclusionCompositeOp:
1438  case HardLightCompositeOp:
1439  case HardMixCompositeOp:
1440  case LinearBurnCompositeOp:
1443  case LightenCompositeOp:
1445  case MinusDstCompositeOp:
1446  case MinusSrcCompositeOp:
1447  case ModulusAddCompositeOp:
1449  case MultiplyCompositeOp:
1450  case OverlayCompositeOp:
1452  case PinLightCompositeOp:
1453  case ScreenCompositeOp:
1454  case SoftLightCompositeOp:
1455  case VividLightCompositeOp:
1456  {
1457  alpha=RoundToUnity(Sa+Da-Sa*Da);
1458  break;
1459  }
1460  case DstAtopCompositeOp:
1461  case DstInCompositeOp:
1462  case InCompositeOp:
1463  case SrcInCompositeOp:
1464  {
1465  alpha=Sa*Da;
1466  break;
1467  }
1468  case DissolveCompositeOp:
1469  {
1470  alpha=source_dissolve*Sa*(-canvas_dissolve*Da)+source_dissolve*Sa+
1471  canvas_dissolve*Da;
1472  break;
1473  }
1474  case DstOverCompositeOp:
1475  case OverCompositeOp:
1476  case SrcOverCompositeOp:
1477  {
1478  alpha=Sa+Da-Sa*Da;
1479  break;
1480  }
1481  case DstOutCompositeOp:
1482  {
1483  alpha=Da*(1.0-Sa);
1484  break;
1485  }
1486  case OutCompositeOp:
1487  case SrcOutCompositeOp:
1488  {
1489  alpha=Sa*(1.0-Da);
1490  break;
1491  }
1492  case BlendCompositeOp:
1493  case PlusCompositeOp:
1494  {
1495  alpha=RoundToUnity(source_dissolve*Sa+canvas_dissolve*Da);
1496  break;
1497  }
1498  case XorCompositeOp:
1499  {
1500  alpha=Sa+Da-2.0*Sa*Da;
1501  break;
1502  }
1503  default:
1504  {
1505  alpha=1.0;
1506  break;
1507  }
1508  }
1509  if (GetPixelWriteMask(image,q) <= (QuantumRange/2))
1510  {
1511  p+=GetPixelChannels(source_image);
1512  q+=GetPixelChannels(image);
1513  continue;
1514  }
1515  switch (compose)
1516  {
1517  case ColorizeCompositeOp:
1518  case HueCompositeOp:
1519  case LuminizeCompositeOp:
1520  case ModulateCompositeOp:
1521  case SaturateCompositeOp:
1522  {
1523  GetPixelInfoPixel(source_image,p,&source_pixel);
1524  GetPixelInfoPixel(image,q,&canvas_pixel);
1525  break;
1526  }
1527  default:
1528  break;
1529  }
1530  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1531  {
1533  pixel,
1534  sans;
1535 
1536  PixelChannel channel = GetPixelChannelChannel(image,i);
1537  PixelTrait traits = GetPixelChannelTraits(image,channel);
1538  PixelTrait source_traits=GetPixelChannelTraits(source_image,channel);
1539  if (traits == UndefinedPixelTrait)
1540  continue;
1541  if (channel == AlphaPixelChannel)
1542  {
1543  /*
1544  Set alpha channel.
1545  */
1546  switch (compose)
1547  {
1548  case AlphaCompositeOp:
1549  {
1550  pixel=QuantumRange*Sa;
1551  break;
1552  }
1553  case AtopCompositeOp:
1554  case CopyBlackCompositeOp:
1555  case CopyBlueCompositeOp:
1556  case CopyCyanCompositeOp:
1557  case CopyGreenCompositeOp:
1559  case CopyRedCompositeOp:
1560  case CopyYellowCompositeOp:
1561  case SrcAtopCompositeOp:
1562  case DstCompositeOp:
1563  case NoCompositeOp:
1564  {
1565  pixel=QuantumRange*Da;
1566  break;
1567  }
1568  case ChangeMaskCompositeOp:
1569  {
1571  equivalent;
1572 
1573  if (Da < 0.5)
1574  {
1576  break;
1577  }
1578  equivalent=IsFuzzyEquivalencePixel(source_image,p,image,q);
1579  if (equivalent != MagickFalse)
1581  else
1582  pixel=(MagickRealType) OpaqueAlpha;
1583  break;
1584  }
1585  case ClearCompositeOp:
1586  {
1588  break;
1589  }
1590  case ColorizeCompositeOp:
1591  case HueCompositeOp:
1592  case LuminizeCompositeOp:
1593  case SaturateCompositeOp:
1594  {
1595  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1596  {
1597  pixel=QuantumRange*Da;
1598  break;
1599  }
1600  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
1601  {
1602  pixel=QuantumRange*Sa;
1603  break;
1604  }
1605  if (Sa < Da)
1606  {
1607  pixel=QuantumRange*Da;
1608  break;
1609  }
1610  pixel=QuantumRange*Sa;
1611  break;
1612  }
1613  case CopyAlphaCompositeOp:
1614  {
1615  if (source_image->alpha_trait == UndefinedPixelTrait)
1616  pixel=GetPixelIntensity(source_image,p);
1617  else
1618  pixel=QuantumRange*Sa;
1619  break;
1620  }
1621  case CopyCompositeOp:
1622  case DisplaceCompositeOp:
1623  case DistortCompositeOp:
1624  case DstAtopCompositeOp:
1625  case ReplaceCompositeOp:
1626  case SrcCompositeOp:
1627  {
1628  pixel=QuantumRange*Sa;
1629  break;
1630  }
1632  {
1633  pixel=Sa*GetPixelIntensity(source_image,p) <
1634  Da*GetPixelIntensity(image,q) ? Sa : Da;
1635  break;
1636  }
1638  {
1639  pixel=Sa*GetPixelIntensity(source_image,p) >
1640  Da*GetPixelIntensity(image,q) ? Sa : Da;
1641  break;
1642  }
1643  case ModulateCompositeOp:
1644  {
1645  pixel=QuantumRange*Da;
1646  break;
1647  }
1648  case MultiplyCompositeOp:
1649  {
1650  pixel=QuantumRange*Sa*Da;
1651  break;
1652  }
1653  default:
1654  {
1655  pixel=QuantumRange*alpha;
1656  break;
1657  }
1658  }
1659  q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
1660  ClampToQuantum(pixel);
1661  continue;
1662  }
1663  if (source_traits == UndefinedPixelTrait)
1664  continue;
1665  /*
1666  Sc: source color.
1667  Dc: canvas color.
1668  */
1669  Sc=(MagickRealType) GetPixelChannel(source_image,channel,p);
1670  Dc=(MagickRealType) q[i];
1671  if ((traits & CopyPixelTrait) != 0)
1672  {
1673  /*
1674  Copy channel.
1675  */
1676  q[i]=ClampToQuantum(Dc);
1677  continue;
1678  }
1679  /*
1680  Porter-Duff compositions:
1681  Sca: source normalized color multiplied by alpha.
1682  Dca: normalized canvas color multiplied by alpha.
1683  */
1684  Sca=QuantumScale*Sa*Sc;
1685  Dca=QuantumScale*Da*Dc;
1686  SaSca=Sa*PerceptibleReciprocal(Sca);
1687  DcaDa=Dca*PerceptibleReciprocal(Da);
1688  switch (compose)
1689  {
1690  case DarkenCompositeOp:
1691  case LightenCompositeOp:
1693  {
1694  gamma=PerceptibleReciprocal(1.0-alpha);
1695  break;
1696  }
1697  default:
1698  {
1699  gamma=PerceptibleReciprocal(alpha);
1700  break;
1701  }
1702  }
1703  pixel=Dc;
1704  switch (compose)
1705  {
1706  case AlphaCompositeOp:
1707  {
1708  pixel=QuantumRange*Sa;
1709  break;
1710  }
1711  case AtopCompositeOp:
1712  case SrcAtopCompositeOp:
1713  {
1714  pixel=QuantumRange*(Sca*Da+Dca*(1.0-Sa));
1715  break;
1716  }
1717  case BlendCompositeOp:
1718  {
1719  pixel=gamma*(source_dissolve*Sa*Sc+canvas_dissolve*Da*Dc);
1720  break;
1721  }
1722  case BlurCompositeOp:
1723  case CopyCompositeOp:
1724  case ReplaceCompositeOp:
1725  case SrcCompositeOp:
1726  {
1727  pixel=QuantumRange*Sca;
1728  break;
1729  }
1730  case DisplaceCompositeOp:
1731  case DistortCompositeOp:
1732  {
1733  pixel=Sc;
1734  break;
1735  }
1736  case BumpmapCompositeOp:
1737  {
1738  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1739  {
1740  pixel=Dc;
1741  break;
1742  }
1743  pixel=QuantumScale*GetPixelIntensity(source_image,p)*Dc;
1744  break;
1745  }
1746  case ChangeMaskCompositeOp:
1747  {
1748  pixel=Dc;
1749  break;
1750  }
1751  case ClearCompositeOp:
1752  {
1753  pixel=0.0;
1754  break;
1755  }
1756  case ColorBurnCompositeOp:
1757  {
1758  if ((Sca == 0.0) && (Dca == Da))
1759  {
1760  pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1761  break;
1762  }
1763  if (Sca == 0.0)
1764  {
1765  pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1766  break;
1767  }
1768  pixel=QuantumRange*gamma*(Sa*Da-Sa*Da*MagickMin(1.0,(1.0-DcaDa)*
1769  SaSca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
1770  break;
1771  }
1772  case ColorDodgeCompositeOp:
1773  {
1774  if ((Sca*Da+Dca*Sa) >= Sa*Da)
1775  pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1776  else
1777  pixel=QuantumRange*gamma*(Dca*Sa*Sa*PerceptibleReciprocal(Sa-Sca)+
1778  Sca*(1.0-Da)+Dca*(1.0-Sa));
1779  break;
1780  }
1781  case ColorizeCompositeOp:
1782  {
1783  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1784  {
1785  pixel=Dc;
1786  break;
1787  }
1788  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
1789  {
1790  pixel=Sc;
1791  break;
1792  }
1793  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
1794  &sans,&sans,&luma);
1795  CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1796  &hue,&chroma,&sans);
1797  HCLComposite(hue,chroma,luma,&red,&green,&blue);
1798  switch (channel)
1799  {
1800  case RedPixelChannel: pixel=red; break;
1801  case GreenPixelChannel: pixel=green; break;
1802  case BluePixelChannel: pixel=blue; break;
1803  default: pixel=Dc; break;
1804  }
1805  break;
1806  }
1807  case CopyAlphaCompositeOp:
1808  {
1809  pixel=Dc;
1810  break;
1811  }
1812  case CopyBlackCompositeOp:
1813  {
1814  if (channel == BlackPixelChannel)
1815  pixel=(MagickRealType) (QuantumRange-
1816  GetPixelBlack(source_image,p));
1817  break;
1818  }
1819  case CopyBlueCompositeOp:
1820  case CopyYellowCompositeOp:
1821  {
1822  if (channel == BluePixelChannel)
1823  pixel=(MagickRealType) GetPixelBlue(source_image,p);
1824  break;
1825  }
1826  case CopyGreenCompositeOp:
1828  {
1829  if (channel == GreenPixelChannel)
1830  pixel=(MagickRealType) GetPixelGreen(source_image,p);
1831  break;
1832  }
1833  case CopyRedCompositeOp:
1834  case CopyCyanCompositeOp:
1835  {
1836  if (channel == RedPixelChannel)
1837  pixel=(MagickRealType) GetPixelRed(source_image,p);
1838  break;
1839  }
1840  case DarkenCompositeOp:
1841  {
1842  /*
1843  Darken is equivalent to a 'Minimum' method
1844  OR a greyscale version of a binary 'Or'
1845  OR the 'Intersection' of pixel sets.
1846  */
1847  if ((Sca*Da) < (Dca*Sa))
1848  {
1849  pixel=QuantumRange*(Sca+Dca*(1.0-Sa));
1850  break;
1851  }
1852  pixel=QuantumRange*(Dca+Sca*(1.0-Da));
1853  break;
1854  }
1856  {
1857  pixel=Sa*GetPixelIntensity(source_image,p) <
1858  Da*GetPixelIntensity(image,q) ? Sc : Dc;
1859  break;
1860  }
1861  case DifferenceCompositeOp:
1862  {
1863  pixel=QuantumRange*gamma*(Sca+Dca-2.0*MagickMin(Sca*Da,Dca*Sa));
1864  break;
1865  }
1866  case DissolveCompositeOp:
1867  {
1868  pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1869  canvas_dissolve*Da*Dc+canvas_dissolve*Da*Dc);
1870  break;
1871  }
1872  case DivideDstCompositeOp:
1873  {
1874  if ((fabs((double) Sca) < MagickEpsilon) &&
1875  (fabs((double) Dca) < MagickEpsilon))
1876  {
1877  pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1878  break;
1879  }
1880  if (fabs((double) Dca) < MagickEpsilon)
1881  {
1882  pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1883  break;
1884  }
1885  pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1886  break;
1887  }
1888  case DivideSrcCompositeOp:
1889  {
1890  if ((fabs((double) Dca) < MagickEpsilon) &&
1891  (fabs((double) Sca) < MagickEpsilon))
1892  {
1893  pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1894  break;
1895  }
1896  if (fabs((double) Sca) < MagickEpsilon)
1897  {
1898  pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1899  break;
1900  }
1901  pixel=QuantumRange*gamma*(Dca*Sa*SaSca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1902  break;
1903  }
1904  case DstAtopCompositeOp:
1905  {
1906  pixel=QuantumRange*(Dca*Sa+Sca*(1.0-Da));
1907  break;
1908  }
1909  case DstCompositeOp:
1910  case NoCompositeOp:
1911  {
1912  pixel=QuantumRange*Dca;
1913  break;
1914  }
1915  case DstInCompositeOp:
1916  {
1917  pixel=QuantumRange*(Dca*Sa);
1918  break;
1919  }
1920  case DstOutCompositeOp:
1921  {
1922  pixel=QuantumRange*(Dca*(1.0-Sa));
1923  break;
1924  }
1925  case DstOverCompositeOp:
1926  {
1927  pixel=QuantumRange*gamma*(Dca+Sca*(1.0-Da));
1928  break;
1929  }
1930  case ExclusionCompositeOp:
1931  {
1932  pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1933  Dca*(1.0-Sa));
1934  break;
1935  }
1936  case HardLightCompositeOp:
1937  {
1938  if ((2.0*Sca) < Sa)
1939  {
1940  pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-
1941  Sa));
1942  break;
1943  }
1944  pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1945  Dca*(1.0-Sa));
1946  break;
1947  }
1948  case HardMixCompositeOp:
1949  {
1950  pixel=gamma*(((Sca+Dca) < 1.0) ? 0.0 : QuantumRange);
1951  break;
1952  }
1953  case HueCompositeOp:
1954  {
1955  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1956  {
1957  pixel=Dc;
1958  break;
1959  }
1960  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
1961  {
1962  pixel=Sc;
1963  break;
1964  }
1965  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
1966  &hue,&chroma,&luma);
1967  CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1968  &hue,&sans,&sans);
1969  HCLComposite(hue,chroma,luma,&red,&green,&blue);
1970  switch (channel)
1971  {
1972  case RedPixelChannel: pixel=red; break;
1973  case GreenPixelChannel: pixel=green; break;
1974  case BluePixelChannel: pixel=blue; break;
1975  default: pixel=Dc; break;
1976  }
1977  break;
1978  }
1979  case InCompositeOp:
1980  case SrcInCompositeOp:
1981  {
1982  pixel=QuantumRange*(Sca*Da);
1983  break;
1984  }
1985  case LinearBurnCompositeOp:
1986  {
1987  /*
1988  LinearBurn: as defined by Abode Photoshop, according to
1989  http://www.simplefilter.de/en/basics/mixmods.html is:
1990 
1991  f(Sc,Dc) = Sc + Dc - 1
1992  */
1993  pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1994  break;
1995  }
1997  {
1998  pixel=gamma*(Sa*Sc+Da*Dc);
1999  break;
2000  }
2002  {
2003  /*
2004  LinearLight: as defined by Abode Photoshop, according to
2005  http://www.simplefilter.de/en/basics/mixmods.html is:
2006 
2007  f(Sc,Dc) = Dc + 2*Sc - 1
2008  */
2009  pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
2010  break;
2011  }
2012  case LightenCompositeOp:
2013  {
2014  if ((Sca*Da) > (Dca*Sa))
2015  {
2016  pixel=QuantumRange*(Sca+Dca*(1.0-Sa));
2017  break;
2018  }
2019  pixel=QuantumRange*(Dca+Sca*(1.0-Da));
2020  break;
2021  }
2023  {
2024  /*
2025  Lighten is equivalent to a 'Maximum' method
2026  OR a greyscale version of a binary 'And'
2027  OR the 'Union' of pixel sets.
2028  */
2029  pixel=Sa*GetPixelIntensity(source_image,p) >
2030  Da*GetPixelIntensity(image,q) ? Sc : Dc;
2031  break;
2032  }
2033  case LuminizeCompositeOp:
2034  {
2035  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2036  {
2037  pixel=Dc;
2038  break;
2039  }
2040  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
2041  {
2042  pixel=Sc;
2043  break;
2044  }
2045  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
2046  &hue,&chroma,&luma);
2047  CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2048  &sans,&sans,&luma);
2049  HCLComposite(hue,chroma,luma,&red,&green,&blue);
2050  switch (channel)
2051  {
2052  case RedPixelChannel: pixel=red; break;
2053  case GreenPixelChannel: pixel=green; break;
2054  case BluePixelChannel: pixel=blue; break;
2055  default: pixel=Dc; break;
2056  }
2057  break;
2058  }
2060  {
2061  /*
2062  'Mathematics' a free form user control mathematical composition
2063  is defined as...
2064 
2065  f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
2066 
2067  Where the arguments A,B,C,D are (currently) passed to composite
2068  as a command separated 'geometry' string in "compose:args" image
2069  artifact.
2070 
2071  A = a->rho, B = a->sigma, C = a->xi, D = a->psi
2072 
2073  Applying the SVG transparency formula (see above), we get...
2074 
2075  Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
2076 
2077  Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
2078  Dca*(1.0-Sa)
2079  */
2080  pixel=QuantumRange*gamma*(geometry_info.rho*Sca*Dca+
2081  geometry_info.sigma*Sca*Da+geometry_info.xi*Dca*Sa+
2082  geometry_info.psi*Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2083  break;
2084  }
2085  case MinusDstCompositeOp:
2086  {
2087  pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2088  break;
2089  }
2090  case MinusSrcCompositeOp:
2091  {
2092  /*
2093  Minus source from canvas.
2094 
2095  f(Sc,Dc) = Sc - Dc
2096  */
2097  pixel=gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2098  break;
2099  }
2100  case ModulateCompositeOp:
2101  {
2102  ssize_t
2103  offset;
2104 
2105  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2106  {
2107  pixel=Dc;
2108  break;
2109  }
2110  offset=(ssize_t) (GetPixelIntensity(source_image,p)-midpoint);
2111  if (offset == 0)
2112  {
2113  pixel=Dc;
2114  break;
2115  }
2116  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
2117  &hue,&chroma,&luma);
2118  luma+=(0.01*percent_luma*offset)/midpoint;
2119  chroma*=0.01*percent_chroma;
2120  HCLComposite(hue,chroma,luma,&red,&green,&blue);
2121  switch (channel)
2122  {
2123  case RedPixelChannel: pixel=red; break;
2124  case GreenPixelChannel: pixel=green; break;
2125  case BluePixelChannel: pixel=blue; break;
2126  default: pixel=Dc; break;
2127  }
2128  break;
2129  }
2130  case ModulusAddCompositeOp:
2131  {
2132  pixel=Sc+Dc;
2133  while (pixel > QuantumRange)
2134  pixel-=QuantumRange;
2135  while (pixel < 0.0)
2136  pixel+=QuantumRange;
2137  pixel=(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2138  break;
2139  }
2141  {
2142  pixel=Sc-Dc;
2143  while (pixel > QuantumRange)
2144  pixel-=QuantumRange;
2145  while (pixel < 0.0)
2146  pixel+=QuantumRange;
2147  pixel=(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2148  break;
2149  }
2150  case MultiplyCompositeOp:
2151  {
2152  pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2153  break;
2154  }
2155  case OutCompositeOp:
2156  case SrcOutCompositeOp:
2157  {
2158  pixel=QuantumRange*(Sca*(1.0-Da));
2159  break;
2160  }
2161  case OverCompositeOp:
2162  case SrcOverCompositeOp:
2163  {
2164  pixel=QuantumRange*gamma*(Sca+Dca*(1.0-Sa));
2165  break;
2166  }
2167  case OverlayCompositeOp:
2168  {
2169  if ((2.0*Dca) < Da)
2170  {
2171  pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*(1.0-
2172  Da));
2173  break;
2174  }
2175  pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2176  Sca*(1.0-Da));
2177  break;
2178  }
2180  {
2181  /*
2182  PegTop: A Soft-Light alternative: A continuous version of the
2183  Softlight function, producing very similar results.
2184 
2185  f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2186 
2187  http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2188  */
2189  if (fabs((double) Da) < MagickEpsilon)
2190  {
2191  pixel=QuantumRange*gamma*(Sca);
2192  break;
2193  }
2194  pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2195  Da)+Dca*(1.0-Sa));
2196  break;
2197  }
2198  case PinLightCompositeOp:
2199  {
2200  /*
2201  PinLight: A Photoshop 7 composition method
2202  http://www.simplefilter.de/en/basics/mixmods.html
2203 
2204  f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2205  */
2206  if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2207  {
2208  pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2209  break;
2210  }
2211  if ((Dca*Sa) > (2.0*Sca*Da))
2212  {
2213  pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2214  break;
2215  }
2216  pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2217  break;
2218  }
2219  case PlusCompositeOp:
2220  {
2221  pixel=QuantumRange*(Sca+Dca);
2222  break;
2223  }
2224  case SaturateCompositeOp:
2225  {
2226  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2227  {
2228  pixel=Dc;
2229  break;
2230  }
2231  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
2232  {
2233  pixel=Sc;
2234  break;
2235  }
2236  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
2237  &hue,&chroma,&luma);
2238  CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2239  &sans,&chroma,&sans);
2240  HCLComposite(hue,chroma,luma,&red,&green,&blue);
2241  switch (channel)
2242  {
2243  case RedPixelChannel: pixel=red; break;
2244  case GreenPixelChannel: pixel=green; break;
2245  case BluePixelChannel: pixel=blue; break;
2246  default: pixel=Dc; break;
2247  }
2248  break;
2249  }
2250  case ScreenCompositeOp:
2251  {
2252  /*
2253  Screen: a negated multiply:
2254 
2255  f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2256  */
2257  pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2258  break;
2259  }
2260  case SoftLightCompositeOp:
2261  {
2262  if ((2.0*Sca) < Sa)
2263  {
2264  pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-DcaDa))+
2265  Sca*(1.0-Da)+Dca*(1.0-Sa));
2266  break;
2267  }
2268  if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2269  {
2270  pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*DcaDa*
2271  (4.0*DcaDa+1.0)*(DcaDa-1.0)+7.0*DcaDa)+Sca*(1.0-Da)+
2272  Dca*(1.0-Sa));
2273  break;
2274  }
2275  pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow(DcaDa,0.5)-
2276  DcaDa)+Sca*(1.0-Da)+Dca*(1.0-Sa));
2277  break;
2278  }
2279  case StereoCompositeOp:
2280  {
2281  if (channel == RedPixelChannel)
2282  pixel=(MagickRealType) GetPixelRed(source_image,p);
2283  break;
2284  }
2285  case ThresholdCompositeOp:
2286  {
2288  delta;
2289 
2290  delta=Sc-Dc;
2291  if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2292  {
2293  pixel=gamma*Dc;
2294  break;
2295  }
2296  pixel=gamma*(Dc+delta*amount);
2297  break;
2298  }
2299  case VividLightCompositeOp:
2300  {
2301  /*
2302  VividLight: A Photoshop 7 composition method. See
2303  http://www.simplefilter.de/en/basics/mixmods.html.
2304 
2305  f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2306  */
2307  if ((fabs((double) Sa) < MagickEpsilon) ||
2308  (fabs((double) (Sca-Sa)) < MagickEpsilon))
2309  {
2310  pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2311  break;
2312  }
2313  if ((2.0*Sca) <= Sa)
2314  {
2315  pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)*
2316  PerceptibleReciprocal(2.0*Sca))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2317  break;
2318  }
2319  pixel=QuantumRange*gamma*(Dca*Sa*Sa*PerceptibleReciprocal(2.0*
2320  (Sa-Sca))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2321  break;
2322  }
2323  case XorCompositeOp:
2324  {
2325  pixel=QuantumRange*(Sca*(1.0-Da)+Dca*(1.0-Sa));
2326  break;
2327  }
2328  default:
2329  {
2330  pixel=Sc;
2331  break;
2332  }
2333  }
2334  q[i]=clamp != MagickFalse ? ClampPixel(pixel) : ClampToQuantum(pixel);
2335  }
2336  p+=GetPixelChannels(source_image);
2337  channels=GetPixelChannels(source_image);
2338  if (p >= (pixels+channels*source_image->columns))
2339  p=pixels;
2340  q+=GetPixelChannels(image);
2341  }
2342  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2343  status=MagickFalse;
2344  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2345  {
2347  proceed;
2348 
2349 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2350  #pragma omp critical (MagickCore_CompositeImage)
2351 #endif
2352  proceed=SetImageProgress(image,CompositeImageTag,progress++,
2353  image->rows);
2354  if (proceed == MagickFalse)
2355  status=MagickFalse;
2356  }
2357  }
2358  source_view=DestroyCacheView(source_view);
2359  image_view=DestroyCacheView(image_view);
2360  if (canvas_image != (Image * ) NULL)
2361  canvas_image=DestroyImage(canvas_image);
2362  else
2363  source_image=DestroyImage(source_image);
2364  return(status);
2365 }
2366 
2367 /*
2368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2369 % %
2370 % %
2371 % %
2372 % T e x t u r e I m a g e %
2373 % %
2374 % %
2375 % %
2376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2377 %
2378 % TextureImage() repeatedly tiles the texture image across and down the image
2379 % canvas.
2380 %
2381 % The format of the TextureImage method is:
2382 %
2383 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2384 % ExceptionInfo *exception)
2385 %
2386 % A description of each parameter follows:
2387 %
2388 % o image: the image.
2389 %
2390 % o texture_image: This image is the texture to layer on the background.
2391 %
2392 */
2394  ExceptionInfo *exception)
2395 {
2396 #define TextureImageTag "Texture/Image"
2397 
2398  CacheView
2399  *image_view,
2400  *texture_view;
2401 
2402  Image
2403  *texture_image;
2404 
2406  status;
2407 
2408  ssize_t
2409  y;
2410 
2411  assert(image != (Image *) NULL);
2412  if (image->debug != MagickFalse)
2413  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2414  assert(image->signature == MagickCoreSignature);
2415  if (texture == (const Image *) NULL)
2416  return(MagickFalse);
2417  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2418  return(MagickFalse);
2419  texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2420  if (texture_image == (const Image *) NULL)
2421  return(MagickFalse);
2422  (void) TransformImageColorspace(texture_image,image->colorspace,exception);
2424  exception);
2425  status=MagickTrue;
2426  if ((image->compose != CopyCompositeOp) &&
2427  ((image->compose != OverCompositeOp) ||
2428  (image->alpha_trait != UndefinedPixelTrait) ||
2429  (texture_image->alpha_trait != UndefinedPixelTrait)))
2430  {
2431  /*
2432  Tile texture onto the image background.
2433  */
2434  for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2435  {
2436  register ssize_t
2437  x;
2438 
2439  if (status == MagickFalse)
2440  continue;
2441  for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2442  {
2444  thread_status;
2445 
2446  thread_status=CompositeImage(image,texture_image,image->compose,
2447  MagickTrue,x+texture_image->tile_offset.x,y+
2448  texture_image->tile_offset.y,exception);
2449  if (thread_status == MagickFalse)
2450  {
2451  status=thread_status;
2452  break;
2453  }
2454  }
2455  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2456  {
2458  proceed;
2459 
2461  image->rows);
2462  if (proceed == MagickFalse)
2463  status=MagickFalse;
2464  }
2465  }
2467  image->rows,image->rows);
2468  texture_image=DestroyImage(texture_image);
2469  return(status);
2470  }
2471  /*
2472  Tile texture onto the image background (optimized).
2473  */
2474  status=MagickTrue;
2475  texture_view=AcquireVirtualCacheView(texture_image,exception);
2476  image_view=AcquireAuthenticCacheView(image,exception);
2477 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2478  #pragma omp parallel for schedule(static) shared(status) \
2479  magick_number_threads(texture_image,image,image->rows,1)
2480 #endif
2481  for (y=0; y < (ssize_t) image->rows; y++)
2482  {
2484  sync;
2485 
2486  register const Quantum
2487  *p,
2488  *pixels;
2489 
2490  register ssize_t
2491  x;
2492 
2493  register Quantum
2494  *q;
2495 
2496  size_t
2497  width;
2498 
2499  if (status == MagickFalse)
2500  continue;
2501  pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2502  (y+texture_image->tile_offset.y) % texture_image->rows,
2503  texture_image->columns,1,exception);
2504  q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2505  if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2506  {
2507  status=MagickFalse;
2508  continue;
2509  }
2510  for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2511  {
2512  register ssize_t
2513  j;
2514 
2515  p=pixels;
2516  width=texture_image->columns;
2517  if ((x+(ssize_t) width) > (ssize_t) image->columns)
2518  width=image->columns-x;
2519  for (j=0; j < (ssize_t) width; j++)
2520  {
2521  register ssize_t
2522  i;
2523 
2524  if (GetPixelWriteMask(image,q) <= (QuantumRange/2))
2525  {
2526  p+=GetPixelChannels(texture_image);
2527  q+=GetPixelChannels(image);
2528  continue;
2529  }
2530  for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2531  {
2532  PixelChannel channel = GetPixelChannelChannel(texture_image,i);
2533  PixelTrait traits = GetPixelChannelTraits(image,channel);
2534  PixelTrait texture_traits=GetPixelChannelTraits(texture_image,
2535  channel);
2536  if ((traits == UndefinedPixelTrait) ||
2537  (texture_traits == UndefinedPixelTrait))
2538  continue;
2539  SetPixelChannel(image,channel,p[i],q);
2540  }
2541  p+=GetPixelChannels(texture_image);
2542  q+=GetPixelChannels(image);
2543  }
2544  }
2545  sync=SyncCacheViewAuthenticPixels(image_view,exception);
2546  if (sync == MagickFalse)
2547  status=MagickFalse;
2548  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2549  {
2551  proceed;
2552 
2554  image->rows);
2555  if (proceed == MagickFalse)
2556  status=MagickFalse;
2557  }
2558  }
2559  texture_view=DestroyCacheView(texture_view);
2560  image_view=DestroyCacheView(image_view);
2561  texture_image=DestroyImage(texture_image);
2562  return(status);
2563 }
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:2393
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:1325
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:1692
#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:5473
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: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: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: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:967
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:123
static Quantum GetPixelGreen(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
MagickExport MagickBooleanType IsStringTrue(const char *value)
Definition: string.c:1498
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:3409
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:134
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:2602
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:5946
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:1134
MagickExport MagickStatusType ParseGeometry(const char *geometry, GeometryInfo *geometry_info)
Definition: geometry.c:852
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: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:132
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:1183
MagickExport Image * CloneImage(const Image *image, const size_t columns, const size_t rows, const MagickBooleanType detach, ExceptionInfo *exception)
Definition: image.c:800
ColorspaceType colorspace
Definition: image.h:157
#define QuantumRange
Definition: magick-type.h:83
MagickBooleanType debug
Definition: image.h:334