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

StretchBlt函数生成位图出现异常白点,求排查解决

Windows API位图缩放后仅显示白点的问题排查与解决

核心问题分析

ResizeBitmap函数生成全白位图的主要原因是创建目标位图时使用了错误的DC:

  • CreateCompatibleDC(NULL)创建的内存DC默认是单色(1位)格式,用它调用CreateCompatibleBitmap生成的hNewBitmap是单色位图,而非与源位图同深度的真彩色位图。当StretchBlt将真彩色源位图绘制到单色目标位图时,颜色会被强制转换为黑白,最终出现全白的结果。

此外还有两处潜在问题:

  • 未检查SelectObject的返回值,无法及时发现对象选择失败的情况
  • 目标DC(hdcDest)未还原初始GDI对象,可能导致资源泄漏

修复步骤

  1. 替换CreateCompatibleBitmap的DC参数
    使用关联了源位图的hdcSrc来创建目标位图,保证目标位图与源位图的位深度、颜色格式一致。
  2. 还原目标DC的初始对象
    保存SelectObject(hdcDest, hNewBitmap)的返回值,在删除DC前将其选回,避免资源泄漏。
  3. 添加关键函数的返回值检查
    对SelectObject、StretchBlt等函数的返回值进行校验,提前捕获错误。

修改后的ResizeBitmap函数

BOOL ResizeBitmap(HBITMAP hOriginalBitmap, const char resizedFilename[], BitmapAngle NewAngle, BitmapAngle BmAngle){
    HDC hdcSrc = CreateCompatibleDC(NULL);
    if (!hdcSrc) {
        GetErrorCode("CreateCompatibleDC(hdcSrc)");
        ExitProcess(0);
    }

    HGDIOBJ originalObjectSrc = SelectObject(hdcSrc, hOriginalBitmap);
    if (originalObjectSrc == NULL || originalObjectSrc == HGDI_ERROR) {
        GetErrorCode("SelectObject(hdcSrc)");
        DeleteDC(hdcSrc);
        ExitProcess(0);
    }

    HDC hdcDest = CreateCompatibleDC(NULL);
    if (!hdcDest) {
        GetErrorCode("CreateCompatibleDC(hdcDest)");
        SelectObject(hdcSrc, originalObjectSrc);
        DeleteDC(hdcSrc);
        ExitProcess(0);
    }

    // 关键修复:使用hdcSrc创建兼容位图,保证颜色格式与源一致
    HBITMAP hNewBitmap = CreateCompatibleBitmap(hdcSrc, NewAngle.Width, NewAngle.Height);
    if (!hNewBitmap) {
        GetErrorCode("CreateCompatibleBitmap");
        SelectObject(hdcSrc, originalObjectSrc);
        DeleteDC(hdcSrc);
        DeleteDC(hdcDest);
        ExitProcess(0);
    }

    HGDIOBJ originalObjectDest = SelectObject(hdcDest, hNewBitmap);
    if (originalObjectDest == NULL || originalObjectDest == HGDI_ERROR) {
        GetErrorCode("SelectObject(hdcDest)");
        DeleteObject(hNewBitmap);
        SelectObject(hdcSrc, originalObjectSrc);
        DeleteDC(hdcSrc);
        DeleteDC(hdcDest);
        ExitProcess(0);
    }

    // 设置高质量缩放模式
    SetStretchBltMode(hdcDest, HALFTONE);
    SetBrushOrgEx(hdcDest, 0, 0, NULL);

    // 执行缩放绘制
    BOOL bltResult = StretchBlt(hdcDest, 0, 0, NewAngle.Width, NewAngle.Height,
               hdcSrc, 0, 0, BmAngle.Width, BmAngle.Height,
               SRCCOPY);
    if (!bltResult) {
        GetErrorCode("StretchBlt");
    }

    // 保存缩放后的位图
    SaveBitmapToFile(hNewBitmap, NewAngle, resizedFilename);

    // 还原并释放资源
    SelectObject(hdcSrc, originalObjectSrc);
    SelectObject(hdcDest, originalObjectDest);
    DeleteDC(hdcSrc);
    DeleteDC(hdcDest);
    DeleteObject(hNewBitmap);

    return bltResult;
}

额外优化建议

  • 在SaveBitmapToFile中,不要硬编码24位像素格式,应该通过GetDIBits先获取位图的真实位深度,再计算内存大小,避免因源位图位深度不同导致的错误。
  • 尽量避免使用ExitProcess直接终止程序,可以改为返回错误码让调用方处理,提升程序的健壮性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 22:32:07