簡體   English   中英

加載bpg圖像:兼容,簡單,高效的技術

[英]loading bpg images: compatible, simple and efficient techniques

最近有一些關於Fabrice Bellard的BPG圖像格式( http://bellard.org/bpg/ )的喧嘩,基於他網站上提供的演示,它提供了比jpeg,webp和其他一些更好的壓縮。 圖像解碼在瀏覽器中使用JS完成,這意味着它可以立即使用,無需等待瀏覽器采用。 總的來說,這似乎是一個好主意,並且為了更快的下載而交換一些CPU時間通常是可行的權衡。

這里用於交換圖像的技術是在window.load上迭代document.images,找到src屬性包含以“.bpg”結尾的URL的任何位置,並用畫布替換它。

然而,這絕對不是解決問題的唯一方法,我看到這種技術的一些缺點,包括:a)畫布與圖像沒有完全相同的布局規則 - 例如,設置寬度屬性就意味着不同的東西在img vs a canvas上,b)似乎至少在Chrome中,對於縮小與畫布相比的圖像,縮放是如何進行的。

理想情況下,更好的解決方案可滿足這些要求

  • 嘗試不再需要在內存中復制圖像數據(並且也不會不必要地使用比必要的CPU更多的CPU - 與本機圖像處理相比,JS中的解碼已經需要很多)
  • 擁有盡可能多的瀏覽器兼容性
  • 使用<img>標簽而不是<canvas>(不是要求,但似乎更好)
  • 提供一種簡單的方法,不僅可以處理文檔加載上的圖像,還可以處理稍后添加到文檔中的圖像(例如,響應用戶活動)
  • 仍然易於使用(bellard.org上的現有技術肯定易於集成)
  • 編輯:使用網絡工作者解碼圖像而不阻止頁面也是一個很好的方法。

想到的一些相關工具包括data:和blob:urls。

任何人都有使用這種“更好”技術加載BPG的工作代碼示例? (Fabrice在他的例子中使用它的方式也不錯,當然方法有權衡,但我認為可能有更好的廣泛使用。)

BPG確實看起來很有前景。 如果要隨時從任何來源檢測到<img>元素的添加,可以使用MutationObservers 如果您不了解它們,它們是異步的,記錄文檔中所有DOM突變的子集,並允許回調一次處理這些突變,而不是像DOM事件那樣同步。 因此,如果您在腳本中創建或更改大量圖像的來源,觀察者將等待您的腳本完成,然后一次性處理所有新圖像(因此回調中的循環)。

以下假設您有一個名為doSomethingToDecode(img)的函數(抱歉,我現在不會幫助它),它將(很可能)生成的PNG替換為img的src 它可以異步執行,這不是問題。 此外,只要生成的重新加入不以“.bpg”結尾,您就不需要在交換src時停止觀察圖像。

當你在任何地方添加<img>后代時,第一個觀察者會做出反應(而其他元素卻會忽略它們); 遺憾的是,在一般情況下不可能對其進行大量優化。 它必須迭代突變列表,然后迭代每個突變的新節點列表,因此嵌套for循環。

imgObs=new MutationObserver(
    function(mutations){
        for(var i=0, m; m=mutations[i]; i++) if(m.addedNodes.length)
            for(var j=0, img; img=m.addedNodes[j]; j++) if(img.localName=="img"){
                if(img.src && /\.bpg$/.test(img.src))
                    doSomethingToDecode(img)
                srcObs.observe(img, srcOptions)
            }
    }
)

當你更改元素的src屬性時,另一個觀察者會做出反應,並且應該只觀察<img>元素(對於最佳性能,如果你讓它觀察其他元素,它沒有故障,所以不要)。

srcObs=new MutationObserver(
    function(mutations){
        for(var i=0, m; m=mutations[i]; i++){
            var img=m.target
            if(img.src && /\.bpg$/.test(img.src))
                doSomethingToDecode(img)
        }
    }
)

保持這個方便,我們每次開始觀察新圖像時都需要它:

var srcOptions={childList:false, attributes:true, attributeFilter:["src"]}

您還可以讓觀察者對<img>元素的刪除作出反應,然后停止觀察它們,並釋放任何與解碼相關的資源,但希望瀏覽器至少足夠聰明,可以停止觀察應該被垃圾收集的元素(不是測試!)。

加載HTML后運行此命令(不要等待整個頁面包含圖像和CSS等)。 注意:這是使用DOM級別0 document.images集合。 非常老派,但它正在非常有效和簡潔地完成我們想要的,所以為什么不呢?

首先,您使用bpg源解碼現有的<img> ,並在以后觀察它們的src更改:

for(var i=0, img; img=document.images[i]; i++){
    if(img.src && /\.bpg$/.test(img.src))
        doSomethingToDecode(img)
    srcObs.observe(img, srcOptions)
}

然后這告訴第一個觀察者對整個文檔的<body>中的東西作出反應; 遺憾的是,沒有tagNameFilter參數來本地過濾掉非<img> childList突變。

imgObs.observe(document.body, {subtree:true, childList:true, attributes:false})

向圖像添加錯誤事件處理程序。 在Chrome 40上,當圖像丟失或瀏覽器不知道如何顯示時會觸發它:

<script>
var errors = [];
function fallback(elt) {
    if(errors[elt.src]) return;
    // you should also extract the extension in order to test lena.bpg, lena.png, lena.jpg and not lena.bpg.png, lena.bpg.png.jpg
    errors[elt.src] = true;
    console.error('could not load image, falling back');
    elt.src = elt.src + '.png';
    // stop trying
    elt.onerror= function(){};
}
</script>
<img src="test.html" onerror="fallback(this);" width=300 height=300 />

優點:客戶端部分沒有內存/ CPU使用情況。 缺點:需要在服務器上提供備用圖像。

我相信你可以在所有img標簽上聲明一個全局錯誤監聽器,這樣這對於將來的圖像也是如此。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM