/** * Convert an array of Image *s to an ImageMagick scene sequence (i.e. a * doubly-linked list of Images). * * No Ruby usage (internal function) * * @param imagelist the imagelist * @return a pointer to the head of the scene sequence list * @see rm_imagelist_from_images */ static Image * images_from_imagelist(VALUE imagelist) { long x, len; Image *head = NULL; VALUE images, t; len = check_imagelist_length(imagelist); images = rb_iv_get(imagelist, "@images"); for (x = 0; x < len; x++) { Image *image; t = rb_ary_entry(images, x); image = rm_check_destroyed(t); // avoid a loop in this linked imagelist, issue #202 if (head == image || GetPreviousImageInList(image) != NULL) { image = rm_clone_image(image); } AppendImageToList(&head, image); } RB_GC_GUARD(images); RB_GC_GUARD(t); return head; }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % 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) { Image *image; long j, y; MagickBooleanType status; MagickOffsetType offset; QuantumInfo quantum_info; register long i; register PixelPacket *q; ssize_t count; size_t packet_size; unsigned char *pixels; unsigned long width; /* 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=AllocateImage(image_info); 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); } for (i=0; i < image->offset; i++) if (ReadBlobByte(image) == EOF) { ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", image->filename); break; } /* Allocate memory for a pixels. */ packet_size=(size_t) (image->depth+7)/8; pixels=(unsigned char *) AcquireQuantumMemory(image->extract_info.width, packet_size*sizeof(*pixels)); if (pixels == (unsigned char *) NULL) ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); if (image_info->number_scenes != 0) while (image->scene < image_info->scene) { /* Skip to next image. */ image->scene++; for (y=0; y < (long) image->rows; y++) { count=ReadBlob(image,packet_size*image->extract_info.width,pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; } } offset=(MagickOffsetType) (packet_size*image->extract_info.x); do { /* Convert raster image to pixel packets. */ GetQuantumInfo(image_info,&quantum_info); if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0)) if (image->scene >= (image_info->scene+image_info->number_scenes-1)) break; if (SetImageExtent(image,0,0) == MagickFalse) { InheritException(exception,&image->exception); return(DestroyImageList(image)); } for (y=0; y < image->extract_info.y; y++) { count=ReadBlob(image,packet_size*image->extract_info.width,pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; } for (y=0; y < (long) image->rows; y++) { if ((y > 0) || (GetPreviousImageInList(image) == (Image *) NULL)) { count=ReadBlob(image,packet_size*image->extract_info.width,pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; } q=SetImagePixels(image,0,y,image->columns,1); if (q == (PixelPacket *) NULL) break; (void) ExportQuantumPixels(image,&quantum_info,GrayQuantum,pixels+offset); if (SyncImagePixels(image) == MagickFalse) break; if (image->previous == (Image *) NULL) if ((image->progress_monitor != (MagickProgressMonitor) NULL) && (QuantumTick(y,image->rows) != MagickFalse)) { status=image->progress_monitor(LoadImageTag,y,image->rows, image->client_data); if (status == MagickFalse) break; } } width=image->extract_info.height-image->rows-image->extract_info.y; for (j=0; j < (long) width; j++) { count=ReadBlob(image,packet_size*image->extract_info.width,pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; } if (y < (long) image->rows) { ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", image->filename); break; } /* Proceed to next image. */ if (image_info->number_scenes != 0) if (image->scene >= (image_info->scene+image_info->number_scenes-1)) break; count=ReadBlob(image,packet_size*image->extract_info.width,pixels); if (count == (ssize_t) (packet_size*image->extract_info.width)) { /* Allocate next image structure. */ AllocateNextImage(image_info,image); if (GetNextImageInList(image) == (Image *) NULL) { image=DestroyImageList(image); return((Image *) NULL); } image=SyncNextImageInList(image); if (image->progress_monitor != (MagickProgressMonitor) NULL) { status=image->progress_monitor(LoadImagesTag,TellBlob(image), GetBlobSize(image),image->client_data); if (status == MagickFalse) break; } } } while (count == (ssize_t) (packet_size*image->extract_info.width)); pixels=(unsigned char *) RelinquishMagickMemory(pixels); CloseBlob(image); return(GetFirstImageInList(image)); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % W r i t e I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % WriteImage() writes an image or an image sequence to a file or file handle. % If writing to a file is on disk, the name is defined by the filename member % of the image structure. WriteImage() returns MagickFalse is there is a % memory shortage or if the image cannot be written. Check the exception % member of image to determine the cause for any failure. % % The format of the WriteImage method is: % % MagickBooleanType WriteImage(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. % */ MagickExport MagickBooleanType WriteImage(const ImageInfo *image_info, Image *image,ExceptionInfo *exception) { char filename[MaxTextExtent]; const char *option; const DelegateInfo *delegate_info; const MagickInfo *magick_info; ExceptionInfo *sans_exception; ImageInfo *write_info; MagickBooleanType status, temporary; MagickStatusType thread_support; PolicyDomain domain; PolicyRights rights; /* Determine image type from filename prefix or suffix (e.g. image.jpg). */ assert(image_info != (ImageInfo *) NULL); assert(image_info->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", image_info->filename); assert(image != (Image *) NULL); assert(image->signature == MagickSignature); assert(exception != (ExceptionInfo *) NULL); sans_exception=AcquireExceptionInfo(); write_info=CloneImageInfo(image_info); (void) CopyMagickString(write_info->filename,image->filename,MaxTextExtent); if (*write_info->magick == '\0') (void) CopyMagickString(write_info->magick,image->magick,MaxTextExtent); (void) SetImageInfo(write_info,1,sans_exception); if (LocaleCompare(write_info->magick,"clipmask") == 0) { if (image->clip_mask == (Image *) NULL) { (void) ThrowMagickException(exception,GetMagickModule(), OptionError,"NoClipPathDefined","`%s'",image->filename); return(MagickFalse); } image=image->clip_mask; (void) SetImageInfo(write_info,1,sans_exception); } (void) CopyMagickString(filename,image->filename,MaxTextExtent); (void) CopyMagickString(image->filename,write_info->filename,MaxTextExtent); domain=CoderPolicyDomain; rights=WritePolicyRights; if (IsRightsAuthorized(domain,rights,write_info->magick) == MagickFalse) { sans_exception=DestroyExceptionInfo(sans_exception); errno=EPERM; ThrowBinaryException(PolicyError,"NotAuthorized",filename); } magick_info=GetMagickInfo(write_info->magick,sans_exception); sans_exception=DestroyExceptionInfo(sans_exception); if (magick_info != (const MagickInfo *) NULL) { if (GetMagickEndianSupport(magick_info) == MagickFalse) image->endian=UndefinedEndian; else if ((image_info->endian == UndefinedEndian) && (GetMagickRawSupport(magick_info) != MagickFalse)) { size_t lsb_first; lsb_first=1; image->endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian; } } (void) SyncImageProfiles(image); option=GetImageOption(image_info,"delegate:bimodal"); if ((option != (const char *) NULL) && (IsMagickTrue(option) != MagickFalse) && (write_info->page == (char *) NULL) && (GetPreviousImageInList(image) == (Image *) NULL) && (GetNextImageInList(image) == (Image *) NULL) && (IsTaintImage(image) == MagickFalse)) { delegate_info=GetDelegateInfo(image->magick,write_info->magick,exception); if ((delegate_info != (const DelegateInfo *) NULL) && (GetDelegateMode(delegate_info) == 0) && (IsPathAccessible(image->magick_filename) != MagickFalse)) { /* Process image with bi-modal delegate. */ (void) CopyMagickString(image->filename,image->magick_filename, MaxTextExtent); status=InvokeDelegate(write_info,image,image->magick, write_info->magick,exception); write_info=DestroyImageInfo(write_info); (void) CopyMagickString(image->filename,filename,MaxTextExtent); return(status); } } status=MagickFalse; temporary=MagickFalse; if ((magick_info != (const MagickInfo *) NULL) && (GetMagickSeekableStream(magick_info) != MagickFalse)) { char filename[MaxTextExtent]; (void) CopyMagickString(filename,image->filename,MaxTextExtent); status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); (void) CopyMagickString(image->filename,filename,MaxTextExtent); if (status != MagickFalse) { if (IsBlobSeekable(image) == MagickFalse) { /* A seekable stream is required by the encoder. */ write_info->adjoin=MagickTrue; (void) CopyMagickString(write_info->filename,image->filename, MaxTextExtent); (void) AcquireUniqueFilename(image->filename); temporary=MagickTrue; } (void) CloseBlob(image); } } if (constitute_semaphore == (SemaphoreInfo *) NULL) AcquireSemaphoreInfo(&constitute_semaphore); if ((magick_info != (const MagickInfo *) NULL) && (GetImageEncoder(magick_info) != (EncodeImageHandler *) NULL)) { /* Call appropriate image writer based on image type. */ thread_support=GetMagickThreadSupport(magick_info); if ((thread_support & EncoderThreadSupport) == 0) LockSemaphoreInfo(constitute_semaphore); status=GetImageEncoder(magick_info)(write_info,image,exception); if ((thread_support & EncoderThreadSupport) == 0) UnlockSemaphoreInfo(constitute_semaphore); } else { delegate_info=GetDelegateInfo((char *) NULL,write_info->magick,exception); if (delegate_info != (DelegateInfo *) NULL) { /* Process the image with delegate. */ *write_info->filename='\0'; if (GetDelegateThreadSupport(delegate_info) == MagickFalse) LockSemaphoreInfo(constitute_semaphore); status=InvokeDelegate(write_info,image,(char *) NULL, write_info->magick,exception); if (GetDelegateThreadSupport(delegate_info) == MagickFalse) UnlockSemaphoreInfo(constitute_semaphore); (void) CopyMagickString(image->filename,filename,MaxTextExtent); } else { sans_exception=AcquireExceptionInfo(); magick_info=GetMagickInfo(write_info->magick,sans_exception); sans_exception=DestroyExceptionInfo(sans_exception); if ((write_info->affirm == MagickFalse) && (magick_info == (const MagickInfo *) NULL)) { (void) CopyMagickString(write_info->magick,image->magick, MaxTextExtent); magick_info=GetMagickInfo(write_info->magick,exception); } if ((magick_info == (const MagickInfo *) NULL) || (GetImageEncoder(magick_info) == (EncodeImageHandler *) NULL)) { char extension[MaxTextExtent]; GetPathComponent(image->filename,ExtensionPath,extension); if (*extension != '\0') magick_info=GetMagickInfo(extension,exception); else magick_info=GetMagickInfo(image->magick,exception); (void) CopyMagickString(image->filename,filename,MaxTextExtent); } if ((magick_info == (const MagickInfo *) NULL) || (GetImageEncoder(magick_info) == (EncodeImageHandler *) NULL)) (void) ThrowMagickException(exception,GetMagickModule(), MissingDelegateError,"NoEncodeDelegateForThisImageFormat","`%s'", image->filename); else { /* Call appropriate image writer based on image type. */ thread_support=GetMagickThreadSupport(magick_info); if ((thread_support & EncoderThreadSupport) == 0) LockSemaphoreInfo(constitute_semaphore); status=GetImageEncoder(magick_info)(write_info,image,exception); if ((thread_support & EncoderThreadSupport) == 0) UnlockSemaphoreInfo(constitute_semaphore); } } } if (GetBlobError(image) != MagickFalse) ThrowFileException(exception,FileOpenError, "AnErrorHasOccurredWritingToFile",image->filename); if (temporary == MagickTrue) { /* Copy temporary image file to permanent. */ status=OpenBlob(write_info,image,ReadBinaryBlobMode,exception); if (status != MagickFalse) status=ImageToFile(image,write_info->filename,exception); (void) CloseBlob(image); (void) RelinquishUniqueFileResource(image->filename); (void) CopyMagickString(image->filename,write_info->filename, MaxTextExtent); } if ((LocaleCompare(write_info->magick,"info") != 0) && (write_info->verbose != MagickFalse)) (void) IdentifyImage(image,stdout,MagickFalse,exception); write_info=DestroyImageInfo(write_info); return(status); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d R G B I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ReadRGBImage() reads an image of raw red, green, and blue 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 ReadRGBImage method is: % % Image *ReadRGBImage(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 *ReadRGBImage(const ImageInfo *image_info,ExceptionInfo *exception) { Image *image; long y; MagickBooleanType status; MagickOffsetType offset; QuantumInfo quantum_info; register long i; register PixelPacket *q; ssize_t count; size_t packet_size; unsigned char *pixels; unsigned long width; assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickSignature); if (image_info->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", image_info->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); image=AllocateImage(image_info); if ((image->columns == 0) || (image->rows == 0)) ThrowReaderException(OptionError,"MustSpecifyImageSize"); if (image_info->interlace != PartitionInterlace) { /* Open image file. */ status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) { image=DestroyImageList(image); return((Image *) NULL); } for (i=0; i < image->offset; i++) if (ReadBlobByte(image) == EOF) { ThrowFileException(exception,CorruptImageError, "UnexpectedEndOfFile",image->filename); break; } } /* Allocate memory for a pixels. */ packet_size=(size_t) ((3*image->depth+7)/8); if ((LocaleCompare(image_info->magick,"RGBA") == 0) || (LocaleCompare(image_info->magick,"RGBO") == 0)) { packet_size+=(image->depth+7)/8; image->matte=MagickTrue; } pixels=(unsigned char *) AcquireQuantumMemory(image->extract_info.width, packet_size*sizeof(*pixels)); if (pixels == (unsigned char *) NULL) ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); if (image_info->number_scenes != 0) while (image->scene < image_info->scene) { /* Skip to next image. */ image->scene++; for (y=0; y < (long) image->rows; y++) { count=ReadBlob(image,packet_size*image->extract_info.width,pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; } } offset=(MagickOffsetType) (packet_size*image->extract_info.x); do { /* Convert raster image to pixel packets. */ GetQuantumInfo(image_info,&quantum_info); if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0)) if (image->scene >= (image_info->scene+image_info->number_scenes-1)) break; if (SetImageExtent(image,0,0) == MagickFalse) { InheritException(exception,&image->exception); return(DestroyImageList(image)); } switch (image_info->interlace) { case NoInterlace: default: { /* No interlacing: RGBRGBRGBRGBRGBRGB... */ for (y=0; y < image->extract_info.y; y++) { count=ReadBlob(image,packet_size*image->extract_info.width,pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; } for (y=0; y < (long) image->rows; y++) { if ((y > 0) || (GetPreviousImageInList(image) == (Image *) NULL)) { count=ReadBlob(image,packet_size*image->extract_info.width, pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; } q=SetImagePixels(image,0,y,image->columns,1); if (q == (PixelPacket *) NULL) break; if (image->matte == MagickFalse) (void) ExportQuantumPixels(image,&quantum_info,RGBQuantum, pixels+offset); else if (LocaleCompare(image_info->magick,"RGBA") == 0) (void) ExportQuantumPixels(image,&quantum_info,RGBAQuantum, pixels+offset); else (void) ExportQuantumPixels(image,&quantum_info,RGBOQuantum, pixels+offset); if (SyncImagePixels(image) == MagickFalse) break; if (image->previous == (Image *) NULL) if ((image->progress_monitor != (MagickProgressMonitor) NULL) && (QuantumTick(y,image->rows) != MagickFalse)) { status=image->progress_monitor(LoadImageTag,y,image->rows, image->client_data); if (status == MagickFalse) break; } } width=image->extract_info.height-image->rows-image->extract_info.y; for (i=0; i < (long) width; i++) { count=ReadBlob(image,packet_size*image->extract_info.width,pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; } break; } case LineInterlace: { /* Line interlacing: RRR...GGG...BBB...RRR...GGG...BBB... */ packet_size=(size_t) ((image->depth+7)/8); for (y=0; y < image->extract_info.y; y++) { count=ReadBlob(image,packet_size*image->extract_info.width,pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; } for (y=0; y < (long) image->rows; y++) { if ((y > 0) || (GetPreviousImageInList(image) == (Image *) NULL)) { count=ReadBlob(image,packet_size*image->extract_info.width, pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; } q=SetImagePixels(image,0,y,image->columns,1); if (q == (PixelPacket *) NULL) break; (void) ExportQuantumPixels(image,&quantum_info,RedQuantum, pixels+offset); count=ReadBlob(image,packet_size*image->extract_info.width,pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; (void) ExportQuantumPixels(image,&quantum_info,GreenQuantum, pixels+offset); count=ReadBlob(image,packet_size*image->extract_info.width,pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; (void) ExportQuantumPixels(image,&quantum_info,BlueQuantum, pixels+offset); if (image->matte != MagickFalse) { count=ReadBlob(image,packet_size*image->extract_info.width, pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; if (LocaleCompare(image_info->magick,"RGBA") == 0) (void) ExportQuantumPixels(image,&quantum_info,AlphaQuantum, pixels+offset); else (void) ExportQuantumPixels(image,&quantum_info,OpacityQuantum, pixels+offset); } if (SyncImagePixels(image) == MagickFalse) break; if (image->previous == (Image *) NULL) if ((image->progress_monitor != (MagickProgressMonitor) NULL) && (QuantumTick(y,image->rows) != MagickFalse)) { status=image->progress_monitor(LoadImageTag,y,image->rows, image->client_data); if (status == MagickFalse) break; } } width=image->extract_info.height-image->rows-image->extract_info.y; for (i=0; i < (long) width; i++) { count=ReadBlob(image,packet_size*image->extract_info.width,pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; } break; } case PlaneInterlace: case PartitionInterlace: { unsigned long span; /* Plane interlacing: RRRRRR...GGGGGG...BBBBBB... */ if (image_info->interlace == PartitionInterlace) { AppendImageFormat("R",image->filename); status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) { image=DestroyImageList(image); return((Image *) NULL); } } packet_size=(size_t) ((image->depth+7)/8); for (y=0; y < image->extract_info.y; y++) { count=ReadBlob(image,packet_size*image->extract_info.width,pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; } i=0; span=image->rows*(image->matte != MagickFalse ? 4 : 3); for (y=0; y < (long) image->rows; y++) { if ((y > 0) || (GetPreviousImageInList(image) == (Image *) NULL)) { count=ReadBlob(image,packet_size*image->extract_info.width, pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; } q=SetImagePixels(image,0,y,image->columns,1); if (q == (PixelPacket *) NULL) break; (void) ExportQuantumPixels(image,&quantum_info,RedQuantum, pixels+offset); if (SyncImagePixels(image) == MagickFalse) break; if (image->previous == (Image *) NULL) if ((image->progress_monitor != (MagickProgressMonitor) NULL) && (QuantumTick(i,span) != MagickFalse)) { status=image->progress_monitor(LoadImageTag,i,span, image->client_data); if (status == MagickFalse) break; } i++; } width=image->extract_info.height-image->rows-image->extract_info.y; for (i=0; i < (long) width; i++) { count=ReadBlob(image,packet_size*image->extract_info.width,pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; } if (image_info->interlace == PartitionInterlace) { CloseBlob(image); AppendImageFormat("G",image->filename); status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) { image=DestroyImageList(image); return((Image *) NULL); } } for (y=0; y < image->extract_info.y; y++) { count=ReadBlob(image,packet_size*image->extract_info.width,pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; } for (y=0; y < (long) image->rows; y++) { count=ReadBlob(image,packet_size*image->extract_info.width,pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; q=GetImagePixels(image,0,y,image->columns,1); if (q == (PixelPacket *) NULL) break; (void) ExportQuantumPixels(image,&quantum_info,GreenQuantum, pixels+offset); if (SyncImagePixels(image) == MagickFalse) break; if (image->previous == (Image *) NULL) if ((image->progress_monitor != (MagickProgressMonitor) NULL) && (QuantumTick(i,span) != MagickFalse)) { status=image->progress_monitor(LoadImageTag,i,span, image->client_data); if (status == MagickFalse) break; } i++; } width=image->extract_info.height-image->rows-image->extract_info.y; for (i=0; i < (long) width; i++) { count=ReadBlob(image,packet_size*image->extract_info.width,pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; } if (image_info->interlace == PartitionInterlace) { CloseBlob(image); AppendImageFormat("B",image->filename); status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) { image=DestroyImageList(image); return((Image *) NULL); } } for (y=0; y < image->extract_info.y; y++) { count=ReadBlob(image,packet_size*image->extract_info.width,pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; } for (y=0; y < (long) image->rows; y++) { count=ReadBlob(image,packet_size*image->extract_info.width,pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; q=GetImagePixels(image,0,y,image->columns,1); if (q == (PixelPacket *) NULL) break; (void) ExportQuantumPixels(image,&quantum_info,BlueQuantum, pixels+offset); if (SyncImagePixels(image) == MagickFalse) break; if (image->previous == (Image *) NULL) if ((image->progress_monitor != (MagickProgressMonitor) NULL) && (QuantumTick(i,span) != MagickFalse)) { status=image->progress_monitor(LoadImageTag,i,span, image->client_data); if (status == MagickFalse) break; } i++; } width=image->extract_info.height-image->rows-image->extract_info.y; for (i=0; i < (long) width; i++) { count=ReadBlob(image,packet_size*image->extract_info.width,pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; } if (image->matte != MagickFalse) { /* Read matte channel. */ if (image_info->interlace == PartitionInterlace) { CloseBlob(image); AppendImageFormat("A",image->filename); status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) { image=DestroyImageList(image); return((Image *) NULL); } } for (y=0; y < image->extract_info.y; y++) { count=ReadBlob(image,packet_size*image->extract_info.width, pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; } for (y=0; y < (long) image->rows; y++) { count=ReadBlob(image,packet_size*image->extract_info.width, pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; q=GetImagePixels(image,0,y,image->columns,1); if (q == (PixelPacket *) NULL) break; if (LocaleCompare(image_info->magick,"RGBA") == 0) (void) ExportQuantumPixels(image,&quantum_info,AlphaQuantum, pixels+offset); else (void) ExportQuantumPixels(image,&quantum_info,OpacityQuantum, pixels+offset); if (SyncImagePixels(image) == MagickFalse) break; if (image->previous == (Image *) NULL) if ((image->progress_monitor != (MagickProgressMonitor) NULL) && (QuantumTick(i,span) != MagickFalse)) { status=image->progress_monitor(LoadImageTag,i,span, image->client_data); if (status == MagickFalse) break; } i++; } width=image->extract_info.height-image->rows-image->extract_info.y; for (i=0; i < (long) width; i++) { count=ReadBlob(image,packet_size*image->extract_info.width, pixels); if (count != (ssize_t) (packet_size*image->extract_info.width)) break; } } if (image_info->interlace == PartitionInterlace) (void) CopyMagickString(image->filename,image_info->filename, MaxTextExtent); break; } } if (y < (long) image->rows) { ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", image->filename); break; } /* Proceed to next image. */ if (image_info->number_scenes != 0) if (image->scene >= (image_info->scene+image_info->number_scenes-1)) break; if (image_info->interlace == PartitionInterlace) break; count=ReadBlob(image,packet_size*image->extract_info.width,pixels); if (count == (ssize_t) (packet_size*image->extract_info.width)) { /* Allocate next image structure. */ AllocateNextImage(image_info,image); if (GetNextImageInList(image) == (Image *) NULL) { image=DestroyImageList(image); return((Image *) NULL); } image=SyncNextImageInList(image); if (image->progress_monitor != (MagickProgressMonitor) NULL) { status=image->progress_monitor(LoadImagesTag,TellBlob(image), GetBlobSize(image),image->client_data); if (status == MagickFalse) break; } } } while ((size_t) count == (packet_size*image->extract_info.width)); pixels=(unsigned char *) RelinquishMagickMemory(pixels); CloseBlob(image); return(GetFirstImageInList(image)); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d Y U V I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ReadYUVImage() reads an image with digital YUV (CCIR 601 4:1:1, plane % or partition interlaced, or 4:2:2 plane, partition interlaced or % noninterlaced) bytes 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 ReadYUVImage method is: % % Image *ReadYUVImage(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 *ReadYUVImage(const ImageInfo *image_info,ExceptionInfo *exception) { Image *chroma_image, *image, *resize_image; InterlaceType interlace; MagickBooleanType status; register const PixelPacket *chroma_pixels; register ssize_t x; register PixelPacket *q; register unsigned char *p; ssize_t count, horizontal_factor, vertical_factor, y; size_t quantum; unsigned char *scanline; /* Allocate image structure. */ assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickSignature); if (image_info->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", image_info->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); image=AcquireImage(image_info); if ((image->columns == 0) || (image->rows == 0)) ThrowReaderException(OptionError,"MustSpecifyImageSize"); status=SetImageExtent(image,image->columns,image->rows); if (status == MagickFalse) { InheritException(exception,&image->exception); return(DestroyImageList(image)); } quantum=(size_t) (image->depth <= 8 ? 1 : 2); interlace=image_info->interlace; horizontal_factor=2; vertical_factor=2; if (image_info->sampling_factor != (char *) NULL) { GeometryInfo geometry_info; MagickStatusType flags; flags=ParseGeometry(image_info->sampling_factor,&geometry_info); horizontal_factor=(ssize_t) geometry_info.rho; vertical_factor=(ssize_t) geometry_info.sigma; if ((flags & SigmaValue) == 0) vertical_factor=horizontal_factor; if ((horizontal_factor != 1) && (horizontal_factor != 2) && (vertical_factor != 1) && (vertical_factor != 2)) ThrowReaderException(CorruptImageError,"UnexpectedSamplingFactor"); } if ((interlace == UndefinedInterlace) || ((interlace == NoInterlace) && (vertical_factor == 2))) { interlace=NoInterlace; /* CCIR 4:2:2 */ if (vertical_factor == 2) interlace=PlaneInterlace; /* CCIR 4:1:1 */ } if (interlace != PartitionInterlace) { /* Open image file. */ status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) { image=DestroyImageList(image); return((Image *) NULL); } if (DiscardBlobBytes(image,(MagickSizeType) image->offset) == MagickFalse) ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", image->filename); } /* Allocate memory for a scanline. */ if (interlace == NoInterlace) scanline=(unsigned char *) AcquireQuantumMemory((size_t) 2UL* image->columns+2UL,quantum*sizeof(*scanline)); else scanline=(unsigned char *) AcquireQuantumMemory(image->columns, quantum*sizeof(*scanline)); if (scanline == (unsigned char *) NULL) ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); do { chroma_image=CloneImage(image,(image->columns + horizontal_factor - 1) / horizontal_factor, (image->rows + vertical_factor - 1) / vertical_factor, MagickTrue,exception); if (chroma_image == (Image *) NULL) ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); /* Convert raster image to pixel packets. */ 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); if (status == MagickFalse) { InheritException(exception,&image->exception); return(DestroyImageList(image)); } if (interlace == PartitionInterlace) { AppendImageFormat("Y",image->filename); status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) { image=DestroyImageList(image); return((Image *) NULL); } } for (y=0; y < (ssize_t) image->rows; y++) { register PixelPacket *chroma_pixels; if (interlace == NoInterlace) { if ((y > 0) || (GetPreviousImageInList(image) == (Image *) NULL)) (void) ReadBlob(image,(size_t) (2*quantum*image->columns),scanline); p=scanline; q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); if (q == (PixelPacket *) NULL) break; chroma_pixels=QueueAuthenticPixels(chroma_image,0,y, chroma_image->columns,1,exception); if (chroma_pixels == (PixelPacket *) NULL) break; for (x=0; x < (ssize_t) image->columns; x+=2) { SetPixelRed(chroma_pixels,0); if (quantum == 1) SetPixelGreen(chroma_pixels,ScaleCharToQuantum(*p++)); else { SetPixelGreen(chroma_pixels,ScaleShortToQuantum(((*p) << 8) | *(p+1))); p+=2; } if (quantum == 1) SetPixelRed(q,ScaleCharToQuantum(*p++)); else { SetPixelRed(q,ScaleShortToQuantum(((*p) << 8) | *(p+1))); p+=2; } SetPixelGreen(q,0); SetPixelBlue(q,0); q++; SetPixelGreen(q,0); SetPixelBlue(q,0); if (quantum == 1) SetPixelBlue(chroma_pixels,ScaleCharToQuantum(*p++)); else { SetPixelBlue(chroma_pixels,ScaleShortToQuantum(((*p) << 8) | *(p+1))); p+=2; } if (quantum == 1) SetPixelRed(q,ScaleCharToQuantum(*p++)); else { SetPixelRed(q,ScaleShortToQuantum(((*p) << 8) | *(p+1))); p+=2; } chroma_pixels++; q++; } } else { if ((y > 0) || (GetPreviousImageInList(image) == (Image *) NULL)) (void) ReadBlob(image,(size_t) quantum*image->columns,scanline); p=scanline; q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); if (q == (PixelPacket *) NULL) break; for (x=0; x < (ssize_t) image->columns; x++) { if (quantum == 1) SetPixelRed(q,ScaleCharToQuantum(*p++)); else { SetPixelRed(q,ScaleShortToQuantum(((*p) << 8) | *(p+1))); p+=2; } SetPixelGreen(q,0); SetPixelBlue(q,0); q++; } } if (SyncAuthenticPixels(image,exception) == MagickFalse) break; if (interlace == NoInterlace) if (SyncAuthenticPixels(chroma_image,exception) == MagickFalse) break; if (image->previous == (Image *) NULL) { status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, image->rows); if (status == MagickFalse) break; } } if (interlace == PartitionInterlace) { (void) CloseBlob(image); AppendImageFormat("U",image->filename); status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) { image=DestroyImageList(image); return((Image *) NULL); } } if (interlace != NoInterlace) { for (y=0; y < (ssize_t) chroma_image->rows; y++) { (void) ReadBlob(image,(size_t) quantum*chroma_image->columns,scanline); p=scanline; q=QueueAuthenticPixels(chroma_image,0,y,chroma_image->columns,1, exception); if (q == (PixelPacket *) NULL) break; for (x=0; x < (ssize_t) chroma_image->columns; x++) { SetPixelRed(q,0); if (quantum == 1) SetPixelGreen(q,ScaleCharToQuantum(*p++)); else { SetPixelGreen(q,ScaleShortToQuantum(((*p) << 8) | *(p+1))); p+=2; } SetPixelBlue(q,0); q++; } if (SyncAuthenticPixels(chroma_image,exception) == MagickFalse) break; } if (interlace == PartitionInterlace) { (void) CloseBlob(image); AppendImageFormat("V",image->filename); status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) { image=DestroyImageList(image); return((Image *) NULL); } } for (y=0; y < (ssize_t) chroma_image->rows; y++) { (void) ReadBlob(image,(size_t) quantum*chroma_image->columns,scanline); p=scanline; q=GetAuthenticPixels(chroma_image,0,y,chroma_image->columns,1, exception); if (q == (PixelPacket *) NULL) break; for (x=0; x < (ssize_t) chroma_image->columns; x++) { if (quantum == 1) SetPixelBlue(q,ScaleCharToQuantum(*p++)); else { SetPixelBlue(q,ScaleShortToQuantum(((*p) << 8) | *(p+1))); p+=2; } q++; } if (SyncAuthenticPixels(chroma_image,exception) == MagickFalse) break; } } /* Scale image. */ resize_image=ResizeImage(chroma_image,image->columns,image->rows, TriangleFilter,1.0,exception); chroma_image=DestroyImage(chroma_image); if (resize_image == (Image *) NULL) ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); for (y=0; y < (ssize_t) image->rows; y++) { q=GetAuthenticPixels(image,0,y,image->columns,1,exception); chroma_pixels=GetVirtualPixels(resize_image,0,y,resize_image->columns,1, &resize_image->exception); if ((q == (PixelPacket *) NULL) || (chroma_pixels == (const PixelPacket *) NULL)) break; for (x=0; x < (ssize_t) image->columns; x++) { SetPixelGreen(q,GetPixelGreen(chroma_pixels)); SetPixelBlue(q,GetPixelBlue(chroma_pixels)); chroma_pixels++; q++; } if (SyncAuthenticPixels(image,exception) == MagickFalse) break; } resize_image=DestroyImage(resize_image); SetImageColorspace(image,YCbCrColorspace); if (interlace == PartitionInterlace) (void) CopyMagickString(image->filename,image_info->filename, MaxTextExtent); if (EOFBlob(image) != MagickFalse) { ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", image->filename); break; } /* Proceed to next image. */ if (image_info->number_scenes != 0) if (image->scene >= (image_info->scene+image_info->number_scenes-1)) break; if (interlace == NoInterlace) count=ReadBlob(image,(size_t) (2*quantum*image->columns),scanline); else count=ReadBlob(image,(size_t) quantum*image->columns,scanline); if (count != 0) { /* 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; } } while (count != 0); scanline=(unsigned char *) RelinquishMagickMemory(scanline); (void) CloseBlob(image); return(GetFirstImageInList(image)); }
MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file, const MagickBooleanType verbose,ExceptionInfo *exception) { char color[MaxTextExtent], format[MaxTextExtent], key[MaxTextExtent]; ChannelFeatures *channel_features; ChannelStatistics *channel_statistics; ColorspaceType colorspace; const char *artifact, *name, *property, *registry, *value; const MagickInfo *magick_info; double elapsed_time, user_time; ImageType type; MagickBooleanType ping; register const Quantum *p; register ssize_t i, x; size_t distance, scale; ssize_t y; assert(image != (Image *) NULL); assert(image->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); if (file == (FILE *) NULL) file=stdout; *format='\0'; elapsed_time=GetElapsedTime(&image->timer); user_time=GetUserTime(&image->timer); GetTimerInfo(&image->timer); if (verbose == MagickFalse) { /* Display summary info about the image. */ if (*image->magick_filename != '\0') if (LocaleCompare(image->magick_filename,image->filename) != 0) (void) FormatLocaleFile(file,"%s=>",image->magick_filename); if ((GetPreviousImageInList(image) == (Image *) NULL) && (GetNextImageInList(image) == (Image *) NULL) && (image->scene == 0)) (void) FormatLocaleFile(file,"%s ",image->filename); else (void) FormatLocaleFile(file,"%s[%.20g] ",image->filename,(double) image->scene); (void) FormatLocaleFile(file,"%s ",image->magick); if ((image->magick_columns != 0) || (image->magick_rows != 0)) if ((image->magick_columns != image->columns) || (image->magick_rows != image->rows)) (void) FormatLocaleFile(file,"%.20gx%.20g=>",(double) image->magick_columns,(double) image->magick_rows); (void) FormatLocaleFile(file,"%.20gx%.20g ",(double) image->columns, (double) image->rows); if ((image->page.width != 0) || (image->page.height != 0) || (image->page.x != 0) || (image->page.y != 0)) (void) FormatLocaleFile(file,"%.20gx%.20g%+.20g%+.20g ",(double) image->page.width,(double) image->page.height,(double) image->page.x, (double) image->page.y); (void) FormatLocaleFile(file,"%.20g-bit ",(double) image->depth); if (image->type != UndefinedType) (void) FormatLocaleFile(file,"%s ",CommandOptionToMnemonic( MagickTypeOptions,(ssize_t) image->type)); if (image->storage_class == DirectClass) { (void) FormatLocaleFile(file,"DirectClass "); if (image->total_colors != 0) { (void) FormatMagickSize(image->total_colors,MagickFalse,format); (void) FormatLocaleFile(file,"%s ",format); } } else if (image->total_colors <= image->colors) (void) FormatLocaleFile(file,"PseudoClass %.20gc ",(double) image->colors); else (void) FormatLocaleFile(file,"PseudoClass %.20g=>%.20gc ",(double) image->total_colors,(double) image->colors); if (image->error.mean_error_per_pixel != 0.0) (void) FormatLocaleFile(file,"%.20g/%f/%fdb ",(double) (image->error.mean_error_per_pixel+0.5), image->error.normalized_mean_error, image->error.normalized_maximum_error); if (GetBlobSize(image) != 0) { (void) FormatMagickSize(GetBlobSize(image),MagickFalse,format); (void) FormatLocaleFile(file,"%s ",format); } (void) FormatLocaleFile(file,"%0.3fu %lu:%02lu.%03lu",user_time, (unsigned long) (elapsed_time/60.0),(unsigned long) floor(fmod( elapsed_time,60.0)),(unsigned long) (1000.0*(elapsed_time- floor(elapsed_time)))); (void) FormatLocaleFile(file,"\n"); (void) fflush(file); return(ferror(file) != 0 ? MagickFalse : MagickTrue); } /* Display verbose info about the image. */ p=GetVirtualPixels(image,0,0,1,1,exception); ping=p == (const Quantum *) NULL ? MagickTrue : MagickFalse; type=GetImageType(image,exception); (void) SignatureImage(image,exception); (void) FormatLocaleFile(file,"Image: %s\n",image->filename); if (*image->magick_filename != '\0') if (LocaleCompare(image->magick_filename,image->filename) != 0) { char filename[MaxTextExtent]; GetPathComponent(image->magick_filename,TailPath,filename); (void) FormatLocaleFile(file," Base filename: %s\n",filename); } magick_info=GetMagickInfo(image->magick,exception); if ((magick_info == (const MagickInfo *) NULL) || (*GetMagickDescription(magick_info) == '\0')) (void) FormatLocaleFile(file," Format: %s\n",image->magick); else (void) FormatLocaleFile(file," Format: %s (%s)\n",image->magick, GetMagickDescription(magick_info)); (void) FormatLocaleFile(file," Class: %s\n",CommandOptionToMnemonic( MagickClassOptions,(ssize_t) image->storage_class)); (void) FormatLocaleFile(file," Geometry: %.20gx%.20g%+.20g%+.20g\n",(double) image->columns,(double) image->rows,(double) image->tile_offset.x,(double) image->tile_offset.y); if ((image->magick_columns != 0) || (image->magick_rows != 0)) if ((image->magick_columns != image->columns) || (image->magick_rows != image->rows)) (void) FormatLocaleFile(file," Base geometry: %.20gx%.20g\n",(double) image->magick_columns,(double) image->magick_rows); if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0)) { (void) FormatLocaleFile(file," Resolution: %gx%g\n",image->resolution.x, image->resolution.y); (void) FormatLocaleFile(file," Print size: %gx%g\n",(double) image->columns/image->resolution.x,(double) image->rows/ image->resolution.y); } (void) FormatLocaleFile(file," Units: %s\n",CommandOptionToMnemonic( MagickResolutionOptions,(ssize_t) image->units)); (void) FormatLocaleFile(file," Type: %s\n",CommandOptionToMnemonic( MagickTypeOptions,(ssize_t) type)); if (image->type != UndefinedType) (void) FormatLocaleFile(file," Base type: %s\n",CommandOptionToMnemonic( MagickTypeOptions,(ssize_t) image->type)); (void) FormatLocaleFile(file," Endianess: %s\n",CommandOptionToMnemonic( MagickEndianOptions,(ssize_t) image->endian)); /* Detail channel depth and extrema. */ (void) FormatLocaleFile(file," Colorspace: %s\n",CommandOptionToMnemonic( MagickColorspaceOptions,(ssize_t) image->colorspace)); channel_statistics=(ChannelStatistics *) NULL; channel_features=(ChannelFeatures *) NULL; colorspace=image->colorspace; scale=1; if (ping == MagickFalse) { size_t depth; channel_statistics=GetImageStatistics(image,exception); artifact=GetImageArtifact(image,"identify:features"); if (artifact != (const char *) NULL) { distance=StringToUnsignedLong(artifact); channel_features=GetImageFeatures(image,distance,exception); } depth=GetImageDepth(image,exception); if (image->depth == depth) (void) FormatLocaleFile(file," Depth: %.20g-bit\n",(double) image->depth); else (void) FormatLocaleFile(file," Depth: %.20g/%.20g-bit\n",(double) image->depth,(double) depth); (void) FormatLocaleFile(file," Channel depth:\n"); if (IsImageGray(image,exception) != MagickFalse) colorspace=GRAYColorspace; switch (colorspace) { case RGBColorspace: default: { (void) FormatLocaleFile(file," red: %.20g-bit\n",(double) channel_statistics[RedPixelChannel].depth); (void) FormatLocaleFile(file," green: %.20g-bit\n",(double) channel_statistics[GreenPixelChannel].depth); (void) FormatLocaleFile(file," blue: %.20g-bit\n",(double) channel_statistics[BluePixelChannel].depth); break; } case CMYKColorspace: { (void) FormatLocaleFile(file," cyan: %.20g-bit\n",(double) channel_statistics[CyanPixelChannel].depth); (void) FormatLocaleFile(file," magenta: %.20g-bit\n",(double) channel_statistics[MagentaPixelChannel].depth); (void) FormatLocaleFile(file," yellow: %.20g-bit\n",(double) channel_statistics[YellowPixelChannel].depth); (void) FormatLocaleFile(file," black: %.20g-bit\n",(double) channel_statistics[BlackPixelChannel].depth); break; } case GRAYColorspace: { (void) FormatLocaleFile(file," gray: %.20g-bit\n",(double) channel_statistics[GrayPixelChannel].depth); break; } } if (image->matte != MagickFalse) (void) FormatLocaleFile(file," alpha: %.20g-bit\n",(double) channel_statistics[AlphaPixelChannel].depth); scale=1; if (image->depth <= MAGICKCORE_QUANTUM_DEPTH) scale=QuantumRange/((size_t) QuantumRange >> ((size_t) MAGICKCORE_QUANTUM_DEPTH-image->depth)); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % W r i t e M P C I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % WriteMPCImage() writes an Magick Persistent Cache image to a file. % % The format of the WriteMPCImage method is: % % MagickBooleanType WriteMPCImage(const ImageInfo *image_info,Image *image) % % A description of each parameter follows: % % o image_info: the image info. % % o image: the image. % */ static MagickBooleanType WriteMPCImage(const ImageInfo *image_info,Image *image) { char buffer[MaxTextExtent], cache_filename[MaxTextExtent]; const char *property, *value; MagickBooleanType status; MagickOffsetType offset, scene; register long i; unsigned long depth; /* Open persistent cache. */ 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) CopyMagickString(cache_filename,image->filename,MaxTextExtent); AppendImageFormat("cache",cache_filename); scene=0; offset=0; do { /* Write persistent cache meta-information. */ depth=GetImageQuantumDepth(image,MagickTrue); if ((image->storage_class == PseudoClass) && (image->colors > (1UL << depth))) image->storage_class=DirectClass; (void) WriteBlobString(image,"id=MagickCache\n"); (void) FormatMagickString(buffer,MaxTextExtent,"quantum-depth=%d\n", MAGICKCORE_QUANTUM_DEPTH); (void) WriteBlobString(image,buffer); (void) FormatMagickString(buffer,MaxTextExtent, "class=%s colors=%lu matte=%s\n",MagickOptionToMnemonic( MagickClassOptions,image->storage_class),image->colors, MagickOptionToMnemonic(MagickBooleanOptions,(long) image->matte)); (void) WriteBlobString(image,buffer); (void) FormatMagickString(buffer,MaxTextExtent, "columns=%lu rows=%lu depth=%lu\n",image->columns,image->rows, image->depth); (void) WriteBlobString(image,buffer); if (image->type != UndefinedType) { (void) FormatMagickString(buffer,MaxTextExtent,"type=%s\n", MagickOptionToMnemonic(MagickTypeOptions,image->type)); (void) WriteBlobString(image,buffer); } if (image->colorspace != UndefinedColorspace) { (void) FormatMagickString(buffer,MaxTextExtent,"colorspace=%s\n", MagickOptionToMnemonic(MagickColorspaceOptions,image->colorspace)); (void) WriteBlobString(image,buffer); } if (image->endian != UndefinedEndian) { (void) FormatMagickString(buffer,MaxTextExtent,"endian=%s\n", MagickOptionToMnemonic(MagickEndianOptions,image->endian)); (void) WriteBlobString(image,buffer); } if (image->compression != UndefinedCompression) { (void) FormatMagickString(buffer,MaxTextExtent, "compression=%s quality=%lu\n",MagickOptionToMnemonic( MagickCompressOptions,image->compression),image->quality); (void) WriteBlobString(image,buffer); } if (image->units != UndefinedResolution) { (void) FormatMagickString(buffer,MaxTextExtent,"units=%s\n", MagickOptionToMnemonic(MagickResolutionOptions,image->units)); (void) WriteBlobString(image,buffer); } if ((image->x_resolution != 0) || (image->y_resolution != 0)) { (void) FormatMagickString(buffer,MaxTextExtent, "resolution=%gx%g\n",image->x_resolution,image->y_resolution); (void) WriteBlobString(image,buffer); } if ((image->page.width != 0) || (image->page.height != 0)) { (void) FormatMagickString(buffer,MaxTextExtent,"page=%lux%lu%+ld%+ld\n", image->page.width,image->page.height,image->page.x,image->page.y); (void) WriteBlobString(image,buffer); } else if ((image->page.x != 0) || (image->page.y != 0)) { (void) FormatMagickString(buffer,MaxTextExtent,"page=%+ld%+ld\n", image->page.x,image->page.y); (void) WriteBlobString(image,buffer); } if ((image->page.x != 0) || (image->page.y != 0)) { (void) FormatMagickString(buffer,MaxTextExtent,"tile-offset=%+ld%+ld\n", image->tile_offset.x,image->tile_offset.y); (void) WriteBlobString(image,buffer); } if ((GetNextImageInList(image) != (Image *) NULL) || (GetPreviousImageInList(image) != (Image *) NULL)) { if (image->scene == 0) (void) FormatMagickString(buffer,MaxTextExtent, "iterations=%lu delay=%lu ticks-per-second=%lu\n", image->iterations,image->delay,image->ticks_per_second); else (void) FormatMagickString(buffer,MaxTextExtent, "scene=%lu iterations=%lu delay=%lu ticks-per-second=%lu\n", image->scene,image->iterations,image->delay, image->ticks_per_second); (void) WriteBlobString(image,buffer); } else { if (image->scene != 0) { (void) FormatMagickString(buffer,MaxTextExtent,"scene=%lu\n", image->scene); (void) WriteBlobString(image,buffer); } if (image->iterations != 0) { (void) FormatMagickString(buffer,MaxTextExtent,"iterations=%lu\n", image->iterations); (void) WriteBlobString(image,buffer); } if (image->delay != 0) { (void) FormatMagickString(buffer,MaxTextExtent,"delay=%lu\n", image->delay); (void) WriteBlobString(image,buffer); } if (image->ticks_per_second != UndefinedTicksPerSecond) { (void) FormatMagickString(buffer,MaxTextExtent, "ticks-per-second=%lu\n",image->ticks_per_second); (void) WriteBlobString(image,buffer); } } if (image->gravity != UndefinedGravity) { (void) FormatMagickString(buffer,MaxTextExtent,"gravity=%s\n", MagickOptionToMnemonic(MagickGravityOptions,image->gravity)); (void) WriteBlobString(image,buffer); } if (image->dispose != UndefinedDispose) { (void) FormatMagickString(buffer,MaxTextExtent,"dispose=%s\n", MagickOptionToMnemonic(MagickDisposeOptions,image->dispose)); (void) WriteBlobString(image,buffer); } if (image->rendering_intent != UndefinedIntent) { (void) FormatMagickString(buffer,MaxTextExtent, "rendering-intent=%s\n", MagickOptionToMnemonic(MagickIntentOptions,image->rendering_intent)); (void) WriteBlobString(image,buffer); } if (image->gamma != 0.0) { (void) FormatMagickString(buffer,MaxTextExtent,"gamma=%g\n", image->gamma); (void) WriteBlobString(image,buffer); } if (image->chromaticity.white_point.x != 0.0) { /* Note chomaticity points. */ (void) FormatMagickString(buffer,MaxTextExtent,"red-primary=" "%g,%g green-primary=%g,%g blue-primary=%g,%g\n", image->chromaticity.red_primary.x,image->chromaticity.red_primary.y, image->chromaticity.green_primary.x, image->chromaticity.green_primary.y, image->chromaticity.blue_primary.x, image->chromaticity.blue_primary.y); (void) WriteBlobString(image,buffer); (void) FormatMagickString(buffer,MaxTextExtent, "white-point=%g,%g\n",image->chromaticity.white_point.x, image->chromaticity.white_point.y); (void) WriteBlobString(image,buffer); } if (image->orientation != UndefinedOrientation) { (void) FormatMagickString(buffer,MaxTextExtent, "orientation=%s\n",MagickOptionToMnemonic(MagickOrientationOptions, image->orientation)); (void) WriteBlobString(image,buffer); } if (image->profiles != (void *) NULL) { const char *name; const StringInfo *profile; /* Generic profile. */ ResetImageProfileIterator(image); for (name=GetNextImageProfile(image); name != (const char *) NULL; ) { profile=GetImageProfile(image,name); if (profile != (StringInfo *) NULL) { (void) FormatMagickString(buffer,MaxTextExtent,"profile:%s=%lu\n", name,(unsigned long) GetStringInfoLength(profile)); (void) WriteBlobString(image,buffer); } name=GetNextImageProfile(image); } } if (image->montage != (char *) NULL) { (void) FormatMagickString(buffer,MaxTextExtent,"montage=%s\n", image->montage); (void) WriteBlobString(image,buffer); } ResetImagePropertyIterator(image); property=GetNextImageProperty(image); while (property != (const char *) NULL) { (void) FormatMagickString(buffer,MaxTextExtent,"%s=",property); (void) WriteBlobString(image,buffer); value=GetImageProperty(image,property); if (value != (const char *) NULL) { for (i=0; i < (long) strlen(value); i++) if (isspace((int) ((unsigned char) value[i])) != 0) break; if (i <= (long) strlen(value)) (void) WriteBlobByte(image,'{'); (void) WriteBlob(image,strlen(value),(unsigned char *) value); if (i <= (long) strlen(value)) (void) WriteBlobByte(image,'}'); } (void) WriteBlobByte(image,'\n'); property=GetNextImageProperty(image); } ResetImageArtifactIterator(image); (void) WriteBlobString(image,"\f\n:\032"); if (image->montage != (char *) NULL) { /* Write montage tile directory. */ if (image->directory != (char *) NULL) (void) WriteBlobString(image,image->directory); (void) WriteBlobByte(image,'\0'); } if (image->profiles != 0) { const char *name; const StringInfo *profile; /* Write image profiles. */ ResetImageProfileIterator(image); name=GetNextImageProfile(image); while (name != (const char *) NULL) { profile=GetImageProfile(image,name); (void) WriteBlob(image,GetStringInfoLength(profile), GetStringInfoDatum(profile)); name=GetNextImageProfile(image); } } if (image->storage_class == PseudoClass) { size_t packet_size; unsigned char *colormap, *q; /* Allocate colormap. */ packet_size=(size_t) (3UL*depth/8UL); colormap=(unsigned char *) AcquireQuantumMemory(image->colors, packet_size*sizeof(*colormap)); if (colormap == (unsigned char *) NULL) return(MagickFalse); /* Write colormap to file. */ q=colormap; for (i=0; i < (long) image->colors; i++) { switch (depth) { default: ThrowWriterException(CorruptImageError,"ImageDepthNotSupported"); case 32: { unsigned long pixel; pixel=ScaleQuantumToLong(image->colormap[i].red); q=PopLongPixel(MSBEndian,pixel,q); pixel=ScaleQuantumToLong(image->colormap[i].green); q=PopLongPixel(MSBEndian,pixel,q); pixel=ScaleQuantumToLong(image->colormap[i].blue); q=PopLongPixel(MSBEndian,pixel,q); } case 16: { unsigned short pixel; pixel=ScaleQuantumToShort(image->colormap[i].red); q=PopShortPixel(MSBEndian,pixel,q); pixel=ScaleQuantumToShort(image->colormap[i].green); q=PopShortPixel(MSBEndian,pixel,q); pixel=ScaleQuantumToShort(image->colormap[i].blue); q=PopShortPixel(MSBEndian,pixel,q); break; } case 8: { unsigned char pixel; pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].red); q=PopCharPixel(pixel,q); pixel=(unsigned char) ScaleQuantumToChar( image->colormap[i].green); q=PopCharPixel(pixel,q); pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].blue); q=PopCharPixel(pixel,q); break; } } } (void) WriteBlob(image,packet_size*image->colors,colormap); colormap=(unsigned char *) RelinquishMagickMemory(colormap); } /* Initialize persistent pixel cache. */ status=PersistPixelCache(image,cache_filename,MagickFalse,&offset, &image->exception); if (status == MagickFalse) ThrowWriterException(CacheError,"UnableToPersistPixelCache"); if (GetNextImageInList(image) == (Image *) NULL) break; image=SyncNextImageInList(image); if (image->progress_monitor != (MagickProgressMonitor) NULL) { status=image->progress_monitor(SaveImagesTag,scene, GetImageListLength(image),image->client_data); if (status == MagickFalse) break; } scene++; } while (image_info->adjoin != MagickFalse); (void) CloseBlob(image); return(status); }
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); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % I d e n t i f y I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % IdentifyImage() identifies an image by printing its attributes to the file. % Attributes include the image width, height, size, and others. % % The format of the IdentifyImage method is: % % MagickBooleanType IdentifyImage(Image *image,FILE *file, % const MagickBooleanType verbose) % % A description of each parameter follows: % % o image: The image. % % o file: The file, typically stdout. % % o verbose: A value other than zero prints more detailed information % about the image. % */ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file, const MagickBooleanType verbose) { #define IdentifyFormat " %s:\n Min: " QuantumFormat \ " (%g)\n Max: " QuantumFormat " (%g)\n" \ " Mean: %g (%g)\n Standard deviation: %g (%g)\n" char color[MaxTextExtent], format[MaxTextExtent], key[MaxTextExtent]; ColorspaceType colorspace; const char *property, *value; const MagickInfo *magick_info; const PixelPacket *pixels; double elapsed_time, user_time; ExceptionInfo *exception; Image *p; ImageType type; long y; MagickBooleanType ping; register long i, x; unsigned long scale; assert(image != (Image *) NULL); assert(image->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); if (file == (FILE *) NULL) file=stdout; *format='\0'; elapsed_time=GetElapsedTime(&image->timer); user_time=GetUserTime(&image->timer); GetTimerInfo(&image->timer); if (verbose == MagickFalse) { /* Display summary info about the image. */ if (*image->magick_filename != '\0') if (LocaleCompare(image->magick_filename,image->filename) != 0) (void) fprintf(file,"%s=>",image->magick_filename); if ((GetPreviousImageInList(image) == (Image *) NULL) && (GetNextImageInList(image) == (Image *) NULL) && (image->scene == 0)) (void) fprintf(file,"%s ",image->filename); else (void) fprintf(file,"%s[%lu] ",image->filename,image->scene); (void) fprintf(file,"%s ",image->magick); if ((image->magick_columns != 0) || (image->magick_rows != 0)) if ((image->magick_columns != image->columns) || (image->magick_rows != image->rows)) (void) fprintf(file,"%lux%lu=>",image->magick_columns, image->magick_rows); (void) fprintf(file,"%lux%lu ",image->columns,image->rows); if ((image->page.width != 0) || (image->page.height != 0) || (image->page.x != 0) || (image->page.y != 0)) (void) fprintf(file,"%lux%lu%+ld%+ld ",image->page.width, image->page.height,image->page.x,image->page.y); if (image->storage_class == DirectClass) { (void) fprintf(file,"DirectClass "); if (image->total_colors != 0) { (void) FormatMagickSize(image->total_colors,format); (void) fprintf(file,"%s ",format); } } else if (image->total_colors <= image->colors) (void) fprintf(file,"PseudoClass %luc ",image->colors); else (void) fprintf(file,"PseudoClass %lu=>%luc ",image->total_colors, image->colors); (void) fprintf(file,"%lu-bit ",image->depth); if (image->error.mean_error_per_pixel != 0.0) (void) fprintf(file,"%ld/%f/%fdb ", (long) (image->error.mean_error_per_pixel+0.5), image->error.normalized_mean_error, image->error.normalized_maximum_error); if (GetBlobSize(image) != 0) { (void) FormatMagickSize(GetBlobSize(image),format); (void) fprintf(file,"%s ",format); } if (elapsed_time > 0.06) (void) fprintf(file,"%0.3fu %ld:%02ld",user_time, (long) (elapsed_time/60.0+0.5),(long) ceil(fmod(elapsed_time,60.0))); (void) fprintf(file,"\n"); (void) fflush(file); return(ferror(file) != 0 ? MagickFalse : MagickTrue); } /* Display verbose info about the image. */ exception=AcquireExceptionInfo(); pixels=AcquireImagePixels(image,0,0,1,1,exception); exception=DestroyExceptionInfo(exception); ping=pixels == (const PixelPacket *) NULL ? MagickTrue : MagickFalse; type=GetImageType(image,&image->exception); (void) SignatureImage(image); (void) fprintf(file,"Image: %s\n",image->filename); if (*image->magick_filename != '\0') if (LocaleCompare(image->magick_filename,image->filename) != 0) { char filename[MaxTextExtent]; GetPathComponent(image->magick_filename,TailPath,filename); (void) fprintf(file," Base filename: %s\n",filename); } magick_info=GetMagickInfo(image->magick,&image->exception); if ((magick_info == (const MagickInfo *) NULL) || (*GetMagickDescription(magick_info) == '\0')) (void) fprintf(file," Format: %s\n",image->magick); else (void) fprintf(file," Format: %s (%s)\n",image->magick, GetMagickDescription(magick_info)); (void) fprintf(file," Class: %s\n", MagickOptionToMnemonic(MagickClassOptions,(long) image->storage_class)); (void) fprintf(file," Geometry: %lux%lu%+ld%+ld\n",image->columns, image->rows,image->tile_offset.x,image->tile_offset.y); if ((image->magick_columns != 0) || (image->magick_rows != 0)) if ((image->magick_columns != image->columns) || (image->magick_rows != image->rows)) (void) fprintf(file," Base geometry: %lux%lu\n",image->magick_columns, image->magick_rows); (void) fprintf(file," Type: %s\n",MagickOptionToMnemonic(MagickTypeOptions, (long) type)); (void) fprintf(file," Endianess: %s\n",MagickOptionToMnemonic( MagickEndianOptions,(long) image->endian)); /* Detail channel depth and extrema. */ colorspace=image->colorspace; if (IsGrayImage(image,&image->exception) != MagickFalse) colorspace=GRAYColorspace; (void) fprintf(file," Colorspace: %s\n", MagickOptionToMnemonic(MagickColorspaceOptions,(long) colorspace)); if (ping == MagickFalse) { ChannelStatistics *channel_statistics; (void) fprintf(file," Depth: %lu-bit\n",GetImageDepth(image, &image->exception)); channel_statistics=GetImageChannelStatistics(image,&image->exception); (void) fprintf(file," Channel depth:\n"); switch (colorspace) { case RGBColorspace: default: { (void) fprintf(file," Red: %lu-bit\n", channel_statistics[RedChannel].depth); (void) fprintf(file," Green: %lu-bit\n", channel_statistics[GreenChannel].depth); (void) fprintf(file," Blue: %lu-bit\n", channel_statistics[BlueChannel].depth); if (image->matte != MagickFalse) (void) fprintf(file," Alpha: %lu-bit\n", channel_statistics[OpacityChannel].depth); break; } case CMYKColorspace: { (void) fprintf(file," Cyan: %lu-bit\n", channel_statistics[CyanChannel].depth); (void) fprintf(file," Magenta: %lu-bit\n", channel_statistics[MagentaChannel].depth); (void) fprintf(file," Yellow: %lu-bit\n", channel_statistics[YellowChannel].depth); (void) fprintf(file," Black: %lu-bit\n", channel_statistics[BlackChannel].depth); if (image->matte != MagickFalse) (void) fprintf(file," Alpha: %lu-bit\n", channel_statistics[OpacityChannel].depth); break; } case GRAYColorspace: { (void) fprintf(file," Gray: %lu-bit\n", channel_statistics[GrayChannel].depth); if (image->matte != MagickFalse) (void) fprintf(file," Alpha: %lu-bit\n", channel_statistics[OpacityChannel].depth); break; } } scale=QuantumRange/((unsigned long) QuantumRange >> ((unsigned long) MAGICKCORE_QUANTUM_DEPTH-channel_statistics[AllChannels].depth)); (void) fprintf(file," Channel statistics:\n"); switch (colorspace) { case RGBColorspace: default: { (void) fprintf(file,IdentifyFormat,"Red",(Quantum) (channel_statistics[RedChannel].minima/scale),(double) channel_statistics[RedChannel].minima/(double) QuantumRange, (Quantum) (channel_statistics[RedChannel].maxima/scale),(double) channel_statistics[RedChannel].maxima/(double) QuantumRange, channel_statistics[RedChannel].mean/(double) scale, channel_statistics[RedChannel].mean/(double) QuantumRange, channel_statistics[RedChannel].standard_deviation/(double) scale, channel_statistics[RedChannel].standard_deviation/(double) QuantumRange); (void) fprintf(file,IdentifyFormat,"Green",(Quantum) (channel_statistics[GreenChannel].minima/scale),(double) channel_statistics[GreenChannel].minima/(double) QuantumRange, (Quantum) (channel_statistics[GreenChannel].maxima/scale),(double) channel_statistics[GreenChannel].maxima/(double) QuantumRange, channel_statistics[GreenChannel].mean/(double) scale, channel_statistics[GreenChannel].mean/(double) QuantumRange, channel_statistics[GreenChannel].standard_deviation/(double) scale, channel_statistics[GreenChannel].standard_deviation/(double) QuantumRange); (void) fprintf(file,IdentifyFormat,"Blue",(Quantum) (channel_statistics[BlueChannel].minima/scale),(double) channel_statistics[BlueChannel].minima/(double) QuantumRange, (Quantum) (channel_statistics[BlueChannel].maxima/scale),(double) channel_statistics[BlueChannel].maxima/(double) QuantumRange, channel_statistics[BlueChannel].mean/(double) scale, channel_statistics[BlueChannel].mean/(double) QuantumRange, channel_statistics[BlueChannel].standard_deviation/(double) scale, channel_statistics[BlueChannel].standard_deviation/(double) QuantumRange); break; } case CMYKColorspace: { (void) fprintf(file,IdentifyFormat,"Cyan",(Quantum) (channel_statistics[CyanChannel].minima/scale),(double) channel_statistics[CyanChannel].minima/(double) QuantumRange, (Quantum) (channel_statistics[CyanChannel].maxima/scale),(double) channel_statistics[CyanChannel].maxima/(double) QuantumRange, channel_statistics[CyanChannel].mean/(double) scale, channel_statistics[CyanChannel].mean/(double) QuantumRange, channel_statistics[CyanChannel].standard_deviation/(double) scale, channel_statistics[CyanChannel].standard_deviation/(double) QuantumRange); (void) fprintf(file,IdentifyFormat,"Magenta",(Quantum) (channel_statistics[MagentaChannel].minima/scale),(double) channel_statistics[MagentaChannel].minima/(double) QuantumRange, (Quantum) (channel_statistics[MagentaChannel].maxima/scale),(double) channel_statistics[MagentaChannel].maxima/(double) QuantumRange, channel_statistics[MagentaChannel].mean/(double) scale, channel_statistics[MagentaChannel].mean/(double) QuantumRange, channel_statistics[MagentaChannel].standard_deviation/(double) scale,channel_statistics[MagentaChannel].standard_deviation/(double) QuantumRange); (void) fprintf(file,IdentifyFormat,"Yellow",(Quantum) (channel_statistics[YellowChannel].minima/scale),(double) channel_statistics[YellowChannel].minima/(double) QuantumRange, (Quantum) (channel_statistics[YellowChannel].maxima/scale),(double) channel_statistics[YellowChannel].maxima/(double) QuantumRange, channel_statistics[YellowChannel].mean/(double) scale, channel_statistics[YellowChannel].mean/(double) QuantumRange, channel_statistics[YellowChannel].standard_deviation/(double) scale, channel_statistics[YellowChannel].standard_deviation/(double) QuantumRange); (void) fprintf(file,IdentifyFormat,"Black",(Quantum) (channel_statistics[BlackChannel].minima/scale),(double) channel_statistics[BlackChannel].minima/(double) QuantumRange, (Quantum) (channel_statistics[BlackChannel].maxima/scale),(double) channel_statistics[BlackChannel].maxima/(double) QuantumRange, channel_statistics[BlackChannel].mean/(double) scale, channel_statistics[BlackChannel].mean/(double) QuantumRange, channel_statistics[BlackChannel].standard_deviation/(double) scale, channel_statistics[BlackChannel].standard_deviation/(double) QuantumRange); break; } case GRAYColorspace: { (void) fprintf(file,IdentifyFormat,"Gray",(Quantum) (channel_statistics[GrayChannel].minima/scale),(double) channel_statistics[GrayChannel].minima/(double) QuantumRange, (Quantum) (channel_statistics[GrayChannel].maxima/scale),(double) channel_statistics[GrayChannel].maxima/(double) QuantumRange, channel_statistics[GrayChannel].mean/(double) scale, channel_statistics[GrayChannel].mean/(double) QuantumRange, channel_statistics[GrayChannel].standard_deviation/(double) scale, channel_statistics[GrayChannel].standard_deviation/(double) QuantumRange); break; } } if (image->matte != MagickFalse) (void) fprintf(file,IdentifyFormat,"Opacity",(Quantum) (channel_statistics[OpacityChannel].minima/scale),(double) channel_statistics[OpacityChannel].minima/(double) QuantumRange, (Quantum) (channel_statistics[OpacityChannel].maxima/scale),(double) channel_statistics[OpacityChannel].maxima/(double) QuantumRange, channel_statistics[OpacityChannel].mean/(double) scale, channel_statistics[OpacityChannel].mean/(double) QuantumRange, channel_statistics[OpacityChannel].standard_deviation/(double) scale, channel_statistics[OpacityChannel].standard_deviation/(double) QuantumRange); channel_statistics=(ChannelStatistics *) RelinquishMagickMemory( channel_statistics); if (colorspace == CMYKColorspace) (void) fprintf(file," Total ink density: %.0f%%\n",100.0* GetImageTotalInkDensity(image)/(double) QuantumRange); x=0; p=NewImageList(); if (image->matte != MagickFalse) { register const IndexPacket *indexes; register const PixelPacket *p; p=(PixelPacket *) NULL; indexes=(IndexPacket *) NULL; for (y=0; y < (long) image->rows; y++) { p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); if (p == (const PixelPacket *) NULL) break; indexes=AcquireIndexes(image); for (x=0; x < (long) image->columns; x++) { if (p->opacity == (Quantum) TransparentOpacity) break; p++; } if (x < (long) image->columns) break; } if ((x < (long) image->columns) || (y < (long) image->rows)) { char tuple[MaxTextExtent]; MagickPixelPacket pixel; GetMagickPixelPacket(image,&pixel); SetMagickPixelPacket(image,p,indexes+x,&pixel); (void) QueryMagickColorname(image,&pixel,SVGCompliance, MagickFalse,tuple,&image->exception); (void) fprintf(file," Alpha: %s ",tuple); (void) QueryMagickColorname(image,&pixel,SVGCompliance,MagickTrue, tuple,&image->exception); (void) fprintf(file," %s\n",tuple); } } if ((ping == MagickFalse) && (IsHistogramImage(image,&image->exception) != MagickFalse)) { (void) fprintf(file," Histogram:\n"); (void) GetNumberColors(image,file,&image->exception); } }