使用 IText 7 签署 Pdf 时的 Java 堆空间

法比奥·埃伯纳

我使用此方法来签署 pdf 文件:

public File sign7(File pdfOriginal,
                          String diretorioSalvar,
                          String nomeArquivo,
                          String motivo, String local,
                          LocalDateTime data,
                          String textoAssinatura,
                          boolean visible,
                          PDFService.DisposicaoPagina dispPagina,
                          File arquivoOriginal
                          ) throws IOException, DocumentException, GeneralSecurityException {

            log.debug("comecou assinar");
            File diretorioSaida = new File(diretorioSalvar);
            diretorioSaida.mkdirs();
            File pdfAssinado = new File(diretorioSalvar+File.separator+nomeArquivo);
            String keystore_password = KEYSTORE_PASSWORD;
            String key_password = KEYSTORE_PASSWORD;
            keystore.load(KEYSTORE.getInputStream(), keystore_password.toCharArray());

            PrivateKey key = (PrivateKey) keystore.getKey(alias, key_password.toCharArray());
            Certificate[] chain = keystore.getCertificateChain(alias);

            log.debug("keystore provider   : {}", keystore.getProvider().getName());
            log.debug("Assinando com alias :{}", alias);
            log.debug("chain size: " + chain.length);

            PdfReader reader = new PdfReader(new RandomAccessBufferedFileInputStream(pdfOriginal));
            PdfWriter writer = new PdfWriter(pdfAssinado);
            PdfDocument doc = new PdfDocument(reader,writer);
            FileOutputStream os = new FileOutputStream(pdfAssinado);

            PdfSigner signer = new PdfSigner(doc.getReader(),os,true);
            signer.setCertificationLevel(PdfSigner.NOT_CERTIFIED);


            //TEXTO DO CARIMBO
            String texto;
            ImageData imgCarimbo;


            PdfPage moldPage = doc.getLastPage();
            PageSize pSize = new PageSize(moldPage.getPageSize());
            PdfCanvas cPage = new PdfCanvas(moldPage);


            PdfFont font = null;
            try {
                font = PdfFontFactory.createFont(FONT.getFile().getPath(), PdfEncodings.WINANSI, true);
            } catch (IOException e) {
                e.printStackTrace();
            }
            cPage.setFillColor(Color.BLACK);

            Rectangle rect = new Rectangle(
                    (float) (pSize.getWidth()*0.653),  //0.725  Y
                    (float) (pSize.getHeight()*0.9),  //0.90    X
                    (float) (pSize.getWidth()*0.32),   //0.25   Largura
                    (float) (pSize.getHeight()*0.068)); //0.07   Altura



            cPage.fillStroke();


            PdfFormXObject xObject = new PdfFormXObject(rect);

            Image rectImg = new Image(xObject);

            ImageData imgLogoCarimboOval = ImageDataFactory.create(LOGO_CARIMBO_DIGITAL.getFile().getPath());
            ImageData imgLogoCarimboBg = ImageDataFactory.create(LOGO_CARIMBO_BG.getFile().getPath());


            int paginaAparencia = (dispPagina == PDFService.DisposicaoPagina.ULTIMA_PAGINA?doc.getNumberOfPages():1);

            String arqOriginalHash = "";
            if (arquivoOriginal != null) {
                arqOriginalHash = pdfService.gerarHash(arquivoOriginal);
            }

            PdfSignatureAppearance appearance = signer
                    .getSignatureAppearance()
                    .setReason(motivo + " - Hash: " + arqOriginalHash)
                    .setLocation(local)
                    .setReuseAppearance(false)
                    .setImage(imgLogoCarimboBg)
                    .setSignatureGraphic(imgLogoCarimboOval)
                    .setImageScale(100)
                    .setRenderingMode(RenderingMode.GRAPHIC_AND_DESCRIPTION)
                    .setPageRect(rect)
                    .setLayer2Font(font)
                    .setLayer2FontSize(6)
                    .setLayer2Text(textoAssinatura)
                    .setPageNumber(paginaAparencia);



            signer.setFieldName(signer.getNewSigFieldName());
            // Creating the signature
            IExternalSignature pks = new PrivateKeySignature(key, DigestAlgorithms.SHA1, "BC");
            IExternalDigest digest = new ProviderDigest("BC");


            Collection<ICrlClient> crlList=null; IOcspClient ocspClient = null; ITSAClient tsaClient=null;

            writer.close();
            signer.signDetached(digest, pks, chain, crlList, ocspClient, tsaClient, 0, PdfSigner.CryptoStandard.CMS);
            reader.close();

            os.close();
            log.debug("acabou assinar");
            return pdfAssinado;
    }    

(此方法在我的最后一页中创建一个图章并签署 pdf)但是当我尝试签署一个 500MB 的文件时,我得到了一个 Java 堆空间:

signer.signDetached(digest, pks, chain, crlList, ocspClient, tsaClient, 0, PdfSigner.CryptoStandard.CMS);

如果我尝试签署较小的文件有效(我只尝试了一个,不知道我是否同时尝试多个我会得到同样的错误)

我已经尝试从我的应用程序更改内存但没有成功。

马克尔

PdfReader 实例化

在您的PdfReader实例化过程中,您将 PDF 库与内存中原始文件副本的额外内存需求混合在一起,再加上一点。对于File pdfOriginal你做的:

PdfReader reader = new PdfReader(new RandomAccessBufferedFileInputStream(pdfOriginal));

RandomAccessBufferedFileInputStream不是 iText 类!但是我假设您在这里使用了这个名称的 PDFBox 类。这个 PDFBox 类也是一个InputStream实现 PDFBox 的RandomAccessRead接口,它以通用的随机访问方式处理本地文件系统文件。

由于 iText 确实有自己的机制来实现文件随机访问,特别是不使用 PDFBox 接口,它只识别和使用一个RandomAccessBufferedFileInputStream实例作为InputStream. 因此,iText 将该 Stream 中的所有数据读入 abyte[]以获得适当的随机访问支持。

相反,如果您允许 iText 查看源是本地文件系统文件,则它可以使用自己的随机文件访问,并且不会创建文件的内存副本。只需使用

PdfReader reader = new PdfReader(pdfOriginal);

对于您的500MB 文件,这将减少 500 MB 的内存使用量,并且已经减少了一点。

额外PdfWriterPdfDocument实例

此外,你做

PdfWriter writer = new PdfWriter(pdfAssinado);
PdfDocument doc = new PdfDocument(reader,writer);
FileOutputStream os = new FileOutputStream(pdfAssinado);

PdfSigner signer = new PdfSigner(doc.getReader(),os,true);

即您自己创建一个PdfWriter和一个PdfDocument实例,它只会消耗额外的内存,然后创建一个PdfSigner具有自己内部PdfWriterPdfDocument实例的实例。

因此,不要创建自己PdfWriterPdfDocument实例。PdfDocument稍后访问自己的实例以确定页面大小;你应该改用PdfSigner

FileOutputStream os = new FileOutputStream(pdfAssinado);
PdfSigner signer = new PdfSigner(reader,os,true);
PdfDocument doc = signer.getDocument();

并删除后面的writer.close()指令。

这减少了那些额外对象需要的内存使用量。

内存中的临时文件复制

PdfSigner像这样实例化

PdfSigner signer = new PdfSigner(reader,os,true);

如 JavaDocs 中所述,此构造函数将中间文件副本(在签名创建期间需要)保存在一个ByteArrayOutputStream实例中,即在内存中:

/**
 * Creates a PdfSigner instance. Uses a {@link java.io.ByteArrayOutputStream} instead of a temporary file.
 *
 * @param reader       PdfReader that reads the PDF file
 * @param outputStream OutputStream to write the signed PDF file
 * @param append       boolean to indicate whether the signing should happen in append mode or not
 * @throws IOException
 * @deprecated         will be removed in next major release.
 *                     Use {@link #PdfSigner(PdfReader, OutputStream, StampingProperties)} instead.
 */
@Deprecated
public PdfSigner(PdfReader reader, OutputStream outputStream, boolean append) throws IOException

而是为此在文件系统中提供一个临时文件:

String temporaryFile = pdfAssinado.getAbsolutePath() + ".tmp";
PdfSigner signer = new PdfSigner(reader, os, temporaryFile, true);

对于您的500MB 文件,这将再次减少 500 MB 的内存使用量。


对 500 MB 文件进行签名时,上述更改将使您的内存占用减少 1 GB 以上。我不知道这是否足够,但这至少应该大大减少内存需求。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

使用IText SignDeferred签署文件时如何保留PDF-A

来自分类Dev

itext-无法使用其他USB令牌签署pdf

来自分类Dev

使用Carrot2时出现Java堆空间错误

来自分类Dev

关于使用Collection对象时的Java堆空间

来自分类Dev

使用iText7和Vb.Net签名Pdf时缺少MissingMethodException

来自分类Dev

如何使用证书 pkcs7 签署 xml - Java

来自分类Dev

尝试使用 java 签署 pdf 文档。为什么 PDF 文件中的签名无效?

来自分类Dev

使用toPandas()和databricks连接时遇到“ java.lang.OutOfMemoryError:Java堆空间”

来自分类Dev

在控制台中打印西班牙语文本并使用 Itext 7 将其写入 PDF 时出现问题

来自分类Dev

使用 Azure Key Vault + Azure Function Apps + CA 证书签署 PDF 文档时出错

来自分类Dev

如何使用iText 7将PDF写入HttpResponseMessage

来自分类Dev

如何使用 iText 7 删除 PDF 文件中的重复字体

来自分类Dev

iText Java签名PDF DocumentException:没有足够的空间

来自分类Dev

使用大型并行Java 8流时如何防止堆空间错误

来自分类Dev

使用多个连续图像时如何修复内存不足的Java堆空间

来自分类Dev

使用PDFBox 2.0.0签署加密的PDF文档

来自分类Dev

使用 PDBOX 签署大 PDF 文件

来自分类Dev

在Android上使用IText创建PDF时获取IOException

来自分类Dev

使用iText从pdf文件读取json时出错

来自分类Dev

选择使用itext填充的pdf时出现错误

来自分类Dev

使用 itext 编辑 pdf 时出现异常

来自分类Dev

OutOfMemoryError:使用 XSLT 转换的 Java 堆空间

来自分类Dev

使用 iText 锁定 pdf

来自分类Dev

压缩大量pdf文件并下载:OutOfMemoryError:Java堆空间

来自分类Dev

合并PDF并在Java中使用iText添加书签

来自分类Dev

从Java代码创建PDF文件[不使用iText]

来自分类Dev

合并PDF并在Java中使用iText添加书签

来自分类Dev

如何使用itext 5.3.0在PDF文档中显示Java List <>?

来自分类Dev

IText 无法使用 Java 读取 PDF 中的空格

Related 相关文章

  1. 1

    使用IText SignDeferred签署文件时如何保留PDF-A

  2. 2

    itext-无法使用其他USB令牌签署pdf

  3. 3

    使用Carrot2时出现Java堆空间错误

  4. 4

    关于使用Collection对象时的Java堆空间

  5. 5

    使用iText7和Vb.Net签名Pdf时缺少MissingMethodException

  6. 6

    如何使用证书 pkcs7 签署 xml - Java

  7. 7

    尝试使用 java 签署 pdf 文档。为什么 PDF 文件中的签名无效?

  8. 8

    使用toPandas()和databricks连接时遇到“ java.lang.OutOfMemoryError:Java堆空间”

  9. 9

    在控制台中打印西班牙语文本并使用 Itext 7 将其写入 PDF 时出现问题

  10. 10

    使用 Azure Key Vault + Azure Function Apps + CA 证书签署 PDF 文档时出错

  11. 11

    如何使用iText 7将PDF写入HttpResponseMessage

  12. 12

    如何使用 iText 7 删除 PDF 文件中的重复字体

  13. 13

    iText Java签名PDF DocumentException:没有足够的空间

  14. 14

    使用大型并行Java 8流时如何防止堆空间错误

  15. 15

    使用多个连续图像时如何修复内存不足的Java堆空间

  16. 16

    使用PDFBox 2.0.0签署加密的PDF文档

  17. 17

    使用 PDBOX 签署大 PDF 文件

  18. 18

    在Android上使用IText创建PDF时获取IOException

  19. 19

    使用iText从pdf文件读取json时出错

  20. 20

    选择使用itext填充的pdf时出现错误

  21. 21

    使用 itext 编辑 pdf 时出现异常

  22. 22

    OutOfMemoryError:使用 XSLT 转换的 Java 堆空间

  23. 23

    使用 iText 锁定 pdf

  24. 24

    压缩大量pdf文件并下载:OutOfMemoryError:Java堆空间

  25. 25

    合并PDF并在Java中使用iText添加书签

  26. 26

    从Java代码创建PDF文件[不使用iText]

  27. 27

    合并PDF并在Java中使用iText添加书签

  28. 28

    如何使用itext 5.3.0在PDF文档中显示Java List <>?

  29. 29

    IText 无法使用 Java 读取 PDF 中的空格

热门标签

归档