java使用poi、itextpdf将word、ppt转为pdf文件,并对pdf文件加盖签章
转pdf文件
·
1 环境及背景
SpringBoot项目,使用poi、itextpdf将excel、ppt、word文件转为pdf,并对pdf文件进行签章;
对Excel文件加图片水印,并加密设置为只读。
下面的方法都是返回的byte数组,可视具体情况直接将文件输出。
office文件分为2003跟2007版本,所以处理的方法有所区别。
还有很多其他方式可以实现转pdf,例如可以用第三方插件aspose处理office文件,但是需要收费;
可以使用spire,也是收费的;
还可以使用OpenOffice办公组件,加org.jodconverter,组件是适用于Linux,windows的。
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.0.1</version>
</dependency>
<!--添加poi-ooxml依赖包-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>xdocreport</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>com.itextpdf.tool</groupId>
<artifactId>xmlworker</artifactId>
<version>5.5.11</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
2 pdf文件加盖签章
数字证书生成:
keytool -storepass 123456 -genkeypair -keyalg RSA -keysize 1024 -sigalg SHA1withRSA -validity 3650 -alias mycert -keystore my.keystore -dname "CN=www.sample.com, OU=sample, O=sample, L=BJ, ST=BJ, C=CN"
打开cmd窗口直接执行上面命令即可,会生成一个 my.keystore的文件。
/**
* 对pdf进行签章
* @param src pdf文件输入流
* @param imgPath 签章图片路径
* @param reason 签章原因
* @param location 签章地点
* @return
* @throws GeneralSecurityException
* @throws IOException
* @throws DocumentException
*/
public static byte[] sign(InputStream src,String imgPath,String reason,String location) throws GeneralSecurityException, IOException, DocumentException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] resBytes = null;
try{
//读取keystore ,获得私钥和证书链
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(ConvertImgToBase64Util.loadImgResource("templates/keystore/keystore.p12"),"123456".toCharArray());
String alias = (String)keyStore.aliases().nextElement();
PrivateKey PrivateKey = (PrivateKey) keyStore.getKey(alias, "123456".toCharArray());
Certificate[] chain = keyStore.getCertificateChain(alias);
PdfReader pdfReader = new PdfReader(src);
Rectangle rectangle= pdfReader.getPageSize(1);
float urx = rectangle.getRight()-100;
float ury = rectangle.getTop()-100;
float llx = urx-200;
float lly = ury-200;
PdfStamper stamper = PdfStamper.createSignature(pdfReader, baos, '\0', null, false);
// 获取数字签章属性对象,设定数字签章的属性
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation(location);
appearance.setVisibleSignature(new Rectangle(llx,lly,urx,ury), 1, "sign");
//获取盖章图片
byte[] imgBytes = ConvertImgToBase64Util.image2Bytes(imgPath);
Image image = Image.getInstance(imgBytes);
appearance.setSignatureGraphic(image);
//设置认证等级
appearance.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED);
//印章的渲染方式,这里选择只显示印章
appearance.setRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);
ExternalDigest digest = new BouncyCastleDigest();
//签名算法,参数依次为:证书秘钥、摘要算法名称,例如MD5 | SHA-1 | SHA-2.... 以及 提供者
ExternalSignature signature = new PrivateKeySignature(PrivateKey, DigestAlgorithms.SHA1, null);
//调用itext签名方法完成pdf签章
MakeSignature.signDetached(appearance, digest, signature, chain, null, null, null, 0,MakeSignature.CryptoStandard.CMS);
resBytes = baos.toByteArray();
}catch (Exception e){
log.error("pdf文件签章异常:{}",e);
}finally {
try{
if(baos != null){
baos.close();
}
}catch (IOException e){
log.error("关闭io流异常:{}",e);
}
}
return resBytes;
}
上面代码出现的keystore.p12就是my.keystore
3 word转pdf
3.1 docx转pdf
public static byte[] docxToPdf(InputStream src) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] resBytes = null;
String result;
try {
// pdf文件的尺寸
Document pdfDocument = new Document(PageSize.A3, 72, 72, 72, 72);
PdfWriter pdfWriter = PdfWriter.getInstance(pdfDocument, baos);
XWPFDocument doc = new XWPFDocument(src);
pdfWriter.setInitialLeading(20);
java.util.List<XWPFParagraph> plist = doc.getParagraphs();
pdfWriter.open();
pdfDocument.open();
for (int i = 0; i < plist.size(); i++) {
XWPFParagraph pa = plist.get(i);
java.util.List<XWPFRun> runs = pa.getRuns();
for (int j = 0; j < runs.size(); j++) {
XWPFRun run = runs.get(j);
java.util.List<XWPFPicture> piclist = run.getEmbeddedPictures();
Iterator<XWPFPicture> iterator = piclist.iterator();
while (iterator.hasNext()) {
XWPFPicture pic = iterator.next();
XWPFPictureData picdata = pic.getPictureData();
byte[] bytepic = picdata.getData();
Image imag = Image.getInstance(bytepic);
pdfDocument.add(imag);
}
// 中文字体的解决
BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
Font font = new Font(bf, 11.0f, Font.NORMAL, BaseColor.BLACK);
String text = run.getText(-1);
byte[] bs;
if (text != null) {
bs = text.getBytes();
String str = new String(bs);
Chunk chObj1 = new Chunk(str, font);
pdfDocument.add(chObj1);
}
}
pdfDocument.add(new Chunk(Chunk.NEWLINE));
}
//需要关闭,不然无法获取到输出流
pdfDocument.close();
pdfWriter.close();
resBytes = baos.toByteArray();
} catch (Exception e) {
log.error("docx转pdf文件异常:{}",e);
}finally {
try{
if(baos != null){
baos.close();
}
}catch (IOException e){
log.error("docx转pdf关闭io流异常:{}",e);
}
}
return resBytes;
}
3.2 doc转pdf
/**
* doc转为pdf,先将doc转为html,再将html转为pdf,因为使用poi无法直接将doc转为pdf
* @param src
* @return
*/
public static byte[] doc2pdf(InputStream src){
byte[] res = null;
try{
String html = OfficeToPdfUtil.doc2Html(src);
html = OfficeToPdfUtil.formatHtml(html);
res = OfficeToPdfUtil.htmlToPdf(html);
}catch (Exception e){
log.error("doc转pdf异常:{}",e);
}
return res;
}
public class OfficeToPdfUtil {
/**
* html转为pdf
* @param html
* @return
*/
public static byte[] htmlToPdf(String html) {
com.itextpdf.text.Document document = null;
ByteArrayInputStream bais = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] resBytes = null;
try {
document = new com.itextpdf.text.Document(PageSize.A4);
PdfWriter writer = PdfWriter.getInstance(document, baos);
document.open();
bais = new ByteArrayInputStream(html.getBytes());
XMLWorkerHelper.getInstance().parseXHtml(writer, document, bais,
Charset.forName("UTF-8"), new FontProvider() {
@Override
public boolean isRegistered(String s) {
return false;
}
@Override
public Font getFont(String s, String s1, boolean embedded, float size, int style, BaseColor baseColor) {
// 配置字体
Font font = null;
try {
BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
font = new Font(bf, size, style, baseColor);
font.setColor(baseColor);
} catch (Exception e) {
e.printStackTrace();
}
return font;
}
});
document.close();
writer.close();
resBytes = baos.toByteArray();
} catch (Exception e) {
log.error("html转pdf异常:{}",e);
} finally {
if (document != null) {
document.close();
}
if (bais != null) {
try {
bais.close();
} catch (IOException e) {
log.error("html转pdf关闭io流异常:{}",e);
}
}
}
return resBytes;
}
/**
* doc文件转为html
* @param inputStream
* @return
*/
public static String doc2Html(InputStream inputStream) {
String content = null;
ByteArrayOutputStream baos = null;
try {
HWPFDocument wordDocument = new HWPFDocument(inputStream);
WordToHtmlConverter wordToHtmlConverter = new WordToHtmlConverter(DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument());
wordToHtmlConverter.setPicturesManager(new PicturesManager() {
@Override
public String savePicture(byte[] content, PictureType pictureType, String suggestedName, float widthInches, float heightInches) {
return null;
}
});
wordToHtmlConverter.processDocument(wordDocument);
org.w3c.dom.Document htmlDocument = wordToHtmlConverter.getDocument();
DOMSource domSource = new DOMSource(htmlDocument);
baos = new ByteArrayOutputStream();
StreamResult streamResult = new StreamResult(baos);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer serializer = tf.newTransformer();
serializer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
serializer.setOutputProperty(OutputKeys.INDENT, "yes");
serializer.setOutputProperty(OutputKeys.METHOD, "html");
serializer.transform(domSource, streamResult);
} catch (Exception e) {
log.error("doc转html异常:{}",e);
} finally {
try {
if (baos != null) {
content = new String(baos.toByteArray(), "utf-8");
baos.close();
}
} catch (Exception e) {
log.error("doc转html关闭io流异常:{}",e);
}
}
return content;
}
/**
* 使用jsoup规范化html
* @param html html内容
* @return 规范化后的html
*/
public static String formatHtml(String html) {
org.jsoup.nodes.Document doc = Jsoup.parse(html);
// 去除过大的宽度
String style = doc.attr("style");
if (StringUtils.isNotEmpty(style) && style.contains("width")) {
doc.attr("style", "");
}
Elements divs = doc.select("div");
for (org.jsoup.nodes.Element div : divs) {
String divStyle = div.attr("style");
if (StringUtils.isNotEmpty(divStyle) && divStyle.contains("width")) {
div.attr("style", "");
}
}
// jsoup生成闭合标签
doc.outputSettings().syntax(org.jsoup.nodes.Document.OutputSettings.Syntax.xml);
doc.outputSettings().escapeMode(Entities.EscapeMode.xhtml);
return doc.html();
}
}
4 ppt转pdf
4.1 pptx转pdf
public static byte[] pptxToPdf(InputStream src) {
Document document = null;
XMLSlideShow slideShow = null;
FileOutputStream fileOutputStream = null;
PdfWriter pdfWriter = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] resBytes = null;
try {
//使用输入流pptx文件
slideShow = new XMLSlideShow(src);
//获取幻灯片的尺寸
Dimension dimension = slideShow.getPageSize();
//创建一个写内容的容器
document = new Document(PageSize.A3, 72, 72, 72, 72);
//使用输出流写入
pdfWriter = PdfWriter.getInstance(document, baos);
//使用之前必须打开
document.open();
pdfWriter.open();
PdfPTable pdfPTable = new PdfPTable(1);
//获取幻灯片
java.util.List<XSLFSlide> slideList = slideShow.getSlides();
for (int i = 0, row = slideList.size(); i < row; i++) {
//获取每一页幻灯片
XSLFSlide slide = slideList.get(i);
for (XSLFShape shape : slide.getShapes()) {
//判断是否是文本
if(shape instanceof XSLFTextShape){
// 设置字体, 解决中文乱码
XSLFTextShape textShape = (XSLFTextShape) shape;
for (XSLFTextParagraph textParagraph : textShape.getTextParagraphs()) {
for (XSLFTextRun textRun : textParagraph.getTextRuns()) {
textRun.setFontFamily("宋体");
}
}
}
}
//根据幻灯片尺寸创建图形对象
BufferedImage bufferedImage = new BufferedImage((int)dimension.getWidth(), (int)dimension.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2d = bufferedImage.createGraphics();
graphics2d.setPaint(Color.white);
graphics2d.setFont(new java.awt.Font("宋体", java.awt.Font.PLAIN, 12));
//把内容写入图形对象
slide.draw(graphics2d);
graphics2d.dispose();
//封装到Image对象中
Image image = Image.getInstance(bufferedImage, null);
image.scalePercent(50f);
// 写入单元格
pdfPTable.addCell(new PdfPCell(image, true));
document.add(image);
}
document.close();
pdfWriter.close();
resBytes = baos.toByteArray();
} catch (Exception e) {
log.error("pptx转pdf异常:{}",e);
} finally {
try {
if (baos != null) {
baos.close();
}
} catch (IOException e) {
log.error("pptx转pdf关闭io流异常:{}",e);
}
}
return resBytes;
}
4.2 ppt转pdf
/**
* 将ppt转为pdf,兼容ppt和pptx
* @param is
* @return
*/
public static byte[] ppt2pdf(InputStream is) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] resBytes = null;
try {
Document pdfDocument = new Document();
PdfWriter pdfWriter = PdfWriter.getInstance(pdfDocument, baos);
HSLFSlideShow hslfSlideShow = new HSLFSlideShow(is);
double zoom = 2;
if (hslfSlideShow == null) {
XMLSlideShow ppt = new XMLSlideShow(is);
if (ppt == null) {
throw new NullPointerException("获取ppt文件数据失败");
}
Dimension pgsize = ppt.getPageSize();
List<XSLFSlide> slide = ppt.getSlides();
AffineTransform at = new AffineTransform();
at.setToScale(zoom, zoom);
pdfDocument.setPageSize(new Rectangle((float) pgsize.getWidth(), (float) pgsize.getHeight()));
pdfWriter.open();
pdfDocument.open();
PdfPTable table = new PdfPTable(1);
for (XSLFSlide xslfSlide : slide) {
BufferedImage img = new BufferedImage((int) Math.ceil(pgsize.width * zoom), (int) Math.ceil(pgsize.height * zoom), BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = img.createGraphics();
graphics.setTransform(at);
graphics.setPaint(Color.white);
graphics.fill(new Rectangle2D.Float(0, 0, pgsize.width, pgsize.height));
xslfSlide.draw(graphics);
graphics.getPaint();
Image slideImage = Image.getInstance(img, null);
table.addCell(new PdfPCell(slideImage, true));
}
ppt.close();
pdfDocument.add(table);
pdfDocument.close();
pdfWriter.close();
resBytes = baos.toByteArray();
return resBytes;
}
Dimension pgsize = hslfSlideShow.getPageSize();
List<HSLFSlide> slides = hslfSlideShow.getSlides();
pdfDocument.setPageSize(new Rectangle((float) pgsize.getWidth(), (float) pgsize.getHeight()));
pdfWriter.open();
pdfDocument.open();
AffineTransform at = new AffineTransform();
PdfPTable table = new PdfPTable(1);
for (HSLFSlide hslfSlide : slides) {
BufferedImage img = new BufferedImage((int) Math.ceil(pgsize.width * zoom), (int) Math.ceil(pgsize.height * zoom), BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = img.createGraphics();
graphics.setTransform(at);
graphics.setPaint(Color.white);
graphics.fill(new Rectangle2D.Float(0, 0, pgsize.width, pgsize.height));
hslfSlide.draw(graphics);
graphics.getPaint();
Image slideImage = Image.getInstance(img, null);
table.addCell(new PdfPCell(slideImage, true));
}
hslfSlideShow.close();
pdfDocument.add(table);
pdfDocument.close();
pdfWriter.close();
resBytes = baos.toByteArray();
return resBytes;
} catch (Exception e) {
log.error("ppt转为pdf异常:{}",e);
}
return resBytes;
}
这里兼容有点问题,当HSLFSlideShow hslfSlideShow = new HSLFSlideShow(is)无法创建对象时,io流无法再被使用了,则无法再去创建XMLSlideShow对象。但是可以使用此方法转ppt后缀的文件。
5 excel文件加图片水印,并加密
@Slf4j
public class ExcelWaterMakerUtils {
/**
* 给Excel添加图片水印,并加密,返回新文件的byte数组
* @param imgPath
* @param fileName
* @param fis
* @return
*/
public static byte[] addWaterMaker(String imgPath,String fileName, InputStream fis){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedImage bufferImg = null;
byte[] resBytes = null;
try {
Workbook workbook;
if (fileName.endsWith(".xlsx")){
workbook = new XSSFWorkbook(fis);
} else {
workbook = new HSSFWorkbook(fis);
}
//设置Excel为只读
String password = RandomStringUtils.random(6,false,true);
int sheetNumbers = workbook.getNumberOfSheets();
short rightNum = 3;
short leftNum = 2;
for (int i = 0; i < sheetNumbers; i++) {
Sheet sheet = workbook.getSheetAt(i);
sheet.protectSheet(password);
Row row = sheet.getRow(1);
if(row == null){
break;
}
short cellLastNum = row.getLastCellNum();
rightNum = (short) (cellLastNum-1);
leftNum = (short) (cellLastNum - 2);
ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
InputStream img = ConvertImgToBase64Util.loadImgResource(imgPath);
bufferImg = ImageIO.read(img);
//第二个参数将会决定插入图片形式,如果是一个png的图片,背景透明,但是此处设置为jpg格式将会自动添加黑色背景
ImageIO.write(bufferImg, "png", byteArrayOut);
//画图的顶级管理器,一个sheet只能获取一个
Drawing drawing = sheet.createDrawingPatriarch();
//anchor主要用于设置图片的属性
ClientAnchor anchor = drawing.createAnchor(0, 0, 255, 255,leftNum, 1, rightNum, 1);
// anchor.setAnchorType(2);
//插入图片
drawing.createPicture(anchor, workbook.addPicture(byteArrayOut.toByteArray(), HSSFWorkbook.PICTURE_TYPE_PNG));
Picture pic = drawing.createPicture(anchor,
workbook.addPicture(byteArrayOut.toByteArray(), Workbook.PICTURE_TYPE_PNG));
pic.resize();
}
workbook.write(baos);
resBytes = baos.toByteArray();
fis.close();
baos.close();
} catch (Exception e) {
log.error("Excel盖章异常:{}",e);
}finally{
try{
if(fis != null){
fis.close();
}
if(baos != null){
baos.close();
}
}catch (IOException ioe){
log.error("Excel盖章关闭io流异常:{}",ioe);
}
}
return resBytes;
}
}
图片的位置是根据excel表的行列来定位的,所以不同的excel文件图片的大小可能会有变化,需要优化下,我优化了很久没能实现,将就用着吧。。。
原本是将excel转成pdf文件,加盖受控签章的,但是复杂的exce转成pdf后,样式变化太大,乱了。
更多推荐
已为社区贡献1条内容
所有评论(0)