Search code examples
xamarinxamarin.formsmemorystreamsignaturepad

Xamarin.Forms MemoryStream Manipulation. Why is Android different from iOS?


So am using the SignaturePad.PCL nuget package and you can recover a Stream from the plugin that takes the Draw Points and creates an image. Then I am passing that image across to a web service as a base 64 string and displaying it in a web app. Well I found that I was able to get the conversion to base 64 string working like this

//This works on android but not iOS
string base64Str = Convert.ToBase64String(((MemoryStream) theStream).ToArray());


//Works on iOS but not android
string base64Str = Convert.ToBase64String(StreamConvert(theStream));
private byte[] StreamConvert(Stream stream){
  using (var ms = new MemoryStream())
        {
            stream.CopyTo(ms);
            return ms.ToArray();
        }​
     }


//For both I use this, unless someone else can figure out a cross platform solution
string base64Str = Convert.ToBase64String(Device.OS == TargetPlatform.Android ? ((MemoryStream) theStream).ToArray() : StreamConvert(theStream));

Anyone know why there is a difference?


Solution

  • I took a quick look at the SignaturePad's source code (found here) and reviewed how the Android and iOS version handle the image it creates.

    The main difference is that on Android you get a Bitmap object and on iOS you get an UIImage object from the SignaturePad's GetImage() method. See here for Android GetImage and here for iOS GetImage().

    iOS

    Let's drill down into UIImage first (see UIImage here).

    Taking a look at how UIImage generates it image, you'll find there are several methods that will return an NSData object: ToJPEG() and ToPNG().

    Taking a look at NSData API reference, it has a ToStream() method which returns a Stream object.

    Android

    Okay, now onto Android!

    I found the Bitmap API docs here. You either get a another Bitmap (from the CreateBitmap methods), a Buffer (from the CopyBuffer methods) or Compress / CompressAsync.

    Compress and CompressAsync let you pass in a writeable stream object like MemoryStream as the 3rd parameter. Here's an example (from jzeferino's comment):

    var stream = new System.IO.MemoryStream(); imageBitpmap.Compress(Bitmap.CompressFormat.Jpeg, 100, stream);

    Hopefully this helps clarify what SignaturePad is doing when it gives you an image.