java - For 循环很慢 - Java
问题描述
我基本上想使用 Apache pdfbox 加载 pdf 并将其转换为每个页面的 base64 列表。
我尝试了以下代码,但它非常慢。我不需要转换成图像,我只想转换成base64传递给前端
PDDocument document = PDDocument.loadNonSeq(new File("Random.pdf"), null);
@SuppressWarnings("unchecked")
List<PDPage> pdPages = document.getDocumentCatalog().getAllPages();
int page = 0;
List<String> base64DocumentPages = new ArrayList<>();
for (PDPage pdPage : pdPages)
{
++page;
BufferedImage img = pdPage.convertToImage(BufferedImage.TYPE_INT_RGB, 300); // this is slow
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIOUtil.writeImage(img, ".png", os);
String base64Page = Base64.getEncoder().encodeToString(os.toByteArray());
base64DocumentPages.add(URLEncoder.encode(base64Page, "UTF-8"));
}
document.close();
我正在使用 PDFBOX 来循环页面,但如果您知道更多,我可以使用任何东西。
PS:我真的需要以某种数组分隔的页面的Base64数据
解决方案
你确定它的convertToImage
方法?在我们的例子中,这是writeImage
需要最长的方法。问题是您使用标准的 PNGWriter。这个有一个缺陷/错误,它总是在时间成本上使用最好的压缩。这已针对 Java 9 进行了修复,但在此之前有一个向后移植的版本可用。那么你需要做什么?
(1)将以下依赖项添加到您的maven projet(如果您不使用maven,则手动添加)
<dependency>
<groupId>net.gredler</groupId>
<artifactId>jdk9-png-writer-backport</artifactId>
<version>1.0.0</version>
</dependency>
(2) 确保您使用 PdfBox 2.X
(3) 更改转换代码:
private static void convertMethod2(File pdf) {
try (final PDDocument document = PDDocument.load(pdf)) {
PDFRenderer pdfRenderer = new PDFRenderer(document);
List<String> base64DocumentPages = new ArrayList<>();
for (int page = 0; page < document.getNumberOfPages(); ++page) {
BufferedImage bim = pdfRenderer.renderImageWithDPI(page, 150, ImageType.RGB);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PNGImageWriterBackport writer = chosePngWriter();
if(writer!=null) {
try (ImageOutputStream stream = new MemoryCacheImageOutputStream(baos)) {
writer.setOutput(stream);
writer.write(null,new IIOImage(bim, null, null), getImageParams(writer));
}
finally {
writer.dispose();
}
}
else {
System.err.println("PNGImageWriterBackport not found! Aborting");
}
String base64Page = Base64.getEncoder().encodeToString(os.toByteArray());
base64DocumentPages.add(URLEncoder.encode(base64Page, "UTF-8"));
}
document.close();
}
catch (IOException e) {
//handle exception
}
}
private static PNGImageWriterBackport chosePngWriter() {
Iterator<ImageWriter> imageWriters = ImageIO.getImageWritersByFormatName("png");
ImageWriter writer = null;
while(imageWriters.hasNext()) {
writer = imageWriters.next();
if (writer instanceof PNGImageWriterBackport) {
return (PNGImageWriterBackport)writer;
}
}
return null;
}
private static ImageWriteParam getImageParams(PNGImageWriterBackport writer) {
ImageWriteParam writeParam = writer.getDefaultWriteParam();
//set compression mode which wasn't possible before
writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
//0.0f highest compression, slowest
//1.0f lowest compression, fastest
writeParam.setCompressionQuality(0.86f);
return writeParam;
}
(4) 当然,如果可以将 DPI 降低到例如 150,它也会加快处理速度。但我知道这并不总是可能的......
对于最小增加 png 文件大小的价格,这将快得多......
推荐阅读
- mysql-workbench - 如何从具有特殊条件mysql的另一个表中创建一个新表
- postgresql - 现有对象的 Postgres 大对象不存在错误
- java - 如何对使用反射填充 subTypesOf 类的 java 代码进行单元测试?
- qt - 如何拆分嵌入在 DLL 中的 QML 文件?
- php - PHP 7.1 致命错误:允许的内存大小为 268435456 字节已用尽
- javascript - 如何动态地将函数数组添加到 javascript 函数中?
- html - 我们如何在 Angular 中预加载字体?
- ocaml - 为什么OCaml类型转换函数以“A_of_B”形式命名?
- .net - 如何使用 C#.NET API 或 Nuget 包运行 Sqlite CLI 点命令(不是 SQL)
- firebase - 限制用户可以调用firebase onCall 函数的次数?