最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java使用Apache?PDFBox進(jìn)行PDF轉(zhuǎn)圖片體積過大的優(yōu)化指南

 更新時(shí)間:2026年03月05日 08:45:55   作者:一勺菠蘿丶  
在項(xiàng)目中,我們有一個(gè)接口用于將 PDF 按頁拆分為圖片,方便前端逐頁展示,上線一段時(shí)間后發(fā)現(xiàn)體積過大了,下面我們就來看看如何進(jìn)行簡(jiǎn)單的優(yōu)化吧

一、背景

在項(xiàng)目中,我們有一個(gè)接口用于將 PDF 按頁拆分為圖片,方便前端逐頁展示。

原始實(shí)現(xiàn)邏輯:

  • 使用 Apache PDFBoxPDFRenderer
  • 調(diào)用 renderImageWithDPI
  • 使用 ImageIO.write(image, "PNG", file) 輸出 PNG
  • 每一頁生成一張大圖,路徑存入數(shù)據(jù)庫

上線一段時(shí)間后發(fā)現(xiàn):

  • 服務(wù)器磁盤增長很快
  • 圖片加載明顯變慢
  • 圖片接口內(nèi)存壓力升高
  • 單頁圖片體積動(dòng)輒幾 MB

于是開始排查問題。

二、問題分析

造成圖片體積過大的核心原因有 3 個(gè):

DPI 過高

原始代碼:

renderer.renderImageWithDPI(i, 144);

144 DPI 會(huì)生成較高分辨率圖片,頁面尺寸較大。

DPI 越高,生成的圖片分辨率越大,文件體積呈指數(shù)級(jí)增長。

不做尺寸限制

直接按 PDF 原始尺寸渲染輸出。

例如:

  • A4 頁面在 144 DPI 下
  • 寬度可能接近 2000+ 像素

對(duì)于僅用于網(wǎng)頁展示來說完全沒有必要。

使用 PNG 無損格式

PNG 是無損壓縮,適合:

  • 圖標(biāo)
  • 透明圖片
  • 插畫

但對(duì)于:

  • 含大量文字 + 圖片的課件 PDF
  • 整頁截圖型內(nèi)容

PNG 文件體積會(huì)非常大。

總結(jié)一句話

高 DPI + 原始大尺寸 + PNG 無損 = 單頁圖片非常大

三、優(yōu)化目標(biāo)

在保證肉眼清晰可讀的前提下:

  • 降低圖片體積
  • 降低磁盤增長速度
  • 減少網(wǎng)絡(luò)傳輸時(shí)間
  • 降低內(nèi)存壓力

并且:

  • 不改接口簽名
  • 不改 Controller
  • 只在工具類內(nèi)部優(yōu)化

四、整體優(yōu)化方案

優(yōu)化策略:

  • 降低 DPI
  • 限制最大寬度,等比例縮放
  • 保持 PNG(兼容現(xiàn)有業(yè)務(wù))

五、最終實(shí)現(xiàn)代碼(核心優(yōu)化版)

public class PdfToImageUtil {

    /**
     * 將 PDF 逐頁轉(zhuǎn)為壓縮后的 PNG 圖片
     */
    public static List<BizPptImage> convertPdfToImages(File pdfFile,
                                                       String outputDir,
                                                       String courseDetailId) throws IOException {

        List<BizPptImage> list = new ArrayList<>();

        try (PDDocument doc = PDDocument.load(pdfFile)) {

            PDFRenderer renderer = new PDFRenderer(doc);
            int pageCount = doc.getNumberOfPages();

            for (int i = 0; i < pageCount; i++) {

                // ① 降低 DPI(原 144 → 96)
                BufferedImage sourceImage = renderer.renderImageWithDPI(i, 96);

                // ② 限制最大寬度,等比例縮放
                BufferedImage scaledImage = scaleIfNecessary(sourceImage, 1280);

                String fileName = UUID.randomUUID() + "_" + (i + 1) + ".png";
                File outFile = new File(outputDir, fileName);

                ImageIO.write(scaledImage, "PNG", outFile);

                BizPptImage vo = new BizPptImage();
                vo.setImagePath(outFile.getAbsolutePath());
                vo.setFileName(fileName);
                vo.setCourseDetailId(courseDetailId);

                list.add(vo);
            }
        }

        return list;
    }

    /**
     * 按最大寬度等比例縮放
     */
    private static BufferedImage scaleIfNecessary(BufferedImage source, int maxWidth) {

        int width = source.getWidth();
        int height = source.getHeight();

        if (width <= maxWidth) {
            return source;
        }

        double scale = (double) maxWidth / width;
        int targetWidth = maxWidth;
        int targetHeight = (int) Math.round(height * scale);

        BufferedImage target = new BufferedImage(
                targetWidth,
                targetHeight,
                BufferedImage.TYPE_INT_RGB
        );

        Graphics2D g2d = target.createGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
                RenderingHints.VALUE_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);

        g2d.drawImage(source, 0, 0, targetWidth, targetHeight, null);
        g2d.dispose();

        return target;
    }
}

六、參數(shù)調(diào)優(yōu)建議

平衡清晰度 + 體積(推薦)

  • DPI = 96
  • maxWidth = 1280

適合 PC 展示場(chǎng)景。

清晰度優(yōu)先

  • DPI = 120
  • maxWidth = 1600 ~ 1920

適合高分屏場(chǎng)景。

體積優(yōu)先(縮略圖/預(yù)覽)

  • DPI = 72
  • maxWidth = 800 ~ 1024

圖片體積可以大幅降低。

七、優(yōu)化順序建議

建議按以下步驟逐步調(diào)優(yōu):

  • 固定 DPI(例如 96)
  • 調(diào)整 maxWidth
  • 觀察清晰度和體積
  • 如仍然過大,再降低 DPI

八、如果體積仍然偏大

可以考慮:

改為 JPEG

JPEG 是有損壓縮,體積會(huì)顯著下降。

缺點(diǎn):

  • 需要自定義 ImageWriter
  • 需要設(shè)置壓縮質(zhì)量參數(shù)
  • 對(duì)文字邊緣可能略微模糊

如果對(duì)清晰度要求不極端,可以考慮此方案。

九、優(yōu)化效果驗(yàn)證方式

同一份 PDF:

  • 用老代碼生成圖片
  • 用新代碼生成圖片

對(duì)比:

ls -lh
du -sh 目錄名

重點(diǎn)觀察:

  • 單頁圖片大小
  • 總目錄大小
  • 前端加載速度
  • 服務(wù)器磁盤增長趨勢(shì)

十、最終效果

在本項(xiàng)目中:

原方案:

  • DPI = 144
  • 不縮放
  • 單頁 2~5MB

優(yōu)化后:

  • DPI = 96
  • maxWidth = 1280

結(jié)果:

  • 單頁體積顯著下降
  • 總目錄大小大幅縮減
  • 前端加載速度明顯提升
  • 磁盤增長速度趨緩

并且:

  • 接口簽名未變
  • Controller 無感知
  • 業(yè)務(wù)層零改動(dòng)

十一、經(jīng)驗(yàn)總結(jié)

PDF 轉(zhuǎn)圖片時(shí),一定要考慮:

  • DPI
  • 輸出尺寸
  • 圖片格式

默認(rèn)配置往往偏“高清優(yōu)先”,不適合大規(guī)模線上使用。

一句話總結(jié):PDF 轉(zhuǎn)圖片不優(yōu)化,遲早磁盤爆炸。

到此這篇關(guān)于Java使用Apache PDFBox進(jìn)行PDF轉(zhuǎn)圖片體積過大的優(yōu)化指南的文章就介紹到這了,更多相關(guān)Java解決PDF轉(zhuǎn)圖片體積過大內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 解決Idea查看源代碼警告Library source does not match the bytecode for class XXX問題

    解決Idea查看源代碼警告Library source does not mat

    在使用IDEA開發(fā)時(shí),遇到第三方j(luò)ar包中的源代碼和字節(jié)碼不一致的問題,會(huì)導(dǎo)致無法正確打斷點(diǎn)進(jìn)行調(diào)試,這通常是因?yàn)閖ar包更新后源代碼沒有同步更新造成的,解決方法是刪除舊的jar包,通過Maven重新下載或手動(dòng)下載最新的源代碼包,確保IDE中的源碼與字節(jié)碼版本一致
    2024-10-10
  • java異步編程詳解

    java異步編程詳解

    這篇文章主要介紹了java異步編程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • spring基礎(chǔ)概念A(yù)OP與動(dòng)態(tài)代理理解

    spring基礎(chǔ)概念A(yù)OP與動(dòng)態(tài)代理理解

    這篇文章主要為大家詳細(xì)介紹了spring基礎(chǔ)概念A(yù)OP與動(dòng)態(tài)代理,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • Java Map集合詳解與演示

    Java Map集合詳解與演示

    Map用于保存具有映射關(guān)系的數(shù)據(jù),Map集合里保存著兩組值,一組用于保存Map的ley,另一組保存著Map的value,可以理解為Map中的元素是兩個(gè)對(duì)象,一個(gè)對(duì)象作為鍵,一個(gè)對(duì)象作為值。鍵不可以重復(fù),但是值可以重復(fù)
    2021-11-11
  • Java發(fā)送帶html標(biāo)簽內(nèi)容的郵件實(shí)例代碼

    Java發(fā)送帶html標(biāo)簽內(nèi)容的郵件實(shí)例代碼

    下面小編就為大家?guī)硪黄狫ava發(fā)送帶html標(biāo)簽內(nèi)容的郵件實(shí)例代碼。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-11-11
  • Java并發(fā)容器介紹

    Java并發(fā)容器介紹

    這篇文章主要介紹了Java并發(fā)容器,Java并發(fā)包(concurrent)是Java用來處理并發(fā)問題的利器,該并發(fā)包中主要有原子類,鎖(lock),并發(fā)容器類等等。本系列博客主要就是介紹并發(fā)包中一些常用的并發(fā)容器,常用的類,那么我們就來看看下面文章的詳細(xì)內(nèi)容吧
    2021-10-10
  • Java中集合遍歷的方法示例代碼展示

    Java中集合遍歷的方法示例代碼展示

    在 Java 編程中,集合(Collection)是用于存儲(chǔ)和操作一組對(duì)象的重要工具,無論是數(shù)組、列表(List)、集合(Set),還是映射(Map),它們都提供了在不同場(chǎng)景下靈活使用的數(shù)據(jù)結(jié)構(gòu),這篇文章主要介紹了Java中集合遍歷的方法示例代碼展示,需要的朋友可以參考下
    2024-08-08
  • spring boot2.0圖片上傳至本地或服務(wù)器并配置虛擬路徑的方法

    spring boot2.0圖片上傳至本地或服務(wù)器并配置虛擬路徑的方法

    最近寫了關(guān)于圖片上傳至本地文件夾或服務(wù)器,上傳路徑到數(shù)據(jù)庫,并在上傳時(shí)預(yù)覽圖片。本文通過實(shí)例代碼給大家分享spring boot2.0圖片上傳至本地或服務(wù)器并配置虛擬路徑的方法,需要的朋友參考下
    2018-12-12
  • jmeter中json提取器如何提取多個(gè)參數(shù)值

    jmeter中json提取器如何提取多個(gè)參數(shù)值

    關(guān)于jmeter中的正則表達(dá)式及json提取器可以提取響應(yīng)值,但是實(shí)際可以需要上個(gè)接口的多個(gè)響應(yīng)值,本文就詳細(xì)的介紹一下如何使用,感興趣的可以了解一下
    2021-11-11
  • StateMachine 狀態(tài)機(jī)機(jī)制深入解析

    StateMachine 狀態(tài)機(jī)機(jī)制深入解析

    這篇文章主要介紹了,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-08-08

最新評(píng)論

济宁市| 巴马| 蓬安县| 大庆市| 星子县| 化德县| 会理县| 蚌埠市| 平远县| 广宁县| 中宁县| 卓资县| 舒城县| 江都市| 阜城县| 岳阳市| 德兴市| 车致| 普兰店市| 雅安市| 廊坊市| 敖汉旗| 突泉县| 搜索| 镇原县| 涞源县| 双桥区| 新乡市| 芜湖市| 彩票| 琼海市| 镇赉县| 宁波市| 通道| 仁化县| 饶阳县| 福泉市| 磐石市| 怀化市| 南城县| 日土县|