小程序实战:PDF转换为图片工具开发
wptr33 2024-11-14 19:22 20 浏览
今天给大家分享小程序开发系列,PDF转换为图片工具的开发实战,感兴趣的朋友可以一起来学习一下!
一、开发思路
- 申请微信小程序
- 编写后端接口
- 后端接口部署
- 微信小程序前端页面开发
- 微信小程序部署上线
1.1 申请微信小程序
关于如何申请微信小程序这里就不过多介绍了,大家可以参考腾讯官方的文档,里面介绍的非常详细。
1.2 编写后端接口
这里使用Java编程语言的SpringBoot框架来快速搭建WebAPI服务。因为涉及到PDF转换为图片,这里使用spire.pdf来实现。首先引入依赖项
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.pdf.free</artifactId>
<version>2.6.3</version>
<scope>provided</scope>
</dependency>
新建PdfUtils.java工具类库用来实现PDF转换为图片的功能
思路:通过微信小程序传递过来的文件转换为InputStream输出流,然后保存到服务器端,因为PDF可能涉及有多页,每一页单独为一个图片文件,然后调用图片拼接的方法实现所有页面图片合并为一张长图。注意:免费的spire.pdf支持10页之内的pdf转换,大家如果更高需求,可以考虑购买收费版。
主要代码如下:转换方法主函数
/**
* 根据文件流转换为图片
*
* @param stream
* @return
*/
public String pdftoimage(InputStream stream, String fileNameOld) {
Date currentDate = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss_SSS"); // 指定日期格式,包含毫秒
String formattedDate = sdf.format(currentDate);
String pathPath = "/mnt/files/" + formattedDate + "_" + fileNameOld;
// 4、最终生成的doc所在的目录,默认是和引入的一个地方,开源时对外提供下载的接口。
saveInputStreamToFile(stream, pathPath);
String fileName = "result" + formattedDate + ".png";
String desPath = "/mnt/files/" + fileName; // 构造文件名
String sux = fileNameOld + "_" + formattedDate;// 临时文件前缀
boolean result = false;
try {
// 0、判断输入的是否是pdf文件
//第一步:判断输入的是否合法
//boolean flag = isPDFFile(srcPath);
//第二步:在输入的路径下新建文件夹
boolean flag1 = create();
if (flag1) {
// 1、加载pdf
PdfDocument pdf = new PdfDocument();
//pdf.loadFromStream(stream);
pdf.loadFromFile(pathPath);
PdfPageCollection num = pdf.getPages();
// 2、如果pdf的页数小于11,那么直接进行转化
if (num.getCount() <= 10) {
try {
for (int i = 0; i < pdf.getPages().getCount(); i++) {
BufferedImage image = pdf.saveAsImage(i, PdfImageType.Bitmap, 300, 300);
String imgTemp = imgPath + sux + (i + 1) + ".png"; // 构造输出文件路径
ImageIO.write(image, "PNG", new File(imgTemp));
}
pdf.close();
System.out.println("PDF转图片完成!");
MergeWordDocument.mergeImage(imgPath, desPath, sux);
clearFiles(imgPath, formattedDate);
clearFiles(pathPath, formattedDate);
} catch (IOException e) {
e.printStackTrace();
System.out.println("PDF转图片失败: " + e.getMessage());
}
}
// 3、否则输入的页数比较多,就开始进行切分再转化
else {
try {
for (int i = 0; i < 10; i++) {
BufferedImage image = pdf.saveAsImage(i, PdfImageType.Bitmap, 300, 300);
String imgTemp = imgPath + sux + (i + 1) + ".png"; // 构造输出文件路径
ImageIO.write(image, "PNG", new File(imgTemp));
}
pdf.close();
System.out.println("PDF转图片完成!");
MergeWordDocument.mergeImage(imgPath, desPath, sux);
} catch (IOException e) {
e.printStackTrace();
System.out.println("PDF转图片失败: " + e.getMessage());
} finally {
//clearFiles(imgPath);
clearFiles(pathPath, formattedDate);
}
}
} else {
System.out.println("输入的不是pdf文件");
fileName = "";
return fileName;
}
} catch (Exception e) {
fileName = "";
e.printStackTrace();
} finally {
//4、把刚刚缓存的split和doc删除
if (result == true) {
clearFiles(pathPath, formattedDate);
clearFiles(splitPath, formattedDate);
clearFiles(docPath, formattedDate);
}
}
return fileName;
}
保存PDF文件到本地,然后使用后删除
/**
* 保存原始的pdf文件为了方便拆分
*
* @param inputStream
* @param filePath
*/
public static void saveInputStreamToFile(InputStream inputStream, String filePath) {
// 使用try-with-resources自动关闭流
try (FileOutputStream outputStream = new FileOutputStream(new File(filePath))) {
byte[] buffer = new byte[1024];
int length;
// 读取输入流并写入到输出流
while ((length = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
System.out.println("文件保存成功!");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
多张图片合并逻辑
/**
* 多张图片合并之后的逻辑
* @param imagePath
* @param desPath
* @return
*/
public static boolean mergeImage(String imagePath, String desPath,String sux) {
try {
File folder = new File(imagePath);
// 包含文件前缀的文件 简单解决并发的问题
File[] imageFiles = folder.listFiles((dir, name) ->
(name.toLowerCase().endsWith(".png") || name.toLowerCase().endsWith(".jpg") && name.contains(sux)));
if (imageFiles != null && imageFiles.length > 0) {
int maxWidth = 0;
int totalHeight = 0;
// 预先计算最大宽度和总高度
for (File imageFile : imageFiles) {
BufferedImage image = ImageIO.read(imageFile);
maxWidth = Math.max(maxWidth, image.getWidth());
totalHeight += image.getHeight();
image.flush(); // 尝试释放资源
}
// 创建合并后的图片,仅初始化一次
BufferedImage mergedImage = new BufferedImage(maxWidth, totalHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = mergedImage.createGraphics();
int currentY = 0;
for (File imageFile : imageFiles) {
BufferedImage image = ImageIO.read(imageFile);
g2d.drawImage(image, 0, currentY, null);
currentY += image.getHeight();
image.flush(); // 处理完后释放当前图片资源
}
g2d.dispose();
// 保存合并后的图片
ImageIO.write(mergedImage, "PNG", new File(desPath));
System.out.println("图片合并完成!");
for (File file : imageFiles){
if (file.exists()) {
if (file.delete()) {
System.out.println("文件 " + file.getName() + " 已被删除");
} else {
System.out.println("无法删除文件 " + file.getName());
}
} else {
System.out.println("文件 " + file.getName() + " 不存在");
}
}
} else {
System.out.println("输入文件夹中没有图片文件!");
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("图片合并失败: " + e.getMessage());
}
return true;
}
新建控制器PdfApi.java
用来接收小程序调用传递过来的参数,需要判断传递过来的文件是否为图片格式,然后调用转换方法即可。
/**
* pdf转图片 多页转一张图
* @param uploadFile
* @return
* @throws IOException
*/
@PostMapping("pdfconvertimage")
public String upload(@RequestPart("file") MultipartFile uploadFile) throws IOException {
if (null == uploadFile) {
return null;
}
// BMP、JPG、JPEG、PNG、GIF
String fileName = uploadFile.getOriginalFilename().toLowerCase();
if (!fileName.endsWith(".pdf")) {
return null;
}
//String image= PdfUtils.pdf(uploadFile.getInputStream(),Integer.valueOf(type));
String image= PdfUtils.pdfToPng(uploadFile.getInputStream(),fileName);
// 返回响应实体
return image;
}
1.3 后端接口部署
因为微信小程序调用第三方接口需要https域名形式,所以接口开发完成后,需要部署到云服务器,然后申请域名、申请SSL证书,确保接口可以通过https域名正常访问。并且在微信小程序开发设置配置request合法域名白名单,保证接口可以调通。
1.4 微信小程序前端页面开发
打开微信开发者工具,然后微信小程序管理员扫码登录自己的微信小程序。这里主要给大家贴出主要的代码以及实现思路。具体界面如下:
上传方式:支持微信会话文件上传、直接输入PDF文件的URL,转换成功后可以点击下载按钮进行下载图片。
wxml文件代码如下:
<view style="text-align: center;">
<image style="width: 98%;" src="推广图片"></image>
</view>
<view class="selectSection">
<text class="textmag">上传方式:</text>
<radio-group bindchange="radioChange" class="radio-group">
<label class="radio" wx:for="{{direction}}" wx:key="i">
<icon class="radioIcon {{item.checked?'actIcon':''}}"></icon>
<radio checked="{{item.checked}}" value="{{item.name}}"></radio>{{item.value}}
</label>
</radio-group>
</view>
<view class="container">
<view wx:if="{{directionType==1}}" class="item"> <button style="width: 120px;" class="butss" bindtap="chooseFile">上传pdf文件</button></view>
<view wx:if="{{directionType==2}}" class="item"> <button style="width: 120px;" class="butss" bindtap="chooseFileNew">生成图片</button></view>
<view class="item"> <button style="width: 90px;" class="butss" bindtap="saveTap">下载</button></view>
<view class="item"> <button style="width: 90px;" class="butss" bindtap="clearTap">清空</button></view>
</view>
<view style="padding: 20px;">
<span style="color: red;font-size: 12px;">温馨提示:目前支持10页以内的pdf文件转换</span>
</view>
<view>
<textarea auto-height bindinput="handleInput" class="input-content" value="{{uploadUrl}}" placeholder="请输入pdf文件url" wx:if="{{directionType==2}}"></textarea>
</view><view class="instruction">
<span style="color: black;padding-left: 10px;">结果文件:{{data}}</span>
</view>
js主要代码:
// 选择微信会话文件 然后直接调用上传接口
chooseFile: function () {
var that = this;
wx.showLoading({
title: '图片上传处理中,请稍后...',
});
wx.chooseMessageFile({
count: 1,
type: 'file',
extension: ['pdf'], // 限定选择的文件格式为.doc, .docx, .pdf
success: function (res) {
const tempFilePath = res.tempFiles[0].path;
if (res.tempFiles[0].size > 10 * 1024 * 1024) { // 限定文件大小为2MB
wx.showToast({
title: '文件大小超过限制,请选择小于10MB的文件',
icon: 'none'
});
return;
}
that.setData({
pdfPath: tempFilePath
})
wx.uploadFile({
url: '后端接口API',
filePath: tempFilePath,
formData: {
},
name: 'file',
success: function (res) {
if (res.statusCode == "200") {
that.setData({
imageUrl: res.data,// 直接可以访问的url
data: res.data
});
wx.showToast({
title: '转换成功',
icon: 'success',
duration: 2000
});
} else {
wx.showToast({
title: '转换失败,请联系管理员',
icon: 'none',
duration: 2000
});
}
},
fail: function (res) {
wx.showToast({
title: '上传失败',
icon: 'none',
duration: 2000
});
}
});
},
fail: function (res) {
console.error('选择文件失败', res);
wx.showToast({
title: '选择文件失败',
icon: 'none',
duration: 2000
});
}
});
},
// 下载按钮事件
saveTap: function () {
if (this.data.imageUrl) {
wx.downloadFile({
url: this.data.imageUrl,
success: function (res) {
if (res.statusCode === 200) {
var filePath = res.tempFilePath;
// 调用保存图片方法
wx.saveImageToPhotosAlbum({
filePath: filePath,
success: function (res) {
wx.showToast({
title: '保存成功',
icon: 'success',
duration: 2000
});
},
fail: function (err) {
console.error(err);
wx.showToast({
title: '保存失败',
icon: 'none',
duration: 2000
});
}
});
}
},
fail: function (err) {
console.error(err);
wx.showToast({
title: '下载失败',
icon: 'none',
duration: 2000
});
}
});
} else {
wx.showToast({
title: '请先上传pdf文件,转换成功后再保存',
icon: 'none',
duration: 2000
});
}
},
1.5 运行效果
选择pdf文件上传
转换成功之后的结果文件如下:
然后可以点击下载按钮下载图片文件。整体转还原度还是很高的。大家可以微信搜一搜“小明工作助手”小程序直接体验一下。
1.6 小程序部署上线
该步骤对于小程序开发的朋友来说,还是非常简单的,这里就不过多介绍了,大家有问题的话,欢迎沟通交流!
相关推荐
- VPS主机搭建Ghost环境:Nginx Node.js MariaDB
-
Ghost是一款个人博客系统,它是使用Node.js语言和MySQL数据库开发的,同时支持MySQL、MariaDB、SQLite和PostgreSQL。用户可以在支持Node.js的服务器上使用自己...
- centos7飞速搭建zabbix5.0并添加windows、linux监控
-
一、环境zabbix所在服务器系统为centos7,监控的服务器为windows2016和centos7。二、安装zabbix官方安装帮助页面...
- Zabbix5.0安装部署
-
全盘展示运行状态,减轻运维人员的重复性工作量,提高系统排错速度,加速运维知识学习积累。1.png...
- MariaDB10在CentOS7系统下,迁移数据存储位置
-
背景在CentOS7下如果没有默认安装MySQL数据库,可以选择安装MariaDB,最新的版本现在是10可以选择直接yum默认安装的方式yum-yinstallmariadbyum-yi...
- frappe项目安装过程
-
1,准备一台虚拟机,debian12或者ubuntusever22.04.3可以用virtualbox/qemu,或者你的超融合服务器安装一些常用工具和依赖库我这里选择server模式安装,用tab...
- 最新zabbix一键安装脚本(基于centos8)
-
一、环境准备注意:操作系统必须是centos8及以上的,因为我配的安装源是centos8的。并且必须连接互联网,脚本是基于yum安装的!!!...
- ip地址管理之phpIPAM保姆级安装教程 (原创)
-
本教程基于Ubuntu24.04LTS,安装phpIPAM(最新稳定版1.7),使用Apache、PHP8.3和MariaDB,遵循最佳实践,确保安全性和稳定性。一、环境准备1....
- centos7傻瓜式安装搭建zabbix5.0监控服务器教程
-
zabbix([`zaebiks])是一个基于WEB界面的提供分布式系统监视...
- zabbix7.0LTS 保姆级安装教程 小白也能轻松上手安装
-
系统环境:rockylinux9.4(yumupdate升级到最新版本)数据库:mariadb10.5.22第一步:关闭防火墙和selinux使用脚本关闭...
- ubuntu通过下载安装包安装mariadb10.4
-
要在Ubuntu18.04上安装MariaDB10.4.34,用的是那个tar.gz的安装包。步骤大概是:...
- 从0到1:基于 Linux 快速搭建高可用 MariaDB Galera 集群(实战指南)
-
在企业生产环境中,数据库的高可用性至关重要。今天带你从0到1,手把手在Linux系统上快速搭建一个高可用MariaDBGaleraCluster,实现数据库同步复制、故障自动恢复,保障业务...
- Windows 中安装 MariaDB 数据库
-
mariadb在Windows下的安装非常简单,下载程序双击运行就可以了。需要注意:mariadb和MySQL数据库在Windows下默认是不区分大小写的,但是在Linux下是区分...
- SQL执行顺序(SqlServer)
-
学习SQL这么久,如果突然有人问你SQL的执行顺是怎么样的?是不是很多人会觉得C#、JavaScript都是根据编程顺序来处理的,那么SQL也是根据编程顺序来执行的吗?...
- C# - StreamWriter与StreamReader 读写文件 101
-
读写文本文件的方式:1)File静态类的File.ReadAllLines();与File.WriteAllLines();方法进行读写...
- C#中的数组探究与学习
-
C#中的数组一般分为:...
- 一周热门
-
-
C# 13 和 .NET 9 全知道 :13 使用 ASP.NET Core 构建网站 (1)
-
因果推断Matching方式实现代码 因果推断模型
-
git pull命令使用实例 git pull--rebase
-
git pull 和git fetch 命令分别有什么作用?二者有什么区别?
-
面试官:git pull是哪两个指令的组合?
-
git 执行pull错误如何撤销 git pull fail
-
git fetch 和git pull 的异同 git中fetch和pull的区别
-
git pull 之后本地代码被覆盖 解决方案
-
还可以这样玩?Git基本原理及各种骚操作,涨知识了
-
git命令之pull git.pull
-
- 最近发表
- 标签列表
-
- git pull (33)
- git fetch (35)
- mysql insert (35)
- mysql distinct (37)
- concat_ws (36)
- java continue (36)
- jenkins官网 (37)
- mysql 子查询 (37)
- python元组 (33)
- mysql max (33)
- vba instr (33)
- mybatis 分页 (35)
- vba split (37)
- redis watch (34)
- python list sort (37)
- nvarchar2 (34)
- mysql not null (36)
- hmset (35)
- python telnet (35)
- python readlines() 方法 (36)
- munmap (35)
- docker network create (35)
- redis 集合 (37)
- python sftp (37)
- setpriority (34)