BitmapSource与Bitmap

时间:2014-07-22 11:19:45

标签: c# wpf image-processing

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

为什么有Bitmap和BitmapSource?每个人的优势是什么?

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

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

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

我们比较了每一代的速度。使用SetPixel(Bitmap)远比使用字节数组(BitmapSource)慢,但使用字节数组意味着并发症:步幅,像素格式...

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

我们的结论是:

位图优势:

  1. 简单
  2. 串行性
  3. BitmapSource优势:

    1. 发电速度
    2. WPF的继承(ImageSource)
    3. 你看到其他一些观点吗?

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

      转换:

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

1 个答案:

答案 0 :(得分:3)

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

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

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