WPF - 截取屏幕截图 - System.OutOfMemoryException

时间:2021-02-11 16:16:21

标签: c# wpf graphics bitmap screenshot

我正在尝试获取连接到 PC 的显示器的屏幕截图,并将结果作为字节返回 []
Display 类是 WindowsDisplayAPI。

/// <summary>
/// Returns the screenshot to be displayed
/// </summary>
/// <param name="display"></param>
/// <returns></returns>
public static byte[] GetImage(Display display)
{
    // Define bitmap
    using (Bitmap sc = new Bitmap(display.GetScreen().Bounds.Width, display.GetScreen().Bounds.Height, 
                      System.Drawing.Imaging.PixelFormat.Format32bppArgb))
    {
        if (sc == null)
            return null;

        // Define graphics object
        using (Graphics memoryGraphics = Graphics.FromImage(sc))
        {
            if (memoryGraphics == null)
                return null;

            memoryGraphics.CopyFromScreen(display.GetScreen().Bounds.X, display.GetScreen().Bounds.Y, 0, 
                  0, display.GetScreen().Bounds.Size, CopyPixelOperation.SourceCopy);
            BitmapSource tmp = CreateBitmapSourceFromGdiBitmap(sc);
            JpegBitmapEncoder encoder = new JpegBitmapEncoder();
            byte[] bit = new byte[0];                    
            using (MemoryStream stream = new MemoryStream())
            {
                 encoder.Frames.Add(BitmapFrame.Create(tmp));
                 encoder.Save(stream);
                 bit = stream.ToArray();
                 stream.Dispose();
                 stream.Close();
             }

             GC.Collect();
             return bit;                                       
         }
    }
}

与辅助方法一起

/// <summary>
/// Helper for GetImage 
/// </summary>
/// <param name="bitmap"></param>
/// <returns></returns>
private static BitmapSource CreateBitmapSourceFromGdiBitmap(Bitmap bitmap)
{
     #region
      // Transform the image for CaptureScreen method
      if (bitmap == null)
           throw new ArgumentNullException("bitmap");

      var rect = new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height);

      var bitmapData = bitmap.LockBits(
                rect,
                ImageLockMode.ReadWrite,
                System.Drawing.Imaging.PixelFormat.Format32bppArgb);

       try
       {
            var size = (rect.Width * rect.Height) * 4;

            return BitmapSource.Create(
                bitmap.Width,
                bitmap.Height,
                bitmap.HorizontalResolution,
                bitmap.VerticalResolution,
                System.Windows.Media.PixelFormats.Bgra32,
                null,
                bitmapData.Scan0,
                size,
                bitmapData.Stride);
        }
        finally
        {
            bitmap.UnlockBits(bitmapData);
        }
            #endregion
        }

我不相信我有内存泄漏,尽管不确定。如果我采用普通静态屏幕,该方法工作正常,但抛出 System.OutOfMemoryException: '内存不足,无法继续执行程序。'例如,如果我尝试获取视频的屏幕截图。

以下是更多详细信息:
2021-02-11 16:32:52,395 错误 SSDS.Main.Core.WindowsMethods - System.ArgumentException:参数无效。
在 System.Drawing.Graphics.GetHdc()
在 System.Drawing.Graphics.CopyFromScreen(Int32 sourceX, Int32 sourceY, Int32 destinationX, Int32 destinationY, Size blockRegionSize, CopyPixelOperation copyPixelOperation)
在 SSDS.Main.Core.WindowsMethods.GetImage(Display display) in WindowsMethods.cs:line 204
在 WindowsMethods.cs 中的 SSDS.Main.Core.WindowsMethods.d__26.MoveNext():line 364
抛出异常:System.Drawing.dll 中的“System.ArgumentException”
这是第 204 行:
memoryGraphics.CopyFromScreen(display.GetScreen().Bounds.X, display.GetScreen().Bounds.Y, 0, 0, display.GetScreen().Bounds.Size, CopyPixelOperation.SourceCopy);

如果我将应用程序作为 x64 发送,它工作正常,但是我看到内存使用量攀升至略低于 2GB,而在任何 cpu 设置下它都保持在 900MB 以下。所以我猜测创建的图像不必要的大,我怎么能减少到 300 像素宽度?
还是其他地方的问题?

1 个答案:

答案 0 :(得分:0)

将 GetImage() 方法更改为此。可能是因为Desktop也给了一个消息。

public static byte[] GetImage()
{
   // Define bitmap
   double screenLeft = SystemParameters.VirtualScreenLeft;
   double screenTop = SystemParameters.VirtualScreenTop;
   double screenWidth = SystemParameters.VirtualScreenWidth;
   double screenHeight = SystemParameters.VirtualScreenHeight;

   using (Bitmap sc = new Bitmap((int)screenWidth, (int)screenHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
   {
       if (sc == null)
          return null;

       // Define graphics object
       using (Graphics memoryGraphics = Graphics.FromImage(sc))
       {
          if (memoryGraphics == null)
             return null;

          memoryGraphics.CopyFromScreen((int)screenLeft, (int)screenTop, 0,
               0, sc.Size, CopyPixelOperation.SourceCopy);
          BitmapSource tmp = CreateBitmapSourceFromGdiBitmap(sc);
          JpegBitmapEncoder encoder = new JpegBitmapEncoder();
          byte[] bit = new byte[0];
          using (MemoryStream stream = new MemoryStream())
          {
             encoder.Frames.Add(BitmapFrame.Create(tmp));
             encoder.Save(stream);
             bit = stream.ToArray();
             stream.Dispose();
             stream.Close();
          }

          GC.Collect();
          return bit;
       }
   }
}
相关问题