You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#使用StretchBlt在两个Bitmap间拷贝无绘制结果问题

问题:StretchBlt调用返回成功但内存位图无绘制内容

概述

尝试使用以下代码,通过StretchBlt将srcBmp位图的部分区域缩放拷贝到destBmp中——该方法返回1表示成功,但目标位图上没有任何绘制内容:

public static void StretchBltImage()
{
    // create the source bitmap
    var srcBmp = new Bitmap(500, 500, PixelFormat.Format32bppArgb);
    var srcGfx = Graphics.FromImage(srcBmp);
    srcGfx.Clear(Color.Green);
    var srcHdc = srcGfx.GetHdc();

    // create the target image
    var destBmp = new Bitmap(200, 200, PixelFormat.Format32bppArgb);
    using var destGfx = Graphics.FromImage(destBmp);
    destGfx.Clear(Color.Gray);
    var destHdc = destGfx.GetHdc();

    var res1 = SetStretchBltMode(destHdc, STRETCH_HALFTONE);
    var res2 = StretchBlt(destHdc, 75, 75, 50, 50, srcHdc, 0, 0, 100, 100, SRCCOPY);

    srcGfx.ReleaseHdc(srcHdc);
    destGfx.ReleaseHdc(destHdc);
    destBmp.Save(".\\image.png");
}

详细说明

正在编写一个C#应用程序,该程序已成功使用StretchBlt将桌面的一部分区域捕获(并缩小)到位图中,简化代码如下:

ConsoleApp1.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0-windows</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="System.Drawing.Common" Version="8.0.0-preview.5.23280.5" />
  </ItemGroup>

</Project>

Capture.cs

public static partial class Capture
{
    [LibraryImport("user32")]
    internal static partial nint GetDesktopWindow();

    [LibraryImport("user32")]
    internal static partial nint GetWindowDC(nint hWnd);

    [LibraryImport("gdi32")]
    internal static partial int SetStretchBltMode(
        nint hdc,
        int mode);

    [LibraryImport("gdi32")]
    internal static partial int StretchBlt(nint hdcDest, int xDest, int yDest, int wDest, int hDest, nint hdcSrc, int xSrc, int ySrc, int wSrc, int hSrc, int rop);

    private const int BLACKNESS = 0x00000042;
    private const int SRCCOPY = 0x00CC0020;
    private const int STRETCH_HALFTONE = 4;

    public static void StretchBltScreen()
    {
        // open the desktop handles
        var srcHwnd = GetDesktopWindow();
        var srcHdc = GetWindowDC(srcHwnd);

        // create the target image
        var destBmp = new Bitmap(200, 200, PixelFormat.Format32bppArgb);
        using var destGfx = Graphics.FromImage(destBmp);
        destGfx.Clear(Color.Gray);
        var destHdc = destGfx.GetHdc();

        var res1 = SetStretchBltMode(destHdc, STRETCH_HALFTONE);
        var res2 = StretchBlt(destHdc, 75, 75, 50, 50, srcHdc, 0, 0, 100, 100, SRCCOPY);

        destGfx.ReleaseHdc(destHdc);
        destBmp.Save(".\\screen.png");
    }
}

补充说明:使用StretchBlt的原因是需要将超宽显示器(5120 x 1440)的大部分区域拷贝为小缩略图,因此不想先通过Graphics.CopyFromScreen拷贝完整图像再缩放——根据测试,StretchBlt一步完成的速度快得多。


调用StretchBltScreen时可以正常工作并生成截图,但编写单元测试时,尝试使用内存中的静态Bitmap作为源,StretchBlt返回1表示成功,却没有任何内容绘制到目标缩略图中。

怀疑这与设备上下文、兼容位图、DIB等相关,尝试了多种GDI调用组合仍未解决,希望得到相关技术见解。

内容的提问来源于stack exchange,提问作者mclayton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 11:49:52