优秀的编程知识分享平台

网站首页 > 技术文章 正文

如何将PDF文件切分成图片进行存储?

nanyue 2024-07-29 01:09:45 技术文章 7 ℃

前段时间,老板接到一个需求,说是某个小程序打开PDF文件加载太慢了?开发团队的同学一脸闷逼,大家不都是这样做的?提升服务器的带宽不就可以了么。

结果运维同学在提升了服务器带宽,增加了服务器内存之后,老板到客户面前去装X的时候,还是翻车了。所以就要求开发同学一定要解决这个问题。

我们日常使用的PDF,有两种形式

  • 文档形式的PDF:通过Word文档或者PPT等内容导出生成的PDF。
  • 图片形式的PDF:通过图片生成的PDF

根据这个思路,我们可以将PDF的每一页切分成一个图片,这样按照图片加载内容,总比直接加载一个一两百兆的PDF文件要加载的快吧,说干就干。下面我们就来看看如何去实现一个PDF文件的切分。

创建一个文件上传的接口

在这个接口中主要完成PDF文件的上传工作。

    /**
     * 通用上传请求(单个)
     */
    @PostMapping("/uploadPdf")
    @ResponseBody
    public AjaxResult uploadFilePdf(MultipartFile file) throws Exception
    {
        try
        {
            String prefix = RuoYiConfig.getImageProxyPath();
            // 上传文件路径
            String filePath = RuoYiConfig.getUploadPath();
            // 上传并返回新文件名称
            String fileName = FileUploadUtils.uploadPdf(filePath, file);
            String url = prefix + fileName;
            AjaxResult ajax = AjaxResult.success();
            ajax.put("url", url);
            ajax.put("fileName", fileName);
            ajax.put("newFileName", FileUtils.getName(fileName));
            ajax.put("originalFilename", file.getOriginalFilename());
            return ajax;
        }
        catch (Exception e)
        {
            return AjaxResult.error(e.getMessage());
        }
    }

PDF文件切分操作

首先需要引入两个POM的依赖

<!-- apache PDF转图片-->
<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>pdfbox</artifactId>
    <version>2.0.24</version>
</dependency>
<!--itext 图片合成PDF-->
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.5.13.2</version>
</dependency>

编写一个接收PDF文件并且进行拆分的方法

/**
     * 将PDF文档拆分成图像列表
     *
     * @param pdf PDF文件
     */
    private static List<BufferedImage> getImgList(File pdf) throws IOException {
        PDDocument pdfDoc = PDDocument.load(pdf);
        log.info("加载PDF文件成功");
        List<BufferedImage> imgList = new ArrayList<>();
        PDFRenderer pdfRenderer = new PDFRenderer(pdfDoc);
        int numPages = pdfDoc.getNumberOfPages();
        log.info("获取到PDF文件页码 {}",numPages);
        Instant start = Instant.now();
        for (int i = 0; i < numPages; i++) {
            BufferedImage image = pdfRenderer.renderImageWithDPI(i, 300, ImageType.RGB);
            imgList.add(image);
        }
        Instant end = Instant.now();

        Duration duration = Duration.between(start, end);
        log.info("分解PDF Time elapsed: " + duration.toMillis() + " milliseconds");
        pdfDoc.close();
        return imgList;
    }

将图片切分成一个List<BufferedImage>列表之后,接下来的操作就是将这个列表转换成对应的图片进行存储。

    /**
     * PDF分解图片文件
     *
     * @param pdf    pdf文件
     * @param outDir 输出文件夹
     */
    public static List<Map<String,Object>> cutPNG(File pdf, File outDir) throws IOException {
        log.info("PDF分解图片工作开始");
        String pdfName = pdf.getName();
        List<Map<String,Object>> fileNameList = new ArrayList<>();
        List<BufferedImage> list = getImgList(pdf);
        log.info(pdf.getName() + " 一共发现了 " + list.size() + " 页");
        FileUtils.cleanDir(outDir);
        Instant start = Instant.now();
        String outDirPath = outDir.getAbsolutePath();
        String name = outDir.getCanonicalPath();
        log.info("获取输出文件路径 {}",outDirPath);
        for (int i = 0; i < list.size(); i++) {
            Map<String,Object> fileMap = new HashMap<>();
            String format = StringUtils.format("{}/{}/{}.png", DateUtils.datePath(),pdfName.substring(0,pdfName.lastIndexOf(".")).trim()+"_pngs",i+1);
            IMGUtils.saveImageToFile(list.get(i),  outDirPath + File.separator + (i + 1) + ".png");
            String pathFileName = FileUploadUtils.getPathFileName(RuoYiConfig.getUploadPath(), format);
            fileMap.put("pageNumber",i+1);
            fileMap.put("filePath",RuoYiConfig.getImageProxyPath()+pathFileName);
            fileNameList.add(fileMap);

        }
        Instant end = Instant.now();
        Duration duration = Duration.between(start, end);
        log.info("保存图片 Time elapsed: " + duration.toMillis() + " milliseconds");
        log.info("PDF分解图片工作结束,一共分解出" + list.size() + "个图片文件,保存至:" + outDir.getAbsolutePath());
        return fileNameList;
    }

保存图像到指定路径

 /**
  * 保存图像到指定文件
  * @param image 图像
  * @param filePath 文件路径
  */
 public static void saveImageToFile(BufferedImage image, String filePath) throws IOException {
     FileUtils.saveDataToFile(filePath,getBytes(image));
 }

将数据保存到指定的路径

/**
 * 将数据保存到指定文件路径
 */
public static void saveDataToFile(String filePath,byte[] data) throws IOException {
    File file = new File(filePath);
    if(!file.exists()){
        file.createNewFile() ;
    }
    FileOutputStream outStream = new FileOutputStream(file);
    outStream.write(data);
    outStream.flush();
    outStream.close();
}

最终通过这样的操作可以让PDF转换换成一张一张的图片。然后通过getList的方式去加载这些图片。就不会出现因为PDF文件过大而导致的加载缓慢的问题。

最近发表
标签列表