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