今天给大家分享小程序开发系列,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>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 小程序部署上线该步骤对于小程序开发的朋友来说,还是非常简单的,这里就不过多介绍了,大家有问题的话,欢迎沟通交流!