/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % F r a m e I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % FrameImage() adds a simulated three-dimensional border around the image. % The color of the border is defined by the matte_color member of image. % Members width and height of frame_info specify the border width of the % vertical and horizontal sides of the frame. Members inner and outer % indicate the width of the inner and outer shadows of the frame. % % The format of the FrameImage method is: % % Image *FrameImage(const Image *image,const FrameInfo *frame_info, % const CompositeOperator compose,ExceptionInfo *exception) % % A description of each parameter follows: % % o image: the image. % % o frame_info: Define the width and height of the frame and its bevels. % % o compose: the composite operator. % % o exception: return any errors or warnings in this structure. % */ MagickExport Image *FrameImage(const Image *image,const FrameInfo *frame_info, const CompositeOperator compose,ExceptionInfo *exception) { #define FrameImageTag "Frame/Image" CacheView *image_view, *frame_view; Image *frame_image; MagickBooleanType status; MagickOffsetType progress; PixelInfo accentuate, highlight, interior, matte, shadow, trough; register ssize_t x; size_t bevel_width, height, width; ssize_t y; /* Check frame geometry. */ assert(image != (Image *) NULL); assert(image->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); assert(frame_info != (FrameInfo *) NULL); if ((frame_info->outer_bevel < 0) || (frame_info->inner_bevel < 0)) ThrowImageException(OptionError,"FrameIsLessThanImageSize"); bevel_width=(size_t) (frame_info->outer_bevel+frame_info->inner_bevel); width=frame_info->width-frame_info->x-bevel_width; height=frame_info->height-frame_info->y-bevel_width; if ((width < image->columns) || (height < image->rows)) ThrowImageException(OptionError,"FrameIsLessThanImageSize"); /* Initialize framed image attributes. */ frame_image=CloneImage(image,frame_info->width,frame_info->height,MagickTrue, exception); if (frame_image == (Image *) NULL) return((Image *) NULL); if (SetImageStorageClass(frame_image,DirectClass,exception) == MagickFalse) { frame_image=DestroyImage(frame_image); return((Image *) NULL); } if ((IsGrayColorspace(image->colorspace) != MagickFalse) && (IsPixelInfoGray(&image->matte_color) == MagickFalse)) SetImageColorspace(frame_image,sRGBColorspace,exception); if ((frame_image->border_color.matte != MagickFalse) && (frame_image->matte == MagickFalse)) (void) SetImageAlpha(frame_image,OpaqueAlpha,exception); frame_image->page=image->page; if ((image->page.width != 0) && (image->page.height != 0)) { frame_image->page.width+=frame_image->columns-image->columns; frame_image->page.height+=frame_image->rows-image->rows; } /* Initialize 3D effects color. */ interior=image->border_color; matte=image->matte_color; accentuate=matte; accentuate.red=(MagickRealType) (QuantumScale*((QuantumRange- AccentuateModulate)*matte.red+(QuantumRange*AccentuateModulate))); accentuate.green=(MagickRealType) (QuantumScale*((QuantumRange- AccentuateModulate)*matte.green+(QuantumRange*AccentuateModulate))); accentuate.blue=(MagickRealType) (QuantumScale*((QuantumRange- AccentuateModulate)*matte.blue+(QuantumRange*AccentuateModulate))); accentuate.black=(MagickRealType) (QuantumScale*((QuantumRange- AccentuateModulate)*matte.black+(QuantumRange*AccentuateModulate))); accentuate.alpha=matte.alpha; highlight=matte; highlight.red=(MagickRealType) (QuantumScale*((QuantumRange- HighlightModulate)*matte.red+(QuantumRange*HighlightModulate))); highlight.green=(MagickRealType) (QuantumScale*((QuantumRange- HighlightModulate)*matte.green+(QuantumRange*HighlightModulate))); highlight.blue=(MagickRealType) (QuantumScale*((QuantumRange- HighlightModulate)*matte.blue+(QuantumRange*HighlightModulate))); highlight.black=(MagickRealType) (QuantumScale*((QuantumRange- HighlightModulate)*matte.black+(QuantumRange*HighlightModulate))); highlight.alpha=matte.alpha; shadow=matte; shadow.red=QuantumScale*matte.red*ShadowModulate; shadow.green=QuantumScale*matte.green*ShadowModulate; shadow.blue=QuantumScale*matte.blue*ShadowModulate; shadow.black=QuantumScale*matte.black*ShadowModulate; shadow.alpha=matte.alpha; trough=matte; trough.red=QuantumScale*matte.red*TroughModulate; trough.green=QuantumScale*matte.green*TroughModulate; trough.blue=QuantumScale*matte.blue*TroughModulate; trough.black=QuantumScale*matte.black*TroughModulate; trough.alpha=matte.alpha; status=MagickTrue; progress=0; image_view=AcquireCacheView(image); frame_view=AcquireCacheView(frame_image); height=(size_t) (frame_info->outer_bevel+(frame_info->y-bevel_width)+ frame_info->inner_bevel); if (height != 0) { register ssize_t x; register Quantum *restrict q; /* Draw top of ornamental border. */ q=QueueCacheViewAuthenticPixels(frame_view,0,0,frame_image->columns, height,exception); if (q != (Quantum *) NULL) { /* Draw top of ornamental border. */ for (y=0; y < (ssize_t) frame_info->outer_bevel; y++) { for (x=0; x < (ssize_t) (frame_image->columns-y); x++) { if (x < y) SetPixelInfoPixel(frame_image,&highlight,q); else SetPixelInfoPixel(frame_image,&accentuate,q); q+=GetPixelChannels(frame_image); } for ( ; x < (ssize_t) frame_image->columns; x++) { SetPixelInfoPixel(frame_image,&shadow,q); q+=GetPixelChannels(frame_image); } } for (y=0; y < (ssize_t) (frame_info->y-bevel_width); y++) { for (x=0; x < (ssize_t) frame_info->outer_bevel; x++) { SetPixelInfoPixel(frame_image,&highlight,q); q+=GetPixelChannels(frame_image); } width=frame_image->columns-2*frame_info->outer_bevel; for (x=0; x < (ssize_t) width; x++) { SetPixelInfoPixel(frame_image,&matte,q); q+=GetPixelChannels(frame_image); } for (x=0; x < (ssize_t) frame_info->outer_bevel; x++) { SetPixelInfoPixel(frame_image,&shadow,q); q+=GetPixelChannels(frame_image); } } for (y=0; y < (ssize_t) frame_info->inner_bevel; y++) { for (x=0; x < (ssize_t) frame_info->outer_bevel; x++) { SetPixelInfoPixel(frame_image,&highlight,q); q+=GetPixelChannels(frame_image); } for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++) { SetPixelInfoPixel(frame_image,&matte,q); q+=GetPixelChannels(frame_image); } width=image->columns+((size_t) frame_info->inner_bevel << 1)- y; for (x=0; x < (ssize_t) width; x++) { if (x < y) SetPixelInfoPixel(frame_image,&shadow,q); else SetPixelInfoPixel(frame_image,&trough,q); q+=GetPixelChannels(frame_image); } for ( ; x < (ssize_t) (image->columns+2*frame_info->inner_bevel); x++) { SetPixelInfoPixel(frame_image,&highlight,q); q+=GetPixelChannels(frame_image); } width=frame_info->width-frame_info->x-image->columns-bevel_width; for (x=0; x < (ssize_t) width; x++) { SetPixelInfoPixel(frame_image,&matte,q); q+=GetPixelChannels(frame_image); } for (x=0; x < (ssize_t) frame_info->outer_bevel; x++) { SetPixelInfoPixel(frame_image,&shadow,q); q+=GetPixelChannels(frame_image); } } (void) SyncCacheViewAuthenticPixels(frame_view,exception); } } /* Draw sides of ornamental border. */ #if defined(MAGICKCORE_OPENMP_SUPPORT) #pragma omp parallel for schedule(static) shared(progress,status) #endif for (y=0; y < (ssize_t) image->rows; y++) { register ssize_t x; register Quantum *restrict q; size_t width; /* Initialize scanline with matte color. */ if (status == MagickFalse) continue; q=QueueCacheViewAuthenticPixels(frame_view,0,frame_info->y+y, frame_image->columns,1,exception); if (q == (Quantum *) NULL) { status=MagickFalse; continue; } for (x=0; x < (ssize_t) frame_info->outer_bevel; x++) { SetPixelInfoPixel(frame_image,&highlight,q); q+=GetPixelChannels(frame_image); } for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++) { SetPixelInfoPixel(frame_image,&matte,q); q+=GetPixelChannels(frame_image); } for (x=0; x < (ssize_t) frame_info->inner_bevel; x++) { SetPixelInfoPixel(frame_image,&shadow,q); q+=GetPixelChannels(frame_image); } /* Set frame interior to interior color. */ if ((compose != CopyCompositeOp) && ((compose != OverCompositeOp) || (image->matte != MagickFalse))) for (x=0; x < (ssize_t) image->columns; x++) { SetPixelInfoPixel(frame_image,&interior,q); q+=GetPixelChannels(frame_image); } else { register const Quantum *p; p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); if (p == (const Quantum *) NULL) { status=MagickFalse; continue; } for (x=0; x < (ssize_t) image->columns; x++) { if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) SetPixelRed(frame_image,GetPixelRed(image,p),q); if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) SetPixelGreen(frame_image,GetPixelGreen(image,p),q); if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) SetPixelBlue(frame_image,GetPixelBlue(image,p),q); if ((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) SetPixelBlack(frame_image,GetPixelBlack(image,p),q); if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) SetPixelAlpha(frame_image,GetPixelAlpha(image,p),q); p+=GetPixelChannels(image); q+=GetPixelChannels(frame_image); } } for (x=0; x < (ssize_t) frame_info->inner_bevel; x++) { SetPixelInfoPixel(frame_image,&highlight,q); q+=GetPixelChannels(frame_image); } width=frame_info->width-frame_info->x-image->columns-bevel_width; for (x=0; x < (ssize_t) width; x++) { SetPixelInfoPixel(frame_image,&matte,q); q+=GetPixelChannels(frame_image); } for (x=0; x < (ssize_t) frame_info->outer_bevel; x++) { SetPixelInfoPixel(frame_image,&shadow,q); q+=GetPixelChannels(frame_image); } if (SyncCacheViewAuthenticPixels(frame_view,exception) == MagickFalse) status=MagickFalse; if (image->progress_monitor != (MagickProgressMonitor) NULL) { MagickBooleanType proceed; #if defined(MAGICKCORE_OPENMP_SUPPORT) #pragma omp critical (MagickCore_FrameImage) #endif proceed=SetImageProgress(image,FrameImageTag,progress++,image->rows); if (proceed == MagickFalse) status=MagickFalse; } } height=(size_t) (frame_info->inner_bevel+frame_info->height- frame_info->y-image->rows-bevel_width+frame_info->outer_bevel); if (height != 0) { register ssize_t x; register Quantum *restrict q; /* Draw bottom of ornamental border. */ q=QueueCacheViewAuthenticPixels(frame_view,0,(ssize_t) (frame_image->rows- height),frame_image->columns,height,exception); if (q != (Quantum *) NULL) { /* Draw bottom of ornamental border. */ for (y=frame_info->inner_bevel-1; y >= 0; y--) { for (x=0; x < (ssize_t) frame_info->outer_bevel; x++) { SetPixelInfoPixel(frame_image,&highlight,q); q+=GetPixelChannels(frame_image); } for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++) { SetPixelInfoPixel(frame_image,&matte,q); q+=GetPixelChannels(frame_image); } for (x=0; x < y; x++) { SetPixelInfoPixel(frame_image,&shadow,q); q+=GetPixelChannels(frame_image); } for ( ; x < (ssize_t) (image->columns+2*frame_info->inner_bevel); x++) { if (x >= (ssize_t) (image->columns+2*frame_info->inner_bevel-y)) SetPixelInfoPixel(frame_image,&highlight,q); else SetPixelInfoPixel(frame_image,&accentuate,q); q+=GetPixelChannels(frame_image); } width=frame_info->width-frame_info->x-image->columns-bevel_width; for (x=0; x < (ssize_t) width; x++) { SetPixelInfoPixel(frame_image,&matte,q); q+=GetPixelChannels(frame_image); } for (x=0; x < (ssize_t) frame_info->outer_bevel; x++) { SetPixelInfoPixel(frame_image,&shadow,q); q+=GetPixelChannels(frame_image); } } height=frame_info->height-frame_info->y-image->rows-bevel_width; for (y=0; y < (ssize_t) height; y++) { for (x=0; x < (ssize_t) frame_info->outer_bevel; x++) { SetPixelInfoPixel(frame_image,&highlight,q); q+=GetPixelChannels(frame_image); } width=frame_image->columns-2*frame_info->outer_bevel; for (x=0; x < (ssize_t) width; x++) { SetPixelInfoPixel(frame_image,&matte,q); q+=GetPixelChannels(frame_image); } for (x=0; x < (ssize_t) frame_info->outer_bevel; x++) { SetPixelInfoPixel(frame_image,&shadow,q); q+=GetPixelChannels(frame_image); } } for (y=frame_info->outer_bevel-1; y >= 0; y--) { for (x=0; x < y; x++) { SetPixelInfoPixel(frame_image,&highlight,q); q+=GetPixelChannels(frame_image); } for ( ; x < (ssize_t) frame_image->columns; x++) { if (x >= (ssize_t) (frame_image->columns-y)) SetPixelInfoPixel(frame_image,&shadow,q); else SetPixelInfoPixel(frame_image,&trough,q); q+=GetPixelChannels(frame_image); } } (void) SyncCacheViewAuthenticPixels(frame_view,exception); } } frame_view=DestroyCacheView(frame_view); image_view=DestroyCacheView(image_view); if ((compose != CopyCompositeOp) && ((compose != OverCompositeOp) || (image->matte != MagickFalse))) { x=(ssize_t) (frame_info->outer_bevel+(frame_info->x-bevel_width)+ frame_info->inner_bevel); y=(ssize_t) (frame_info->outer_bevel+(frame_info->y-bevel_width)+ frame_info->inner_bevel); (void) CompositeImage(frame_image,image,compose,MagickTrue,x,y, exception); } return(frame_image); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % O p a q u e P a i n t I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % OpaquePaintImage() changes any pixel that matches color with the color % defined by fill. % % By default color must match a particular pixel color exactly. However, in % many cases two colors may differ by a small amount. Fuzz 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. % % The format of the OpaquePaintImage method is: % % MagickBooleanType OpaquePaintImage(Image *image, % const PixelInfo *target,const PixelInfo *fill, % const MagickBooleanType invert,ExceptionInfo *exception) % % A description of each parameter follows: % % o image: the image. % % o target: the RGB value of the target color. % % o fill: the replacement color. % % o invert: paint any pixel that does not match the target color. % % o exception: return any errors or warnings in this structure. % */ MagickExport MagickBooleanType OpaquePaintImage(Image *image, const PixelInfo *target,const PixelInfo *fill,const MagickBooleanType invert, ExceptionInfo *exception) { #define OpaquePaintImageTag "Opaque/Image" CacheView *image_view; MagickBooleanType status; MagickOffsetType progress; PixelInfo zero; ssize_t y; assert(image != (Image *) NULL); assert(image->signature == MagickSignature); assert(target != (PixelInfo *) NULL); assert(fill != (PixelInfo *) NULL); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) return(MagickFalse); if ((IsGrayColorspace(image->colorspace) != MagickFalse) && (IsPixelInfoGray(fill) == MagickFalse)) (void) SetImageColorspace(image,sRGBColorspace,exception); if ((fill->alpha_trait == BlendPixelTrait) && (image->alpha_trait != BlendPixelTrait)) (void) SetImageAlpha(image,OpaqueAlpha,exception); /* Make image color opaque. */ status=MagickTrue; progress=0; GetPixelInfo(image,&zero); image_view=AcquireAuthenticCacheView(image,exception); #if defined(MAGICKCORE_OPENMP_SUPPORT) #pragma omp parallel for schedule(static,4) shared(progress,status) \ magick_threads(image,image,image->rows,1) #endif for (y=0; y < (ssize_t) image->rows; y++) { PixelInfo pixel; register Quantum *restrict q; register ssize_t x; if (status == MagickFalse) continue; q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception); if (q == (Quantum *) NULL) { status=MagickFalse; continue; } pixel=zero; for (x=0; x < (ssize_t) image->columns; x++) { GetPixelInfoPixel(image,q,&pixel); if (IsFuzzyEquivalencePixelInfo(&pixel,target) != invert) SetPixelInfoPixel(image,fill,q); q+=GetPixelChannels(image); } 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_OpaquePaintImage) #endif proceed=SetImageProgress(image,OpaquePaintImageTag,progress++, image->rows); if (proceed == MagickFalse) status=MagickFalse; } } image_view=DestroyCacheView(image_view); return(status); }