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