ToB企服应用市场:ToB评测及商务社交产业平台

标题: 小步伐开发实战:PDF转换为图片工具开发 [打印本页]

作者: 石小疯    时间: 2024-10-24 05:29
标题: 小步伐开发实战:PDF转换为图片工具开发
目录

一、开发思绪
1.1 申请微信小步伐
1.2 编写后端接口
1.3 后端接口摆设
1.4 微信小步伐前端页面开发
1.5 运行效果
1.6 小步伐摆设上线







本日给大家分享小步伐开发系列,PDF转换为图片工具的开发实战,感爱好的朋友可以一起来学习一下!
一、开发思绪


1.1 申请微信小步伐

关于怎样申请微信小步伐这里就不外多先容了,大家可以参考腾讯官方的文档,内里先容的非常详细。


1.2 编写后端接口

这里使用Java编程语言的SpringBoot框架来快速搭建WebAPI服务。由于涉及到PDF转换为图片,这里使用spire.pdf来实现。首先引入依靠项
  1.       <dependency>
  2.           <groupId>e-iceblue</groupId>
  3.            <artifactId>spire.pdf.free</artifactId>
  4.            <version>2.6.3</version>
  5.            <scope>provided</scope>
  6.        </dependency>
复制代码

新建PdfUtils.java工具类库用来实现PDF转换为图片的功能
思绪:通过微信小步伐传递过来的文件转换为InputStream输出流,然后保存到服务器端,由于PDF可能涉及有多页,每一页单独为一个图片文件,然后调用图片拼接的方法实现全部页面图片归并为一张长图。注意:免费的spire.pdf支持10页之内的pdf转换,大家如果更高需求,可以考虑购买收费版。
主要代码如下:转换方法主函数
  1. [/code] [code]   /**
  2.     * 根据文件流转换为图片
  3.     *
  4.     * @param stream
  5.     * @return
  6.     */
  7.    public String pdftoimage(InputStream stream, String fileNameOld) {
  8.    Date currentDate = new Date();
  9.    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss_SSS"); // 指定日期格式,包含毫秒
  10.    String formattedDate = sdf.format(currentDate);
  11.    String pathPath = "/mnt/files/" + formattedDate + "_" + fileNameOld;
  12.    // 4、最终生成的doc所在的目录,默认是和引入的一个地方,开源时对外提供下载的接口。
  13.    saveInputStreamToFile(stream, pathPath);
  14.    String fileName = "result" + formattedDate + ".png";
  15.    String desPath = "/mnt/files/" + fileName; // 构造文件名
  16.    String sux = fileNameOld + "_" + formattedDate;// 临时文件前缀
  17.    boolean result = false;
  18.    try {
  19.        // 0、判断输入的是否是pdf文件
  20.        //第一步:判断输入的是否合法
  21.        //boolean flag = isPDFFile(srcPath);
  22.        //第二步:在输入的路径下新建文件夹
  23.        boolean flag1 = create();
  24.        if (flag1) {
  25.            // 1、加载pdf
  26.            PdfDocument pdf = new PdfDocument();
  27.            //pdf.loadFromStream(stream);
  28.            pdf.loadFromFile(pathPath);
  29.            PdfPageCollection num = pdf.getPages();
  30.            // 2、如果pdf的页数小于11,那么直接进行转化
  31.            if (num.getCount() <= 10) {
  32.                try {
  33.                    for (int i = 0; i < pdf.getPages().getCount(); i++) {
  34.                        BufferedImage image = pdf.saveAsImage(i, PdfImageType.Bitmap, 300, 300);
  35.                        String imgTemp = imgPath + sux + (i + 1) + ".png"; // 构造输出文件路径
  36.                        ImageIO.write(image, "PNG", new File(imgTemp));
  37.                   }
  38.                    pdf.close();
  39.                    System.out.println("PDF转图片完成!");
  40.                    MergeWordDocument.mergeImage(imgPath, desPath, sux);
  41.                    clearFiles(imgPath, formattedDate);
  42.                    clearFiles(pathPath, formattedDate);
  43.               } catch (IOException e) {
  44.                    e.printStackTrace();
  45.                    System.out.println("PDF转图片失败: " + e.getMessage());
  46.               }
  47.           }
  48.            // 3、否则输入的页数比较多,就开始进行切分再转化
  49.            else {
  50.                try {
  51.                    for (int i = 0; i < 10; i++) {
  52.                        BufferedImage image = pdf.saveAsImage(i, PdfImageType.Bitmap, 300, 300);
  53.                        String imgTemp = imgPath + sux + (i + 1) + ".png"; // 构造输出文件路径
  54.                        ImageIO.write(image, "PNG", new File(imgTemp));
  55.                   }
  56.                    pdf.close();
  57.                    System.out.println("PDF转图片完成!");
  58.                    MergeWordDocument.mergeImage(imgPath, desPath, sux);
  59.               } catch (IOException e) {
  60.                    e.printStackTrace();
  61.                    System.out.println("PDF转图片失败: " + e.getMessage());
  62.               } finally {
  63.                    //clearFiles(imgPath);
  64.                    clearFiles(pathPath, formattedDate);
  65.               }
  66.           }
  67.       } else {
  68.            System.out.println("输入的不是pdf文件");
  69.            fileName = "";
  70.            return fileName;
  71.       }
  72.   } catch (Exception e) {
  73.        fileName = "";
  74.        e.printStackTrace();
  75.   } finally {
  76.        //4、把刚刚缓存的split和doc删除
  77.        if (result == true) {
  78.            clearFiles(pathPath, formattedDate);
  79.            clearFiles(splitPath, formattedDate);
  80.            clearFiles(docPath, formattedDate);
  81.       }
  82.   }
  83.    return fileName;
  84. }
复制代码
保存PDF文件到当地,然后使用后删除
  1. /**
  2. * 保存原始的pdf文件为了方便拆分
  3. *
  4. * @param inputStream
  5. * @param filePath
  6. */
  7. public static void saveInputStreamToFile(InputStream inputStream, String filePath) {
  8.    // 使用try-with-resources自动关闭流
  9.    try (FileOutputStream outputStream = new FileOutputStream(new File(filePath))) {
  10.        byte[] buffer = new byte[1024];
  11.        int length;
  12.        // 读取输入流并写入到输出流
  13.        while ((length = inputStream.read(buffer)) > 0) {
  14.            outputStream.write(buffer, 0, length);
  15.       }
  16.        System.out.println("文件保存成功!");
  17.   } catch (FileNotFoundException e) {
  18.        e.printStackTrace();
  19.   } catch (IOException e) {
  20.        e.printStackTrace();
  21.   }
  22. }
复制代码
多张图片归并逻辑
  1. /**
  2. * 多张图片合并之后的逻辑
  3. * @param imagePath
  4. * @param desPath
  5. * @return
  6. */
  7. public static boolean mergeImage(String imagePath, String desPath,String sux) {
  8.    try {
  9.        File folder = new File(imagePath);
  10.        // 包含文件前缀的文件 简单解决并发的问题
  11.        File[] imageFiles = folder.listFiles((dir, name) ->
  12.               (name.toLowerCase().endsWith(".png") || name.toLowerCase().endsWith(".jpg") && name.contains(sux)));
  13.        if (imageFiles != null && imageFiles.length > 0) {
  14.            int maxWidth = 0;
  15.            int totalHeight = 0;
  16.            // 预先计算最大宽度和总高度
  17.            for (File imageFile : imageFiles) {
  18.                BufferedImage image = ImageIO.read(imageFile);
  19.                maxWidth = Math.max(maxWidth, image.getWidth());
  20.                totalHeight += image.getHeight();
  21.                image.flush(); // 尝试释放资源
  22.           }
  23.            // 创建合并后的图片,仅初始化一次
  24.            BufferedImage mergedImage = new BufferedImage(maxWidth, totalHeight, BufferedImage.TYPE_INT_ARGB);
  25.            Graphics2D g2d = mergedImage.createGraphics();
  26.            int currentY = 0;
  27.            for (File imageFile : imageFiles) {
  28.                BufferedImage image = ImageIO.read(imageFile);
  29.                g2d.drawImage(image, 0, currentY, null);
  30.                currentY += image.getHeight();
  31.                image.flush(); // 处理完后释放当前图片资源
  32.           }
  33.            g2d.dispose();
  34.            // 保存合并后的图片
  35.            ImageIO.write(mergedImage, "PNG", new File(desPath));
  36.            System.out.println("图片合并完成!");
  37.            for (File file : imageFiles){
  38.                if (file.exists()) {
  39.                    if (file.delete()) {
  40.                        System.out.println("文件 " + file.getName() + " 已被删除");
  41.                   } else {
  42.                        System.out.println("无法删除文件 " + file.getName());
  43.                   }
  44.               } else {
  45.                    System.out.println("文件 " + file.getName() + " 不存在");
  46.               }
  47.           }
  48.       } else {
  49.            System.out.println("输入文件夹中没有图片文件!");
  50.       }
  51.   } catch (IOException e) {
  52.        e.printStackTrace();
  53.        System.out.println("图片合并失败: " + e.getMessage());
  54.   }
  55.    return true;
  56. }
复制代码
新建控制器PdfApi.java
用来接收小步伐调用传递过来的参数,需要判断传递过来的文件是否为图片格式,然后调用转换方法即可。
  1.  /**
  2.     * pdf转图片 多页转一张图
  3.     * @param uploadFile
  4.     * @return
  5.     * @throws IOException
  6.     */
  7.    @PostMapping("pdfconvertimage")
  8.    public String upload(@RequestPart("file") MultipartFile uploadFile) throws IOException {
  9.        if (null == uploadFile) {
  10.            return null;
  11.       }
  12.        // BMP、JPG、JPEG、PNG、GIF
  13.        String fileName = uploadFile.getOriginalFilename().toLowerCase();
  14.        if (!fileName.endsWith(".pdf")) {
  15.            return null;
  16.       }
  17.        //String image= PdfUtils.pdf(uploadFile.getInputStream(),Integer.valueOf(type));
  18.        String image= PdfUtils.pdfToPng(uploadFile.getInputStream(),fileName);
  19.        // 返回响应实体
  20.        return image;
  21.   }
复制代码
  1. [/code]
  2. [size=3]1.3 后端接口摆设[/size]
  3. 由于微信小步伐调用第三方接口需要https域名形式,以是接口开发完成后,需要摆设到云服务器,然后申请域名、申请SSL证书,确保接口可以通过https域名正常访问。而且在微信小步伐开发设置配置request正当域名白名单,包管接口可以调通。
  4. [align=center][img=1080,242]https://img-blog.csdnimg.cn/img_convert/74183d95edcf74ba5e44aff19ad9123f.png[/img][/align]
  5. [size=3]1.4 微信小步伐前端页面开发[/size]
  6. 打开微信开发者工具,然后微信小步伐管理员扫码登录自己的微信小步伐。这里主要给大家贴出主要的代码以及实现思绪。具体界面如下:
  7. 上传方式:支持微信会话文件上传、直接输入PDF文件的URL,转换成功后可以点击下载按钮进行下载图片。
  8. [align=center][img=369,627]https://img-blog.csdnimg.cn/img_convert/7a82d097e6be78587547857dbf7f3b49.png[/img][/align]
  9. [b]wxml文件代码如下:[/b]
  10. [code]
  11. <view style="text-align: center;">
  12. <image style="width: 98%;"  src="推广图片"></image>
  13. </view>
  14. <view class="selectSection">
  15.     <text class="textmag">上传方式:</text>
  16.     <radio-group bindchange="radioChange" class="radio-group">
  17.         <label class="radio" wx:for="{{direction}}" wx:key="i">
  18.             <icon class="radioIcon {{item.checked?'actIcon':''}}"></icon>
  19.             <radio checked="{{item.checked}}" value="{{item.name}}"></radio>{{item.value}}
  20.         </label>
  21.     </radio-group>
  22. </view>
  23. <view class="container">
  24.     <view wx:if="{{directionType==1}}" class="item"> <button style="width: 120px;" class="butss" bindtap="chooseFile">上传pdf文件</button></view>
  25.     <view wx:if="{{directionType==2}}" class="item"> <button style="width: 120px;" class="butss" bindtap="chooseFileNew">生成图片</button></view>
  26.     <view class="item"> <button style="width: 90px;" class="butss" bindtap="saveTap">下载</button></view>
  27.     <view class="item"> <button style="width: 90px;" class="butss" bindtap="clearTap">清空</button></view>
  28. </view>
  29. <view style="padding: 20px;">
  30.     <span style="color: red;font-size: 12px;">温馨提示:目前支持10页以内的pdf文件转换</span>
  31. </view>
  32. <view>
  33.   <textarea  auto-height bindinput="handleInput" class="input-content" value="{{uploadUrl}}"  placeholder="请输入pdf文件url" wx:if="{{directionType==2}}"></textarea>
  34. </view><view class="instruction">
  35.     <span style="color: black;padding-left: 10px;">结果文件:{{data}}</span>
  36. </view>
复制代码

js主要代码:
  1. // 选择微信会话文件 然后直接调用上传接口
  2.     chooseFile: function () {
  3.         var that = this;
  4.         wx.showLoading({
  5.             title: '图片上传处理中,请稍后...',
  6.         });
  7.         wx.chooseMessageFile({
  8.             count: 1,
  9.             type: 'file',
  10.             extension: ['pdf'], // 限定选择的文件格式为.doc, .docx, .pdf
  11.             success: function (res) {
  12.                 const tempFilePath = res.tempFiles[0].path;
  13.                 if (res.tempFiles[0].size > 10 * 1024 * 1024) { // 限定文件大小为2MB
  14.                     wx.showToast({
  15.                         title: '文件大小超过限制,请选择小于10MB的文件',
  16.                         icon: 'none'
  17.                     });
  18.                     return;
  19.                 }
  20.                 that.setData({
  21.                     pdfPath: tempFilePath                })wx.uploadFile({
  22. url: '后端接口API',
  23. filePath: tempFilePath,
  24. formData: {
  25. },
  26. name: 'file',
  27. success: function (res) {
  28. if (res.statusCode == "200") {
  29. that.setData({
  30. imageUrl: res.data,// 直接可以访问的url
  31. data: res.data
  32. });
  33. wx.showToast({
  34. title: '转换成功',
  35. icon: 'success',
  36. duration: 2000
  37. });
  38. } else {
  39. wx.showToast({
  40. title: '转换失败,请联系管理员',
  41. icon: 'none',
  42. duration: 2000
  43. });
  44. }
  45. },
  46. fail: function (res) {
  47. wx.showToast({
  48. title: '上传失败',
  49. icon: 'none',
  50. duration: 2000
  51. });
  52. }
  53. });
  54. },
  55. fail: function (res) {
  56. console.error('选择文件失败', res);
  57. wx.showToast({
  58. title: '选择文件失败',
  59. icon: 'none',
  60. duration: 2000
  61. });
  62. }
  63. });
  64. },
  65. // 下载按钮事件
  66. saveTap: function () {
  67. if (this.data.imageUrl) {
  68. wx.downloadFile({
  69. url: this.data.imageUrl,
  70. success: function (res) {
  71. if (res.statusCode === 200) {
  72. var filePath = res.tempFilePath;
  73. // 调用保存图片方法
  74. wx.saveImageToPhotosAlbum({
  75. filePath: filePath,
  76. success: function (res) {
  77. wx.showToast({
  78. title: '保存成功',
  79. icon: 'success',
  80. duration: 2000
  81. });
  82. },
  83. fail: function (err) {
  84. console.error(err);
  85. wx.showToast({
  86. title: '保存失败',
  87. icon: 'none',
  88. duration: 2000
  89. });
  90. }
  91. });
  92. }
  93. },
  94. fail: function (err) {
  95. console.error(err);
  96. wx.showToast({
  97. title: '下载失败',
  98. icon: 'none',
  99. duration: 2000
  100. });
  101. }
  102. });
  103. } else {
  104. wx.showToast({
  105. title: '请先上传pdf文件,转换成功后再保存',
  106. icon: 'none',
  107. duration: 2000
  108. });
  109. }
  110. },
复制代码

1.5 运行效果


选择pdf文件上传



转换成功之后的结果文件如下:



然后可以点击下载按钮下载图片文件。整体转还原度还是很高的。
1.6 小步伐摆设上线


该步骤对于小步伐开发的朋友来说,还黑白常简单的,这里就不外多先容了,大家有问题的话,接待沟通交换!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4