最近收到很多文件,为了保持格式统一,需要统一保存为PDF,但是现在在网上搜索下PDF相关的转换软件,号称免费的给你转前几页(日常简单任务已经可以胜任了,可以先pdf拆分后在转换),要不就是收费的,要不号称免费但进去后还是收费的,还有转换是免费的,下载是收费的。
上图说什么我也不知道的,动图没有文字。
不过大多数提供的功能还是比较完善的,知识付费时代提供服务收取一定费用无可厚非,但是诱导付费行为不值得提倡,前段时间听说有个公司提供VS Code下载还要收费的,这是真的么。
说这么多呢,其实就是一个原因 我想(bai) (piao),怎么实现这个愿望呢,那么自己尝试实现一个吧。下面以PDF转图片举例看下实现过程,PDF转换在网上有很多开源代码,大家可以尝试下
本人CSS小白,不会修改样式,大家将就看看就可以哈
PDF转图片页面
转换后直接生成target压缩包下载
前端实现
<template>
<el-card>
<el-row :gutter="10">
<el-col :span="12">
<h4 class="mgb20">PDF转图片</h4>
</el-col>
<el-col :span="12" align="right">
<el-button @click=""><i class="icon-heart" style="margin-right: 5px;"></i> <span>点赞</span>
(<span>12345</span>)</el-button>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="24">
<el-card class="mgb20">
<el-upload ref="upload" class="upload-demo" drag action="#" :auto-upload="false" :limit="1" :before-upload="beforeUpload"
:http-request="uploadFile">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">只能上传PDF文件,且不超过500kb</div>
</el-upload>
</el-card>
</el-col>
</el-row>
<el-row>
<el-col>
<el-button type="success" @click="submitUpload">转换</el-button>
</el-col>
</el-row>
</el-card>
</template>
<script>
import axios from 'axios';
let server = axios.create({
transformRequest: [
function(data) {
let ret = ''
for (let it in data) {
ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
}
ret = ret.substring(0, ret.lastIndexOf('&'));
return ret
}
],
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
export default {
data() {
return {
user: JSON.parse(localStorage.getItem('wr_user')),
fileList: [],
thumbs: ''
}
},
created() {
},
methods: {
//校验格式
beforeUpload(file) {
const isPDF = file.type === 'application/pdf';
if(!isPDF) {
this.$message.warning('只支持PDF格式文件');
return false;
}
},
uploadFile(file) {
const loading = this.$loading({
lock: true,
text: '转换中,请等待',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
// 把文件放入 FormData 进行提交
const param = new FormData()
if (undefined !== file) {
param.append('files', file.file)
}
param.append("username", this.user.username)
axios({
url: "/pdf/tools/pdf2img",
method: "post",
responseType: 'blob', //不可省,非常重要
data: param
}).then((res) => {
if(res.data.type === 'text/xml') {
let fileName = window.decodeURI(res.headers['content-disposition'].split('=')[1]);
let contentType = res.headers['content-type'];
let blob = new Blob([res.data], {
type: contentType + ';charset=utf-8'
});
let downloadElement = document.createElement('a');
let href = window.URL.createObjectURL(blob); //创建下载的链接
downloadElement.href = href;
downloadElement.download = fileName; //下载后文件名
document.body.appendChild(downloadElement);
downloadElement.click(); //点击下载
document.body.removeChild(downloadElement); //下载完成移除元素
window.URL.revokeObjectURL(href); //释放掉blob对象
this.$refs.upload.clearFiles();
if (res.status == 200) {
this.$message.warning("执行成功");
} else {
this.$message.warning("执行失败");
}
} else {
this.$message.warning("请求过于频繁,请稍后再试");
}
loading.close();
})
},
submitUpload() {
this.$refs.upload.submit();
},
}
}
</script>
<style>
</style>
后端实现
1、添加maven依赖
<dependency>
<groupId>org.icepdf.os</groupId>
<artifactId>icepdf-core</artifactId>
<version>6.1.2</version>
<exclusions>
<exclusion>
<groupId>javax.media</groupId>
<artifactId>jai-core</artifactId>
</exclusion>
</exclusions>
</dependency>
2、java pdf转img实现
/**
* 将pdf文件转换为图片
*
* @param pdfPath pdf文件路径
* @param imagePath 文件存储路径
* @param imageNamePrefix 保存图片名称前缀
* @param imageType 保存图片类型
* @param scale 图片缩放
* @param rotation 图片旋转
* @throws IOException
* @throws PDFException
* @throws PDFSecurityException
*/
public static List<String> pdf2img(String pdfPath, String imagePath, String imageNamePrefix, String imageType, float scale, float rotation) throws IOException, PDFException, PDFSecurityException {
List<String> imageList = new ArrayList<>();
Document document = new Document();
document.setFile(pdfPath);
for (int i = 0; i < document.getNumberOfPages(); i++) {
BufferedImage image = (BufferedImage)document.getPageImage(i, GraphicsRenderingHints.SCREEN, Page.BOUNDARY_CROPBOX, rotation, scale);
RenderedImage rendImage = image;
try {
if("".equals(imageNamePrefix) || null == imageNamePrefix) {
imageNamePrefix = new File(pdfPath).getName();
}
String imgName = imageNamePrefix + "_" + new DecimalFormat("000").format(i) + "." + imageType;
String savePath = "";
if("/".equals(imagePath.substring(imagePath.length()-1))) {
savePath = imagePath + imgName;
} else {
savePath = imagePath + "/" + imgName;
}
File file = new File(savePath);
File fileParent = file.getParentFile();
if (!fileParent.exists()) {
fileParent.mkdirs();
}
if (!file.exists()) {
file.createNewFile();
}
ImageIO.write(rendImage, imageType, file);
// 保存文件路径
imageList.add(savePath);
} catch (IOException e) {
e.printStackTrace();
}
image.flush();
}
document.dispose();
System.out.println("转换完成");
return imageList;
}
3、controller层
@RequestMapping("/pdf2img")
@ResponseBody
public void pdf2img(@RequestParam("files") MultipartFile[] files,
@RequestParam("username") String username,
HttpServletResponse response) throws IOException, PDFException, PDFSecurityException {
List<String> result = new ArrayList<>();
// 注意:rootPath, pdfPath, imagePath 文件路径修改为自己需要的文件路径
String rootPath = getPath(FileType.TYPE.ROOT.getCode(), username);
String pdfPath = getPath(FileType.TYPE.PDF.getCode(), username);
String imagePath = getPath(FileType.TYPE.IMG.getCode(), username);
for (MultipartFile file : files) {
String filename = file.getOriginalFilename();
FileUtils.createFile(file, pdfPath, filename);
result = PDFUtils.pdf2img(pdfPath + filename, imagePath, "target", "jpg", 2.5f, 0f);
}
// 打包文件
String zipPath = imagePath + "target.zip";
FileOutputStream fos = new FileOutputStream(zipPath);
List<File> fileList = new ArrayList<>();
for (String path : result) {
fileList.add(new File(path));
}
ZipUtils.toZip(fileList, fos);
String fileName = zipPath.substring(zipPath.lastIndexOf("/") + 1);
response.reset();
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
//读取指定路径下面的文件
InputStream in = new FileInputStream(zipPath);
OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
response(in, outputStream);
}
4、压缩工具
/**
* 文件列表压缩成ZIP
*
* @param srcFiles 需要压缩的文件列表
* @param out 压缩文件输出流
* @throws RuntimeException 压缩失败会抛出运行时异常
*/
public static void toZip(List<File> srcFiles, OutputStream out) throws RuntimeException {
long start = System.currentTimeMillis();
ZipOutputStream zos = null;
try {
zos = new ZipOutputStream(out);
for (File srcFile : srcFiles) {
byte[] buf = new byte[1024];
zos.putNextEntry(new ZipEntry(srcFile.getName()));
int len;
FileInputStream in = new FileInputStream(srcFile);
while ((len = in.read(buf)) != -1) {
zos.write(buf, 0, len);
}
zos.closeEntry();
in.close();
}
long end = System.currentTimeMillis();
System.out.println("压缩完成,耗时:" + (end - start) + " ms");
} catch (Exception e) {
throw new RuntimeException("zip error from ZipUtils", e);
} finally {
if (zos != null) {
try {
zos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}