MagickCore  7.1.0
paint.c
Go to the documentation of this file.
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % PPPP AAA IIIII N N TTTTT %
7 % P P A A I NN N T %
8 % PPPP AAAAA I N N N T %
9 % P A A I N NN T %
10 % P A A IIIII N N T %
11 % %
12 % %
13 % Methods to Paint on an Image %
14 % %
15 % Software Design %
16 % Cristy %
17 % July 1998 %
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  Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/artifact.h"
44 #include "MagickCore/channel.h"
45 #include "MagickCore/color.h"
48 #include "MagickCore/composite.h"
50 #include "MagickCore/draw.h"
52 #include "MagickCore/exception.h"
54 #include "MagickCore/gem.h"
55 #include "MagickCore/gem-private.h"
56 #include "MagickCore/monitor.h"
58 #include "MagickCore/option.h"
59 #include "MagickCore/paint.h"
61 #include "MagickCore/resource_.h"
62 #include "MagickCore/statistic.h"
63 #include "MagickCore/string_.h"
66 
67 /*
68 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
69 % %
70 % %
71 % %
72 % F l o o d f i l l P a i n t I m a g e %
73 % %
74 % %
75 % %
76 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
77 %
78 % FloodfillPaintImage() changes the color value of any pixel that matches
79 % target and is an immediate neighbor. If the method FillToBorderMethod is
80 % specified, the color value is changed for any neighbor pixel that does not
81 % match the bordercolor member of image.
82 %
83 % By default target must match a particular pixel color exactly. However,
84 % in many cases two colors may differ by a small amount. The fuzz member of
85 % image defines how much tolerance is acceptable to consider two colors as
86 % the same. For example, set fuzz to 10 and the color red at intensities of
87 % 100 and 102 respectively are now interpreted as the same color for the
88 % purposes of the floodfill.
89 %
90 % The format of the FloodfillPaintImage method is:
91 %
92 % MagickBooleanType FloodfillPaintImage(Image *image,
93 % const DrawInfo *draw_info,const PixelInfo target,
94 % const ssize_t x_offset,const ssize_t y_offset,
95 % const MagickBooleanType invert,ExceptionInfo *exception)
96 %
97 % A description of each parameter follows:
98 %
99 % o image: the image.
100 %
101 % o draw_info: the draw info.
102 %
103 % o target: the RGB value of the target color.
104 %
105 % o x_offset,y_offset: the starting location of the operation.
106 %
107 % o invert: paint any pixel that does not match the target color.
108 %
109 % o exception: return any errors or warnings in this structure.
110 %
111 */
113  const DrawInfo *draw_info,const PixelInfo *target,const ssize_t x_offset,
114  const ssize_t y_offset,const MagickBooleanType invert,
115  ExceptionInfo *exception)
116 {
117 #define MaxStacksize 524288UL
118 #define PushSegmentStack(up,left,right,delta) \
119 { \
120  if (s >= (segment_stack+MaxStacksize)) \
121  { \
122  segment_info=RelinquishVirtualMemory(segment_info); \
123  image_view=DestroyCacheView(image_view); \
124  floodplane_view=DestroyCacheView(floodplane_view); \
125  floodplane_image=DestroyImage(floodplane_image); \
126  ThrowBinaryException(DrawError,"SegmentStackOverflow",image->filename) \
127  } \
128  else \
129  { \
130  if ((((up)+(delta)) >= 0) && (((up)+(delta)) < (ssize_t) image->rows)) \
131  { \
132  s->x1=(double) (left); \
133  s->y1=(double) (up); \
134  s->x2=(double) (right); \
135  s->y2=(double) (delta); \
136  s++; \
137  } \
138  } \
139 }
140 
141  CacheView
142  *floodplane_view,
143  *image_view;
144 
145  Image
146  *floodplane_image;
147 
149  skip,
150  status;
151 
152  MemoryInfo
153  *segment_info;
154 
155  PixelInfo
156  fill_color,
157  pixel;
158 
160  *s;
161 
163  *segment_stack;
164 
165  ssize_t
166  offset,
167  start,
168  x1,
169  x2,
170  y;
171 
172  /*
173  Check boundary conditions.
174  */
175  assert(image != (Image *) NULL);
176  assert(image->signature == MagickCoreSignature);
177  if (image->debug != MagickFalse)
178  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
179  assert(draw_info != (DrawInfo *) NULL);
180  assert(draw_info->signature == MagickCoreSignature);
181  if ((x_offset < 0) || (x_offset >= (ssize_t) image->columns))
182  return(MagickFalse);
183  if ((y_offset < 0) || (y_offset >= (ssize_t) image->rows))
184  return(MagickFalse);
185  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
186  return(MagickFalse);
187  if (IsGrayColorspace(image->colorspace) != MagickFalse)
188  (void) SetImageColorspace(image,sRGBColorspace,exception);
189  if ((image->alpha_trait == UndefinedPixelTrait) &&
190  (draw_info->fill.alpha_trait != UndefinedPixelTrait))
191  (void) SetImageAlpha(image,OpaqueAlpha,exception);
192  /*
193  Set floodfill state.
194  */
195  floodplane_image=CloneImage(image,0,0,MagickTrue,exception);
196  if (floodplane_image == (Image *) NULL)
197  return(MagickFalse);
198  floodplane_image->alpha_trait=UndefinedPixelTrait;
199  floodplane_image->colorspace=GRAYColorspace;
200  (void) QueryColorCompliance("#000",AllCompliance,
201  &floodplane_image->background_color,exception);
202  (void) SetImageBackgroundColor(floodplane_image,exception);
203  segment_info=AcquireVirtualMemory(MaxStacksize,sizeof(*segment_stack));
204  if (segment_info == (MemoryInfo *) NULL)
205  {
206  floodplane_image=DestroyImage(floodplane_image);
207  ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
208  image->filename);
209  }
210  segment_stack=(SegmentInfo *) GetVirtualMemoryBlob(segment_info);
211  /*
212  Push initial segment on stack.
213  */
214  status=MagickTrue;
215  start=0;
216  s=segment_stack;
217  GetPixelInfo(image,&pixel);
218  image_view=AcquireVirtualCacheView(image,exception);
219  floodplane_view=AcquireAuthenticCacheView(floodplane_image,exception);
220  PushSegmentStack(y_offset,x_offset,x_offset,1);
221  PushSegmentStack(y_offset+1,x_offset,x_offset,-1);
222  while (s > segment_stack)
223  {
224  const Quantum
225  *magick_restrict p;
226 
227  Quantum
228  *magick_restrict q;
229 
230  ssize_t
231  x;
232 
233  /*
234  Pop segment off stack.
235  */
236  s--;
237  x1=(ssize_t) s->x1;
238  x2=(ssize_t) s->x2;
239  offset=(ssize_t) s->y2;
240  y=(ssize_t) s->y1+offset;
241  /*
242  Recolor neighboring pixels.
243  */
244  p=GetCacheViewVirtualPixels(image_view,0,y,(size_t) (x1+1),1,exception);
245  q=GetCacheViewAuthenticPixels(floodplane_view,0,y,(size_t) (x1+1),1,
246  exception);
247  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
248  break;
249  p+=x1*GetPixelChannels(image);
250  q+=x1*GetPixelChannels(floodplane_image);
251  for (x=x1; x >= 0; x--)
252  {
253  if (GetPixelGray(floodplane_image,q) != 0)
254  break;
255  GetPixelInfoPixel(image,p,&pixel);
256  if (IsFuzzyEquivalencePixelInfo(&pixel,target) == invert)
257  break;
258  SetPixelGray(floodplane_image,QuantumRange,q);
259  p-=GetPixelChannels(image);
260  q-=GetPixelChannels(floodplane_image);
261  }
262  if (SyncCacheViewAuthenticPixels(floodplane_view,exception) == MagickFalse)
263  break;
264  skip=x >= x1 ? MagickTrue : MagickFalse;
265  if (skip == MagickFalse)
266  {
267  start=x+1;
268  if (start < x1)
269  PushSegmentStack(y,start,x1-1,-offset);
270  x=x1+1;
271  }
272  do
273  {
274  if (skip == MagickFalse)
275  {
276  if (x < (ssize_t) image->columns)
277  {
278  p=GetCacheViewVirtualPixels(image_view,x,y,image->columns-x,1,
279  exception);
280  q=GetCacheViewAuthenticPixels(floodplane_view,x,y,image->columns-
281  x,1,exception);
282  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
283  break;
284  for ( ; x < (ssize_t) image->columns; x++)
285  {
286  if (GetPixelGray(floodplane_image,q) != 0)
287  break;
288  GetPixelInfoPixel(image,p,&pixel);
289  if (IsFuzzyEquivalencePixelInfo(&pixel,target) == invert)
290  break;
291  SetPixelGray(floodplane_image,QuantumRange,q);
292  p+=GetPixelChannels(image);
293  q+=GetPixelChannels(floodplane_image);
294  }
295  status=SyncCacheViewAuthenticPixels(floodplane_view,exception);
296  if (status == MagickFalse)
297  break;
298  }
299  PushSegmentStack(y,start,x-1,offset);
300  if (x > (x2+1))
301  PushSegmentStack(y,x2+1,x-1,-offset);
302  }
303  skip=MagickFalse;
304  x++;
305  if (x <= x2)
306  {
307  p=GetCacheViewVirtualPixels(image_view,x,y,(size_t) (x2-x+1),1,
308  exception);
309  q=GetCacheViewAuthenticPixels(floodplane_view,x,y,(size_t) (x2-x+1),1,
310  exception);
311  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
312  break;
313  for ( ; x <= x2; x++)
314  {
315  if (GetPixelGray(floodplane_image,q) != 0)
316  break;
317  GetPixelInfoPixel(image,p,&pixel);
318  if (IsFuzzyEquivalencePixelInfo(&pixel,target) != invert)
319  break;
320  p+=GetPixelChannels(image);
321  q+=GetPixelChannels(floodplane_image);
322  }
323  }
324  start=x;
325  } while (x <= x2);
326  }
327  status=MagickTrue;
328  for (y=0; y < (ssize_t) image->rows; y++)
329  {
330  const Quantum
331  *magick_restrict p;
332 
333  Quantum
334  *magick_restrict q;
335 
336  ssize_t
337  x;
338 
339  /*
340  Tile fill color onto floodplane.
341  */
342  if (status == MagickFalse)
343  continue;
344  p=GetCacheViewVirtualPixels(floodplane_view,0,y,image->columns,1,exception);
345  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
346  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
347  {
348  status=MagickFalse;
349  continue;
350  }
351  for (x=0; x < (ssize_t) image->columns; x++)
352  {
353  if (GetPixelGray(floodplane_image,p) != 0)
354  {
355  GetFillColor(draw_info,x,y,&fill_color,exception);
356  SetPixelViaPixelInfo(image,&fill_color,q);
357  }
358  p+=GetPixelChannels(floodplane_image);
359  q+=GetPixelChannels(image);
360  }
361  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
362  status=MagickFalse;
363  }
364  floodplane_view=DestroyCacheView(floodplane_view);
365  image_view=DestroyCacheView(image_view);
366  segment_info=RelinquishVirtualMemory(segment_info);
367  floodplane_image=DestroyImage(floodplane_image);
368  return(status);
369 }
370 
371 /*
372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
373 % %
374 % %
375 % %
376 + G r a d i e n t I m a g e %
377 % %
378 % %
379 % %
380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
381 %
382 % GradientImage() applies a continuously smooth color transitions along a
383 % vector from one color to another.
384 %
385 % Note, the interface of this method will change in the future to support
386 % more than one transistion.
387 %
388 % The format of the GradientImage method is:
389 %
390 % MagickBooleanType GradientImage(Image *image,const GradientType type,
391 % const SpreadMethod method,const PixelInfo *start_color,
392 % const PixelInfo *stop_color,ExceptionInfo *exception)
393 %
394 % A description of each parameter follows:
395 %
396 % o image: the image.
397 %
398 % o type: the gradient type: linear or radial.
399 %
400 % o spread: the gradient spread meathod: pad, reflect, or repeat.
401 %
402 % o start_color: the start color.
403 %
404 % o stop_color: the stop color.
405 %
406 % o exception: return any errors or warnings in this structure.
407 %
408 */
410  const GradientType type,const SpreadMethod method,const StopInfo *stops,
411  const size_t number_stops,ExceptionInfo *exception)
412 {
413  const char
414  *artifact;
415 
416  DrawInfo
417  *draw_info;
418 
420  *gradient;
421 
423  status;
424 
425  /*
426  Set gradient start-stop end points.
427  */
428  assert(image != (const Image *) NULL);
429  assert(image->signature == MagickCoreSignature);
430  if (image->debug != MagickFalse)
431  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
432  assert(stops != (const StopInfo *) NULL);
433  assert(number_stops > 0);
434  draw_info=AcquireDrawInfo();
435  gradient=(&draw_info->gradient);
436  gradient->type=type;
437  gradient->bounding_box.width=image->columns;
438  gradient->bounding_box.height=image->rows;
439  artifact=GetImageArtifact(image,"gradient:bounding-box");
440  if (artifact != (const char *) NULL)
441  (void) ParseAbsoluteGeometry(artifact,&gradient->bounding_box);
442  gradient->gradient_vector.x2=(double) image->columns-1;
443  gradient->gradient_vector.y2=(double) image->rows-1;
444  artifact=GetImageArtifact(image,"gradient:direction");
445  if (artifact != (const char *) NULL)
446  {
448  direction;
449 
451  MagickFalse,artifact);
452  switch (direction)
453  {
454  case NorthWestGravity:
455  {
456  gradient->gradient_vector.x1=(double) image->columns-1;
457  gradient->gradient_vector.y1=(double) image->rows-1;
458  gradient->gradient_vector.x2=0.0;
459  gradient->gradient_vector.y2=0.0;
460  break;
461  }
462  case NorthGravity:
463  {
464  gradient->gradient_vector.x1=0.0;
465  gradient->gradient_vector.y1=(double) image->rows-1;
466  gradient->gradient_vector.x2=0.0;
467  gradient->gradient_vector.y2=0.0;
468  break;
469  }
470  case NorthEastGravity:
471  {
472  gradient->gradient_vector.x1=0.0;
473  gradient->gradient_vector.y1=(double) image->rows-1;
474  gradient->gradient_vector.x2=(double) image->columns-1;
475  gradient->gradient_vector.y2=0.0;
476  break;
477  }
478  case WestGravity:
479  {
480  gradient->gradient_vector.x1=(double) image->columns-1;
481  gradient->gradient_vector.y1=0.0;
482  gradient->gradient_vector.x2=0.0;
483  gradient->gradient_vector.y2=0.0;
484  break;
485  }
486  case EastGravity:
487  {
488  gradient->gradient_vector.x1=0.0;
489  gradient->gradient_vector.y1=0.0;
490  gradient->gradient_vector.x2=(double) image->columns-1;
491  gradient->gradient_vector.y2=0.0;
492  break;
493  }
494  case SouthWestGravity:
495  {
496  gradient->gradient_vector.x1=(double) image->columns-1;
497  gradient->gradient_vector.y1=0.0;
498  gradient->gradient_vector.x2=0.0;
499  gradient->gradient_vector.y2=(double) image->rows-1;
500  break;
501  }
502  case SouthGravity:
503  {
504  gradient->gradient_vector.x1=0.0;
505  gradient->gradient_vector.y1=0.0;
506  gradient->gradient_vector.x2=0.0;
507  gradient->gradient_vector.y2=(double) image->columns-1;
508  break;
509  }
510  case SouthEastGravity:
511  {
512  gradient->gradient_vector.x1=0.0;
513  gradient->gradient_vector.y1=0.0;
514  gradient->gradient_vector.x2=(double) image->columns-1;
515  gradient->gradient_vector.y2=(double) image->rows-1;
516  break;
517  }
518  default:
519  break;
520  }
521  }
522  artifact=GetImageArtifact(image,"gradient:angle");
523  if (artifact != (const char *) NULL)
524  gradient->angle=StringToDouble(artifact,(char **) NULL);
525  artifact=GetImageArtifact(image,"gradient:vector");
526  if (artifact != (const char *) NULL)
527  (void) sscanf(artifact,"%lf%*[ ,]%lf%*[ ,]%lf%*[ ,]%lf",
528  &gradient->gradient_vector.x1,&gradient->gradient_vector.y1,
529  &gradient->gradient_vector.x2,&gradient->gradient_vector.y2);
530  if ((GetImageArtifact(image,"gradient:angle") == (const char *) NULL) &&
531  (GetImageArtifact(image,"gradient:direction") == (const char *) NULL) &&
532  (GetImageArtifact(image,"gradient:extent") == (const char *) NULL) &&
533  (GetImageArtifact(image,"gradient:vector") == (const char *) NULL))
534  if ((type == LinearGradient) && (gradient->gradient_vector.y2 != 0.0))
535  gradient->gradient_vector.x2=0.0;
536  gradient->center.x=(double) gradient->gradient_vector.x2/2.0;
537  gradient->center.y=(double) gradient->gradient_vector.y2/2.0;
538  artifact=GetImageArtifact(image,"gradient:center");
539  if (artifact != (const char *) NULL)
540  (void) sscanf(artifact,"%lf%*[ ,]%lf",&gradient->center.x,
541  &gradient->center.y);
542  artifact=GetImageArtifact(image,"gradient:angle");
543  if ((type == LinearGradient) && (artifact != (const char *) NULL))
544  {
545  double
546  sine,
547  cosine,
548  distance;
549 
550  /*
551  Reference https://drafts.csswg.org/css-images-3/#linear-gradients.
552  */
553  sine=sin((double) DegreesToRadians(gradient->angle-90.0));
554  cosine=cos((double) DegreesToRadians(gradient->angle-90.0));
555  distance=fabs((double) (image->columns-1.0)*cosine)+
556  fabs((double) (image->rows-1.0)*sine);
557  gradient->gradient_vector.x1=0.5*((image->columns-1.0)-distance*cosine);
558  gradient->gradient_vector.y1=0.5*((image->rows-1.0)-distance*sine);
559  gradient->gradient_vector.x2=0.5*((image->columns-1.0)+distance*cosine);
560  gradient->gradient_vector.y2=0.5*((image->rows-1.0)+distance*sine);
561  }
562  gradient->radii.x=(double) MagickMax((image->columns-1.0),(image->rows-1.0))/
563  2.0;
564  gradient->radii.y=gradient->radii.x;
565  artifact=GetImageArtifact(image,"gradient:extent");
566  if (artifact != (const char *) NULL)
567  {
568  if (LocaleCompare(artifact,"Circle") == 0)
569  {
570  gradient->radii.x=(double) MagickMax((image->columns-1.0),
571  (image->rows-1.0))/2.0;
572  gradient->radii.y=gradient->radii.x;
573  }
574  if (LocaleCompare(artifact,"Diagonal") == 0)
575  {
576  gradient->radii.x=(double) (sqrt((double) (image->columns-1.0)*
577  (image->columns-1.0)+(image->rows-1.0)*(image->rows-1.0)))/2.0;
578  gradient->radii.y=gradient->radii.x;
579  }
580  if (LocaleCompare(artifact,"Ellipse") == 0)
581  {
582  gradient->radii.x=(double) (image->columns-1.0)/2.0;
583  gradient->radii.y=(double) (image->rows-1.0)/2.0;
584  }
585  if (LocaleCompare(artifact,"Maximum") == 0)
586  {
587  gradient->radii.x=(double) MagickMax((image->columns-1.0),
588  (image->rows-1.0))/2.0;
589  gradient->radii.y=gradient->radii.x;
590  }
591  if (LocaleCompare(artifact,"Minimum") == 0)
592  {
593  gradient->radii.x=(double) (MagickMin((image->columns-1.0),
594  (image->rows-1.0)))/2.0;
595  gradient->radii.y=gradient->radii.x;
596  }
597  }
598  artifact=GetImageArtifact(image,"gradient:radii");
599  if (artifact != (const char *) NULL)
600  (void) sscanf(artifact,"%lf%*[ ,]%lf",&gradient->radii.x,
601  &gradient->radii.y);
602  gradient->radius=MagickMax(gradient->radii.x,gradient->radii.y);
603  gradient->spread=method;
604  /*
605  Define the gradient to fill between the stops.
606  */
607  gradient->number_stops=number_stops;
608  gradient->stops=(StopInfo *) AcquireQuantumMemory(gradient->number_stops,
609  sizeof(*gradient->stops));
610  if (gradient->stops == (StopInfo *) NULL)
611  ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
612  image->filename);
613  (void) memcpy(gradient->stops,stops,(size_t) number_stops*sizeof(*stops));
614  /*
615  Draw a gradient on the image.
616  */
617  status=DrawGradientImage(image,draw_info,exception);
618  draw_info=DestroyDrawInfo(draw_info);
619  return(status);
620 }
621 
622 /*
623 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
624 % %
625 % %
626 % %
627 % O i l P a i n t I m a g e %
628 % %
629 % %
630 % %
631 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
632 %
633 % OilPaintImage() applies a special effect filter that simulates an oil
634 % painting. Each pixel is replaced by the most frequent color occurring
635 % in a circular region defined by radius.
636 %
637 % The format of the OilPaintImage method is:
638 %
639 % Image *OilPaintImage(const Image *image,const double radius,
640 % const double sigma,ExceptionInfo *exception)
641 %
642 % A description of each parameter follows:
643 %
644 % o image: the image.
645 %
646 % o radius: the radius of the circular neighborhood.
647 %
648 % o sigma: the standard deviation of the Gaussian, in pixels.
649 %
650 % o exception: return any errors or warnings in this structure.
651 %
652 */
653 
654 static size_t **DestroyHistogramThreadSet(size_t **histogram)
655 {
656  ssize_t
657  i;
658 
659  assert(histogram != (size_t **) NULL);
660  for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
661  if (histogram[i] != (size_t *) NULL)
662  histogram[i]=(size_t *) RelinquishMagickMemory(histogram[i]);
663  histogram=(size_t **) RelinquishMagickMemory(histogram);
664  return(histogram);
665 }
666 
667 static size_t **AcquireHistogramThreadSet(const size_t count)
668 {
669  ssize_t
670  i;
671 
672  size_t
673  **histogram,
674  number_threads;
675 
676  number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
677  histogram=(size_t **) AcquireQuantumMemory(number_threads,sizeof(*histogram));
678  if (histogram == (size_t **) NULL)
679  return((size_t **) NULL);
680  (void) memset(histogram,0,number_threads*sizeof(*histogram));
681  for (i=0; i < (ssize_t) number_threads; i++)
682  {
683  histogram[i]=(size_t *) AcquireQuantumMemory(count,sizeof(**histogram));
684  if (histogram[i] == (size_t *) NULL)
685  return(DestroyHistogramThreadSet(histogram));
686  }
687  return(histogram);
688 }
689 
690 MagickExport Image *OilPaintImage(const Image *image,const double radius,
691  const double sigma,ExceptionInfo *exception)
692 {
693 #define NumberPaintBins 256
694 #define OilPaintImageTag "OilPaint/Image"
695 
696  CacheView
697  *image_view,
698  *paint_view;
699 
700  Image
701  *linear_image,
702  *paint_image;
703 
705  status;
706 
708  progress;
709 
710  size_t
711  **histograms,
712  width;
713 
714  ssize_t
715  center,
716  y;
717 
718  /*
719  Initialize painted image attributes.
720  */
721  assert(image != (const Image *) NULL);
722  assert(image->signature == MagickCoreSignature);
723  if (image->debug != MagickFalse)
724  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
725  assert(exception != (ExceptionInfo *) NULL);
726  assert(exception->signature == MagickCoreSignature);
727  width=GetOptimalKernelWidth2D(radius,sigma);
728  linear_image=CloneImage(image,0,0,MagickTrue,exception);
729  paint_image=CloneImage(image,0,0,MagickTrue,exception);
730  if ((linear_image == (Image *) NULL) || (paint_image == (Image *) NULL))
731  {
732  if (linear_image != (Image *) NULL)
733  linear_image=DestroyImage(linear_image);
734  if (paint_image != (Image *) NULL)
735  linear_image=DestroyImage(paint_image);
736  return((Image *) NULL);
737  }
738  if (SetImageStorageClass(paint_image,DirectClass,exception) == MagickFalse)
739  {
740  linear_image=DestroyImage(linear_image);
741  paint_image=DestroyImage(paint_image);
742  return((Image *) NULL);
743  }
745  if (histograms == (size_t **) NULL)
746  {
747  linear_image=DestroyImage(linear_image);
748  paint_image=DestroyImage(paint_image);
749  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
750  }
751  /*
752  Oil paint image.
753  */
754  status=MagickTrue;
755  progress=0;
756  center=(ssize_t) GetPixelChannels(linear_image)*(linear_image->columns+width)*
757  (width/2L)+GetPixelChannels(linear_image)*(width/2L);
758  image_view=AcquireVirtualCacheView(linear_image,exception);
759  paint_view=AcquireAuthenticCacheView(paint_image,exception);
760 #if defined(MAGICKCORE_OPENMP_SUPPORT)
761  #pragma omp parallel for schedule(static) shared(progress,status) \
762  magick_number_threads(linear_image,paint_image,linear_image->rows,1)
763 #endif
764  for (y=0; y < (ssize_t) linear_image->rows; y++)
765  {
766  const Quantum
767  *magick_restrict p;
768 
769  Quantum
770  *magick_restrict q;
771 
772  size_t
773  *histogram;
774 
775  ssize_t
776  x;
777 
778  if (status == MagickFalse)
779  continue;
780  p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t)
781  (width/2L),linear_image->columns+width,width,exception);
782  q=QueueCacheViewAuthenticPixels(paint_view,0,y,paint_image->columns,1,
783  exception);
784  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
785  {
786  status=MagickFalse;
787  continue;
788  }
789  histogram=histograms[GetOpenMPThreadId()];
790  for (x=0; x < (ssize_t) linear_image->columns; x++)
791  {
792  ssize_t
793  i,
794  u;
795 
796  size_t
797  count;
798 
799  ssize_t
800  j,
801  k,
802  n,
803  v;
804 
805  /*
806  Assign most frequent color.
807  */
808  k=0;
809  j=0;
810  count=0;
811  (void) memset(histogram,0,NumberPaintBins* sizeof(*histogram));
812  for (v=0; v < (ssize_t) width; v++)
813  {
814  for (u=0; u < (ssize_t) width; u++)
815  {
816  n=(ssize_t) ScaleQuantumToChar(ClampToQuantum(GetPixelIntensity(
817  linear_image,p+GetPixelChannels(linear_image)*(u+k))));
818  histogram[n]++;
819  if (histogram[n] > count)
820  {
821  j=k+u;
822  count=histogram[n];
823  }
824  }
825  k+=(ssize_t) (linear_image->columns+width);
826  }
827  for (i=0; i < (ssize_t) GetPixelChannels(linear_image); i++)
828  {
829  PixelChannel channel = GetPixelChannelChannel(linear_image,i);
830  PixelTrait traits = GetPixelChannelTraits(linear_image,channel);
831  PixelTrait paint_traits=GetPixelChannelTraits(paint_image,channel);
832  if ((traits == UndefinedPixelTrait) ||
833  (paint_traits == UndefinedPixelTrait))
834  continue;
835  if ((paint_traits & CopyPixelTrait) != 0)
836  {
837  SetPixelChannel(paint_image,channel,p[center+i],q);
838  continue;
839  }
840  SetPixelChannel(paint_image,channel,p[j*GetPixelChannels(linear_image)+
841  i],q);
842  }
843  p+=GetPixelChannels(linear_image);
844  q+=GetPixelChannels(paint_image);
845  }
846  if (SyncCacheViewAuthenticPixels(paint_view,exception) == MagickFalse)
847  status=MagickFalse;
848  if (linear_image->progress_monitor != (MagickProgressMonitor) NULL)
849  {
851  proceed;
852 
853 #if defined(MAGICKCORE_OPENMP_SUPPORT)
854  #pragma omp atomic
855 #endif
856  progress++;
857  proceed=SetImageProgress(linear_image,OilPaintImageTag,progress,
858  linear_image->rows);
859  if (proceed == MagickFalse)
860  status=MagickFalse;
861  }
862  }
863  paint_view=DestroyCacheView(paint_view);
864  image_view=DestroyCacheView(image_view);
865  histograms=DestroyHistogramThreadSet(histograms);
866  linear_image=DestroyImage(linear_image);
867  if (status == MagickFalse)
868  paint_image=DestroyImage(paint_image);
869  return(paint_image);
870 }
871 
872 /*
873 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
874 % %
875 % %
876 % %
877 % O p a q u e P a i n t I m a g e %
878 % %
879 % %
880 % %
881 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
882 %
883 % OpaquePaintImage() changes any pixel that matches color with the color
884 % defined by fill argument.
885 %
886 % By default color must match a particular pixel color exactly. However, in
887 % many cases two colors may differ by a small amount. Fuzz defines how much
888 % tolerance is acceptable to consider two colors as the same. For example,
889 % set fuzz to 10 and the color red at intensities of 100 and 102 respectively
890 % are now interpreted as the same color.
891 %
892 % The format of the OpaquePaintImage method is:
893 %
894 % MagickBooleanType OpaquePaintImage(Image *image,const PixelInfo *target,
895 % const PixelInfo *fill,const MagickBooleanType invert,
896 % ExceptionInfo *exception)
897 %
898 % A description of each parameter follows:
899 %
900 % o image: the image.
901 %
902 % o target: the RGB value of the target color.
903 %
904 % o fill: the replacement color.
905 %
906 % o invert: paint any pixel that does not match the target color.
907 %
908 % o exception: return any errors or warnings in this structure.
909 %
910 */
912  const PixelInfo *target,const PixelInfo *fill,const MagickBooleanType invert,
913  ExceptionInfo *exception)
914 {
915 #define OpaquePaintImageTag "Opaque/Image"
916 
917  CacheView
918  *image_view;
919 
921  status;
922 
924  progress;
925 
926  PixelInfo
927  conform_fill,
928  conform_target,
929  zero;
930 
931  ssize_t
932  y;
933 
934  assert(image != (Image *) NULL);
935  assert(image->signature == MagickCoreSignature);
936  assert(target != (PixelInfo *) NULL);
937  assert(fill != (PixelInfo *) NULL);
938  if (image->debug != MagickFalse)
939  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
940  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
941  return(MagickFalse);
942  ConformPixelInfo(image,fill,&conform_fill,exception);
943  ConformPixelInfo(image,target,&conform_target,exception);
944  /*
945  Make image color opaque.
946  */
947  status=MagickTrue;
948  progress=0;
949  GetPixelInfo(image,&zero);
950  image_view=AcquireAuthenticCacheView(image,exception);
951 #if defined(MAGICKCORE_OPENMP_SUPPORT)
952  #pragma omp parallel for schedule(static) shared(progress,status) \
953  magick_number_threads(image,image,image->rows,1)
954 #endif
955  for (y=0; y < (ssize_t) image->rows; y++)
956  {
957  PixelInfo
958  pixel;
959 
960  Quantum
961  *magick_restrict q;
962 
963  ssize_t
964  x;
965 
966  if (status == MagickFalse)
967  continue;
968  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
969  if (q == (Quantum *) NULL)
970  {
971  status=MagickFalse;
972  continue;
973  }
974  pixel=zero;
975  for (x=0; x < (ssize_t) image->columns; x++)
976  {
977  GetPixelInfoPixel(image,q,&pixel);
978  if (IsFuzzyEquivalencePixelInfo(&pixel,&conform_target) != invert)
979  {
980  PixelTrait
981  traits;
982 
984  if ((traits & UpdatePixelTrait) != 0)
985  SetPixelRed(image,(Quantum) conform_fill.red,q);
987  if ((traits & UpdatePixelTrait) != 0)
988  SetPixelGreen(image,(Quantum) conform_fill.green,q);
990  if ((traits & UpdatePixelTrait) != 0)
991  SetPixelBlue(image,(Quantum) conform_fill.blue,q);
993  if ((traits & UpdatePixelTrait) != 0)
994  SetPixelBlack(image,(Quantum) conform_fill.black,q);
996  if ((traits & UpdatePixelTrait) != 0)
997  SetPixelAlpha(image,(Quantum) conform_fill.alpha,q);
998  }
999  q+=GetPixelChannels(image);
1000  }
1001  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1002  status=MagickFalse;
1003  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1004  {
1006  proceed;
1007 
1008 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1009  #pragma omp atomic
1010 #endif
1011  progress++;
1012  proceed=SetImageProgress(image,OpaquePaintImageTag,progress,
1013  image->rows);
1014  if (proceed == MagickFalse)
1015  status=MagickFalse;
1016  }
1017  }
1018  image_view=DestroyCacheView(image_view);
1019  return(status);
1020 }
1021 
1022 /*
1023 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1024 % %
1025 % %
1026 % %
1027 % T r a n s p a r e n t P a i n t I m a g e %
1028 % %
1029 % %
1030 % %
1031 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1032 %
1033 % TransparentPaintImage() changes the opacity value associated with any pixel
1034 % that matches color to the value defined by opacity.
1035 %
1036 % By default color must match a particular pixel color exactly. However, in
1037 % many cases two colors may differ by a small amount. Fuzz defines how much
1038 % tolerance is acceptable to consider two colors as the same. For example,
1039 % set fuzz to 10 and the color red at intensities of 100 and 102 respectively
1040 % are now interpreted as the same color.
1041 %
1042 % The format of the TransparentPaintImage method is:
1043 %
1044 % MagickBooleanType TransparentPaintImage(Image *image,
1045 % const PixelInfo *target,const Quantum opacity,
1046 % const MagickBooleanType invert,ExceptionInfo *exception)
1047 %
1048 % A description of each parameter follows:
1049 %
1050 % o image: the image.
1051 %
1052 % o target: the target color.
1053 %
1054 % o opacity: the replacement opacity value.
1055 %
1056 % o invert: paint any pixel that does not match the target color.
1057 %
1058 % o exception: return any errors or warnings in this structure.
1059 %
1060 */
1062  const PixelInfo *target,const Quantum opacity,const MagickBooleanType invert,
1063  ExceptionInfo *exception)
1064 {
1065 #define TransparentPaintImageTag "Transparent/Image"
1066 
1067  CacheView
1068  *image_view;
1069 
1071  status;
1072 
1074  progress;
1075 
1076  PixelInfo
1077  zero;
1078 
1079  ssize_t
1080  y;
1081 
1082  assert(image != (Image *) NULL);
1083  assert(image->signature == MagickCoreSignature);
1084  assert(target != (PixelInfo *) NULL);
1085  if (image->debug != MagickFalse)
1086  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1087  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1088  return(MagickFalse);
1089  if (image->alpha_trait == UndefinedPixelTrait)
1090  (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1091  /*
1092  Make image color transparent.
1093  */
1094  status=MagickTrue;
1095  progress=0;
1096  GetPixelInfo(image,&zero);
1097  image_view=AcquireAuthenticCacheView(image,exception);
1098 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1099  #pragma omp parallel for schedule(static) shared(progress,status) \
1100  magick_number_threads(image,image,image->rows,1)
1101 #endif
1102  for (y=0; y < (ssize_t) image->rows; y++)
1103  {
1104  PixelInfo
1105  pixel;
1106 
1107  ssize_t
1108  x;
1109 
1110  Quantum
1111  *magick_restrict q;
1112 
1113  if (status == MagickFalse)
1114  continue;
1115  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1116  if (q == (Quantum *) NULL)
1117  {
1118  status=MagickFalse;
1119  continue;
1120  }
1121  pixel=zero;
1122  for (x=0; x < (ssize_t) image->columns; x++)
1123  {
1124  GetPixelInfoPixel(image,q,&pixel);
1125  if (IsFuzzyEquivalencePixelInfo(&pixel,target) != invert)
1126  SetPixelAlpha(image,opacity,q);
1127  q+=GetPixelChannels(image);
1128  }
1129  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1130  status=MagickFalse;
1131  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1132  {
1134  proceed;
1135 
1136 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1137  #pragma omp atomic
1138 #endif
1139  progress++;
1140  proceed=SetImageProgress(image,TransparentPaintImageTag,progress,
1141  image->rows);
1142  if (proceed == MagickFalse)
1143  status=MagickFalse;
1144  }
1145  }
1146  image_view=DestroyCacheView(image_view);
1147  return(status);
1148 }
1149 
1150 /*
1151 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1152 % %
1153 % %
1154 % %
1155 % T r a n s p a r e n t P a i n t I m a g e C h r o m a %
1156 % %
1157 % %
1158 % %
1159 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1160 %
1161 % TransparentPaintImageChroma() changes the opacity value associated with any
1162 % pixel that matches color to the value defined by opacity.
1163 %
1164 % As there is one fuzz value for the all the channels, TransparentPaintImage()
1165 % is not suitable for the operations like chroma, where the tolerance for
1166 % similarity of two color component (RGB) can be different. Thus we define
1167 % this method to take two target pixels (one low and one high) and all the
1168 % pixels of an image which are lying between these two pixels are made
1169 % transparent.
1170 %
1171 % The format of the TransparentPaintImageChroma method is:
1172 %
1173 % MagickBooleanType TransparentPaintImageChroma(Image *image,
1174 % const PixelInfo *low,const PixelInfo *high,const Quantum opacity,
1175 % const MagickBooleanType invert,ExceptionInfo *exception)
1176 %
1177 % A description of each parameter follows:
1178 %
1179 % o image: the image.
1180 %
1181 % o low: the low target color.
1182 %
1183 % o high: the high target color.
1184 %
1185 % o opacity: the replacement opacity value.
1186 %
1187 % o invert: paint any pixel that does not match the target color.
1188 %
1189 % o exception: return any errors or warnings in this structure.
1190 %
1191 */
1193  const PixelInfo *low,const PixelInfo *high,const Quantum opacity,
1194  const MagickBooleanType invert,ExceptionInfo *exception)
1195 {
1196 #define TransparentPaintImageTag "Transparent/Image"
1197 
1198  CacheView
1199  *image_view;
1200 
1202  status;
1203 
1205  progress;
1206 
1207  ssize_t
1208  y;
1209 
1210  assert(image != (Image *) NULL);
1211  assert(image->signature == MagickCoreSignature);
1212  assert(high != (PixelInfo *) NULL);
1213  assert(low != (PixelInfo *) NULL);
1214  if (image->debug != MagickFalse)
1215  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1216  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1217  return(MagickFalse);
1218  if (image->alpha_trait == UndefinedPixelTrait)
1219  (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1220  /*
1221  Make image color transparent.
1222  */
1223  status=MagickTrue;
1224  progress=0;
1225  image_view=AcquireAuthenticCacheView(image,exception);
1226 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1227  #pragma omp parallel for schedule(static) shared(progress,status) \
1228  magick_number_threads(image,image,image->rows,1)
1229 #endif
1230  for (y=0; y < (ssize_t) image->rows; y++)
1231  {
1233  match;
1234 
1235  PixelInfo
1236  pixel;
1237 
1238  Quantum
1239  *magick_restrict q;
1240 
1241  ssize_t
1242  x;
1243 
1244  if (status == MagickFalse)
1245  continue;
1246  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1247  if (q == (Quantum *) NULL)
1248  {
1249  status=MagickFalse;
1250  continue;
1251  }
1252  GetPixelInfo(image,&pixel);
1253  for (x=0; x < (ssize_t) image->columns; x++)
1254  {
1255  GetPixelInfoPixel(image,q,&pixel);
1256  match=((pixel.red >= low->red) && (pixel.red <= high->red) &&
1257  (pixel.green >= low->green) && (pixel.green <= high->green) &&
1258  (pixel.blue >= low->blue) && (pixel.blue <= high->blue)) ? MagickTrue :
1259  MagickFalse;
1260  if (match != invert)
1261  SetPixelAlpha(image,opacity,q);
1262  q+=GetPixelChannels(image);
1263  }
1264  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1265  status=MagickFalse;
1266  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1267  {
1269  proceed;
1270 
1271 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1272  #pragma omp atomic
1273 #endif
1274  progress++;
1275  proceed=SetImageProgress(image,TransparentPaintImageTag,progress,
1276  image->rows);
1277  if (proceed == MagickFalse)
1278  status=MagickFalse;
1279  }
1280  }
1281  image_view=DestroyCacheView(image_view);
1282  return(status);
1283 }
size_t rows
Definition: image.h:172
#define magick_restrict
Definition: MagickCore.h:41
PixelInfo fill
Definition: draw.h:214
MagickExport CacheView * DestroyCacheView(CacheView *cache_view)
Definition: cache-view.c:252
double x2
Definition: image.h:107
MagickExport MemoryInfo * RelinquishVirtualMemory(MemoryInfo *memory_info)
Definition: memory.c:1229
MagickProgressMonitor progress_monitor
Definition: image.h:303
PixelTrait alpha_trait
Definition: pixel.h:181
GradientType type
Definition: draw.h:150
RectangleInfo bounding_box
Definition: draw.h:153
MagickExport ssize_t ParseCommandOption(const CommandOption option, const MagickBooleanType list, const char *options)
Definition: option.c:3055
MagickExport MemoryInfo * AcquireVirtualMemory(const size_t count, const size_t quantum)
Definition: memory.c:705
static Quantum GetPixelGray(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
size_t signature
Definition: exception.h:123
MagickExport MagickStatusType ParseAbsoluteGeometry(const char *geometry, RectangleInfo *region_info)
Definition: geometry.c:710
static void GetFillColor(const DrawInfo *draw_info, const ssize_t x, const ssize_t y, PixelInfo *fill, ExceptionInfo *exception)
Definition: draw-private.h:29
static void SetPixelGray(const Image *magick_restrict image, const Quantum gray, Quantum *magick_restrict pixel)
#define OpaqueAlpha
Definition: image.h:25
MagickExport const char * GetImageArtifact(const Image *image, const char *artifact)
Definition: artifact.c:273
MagickRealType red
Definition: pixel.h:193
MagickExport MagickBooleanType TransparentPaintImage(Image *image, const PixelInfo *target, const Quantum opacity, const MagickBooleanType invert, ExceptionInfo *exception)
Definition: paint.c:1061
MagickExport MagickBooleanType SetImageAlpha(Image *image, const Quantum alpha, ExceptionInfo *exception)
Definition: image.c:2335
static PixelTrait GetPixelChannelTraits(const Image *magick_restrict image, const PixelChannel channel)
static void SetPixelViaPixelInfo(const Image *magick_restrict image, const PixelInfo *magick_restrict pixel_info, Quantum *magick_restrict pixel)
static MagickBooleanType IsGrayColorspace(const ColorspaceType colorspace)
#define NumberPaintBins
double angle
Definition: draw.h:175
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
MagickExport MagickBooleanType FloodfillPaintImage(Image *image, const DrawInfo *draw_info, const PixelInfo *target, const ssize_t x_offset, const ssize_t y_offset, const MagickBooleanType invert, ExceptionInfo *exception)
Definition: paint.c:112
MagickRealType alpha
Definition: pixel.h:193
PointInfo radii
Definition: draw.h:171
SpreadMethod spread
Definition: draw.h:165
size_t width
Definition: geometry.h:131
#define ThrowBinaryException(severity, tag, context)
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
MagickExport MagickBooleanType DrawGradientImage(Image *image, const DrawInfo *draw_info, ExceptionInfo *exception)
Definition: draw.c:1999
double x
Definition: geometry.h:124
#define MaxStacksize
SpreadMethod
Definition: draw.h:130
#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
GradientType
Definition: draw.h:71
MagickExport MagickBooleanType SetImageAlphaChannel(Image *image, const AlphaChannelOption alpha_type, ExceptionInfo *exception)
Definition: channel.c:974
MagickBooleanType
Definition: magick-type.h:165
MagickExport MagickBooleanType TransparentPaintImageChroma(Image *image, const PixelInfo *low, const PixelInfo *high, const Quantum opacity, const MagickBooleanType invert, ExceptionInfo *exception)
Definition: paint.c:1192
static size_t ** AcquireHistogramThreadSet(const size_t count)
Definition: paint.c:667
double x1
Definition: image.h:107
MagickExport DrawInfo * AcquireDrawInfo(void)
Definition: draw.c:232
MagickExport void * AcquireQuantumMemory(const size_t count, const size_t quantum)
Definition: memory.c:665
PointInfo center
Definition: draw.h:171
MagickPrivate size_t GetOptimalKernelWidth2D(const double, const double)
Definition: gem.c:1685
static double DegreesToRadians(const double degrees)
Definition: image-private.h:64
double y
Definition: geometry.h:124
static int GetOpenMPThreadId(void)
StopInfo * stops
Definition: draw.h:159
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
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
GravityType
Definition: geometry.h:78
double y2
Definition: image.h:107
MagickExport MagickBooleanType LogMagickEvent(const LogEventType type, const char *module, const char *function, const size_t line, const char *format,...)
Definition: log.c:1660
MagickExport MagickBooleanType SetImageBackgroundColor(Image *image, ExceptionInfo *exception)
Definition: image.c:2414
size_t signature
Definition: image.h:354
MagickExport MagickSizeType GetMagickResourceLimit(const ResourceType type)
Definition: resource.c:793
size_t columns
Definition: image.h:172
MagickBooleanType(* MagickProgressMonitor)(const char *, const MagickOffsetType, const MagickSizeType, void *)
Definition: monitor.h:26
size_t height
Definition: geometry.h:131
MagickExport MagickBooleanType QueryColorCompliance(const char *name, const ComplianceType compliance, PixelInfo *color, ExceptionInfo *exception)
Definition: color.c:2265
static void SetPixelBlue(const Image *magick_restrict image, const Quantum blue, Quantum *magick_restrict pixel)
MagickExport MagickBooleanType SetImageStorageClass(Image *image, const ClassType storage_class, ExceptionInfo *exception)
Definition: image.c:2614
PixelChannel
Definition: pixel.h:70
#define TransparentPaintImageTag
GradientInfo gradient
Definition: draw.h:227
#define MagickMax(x, y)
Definition: image-private.h:36
MagickExport MagickBooleanType OpaquePaintImage(Image *image, const PixelInfo *target, const PixelInfo *fill, const MagickBooleanType invert, ExceptionInfo *exception)
Definition: paint.c:911
static size_t GetPixelChannels(const Image *magick_restrict image)
MagickExport int LocaleCompare(const char *p, const char *q)
Definition: locale.c:1399
char filename[MagickPathExtent]
Definition: image.h:319
#define GetMagickModule()
Definition: log.h:28
#define OilPaintImageTag
MagickExport void ConformPixelInfo(Image *image, const PixelInfo *source, PixelInfo *destination, ExceptionInfo *exception)
Definition: pixel.c:212
#define ThrowImageException(severity, tag)
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
size_t signature
Definition: draw.h:323
unsigned short Quantum
Definition: magick-type.h:86
MagickExport MagickBooleanType SetImageColorspace(Image *image, const ColorspaceType colorspace, ExceptionInfo *exception)
Definition: colorspace.c:1420
MagickExport DrawInfo * DestroyDrawInfo(DrawInfo *draw_info)
Definition: draw.c:966
static size_t ** DestroyHistogramThreadSet(size_t **histogram)
Definition: paint.c:654
MagickRealType black
Definition: pixel.h:193
MagickExport MagickBooleanType IsFuzzyEquivalencePixelInfo(const PixelInfo *p, const PixelInfo *q)
Definition: pixel.c:6054
SegmentInfo gradient_vector
Definition: draw.h:156
#define OpaquePaintImageTag
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)
static double StringToDouble(const char *magick_restrict string, char *magick_restrict *sentinal)
MagickExport void * RelinquishMagickMemory(void *memory)
Definition: memory.c:1162
MagickRealType green
Definition: pixel.h:193
MagickExport MagickBooleanType GradientImage(Image *image, const GradientType type, const SpreadMethod method, const StopInfo *stops, const size_t number_stops, ExceptionInfo *exception)
Definition: paint.c:409
static void SetPixelRed(const Image *magick_restrict image, const Quantum red, Quantum *magick_restrict pixel)
size_t number_stops
Definition: draw.h:162
#define PushSegmentStack(up, left, right, delta)
#define MagickExport
double radius
Definition: draw.h:175
MagickExport MagickBooleanType SyncCacheViewAuthenticPixels(CacheView *magick_restrict cache_view, ExceptionInfo *exception)
Definition: cache-view.c:1100
MagickExport Image * OilPaintImage(const Image *image, const double radius, const double sigma, ExceptionInfo *exception)
Definition: paint.c:690
MagickExport CacheView * AcquireAuthenticCacheView(const Image *image, ExceptionInfo *exception)
Definition: cache-view.c:112
double y1
Definition: image.h:107
static void SetPixelBlack(const Image *magick_restrict image, const Quantum black, Quantum *magick_restrict pixel)
PixelTrait
Definition: pixel.h:137
MagickExport void * GetVirtualMemoryBlob(const MemoryInfo *memory_info)
Definition: memory.c:1090
MagickExport MagickRealType GetPixelIntensity(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
Definition: pixel.c:2358
PixelInfo background_color
Definition: image.h:179
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
static void SetPixelGreen(const Image *magick_restrict image, const Quantum green, Quantum *magick_restrict pixel)