/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + I n t e g r a l R o t a t e I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % IntegralRotateImage() rotates the image an integral of 90 degrees. It % allocates the memory necessary for the new Image structure and returns a % pointer to the rotated image. % % The format of the IntegralRotateImage method is: % % Image *IntegralRotateImage(const Image *image,unsigned long rotations, % ExceptionInfo *exception) % % A description of each parameter follows. % % o image: The image. % % o rotations: Specifies the number of 90 degree rotations. % % */ static Image *IntegralRotateImage(const Image *image,unsigned long rotations, ExceptionInfo *exception) { #define RotateImageTag "Rotate/Image" Image *rotate_image; long y; MagickBooleanType status; RectangleInfo page; register IndexPacket *indexes, *rotate_indexes; register const PixelPacket *p; register long x; register PixelPacket *q; /* Initialize rotated image attributes. */ assert(image != (Image *) NULL); page=image->page; rotations%=4; if ((rotations == 1) || (rotations == 3)) rotate_image=CloneImage(image,image->rows,image->columns,MagickTrue, exception); else rotate_image=CloneImage(image,image->columns,image->rows,MagickTrue, exception); if (rotate_image == (Image *) NULL) return((Image *) NULL); /* Integral rotate the image. */ switch (rotations) { case 0: { /* Rotate 0 degrees. */ for (y=0; y < (long) image->rows; y++) { p=AcquireImagePixels(image,0,y,image->columns,1,exception); q=SetImagePixels(rotate_image,0,y,rotate_image->columns,1); if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL)) break; (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q)); indexes=GetIndexes(image); rotate_indexes=GetIndexes(rotate_image); if ((indexes != (IndexPacket *) NULL) && (rotate_indexes != (IndexPacket *) NULL)) (void) CopyMagickMemory(rotate_indexes,indexes,(size_t) image->columns*sizeof(*rotate_indexes)); if (SyncImagePixels(rotate_image) == MagickFalse) break; if ((image->progress_monitor != (MagickProgressMonitor) NULL) && (QuantumTick(y,image->rows) != MagickFalse)) { status=image->progress_monitor(RotateImageTag,y,image->rows, image->client_data); if (status == MagickFalse) break; } } break; } case 1: { /* Rotate 90 degrees. */ for (y=0; y < (long) image->rows; y++) { p=AcquireImagePixels(image,0,y,image->columns,1,exception); q=SetImagePixels(rotate_image,(long) (image->rows-y-1),0,1, rotate_image->rows); if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL)) break; (void) CopyMagickMemory(q,p,(size_t) image->columns*sizeof(*q)); indexes=GetIndexes(image); rotate_indexes=GetIndexes(rotate_image); if ((indexes != (IndexPacket *) NULL) && (rotate_indexes != (IndexPacket *) NULL)) (void) CopyMagickMemory(rotate_indexes,indexes,(size_t) image->columns*sizeof(*rotate_indexes)); if (SyncImagePixels(rotate_image) == MagickFalse) break; if ((image->progress_monitor != (MagickProgressMonitor) NULL) && (QuantumTick(y,image->rows) != MagickFalse)) { status=image->progress_monitor(RotateImageTag,y,image->rows, image->client_data); if (status == MagickFalse) break; } } Swap(page.width,page.height); Swap(page.x,page.y); if (page.width != 0) page.x=(long) (page.width-rotate_image->columns-page.x); break; } case 2: { /* Rotate 180 degrees. */ for (y=0; y < (long) image->rows; y++) { p=AcquireImagePixels(image,0,y,image->columns,1,exception); q=SetImagePixels(rotate_image,0,(long) (image->rows-y-1), image->columns,1); if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL)) break; q+=image->columns; indexes=GetIndexes(image); rotate_indexes=GetIndexes(rotate_image); if ((indexes != (IndexPacket *) NULL) && (rotate_indexes != (IndexPacket *) NULL)) for (x=0; x < (long) image->columns; x++) rotate_indexes[image->columns-x-1]=indexes[x]; for (x=0; x < (long) image->columns; x++) *--q=(*p++); if (SyncImagePixels(rotate_image) == MagickFalse) break; if ((image->progress_monitor != (MagickProgressMonitor) NULL) && (QuantumTick(y,image->rows) != MagickFalse)) { status=image->progress_monitor(RotateImageTag,y,image->rows, image->client_data); if (status == MagickFalse) break; } } if (page.width != 0) page.x=(long) (page.width-rotate_image->columns-page.x); if (page.height != 0) page.y=(long) (page.height-rotate_image->rows-page.y); break; } case 3: { /* Rotate 270 degrees. */ for (y=0; y < (long) image->rows; y++) { p=AcquireImagePixels(image,0,y,image->columns,1,exception); q=SetImagePixels(rotate_image,y,0,1,rotate_image->rows); if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL)) break; q+=image->columns; for (x=0; x < (long) image->columns; x++) *--q=(*p++); indexes=GetIndexes(image); rotate_indexes=GetIndexes(rotate_image); if ((indexes != (IndexPacket *) NULL) && (rotate_indexes != (IndexPacket *) NULL)) for (x=0; x < (long) image->columns; x++) rotate_indexes[image->columns-x-1]=indexes[x]; if (SyncImagePixels(rotate_image) == MagickFalse) break; if ((image->progress_monitor != (MagickProgressMonitor) NULL) && (QuantumTick(y,image->rows) != MagickFalse)) { status=image->progress_monitor(RotateImageTag,y,image->rows, image->client_data); if (status == MagickFalse) break; } } Swap(page.width,page.height); Swap(page.x,page.y); if (page.height != 0) page.y=(long) (page.height-rotate_image->rows-page.y); break; } } rotate_image->page=page; return(rotate_image); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d G R A Y I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ReadGRAYImage() reads an image of raw grayscale samples and returns % it. It allocates the memory necessary for the new Image structure and % returns a pointer to the new image. % % The format of the ReadGRAYImage method is: % % Image *ReadGRAYImage(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 *ReadGRAYImage(const ImageInfo *image_info, ExceptionInfo *exception) { const unsigned char *pixels; Image *canvas_image, *image; MagickBooleanType status; MagickOffsetType scene; QuantumInfo *quantum_info; QuantumType quantum_type; size_t length; ssize_t count, y; /* Open image file. */ assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickCoreSignature); if (image_info->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", image_info->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickCoreSignature); image=AcquireImage(image_info,exception); if ((image->columns == 0) || (image->rows == 0)) ThrowReaderException(OptionError,"MustSpecifyImageSize"); status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) { image=DestroyImageList(image); return((Image *) NULL); } if (DiscardBlobBytes(image,(size_t) image->offset) == MagickFalse) ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", image->filename); /* Create virtual canvas to support cropping (i.e. image.gray[100x100+10+20]). */ SetImageColorspace(image,GRAYColorspace,exception); canvas_image=CloneImage(image,image->extract_info.width,1,MagickFalse, exception); (void) SetImageVirtualPixelMethod(canvas_image,BlackVirtualPixelMethod, exception); quantum_type=GrayQuantum; quantum_info=AcquireQuantumInfo(image_info,canvas_image); if (quantum_info == (QuantumInfo *) NULL) ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); pixels=(const unsigned char *) NULL; if (image_info->number_scenes != 0) while (image->scene < image_info->scene) { /* Skip to next image. */ image->scene++; length=GetQuantumExtent(canvas_image,quantum_info,quantum_type); for (y=0; y < (ssize_t) image->rows; y++) { pixels=(const unsigned char *) ReadBlobStream(image,length, GetQuantumPixels(quantum_info),&count); if (count != (ssize_t) length) break; } } scene=0; count=0; length=0; do { /* Read pixels to virtual canvas image then push to image. */ if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0)) if (image->scene >= (image_info->scene+image_info->number_scenes-1)) break; status=SetImageExtent(image,image->columns,image->rows,exception); if (status == MagickFalse) return(DestroyImageList(image)); SetImageColorspace(image,GRAYColorspace,exception); if (scene == 0) { length=GetQuantumExtent(canvas_image,quantum_info,quantum_type); pixels=(const unsigned char *) ReadBlobStream(image,length, GetQuantumPixels(quantum_info),&count); } for (y=0; y < (ssize_t) image->extract_info.height; y++) { register const Quantum *magick_restrict p; register ssize_t x; register Quantum *magick_restrict q; if (count != (ssize_t) length) { ThrowFileException(exception,CorruptImageError, "UnexpectedEndOfFile",image->filename); break; } q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,exception); if (q == (Quantum *) NULL) break; length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,quantum_info, quantum_type,pixels,exception); if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse) break; if (((y-image->extract_info.y) >= 0) && ((y-image->extract_info.y) < (ssize_t) image->rows)) { p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0, image->columns,1,exception); q=QueueAuthenticPixels(image,0,y-image->extract_info.y,image->columns, 1,exception); if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) break; for (x=0; x < (ssize_t) image->columns; x++) { SetPixelGray(image,GetPixelGray(canvas_image,p),q); p+=GetPixelChannels(canvas_image); q+=GetPixelChannels(image); } if (SyncAuthenticPixels(image,exception) == MagickFalse) break; } if (image->previous == (Image *) NULL) { status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, image->rows); if (status == MagickFalse) break; } pixels=(const unsigned char *) ReadBlobStream(image,length, GetQuantumPixels(quantum_info),&count); } SetQuantumImageType(image,quantum_type); /* Proceed to next image. */ if (image_info->number_scenes != 0) if (image->scene >= (image_info->scene+image_info->number_scenes-1)) break; if (count == (ssize_t) length) { /* Allocate next image structure. */ AcquireNextImage(image_info,image,exception); if (GetNextImageInList(image) == (Image *) NULL) { image=DestroyImageList(image); return((Image *) NULL); } image=SyncNextImageInList(image); status=SetImageProgress(image,LoadImagesTag,TellBlob(image), GetBlobSize(image)); if (status == MagickFalse) break; } scene++; } while (count == (ssize_t) length); quantum_info=DestroyQuantumInfo(quantum_info); canvas_image=DestroyImage(canvas_image); (void) CloseBlob(image); return(GetFirstImageInList(image)); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d X T R N I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ReadXTRNImage() reads a XTRN image file and returns it. It % allocates the memory necessary for the new Image structure and returns a % pointer to the new image. % % The format of the ReadXTRNImage method is: % % Image *ReadXTRNImage(const ImageInfo *image_info, % ExceptionInfo *exception) % % A description of each parameter follows: % % o image_info: Specifies a pointer to an ImageInfo structure. % % o exception: return any errors or warnings in this structure. % */ static Image *ReadXTRNImage(const ImageInfo *image_info, ExceptionInfo *exception) { Image *image; ImageInfo *clone_info; void *param1, *param2, *param3; param1 = param2 = param3 = (void *) NULL; image = (Image *) NULL; clone_info=CloneImageInfo(image_info); if (clone_info->filename == NULL) { clone_info=DestroyImageInfo(clone_info); ThrowReaderException(FileOpenWarning,"No filename specified"); } if (LocaleCompare(image_info->magick,"XTRNFILE") == 0) { image=ReadImage(clone_info,exception); CatchException(exception); } else if (LocaleCompare(image_info->magick,"XTRNIMAGE") == 0) { Image **image_ptr; #ifdef ALL_IMAGEINFO ImageInfo **image_info_ptr; #endif (void) sscanf(clone_info->filename,"%lx,%lx",¶m1,¶m2); image_ptr=(Image **) param2; if (*image_ptr != (Image *)NULL) image=CloneImage(*image_ptr,0,0,MagickFalse,&(*image_ptr)->exception); #ifdef ALL_IMAGEINFO image_info_ptr=(ImageInfo **) param1; if (*image_info_ptr != (ImageInfo *)NULL) image_info=*image_info_ptr; #endif } else if (LocaleCompare(image_info->magick,"XTRNBLOB") == 0) { char **blob_data; size_t *blob_length; char filename[MaxTextExtent]; (void) sscanf(clone_info->filename,"%lx,%lx,%s",¶m1,¶m2,&filename); blob_data=(char **) param1; blob_length=(size_t *) param2; image=BlobToImage(clone_info,*blob_data,*blob_length,exception); CatchException(exception); } else if (LocaleCompare(image_info->magick,"XTRNARRAY") == 0) { char *blob_data, filename[MaxTextExtent]; HRESULT hr; long lBoundl, lBoundu; SAFEARRAY *pSafeArray; size_t blob_length; *filename='\0'; (void) sscanf(clone_info->filename,"%lx,%s",¶m1,&filename); hr=S_OK; pSafeArray=(SAFEARRAY *) param1; if (pSafeArray) { hr = SafeArrayGetLBound(pSafeArray, 1, &lBoundl); if (SUCCEEDED(hr)) hr = SafeArrayGetUBound(pSafeArray, 1, &lBoundu); if (SUCCEEDED(hr)) { blob_length = lBoundu - lBoundl + 1; hr = SafeArrayAccessData(pSafeArray,(void**) &blob_data); if(SUCCEEDED(hr)) { *clone_info->filename='\0'; *clone_info->magick='\0'; if (*filename != '\0') (void) CopyMagickString(clone_info->filename,filename, MaxTextExtent); image=BlobToImage(clone_info,blob_data,blob_length,exception); hr=SafeArrayUnaccessData(pSafeArray); CatchException(exception); } } } } clone_info=DestroyImageInfo(clone_info); return(image); }
MagickExport Image *ChannelFxImage(const Image *image,const char *expression, ExceptionInfo *exception) { #define ChannelFxImageTag "ChannelFx/Image" ChannelFx channel_op; ChannelType channel_mask; char token[MagickPathExtent]; const char *p; const Image *source_image; double pixel; Image *destination_image; MagickBooleanType status; PixelChannel source_channel, destination_channel; ssize_t channels; assert(image != (Image *) NULL); assert(image->signature == MagickCoreSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickCoreSignature); source_image=image; destination_image=CloneImage(source_image,0,0,MagickTrue,exception); if (destination_image == (Image *) NULL) return((Image *) NULL); if (expression == (const char *) NULL) return(destination_image); destination_channel=RedPixelChannel; channel_mask=UndefinedChannel; pixel=0.0; p=(char *) expression; GetMagickToken(p,&p,token); channel_op=ExtractChannelOp; for (channels=0; *token != '\0'; ) { ssize_t i; /* Interpret channel expression. */ switch (*token) { case ',': { GetMagickToken(p,&p,token); break; } case '|': { if (GetNextImageInList(source_image) != (Image *) NULL) source_image=GetNextImageInList(source_image); else source_image=GetFirstImageInList(source_image); GetMagickToken(p,&p,token); break; } case ';': { Image *canvas; (void) SetPixelChannelMask(destination_image,channel_mask); if ((channel_op == ExtractChannelOp) && (channels == 1)) (void) SetImageColorspace(destination_image,GRAYColorspace,exception); status=SetImageStorageClass(destination_image,DirectClass,exception); if (status == MagickFalse) { destination_image=DestroyImageList(destination_image); return(destination_image); } canvas=CloneImage(source_image,0,0,MagickTrue,exception); if (canvas == (Image *) NULL) { destination_image=DestroyImageList(destination_image); return(destination_image); } AppendImageToList(&destination_image,canvas); destination_image=GetLastImageInList(destination_image); GetMagickToken(p,&p,token); channels=0; destination_channel=RedPixelChannel; channel_mask=UndefinedChannel; break; } default: break; } i=ParsePixelChannelOption(token); if (i < 0) { (void) ThrowMagickException(exception,GetMagickModule(),OptionError, "UnrecognizedChannelType","`%s'",token); destination_image=DestroyImageList(destination_image); return(destination_image); } source_channel=(PixelChannel) i; channel_op=ExtractChannelOp; GetMagickToken(p,&p,token); if (*token == '<') { channel_op=ExchangeChannelOp; GetMagickToken(p,&p,token); } if (*token == '=') { if (channel_op != ExchangeChannelOp) channel_op=AssignChannelOp; GetMagickToken(p,&p,token); } if (*token == '>') { if (channel_op != ExchangeChannelOp) channel_op=TransferChannelOp; GetMagickToken(p,&p,token); } switch (channel_op) { case AssignChannelOp: { pixel=StringToDoubleInterval(token,(double) QuantumRange+1.0); GetMagickToken(p,&p,token); break; } case ExchangeChannelOp: case TransferChannelOp: { i=ParsePixelChannelOption(token); if (i < 0) { (void) ThrowMagickException(exception,GetMagickModule(),OptionError, "UnrecognizedChannelType","`%s'",token); destination_image=DestroyImageList(destination_image); return(destination_image); } destination_channel=(PixelChannel) i; switch (destination_channel) { case RedPixelChannel: case GreenPixelChannel: case BluePixelChannel: case BlackPixelChannel: case IndexPixelChannel: break; case AlphaPixelChannel: { destination_image->alpha_trait=BlendPixelTrait; break; } case ReadMaskPixelChannel: { destination_image->read_mask=MagickTrue; break; } case WriteMaskPixelChannel: { destination_image->write_mask=MagickTrue; break; } case MetaPixelChannel: default: { (void) SetPixelMetaChannels(destination_image,(size_t) (i- GetPixelChannels(destination_image)+1),exception); break; } } channel_mask=(ChannelType) (channel_mask | ParseChannelOption(token)); if (((channels >= 1) || (destination_channel >= 1)) && (IsGrayColorspace(destination_image->colorspace) != MagickFalse)) (void) SetImageColorspace(destination_image,sRGBColorspace,exception); GetMagickToken(p,&p,token); break; } default: break; } status=ChannelImage(destination_image,destination_channel,channel_op, source_image,source_channel,ClampToQuantum(pixel),exception); if (status == MagickFalse) { destination_image=DestroyImageList(destination_image); break; } channels++; if (channel_op == ExchangeChannelOp) { status=ChannelImage(destination_image,source_channel,channel_op, source_image,destination_channel,ClampToQuantum(pixel),exception); if (status == MagickFalse) { destination_image=DestroyImageList(destination_image); break; } channels++; } switch (channel_op) { case ExtractChannelOp: { channel_mask=(ChannelType) (channel_mask | (1 << destination_channel)); destination_channel=(PixelChannel) (destination_channel+1); break; } default: break; } status=SetImageProgress(source_image,ChannelFxImageTag,p-expression, strlen(expression)); if (status == MagickFalse) break; } (void) SetPixelChannelMask(destination_image,channel_mask); if ((channel_op == ExtractChannelOp) && (channels == 1)) (void) SetImageColorspace(destination_image,GRAYColorspace,exception); status=SetImageStorageClass(destination_image,DirectClass,exception); if (status == MagickFalse) { destination_image=GetLastImageInList(destination_image); return((Image *) NULL); } return(GetFirstImageInList(destination_image)); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % S e p a r a t e I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % SeparateImage() separates a channel from the image and returns it as a % grayscale image. % % The format of the SeparateImage method is: % % Image *SeparateImage(const Image *image,const ChannelType channel, % ExceptionInfo *exception) % % A description of each parameter follows: % % o image: the image. % % o channel: the image channel. % % o exception: return any errors or warnings in this structure. % */ MagickExport Image *SeparateImage(const Image *image, const ChannelType channel_type,ExceptionInfo *exception) { #define GetChannelBit(mask,bit) (((size_t) (mask) >> (size_t) (bit)) & 0x01) #define SeparateImageTag "Separate/Image" CacheView *image_view, *separate_view; Image *separate_image; MagickBooleanType status; MagickOffsetType progress; ssize_t y; /* Initialize separate image attributes. */ assert(image != (Image *) NULL); assert(image->signature == MagickCoreSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickCoreSignature); separate_image=CloneImage(image,image->columns,image->rows,MagickTrue, exception); if (separate_image == (Image *) NULL) return((Image *) NULL); if (SetImageStorageClass(separate_image,DirectClass,exception) == MagickFalse) { separate_image=DestroyImage(separate_image); return((Image *) NULL); } (void) SetImageColorspace(separate_image,GRAYColorspace,exception); separate_image->alpha_trait=UndefinedPixelTrait; /* Separate image. */ status=MagickTrue; progress=0; image_view=AcquireVirtualCacheView(image,exception); separate_view=AcquireAuthenticCacheView(separate_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++) { register const Quantum *magick_restrict p; register Quantum *magick_restrict q; register ssize_t x; if (status == MagickFalse) continue; p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); q=QueueCacheViewAuthenticPixels(separate_view,0,y,separate_image->columns,1, exception); if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) { status=MagickFalse; continue; } for (x=0; x < (ssize_t) image->columns; x++) { register ssize_t i; if (GetPixelReadMask(image,p) == 0) { SetPixelBackgoundColor(separate_image,q); p+=GetPixelChannels(image); q+=GetPixelChannels(separate_image); continue; } SetPixelChannel(separate_image,GrayPixelChannel,0,q); for (i=0; i < (ssize_t) GetPixelChannels(image); i++) { PixelChannel channel=GetPixelChannelChannel(image,i); PixelTrait traits=GetPixelChannelTraits(image,channel); if ((traits == UndefinedPixelTrait) || (GetChannelBit(channel_type,channel) == 0)) continue; SetPixelChannel(separate_image,GrayPixelChannel,p[i],q); } p+=GetPixelChannels(image); q+=GetPixelChannels(separate_image); } if (SyncCacheViewAuthenticPixels(separate_view,exception) == MagickFalse) status=MagickFalse; if (image->progress_monitor != (MagickProgressMonitor) NULL) { MagickBooleanType proceed; #if defined(MAGICKCORE_OPENMP_SUPPORT) #pragma omp critical (MagickCore_SeparateImage) #endif proceed=SetImageProgress(image,SeparateImageTag,progress++,image->rows); if (proceed == MagickFalse) status=MagickFalse; } } separate_view=DestroyCacheView(separate_view); image_view=DestroyCacheView(image_view); (void) SetImageChannelMask(separate_image,DefaultChannels); if (status == MagickFalse) separate_image=DestroyImage(separate_image); return(separate_image); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % A v e r a g e I m a g e s % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % The Average() method takes a set of images and averages them together. % Each image in the set must have the same width and height. Average() % returns a single image with each corresponding pixel component of % each image averaged. On failure, a NULL image is returned and % exception describes the reason for the failure. % % The format of the AverageImage method is: % % Image *AverageImages(Image *image,ExceptionInfo *exception) % % A description of each parameter follows: % % o image: The image sequence. % % o exception: Return any errors or warnings in this structure. % % */ MagickExport Image *AverageImages(const Image *image,ExceptionInfo *exception) { ThreadViewDataSet *pixels_sums; Image *average_image; const Image *last_image; long y; unsigned long row_count=0; double number_scenes; unsigned long number_pixels; MagickPassFail status=MagickPass; /* Ensure the image are the same size. */ assert(image != (Image *) NULL); assert(image->signature == MagickSignature); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); if (image->next == (Image *) NULL) ThrowImageException3(ImageError,ImageSequenceIsRequired, UnableToAverageImage); { const Image *next; for (next=image; next != (Image *) NULL; next=next->next) { if ((next->columns != image->columns) || (next->rows != image->rows)) ThrowImageException3(OptionError,UnableToAverageImageSequence, ImageWidthsOrHeightsDiffer); } } /* Allocate sum accumulation buffer. */ number_pixels=image->columns; pixels_sums=AllocateThreadViewDataArray(image,exception,number_pixels, sizeof(DoublePixelPacket)); if (pixels_sums == (ThreadViewDataSet *) NULL) ThrowImageException3(ResourceLimitError,MemoryAllocationFailed, UnableToAverageImageSequence); /* Initialize average next attributes. */ average_image=CloneImage(image,image->columns,image->rows,True,exception); if (average_image == (Image *) NULL) { DestroyThreadViewDataSet(pixels_sums); return((Image *) NULL); } average_image->storage_class=DirectClass; number_scenes=(double) GetImageListLength(image); last_image=GetLastImageInList(image); #if defined(HAVE_OPENMP) # pragma omp parallel for schedule(dynamic) shared(row_count, status) #endif for (y=0; y < (long) image->rows; y++) { register DoublePixelPacket *pixels_sum; const Image *next; register const PixelPacket *p; register long x; MagickBool thread_status; thread_status=status; if (thread_status == MagickFail) continue; pixels_sum=AccessThreadViewData(pixels_sums); /* Compute sum over each pixel color component. */ for (next=image; next != (Image *) NULL; next=next->next) { ViewInfo *next_view; next_view=OpenCacheView((Image *) next); if (next_view == (ViewInfo *) NULL) thread_status=MagickFail; if (next_view != (ViewInfo *) NULL) { p=AcquireCacheViewPixels(next_view,0,y,next->columns,1,exception); if (p == (const PixelPacket *) NULL) thread_status=MagickFail; if (p != (const PixelPacket *) NULL) { if (next == image) { for (x=0; x < (long) next->columns; x++) { pixels_sum[x].red=p[x].red; pixels_sum[x].green=p[x].green; pixels_sum[x].blue=p[x].blue; pixels_sum[x].opacity=p[x].opacity; } } else { for (x=0; x < (long) next->columns; x++) { pixels_sum[x].red+=p[x].red; pixels_sum[x].green+=p[x].green; pixels_sum[x].blue+=p[x].blue; pixels_sum[x].opacity+=p[x].opacity; } } } CloseCacheView(next_view); } } /* Average next pixels. */ if (thread_status != MagickFail) { register PixelPacket *q; q=SetImagePixelsEx(average_image,0,y,average_image->columns,1,exception); if (q == (PixelPacket *) NULL) thread_status=MagickFail; if (q != (PixelPacket *) NULL) { for (x=0; x < (long) average_image->columns; x++) { q[x].red=(Quantum) (pixels_sum[x].red/number_scenes+0.5); q[x].green=(Quantum) (pixels_sum[x].green/number_scenes+0.5); q[x].blue=(Quantum) (pixels_sum[x].blue/number_scenes+0.5); q[x].opacity=(Quantum) (pixels_sum[x].opacity/number_scenes+0.5); } if (!SyncImagePixelsEx(average_image,exception)) thread_status=MagickFail; } } #if defined(HAVE_OPENMP) # pragma omp critical (GM_AverageImages) #endif { row_count++; if (QuantumTick(row_count,average_image->rows)) if (!MagickMonitorFormatted(row_count,average_image->rows,exception, "[%s,...,%s] Average image sequence...", image->filename,last_image->filename)) thread_status=MagickFail; if (thread_status == MagickFail) status=MagickFail; } } DestroyThreadViewDataSet(pixels_sums); if (status == MagickFail) { DestroyImage(average_image); average_image=(Image *) NULL; } return(average_image); }
static MagickBooleanType load_level(Image *image,XCFDocInfo *inDocInfo, XCFLayerInfo *inLayerInfo) { ExceptionInfo *exception; int destLeft = 0, destTop = 0; Image* tile_image; MagickBooleanType status; MagickOffsetType saved_pos, offset, offset2; register ssize_t i; size_t width, height, ntiles, ntile_rows, ntile_cols, tile_image_width, tile_image_height; /* start reading the data */ exception=inDocInfo->exception; width=ReadBlobMSBLong(image); height=ReadBlobMSBLong(image); /* Read in the first tile offset. If it is '0', then this tile level is empty and we can simply return. */ offset=(MagickOffsetType) ReadBlobMSBLong(image); if (offset == 0) return(MagickTrue); /* Initialize the reference for the in-memory tile-compression. */ ntile_rows=(height+TILE_HEIGHT-1)/TILE_HEIGHT; ntile_cols=(width+TILE_WIDTH-1)/TILE_WIDTH; ntiles=ntile_rows*ntile_cols; for (i = 0; i < (ssize_t) ntiles; i++) { status=MagickFalse; if (offset == 0) ThrowBinaryException(CorruptImageError,"NotEnoughTiles",image->filename); /* save the current position as it is where the * next tile offset is stored. */ saved_pos=TellBlob(image); /* read in the offset of the next tile so we can calculate the amount of data needed for this tile*/ offset2=(MagickOffsetType)ReadBlobMSBLong(image); /* if the offset is 0 then we need to read in the maximum possible allowing for negative compression */ if (offset2 == 0) offset2=(MagickOffsetType) (offset + TILE_WIDTH * TILE_WIDTH * 4* 1.5); /* seek to the tile offset */ offset=SeekBlob(image, offset, SEEK_SET); /* allocate the image for the tile NOTE: the last tile in a row or column may not be a full tile! */ tile_image_width=(size_t) (destLeft == (int) ntile_cols-1 ? (int) width % TILE_WIDTH : TILE_WIDTH); if (tile_image_width == 0) tile_image_width=TILE_WIDTH; tile_image_height = (size_t) (destTop == (int) ntile_rows-1 ? (int) height % TILE_HEIGHT : TILE_HEIGHT); if (tile_image_height == 0) tile_image_height=TILE_HEIGHT; tile_image=CloneImage(inLayerInfo->image,tile_image_width, tile_image_height,MagickTrue,exception); /* read in the tile */ switch (inDocInfo->compression) { case COMPRESS_NONE: if (load_tile(image,tile_image,inDocInfo,inLayerInfo,(size_t) (offset2-offset)) == 0) status=MagickTrue; break; case COMPRESS_RLE: if (load_tile_rle (image,tile_image,inDocInfo,inLayerInfo, (int) (offset2-offset)) == 0) status=MagickTrue; break; case COMPRESS_ZLIB: ThrowBinaryException(CoderError,"ZipCompressNotSupported", image->filename) case COMPRESS_FRACTAL: ThrowBinaryException(CoderError,"FractalCompressNotSupported", image->filename) } /* composite the tile onto the layer's image, and then destroy it */ (void) CompositeImage(inLayerInfo->image,CopyCompositeOp,tile_image, destLeft * TILE_WIDTH,destTop*TILE_HEIGHT); tile_image=DestroyImage(tile_image); /* adjust tile position */ destLeft++; if (destLeft >= (int) ntile_cols) { destLeft = 0; destTop++; } if (status != MagickFalse) return(MagickFalse); /* restore the saved position so we'll be ready to * read the next offset. */ offset=SeekBlob(image, saved_pos, SEEK_SET); /* read in the offset of the next tile */ offset=(MagickOffsetType) ReadBlobMSBLong(image); } if (offset != 0) ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename) return(MagickTrue); }
void APITests::testBasicOperations(int width, int height) { const PixelFormat format = PF_R8G8B8A8; const int bpp = 4; auto_ptr<Image> image(CreateImage(width, height, format)); CPPUNIT_ASSERT(image->getWidth() == width); CPPUNIT_ASSERT(image->getHeight() == height); CPPUNIT_ASSERT(image->getFormat() == format); // verify that the image is black byte* pixels = (byte*)image->getPixels(); for (int i = 0; i < width * height * bpp; ++i) { CPPUNIT_ASSERT(pixels[i] == 0); } // fill the image with random pixels for (int i = 0; i < width * height * bpp; ++i) { pixels[i] = rand() % 256; } auto_ptr<Image> create_clone( CreateImage(image->getWidth(), image->getHeight(), image->getFormat(), image->getPixels())); CPPUNIT_ASSERT(create_clone.get() != 0); CPPUNIT_ASSERT(image->getWidth() == create_clone->getWidth()); CPPUNIT_ASSERT(image->getHeight() == create_clone->getHeight()); CPPUNIT_ASSERT(image->getFormat() == create_clone->getFormat()); CPPUNIT_ASSERT(memcmp(image->getPixels(), create_clone->getPixels(), width * height * bpp) == 0); // clone the image (use same pixel format) auto_ptr<Image> identical_clone(CloneImage(image.get())); CPPUNIT_ASSERT(image->getWidth() == identical_clone->getWidth()); CPPUNIT_ASSERT(image->getHeight() == identical_clone->getHeight()); CPPUNIT_ASSERT(image->getFormat() == identical_clone->getFormat()); CPPUNIT_ASSERT(memcmp(image->getPixels(), identical_clone->getPixels(), width * height * bpp) == 0); // clone the image, removing the alpha channel auto_ptr<Image> other_clone(CloneImage(identical_clone.get(), PF_R8G8B8)); CPPUNIT_ASSERT(image->getWidth() == other_clone->getWidth()); CPPUNIT_ASSERT(image->getHeight() == other_clone->getHeight()); CPPUNIT_ASSERT(other_clone->getFormat() == PF_R8G8B8); byte* image_p = (byte*)image->getPixels(); byte* other_p = (byte*)other_clone->getPixels(); for (int i = 0; i < width * height; ++i) { CPPUNIT_ASSERT(*image_p++ == *other_p++); CPPUNIT_ASSERT(*image_p++ == *other_p++); CPPUNIT_ASSERT(*image_p++ == *other_p++); ++image_p; // skip alpha } // flip the image // clone source first, since flip frees the original auto_ptr<Image> flip_none(FlipImage(CloneImage(image.get()), 0)); auto_ptr<Image> flip_x (FlipImage(CloneImage(image.get()), CA_X)); auto_ptr<Image> flip_y (FlipImage(CloneImage(image.get()), CA_Y)); auto_ptr<Image> flip_xy (FlipImage(CloneImage(image.get()), CA_X | CA_Y)); AssertImagesEqual("No flipping", flip_none.get(), image.get()); CPPUNIT_ASSERT(flip_x.get() != 0); CPPUNIT_ASSERT(width == flip_x->getWidth()); CPPUNIT_ASSERT(height == flip_x->getHeight()); CPPUNIT_ASSERT(format == flip_x->getFormat()); CPPUNIT_ASSERT(flip_y.get() != 0); CPPUNIT_ASSERT(width == flip_y->getWidth()); CPPUNIT_ASSERT(height == flip_y->getHeight()); CPPUNIT_ASSERT(format == flip_y->getFormat()); CPPUNIT_ASSERT(flip_xy.get() != 0); CPPUNIT_ASSERT(width == flip_xy->getWidth()); CPPUNIT_ASSERT(height == flip_xy->getHeight()); CPPUNIT_ASSERT(format == flip_xy->getFormat()); const byte* flip_x_pixels = (const byte*)flip_x->getPixels(); const byte* flip_y_pixels = (const byte*)flip_y->getPixels(); const byte* flip_xy_pixels = (const byte*)flip_xy->getPixels(); for (int h = 0; h < height; h++) { for (int w = 0; w < width; w++) { const int image_index = (h * width + w) * bpp; const int opp_w = width - 1 - w; const int opp_h = height - 1 - h; const int flip_x_index = (opp_h * width + w) * bpp; const int flip_y_index = (h * width + opp_w) * bpp; const int flip_xy_index = (opp_h * width + opp_w) * bpp; for (int p = 0; p < bpp; p++) { CPPUNIT_ASSERT(pixels[image_index] == flip_x_pixels [flip_x_index]); CPPUNIT_ASSERT(pixels[image_index] == flip_y_pixels [flip_y_index]); CPPUNIT_ASSERT(pixels[image_index] == flip_xy_pixels[flip_xy_index]); } } } }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % 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 DrawInfo *draw_info,const PixelInfo target, % const ssize_t x_offset,const ssize_t y_offset, % const MagickBooleanType invert,ExceptionInfo *exception) % % A description of each parameter follows: % % o image: the image. % % 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. % % o exception: return any errors or warnings in this structure. % */ MagickExport MagickBooleanType FloodfillPaintImage(Image *image, const DrawInfo *draw_info,const PixelInfo *target,const ssize_t x_offset, const ssize_t y_offset,const MagickBooleanType invert, ExceptionInfo *exception) { #define MaxStacksize 131072UL #define PushSegmentStack(up,left,right,delta) \ { \ if (s >= (segment_stack+MaxStacksize)) \ ThrowBinaryException(DrawError,"SegmentStackOverflow",image->filename) \ else \ { \ if ((((up)+(delta)) >= 0) && (((up)+(delta)) < (ssize_t) image->rows)) \ { \ s->x1=(double) (left); \ s->y1=(double) (up); \ s->x2=(double) (right); \ s->y2=(double) (delta); \ s++; \ } \ } \ } CacheView *floodplane_view, *image_view; Image *floodplane_image; MagickBooleanType skip, status; MemoryInfo *segment_info; PixelInfo fill_color, pixel; register SegmentInfo *s; SegmentInfo *segment_stack; ssize_t offset, start, x, x1, x2, y; /* 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 >= (ssize_t) image->columns)) return(MagickFalse); if ((y_offset < 0) || (y_offset >= (ssize_t) image->rows)) return(MagickFalse); if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) return(MagickFalse); if (IsGrayColorspace(image->colorspace) != MagickFalse) (void) SetImageColorspace(image,sRGBColorspace,exception); if ((image->alpha_trait != BlendPixelTrait) && (draw_info->fill.alpha_trait == BlendPixelTrait)) (void) SetImageAlpha(image,OpaqueAlpha,exception); /* Set floodfill state. */ floodplane_image=CloneImage(image,image->columns,image->rows,MagickTrue, exception); if (floodplane_image == (Image *) NULL) return(MagickFalse); floodplane_image->alpha_trait=UndefinedPixelTrait; floodplane_image->colorspace=GRAYColorspace; (void) QueryColorCompliance("#000",AllCompliance, &floodplane_image->background_color,exception); (void) SetImageBackgroundColor(floodplane_image,exception); segment_info=AcquireVirtualMemory(MaxStacksize,sizeof(*segment_stack)); if (segment_info == (MemoryInfo *) NULL) { floodplane_image=DestroyImage(floodplane_image); ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", image->filename); } segment_stack=(SegmentInfo *) GetVirtualMemoryBlob(segment_info); /* Push initial segment on stack. */ status=MagickTrue; x=x_offset; y=y_offset; start=0; s=segment_stack; PushSegmentStack(y,x,x,1); PushSegmentStack(y+1,x,x,-1); GetPixelInfo(image,&pixel); image_view=AcquireVirtualCacheView(image,exception); floodplane_view=AcquireAuthenticCacheView(floodplane_image,exception); while (s > segment_stack) { register const Quantum *restrict p; register Quantum *restrict q; register ssize_t x; /* Pop segment off stack. */ s--; x1=(ssize_t) s->x1; x2=(ssize_t) s->x2; offset=(ssize_t) s->y2; y=(ssize_t) s->y1+offset; /* Recolor neighboring pixels. */ p=GetCacheViewVirtualPixels(image_view,0,y,(size_t) (x1+1),1,exception); q=GetCacheViewAuthenticPixels(floodplane_view,0,y,(size_t) (x1+1),1, exception); if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) break; p+=x1*GetPixelChannels(image); q+=x1*GetPixelChannels(floodplane_image); for (x=x1; x >= 0; x--) { if (GetPixelGray(floodplane_image,q) != 0) break; GetPixelInfoPixel(image,p,&pixel); if (IsFuzzyEquivalencePixelInfo(&pixel,target) == invert) break; SetPixelGray(floodplane_image,QuantumRange,q); p-=GetPixelChannels(image); q-=GetPixelChannels(floodplane_image); } if (SyncCacheViewAuthenticPixels(floodplane_view,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 < (ssize_t) image->columns) { p=GetCacheViewVirtualPixels(image_view,x,y,image->columns-x,1, exception); q=GetCacheViewAuthenticPixels(floodplane_view,x,y,image->columns- x,1,exception); if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) break; for ( ; x < (ssize_t) image->columns; x++) { if (GetPixelGray(floodplane_image,q) != 0) break; GetPixelInfoPixel(image,p,&pixel); if (IsFuzzyEquivalencePixelInfo(&pixel,target) == invert) break; SetPixelGray(floodplane_image,QuantumRange,q); p+=GetPixelChannels(image); q+=GetPixelChannels(floodplane_image); } status=SyncCacheViewAuthenticPixels(floodplane_view,exception); if (status == 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=GetCacheViewVirtualPixels(image_view,x,y,(size_t) (x2-x+1),1, exception); q=GetCacheViewAuthenticPixels(floodplane_view,x,y,(size_t) (x2-x+1),1, exception); if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) break; for ( ; x <= x2; x++) { if (GetPixelGray(floodplane_image,q) != 0) break; GetPixelInfoPixel(image,p,&pixel); if (IsFuzzyEquivalencePixelInfo(&pixel,target) != invert) break; p+=GetPixelChannels(image); q+=GetPixelChannels(floodplane_image); } } start=x; } while (x <= x2); } for (y=0; y < (ssize_t) image->rows; y++) { register const Quantum *restrict p; register Quantum *restrict q; register ssize_t x; /* Tile fill color onto floodplane. */ p=GetCacheViewVirtualPixels(floodplane_view,0,y,image->columns,1,exception); q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception); if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) break; for (x=0; x < (ssize_t) image->columns; x++) { if (GetPixelGray(floodplane_image,p) != 0) { (void) GetFillColor(draw_info,x,y,&fill_color,exception); SetPixelInfoPixel(image,&fill_color,q); } p+=GetPixelChannels(floodplane_image); q+=GetPixelChannels(image); } if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) break; } floodplane_view=DestroyCacheView(floodplane_view); image_view=DestroyCacheView(image_view); segment_info=RelinquishVirtualMemory(segment_info); floodplane_image=DestroyImage(floodplane_image); return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse); }
static Image *IntegralRotateImage(const Image *image,unsigned int rotations, ExceptionInfo *exception) { char message[MaxTextExtent]; Image *rotate_image; RectangleInfo page; long tile_width_max, tile_height_max; MagickPassFail status=MagickPass; /* Initialize rotated image attributes. */ assert(image != (Image *) NULL); page=image->page; rotations%=4; { /* Clone appropriately to create rotate image. */ unsigned long clone_columns=0, clone_rows=0; switch (rotations) { case 0: clone_columns=0; clone_rows=0; break; case 2: clone_columns=image->columns; clone_rows=image->rows; break; case 1: case 3: clone_columns=image->rows; clone_rows=image->columns; break; } rotate_image=CloneImage(image,clone_columns,clone_rows,True,exception); if (rotate_image == (Image *) NULL) return((Image *) NULL); if (rotations != 0) if (ModifyCache(rotate_image,exception) != MagickPass) { DestroyImage(rotate_image); return (Image *) NULL; } } tile_height_max=tile_width_max=2048/sizeof(PixelPacket); /* 2k x 2k = 4MB */ if ((rotations == 1) || (rotations == 3)) { /* Allow override of tile geometry for testing. */ const char * value; if (!GetPixelCacheInCore(image) || !GetPixelCacheInCore(rotate_image)) tile_height_max=tile_width_max=8192/sizeof(PixelPacket); /* 8k x 8k = 64MB */ if ((value=getenv("MAGICK_ROTATE_TILE_GEOMETRY"))) { double width, height; if (GetMagickDimension(value,&width,&height,NULL,NULL) == 2) { tile_height_max=(unsigned long) height; tile_width_max=(unsigned long) width; } } } /* Integral rotate the image. */ switch (rotations) { case 0: { /* Rotate 0 degrees (nothing more to do). */ (void) strlcpy(message,"[%s] Rotate: 0 degrees...",sizeof(message)); if (!MagickMonitorFormatted(image->rows-1,image->rows,exception, message,image->filename)) status=MagickFail; break; } case 1: { /* Rotate 90 degrees. */ magick_int64_t tile; magick_uint64_t total_tiles; long tile_y; (void) strlcpy(message,"[%s] Rotate: 90 degrees...",sizeof(message)); total_tiles=(((image->rows/tile_height_max)+1)* ((image->columns/tile_width_max)+1)); tile=0; #if defined(IntegralRotateImageUseOpenMP) # if defined(HAVE_OPENMP) # pragma omp parallel for schedule(static,1) shared(status, tile) # endif #endif for (tile_y=0; tile_y < (long) image->rows; tile_y+=tile_height_max) { long tile_x; MagickPassFail thread_status; thread_status=status; if (thread_status == MagickFail) continue; for (tile_x=0; tile_x < (long) image->columns; tile_x+=tile_width_max) { long dest_tile_x, dest_tile_y; long tile_width, tile_height; const PixelPacket *tile_pixels; long y; /* Compute image region corresponding to tile. */ if ((unsigned long) tile_x+tile_width_max > image->columns) tile_width=(tile_width_max-(tile_x+tile_width_max-image->columns)); else tile_width=tile_width_max; if ((unsigned long) tile_y+tile_height_max > image->rows) tile_height=(tile_height_max-(tile_y+tile_height_max-image->rows)); else tile_height=tile_height_max; /* Acquire tile */ tile_pixels=AcquireImagePixels(image,tile_x,tile_y, tile_width,tile_height,exception); if (tile_pixels == (const PixelPacket *) NULL) { thread_status=MagickFail; break; } /* Compute destination tile coordinates. */ dest_tile_x=rotate_image->columns-(tile_y+tile_height); dest_tile_y=tile_x; /* Rotate tile */ for (y=0; y < tile_width; y++) { register const PixelPacket *p; register PixelPacket *q; register const IndexPacket *indexes; IndexPacket *rotate_indexes; register long x; q=SetImagePixelsEx(rotate_image,dest_tile_x,dest_tile_y+y, tile_height,1,exception); if (q == (PixelPacket *) NULL) { thread_status=MagickFail; break; } /* DirectClass pixels */ p=tile_pixels+(tile_height-1)*tile_width + y; for (x=tile_height; x != 0; x--) { *q = *p; q++; p-=tile_width; } /* Indexes */ indexes=AccessImmutableIndexes(image); if (indexes != (IndexPacket *) NULL) { rotate_indexes=AccessMutableIndexes(rotate_image); if (rotate_indexes != (IndexPacket *) NULL) { register IndexPacket *iq; register const IndexPacket *ip; iq=rotate_indexes; ip=indexes+(tile_height-1)*tile_width + y; for (x=tile_height; x != 0; x--) { *iq = *ip; iq++; ip -= tile_width; } } } if (!SyncImagePixelsEx(rotate_image,exception)) { thread_status=MagickFail; break; } } #if defined(IntegralRotateImageUseOpenMP) # if defined(HAVE_OPENMP) # pragma omp critical (GM_IntegralRotateImage) # endif #endif { tile++; if (QuantumTick(tile,total_tiles)) if (!MagickMonitorFormatted(tile,total_tiles,exception, message,image->filename)) thread_status=MagickFail; if (thread_status == MagickFail) status=MagickFail; } } } Swap(page.width,page.height); Swap(page.x,page.y); page.x=(long) (page.width-rotate_image->columns-page.x); break; } case 2: { /* Rotate 180 degrees. */ long y; unsigned long row_count=0; (void) strlcpy(message,"[%s] Rotate: 180 degrees...",sizeof(message)); #if defined(IntegralRotateImageUseOpenMP) # if defined(HAVE_OPENMP) # pragma omp parallel for schedule(static,8) shared(row_count, status) # endif #endif for (y=0; y < (long) image->rows; y++) { register const PixelPacket *p; register PixelPacket *q; register const IndexPacket *indexes; IndexPacket *rotate_indexes; register long x; MagickPassFail thread_status; thread_status=status; if (thread_status == MagickFail) continue; p=AcquireImagePixels(image,0,y,image->columns,1,exception); q=SetImagePixelsEx(rotate_image,0,(long) (image->rows-y-1), image->columns,1,exception); if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL)) thread_status=MagickFail; if (thread_status != MagickFail) { q+=image->columns; indexes=AccessImmutableIndexes(image); rotate_indexes=AccessMutableIndexes(rotate_image); if ((indexes != (IndexPacket *) NULL) && (rotate_indexes != (IndexPacket *) NULL)) for (x=0; x < (long) image->columns; x++) rotate_indexes[image->columns-x-1]=indexes[x]; for (x=0; x < (long) image->columns; x++) *--q=(*p++); if (!SyncImagePixelsEx(rotate_image,exception)) thread_status=MagickFail; } #if defined(IntegralRotateImageUseOpenMP) # if defined(HAVE_OPENMP) # pragma omp critical (GM_IntegralRotateImage) # endif #endif { row_count++; if (QuantumTick(row_count,image->rows)) if (!MagickMonitorFormatted(row_count,image->rows,exception, message,image->filename)) thread_status=MagickFail; if (thread_status == MagickFail) status=MagickFail; } } page.x=(long) (page.width-rotate_image->columns-page.x); page.y=(long) (page.height-rotate_image->rows-page.y); break; } case 3: { /* Rotate 270 degrees. */ magick_int64_t tile; magick_uint64_t total_tiles; long tile_y; (void) strlcpy(message,"[%s] Rotate: 270 degrees...",sizeof(message)); total_tiles=(((image->rows/tile_height_max)+1)* ((image->columns/tile_width_max)+1)); tile=0; #if defined(IntegralRotateImageUseOpenMP) # if defined(HAVE_OPENMP) # pragma omp parallel for schedule(static,1) shared(status, tile) # endif #endif for (tile_y=0; tile_y < (long) image->rows; tile_y+=tile_height_max) { long tile_x; MagickPassFail thread_status; thread_status=status; if (thread_status == MagickFail) continue; for (tile_x=0; tile_x < (long) image->columns; tile_x+=tile_width_max) { long tile_width, tile_height; long dest_tile_x, dest_tile_y; long y; const PixelPacket *tile_pixels; /* Compute image region corresponding to tile. */ if ((unsigned long) tile_x+tile_width_max > image->columns) tile_width=(tile_width_max-(tile_x+tile_width_max-image->columns)); else tile_width=tile_width_max; if ((unsigned long) tile_y+tile_height_max > image->rows) tile_height=(tile_height_max-(tile_y+tile_height_max-image->rows)); else tile_height=tile_height_max; /* Acquire tile */ tile_pixels=AcquireImagePixels(image,tile_x,tile_y, tile_width,tile_height,exception); if (tile_pixels == (const PixelPacket *) NULL) { thread_status=MagickFail; break; } /* Compute destination tile coordinates. */ dest_tile_x=tile_y; dest_tile_y=rotate_image->rows-(tile_x+tile_width); /* Rotate tile */ for (y=0; y < tile_width; y++) { register const PixelPacket *p; register PixelPacket *q; register const IndexPacket *indexes; register long x; IndexPacket *rotate_indexes; q=SetImagePixelsEx(rotate_image,dest_tile_x,dest_tile_y+y, tile_height,1,exception); if (q == (PixelPacket *) NULL) { thread_status=MagickFail; break; } /* DirectClass pixels */ p=tile_pixels+(tile_width-1-y); for (x=tile_height; x != 0; x--) { *q = *p; q++; p += tile_width; } /* Indexes */ indexes=AccessImmutableIndexes(image); if (indexes != (IndexPacket *) NULL) { rotate_indexes=AccessMutableIndexes(rotate_image); if (rotate_indexes != (IndexPacket *) NULL) { register IndexPacket *iq; register const IndexPacket *ip; iq=rotate_indexes; ip=indexes+(tile_width-1-y); for (x=tile_height; x != 0; x--) { *iq = *ip; iq++; ip += tile_width; } } } if (!SyncImagePixelsEx(rotate_image,exception)) { thread_status=MagickFail; break; } } #if defined(IntegralRotateImageUseOpenMP) # if defined(HAVE_OPENMP) # pragma omp critical (GM_IntegralRotateImage) # endif #endif { tile++; if (QuantumTick(tile,total_tiles)) if (!MagickMonitorFormatted(tile,total_tiles,exception, message,image->filename)) thread_status=MagickFail; } if (thread_status == MagickFail) { status=MagickFail; break; } } } Swap(page.width,page.height); Swap(page.x,page.y); page.y=(long) (page.height-rotate_image->rows-page.y); break; } } rotate_image->page=page; rotate_image->is_grayscale=image->is_grayscale; rotate_image->is_monochrome=image->is_monochrome; return(rotate_image); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % A f f i n e T r a n s f o r m I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % AffineTransformImage() transforms an image as dictated by the affine matrix. % It allocates the memory necessary for the new Image structure and returns % a pointer to the new image. % % The format of the AffineTransformImage method is: % % Image *AffineTransformImage(const Image *image, % AffineMatrix *affine,ExceptionInfo *exception) % % A description of each parameter follows: % % o image: The image. % % o affine: The affine transform. % % o exception: Return any errors or warnings in this structure. % % */ MagickExport Image *AffineTransformImage(const Image *image, const AffineMatrix *affine,ExceptionInfo *exception) { AffineMatrix transform; Image *affine_image; long y; PointInfo extent[4], min, max; register long i, x; /* Determine bounding box. */ assert(image != (const Image *) NULL); assert(image->signature == MagickSignature); assert(affine != (AffineMatrix *) NULL); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); extent[0].x=0; extent[0].y=0; extent[1].x=image->columns; extent[1].y=0; extent[2].x=image->columns; extent[2].y=image->rows; extent[3].x=0; extent[3].y=image->rows; for (i=0; i < 4; i++) { x=(long) (extent[i].x+0.5); y=(long) (extent[i].y+0.5); extent[i].x=x*affine->sx+y*affine->ry+affine->tx; extent[i].y=x*affine->rx+y*affine->sy+affine->ty; } min=extent[0]; max=extent[0]; for (i=1; i < 4; i++) { if (min.x > extent[i].x) min.x=extent[i].x; if (min.y > extent[i].y) min.y=extent[i].y; if (max.x < extent[i].x) max.x=extent[i].x; if (max.y < extent[i].y) max.y=extent[i].y; } /* Affine transform image. */ affine_image=CloneImage(image,(unsigned long) ceil(max.x-min.x-0.5), (unsigned long) ceil(max.y-min.y-0.5),True,exception); if (affine_image == (Image *) NULL) return((Image *) NULL); (void) SetImage(affine_image,TransparentOpacity); transform.sx=affine->sx; transform.rx=affine->rx; transform.ry=affine->ry; transform.sy=affine->sy; transform.tx=(-min.x); transform.ty=(-min.y); (void) DrawAffineImage(affine_image,image,&transform); return(affine_image); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % W r i t e E P T I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % WriteEPTImage() writes an image in the Encapsulated Postscript format % with a TIFF preview. % % The format of the WriteEPTImage method is: % % MagickBooleanType WriteEPTImage(const ImageInfo *image_info,Image *image) % % A description of each parameter follows. % % o image_info: the image info. % % o image: The image. % */ static MagickBooleanType WriteEPTImage(const ImageInfo *image_info,Image *image) { EPTInfo ept_info; Image *write_image; ImageInfo *write_info; MagickBooleanType status; /* Write EPT image. */ assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickSignature); assert(image != (Image *) NULL); assert(image->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); if (status == MagickFalse) return(status); write_image=CloneImage(image,0,0,MagickTrue,&image->exception); if (write_image == (Image *) NULL) return(MagickFalse); DestroyBlob(write_image); write_image->blob=CloneBlobInfo((BlobInfo *) NULL); write_info=CloneImageInfo(image_info); (void) CopyMagickString(write_info->magick,"EPS",MaxTextExtent); if (LocaleCompare(image_info->magick,"EPT2") == 0) (void) CopyMagickString(write_info->magick,"EPS2",MaxTextExtent); if (LocaleCompare(image_info->magick,"EPT3") == 0) (void) CopyMagickString(write_info->magick,"EPS3",MaxTextExtent); (void) ResetMagickMemory(&ept_info,0,sizeof(ept_info)); ept_info.magick=0xc6d3d0c5ul; ept_info.postscript=(unsigned char *) ImageToBlob(write_info,write_image, &ept_info.postscript_length,&image->exception); write_image=DestroyImage(write_image); write_info=DestroyImageInfo(write_info); if (ept_info.postscript == (void *) NULL) return(MagickFalse); write_image=CloneImage(image,0,0,MagickTrue,&image->exception); if (write_image == (Image *) NULL) return(MagickFalse); DestroyBlob(write_image); write_image->blob=CloneBlobInfo((BlobInfo *) NULL); write_info=CloneImageInfo(image_info); (void) CopyMagickString(write_info->magick,"TIFF",MaxTextExtent); (void) FormatMagickString(write_info->filename,MaxTextExtent,"tiff:%.1024s", write_info->filename); (void) TransformImage(&write_image,(char *) NULL,"512x512>"); if ((write_image->storage_class == DirectClass) || (write_image->colors > 256)) { QuantizeInfo quantize_info; /* EPT preview requires that the image is colormapped. */ GetQuantizeInfo(&quantize_info); quantize_info.dither=IsPaletteImage(write_image,&image->exception) == MagickFalse ? MagickTrue : MagickFalse; (void) QuantizeImage(&quantize_info,write_image); } write_image->compression=NoCompression; ept_info.tiff=(unsigned char *) ImageToBlob(write_info,write_image, &ept_info.tiff_length,&image->exception); write_image=DestroyImage(write_image); write_info=DestroyImageInfo(write_info); if (ept_info.tiff == (void *) NULL) { ept_info.postscript=(unsigned char *) RelinquishMagickMemory( ept_info.postscript); return(MagickFalse); } /* Write EPT image. */ (void) WriteBlobLSBLong(image,ept_info.magick); (void) WriteBlobLSBLong(image,30); (void) WriteBlobLSBLong(image,(unsigned long) ept_info.postscript_length); (void) WriteBlobLSBLong(image,0); (void) WriteBlobLSBLong(image,0); (void) WriteBlobLSBLong(image,(unsigned long) ept_info.postscript_length+30); (void) WriteBlobLSBLong(image,(unsigned long) ept_info.tiff_length); (void) WriteBlobLSBShort(image,0xffff); (void) WriteBlob(image,ept_info.postscript_length,ept_info.postscript); (void) WriteBlob(image,ept_info.tiff_length,ept_info.tiff); /* Relinquish resources. */ ept_info.postscript=(unsigned char *) RelinquishMagickMemory( ept_info.postscript); ept_info.tiff=(unsigned char *) RelinquishMagickMemory(ept_info.tiff); (void) CloseBlob(image); return(MagickTrue); }
bool SavePNG(File* file, Image* image) { COR_GUARD("SavePNG"); if (!image) { return false; } // If the image format isn't supported directly by this function, // clone to a supported format and try to save with that. switch (image->getFormat()) { case PF_R8G8B8A8: case PF_R8G8B8: case PF_I8: break; default: { COR_LOG("Unsupported pixel format... cloning"); std::auto_ptr<Image> cloned(CloneImage(image, PF_R8G8B8A8)); return SavePNG(file, cloned.get()); } } // create write struct png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { return false; } // error handling! if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, NULL); return false; } // create info struct png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, NULL); return false; } int width = image->getWidth(); int height = image->getHeight(); // set image characteristics png_set_write_fn(png_ptr, file, PNG_write, PNG_flush); int color_format = 0; // png output format int color_format_bpp = 0; // png bytes per pixel bool color_format_paletted = false; // png palette needed flag // figure out output format switch (image->getFormat()) { case PF_R8G8B8A8: color_format = PNG_COLOR_TYPE_RGB_ALPHA; color_format_bpp = 4; break; case PF_R8G8B8: color_format = PNG_COLOR_TYPE_RGB; color_format_bpp = 3; break; case PF_I8: color_format = PNG_COLOR_TYPE_PALETTE; color_format_bpp = 1; color_format_paletted = true; break; default: // Unsupported format. This should already be taken care of // by the test at the beginning of this function. return false; } png_set_IHDR( png_ptr, info_ptr, width, height, 8, color_format, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); if (color_format_paletted) { COR_LOG("Saving palettized image..."); int image_palette_format = image->getPaletteFormat(); // palette format int image_palette_size = image->getPaletteSize(); // palette size // allocate png palette and get pointer to image palette png_color* png_palette = (png_color*)png_malloc( png_ptr, sizeof(png_color) * image_palette_size); byte* image_palette = (byte*)image->getPalette(); if (image_palette_format == PF_R8G8B8) { // 24 bit source palette for (int i = 0; i < image_palette_size; i++) { // copy entry directly png_palette[i].red = *image_palette++; png_palette[i].green = *image_palette++; png_palette[i].blue = *image_palette++; } } else if (image_palette_format == PF_R8G8B8A8) { // 32 bit source palette for (int i = 0; i < image_palette_size; i++) { // copy entry, skip alpha png_palette[i].red = *image_palette++; png_palette[i].green = *image_palette++; png_palette[i].blue = *image_palette++; image_palette++; } } // write palette png_set_PLTE(png_ptr, info_ptr, png_palette, image_palette_size); } byte* pixels = (byte*)image->getPixels(); // build rows void** rows = (void**)png_malloc(png_ptr, sizeof(void*) * height); for (int i = 0; i < height; ++i) { rows[i] = png_malloc(png_ptr, color_format_bpp * width); memcpy(rows[i], pixels, color_format_bpp * width); pixels += width * color_format_bpp; } png_set_rows(png_ptr, info_ptr, (png_bytepp)rows); info_ptr->valid |= PNG_INFO_IDAT; // actually write the image png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); png_destroy_write_struct(&png_ptr, &info_ptr); return true; }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % A f f i n e T r a n s f o r m I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % AffineTransformImage() transforms an image as dictated by the affine matrix. % It allocates the memory necessary for the new Image structure and returns % a pointer to the new image. % % The format of the AffineTransformImage method is: % % Image *AffineTransformImage(const Image *image,AffineMatrix *affine, % ExceptionInfo *exception) % % A description of each parameter follows: % % o image: The image. % % o affine: The affine transform. % % o exception: Return any errors or warnings in this structure. % % */ MagickExport Image *AffineTransformImage(const Image *image, const AffineMatrix *affine,ExceptionInfo *exception) { AffineMatrix transform; Image *affine_image; PointInfo extent[4], min, max, point; register long i; /* Determine bounding box. */ assert(image != (const Image *) NULL); assert(image->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); assert(affine != (AffineMatrix *) NULL); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); extent[0].x=0.0; extent[0].y=0.0; extent[1].x=(double) image->columns; extent[1].y=0.0; extent[2].x=(double) image->columns; extent[2].y=(double) image->rows; extent[3].x=0.0; extent[3].y=(double) image->rows; for (i=0; i < 4; i++) { point=extent[i]; extent[i].x=(double) (point.x*affine->sx+point.y*affine->ry+affine->tx); extent[i].y=(double) (point.x*affine->rx+point.y*affine->sy+affine->ty); } min=extent[0]; max=extent[0]; for (i=1; i < 4; i++) { if (min.x > extent[i].x) min.x=extent[i].x; if (min.y > extent[i].y) min.y=extent[i].y; if (max.x < extent[i].x) max.x=extent[i].x; if (max.y < extent[i].y) max.y=extent[i].y; } /* Affine transform image. */ affine_image=CloneImage(image,(unsigned long) (max.x-min.x+0.5), (unsigned long) (max.y-min.y+0.5),MagickTrue,exception); if (affine_image == (Image *) NULL) return((Image *) NULL); affine_image->background_color.opacity=TransparentOpacity; SetImageBackgroundColor(affine_image); transform.sx=affine->sx; transform.rx=affine->rx; transform.ry=affine->ry; transform.sy=affine->sy; transform.tx=min.x; transform.ty=min.y; (void) DrawAffineImage(affine_image,image,&transform); return(affine_image); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % 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, % 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 exception: return any errors or warnings in this structure. % */ MagickExport Image *FrameImage(const Image *image,const FrameInfo *frame_info, ExceptionInfo *exception) { #define FrameImageTag "Frame/Image" CacheView *image_view, *frame_view; Image *frame_image; MagickBooleanType status; MagickOffsetType progress; MagickPixelPacket accentuate, border, 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) == MagickFalse) { InheritException(exception,&frame_image->exception); frame_image=DestroyImage(frame_image); return((Image *) NULL); } if ((IsPixelGray(&frame_image->border_color) == MagickFalse) && (IsGrayColorspace(frame_image->colorspace) != MagickFalse)) (void) SetImageColorspace(frame_image,RGBColorspace); if ((frame_image->border_color.opacity != OpaqueOpacity) && (frame_image->matte == MagickFalse)) (void) SetImageAlphaChannel(frame_image,OpaqueAlphaChannel); 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. */ GetMagickPixelPacket(frame_image,&interior); SetMagickPixelPacket(frame_image,&image->border_color,(IndexPacket *) NULL, &interior); GetMagickPixelPacket(frame_image,&matte); matte.colorspace=sRGBColorspace; SetMagickPixelPacket(frame_image,&image->matte_color,(IndexPacket *) NULL, &matte); GetMagickPixelPacket(frame_image,&border); border.colorspace=sRGBColorspace; SetMagickPixelPacket(frame_image,&image->border_color,(IndexPacket *) NULL, &border); GetMagickPixelPacket(frame_image,&accentuate); 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.opacity=matte.opacity; GetMagickPixelPacket(frame_image,&highlight); 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.opacity=matte.opacity; GetMagickPixelPacket(frame_image,&shadow); shadow.red=QuantumScale*matte.red*ShadowModulate; shadow.green=QuantumScale*matte.green*ShadowModulate; shadow.blue=QuantumScale*matte.blue*ShadowModulate; shadow.opacity=matte.opacity; GetMagickPixelPacket(frame_image,&trough); trough.red=QuantumScale*matte.red*TroughModulate; trough.green=QuantumScale*matte.green*TroughModulate; trough.blue=QuantumScale*matte.blue*TroughModulate; trough.opacity=matte.opacity; if (image->colorspace == CMYKColorspace) { ConvertRGBToCMYK(&interior); ConvertRGBToCMYK(&matte); ConvertRGBToCMYK(&border); ConvertRGBToCMYK(&accentuate); ConvertRGBToCMYK(&highlight); ConvertRGBToCMYK(&shadow); ConvertRGBToCMYK(&trough); } status=MagickTrue; progress=0; image_view=AcquireVirtualCacheView(image,exception); frame_view=AcquireAuthenticCacheView(frame_image,exception); height=(size_t) (frame_info->outer_bevel+(frame_info->y-bevel_width)+ frame_info->inner_bevel); if (height != 0) { register IndexPacket *restrict frame_indexes; register ssize_t x; register PixelPacket *restrict q; /* Draw top of ornamental border. */ q=QueueCacheViewAuthenticPixels(frame_view,0,0,frame_image->columns, height,exception); frame_indexes=GetCacheViewAuthenticIndexQueue(frame_view); if (q != (PixelPacket *) 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) SetPixelPacket(frame_image,&highlight,q,frame_indexes); else SetPixelPacket(frame_image,&accentuate,q,frame_indexes); q++; frame_indexes++; } for ( ; x < (ssize_t) frame_image->columns; x++) { SetPixelPacket(frame_image,&shadow,q,frame_indexes); q++; frame_indexes++; } } for (y=0; y < (ssize_t) (frame_info->y-bevel_width); y++) { for (x=0; x < (ssize_t) frame_info->outer_bevel; x++) { SetPixelPacket(frame_image,&highlight,q,frame_indexes); q++; frame_indexes++; } width=frame_image->columns-2*frame_info->outer_bevel; for (x=0; x < (ssize_t) width; x++) { SetPixelPacket(frame_image,&matte,q,frame_indexes); q++; frame_indexes++; } for (x=0; x < (ssize_t) frame_info->outer_bevel; x++) { SetPixelPacket(frame_image,&shadow,q,frame_indexes); q++; frame_indexes++; } } for (y=0; y < (ssize_t) frame_info->inner_bevel; y++) { for (x=0; x < (ssize_t) frame_info->outer_bevel; x++) { SetPixelPacket(frame_image,&highlight,q,frame_indexes); q++; frame_indexes++; } for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++) { SetPixelPacket(frame_image,&matte,q,frame_indexes); q++; frame_indexes++; } width=image->columns+((size_t) frame_info->inner_bevel << 1)- y; for (x=0; x < (ssize_t) width; x++) { if (x < y) SetPixelPacket(frame_image,&shadow,q,frame_indexes); else SetPixelPacket(frame_image,&trough,q,frame_indexes); q++; frame_indexes++; } for ( ; x < (ssize_t) (image->columns+2*frame_info->inner_bevel); x++) { SetPixelPacket(frame_image,&highlight,q,frame_indexes); q++; frame_indexes++; } width=frame_info->width-frame_info->x-image->columns-bevel_width; for (x=0; x < (ssize_t) width; x++) { SetPixelPacket(frame_image,&matte,q,frame_indexes); q++; frame_indexes++; } for (x=0; x < (ssize_t) frame_info->outer_bevel; x++) { SetPixelPacket(frame_image,&shadow,q,frame_indexes); q++; frame_indexes++; } } (void) SyncCacheViewAuthenticPixels(frame_view,exception); } } /* Draw sides of ornamental border. */ #if defined(MAGICKCORE_OPENMP_SUPPORT) #pragma omp parallel for schedule(static,4) shared(status) \ magick_threads(image,frame_image,1,1) #endif for (y=0; y < (ssize_t) image->rows; y++) { register IndexPacket *restrict frame_indexes; register ssize_t x; register PixelPacket *restrict q; /* 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 == (PixelPacket *) NULL) { status=MagickFalse; continue; } frame_indexes=GetCacheViewAuthenticIndexQueue(frame_view); for (x=0; x < (ssize_t) frame_info->outer_bevel; x++) { SetPixelPacket(frame_image,&highlight,q,frame_indexes); q++; frame_indexes++; } for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++) { SetPixelPacket(frame_image,&matte,q,frame_indexes); q++; frame_indexes++; } for (x=0; x < (ssize_t) frame_info->inner_bevel; x++) { SetPixelPacket(frame_image,&shadow,q,frame_indexes); q++; frame_indexes++; } /* Set frame interior to interior color. */ if ((image->compose != CopyCompositeOp) && ((image->compose != OverCompositeOp) || (image->matte != MagickFalse))) for (x=0; x < (ssize_t) image->columns; x++) { SetPixelPacket(frame_image,&interior,q,frame_indexes); q++; frame_indexes++; } else { register const IndexPacket *indexes; register const PixelPacket *p; p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); if (p == (const PixelPacket *) NULL) { status=MagickFalse; continue; } indexes=GetCacheViewVirtualIndexQueue(image_view); (void) CopyMagickMemory(q,p,image->columns*sizeof(*p)); if ((image->colorspace == CMYKColorspace) && (frame_image->colorspace == CMYKColorspace)) { (void) CopyMagickMemory(frame_indexes,indexes,image->columns* sizeof(*indexes)); frame_indexes+=image->columns; } q+=image->columns; } for (x=0; x < (ssize_t) frame_info->inner_bevel; x++) { SetPixelPacket(frame_image,&highlight,q,frame_indexes); q++; frame_indexes++; } width=frame_info->width-frame_info->x-image->columns-bevel_width; for (x=0; x < (ssize_t) width; x++) { SetPixelPacket(frame_image,&matte,q,frame_indexes); q++; frame_indexes++; } for (x=0; x < (ssize_t) frame_info->outer_bevel; x++) { SetPixelPacket(frame_image,&shadow,q,frame_indexes); q++; frame_indexes++; } 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 IndexPacket *restrict frame_indexes; register ssize_t x; register PixelPacket *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 != (PixelPacket *) NULL) { /* Draw bottom of ornamental border. */ frame_indexes=GetCacheViewAuthenticIndexQueue(frame_view); for (y=frame_info->inner_bevel-1; y >= 0; y--) { for (x=0; x < (ssize_t) frame_info->outer_bevel; x++) { SetPixelPacket(frame_image,&highlight,q,frame_indexes); q++; frame_indexes++; } for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++) { SetPixelPacket(frame_image,&matte,q,frame_indexes); q++; frame_indexes++; } for (x=0; x < y; x++) { SetPixelPacket(frame_image,&shadow,q,frame_indexes); q++; frame_indexes++; } for ( ; x < (ssize_t) (image->columns+2*frame_info->inner_bevel); x++) { if (x >= (ssize_t) (image->columns+2*frame_info->inner_bevel-y)) SetPixelPacket(frame_image,&highlight,q,frame_indexes); else SetPixelPacket(frame_image,&accentuate,q,frame_indexes); q++; frame_indexes++; } width=frame_info->width-frame_info->x-image->columns-bevel_width; for (x=0; x < (ssize_t) width; x++) { SetPixelPacket(frame_image,&matte,q,frame_indexes); q++; frame_indexes++; } for (x=0; x < (ssize_t) frame_info->outer_bevel; x++) { SetPixelPacket(frame_image,&shadow,q,frame_indexes); q++; frame_indexes++; } } 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++) { SetPixelPacket(frame_image,&highlight,q,frame_indexes); q++; frame_indexes++; } width=frame_image->columns-2*frame_info->outer_bevel; for (x=0; x < (ssize_t) width; x++) { SetPixelPacket(frame_image,&matte,q,frame_indexes); q++; frame_indexes++; } for (x=0; x < (ssize_t) frame_info->outer_bevel; x++) { SetPixelPacket(frame_image,&shadow,q,frame_indexes); q++; frame_indexes++; } } for (y=frame_info->outer_bevel-1; y >= 0; y--) { for (x=0; x < y; x++) { SetPixelPacket(frame_image,&highlight,q,frame_indexes); q++; frame_indexes++; } for ( ; x < (ssize_t) frame_image->columns; x++) { if (x >= (ssize_t) (frame_image->columns-y)) SetPixelPacket(frame_image,&shadow,q,frame_indexes); else SetPixelPacket(frame_image,&trough,q,frame_indexes); q++; frame_indexes++; } } (void) SyncCacheViewAuthenticPixels(frame_view,exception); } } frame_view=DestroyCacheView(frame_view); image_view=DestroyCacheView(image_view); if ((image->compose != CopyCompositeOp) && ((image->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,image,x,y); } if (status == MagickFalse) frame_image=DestroyImage(frame_image); return(frame_image); }
MagickExport Image *OilPaintImage(const Image *image,const double radius, const double sigma,ExceptionInfo *exception) { #define NumberPaintBins 256 #define OilPaintImageTag "OilPaint/Image" CacheView *image_view, *paint_view; Image *linear_image, *paint_image; MagickBooleanType status; MagickOffsetType progress; size_t **histograms, width; ssize_t center, y; /* Initialize painted image attributes. */ assert(image != (const Image *) NULL); assert(image->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); width=GetOptimalKernelWidth2D(radius,sigma); linear_image=CloneImage(image,0,0,MagickTrue,exception); paint_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception); if ((linear_image == (Image *) NULL) || (paint_image == (Image *) NULL)) { if (linear_image != (Image *) NULL) linear_image=DestroyImage(linear_image); if (paint_image != (Image *) NULL) linear_image=DestroyImage(paint_image); return((Image *) NULL); } if (SetImageStorageClass(paint_image,DirectClass,exception) == MagickFalse) { linear_image=DestroyImage(linear_image); paint_image=DestroyImage(paint_image); return((Image *) NULL); } histograms=AcquireHistogramThreadSet(NumberPaintBins); if (histograms == (size_t **) NULL) { linear_image=DestroyImage(linear_image); paint_image=DestroyImage(paint_image); ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); } /* Oil paint image. */ status=MagickTrue; progress=0; center=(ssize_t) GetPixelChannels(linear_image)*(linear_image->columns+width)* (width/2L)+GetPixelChannels(linear_image)*(width/2L); image_view=AcquireVirtualCacheView(linear_image,exception); paint_view=AcquireAuthenticCacheView(paint_image,exception); #if defined(MAGICKCORE_OPENMP_SUPPORT) #pragma omp parallel for schedule(static,4) shared(progress,status) \ magick_threads(linear_image,paint_image,linear_image->rows,1) #endif for (y=0; y < (ssize_t) linear_image->rows; y++) { register const Quantum *restrict p; register Quantum *restrict q; register size_t *histogram; register ssize_t x; if (status == MagickFalse) continue; p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t) (width/2L),linear_image->columns+width,width,exception); q=QueueCacheViewAuthenticPixels(paint_view,0,y,paint_image->columns,1, exception); if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) { status=MagickFalse; continue; } histogram=histograms[GetOpenMPThreadId()]; for (x=0; x < (ssize_t) linear_image->columns; x++) { register ssize_t i, u; size_t count; ssize_t j, k, n, v; /* Assign most frequent color. */ k=0; j=0; count=0; (void) ResetMagickMemory(histogram,0,NumberPaintBins* sizeof(*histogram)); for (v=0; v < (ssize_t) width; v++) { for (u=0; u < (ssize_t) width; u++) { n=(ssize_t) ScaleQuantumToChar(ClampToQuantum(GetPixelIntensity( linear_image,p+GetPixelChannels(linear_image)*(u+k)))); histogram[n]++; if (histogram[n] > count) { j=k+u; count=histogram[n]; } } k+=(ssize_t) (linear_image->columns+width); } for (i=0; i < (ssize_t) GetPixelChannels(linear_image); i++) { PixelChannel channel=GetPixelChannelChannel(linear_image,i); PixelTrait traits=GetPixelChannelTraits(linear_image,channel); PixelTrait paint_traits=GetPixelChannelTraits(paint_image,channel); if ((traits == UndefinedPixelTrait) || (paint_traits == UndefinedPixelTrait)) continue; if (((paint_traits & CopyPixelTrait) != 0) || (GetPixelReadMask(linear_image,p) == 0)) { SetPixelChannel(paint_image,channel,p[center+i],q); continue; } SetPixelChannel(paint_image,channel,p[j*GetPixelChannels(linear_image)+ i],q); } p+=GetPixelChannels(linear_image); q+=GetPixelChannels(paint_image); } if (SyncCacheViewAuthenticPixels(paint_view,exception) == MagickFalse) status=MagickFalse; if (linear_image->progress_monitor != (MagickProgressMonitor) NULL) { MagickBooleanType proceed; #if defined(MAGICKCORE_OPENMP_SUPPORT) #pragma omp critical (MagickCore_OilPaintImage) #endif proceed=SetImageProgress(linear_image,OilPaintImageTag,progress++, linear_image->rows); if (proceed == MagickFalse) status=MagickFalse; } } paint_view=DestroyCacheView(paint_view); image_view=DestroyCacheView(image_view); histograms=DestroyHistogramThreadSet(histograms); linear_image=DestroyImage(linear_image); if (status == MagickFalse) paint_image=DestroyImage(paint_image); return(paint_image); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d Y C b C r I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ReadYCBCRImage() reads an image of raw YCbCr or YCbCrA samples and returns % it. It allocates the memory necessary for the new Image structure and % returns a pointer to the new image. % % The format of the ReadYCBCRImage method is: % % Image *ReadYCBCRImage(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 *ReadYCBCRImage(const ImageInfo *image_info, ExceptionInfo *exception) { Image *canvas_image, *image; ssize_t y; MagickBooleanType status; MagickOffsetType scene; QuantumInfo *quantum_info; QuantumType quantum_type; register const PixelPacket *p; register ssize_t i, x; register PixelPacket *q; ssize_t count; size_t length; unsigned char *pixels; /* Open image file. */ 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); if ((image->columns == 0) || (image->rows == 0)) ThrowReaderException(OptionError,"MustSpecifyImageSize"); image->colorspace=YCbCrColorspace; if (image_info->interlace != PartitionInterlace) { status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) { image=DestroyImageList(image); return((Image *) NULL); } if (DiscardBlobBytes(image,image->offset) == MagickFalse) ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", image->filename); } /* Create virtual canvas to support cropping (i.e. image.rgb[100x100+10+20]). */ canvas_image=CloneImage(image,image->extract_info.width,1,MagickFalse, exception); (void) SetImageVirtualPixelMethod(canvas_image,BlackVirtualPixelMethod); quantum_info=AcquireQuantumInfo(image_info,canvas_image); if (quantum_info == (QuantumInfo *) NULL) ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); pixels=GetQuantumPixels(quantum_info); quantum_type=RGBQuantum; if (LocaleCompare(image_info->magick,"YCbCrA") == 0) { quantum_type=RGBAQuantum; image->matte=MagickTrue; } if (image_info->number_scenes != 0) while (image->scene < image_info->scene) { /* Skip to next image. */ image->scene++; length=GetQuantumExtent(canvas_image,quantum_info,quantum_type); for (y=0; y < (ssize_t) image->rows; y++) { count=ReadBlob(image,length,pixels); if (count != (ssize_t) length) break; } } count=0; length=0; scene=0; do { /* Read pixels to virtual canvas image then push to image. */ if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0)) if (image->scene >= (image_info->scene+image_info->number_scenes-1)) break; image->colorspace=YCbCrColorspace; switch (image_info->interlace) { case NoInterlace: default: { /* No interlacing: YCbCrYCbCrYCbCrYCbCrYCbCrYCbCr... */ if (scene == 0) { length=GetQuantumExtent(canvas_image,quantum_info,quantum_type); count=ReadBlob(image,length,pixels); } for (y=0; y < (ssize_t) image->extract_info.height; y++) { if (count != (ssize_t) length) { ThrowFileException(exception,CorruptImageError, "UnexpectedEndOfFile",image->filename); break; } q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1, exception); if (q == (PixelPacket *) NULL) break; length=ImportQuantumPixels(canvas_image,(CacheView *) NULL, quantum_info,quantum_type,pixels,exception); if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse) break; if (((y-image->extract_info.y) >= 0) && ((y-image->extract_info.y) < (ssize_t) image->rows)) { p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0, canvas_image->columns,1,exception); q=QueueAuthenticPixels(image,0,y-image->extract_info.y, image->columns,1,exception); if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL)) break; for (x=0; x < (ssize_t) image->columns; x++) { SetRedPixelComponent(q,GetRedPixelComponent(p)); SetGreenPixelComponent(q,GetGreenPixelComponent(p)); SetBluePixelComponent(q,GetBluePixelComponent(p)); if (image->matte != MagickFalse) SetOpacityPixelComponent(q,GetOpacityPixelComponent(p)); p++; q++; } if (SyncAuthenticPixels(image,exception) == MagickFalse) break; } if (image->previous == (Image *) NULL) { status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, image->rows); if (status == MagickFalse) break; } count=ReadBlob(image,length,pixels); } break; } case LineInterlace: { static QuantumType quantum_types[4] = { RedQuantum, GreenQuantum, BlueQuantum, OpacityQuantum }; /* Line interlacing: YYY...CbCbCb...CrCrCr...YYY...CbCbCb...CrCrCr... */ if (scene == 0) { length=GetQuantumExtent(canvas_image,quantum_info,RedQuantum); count=ReadBlob(image,length,pixels); } for (y=0; y < (ssize_t) image->extract_info.height; y++) { for (i=0; i < (image->matte != MagickFalse ? 4 : 3); i++) { if (count != (ssize_t) length) { ThrowFileException(exception,CorruptImageError, "UnexpectedEndOfFile",image->filename); break; } quantum_type=quantum_types[i]; q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1, exception); if (q == (PixelPacket *) NULL) break; length=ImportQuantumPixels(canvas_image,(CacheView *) NULL, quantum_info,quantum_type,pixels,exception); if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse) break; if (((y-image->extract_info.y) >= 0) && ((y-image->extract_info.y) < (ssize_t) image->rows)) { p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x, 0,canvas_image->columns,1,exception); q=GetAuthenticPixels(image,0,y-image->extract_info.y, image->columns,1,exception); if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL)) break; for (x=0; x < (ssize_t) image->columns; x++) { switch (quantum_type) { case RedQuantum: { SetRedPixelComponent(q,GetRedPixelComponent(p)); break; } case GreenQuantum: { SetGreenPixelComponent(q,GetGreenPixelComponent(p)); break; } case BlueQuantum: { SetBluePixelComponent(q,GetBluePixelComponent(p)); break; } case OpacityQuantum: { SetOpacityPixelComponent(q,GetOpacityPixelComponent(p)); break; } default: break; } p++; q++; } if (SyncAuthenticPixels(image,exception) == MagickFalse) break; } count=ReadBlob(image,length,pixels); } if (image->previous == (Image *) NULL) { status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, image->rows); if (status == MagickFalse) break; } } break; } case PlaneInterlace: { /* Plane interlacing: YYYYYY...CbCbCbCbCbCb...CrCrCrCrCrCr... */ if (scene == 0) { length=GetQuantumExtent(canvas_image,quantum_info,RedQuantum); count=ReadBlob(image,length,pixels); } for (y=0; y < (ssize_t) image->extract_info.height; y++) { if (count != (ssize_t) length) { ThrowFileException(exception,CorruptImageError, "UnexpectedEndOfFile",image->filename); break; } q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1, exception); if (q == (PixelPacket *) NULL) break; length=ImportQuantumPixels(canvas_image,(CacheView *) NULL, quantum_info,RedQuantum,pixels,exception); if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse) break; if (((y-image->extract_info.y) >= 0) && ((y-image->extract_info.y) < (ssize_t) image->rows)) { p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0, canvas_image->columns,1,exception); q=GetAuthenticPixels(image,0,y-image->extract_info.y, image->columns,1,exception); if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL)) break; for (x=0; x < (ssize_t) image->columns; x++) { SetRedPixelComponent(q,GetRedPixelComponent(p)); p++; q++; } if (SyncAuthenticPixels(image,exception) == MagickFalse) break; } count=ReadBlob(image,length,pixels); } if (image->previous == (Image *) NULL) { status=SetImageProgress(image,LoadImageTag,1,5); if (status == MagickFalse) break; } for (y=0; y < (ssize_t) image->extract_info.height; y++) { if (count != (ssize_t) length) { ThrowFileException(exception,CorruptImageError, "UnexpectedEndOfFile",image->filename); break; } q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1, exception); if (q == (PixelPacket *) NULL) break; length=ImportQuantumPixels(canvas_image,(CacheView *) NULL, quantum_info,GreenQuantum,pixels,exception); if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse) break; if (((y-image->extract_info.y) >= 0) && ((y-image->extract_info.y) < (ssize_t) image->rows)) { p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0, canvas_image->columns,1,exception); q=GetAuthenticPixels(image,0,y-image->extract_info.y, image->columns,1,exception); if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL)) break; for (x=0; x < (ssize_t) image->columns; x++) { SetGreenPixelComponent(q,GetGreenPixelComponent(p)); p++; q++; } if (SyncAuthenticPixels(image,exception) == MagickFalse) break; } count=ReadBlob(image,length,pixels); } if (image->previous == (Image *) NULL) { status=SetImageProgress(image,LoadImageTag,2,5); if (status == MagickFalse) break; } for (y=0; y < (ssize_t) image->extract_info.height; y++) { if (count != (ssize_t) length) { ThrowFileException(exception,CorruptImageError, "UnexpectedEndOfFile",image->filename); break; } q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1, exception); if (q == (PixelPacket *) NULL) break; length=ImportQuantumPixels(canvas_image,(CacheView *) NULL, quantum_info,BlueQuantum,pixels,exception); if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse) break; if (((y-image->extract_info.y) >= 0) && ((y-image->extract_info.y) < (ssize_t) image->rows)) { p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0, canvas_image->columns,1,exception); q=GetAuthenticPixels(image,0,y-image->extract_info.y, image->columns,1,exception); if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL)) break; for (x=0; x < (ssize_t) image->columns; x++) { SetBluePixelComponent(q,GetBluePixelComponent(p)); p++; q++; } if (SyncAuthenticPixels(image,exception) == MagickFalse) break; } count=ReadBlob(image,length,pixels); } if (image->previous == (Image *) NULL) { status=SetImageProgress(image,LoadImageTag,3,5); if (status == MagickFalse) break; } if (image->matte != MagickFalse) { for (y=0; y < (ssize_t) image->extract_info.height; y++) { if (count != (ssize_t) length) { ThrowFileException(exception,CorruptImageError, "UnexpectedEndOfFile",image->filename); break; } q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1, exception); if (q == (PixelPacket *) NULL) break; length=ImportQuantumPixels(canvas_image,(CacheView *) NULL, quantum_info,AlphaQuantum,pixels,exception); if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse) break; if (((y-image->extract_info.y) >= 0) && ((y-image->extract_info.y) < (ssize_t) image->rows)) { p=GetVirtualPixels(canvas_image, canvas_image->extract_info.x,0,canvas_image->columns,1, exception); q=GetAuthenticPixels(image,0,y-image->extract_info.y, image->columns,1,exception); if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL)) break; for (x=0; x < (ssize_t) image->columns; x++) { SetOpacityPixelComponent(q,GetOpacityPixelComponent(p)); p++; q++; } if (SyncAuthenticPixels(image,exception) == MagickFalse) break; } count=ReadBlob(image,length,pixels); } if (image->previous == (Image *) NULL) { status=SetImageProgress(image,LoadImageTag,4,5); if (status == MagickFalse) break; } } if (image->previous == (Image *) NULL) { status=SetImageProgress(image,LoadImageTag,5,5); if (status == MagickFalse) break; } break; } case PartitionInterlace: { /* Partition interlacing: YYYYYY..., CbCbCbCbCbCb..., CrCrCrCrCrCr... */ AppendImageFormat("Y",image->filename); status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) { canvas_image=DestroyImageList(canvas_image); image=DestroyImageList(image); return((Image *) NULL); } if (DiscardBlobBytes(image,image->offset) == MagickFalse) ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", image->filename); length=GetQuantumExtent(canvas_image,quantum_info,RedQuantum); for (i=0; i < (ssize_t) scene; i++) for (y=0; y < (ssize_t) image->extract_info.height; y++) if (ReadBlob(image,length,pixels) != (ssize_t) length) { ThrowFileException(exception,CorruptImageError, "UnexpectedEndOfFile",image->filename); break; } count=ReadBlob(image,length,pixels); for (y=0; y < (ssize_t) image->extract_info.height; y++) { if (count != (ssize_t) length) { ThrowFileException(exception,CorruptImageError, "UnexpectedEndOfFile",image->filename); break; } q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1, exception); if (q == (PixelPacket *) NULL) break; length=ImportQuantumPixels(canvas_image,(CacheView *) NULL, quantum_info,RedQuantum,pixels,exception); if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse) break; if (((y-image->extract_info.y) >= 0) && ((y-image->extract_info.y) < (ssize_t) image->rows)) { p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0, canvas_image->columns,1,exception); q=GetAuthenticPixels(image,0,y-image->extract_info.y, image->columns,1,exception); if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL)) break; for (x=0; x < (ssize_t) image->columns; x++) { SetRedPixelComponent(q,GetRedPixelComponent(p)); p++; q++; } if (SyncAuthenticPixels(image,exception) == MagickFalse) break; } count=ReadBlob(image,length,pixels); } if (image->previous == (Image *) NULL) { status=SetImageProgress(image,LoadImageTag,1,5); if (status == MagickFalse) break; } (void) CloseBlob(image); AppendImageFormat("Cb",image->filename); status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) { canvas_image=DestroyImageList(canvas_image); image=DestroyImageList(image); return((Image *) NULL); } length=GetQuantumExtent(canvas_image,quantum_info,GreenQuantum); for (i=0; i < (ssize_t) scene; i++) for (y=0; y < (ssize_t) image->extract_info.height; y++) if (ReadBlob(image,length,pixels) != (ssize_t) length) { ThrowFileException(exception,CorruptImageError, "UnexpectedEndOfFile",image->filename); break; } count=ReadBlob(image,length,pixels); for (y=0; y < (ssize_t) image->extract_info.height; y++) { if (count != (ssize_t) length) { ThrowFileException(exception,CorruptImageError, "UnexpectedEndOfFile",image->filename); break; } q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1, exception); if (q == (PixelPacket *) NULL) break; length=ImportQuantumPixels(canvas_image,(CacheView *) NULL, quantum_info,GreenQuantum,pixels,exception); if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse) break; if (((y-image->extract_info.y) >= 0) && ((y-image->extract_info.y) < (ssize_t) image->rows)) { p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0, canvas_image->columns,1,exception); q=GetAuthenticPixels(image,0,y-image->extract_info.y, image->columns,1,exception); if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL)) break; for (x=0; x < (ssize_t) image->columns; x++) { SetGreenPixelComponent(q,GetGreenPixelComponent(p)); p++; q++; } if (SyncAuthenticPixels(image,exception) == MagickFalse) break; } count=ReadBlob(image,length,pixels); } if (image->previous == (Image *) NULL) { status=SetImageProgress(image,LoadImageTag,2,5); if (status == MagickFalse) break; } (void) CloseBlob(image); AppendImageFormat("Cr",image->filename); status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) { canvas_image=DestroyImageList(canvas_image); image=DestroyImageList(image); return((Image *) NULL); } length=GetQuantumExtent(canvas_image,quantum_info,BlueQuantum); for (i=0; i < (ssize_t) scene; i++) for (y=0; y < (ssize_t) image->extract_info.height; y++) if (ReadBlob(image,length,pixels) != (ssize_t) length) { ThrowFileException(exception,CorruptImageError, "UnexpectedEndOfFile",image->filename); break; } count=ReadBlob(image,length,pixels); for (y=0; y < (ssize_t) image->extract_info.height; y++) { if (count != (ssize_t) length) { ThrowFileException(exception,CorruptImageError, "UnexpectedEndOfFile",image->filename); break; } q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1, exception); if (q == (PixelPacket *) NULL) break; length=ImportQuantumPixels(canvas_image,(CacheView *) NULL, quantum_info,BlueQuantum,pixels,exception); if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse) break; if (((y-image->extract_info.y) >= 0) && ((y-image->extract_info.y) < (ssize_t) image->rows)) { p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0, canvas_image->columns,1,exception); q=GetAuthenticPixels(image,0,y-image->extract_info.y, image->columns,1,exception); if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL)) break; for (x=0; x < (ssize_t) image->columns; x++) { SetBluePixelComponent(q,GetBluePixelComponent(p)); p++; q++; } if (SyncAuthenticPixels(image,exception) == MagickFalse) break; } count=ReadBlob(image,length,pixels); } if (image->previous == (Image *) NULL) { status=SetImageProgress(image,LoadImageTag,3,5); if (status == MagickFalse) break; } if (image->matte != MagickFalse) { (void) CloseBlob(image); AppendImageFormat("A",image->filename); status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) { canvas_image=DestroyImageList(canvas_image); image=DestroyImageList(image); return((Image *) NULL); } length=GetQuantumExtent(canvas_image,quantum_info,AlphaQuantum); for (i=0; i < (ssize_t) scene; i++) for (y=0; y < (ssize_t) image->extract_info.height; y++) if (ReadBlob(image,length,pixels) != (ssize_t) length) { ThrowFileException(exception,CorruptImageError, "UnexpectedEndOfFile",image->filename); break; } count=ReadBlob(image,length,pixels); for (y=0; y < (ssize_t) image->extract_info.height; y++) { if (count != (ssize_t) length) { ThrowFileException(exception,CorruptImageError, "UnexpectedEndOfFile",image->filename); break; } q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1, exception); if (q == (PixelPacket *) NULL) break; length=ImportQuantumPixels(canvas_image,(CacheView *) NULL, quantum_info,BlueQuantum,pixels,exception); if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse) break; if (((y-image->extract_info.y) >= 0) && ((y-image->extract_info.y) < (ssize_t) image->rows)) { p=GetVirtualPixels(canvas_image, canvas_image->extract_info.x,0,canvas_image->columns,1, exception); q=GetAuthenticPixels(image,0,y-image->extract_info.y, image->columns,1,exception); if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL)) break; for (x=0; x < (ssize_t) image->columns; x++) { SetOpacityPixelComponent(q,GetOpacityPixelComponent(p)); p++; q++; } if (SyncAuthenticPixels(image,exception) == MagickFalse) break; } count=ReadBlob(image,length,pixels); } if (image->previous == (Image *) NULL) { status=SetImageProgress(image,LoadImageTag,4,5); if (status == MagickFalse) break; } } if (image->previous == (Image *) NULL) { status=SetImageProgress(image,LoadImageTag,5,5); if (status == MagickFalse) break; } break; } } SetQuantumImageType(image,quantum_type); /* Proceed to next image. */ if (image_info->number_scenes != 0) if (image->scene >= (image_info->scene+image_info->number_scenes-1)) break; if (count == (ssize_t) length) { /* Allocate next image structure. */ AcquireNextImage(image_info,image); if (GetNextImageInList(image) == (Image *) NULL) { image=DestroyImageList(image); return((Image *) NULL); } image=SyncNextImageInList(image); status=SetImageProgress(image,LoadImagesTag,TellBlob(image), GetBlobSize(image)); if (status == MagickFalse) break; } scene++; } while (count == (ssize_t) length); quantum_info=DestroyQuantumInfo(quantum_info); InheritException(&image->exception,&canvas_image->exception); canvas_image=DestroyImage(canvas_image); (void) CloseBlob(image); return(GetFirstImageInList(image)); }
MagickExport Image *ConnectedComponentsImage(const Image *image, const size_t connectivity,ExceptionInfo *exception) { #define ConnectedComponentsImageTag "ConnectedComponents/Image" CacheView *image_view, *component_view; const char *artifact; double area_threshold; Image *component_image; MagickBooleanType status; MagickOffsetType progress; MatrixInfo *equivalences; size_t size; ssize_t n, y; /* Initialize connected components image attributes. */ assert(image != (Image *) NULL); assert(image->signature == MagickCoreSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickCoreSignature); component_image=CloneImage(image,image->columns,image->rows,MagickTrue, exception); if (component_image == (Image *) NULL) return((Image *) NULL); component_image->depth=MAGICKCORE_QUANTUM_DEPTH; component_image->colorspace=GRAYColorspace; status=SetImageStorageClass(component_image,DirectClass,exception); if (status == MagickFalse) { component_image=DestroyImage(component_image); return((Image *) NULL); } /* Initialize connected components equivalences. */ size=image->columns*image->rows; if (image->columns != (size/image->rows)) { component_image=DestroyImage(component_image); ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); } equivalences=AcquireMatrixInfo(size,1,sizeof(ssize_t),exception); if (equivalences == (MatrixInfo *) NULL) { component_image=DestroyImage(component_image); return((Image *) NULL); } for (n=0; n < (ssize_t) (image->columns*image->rows); n++) status=SetMatrixElement(equivalences,n,0,&n); /* Find connected components. */ status=MagickTrue; progress=0; image_view=AcquireVirtualCacheView(image,exception); for (n=0; n < (ssize_t) (connectivity > 4 ? 4 : 2); n++) { ssize_t connect4[2][2] = { { -1, 0 }, { 0, -1 } }, connect8[4][2] = { { -1, -1 }, { -1, 0 }, { -1, 1 }, { 0, -1 } }, dx, dy; if (status == MagickFalse) continue; dy=connectivity > 4 ? connect8[n][0] : connect4[n][0]; dx=connectivity > 4 ? connect8[n][1] : connect4[n][1]; for (y=0; y < (ssize_t) image->rows; y++) { register const Quantum *magick_restrict p; register ssize_t x; if (status == MagickFalse) continue; p=GetCacheViewVirtualPixels(image_view,0,y-1,image->columns,3,exception); if (p == (const Quantum *) NULL) { status=MagickFalse; continue; } p+=GetPixelChannels(image)*image->columns; for (x=0; x < (ssize_t) image->columns; x++) { PixelInfo pixel, target; ssize_t neighbor_offset, object, offset, ox, oy, root; /* Is neighbor an authentic pixel and a different color than the pixel? */ GetPixelInfoPixel(image,p,&pixel); neighbor_offset=dy*(GetPixelChannels(image)*image->columns)+dx* GetPixelChannels(image); GetPixelInfoPixel(image,p+neighbor_offset,&target); if (((x+dx) < 0) || ((x+dx) >= (ssize_t) image->columns) || ((y+dy) < 0) || ((y+dy) >= (ssize_t) image->rows) || (IsFuzzyEquivalencePixelInfo(&pixel,&target) == MagickFalse)) { p+=GetPixelChannels(image); continue; } /* Resolve this equivalence. */ offset=y*image->columns+x; neighbor_offset=dy*image->columns+dx; ox=offset; status=GetMatrixElement(equivalences,ox,0,&object); while (object != ox) { ox=object; status=GetMatrixElement(equivalences,ox,0,&object); } oy=offset+neighbor_offset; status=GetMatrixElement(equivalences,oy,0,&object); while (object != oy) { oy=object; status=GetMatrixElement(equivalences,oy,0,&object); } if (ox < oy) { status=SetMatrixElement(equivalences,oy,0,&ox); root=ox; } else { status=SetMatrixElement(equivalences,ox,0,&oy); root=oy; } ox=offset; status=GetMatrixElement(equivalences,ox,0,&object); while (object != root) { status=GetMatrixElement(equivalences,ox,0,&object); status=SetMatrixElement(equivalences,ox,0,&root); } oy=offset+neighbor_offset; status=GetMatrixElement(equivalences,oy,0,&object); while (object != root) { status=GetMatrixElement(equivalences,oy,0,&object); status=SetMatrixElement(equivalences,oy,0,&root); } status=SetMatrixElement(equivalences,y*image->columns+x,0,&root); p+=GetPixelChannels(image); } } } image_view=DestroyCacheView(image_view); /* Label connected components. */ n=0; component_view=AcquireAuthenticCacheView(component_image,exception); for (y=0; y < (ssize_t) component_image->rows; y++) { register Quantum *magick_restrict q; register ssize_t x; if (status == MagickFalse) continue; q=QueueCacheViewAuthenticPixels(component_view,0,y,component_image->columns, 1,exception); if (q == (Quantum *) NULL) { status=MagickFalse; continue; } for (x=0; x < (ssize_t) component_image->columns; x++) { ssize_t object, offset; offset=y*image->columns+x; status=GetMatrixElement(equivalences,offset,0,&object); if (object == offset) { object=n++; status=SetMatrixElement(equivalences,offset,0,&object); } else { status=GetMatrixElement(equivalences,object,0,&object); status=SetMatrixElement(equivalences,offset,0,&object); } *q=(Quantum) (object > (ssize_t) QuantumRange ? (ssize_t) QuantumRange : object); q+=GetPixelChannels(component_image); } if (SyncCacheViewAuthenticPixels(component_view,exception) == MagickFalse) status=MagickFalse; if (image->progress_monitor != (MagickProgressMonitor) NULL) { MagickBooleanType proceed; proceed=SetImageProgress(image,ConnectedComponentsImageTag,progress++, image->rows); if (proceed == MagickFalse) status=MagickFalse; } } component_view=DestroyCacheView(component_view); equivalences=DestroyMatrixInfo(equivalences); if (n > (ssize_t) QuantumRange) { component_image=DestroyImage(component_image); ThrowImageException(ResourceLimitError,"TooManyObjects"); } artifact=GetImageArtifact(image,"connected-components:area-threshold"); area_threshold=0.0; if (artifact != (const char *) NULL) area_threshold=StringToDouble(artifact,(char **) NULL); if (area_threshold > 0.0) status=MergeConnectedComponents(component_image,(size_t) n,area_threshold, exception); artifact=GetImageArtifact(image,"connected-components:verbose"); if (IsStringTrue(artifact) != MagickFalse) status=StatisticsComponentsStatistics(image,component_image,(size_t) n, exception); if (status == MagickFalse) component_image=DestroyImage(component_image); return(component_image); }
WandExport MagickBooleanType CompareImagesCommand(ImageInfo *image_info, int argc,char **argv,char **metadata,ExceptionInfo *exception) { #define CompareEpsilon (1.0e-06) #define DefaultDissimilarityThreshold 0.31830988618379067154 #define DefaultSimilarityThreshold (-1.0) #define DestroyCompare() \ { \ if (similarity_image != (Image *) NULL) \ similarity_image=DestroyImageList(similarity_image); \ if (difference_image != (Image *) NULL) \ difference_image=DestroyImageList(difference_image); \ DestroyImageStack(); \ for (i=0; i < (ssize_t) argc; i++) \ argv[i]=DestroyString(argv[i]); \ argv=(char **) RelinquishMagickMemory(argv); \ } #define ThrowCompareException(asperity,tag,option) \ { \ if (exception->severity < (asperity)) \ (void) ThrowMagickException(exception,GetMagickModule(),asperity,tag, \ "`%s'",option); \ DestroyCompare(); \ return(MagickFalse); \ } #define ThrowCompareInvalidArgumentException(option,argument) \ { \ (void) ThrowMagickException(exception,GetMagickModule(),OptionError, \ "InvalidArgument","'%s': %s",option,argument); \ DestroyCompare(); \ return(MagickFalse); \ } char *filename, *option; const char *format; double dissimilarity_threshold, distortion, similarity_metric, similarity_threshold; Image *difference_image, *image, *reconstruct_image, *similarity_image; ImageStack image_stack[MaxImageStackDepth+1]; MagickBooleanType fire, pend, respect_parenthesis, subimage_search; MagickStatusType status; MetricType metric; RectangleInfo offset; register ssize_t i; ssize_t j, k; /* Set defaults. */ assert(image_info != (ImageInfo *) NULL); assert(image_info->signature == MagickSignature); if (image_info->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); assert(exception != (ExceptionInfo *) NULL); if (argc == 2) { option=argv[1]; if ((LocaleCompare("version",option+1) == 0) || (LocaleCompare("-version",option+1) == 0)) { ListMagickVersion(stdout); return(MagickFalse); } } if (argc < 3) return(CompareUsage()); difference_image=NewImageList(); similarity_image=NewImageList(); dissimilarity_threshold=DefaultDissimilarityThreshold; similarity_threshold=DefaultSimilarityThreshold; distortion=0.0; format=(char *) NULL; j=1; k=0; metric=UndefinedErrorMetric; NewImageStack(); option=(char *) NULL; pend=MagickFalse; reconstruct_image=NewImageList(); respect_parenthesis=MagickFalse; status=MagickTrue; subimage_search=MagickFalse; /* Compare an image. */ ReadCommandlLine(argc,&argv); status=ExpandFilenames(&argc,&argv); if (status == MagickFalse) ThrowCompareException(ResourceLimitError,"MemoryAllocationFailed", GetExceptionMessage(errno)); for (i=1; i < (ssize_t) (argc-1); i++) { option=argv[i]; if (LocaleCompare(option,"(") == 0) { FireImageStack(MagickTrue,MagickTrue,pend); if (k == MaxImageStackDepth) ThrowCompareException(OptionError,"ParenthesisNestedTooDeeply", option); PushImageStack(); continue; } if (LocaleCompare(option,")") == 0) { FireImageStack(MagickTrue,MagickTrue,MagickTrue); if (k == 0) ThrowCompareException(OptionError,"UnableToParseExpression",option); PopImageStack(); continue; } if (IsCommandOption(option) == MagickFalse) { Image *images; /* Read input image. */ FireImageStack(MagickFalse,MagickFalse,pend); filename=argv[i]; if ((LocaleCompare(filename,"--") == 0) && (i < (ssize_t) (argc-1))) filename=argv[++i]; images=ReadImages(image_info,filename,exception); status&=(images != (Image *) NULL) && (exception->severity < ErrorException); if (images == (Image *) NULL) continue; AppendImageStack(images); continue; } pend=image != (Image *) NULL ? MagickTrue : MagickFalse; switch (*(option+1)) { case 'a': { if (LocaleCompare("alpha",option+1) == 0) { ssize_t type; if (*option == '+') break; i++; if (i == (ssize_t) argc) ThrowCompareException(OptionError,"MissingArgument",option); type=ParseCommandOption(MagickAlphaChannelOptions,MagickFalse,argv[i]); if (type < 0) ThrowCompareException(OptionError,"UnrecognizedAlphaChannelOption", argv[i]); break; } if (LocaleCompare("authenticate",option+1) == 0) { if (*option == '+') break; i++; if (i == (ssize_t) argc) ThrowCompareException(OptionError,"MissingArgument",option); break; } ThrowCompareException(OptionError,"UnrecognizedOption",option); } case 'c': { if (LocaleCompare("cache",option+1) == 0) { if (*option == '+') break; i++; if (i == (ssize_t) argc) ThrowCompareException(OptionError,"MissingArgument",option); if (IsGeometry(argv[i]) == MagickFalse) ThrowCompareInvalidArgumentException(option,argv[i]); break; } if (LocaleCompare("channel",option+1) == 0) { ssize_t channel; if (*option == '+') break; i++; if (i == (ssize_t) (argc-1)) ThrowCompareException(OptionError,"MissingArgument",option); channel=ParseChannelOption(argv[i]); if (channel < 0) ThrowCompareException(OptionError,"UnrecognizedChannelType", argv[i]); SetPixelChannelMask(image,(ChannelType) channel); break; } if (LocaleCompare("colorspace",option+1) == 0) { ssize_t colorspace; if (*option == '+') break; i++; if (i == (ssize_t) (argc-1)) ThrowCompareException(OptionError,"MissingArgument",option); colorspace=ParseCommandOption(MagickColorspaceOptions,MagickFalse, argv[i]); if (colorspace < 0) ThrowCompareException(OptionError,"UnrecognizedColorspace", argv[i]); break; } if (LocaleCompare("compose",option+1) == 0) { ssize_t compose; if (*option == '+') break; i++; if (i == (ssize_t) argc) ThrowCompareException(OptionError,"MissingArgument",option); compose=ParseCommandOption(MagickComposeOptions,MagickFalse, argv[i]); if (compose < 0) ThrowCompareException(OptionError,"UnrecognizedComposeOperator", argv[i]); break; } if (LocaleCompare("compress",option+1) == 0) { ssize_t compress; if (*option == '+') break; i++; if (i == (ssize_t) (argc-1)) ThrowCompareException(OptionError,"MissingArgument",option); compress=ParseCommandOption(MagickCompressOptions,MagickFalse, argv[i]); if (compress < 0) ThrowCompareException(OptionError,"UnrecognizedImageCompression", argv[i]); break; } if (LocaleCompare("concurrent",option+1) == 0) break; ThrowCompareException(OptionError,"UnrecognizedOption",option) } case 'd': { if (LocaleCompare("debug",option+1) == 0) { LogEventType event_mask; if (*option == '+') break; i++; if (i == (ssize_t) argc) ThrowCompareException(OptionError,"MissingArgument",option); event_mask=SetLogEventMask(argv[i]); if (event_mask == UndefinedEvents) ThrowCompareException(OptionError,"UnrecognizedEventType", argv[i]); break; } if (LocaleCompare("decipher",option+1) == 0) { if (*option == '+') break; i++; if (i == (ssize_t) (argc-1)) ThrowCompareException(OptionError,"MissingArgument",option); break; } if (LocaleCompare("define",option+1) == 0) { i++; if (i == (ssize_t) argc) ThrowCompareException(OptionError,"MissingArgument",option); if (*option == '+') { const char *define; define=GetImageOption(image_info,argv[i]); if (define == (const char *) NULL) ThrowCompareException(OptionError,"NoSuchOption",argv[i]); break; } break; } if (LocaleCompare("density",option+1) == 0) { if (*option == '+') break; i++; if (i == (ssize_t) argc) ThrowCompareException(OptionError,"MissingArgument",option); if (IsGeometry(argv[i]) == MagickFalse) ThrowCompareInvalidArgumentException(option,argv[i]); break; } if (LocaleCompare("depth",option+1) == 0) { if (*option == '+') break; i++; if (i == (ssize_t) argc) ThrowCompareException(OptionError,"MissingArgument",option); if (IsGeometry(argv[i]) == MagickFalse) ThrowCompareInvalidArgumentException(option,argv[i]); break; } if (LocaleCompare("dissimilarity-threshold",option+1) == 0) { if (*option == '+') break; i++; if (i == (ssize_t) argc) ThrowCompareException(OptionError,"MissingArgument",option); if (IsGeometry(argv[i]) == MagickFalse) ThrowCompareInvalidArgumentException(option,argv[i]); if (*option == '+') dissimilarity_threshold=DefaultDissimilarityThreshold; else dissimilarity_threshold=StringToDouble(argv[i],(char **) NULL); break; } if (LocaleCompare("duration",option+1) == 0) { if (*option == '+') break; i++; if (i == (ssize_t) (argc-1)) ThrowCompareException(OptionError,"MissingArgument",option); if (IsGeometry(argv[i]) == MagickFalse) ThrowCompareInvalidArgumentException(option,argv[i]); break; } ThrowCompareException(OptionError,"UnrecognizedOption",option) } case 'e': { if (LocaleCompare("encipher",option+1) == 0) { if (*option == '+') break; i++; if (i == (ssize_t) (argc-1)) ThrowCompareException(OptionError,"MissingArgument",option); break; } if (LocaleCompare("extract",option+1) == 0) { if (*option == '+') break; i++; if (i == (ssize_t) (argc-1)) ThrowCompareException(OptionError,"MissingArgument",option); if (IsGeometry(argv[i]) == MagickFalse) ThrowCompareInvalidArgumentException(option,argv[i]); break; } ThrowCompareException(OptionError,"UnrecognizedOption",option) } case 'f': { if (LocaleCompare("format",option+1) == 0) { if (*option == '+') break; i++; if (i == (ssize_t) argc) ThrowCompareException(OptionError,"MissingArgument",option); format=argv[i]; break; } if (LocaleCompare("fuzz",option+1) == 0) { if (*option == '+') break; i++; if (i == (ssize_t) (argc-1)) ThrowCompareException(OptionError,"MissingArgument",option); if (IsGeometry(argv[i]) == MagickFalse) ThrowCompareInvalidArgumentException(option,argv[i]); break; } ThrowCompareException(OptionError,"UnrecognizedOption",option) } case 'h': { if ((LocaleCompare("help",option+1) == 0) || (LocaleCompare("-help",option+1) == 0)) return(CompareUsage()); if (LocaleCompare("highlight-color",option+1) == 0) { if (*option == '+') break; i++; if (i == (ssize_t) (argc-1)) ThrowCompareException(OptionError,"MissingArgument",option); break; } ThrowCompareException(OptionError,"UnrecognizedOption",option) } case 'i': { if (LocaleCompare("identify",option+1) == 0) break; if (LocaleCompare("interlace",option+1) == 0) { ssize_t interlace; if (*option == '+') break; i++; if (i == (ssize_t) argc) ThrowCompareException(OptionError,"MissingArgument",option); interlace=ParseCommandOption(MagickInterlaceOptions,MagickFalse, argv[i]); if (interlace < 0) ThrowCompareException(OptionError,"UnrecognizedInterlaceType", argv[i]); break; } ThrowCompareException(OptionError,"UnrecognizedOption",option) } case 'l': { if (LocaleCompare("limit",option+1) == 0) { char *p; double value; ssize_t resource; if (*option == '+') break; i++; if (i == (ssize_t) argc) ThrowCompareException(OptionError,"MissingArgument",option); resource=ParseCommandOption(MagickResourceOptions,MagickFalse, argv[i]); if (resource < 0) ThrowCompareException(OptionError,"UnrecognizedResourceType", argv[i]); i++; if (i == (ssize_t) argc) ThrowCompareException(OptionError,"MissingArgument",option); value=StringToDouble(argv[i],&p); (void) value; if ((p == argv[i]) && (LocaleCompare("unlimited",argv[i]) != 0)) ThrowCompareInvalidArgumentException(option,argv[i]); break; } if (LocaleCompare("list",option+1) == 0) { ssize_t list; if (*option == '+') break; i++; if (i == (ssize_t) argc) ThrowCompareException(OptionError,"MissingArgument",option); list=ParseCommandOption(MagickListOptions,MagickFalse,argv[i]); if (list < 0) ThrowCompareException(OptionError,"UnrecognizedListType",argv[i]); status=MogrifyImageInfo(image_info,(int) (i-j+1),(const char **) argv+j,exception); DestroyCompare(); return(status != 0 ? MagickFalse : MagickTrue); } if (LocaleCompare("log",option+1) == 0) { if (*option == '+') break; i++; if ((i == (ssize_t) argc) || (strchr(argv[i],'%') == (char *) NULL)) ThrowCompareException(OptionError,"MissingArgument",option); break; } if (LocaleCompare("lowlight-color",option+1) == 0) { if (*option == '+') break; i++; if (i == (ssize_t) (argc-1)) ThrowCompareException(OptionError,"MissingArgument",option); break; } ThrowCompareException(OptionError,"UnrecognizedOption",option) } case 'm': { if (LocaleCompare("matte",option+1) == 0) break; if (LocaleCompare("metric",option+1) == 0) { ssize_t type; if (*option == '+') break; i++; if (i == (ssize_t) argc) ThrowCompareException(OptionError,"MissingArgument",option); type=ParseCommandOption(MagickMetricOptions,MagickTrue,argv[i]); if (type < 0) ThrowCompareException(OptionError,"UnrecognizedMetricType", argv[i]); metric=(MetricType) type; break; } if (LocaleCompare("monitor",option+1) == 0) break; ThrowCompareException(OptionError,"UnrecognizedOption",option) } case 'p': { if (LocaleCompare("profile",option+1) == 0) { i++; if (i == (ssize_t) (argc-1)) ThrowCompareException(OptionError,"MissingArgument",option); break; } ThrowCompareException(OptionError,"UnrecognizedOption",option) } case 'q': { if (LocaleCompare("quality",option+1) == 0) { if (*option == '+') break; i++; if (i == (ssize_t) (argc-1)) ThrowCompareException(OptionError,"MissingArgument",option); if (IsGeometry(argv[i]) == MagickFalse) ThrowCompareInvalidArgumentException(option,argv[i]); break; } if (LocaleCompare("quantize",option+1) == 0) { ssize_t colorspace; if (*option == '+') break; i++; if (i == (ssize_t) (argc-1)) ThrowCompareException(OptionError,"MissingArgument",option); colorspace=ParseCommandOption(MagickColorspaceOptions, MagickFalse,argv[i]); if (colorspace < 0) ThrowCompareException(OptionError,"UnrecognizedColorspace", argv[i]); break; } if (LocaleCompare("quiet",option+1) == 0) break; ThrowCompareException(OptionError,"UnrecognizedOption",option) } case 'r': { if (LocaleCompare("regard-warnings",option+1) == 0) break; if (LocaleNCompare("respect-parentheses",option+1,17) == 0) { respect_parenthesis=(*option == '-') ? MagickTrue : MagickFalse; break; } ThrowCompareException(OptionError,"UnrecognizedOption",option) } case 's': { if (LocaleCompare("sampling-factor",option+1) == 0) { if (*option == '+') break; i++; if (i == (ssize_t) argc) ThrowCompareException(OptionError,"MissingArgument",option); if (IsGeometry(argv[i]) == MagickFalse) ThrowCompareInvalidArgumentException(option,argv[i]); break; } if (LocaleCompare("seed",option+1) == 0) { if (*option == '+') break; i++; if (i == (ssize_t) (argc-1)) ThrowCompareException(OptionError,"MissingArgument",option); if (IsGeometry(argv[i]) == MagickFalse) ThrowCompareInvalidArgumentException(option,argv[i]); break; } if (LocaleCompare("set",option+1) == 0) { i++; if (i == (ssize_t) argc) ThrowCompareException(OptionError,"MissingArgument",option); if (*option == '+') break; i++; if (i == (ssize_t) argc) ThrowCompareException(OptionError,"MissingArgument",option); break; } if (LocaleCompare("similarity-threshold",option+1) == 0) { if (*option == '+') break; i++; if (i == (ssize_t) argc) ThrowCompareException(OptionError,"MissingArgument",option); if (IsGeometry(argv[i]) == MagickFalse) ThrowCompareInvalidArgumentException(option,argv[i]); if (*option == '+') similarity_threshold=DefaultSimilarityThreshold; else similarity_threshold=StringToDouble(argv[i],(char **) NULL); break; } if (LocaleCompare("size",option+1) == 0) { if (*option == '+') break; i++; if (i == (ssize_t) argc) ThrowCompareException(OptionError,"MissingArgument",option); if (IsGeometry(argv[i]) == MagickFalse) ThrowCompareInvalidArgumentException(option,argv[i]); break; } if (LocaleCompare("subimage-search",option+1) == 0) { if (*option == '+') { subimage_search=MagickFalse; break; } subimage_search=MagickTrue; break; } if (LocaleCompare("synchronize",option+1) == 0) break; ThrowCompareException(OptionError,"UnrecognizedOption",option) } case 't': { if (LocaleCompare("taint",option+1) == 0) break; if (LocaleCompare("transparent-color",option+1) == 0) { if (*option == '+') break; i++; if (i == (ssize_t) (argc-1)) ThrowCompareException(OptionError,"MissingArgument",option); break; } if (LocaleCompare("type",option+1) == 0) { ssize_t type; if (*option == '+') break; i++; if (i == (ssize_t) argc) ThrowCompareException(OptionError,"MissingArgument",option); type=ParseCommandOption(MagickTypeOptions,MagickFalse,argv[i]); if (type < 0) ThrowCompareException(OptionError,"UnrecognizedImageType", argv[i]); break; } ThrowCompareException(OptionError,"UnrecognizedOption",option) } case 'v': { if (LocaleCompare("verbose",option+1) == 0) break; if ((LocaleCompare("version",option+1) == 0) || (LocaleCompare("-version",option+1) == 0)) { ListMagickVersion(stdout); break; } if (LocaleCompare("virtual-pixel",option+1) == 0) { ssize_t method; if (*option == '+') break; i++; if (i == (ssize_t) (argc-1)) ThrowCompareException(OptionError,"MissingArgument",option); method=ParseCommandOption(MagickVirtualPixelOptions,MagickFalse, argv[i]); if (method < 0) ThrowCompareException(OptionError, "UnrecognizedVirtualPixelMethod",argv[i]); break; } ThrowCompareException(OptionError,"UnrecognizedOption",option) } case '?': break; default: ThrowCompareException(OptionError,"UnrecognizedOption",option) } fire=(GetCommandOptionFlags(MagickCommandOptions,MagickFalse,option) & FireOptionFlag) == 0 ? MagickFalse : MagickTrue; if (fire != MagickFalse) FireImageStack(MagickTrue,MagickTrue,MagickTrue); } if (k != 0) ThrowCompareException(OptionError,"UnbalancedParenthesis",argv[i]); if (i-- != (ssize_t) (argc-1)) ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]); if ((image == (Image *) NULL) || (GetImageListLength(image) < 2)) ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]); FinalizeImageSettings(image_info,image,MagickTrue); if ((image == (Image *) NULL) || (GetImageListLength(image) < 2)) ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]); image=GetImageFromList(image,0); reconstruct_image=GetImageFromList(image,1); if (subimage_search != MagickFalse) { similarity_image=SimilarityImage(image,reconstruct_image,metric, similarity_threshold,&offset,&similarity_metric,exception); if (similarity_metric > dissimilarity_threshold) ThrowCompareException(ImageError,"ImagesTooDissimilar",image->filename); } if ((reconstruct_image->columns == image->columns) && (reconstruct_image->rows == image->rows)) difference_image=CompareImages(image,reconstruct_image,metric,&distortion, exception); else if (similarity_image == (Image *) NULL) ThrowCompareException(OptionError,"ImageWidthsOrHeightsDiffer", image->filename) else { Image *composite_image; /* Determine if reconstructed image is a subimage of the image. */ composite_image=CloneImage(image,0,0,MagickTrue,exception); if (composite_image == (Image *) NULL) difference_image=CompareImages(image,reconstruct_image,metric, &distortion,exception); else { Image *distort_image; RectangleInfo page; (void) CompositeImage(composite_image,reconstruct_image, CopyCompositeOp,MagickTrue,offset.x,offset.y,exception); difference_image=CompareImages(image,composite_image,metric, &distortion,exception); if (difference_image != (Image *) NULL) { difference_image->page.x=offset.x; difference_image->page.y=offset.y; } composite_image=DestroyImage(composite_image); page.width=reconstruct_image->columns; page.height=reconstruct_image->rows; page.x=offset.x; page.y=offset.y; distort_image=CropImage(image,&page,exception); if (distort_image != (Image *) NULL) { Image *sans_image; sans_image=CompareImages(distort_image,reconstruct_image,metric, &distortion,exception); distort_image=DestroyImage(distort_image); if (sans_image != (Image *) NULL) sans_image=DestroyImage(sans_image); } } if (difference_image != (Image *) NULL) { AppendImageToList(&difference_image,similarity_image); similarity_image=(Image *) NULL; } } if (difference_image == (Image *) NULL) status=0; else { if (image_info->verbose != MagickFalse) (void) IsImagesEqual(image,reconstruct_image,exception); if (*difference_image->magick == '\0') (void) CopyMagickString(difference_image->magick,image->magick, MaxTextExtent); if (image_info->verbose == MagickFalse) { switch (metric) { case FuzzErrorMetric: case MeanAbsoluteErrorMetric: case MeanSquaredErrorMetric: case RootMeanSquaredErrorMetric: case PeakAbsoluteErrorMetric: { (void) FormatLocaleFile(stderr,"%g (%g)",QuantumRange*distortion, (double) distortion); if ((reconstruct_image->columns != image->columns) || (reconstruct_image->rows != image->rows)) (void) FormatLocaleFile(stderr," @ %.20g,%.20g",(double) difference_image->page.x,(double) difference_image->page.y); break; } case AbsoluteErrorMetric: case NormalizedCrossCorrelationErrorMetric: case PeakSignalToNoiseRatioMetric: { (void) FormatLocaleFile(stderr,"%g",distortion); if ((reconstruct_image->columns != image->columns) || (reconstruct_image->rows != image->rows)) (void) FormatLocaleFile(stderr," @ %.20g,%.20g",(double) difference_image->page.x,(double) difference_image->page.y); break; } case MeanErrorPerPixelMetric: { (void) FormatLocaleFile(stderr,"%g (%g, %g)",distortion, image->error.normalized_mean_error, image->error.normalized_maximum_error); if ((reconstruct_image->columns != image->columns) || (reconstruct_image->rows != image->rows)) (void) FormatLocaleFile(stderr," @ %.20g,%.20g",(double) difference_image->page.x,(double) difference_image->page.y); break; } case UndefinedErrorMetric: break; } } else { double *channel_distortion; channel_distortion=GetImageDistortions(image,reconstruct_image, metric,exception); (void) FormatLocaleFile(stderr,"Image: %s\n",image->filename); if ((reconstruct_image->columns != image->columns) || (reconstruct_image->rows != image->rows)) (void) FormatLocaleFile(stderr,"Offset: %.20g,%.20g\n",(double) difference_image->page.x,(double) difference_image->page.y); (void) FormatLocaleFile(stderr," Channel distortion: %s\n", CommandOptionToMnemonic(MagickMetricOptions,(ssize_t) metric)); switch (metric) { case FuzzErrorMetric: case MeanAbsoluteErrorMetric: case MeanSquaredErrorMetric: case RootMeanSquaredErrorMetric: case PeakAbsoluteErrorMetric: { switch (image->colorspace) { case RGBColorspace: default: { (void) FormatLocaleFile(stderr," red: %g (%g)\n", QuantumRange*channel_distortion[RedPixelChannel], channel_distortion[RedPixelChannel]); (void) FormatLocaleFile(stderr," green: %g (%g)\n", QuantumRange*channel_distortion[GreenPixelChannel], channel_distortion[GreenPixelChannel]); (void) FormatLocaleFile(stderr," blue: %g (%g)\n", QuantumRange*channel_distortion[BluePixelChannel], channel_distortion[BluePixelChannel]); if (image->alpha_trait == BlendPixelTrait) (void) FormatLocaleFile(stderr," alpha: %g (%g)\n", QuantumRange*channel_distortion[AlphaPixelChannel], channel_distortion[AlphaPixelChannel]); break; } case CMYKColorspace: { (void) FormatLocaleFile(stderr," cyan: %g (%g)\n", QuantumRange*channel_distortion[CyanPixelChannel], channel_distortion[CyanPixelChannel]); (void) FormatLocaleFile(stderr," magenta: %g (%g)\n", QuantumRange*channel_distortion[MagentaPixelChannel], channel_distortion[MagentaPixelChannel]); (void) FormatLocaleFile(stderr," yellow: %g (%g)\n", QuantumRange*channel_distortion[YellowPixelChannel], channel_distortion[YellowPixelChannel]); (void) FormatLocaleFile(stderr," black: %g (%g)\n", QuantumRange*channel_distortion[BlackPixelChannel], channel_distortion[BlackPixelChannel]); if (image->alpha_trait == BlendPixelTrait) (void) FormatLocaleFile(stderr," alpha: %g (%g)\n", QuantumRange*channel_distortion[AlphaPixelChannel], channel_distortion[AlphaPixelChannel]); break; } case GRAYColorspace: { (void) FormatLocaleFile(stderr," gray: %g (%g)\n", QuantumRange*channel_distortion[GrayPixelChannel], channel_distortion[GrayPixelChannel]); if (image->alpha_trait == BlendPixelTrait) (void) FormatLocaleFile(stderr," alpha: %g (%g)\n", QuantumRange*channel_distortion[AlphaPixelChannel], channel_distortion[AlphaPixelChannel]); break; } } (void) FormatLocaleFile(stderr," all: %g (%g)\n", QuantumRange*channel_distortion[MaxPixelChannels], channel_distortion[MaxPixelChannels]); break; } case AbsoluteErrorMetric: case NormalizedCrossCorrelationErrorMetric: case PeakSignalToNoiseRatioMetric: { switch (image->colorspace) { case RGBColorspace: default: { (void) FormatLocaleFile(stderr," red: %g\n", channel_distortion[RedPixelChannel]); (void) FormatLocaleFile(stderr," green: %g\n", channel_distortion[GreenPixelChannel]); (void) FormatLocaleFile(stderr," blue: %g\n", channel_distortion[BluePixelChannel]); if (image->alpha_trait == BlendPixelTrait) (void) FormatLocaleFile(stderr," alpha: %g\n", channel_distortion[AlphaPixelChannel]); break; } case CMYKColorspace: { (void) FormatLocaleFile(stderr," cyan: %g\n", channel_distortion[CyanPixelChannel]); (void) FormatLocaleFile(stderr," magenta: %g\n", channel_distortion[MagentaPixelChannel]); (void) FormatLocaleFile(stderr," yellow: %g\n", channel_distortion[YellowPixelChannel]); (void) FormatLocaleFile(stderr," black: %g\n", channel_distortion[BlackPixelChannel]); if (image->alpha_trait == BlendPixelTrait) (void) FormatLocaleFile(stderr," alpha: %g\n", channel_distortion[AlphaPixelChannel]); break; } case GRAYColorspace: { (void) FormatLocaleFile(stderr," gray: %g\n", channel_distortion[GrayPixelChannel]); if (image->alpha_trait == BlendPixelTrait) (void) FormatLocaleFile(stderr," alpha: %g\n", channel_distortion[AlphaPixelChannel]); break; } } (void) FormatLocaleFile(stderr," all: %g\n", channel_distortion[MaxPixelChannels]); break; } case MeanErrorPerPixelMetric: { (void) FormatLocaleFile(stderr," %g (%g, %g)\n", channel_distortion[MaxPixelChannels], image->error.normalized_mean_error, image->error.normalized_maximum_error); break; } case UndefinedErrorMetric: break; } channel_distortion=(double *) RelinquishMagickMemory( channel_distortion); } status&=WriteImages(image_info,difference_image,argv[argc-1],exception); if ((metadata != (char **) NULL) && (format != (char *) NULL)) { char *text; text=InterpretImageProperties(image_info,difference_image,format, exception); if (text == (char *) NULL) ThrowCompareException(ResourceLimitError,"MemoryAllocationFailed", GetExceptionMessage(errno)); (void) ConcatenateString(&(*metadata),text); text=DestroyString(text); } difference_image=DestroyImageList(difference_image); } DestroyCompare(); if ((metric == NormalizedCrossCorrelationErrorMetric) || (metric == UndefinedErrorMetric)) { if (fabs(distortion-1.0) > CompareEpsilon) return(MagickTrue); } else if (fabs(distortion) > CompareEpsilon) return(MagickTrue); return(status != 0 ? MagickTrue : MagickFalse); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % W r i t e I N L I N E I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % WriteINLINEImage() writes an image to a file in INLINE format (Base64). % % The format of the WriteINLINEImage method is: % % MagickBooleanType WriteINLINEImage(const ImageInfo *image_info, % Image *image,ExceptionInfo *exception) % % A description of each parameter follows. % % o image_info: the image info. % % o image: The image. % % o exception: return any errors or warnings in this structure. % */ static MagickBooleanType WriteINLINEImage(const ImageInfo *image_info, Image *image,ExceptionInfo *exception) { char *base64, message[MagickPathExtent]; const MagickInfo *magick_info; Image *write_image; ImageInfo *write_info; MagickBooleanType status; size_t blob_length, encode_length; unsigned char *blob; /* Convert image to base64-encoding. */ assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickCoreSignature); assert(image != (Image *) NULL); assert(image->signature == MagickCoreSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); write_info=CloneImageInfo(image_info); (void) SetImageInfo(write_info,1,exception); if (LocaleCompare(write_info->magick,"INLINE") == 0) (void) CopyMagickString(write_info->magick,image->magick,MagickPathExtent); magick_info=GetMagickInfo(write_info->magick,exception); if ((magick_info == (const MagickInfo *) NULL) || (GetMagickMimeType(magick_info) == (const char *) NULL)) ThrowWriterException(CorruptImageError,"ImageTypeNotSupported"); (void) CopyMagickString(image->filename,write_info->filename,MagickPathExtent); blob_length=2048; write_image=CloneImage(image,0,0,MagickTrue,exception); if (write_image == (Image *) NULL) { write_info=DestroyImageInfo(write_info); return(MagickTrue); } blob=(unsigned char *) ImageToBlob(write_info,write_image,&blob_length, exception); write_image=DestroyImage(write_image); write_info=DestroyImageInfo(write_info); if (blob == (unsigned char *) NULL) return(MagickFalse); encode_length=0; base64=Base64Encode(blob,blob_length,&encode_length); blob=(unsigned char *) RelinquishMagickMemory(blob); if (base64 == (char *) NULL) ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); /* Write base64-encoded image. */ status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); if (status == MagickFalse) { base64=DestroyString(base64); return(status); } (void) FormatLocaleString(message,MagickPathExtent,"data:%s;base64,", GetMagickMimeType(magick_info)); (void) WriteBlobString(image,message); (void) WriteBlobString(image,base64); base64=DestroyString(base64); return(MagickTrue); }
static MagickBooleanType ReadOneLayer(Image* image,XCFDocInfo* inDocInfo, XCFLayerInfo *outLayer, ExceptionInfo *exception ) { MagickOffsetType offset; unsigned int foundPropEnd = 0; size_t hierarchy_offset, layer_mask_offset; /* clear the block! */ (void) ResetMagickMemory( outLayer, 0, sizeof( XCFLayerInfo ) ); /* read in the layer width, height, type and name */ outLayer->width = ReadBlobMSBLong(image); outLayer->height = ReadBlobMSBLong(image); outLayer->type = ReadBlobMSBLong(image); (void) ReadBlobStringWithLongSize(image, outLayer->name, sizeof(outLayer->name),exception); /* allocate the image for this layer */ outLayer->image=CloneImage(image,outLayer->width, outLayer->height,MagickTrue, exception); if (outLayer->image == (Image *) NULL) return MagickFalse; /* read the layer properties! */ foundPropEnd = 0; while ( (foundPropEnd == MagickFalse) && (EOFBlob(image) == MagickFalse) ) { PropType prop_type = (PropType) ReadBlobMSBLong(image); size_t prop_size = ReadBlobMSBLong(image); switch (prop_type) { case PROP_END: foundPropEnd = 1; break; case PROP_ACTIVE_LAYER: outLayer->active = 1; break; case PROP_FLOATING_SELECTION: outLayer->floating_offset = ReadBlobMSBLong(image); break; case PROP_OPACITY: outLayer->opacity = ReadBlobMSBLong(image); break; case PROP_VISIBLE: outLayer->visible = ReadBlobMSBLong(image); break; case PROP_LINKED: outLayer->linked = ReadBlobMSBLong(image); break; case PROP_PRESERVE_TRANSPARENCY: outLayer->preserve_trans = ReadBlobMSBLong(image); break; case PROP_APPLY_MASK: outLayer->apply_mask = ReadBlobMSBLong(image); break; case PROP_EDIT_MASK: outLayer->edit_mask = ReadBlobMSBLong(image); break; case PROP_SHOW_MASK: outLayer->show_mask = ReadBlobMSBLong(image); break; case PROP_OFFSETS: outLayer->offset_x = (int) ReadBlobMSBLong(image); outLayer->offset_y = (int) ReadBlobMSBLong(image); break; case PROP_MODE: outLayer->mode = ReadBlobMSBLong(image); break; case PROP_TATTOO: outLayer->preserve_trans = ReadBlobMSBLong(image); break; case PROP_PARASITES: { if (DiscardBlobBytes(image,prop_size) == MagickFalse) ThrowFileException(exception,CorruptImageError, "UnexpectedEndOfFile",image->filename); /* ssize_t base = info->cp; GimpParasite *p; while (info->cp - base < prop_size) { p = xcf_load_parasite(info); gimp_drawable_parasite_attach(GIMP_DRAWABLE(layer), p); gimp_parasite_free(p); } if (info->cp - base != prop_size) g_message ("Error detected while loading a layer's parasites"); */ } break; default: /* g_message ("unexpected/unknown layer property: %d (skipping)", prop_type); */ { int buf[16]; ssize_t amount; /* read over it... */ while ((prop_size > 0) && (EOFBlob(image) == MagickFalse)) { amount = (ssize_t) MagickMin(16, prop_size); amount = ReadBlob(image, (size_t) amount, (unsigned char *) &buf); if (!amount) ThrowBinaryException(CorruptImageError,"CorruptImage", image->filename); prop_size -= (size_t) MagickMin(16, (size_t) amount); } } break; } } if (foundPropEnd == MagickFalse) return(MagickFalse); /* clear the image based on the layer opacity */ outLayer->image->background_color.opacity= ScaleCharToQuantum((unsigned char) (255-outLayer->opacity)); (void) SetImageBackgroundColor(outLayer->image); /* set the compositing mode */ outLayer->image->compose = GIMPBlendModeToCompositeOperator( outLayer->mode ); if ( outLayer->visible == MagickFalse ) { /* BOGUS: should really be separate member var! */ outLayer->image->compose = NoCompositeOp; } /* read the hierarchy and layer mask offsets */ hierarchy_offset = ReadBlobMSBLong(image); layer_mask_offset = ReadBlobMSBLong(image); /* read in the hierarchy */ offset=SeekBlob(image, (MagickOffsetType) hierarchy_offset, SEEK_SET); if (offset < 0) (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError, "InvalidImageHeader","`%s'",image->filename); if (load_hierarchy (image, inDocInfo, outLayer) == 0) return(MagickFalse); /* read in the layer mask */ if (layer_mask_offset != 0) { offset=SeekBlob(image, (MagickOffsetType) layer_mask_offset, SEEK_SET); #if 0 /* BOGUS: support layer masks! */ layer_mask = xcf_load_layer_mask (info, gimage); if (layer_mask == 0) goto error; /* set the offsets of the layer_mask */ GIMP_DRAWABLE (layer_mask)->offset_x = GIMP_DRAWABLE (layer)->offset_x; GIMP_DRAWABLE (layer_mask)->offset_y = GIMP_DRAWABLE (layer)->offset_y; gimp_layer_add_mask (layer, layer_mask, MagickFalse); layer->mask->apply_mask = apply_mask; layer->mask->edit_mask = edit_mask; layer->mask->show_mask = show_mask; #endif } /* attach the floating selection... */ #if 0 /* BOGUS: we may need to read this, even if we don't support it! */ if (add_floating_sel) { GimpLayer *floating_sel; floating_sel = info->floating_sel; floating_sel_attach (floating_sel, GIMP_DRAWABLE (layer)); } #endif return MagickTrue; }
MagickExport Image *MontageImageList(const ImageInfo *image_info, const MontageInfo *montage_info,const Image *images,ExceptionInfo *exception) { #define MontageImageTag "Montage/Image" #define TileImageTag "Tile/Image" char tile_geometry[MaxTextExtent], *title; const char *value; DrawInfo *draw_info; FrameInfo frame_info; Image *image, **image_list, **master_list, *montage, *texture, *tile_image, *thumbnail; ImageInfo *clone_info; long tile, x, x_offset, y, y_offset; MagickBooleanType concatenate, proceed, status; MagickOffsetType tiles; MagickStatusType flags; MagickProgressMonitor progress_monitor; register long i; RectangleInfo bounds, geometry, extract_info; size_t extent; TypeMetric metrics; unsigned long bevel_width, border_width, height, images_per_page, max_height, number_images, number_lines, sans, tiles_per_column, tiles_per_page, tiles_per_row, title_offset, total_tiles, width; /* Create image tiles. */ assert(images != (Image *) NULL); assert(images->signature == MagickSignature); if (images->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); assert(montage_info != (MontageInfo *) NULL); assert(montage_info->signature == MagickSignature); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); number_images=GetImageListLength(images); master_list=ImageListToArray(images,exception); image_list=master_list; image=image_list[0]; if (master_list == (Image **) NULL) ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); thumbnail=NewImageList(); for (i=0; i < (long) number_images; i++) { image=CloneImage(image_list[i],0,0,MagickTrue,exception); if (image == (Image *) NULL) break; (void) ParseAbsoluteGeometry("0x0+0+0",&image->page); progress_monitor=SetImageProgressMonitor(image,(MagickProgressMonitor) NULL, image->client_data); flags=ParseRegionGeometry(image,montage_info->geometry,&geometry,exception); thumbnail=ThumbnailImage(image,geometry.width,geometry.height,exception); if (thumbnail == (Image *) NULL) break; image_list[i]=thumbnail; (void) SetImageProgressMonitor(image,progress_monitor,image->client_data); proceed=SetImageProgress(image,TileImageTag,i,number_images); if (proceed == MagickFalse) break; image=DestroyImage(image); } if (i < (long) number_images) { if (thumbnail == (Image *) NULL) i--; for (tile=0; (long) tile <= i; tile++) if (image_list[tile] != (Image *) NULL) image_list[tile]=DestroyImage(image_list[tile]); master_list=(Image **) RelinquishMagickMemory(master_list); return((Image *) NULL); } /* Sort image list by increasing tile number. */ for (i=0; i < (long) number_images; i++) if (image_list[i]->scene == 0) break; if (i == (long) number_images) qsort((void *) image_list,(size_t) number_images,sizeof(*image_list), SceneCompare); /* Determine tiles per row and column. */ tiles_per_column=(unsigned long) sqrt((double) number_images); tiles_per_row=(unsigned long) ceil((double) number_images/tiles_per_column); x_offset=0; y_offset=0; if (montage_info->tile != (char *) NULL) GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset, &tiles_per_column,&tiles_per_row); /* Determine tile sizes. */ concatenate=MagickFalse; SetGeometry(image_list[0],&extract_info); extract_info.x=(long) montage_info->border_width; extract_info.y=(long) montage_info->border_width; if (montage_info->geometry != (char *) NULL) { /* Initialize tile geometry. */ flags=GetGeometry(montage_info->geometry,&extract_info.x,&extract_info.y, &extract_info.width,&extract_info.height); if ((extract_info.x == 0) && (extract_info.y == 0)) concatenate=((flags & RhoValue) == 0) && ((flags & SigmaValue) == 0) ? MagickTrue : MagickFalse; } border_width=montage_info->border_width; bevel_width=0; if (montage_info->frame != (char *) NULL) { char absolute_geometry[MaxTextExtent]; (void) ResetMagickMemory(&frame_info,0,sizeof(frame_info)); frame_info.width=extract_info.width; frame_info.height=extract_info.height; (void) FormatMagickString(absolute_geometry,MaxTextExtent,"%s!", montage_info->frame); flags=ParseMetaGeometry(absolute_geometry,&frame_info.outer_bevel, &frame_info.inner_bevel,&frame_info.width,&frame_info.height); if ((flags & HeightValue) == 0) frame_info.height=frame_info.width; if ((flags & XiValue) == 0) frame_info.outer_bevel=(long) frame_info.width/2; if ((flags & PsiValue) == 0) frame_info.inner_bevel=frame_info.outer_bevel; frame_info.x=(long) frame_info.width; frame_info.y=(long) frame_info.height; bevel_width=(unsigned long) MagickMax(frame_info.inner_bevel, frame_info.outer_bevel); border_width=(unsigned long) MagickMax((long) frame_info.width, (long) frame_info.height); } for (i=0; i < (long) number_images; i++) { if (image_list[i]->columns > extract_info.width) extract_info.width=image_list[i]->columns; if (image_list[i]->rows > extract_info.height) extract_info.height=image_list[i]->rows; } /* Initialize draw attributes. */ clone_info=CloneImageInfo(image_info); clone_info->background_color=montage_info->background_color; clone_info->border_color=montage_info->border_color; draw_info=CloneDrawInfo(clone_info,(DrawInfo *) NULL); if (montage_info->font != (char *) NULL) (void) CloneString(&draw_info->font,montage_info->font); if (montage_info->pointsize != 0.0) draw_info->pointsize=montage_info->pointsize; draw_info->gravity=CenterGravity; draw_info->stroke=montage_info->stroke; draw_info->fill=montage_info->fill; draw_info->text=AcquireString(""); (void) GetTypeMetrics(image_list[0],draw_info,&metrics); texture=NewImageList(); if (montage_info->texture != (char *) NULL) { (void) CopyMagickString(clone_info->filename,montage_info->texture, MaxTextExtent); texture=ReadImage(clone_info,exception); } /* Determine the number of lines in an next label. */ title=InterpretImageProperties(clone_info,image_list[0],montage_info->title); title_offset=0; if (montage_info->title != (char *) NULL) title_offset=(unsigned long) (2*(metrics.ascent-metrics.descent)* MultilineCensus(title)+2*extract_info.y); number_lines=0; for (i=0; i < (long) number_images; i++) { value=GetImageProperty(image_list[i],"label"); if (value == (const char *) NULL) continue; if (MultilineCensus(value) > number_lines) number_lines=MultilineCensus(value); } /* Allocate next structure. */ tile_image=AcquireImage(NULL); montage=AcquireImage(clone_info); montage->scene=0; images_per_page=(number_images-1)/(tiles_per_row*tiles_per_column)+1; tiles=0; total_tiles=(unsigned long) number_images; for (i=0; i < (long) images_per_page; i++) { /* Determine bounding box. */ tiles_per_page=tiles_per_row*tiles_per_column; x_offset=0; y_offset=0; if (montage_info->tile != (char *) NULL) GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset, &sans,&sans); tiles_per_page=tiles_per_row*tiles_per_column; y_offset+=(long) title_offset; max_height=0; bounds.width=0; bounds.height=0; width=0; for (tile=0; tile < (long) tiles_per_page; tile++) { if (tile < (long) number_images) { width=concatenate != MagickFalse ? image_list[tile]->columns : extract_info.width; if (image_list[tile]->rows > max_height) max_height=image_list[tile]->rows; } x_offset+=width+(extract_info.x+border_width)*2; if (x_offset > (long) bounds.width) bounds.width=(unsigned long) x_offset; if (((tile+1) == (long) tiles_per_page) || (((tile+1) % tiles_per_row) == 0)) { x_offset=0; if (montage_info->tile != (char *) NULL) GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y, &sans,&sans); height=concatenate != MagickFalse ? max_height : extract_info.height; y_offset+=(unsigned long) (height+(extract_info.y+border_width)*2+ (metrics.ascent-metrics.descent+4)*number_lines+ (montage_info->shadow != MagickFalse ? 4 : 0)); if (y_offset > (long) bounds.height) bounds.height=(unsigned long) y_offset; max_height=0; } } if (montage_info->shadow != MagickFalse) bounds.width+=4; /* Initialize montage image. */ (void) CopyMagickString(montage->filename,montage_info->filename, MaxTextExtent); montage->columns=bounds.width; montage->rows=bounds.height; (void) SetImageBackgroundColor(montage); /* Set montage geometry. */ montage->montage=AcquireString((char *) NULL); tile=0; extent=1; while (tile < MagickMin((long) tiles_per_page,(long) number_images)) { extent+=strlen(image_list[tile]->filename)+1; tile++; } montage->directory=(char *) AcquireQuantumMemory(extent, sizeof(*montage->directory)); if ((montage->montage == (char *) NULL) || (montage->directory == (char *) NULL)) ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); x_offset=0; y_offset=0; if (montage_info->tile != (char *) NULL) GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset, &sans,&sans); y_offset+=(long) title_offset; (void) FormatMagickString(montage->montage,MaxTextExtent,"%ldx%ld%+ld%+ld", (long) (extract_info.width+(extract_info.x+border_width)*2), (long) (extract_info.height+(extract_info.y+border_width)*2+ (metrics.ascent-metrics.descent+4)*number_lines+ (montage_info->shadow != MagickFalse ? 4 : 0)),x_offset,y_offset); *montage->directory='\0'; tile=0; while (tile < MagickMin((long) tiles_per_page,(long) number_images)) { (void) ConcatenateMagickString(montage->directory, image_list[tile]->filename,extent); (void) ConcatenateMagickString(montage->directory,"\n",extent); tile++; } progress_monitor=SetImageProgressMonitor(montage,(MagickProgressMonitor) NULL,montage->client_data); if (texture != (Image *) NULL) (void) TextureImage(montage,texture); if (montage_info->title != (char *) NULL) { char geometry[MaxTextExtent]; DrawInfo *clone_info; TypeMetric metrics; /* Annotate composite image with title. */ clone_info=CloneDrawInfo(image_info,draw_info); clone_info->gravity=CenterGravity; clone_info->pointsize*=2.0; (void) GetTypeMetrics(image_list[0],clone_info,&metrics); (void) FormatMagickString(geometry,MaxTextExtent,"%lux%lu%+ld%+ld", montage->columns,(unsigned long) (metrics.ascent-metrics.descent), 0L,(long) extract_info.y+4); (void) CloneString(&clone_info->geometry,geometry); (void) CloneString(&clone_info->text,title); (void) AnnotateImage(montage,clone_info); clone_info=DestroyDrawInfo(clone_info); } (void) SetImageProgressMonitor(montage,progress_monitor, montage->client_data); /* Copy tile to the composite. */ x_offset=0; y_offset=0; if (montage_info->tile != (char *) NULL) GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset, &sans,&sans); x_offset+=extract_info.x; y_offset+=(long) title_offset+extract_info.y; max_height=0; for (tile=0; tile < MagickMin((long) tiles_per_page,(long) number_images); tile++) { /* Copy this tile to the composite. */ image=CloneImage(image_list[tile],0,0,MagickTrue,exception); progress_monitor=SetImageProgressMonitor(image, (MagickProgressMonitor) NULL,image->client_data); width=concatenate != MagickFalse ? image->columns : extract_info.width; if (image->rows > max_height) max_height=image->rows; height=concatenate != MagickFalse ? max_height : extract_info.height; if (border_width != 0) { Image *border_image; RectangleInfo border_info; /* Put a border around the image. */ border_info.width=border_width; border_info.height=border_width; if (montage_info->frame != (char *) NULL) { border_info.width=(width-image->columns+1)/2; border_info.height=(height-image->rows+1)/2; } border_image=BorderImage(image,&border_info,exception); if (border_image != (Image *) NULL) { image=DestroyImage(image); image=border_image; } if ((montage_info->frame != (char *) NULL) && (image->compose == DstOutCompositeOp)) (void) NegateImageChannel(image,OpacityChannel,MagickFalse); } /* Gravitate as specified by the tile gravity. */ tile_image->columns=width; tile_image->rows=height; tile_image->gravity=montage_info->gravity; if (image->gravity != UndefinedGravity) tile_image->gravity=image->gravity; (void) FormatMagickString(tile_geometry,MaxTextExtent,"%lux%lu+0+0", image->columns,image->rows); flags=ParseGravityGeometry(tile_image,tile_geometry,&geometry,exception); x=(long) (geometry.x+border_width); y=(long) (geometry.y+border_width); if ((montage_info->frame != (char *) NULL) && (bevel_width != 0)) { FrameInfo extract_info; Image *frame_image; /* Put an ornamental border around this tile. */ extract_info=frame_info; extract_info.width=width+2*frame_info.width; extract_info.height=height+2*frame_info.height; value=GetImageProperty(image,"label"); if (value != (const char *) NULL) extract_info.height+=(unsigned long) ((metrics.ascent- metrics.descent+4)*MultilineCensus(value)); frame_image=FrameImage(image,&extract_info,exception); if (frame_image != (Image *) NULL) { image=DestroyImage(image); image=frame_image; } x=0; y=0; } if (LocaleCompare(image->magick,"NULL") != 0) { /* Composite background with tile. */ if (montage_info->shadow != MagickFalse) { Image *shadow_image; /* Shadow image. */ (void) QueryColorDatabase("#000000",&image->background_color, exception); shadow_image=ShadowImage(image,80.0,2.0,5,5,exception); if (shadow_image != (Image *) NULL) { InheritException(&shadow_image->exception,exception); (void) CompositeImage(shadow_image,OverCompositeOp,image,0,0); image=DestroyImage(image); image=shadow_image; } } (void) CompositeImage(montage,OverCompositeOp,image,x_offset+x, y_offset+y); value=GetImageProperty(image,"label"); if (value != (const char *) NULL) { char geometry[MaxTextExtent]; /* Annotate composite tile with label. */ (void) FormatMagickString(geometry,MaxTextExtent, "%lux%lu%+ld%+ld",(montage_info->frame ? image->columns : width)-2*border_width,(unsigned long) (metrics.ascent- metrics.descent+4)*MultilineCensus(value),x_offset+ border_width,(montage_info->frame ? y_offset+height+ border_width+4 : y_offset+extract_info.height+border_width+ (montage_info->shadow != MagickFalse ? 4 : 0))); (void) CloneString(&draw_info->geometry,geometry); (void) CloneString(&draw_info->text,value); (void) AnnotateImage(montage,draw_info); } } x_offset+=width+(extract_info.x+border_width)*2; if (((tile+1) == (long) tiles_per_page) || (((tile+1) % tiles_per_row) == 0)) { x_offset=extract_info.x; y_offset+=(unsigned long) (height+(extract_info.y+border_width)*2+ (metrics.ascent-metrics.descent+4)*number_lines+ (montage_info->shadow != MagickFalse ? 4 : 0)); max_height=0; } if ((images->progress_monitor != (MagickProgressMonitor) NULL) && (QuantumTick(tiles,total_tiles) != MagickFalse)) { status=images->progress_monitor(MontageImageTag,tiles,total_tiles, images->client_data); if (status == MagickFalse) break; } image_list[tile]=DestroyImage(image_list[tile]); image=DestroyImage(image); tiles++; } if ((i+1) < (long) images_per_page) { /* Allocate next image structure. */ AcquireNextImage(clone_info,montage); if (GetNextImageInList(montage) == (Image *) NULL) { montage=DestroyImageList(montage); return((Image *) NULL); } montage=GetNextImageInList(montage); image_list+=tiles_per_page; number_images-=tiles_per_page; } } tile_image=DestroyImage(tile_image); if (texture != (Image *) NULL) texture=DestroyImage(texture); master_list=(Image **) RelinquishMagickMemory(master_list); draw_info=DestroyDrawInfo(draw_info); clone_info=DestroyImageInfo(clone_info); while (GetPreviousImageInList(montage) != (Image *) NULL) montage=GetPreviousImageInList(montage); return(montage); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % C o m b i n e I m a g e s % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % CombineImages() combines one or more images into a single image. The % grayscale value of the pixels of each image in the sequence is assigned in % order to the specified channels of the combined image. The typical % ordering would be image 1 => Red, 2 => Green, 3 => Blue, etc. % % The format of the CombineImages method is: % % Image *CombineImages(const Image *images,const ColorspaceType colorspace, % ExceptionInfo *exception) % % A description of each parameter follows: % % o images: the image sequence. % % o colorspace: the image colorspace. % % o exception: return any errors or warnings in this structure. % */ MagickExport Image *CombineImages(const Image *image, const ColorspaceType colorspace,ExceptionInfo *exception) { #define CombineImageTag "Combine/Image" CacheView *combine_view; Image *combine_image; MagickBooleanType status; MagickOffsetType progress; ssize_t y; /* Ensure the image are the same size. */ assert(image != (const Image *) NULL); assert(image->signature == MagickCoreSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickCoreSignature); combine_image=CloneImage(image,0,0,MagickTrue,exception); if (combine_image == (Image *) NULL) return((Image *) NULL); if (SetImageStorageClass(combine_image,DirectClass,exception) == MagickFalse) { combine_image=DestroyImage(combine_image); return((Image *) NULL); } if ((colorspace == UndefinedColorspace) || (image->number_channels == 1)) (void) SetImageColorspace(combine_image,sRGBColorspace,exception); else (void) SetImageColorspace(combine_image,colorspace,exception); if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) combine_image->alpha_trait=BlendPixelTrait; /* Combine images. */ status=MagickTrue; progress=0; combine_view=AcquireAuthenticCacheView(combine_image,exception); for (y=0; y < (ssize_t) combine_image->rows; y++) { CacheView *image_view; const Image *next; Quantum *pixels; register const Quantum *magick_restrict p; register Quantum *magick_restrict q; register ssize_t i; if (status == MagickFalse) continue; pixels=GetCacheViewAuthenticPixels(combine_view,0,y,combine_image->columns, 1,exception); if (pixels == (Quantum *) NULL) { status=MagickFalse; continue; } next=image; for (i=0; i < (ssize_t) GetPixelChannels(combine_image); i++) { register ssize_t x; PixelChannel channel=GetPixelChannelChannel(combine_image,i); PixelTrait traits=GetPixelChannelTraits(combine_image,channel); if (traits == UndefinedPixelTrait) continue; if (next == (Image *) NULL) continue; image_view=AcquireVirtualCacheView(next,exception); p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception); if (p == (const Quantum *) NULL) continue; q=pixels; for (x=0; x < (ssize_t) combine_image->columns; x++) { if (x < (ssize_t) next->columns) { q[i]=GetPixelGray(next,p); p+=GetPixelChannels(next); } q+=GetPixelChannels(combine_image); } image_view=DestroyCacheView(image_view); next=GetNextImageInList(next); } if (SyncCacheViewAuthenticPixels(combine_view,exception) == MagickFalse) status=MagickFalse; if (image->progress_monitor != (MagickProgressMonitor) NULL) { MagickBooleanType proceed; proceed=SetImageProgress(image,CombineImageTag,progress++, combine_image->rows); if (proceed == MagickFalse) status=MagickFalse; } } combine_view=DestroyCacheView(combine_view); if (status == MagickFalse) combine_image=DestroyImage(combine_image); return(combine_image); }
static MagickBooleanType WritePS3MaskImage(const ImageInfo *image_info, Image *image,const CompressionType compression) { char buffer[MaxTextExtent]; Image *mask_image; MagickBooleanType status; MagickOffsetType offset, start, stop; register long i; size_t length; unsigned char *pixels; assert(image_info != (ImageInfo *) NULL); assert(image_info->signature == MagickSignature); assert(image != (Image *) NULL); assert(image->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); assert(image->matte != MagickFalse); status=MagickTrue; /* Note BeginData DSC comment for update later. */ start=TellBlob(image); (void) FormatMagickString(buffer,MaxTextExtent, "%%%%BeginData:%13ld %s Bytes\n",0L, compression == NoCompression ? "ASCII" : "BINARY"); (void) WriteBlobString(image,buffer); stop=TellBlob(image); /* Only lossless compressions for the mask. */ switch (compression) { case NoCompression: default: { (void) FormatMagickString(buffer,MaxTextExtent, "currentfile %lu %lu "PS3_NoCompression" ByteStreamDecodeFilter\n", image->columns,image->rows); break; } case FaxCompression: case Group4Compression: { (void) FormatMagickString(buffer,MaxTextExtent, "currentfile %lu %lu "PS3_FaxCompression" ByteStreamDecodeFilter\n", image->columns,image->rows); break; } case LZWCompression: { (void) FormatMagickString(buffer,MaxTextExtent, "currentfile %lu %lu "PS3_LZWCompression" ByteStreamDecodeFilter\n", image->columns,image->rows); break; } case RLECompression: { (void) FormatMagickString(buffer,MaxTextExtent, "currentfile %lu %lu "PS3_RLECompression" ByteStreamDecodeFilter\n", image->columns,image->rows); break; } case ZipCompression: { (void) FormatMagickString(buffer,MaxTextExtent, "currentfile %lu %lu "PS3_ZipCompression" ByteStreamDecodeFilter\n", image->columns,image->rows); break; } } (void) WriteBlobString(image,buffer); (void) WriteBlobString(image,"/ReusableStreamDecode filter\n"); mask_image=CloneImage(image,0,0,MagickTrue,&image->exception); if (mask_image == (Image *) NULL) ThrowWriterException(CoderError,image->exception.reason); status=SeparateImageChannel(mask_image,OpacityChannel); if (status == MagickFalse) { mask_image=DestroyImage(mask_image); return(MagickFalse); } (void) SetImageType(mask_image,BilevelType); (void) SetImageType(mask_image,PaletteType); mask_image->matte=MagickFalse; pixels=(unsigned char *) NULL; length=0; switch (compression) { case NoCompression: default: { status=SerializeImageChannel(image_info,mask_image,&pixels,&length); if (status == MagickFalse) break; Ascii85Initialize(image); for (i=0; i < (long) length; i++) Ascii85Encode(image,pixels[i]); Ascii85Flush(image); pixels=(unsigned char *) RelinquishMagickMemory(pixels); break; } case FaxCompression: case Group4Compression: { if ((compression == FaxCompression) || (LocaleCompare(CCITTParam,"0") == 0)) status=HuffmanEncodeImage(image_info,image,mask_image); else status=Huffman2DEncodeImage(image_info,image,mask_image); break; } case LZWCompression: { status=SerializeImageChannel(image_info,mask_image,&pixels,&length); if (status == MagickFalse) break; status=LZWEncodeImage(image,length,pixels); pixels=(unsigned char *) RelinquishMagickMemory(pixels); break; } case RLECompression: { status=SerializeImageChannel(image_info,mask_image,&pixels,&length); if (status == MagickFalse) break; status=PackbitsEncodeImage(image,length,pixels); pixels=(unsigned char *) RelinquishMagickMemory(pixels); break; } case ZipCompression: { status=SerializeImageChannel(image_info,mask_image,&pixels,&length); if (status == MagickFalse) break; status=ZLIBEncodeImage(image,length,pixels); pixels=(unsigned char *) RelinquishMagickMemory(pixels); break; } } mask_image=DestroyImage(mask_image); (void) WriteBlobByte(image,'\n'); length=(size_t) (TellBlob(image)-stop); stop=TellBlob(image); offset=SeekBlob(image,start,SEEK_SET); if (offset < 0) ThrowWriterException(CorruptImageError,"ImproperImageHeader"); (void) FormatMagickString(buffer,MaxTextExtent, "%%%%BeginData:%13ld %s Bytes\n",(long) length, compression == NoCompression ? "ASCII" : "BINARY"); (void) WriteBlobString(image,buffer); offset=SeekBlob(image,stop,SEEK_SET); if (offset < 0) ThrowWriterException(CorruptImageError,"ImproperImageHeader"); (void) WriteBlobString(image,"%%EndData\n"); (void) WriteBlobString(image, "/mask_stream exch def\n"); return(status); }
static MagickBooleanType WriteMPEGImage(const ImageInfo *image_info, Image *image) { #define WriteMPEGIntermediateFormat "jpg" char basename[MaxTextExtent], filename[MaxTextExtent]; double delay; Image *coalesce_image; ImageInfo *write_info; int file; MagickBooleanType status; register Image *p; register ssize_t i; size_t count, length, scene; unsigned char *blob; /* Open output image file. */ assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickSignature); assert(image != (Image *) NULL); assert(image->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); if (status == MagickFalse) return(status); (void) CloseBlob(image); /* Write intermediate files. */ coalesce_image=CoalesceImages(image,&image->exception); if (coalesce_image == (Image *) NULL) return(MagickFalse); file=AcquireUniqueFileResource(basename); if (file != -1) file=close(file)-1; (void) FormatLocaleString(coalesce_image->filename,MaxTextExtent,"%s", basename); count=0; write_info=CloneImageInfo(image_info); *write_info->magick='\0'; for (p=coalesce_image; p != (Image *) NULL; p=GetNextImageInList(p)) { char previous_image[MaxTextExtent]; blob=(unsigned char *) NULL; length=0; scene=p->scene; delay=100.0*p->delay/MagickMax(1.0*p->ticks_per_second,1.0); for (i=0; i < (ssize_t) MagickMax((1.0*delay+1.0)/3.0,1.0); i++) { p->scene=count; count++; status=MagickFalse; switch (i) { case 0: { Image *frame; (void) FormatLocaleString(p->filename,MaxTextExtent,"%s%.20g.%s", basename,(double) p->scene,WriteMPEGIntermediateFormat); (void) FormatLocaleString(filename,MaxTextExtent,"%s%.20g.%s", basename,(double) p->scene,WriteMPEGIntermediateFormat); (void) FormatLocaleString(previous_image,MaxTextExtent, "%s%.20g.%s",basename,(double) p->scene, WriteMPEGIntermediateFormat); frame=CloneImage(p,0,0,MagickTrue,&p->exception); if (frame == (Image *) NULL) break; status=WriteImage(write_info,frame); frame=DestroyImage(frame); break; } case 1: { blob=(unsigned char *) FileToBlob(previous_image,~0UL,&length, &image->exception); } default: { (void) FormatLocaleString(filename,MaxTextExtent,"%s%.20g.%s", basename,(double) p->scene,WriteMPEGIntermediateFormat); if (length > 0) status=BlobToFile(filename,blob,length,&image->exception); break; } } if (image->debug != MagickFalse) { if (status != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), "%.20g. Wrote %s file for scene %.20g:",(double) i, WriteMPEGIntermediateFormat,(double) p->scene); else (void) LogMagickEvent(CoderEvent,GetMagickModule(), "%.20g. Failed to write %s file for scene %.20g:",(double) i, WriteMPEGIntermediateFormat,(double) p->scene); (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s",filename); } } p->scene=scene; if (blob != (unsigned char *) NULL) blob=(unsigned char *) RelinquishMagickMemory(blob); if (status == MagickFalse) break; } /* Convert JPEG to MPEG. */ (void) CopyMagickString(coalesce_image->magick_filename,basename, MaxTextExtent); (void) CopyMagickString(coalesce_image->filename,basename,MaxTextExtent); GetPathComponent(image_info->filename,ExtensionPath,coalesce_image->magick); if (*coalesce_image->magick == '\0') (void) CopyMagickString(coalesce_image->magick,image->magick,MaxTextExtent); status=InvokeDelegate(write_info,coalesce_image,(char *) NULL,"mpeg:encode", &image->exception); (void) FormatLocaleString(write_info->filename,MaxTextExtent,"%s.%s", write_info->unique,coalesce_image->magick); status=CopyDelegateFile(write_info->filename,image->filename); (void) RelinquishUniqueFileResource(write_info->filename); write_info=DestroyImageInfo(write_info); /* Relinquish resources. */ count=0; for (p=coalesce_image; p != (Image *) NULL; p=GetNextImageInList(p)) { delay=100.0*p->delay/MagickMax(1.0*p->ticks_per_second,1.0); for (i=0; i < (ssize_t) MagickMax((1.0*delay+1.0)/3.0,1.0); i++) { (void) FormatLocaleString(p->filename,MaxTextExtent,"%s%.20g.%s", basename,(double) count++,WriteMPEGIntermediateFormat); (void) RelinquishUniqueFileResource(p->filename); } (void) CopyMagickString(p->filename,image_info->filename,MaxTextExtent); } (void) RelinquishUniqueFileResource(basename); coalesce_image=DestroyImageList(coalesce_image); if (image->debug != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit"); return(status); }
MagickExport Image *InverseFourierTransformImage(const Image *magnitude_image, const Image *phase_image,const MagickBooleanType modulus, ExceptionInfo *exception) { Image *fourier_image; assert(magnitude_image != (Image *) NULL); assert(magnitude_image->signature == MagickSignature); if (magnitude_image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", magnitude_image->filename); if (phase_image == (Image *) NULL) { (void) ThrowMagickException(exception,GetMagickModule(),ImageError, "ImageSequenceRequired","`%s'",magnitude_image->filename); return((Image *) NULL); } #if !defined(MAGICKCORE_FFTW_DELEGATE) fourier_image=(Image *) NULL; (void) modulus; (void) ThrowMagickException(exception,GetMagickModule(), MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (FFTW)", magnitude_image->filename); #else { fourier_image=CloneImage(magnitude_image,magnitude_image->columns, magnitude_image->rows,MagickFalse,exception); if (fourier_image != (Image *) NULL) { MagickBooleanType is_gray, status; register long i; status=MagickTrue; is_gray=IsGrayImage(magnitude_image,exception); if (is_gray != MagickFalse) is_gray=IsGrayImage(phase_image,exception); #if defined(MAGICKCORE_OPENMP_SUPPORT) #pragma omp parallel for schedule(dynamic,4) shared(status) #endif for (i=0L; i < 5L; i++) { MagickBooleanType thread_status; thread_status=MagickTrue; switch (i) { case 0: { if (is_gray != MagickFalse) { thread_status=InverseFourierTransformChannel(magnitude_image, phase_image,GrayChannels,modulus,fourier_image,exception); break; } thread_status=InverseFourierTransformChannel(magnitude_image, phase_image,RedChannel,modulus,fourier_image,exception); break; } case 1: { if (is_gray == MagickFalse) thread_status=InverseFourierTransformChannel(magnitude_image, phase_image,GreenChannel,modulus,fourier_image,exception); break; } case 2: { if (is_gray == MagickFalse) thread_status=InverseFourierTransformChannel(magnitude_image, phase_image,BlueChannel,modulus,fourier_image,exception); break; } case 3: { if (magnitude_image->matte != MagickFalse) thread_status=InverseFourierTransformChannel(magnitude_image, phase_image,OpacityChannel,modulus,fourier_image,exception); break; } case 4: { if (magnitude_image->colorspace == CMYKColorspace) thread_status=InverseFourierTransformChannel(magnitude_image, phase_image,IndexChannel,modulus,fourier_image,exception); break; } } if (thread_status == MagickFalse) status=thread_status; } if (status == MagickFalse) fourier_image=DestroyImage(fourier_image); } fftw_cleanup(); } #endif return(fourier_image); }
static MagickBooleanType WriteHISTOGRAMImage(const ImageInfo *image_info, Image *image) { #define HistogramDensity "256x200" ChannelType channel; char filename[MaxTextExtent]; ExceptionInfo *exception; FILE *file; Image *histogram_image; ImageInfo *write_info; int unique_file; long y; MagickBooleanType status; MagickPixelPacket *histogram; MagickRealType maximum, scale; RectangleInfo geometry; register const PixelPacket *p; register long x; register PixelPacket *q, *r; size_t length; /* Allocate histogram image. */ assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickSignature); assert(image != (Image *) NULL); assert(image->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", image_info->filename); SetGeometry(image,&geometry); if (image_info->density == (char *) NULL) (void) ParseAbsoluteGeometry(HistogramDensity,&geometry); else (void) ParseAbsoluteGeometry(image_info->density,&geometry); histogram_image=CloneImage(image,geometry.width,geometry.height,MagickTrue, &image->exception); if (histogram_image == (Image *) NULL) ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); (void) SetImageStorageClass(histogram_image,DirectClass); /* Allocate histogram count arrays. */ length=MagickMax((size_t) ScaleQuantumToChar((Quantum) QuantumRange)+1UL, histogram_image->columns); histogram=(MagickPixelPacket *) AcquireQuantumMemory(length, sizeof(*histogram)); if (histogram == (MagickPixelPacket *) NULL) { histogram_image=DestroyImage(histogram_image); ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); } /* Initialize histogram count arrays. */ channel=image_info->channel; (void) ResetMagickMemory(histogram,0,length*sizeof(*histogram)); for (y=0; y < (long) image->rows; y++) { p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception); if (p == (const PixelPacket *) NULL) break; for (x=0; x < (long) image->columns; x++) { if ((channel & RedChannel) != 0) histogram[ScaleQuantumToChar(p->red)].red++; if ((channel & GreenChannel) != 0) histogram[ScaleQuantumToChar(p->green)].green++; if ((channel & BlueChannel) != 0) histogram[ScaleQuantumToChar(p->blue)].blue++; p++; } } maximum=histogram[0].red; for (x=0; x < (long) histogram_image->columns; x++) { if (((channel & RedChannel) != 0) && (maximum < histogram[x].red)) maximum=histogram[x].red; if (((channel & GreenChannel) != 0) && (maximum < histogram[x].green)) maximum=histogram[x].green; if (((channel & BlueChannel) != 0) && (maximum < histogram[x].blue)) maximum=histogram[x].blue; } scale=(MagickRealType) histogram_image->rows/maximum; /* Initialize histogram image. */ exception=(&image->exception); (void) QueryColorDatabase("#000000",&histogram_image->background_color, &image->exception); (void) SetImageBackgroundColor(histogram_image); for (x=0; x < (long) histogram_image->columns; x++) { q=GetAuthenticPixels(histogram_image,x,0,1,histogram_image->rows,exception); if (q == (PixelPacket *) NULL) break; if ((channel & RedChannel) != 0) { y=(long) (histogram_image->rows-scale*histogram[x].red+0.5); r=q+y; for ( ; y < (long) histogram_image->rows; y++) { r->red=(Quantum) QuantumRange; r++; } } if ((channel & GreenChannel) != 0) { y=(long) (histogram_image->rows-scale*histogram[x].green+0.5); r=q+y; for ( ; y < (long) histogram_image->rows; y++) { r->green=(Quantum) QuantumRange; r++; } } if ((channel & BlueChannel) != 0) { y=(long) (histogram_image->rows-scale*histogram[x].blue+0.5); r=q+y; for ( ; y < (long) histogram_image->rows; y++) { r->blue=(Quantum) QuantumRange; r++; } } if (SyncAuthenticPixels(histogram_image,exception) == MagickFalse) break; status=SetImageProgress(image,SaveImageTag,y,histogram_image->rows); if (status == MagickFalse) break; } /* Relinquish resources. */ histogram=(MagickPixelPacket *) RelinquishMagickMemory(histogram); file=(FILE *) NULL; unique_file=AcquireUniqueFileResource(filename); if (unique_file != -1) file=fdopen(unique_file,"wb"); if ((unique_file != -1) && (file != (FILE *) NULL)) { char *property; /* Add a histogram as an image comment. */ (void) GetNumberColors(image,file,&image->exception); (void) fclose(file); property=FileToString(filename,~0UL,&image->exception); if (property != (char *) NULL) { (void) SetImageProperty(histogram_image,"comment",property); property=DestroyString(property); } } (void) RelinquishUniqueFileResource(filename); /* Write Histogram image. */ (void) CopyMagickString(histogram_image->filename,image_info->filename, MaxTextExtent); write_info=CloneImageInfo(image_info); (void) SetImageInfo(write_info,MagickTrue,&image->exception); if (LocaleCompare(write_info->magick,"HISTOGRAM") == 0) (void) FormatMagickString(histogram_image->filename,MaxTextExtent, "miff:%s",write_info->filename); status=WriteImage(write_info,histogram_image); histogram_image=DestroyImage(histogram_image); write_info=DestroyImageInfo(write_info); return(status); }
MagickExport Image *ForwardFourierTransformImage(const Image *image, const MagickBooleanType modulus,ExceptionInfo *exception) { Image *fourier_image; fourier_image=NewImageList(); #if !defined(MAGICKCORE_FFTW_DELEGATE) (void) modulus; (void) ThrowMagickException(exception,GetMagickModule(), MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (FFTW)", image->filename); #else { Image *magnitude_image; unsigned long extent, width; width=image->columns; if ((image->columns != image->rows) || ((image->columns % 2) != 0) || ((image->rows % 2) != 0)) { extent=image->columns < image->rows ? image->rows : image->columns; width=(extent & 0x01) == 1 ? extent+1UL : extent; } magnitude_image=CloneImage(image,width,width,MagickFalse,exception); if (magnitude_image != (Image *) NULL) { Image *phase_image; magnitude_image->storage_class=DirectClass; magnitude_image->depth=32UL; phase_image=CloneImage(image,width,width,MagickFalse,exception); if (phase_image == (Image *) NULL) magnitude_image=DestroyImage(magnitude_image); else { MagickBooleanType is_gray, status; register long i; phase_image->storage_class=DirectClass; phase_image->depth=32UL; AppendImageToList(&fourier_image,magnitude_image); AppendImageToList(&fourier_image,phase_image); status=MagickTrue; is_gray=IsGrayImage(image,exception); #if defined(MAGICKCORE_OPENMP_SUPPORT) #pragma omp parallel for schedule(dynamic,4) shared(status) #endif for (i=0L; i < 5L; i++) { MagickBooleanType thread_status; thread_status=MagickTrue; switch (i) { case 0: { if (is_gray != MagickFalse) { thread_status=ForwardFourierTransformChannel(image, GrayChannels,modulus,fourier_image,exception); break; } thread_status=ForwardFourierTransformChannel(image,RedChannel, modulus,fourier_image,exception); break; } case 1: { if (is_gray == MagickFalse) thread_status=ForwardFourierTransformChannel(image, GreenChannel,modulus,fourier_image,exception); break; } case 2: { if (is_gray == MagickFalse) thread_status=ForwardFourierTransformChannel(image, BlueChannel,modulus,fourier_image,exception); break; } case 4: { if (image->matte != MagickFalse) thread_status=ForwardFourierTransformChannel(image, OpacityChannel,modulus,fourier_image,exception); break; } case 5: { if (image->colorspace == CMYKColorspace) thread_status=ForwardFourierTransformChannel(image, IndexChannel,modulus,fourier_image,exception); break; } } if (thread_status == MagickFalse) status=thread_status; } if (status == MagickFalse) fourier_image=DestroyImageList(fourier_image); fftw_cleanup(); } } } #endif return(fourier_image); }
static MagickBooleanType WriteXTRNImage(const ImageInfo *image_info, Image *image) { Image * p; ImageInfo *clone_info; int scene; MagickBooleanType status; void *param1, *param2, *param3; param1 = param2 = param3 = (void *) NULL; if (LocaleCompare(image_info->magick,"XTRNFILE") == 0) { clone_info=CloneImageInfo(image_info); status=WriteImage(image_info,image); if (status == MagickFalse) CatchImageException(image); clone_info=DestroyImageInfo(clone_info); } else if (LocaleCompare(image_info->magick,"XTRNIMAGE") == 0) { Image **image_ptr; ImageInfo **image_info_ptr; clone_info=CloneImageInfo(image_info); if (clone_info->filename[0]) { (void) sscanf(clone_info->filename,"%lx,%lx",¶m1,¶m2); image_info_ptr=(ImageInfo **) param1; image_ptr=(Image **) param2; if ((image_info_ptr != (ImageInfo **) NULL) && (image_ptr != (Image **) NULL)) { *image_ptr=CloneImage(image,0,0,MagickFalse,&(image->exception)); *image_info_ptr=clone_info; } } } else if (LocaleCompare(image_info->magick,"XTRNBLOB") == 0) { char **blob_data; ExceptionInfo *exception; size_t *blob_length; char filename[MaxTextExtent]; clone_info=CloneImageInfo(image_info); if (clone_info->filename[0]) { (void) sscanf(clone_info->filename,"%lx,%lx,%s", ¶m1,¶m2,&filename); blob_data=(char **) param1; blob_length=(size_t *) param2; scene = 0; (void) CopyMagickString(clone_info->filename,filename,MaxTextExtent); for (p=image; p != (Image *) NULL; p=GetNextImageInList(p)) { (void) CopyMagickString(p->filename,filename,MaxTextExtent); p->scene=scene++; } SetImageInfo(clone_info,1,&image->exception); (void) CopyMagickString(image->magick,clone_info->magick, MaxTextExtent); exception=AcquireExceptionInfo(); if (*blob_length == 0) *blob_length=8192; *blob_data=(char *) ImageToBlob(clone_info,image,blob_length, exception); exception=DestroyExceptionInfo(exception); if (*blob_data == NULL) status=MagickFalse; if (status == MagickFalse) CatchImageException(image); } clone_info=DestroyImageInfo(clone_info); } else if (LocaleCompare(image_info->magick,"XTRNARRAY") == 0) { char filename[MaxTextExtent]; size_t blob_length; unsigned char *blob_data; clone_info=CloneImageInfo(image_info); if (*clone_info->filename != '\0') { (void) sscanf(clone_info->filename,"%lx,%s",¶m1,&filename); image->client_data=param1; scene=0; (void) CopyMagickString(clone_info->filename,filename,MaxTextExtent); for (p=image; p != (Image *) NULL; p=GetNextImageInList(p)) { (void) CopyMagickString(p->filename,filename,MaxTextExtent); p->scene=scene++; } SetImageInfo(clone_info,1,&image->exception); (void) CopyMagickString(image->magick,clone_info->magick, MaxTextExtent); blob_data=ImageToBlob(clone_info,image,&blob_length, &image->exception); if (blob_data == (unsigned char *) NULL) status=MagickFalse; else SafeArrayFifo(image,blob_data,blob_length); if (status == MagickFalse) CatchImageException(image); } clone_info=DestroyImageInfo(clone_info); } return(MagickTrue); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % S h e a r I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ShearImage() creates a new image that is a shear_image copy of an existing % one. Shearing slides one edge of an image along the X or Y axis, creating % a parallelogram. An X direction shear slides an edge along the X axis, % while a Y direction shear slides an edge along the Y axis. The amount of % the shear is controlled by a shear angle. For X direction shears, x_shear % is measured relative to the Y axis, and similarly, for Y direction shears % y_shear is measured relative to the X axis. Empty triangles left over from % shearing the image are filled with the background color defined by member % 'background_color' of the image.. ShearImage() allocates the memory % necessary for the new Image structure and returns a pointer to the new image. % % ShearImage() is based on the paper "A Fast Algorithm for General Raster % Rotatation" by Alan W. Paeth. % % The format of the ShearImage method is: % % Image *ShearImage(const Image *image,const double x_shear, % const double y_shear,ExceptionInfo *exception) % % A description of each parameter follows. % % o image: The image. % % o x_shear, y_shear: Specifies the number of degrees to shear the image. % % o exception: Return any errors or warnings in this structure. % % */ MagickExport Image *ShearImage(const Image *image,const double x_shear, const double y_shear,ExceptionInfo *exception) { Image *integral_image, *shear_image; long x_offset, y_offset; PointInfo shear; RectangleInfo border_info; unsigned long y_width; assert(image != (Image *) NULL); assert(image->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); if ((x_shear != 0.0) && (fmod(x_shear,90.0) == 0.0)) ThrowImageException(ImageError,"AngleIsDiscontinuous"); if ((y_shear != 0.0) && (fmod(y_shear,90.0) == 0.0)) ThrowImageException(ImageError,"AngleIsDiscontinuous"); /* Initialize shear angle. */ integral_image=CloneImage(image,0,0,MagickTrue,exception); if (integral_image == (Image *) NULL) ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); shear.x=(-tan(DegreesToRadians(x_shear))); shear.y=tan(DegreesToRadians(y_shear)); if ((shear.x == 0.0) && (shear.y == 0.0)) return(integral_image); integral_image->storage_class=DirectClass; if (integral_image->matte == MagickFalse) SetImageOpacity(integral_image,OpaqueOpacity); /* Compute image size. */ x_offset=(long) (fabs((double) image->rows*shear.x)+0.5); y_width=(unsigned long) (fabs((double) image->rows*shear.x)+image->columns+0.5); y_offset=(long) (fabs((double) y_width*shear.y)+0.5); /* Surround image with border. */ integral_image->border_color=integral_image->background_color; border_info.width=(unsigned long) x_offset; border_info.height=(unsigned long) y_offset; shear_image=BorderImage(integral_image,&border_info,exception); if (shear_image == (Image *) NULL) ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); integral_image=DestroyImage(integral_image); /* Shear the image. */ if (shear_image->matte == MagickFalse) SetImageOpacity(shear_image,OpaqueOpacity); XShearImage(shear_image,shear.x,image->columns,image->rows,x_offset, ((long) shear_image->rows-image->rows)/2); YShearImage(shear_image,shear.y,y_width,image->rows, ((long) shear_image->columns-y_width)/2,y_offset); CropToFitImage(&shear_image,shear.x,shear.y,(MagickRealType) image->columns, (MagickRealType) image->rows,MagickFalse,exception); shear_image->page.width=0; shear_image->page.height=0; return(shear_image); }