MagickCore  7.0.10
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-2020 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 %
38 */
39 
40 /*
41  Include declarations.
42 */
43 #include "MagickCore/studio.h"
44 #include "MagickCore/artifact.h"
45 #include "MagickCore/cache.h"
47 #include "MagickCore/cache-view.h"
48 #include "MagickCore/channel.h"
49 #include "MagickCore/client.h"
50 #include "MagickCore/color.h"
52 #include "MagickCore/colorspace.h"
54 #include "MagickCore/composite.h"
56 #include "MagickCore/constitute.h"
57 #include "MagickCore/draw.h"
58 #include "MagickCore/fx.h"
59 #include "MagickCore/gem.h"
60 #include "MagickCore/geometry.h"
61 #include "MagickCore/image.h"
63 #include "MagickCore/list.h"
64 #include "MagickCore/log.h"
65 #include "MagickCore/monitor.h"
67 #include "MagickCore/memory_.h"
68 #include "MagickCore/option.h"
70 #include "MagickCore/property.h"
71 #include "MagickCore/quantum.h"
72 #include "MagickCore/resample.h"
73 #include "MagickCore/resource_.h"
74 #include "MagickCore/string_.h"
76 #include "MagickCore/threshold.h"
77 #include "MagickCore/token.h"
78 #include "MagickCore/utility.h"
80 #include "MagickCore/version.h"
81 
82 /*
83 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
84 % %
85 % %
86 % %
87 % C o m p o s i t e I m a g e %
88 % %
89 % %
90 % %
91 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
92 %
93 % CompositeImage() returns the second image composited onto the first
94 % at the specified offset, using the specified composite method.
95 %
96 % The format of the CompositeImage method is:
97 %
98 % MagickBooleanType CompositeImage(Image *image,
99 % const Image *source_image,const CompositeOperator compose,
100 % const MagickBooleanType clip_to_self,const ssize_t x_offset,
101 % const ssize_t y_offset,ExceptionInfo *exception)
102 %
103 % A description of each parameter follows:
104 %
105 % o image: the canvas image, modified by he composition
106 %
107 % o source_image: the source image.
108 %
109 % o compose: This operator affects how the composite is applied to
110 % the image. The operators and how they are utilized are listed here
111 % http://www.w3.org/TR/SVG12/#compositing.
112 %
113 % o clip_to_self: set to MagickTrue to limit composition to area composed.
114 %
115 % o x_offset: the column offset of the composited image.
116 %
117 % o y_offset: the row offset of the composited image.
118 %
119 % Extra Controls from Image meta-data in 'image' (artifacts)
120 %
121 % o "compose:args"
122 % A string containing extra numerical arguments for specific compose
123 % methods, generally expressed as a 'geometry' or a comma separated list
124 % of numbers.
125 %
126 % Compose methods needing such arguments include "BlendCompositeOp" and
127 % "DisplaceCompositeOp".
128 %
129 % o exception: return any errors or warnings in this structure.
130 %
131 */
132 
133 /*
134  Composition based on the SVG specification:
135 
136  A Composition is defined by...
137  Color Function : f(Sc,Dc) where Sc and Dc are the normizalized colors
138  Blending areas : X = 1 for area of overlap, ie: f(Sc,Dc)
139  Y = 1 for source preserved
140  Z = 1 for canvas preserved
141 
142  Conversion to transparency (then optimized)
143  Dca' = f(Sc, Dc)*Sa*Da + Y*Sca*(1-Da) + Z*Dca*(1-Sa)
144  Da' = X*Sa*Da + Y*Sa*(1-Da) + Z*Da*(1-Sa)
145 
146  Where...
147  Sca = Sc*Sa normalized Source color divided by Source alpha
148  Dca = Dc*Da normalized Dest color divided by Dest alpha
149  Dc' = Dca'/Da' the desired color value for this channel.
150 
151  Da' in in the follow formula as 'gamma' The resulting alpla value.
152 
153  Most functions use a blending mode of over (X=1,Y=1,Z=1) this results in
154  the following optimizations...
155  gamma = Sa+Da-Sa*Da;
156  gamma = 1 - QuantumScale*alpha * QuantumScale*beta;
157  opacity = QuantumScale*alpha*beta; // over blend, optimized 1-Gamma
158 
159  The above SVG definitions also define that Mathematical Composition
160  methods should use a 'Over' blending mode for Alpha Channel.
161  It however was not applied for composition modes of 'Plus', 'Minus',
162  the modulus versions of 'Add' and 'Subtract'.
163 
164  Mathematical operator changes to be applied from IM v6.7...
165 
166  1) Modulus modes 'Add' and 'Subtract' are obsoleted and renamed
167  'ModulusAdd' and 'ModulusSubtract' for clarity.
168 
169  2) All mathematical compositions work as per the SVG specification
170  with regard to blending. This now includes 'ModulusAdd' and
171  'ModulusSubtract'.
172 
173  3) When the special channel flag 'sync' (syncronize channel updates)
174  is turned off (enabled by default) then mathematical compositions are
175  only performed on the channels specified, and are applied
176  independantally of each other. In other words the mathematics is
177  performed as 'pure' mathematical operations, rather than as image
178  operations.
179 */
180 
181 static void HCLComposite(const MagickRealType hue,const MagickRealType chroma,
182  const MagickRealType luma,MagickRealType *red,MagickRealType *green,
183  MagickRealType *blue)
184 {
186  b,
187  c,
188  g,
189  h,
190  m,
191  r,
192  x;
193 
194  /*
195  Convert HCL to RGB colorspace.
196  */
197  assert(red != (MagickRealType *) NULL);
198  assert(green != (MagickRealType *) NULL);
199  assert(blue != (MagickRealType *) NULL);
200  h=6.0*hue;
201  c=chroma;
202  x=c*(1.0-fabs(fmod(h,2.0)-1.0));
203  r=0.0;
204  g=0.0;
205  b=0.0;
206  if ((0.0 <= h) && (h < 1.0))
207  {
208  r=c;
209  g=x;
210  }
211  else
212  if ((1.0 <= h) && (h < 2.0))
213  {
214  r=x;
215  g=c;
216  }
217  else
218  if ((2.0 <= h) && (h < 3.0))
219  {
220  g=c;
221  b=x;
222  }
223  else
224  if ((3.0 <= h) && (h < 4.0))
225  {
226  g=x;
227  b=c;
228  }
229  else
230  if ((4.0 <= h) && (h < 5.0))
231  {
232  r=x;
233  b=c;
234  }
235  else
236  if ((5.0 <= h) && (h < 6.0))
237  {
238  r=c;
239  b=x;
240  }
241  m=luma-(0.298839*r+0.586811*g+0.114350*b);
242  *red=QuantumRange*(r+m);
243  *green=QuantumRange*(g+m);
244  *blue=QuantumRange*(b+m);
245 }
246 
247 static void CompositeHCL(const MagickRealType red,const MagickRealType green,
248  const MagickRealType blue,MagickRealType *hue,MagickRealType *chroma,
249  MagickRealType *luma)
250 {
252  b,
253  c,
254  g,
255  h,
256  max,
257  r;
258 
259  /*
260  Convert RGB to HCL colorspace.
261  */
262  assert(hue != (MagickRealType *) NULL);
263  assert(chroma != (MagickRealType *) NULL);
264  assert(luma != (MagickRealType *) NULL);
265  r=red;
266  g=green;
267  b=blue;
268  max=MagickMax(r,MagickMax(g,b));
269  c=max-(MagickRealType) MagickMin(r,MagickMin(g,b));
270  h=0.0;
271  if (c == 0)
272  h=0.0;
273  else
274  if (red == max)
275  h=fmod((g-b)/c+6.0,6.0);
276  else
277  if (green == max)
278  h=((b-r)/c)+2.0;
279  else
280  if (blue == max)
281  h=((r-g)/c)+4.0;
282  *hue=(h/6.0);
283  *chroma=QuantumScale*c;
284  *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
285 }
286 
288  const Image *source_image,const MagickBooleanType clip_to_self,
289  const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
290 {
291 #define CompositeImageTag "Composite/Image"
292 
293  CacheView
294  *image_view,
295  *source_view;
296 
297  const char
298  *value;
299 
301  clamp,
302  status;
303 
305  progress;
306 
307  ssize_t
308  y;
309 
310  /*
311  Composite image.
312  */
313  status=MagickTrue;
314  progress=0;
315  clamp=MagickTrue;
316  value=GetImageArtifact(image,"compose:clamp");
317  if (value != (const char *) NULL)
318  clamp=IsStringTrue(value);
319  status=MagickTrue;
320  progress=0;
321  source_view=AcquireVirtualCacheView(source_image,exception);
322  image_view=AcquireAuthenticCacheView(image,exception);
323 #if defined(MAGICKCORE_OPENMP_SUPPORT)
324  #pragma omp parallel for schedule(static) shared(progress,status) \
325  magick_number_threads(source_image,image,image->rows,1)
326 #endif
327  for (y=0; y < (ssize_t) image->rows; y++)
328  {
329  const Quantum
330  *pixels;
331 
332  PixelInfo
333  canvas_pixel,
334  source_pixel;
335 
336  register const Quantum
337  *magick_restrict p;
338 
339  register Quantum
340  *magick_restrict q;
341 
342  register ssize_t
343  x;
344 
345  if (status == MagickFalse)
346  continue;
347  if (clip_to_self != MagickFalse)
348  {
349  if (y < y_offset)
350  continue;
351  if ((y-y_offset) >= (ssize_t) source_image->rows)
352  continue;
353  }
354  /*
355  If pixels is NULL, y is outside overlay region.
356  */
357  pixels=(Quantum *) NULL;
358  p=(Quantum *) NULL;
359  if ((y >= y_offset) && ((y-y_offset) < (ssize_t) source_image->rows))
360  {
361  p=GetCacheViewVirtualPixels(source_view,0,y-y_offset,
362  source_image->columns,1,exception);
363  if (p == (const Quantum *) NULL)
364  {
365  status=MagickFalse;
366  continue;
367  }
368  pixels=p;
369  if (x_offset < 0)
370  p-=x_offset*(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  register ssize_t
395  i;
396 
397  size_t
398  channels;
399 
400  if (clip_to_self != MagickFalse)
401  {
402  if (x < x_offset)
403  {
404  q+=GetPixelChannels(image);
405  continue;
406  }
407  if ((x-x_offset) >= (ssize_t) source_image->columns)
408  break;
409  }
410  if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
411  ((x-x_offset) >= (ssize_t) source_image->columns))
412  {
413  Quantum
414  source[MaxPixelChannels];
415 
416  /*
417  Virtual composite:
418  Sc: source color.
419  Dc: canvas color.
420  */
421  (void) GetOneVirtualPixel(source_image,x-x_offset,y-y_offset,source,
422  exception);
423  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
424  {
426  pixel;
427 
428  PixelChannel channel = GetPixelChannelChannel(image,i);
429  PixelTrait traits = GetPixelChannelTraits(image,channel);
430  PixelTrait source_traits=GetPixelChannelTraits(source_image,
431  channel);
432  if ((traits == UndefinedPixelTrait) ||
433  (source_traits == UndefinedPixelTrait))
434  continue;
435  if (channel == AlphaPixelChannel)
437  else
438  pixel=(MagickRealType) q[i];
439  q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
440  ClampToQuantum(pixel);
441  }
442  q+=GetPixelChannels(image);
443  continue;
444  }
445  /*
446  Authentic composite:
447  Sa: normalized source alpha.
448  Da: normalized canvas alpha.
449  */
450  Sa=QuantumScale*GetPixelAlpha(source_image,p);
451  Da=QuantumScale*GetPixelAlpha(image,q);
452  alpha=Sa+Da-Sa*Da;
453  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
454  {
456  pixel;
457 
458  PixelChannel channel = GetPixelChannelChannel(image,i);
459  PixelTrait traits = GetPixelChannelTraits(image,channel);
460  PixelTrait source_traits=GetPixelChannelTraits(source_image,channel);
461  if (traits == UndefinedPixelTrait)
462  continue;
463  if ((source_traits == UndefinedPixelTrait) &&
464  (channel != AlphaPixelChannel))
465  continue;
466  if (channel == AlphaPixelChannel)
467  {
468  /*
469  Set alpha channel.
470  */
471  pixel=QuantumRange*alpha;
472  q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
473  ClampToQuantum(pixel);
474  continue;
475  }
476  /*
477  Sc: source color.
478  Dc: canvas color.
479  */
480  Sc=(MagickRealType) GetPixelChannel(source_image,channel,p);
481  Dc=(MagickRealType) q[i];
482  if ((traits & CopyPixelTrait) != 0)
483  {
484  /*
485  Copy channel.
486  */
487  q[i]=ClampToQuantum(Sc);
488  continue;
489  }
490  /*
491  Porter-Duff compositions:
492  Sca: source normalized color multiplied by alpha.
493  Dca: normalized canvas color multiplied by alpha.
494  */
495  Sca=QuantumScale*Sa*Sc;
496  Dca=QuantumScale*Da*Dc;
497  gamma=PerceptibleReciprocal(alpha);
498  pixel=QuantumRange*gamma*(Sca+Dca*(1.0-Sa));
499  q[i]=clamp != MagickFalse ? ClampPixel(pixel) : ClampToQuantum(pixel);
500  }
501  p+=GetPixelChannels(source_image);
502  channels=GetPixelChannels(source_image);
503  if (p >= (pixels+channels*source_image->columns))
504  p=pixels;
505  q+=GetPixelChannels(image);
506  }
507  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
508  status=MagickFalse;
509  if (image->progress_monitor != (MagickProgressMonitor) NULL)
510  {
512  proceed;
513 
514 #if defined(MAGICKCORE_OPENMP_SUPPORT)
515  #pragma omp atomic
516 #endif
517  progress++;
518  proceed=SetImageProgress(image,CompositeImageTag,progress,image->rows);
519  if (proceed == MagickFalse)
520  status=MagickFalse;
521  }
522  }
523  source_view=DestroyCacheView(source_view);
524  image_view=DestroyCacheView(image_view);
525  return(status);
526 }
527 
529  const Image *composite,const CompositeOperator compose,
530  const MagickBooleanType clip_to_self,const ssize_t x_offset,
531  const ssize_t y_offset,ExceptionInfo *exception)
532 {
533 #define CompositeImageTag "Composite/Image"
534 
535  CacheView
536  *source_view,
537  *image_view;
538 
539  const char
540  *value;
541 
543  geometry_info;
544 
545  Image
546  *canvas_image,
547  *source_image;
548 
550  clamp,
551  status;
552 
554  progress;
555 
557  amount,
558  canvas_dissolve,
559  midpoint,
560  percent_luma,
561  percent_chroma,
562  source_dissolve,
563  threshold;
564 
566  flags;
567 
568  ssize_t
569  y;
570 
571  assert(image != (Image *) NULL);
572  assert(image->signature == MagickCoreSignature);
573  if (image->debug != MagickFalse)
574  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
575  assert(composite != (Image *) NULL);
576  assert(composite->signature == MagickCoreSignature);
577  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
578  return(MagickFalse);
579  source_image=CloneImage(composite,0,0,MagickTrue,exception);
580  if (source_image == (const Image *) NULL)
581  return(MagickFalse);
582  (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  register const Quantum
628  *p;
629 
630  register Quantum
631  *q;
632 
633  register 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  register 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  register const Quantum
712  *p;
713 
714  register Quantum
715  *q;
716 
717  register 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  register const Quantum
884  *magick_restrict p;
885 
886  register Quantum
887  *magick_restrict q;
888 
889  register 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  register const Quantum
1055  *magick_restrict p;
1056 
1057  register Quantum
1058  *magick_restrict q;
1059 
1060  register 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  register const Quantum
1235  *magick_restrict p;
1236 
1237  register Quantum
1238  *magick_restrict q;
1239 
1240  register 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  register 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  {
1563  equivalent;
1564 
1565  if (Da < 0.5)
1566  {
1568  break;
1569  }
1570  equivalent=IsFuzzyEquivalencePixel(source_image,p,image,q);
1571  if (equivalent != MagickFalse)
1573  else
1574  pixel=(MagickRealType) OpaqueAlpha;
1575  break;
1576  }
1577  case ClearCompositeOp:
1578  {
1580  break;
1581  }
1582  case ColorizeCompositeOp:
1583  case HueCompositeOp:
1584  case LuminizeCompositeOp:
1585  case RMSECompositeOp:
1586  case SaturateCompositeOp:
1587  {
1588  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1589  {
1590  pixel=QuantumRange*Da;
1591  break;
1592  }
1593  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
1594  {
1595  pixel=QuantumRange*Sa;
1596  break;
1597  }
1598  if (Sa < Da)
1599  {
1600  pixel=QuantumRange*Da;
1601  break;
1602  }
1603  pixel=QuantumRange*Sa;
1604  break;
1605  }
1606  case CopyAlphaCompositeOp:
1607  {
1608  if (source_image->alpha_trait == UndefinedPixelTrait)
1609  pixel=GetPixelIntensity(source_image,p);
1610  else
1611  pixel=QuantumRange*Sa;
1612  break;
1613  }
1614  case BlurCompositeOp:
1615  case CopyCompositeOp:
1616  case DisplaceCompositeOp:
1617  case DistortCompositeOp:
1618  case DstAtopCompositeOp:
1619  case ReplaceCompositeOp:
1620  case SrcCompositeOp:
1621  {
1622  pixel=QuantumRange*Sa;
1623  break;
1624  }
1626  {
1627  pixel=Sa*GetPixelIntensity(source_image,p) <
1628  Da*GetPixelIntensity(image,q) ? Sa : Da;
1629  break;
1630  }
1631  case DifferenceCompositeOp:
1632  {
1633  pixel=QuantumRange*fabs(Sa-Da);
1634  break;
1635  }
1636  case FreezeCompositeOp:
1637  {
1638  pixel=QuantumRange*(1.0-(1.0-Sa)*(1.0-Sa)*
1639  PerceptibleReciprocal(Da));
1640  if (pixel < 0.0)
1641  pixel=0.0;
1642  break;
1643  }
1645  {
1646  pixel=QuantumRange*(0.5-0.25*cos(MagickPI*Sa)-0.25*
1647  cos(MagickPI*Da));
1648  break;
1649  }
1651  {
1652  pixel=Sa*GetPixelIntensity(source_image,p) >
1653  Da*GetPixelIntensity(image,q) ? Sa : Da;
1654  break;
1655  }
1656  case ModulateCompositeOp:
1657  {
1658  pixel=QuantumRange*Da;
1659  break;
1660  }
1661  case MultiplyCompositeOp:
1662  {
1663  pixel=QuantumRange*Sa*Da;
1664  break;
1665  }
1666  case NegateCompositeOp:
1667  {
1668  pixel=QuantumRange*((1.0-Sa-Da));
1669  break;
1670  }
1671  case ReflectCompositeOp:
1672  {
1673  pixel=QuantumRange*(Sa*Sa*PerceptibleReciprocal(1.0-Da));
1674  if (pixel > QuantumRange)
1675  pixel=QuantumRange;
1676  break;
1677  }
1678  case StampCompositeOp:
1679  {
1680  pixel=QuantumRange*(Sa+Da*Da-1.0);
1681  break;
1682  }
1683  case StereoCompositeOp:
1684  {
1685  pixel=QuantumRange*(Sa+Da)/2;
1686  break;
1687  }
1688  default:
1689  {
1690  pixel=QuantumRange*alpha;
1691  break;
1692  }
1693  }
1694  q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
1695  ClampToQuantum(pixel);
1696  continue;
1697  }
1698  if (source_traits == UndefinedPixelTrait)
1699  continue;
1700  /*
1701  Sc: source color.
1702  Dc: canvas color.
1703  */
1704  Sc=(MagickRealType) GetPixelChannel(source_image,channel,p);
1705  Dc=(MagickRealType) q[i];
1706  if ((traits & CopyPixelTrait) != 0)
1707  {
1708  /*
1709  Copy channel.
1710  */
1711  q[i]=ClampToQuantum(Dc);
1712  continue;
1713  }
1714  /*
1715  Porter-Duff compositions:
1716  Sca: source normalized color multiplied by alpha.
1717  Dca: normalized canvas color multiplied by alpha.
1718  */
1719  Sca=QuantumScale*Sa*Sc;
1720  Dca=QuantumScale*Da*Dc;
1721  SaSca=Sa*PerceptibleReciprocal(Sca);
1722  DcaDa=Dca*PerceptibleReciprocal(Da);
1723  switch (compose)
1724  {
1725  case DarkenCompositeOp:
1726  case LightenCompositeOp:
1728  {
1729  gamma=PerceptibleReciprocal(1.0-alpha);
1730  break;
1731  }
1732  default:
1733  {
1734  gamma=PerceptibleReciprocal(alpha);
1735  break;
1736  }
1737  }
1738  pixel=Dc;
1739  switch (compose)
1740  {
1741  case AlphaCompositeOp:
1742  {
1743  pixel=QuantumRange*Sa;
1744  break;
1745  }
1746  case AtopCompositeOp:
1747  case SrcAtopCompositeOp:
1748  {
1749  pixel=QuantumRange*(Sca*Da+Dca*(1.0-Sa));
1750  break;
1751  }
1752  case BlendCompositeOp:
1753  {
1754  pixel=gamma*(source_dissolve*Sa*Sc+canvas_dissolve*Da*Dc);
1755  break;
1756  }
1757  case CopyCompositeOp:
1758  case ReplaceCompositeOp:
1759  case SrcCompositeOp:
1760  {
1761  pixel=QuantumRange*Sca;
1762  break;
1763  }
1764  case BlurCompositeOp:
1765  case DisplaceCompositeOp:
1766  case DistortCompositeOp:
1767  {
1768  pixel=Sc;
1769  break;
1770  }
1771  case BumpmapCompositeOp:
1772  {
1773  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1774  {
1775  pixel=Dc;
1776  break;
1777  }
1778  pixel=QuantumScale*GetPixelIntensity(source_image,p)*Dc;
1779  break;
1780  }
1781  case ChangeMaskCompositeOp:
1782  {
1783  pixel=Dc;
1784  break;
1785  }
1786  case ClearCompositeOp:
1787  {
1788  pixel=0.0;
1789  break;
1790  }
1791  case ColorBurnCompositeOp:
1792  {
1793  if ((Sca == 0.0) && (Dca == Da))
1794  {
1795  pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1796  break;
1797  }
1798  if (Sca == 0.0)
1799  {
1800  pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1801  break;
1802  }
1803  pixel=QuantumRange*gamma*(Sa*Da-Sa*Da*MagickMin(1.0,(1.0-DcaDa)*
1804  SaSca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
1805  break;
1806  }
1807  case ColorDodgeCompositeOp:
1808  {
1809  if ((Sca*Da+Dca*Sa) >= Sa*Da)
1810  pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1811  else
1812  pixel=QuantumRange*gamma*(Dca*Sa*Sa*PerceptibleReciprocal(Sa-Sca)+
1813  Sca*(1.0-Da)+Dca*(1.0-Sa));
1814  break;
1815  }
1816  case ColorizeCompositeOp:
1817  {
1818  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1819  {
1820  pixel=Dc;
1821  break;
1822  }
1823  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
1824  {
1825  pixel=Sc;
1826  break;
1827  }
1828  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
1829  &sans,&sans,&luma);
1830  CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1831  &hue,&chroma,&sans);
1832  HCLComposite(hue,chroma,luma,&red,&green,&blue);
1833  switch (channel)
1834  {
1835  case RedPixelChannel: pixel=red; break;
1836  case GreenPixelChannel: pixel=green; break;
1837  case BluePixelChannel: pixel=blue; break;
1838  default: pixel=Dc; break;
1839  }
1840  break;
1841  }
1842  case CopyAlphaCompositeOp:
1843  {
1844  pixel=Dc;
1845  break;
1846  }
1847  case CopyBlackCompositeOp:
1848  {
1849  if (channel == BlackPixelChannel)
1850  pixel=(MagickRealType) GetPixelBlack(source_image,p);
1851  break;
1852  }
1853  case CopyBlueCompositeOp:
1854  case CopyYellowCompositeOp:
1855  {
1856  if (channel == BluePixelChannel)
1857  pixel=(MagickRealType) GetPixelBlue(source_image,p);
1858  break;
1859  }
1860  case CopyGreenCompositeOp:
1862  {
1863  if (channel == GreenPixelChannel)
1864  pixel=(MagickRealType) GetPixelGreen(source_image,p);
1865  break;
1866  }
1867  case CopyRedCompositeOp:
1868  case CopyCyanCompositeOp:
1869  {
1870  if (channel == RedPixelChannel)
1871  pixel=(MagickRealType) GetPixelRed(source_image,p);
1872  break;
1873  }
1874  case DarkenCompositeOp:
1875  {
1876  /*
1877  Darken is equivalent to a 'Minimum' method
1878  OR a greyscale version of a binary 'Or'
1879  OR the 'Intersection' of pixel sets.
1880  */
1881  if ((Sca*Da) < (Dca*Sa))
1882  {
1883  pixel=QuantumRange*(Sca+Dca*(1.0-Sa));
1884  break;
1885  }
1886  pixel=QuantumRange*(Dca+Sca*(1.0-Da));
1887  break;
1888  }
1890  {
1891  pixel=Sa*GetPixelIntensity(source_image,p) <
1892  Da*GetPixelIntensity(image,q) ? Sc : Dc;
1893  break;
1894  }
1895  case DifferenceCompositeOp:
1896  {
1897  pixel=QuantumRange*gamma*(Sca+Dca-2.0*MagickMin(Sca*Da,Dca*Sa));
1898  break;
1899  }
1900  case DissolveCompositeOp:
1901  {
1902  pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1903  canvas_dissolve*Da*Dc+canvas_dissolve*Da*Dc);
1904  break;
1905  }
1906  case DivideDstCompositeOp:
1907  {
1908  if ((fabs((double) Sca) < MagickEpsilon) &&
1909  (fabs((double) Dca) < MagickEpsilon))
1910  {
1911  pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1912  break;
1913  }
1914  if (fabs((double) Dca) < MagickEpsilon)
1915  {
1916  pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1917  break;
1918  }
1919  pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1920  break;
1921  }
1922  case DivideSrcCompositeOp:
1923  {
1924  if ((fabs((double) Dca) < MagickEpsilon) &&
1925  (fabs((double) Sca) < MagickEpsilon))
1926  {
1927  pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1928  break;
1929  }
1930  if (fabs((double) Sca) < MagickEpsilon)
1931  {
1932  pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1933  break;
1934  }
1935  pixel=QuantumRange*gamma*(Dca*Sa*SaSca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1936  break;
1937  }
1938  case DstAtopCompositeOp:
1939  {
1940  pixel=QuantumRange*(Dca*Sa+Sca*(1.0-Da));
1941  break;
1942  }
1943  case DstCompositeOp:
1944  case NoCompositeOp:
1945  {
1946  pixel=QuantumRange*Dca;
1947  break;
1948  }
1949  case DstInCompositeOp:
1950  {
1951  pixel=QuantumRange*gamma*(Dca*Sa);
1952  break;
1953  }
1954  case DstOutCompositeOp:
1955  {
1956  pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1957  break;
1958  }
1959  case DstOverCompositeOp:
1960  {
1961  pixel=QuantumRange*gamma*(Dca+Sca*(1.0-Da));
1962  break;
1963  }
1964  case ExclusionCompositeOp:
1965  {
1966  pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1967  Dca*(1.0-Sa));
1968  break;
1969  }
1970  case FreezeCompositeOp:
1971  {
1972  pixel=QuantumRange*gamma*(1.0-(1.0-Sca)*(1.0-Sca)*
1973  PerceptibleReciprocal(Dca));
1974  if (pixel < 0.0)
1975  pixel=0.0;
1976  break;
1977  }
1978  case HardLightCompositeOp:
1979  {
1980  if ((2.0*Sca) < Sa)
1981  {
1982  pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-
1983  Sa));
1984  break;
1985  }
1986  pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1987  Dca*(1.0-Sa));
1988  break;
1989  }
1990  case HardMixCompositeOp:
1991  {
1992  pixel=gamma*(((Sca+Dca) < 1.0) ? 0.0 : QuantumRange);
1993  break;
1994  }
1995  case HueCompositeOp:
1996  {
1997  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1998  {
1999  pixel=Dc;
2000  break;
2001  }
2002  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
2003  {
2004  pixel=Sc;
2005  break;
2006  }
2007  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
2008  &hue,&chroma,&luma);
2009  CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2010  &hue,&sans,&sans);
2011  HCLComposite(hue,chroma,luma,&red,&green,&blue);
2012  switch (channel)
2013  {
2014  case RedPixelChannel: pixel=red; break;
2015  case GreenPixelChannel: pixel=green; break;
2016  case BluePixelChannel: pixel=blue; break;
2017  default: pixel=Dc; break;
2018  }
2019  break;
2020  }
2021  case InCompositeOp:
2022  case SrcInCompositeOp:
2023  {
2024  pixel=QuantumRange*(Sca*Da);
2025  break;
2026  }
2028  {
2029  pixel=QuantumRange*(0.5-0.25*cos(MagickPI*Sca)-0.25*
2030  cos(MagickPI*Dca));
2031  break;
2032  }
2033  case LinearBurnCompositeOp:
2034  {
2035  /*
2036  LinearBurn: as defined by Abode Photoshop, according to
2037  http://www.simplefilter.de/en/basics/mixmods.html is:
2038 
2039  f(Sc,Dc) = Sc + Dc - 1
2040  */
2041  pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
2042  break;
2043  }
2045  {
2046  pixel=gamma*(Sa*Sc+Da*Dc);
2047  break;
2048  }
2050  {
2051  /*
2052  LinearLight: as defined by Abode Photoshop, according to
2053  http://www.simplefilter.de/en/basics/mixmods.html is:
2054 
2055  f(Sc,Dc) = Dc + 2*Sc - 1
2056  */
2057  pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
2058  break;
2059  }
2060  case LightenCompositeOp:
2061  {
2062  if ((Sca*Da) > (Dca*Sa))
2063  {
2064  pixel=QuantumRange*(Sca+Dca*(1.0-Sa));
2065  break;
2066  }
2067  pixel=QuantumRange*(Dca+Sca*(1.0-Da));
2068  break;
2069  }
2071  {
2072  /*
2073  Lighten is equivalent to a 'Maximum' method
2074  OR a greyscale version of a binary 'And'
2075  OR the 'Union' of pixel sets.
2076  */
2077  pixel=Sa*GetPixelIntensity(source_image,p) >
2078  Da*GetPixelIntensity(image,q) ? Sc : Dc;
2079  break;
2080  }
2081  case LuminizeCompositeOp:
2082  {
2083  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2084  {
2085  pixel=Dc;
2086  break;
2087  }
2088  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
2089  {
2090  pixel=Sc;
2091  break;
2092  }
2093  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
2094  &hue,&chroma,&luma);
2095  CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2096  &sans,&sans,&luma);
2097  HCLComposite(hue,chroma,luma,&red,&green,&blue);
2098  switch (channel)
2099  {
2100  case RedPixelChannel: pixel=red; break;
2101  case GreenPixelChannel: pixel=green; break;
2102  case BluePixelChannel: pixel=blue; break;
2103  default: pixel=Dc; break;
2104  }
2105  break;
2106  }
2108  {
2109  /*
2110  'Mathematics' a free form user control mathematical composition
2111  is defined as...
2112 
2113  f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
2114 
2115  Where the arguments A,B,C,D are (currently) passed to composite
2116  as a command separated 'geometry' string in "compose:args" image
2117  artifact.
2118 
2119  A = a->rho, B = a->sigma, C = a->xi, D = a->psi
2120 
2121  Applying the SVG transparency formula (see above), we get...
2122 
2123  Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
2124 
2125  Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
2126  Dca*(1.0-Sa)
2127  */
2128  pixel=QuantumRange*gamma*(geometry_info.rho*Sca*Dca+
2129  geometry_info.sigma*Sca*Da+geometry_info.xi*Dca*Sa+
2130  geometry_info.psi*Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2131  break;
2132  }
2133  case MinusDstCompositeOp:
2134  {
2135  pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2136  break;
2137  }
2138  case MinusSrcCompositeOp:
2139  {
2140  /*
2141  Minus source from canvas.
2142 
2143  f(Sc,Dc) = Sc - Dc
2144  */
2145  pixel=gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2146  break;
2147  }
2148  case ModulateCompositeOp:
2149  {
2150  ssize_t
2151  offset;
2152 
2153  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2154  {
2155  pixel=Dc;
2156  break;
2157  }
2158  offset=(ssize_t) (GetPixelIntensity(source_image,p)-midpoint);
2159  if (offset == 0)
2160  {
2161  pixel=Dc;
2162  break;
2163  }
2164  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
2165  &hue,&chroma,&luma);
2166  luma+=(0.01*percent_luma*offset)/midpoint;
2167  chroma*=0.01*percent_chroma;
2168  HCLComposite(hue,chroma,luma,&red,&green,&blue);
2169  switch (channel)
2170  {
2171  case RedPixelChannel: pixel=red; break;
2172  case GreenPixelChannel: pixel=green; break;
2173  case BluePixelChannel: pixel=blue; break;
2174  default: pixel=Dc; break;
2175  }
2176  break;
2177  }
2178  case ModulusAddCompositeOp:
2179  {
2180  if ((Sca+Dca) <= 1.0)
2181  {
2182  pixel=QuantumRange*(Sca+Dca);
2183  break;
2184  }
2185  pixel=QuantumRange*((Sca+Dca)-1.0);
2186  break;
2187  }
2189  {
2190  if ((Sca-Dca) >= 0.0)
2191  {
2192  pixel=QuantumRange*(Sca-Dca);
2193  break;
2194  }
2195  pixel=QuantumRange*((Sca-Dca)+1.0);
2196  break;
2197  }
2198  case MultiplyCompositeOp:
2199  {
2200  pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2201  break;
2202  }
2203  case NegateCompositeOp:
2204  {
2205  pixel=QuantumRange*(1.0-fabs(1.0-Sca-Dca));
2206  break;
2207  }
2208  case OutCompositeOp:
2209  case SrcOutCompositeOp:
2210  {
2211  pixel=QuantumRange*(Sca*(1.0-Da));
2212  break;
2213  }
2214  case OverCompositeOp:
2215  case SrcOverCompositeOp:
2216  {
2217  pixel=QuantumRange*gamma*(Sca+Dca*(1.0-Sa));
2218  break;
2219  }
2220  case OverlayCompositeOp:
2221  {
2222  if ((2.0*Dca) < Da)
2223  {
2224  pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*(1.0-
2225  Da));
2226  break;
2227  }
2228  pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2229  Sca*(1.0-Da));
2230  break;
2231  }
2233  {
2234  /*
2235  PegTop: A Soft-Light alternative: A continuous version of the
2236  Softlight function, producing very similar results.
2237 
2238  f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2239 
2240  http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2241  */
2242  if (fabs((double) Da) < MagickEpsilon)
2243  {
2244  pixel=QuantumRange*gamma*Sca;
2245  break;
2246  }
2247  pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2248  Da)+Dca*(1.0-Sa));
2249  break;
2250  }
2251  case PinLightCompositeOp:
2252  {
2253  /*
2254  PinLight: A Photoshop 7 composition method
2255  http://www.simplefilter.de/en/basics/mixmods.html
2256 
2257  f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc ? 2*Sc : Dc
2258  */
2259  if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2260  {
2261  pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2262  break;
2263  }
2264  if ((Dca*Sa) > (2.0*Sca*Da))
2265  {
2266  pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2267  break;
2268  }
2269  pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2270  break;
2271  }
2272  case PlusCompositeOp:
2273  {
2274  pixel=QuantumRange*(Sca+Dca);
2275  break;
2276  }
2277  case ReflectCompositeOp:
2278  {
2279  pixel=QuantumRange*gamma*(Sca*Sca*PerceptibleReciprocal(1.0-Dca));
2280  if (pixel > QuantumRange)
2281  pixel=QuantumRange;
2282  break;
2283  }
2284  case RMSECompositeOp:
2285  {
2286  double
2287  gray;
2288 
2289  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2290  {
2291  pixel=Dc;
2292  break;
2293  }
2294  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
2295  {
2296  pixel=Sc;
2297  break;
2298  }
2299  gray=sqrt(
2300  (canvas_pixel.red-source_pixel.red)*
2301  (canvas_pixel.red-source_pixel.red)+
2302  (canvas_pixel.green-source_pixel.green)*
2303  (canvas_pixel.green-source_pixel.green)+
2304  (canvas_pixel.blue-source_pixel.blue)*
2305  (canvas_pixel.blue-source_pixel.blue)/3.0);
2306  switch (channel)
2307  {
2308  case RedPixelChannel: pixel=gray; break;
2309  case GreenPixelChannel: pixel=gray; break;
2310  case BluePixelChannel: pixel=gray; break;
2311  default: pixel=Dc; break;
2312  }
2313  break;
2314  }
2315  case SaturateCompositeOp:
2316  {
2317  if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2318  {
2319  pixel=Dc;
2320  break;
2321  }
2322  if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
2323  {
2324  pixel=Sc;
2325  break;
2326  }
2327  CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
2328  &hue,&chroma,&luma);
2329  CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2330  &sans,&chroma,&sans);
2331  HCLComposite(hue,chroma,luma,&red,&green,&blue);
2332  switch (channel)
2333  {
2334  case RedPixelChannel: pixel=red; break;
2335  case GreenPixelChannel: pixel=green; break;
2336  case BluePixelChannel: pixel=blue; break;
2337  default: pixel=Dc; break;
2338  }
2339  break;
2340  }
2341  case ScreenCompositeOp:
2342  {
2343  /*
2344  Screen: a negated multiply:
2345 
2346  f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2347  */
2348  pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2349  break;
2350  }
2351  case SoftBurnCompositeOp:
2352  {
2353  if ((Sca+Dca) < 1.0)
2354  pixel=QuantumRange*gamma*(0.5*Dca*PerceptibleReciprocal(1.0-Sca));
2355  else
2356  pixel=QuantumRange*gamma*(1.0-0.5*(1.0-Sca)*
2357  PerceptibleReciprocal(Dca));
2358  break;
2359  }
2360  case SoftDodgeCompositeOp:
2361  {
2362  if ((Sca+Dca) < 1.0)
2363  pixel=QuantumRange*gamma*(0.5*Sca*PerceptibleReciprocal(1.0-Dca));
2364  else
2365  pixel=QuantumRange*gamma*(1.0-0.5*(1.0-Dca)*
2366  PerceptibleReciprocal(Sca));
2367  break;
2368  }
2369  case SoftLightCompositeOp:
2370  {
2371  if ((2.0*Sca) < Sa)
2372  {
2373  pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-DcaDa))+
2374  Sca*(1.0-Da)+Dca*(1.0-Sa));
2375  break;
2376  }
2377  if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2378  {
2379  pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*DcaDa*
2380  (4.0*DcaDa+1.0)*(DcaDa-1.0)+7.0*DcaDa)+Sca*(1.0-Da)+
2381  Dca*(1.0-Sa));
2382  break;
2383  }
2384  pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow(DcaDa,0.5)-
2385  DcaDa)+Sca*(1.0-Da)+Dca*(1.0-Sa));
2386  break;
2387  }
2388  case StampCompositeOp:
2389  {
2390  pixel=QuantumRange*(Sca+Dca*Dca-1.0);
2391  break;
2392  }
2393  case StereoCompositeOp:
2394  {
2395  if (channel == RedPixelChannel)
2396  pixel=(MagickRealType) GetPixelRed(source_image,p);
2397  break;
2398  }
2399  case ThresholdCompositeOp:
2400  {
2402  delta;
2403 
2404  delta=Sc-Dc;
2405  if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2406  {
2407  pixel=gamma*Dc;
2408  break;
2409  }
2410  pixel=gamma*(Dc+delta*amount);
2411  break;
2412  }
2413  case VividLightCompositeOp:
2414  {
2415  /*
2416  VividLight: A Photoshop 7 composition method. See
2417  http://www.simplefilter.de/en/basics/mixmods.html.
2418 
2419  f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2420  */
2421  if ((fabs((double) Sa) < MagickEpsilon) ||
2422  (fabs((double) (Sca-Sa)) < MagickEpsilon))
2423  {
2424  pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2425  break;
2426  }
2427  if ((2.0*Sca) <= Sa)
2428  {
2429  pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)*
2430  PerceptibleReciprocal(2.0*Sca))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2431  break;
2432  }
2433  pixel=QuantumRange*gamma*(Dca*Sa*Sa*PerceptibleReciprocal(2.0*
2434  (Sa-Sca))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2435  break;
2436  }
2437  case XorCompositeOp:
2438  {
2439  pixel=QuantumRange*(Sca*(1.0-Da)+Dca*(1.0-Sa));
2440  break;
2441  }
2442  default:
2443  {
2444  pixel=Sc;
2445  break;
2446  }
2447  }
2448  q[i]=clamp != MagickFalse ? ClampPixel(pixel) : ClampToQuantum(pixel);
2449  }
2450  p+=GetPixelChannels(source_image);
2451  channels=GetPixelChannels(source_image);
2452  if (p >= (pixels+channels*source_image->columns))
2453  p=pixels;
2454  q+=GetPixelChannels(image);
2455  }
2456  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2457  status=MagickFalse;
2458  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2459  {
2461  proceed;
2462 
2463 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2464  #pragma omp atomic
2465 #endif
2466  progress++;
2467  proceed=SetImageProgress(image,CompositeImageTag,progress,image->rows);
2468  if (proceed == MagickFalse)
2469  status=MagickFalse;
2470  }
2471  }
2472  source_view=DestroyCacheView(source_view);
2473  image_view=DestroyCacheView(image_view);
2474  if (canvas_image != (Image * ) NULL)
2475  canvas_image=DestroyImage(canvas_image);
2476  else
2477  source_image=DestroyImage(source_image);
2478  return(status);
2479 }
2480 
2481 /*
2482 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2483 % %
2484 % %
2485 % %
2486 % T e x t u r e I m a g e %
2487 % %
2488 % %
2489 % %
2490 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2491 %
2492 % TextureImage() repeatedly tiles the texture image across and down the image
2493 % canvas.
2494 %
2495 % The format of the TextureImage method is:
2496 %
2497 % MagickBooleanType TextureImage(Image *image,const Image *texture,
2498 % ExceptionInfo *exception)
2499 %
2500 % A description of each parameter follows:
2501 %
2502 % o image: the image.
2503 %
2504 % o texture_image: This image is the texture to layer on the background.
2505 %
2506 */
2508  ExceptionInfo *exception)
2509 {
2510 #define TextureImageTag "Texture/Image"
2511 
2512  CacheView
2513  *image_view,
2514  *texture_view;
2515 
2516  Image
2517  *texture_image;
2518 
2520  status;
2521 
2522  ssize_t
2523  y;
2524 
2525  assert(image != (Image *) NULL);
2526  if (image->debug != MagickFalse)
2527  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2528  assert(image->signature == MagickCoreSignature);
2529  if (texture == (const Image *) NULL)
2530  return(MagickFalse);
2531  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2532  return(MagickFalse);
2533  texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2534  if (texture_image == (const Image *) NULL)
2535  return(MagickFalse);
2536  (void) TransformImageColorspace(texture_image,image->colorspace,exception);
2538  exception);
2539  status=MagickTrue;
2540  if ((image->compose != CopyCompositeOp) &&
2541  ((image->compose != OverCompositeOp) ||
2542  (image->alpha_trait != UndefinedPixelTrait) ||
2543  (texture_image->alpha_trait != UndefinedPixelTrait)))
2544  {
2545  /*
2546  Tile texture onto the image background.
2547  */
2548  for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2549  {
2550  register ssize_t
2551  x;
2552 
2553  if (status == MagickFalse)
2554  continue;
2555  for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2556  {
2558  thread_status;
2559 
2560  thread_status=CompositeImage(image,texture_image,image->compose,
2561  MagickTrue,x+texture_image->tile_offset.x,y+
2562  texture_image->tile_offset.y,exception);
2563  if (thread_status == MagickFalse)
2564  {
2565  status=thread_status;
2566  break;
2567  }
2568  }
2569  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2570  {
2572  proceed;
2573 
2575  image->rows);
2576  if (proceed == MagickFalse)
2577  status=MagickFalse;
2578  }
2579  }
2581  image->rows,image->rows);
2582  texture_image=DestroyImage(texture_image);
2583  return(status);
2584  }
2585  /*
2586  Tile texture onto the image background (optimized).
2587  */
2588  status=MagickTrue;
2589  texture_view=AcquireVirtualCacheView(texture_image,exception);
2590  image_view=AcquireAuthenticCacheView(image,exception);
2591 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2592  #pragma omp parallel for schedule(static) shared(status) \
2593  magick_number_threads(texture_image,image,image->rows,1)
2594 #endif
2595  for (y=0; y < (ssize_t) image->rows; y++)
2596  {
2598  sync;
2599 
2600  register const Quantum
2601  *p,
2602  *pixels;
2603 
2604  register ssize_t
2605  x;
2606 
2607  register Quantum
2608  *q;
2609 
2610  size_t
2611  width;
2612 
2613  if (status == MagickFalse)
2614  continue;
2615  pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2616  (y+texture_image->tile_offset.y) % texture_image->rows,
2617  texture_image->columns,1,exception);
2618  q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2619  if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2620  {
2621  status=MagickFalse;
2622  continue;
2623  }
2624  for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2625  {
2626  register ssize_t
2627  j;
2628 
2629  p=pixels;
2630  width=texture_image->columns;
2631  if ((x+(ssize_t) width) > (ssize_t) image->columns)
2632  width=image->columns-x;
2633  for (j=0; j < (ssize_t) width; j++)
2634  {
2635  register ssize_t
2636  i;
2637 
2638  for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2639  {
2640  PixelChannel channel = GetPixelChannelChannel(texture_image,i);
2641  PixelTrait traits = GetPixelChannelTraits(image,channel);
2642  PixelTrait texture_traits=GetPixelChannelTraits(texture_image,
2643  channel);
2644  if ((traits == UndefinedPixelTrait) ||
2645  (texture_traits == UndefinedPixelTrait))
2646  continue;
2647  SetPixelChannel(image,channel,p[i],q);
2648  }
2649  p+=GetPixelChannels(texture_image);
2650  q+=GetPixelChannels(image);
2651  }
2652  }
2653  sync=SyncCacheViewAuthenticPixels(image_view,exception);
2654  if (sync == MagickFalse)
2655  status=MagickFalse;
2656  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2657  {
2659  proceed;
2660 
2662  image->rows);
2663  if (proceed == MagickFalse)
2664  status=MagickFalse;
2665  }
2666  }
2667  texture_view=DestroyCacheView(texture_view);
2668  image_view=DestroyCacheView(image_view);
2669  texture_image=DestroyImage(texture_image);
2670  return(status);
2671 }
double psi
Definition: geometry.h:106
size_t rows
Definition: image.h:172
#define magick_restrict
Definition: MagickCore.h:41
MagickExport MagickBooleanType TextureImage(Image *image, const Image *texture, ExceptionInfo *exception)
Definition: composite.c:2507
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:1503
static Quantum GetPixelRed(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
MagickExport MagickBooleanType ResamplePixelColor(ResampleFilter *resample_filter, const double u0, const double v0, PixelInfo *pixel, ExceptionInfo *exception)
Definition: resample.c:315
double rho
Definition: geometry.h:106
MagickExport void SetGeometryInfo(GeometryInfo *geometry_info)
Definition: geometry.c:1723
#define OpaqueAlpha
Definition: image.h:25
static Quantum GetPixelChannel(const Image *magick_restrict image, const PixelChannel channel, const Quantum *magick_restrict pixel)
MagickExport const char * GetImageArtifact(const Image *image, const char *artifact)
Definition: artifact.c:273
MagickRealType red
Definition: pixel.h: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:1986
#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:5483
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:106
MagickExport MagickBooleanType CompositeImage(Image *image, const Image *composite, const CompositeOperator compose, const MagickBooleanType clip_to_self, const ssize_t x_offset, const ssize_t y_offset, ExceptionInfo *exception)
Definition: composite.c:528
RectangleInfo tile_offset
Definition: image.h:261
MagickExport ResampleFilter * AcquireResampleFilter(const Image *image, ExceptionInfo *exception)
Definition: resample.c:208
Definition: log.h:52
ssize_t MagickOffsetType
Definition: magick-type.h: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:123
#define MagickCoreSignature
MagickExport Quantum * GetCacheViewAuthenticPixels(CacheView *cache_view, const ssize_t x, const ssize_t y, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: cache-view.c:299
static Quantum ClampPixel(const MagickRealType pixel)
MagickExport MagickBooleanType SetImageAlphaChannel(Image *image, const AlphaChannelOption alpha_type, ExceptionInfo *exception)
Definition: channel.c:974
MagickBooleanType
Definition: magick-type.h: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:53
double y
Definition: geometry.h:123
static Quantum GetPixelGreen(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
MagickExport MagickBooleanType IsStringTrue(const char *value)
Definition: string.c:1415
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:3479
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:134
MagickBooleanType(* MagickProgressMonitor)(const char *, const MagickOffsetType, const MagickSizeType, void *)
Definition: monitor.h:26
MagickExport ResampleFilter * DestroyResampleFilter(ResampleFilter *resample_filter)
Definition: resample.c:262
MagickExport MagickBooleanType SetImageStorageClass(Image *image, const ClassType storage_class, ExceptionInfo *exception)
Definition: image.c:2595
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:5956
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:106
MagickExport MagickBooleanType SetImageColorspace(Image *image, const ColorspaceType colorspace, ExceptionInfo *exception)
Definition: colorspace.c:1312
MagickExport MagickStatusType ParseGeometry(const char *geometry, GeometryInfo *geometry_info)
Definition: geometry.c:853
static void SetPixelChannel(const Image *magick_restrict image, const PixelChannel channel, const Quantum quantum, Quantum *magick_restrict pixel)
#define MagickMin(x, y)
Definition: image-private.h: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:134
MagickExport CacheView * AcquireAuthenticCacheView(const Image *image, ExceptionInfo *exception)
Definition: cache-view.c:112
double y1
Definition: image.h:107
static Quantum GetPixelBlue(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
PixelTrait
Definition: pixel.h: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:1160
MagickExport Image * CloneImage(const Image *image, const size_t columns, const size_t rows, const MagickBooleanType detach, ExceptionInfo *exception)
Definition: image.c:775
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