wpf 位图源与位图

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24885977/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 12:11:40  来源:igfitidea点击:

BitmapSource vs Bitmap

c#wpfimage-processing

提问by Antoine ESTEVE

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 :

7个月前,我们开始学习C#和WPF,作为所有想做一些图像处理的新手,我们遇到了这个问题:

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

为什么有一个 Bitmap 和一个 BitmapSource ?以及各自的优势是什么?

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.

我们从 Bitmap 开始,因为它更容易(特别是方法:get/setpixel),并且有很多例子。但是后来我们发现了 WPF 中打印位图的转换问题。

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

所以我们尝试使用 BitmapSource,由于不同的像素格式,这并不容易。但我们最终成功了。

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 ...

我们比较了每一代的速度。使用 SetPixel (Bitmap) 比使用字节数组 (BitmapSource) 慢得多,但使用字节数组意味着复杂性:步幅、像素格式......

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).

所以我们肯定选择了 BitmapSource。但后来我们想序列化一些 BitmapSource。BitmapSource 不可序列化。因此,使用 [OnSerializing] [OnDeserialized] 我们将 BitmapSource 转换为 Bitmap(可序列化)。

Our conclusions are :

我们的结论是:

Bitmap advantages :

位图优势:

  1. Simplicity
  2. Serializability
  1. 简单
  2. 可串行化

BitmapSource advantages :

BitmapSource 优点:

  1. Generation Speed
  2. Inheritance (ImageSource) for WPF
  1. 生成速度
  2. WPF 的继承(ImageSource)

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 :

快照到 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);
        }
    }

采纳答案by Savvas Kleanthous

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.

我只想说 Bitmap 实际上提供了一种通过BitmapLockBits 方法进行像素操作的超快速方法。如果您想通过手动设置像素来​​创建位图,这是创建位图的最快方法之一。请注意,BitmapSource 使用 WIC,而 Bitmap 使用 GDI+。因此,加载或复制像素数据数组不应该有任何差异(或充其量只是边缘),并且这不是 Bitmapsource 或 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.

我还会添加对 Bitmaps 方面的支持,因为它是一个非常古老的结构,很多库都接受 Bitmap 进行编辑。

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

我看到 BitmapSource 的唯一好处是它是 WPF 中的图像源并且可以很容易地使用。