漸進式載入 - 基礎講解

夏雨友人帳發表於2017-03-23

前言:

我們在PC端用瀏覽器看圖片的時候,經常是先看到一張模糊圖,然後再漸漸的變得清晰,這種情況在看漫畫的時候尤其常見(模糊圖如下),這種效果就叫做漸進式載入.漸進式載入能夠大大的提升體驗感,我們先來了解一下漸進式載入的原理.

漸進式載入 - 基礎講解
圖片來自網路

(圖片來自網路)

1.JPEG

要做到漸進式載入,我們的圖片需要是JPEG格式,而JPEG格式的圖片又分為兩種,我們要做到漸進式載入的話,需要的是Progressive JPEG.

(1)Baseline JPEG(標準型)

這種格式的圖片在儲存資訊的時候,是從上往下,將每一行的資料順序的儲存起來的,所以讀一部分就展示的話,那麼效果就會像是從上往下一點一點展示.

漸進式載入 - 基礎講解

(圖片來自網路)

(2)Progressive JPEG(漸進式)

這種格式的圖片在儲存資訊的時候,是一幀一幀的儲存的,如果逐幀逐幀的讀的話,就會先看到模糊圖,然後一點一點變清晰

漸進式載入 - 基礎講解

(圖片來自網路)


漸進式載入 - 基礎講解

(圖片來自網路)

2.解碼

如何判斷是否JPEG格式的圖片呢?下面引用一段Glide框架的程式碼
//ImageHeaderParser.java

private static final int EXIF_MAGIC_NUMBER = 0xFFD8;

// JPEG.
if (firstTwoBytes == EXIF_MAGIC_NUMBER) {
   return JPEG;
}複製程式碼
我們可以看出,JPEG是以FFD8開頭的
其實JPEG是以FFD8開頭,FFD9結尾,FFDA代表一個幀的開頭
FFD8 ... FFDA ... FFDA ... FFDA ... FFD9複製程式碼
Baseline JPEG 裡面只有一個FFDA
Progressive JPEG 裡面含有多個FFDA

比較完整的資料結構如下

漸進式載入 - 基礎講解

(圖片來自Wiki)
en.wikipedia.org/wiki/JPEG

3.如何儲存或者轉換成JPEG

(以下轉換方法來自網路,由於非java程式碼,所以沒有做驗證,特此說明一下)

1、PhotoShop

在photoshop中有“儲存為web所用格式”,開啟後選擇“連續”就是漸進式JPEG。

漸進式載入 - 基礎講解

2、Linux

檢測是否為progressive jpeg : identify -verbose filename.jpg | grep Interlace(如果輸出 None 說明不是progressive jpeg;如果輸出 Plane 說明是 progressive jpeg。)
將basic jpeg轉換成progressive jpeg:> convert infile.jpg -interlace Plane outfile.jpg

3、PHP

使用imageinterlace和imagejpeg函式我們可以輕鬆解決轉換問題。

<?php
    $im = imagecreatefromjpeg('pic.jpg');
    imageinterlace($im, 1);
    imagejpeg($im, './php_interlaced.jpg', 100);
    imagedestroy($im);
?>複製程式碼

4、Python

import PIL
from exceptions import IOError
img = PIL.Image.open("c:\\users\\biaodianfu\\pictures\\in.jpg")
destination = "c:\\users\\biaodianfu\\pictures\\test.jpeg"
try:
    img.save(destination, "JPEG", quality=80, optimize=True, progressive=True)
except IOError:
    PIL.ImageFile.MAXBLOCK = img.size[0] * img.size[1]
    img.save(destination, "JPEG", quality=80, optimize=True, progressive=True)複製程式碼

5、jpegtran

jpegtran -copy none -progressive <inputfile> <outputfile>複製程式碼

6、C

using (Image source = Image.FromFile(@"D:\temp\test2.jpg")) { 
    ImageCodecInfo codec = ImageCodecInfo.GetImageEncoders().First(c => c.MimeType == "image/jpeg"); 
    EncoderParameters parameters = new EncoderParameters(3);
    parameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
    parameters.Param[1] = new EncoderParameter(System.Drawing.Imaging.Encoder.ScanMethod, (int)EncoderValue.ScanMethodInterlaced);
    parameters.Param[2] = new EncoderParameter(System.Drawing.Imaging.Encoder.RenderMethod, (int)EncoderValue.RenderProgressive); 
    source.Save(@"D:\temp\saved.jpg", codec, parameters);
}複製程式碼

4.效果

明白了漸進式載入的原理後,我們就能想辦法在app端也做到漸進式載入的效果了.

(大概就是判斷是否JPEG圖片,然後根據每一幀的節點來判斷並決定是否需要載入)

下面展示一下效果圖

(1)原圖

漸進式載入 - 基礎講解

(Progressive JPEG的圖一打水印就變成Baseline JPEG,應該是CSDN打水印儲存的時候處理了)

(2)解碼到第一個FFDA與第二個FFDA的中間

漸進式載入 - 基礎講解

(3)剛好解碼到第二個FFDA

漸進式載入 - 基礎講解

(4)解碼到第五個FFDA

漸進式載入 - 基礎講解

需要看圖片二進位制結構的,可以下載一些工具(如hex-editor-neo)
hex-editor-neo下載

在後面的文章裡面我們將具體講解如何在app端做漸進式載入

熱門文章

相關文章