Forum Xamarin.Forms
We are excited to announce that the Xamarin Forums are moving to the new Microsoft Q&A experience. Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

We encourage you to head over to Microsoft Q&A for .NET for posting new questions and get involved today.

Stride or DPI issues with ImageSource.FromStream

Hope someone can point me in the right direction with this.

I'm receiving VP8 Encoded images and decoding them to a byte array. This is with libvpx. Then using ImageSource.FromStream to create an ImageSource.

It looks like the decoded byte array doesn't have a header as the image was empty so i manually add one. This gives me a result but it looks like there's something up with the stride or dpi in the header i'm creating.

Strange i have to add a header as in Android Studio i just make an image from the decoded bytes and it shows normally. Same as in my WPF application. Must be different things under the hood i guess?

This is the code in Xamarin Forms:

byte[] imageBytes = data.vdecoder[index].Decode(userBytes, out screenWidth, out screenHeight);
    byte[] getBytes = GetBitmap(imageBytes, screenWidth, screenHeight);

    var DesktopImage = ImageSource.FromStream(() => new MemoryStream(getBytes));
           //ImageSource DesktopImage = Imaging.BitmapSource.Create((int)screenWidth, (int)screenHeight, 96, 96, PixelFormats.Bgr24, null, image, (int)screenWidth * 3);
    if (DesktopImage != null)
    {
        data.studentScreen[index].Source = DesktopImage;
        data.FPSInCount++;
     }
     imageBytes = null;
     GC.Collect();
     GC.WaitForPendingFinalizers();

This is the function to add the header. Found online by some very helpful person.

    byte[] GetBitmap(byte[] bytesIn, int width, int height)
    {
        #region Bitmap Making...

        int BmpBufferSize = bytesIn.Length;

        // BmpBufferSize : a pure length of raw bitmap data without the header.
        // the 54 value here is the length of bitmap header.
        byte[] BitmapBytes = new byte[BmpBufferSize + 54];

        #region Bitmap Header

        // 0~2 "BM"
        BitmapBytes[0] = 0x42;
        BitmapBytes[1] = 0x4d;

        // 2~6 Size of the BMP file - Bit cound + Header 54
        Array.Copy(BitConverter.GetBytes(BmpBufferSize + 54), 0, BitmapBytes, 2, 4);

        // 6~8 Application Specific : normally, set zero
        Array.Copy(BitConverter.GetBytes(0), 0, BitmapBytes, 6, 2);

        // 8~10 Application Specific : normally, set zero
        Array.Copy(BitConverter.GetBytes(0), 0, BitmapBytes, 8, 2);

        // 10~14 Offset where the pixel array can be found - 24bit bitmap data always starts at 54 offset.
        Array.Copy(BitConverter.GetBytes(54), 0, BitmapBytes, 10, 4);
        #endregion

        #region DIB Header
        // 14~18 Number of bytes in the DIB header. 40 bytes constant.
        Array.Copy(BitConverter.GetBytes(40), 0, BitmapBytes, 14, 4);

        // 18~22 Width of the bitmap.
        Array.Copy(BitConverter.GetBytes(width), 0, BitmapBytes, 18, 4);

        // 22~26 Height of the bitmap.
        Array.Copy(BitConverter.GetBytes(-height), 0, BitmapBytes, 22, 4);

        // 26~28 Number of color planes being used
        Array.Copy(BitConverter.GetBytes(0), 0, BitmapBytes, 26, 2);

        // 28~30 Number of bits. If you don't know the pixel format, trying to calculate it with the quality of the video/image source.
        Array.Copy(BitConverter.GetBytes(24), 0, BitmapBytes, 28, 2);

        // 30~34 BI_RGB no pixel array compression used : most of the time, just set zero if it is raw data.
        Array.Copy(BitConverter.GetBytes(0), 0, BitmapBytes, 30, 4);

        // 34~38 Size of the raw bitmap data ( including padding )
        Array.Copy(BitConverter.GetBytes(BmpBufferSize), 0, BitmapBytes, 34, 4);

        // 38~46 Print resolution of the image, 72 DPI x 39.3701 inches per meter yields *****************************************************************
        Array.Copy(BitConverter.GetBytes(0), 0, BitmapBytes, 38, 4);
        Array.Copy(BitConverter.GetBytes(0), 0, BitmapBytes, 42, 4);

        // 46~50 Number of colors in the palette
        Array.Copy(BitConverter.GetBytes(0), 0, BitmapBytes, 46, 4);

        // 50~54 means all colors are important
        Array.Copy(BitConverter.GetBytes(0), 0, BitmapBytes, 50, 4);

        // 54~end : Pixel Data : Finally, time to combine your raw data, BmpBuffer in this code, with a bitmap header you've just created.
        Array.Copy(bytesIn as Array, 0, BitmapBytes, 54, BmpBufferSize);

        return BitmapBytes;

        #endregion - bitmap header process

        #endregion - bitmap making process        
    }

Here is how the image looks when rendered:

looks like a can't post a link to the image? there are 3 squashed up images in 1 that only take up half the area. rest is black

If i divide the width in the header by 3 (just to see what happened), this is what it looks like. right height.

and this one is the correct height but obviously on 1/3 of the width and the width is squashed into that.

I'm convinced there's something wrong with the header but not sure how to correct. not sure why i need to add a header when i don't need to in Android Studio or WPF but maybe there's a better way than ImageSource.FromStream?

Appreciate any help.

Posts

  • drewdbdrewdb Member

    I might be able to get the url this way?

    https ibb.co fMf5D0 ( for the first one) and
    https ibb.co duJ8Y0 (for the second one)

    hope that works to show the result

Sign In or Register to comment.