Wednesday 28 November 2012

Image files in Virtual Volumes

In  a recent Real Studio project, I realised that I needed to save image files with a Virtual Volume. At first, I didn't give this any thought, I proceeded with my normal way of saving and loading the images. Little did I know at that time, but images cannot be saved in this way when using a Virtual Volume, so I needed to come up with a new method.
The best way I discovered to accomplish this is using a MemoryBlock as an intermediary class. Fortunately, the Picture class has a method called GetData and a shared method called FromData that allow us to transfer the image to and from a MemoryBlock.
So armed with this information, I first created a new save routine. I decided to extend the Picture class to help keep things neat:

Sub SaveToVirtualVolume(Extends MyPicture As Picture, file as FolderItem, format As String="public.png", quality As Integer=Picture.QualityDefault)

  'Create a new memory block with the data from the Picture class

  Dim m As MemoryBlock=MyPicture.GetData(format,quality)

  'Open a binary stream to the file, overwriting it if the file already exists
  Dim s As BinaryStream=BinaryStream.Create(file,True)
 
  'If the binary stream has successfully been opened, write out each 

  'byte from the memory block to the binary stream
 if s<>Nil then
    Dim Index As Integer=0
    while Index<m.Size
      s.WriteByte(m.Byte(Index))
      Index=Index+1
    wend
    s.Close
  end if
End Sub


As I normally use the PNG file type for images, I created this method to default to PNG should I not specify a format.
To read the image back from the Virtual Volume, I created a stand alone function, so that if the load failed, it would return a Nil object:

Function LoadImageFromVirtualVolume(file As FolderItem) As Picture
  'Create a new picture object to receive the image file

  Dim MyPicture As Picture

  'If there is a problem with the file passed to the
  'function, we should not attempt to load the image, 
  'and just return a Nil object
  if file<>Nil and file.Exists and not file.Directory then


    'Open the file as a binary stream and load it into a 
    'memory block that we create to hold the contents of the file
    Dim s As BinaryStream=BinaryStream.Open(file)
    if s<>Nil then

      'Create the new memory block with a size that matches the files contents
      Dim m As MemoryBlock=New MemoryBlock(s.Length)
      Dim Index As Integer=0
      while not s.EOF
        m.byte(Index)=s.ReadByte()
        Index=Index+1
      wend
      s.Close


      'Now simply use the FromData shared method to create 
      'the Picture object from the memoryblock contents
      MyPicture=Picture.FromData(m)
    end if
  end if


  'Return the object that is now either nil or the loaded image
  Return MyPicture

End Function

This is a very rough and ready way to accomplish what I am after, but now, when I have an image I need to save in a Virtual Volume, I simply use:

   MyImage.SaveToVirtualVolume(file)

or if I wish to save a JPEG, I could use:
   MyImage.SaveToVirtualVolume(file,Picture.FormatJPEG,Picture.QualityHigh)

To load an image back in from a Virtual Volume, I would use:

  MyImage=LoadImageFromVirtualVolume(file)

If the load was successful, then the variable MyImage would now contain the picture loaded, otherwise it would contain Nil.

Hope this is of some help to anyone who also encounters this minor oddity.