javascript - 加载bpg图片: compatible,简单高效的技巧

标签 javascript image image-processing bpg

最近有一些关于 Fabrice Bellard 的 BPG 图像格式 (http://bellard.org/bpg/) 的讨论,它(基于他网站上提供的演示)提供比 jpeg、webp 和其他一些更好的压缩。图像解码是在浏览器中用JS完成的,这意味着它可以立即使用,无需等待浏览器采用。总的来说,这似乎是一个好主意,用一些 CPU 时间换取更快的下载速度通常是一个可行的折衷方案。

技术是used here换出图像是在 window.load 上迭代 document.images,找到 src 属性包含以“.bpg”结尾的 URL 的任何位置,并将其替换为 Canvas 。

然而,这绝对不是解决问题的唯一方法,我看到了这种技术的一些缺点,其中包括:a) Canvas 与图像没有完全相同的布局规则 - 例如在其上设置宽度属性意味着在 img 与 Canvas 上有所不同,b) 至少在 Chrome 中,对于缩小与 Canvas 的图像的缩放方式似乎是不同的。

一个更好的解决方案将理想地满足这些要求:

  • 尽量不要在内存中复制不必要的图像数据(也不要不必要地使用比必要更多的 CPU - 与原生图像处理相比,JS 中的解码已经需要很多)
  • 尽可能多地兼容浏览器
  • 使用 标签而不是 (不是必需的,但似乎更好)
  • 提供一种简单的方法,不仅可以处理文档加载时的图像,还可以处理稍后添加到文档中的图像(例如,响应用户事件)
  • 仍然易于使用(bellard.org 上的现有技术当然很容易集成)
  • 编辑:使用网络 worker 在不阻塞页面的情况下解码图像也可能是一个好方法。

  • 想到的一些相关工具包括 data: 和 blob: url。

    任何人都有使用这种“更好”技术加载 BPG 的工作代码示例? (Fabrice 在他的示例中使用它的方式还不错,当然方法也有取舍,但我认为可能有更好的东西可以更广泛地使用。)

    最佳答案

    BPG 看起来确实很有希望。如果要检测添加<img>任何时间、任何来源的元素,您都可以使用MutationObservers .
    如果您不了解它们,它们是异步的,将所有 DOM 突变的子集记录在文档中,并允许回调立即处理这些突变,而不是像 DOM 事件那样同步处理。因此,如果您在脚本中创建或更改大量图像的来源,观察者将等到您的脚本完成,然后一次性处理所有新图像(因此回调中的循环)。

    以下假设您有一个名为 doSomethingToDecode(img) 的函数。 (对不起,我现在不打算提供帮助)替换 src带有(很可能)生成的 PNG 的 img。它可以异步执行此操作,这不是问题。此外,您无需在交换 src 时停止观察图像。只要生成的替换不以“.bpg”结尾。

    当您添加 <img> 时,第一个观察者会使用react任何地方的后代(和其他元素,但它忽略了那些);不幸的是,在一般情况下不可能对其进行太多优化。它必须遍历突变列表,然后是每个突变的新节点列表,因此嵌套的 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 时,其他观察者会使用react元素的属性,并且应该只观察 <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> 使用react。元素然后停止观察它们,并释放任何与解码相关的资源,但希望浏览器至少足够聪明,可以停止观察应该被垃圾收集的元素(未经测试!)。

    在加载 HTML 后运行它(不要等待带有图像和 CSS 等的整个页面)。注意:这是使用 DOM 级别 0 document.images收藏。非常老派,但它正在做我们想要的非常有效和简洁的事情,那为什么不呢?

    所以首先你解码现有的<img> s 与 bpg 源,并观察它们是否有 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> 中的内容使用react。 ;不幸的是没有tagNameFilter参数以 native 过滤掉非 <img> childList 突变。
    imgObs.observe(document.body, {subtree:true, childList:true, attributes:false})
    

    关于javascript - 加载bpg图片: compatible,简单高效的技巧,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27586134/

    相关文章:

    javascript - 如何从 moment.tz 对象中获取唯一的时区名称?

    javascript - 将 key 对添加到 typescript 中的对象数组

    javascript - 如果上传的图片名称包含.php.jpg

    java - fork 点和山脊终点

    c++ - 图像中的物体检测

    javascript - 在类中使用 JavaScript 的 onmouseover 事件时出现问题

    javascript - 流程图 x 轴显示时间

    python - 如何使用python通过与文件夹中的文件名进行比较来显示图像?

    image - 使用 SkiaSharp 翻转 SKPath

    python - 相对于定义的质心,图像中的颜色分布是什么