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
相关产品推荐
相关产品推荐

