BitmapSource与位图

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

为什么有一个位图和一个BitmapSource? 每个的优点是什么?

在我们的项目中,我们必须从数据生成位图。 速度对我们来说非常重要。

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

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

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

所以我们肯定选择了BitmapSource。 但是,我们想要序列化一些BitmapSource。 BitmapSource不可序列化。 所以[OnSerializing] [OnDeserialized]我们将BitmapSource转换为Bitmap(serializable)。

我们的结论是:

位图优点:

  • 简单
  • 串行化
  • BitmapSource的优点:

  • 发电速度
  • 继承(ImageSource)的WPF
  • 你看到其他一些点吗?

    为了说明和像我们这样的新手,下面是我们需要的一些有用的方法:

    转换:

    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);
        }
    }
    

    无锁的图像打开:

        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;
        }
    

    调整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;
        }
    

    一代:

        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))
                );
        }
    

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

    我只想说Bitmap实际上提供了一种通过Bitmap的LockBits方法进行像素操作的超快速手段。 如果您想通过手动设置像素来​​创建位图,它是最快的方法之一。 请注意,BitmapSource使用WIC,而Bitmap使用GDI +。 由于这个原因,加载或复制像素数据的阵列不应该有任何差异(或者说边际效应),并且它不是Bitmapsource或Bitmap的好处。

    我还将添加对Bitmaps的支持,因为它是一个非常旧的结构,许多库接受Bitmap进行编辑。

    我对BitmapSource看到的唯一好处是它是WPF中的图像源,并且可以方便地使用。

    链接地址: http://www.djcxy.com/p/80467.html

    上一篇: BitmapSource vs Bitmap

    下一篇: How to increment a java String through all the possibilities?