Chrome 图片解码与 Image.decode API

在这篇文章里面,我会对 Chrome 是何时对图片进行解码进行说明,并结合 Chrome 的渲染流水线说明为什么图片解码可能会造成动画卡顿,而新的 Image.decode API 是如何让我们控制图片解码的时机,通过预先解码来避免动画卡顿。

为了让读者更好地了解本文的内容,请阅读我之前的文章 —— 浏览器渲染流水线解析与网页动画性能优化

图片解码

图片解码与动画

默认的情况下,图片的解码会发生在这个图片所属的 image 元素被光栅化的过程中。而当一个元素处于可见区域,或者非常接近可见区域,浏览器的合成器就会安排元素所在图层的光栅化。合成器会检查该图层是否包含图片,如果有的话会创建对应的图片解码任务交由光栅化线程去执行,在这个过程中,合成器所在的合成线程是前台线程,光栅化线程是后台线程。

光栅化线程的图片解码任务

光栅化线程的图片解码任务

我们从浏览器渲染流水线解析与网页动画性能优化了解到网页动画可以分为合成器动画(也可以称为图层动画)和非合成器动画(也可以称为 DOM 动画),对于合成器动画来说,因为可见区域的绘制允许出现空白,所以合成器在动画每一帧的绘制过程中不需要等待该帧可见区域的光栅化任务(包含图片解码任务)的完成,动画的运行和光栅化是异步的。而对于非合成器动画来说,因为不允许可见区域的绘制出现空白,所以动画的每一帧都需要等待可见区域的光栅化任务的完成才允许提交绘制请求,这相当于动画的运行和光栅化是强制同步的。

我在支付宝的技术分享上也解释过为什么页端通过 rAF/timer 来连续改变元素的 transform,模拟惯性滚动的动画,始终在流畅度上很难达到由浏览器合成器驱动的惯性滚动动画的水平,容易出现卡顿掉帧的情况(旧版的手淘页面就是采用这种方式模拟惯性滚动)。其中一个重要的原因就是图片解码,图片解码是光栅化过程中非常耗时的一个步骤,通常需要花费几十毫秒或者上百毫秒,有的超大图片甚至可能达到几百毫秒,如果动画会被图片解码所阻塞,那么当图片即将出现在可见区域时,掉帧也是必然会发生的事情。

之前也有帮蚂蚁庄园分析过一个弹出面板卡顿的问题,这个弹出面板动画也是一个 rAF/timer 驱动的非合成器动画,面板上包含了一个超大图片的显示,动画过程中当图片即将出现在可见区域时,触发图片解码就造成了几百毫秒的动画卡顿。

图片解码缓存

合成器会通过一个图片解码缓存 ImageDecodeCache 来缓存解码后的图片像素数据和生成的纹理,如果一个图片已经解码并在缓存中时,它再次被绘制时就不需要重复解码。但是解码缓存的大小是有限制的,只能容纳有限的图片(在移动设备的上限通常是 128 兆或者更低),缓存采用 MRU(最近使用)的淘汰策略,如果一个图片已经被移出可见区域并且一段时间没有参与绘制,就有可能会被缓存淘汰,当它重新进入可见区域时,就会触发重解码。

Image.decode API

因为图片解码可能会造成非合成器动画的卡顿,那么最直观的优化想法就是,我能不能先解码图片,解码完成后再把图片加入到 DOM 树里面参与绘制。这种方式在 UI 编程里面也十分常见,应用自己管理一个解码图片的缓存池,如果一个图片需要显示时先请求解码,解码完成后才真正加入到 UI 界面中参与绘制。浏览器新增的 Image.decode API 就是让 Web 也具备相似的能力。

Image.decode 可以让 Web 端请求对这个图片进行提前解码,这个请求被 Blink 发送到合成器,合成器就会生成一个图片解码任务交由光栅化线程去运行。Image.decode 会返回一个 Promise,当光栅化线程完成解码任务后会通知合成器并将结果保存在解码缓存里面,合成器再通知 Blink resolve 这个 Promise,这时 Web 端就能接收到图片解码完成的通知。

ScriptPromise HTMLImageElement::decode(ScriptState* script_state,
                                       ExceptionState& exception_state) {
  return GetImageLoader().Decode(script_state, exception_state);
}

void ImageLoader::DispatchDecodeRequestsIfComplete() {
  ...

  LocalFrame* frame = GetElement()->GetDocument().GetFrame();
  for (auto& request : decode_requests_) {
    ...
    Image* image = GetContent()->GetImage();
    frame->GetChromeClient().RequestDecode(
        frame, image->PaintImageForCurrentFrame(),
        WTF::Bind(&ImageLoader::DecodeRequestFinished,
                  WrapCrossThreadWeakPersistent(this), request->request_id()));
    request->NotifyDecodeDispatched();
  }
}

Image.decode API 在 Chrome 中的部分实现,Blink 向合成器发起解码请求

这个演示视频显示了如何使用 Image.decode API 来避免一个 rAF 动画的突然卡顿,这里是Demo 的代码

function prepareImage() {
  var img = new Image();
  img.src = "nebula.jpg";
  img.decode().then(function() { document.body.appendChild(img); });
}

上面的示例代码中,prepareImage 中请求对 nebula.jpg 进行解码,在解码完成后再把它加入到 DOM 树,这样就规避了 rAF 驱动的时钟指针旋转动画因为图片解码造成的卡顿。

如前所述,合成器的图片解码缓存大小是有限的,而且不必要的内存占用也是不好的行为,所以对所有已经加载的图片都发起解码请求并不是一个良好的使用方式。一个可能的更好做法是:

  1. 当图片加载完成后,需要在可见区域显示或者即将需要显示,这时先发起解码请求,等待解码完成后再加入到 DOM 树中(可以跟图片延迟加载的机制相结合);
  2. 如果一个图片已经不在可见区域很长一段时间,可以考虑从 DOM 树移除,只保留一个大小相同的占位符,等下次再进入可见区域时再重复 1 的操作;

如果读者觉得这篇文章有所帮助,请继续关注专栏和为本文点赞,这样可以帮助我继续创作更多更有价值的文章。

SeleniumChrome深度配置实战:突破动态渲染反爬虫的完整指南 在数据采集领域,动态内容渲染和反爬虫机制已成为核心挑战。其原理在于现代Web应用普遍采用JavaScript在前端动态生成内容,并辅以浏览器指纹、行为检测等技术识别自动化脚本。这直接关系到数据获取的稳定性和效率,是爬虫工程实践中的关键技术价值所在。应用场景广泛,包括电商价格监控、社交媒体分析和舆情监测等。针对这些挑战,通过Selenium驱动真实Chrome浏览器进行深度伪装自动化操作,成为可靠的解决方案。本文聚焦于如何配置Chrome启动参数、使用CDP协议修改浏览器指纹,并结合selenium-wir 阅读详情

相关推荐

前端 Base64 图片互转:3种场景下的性能对比最佳实践

本文深入探讨前端开发中Base64图片互转的三种实现方式,通过性能对比测试揭示Base64内联、File/Blob转换和Canvas绘制在不同场景下的表现差异。针对小于2KB的小图标、中等尺寸图片和大图片处理,提供场景化的最佳实践方案,帮助开发者优化图片处理性能,平衡用户体验开发效率。

dieyuqi2955的博客 399

VC++解析TIFF格式文件库

VC++解析TIFF\TIF格式类型文件所需库, VC++解析TIFF\TIF格式类型文件所需库

Gatsby图片优化深度解析:从sharp配置到gatsbyImageData迁移

现代静态站点的图像交付已远超简单格式转换,本质是编译时元数据生成运行时智能加载的协同工程。理解Sharp图像处理原理、GraphQL查询驱动的像素计算逻辑,以及gatsby-plugin-sharp在Gatsby构建流水线中的语义解析角色,是实现真正高性能图片加载的前提。技术价值体现在LCP优化、CLS控制WebP精准生效;典型应用场景包括CMS集成的Banner首屏、电商商品图响应式适配及Gatsby v4到v5的平滑升级。本文聚焦gatsby-plugin-sharp和gatsbyImageData

weixin_33957648的博客 431

How to decompress tiff CCITT Group 3 and CCITT Group 4 use C language

How to decompress tiff CCITT Group 3 and CCITT Group 4 use C language

图片解码缓存

解码 = 在图片真正要出现在视口里之前,提前完成 decode,把「压缩数据 → 位图」这一步做完。典型场景:列表里下一屏的头像、封面,轮播下一张,路由切换前,提前加载详情页大图。目标:显示时只做合成,不再临时 decode,首帧更稳。这里的「缓存」通常指:把已经 decode 好的位图(或可直接绘制的对象)留在内存里,下次再用同一张图时,跳过 decode。网络层:HTTP 缓存,同 URL 不必再下解码层:同 URL 的位图可能已在内存里,可见<img>再绑这个 URL 时更快层级。

weixin_47138303的博客 424

前端优化- 图片优化

NextJs的Image组件的解决方法是”在img标签外套一个span标签,在使用组件的时候传入宽高“,这样将内部图片的活动区域进行限制,从而减少布局修改频率。在少量图片/小图加载的时候可能对网站的性能影响不大,但是如果一旦出现对网站产生性能影响的时候就需要考虑一些关于图片优化的方案,所以有了这篇图片优化记录。表现出来的效果是”在需要加载图片的时候会更快的显示图片“。因为它预先加载了,现在需要做的就只有显示。表现出来的效果是”视图内的图片先加载,视图以外的图片在达到某个阈值的时候再加载进来“。

weixin_44294593的博客 537

golang图片属性orientation在image.Decode后丢失,导致图片上传后旋转

通常图片web上传后,会进行image.Decode() 解码、resize.Reszie()图片压缩、jpeg.Encode()编码保存等处理。 但部分图片在处理过后,图片显示会被旋转。通常在于苹果手机拍出的照片,而安卓手机正常。 这是苹果手机等设备拍照后,图片文件上带有orientation方向属性,系统打开显示时会自动根据方向属性进行调整,让我们看起来是正常的。 而后台处理后,orientation方向属性丢失(类似安卓手机拍的照片),导致保存后的新图片被旋转。 可以通过github.com.

虚月的专栏 1448

Chrome安装插件提示 出现错误 image decode failed

今天安装插件遇到这个问题了,网上搜了一下解决方案试了没有效果。 其实是因为图片加载失败导致的 解决方法: 在插件界面的展示图片上右键,复制图片地址 把图片地址的域名例如“*.googleusercontent.com”加入你梯子的过滤规则里,刷新界面重新安装就可以了。 当然,浏览器浏览器的体质不能一概而论??? 仅供参考 ...

2万+

tf.image.decode_jpeg(别名tf.io.decode_jpeg)函数工作原理分析

tf.image.decode_jpeg(别名tf.io.decode_jpeg)函数工作原理分析

RSMung的博客 1549

Chrome 图片解码 Image Decoding Hint

我在之前的一篇文章Chrome 图片解码 Image.decode API,说明了为什么图片解码可能会导致非合成器动画的阻塞和如何使用 Image.decode API 来避免动画的阻塞。不过虽然 Image.decode API 给页端提供了更灵活的控制图片解码时机的能力,但是使用起来较为复杂,也容易误用,而 Image Decoding Hint ...

weixin_34166472的博客 507

JavaScript QRCode 解码库架构解析WebRTC实时扫描实现

jsqrcode是一个基于ZXing开源项目实现的纯JavaScript QR码解码库,采用模块化设计架构,将二维码解码过程分解为多个独立的处理单元。该库的核心价值在于无需任何浏览器插件即可在HTML5兼容环境中实现二维码的实时扫描解码功能,为Web应用提供了原生的二维码处理能力。 ## 模块化架构设计 ### 核心解码模块 库的核心功能分布在14个独立的JavaScript文件中,每个文

gitblog_00421的博客 255

React-Cool-Img性能优化实战:提升网站图片加载速度的终极方案

想要让您的React网站图片加载速度提升300%?React-Cool-Img正是您需要的终极解决方案!😎 这款轻量级React图片组件让您能够像专业开发者一样处理图片用户体验和性能优化。在当今注重页面加载速度的Web开发环境中,图片优化已成为提升网站性能的关键因素。 ## 为什么图片性能优化如此重要? 图片通常是网页中最大的资源,占页面总大小的50%以上。缓慢的图片加载会直接影响用户体验、

gitblog_01130的博客 606

UTIF.js:快速和先进的TIFF解码

UTIF.js 小型,快速和高级的TIFF / EXIF(+ DNG,CR2,NEF和其他TIFF格式的文件)解码器和编码器。 它是的主要TIFF库。 尝试使用Photopea打开TIFF文件,以查看UTIF.js是否可以解析该文件。 支持黑白,灰度,RGB和调色板图像 支持传真3和传真4(CCITT),JPEG,LZW,PackBits和其他压缩(1、3、4、5、6、7、8、32773、32809) 例如,带有传真4压缩的仅为56 kB( ) 对于RAW文件,UTIF.js仅解码原始传感器数据(和JPG预览,如果有的话)。 它不会将原始数据转换为可显示图像(RGBA)。 这种转换很复杂,超出了该库的范围。 安装 下载UTIF.js文件并将其包含在您的代码中。 如果您使用的是NodeJS或使用NPM,请运行: npm install utif UTIF.decode(buffer)

TIFF 图像文件读写源代码

支持多种压缩方法的TIFF图像文件读写。

tiff:完全用JavaScript编写的TIFF图像解码

蒂芙 TIFF图像解码器完全用JavaScript编写。 由维护 安装 npm i tiff 兼容性 该库当前可以解码灰度和RGB图像(8、16或32位)。 它支持LZW压缩和带有附加alpha通道的图像。 扩展名 还支持使用Zlib / deflate算法压缩的图像。 原料药 tiff.decode(data [,options]) 解码文件并返回TIFF IFD。 IFD对象 每个解码图像都存储在IFD 。 IFD#data data属性是包含像素数据的类型化数组。 这是一个Uint8Array为8位图像, Uint16Array为16个图像和Float32Array为32个图像。 IFD的其他属性 size -像素数 width -列数 height -行数 bitsPerSample位深度 alpha如果图像具有其他alpha通道,则为true xResolution

C#图片处理全攻略:从System.Drawing到ImageSharpSkiaSharp实战

在软件开发中,图片处理是常见且关键的技术需求,涉及文件读取、格式转换、内存管理网络传输等多个环节。其核心原理在于将图像数据从文件系统或网络流转换为可操作的字节流,并通过图形库进行解码、处理和编码。掌握高效的图片处理技术能显著提升应用性能用户体验,尤其在Web应用、移动开发和服务端批处理等场景中至关重要。本文聚焦C#生态,通过对比分析System.Drawing、ImageSharp和SkiaSharp等主流工具链,深入探讨如何避免内存泄漏、优化大图加载及实现跨平台兼容等实践难题,帮助开发者构建稳健高效的

weixin_34345753的博客 310

图片Skill开发实战:从概念到部署,构建标准化AI图片处理能力

在AI应用开发中,API和SDK是开发者集成外部能力的传统方式,它们通过预定义的网络端点或客户端库提供特定功能,但往往伴随着较高的集成成本和供应商锁定风险。其技术原理在于封装复杂功能并提供标准化调用接口,以提升开发效率。随着AI应用生态的演进,一种名为“Skill”的新范式应运而生,它通过将AI能力封装成可即插即用、描述执行分离的标准化单元,旨在解决传统集成模式的痛点,实现能力的快速发现、调用组合。这种模式在图片处理领域尤为突出,形成了“图片Skill”热潮,其核心价值在于大幅降低AI能力集成门槛,提升

congdi7904的博客 340

前端性能优化学习 08 资源加载优化

图片延迟加载 什么是延迟加载 首先来想象一个场景,当浏览一个内容丰富的网站时,比如电商的商品列表页、主流视频网站的节目列表等,由于屏幕尺寸的限制,每次只能查看到视窗中的那部分内容,而要浏览完页面所包含的全部信息,就需要滚动页面,让屏幕视窗依次展示出整个页面的所有局部内容。 显而易见,对于首屏之外的内容,特别是图片和视频,一方面由于资源文件很大,若是全部加载完,既费时又费力,还容易阻塞渲染引起卡顿;另一方面,就算加载完成,用户也不一定会滚动屏幕浏览到全部页面内容,如果首屏内容没能吸引住用户,那么很可能整个页面

皮蛋很白的博客 1662
上一篇: BZOJ2303:[APIO2011]方格染色(并查集)
下一篇: 隐马尔科夫模型
weixin_33694620
博客等级 码龄11年 4374粉丝 1397原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值