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

iTextSharp:扁平化注释位置偏移及拉伸问题

问题分析与解决方案

你的代码仅开启了表单和自由文本注释的扁平化,但忽略了两个核心问题:

  • 原PDF页面尺寸可能并非Letter,扁平化时未同步处理页面尺寸转换,导致注释坐标系统与目标尺寸不匹配
  • iText的PdfStamper默认不会自动适配页面尺寸缩放,注释位置基于原页面坐标系计算,直接扁平化后调整尺寸会引发拉伸偏移

修正后的扁平化+页面尺寸统一代码

using iTextSharp.text;
using iTextSharp.text.pdf;
using System.Collections.Generic;
using System.IO;
using System;

private List<byte[]> FlattenAndNormalizePdfToLetter(List<byte[]> pdfs)
{
    List<byte[]> outputPdfs = new List<byte[]>();
    if (pdfs == null) return outputPdfs;

    // 目标Letter页面尺寸(8.5x11英寸,PDF用户单位:1英寸=72单位)
    Rectangle letterSize = PageSize.LETTER;

    foreach (byte[] pdf in pdfs)
    {
        using (var inputStream = new MemoryStream(pdf))
        using (var outputStream = new MemoryStream())
        {
            var reader = new PdfReader(inputStream);
            Rectangle originalSize = reader.GetPageSize(1);

            // 计算等比例缩放系数,确保原页面适配Letter尺寸
            float scaleX = letterSize.Width / originalSize.Width;
            float scaleY = letterSize.Height / originalSize.Height;
            float scale = Math.Min(scaleX, scaleY);

            var stamper = new PdfStamper(reader, outputStream)
            {
                FormFlattening = true,
                FreeTextFlattening = true
            };

            // 遍历所有页面,调整尺寸并适配内容与注释
            for (int i = 1; i <= reader.NumberOfPages; i++)
            {
                PdfDictionary pageDict = reader.GetPageN(i);
                // 更新页面基础尺寸为Letter
                pageDict.Put(PdfName.MEDIABOX, new PdfRectangle(letterSize));

                // 调整注释的位置与尺寸
                PdfArray annotations = pageDict.GetAsArray(PdfName.ANNOTS);
                if (annotations != null)
                {
                    foreach (PdfObject annotObj in annotations.ArrayList)
                    {
                        if (annotObj.IsIndirect())
                        {
                            PdfDictionary annotDict = (PdfDictionary)PdfReader.GetPdfObject(annotObj);
                            PdfRectangle annotRect = annotDict.GetAsRectangle(PdfName.RECT);
                            if (annotRect != null)
                            {
                                // 缩放注释坐标
                                float newX = annotRect.Left * scale;
                                float newY = annotRect.Bottom * scale;
                                float newWidth = annotRect.Width * scale;
                                float newHeight = annotRect.Height * scale;
                                // 修正PDF坐标系Y轴偏移(原点在左下角)
                                newY = letterSize.Height - (newY + newHeight);
                                annotDict.Put(PdfName.RECT, new PdfRectangle(newX, newY, newX + newWidth, newY + newHeight));
                            }
                        }
                    }
                }

                // 缩放并居中页面内容
                PdfContentByte content = stamper.GetOverContent(i);
                content.SaveState();
                float offsetX = (letterSize.Width - originalSize.Width * scale) / 2;
                float offsetY = (letterSize.Height - originalSize.Height * scale) / 2;
                content.ConcatCTM(scale, 0, 0, scale, offsetX, offsetY);
                content.RestoreState();
            }

            stamper.Close();
            reader.Close();
            outputPdfs.Add(outputStream.ToArray());
        }
    }

    return outputPdfs;
}

关键修改说明

  • 页面尺寸同步更新:直接修改页面MEDIABOX为Letter尺寸,确保扁平化后的PDF基础尺寸统一
  • 注释坐标适配:遍历所有注释,按原页面与Letter页面的缩放比例重新计算位置和尺寸,同时修正PDF坐标系的Y轴偏移
  • 内容等比例缩放:通过ConcatCTM对页面内容进行等比例缩放并居中,避免拉伸变形
  • 资源自动释放:使用using语句自动管理流和阅读器资源,避免内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 17:48:14