Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BitmapSource vs Bitmap

7 months ago, we started to learn C# and WPF, and, as all newbies who want to do some image processing, we ran into this question :

Why is there a Bitmap and a BitmapSource ? And what are the advantages of each ?

In our project, we had to generate a bitmap from data. Speed was very important for us.

We started with Bitmap because it is easier (expecialy methods : get/setpixel), well documented with a lot of exemples. But then we discovered the conversions problems in WPF to print a Bitmap.

So we tried with BitmapSource, It wasn't easy because of differents pixels formats. But we finaly succeded.

We compared speed of each generation. Working with SetPixel (Bitmap) is far slower than working with byte array (BitmapSource), but working with byte array means complications : stride, pixel format ...

So for sure we chose BitmapSource. But then we wanted to serialize some BitmapSource. BitmapSource is not serializable. So with [OnSerializing] [OnDeserialized] we converted the BitmapSource in Bitmap (serializable).

Our conclusions are :

Bitmap advantages :

  1. Simplicity
  2. Serializability

BitmapSource advantages :

  1. Generation Speed
  2. Inheritance (ImageSource) for WPF

Do you see some others points ?

To illustrate and for newbies like us, here is some usefull methods we needed :

Conversion :

public static System.Windows.Media.Imaging.BitmapSource BitmapToBitmapSource(System.Drawing.Bitmap source)
{
    using (MemoryStream memory = new MemoryStream())
    {
        source.Save(memory, ImageFormat.Png);
        memory.Position = 0;
        BitmapImage bitmapImage = new BitmapImage();
        bitmapImage.BeginInit();
        bitmapImage.StreamSource = memory;
        bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
        bitmapImage.EndInit();
        return bitmapImage;
    }
}

public static System.Drawing.Bitmap BitmapFromSource(BitmapSource source)
{
    using (MemoryStream outStream = new MemoryStream())
    {
        BitmapEncoder enc = new PngBitmapEncoder();
        enc.Frames.Add(BitmapFrame.Create(source));
        enc.Save(outStream);
        System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(outStream);

        // return bitmap; <-- leads to problems, stream is closed/closing ...
        return new Bitmap(bitmap);
    }
}

Image opening without Lock :

    public static BitmapImage LoadImage(string uri)
    {
        BitmapImage monImage = null;
        if (uri != null)
        {
            BitmapImage image = new BitmapImage();
            using (FileStream stream = File.OpenRead(uri))
            {
                image.BeginInit();
                image.CacheOption = BitmapCacheOption.OnLoad;
                image.StreamSource = stream;
                image.EndInit();
            }
            monImage = image;
        }
        return monImage;
    }

Resize BitmapSource :

    public static BitmapImage BitmapImageFromBitmapSourceResized(BitmapSource bitmapSource, int newWidth)
    {
        BmpBitmapEncoder encoder = new BmpBitmapEncoder();
        MemoryStream memoryStream = new MemoryStream();
        BitmapImage bImg = new BitmapImage();

        encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
        encoder.Save(memoryStream);

        bImg.BeginInit();
        bImg.StreamSource = new MemoryStream(memoryStream.ToArray());
        bImg.DecodePixelWidth = newWidth;
        bImg.EndInit();
        memoryStream.Close();
        return bImg;
    }

Generation :

    public static int GetBytesPerPixel(BitmapSource bmp)
    {
        return (bmp.Format.BitsPerPixel + 7) / 8;
    }

    public static int GetStrideFromeBitmapSource(BitmapSource bmp)
    {
        return 4 * ((bmp.PixelWidth * GetBytesPerPixel(bmp) + 3) / 4);
    }

    public static byte[] GetBytesFromBitmapSource(BitmapSource bmp)
    {
        int height = bmp.PixelHeight;
        int stride = GetStrideFromeBitmapSource(bmp);

        byte[] pixels = new byte[height * stride];

        bmp.CopyPixels(pixels, stride, 0);

        return pixels;
    }

    public static int GetWidth(int stride, int bytesPerPixel)
    {
        int width = (int)(
                            (float)stride
                            / (float)bytesPerPixel
                        );
        return width;
    }

    public static int GetHeight(byte[] bits, int stride)
    {
        int height = (int)(
                            (float)bits.Length
                            / (float)stride
                        );
        return height;
    }

    public static void SetPixelRgb24(ref byte[] bits, int x, int y, int stride, Color c)
    {
        bits[x * 3 + y * stride] = c.R;
        bits[x * 3 + y * stride + 1] = c.G;
        bits[x * 3 + y * stride + 2] = c.B;
    }

    public static void SetPixelBgra32(ref byte[] bits, int x, int y, int stride, Couleur c)
    {
        bits[x * 4 + y * stride + 0] = c.B;
        bits[x * 4 + y * stride + 1] = c.G;
        bits[x * 4 + y * stride + 2] = c.R;
        bits[x * 4 + y * stride + 3] = c.A;
    }

    public static int GetAverageValueOfPixel(ref byte[] bits, int x, int y, int stride, int bytesPerPixel)
    {
        int sum = 0;
        for (var i = 0; i < bytesPerPixel; i++)
            sum += bits[x * bytesPerPixel + y * stride + i];
        return (int)
            (
                sum
                * (255f / (255f * bytesPerPixel))
            );
    }

Snapshot to BitmapSource :

    public static BitmapSource SnapShotToBitmap(this UIElement source, double zoomX, double zoomY)
    {
        try
        {
            DataObject dataObject = new DataObject();

            double actualHeight = source.RenderSize.Height;
            double actualWidth = source.RenderSize.Width;

            if (actualHeight == 0)
                actualHeight = 1;
            if (actualWidth == 0)
                actualWidth = 1;

            double renderHeight = actualHeight * zoomY;
            double renderWidth = actualWidth * zoomX;

            RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)renderWidth, (int)renderHeight, 96, 96, PixelFormats.Pbgra32);
            VisualBrush sourceBrush = new VisualBrush(source);

            DrawingVisual drawingVisual = new DrawingVisual();
            DrawingContext drawingContext = drawingVisual.RenderOpen();

            using (drawingContext)
            {
                drawingContext.PushTransform(new ScaleTransform(zoomX, zoomY));
                drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, 0), new Point(actualWidth, actualHeight)));
            }
            renderTarget.Render(drawingVisual);

            return renderTarget;
        }
        catch (Exception e)
        {
            throw new Exception(e);
        }
    }
like image 304
antoinestv Avatar asked Jul 22 '14 11:07

antoinestv


People also ask

What is BitmapSource?

Bitmap (BMP) is an image file format that can be used to create and store computer graphics. A bitmap file displays a small dots in a pattern that, when viewed from afar, creates an overall image.

What is a bitmap frame?

A bitmap consists of at least one frame (an image). If there are more than one frame stored within the bitmap, the bitmap is called 'multi-frame'.

What is bitmap image in C#?

A Bitmap is an object used to work with images defined by pixel data.

What is new bitmap image?

A bitmap is one of many types of file formats for images stored in a computerized form. It carries the extension . BMP. Computers use bits of 1 and 0 to store data. A bitmap is literally a map of bits that form a particular picture when rendered to a display like a computer monitor.


1 Answers

I just want to say that Bitmap actually provides a super-fast means of doing pixel manipulation through the LockBits method of Bitmap. It is one of the fastest ways to create a bitmap if you want to do it by setting the pixels manually. Note that BitmapSource uses WIC while Bitmap uses GDI+. Due to this there should not be any difference (or a marginal at best) for loading or copying arrays of pixel data, and it is not a benefit of either Bitmapsource or Bitmap.

I would also add support to Bitmaps side, as it is a very old structure, with a lot of libraries accepting a Bitmap for editing.

The only benefit I see for BitmapSource is that it is a source for images in WPF and can be readily used.

like image 195
Savvas Kleanthous Avatar answered Oct 04 '22 09:10

Savvas Kleanthous