簡體   English   中英

使用iText在AWS S3存儲桶中編輯pdf文件

[英]Edit pdf file in AWS S3 bucket using iText

AWS S3存儲桶具有1個pdf文件。 該pdf文件的內容需要使用iText Java庫進行編輯。 修改后的文件需要再次存儲在S3存儲桶中。 當前,我們正在使用AWS Lambda函數。 在目標s3存儲桶中創建空pdf文件,並在AWS cloudWatch中顯示錯誤消息:“管道已關閉”

Lambda Java代碼:

private String bucketName = "forms-storage";

public String getProposalPdf(InputRequest inputRequest, Context context) throws DocumentException, IOException{

    final BasicAWSCredentials awsCreds = new BasicAWSCredentials(ConstantValues.AccessKey, ConstantValues.SecretKey);
    final AmazonS3Client s3client = (AmazonS3Client) AmazonS3ClientBuilder.standard().withRegion(Regions.AP_SOUTH_1)
                    .withCredentials(new AWSStaticCredentialsProvider(awsCreds)).build();
    S3Object object = s3client.getObject(new GetObjectRequest(bucketName, "forms/COMBO ver 1.1.pdf"));
    InputStream objectData = object.getObjectContent();

    PdfReader reader;
    PdfStamper stamper = null;
    BaseFont bf;

    PipedOutputStream pdfBytes = new PipedOutputStream();

    try {           
        reader = new PdfReader(objectData);
        stamper = new PdfStamper(reader, pdfBytes);

        bf = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);

        PdfContentByte over = stamper.getOverContent(1);
        over.beginText();
        over.setColorFill(BaseColor.BLACK);
        over.setFontAndSize(bf, 12);
        over.setTextMatrix(120,717);
        over.showText("this is edited text");
        over.endText();

        PipedInputStream inputStream = new PipedInputStream(pdfBytes);

        ObjectMetadata meta = new ObjectMetadata();
        meta= object.getObjectMetadata();
        meta.setContentLength(inputStream.available());         

        s3client.putObject(new PutObjectRequest(bucketName, "forms/123.pdf", inputStream, meta));           

    } catch (IOException e) {
        e.printStackTrace();
    } catch (DocumentException e) {
        e.printStackTrace();
    } 
    finally
    {
        stamper.close();            
        objectData.close();
    }
    return "PDF Created";
}

問題不在於AWS或iText,而在於您處理PipedInputStreamPipedOutputStream

特別是,在stamper.close()時,大多數有價值的數據都會寫入PDF,但是您可以設置內容長度meta.setContentLength(inputStream.available()); 關閉壓模之前,因此長度無效。 調用putObject ,將關閉inputStream實例(請檢查內部的closedByReader字段),但pdfBytes保持連接狀態,並且在inputStream關閉后無法對其進行寫入,因此,在stamper.close(); ,該方法不可用stamper.close(); 被調用時,您將收到一個異常,因為您不再能夠寫入inputStream

我認為以當前方法解決該問題的任何嘗試都無法滿足要求,因為在文檔中明確指出:

通常,一個線程從PipedInputStream對象讀取數據,而另一個線程將數據寫入相應的PipedOutputStream。 不建議嘗試從單個線程使用兩個對象,因為這可能會死鎖該線程

因此,一種解決方案是使用ByteArrayOutputStreamByteArrayInputStream ,盡管內存效率不高:

ByteArrayOutputStream pdfBytes = new ByteArrayOutputStream();

try {
    reader = new PdfReader(objectData);
    stamper = new PdfStamper(reader, pdfBytes);

    bf = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);

    PdfContentByte over = stamper.getOverContent(1);
    over.beginText();
    over.setColorFill(BaseColor.BLACK);
    over.setFontAndSize(bf, 12);
    over.setTextMatrix(120,717);
    over.showText("this is edited text");
    over.endText();

    stamper.close();
    objectData.close();

    ObjectMetadata meta = new ObjectMetadata();
    meta= object.getObjectMetadata();
    ByteArrayInputStream inputStream = new ByteArrayInputStream(pdfBytes.toByteArray());
    meta.setContentLength(inputStream.available());

    s3client.putObject(new PutObjectRequest(bucketName, "forms/123.pdf", inputStream, meta));      

} catch (IOException e) {
    e.printStackTrace();
} catch (DocumentException e) {
    e.printStackTrace();
}

通常,PDF的大小不是很大,因此您可以自己將它們存儲在內存中。 如果要優化內存消耗,則應在單獨的線程中進行PDF處理。 我建議檢查這個文章或搜索使用的通用例子PipedInputStreamPipedOutputStream

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM