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