How to Convert from Bitmap to byte[] without Bitmap.Compress?

NicNic IDMember

Hi,

Just like the title says, how can I convert Bitmap object to byte[] without the use of Bitmap.Compress?

This is what I've done so far but failed on .ToArray() method.

ByteBuffer byteBuffer = ByteBuffer.Allocate(bitmap.ByteCount);
bitmap.CopyPixelsToBuffer(byteBuffer);
byte[] bytes = byteBuffer.ToArray<byte>();
return bytes;

with the following stack trace:

  at Android.Runtime.JNIEnv.AssertCompatibleArrayTypes (IntPtr sourceArray, System.Type destType) [0x0001a] in /Users/builder/data/lanes/monodroid-lion-bs1/0cc7ae3b/source/monodroid/src/Mono.Android/src/Runtime/JNIEnv.cs:581 
07-12 14:49:05.433 I/mono-stdout(12726):   at Android.Runtime.JNIEnv.AssertCompatibleArrayTypes (IntPtr sourceArray, System.Type destType) [0x0001a] in /Users/builder/data/lanes/monodroid-lion-bs1/0cc7ae3b/source/monodroid/src/Mono.Android/src/Runtime/JNIEnv.cs:581 

  at Android.Runtime.JNIEnv.GetArray[Byte] (IntPtr array_ptr) [0x00026] in /Users/builder/data/lanes/monodroid-lion-bs1/0cc7ae3b/source/monodroid/src/Mono.Android/src/Runtime/JNIEnv.cs:1000 
  at Java.Lang.Object.ToArray[Byte] () [0x00000] in /Users/builder/data/lanes/monodroid-lion-bs1/0cc7ae3b/source/monodroid/src/Mono.Android/src/Java.Lang/Object.cs:232 
  at Intersoft.Crosslight.Android.BitmapExtensions.ToByteArray (Android.Graphics.Bitmap bitmap) [0x00016] in d:\hpv-tfs12\ComponentProjects\Crosslight\Intersoft.Crosslight.Android\Extensions\BitmapExtensions.cs:16 
07-12 14:49:05.433 I/mono-stdout(12726):   at Android.Runtime.JNIEnv.GetArray[Byte] (IntPtr array_ptr) [0x00026] in /Users/builder/data/lanes/monodroid-lion-bs1/0cc7ae3b/source/monodroid/src/Mono.Android/src/Runtime/JNIEnv.cs:1000 
07-12 14:49:05.443 I/mono-stdout(12726):   at Java.Lang.Object.ToArray[Byte] () [0x00000] in /Users/builder/data/lanes/monodroid-lion-bs1/0cc7ae3b/source/monodroid/src/Mono.Android/src/Java.Lang/Object.cs:232 
07-12 14:49:05.443 I/mono-stdout(12726):   at Intersoft.Crosslight.Android.BitmapExtensions.ToByteArray (Android.Graphics.Bitmap bitmap) [0x00016] in d:\hpv-tfs12\ComponentProjects\Crosslight\Intersoft.Crosslight.Android\Extensions\BitmapExtensions.cs:16 

Any help would be appreciated. Thanks!

Posts

  • NicNic IDMember

    Note: I don't want to use this way because Bitmap.Compress really slows down performance.

    MemoryStream stream = new MemoryStream();
    bitmap.Compress(Bitmap.CompressFormat.Png, 0, stream);
    byte[] bitmapData = stream.ToArray();
    return bitmapData;
    
  • rmaciasrmacias USBeta, University ✭✭✭✭✭
    ByteBuffer byteBuffer = ByteBuffer.Allocate(bitmap.ByteCount);
    bitmap.CopyPixelsToBuffer(byteBuffer);
    byte[] bytes = byteBuffer.ToArray<byte>();
    return bytes;
    

    That code looks right to me. I have production code that does the exact same thing (different variable names of course), except that I have:

    var byteBuffer = ByteBuffer.Allocate(bitmap.ByteCount);

    I don't see why that would make a difference though.

  • NicNic IDMember

    Hi Ruben, yes, can I extract byte[] out of the buffer?

  • CheesebaronCheesebaron DKInsider, University mod

    @Nic have you even read @rmacias's answer? It is a byte array that is the result...

  • NicNic IDMember

    Hi Tomasz, yes I've read Ruben's answer. I mean, I've tried to do the same thing, but I got an error when trying to cast the ByteBuffer to byte[]. Referring to my first post (original question):

    ByteBuffer byteBuffer = ByteBuffer.Allocate(bitmap.ByteCount);
    bitmap.CopyPixelsToBuffer(byteBuffer);
    byte[] bytes = byteBuffer.ToArray<byte>();
    return bytes;
    

    This is what I've done so far but failed on .ToArray() method.

    at Android.Runtime.JNIEnv.AssertCompatibleArrayTypes (IntPtr sourceArray, System.Type destType) [0x0001a] in /Users/builder/data/lanes/monodroid-lion-bs1/0cc7ae3b/source/monodroid/src/Mono.Android/src/Runtime/JNIEnv.cs:581 
    07-12 14:49:05.433 I/mono-stdout(12726):   at Android.Runtime.JNIEnv.AssertCompatibleArrayTypes (IntPtr sourceArray, System.Type destType) [0x0001a] in /Users/builder/data/lanes/monodroid-lion-bs1/0cc7ae3b/source/monodroid/src/Mono.Android/src/Runtime/JNIEnv.cs:581 
    
          at Android.Runtime.JNIEnv.GetArray[Byte] (IntPtr array_ptr) [0x00026] in /Users/builder/data/lanes/monodroid-lion-bs1/0cc7ae3b/source/monodroid/src/Mono.Android/src/Runtime/JNIEnv.cs:1000 
          at Java.Lang.Object.ToArray[Byte] () [0x00000] in /Users/builder/data/lanes/monodroid-lion-bs1/0cc7ae3b/source/monodroid/src/Mono.Android/src/Java.Lang/Object.cs:232 
    

    So basically I guess something is wrong at my end then.

  • gregkogregko USMember

    Nic,
    I don't have a complete answer for you, but in situations like this it's good to look at the Java end of things, as these are Java classes, thinly wrapped by Xamarin C#. Look e.g. at http://developer.android.com/reference/java/nio/ByteBuffer.html, there are methods there like final byte[] array(); final int arrayOffset(); which "Returns the offset of the byte array which this buffer is based on, if there is one.", also check final boolean hasArray(); "Returns true if array and arrayOffset won't throw." Maybe you try to allocate a buffer which is too long and running out of memory? Or there is some error in CopyPixelsToBuffer() - can you check for error conditions after calling this function? No time here to look at for this...

    Greg

  • rmaciasrmacias USBeta, University ✭✭✭✭✭

    @Nic, just for kicks, try modifying your code like this and see if it works. If not, it's hard to tell what's going on without actually debugging your app. This is how my production code looks like and have zero issues with it.

    var byteBuffer = ByteBuffer.Allocate(bitmap.ByteCount);
    bitmap.CopyPixelsToBuffer(byteBuffer);
    var bytes = byteBuffer.ToArray<byte>();
    return bytes;
    
  • BoKingoDamgaardBoKingoDamgaard DKMember ✭✭

    Was there a solution to this? I have the same problem

    /Bo

  • NicholasNicholas USMember

    Hi Bo,

    I ended up writing the Bitmap to a temporary Java.IO.File cache, then extract the byte[] out of the File. I find it much faster.

  • bnybny BEBeta
    edited March 2014

    I encountered the same problem and figured it out, i thought i'd share my solution for others that get here with the same problem.
    it should be smth like this:
    var bytesize = bitmap.RowBytes * bitmap.Height; // or bitmap.ByteCount if target is api 12 or later var buffer = Java.Nio.ByteBuffer.Allocate(bytesize); bitmap.CopyPixelsToBuffer(buffer); buffer.Rewind(); var bytes = new byte[bytesize]; buffer.Get(bytes);

    but this is pretty expensive operation apparently, and may be too expensive if you're trying to load large/several bitmaps; going via a FileInputStream might be a better solution then :
    var imgFile = new Java.IO.File("//path/to/image/"); var stream = new Java.IO.FileInputStream(imgFile); var bytes = new byte[imgFile.Length()]; stream.Read(bytes);

  • DavidSchweglerDavidSchwegler USMember
    edited June 2014

    This is an old post, but I'll post a solution in case someone's looking for the answer.

    Since Xamarin's .ToArray() method doesn't work (and I don't think it's intended to), we can call the underlying array() method using JNI like so:

    ByteBuffer buffer = ByteBuffer.Allocate(bitmap.ByteCount);
    bitmap.CopyPixelsToBuffer(buffer);
    buffer.Rewind();
    
    IntPtr classHandle = JNIEnv.FindClass("java/nio/ByteBuffer");
    IntPtr methodId = JNIEnv.GetMethodID(classHandle, "array", "()[B");
    IntPtr resultHandle = JNIEnv.CallObjectMethod(buffer.Handle, methodId);
    byte[] result = JNIEnv.GetArray<byte>(resultHandle);
    JNIEnv.DeleteLocalRef(resultHandle);
    

    FYI, I've reported this bug to Xamarin here: https://bugzilla.xamarin.com/show_bug.cgi?id=20772

  • melankemelanke BRMember ✭✭
    edited August 2014

    thanks @bny and @DavidSchwegler‌
    It is not throwing an Exception anymore but when I try to revert back to Bitmap

    using (Bitmap bitmap = BitmapFactory.DecodeByteArray(bytes, 0, bytes.Length))
    {
        img.SetImageBitmap(bitmap);
    }
    

    the variable bitmap is null

    When I was using Compress this code was working

    Can you help me?

    Thanks

  • markgamachemarkgamache USBeta ✭✭
    edited October 2014

    I was having a related issue. I tried to convert a ByteBuffer without a backing array to Xamarin byte array.
    I got this to work:

    var xBytes = new byte[info.Size];
    byteBuffer.Get(xBytes,info.Offset,info.Size);
    

    But your method failed because the ByteBuffer I was using was not backed by an array. Just my $0.02

  • vibhavibha INMember
    edited July 2016

    Hoe to compress an Byte Array Image for Android?

  • MizanurRahman.0834MizanurRahman.0834 USMember ✭✭

    This is working for me
    byte[] bitmapData;
    using (var stream = new MemoryStream())
    {
    barcode.Compress(Bitmap.CompressFormat.Png, 0, stream);
    bitmapData = stream.ToArray();
    }

    Thanks

  • armanDeltaarmanDelta CAMember ✭✭

    @MizanurRahman.0834 said:
    This is working for me
    byte[] bitmapData;
    using (var stream = new MemoryStream())
    {
    barcode.Compress(Bitmap.CompressFormat.Png, 0, stream);
    bitmapData = stream.ToArray();
    }

    Thanks

    What is the barcode ?

  • gregfoxgregfox USMember ✭✭

    Here is the updated is working for me

    Bitmap b = null;
    byte[] bitmapData;
    using (var stream = new System.IO.MemoryStream())
    {
    b.Compress(Bitmap.CompressFormat.Png, 0, stream);
    bitmapData = stream.ToArray();
    }

  • Ajay87Ajay87 INMember ✭✭

    how to create image like (Circle,Rec,Triangle) using bitmap in xamarin forms

Sign In or Register to comment.