小程序开发实战: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 小程序部署上线

该步骤对于小程序开发的朋友来说,还是非常简单的,这里就不过多介绍了,大家有问题的话,欢迎沟通交流!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/883447.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Springboot无人驾驶车辆路径规划系统(源码+定制+开发)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

Hadoop:yarn的Rust API接口

今天头一次接触了yarn的Rust API接口&#xff0c;在本地搭建了集群&#xff0c;能够得到每个任务的详细信息。 (一)得到所有任务的所有信息命令&#xff1a; 默认是json格式&#xff0c;也可以指定xml的格式&#xff0c;如(curl --compressed -H "Accept: application/x…

【大模型理论篇】主流大模型的分词器选择及讨论(BPE/BBPE/WordPiece/Unigram)

1. 背景分析 分词是将输入和输出文本拆分成更小单位的过程&#xff0c;使得大模型能够处理。token可以是单词、字符、子词或符号&#xff0c;取决于模型的类型和大小。分词可以帮助模型处理不同的语言、词汇和格式&#xff0c;并降低计算和内存成本。分词还可以通过影响token的…

fmql之Linux RTC

模拟i2c&#xff0c;连接rtc芯片。 dts&#xff1a; /{ // 根节点i2c_gpio: i2c-gpio {#address-cells <1>;#size-cells <0>;compatible "i2c-gpio";// MIO56-SDA, MIO55-SCL // 引脚编号gpios <&portc 2 0&portc 1 0 >;i2c-gp…

Modbus TCP报错:Response length is only 0 bytes

问题描述&#xff1a; 使用modbus_tk库&#xff0c;通过Modbus tcp连接PLC时&#xff0c;python中的一个报错信息&#xff1a; Response length is only 0 bytes报错原因&#xff1a; 与Modbus TCP 服务端建立连接后没有断开&#xff0c;继续作为长连接使用&#xff0c;客户端…

随笔—git操作

1. 创建一个 GitHub 仓库 登录到 GitHub。点击右上角的 “” 按钮&#xff0c;然后选择 “New repository”。填写仓库名称和描述&#xff0c;选择是否公开&#xff0c;最后点击 “Create repository”。 2. 在本地初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; 在…

【Lammps】atomsk安装与环境变量设置(Linux环境)

【Lammps】atomsk安装与环境变量设置&#xff08;Linux环境&#xff09; 官网配置环境变量测试 官网 https://atomsk.univ-lille.fr/dl.php 下载的安装包如下&#xff1a; 使用Linux的解压命令进行解压&#xff1a; tar -xzvf file.tar.gz注意&#xff1a;file.tar.gz 替换…

【Vue 3】最全组件设计指南:从基础到进阶

&#x1f9d1;‍&#x1f4bc; 一名茫茫大海中沉浮的小小程序员&#x1f36c; &#x1f449; 你的一键四连 (关注 点赞收藏评论)是我更新的最大动力❤️&#xff01; &#x1f4d1; 目录 &#x1f53d; 前言1️⃣ 组件的基础概念与构建2️⃣ 组件通信的核心技术3️⃣ 组件的生命…

【文献及模型、制图分享】中国自然保护地典型治理模式成效比较——基于社区居民感知视角

采取何种治理模式能够更好地提升自然保护地治理的生态、社会和经济成效?基于制度分析与发展&#xff08;IAD&#xff09;框架&#xff0c;选择大熊猫国家公园内部及周边17个社区&#xff0c;通过问卷调查、半结构化访谈、单因素方差、逐步回归分析&#xff0c;比较统治、分治和…

CSP/信奥赛C++刷题训练:经典二分答案例题(3): 洛谷P2920:Time Management S

CSP/信奥赛C++刷题训练:经典二分答案例题(3) [USACO08NOV] Time Management S 题目描述 Ever the maturing businessman, Farmer John realizes that he must manage his time effectively. He has N jobs conveniently numbered 1…N (1 <= N <= 1,000) to accompl…

Spring Boot集成iText实现电子签章

文章目录 一 电子签章1.1 什么是电子签章1.2 签名流程1.3 技术选型 二 实战2.1 生成数字证书2.2 生成印章图片2.3 PDF 签名 一 电子签章 1.1 什么是电子签章 基于《中华人民共和国电子签名法》等相关法规和技术规范&#xff0c;具有法律效力的电子签章一定是需要使用 CA 数字…

Unbounded:一个无限生成式交互的角色生活模拟游戏

❤️ 如果你也关注大模型与 AI 的发展现状&#xff0c;且对大模型应用开发非常感兴趣&#xff0c;我会快速跟你分享最新的感兴趣的 AI 应用和热点信息&#xff0c;也会不定期分享自己的想法和开源实例&#xff0c;欢迎关注我哦&#xff01; &#x1f966; 微信公众号&#xff…

Vertx实现和spring的application.yml自动配置加载

前言 在用vertx写项目的时候&#xff0c;由于需要不同的环境加载不同的配置文件&#xff0c;这里就需要和spring架构的application.yml配置文件一样&#xff0c;可以根据环境变量加载不同的配置。 代码 引入vertx相关依赖 <dependency><groupId>io.vertx</gr…

ECharts饼图-饼图自定义样式,附视频讲解与代码下载

引言&#xff1a; 在数据可视化的世界里&#xff0c;ECharts凭借其丰富的图表类型和强大的配置能力&#xff0c;成为了众多开发者的首选。今天&#xff0c;我将带大家一起实现一个饼图图表&#xff0c;通过该图表我们可以直观地展示和分析数据。此外&#xff0c;我还将提供详…

猫头虎 分享:前端工具 NVM 的简介、安装、用法详解入门教程

&#x1f42f; 猫头虎 分享&#xff1a;前端工具 NVM 的简介、安装、用法详解入门教程 今天猫头虎带您深入了解 NVM&#xff01;最近&#xff0c;猫哥在项目中遇到一个前端小伙伴&#xff0c;询问如何在开发过程中高效地切换不同的 Node.js 版本。前端项目往往需要特定版本的 …

二分查找_在排序数组中查找元素的第一个和最后一个位置

1.朴素二分查找 .二分查找 二分查找思路&#xff1a; 1.left0,rightnums.size()-1&#xff08;最后一个元素下标&#xff09;&#xff0c;取中间元素下标 midleft(right-left)/2 &#xff08;防溢出&#xff09; 2.nums[mid]>target &#xff0c;说明mid右边的元素都大于ta…

Discuz 论坛开发一套传奇发布站与传奇开服表

Discuz 论坛开发一套传奇发布站与传奇开服表 随着互联网技术的飞速发展&#xff0c;网络游戏已成为人们休闲娱乐的重要方式之一。在众多网络游戏中&#xff0c;传奇系列以其独特的魅力吸引了大量忠实玩家。为了满足这些玩家的需求&#xff0c;并促进游戏信息的交流与分享&…

QtCreator通过CMake多文件编译.cpp、.qss、.h、.ui文件,达到MVC三层架构的效果

博主在构建C项目的时候&#xff0c;一般都喜欢将头文件和源文件分开为不同的文件夹&#xff0c;比如include目录下只存放.h文件和.ui文件&#xff0c;src目录下只存放.cpp和.qss文件&#xff0c;res目录下只存放图片、音频等文件&#xff0c;这时候使用CMake对项目进行分文件管…

qml圆形图片,qml圆形头像制作

代码比较简单&#xff0c;就不细讲了&#xff0c;大家直接看下面源码吧&#xff01;如果对你有所帮助&#xff0c;可以帮角角点个关注嘛&#xff1f; import QtQuick import QtQuick.Effects import Qt5Compat.GraphicalEffectsWindow {width: 640height: 480visible: truetit…

使用代理服务器后sse数据合并问题

如果是使用本地代理服务器devServer compress:false,如果是发布到生产环境下的代理服务器nginx 增加如下配置&#xff0c;该配置同时支持websocket和sse proxy_http_version 1.1; #设置代理请求使用 HTTP/1.1 版本。WebSocket 需要 HTTP/1.1&#xff0c;因为它支持持久连接和更…