漸進式加載 - 基礎講解

前言:

咱們在PC端用瀏覽器看圖片的時候,常常是先看到一張模糊圖,而後再漸漸的變得清晰,這種狀況在看漫畫的時候尤爲常見(模糊圖以下),這種效果就叫作漸進式加載.漸進式加載可以大大的提高體驗感,咱們先來了解一下漸進式加載的原理.

圖片來自網絡

(圖片來自網絡)javascript

1.JPEG

要作到漸進式加載,咱們的圖片須要是JPEG格式,而JPEG格式的圖片又分爲兩種,咱們要作到漸進式加載的話,須要的是Progressive JPEG.

(1)Baseline JPEG(標準型)

這種格式的圖片在保存信息的時候,是從上往下,將每一行的數據順序的保存起來的,因此讀一部分就展現的話,那麼效果就會像是從上往下一點一點展現.

(圖片來自網絡)php

(2)Progressive JPEG(漸進式)

這種格式的圖片在保存信息的時候,是一幀一幀的存儲的,若是逐幀逐幀的讀的話,就會先看到模糊圖,而後一點一點變清晰

(圖片來自網絡)java


(圖片來自網絡)python

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/JPEGlinux

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

(如下轉換方法來自網絡,因爲非java代碼,因此沒有作驗證,特此說明一下)web

一、PhotoShop

在photoshop中有「存儲爲web所用格式」,打開後選擇「連續」就是漸進式JPEG。 瀏覽器

二、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緩存

三、PHP

使用imageinterlace和imagejpeg函數咱們能夠輕鬆解決轉換問題。網絡

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

四、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)複製代碼

五、jpegtran

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

六、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端作漸進式加載

熱門文章

相關文章
相關標籤/搜索