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

C#使用twaindotnet拼接扫描图像出现大面积空白问题

问题解答

1. Image.Height 与 Bitmap.Height 是否存在差异

不存在取值差异。Bitmap 类继承自 Image 类,Height 属性是 Image 基类定义的成员,返回图像的实际像素高度,二者返回值完全一致,不是产生空白问题的原因。

2. 大面积空白的根本原因

空白来自GDI+ DrawImage 方法的默认自动缩放逻辑:

  • Twain 扫描输出的图像自带DPI元数据(通常为扫描仪设置的200/300/600DPI),而通过new Bitmap()创建的拼接画布如果不手动指定DPI,会默认使用系统屏幕DPI(绝大多数设备为96DPI)。
  • 调用无矩形参数的DrawImage重载时,GDI+不会按1:1像素绘制图像,而是会根据源图和目标画布的DPI差值自动计算缩放比例。比如300DPI的扫描图绘制到96DPI的画布上,实际绘制尺寸会放大到原像素尺寸的300/96≈3.125倍,观察到的4倍左右高度差、图像下方大面积空白,就是旧图和新图都被放大绘制、超出创建的Bitmap尺寸后,画布剩余区域显示默认灰色导致的。
  • 原代码额外存在隐患:每次替换pictureBox1.Image后没有释放旧图像资源,连续扫描会出现内存泄漏。

3. 修复代码

修复核心是三点:新建画布时匹配扫描图DPI、调用DrawImage时明确指定按像素1:1绘制、及时释放旧资源。

private void _twain_TransferImage(object sender, TransferImageEventArgs e)
{
    if (e.Image == null) return;
    
    Image newScanImg = e.Image;
    if (pictureBox1.Image == null)
    {
        pictureBox1.Image = newScanImg;
        return;
    }

    Image oldCombinedImg = pictureBox1.Image;
    // 新画布宽度取两张图最大值避免裁切,高度为两张图像素高度之和
    int canvasWidth = Math.Max(oldCombinedImg.Width, newScanImg.Width);
    int canvasHeight = oldCombinedImg.Height + newScanImg.Height;
    
    Bitmap combinedBmp = new Bitmap(canvasWidth, canvasHeight);
    // 关键:匹配扫描图DPI,避免自动缩放
    combinedBmp.SetResolution(newScanImg.HorizontalResolution, newScanImg.VerticalResolution);

    using (Graphics g = Graphics.FromImage(combinedBmp))
    {
        // 画布填充白色,避免透明/灰色底
        g.Clear(Color.White);
        // 绘制已拼接的旧图,强制按像素1:1渲染
        g.DrawImage(oldCombinedImg,
            new Rectangle(0, 0, oldCombinedImg.Width, oldCombinedImg.Height),
            new Rectangle(0, 0, oldCombinedImg.Width, oldCombinedImg.Height),
            GraphicsUnit.Pixel);
        // 新扫描图绘制在旧图正下方
        g.DrawImage(newScanImg,
            new Rectangle(0, oldCombinedImg.Height, newScanImg.Width, newScanImg.Height),
            new Rectangle(0, 0, newScanImg.Width, newScanImg.Height),
            GraphicsUnit.Pixel);
    }

    // 释放旧资源,避免内存泄漏
    Image oldImg = pictureBox1.Image;
    pictureBox1.Image = combinedBmp;
    oldImg.Dispose();
    newScanImg.Dispose();
}

修复后拼接的长图总高度为所有扫描图像素高度之和,不会出现多余空白,多张扫描图会紧密上下拼接。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 12:39:14