From: Dirk Lemstra Date: Fri, 27 Jan 2017 22:01:24 +0000 (+0100) Subject: Added new method that can be used to write an image with a user specified blob write... X-Git-Tag: 7.0.4-7~60 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=65cffae2e72b66faaa825239c1e9a6f443ae149a;p=imagemagick Added new method that can be used to write an image with a user specified blob write delegate. --- diff --git a/MagickCore/blob-private.h b/MagickCore/blob-private.h index 1282ebacd..5d62c813d 100644 --- a/MagickCore/blob-private.h +++ b/MagickCore/blob-private.h @@ -52,7 +52,8 @@ typedef enum ZipStream, BZipStream, FifoStream, - BlobStream + BlobStream, + UserStream } StreamType; extern MagickExport BlobInfo diff --git a/MagickCore/blob.c b/MagickCore/blob.c index a9fa88390..cb9a0e73a 100644 --- a/MagickCore/blob.c +++ b/MagickCore/blob.c @@ -145,6 +145,9 @@ struct _BlobInfo StreamHandler stream; + UserBlobInfo + *user_info; + unsigned char *data; @@ -462,6 +465,7 @@ MagickExport BlobInfo *CloneBlobInfo(const BlobInfo *blob_info) clone_info->file_info.file=blob_info->file_info.file; clone_info->properties=blob_info->properties; clone_info->stream=blob_info->stream; + clone_info->user_info=blob_info->user_info; clone_info->data=blob_info->data; clone_info->debug=IsEventLogging(); clone_info->reference_count=1; @@ -545,6 +549,8 @@ MagickExport MagickBooleanType CloseBlob(Image *image) } break; } + case UserStream: + break; } image->blob->status=status < 0 ? MagickTrue : MagickFalse; image->blob->size=GetBlobSize(image); @@ -594,6 +600,8 @@ MagickExport MagickBooleanType CloseBlob(Image *image) status=fclose(image->blob->file_info.file); break; } + case UserStream: + break; } (void) DetachBlob(image->blob); image->blob->status=status < 0 ? MagickTrue : MagickFalse; @@ -700,6 +708,7 @@ MagickExport void *DetachBlob(BlobInfo *blob_info) data=blob_info->data; blob_info->data=(unsigned char *) NULL; blob_info->stream=(StreamHandler) NULL; + blob_info->user_info=(UserBlobInfo*) NULL; return(data); } @@ -916,6 +925,8 @@ MagickExport int EOFBlob(const Image *image) } case BlobStream: break; + case UserStream: + break; } return((int) image->blob->eof); } @@ -1381,10 +1392,6 @@ MagickExport MagickSizeType GetBlobSize(const Image *image) switch (image->blob->type) { case UndefinedStream: - { - extent=image->blob->size; - break; - } case StandardStream: { extent=image->blob->size; @@ -1419,6 +1426,8 @@ MagickExport MagickSizeType GetBlobSize(const Image *image) extent=(MagickSizeType) image->blob->length; break; } + case UserStream: + break; } return(extent); } @@ -1623,6 +1632,143 @@ MagickExport void *ImageToBlob(const ImageInfo *image_info, % % % % % % ++ I m a g e T o U s e r B l o b % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% ImageToUserBlob() is the equivalent of WriteImage(), but writes the +% formatted "file" to the suplied method rather than to an actual file. +% +% The format of the ImageToUserBlob method is: +% +% void ImageToUserBlob(const ImageInfo *image_info,Image *image, +% UserBlobInfo *user_info,ExceptionInfo *exception) +% +% A description of each parameter follows: +% +% o image_info: the image info. +% +% o image: the image. +% +% o user_info: the methods to use when writing and seeking. +% +% o exception: return any errors or warnings in this structure. +% +*/ +MagickExport void ImageToUserBlob(const ImageInfo *image_info,Image *image, + UserBlobInfo *user_info,ExceptionInfo *exception) +{ + const MagickInfo + *magick_info; + + ImageInfo + *blob_info; + + MagickBooleanType + status; + + 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(image != (Image *) NULL); + assert(image->signature == MagickCoreSignature); + assert(user_info != (UserBlobInfo *) NULL); + assert(user_info->handler != (BlobHandler) NULL); + assert(exception != (ExceptionInfo *) NULL); + blob_info=CloneImageInfo(image_info); + blob_info->adjoin=MagickFalse; + blob_info->user_info=user_info; + (void) SetImageInfo(blob_info,1,exception); + if (*blob_info->magick != '\0') + (void) CopyMagickString(image->magick,blob_info->magick,MagickPathExtent); + magick_info=GetMagickInfo(image->magick,exception); + if (magick_info == (const MagickInfo *) NULL) + { + (void) ThrowMagickException(exception,GetMagickModule(), + MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'", + image->magick); + blob_info=DestroyImageInfo(blob_info); + return; + } + (void) CopyMagickString(blob_info->magick,image->magick,MagickPathExtent); + if (GetMagickBlobSupport(magick_info) != MagickFalse) + { + /* + Native blob support for this image format. + */ + (void) CloseBlob(image); + image->blob->user_info=user_info; + *image->filename='\0'; + status=WriteImage(blob_info,image,exception); + (void) CloseBlob(image); + } + else + { + char + unique[MagickPathExtent]; + + int + file; + + unsigned char + *blob; + + /* + Write file to disk in blob image format. + */ + blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent, + sizeof(*blob)); + if (blob == (unsigned char *) NULL) + { + ThrowFileException(exception,BlobError,"UnableToWriteBlob", + image_info->filename); + blob_info=DestroyImageInfo(blob_info); + return; + } + file=AcquireUniqueFileResource(unique); + if (file == -1) + { + ThrowFileException(exception,BlobError,"UnableToWriteBlob", + image_info->filename); + blob=(unsigned char *) RelinquishMagickMemory(blob); + blob_info=DestroyImageInfo(blob_info); + return; + } + blob_info->file=fdopen(file,"wb+"); + if (blob_info->file != (FILE *) NULL) + { + ssize_t + count; + + (void) FormatLocaleString(image->filename,MagickPathExtent, + "%s:%s",image->magick,unique); + status=WriteImage(blob_info,image,exception); + (void) CloseBlob(image); + (void) fseek(blob_info->file,0,SEEK_SET); + count=(ssize_t) MagickMaxBufferExtent; + while (count == (ssize_t) MagickMaxBufferExtent) + { + count=(ssize_t) fread(blob,sizeof(*blob),MagickMaxBufferExtent, + blob_info->file); + user_info->handler(blob,count,user_info->data); + } + (void) fclose(blob_info->file); + } + blob=(unsigned char *) RelinquishMagickMemory(blob); + (void) RelinquishUniqueFileResource(unique); + } + blob_info=DestroyImageInfo(blob_info); +} + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % % I m a g e T o F i l e % % % % % @@ -1875,6 +2021,147 @@ MagickExport void *ImagesToBlob(const ImageInfo *image_info,Image *images, blob_info=DestroyImageInfo(blob_info); return(blob); } + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % ++ I m a g e s T o U s e r B l o b % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% ImagesToUserBlob() is the equivalent of WriteImages(), but writes the +% formatted "file" to the suplied method rather than to an actual file. +% +% The format of the ImageToUserBlob method is: +% +% void ImagesToUserBlob(const ImageInfo *image_info,Image *images, +% UserBlobInfo *user_info,ExceptionInfo *exception) +% +% A description of each parameter follows: +% +% o image_info: the image info. +% +% o images: the image list. +% +% o user_info: the methods to use when writing and seeking. +% +% o exception: return any errors or warnings in this structure. +% +*/ +MagickExport void ImagesToUserBlob(const ImageInfo *image_info,Image *images, + UserBlobInfo *user_info,ExceptionInfo *exception) +{ + const MagickInfo + *magick_info; + + ImageInfo + *blob_info; + + MagickBooleanType + status; + + 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(images != (Image *) NULL); + assert(images->signature == MagickCoreSignature); + assert(user_info != (UserBlobInfo *) NULL); + assert(user_info->handler != (BlobHandler) NULL); + assert(exception != (ExceptionInfo *) NULL); + blob_info=CloneImageInfo(image_info); + blob_info->adjoin=MagickFalse; + blob_info->user_info=user_info; + (void) SetImageInfo(blob_info,(unsigned int) GetImageListLength(images), + exception); + if (*blob_info->magick != '\0') + (void) CopyMagickString(images->magick,blob_info->magick,MagickPathExtent); + magick_info=GetMagickInfo(images->magick,exception); + if (magick_info == (const MagickInfo *) NULL) + { + (void) ThrowMagickException(exception,GetMagickModule(), + MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'", + images->magick); + blob_info=DestroyImageInfo(blob_info); + return; + } + (void) CopyMagickString(blob_info->magick,images->magick,MagickPathExtent); + if (GetMagickBlobSupport(magick_info) != MagickFalse) + { + /* + Native blob support for this image format. + */ + (void) CloseBlob(images); + images->blob->user_info=user_info; + *images->filename='\0'; + status=WriteImages(blob_info,images,images->filename,exception); + (void) CloseBlob(images); + } + else + { + char + filename[MagickPathExtent], + unique[MagickPathExtent]; + + int + file; + + unsigned char + *blob; + + /* + Write file to disk in blob image format. + */ + blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent, + sizeof(*blob)); + if (blob == (unsigned char *) NULL) + { + ThrowFileException(exception,BlobError,"UnableToWriteBlob", + image_info->filename); + blob_info=DestroyImageInfo(blob_info); + return; + } + file=AcquireUniqueFileResource(unique); + if (file == -1) + { + ThrowFileException(exception,BlobError,"UnableToWriteBlob", + image_info->filename); + blob=(unsigned char *) RelinquishMagickMemory(blob); + blob_info=DestroyImageInfo(blob_info); + return; + } + blob_info->file=fdopen(file,"wb+"); + if (blob_info->file != (FILE *) NULL) + { + ssize_t + count; + + (void) FormatLocaleString(filename,MagickPathExtent,"%s:%s", + images->magick,unique); + status=WriteImages(blob_info,images,filename,exception); + (void) CloseBlob(images); + (void) fseek(blob_info->file,0,SEEK_SET); + count=(ssize_t) MagickMaxBufferExtent; + while (count == (ssize_t) MagickMaxBufferExtent) + { + count=(ssize_t) fread(blob,sizeof(*blob),MagickMaxBufferExtent, + blob_info->file); + user_info->handler(blob,count,user_info->data); + } + (void) fclose(blob_info->file); + } + blob=(unsigned char *) RelinquishMagickMemory(blob); + (void) RelinquishUniqueFileResource(unique); + } + blob_info=DestroyImageInfo(blob_info); + return; +} + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -2102,11 +2389,25 @@ MagickExport MagickBooleanType IsBlobSeekable(const Image *image) seekable=MagickTrue; break; } + case UndefinedStream: + case StandardStream: + case BZipStream: + case FifoStream: + case PipeStream: default: { seekable=MagickFalse; break; } + case UserStream: + { + if ((image->blob->user_info->seeker != (BlobSeeker) NULL) && + (image->blob->user_info->teller != (BlobTeller) NULL)) + seekable=MagickTrue; + else + seekable=MagickFalse; + break; + } } return(seekable); } @@ -2411,6 +2712,12 @@ MagickExport MagickBooleanType OpenBlob(const ImageInfo *image_info, AttachBlob(image->blob,image_info->blob,image_info->length); return(MagickTrue); } + if (image_info->user_info != (UserBlobInfo *) NULL) + { + image->blob->type=UserStream; + image->blob->user_info=image_info->user_info; + return(MagickTrue); + } (void) DetachBlob(image->blob); switch (mode) { @@ -2961,6 +3268,12 @@ MagickExport ssize_t ReadBlob(Image *image,const size_t length,void *data) (void) memcpy(q,p,(size_t) count); break; } + case UserStream: + { + count=image->blob->user_info->handler(q,length, + image->blob->user_info->data); + break; + } } return(count); } @@ -4022,6 +4335,15 @@ MagickExport MagickOffsetType SeekBlob(Image *image, } break; } + case UserStream: + { + if (image->blob->user_info->seeker == (BlobSeeker) NULL) + return(-1); + image->blob->user_info->seeker(offset,whence, + image->blob->user_info->data); + image->blob->offset=TellBlob(image); + break; + } } return(image->blob->offset); } @@ -4203,6 +4525,8 @@ MagickExport MagickBooleanType SetBlobExtent(Image *image, } break; } + case UserStream: + break; } return(MagickTrue); } @@ -4271,6 +4595,8 @@ static int SyncBlob(Image *image) break; case BlobStream: break; + case UserStream: + break; } return(status); } @@ -4337,6 +4663,12 @@ MagickExport MagickOffsetType TellBlob(const Image *image) offset=image->blob->offset; break; } + case UserStream: + { + if (image->blob->user_info->teller != (BlobTeller) NULL) + offset=image->blob->user_info->teller(image->blob->user_info->data); + break; + } } return(offset); } @@ -4386,6 +4718,170 @@ MagickExport MagickBooleanType UnmapBlob(void *map,const size_t length) % % % % % % +% U s e r B l o b T o I m a g e % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% UserBlobToImage() is the equivalent of ReadImage(), but reads the +% formatted "file" from the suplied method rather than to an actual file. +% +% The format of the BlobToImage method is: +% +% Image *BlobToImage(const ImageInfo *image_info,const void *blob, +% const size_t length,ExceptionInfo *exception) +% +% A description of each parameter follows: +% +% o image_info: the image info. +% +% o blob: the address of a character stream in one of the image formats +% understood by ImageMagick. +% +% o length: This size_t integer reflects the length in bytes of the blob. +% +% o exception: return any errors or warnings in this structure. +% +*/ +MagickExport Image *UserBlobToImage(const ImageInfo *image_info, + UserBlobInfo *user_info,ExceptionInfo *exception) +{ + const MagickInfo + *magick_info; + + Image + *image; + + ImageInfo + *blob_info; + + MagickBooleanType + status; + + assert(image_info != (ImageInfo *) NULL); + assert(image_info->signature == MagickCoreSignature); + if (image_info->debug != MagickFalse) + (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", + image_info->filename); + assert(user_info != (UserBlobInfo *) NULL); + assert(user_info->handler != (BlobHandler) NULL); + assert(exception != (ExceptionInfo *) NULL); + blob_info=CloneImageInfo(image_info); + if (*blob_info->magick == '\0') + (void) SetImageInfo(blob_info,0,exception); + magick_info=GetMagickInfo(blob_info->magick,exception); + if (magick_info == (const MagickInfo *) NULL) + { + (void) ThrowMagickException(exception,GetMagickModule(), + MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'", + blob_info->magick); + blob_info=DestroyImageInfo(blob_info); + return((Image *) NULL); + } + if (GetMagickBlobSupport(magick_info) != MagickFalse) + { + /* + Native blob support for this image format. + */ + (void) CopyMagickString(blob_info->filename,image_info->filename, + MagickPathExtent); + (void) CopyMagickString(blob_info->magick,image_info->magick, + MagickPathExtent); + blob_info->user_info=user_info; + image=ReadImage(blob_info,exception); + if (image != (Image *) NULL) + (void) DetachBlob(image->blob); + } + else + { + char + unique[MagickPathExtent]; + + int + file; + + ImageInfo + *clone_info; + + unsigned char + *blob; + + /* + Write data to file on disk. + */ + blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent, + sizeof(*blob)); + if (blob == (unsigned char *) NULL) + { + ThrowFileException(exception,BlobError,"UnableToReadBlob", + image_info->filename); + blob_info=DestroyImageInfo(blob_info); + return((Image *) NULL); + } + file=AcquireUniqueFileResource(unique); + if (file == -1) + { + ThrowFileException(exception,BlobError,"UnableToReadBlob", + image_info->filename); + blob=(unsigned char *) RelinquishMagickMemory(blob); + blob_info=DestroyImageInfo(blob_info); + return((Image *) NULL); + } + clone_info=CloneImageInfo(blob_info); + blob_info->file=fdopen(file,"wb+"); + if (blob_info->file != (FILE *) NULL) + { + size_t + length; + + ssize_t + count; + + count=(ssize_t) MagickMaxBufferExtent; + while (count == (ssize_t) MagickMaxBufferExtent) + { + count=user_info->handler(blob,MagickMaxBufferExtent, + user_info->data); + count=(ssize_t) write(file,(const char *) blob,count); + } + (void) fclose(blob_info->file); + (void) FormatLocaleString(clone_info->filename,MagickPathExtent, + "%s:%s",blob_info->magick,unique); + image=ReadImage(clone_info,exception); + clone_info=DestroyImageInfo(clone_info); + if (image != (Image *) NULL) + { + Image + *images; + + /* + Restore original filenames and image format. + */ + for (images=GetFirstImageInList(image); images != (Image *) NULL; ) + { + (void) CopyMagickString(images->filename,image_info->filename, + MagickPathExtent); + (void) CopyMagickString(images->magick_filename, + image_info->filename,MagickPathExtent); + (void) CopyMagickString(images->magick,magick_info->name, + MagickPathExtent); + images=GetNextImageInList(images); + } + } + } + blob=(unsigned char *) RelinquishMagickMemory(blob); + (void) RelinquishUniqueFileResource(unique); + } + blob_info=DestroyImageInfo(blob_info); + return(image); +} + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % + W r i t e B l o b % % % % % @@ -4564,6 +5060,13 @@ MagickExport ssize_t WriteBlob(Image *image,const size_t length, if (image->blob->offset >= (MagickOffsetType) image->blob->length) image->blob->length=(size_t) image->blob->offset; count=(ssize_t) length; + break; + } + case UserStream: + { + count=image->blob->user_info->handler((const unsigned char *) data, + length,image->blob->user_info->data); + break; } } return(count); diff --git a/MagickCore/blob.h b/MagickCore/blob.h index a7a91beed..c2f3e5eb6 100644 --- a/MagickCore/blob.h +++ b/MagickCore/blob.h @@ -18,6 +18,8 @@ #ifndef MAGICKCORE_BLOB_H #define MAGICKCORE_BLOB_H +typedef struct _UserBlobInfo UserBlobInfo; + #include "MagickCore/image.h" #include "MagickCore/stream.h" @@ -34,12 +36,38 @@ typedef enum IOMode } MapMode; +typedef ssize_t + (*BlobHandler)(const unsigned char *,const size_t,const void *); + +typedef size_t + (*BlobSeeker)(const MagickOffsetType offset,const int whence,const void *); + +typedef MagickOffsetType + (*BlobTeller)(const void *); + +struct _UserBlobInfo +{ + BlobHandler + handler; + + BlobSeeker + seeker; + + BlobTeller + teller; + + void + *data; +}; + extern MagickExport FILE *GetBlobFileHandle(const Image *); extern MagickExport Image *BlobToImage(const ImageInfo *,const void *,const size_t,ExceptionInfo *), - *PingBlob(const ImageInfo *,const void *,const size_t,ExceptionInfo *); + *PingBlob(const ImageInfo *,const void *,const size_t,ExceptionInfo *), + *UserBlobToImage(const ImageInfo *image_info,UserBlobInfo *user_info, + ExceptionInfo *exception); extern MagickExport MagickBooleanType BlobToFile(char *,const void *,const size_t,ExceptionInfo *), @@ -64,7 +92,9 @@ extern MagickExport void DuplicateBlob(Image *,const Image *), *FileToBlob(const char *,const size_t,size_t *,ExceptionInfo *), *ImageToBlob(const ImageInfo *,Image *,size_t *,ExceptionInfo *), + ImageToUserBlob(const ImageInfo *,Image *,UserBlobInfo *,ExceptionInfo *), *ImagesToBlob(const ImageInfo *,Image *,size_t *,ExceptionInfo *), + ImagesToUserBlob(const ImageInfo *,Image *,UserBlobInfo *,ExceptionInfo *), SetBlobExempt(Image *,const MagickBooleanType); #if defined(__cplusplus) || defined(c_plusplus) diff --git a/MagickCore/image.c b/MagickCore/image.c index 1b1bdc15b..48e940b61 100644 --- a/MagickCore/image.c +++ b/MagickCore/image.c @@ -996,6 +996,7 @@ MagickExport ImageInfo *CloneImageInfo(const ImageInfo *image_info) SetImageInfoFile(clone_info,image_info->file); SetImageInfoBlob(clone_info,image_info->blob,image_info->length); clone_info->stream=image_info->stream; + clone_info->user_info=image_info->user_info; (void) CopyMagickString(clone_info->magick,image_info->magick, MagickPathExtent); (void) CopyMagickString(clone_info->unique,image_info->unique, diff --git a/MagickCore/image.h b/MagickCore/image.h index 6fa5b13bf..3687e9462 100644 --- a/MagickCore/image.h +++ b/MagickCore/image.h @@ -477,6 +477,9 @@ struct _ImageInfo size_t signature; + + UserBlobInfo + *user_info; }; extern MagickExport ChannelType