使用PdfStamper将图像放置在OverContent上时,如何在以后找到它?

时间:2016-08-20 18:56:46

标签: itext

当使用压模以这种方式将条形码图像放置在pdf上时:

 for (int pageNumber = 1; pageNumber <= pdf.NumberOfPages; pageNumber++)
    {
         PdfDictionary pg = pdf.GetPageN(pageNumber);                  
         PdfObject obj = FindImageInPDFDictionary(pg);
         if (obj != null)
             {
                int XrefIndex = Convert.ToInt32(((PRIndirectReference)obj).Number.ToString(System.Globalization.CultureInfo.InvariantCulture));
                 PdfObject pdfObj = pdf.GetPdfObject(XrefIndex);
                 PdfStream pdfStrem = (PdfStream)pdfObj;
                 byte[] bytes = PdfReader.GetStreamBytesRaw((PRStream)pdfStrem);
                   if ((bytes != null))
                        {
                            using (System.IO.MemoryStream memStream = new System.IO.MemoryStream(bytes))
                            {
                                memStream.Position = 0;
                                System.Drawing.Image img = System.Drawing.Image.FromStream(memStream);
                     // now we have an image and can examine it
                     // to see if it is a barcode               
                            }

                    }
             }

        }

在查看器中呈现PDF时,它会正常显示,但下面的代码(adapted from here)找不到它。代码根本不会将其识别为现有代码。代码找到Acrobat Pro XI放置在Pdf中的图像,但不是以上述方式添加的图像。

在iTextSharp中将条形码图像放在pdf上以使图像包含在PdfDictionary中的正确方法是什么?需要更改什么,上面的代码或下面的代码?

{{1}}

1 个答案:

答案 0 :(得分:1)

首先,iText Image对象不一定是位图图像,但也可以是包含例如对象的表单xobject的包装器。只有矢量图形。另一方面,提取代码仅考虑位图图像。

但就目前的情况而言,事实证明图像确实是位图图像。

iText向OverContent添加图片的方式没有什么特别之处,问题是从accepted answer到您引用的问题的FindImageInPDFDictionary方法:

private static PdfObject FindImageInPDFDictionary(PdfDictionary pg) {
    PdfDictionary res = (PdfDictionary)PdfReader.GetPdfObject(pg.Get(PdfName.RESOURCES));

    PdfDictionary xobj = (PdfDictionary)PdfReader.GetPdfObject(res.Get(PdfName.XOBJECT));
    if (xobj != null) {
        foreach (PdfName name in xobj.Keys) {
            PdfObject obj = xobj.Get(name);
            if (obj.IsIndirect()) {
                PdfDictionary tg = (PdfDictionary)PdfReader.GetPdfObject(obj);

                PdfName type = (PdfName)PdfReader.GetPdfObject(tg.Get(PdfName.SUBTYPE));

                //image at the root of the pdf
                if (PdfName.IMAGE.Equals(type)) {
                    return obj;
                }// image inside a form
                else if (PdfName.FORM.Equals(type)) {
                    return FindImageInPDFDictionary(tg);
                } //image inside a group
                else if (PdfName.GROUP.Equals(type)) {
                    return FindImageInPDFDictionary(tg);
                }
            }
        }
    }
    return null;
}

缺点不止一种方式:

  • 它只考虑pg字典的资源中的第一个图像表单 xobject在任何这些情况下返回都不关心后两种情况中的任何一种情况下的递归调用是否返回非null结果。
  • 将问题放在一边,它会检查页面资源和包含的表单xobjects和group的资源,而不是其他内容。从而,
    • 它不会检查它找到的图像资源是否实际上是在页面上使用,因此它可能会返回一个页面上根本不存在的图像,
    • 它忽略内容流中包含的内嵌图像,
    • 它会忽略图案或Type 3字体中包含的图像。
  • 忽略找到的图像是否有遮罩。有时掩模包含所得图像的主要信息,而基本图像仅确定颜色;特别是墨水签名图像通常包含笔在笔掩模中的路径,而整个基本图像都填充了墨水颜色。
  • 每页不能返回多个图像。

此外,如果在答案中使用它

PdfDictionary pg = pdf.GetPageN(pageNumber);

// recursively search pages, forms and groups for images.
PdfObject obj = FindImageInPDFDictionary(pg);

然后只检查与页面对象直接关联的资源,但也可以从页面树中的祖先节点继承资源。

您应该使用iText解析框架,参见例如the answer"Extract Images from PDF coordinates using iText"或其变体(经常引用MyImageRenderListener类)。特别是

  • 它通过回调返回所有发现,而不仅仅是每页一个;
  • 它不会忽略它所考虑的一些图像;
  • 它扫描内容流,因此,查找内联图像,只查找实际使用的那些资源;
  • 如果适用,它返回图像的掩码;
  • 作为奖励,它返回图像使用的位置和转换。
但是,它并不完美:特别是它不扫描模式并为图像输入3种字体(但是解析框架允许尝试将类型3字体用作文本提取),并且它不会看到继承资源。