【问题标题】:How to copy OCR text data to a new pdf Itext 7 C#如何将 OCR 文本数据复制到新的 pdf Itext 7 C#
【发布时间】:2021-08-07 11:19:53
【问题描述】:

我有一份扫描文件。在本文档中,上面有透明的文本和图像层。有没有办法将文本原样(没有更改,因此它保持透明并在同一位置)复制到我创建的另一个.pdf(没有图像)?我在谷歌搜索它,并没有找到任何解决方案。我知道我可以将文本从页面复制到字符串,然后将其添加到我的新文档中并添加一个新段落。但它会破坏已识别字母的透明度和位置。我真正想做的是更改 OCR 文本下方的图像。首先,想法是从 .pdf 中删除所有图像并添加新图像。然后我明白这不是一个好主意,也不是很容易做到,因为有很多不同的图像类型。(但我是这样做的,请看解决方案)

添加样本:

我的示例文档是我在其中进行 OCR 的扫描文档。

Sample document

我的真实代码示例在这里:

                    String dest = "C:\\ImagePaged.pdf";
                    PdfWriter writer = new PdfWriter(dest);
                   
                    // Creating a PdfDocument  
                    pdfDoc = new PdfDocument(writer);
                    

                    // Creating a Document   Document 
                    iText.Layout.Document document2 = new iText.Layout.Document(pdfDoc);
                    document2.SetMargins(0, 0, 0, 0);

                    //////////////////////

                    List<int> rotatedPages = new List<int>();
                    using (FileStream fs = new FileStream(@"C:\\source.pdf", FileMode.Open))
                 
                    using (Document document = new Document(fs)) // this object represents a PDF document
                    
                    {

                
                        // process and save pages one by one
                        for (int i = 0; i < document.Pages.Count; i++)
                        {
                     

       
                            Page currentPage = document.Pages[i];
                            
                            // we use original page's width and height for image as well as default rendering settings
                            using (Bitmap bitmap = currentPage.Render((int)currentPage.Width*3, (int)currentPage.Height*3, new RenderingSettings()))
                          
                            {
                                if (bitmap.Width>bitmap.Height)
                                {
                                    rotatedPages.Add(i+1);

                                    bitmap.RotateFlip(RotateFlipType.Rotate90FlipNone);

                                }
                                

 bitmap.Save($"C:\\ImagePage{i}.png", ImageFormat.Png);

iText.IO.Image.ImageData imageData = iText.IO.Image.ImageDataFactory.Create($"C:\\ImagePage{i}.png");

 Image image = new Image(imageData);
                             
imageData = null;
             
                                
   document2.Add(image);
                                
     image = null;
     File.Delete($"C:\\ImagePage{i}.png");


                                


                            }
                            GC.Collect();
                        }
                        document.Dispose();
                        document2.Close();
                        GC.Collect();

更新:解决方案

感谢 mkl 提供的代码部分,我能够构建解决方案。

  1. 我使用 Apitron 从带水印的 pdf 中为每一页生成图像(查找代码示例)。
  2. 我使用 mkl 提供的代码,从我的原始 pdf 文档中删除所有图像。
  3. 我使用 Itext 将 Apitron 创建的图像添加到在第 nr.2 条创建的 pdf 文件中。

我不会在此处发布我的整个解决方案,但在执行此操作时要记住的重要事项是:

一个。像这样在目标文档中设置边距:

document2.SetMargins(0, 0, 0, 0);

b.在添加之前旋转您的图像。

 int rotations=  pdfDoc.GetPage(i+1).GetRotation();
                            
                                if (rotations>0)
                                {
                                   

                                    if (rotations == 270)
                                    {
                                        bitmap.RotateFlip(RotateFlipType.Rotate270FlipXY);
                                    } else
                                          if (rotations == 90)
                                    {
                                        bitmap.RotateFlip(RotateFlipType.Rotate90FlipXY);
                                    }
                                    if (rotations == 180)
                                    {
                                        bitmap.RotateFlip(RotateFlipType.Rotate180FlipXY);
                                    }

c。创建带有添加页码的图像。

image = new Image(imageData).SetFixedPosition(i + 1, 0, 0).SetAutoScale(true);   (the first argument i, is the page number)

【问题讨论】:

  • 简单地复制原始页面然后替换有问题的图像 Xobjects 怎么样?
  • 是的。我应该试试。但可能会有一个小问题。如果一页上的图像很少怎么办。我不能替换它们,因为我从来没有做对。所以解决方案可能是从页面中删除所有图像并添加我的新图像。但是,如果我只是添加我的新内容,它是否会出现在正确位置的 OCR 文本后面,这就是问题所在。我明天试试。
  • @mkl 我找到了替换图像的代码,但是您知道如何从页面中删除所有图像 Xobjects 吗?我尝试在 Xobject 中写一个 null 但 id 没有做这件事。 PdfDictionary pageDict = pdfDoc.GetFirstPage().GetPdfObject(); PdfDictionary 资源 = pageDict.GetAsDictionary(PdfName.Resources); PdfDictionary xObjects = resources.GetAsDictionary(PdfName.XObject);
  • 如果您将这些 Xobjects 设置为 null 或完全删除条目,那么严格来说,您的 pdf 将变得无效,因为内容流引用了不存在或 null Xobject。最好在没有任何指令的情况下将其设置为表单 Xobject。
  • 你能告诉我怎么做吗?我更新了我的代码,请看一下。我认为我不知道如何制作一个新的适当的空 Xobject。

标签: c# pdf itext


【解决方案1】:

在 cmets 中,我建议将图像 XObjects 替换为 没有任何说明的表单 Xobject。 您尝试为此使用普通的 PdfDictionary,但这太普通了。而是尝试这样的方法,使用空的PdfFormXObject 下的 PDF 对象作为replacement

void replaceImages(PdfResources pdfResources, PdfObject replacement)
{
    PdfDictionary xobjects = pdfResources.GetPdfObject().GetAsDictionary(PdfName.XObject);
    if (xobjects == null)
        return;
    ISet<PdfName> toReplace = new HashSet<PdfName>();
    foreach (KeyValuePair<PdfName, PdfObject> entry in xobjects.EntrySet())
    {
        PdfObject pdfObject = entry.Value;
        if (pdfObject is PdfIndirectReference reference)
            pdfObject = reference.GetRefersTo();
        if (pdfObject is PdfStream pdfStream && PdfName.Image.Equals(pdfStream.GetAsName(PdfName.Subtype)))
        {
            toReplace.Add(entry.Key);
        }
    }
    foreach (PdfName name in toReplace)
    {
        xobjects.Put(name, replacement);
    }
}

(ReplaceImageWithEmptyObject 辅助方法)

请注意,这会更改实际资源,而不会更新 PdfResources 实例的内部缓存。因此,它的状态可能会变得不一致,您不应将该实例用于其他操作。

您可以像这样将它应用到PdfDocument pdfDocument

PdfFormXObject replacement = new PdfFormXObject(new Rectangle(1, 1));
for (int pageNr = 1; pageNr <= pdfDocument.GetNumberOfPages(); pageNr++)
{
    PdfPage pdfPage = pdfDocument.GetPage(pageNr);
    PdfResources pdfResources = pdfPage.GetResources();
    replaceImages(pdfResources, replacement.GetPdfObject());
}

(ReplaceImageWithEmptyObject 测试testReplaceForVZ)

它在您的示例 PDF 中按预期工作。

【讨论】:

  • 你好 mkl。它正在工作,谢谢。我能够在这里从您的代码构建我的解决方案。我会给你+1,但我不会将你的答案标记为解决方案,因为它只是它的一半。我会用我的解决方案更新我的答案。
  • 我看到您已将解决方案编辑到您的问题中。请不要这样做,而是为此创建自己的答案。堆栈溢出问题严格来说是针对问题和解决方案的答案。此外,您最终可以接受该答案...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
  • 1970-01-01
  • 2022-01-19
  • 2021-07-05
  • 1970-01-01
  • 1970-01-01
  • 2015-05-19
相关资源
最近更新 更多