首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 圖片處理:生成 JPEG 與壓縮圖片為 JPEG 完整代碼示例

     編輯:Java 相關知識

核心 API:ImageIO 與 JPEGImageWriteParam

Java 標準庫 javax.imageio 提供統一圖片讀寫接口。JPEG 壓縮關鍵在於 JPEGImageWriteParam 設置壓縮質量 (0.0f - 1.0f)。

完整工具類:讀取、壓縮、寫入 JPEG


import javax.imageio.*;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;

public class JpegUtil {

    /**
     * 將任意圖片文件壓縮為指定質量的 JPEG
     * @param srcPath 源圖片路徑 (支援 PNG, BMP, JPEG 等)
     * @param destPath 目標 JPEG 路徑
     * @param quality 壓縮質量 0.0f (最小/最差) ~ 1.0f (最大/最好),建議 0.7-0.85
     * @throws IOException
     */
    public static void compressToJpeg(String srcPath, String destPath, float quality) throws IOException {
        // 1. 讀取源圖片
        File srcFile = new File(srcPath);
        BufferedImage srcImage = ImageIO.read(srcFile);
        if (srcImage == null) {
            throw new IOException("不支援的圖片格式或文件損壞: " + srcPath);
        }

        // 2. 若源圖有透明通道,需合成白色背景 (JPEG 不支援透明)
        BufferedImage finalImage = srcImage;
        if (srcImage.getColorModel().hasAlpha()) {
            finalImage = new BufferedImage(
                srcImage.getWidth(), srcImage.getHeight(), BufferedImage.TYPE_INT_RGB);
            Graphics2D g = finalImage.createGraphics();
            g.setColor(Color.WHITE);
            g.fillRect(0, 0, finalImage.getWidth(), finalImage.getHeight());
            g.drawImage(srcImage, 0, 0, null);
            g.dispose();
        }

        // 3. 獲取 JPEG ImageWriter
        ImageWriter writer = ImageIO.getImageWritersByFormatName("jpeg").next();
        
        // 4. 配置壓縮參數
        ImageWriteParam param = writer.getDefaultWriteParam();
        if (param instanceof JPEGImageWriteParam) {
            JPEGImageWriteParam jpegParam = (JPEGImageWriteParam) param;
            jpegParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            jpegParam.setCompressionQuality(clamp(quality, 0.0f, 1.0f));
            // 可選: 設置縮略圖、進度監聽、色度子採樣
            // jpegParam.setSubsamplingMode(JPEGImageWriteParam.SUBSAMPLING_420); // 默認 4:2:0
        }

        // 5. 寫入輸出流
        try (FileOutputStream fos = new FileOutputStream(destPath);
             ImageOutputStream ios = ImageIO.createImageOutputStream(fos)) {
            
            writer.setOutput(ios);
            writer.write(null, new IIOImage(finalImage, null, null), param);
            writer.dispose();
        }
    }

    /**
     * 內存中 BufferedImage 直接壓縮為 byte[] (適合上傳/網絡傳輸)
     */
    public static byte[] toJpegBytes(BufferedImage image, float quality) throws IOException {
        if (image.getColorModel().hasAlpha()) {
            BufferedImage rgb = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
            Graphics2D g = rgb.createGraphics();
            g.setColor(Color.WHITE);
            g.fillRect(0, 0, rgb.getWidth(), rgb.getHeight());
            g.drawImage(image, 0, 0, null);
            g.dispose();
            image = rgb;
        }
        
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try (ImageOutputStream ios = ImageIO.createImageOutputStream(baos)) {
            ImageWriter writer = ImageIO.getImageWritersByFormatName("jpeg").next();
            ImageWriteParam param = writer.getDefaultWriteParam();
            if (param instanceof JPEGImageWriteParam) {
                ((JPEGImageWriteParam) param).setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
                ((JPEGImageWriteParam) param).setCompressionQuality(clamp(quality, 0.0f, 1.0f));
            }
            writer.setOutput(ios);
            writer.write(null, new IIOImage(image, null, null), param);
            writer.dispose();
        }
        return baos.toByteArray();
    }

    /**
     * 生成一張測試 JPEG 圖片 (繪製幾何圖形)
     */
    public static void generateTestJpeg(String destPath, int width, int height) throws IOException {
        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = img.createGraphics();
        
        // 背景漸變
        g.setPaint(new GradientPaint(0, 0, Color.BLUE, width, height, Color.CYAN));
        g.fillRect(0, 0, width, height);
        
        // 繪製圓形
        g.setColor(Color.WHITE);
        g.setStroke(new BasicStroke(3));
        g.drawOval(width/4, height/4, width/2, height/2);
        
        // 繪製文字
        g.setFont(new Font("微軟雅黑", Font.BOLD, 24));
        g.drawString("Java JPEG Demo", width/2 - 80, height/2 + 10);
        
        g.dispose();
        
        // 直接寫入 (默認質量 ~0.75)
        ImageIO.write(img, "jpeg", new File(destPath));
    }

    private static float clamp(float v, float min, float max) {
        return Math.max(min, Math.min(max, v));
    }

    // 測試主方法
    public static void main(String[] args) throws IOException {
        // 1. 生成測試圖
        String testPng = "test_source.png";
        generateTestJpeg(testPng, 800, 600); // 實際生成 JPEG,這裡作為源文件演示
        
        // 2. 壓縮為不同質量
        compressToJpeg(testPng, "output_q10.jpg", 0.1f); // 極低質量,文件極小
        compressToJpeg(testPng, "output_q50.jpg", 0.5f); // 中等
        compressToJpeg(testPng, "output_q85.jpg", 0.85f); // 高質量,推薦 Web 使用
        compressToJpeg(testPng, "output_q100.jpg", 1.0f); // 無損接近 (仍有損失)
        
        System.out.println("壓縮完成,請對比文件大小與視覺質量。");
    }
}

關鍵參數詳解

參數範圍影響建議值
Compression Quality0.0 - 1.0質量越高,文件越大,視覺損失越小Web 圖片 0.75-0.85;存檔 0.9+
Subsampling (色度子採樣)4:4:4 / 4:2:2 / 4:2:04:2:0 最省空間,人眼對色度不敏感默認 4:2:0 即可
Progressive (漸進式)true/false網頁加載時先模糊後清晰,提升體驗Web 圖片建議 true

進階:漸進式 JPEG 與自定義量化表


// 啟用漸進式 JPEG (需 JPEGImageWriteParam 支援)
if (param instanceof JPEGImageWriteParam) {
    JPEGImageWriteParam jpegParam = (JPEGImageWriteParam) param;
    jpegParam.setProgressiveMode(JPEGImageWriteParam.MODE_DEFAULT); // 或 MODE_COPY_FROM_METADATA
    
    // 自定義量化表 (極少用,專業攝影/醫療影像)
    // int[] qTable = ...; jpegParam.setQTable(qTable, JPEGImageWriteParam.TABLE_LUMINANCE);
}

常見問題排查

  1. 輸出全黑/全白:源圖為 CMYK 色彩空間,Java 不支援。需先用工具轉 sRGB。
  2. 透明背景變黑:JPEG 不支援 Alpha。代碼中已處理:檢測 `hasAlpha()` 合成白底。
  3. 中文亂碼/方框:`g.drawString` 使用的字體必須存在於系統。Linux 服務器需安裝中文字體或載入 TTF 文件:Font.createFont(Font.TRUETYPE_FONT, new File("msyh.ttf"))。
  4. 大圖 OOM:`ImageIO.read` 會將整圖解碼進堆。超大圖 (如 10000x10000) 需用 ImageReader.setInput(..., true) 分塊讀取或用 TwelveMonkeys ImageIO 插件。

總結

Java 標準庫 ImageIO + JPEGImageWriteParam 完整支援 JPEG 讀寫與壓縮質量控制。核心要點:處理透明通道合成白底、質量參數 0.7-0.85 平衡體積清晰度、Web 場景啟用漸進式。對於高性能、大圖、現代格式 (WebP, AVIF) 需求,建議引入 TwelveMonkeys ImageIO 或使用 ProcessBuilder 調用 cwebp/imagemagick 等原生工具。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved