]> granicus.if.org Git - imagemagick/commitdiff
Added new method that can be used to write an image with a user specified blob write...
authorDirk Lemstra <dirk@git.imagemagick.org>
Fri, 27 Jan 2017 22:01:24 +0000 (23:01 +0100)
committerDirk Lemstra <dirk@git.imagemagick.org>
Fri, 27 Jan 2017 22:19:58 +0000 (23:19 +0100)
MagickCore/blob-private.h
MagickCore/blob.c
MagickCore/blob.h
MagickCore/image.c
MagickCore/image.h

index 1282ebacdfa15643b1ce0abf6e12e2d7674deb3c..5d62c813d829a1f6fa2f533202ae037d2158c3c4 100644 (file)
@@ -52,7 +52,8 @@ typedef enum
   ZipStream,
   BZipStream,
   FifoStream,
-  BlobStream
+  BlobStream,
+  UserStream
 } StreamType;
 
 extern MagickExport BlobInfo
index a9fa88390590ef95420bf8d6f4761cd0c4100e0b..cb9a0e73a112dce04c00f1c33d2c6626b2860064 100644 (file)
@@ -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);
 }
 \f
@@ -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);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
 %   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);
 }
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  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;
+}
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -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);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
 +  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);
index a7a91beed3f0508266652dd8ae6fe0a9806689dd..c2f3e5eb644dc8701f1cf664dc15cda34a269e26 100644 (file)
@@ -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)
index 1b1bdc15b87e8b944881c41dffcdf347d4e67c75..48e940b6131e26ab2d75d0d05cc9531cfa892899 100644 (file)
@@ -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,
index 6fa5b13bf5eea0cb04b442279fdf9b0332f7d9db..3687e9462f7ac20c97cc02091157296c97e0c980 100644 (file)
@@ -477,6 +477,9 @@ struct _ImageInfo
 
   size_t
     signature;
+
+  UserBlobInfo
+    *user_info;
 };
 
 extern MagickExport ChannelType