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
00042 #include "magick/studio.h"
00043 #include "magick/color.h"
00044 #include "magick/color-private.h"
00045 #include "magick/colorspace-private.h"
00046 #include "magick/composite.h"
00047 #include "magick/composite-private.h"
00048 #include "magick/draw.h"
00049 #include "magick/draw-private.h"
00050 #include "magick/exception.h"
00051 #include "magick/exception-private.h"
00052 #include "magick/gem.h"
00053 #include "magick/monitor.h"
00054 #include "magick/monitor-private.h"
00055 #include "magick/paint.h"
00056 #include "magick/pixel-private.h"
00057 #include "magick/string_.h"
00058 #include "magick/thread-private.h"
00059
00060 static inline double MagickMax(const double x,const double y)
00061 {
00062 return( x > y ? x : y);
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
00108
00109 MagickExport MagickBooleanType FloodfillPaintImage(Image *image,
00110 const ChannelType channel,const DrawInfo *draw_info,
00111 const MagickPixelPacket *target,const long x_offset,const long y_offset,
00112 const MagickBooleanType invert)
00113 {
00114 #define MaxStacksize (1UL << 15)
00115 #define PushSegmentStack(up,left,right,delta) \
00116 { \
00117 if (s >= (segment_stack+MaxStacksize)) \
00118 ThrowBinaryException(DrawError,"SegmentStackOverflow",image->filename) \
00119 else \
00120 { \
00121 if ((((up)+(delta)) >= 0) && (((up)+(delta)) < (long) image->rows)) \
00122 { \
00123 s->x1=(double) (left); \
00124 s->y1=(double) (up); \
00125 s->x2=(double) (right); \
00126 s->y2=(double) (delta); \
00127 s++; \
00128 } \
00129 } \
00130 }
00131
00132 ExceptionInfo
00133 *exception;
00134
00135 Image
00136 *floodplane_image;
00137
00138 long
00139 offset,
00140 start,
00141 x,
00142 x1,
00143 x2,
00144 y;
00145
00146 MagickBooleanType
00147 skip;
00148
00149 MagickPixelPacket
00150 fill,
00151 pixel;
00152
00153 PixelPacket
00154 fill_color;
00155
00156 register SegmentInfo
00157 *s;
00158
00159 SegmentInfo
00160 *segment_stack;
00161
00162
00163
00164
00165 assert(image != (Image *) NULL);
00166 assert(image->signature == MagickSignature);
00167 if (image->debug != MagickFalse)
00168 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00169 assert(draw_info != (DrawInfo *) NULL);
00170 assert(draw_info->signature == MagickSignature);
00171 if ((x_offset < 0) || (x_offset >= (long) image->columns))
00172 return(MagickFalse);
00173 if ((y_offset < 0) || (y_offset >= (long) image->rows))
00174 return(MagickFalse);
00175 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
00176 return(MagickFalse);
00177 if (image->matte == MagickFalse)
00178 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
00179
00180
00181
00182 floodplane_image=CloneImage(image,0,0,MagickTrue,&image->exception);
00183 if (floodplane_image == (Image *) NULL)
00184 return(MagickFalse);
00185 (void) SetImageAlphaChannel(floodplane_image,OpaqueAlphaChannel);
00186 segment_stack=(SegmentInfo *) AcquireQuantumMemory(MaxStacksize,
00187 sizeof(*segment_stack));
00188 if (segment_stack == (SegmentInfo *) NULL)
00189 {
00190 floodplane_image=DestroyImage(floodplane_image);
00191 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
00192 image->filename);
00193 }
00194
00195
00196
00197 exception=(&image->exception);
00198 x=x_offset;
00199 y=y_offset;
00200 start=0;
00201 s=segment_stack;
00202 PushSegmentStack(y,x,x,1);
00203 PushSegmentStack(y+1,x,x,-1);
00204 GetMagickPixelPacket(image,&fill);
00205 GetMagickPixelPacket(image,&pixel);
00206 while (s > segment_stack)
00207 {
00208 register const IndexPacket
00209 *__restrict indexes;
00210
00211 register const PixelPacket
00212 *__restrict p;
00213
00214 register long
00215 x;
00216
00217 register PixelPacket
00218 *__restrict q;
00219
00220
00221
00222
00223 s--;
00224 x1=(long) s->x1;
00225 x2=(long) s->x2;
00226 offset=(long) s->y2;
00227 y=(long) s->y1+offset;
00228
00229
00230
00231 p=GetVirtualPixels(image,0,y,(unsigned long) (x1+1),1,exception);
00232 q=GetAuthenticPixels(floodplane_image,0,y,(unsigned long) (x1+1),1,
00233 exception);
00234 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00235 break;
00236 indexes=GetVirtualIndexQueue(image);
00237 p+=x1;
00238 q+=x1;
00239 for (x=x1; x >= 0; x--)
00240 {
00241 if (q->opacity == (Quantum) TransparentOpacity)
00242 break;
00243 SetMagickPixelPacket(image,p,indexes+x,&pixel);
00244 if (IsMagickColorSimilar(&pixel,target) == invert)
00245 break;
00246 q->opacity=(Quantum) TransparentOpacity;
00247 p--;
00248 q--;
00249 }
00250 if (SyncAuthenticPixels(floodplane_image,exception) == MagickFalse)
00251 break;
00252 skip=x >= x1 ? MagickTrue : MagickFalse;
00253 if (skip == MagickFalse)
00254 {
00255 start=x+1;
00256 if (start < x1)
00257 PushSegmentStack(y,start,x1-1,-offset);
00258 x=x1+1;
00259 }
00260 do
00261 {
00262 if (skip == MagickFalse)
00263 {
00264 if (x < (long) image->columns)
00265 {
00266 p=GetVirtualPixels(image,x,y,image->columns-x,1,exception);
00267 q=GetAuthenticPixels(floodplane_image,x,y,image->columns-x,1,
00268 exception);
00269 if ((p == (const PixelPacket *) NULL) ||
00270 (q == (PixelPacket *) NULL))
00271 break;
00272 indexes=GetVirtualIndexQueue(image);
00273 for ( ; x < (long) image->columns; x++)
00274 {
00275 if (q->opacity == (Quantum) TransparentOpacity)
00276 break;
00277 SetMagickPixelPacket(image,p,indexes+x,&pixel);
00278 if (IsMagickColorSimilar(&pixel,target) == invert)
00279 break;
00280 q->opacity=(Quantum) TransparentOpacity;
00281 p++;
00282 q++;
00283 }
00284 if (SyncAuthenticPixels(floodplane_image,exception) == MagickFalse)
00285 break;
00286 }
00287 PushSegmentStack(y,start,x-1,offset);
00288 if (x > (x2+1))
00289 PushSegmentStack(y,x2+1,x-1,-offset);
00290 }
00291 skip=MagickFalse;
00292 x++;
00293 if (x <= x2)
00294 {
00295 p=GetVirtualPixels(image,x,y,(unsigned long) (x2-x+1),1,exception);
00296 q=GetAuthenticPixels(floodplane_image,x,y,(unsigned long) (x2-x+1),1,
00297 exception);
00298 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00299 break;
00300 indexes=GetVirtualIndexQueue(image);
00301 for ( ; x <= x2; x++)
00302 {
00303 if (q->opacity == (Quantum) TransparentOpacity)
00304 break;
00305 SetMagickPixelPacket(image,p,indexes+x,&pixel);
00306 if (IsMagickColorSimilar(&pixel,target) != invert)
00307 break;
00308 p++;
00309 q++;
00310 }
00311 }
00312 start=x;
00313 } while (x <= x2);
00314 }
00315 for (y=0; y < (long) image->rows; y++)
00316 {
00317 register const PixelPacket
00318 *__restrict p;
00319
00320 register IndexPacket
00321 *__restrict indexes;
00322
00323 register long
00324 x;
00325
00326 register PixelPacket
00327 *__restrict q;
00328
00329
00330
00331
00332 p=GetVirtualPixels(floodplane_image,0,y,image->columns,1,exception);
00333 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
00334 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00335 break;
00336 indexes=GetAuthenticIndexQueue(image);
00337 for (x=0; x < (long) image->columns; x++)
00338 {
00339 if (p->opacity != OpaqueOpacity)
00340 {
00341 (void) GetFillColor(draw_info,x,y,&fill_color);
00342 SetMagickPixelPacket(image,&fill_color,(IndexPacket *) NULL,&fill);
00343 if (image->colorspace == CMYKColorspace)
00344 ConvertRGBToCMYK(&fill);
00345 if ((channel & RedChannel) != 0)
00346 q->red=RoundToQuantum(fill.red);
00347 if ((channel & GreenChannel) != 0)
00348 q->green=RoundToQuantum(fill.green);
00349 if ((channel & BlueChannel) != 0)
00350 q->blue=RoundToQuantum(fill.blue);
00351 if ((channel & OpacityChannel) != 0)
00352 q->opacity=RoundToQuantum(fill.opacity);
00353 if (((channel & IndexChannel) != 0) &&
00354 (image->colorspace == CMYKColorspace))
00355 indexes[x]=RoundToQuantum(fill.index);
00356 }
00357 p++;
00358 q++;
00359 }
00360 if (SyncAuthenticPixels(image,exception) == MagickFalse)
00361 break;
00362 }
00363 segment_stack=(SegmentInfo *) RelinquishMagickMemory(segment_stack);
00364 floodplane_image=DestroyImage(floodplane_image);
00365 return(y == (long) image->rows ? MagickTrue : MagickFalse);
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
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406 MagickExport MagickBooleanType GradientImage(Image *image,
00407 const GradientType type,const SpreadMethod method,
00408 const PixelPacket *start_color,const PixelPacket *stop_color)
00409 {
00410 DrawInfo
00411 *draw_info;
00412
00413 GradientInfo
00414 *gradient;
00415
00416 MagickBooleanType
00417 status;
00418
00419 register long
00420 i;
00421
00422
00423
00424
00425 assert(image != (const Image *) NULL);
00426 assert(image->signature == MagickSignature);
00427 if (image->debug != MagickFalse)
00428 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00429 assert(start_color != (const PixelPacket *) NULL);
00430 assert(stop_color != (const PixelPacket *) NULL);
00431 draw_info=AcquireDrawInfo();
00432 gradient=(&draw_info->gradient);
00433 gradient->type=type;
00434 gradient->bounding_box.width=image->columns;
00435 gradient->bounding_box.height=image->rows;
00436 gradient->gradient_vector.x2=(double) image->columns-1.0;
00437 gradient->gradient_vector.y2=(double) image->rows-1.0;
00438 if ((type == LinearGradient) && (gradient->gradient_vector.y2 != 0.0))
00439 gradient->gradient_vector.x2=0.0;
00440 gradient->center.x=(double) gradient->gradient_vector.x2/2.0;
00441 gradient->center.y=(double) gradient->gradient_vector.y2/2.0;
00442 gradient->radius=MagickMax(gradient->center.x,gradient->center.y);
00443 gradient->spread=method;
00444
00445
00446
00447 gradient->number_stops=2;
00448 gradient->stops=(StopInfo *) AcquireQuantumMemory(gradient->number_stops,
00449 sizeof(*gradient->stops));
00450 if (gradient->stops == (StopInfo *) NULL)
00451 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
00452 image->filename);
00453 (void) ResetMagickMemory(gradient->stops,0,gradient->number_stops*
00454 sizeof(*gradient->stops));
00455 for (i=0; i < (long) gradient->number_stops; i++)
00456 GetMagickPixelPacket(image,&gradient->stops[i].color);
00457 SetMagickPixelPacket(image,start_color,(IndexPacket *) NULL,
00458 &gradient->stops[0].color);
00459 gradient->stops[0].offset=0.0;
00460 SetMagickPixelPacket(image,stop_color,(IndexPacket *) NULL,
00461 &gradient->stops[1].color);
00462 gradient->stops[1].offset=1.0;
00463
00464
00465
00466 status=DrawGradientImage(image,draw_info);
00467 draw_info=DestroyDrawInfo(draw_info);
00468 if ((start_color->opacity == OpaqueOpacity) &&
00469 (stop_color->opacity == OpaqueOpacity))
00470 image->matte=MagickFalse;
00471 if ((IsGrayPixel(start_color) != MagickFalse) &&
00472 (IsGrayPixel(stop_color) != MagickFalse))
00473 image->type=GrayscaleType;
00474 return(status);
00475 }
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507 static unsigned long **DestroyHistogramThreadSet(unsigned long **histogram)
00508 {
00509 register long
00510 i;
00511
00512 assert(histogram != (unsigned long **) NULL);
00513 for (i=0; i < (long) GetOpenMPMaximumThreads(); i++)
00514 if (histogram[i] != (unsigned long *) NULL)
00515 histogram[i]=(unsigned long *) RelinquishMagickMemory(histogram[i]);
00516 histogram=(unsigned long **) RelinquishAlignedMemory(histogram);
00517 return(histogram);
00518 }
00519
00520 static unsigned long **AcquireHistogramThreadSet(const size_t count)
00521 {
00522 register long
00523 i;
00524
00525 unsigned long
00526 **histogram,
00527 number_threads;
00528
00529 number_threads=GetOpenMPMaximumThreads();
00530 histogram=(unsigned long **) AcquireAlignedMemory(number_threads,
00531 sizeof(*histogram));
00532 if (histogram == (unsigned long **) NULL)
00533 return((unsigned long **) NULL);
00534 (void) ResetMagickMemory(histogram,0,number_threads*sizeof(*histogram));
00535 for (i=0; i < (long) number_threads; i++)
00536 {
00537 histogram[i]=(unsigned long *) AcquireQuantumMemory(count,
00538 sizeof(**histogram));
00539 if (histogram[i] == (unsigned long *) NULL)
00540 return(DestroyHistogramThreadSet(histogram));
00541 }
00542 return(histogram);
00543 }
00544
00545 MagickExport Image *OilPaintImage(const Image *image,const double radius,
00546 ExceptionInfo *exception)
00547 {
00548 #define NumberPaintBins 256
00549 #define OilPaintImageTag "OilPaint/Image"
00550
00551 Image
00552 *paint_image;
00553
00554 long
00555 progress,
00556 y;
00557
00558 MagickBooleanType
00559 status;
00560
00561 unsigned long
00562 **histograms,
00563 width;
00564
00565 CacheView
00566 *image_view,
00567 *paint_view;
00568
00569
00570
00571
00572 assert(image != (const Image *) NULL);
00573 assert(image->signature == MagickSignature);
00574 if (image->debug != MagickFalse)
00575 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00576 assert(exception != (ExceptionInfo *) NULL);
00577 assert(exception->signature == MagickSignature);
00578 width=GetOptimalKernelWidth2D(radius,0.5);
00579 if ((image->columns < width) || (image->rows < width))
00580 ThrowImageException(OptionError,"ImageSmallerThanRadius");
00581 paint_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
00582 if (paint_image == (Image *) NULL)
00583 return((Image *) NULL);
00584 if (SetImageStorageClass(paint_image,DirectClass) == MagickFalse)
00585 {
00586 InheritException(exception,&paint_image->exception);
00587 paint_image=DestroyImage(paint_image);
00588 return((Image *) NULL);
00589 }
00590 histograms=AcquireHistogramThreadSet(NumberPaintBins);
00591 if (histograms == (unsigned long **) NULL)
00592 {
00593 paint_image=DestroyImage(paint_image);
00594 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
00595 }
00596
00597
00598
00599 status=MagickTrue;
00600 progress=0;
00601 image_view=AcquireCacheView(image);
00602 paint_view=AcquireCacheView(paint_image);
00603 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00604 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
00605 #endif
00606 for (y=0; y < (long) image->rows; y++)
00607 {
00608 register const IndexPacket
00609 *__restrict indexes;
00610
00611 register const PixelPacket
00612 *__restrict p;
00613
00614 register IndexPacket
00615 *__restrict paint_indexes;
00616
00617 register long
00618 x;
00619
00620 register PixelPacket
00621 *__restrict q;
00622
00623 register unsigned long
00624 *histogram;
00625
00626 if (status == MagickFalse)
00627 continue;
00628 p=GetCacheViewVirtualPixels(image_view,-((long) width/2L),y-(long) (width/
00629 2L),image->columns+width,width,exception);
00630 q=QueueCacheViewAuthenticPixels(paint_view,0,y,paint_image->columns,1,
00631 exception);
00632 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00633 {
00634 status=MagickFalse;
00635 continue;
00636 }
00637 indexes=GetCacheViewVirtualIndexQueue(image_view);
00638 paint_indexes=GetCacheViewAuthenticIndexQueue(paint_view);
00639 histogram=histograms[GetOpenMPThreadId()];
00640 for (x=0; x < (long) image->columns; x++)
00641 {
00642 long
00643 j,
00644 k,
00645 v;
00646
00647 register long
00648 i,
00649 u;
00650
00651 unsigned long
00652 count;
00653
00654
00655
00656
00657 i=0;
00658 j=0;
00659 count=0;
00660 (void) ResetMagickMemory(histogram,0,NumberPaintBins*sizeof(*histogram));
00661 for (v=0; v < (long) width; v++)
00662 {
00663 for (u=0; u < (long) width; u++)
00664 {
00665 k=(long) ScaleQuantumToChar(PixelIntensityToQuantum(p+u+i));
00666 histogram[k]++;
00667 if (histogram[k] > count)
00668 {
00669 j=i+u;
00670 count=histogram[k];
00671 }
00672 }
00673 i+=image->columns+width;
00674 }
00675 *q=(*(p+j));
00676 if (image->colorspace == CMYKColorspace)
00677 paint_indexes[x]=indexes[x+j];
00678 p++;
00679 q++;
00680 }
00681 if (SyncCacheViewAuthenticPixels(paint_view,exception) == MagickFalse)
00682 status=MagickFalse;
00683 if (image->progress_monitor != (MagickProgressMonitor) NULL)
00684 {
00685 MagickBooleanType
00686 proceed;
00687
00688 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00689 #pragma omp critical (MagickCore_OilPaintImage)
00690 #endif
00691 proceed=SetImageProgress(image,OilPaintImageTag,progress++,image->rows);
00692 if (proceed == MagickFalse)
00693 status=MagickFalse;
00694 }
00695 }
00696 paint_view=DestroyCacheView(paint_view);
00697 image_view=DestroyCacheView(image_view);
00698 histograms=DestroyHistogramThreadSet(histograms);
00699 if (status == MagickFalse)
00700 paint_image=DestroyImage(paint_image);
00701 return(paint_image);
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
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747 MagickExport MagickBooleanType OpaquePaintImage(Image *image,
00748 const MagickPixelPacket *target,const MagickPixelPacket *fill,
00749 const MagickBooleanType invert)
00750 {
00751 return(OpaquePaintImageChannel(image,AllChannels,target,fill,invert));
00752 }
00753
00754 MagickExport MagickBooleanType OpaquePaintImageChannel(Image *image,
00755 const ChannelType channel,const MagickPixelPacket *target,
00756 const MagickPixelPacket *fill,const MagickBooleanType invert)
00757 {
00758 #define OpaquePaintImageTag "Opaque/Image"
00759
00760 ExceptionInfo
00761 *exception;
00762
00763 long
00764 progress,
00765 y;
00766
00767 MagickBooleanType
00768 status;
00769
00770 MagickPixelPacket
00771 zero;
00772
00773 CacheView
00774 *image_view;
00775
00776 assert(image != (Image *) NULL);
00777 assert(image->signature == MagickSignature);
00778 assert(target != (MagickPixelPacket *) NULL);
00779 assert(fill != (MagickPixelPacket *) NULL);
00780 if (image->debug != MagickFalse)
00781 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00782 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
00783 return(MagickFalse);
00784
00785
00786
00787 status=MagickTrue;
00788 progress=0;
00789 exception=(&image->exception);
00790 GetMagickPixelPacket(image,&zero);
00791 image_view=AcquireCacheView(image);
00792 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00793 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
00794 #endif
00795 for (y=0; y < (long) image->rows; y++)
00796 {
00797 MagickPixelPacket
00798 pixel;
00799
00800 register IndexPacket
00801 *__restrict indexes;
00802
00803 register long
00804 x;
00805
00806 register PixelPacket
00807 *__restrict q;
00808
00809 if (status == MagickFalse)
00810 continue;
00811 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
00812 if (q == (PixelPacket *) NULL)
00813 {
00814 status=MagickFalse;
00815 continue;
00816 }
00817 indexes=GetCacheViewAuthenticIndexQueue(image_view);
00818 pixel=zero;
00819 for (x=0; x < (long) image->columns; x++)
00820 {
00821 SetMagickPixelPacket(image,q,indexes+x,&pixel);
00822 if (IsMagickColorSimilar(&pixel,target) != invert)
00823 {
00824 if ((channel & RedChannel) != 0)
00825 q->red=RoundToQuantum(fill->red);
00826 if ((channel & GreenChannel) != 0)
00827 q->green=RoundToQuantum(fill->green);
00828 if ((channel & BlueChannel) != 0)
00829 q->blue=RoundToQuantum(fill->blue);
00830 if ((channel & OpacityChannel) != 0)
00831 q->opacity=RoundToQuantum(fill->opacity);
00832 if (((channel & IndexChannel) != 0) &&
00833 (image->colorspace == CMYKColorspace))
00834 indexes[x]=RoundToQuantum(fill->index);
00835 }
00836 q++;
00837 }
00838 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
00839 status=MagickFalse;
00840 if (image->progress_monitor != (MagickProgressMonitor) NULL)
00841 {
00842 MagickBooleanType
00843 proceed;
00844
00845 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00846 #pragma omp critical (MagickCore_OpaquePaintImageChannel)
00847 #endif
00848 proceed=SetImageProgress(image,OpaquePaintImageTag,progress++,
00849 image->rows);
00850 if (proceed == MagickFalse)
00851 status=MagickFalse;
00852 }
00853 }
00854 image_view=DestroyCacheView(image_view);
00855 return(status);
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
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895 MagickExport MagickBooleanType TransparentPaintImage(Image *image,
00896 const MagickPixelPacket *target,const Quantum opacity,
00897 const MagickBooleanType invert)
00898 {
00899 #define TransparentPaintImageTag "Transparent/Image"
00900
00901 ExceptionInfo
00902 *exception;
00903
00904 long
00905 progress,
00906 y;
00907
00908 MagickBooleanType
00909 status;
00910
00911 MagickPixelPacket
00912 zero;
00913
00914 CacheView
00915 *image_view;
00916
00917 assert(image != (Image *) NULL);
00918 assert(image->signature == MagickSignature);
00919 assert(target != (MagickPixelPacket *) NULL);
00920 if (image->debug != MagickFalse)
00921 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00922 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
00923 return(MagickFalse);
00924 if (image->matte == MagickFalse)
00925 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
00926
00927
00928
00929 status=MagickTrue;
00930 progress=0;
00931 exception=(&image->exception);
00932 GetMagickPixelPacket(image,&zero);
00933 image_view=AcquireCacheView(image);
00934 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00935 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
00936 #endif
00937 for (y=0; y < (long) image->rows; y++)
00938 {
00939 MagickPixelPacket
00940 pixel;
00941
00942 register IndexPacket
00943 *__restrict indexes;
00944
00945 register long
00946 x;
00947
00948 register PixelPacket
00949 *__restrict q;
00950
00951 if (status == MagickFalse)
00952 continue;
00953 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
00954 if (q == (PixelPacket *) NULL)
00955 {
00956 status=MagickFalse;
00957 continue;
00958 }
00959 indexes=GetCacheViewAuthenticIndexQueue(image_view);
00960 pixel=zero;
00961 for (x=0; x < (long) image->columns; x++)
00962 {
00963 SetMagickPixelPacket(image,q,indexes+x,&pixel);
00964 if (IsMagickColorSimilar(&pixel,target) != invert)
00965 q->opacity=opacity;
00966 q++;
00967 }
00968 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
00969 status=MagickFalse;
00970 if (image->progress_monitor != (MagickProgressMonitor) NULL)
00971 {
00972 MagickBooleanType
00973 proceed;
00974
00975 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00976 #pragma omp critical (MagickCore_TransparentPaintImage)
00977 #endif
00978 proceed=SetImageProgress(image,TransparentPaintImageTag,progress++,
00979 image->rows);
00980 if (proceed == MagickFalse)
00981 status=MagickFalse;
00982 }
00983 }
00984 image_view=DestroyCacheView(image_view);
00985 return(status);
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
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028 MagickExport MagickBooleanType TransparentPaintImageChroma(Image *image,
01029 const MagickPixelPacket *low,const MagickPixelPacket *high,
01030 const Quantum opacity,const MagickBooleanType invert)
01031 {
01032 #define TransparentPaintImageTag "Transparent/Image"
01033
01034 ExceptionInfo
01035 *exception;
01036
01037 long
01038 progress,
01039 y;
01040
01041 MagickBooleanType
01042 status;
01043
01044 CacheView
01045 *image_view;
01046
01047 assert(image != (Image *) NULL);
01048 assert(image->signature == MagickSignature);
01049 assert(high != (MagickPixelPacket *) NULL);
01050 assert(low != (MagickPixelPacket *) NULL);
01051 if (image->debug != MagickFalse)
01052 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01053 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
01054 return(MagickFalse);
01055 if (image->matte == MagickFalse)
01056 (void) SetImageAlphaChannel(image,ResetAlphaChannel);
01057
01058
01059
01060 status=MagickTrue;
01061 progress=0;
01062 exception=(&image->exception);
01063 image_view=AcquireCacheView(image);
01064 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01065 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
01066 #endif
01067 for (y=0; y < (long) image->rows; y++)
01068 {
01069 MagickBooleanType
01070 match;
01071
01072 MagickPixelPacket
01073 pixel;
01074
01075 register IndexPacket
01076 *__restrict indexes;
01077
01078 register long
01079 x;
01080
01081 register PixelPacket
01082 *__restrict q;
01083
01084 if (status == MagickFalse)
01085 continue;
01086 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
01087 if (q == (PixelPacket *) NULL)
01088 {
01089 status=MagickFalse;
01090 continue;
01091 }
01092 indexes=GetCacheViewAuthenticIndexQueue(image_view);
01093 GetMagickPixelPacket(image,&pixel);
01094 for (x=0; x < (long) image->columns; x++)
01095 {
01096 SetMagickPixelPacket(image,q,indexes+x,&pixel);
01097 match=((pixel.red >= low->red) && (pixel.red <= high->red) &&
01098 (pixel.green >= low->green) && (pixel.green <= high->green) &&
01099 (pixel.blue >= low->blue) && (pixel.blue <= high->blue)) ?
01100 MagickTrue : MagickFalse;
01101 if (match != invert)
01102 q->opacity=opacity;
01103 q++;
01104 }
01105 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
01106 status=MagickFalse;
01107 if (image->progress_monitor != (MagickProgressMonitor) NULL)
01108 {
01109 MagickBooleanType
01110 proceed;
01111
01112 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01113 #pragma omp critical (MagickCore_TransparentPaintImageChroma)
01114 #endif
01115 proceed=SetImageProgress(image,TransparentPaintImageTag,progress++,
01116 image->rows);
01117 if (proceed == MagickFalse)
01118 status=MagickFalse;
01119 }
01120 }
01121 image_view=DestroyCacheView(image_view);
01122 return(status);
01123 }