static inline void MagickCompositeBlend(const PixelPacket *p, const MagickRealType alpha,const PixelPacket *q,const MagickRealType beta, const MagickRealType area,PixelPacket *composite) { MagickRealType gamma; if ((alpha == TransparentOpacity) && (beta == TransparentOpacity)) { *composite=(*p); return; } gamma=RoundToUnity((1.0-QuantumScale*(QuantumRange-(1.0-area)* (QuantumRange-alpha)))+(1.0-QuantumScale*(QuantumRange-area* (QuantumRange-beta)))); composite->opacity=RoundToQuantum(QuantumRange*(1.0-gamma)); gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma); composite->red=RoundToQuantum(gamma*Blend_((MagickRealType) p->red, QuantumRange-(1.0-area)*(QuantumRange-alpha),(MagickRealType) q->red, QuantumRange-area*(QuantumRange-beta))); composite->green=RoundToQuantum(gamma*Blend_((MagickRealType) p->green, QuantumRange-(1.0-area)*(QuantumRange-alpha),(MagickRealType) q->green, QuantumRange-area*(QuantumRange-beta))); composite->blue=RoundToQuantum(gamma*Blend_((MagickRealType) p->blue, QuantumRange-(1.0-area)*(QuantumRange-alpha),(MagickRealType) q->blue, QuantumRange-area*(QuantumRange-beta))); }
MagickExport void ConvertHSLToRGB(const double hue,const double saturation, const double luminosity,Quantum *red,Quantum *green,Quantum *blue) { MagickRealType b, g, r, m1, m2; /* Convert HSL to RGB colorspace. */ assert(red != (Quantum *) NULL); assert(green != (Quantum *) NULL); assert(blue != (Quantum *) NULL); if (saturation == 0) { *red=RoundToQuantum((MagickRealType) QuantumRange*luminosity); *green=(*red); *blue=(*red); return; } if (luminosity <= 0.5) m2=luminosity*(saturation+1.0); else m2=(luminosity+saturation)-(luminosity*saturation); m1=2.0*luminosity-m2; r=ConvertHueToRGB(m1,m2,hue+1.0/3.0); g=ConvertHueToRGB(m1,m2,hue); b=ConvertHueToRGB(m1,m2,hue-1.0/3.0); *red=RoundToQuantum((MagickRealType) QuantumRange*r); *green=RoundToQuantum((MagickRealType) QuantumRange*g); *blue=RoundToQuantum((MagickRealType) QuantumRange*b); }
static MagickBooleanType SigmoidalContrast(ImageView *contrast_view, const ssize_t y,const int id,void *context) { #define QuantumScale ((MagickRealType) 1.0/(MagickRealType) QuantumRange) #define SigmoidalContrast(x) \ (QuantumRange*(1.0/(1+exp(10.0*(0.5-QuantumScale*x)))-0.0066928509)*1.0092503) RectangleInfo extent; register IndexPacket *indexes; register PixelPacket *pixels; register ssize_t x; extent=GetImageViewExtent(contrast_view); pixels=GetImageViewAuthenticPixels(contrast_view); for (x=0; x < (ssize_t) (extent.width-extent.height); x++) { pixels[x].red=RoundToQuantum(SigmoidalContrast(pixels[x].red)); pixels[x].green=RoundToQuantum(SigmoidalContrast(pixels[x].green)); pixels[x].blue=RoundToQuantum(SigmoidalContrast(pixels[x].blue)); pixels[x].opacity=RoundToQuantum(SigmoidalContrast(pixels[x].opacity)); } indexes=GetImageViewAuthenticIndexes(contrast_view); if (indexes != (IndexPacket *) NULL) for (x=0; x < (ssize_t) (extent.width-extent.height); x++) indexes[x]=(IndexPacket) RoundToQuantum(SigmoidalContrast(indexes[x])); return(MagickTrue); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % H S L T r a n s f o r m % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % HSLTransform() converts a (hue, saturation, luminosity) to a (red, green, % blue) triple. % % The format of the HSLTransformImage method is: % % void HSLTransform(const double hue,const double saturation, % const double luminosity,Quantum *red,Quantum *green,Quantum *blue) % % A description of each parameter follows: % % o hue, saturation, luminosity: A double value representing a % component of the HSL color space. % % o red, green, blue: A pointer to a pixel component of type Quantum. % % */ MagickExport void HSLTransform(const double hue,const double saturation, const double luminosity,Quantum *red,Quantum *green,Quantum *blue) { MagickRealType b, g, r, v, x, y, z; /* Convert HSL to RGB colorspace. */ assert(red != (Quantum *) NULL); assert(green != (Quantum *) NULL); assert(blue != (Quantum *) NULL); if (saturation == 0.0) { *red=(Quantum) (QuantumRange*luminosity+0.5); *green=(Quantum) (QuantumRange*luminosity+0.5); *blue=(Quantum) (QuantumRange*luminosity+0.5); return; } v=(luminosity <= 0.5) ? (luminosity*(1.0+saturation)) : (luminosity+saturation-luminosity*saturation); y=2.0*luminosity-v; x=y+(v-y)*(6.0*hue-floor(6.0*hue)); z=v-(v-y)*(6.0*hue-floor(6.0*hue)); switch ((int) (6.0*hue)) { case 0: r=v; g=x; b=y; break; case 1: r=z; g=v; b=y; break; case 2: r=y; g=v; b=x; break; case 3: r=y; g=z; b=v; break; case 4: r=x; g=y; b=v; break; case 5: r=v; g=y; b=z; break; default: r=v; g=x; b=y; break; } *red=RoundToQuantum(QuantumRange*r); *green=RoundToQuantum(QuantumRange*g); *blue=RoundToQuantum(QuantumRange*b); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % C o n v e r t H W B T o R G B % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ConvertHWBToRGB() transforms a (hue, whiteness, blackness) to a (red, green, % blue) triple. % % The format of the ConvertHWBToRGBImage method is: % % void ConvertHWBToRGB(const double hue,const double whiteness, % const double blackness,Quantum *red,Quantum *green,Quantum *blue) % % A description of each parameter follows: % % o hue, whiteness, blackness: A double value representing a % component of the HWB color space. % % o red, green, blue: A pointer to a pixel component of type Quantum. % */ MagickExport void ConvertHWBToRGB(const double hue,const double whiteness, const double blackness,Quantum *red,Quantum *green,Quantum *blue) { MagickRealType b, f, g, n, r, v; register long i; /* Convert HWB to RGB colorspace. */ assert(red != (Quantum *) NULL); assert(green != (Quantum *) NULL); assert(blue != (Quantum *) NULL); v=1.0-blackness; if (hue == 0.0) { *red=RoundToQuantum((MagickRealType) QuantumRange*v); *green=RoundToQuantum((MagickRealType) QuantumRange*v); *blue=RoundToQuantum((MagickRealType) QuantumRange*v); return; } i=(long) floor(6.0*hue); f=6.0*hue-i; if ((i & 0x01) != 0) f=1.0-f; n=whiteness+f*(v-whiteness); /* linear interpolation */ switch (i) { default: case 6: case 0: r=v; g=n; b=whiteness; break; case 1: r=n; g=v; b=whiteness; break; case 2: r=whiteness; g=v; b=n; break; case 3: r=whiteness; g=n; b=v; break; case 4: r=n; g=whiteness; b=v; break; case 5: r=v; g=whiteness; b=n; break; } *red=RoundToQuantum((MagickRealType) QuantumRange*r); *green=RoundToQuantum((MagickRealType) QuantumRange*g); *blue=RoundToQuantum((MagickRealType) QuantumRange*b); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % H S B T r a n s f o r m % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % HSBTransform() converts a (hue, saturation, brightness) to a (red, green, % blue) triple. % % The format of the HSBTransformImage method is: % % void HSBTransform(const double hue,const double saturation, % const double brightness,Quantum *red,Quantum *green,Quantum *blue) % % A description of each parameter follows: % % o hue, saturation, brightness: A double value representing a % component of the HSB color space. % % o red, green, blue: A pointer to a pixel component of type Quantum. % % */ MagickExport void HSBTransform(const double hue,const double saturation, const double brightness,Quantum *red,Quantum *green,Quantum *blue) { MagickRealType f, h, p, q, t; /* Convert HSB to RGB colorspace. */ assert(red != (Quantum *) NULL); assert(green != (Quantum *) NULL); assert(blue != (Quantum *) NULL); if (saturation == 0.0) { *red=RoundToQuantum(QuantumRange*brightness); *green=(*red); *blue=(*red); return; } h=6.0*(hue-floor(hue)); f=h-floor((double) h); p=brightness*(1.0-saturation); q=brightness*(1.0-saturation*f); t=brightness*(1.0-(saturation*(1.0-f))); switch ((int) h) { case 0: default: { *red=RoundToQuantum(QuantumRange*brightness); *green=RoundToQuantum(QuantumRange*t); *blue=RoundToQuantum(QuantumRange*p); break; } case 1: { *red=RoundToQuantum(QuantumRange*q); *green=RoundToQuantum(QuantumRange*brightness); *blue=RoundToQuantum(QuantumRange*p); break; } case 2: { *red=RoundToQuantum(QuantumRange*p); *green=RoundToQuantum(QuantumRange*brightness); *blue=RoundToQuantum(QuantumRange*t); break; } case 3: { *red=RoundToQuantum(QuantumRange*p); *green=RoundToQuantum(QuantumRange*q); *blue=RoundToQuantum(QuantumRange*brightness); break; } case 4: { *red=RoundToQuantum(QuantumRange*t); *green=RoundToQuantum(QuantumRange*p); *blue=RoundToQuantum(QuantumRange*brightness); break; } case 5: { *red=RoundToQuantum(QuantumRange*brightness); *green=RoundToQuantum(QuantumRange*p); *blue=RoundToQuantum(QuantumRange*q); break; } } }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d E X R I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ReadEXRImage reads an image in the high dynamic-range (HDR) file format % developed by Industrial Light & Magic. It allocates the memory necessary % for the new Image structure and returns a pointer to the new image. % % The format of the ReadEXRImage method is: % % Image *ReadEXRImage(const ImageInfo *image_info,ExceptionInfo *exception) % % A description of each parameter follows: % % o image_info: the image info. % % o exception: return any errors or warnings in this structure. % */ static Image *ReadEXRImage(const ImageInfo *image_info,ExceptionInfo *exception) { const ImfHeader *hdr_info; Image *image; ImageInfo *read_info; ImfInputFile *file; ImfRgba *scanline; int max_x, max_y, min_x, min_y; long y; register long x; register PixelPacket *q; MagickBooleanType status; /* Open image. */ assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickSignature); if (image_info->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", image_info->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); image=AcquireImage(image_info); status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) { image=DestroyImageList(image); return((Image *) NULL); } read_info=CloneImageInfo(image_info); if (IsPathAccessible(read_info->filename) == MagickFalse) { (void) AcquireUniqueFilename(read_info->filename); (void) ImageToFile(image,read_info->filename,exception); } file=ImfOpenInputFile(read_info->filename); if (file == (ImfInputFile *) NULL) { ThrowFileException(exception,BlobError,"UnableToOpenBlob", ImfErrorMessage()); read_info=DestroyImageInfo(read_info); return((Image *) NULL); } hdr_info=ImfInputHeader(file); ImfHeaderDataWindow(hdr_info,&min_x,&min_y,&max_x,&max_y); image->columns=max_x-min_x+1UL; image->rows=max_y-min_y+1UL; image->matte=MagickTrue; if (image_info->ping != MagickFalse) { (void) ImfCloseInputFile(file); if (LocaleCompare(image_info->filename,read_info->filename) != 0) (void) RelinquishUniqueFileResource(read_info->filename); read_info=DestroyImageInfo(read_info); (void) CloseBlob(image); return(GetFirstImageInList(image)); } scanline=(ImfRgba *) AcquireQuantumMemory(image->columns,sizeof(*scanline)); if (scanline == (ImfRgba *) NULL) { (void) ImfCloseInputFile(file); ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); } for (y=0; y < (long) image->rows; y++) { q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); if (q == (PixelPacket *) NULL) break; ImfInputSetFrameBuffer(file,scanline-min_x-image->columns*(min_y+y),1, image->columns); ImfInputReadPixels(file,min_y+y,min_y+y); for (x=0; x < (long) image->columns; x++) { q->red=RoundToQuantum((MagickRealType) QuantumRange*ImfHalfToFloat( scanline[x].r)); q->green=RoundToQuantum((MagickRealType) QuantumRange*ImfHalfToFloat( scanline[x].g)); q->blue=RoundToQuantum((MagickRealType) QuantumRange*ImfHalfToFloat( scanline[x].b)); q->opacity=RoundToQuantum((MagickRealType) QuantumRange-QuantumRange* ImfHalfToFloat(scanline[x].a)); q++; } if (SyncAuthenticPixels(image,exception) == MagickFalse) break; } scanline=(ImfRgba *) RelinquishMagickMemory(scanline); (void) ImfCloseInputFile(file); if (LocaleCompare(image_info->filename,read_info->filename) != 0) (void) RelinquishUniqueFileResource(read_info->filename); read_info=DestroyImageInfo(read_info); (void) CloseBlob(image); return(GetFirstImageInList(image)); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d X C I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ReadXCImage creates a constant image and initializes it to the % X server color as specified by the filename. It allocates the memory % necessary for the new Image structure and returns a pointer to the new % image. % % The format of the ReadXCImage method is: % % Image *ReadXCImage(const ImageInfo *image_info,ExceptionInfo *exception) % % A description of each parameter follows: % % o image: The image. % % o image_info: the image info. % % o exception: return any errors or warnings in this structure. % */ static Image *ReadXCImage(const ImageInfo *image_info,ExceptionInfo *exception) { Image *image; IndexPacket *indexes; MagickBooleanType status; MagickPixelPacket color; long y; register long x; register PixelPacket *q; /* Initialize Image structure. */ assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickSignature); if (image_info->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", image_info->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); image=AllocateImage(image_info); if (image->columns == 0) image->columns=1; if (image->rows == 0) image->rows=1; (void) CopyMagickString(image->filename,image_info->filename,MaxTextExtent); status=QueryMagickColor((char *) image_info->filename,&color,exception); if (status == MagickFalse) { image=DestroyImage(image); return((Image *) NULL); } image->colorspace=color.colorspace; image->matte=color.matte; if ((image->colorspace == RGBColorspace) && (image->matte == MagickFalse)) { if (AllocateImageColormap(image,1) == MagickFalse) ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); (void) QueryColorDatabase((char *) image_info->filename, &image->background_color,exception); image->colormap[0]=image->background_color; color.index=0.0; } if (SetImageExtent(image,0,0) == MagickFalse) { InheritException(exception,&image->exception); return(DestroyImageList(image)); } for (y=0; y < (long) image->rows; y++) { q=GetImagePixels(image,0,y,image->columns,1); if (q == (PixelPacket *) NULL) break; indexes=GetIndexes(image); for (x=0; x < (long) image->columns; x++) { q->red=RoundToQuantum(color.red); q->green=RoundToQuantum(color.green); q->blue=RoundToQuantum(color.blue); if (image->matte) q->opacity=RoundToQuantum(color.opacity); if ((image->storage_class == PseudoClass) || (image->colorspace == CMYKColorspace)) indexes[x]=(IndexPacket) RoundToQuantum(color.index); q++; } if (SyncImagePixels(image) == MagickFalse) break; } return(GetFirstImageInList(image)); }
gboolean isTennisFree() { gboolean res = FALSE; ExceptionInfo *exception; Image *image; ImageInfo *image_info; unsigned long colors; ColorPacket *histogram; unsigned long i = 0; char* img_path = "video.jpg"; getImg(); exception = AcquireExceptionInfo(); image_info = CloneImageInfo((ImageInfo *) NULL); strcpy(image_info->filename, img_path); image = ReadImage(image_info,exception); if (exception->severity != UndefinedException) { CatchException(exception); } if (image == (Image *) NULL) { return FALSE; //exit(1); } histogram = GetImageHistogram(image, &colors, exception); qsort((void *) histogram, (size_t) colors, sizeof(*histogram), myHistogramCompare); if (histogram == (ColorPacket*) NULL) { MagickError(exception->severity, exception->reason, exception->description); } if(colors > 0) { if(histogram[i].count > 5000 && ScaleQuantumToChar(RoundToQuantum(histogram[i].pixel.red)) < 35 && ScaleQuantumToChar(RoundToQuantum(histogram[i].pixel.green)) < 35 && ScaleQuantumToChar(RoundToQuantum(histogram[i].pixel.blue)) < 35) { res = TRUE; printf("Empty\n"); } else { res = FALSE; printf("Busy\n"); } // printf("%d %d %d %d\n", (int)histogram[i].count, ScaleQuantumToChar(RoundToQuantum(histogram[i].pixel.red)), ScaleQuantumToChar(RoundToQuantum(histogram[i].pixel.green)), ScaleQuantumToChar(RoundToQuantum(histogram[i].pixel.blue))); } // remove(img_path); histogram = (ColorPacket *) RelinquishMagickMemory(histogram); DestroyImage(image); image_info=DestroyImageInfo(image_info); exception=DestroyExceptionInfo(exception); return res; }
int main(int argc,char **argv) { ExceptionInfo *exception; Image *image; ImageInfo *image_info; unsigned long colors; ColorPacket *histogram; unsigned long i = 0; char* img_path = "video.jpg"; getImg(); MagickCoreGenesis(*argv,MagickTrue); exception = AcquireExceptionInfo(); image_info = CloneImageInfo((ImageInfo *) NULL); strcpy(image_info->filename, img_path); image = ReadImage(image_info,exception); if (exception->severity != UndefinedException) { CatchException(exception); } if (image == (Image *) NULL) { exit(1); } histogram = GetImageHistogram(image, &colors, exception); qsort((void *) histogram, (size_t) colors, sizeof(*histogram), myHistogramCompare); if (histogram == (ColorPacket*) NULL) { MagickError(exception->severity, exception->reason, exception->description); } if(colors > 0) { if(histogram[i].count > 10000 && ScaleQuantumToChar(RoundToQuantum(histogram[i].pixel.red)) < 35 && ScaleQuantumToChar(RoundToQuantum(histogram[i].pixel.green)) < 35 && ScaleQuantumToChar(RoundToQuantum(histogram[i].pixel.blue)) < 35) { printf("Empty\n"); } else { printf("Busy\n"); } // printf("%u %d %d %d\n", histogram[i].count, ScaleQuantumToChar(RoundToQuantum(histogram[i].pixel.red)), ScaleQuantumToChar(RoundToQuantum(histogram[i].pixel.green)), ScaleQuantumToChar(RoundToQuantum(histogram[i].pixel.blue))); } remove(img_path); histogram = (ColorPacket *) RelinquishMagickMemory(histogram); DestroyImage(image); image_info=DestroyImageInfo(image_info); exception=DestroyExceptionInfo(exception); MagickCoreTerminus(); return(0); }
MagickExport MagickBooleanType OpaquePaintImageChannel(Image *image, const ChannelType channel,const MagickPixelPacket *target, const MagickPixelPacket *fill,const MagickBooleanType invert) { #define OpaquePaintImageTag "Opaque/Image" ExceptionInfo *exception; long progress, y; MagickBooleanType status; MagickPixelPacket zero; CacheView *image_view; assert(image != (Image *) NULL); assert(image->signature == MagickSignature); assert(target != (MagickPixelPacket *) NULL); assert(fill != (MagickPixelPacket *) NULL); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); if (SetImageStorageClass(image,DirectClass) == MagickFalse) return(MagickFalse); /* Make image color opaque. */ status=MagickTrue; progress=0; exception=(&image->exception); GetMagickPixelPacket(image,&zero); image_view=AcquireCacheView(image); #if defined(MAGICKCORE_OPENMP_SUPPORT) #pragma omp parallel for schedule(dynamic,4) shared(progress,status) #endif for (y=0; y < (long) image->rows; y++) { MagickPixelPacket pixel; register IndexPacket *__restrict indexes; register long x; register PixelPacket *__restrict q; if (status == MagickFalse) continue; q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception); if (q == (PixelPacket *) NULL) { status=MagickFalse; continue; } indexes=GetCacheViewAuthenticIndexQueue(image_view); pixel=zero; for (x=0; x < (long) image->columns; x++) { SetMagickPixelPacket(image,q,indexes+x,&pixel); if (IsMagickColorSimilar(&pixel,target) != invert) { if ((channel & RedChannel) != 0) q->red=RoundToQuantum(fill->red); if ((channel & GreenChannel) != 0) q->green=RoundToQuantum(fill->green); if ((channel & BlueChannel) != 0) q->blue=RoundToQuantum(fill->blue); if ((channel & OpacityChannel) != 0) q->opacity=RoundToQuantum(fill->opacity); if (((channel & IndexChannel) != 0) && (image->colorspace == CMYKColorspace)) indexes[x]=RoundToQuantum(fill->index); } q++; } if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) status=MagickFalse; if (image->progress_monitor != (MagickProgressMonitor) NULL) { MagickBooleanType proceed; #if defined(MAGICKCORE_OPENMP_SUPPORT) #pragma omp critical (MagickCore_OpaquePaintImageChannel) #endif proceed=SetImageProgress(image,OpaquePaintImageTag,progress++, image->rows); if (proceed == MagickFalse) status=MagickFalse; } } image_view=DestroyCacheView(image_view); return(status); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % F l o o d f i l l P a i n t I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % FloodfillPaintImage() changes the color value of any pixel that matches % target and is an immediate neighbor. If the method FillToBorderMethod is % specified, the color value is changed for any neighbor pixel that does not % match the bordercolor member of image. % % By default target must match a particular pixel color exactly. % However, in many cases two colors may differ by a small amount. The % fuzz member of image defines how much tolerance is acceptable to % consider two colors as the same. For example, set fuzz to 10 and the % color red at intensities of 100 and 102 respectively are now % interpreted as the same color for the purposes of the floodfill. % % The format of the FloodfillPaintImage method is: % % MagickBooleanType FloodfillPaintImage(Image *image, % const ChannelType channel,const DrawInfo *draw_info, % const MagickPixelPacket target,const long x_offset,const long y_offset, % const MagickBooleanType invert) % % A description of each parameter follows: % % o image: the image. % % o channel: the channel(s). % % o draw_info: the draw info. % % o target: the RGB value of the target color. % % o x_offset,y_offset: the starting location of the operation. % % o invert: paint any pixel that does not match the target color. % */ MagickExport MagickBooleanType FloodfillPaintImage(Image *image, const ChannelType channel,const DrawInfo *draw_info, const MagickPixelPacket *target,const long x_offset,const long y_offset, const MagickBooleanType invert) { #define MaxStacksize (1UL << 15) #define PushSegmentStack(up,left,right,delta) \ { \ if (s >= (segment_stack+MaxStacksize)) \ ThrowBinaryException(DrawError,"SegmentStackOverflow",image->filename) \ else \ { \ if ((((up)+(delta)) >= 0) && (((up)+(delta)) < (long) image->rows)) \ { \ s->x1=(double) (left); \ s->y1=(double) (up); \ s->x2=(double) (right); \ s->y2=(double) (delta); \ s++; \ } \ } \ } ExceptionInfo *exception; Image *floodplane_image; long offset, start, x, x1, x2, y; MagickBooleanType skip; MagickPixelPacket fill, pixel; PixelPacket fill_color; register SegmentInfo *s; SegmentInfo *segment_stack; /* Check boundary conditions. */ assert(image != (Image *) NULL); assert(image->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); assert(draw_info != (DrawInfo *) NULL); assert(draw_info->signature == MagickSignature); if ((x_offset < 0) || (x_offset >= (long) image->columns)) return(MagickFalse); if ((y_offset < 0) || (y_offset >= (long) image->rows)) return(MagickFalse); if (SetImageStorageClass(image,DirectClass) == MagickFalse) return(MagickFalse); if (image->matte == MagickFalse) (void) SetImageAlphaChannel(image,OpaqueAlphaChannel); /* Set floodfill state. */ floodplane_image=CloneImage(image,0,0,MagickTrue,&image->exception); if (floodplane_image == (Image *) NULL) return(MagickFalse); (void) SetImageAlphaChannel(floodplane_image,OpaqueAlphaChannel); segment_stack=(SegmentInfo *) AcquireQuantumMemory(MaxStacksize, sizeof(*segment_stack)); if (segment_stack == (SegmentInfo *) NULL) { floodplane_image=DestroyImage(floodplane_image); ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", image->filename); } /* Push initial segment on stack. */ exception=(&image->exception); x=x_offset; y=y_offset; start=0; s=segment_stack; PushSegmentStack(y,x,x,1); PushSegmentStack(y+1,x,x,-1); GetMagickPixelPacket(image,&fill); GetMagickPixelPacket(image,&pixel); while (s > segment_stack) { register const IndexPacket *__restrict indexes; register const PixelPacket *__restrict p; register long x; register PixelPacket *__restrict q; /* Pop segment off stack. */ s--; x1=(long) s->x1; x2=(long) s->x2; offset=(long) s->y2; y=(long) s->y1+offset; /* Recolor neighboring pixels. */ p=GetVirtualPixels(image,0,y,(unsigned long) (x1+1),1,exception); q=GetAuthenticPixels(floodplane_image,0,y,(unsigned long) (x1+1),1, exception); if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL)) break; indexes=GetVirtualIndexQueue(image); p+=x1; q+=x1; for (x=x1; x >= 0; x--) { if (q->opacity == (Quantum) TransparentOpacity) break; SetMagickPixelPacket(image,p,indexes+x,&pixel); if (IsMagickColorSimilar(&pixel,target) == invert) break; q->opacity=(Quantum) TransparentOpacity; p--; q--; } if (SyncAuthenticPixels(floodplane_image,exception) == MagickFalse) break; skip=x >= x1 ? MagickTrue : MagickFalse; if (skip == MagickFalse) { start=x+1; if (start < x1) PushSegmentStack(y,start,x1-1,-offset); x=x1+1; } do { if (skip == MagickFalse) { if (x < (long) image->columns) { p=GetVirtualPixels(image,x,y,image->columns-x,1,exception); q=GetAuthenticPixels(floodplane_image,x,y,image->columns-x,1, exception); if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL)) break; indexes=GetVirtualIndexQueue(image); for ( ; x < (long) image->columns; x++) { if (q->opacity == (Quantum) TransparentOpacity) break; SetMagickPixelPacket(image,p,indexes+x,&pixel); if (IsMagickColorSimilar(&pixel,target) == invert) break; q->opacity=(Quantum) TransparentOpacity; p++; q++; } if (SyncAuthenticPixels(floodplane_image,exception) == MagickFalse) break; } PushSegmentStack(y,start,x-1,offset); if (x > (x2+1)) PushSegmentStack(y,x2+1,x-1,-offset); } skip=MagickFalse; x++; if (x <= x2) { p=GetVirtualPixels(image,x,y,(unsigned long) (x2-x+1),1,exception); q=GetAuthenticPixels(floodplane_image,x,y,(unsigned long) (x2-x+1),1, exception); if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL)) break; indexes=GetVirtualIndexQueue(image); for ( ; x <= x2; x++) { if (q->opacity == (Quantum) TransparentOpacity) break; SetMagickPixelPacket(image,p,indexes+x,&pixel); if (IsMagickColorSimilar(&pixel,target) != invert) break; p++; q++; } } start=x; } while (x <= x2); } for (y=0; y < (long) image->rows; y++) { register const PixelPacket *__restrict p; register IndexPacket *__restrict indexes; register long x; register PixelPacket *__restrict q; /* Tile fill color onto floodplane. */ p=GetVirtualPixels(floodplane_image,0,y,image->columns,1,exception); q=GetAuthenticPixels(image,0,y,image->columns,1,exception); if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL)) break; indexes=GetAuthenticIndexQueue(image); for (x=0; x < (long) image->columns; x++) { if (p->opacity != OpaqueOpacity) { (void) GetFillColor(draw_info,x,y,&fill_color); SetMagickPixelPacket(image,&fill_color,(IndexPacket *) NULL,&fill); if (image->colorspace == CMYKColorspace) ConvertRGBToCMYK(&fill); if ((channel & RedChannel) != 0) q->red=RoundToQuantum(fill.red); if ((channel & GreenChannel) != 0) q->green=RoundToQuantum(fill.green); if ((channel & BlueChannel) != 0) q->blue=RoundToQuantum(fill.blue); if ((channel & OpacityChannel) != 0) q->opacity=RoundToQuantum(fill.opacity); if (((channel & IndexChannel) != 0) && (image->colorspace == CMYKColorspace)) indexes[x]=RoundToQuantum(fill.index); } p++; q++; } if (SyncAuthenticPixels(image,exception) == MagickFalse) break; } segment_stack=(SegmentInfo *) RelinquishMagickMemory(segment_stack); floodplane_image=DestroyImage(floodplane_image); return(y == (long) image->rows ? MagickTrue : MagickFalse); }
MagickExport MagickBooleanType PaintOpaqueImageChannel(Image *image, const ChannelType channel,const MagickPixelPacket *target, const MagickPixelPacket *fill) { #define PaintOpaqueImageTag "Opaque/Image" long y; MagickBooleanType status; MagickPixelPacket pixel; register IndexPacket *indexes; register long x; register PixelPacket *q; /* Make image color opaque. */ assert(image != (Image *) NULL); assert(image->signature == MagickSignature); assert(target != (MagickPixelPacket *) NULL); assert(fill != (MagickPixelPacket *) NULL); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); if (SetImageStorageClass(image,DirectClass) == MagickFalse) return(MagickFalse); GetMagickPixelPacket(image,&pixel); for (y=0; y < (long) image->rows; y++) { q=GetImagePixels(image,0,y,image->columns,1); if (q == (PixelPacket *) NULL) break; indexes=GetIndexes(image); for (x=0; x < (long) image->columns; x++) { SetMagickPixelPacket(image,q,indexes+x,&pixel); if (IsMagickColorSimilar(&pixel,target) != MagickFalse) { if ((channel & RedChannel) != 0) q->red=RoundToQuantum(fill->red); if ((channel & GreenChannel) != 0) q->green=RoundToQuantum(fill->green); if ((channel & BlueChannel) != 0) q->blue=RoundToQuantum(fill->blue); if ((channel & OpacityChannel) != 0) q->opacity=RoundToQuantum(fill->opacity); if (((channel & IndexChannel) != 0) && (image->colorspace == CMYKColorspace)) indexes[x]=RoundToQuantum(fill->index); } q++; } if (SyncImagePixels(image) == MagickFalse) break; if ((image->progress_monitor != (MagickProgressMonitor) NULL) && (QuantumTick(y,image->rows) != MagickFalse)) { status=image->progress_monitor(PaintOpaqueImageTag,y,image->rows, image->client_data); if (status == MagickFalse) break; } } return(MagickTrue); }