使用iText在AWS S3存储桶中编辑pdf文件

时间:2017-10-17 16:32:25

标签: java amazon-web-services amazon-s3 lambda itext

AWS S3存储桶有1个pdf文件。需要使用iText Java库编辑此pdf文件的内容。修改后的文件需要再次存储在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";
}

1 个答案:

答案 0 :(得分:0)

问题不在于AWS或iText,而在于您处理PipedInputStreamPipedOutputStream的方式。

特别是,大多数有价值的数据在调用stamper.close()时写入PDF,但在关闭压模之前设置内容长度meta.setContentLength(inputStream.available());,因此长度无效。致电putObject后,inputStream实例已关闭(请检查内部closedByReader字段),但pdfBytes仍然与之相关,但在inputStream之后无法写入stamper.close();已关闭,因此当调用inputStream时,您会收到异常,因为您无法再写入ByteArrayOutputStream

我认为在当前方法中解决此问题的任何尝试都已足够,因为在documentation中明确指出

  

通常,一个线程从PipedInputStream对象读取数据,而其他线程将数据写入相应的PipedOutputStream。 建议不要尝试使用单个线程中的两个对象,因为它可能使线程死锁

因此,使用ByteArrayInputStreamByteArrayOutputStream 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(); } 时,一种解决方案虽然效率不高,但却是如此:

PipedInputStream

通常,PDF的大小不是很大,因此您可以将自己存储在内存中。如果要优化内存消耗,则应在单独的线程中执行PDF处理。我建议您查看this文章或搜索PipedOutputStream#include <iostream> #include <string> using namespace std; int main(){ while(true){ int m = 0,n = 10; char check; while(true){ cout << "Enter please number m and which digit you want to select"; cin >> m >> n; string m_new = to_string(m); if(m_new.length() > n) break; else cout << "n must be less than or equal to m"; } cout << "The position" << n << "Of integer" << m << "is:" << m_new.substr(n,1); cout << "Do you want to try again?(y/n)\n"; cin >> check; while(check != 'y'&& check != 'n'){ cout <<"Please enter y or n\n"; cin >> check; } if(check == 'n'){ break; } } return 0; } 一起使用的一般示例。