提问者:小点点

如何使用itext7从PdfDocument获取pdf byte[]?


我很难理解如何从PdfDocument中获取内容。我从之前的问题中了解到PdfDocument刷新内容以优化处理大型文档。如果我的函数返回一个新的PdfDocument,我如何让字节[]传递给我的其他函数?

即使使用PdfDocument. GetReader()-我似乎找不到我要找的东西。

我的用例如下:

  1. 从电子邮件附件获取pdf内容
  2. 将pdf传递给帮助函数,该函数从初始附件中提取特定页面
  3. 将新的PdfDocument传递到一个函数中,该函数调用Azure的表单识别器API将字段读取到对象中

总而言之:仅给定一个PdfDocument,如何从中获取/创建一个byte[]?

这是我的代码:

public async Task<BaseResponse> Handle(ReceiveEmailCommand command, CancellationToken cancellationToken) {
  var ms = new MemoryStream(command.attachments.First().Content)
  var extractedDocument = pdfService.PreparePdfDocument(ms);
  var analyzedDocument = await formsRecognizerService.AnalyzeDocument(extractedDocument);
  // Do stuff with the analyzed document...
  var response = await FileWebService.AddAnalyzedDocumentToFileSystem(analyzedDocument);
}

函数AnalyzeDocument需要一个Stream参数。我想传递类似的东西

new Stream(extractedDocument.GetReader().Stream)

Helper函数实现如下:

        public PdfDocument PreparePdfDocument(MemoryStream ms)
        {
            PdfDocument extractedDoc;
            var pdfReader = new PdfReader(ms);
            var pdf = new PdfDocument(pdfReader);
            var doc = new Document(pdf);

            var matches = GetNumberWithPages(pdf);
            if (matches.Count > 0)
            {
                var pageRange = matches
                    .Where(x => x.Number == "125")
                    .Select(x => Convert.ToInt32(x.PageIndex))
                    .ToList();
                extractedDoc = SplitPages(pdf, pageRange.First(), pageRange.Last());
            }
            else
            {
                // If we couldn't parse the PDF then just take first 4, 3 or 2 pages
                try
                {
                    extractedDoc = SplitPages(pdf, 1, 4);
                }
                catch (ITextException)
                {
                    try
                    {
                        extractedDoc = SplitPages(pdf, 1, 3);
                    }
                    catch (ITextException)
                    {
                        try
                        {
                            extractedDoc = SplitPages(pdf, 1, 2);
                        }
                        catch (Exception)
                        {
                            throw;
                        }
                    }
                }
            }

            return extractedDoc;
        }
        private static List<Match> GetNumberWithPages(PdfDocument doc)
        {
            var regex = new Regex(@"\s+([0-9]+)\s+(\([0-9]+\/[0-9]+\))\s+Page\s+([0-9])\s+of\s+([0-9]+)");
            var matches = new List<Match>();

            for (int i = 1; i <= doc.GetNumberOfPages(); i++)
            {
                var page = doc.GetPage(i);
                var text = PdfTextExtractor.GetTextFromPage(page);

                if (!string.IsNullOrEmpty(text))
                {
                    var match = regex.Match(text);
                    if (match.Success)
                    {
                        var match = EvaluateMatch(match, i, doc.GetNumberOfPages());
                        if (match != null)
                        {
                            matches.Add(match);
                        }
                    }
                }
            }

            return matches;
        }
        private static Match? EvaluateMatch(Match match, int pageIndex, int totalPages)
        {
            if (match.Captures.Count == 1 && match.Groups.Count == 5)
            {
                var match = new Match
                {
                    Number = match.Groups[1].Value,
                    Version = match.Groups[2].Value,
                    PageIndex = pageIndex.ToString(),
                    TotalPages = totalPages.ToString()
                };

                return match;
            }
            else
            {
                return null;
            }
        }
        public PdfDocument SplitPages(PdfDocument doc, int startIndex, int endIndex)
        {
            var outputDocument = CreatePdfDocument();
            doc.CopyPagesTo(startIndex, endIndex, outputDocument);

            return outputDocument;
        }
        public PdfDocument CreatePdfDocument()
        {
            var baos = new ByteArrayOutputStream();
            var writer = new PdfWriter(baos);
            var pdf = new PdfDocument(writer);
            
            return pdf;
        }

共1个答案

匿名用户

我很难理解如何从PdfDocument获取内容。

你不知道!

当您创建要写入的PdfDocument时,您可以使用PdfWriter对其进行初始化。该PdfWriter已被初始化以写入某处。如果您想访问最终的PDF,您必须关闭PdfDocument并在某处查看它。此外,从PdfWriter中检索它也不容易,因为它被包裹在其中的许多层中。因此,您应该在附近的某个地方保留对它的引用。

因此,您的ByteArrayOutputStream通常不会隐藏在某个方法CreatePdfDocument中创建,而是在基本方法中创建并作为参数转发给其他方法。然后您最终可以检索其数据。如果您需要像这样隐藏创建您的ByteArrayOutputStream,您可以返回PdfDocumentByteArrayOutputStream而不是<普通code>PdfDocument。

顺便说一下,这种架构背后的想法是iText试图尽早将尽可能多的PDF内容写入某个地方的输出并释放内存。这允许它创建大型文档,而不需要同样大的内存。

当我返回流时,我无法访问关闭的流

ByteArrayOutputStream本质上是一个MemoryStream;因此您可以特别调用ToArray来检索完成的PDF,即使它已关闭。

如果您需要将ByteArrayOutputStream作为常规流,只需为您的编写器调用PdfWriter. SetCloseStream(false),以防止PdfDocument关闭也关闭流。