坦白從寬吧,我就是那個花了兩天兩夜把 1M 圖片優化到 100kb 的家伙——王小二!
自從因為一篇報道登上熱搜后,我差點抑郁,每天要靠 50 片安眠藥才能入睡,
網路上曝光的那些關于一碼通的訊息,有真有假,我這里就不再澄清了,就說說我是怎么把圖片從 1M 優化到 100kb 的故事吧,
是的,由于系統群體規模和訪問規模的特殊性,每一行代碼、每一張圖片、每一個技術檔案都反復核準,優化再優化,精益求精,為確保系統運行得更高效,我們將一張圖片從1MB壓縮到500KB,再從500KB優化到100KB,
這樣的作業在外人看起來,簡單到就好像悄悄給學妹塞一張情書就能讓她做我女朋友一樣簡單,
但殊不知,這其中蘊含著極高的技術含量!
不信,我給你們普及下,
一、影像壓縮
影像壓縮是資料壓縮技術在數字影像上的應用,目的是減少影像資料中的冗余資訊,從而用更加高效的格式存盤和傳輸資料,
影像壓縮可以是有損資料壓縮,也可以是無損資料壓縮,


怎么樣?
是不是感覺影像壓縮技術沒有想象中那么簡單了?
更多關于影像壓縮的資料可參考以下鏈接,
機器之心:https://www.jiqizhixin.com/graph/technologies/08b2b25e-21a0-48e1-9de8-f91d424adfe1
二、Java數字影像處理
作為這次“20 多萬外包專案”的“主力開發人員”,我這里就給大家介紹下 Java 數字影像處理技術吧,一開始我就是用它來處理圖片的,
數字影像處理(Digital Image Processing)是通過計算機對影像進行去除噪聲、增強、復原、分割、提取特征等處理的方法和技術,

輸入的是影像信號,然后經過 DIP 進行有效的演算法處理后,輸出為數字信號,
為了壓縮影像,我們需要讀取影像并將其轉換成 BufferedImage 物件,BufferedImage 是 Image 類的一個子類,描述了一個具有可訪問的影像資料緩沖區,由 ColorModel 和 Raster 的影像資料組成,

廢話我就不多說了,直接進入實戰吧!
三、影像壓縮實戰
剛好我本地有一張之前用過的封面圖,離 1M 只差 236 KB,可以拿來作為測驗用,

這其中要用到 ImageIO 類,這是一個靜態類,提供了一系列方法用來讀和寫影像,同時還可以對影像進行簡單的編碼和解碼,
比如說通過 ImageIO.read() 可以將影像讀取到 BufferedImage 物件:
File input = new File("ceshi.jpg");
BufferedImage image = ImageIO.read(input);
比如說通過 ImageIO.getImageWritersByFormatName() 可以回傳一個Iterator,其中包含了通過命名格式對影像進行編碼的 ImageWriter,
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");
ImageWriter writer = (ImageWriter) writers.next();
比如說通過 ImageIO.createImageOutputStream() 可以創建一個影像的輸出流物件,有了該物件后就可以通過 ImageWriter.setOutput() 將其設定為輸出流,
File compressedImageFile = new File("bbcompress.jpg");
OutputStream os =new FileOutputStream(compressedImageFile);
ImageOutputStream ios = ImageIO.createImageOutputStream(os);
writer.setOutput(ios);
緊接著,可以對 ImageWriter 進行一些引數配置,比如說壓縮模式,壓縮質量等等,
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(0.01f);
壓縮模式一共有四種,MODE_EXPLICIT 是其中一種,表示 ImageWriter 可以根據后續的 set 的附加資訊進行平鋪和壓縮,比如說接下來的 setCompressionQuality() 方法,
setCompressionQuality() 方法的引數是一個 0-1 之間的數,0.0 表示盡最大程度壓縮,1.0 表示保證影像質量很重要,對于有損壓縮方案,壓縮質量應該控制檔案大小和影像質量之間的權衡(例如,通過在寫入 JPEG 影像時選擇量化表), 對于無損方案,壓縮質量可用于控制檔案大小和執行壓縮所需的時間之間的權衡(例如,通過優化行過濾器并在寫入 PNG 影像時設定 ZLIB 壓縮級別),
整體代碼如下所示:
public class Demo {
public static void main(String[] args) {
try {
File input = new File("ceshi.jpg");
BufferedImage image = ImageIO.read(input);
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");
ImageWriter writer = (ImageWriter) writers.next();
File compressedImageFile = new File("bbcompress.jpg");
OutputStream os = new FileOutputStream(compressedImageFile);
ImageOutputStream ios = ImageIO.createImageOutputStream(os);
writer.setOutput(ios);
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(0.01f);
writer.write(null, new IIOImage(image, null, null), param);
os.close();
ios.close();
writer.dispose();
} catch (IOException e) {
e.printStackTrace();
}
}
}
執行壓縮后,可以看到圖片的大小壓縮到了 19 KB:

可以看得出,質量因子為 0.01f 的時候圖片已經有些失真了,可以適當提高質量因子比如說 0.5f,再來看一下,

圖片質量明顯提高了,但大小依然只有 64 KB,壓縮效果還是值得信賴的,
四、其他開源庫
接下來,推薦一些可以輕松集成到專案中的影像處理庫吧,它們全都是免費的,
1)ImageJ,用 Java 撰寫的,可以編輯、分析、處理、保存和列印影像,

2)Apache Commons Imaging,一個讀取和寫入各種影像格式的庫,包括快速決議影像資訊(如大小,顏色,空間,ICC組態檔等)和元資料,

3)ImageMagick,可以讀取和寫入超過100種格式的影像,包括DPX、EXR、GIF、JPEG、JPEG-2000、PDF、PNG、Postscript、SVG和TIFF,還可以調整大小、翻轉、鏡像、旋轉、扭曲、剪切和變換影像,調整影像顏色,應用各種特殊效果,包括繪制文本、線條、多邊形、橢圓和貝塞爾曲線,

4)OpenCV,由BSD許可證發布,可以免費學習和商業使用,提供了包括 C/C++、Python 和 Java 等主流編程語言在內的介面,OpenCV 專為計算效率而設計,強調實時應用,可以充分發揮多核處理器的優勢,

這里就以 OpenCV 為例,來演示一下影像壓縮,當然了,OpenCV 用來壓縮影像屬于典型的大材小用,
第一步,添加 OpenCV 依賴到我們的專案當中,以 Maven 為例,
<dependency>
<groupId>org.openpnp</groupId>
<artifactId>opencv</artifactId>
<version>4.5.1-2</version>
</dependency>
第二步,要想使用 OpenCV,需要先初始化,
OpenCV.loadShared();
第三步,使用 OpenCV 讀取圖片,
Mat src = https://www.cnblogs.com/qing-gee/p/Imgcodecs.imread(imagePath);
第四步,使用 OpenCV 壓縮圖片,
MatOfInt dstImage = new MatOfInt(Imgcodecs.IMWRITE_JPEG_QUALITY, 1);
Imgcodecs.imwrite("resized_image.jpg", sourceImage, dstImage);
MatOfInt 的構造引數是一個可變引數,第一個引數 IMWRITE_JPEG_QUALITY 表示對圖片的質量進行改變,第二個是質量因子,1-100,值越大表示質量越高,
執行代碼后得到的圖片如下所示:

借這個機會,來對比下 OpenCV 和 JDK 原生 API 在壓縮影像時所使用的時間,
這是我本機的配置情況,早年買的頂配 iMac,也是我的主力機,一開始只有 16 G 記憶體,后來加了一個 16 G 記憶體條,不過最近半年電腦突然死機重啟的頻率明顯提高了,不知道是不是 Big Sur 這個作業系統的問題還是電腦硬體老了,

結果如下所示:
opencvCompress壓縮完成,所花時間:1070
jdkCompress壓縮完成,所花時間:322
壓縮后的圖片大小差不多,都是 19 KB,并且質量因子都是最低值,

四、一點點心聲
經過上面的技術分析后,相信你們都明白了,把1M圖片優化到100kb實在是一件“不太容易”的事情,,,,
100KB 很小了吧?只有原來的 1/10,
要知道,我可是連續加班了兩天兩夜,不眠不休,

累到最后,我趴在電腦上都睡著了,
沒想到哈喇子直接給電腦整短路了,我這才算是從夢里面嚇醒來了!
??,生活不易,且行且珍惜吧~
本篇已收錄至 GitHub 上星標 1.6k+ star 的開源專欄《Java 程式員進階之路》,據說每一個優秀的 Java 程式員都喜歡她,風趣幽默、通俗易懂,內容包括 Java 基礎、Java 并發編程、Java 虛擬機、Java 企業級開發、Java 面試等核心知識點,學 Java,就認準 Java 程式員進階之路??,
https://github.com/itwanger/toBeBetterJavaer
star 了這個倉庫就等于你擁有了成為了一名優秀 Java 工程師的潛力,也可以戳下面的鏈接跳轉到《Java 程式員進階之路》的官網網址,開始愉快的學習之旅吧,
https://tobebetterjavaer.com/

沒有什么使我停留——除了目的,縱然岸旁有玫瑰、有綠蔭、有寧靜的港灣,我是不系之舟,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/440344.html
標籤:Java
