我使用此方法来签署 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 的内存使用量,并且已经减少了一点。
PdfWriter
和PdfDocument
实例此外,你做
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
具有自己内部PdfWriter
和PdfDocument
实例的实例。
因此,不要创建自己PdfWriter
和PdfDocument
实例。您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] 删除。
我来说两句