如何通过坐标提取用iTextSharp插入PDF指定位置的图片?
嘿,我明白你遇到的麻烦了——用iTextSharp给PDF插了图片,结果试了各种坐标提取的方法都没成功对吧?先看看你贴出来的插入代码:
String pathin = pdf.src; String pathout = "C:\...."; string signedFile = System.IO.Path.GetTempFileName(); PdfReader reader = new PdfReader(pathin); FileStream fs = new FileStream(pathout, FileMode.Create); PdfStamper stamper = new PdfStamper(reader, fs); PdfContentByte cb = stamper.GetOverContent(1); iTextSharp.text.Image image1 = iTextSharp.text...
为啥按坐标提取会失败?给你捋几个核心原因和解决思路
图片被包装成PDF XObject,你没关联坐标逻辑
用GetOverContent()插入图片时,iTextSharp会把图片转成PDF的XObject资源,不是直接把坐标写在图片本身上。要按坐标找,得先遍历页面的资源字典找到对应XObject,再去内容流里找调用这个XObject的位置,对应的变换矩阵就是它的显示坐标。没考虑PDF的坐标变换矩阵(CTM)
PDF里的内容会经过当前变换矩阵转换显示位置,你提取时不能直接拿图片的原始尺寸去匹配,必须把XObject的调用指令和前面的cm(坐标变换)命令结合,计算出实际显示的坐标范围。混淆了图片自身的BBox和显示坐标
XObject的BBox是它自身的尺寸,而实际在页面上的位置是通过绘图指令里的矩阵设置的,你得解析页面内容流,找到调用该图片XObject的Do指令,再对应上之前的坐标变换参数。
给你一个可行的提取核心逻辑示例
PdfReader reader = new PdfReader("你的输出PDF路径"); // 获取第一页的字典 PdfDictionary pageDict = reader.GetPageN(1); // 拿到页面的资源字典 PdfDictionary resources = pageDict.GetAsDict(PdfName.RESOURCES); // 取出所有XObject资源 PdfDictionary xObjects = resources.GetAsDict(PdfName.XOBJECT); if (xObjects != null) { foreach (PdfName key in xObjects.Keys) { PdfObject obj = xObjects.Get(key); if (obj.IsIndirect()) { PdfDictionary xObjDict = reader.GetPdfObject(obj.GetIndirectReference()) as PdfDictionary; // 判断是否是图片类型的XObject if (PdfName.IMAGE.Equals(xObjDict.GetAsName(PdfName.SUBTYPE))) { // 解析页面内容流,跟踪变换矩阵和XObject调用 PdfContentParser parser = new PdfContentParser(reader); // 自定义处理器来匹配目标坐标 CustomContentProcessor processor = new CustomContentProcessor(key, 你的目标X坐标, 你的目标Y坐标); processor.ProcessContent(reader.GetPageContent(1), resources); } } } } // 自定义内容处理器示例(核心是跟踪变换矩阵和Do指令) public class CustomContentProcessor : PdfContentProcessor { private PdfName _targetXObjKey; private float _targetX; private float _targetY; private Matrix _currentMatrix = new Matrix(); public CustomContentProcessor(PdfName targetKey, float x, float y) { _targetXObjKey = targetKey; _targetX = x; _targetY = y; // 注册处理坐标变换的操作符 RegisterContentOperator("cm", new CmOperatorHandler(this)); // 注册处理XObject调用的操作符 RegisterContentOperator("Do", new DoOperatorHandler(this)); } // 处理cm指令,更新当前变换矩阵 public class CmOperatorHandler : IContentOperator { private CustomContentProcessor _processor; public CmOperatorHandler(CustomContentProcessor processor) => _processor = processor; public void Invoke(PdfContentProcessor processor, PdfLiteral oper, List<PdfObject> operands) { float[] vals = new float[6]; for (int i = 0; i < 6; i++) vals[i] = ((PdfNumber)operands[i]).FloatValue; _processor._currentMatrix = _processor._currentMatrix.Multiply(new Matrix(vals[0], vals[1], vals[2], vals[3], vals[4], vals[5])); } } // 处理Do指令,检查是否是目标XObject并匹配坐标 public class DoOperatorHandler : IContentOperator { private CustomContentProcessor _processor; public DoOperatorHandler(CustomContentProcessor processor) => _processor = processor; public void Invoke(PdfContentProcessor processor, PdfLiteral oper, List<PdfObject> operands) { PdfName xObjName = (PdfName)operands[0]; if (xObjName.Equals(_processor._targetXObjKey)) { // 计算变换后的坐标范围,和目标坐标对比 // 这里可以根据图片的BBox和当前矩阵计算实际显示位置 // 如果匹配上,就提取该图片 Console.WriteLine("找到目标图片!"); } } } }
另外提醒下:你插入图片时用SetAbsolutePosition(x,y)的话,PDF的坐标系是左下角为原点,提取时别搞反Y轴方向哦。
内容的提问来源于stack exchange,提问作者malak alfosail
相关产品推荐
相关产品推荐

