]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/blob.c
Added caNv, eXIf, and pHYs to the list of PNG chunks to be removed
[imagemagick] / MagickCore / blob.c
index d59f8a467ec14ade0235477af73e6c67044cfa69..4bd5c972496c906c395fb0c66ad3ba15ea50077b 100644 (file)
@@ -23,7 +23,7 @@
 %  You may not use this file except in compliance with the License.  You may  %
 %  obtain a copy of the License at                                            %
 %                                                                             %
-%    http://www.imagemagick.org/script/license.php                            %
+%    https://www.imagemagick.org/script/license.php                           %
 %                                                                             %
 %  Unless required by applicable law or agreed to in writing, software        %
 %  distributed under the License is distributed on an "AS IS" BASIS,          %
@@ -145,8 +145,8 @@ struct _BlobInfo
   StreamHandler
     stream;
 
-  UserBlobInfo
-    *user_info;
+  CustomStreamInfo
+    *custom_stream;
 
   unsigned char
     *data;
@@ -163,6 +163,25 @@ struct _BlobInfo
   size_t
     signature;
 };
+
+struct _CustomStreamInfo
+{
+  CustomStreamHandler
+    reader,
+    writer;
+
+  CustomStreamSeeker
+    seeker;
+
+  CustomStreamTeller
+    teller;
+
+  void
+    *data;
+
+  size_t
+    signature;
+};
 \f
 /*
   Forward declarations.
@@ -175,6 +194,44 @@ static int
 %                                                                             %
 %                                                                             %
 %                                                                             %
++   A c q u i r e C u s t o m S t r e a m I n f o                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireCustomStreamInfo() allocates the CustomStreamInfo structure.
+%
+%  The format of the AcquireCustomStreamInfo method is:
+%
+%      CustomStreamInfo *AcquireCustomStreamInfo(ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport CustomStreamInfo *AcquireCustomStreamInfo(
+  ExceptionInfo *magick_unused(exception))
+{
+  CustomStreamInfo
+    *custom_stream;
+
+  magick_unreferenced(exception);
+  custom_stream=(CustomStreamInfo *) AcquireMagickMemory(
+    sizeof(*custom_stream));
+  if (custom_stream == (CustomStreamInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(custom_stream,0,sizeof(*custom_stream));
+  custom_stream->signature=MagickCoreSignature;
+  return(custom_stream);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
 +   A t t a c h B l o b                                                       %
 %                                                                             %
 %                                                                             %
@@ -465,7 +522,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->custom_stream=blob_info->custom_stream;
   clone_info->data=blob_info->data;
   clone_info->debug=IsEventLogging();
   clone_info->reference_count=1;
@@ -549,7 +606,7 @@ MagickExport MagickBooleanType CloseBlob(Image *image)
         }
       break;
     }
-    case UserStream:
+    case CustomStream:
       break;
   }
   image->blob->status=status < 0 ? MagickTrue : MagickFalse;
@@ -600,7 +657,7 @@ MagickExport MagickBooleanType CloseBlob(Image *image)
         status=fclose(image->blob->file_info.file);
       break;
     }
-    case UserStream:
+    case CustomStream:
       break;
   }
   (void) DetachBlob(image->blob);
@@ -667,6 +724,40 @@ MagickExport void DestroyBlob(Image *image)
 %                                                                             %
 %                                                                             %
 %                                                                             %
++   D e s t r o y C u s t o m S t r e a m I n f o                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyCustomStreamInfo() destroys memory associated with the
+%  CustomStreamInfo structure.
+%
+%  The format of the DestroyCustomStreamInfo method is:
+%
+%      CustomStreamInfo *DestroyCustomStreamInfo(CustomStreamInfo *stream_info)
+%
+%  A description of each parameter follows:
+%
+%    o custom_stream: the custom stream info.
+%
+*/
+MagickExport CustomStreamInfo *DestroyCustomStreamInfo(
+  CustomStreamInfo *custom_stream)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(custom_stream != (CustomStreamInfo *) NULL);
+  assert(custom_stream->signature == MagickCoreSignature);
+  custom_stream->signature=(~MagickCoreSignature);
+  custom_stream=(CustomStreamInfo *) RelinquishMagickMemory(custom_stream);
+  return(custom_stream);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
 +   D e t a c h B l o b                                                       %
 %                                                                             %
 %                                                                             %
@@ -708,7 +799,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;
+  blob_info->custom_stream=(CustomStreamInfo *) NULL;
   return(data);
 }
 \f
@@ -925,7 +1016,7 @@ MagickExport int EOFBlob(const Image *image)
     }
     case BlobStream:
       break;
-    case UserStream:
+    case CustomStream:
       break;
   }
   return((int) image->blob->eof);
@@ -1055,7 +1146,7 @@ MagickExport void *FileToBlob(const char *filename,const size_t extent,
       blob[*length]='\0';
       return(blob);
     }
-  *length=(size_t) MagickMin(offset,(MagickOffsetType) 
+  *length=(size_t) MagickMin(offset,(MagickOffsetType)
     MagickMin(extent,SSIZE_MAX));
   blob=(unsigned char *) NULL;
   if (~(*length) >= (MagickPathExtent-1))
@@ -1426,8 +1517,23 @@ MagickExport MagickSizeType GetBlobSize(const Image *image)
       extent=(MagickSizeType) image->blob->length;
       break;
     }
-    case UserStream:
+    case CustomStream:
+    {
+      if ((image->blob->custom_stream->teller != (CustomStreamTeller) NULL) &&
+          (image->blob->custom_stream->seeker != (CustomStreamSeeker) NULL))
+        {
+          MagickOffsetType
+            offset;
+
+          offset=image->blob->custom_stream->teller(
+            image->blob->custom_stream->data);
+          extent=image->blob->custom_stream->seeker(0,SEEK_END,
+            image->blob->custom_stream->data);
+          image->blob->custom_stream->seeker(offset,SEEK_SET,
+            image->blob->custom_stream->data);
+        }
       break;
+    }
   }
   return(extent);
 }
@@ -1632,19 +1738,19 @@ MagickExport void *ImageToBlob(const ImageInfo *image_info,
 %                                                                             %
 %                                                                             %
 %                                                                             %
-+  I m a g e T o U s e r B l o b                                              %
++  I m a g e T o C u s t o m S t r e a m                                      %
 %                                                                             %
 %                                                                             %
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  ImageToUserBlob() is the equivalent of WriteImage(), but writes the
-%  formatted "file" to the suplied method rather than to an actual file.
+%  ImageToCustomStream() is the equivalent of WriteImage(), but writes the
+%  formatted "file" to the custom stream rather than to an actual file.
 %
-%  The format of the ImageToUserBlob method is:
+%  The format of the ImageToCustomStream method is:
 %
-%      void ImageToUserBlob(const ImageInfo *image_info,Image *image,
-%        UserBlobInfo *user_info,ExceptionInfo *exception)
+%      void ImageToCustomStream(const ImageInfo *image_info,Image *image,
+%        ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -1652,13 +1758,11 @@ MagickExport void *ImageToBlob(const ImageInfo *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)
+MagickExport void ImageToCustomStream(const ImageInfo *image_info,Image *image,
+  ExceptionInfo *exception)
 {
   const MagickInfo
     *magick_info;
@@ -1676,12 +1780,12 @@ MagickExport void ImageToUserBlob(const ImageInfo *image_info,Image *image,
       image_info->filename);
   assert(image != (Image *) NULL);
   assert(image->signature == MagickCoreSignature);
-  assert(user_info != (UserBlobInfo *) NULL);
-  assert(user_info->handler != (BlobHandler) NULL);
+  assert(image_info->custom_stream != (CustomStreamInfo *) NULL);
+  assert(image_info->custom_stream->signature == MagickCoreSignature);
+  assert(image_info->custom_stream->writer != (CustomStreamHandler) 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);
@@ -1689,7 +1793,7 @@ MagickExport void ImageToUserBlob(const ImageInfo *image_info,Image *image,
   if (magick_info == (const MagickInfo *) NULL)
     {
       (void) ThrowMagickException(exception,GetMagickModule(),
-        MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
+        MissingDelegateError,"NoEncodeDelegateForThisImageFormat","`%s'",
         image->magick);
       blob_info=DestroyImageInfo(blob_info);
       return;
@@ -1719,7 +1823,7 @@ MagickExport void ImageToUserBlob(const ImageInfo *image_info,Image *image,
       /*
         Write file to disk in blob image format.
       */
-      blob_info->user_info=(UserBlobInfo *) NULL;
+      blob_info->custom_stream=(CustomStreamInfo *) NULL;
       blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
         sizeof(*blob));
       if (blob == (unsigned char *) NULL)
@@ -1756,7 +1860,8 @@ MagickExport void ImageToUserBlob(const ImageInfo *image_info,Image *image,
               {
                 count=(ssize_t) fread(blob,sizeof(*blob),MagickMaxBufferExtent,
                   blob_info->file);
-                user_info->handler(blob,count,user_info->data);
+                image_info->custom_stream->writer(blob,count,
+                  image_info->custom_stream->data);
               }
             }
           (void) fclose(blob_info->file);
@@ -2030,19 +2135,19 @@ MagickExport void *ImagesToBlob(const ImageInfo *image_info,Image *images,
 %                                                                             %
 %                                                                             %
 %                                                                             %
-+  I m a g e s T o U s e r B l o b                                            %
++  I m a g e s T o C u s t o m 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.
+%  ImagesToCustomStream() is the equivalent of WriteImages(), but writes the
+%  formatted "file" to the custom stream rather than to an actual file.
 %
-%  The format of the ImageToUserBlob method is:
+%  The format of the ImageToCustomStream method is:
 %
-%      void ImagesToUserBlob(const ImageInfo *image_info,Image *images,
-%        UserBlobInfo *user_info,ExceptionInfo *exception)
+%      void ImagesToCustomStream(const ImageInfo *image_info,Image *images,
+%        ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -2050,13 +2155,11 @@ MagickExport void *ImagesToBlob(const ImageInfo *image_info,Image *images,
 %
 %    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)
+MagickExport void ImagesToCustomStream(const ImageInfo *image_info,
+  Image *images,ExceptionInfo *exception)
 {
   const MagickInfo
     *magick_info;
@@ -2074,11 +2177,12 @@ MagickExport void ImagesToUserBlob(const ImageInfo *image_info,Image *images,
       image_info->filename);
   assert(images != (Image *) NULL);
   assert(images->signature == MagickCoreSignature);
-  assert(user_info != (UserBlobInfo *) NULL);
-  assert(user_info->handler != (BlobHandler) NULL);
+  assert(image_info->custom_stream != (CustomStreamInfo *) NULL);
+  assert(image_info->custom_stream->signature == MagickCoreSignature);
+  assert(image_info->custom_stream->reader != (CustomStreamHandler) NULL);
+  assert(image_info->custom_stream->writer != (CustomStreamHandler) NULL);
   assert(exception != (ExceptionInfo *) NULL);
   blob_info=CloneImageInfo(image_info);
-  blob_info->user_info=user_info;
   (void) SetImageInfo(blob_info,(unsigned int) GetImageListLength(images),
     exception);
   if (*blob_info->magick != '\0')
@@ -2087,7 +2191,7 @@ MagickExport void ImagesToUserBlob(const ImageInfo *image_info,Image *images,
   if (magick_info == (const MagickInfo *) NULL)
     {
       (void) ThrowMagickException(exception,GetMagickModule(),
-        MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
+        MissingDelegateError,"NoEncodeDelegateForThisImageFormat","`%s'",
         images->magick);
       blob_info=DestroyImageInfo(blob_info);
       return;
@@ -2118,7 +2222,7 @@ MagickExport void ImagesToUserBlob(const ImageInfo *image_info,Image *images,
       /*
         Write file to disk in blob image format.
       */
-      blob_info->user_info=(UserBlobInfo *) NULL;
+      blob_info->custom_stream=(CustomStreamInfo *) NULL;
       blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
         sizeof(*blob));
       if (blob == (unsigned char *) NULL)
@@ -2155,7 +2259,8 @@ MagickExport void ImagesToUserBlob(const ImageInfo *image_info,Image *images,
               {
                 count=(ssize_t) fread(blob,sizeof(*blob),MagickMaxBufferExtent,
                   blob_info->file);
-                user_info->handler(blob,count,user_info->data);
+                image_info->custom_stream->writer(blob,count,
+                  image_info->custom_stream->data);
               }
             }
           (void) fclose(blob_info->file);
@@ -2266,8 +2371,8 @@ MagickExport MagickBooleanType InjectImageBlob(const ImageInfo *image_info,
       (void) RelinquishUniqueFileResource(filename);
       return(MagickFalse);
     }
-  (void) FormatLocaleString(byte_image->filename,MagickPathExtent,"%s:%s",format,
-    filename);
+  (void) FormatLocaleString(byte_image->filename,MagickPathExtent,"%s:%s",
+    format,filename);
   DestroyBlob(byte_image);
   byte_image->blob=CloneBlobInfo((BlobInfo *) NULL);
   write_info=CloneImageInfo(image_info);
@@ -2404,10 +2509,10 @@ MagickExport MagickBooleanType IsBlobSeekable(const Image *image)
       seekable=MagickFalse;
       break;
     }
-    case UserStream:
+    case CustomStream:
     {
-      if ((image->blob->user_info->seeker != (BlobSeeker) NULL) &&
-          (image->blob->user_info->teller != (BlobTeller) NULL))
+      if ((image->blob->custom_stream->seeker != (CustomStreamSeeker) NULL) &&
+          (image->blob->custom_stream->teller != (CustomStreamTeller) NULL))
         seekable=MagickTrue;
       else
         seekable=MagickFalse;
@@ -2717,10 +2822,11 @@ 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)
+  if ((image_info->custom_stream != (CustomStreamInfo *) NULL) &&
+      (*image->filename == '\0'))
     {
-      image->blob->type=UserStream;
-      image->blob->user_info=image_info->user_info;
+      image->blob->type=CustomStream;
+      image->blob->custom_stream=image_info->custom_stream;
       return(MagickTrue);
     }
   (void) DetachBlob(image->blob);
@@ -2738,7 +2844,7 @@ MagickExport MagickBooleanType OpenBlob(const ImageInfo *image_info,
     image->blob->synchronize=image_info->synchronize;
   if (image_info->stream != (StreamHandler) NULL)
     {
-      image->blob->stream=(StreamHandler) image_info->stream;
+      image->blob->stream=image_info->stream;
       if (*type == 'w')
         {
           image->blob->type=FifoStream;
@@ -3273,10 +3379,11 @@ MagickExport ssize_t ReadBlob(Image *image,const size_t length,void *data)
       (void) memcpy(q,p,(size_t) count);
       break;
     }
-    case UserStream:
+    case CustomStream:
     {
-      count=image->blob->user_info->handler(q,length,
-        image->blob->user_info->data);
+      if (image->blob->custom_stream->reader != (CustomStreamHandler) NULL)
+        count=image->blob->custom_stream->reader(q,length,
+          image->blob->custom_stream->data);
       break;
     }
   }
@@ -4340,13 +4447,12 @@ MagickExport MagickOffsetType SeekBlob(Image *image,
         }
       break;
     }
-    case UserStream:
+    case CustomStream:
     {
-      if (image->blob->user_info->seeker == (BlobSeeker) NULL)
+      if (image->blob->custom_stream->seeker == (CustomStreamSeeker) NULL)
         return(-1);
-      image->blob->user_info->seeker(offset,whence,
-        image->blob->user_info->data);
-      image->blob->offset=TellBlob(image);
+      image->blob->offset=image->blob->custom_stream->seeker(offset,whence,
+        image->blob->custom_stream->data);
       break;
     }
   }
@@ -4530,7 +4636,7 @@ MagickExport MagickBooleanType SetBlobExtent(Image *image,
         }
       break;
     }
-    case UserStream:
+    case CustomStream:
       break;
   }
   return(MagickTrue);
@@ -4541,6 +4647,170 @@ MagickExport MagickBooleanType SetBlobExtent(Image *image,
 %                                                                             %
 %                                                                             %
 %                                                                             %
++  S e t C u s t o m S t r e a m D a t a                                      %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetCustomStreamData() sets the stream info data member.
+%
+%  The format of the SetCustomStreamData method is:
+%
+%      void SetCustomStreamData(CustomStreamInfo *custom_stream,void *)
+%
+%  A description of each parameter follows:
+%
+%    o custom_stream: your custom stream.
+%
+%    o void: your data.
+%
+*/
+MagickExport void SetCustomStreamData(CustomStreamInfo *custom_stream,
+  void *data)
+{
+  assert(custom_stream != (CustomStreamInfo *) NULL);
+  assert(custom_stream->signature == MagickCoreSignature);
+  custom_stream->data=data;
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  S e t C u s t o m S t r e a m R e a d e r                                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetCustomStreamReader() sets the stream info reader member.
+%
+%  The format of the SetCustomStreamReader method is:
+%
+%      void SetCustomStreamReader(CustomStreamInfo *custom_stream,
+%        CustomStreamHandler reader)
+%
+%  A description of each parameter follows:
+%
+%    o custom_stream: your custom stream.
+%
+%    o reader: your custom stream reader.
+%
+*/
+MagickExport void SetCustomStreamReader(CustomStreamInfo *custom_stream,
+  CustomStreamHandler reader)
+{
+  assert(custom_stream != (CustomStreamInfo *) NULL);
+  assert(custom_stream->signature == MagickCoreSignature);
+  custom_stream->reader=reader;
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  S e t C u s t o m S t r e a m S e e k e r                                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetCustomStreamSeeker() sets the stream info seeker member.
+%
+%  The format of the SetCustomStreamReader method is:
+%
+%      void SetCustomStreamSeeker(CustomStreamInfo *custom_stream,
+%        CustomStreamSeeker seeker)
+%
+%  A description of each parameter follows:
+%
+%    o custom_stream: your custom stream.
+%
+%    o seeker: your custom stream seeker.
+%
+*/
+MagickExport void SetCustomStreamSeeker(CustomStreamInfo *custom_stream,
+  CustomStreamSeeker seeker)
+{
+  assert(custom_stream != (CustomStreamInfo *) NULL);
+  assert(custom_stream->signature == MagickCoreSignature);
+  custom_stream->seeker=seeker;
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  S e t C u s t o m S t r e a m T e l l e r                                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetCustomStreamTeller() sets the stream info teller member.
+%
+%  The format of the SetCustomStreamTeller method is:
+%
+%      void SetCustomStreamTeller(CustomStreamInfo *custom_stream,
+%        CustomStreamTeller *teller)
+%
+%  A description of each parameter follows:
+%
+%    o custom_stream: your custom stream.
+%
+%    o teller: your custom stream teller.
+%
+*/
+MagickExport void SetCustomStreamTeller(CustomStreamInfo *custom_stream,
+  CustomStreamTeller teller)
+{
+  assert(custom_stream != (CustomStreamInfo *) NULL);
+  assert(custom_stream->signature == MagickCoreSignature);
+  custom_stream->teller=teller;
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  S e t C u s t o m S t r e a m W r i t e r                                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetCustomStreamWriter() sets the stream info writer member.
+%
+%  The format of the SetCustomStreamWriter method is:
+%
+%      void SetCustomStreamWriter(CustomStreamInfo *custom_stream,
+%        CustomStreamHandler *writer)
+%
+%  A description of each parameter follows:
+%
+%    o custom_stream: your custom stream.
+%
+%    o writer: your custom stream writer.
+%
+*/
+MagickExport void SetCustomStreamWriter(CustomStreamInfo *custom_stream,
+  CustomStreamHandler writer)
+{
+  assert(custom_stream != (CustomStreamInfo *) NULL);
+  assert(custom_stream->signature == MagickCoreSignature);
+  custom_stream->writer=writer;
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
 +  S y n c B l o b                                                            %
 %                                                                             %
 %                                                                             %
@@ -4600,7 +4870,7 @@ static int SyncBlob(Image *image)
       break;
     case BlobStream:
       break;
-    case UserStream:
+    case CustomStream:
       break;
   }
   return(status);
@@ -4668,10 +4938,10 @@ MagickExport MagickOffsetType TellBlob(const Image *image)
       offset=image->blob->offset;
       break;
     }
-    case UserStream:
+    case CustomStream:
     {
-      if (image->blob->user_info->teller != (BlobTeller) NULL)
-        offset=image->blob->user_info->teller(image->blob->user_info->data);
+      if (image->blob->custom_stream->teller != (CustomStreamTeller) NULL)
+        offset=image->blob->custom_stream->teller(image->blob->custom_stream->data);
       break;
     }
   }
@@ -4723,34 +4993,29 @@ MagickExport MagickBooleanType UnmapBlob(void *map,const size_t length)
 %                                                                             %
 %                                                                             %
 %                                                                             %
-%   U s e r B l o b T o I m a g e                                             %
+%   C u s t o m S t r e a m T o I m a g e                                     %
 %                                                                             %
 %                                                                             %
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  UserBlobToImage() is the equivalent of ReadImage(), but reads the
+%  CustomStreamToImage() 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:
+%  The format of the CustomStreamToImage method is:
 %
-%      Image *BlobToImage(const ImageInfo *image_info,const void *blob,
-%        const size_t length,ExceptionInfo *exception)
+%      Image *CustomStreamToImage(const ImageInfo *image_info,
+%         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)
+MagickExport Image *CustomStreamToImage(const ImageInfo *image_info,
+  ExceptionInfo *exception)
 {
   const MagickInfo
     *magick_info;
@@ -4766,11 +5031,11 @@ MagickExport Image *UserBlobToImage(const ImageInfo *image_info,
   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(image_info->custom_stream != (CustomStreamInfo *) NULL);
+  assert(image_info->custom_stream->signature == MagickCoreSignature);
+  assert(image_info->custom_stream->reader != (CustomStreamHandler) NULL);
   assert(exception != (ExceptionInfo *) NULL);
   blob_info=CloneImageInfo(image_info);
-  blob_info->user_info=user_info;
   if (*blob_info->magick == '\0')
     (void) SetImageInfo(blob_info,0,exception);
   magick_info=GetMagickInfo(blob_info->magick,exception);
@@ -4783,15 +5048,13 @@ MagickExport Image *UserBlobToImage(const ImageInfo *image_info,
       return((Image *) NULL);
     }
   image=(Image *) NULL;
-  if (GetMagickBlobSupport(magick_info) != MagickFalse)
+  if ((GetMagickBlobSupport(magick_info) != MagickFalse) ||
+      (blob_info->custom_stream == (CustomStreamInfo *) NULL))
     {
       /*
-        Native blob support for this image format.
+        Native blob support for this image format or SetImageInfo changed the
+        blob to a file.
       */
-      (void) CopyMagickString(blob_info->filename,image_info->filename,
-        MagickPathExtent);
-      (void) CopyMagickString(blob_info->magick,image_info->magick,
-        MagickPathExtent);
       image=ReadImage(blob_info,exception);
       if (image != (Image *) NULL)
         (void) CloseBlob(image);
@@ -4813,7 +5076,7 @@ MagickExport Image *UserBlobToImage(const ImageInfo *image_info,
       /*
         Write data to file on disk.
       */
-      blob_info->user_info=(UserBlobInfo *) NULL;
+      blob_info->custom_stream=(CustomStreamInfo *) NULL;
       blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
         sizeof(*blob));
       if (blob == (unsigned char *) NULL)
@@ -4842,8 +5105,8 @@ MagickExport Image *UserBlobToImage(const ImageInfo *image_info,
           count=(ssize_t) MagickMaxBufferExtent;
           while (count == (ssize_t) MagickMaxBufferExtent)
           {
-            count=user_info->handler(blob,MagickMaxBufferExtent,
-              user_info->data);
+            count=image_info->custom_stream->reader(blob,MagickMaxBufferExtent,
+              image_info->custom_stream->data);
             count=(ssize_t) write(file,(const char *) blob,count);
           }
           (void) fclose(blob_info->file);
@@ -4921,11 +5184,11 @@ MagickExport ssize_t WriteBlob(Image *image,const size_t length,
 
   assert(image != (Image *) NULL);
   assert(image->signature == MagickCoreSignature);
-  assert(data != (const void *) NULL);
   assert(image->blob != (BlobInfo *) NULL);
   assert(image->blob->type != UndefinedStream);
   if (length == 0)
     return(0);
+  assert(data != (const void *) NULL);
   count=0;
   p=(const unsigned char *) data;
   switch (image->blob->type)
@@ -5064,10 +5327,11 @@ MagickExport ssize_t WriteBlob(Image *image,const size_t length,
       count=(ssize_t) length;
       break;
     }
-    case UserStream:
+    case CustomStream:
     {
-      count=image->blob->user_info->handler((const unsigned char *) data,
-        length,image->blob->user_info->data);
+      if (image->blob->custom_stream->writer != (CustomStreamHandler) NULL)
+        count=image->blob->custom_stream->writer((const unsigned char *) data,
+          length,image->blob->custom_stream->data);
       break;
     }
   }