小程序开发实战:PDF转换为图片工具开发
目录
一、开发思路
1.1 申请微信小程序
1.2 编写后端接口
1.3 后端接口部署
1.4 微信小程序前端页面开发
1.5 运行效果
1.6 小程序部署上线
今天给大家分享小程序开发系列,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、加载pdfPdfDocument 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、GIFString 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, .pdfsuccess: function (res) {const tempFilePath = res.tempFiles[0].path;if (res.tempFiles[0].size > 10 * 1024 * 1024) { // 限定文件大小为2MBwx.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,// 直接可以访问的urldata: 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 小程序部署上线
该步骤对于小程序开发的朋友来说,还是非常简单的,这里就不过多介绍了,大家有问题的话,欢迎沟通交流!
相关文章:
小程序开发实战:PDF转换为图片工具开发
目录 一、开发思路 1.1 申请微信小程序 1.2 编写后端接口 1.3 后端接口部署 1.4 微信小程序前端页面开发 1.5 运行效果 1.6 小程序部署上线 今天给大家分享小程序开发系列,PDF转换为图片工具的开发实战,感兴趣的朋友可以一起来学习一下!…...
我有两台120kw充电桩一天能赚多少钱
(当前是理想状态下,当然还要看场地费用,还有物业,变压器,等等) ———————————————————— ———————————————————— 要计算两台120kW充电桩能赚多少钱,我们…...
深入了解 Android 中的命名空间:`xmlns:tools` 和其他常见命名空间
在 Android 开发中,xmlns (.xml的namespace)命名空间是一个非常重要的概念。通过引入不同的命名空间,可以使用不同的属性来设计布局、设置工具属性或者支持自定义视图等。除了 xmlns:tools 以外,还有很多常见的命名空间…...
stable-zero123模型构建指南
一、介绍 stabilityai出品,能够对有简单背景的物体进行三维视角图片的生成,简单来说也就是通过调整变换观察的视角生成对应视角的图片。 本项目通过comfyui实现。 二、容器构建说明 1. 部署ComfyUI (1)使用命令克隆ComfyUI g…...
算法题解记录32+++最长连续序列(百题筑基)
你们好,我是蚊子码农,好久不见。由于秋招求职的繁琐事情,我有很长一段时间没更新博客,希望我的粉丝们能够谅解。 秋招我拿到了一些offer,最终决定去一个主要做“网络安全”业务的公司工作,也许明天会更好&a…...
全球知名度最高的华人起名大师颜廷利:世界顶级思想哲学教育家
全国给孩子起名最好的大师颜廷利教授在其最新的哲学探索中,提出了《升命学说》这一前沿理论观点,该理论不仅深刻地回应了古今中外众多哲学流派和思想体系的精髓,还巧妙地融合了实用主义、理想主义以及经验主义的核心理念。通过这一独特的视角…...
Flink Rest API
REST API | Apache Flink Flink官网API 通过curl 或者Rest API工具测试web UI对应的接口返回信息 Flink 提交yarn任务 ./bin/flink run -t yarn-per-job historyServer ../bin/historyserver.sh start...
Zig 语言通用代码生成器:逻辑,冒烟测试版发布二
Zig 语言通用代码生成器:逻辑,冒烟测试版发布二 Zig 语言是一种新的系统编程语言,其生态位类同与 C,是前一段时间大热的 rust 语言的竞品。它某种意义上的确非常像 rust,尤其是在开发过程中无穷无尽抛错的过程&#x…...
mysql 通过GROUP BY 聚合并且拼接去重另个字段
我的需求: 我想知道同一个手机号出现几次,并且手机号出现在哪些地方。下面是要的效果。 源数据: CREATE TABLE bank (id bigint(20) unsigned NOT NULL AUTO_INCREMENT,user_id int(11) NOT NULL DEFAULT 0,tel varchar(255) COLLATE utf8mb4_unicode_…...
Java应用程序的测试覆盖率之设计与实现(一)-- 总体设计
一、背景 作为测试,如何保证开发人员提交上来的代码都被测试覆盖到,是衡量测试质量的一个重要指标。 本系列文章将要说一说,如何搭建一套测试覆盖率的系统。 包括以下内容: jacoco agent采集执行覆盖率数据jacoco climaven集成jacoco:jacoco-maven-pluginant集成jacoco:…...
Unity C#脚本的热更新
以下内容是根据Unity 2020.1.0f1版本进行编写的 目前游戏开发厂商主流还是使用lua框架来进行热更,如xlua,tolua等,也有的小游戏是直接整包更新,这种小游戏的包体很小,代码是用C#写的;还有的游戏就是通过…...
监督学习之逻辑回归
逻辑回归(Logistic Regression) 逻辑回归是一种用于二分类(binary classification)问题的统计模型。尽管其名称中有“回归”二字,但逻辑回归实际上用于分类任务。它的核心思想是通过将线性回归的输出映射到一个概率值…...
深度优先算法(DFS)洛谷P1683-入门
虽然洛谷是有题解的,但是你如果直接看得懂题解,你也不会来看这篇文章.. 这些代码均是我记录自身成长的记录,有写的不好的地方请谅解! 先上代码: #include <iostream> #include <vector> #include<iomanip> #include<cstdio&…...
Python数据分析基础
本文介绍了Python在数据分析中的应用,包括数据读取、清洗、处理和分析的基本操作。通过使用Pandas和Numpy库,我们可以高效地处理大量数据,并利用Matplotlib和Seaborn库进行数据可视化。 1. 引言 Python因其简洁的语法和强大的库支持&#x…...
《企业自设2-软件测试》线下课day3: 006扩展虚拟机
1.win11 修改hosts无权限 分别再cmd终端输入以下两行代码: C:\Windows\System32\drivers\etcnotepad hosts 2.先保存快照!!! 3.关闭虚拟机,将内存,CPU进行修改 就是再这个位置修改: 4.运…...
配置和排查 Lombok 在 IDEA 中使用的详细步骤
在日常开发中,Java 代码常常需要大量的样板代码,比如 getter、setter、toString 等方法。Lombok 是一个 Java 库,可以通过注解的方式,自动生成这些常见的代码,从而让代码更加简洁、清晰。比如,我们可以通过…...
JavaWeb合集18-接口管理Swager
十八、接口管理 1、Swager 使用Swagger你只需要按照它的规范去定义接口及接口相关的信息,就可以做到生成接口文档,以及在线接口调试页面。 官网: https://swagger.io/ Knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案。 <dependency&g…...
背包九讲——二维费用背包问题
目录 二维费用背包问题 问题描述: 解决方法: 方法一: 代码实现: 方法二: 代码实现: 背包问题第五讲——二维费用背包问题 背包问题是一类经典的组合优化问题,通常涉及在限定容量的背包中…...
【mysql进阶】4-7. 通用表空间
通⽤表空间 - General Tablespace 1 通⽤表空间的作⽤和特性? ✅ 解答问题 通⽤表空间是使⽤ CREATE tablespace 语法创建的共享InnoDB表空间 通⽤表空间能够存储多个表的数据,与系统表空间类似也是共享表空间; 服务器运⾏时会把表空间元数…...
2024 年互联网大厂 1300 多道 JAVA 面试题汇总,包含了程序员的所有技术点
作为一个 Java 程序员,你平时总是陷在业务开发里,每天噼里啪啦忙敲着代码,上到系统开发,下到 Bug 修改,你感觉自己无所不能。然而偶尔的一次聚会,你听说和自己一起出道的同学早已经年薪 50 万,而…...
【开源免费】基于SpringBoot+Vue.JS在线文档管理系统(JAVA毕业设计)
本文项目编号 T 038 ,文末自助获取源码 \color{red}{T038,文末自助获取源码} T038,文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…...
Linux资源与网络请求
参数说明: d : 改变显示的更新速度,或是在交谈式指令列( interactive command)按 sq : 没有任何延迟的显示速度,如果使用者是有 superuser 的权限,则 top 将会以最高的优先序执行c : 切换显示模式,共有两种模式&#…...
RPA技术重塑企业自动化的未来
1. RPA定义与原理 1.1 机器人流程自动化(RPA)概念 机器人流程自动化(Robotic Process Automation,简称RPA)是一种软件技术,通过模拟人类用户在计算机界面上的操作来执行重复性的业务流程任务。RPA软件机器人能够自动执行基于规则…...
使用RabbitMQ实现延迟消息的完整指南
在分布式系统中,消息队列通常用于解耦服务,RabbitMQ是一个广泛使用的消息队列服务。延迟消息(也称为延时队列或TTL消息)是一种常见的场景应用,特别适合处理某些任务在一段时间后执行的需求,如订单超时处理、…...
阿里员工:阿里工作7年至少得P7吧,快的都P8了,年薪100W是正常的,80才算及格...
上一篇:一线体面男的收入 年薪64W的阿里蚂蚁员工爆料:在阿里,工作7年至少得P7,快的都P8了,年薪100W才正常,80分才算及格。 其实,在大厂工作,听起来风光无限,但个中滋味&a…...
Django进一步掌握(10月22日)
一、请求响应对象 请求对象request 响应对象HttpResponse 二、HttpResponse常用属性 status设置HTTP响应状态码 status_code查询HTTP响应状态码 content_type设置响应的类型 write()写入响应内容 三、重定向 1、实现URl访问的重定向 (1)使用Ht…...
C++从入门到起飞之——红黑树封装map和set 全方位剖析!
目录 1、map和set的整体框架 2、map和set迭代器的实现 3、map支持[] 4、完整源码 set.h map.h RBTree.h 1、map和set的整体框架 因为map和set的底层都是红黑树,所以我们考虑用一个红黑树的类模版去实例化map和set对象!不过,map节点中存…...
【javax maven项目缺少_Maven的依赖管理 引入依赖】
javax maven项目缺少_Maven的依赖管理 引入依赖 Maven的依赖管理 - 引入依赖依赖管理(引入依赖)导入依赖 https://blog.csdn.net/weixin_28932089/article/details/112381468 Maven的依赖管理 - 引入依赖 依赖管理(引入依赖) 能够掌握依赖引入的配置方式 导入依赖 导入依赖练…...
手搓一个定时器
目录 1.什么是定时器 2.计时器的使用 3.手搓定时器 3.1定义一个TimerTask类 3.2定义一个Timer类 3.3实现schedule方法 3.4实现Timer的构造方法 3.4.1随时随地查看优先级队列中是否有任务要执行 3.4.2获取队首任务,并判断是否到执行时间 3.4.3到达执行时间…...
AI提示词工程优化Prompt-GPT使用手册(科普一键收藏史上最强攻略)
Prompt(提示),最初是 NLP 研究者为下游任务设计出来的一种任务专属的输入形式或模板。在 ChatGPT 引发大语言模型新时代之后,Prompt 指与大模型交互输入的代称。 随着大模型的进展,Prompt Engineering是一个持久的探索过程。 目录 什么是提示…...
企业网站免费模板/网站开发北京公司
2019独角兽企业重金招聘Python工程师标准>>> JavaScript的self和this使用小结 var self this? Getting Out of Binding Situations in JavaScript Window 对象 js对象中使用_selfthis的原因? 转载于:https://my.oschina.net/letiantian/blog/282715...
做网站的诈骗8000块钱犯法吗/合肥网站优化方案
在一个目录下的搜索,即FindElem()不分先后出现顺序。 (一) 先讲一下XML中的物殊字符,手动填写时注意一下。 字符 字符实体& &或#38; &apos…...
dw做网站 后台用什么后台/列表网推广效果怎么样
2019独角兽企业重金招聘Python工程师标准>>> 在Linux shell 中启动图形界面的应用(如eclipse),会遇到一个麻烦:即当不小心关闭或退出shell时,在该shell中启动的程序也会被结束。这在有些情况下是我们不想看…...
网站无域名注册人id/加盟培训机构
1、次数分配数列是()。(2 分) A.按数量标志分组形成的数列 B.按品质标志分组形成的数列 C.按统计指标分组所形成的数列 D.按数量标志和品质标志分组所形成的数列 2、下列指标中属于时…...
网站建设优势/腾讯朋友圈广告怎么投放
docker run --namemydemo -p -d 2222:80 imagename --name: 指定容器名称 -p:指定容器端口号 -d:指定容器后台运行转载于:https://www.cnblogs.com/lishidefengchen/p/10709828.html...
wordpress新闻视频站/站长工具中文
原标题:MYSQL数据损坏修复方法1、myisamchk使用 myisamchk 必须暂时停止 MySQL 服务器。例如,我们要检修 discuz 数据库。执行以下操作:# service mysql stop (停止 MySQL );# myisamchk -r /数据库文件的绝对路径/*MYI# service …...