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

C#打印带水印RichTextBox时文本背景不透明问题排查

问题根因

调用EM_FORMATRANGE消息渲染RichTextBox内容时,默认会先使用控件当前的BackColor属性值(默认为白色)填充整个目标渲染矩形区域,直接覆盖预先绘制的水印背景图,这就是文本区域显示不透明白底、无法透出下方水印的核心原因。

修复方案

两种方案可以组合使用,兼容所有Windows系统版本:

  • 临时修改控件背景色:在触发打印渲染前,临时将RichTextBox的BackColor设置为Color.Transparent,渲染完成后立刻还原为原始背景色。注意RichTextBox本身不支持常驻透明背景,仅在打印流程中临时修改即可,避免界面显示异常。
  • 设置GDI设备上下文透明模式:在获取打印DC后、发送EM_FORMATRANGE消息前,调用Win32 API将DC的背景混合模式设为透明,跳过渲染时的白底填充步骤。
具体代码修改
  1. 新增需要用到的Win32 API声明和常量:
[DllImport("gdi32.dll")]
private static extern int SetBkMode(IntPtr hdc, int iBkMode);
private const int TRANSPARENT_BK_MODE = 1;
  1. 修改printDocument_PrintPage方法,增加背景色临时切换逻辑,同时修复原代码中图片资源未释放的泄漏问题:
private void printDocument_PrintPage(object sender, PrintPageEventArgs e)
{
    int documentWidth = (int)(e.PageSettings.PrintableArea.Width - 0.5);
    int documentHeight = (int)(e.PageSettings.PrintableArea.Height - 0.5);

    // 绘制水印背景,using释放资源避免句柄泄漏
    using (Image bgImg = Image.FromFile("bg.jpeg"))
    {
        e.Graphics.DrawImage(bgImg, 
            new Rectangle(0, 0, documentWidth, documentHeight), 
            new Rectangle(0, 0, bgImg.Width, bgImg.Height), 
            GraphicsUnit.Pixel);
    }

    // 临时切换背景色为透明
    Color originalBkColor = control.BackColor;
    control.BackColor = Color.Transparent;
    try
    {
        m_nFirstCharOnPage = FormatRange(false, e, m_nFirstCharOnPage, control.TextLength);
    }
    finally
    {
        // 无论渲染是否出错,都还原原始背景色
        control.BackColor = originalBkColor;
    }

    e.HasMorePages = m_nFirstCharOnPage < control.TextLength;
}
  1. 修改FormatRange方法,在获取HDC后增加透明模式设置:
public int FormatRange(bool measureOnly, PrintPageEventArgs e, int charFrom, int charTo)
{
    STRUCT_CHARRANGE cr;
    cr.cpMin = charFrom;
    cr.cpMax = charTo;

    STRUCT_RECT rc;
    rc.top = HundredthInchToTwips(10);
    rc.bottom = HundredthInchToTwips((int)e.PageSettings.PrintableArea.Height - 20);
    rc.left = HundredthInchToTwips(20);
    rc.right = HundredthInchToTwips((int)e.PageSettings.PrintableArea.Width - 10);

    STRUCT_RECT rcPage;
    rcPage.top = HundredthInchToTwips(e.PageBounds.Top);
    rcPage.bottom = HundredthInchToTwips(e.PageBounds.Bottom);
    rcPage.left = HundredthInchToTwips(e.PageBounds.Left);
    rcPage.right = HundredthInchToTwips(e.PageBounds.Right);

    IntPtr hdc = e.Graphics.GetHdc();
    // 设置DC背景为透明,跳过白底填充
    SetBkMode(hdc, TRANSPARENT_BK_MODE);

    STRUCT_FORMATRANGE fr;
    fr.chrg = cr;
    fr.hdc = hdc;
    fr.hdcTarget = hdc;
    fr.rc = rc;
    fr.rcPage = rcPage;

    Int32 wParam = measureOnly ? 0 : 1;
    IntPtr lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fr));
    Marshal.StructureToPtr(fr, lParam, false);

    int res = SendMessage(control.Handle, EM_FORMATRANGE, wParam, lParam);

    Marshal.FreeCoTaskMem(lParam);
    e.Graphics.ReleaseHdc(hdc);

    return res;
}

补充说明:原代码中PrintRTF方法里强制设置A4纸尺寸的逻辑,建议增加判断,优先使用打印机默认的纸张设置,避免用户选择其他尺寸纸张时出现内容裁切问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 12:15:29