最近实现发票连续打印时,直接copy其他项目代码来用,主要是对文件的处理,这部分可以不涉及数据库操作,这种功能也很方便写单元测试。在写单元测试图片转PDF功能时,发现了一段有趣的代码:
protected void scaleImage(com.itextpdf.text.Image image) {float imageHeight = image.getScaledHeight();float imageWidth = image.getScaledWidth();int i = 0;while (imageHeight > 500 || imageWidth > 500) {image.scalePercent(100 - i);i++;imageHeight = image.getScaledHeight();imageWidth = image.getScaledWidth();}
}
这段代码是对图片进行缩放,如果宽和高大于500就进行缩放,有意思的地方是明明可以直接计算出缩放倍率,偏偏要从 100%(i++位置调一下也能避免一次无用功)一直尝试到符合为止,我测试的图片是宽795高528,一直尝试到62%才满足,如果图片缩放涉及IO操作,消耗的资源可能会更大,经过查看 itextpdf 源码发现 scalePercent
里面涉及几十次运算,纯计算执行几百或者几千次也很快。
这段代码的思想很好,但要谨慎使用,如果提前计算直接缩放,代码反而更简单:
protected void scaleImage(Image image) {float imageHeight = image.getScaledHeight();float imageWidth = image.getScaledWidth();float scalePercent = Math.min(500 / imageHeight, 500 / imageWidth) * 100;image.scalePercent(scalePercent);
}
做到这一步就算完事了吗?
当然不是,往PDF放图片为什么缩放呢,为什么宽高限制500呢?为什么只有一个图片的情况下,转成的PDF是一张A4纸的比例呢?为什么不像其他电子发票(不是数电发票)那样刚刚好的尺寸?
宽高限制500的情况下和其他PDF格式的发票合并到一起时明显更窄,样式不统一不好看,通过查看PDF的宽高,经过计算将宽度设置为 595 的时候样式是统一的。另外高度不应该限制500,如果发票很长,按高度缩放后会很窄,内容会看不清,因此应该只限制宽度,不限制高度。经过这种调整后代码如下:
protected void scaleImage(Image image) {float imageWidth = image.getScaledWidth();float scalePercent = 595 / imageWidth * 100;image.scalePercent(scalePercent);
}
另外就是PDF的尺寸,直接和缩放后的图片大小一致就可以,没必要浪费纸,因此改造后的整个方法如下:
protected InputStream imageToPdf(InputStream is, List<File> tempFiles) {File outFile = FileUtil.createTempFile(".pdf", true);try (FileOutputStream out = new FileOutputStream(outFile)) {Image image = Image.getInstance(IoUtil.readBytes(is));//缩放图片scaleImage(image);//设置尺寸Document document = new Document(new Rectangle(image.getScaledWidth(), image.getScaledHeight()),0, 0, 0, 0);PdfWriter.getInstance(document, out);document.open();image.setAlignment(Image.ALIGN_CENTER);document.add(image);document.close();out.flush();return Files.newInputStream(outFile.toPath());} catch (Exception e) {log.error("图片转换成pdf失败", e);throw new BusinessException("图片转换成pdf失败");} finally {IoUtil.close(is);tempFiles.add(outFile);}
}
一开始只用图片宽高设置 Document 时发现高度有截断,增加 margin 设置后变成和图片一致了。最终在合并后的PDF中,所有文档的宽度也变得整齐一致了。
图中上面是ofd转pdf后的页面,下面是图片转pdf后的页面。可以从图中(绿边)方框截图放大效果中看到对齐的效果,非常完美!
写代码很简单,想要写好需要多思考,还需要对自己有更高的要求。