Convert a byte array to a bitmap

Hi everyone,

I'm quite new on developing on Xamarin.Android.

I'm trying to convert an image that is in a byte array to a bitmap, just for being able to show it.

My image is not in the resources directory because it is taken from a blob field through a byte array.

I've tried this approach, but bitmap becomes always null.

    /// Loads a Bitmap from a byte array
    public static Bitmap bytesToBitmap (byte[] imageBytes)
    {

        Bitmap bitmap = BitmapFactory.DecodeByteArray(imageBytes, 0, imageBytes.Length);

        return bitmap;
    }

I know for fact that the images are correctly formed, because I use the same database in an iOS app and they are shown properly. I've inserted blob fields from jpg images.

Does anyone know the a form to convert my byte arrays to bitmaps?
Or any other form to show them through an imageView?

Answers

  • rmaciasrmacias USBeta, University ✭✭✭✭✭

    That's the way I do it, but my byte arrays are coming from a webservice, and not directly from a database. If DecodeByteArray is returning null, then that means it was not able to decode the byte array. Are you sure that the byte array is not being manipulated after your database call?

  • RogierKoningRogierKoning ESMember ✭✭

    Thanks @rmacias,

    Yes, I am sure that the byte array is not being manipulated after my database call. I use the same database call that I used in an iOS app without problems like this:

    ...

    byte[] imageBytes = DBFunctions.getRecipeBlobImage(idOfRecipe);
    Bitmap bitmap = Functions.bytesToBitmap(imageBytes);
    

    ...

    And I'm able to get the images correctly through my Mac if I open the .db3 file with a database management software.

    Is there any other form of showing an ImageView from a byte array without converting it to a Bitmap?

  • rmaciasrmacias USBeta, University ✭✭✭✭✭

    Don't know off the top of my head, but if DecodeByteArray is returning null, then there's something wrong with the bytes, or it is not in a format that DecodeByteArray is expecting it to be (in which the iOS equivalent is fine with). I've never had an issue with this method, as I've used it on several projects.

    private void OnGetMemberAvatarCompleted(byte[] avatarBytes)
    {
       var avatarImageView = FindViewById<ImageView>(Resource.Id.memberProfile_avatar);
       if (avatarImageView != null)
       {
          var imageBitmap = BitmapFactory.DecodeByteArray(avatarBytes, 0, avatarBytes.Length);
          RunOnUiThread(() => avatarImageView.SetImageBitmap(imageBitmap));
       }
    }
    
  • RogierKoningRogierKoning ESMember ✭✭

    Thank you again, @rmacias.

    I've given a look to my byte array and it starts with 255 216 255 224, the normal beginning of a jpeg image.

    Moreover, I get the database that is in my android device and open it with the Firefox SQLite Manager and I'm able to get all the images properly from de database.

    I'll keep on searching for a solution...

  • RogierKoningRogierKoning ESMember ✭✭

    I still searching for it. Maybe it's a problem with the bitmap decoder with CMYK images like here:
    https://code.google.com/p/skia/issues/detail?id=69

    I'll keep on searching for a solution...

  • rmaciasrmacias USBeta, University ✭✭✭✭✭

    Interesting.....if you can upload an example image that fails, I can try it out in my app and see if it renders. That'll at least confirm it is the issue in the link you provided.

  • RogierKoningRogierKoning ESMember ✭✭
    edited September 2013

    Thanks a lot @rmacias,

    I attach an image that fails when decoding to a bitmap.

  • Hi, I just came across this post as I'm a newbie too in Android development, but I have some experience with image processing. First of all, I read that you are using CMYK images. CMYK images are still often used in printing environments. My opinion is that you better convert your images to RGB, since displays don't work in the CMYK color space and instead of four color layers in CMYK, you have only three in RGB which will probably use less space.

    This will probably solve your issue.

    I don't know any freeware to convert CMYK images to RGB, but many commercial photo editing software will do.

  • ctschappatctschappat USMember

    I just ran across this thread...I am experiencing a pretty much identical problem. I have a byte[] that comes from a WCF service. I can successfully convert the array to a Bitmap in Windows Phone but the Bitmap is null when I use the DecodeByteArray method in an Android project.

  • RogierKoningRogierKoning ESMember ✭✭

    I'm still having the issue. Images are now all RGB formatted.

    Debugging the process of transforming the byte array the following error message is logged out (in some images, not all):

    [skia] --- decoder->decode returned false

    I'm trying to modify my code

        // Loads a Bitmap from a byte array
        public static Bitmap bytesToBitmap (byte[] imageBytes)
        {
            Bitmap bitmap = BitmapFactory.DecodeByteArray(imageBytes, 0, imageBytes.Length);
    
            return bitmap;
        }
    

    However, I am unable to change some workarounds I've found here from java to C#.
    Could anyone help me?

  • HasHas USMember

    I had a similar issue where I could see that I have a valid byte[] returned from the server but BitmapFactory.DecodeByteArray() returned null. When I switched to a different image, the issue is gone. I assume that the byte[] that I was getting from the server was not the valid image, maybe an error message or something.

    I hope this helps someone else :)

  • RogierKoningRogierKoning ESMember ✭✭

    Finally got it working!!!

    I had to make a workaround like this:

    /// Loads a Bitmap from a byte array
    
    public static Bitmap bytesToUIImage (byte[] bytes)
    {
        if (bytes == null)
            return null;
    
        Bitmap bitmap;
    
    
        var documentsFolder = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
    
        //Create a folder for the images if not exists
        System.IO.Directory.CreateDirectory(System.IO.Path.Combine (documentsFolder, "images"));
    
        string imatge = System.IO.Path.Combine (documents, "images", "image.jpg");
    
    
        System.IO.File.WriteAllBytes(imatge, bytes.Concat(new Byte[]{(byte)0xD9}).ToArray());
    
        bitmap = BitmapFactory.DecodeFile(imatge);
    
        return bitmap;
    }
    

    Note that the file created was missing the ending byte of a .jpeg file "D9" so I had to add it manually. I know for fact that my images had this byte included, and I also tried to generate the bitmap by adding "D9" to the byteArray with BitmapFactory.DecodeByteArray but it didn't work.

    So, the only workaround that works for me is creating a file from the byteArray and decoding that file. Hope it could help someone in the future.

  • mohammadomidvarmohammadomidvar USMember ✭✭
    edited September 2015

    @RogierKoning It seems your problem is solved. For those who still have this problem:
    I had the same problem and I found out the my byte array was incorrect. Because when I was saving the bitmap i had forgotten to write myStream.Flush().

  • MizanurRahman.0834MizanurRahman.0834 USMember ✭✭
    edited May 2017

    Call LoadAndResizeBitmap function inside required load method

    byte[] bitmapBinary;
    Bitmap bitmap = BitmapFactory.DecodeByteArray(bitmapBinary, 0, bitmapBinary.Length);
    var width=imageView.Width;
    var height=imageView.Height;
    using (Bitmap bitmap = App._file.Path.LoadAndResizeBitmap(width, height))
    {
    imageView.RecycleBitmap();
    imageView.SetImageBitmap(bitmap);
    }
    // Resize image and its orientation
    public static Bitmap LoadAndResizeBitmap(this string fileName, int width, int height)
    {
    BitmapFactory.Options options = new BitmapFactory.Options
    {
    InPurgeable = true,
    InJustDecodeBounds = true
    };
    BitmapFactory.DecodeFile(fileName, options);

            int outHeight = options.OutHeight;
            int outWidth = options.OutWidth;
            int inSampleSize = 1;
    
            if (outHeight > height || outWidth > width)
            {
                inSampleSize = outWidth > outHeight
                                   ? outHeight / height
                                   : outWidth / width;
            }
    
            options.InSampleSize = inSampleSize;
            options.InJustDecodeBounds = false;
            Bitmap resizedBitmap = BitmapFactory.DecodeFile(fileName, options);
    
            Matrix mtx = new Matrix();
            ExifInterface exif = new ExifInterface(fileName);
            string orientation = exif.GetAttribute(ExifInterface.TagOrientation);
    
            switch (orientation)
            {
                case "6":
                    mtx.PreRotate(90);
                    resizedBitmap = Bitmap.CreateBitmap(resizedBitmap, 0, 0, resizedBitmap.Width, resizedBitmap.Height, mtx, false);
                    mtx.Dispose();
                    mtx = null;
                    break;
                case "1":
                    break;
                default:
                    mtx.PreRotate(90);
                    resizedBitmap = Bitmap.CreateBitmap(resizedBitmap, 0, 0, resizedBitmap.Width, resizedBitmap.Height, mtx, false);
                    mtx.Dispose();
                    mtx = null;
                    break;
            }
    
            return resizedBitmap;
        }
    
  • WiechowatyWiechowaty Member
    edited January 2018

    Hello, I read your thread and struggled myself with the topic but I think I found a better solution than suggested above.
    In my application I stream images via UDP from PC.
    My images are grayscale but you can do the same with color images.

    So what I do to get the Bitmap is:

        Bitmap ArrayToBitmap(byte[] Image, int width, int height)
        {
            int[] RGBImage = new int[Image.Length];
            for (int i = 0; i < Image.Length; i++)
            {
                Color pixel = new Color(Image[i], Image[i], Image[i]);
                RGBImage[i++] = (int)pixel;
            }
    
            Bitmap createdBitmap = Bitmap.CreateBitmap(RGBImage, width, height, Bitmap.Config.Argb8888);
            return createdBitmap;
        }
    

    You can make this a lot faster if you combine it with loop unrolling and break the processing into multiple threads to make it fast.

Sign In or Register to comment.