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