虎绿林支持HEIC/HEIF/AVIF图片了,但是第一次加载较慢

@Ta 2022-01-14发布,2022-01-24修改 44529点击

HEIC/HEIF演示图片:

https://hu60.cn/q.php/bbs.topic.102432.html?floor=41#41

https://hu60.cn/q.php/bbs.topic.99791.html

https://hu60.cn/q.php/bbs.topic.102386.html?floor=1#1

AVIF演示图片(新版Firefox和Chrome原生支持AVIF,所以可以瞬间显示。请用旧版浏览器或者手机UC浏览器等进行测试):

https://hu60.cn/q.php/bbs.topic.102432.6.html?floor=118#118

解码实现:https://gitee.com/hu60t/heif-web-display

调试页面:https://hu60.cn/tpl/jhin/js/heif-web-display/


可在用户中心清除HEIF图片缓存。

image.png


首次发布:有HEIC/HEIF图片的网页目前会明显卡顿。我考虑把解码改成 web worker 后台进程以避免卡顿。

更新1:已经启用了 web worker 在后台转换,倒是不卡了,但依然不快。UC浏览器的标签页偶尔还会在同时解码多个图片时崩溃。

更新2:已经启用了缓存,所以只有第一次加载特别慢了。只要成功加载过一次,以后都是秒出现。

更新3:改用wasm版heif库进行转换,提高了首次加载速度;转换为jpg,减小内存占用。

更新4:更新3导致3楼的图像解码成这样了(问题展示),所以只能退回更慢但更正确的更新2。

更新5:修复了更新3因为透明通道导致图片扭曲变形的问题。再次使用wasm版heif库+jpg进行转换显示。第一次加载依然不是特别快,而且在UC浏览器里的稳定性好像变差了,很多图片转不出来。

更新6:找到导致UC浏览器里稳定性变差的原因了,是用mozjpeg把RGBA数据转换为jpeg时导致的崩溃。现已更换为通过浏览器自带的canvas转换,转换速度提高了很多,内存和CPU占用也有所降低。

更新7:用canvas转换为png对手机内存的压力还是有点大,UC在加载三张图片时页面经常崩溃。最后改成转换为jpeg,崩溃现象就很少了。不过UC还是偶尔转换不成功,需要刷新。

更新8:为图片解析添加了状态文字显示,解析失败时也会提示刷新。

更新9:为不支持AVIF图片的浏览器(比如手机UC浏览器)添加了AVIF解码支持。


最新效果展示,如果你反复刷新也没有这个状态文字显示,请清除浏览器缓存。

Screenshot_20220116_040753_com.huawei.browser.jpg

回复列表(117|隐藏机器人聊天)
  • @Ta / 2022-01-14 / /

    找了一下上游实现,最终追溯到这里
    https://github.com/catdad-experiments/libheif-emscripten

    所以最终实现代码来自此仓库:
    https://github.com/strukturag/libheif
    它是一个C/C++项目,上述JS是通过Emscripten编译而来,所以理论上可以生成wasm代码,也有相关issues在讨论。

    于是我查了一下npm,目前有一个现成的库:
    https://www.npmjs.com/package/@saschazar/wasm-heif
    从此库的描述来看,应该是支持浏览器的。

    所以可以试试wasm,它应该会比js快很多。
    红米K30 Pro(变焦版)

  • @Ta / 2022-01-14 / /

    @Curtion,很遗憾,libheif不是一个直接可用的库,它距离把图片显示在屏幕上还相当遥远,因为<img>标签不支持显示“a Uint8Array containing raw RGB pixels”。<img>标签只能显示封装好的图片格式。所以要把图片真正显示出来,你还必须完成后半段:把a Uint8Array containing raw RGB pixels转换成<img>标签可以显示的图片格式,比如png。最简单的可能是bmp,它几乎就是原始RGB像素,但是依然有一些工作要做。

  • @Ta / 2022-01-14 / /

    IMG_20220114_222309.HEIC(2.07 MB)
    一加8Pro

  • @Ta / 2022-01-14 / /

    @老虎会游泳,我不明白这个原始RGB数据是什么概念,如果使用Uint8Array创建一个Blob对象,同时指定MIME类型的话,可以显示出图片吗?
    红米K30 Pro(变焦版)

  • @Ta / 2022-01-14 / /

    @Curtion,那么你要指定的MIME类型是什么呢?它肯定不是image/png,也不是image/bmp,也不是image/jpeg,更不是image/webp

  • @Ta / 2022-01-14 / /

    @罐子,已修复大写扩展名不被识别为图片的问题。如果问题依然存在,属于浏览器js缓存。
    当然,3楼不会自动变成图片,因为它已经是个链接了。

  • @Ta / 2022-01-14 / /

    @Curtion原始RGB数据是什么概念

    [R, G, B, R, G, B, R, G, B, ...]
    

    就这样,从左至右从上到下每个像素的RGB数值。
    比如,颜色为#112233的纯色图片会有这样的数据:

    [0x11, 0x22, 0x33, 0x11, 0x22, 0x33, 0x11, 0x22, 0x33, ...]
    
  • @Ta / 2022-01-14 / /

    @老虎会游泳,明白了
    红米K30 Pro(变焦版)

  • @Ta / 2022-01-14 / /

    @Curtion,BMP是最接近原始RGB数据的图片格式,但还是得加一个BMP文件头才行。我会尝试一下。

  • @Ta / 2022-01-14 / /

    第一次知道这种格式。手机试了不会显示
    手机

  • @Ta / 2022-01-14 / /

    @童真再见,3楼的图片在手机UC浏览器上要等15秒才能解析好,偶尔还会解析失败不显示,需要刷新才能解析出来。

    @Curtion,我觉得我应该先做一下呈现优化,比如解析成功一次后就把结果缓存起来,这样就不必每次打开都等很久了。

  • @Ta / 2022-01-14 / /

    @老虎会游泳,那其实可以首先考虑在上传时进行编码转化工作,存储时就已经是jpg/png了,直接显示的功能可以稍后再做。
    红米K30 Pro(变焦版)

  • @Ta / 2022-01-14 / /

    @老虎会游泳,刚才去查了一下,heic支持那么差应该是因为有专利限制,而且解码器需要付费,看来转换成jpeg存储应该是一个好的方法。
    红米K30 Pro(变焦版)

  • @Ta / 2022-01-14 / /

    @Curtion,你把3楼显示出来的图片另存为一下看看大小就知道为什么转换存储不可行了。
    转换成png是无损,但是特别大。转换成jpeg是可以变小,但是画质差。
    而且转换后的jpeg要想画质不是特别垃圾的话,也比原图大很多。
    这种图片格式之所以被认为更先进,一定是因为在同等质量下比jpeg小很多。

  • @Ta / 2022-01-14 / /

    @老虎会游泳,那就转成AVIF
    红米K30 Pro(变焦版)

  • @Ta / 2022-01-14 / /

    @Curtion,我觉得只要把缓存做好,目前这种解码速度也是可以接受的。它本来就完全显示不出来,如果现在花点时间能让它显示出来,刷新后也能立即看到,那就完全可以了。然后我再去尝试用wasm加速解码。

  • @Ta / 2022-01-14 / /

    @Curtion,AVIF也是有损压缩,你会纠结于质量参数选什么,而且搞不好显示的时候也要用到我正在使用的库。
    此外,从一种有损压缩转换为另一种有损压缩一定会损失画质。

    图片.png

  • @Ta / 2022-01-14 / /

    @Curtion,其实吧,可以说前端解码是我唯一可以接受的方案。如果无法实现,我宁愿它只能作为附件下载,不直接显示。现在它已经可以显示了,那我就再也不会退回其他方案了。

  • @Ta / 2022-01-14 / /

    @Curtion,只有一种力量可以让我退回其他方案,就是HEVC的几个专利池跑过来收费。但我记得它们表示非盈利使用不需要交费。而且无论是存储前转码还是存储后转码,都需要交费。所以实际上没有区别。如果它们真的跑来收费,我就退回完全不解码的状态。

添加新回复
回复需要登录