00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #include "magick/studio.h"
00042 #include "magick/color.h"
00043 #include "magick/color-private.h"
00044 #include "magick/colorspace-private.h"
00045 #include "magick/composite.h"
00046 #include "magick/composite-private.h"
00047 #include "magick/draw.h"
00048 #include "magick/draw-private.h"
00049 #include "magick/exception.h"
00050 #include "magick/exception-private.h"
00051 #include "magick/gem.h"
00052 #include "magick/monitor.h"
00053 #include "magick/monitor-private.h"
00054 #include "magick/paint.h"
00055 #include "magick/pixel-private.h"
00056 #include "magick/string_.h"
00057
00058 static inline double MagickMax(const double x,const double y)
00059 {
00060 return( x > y ? x : y);
00061 }
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107 MagickExport MagickBooleanType FloodfillPaintImage(Image *image,
00108 const ChannelType channel,const DrawInfo *draw_info,
00109 const MagickPixelPacket *target,const long x_offset,const long y_offset,
00110 const MagickBooleanType invert)
00111 {
00112 #define MaxStacksize (1UL << 15)
00113 #define PushSegmentStack(up,left,right,delta) \
00114 { \
00115 if (s >= (segment_stack+MaxStacksize)) \
00116 ThrowBinaryException(DrawError,"SegmentStackOverflow",image->filename) \
00117 else \
00118 { \
00119 if ((((up)+(delta)) >= 0) && (((up)+(delta)) < (long) image->rows)) \
00120 { \
00121 s->x1=(double) (left); \
00122 s->y1=(double) (up); \
00123 s->x2=(double) (right); \
00124 s->y2=(double) (delta); \
00125 s++; \
00126 } \
00127 } \
00128 }
00129
00130 ExceptionInfo
00131 *exception;
00132
00133 Image
00134 *floodplane_image;
00135
00136 long
00137 offset,
00138 start,
00139 x1,
00140 x2,
00141 y;
00142
00143 MagickBooleanType
00144 skip;
00145
00146 MagickPixelPacket
00147 fill,
00148 pixel;
00149
00150 PixelPacket
00151 fill_color;
00152
00153 register const IndexPacket
00154 *indexes;
00155
00156 register const PixelPacket
00157 *p;
00158
00159 register long
00160 x;
00161
00162 register PixelPacket
00163 *q;
00164
00165 register SegmentInfo
00166 *s;
00167
00168 SegmentInfo
00169 *segment_stack;
00170
00171
00172
00173
00174 assert(image != (Image *) NULL);
00175 assert(image->signature == MagickSignature);
00176 if (image->debug != MagickFalse)
00177 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00178 assert(draw_info != (DrawInfo *) NULL);
00179 assert(draw_info->signature == MagickSignature);
00180 if ((x_offset < 0) || (x_offset >= (long) image->columns))
00181 return(MagickFalse);
00182 if ((y_offset < 0) || (y_offset >= (long) image->rows))
00183 return(MagickFalse);
00184 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
00185 return(MagickFalse);
00186 if (image->matte == MagickFalse)
00187 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
00188
00189
00190
00191 floodplane_image=CloneImage(image,0,0,MagickTrue,&image->exception);
00192 if (floodplane_image == (Image *) NULL)
00193 return(MagickFalse);
00194 (void) SetImageAlphaChannel(floodplane_image,OpaqueAlphaChannel);
00195 segment_stack=(SegmentInfo *) AcquireQuantumMemory(MaxStacksize,
00196 sizeof(*segment_stack));
00197 if (segment_stack == (SegmentInfo *) NULL)
00198 {
00199 floodplane_image=DestroyImage(floodplane_image);
00200 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
00201 image->filename);
00202 }
00203
00204
00205
00206 exception=(&image->exception);
00207 x=x_offset;
00208 y=y_offset;
00209 start=0;
00210 s=segment_stack;
00211 PushSegmentStack(y,x,x,1);
00212 PushSegmentStack(y+1,x,x,-1);
00213 GetMagickPixelPacket(image,&fill);
00214 GetMagickPixelPacket(image,&pixel);
00215 while (s > segment_stack)
00216 {
00217
00218
00219
00220 s--;
00221 x1=(long) s->x1;
00222 x2=(long) s->x2;
00223 offset=(long) s->y2;
00224 y=(long) s->y1+offset;
00225
00226
00227
00228 p=GetVirtualPixels(image,0,y,(unsigned long) (x1+1),1,exception);
00229 q=GetAuthenticPixels(floodplane_image,0,y,(unsigned long) (x1+1),1,
00230 exception);
00231 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00232 break;
00233 indexes=GetVirtualIndexQueue(image);
00234 p+=x1;
00235 q+=x1;
00236 for (x=x1; x >= 0; x--)
00237 {
00238 if (q->opacity == (Quantum) TransparentOpacity)
00239 break;
00240 SetMagickPixelPacket(image,p,indexes+x,&pixel);
00241 if (IsMagickColorSimilar(&pixel,target) == invert)
00242 break;
00243 q->opacity=(Quantum) TransparentOpacity;
00244 p--;
00245 q--;
00246 }
00247 if (SyncAuthenticPixels(floodplane_image,exception) == MagickFalse)
00248 break;
00249 skip=x >= x1 ? MagickTrue : MagickFalse;
00250 if (skip == MagickFalse)
00251 {
00252 start=x+1;
00253 if (start < x1)
00254 PushSegmentStack(y,start,x1-1,-offset);
00255 x=x1+1;
00256 }
00257 do
00258 {
00259 if (skip == MagickFalse)
00260 {
00261 if (x < (long) image->columns)
00262 {
00263 p=GetVirtualPixels(image,x,y,image->columns-x,1,exception);
00264 q=GetAuthenticPixels(floodplane_image,x,y,image->columns-x,1,
00265 exception);
00266 if ((p == (const PixelPacket *) NULL) ||
00267 (q == (PixelPacket *) NULL))
00268 break;
00269 indexes=GetVirtualIndexQueue(image);
00270 for ( ; x < (long) image->columns; x++)
00271 {
00272 if (q->opacity == (Quantum) TransparentOpacity)
00273 break;
00274 SetMagickPixelPacket(image,p,indexes+x,&pixel);
00275 if (IsMagickColorSimilar(&pixel,target) == invert)
00276 break;
00277 q->opacity=(Quantum) TransparentOpacity;
00278 p++;
00279 q++;
00280 }
00281 if (SyncAuthenticPixels(floodplane_image,exception) == MagickFalse)
00282 break;
00283 }
00284 PushSegmentStack(y,start,x-1,offset);
00285 if (x > (x2+1))
00286 PushSegmentStack(y,x2+1,x-1,-offset);
00287 }
00288 skip=MagickFalse;
00289 x++;
00290 if (x <= x2)
00291 {
00292 p=GetVirtualPixels(image,x,y,(unsigned long) (x2-x+1),1,exception);
00293 q=GetAuthenticPixels(floodplane_image,x,y,(unsigned long) (x2-x+1),1,
00294 exception);
00295 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00296 break;
00297 indexes=GetVirtualIndexQueue(image);
00298 for ( ; x <= x2; x++)
00299 {
00300 if (q->opacity == (Quantum) TransparentOpacity)
00301 break;
00302 SetMagickPixelPacket(image,p,indexes+x,&pixel);
00303 if (IsMagickColorSimilar(&pixel,target) != invert)
00304 break;
00305 p++;
00306 q++;
00307 }
00308 }
00309 start=x;
00310 } while (x <= x2);
00311 }
00312 for (y=0; y < (long) image->rows; y++)
00313 {
00314 register IndexPacket
00315 *indexes;
00316
00317
00318
00319
00320 p=GetVirtualPixels(floodplane_image,0,y,image->columns,1,exception);
00321 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
00322 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00323 break;
00324 indexes=GetAuthenticIndexQueue(image);
00325 for (x=0; x < (long) image->columns; x++)
00326 {
00327 if (p->opacity != OpaqueOpacity)
00328 {
00329 (void) GetFillColor(draw_info,x,y,&fill_color);
00330 SetMagickPixelPacket(image,&fill_color,(IndexPacket *) NULL,&fill);
00331 if (image->colorspace == CMYKColorspace)
00332 ConvertRGBToCMYK(&fill);
00333 if ((channel & RedChannel) != 0)
00334 q->red=RoundToQuantum(fill.red);
00335 if ((channel & GreenChannel) != 0)
00336 q->green=RoundToQuantum(fill.green);
00337 if ((channel & BlueChannel) != 0)
00338 q->blue=RoundToQuantum(fill.blue);
00339 if ((channel & OpacityChannel) != 0)
00340 q->opacity=RoundToQuantum(fill.opacity);
00341 if (((channel & IndexChannel) != 0) &&
00342 (image->colorspace == CMYKColorspace))
00343 indexes[x]=RoundToQuantum(fill.index);
00344 }
00345 p++;
00346 q++;
00347 }
00348 if (SyncAuthenticPixels(image,exception) == MagickFalse)
00349 break;
00350 }
00351 segment_stack=(SegmentInfo *) RelinquishMagickMemory(segment_stack);
00352 floodplane_image=DestroyImage(floodplane_image);
00353 return(y == (long) image->rows ? MagickTrue : MagickFalse);
00354 }
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394 MagickExport MagickBooleanType GradientImage(Image *image,
00395 const GradientType type,const SpreadMethod method,
00396 const PixelPacket *start_color,const PixelPacket *stop_color)
00397 {
00398 DrawInfo
00399 *draw_info;
00400
00401 GradientInfo
00402 *gradient;
00403
00404 MagickBooleanType
00405 status;
00406
00407 register long
00408 i;
00409
00410
00411
00412
00413 assert(image != (const Image *) NULL);
00414 assert(image->signature == MagickSignature);
00415 if (image->debug != MagickFalse)
00416 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00417 assert(start_color != (const PixelPacket *) NULL);
00418 assert(stop_color != (const PixelPacket *) NULL);
00419 draw_info=AcquireDrawInfo();
00420 gradient=(&draw_info->gradient);
00421 gradient->type=type;
00422 gradient->bounding_box.width=image->columns;
00423 gradient->bounding_box.height=image->rows;
00424 gradient->gradient_vector.x2=(double) image->columns-1.0;
00425 gradient->gradient_vector.y2=(double) image->rows-1.0;
00426 if ((type == LinearGradient) && (gradient->gradient_vector.y2 != 0.0))
00427 gradient->gradient_vector.x2=0.0;
00428 gradient->center.x=(double) gradient->gradient_vector.x2/2.0;
00429 gradient->center.y=(double) gradient->gradient_vector.y2/2.0;
00430 gradient->radius=MagickMax(gradient->center.x,gradient->center.y);
00431 gradient->spread=method;
00432
00433
00434
00435 gradient->number_stops=2;
00436 gradient->stops=(StopInfo *) AcquireQuantumMemory(gradient->number_stops,
00437 sizeof(*gradient->stops));
00438 if (gradient->stops == (StopInfo *) NULL)
00439 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
00440 image->filename);
00441 (void) ResetMagickMemory(gradient->stops,0,gradient->number_stops*
00442 sizeof(*gradient->stops));
00443 for (i=0; i < (long) gradient->number_stops; i++)
00444 GetMagickPixelPacket(image,&gradient->stops[i].color);
00445 SetMagickPixelPacket(image,start_color,(IndexPacket *) NULL,
00446 &gradient->stops[0].color);
00447 gradient->stops[0].offset=0.0;
00448 SetMagickPixelPacket(image,stop_color,(IndexPacket *) NULL,
00449 &gradient->stops[1].color);
00450 gradient->stops[1].offset=1.0;
00451
00452
00453
00454 status=DrawGradientImage(image,draw_info);
00455 draw_info=DestroyDrawInfo(draw_info);
00456 if ((start_color->opacity == OpaqueOpacity) &&
00457 (stop_color->opacity == OpaqueOpacity))
00458 image->matte=MagickFalse;
00459 if ((IsGrayPixel(start_color) != MagickFalse) &&
00460 (IsGrayPixel(stop_color) != MagickFalse))
00461 image->type=GrayscaleType;
00462 return(status);
00463 }
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495 static unsigned long **DestroyHistogramThreadSet(unsigned long **histogram)
00496 {
00497 register long
00498 i;
00499
00500 assert(histogram != (unsigned long **) NULL);
00501 for (i=0; i < (long) GetPixelCacheMaximumThreads(); i++)
00502 if (histogram[i] != (unsigned long *) NULL)
00503 histogram[i]=(unsigned long *) RelinquishMagickMemory(histogram[i]);
00504 return((unsigned long **) RelinquishMagickMemory(histogram));
00505 }
00506
00507 static unsigned long **AcquireHistogramThreadSet(const size_t count)
00508 {
00509 register long
00510 i;
00511
00512 unsigned long
00513 **histogram,
00514 number_threads;
00515
00516 number_threads=GetPixelCacheMaximumThreads();
00517 histogram=(unsigned long **) AcquireQuantumMemory(number_threads,
00518 sizeof(*histogram));
00519 if (histogram == (unsigned long **) NULL)
00520 return((unsigned long **) NULL);
00521 (void) ResetMagickMemory(histogram,0,number_threads*sizeof(*histogram));
00522 for (i=0; i < (long) number_threads; i++)
00523 {
00524 histogram[i]=(unsigned long *) AcquireQuantumMemory(count,
00525 sizeof(**histogram));
00526 if (histogram[i] == (unsigned long *) NULL)
00527 return(DestroyHistogramThreadSet(histogram));
00528 }
00529 return(histogram);
00530 }
00531
00532 MagickExport Image *OilPaintImage(const Image *image,const double radius,
00533 ExceptionInfo *exception)
00534 {
00535 #define NumberPaintBins 256
00536 #define OilPaintImageTag "OilPaint/Image"
00537
00538 Image
00539 *paint_image;
00540
00541 long
00542 progress,
00543 y;
00544
00545 MagickBooleanType
00546 status;
00547
00548 unsigned long
00549 **histogram,
00550 width;
00551
00552 ViewInfo
00553 *image_view,
00554 *paint_view;
00555
00556
00557
00558
00559 assert(image != (const Image *) NULL);
00560 assert(image->signature == MagickSignature);
00561 if (image->debug != MagickFalse)
00562 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00563 assert(exception != (ExceptionInfo *) NULL);
00564 assert(exception->signature == MagickSignature);
00565 width=GetOptimalKernelWidth2D(radius,0.5);
00566 if ((image->columns < width) || (image->rows < width))
00567 ThrowImageException(OptionError,"ImageSmallerThanRadius");
00568 paint_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
00569 if (paint_image == (Image *) NULL)
00570 return((Image *) NULL);
00571 if (SetImageStorageClass(paint_image,DirectClass) == MagickFalse)
00572 {
00573 InheritException(exception,&paint_image->exception);
00574 paint_image=DestroyImage(paint_image);
00575 return((Image *) NULL);
00576 }
00577 histogram=AcquireHistogramThreadSet(NumberPaintBins);
00578 if (histogram == (unsigned long **) NULL)
00579 {
00580 paint_image=DestroyImage(paint_image);
00581 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
00582 }
00583
00584
00585
00586 status=MagickTrue;
00587 progress=0;
00588 image_view=AcquireCacheView(image);
00589 paint_view=AcquireCacheView(paint_image);
00590 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00591 #pragma omp parallel for schedule(dynamic,8) shared(progress,status)
00592 #endif
00593 for (y=0; y < (long) image->rows; y++)
00594 {
00595 const IndexPacket
00596 *indexes;
00597
00598 IndexPacket
00599 *paint_indexes;
00600
00601 register const PixelPacket
00602 *p;
00603
00604 register long
00605 id,
00606 x;
00607
00608 register PixelPacket
00609 *q;
00610
00611 if (status == MagickFalse)
00612 continue;
00613 p=GetCacheViewVirtualPixels(image_view,-((long) width/2L),y-(long) (width/
00614 2L),image->columns+width,width,exception);
00615 q=QueueCacheViewAuthenticPixels(paint_view,0,y,paint_image->columns,1,
00616 exception);
00617 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00618 {
00619 status=MagickFalse;
00620 continue;
00621 }
00622 indexes=GetCacheViewVirtualIndexQueue(image_view);
00623 paint_indexes=GetCacheViewAuthenticIndexQueue(paint_view);
00624 id=GetPixelCacheThreadId();
00625 for (x=0; x < (long) image->columns; x++)
00626 {
00627 long
00628 j,
00629 k,
00630 v;
00631
00632 register long
00633 i,
00634 u;
00635
00636 unsigned long
00637 count;
00638
00639
00640
00641
00642 i=0;
00643 j=0;
00644 count=0;
00645 (void) ResetMagickMemory(histogram[id],0,NumberPaintBins*
00646 sizeof(**histogram));
00647 for (v=0; v < (long) width; v++)
00648 {
00649 for (u=0; u < (long) width; u++)
00650 {
00651 k=(long) ScaleQuantumToChar(PixelIntensityToQuantum(p+u+i));
00652 histogram[id][k]++;
00653 if (histogram[id][k] > count)
00654 {
00655 j=i+u;
00656 count=histogram[id][k];
00657 }
00658 }
00659 i+=image->columns+width;
00660 }
00661 *q=(*(p+j));
00662 if (image->colorspace == CMYKColorspace)
00663 paint_indexes[x]=indexes[x+j];
00664 p++;
00665 q++;
00666 }
00667 if (SyncCacheViewAuthenticPixels(paint_view,exception) == MagickFalse)
00668 status=MagickFalse;
00669 if (image->progress_monitor != (MagickProgressMonitor) NULL)
00670 {
00671 MagickBooleanType
00672 proceed;
00673
00674 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00675 #pragma omp critical
00676 #endif
00677 proceed=SetImageProgress(image,OilPaintImageTag,progress++,image->rows);
00678 if (proceed == MagickFalse)
00679 status=MagickFalse;
00680 }
00681 }
00682 paint_view=DestroyCacheView(paint_view);
00683 image_view=DestroyCacheView(image_view);
00684 histogram=DestroyHistogramThreadSet(histogram);
00685 if (status == MagickFalse)
00686 paint_image=DestroyImage(paint_image);
00687 return(paint_image);
00688 }
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733 MagickExport MagickBooleanType OpaquePaintImage(Image *image,
00734 const MagickPixelPacket *target,const MagickPixelPacket *fill,
00735 const MagickBooleanType invert)
00736 {
00737 return(OpaquePaintImageChannel(image,AllChannels,target,fill,invert));
00738 }
00739
00740 MagickExport MagickBooleanType OpaquePaintImageChannel(Image *image,
00741 const ChannelType channel,const MagickPixelPacket *target,
00742 const MagickPixelPacket *fill,const MagickBooleanType invert)
00743 {
00744 #define OpaquePaintImageTag "Opaque/Image"
00745
00746 ExceptionInfo
00747 *exception;
00748
00749 long
00750 progress,
00751 y;
00752
00753 MagickBooleanType
00754 status;
00755
00756 MagickPixelPacket
00757 zero;
00758
00759 ViewInfo
00760 *image_view;
00761
00762 assert(image != (Image *) NULL);
00763 assert(image->signature == MagickSignature);
00764 assert(target != (MagickPixelPacket *) NULL);
00765 assert(fill != (MagickPixelPacket *) NULL);
00766 if (image->debug != MagickFalse)
00767 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00768 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
00769 return(MagickFalse);
00770
00771
00772
00773 status=MagickTrue;
00774 progress=0;
00775 exception=(&image->exception);
00776 GetMagickPixelPacket(image,&zero);
00777 image_view=AcquireCacheView(image);
00778 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00779 #pragma omp parallel for schedule(dynamic,8) shared(progress,status)
00780 #endif
00781 for (y=0; y < (long) image->rows; y++)
00782 {
00783 MagickPixelPacket
00784 pixel;
00785
00786 register IndexPacket
00787 *indexes;
00788
00789 register long
00790 x;
00791
00792 register PixelPacket
00793 *q;
00794
00795 if (status == MagickFalse)
00796 continue;
00797 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
00798 if (q == (PixelPacket *) NULL)
00799 {
00800 status=MagickFalse;
00801 continue;
00802 }
00803 indexes=GetCacheViewAuthenticIndexQueue(image_view);
00804 pixel=zero;
00805 for (x=0; x < (long) image->columns; x++)
00806 {
00807 SetMagickPixelPacket(image,q,indexes+x,&pixel);
00808 if (IsMagickColorSimilar(&pixel,target) != invert)
00809 {
00810 if ((channel & RedChannel) != 0)
00811 q->red=RoundToQuantum(fill->red);
00812 if ((channel & GreenChannel) != 0)
00813 q->green=RoundToQuantum(fill->green);
00814 if ((channel & BlueChannel) != 0)
00815 q->blue=RoundToQuantum(fill->blue);
00816 if ((channel & OpacityChannel) != 0)
00817 q->opacity=RoundToQuantum(fill->opacity);
00818 if (((channel & IndexChannel) != 0) &&
00819 (image->colorspace == CMYKColorspace))
00820 indexes[x]=RoundToQuantum(fill->index);
00821 }
00822 q++;
00823 }
00824 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
00825 status=MagickFalse;
00826 if (image->progress_monitor != (MagickProgressMonitor) NULL)
00827 {
00828 MagickBooleanType
00829 proceed;
00830
00831 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00832 #pragma omp critical
00833 #endif
00834 proceed=SetImageProgress(image,OpaquePaintImageTag,progress++,
00835 image->rows);
00836 if (proceed == MagickFalse)
00837 status=MagickFalse;
00838 }
00839 }
00840 image_view=DestroyCacheView(image_view);
00841 return(status);
00842 }
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881 MagickExport MagickBooleanType TransparentPaintImage(Image *image,
00882 const MagickPixelPacket *target,const Quantum opacity,
00883 const MagickBooleanType invert)
00884 {
00885 #define TransparentPaintImageTag "Transparent/Image"
00886
00887 ExceptionInfo
00888 *exception;
00889
00890 long
00891 progress,
00892 y;
00893
00894 MagickBooleanType
00895 status;
00896
00897 MagickPixelPacket
00898 zero;
00899
00900 ViewInfo
00901 *image_view;
00902
00903 assert(image != (Image *) NULL);
00904 assert(image->signature == MagickSignature);
00905 assert(target != (MagickPixelPacket *) NULL);
00906 if (image->debug != MagickFalse)
00907 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00908 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
00909 return(MagickFalse);
00910 if (image->matte == MagickFalse)
00911 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
00912
00913
00914
00915 status=MagickTrue;
00916 progress=0;
00917 exception=(&image->exception);
00918 GetMagickPixelPacket(image,&zero);
00919 image_view=AcquireCacheView(image);
00920 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00921 #pragma omp parallel for schedule(dynamic,8) shared(progress,status)
00922 #endif
00923 for (y=0; y < (long) image->rows; y++)
00924 {
00925 MagickPixelPacket
00926 pixel;
00927
00928 register IndexPacket
00929 *indexes;
00930
00931 register long
00932 x;
00933
00934 register PixelPacket
00935 *q;
00936
00937 if (status == MagickFalse)
00938 continue;
00939 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
00940 if (q == (PixelPacket *) NULL)
00941 {
00942 status=MagickFalse;
00943 continue;
00944 }
00945 indexes=GetCacheViewAuthenticIndexQueue(image_view);
00946 pixel=zero;
00947 for (x=0; x < (long) image->columns; x++)
00948 {
00949 SetMagickPixelPacket(image,q,indexes+x,&pixel);
00950 if (IsMagickColorSimilar(&pixel,target) != invert)
00951 q->opacity=opacity;
00952 q++;
00953 }
00954 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
00955 status=MagickFalse;
00956 if (image->progress_monitor != (MagickProgressMonitor) NULL)
00957 {
00958 MagickBooleanType
00959 proceed;
00960
00961 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00962 #pragma omp critical
00963 #endif
00964 proceed=SetImageProgress(image,TransparentPaintImageTag,progress++,
00965 image->rows);
00966 if (proceed == MagickFalse)
00967 status=MagickFalse;
00968 }
00969 }
00970 image_view=DestroyCacheView(image_view);
00971 return(status);
00972 }
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014 MagickExport MagickBooleanType TransparentPaintImageChroma(Image *image,
01015 const MagickPixelPacket *low,const MagickPixelPacket *high,
01016 const Quantum opacity,const MagickBooleanType invert)
01017 {
01018 #define TransparentPaintImageTag "Transparent/Image"
01019
01020 ExceptionInfo
01021 *exception;
01022
01023 long
01024 progress,
01025 y;
01026
01027 MagickBooleanType
01028 status;
01029
01030 ViewInfo
01031 *image_view;
01032
01033 assert(image != (Image *) NULL);
01034 assert(image->signature == MagickSignature);
01035 assert(high != (MagickPixelPacket *) NULL);
01036 assert(low != (MagickPixelPacket *) NULL);
01037 if (image->debug != MagickFalse)
01038 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01039 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
01040 return(MagickFalse);
01041 if (image->matte == MagickFalse)
01042 (void) SetImageAlphaChannel(image,ResetAlphaChannel);
01043
01044
01045
01046 status=MagickTrue;
01047 progress=0;
01048 exception=(&image->