HarmonyOS鸿蒙Next系统里面,有没有webview离屏渲染并获取帧数据的方案?
HarmonyOS鸿蒙Next系统里面,有没有webview离屏渲染并获取帧数据的方案?
功能描述
在鸿蒙中,有没有webview离屏渲染并获取帧数据的方案??可以提供一下吗,我在文档库里找到了关于离线web组件的相关用法,有点像,我还在看能不能用。文档里说可以通过buildernode来实现离屏预渲染web页面,buildernode本身可以导出纹理数据。我还没找到导出文理数据的具体接口用法,离屏预渲染的效果也还需要验证一下。关于buildernode的纹理数据导出,有没有相关的参考案例?
场景描述
想对web组件进行离屏渲染并且截大图,所以想找BuilderNode纹理导出的示例,导出后保存成高清图片
参考文档
链接:OpenGL离屏渲染视频画面-关键场景示例-影音娱乐类行业实践 - 华为HarmonyOS开发者
现象
这个是把解码器的数据传给NativeImage的window,然后通过openGL来渲染的,我把这里的Image的SurfaceId设置给BuilderNode,然后没有绘出任何数据,不知道哪里有问题???
更多关于HarmonyOS鸿蒙Next系统里面,有没有webview离屏渲染并获取帧数据的方案?的实战教程也可以访问 https://www.itying.com/category-93-b0.html
【解决方案】
开发者您好,可以参考以下demo, 截图存储沙箱目录filePath:/data/storage/el2/base/haps/entry/files/web_snapshot1.jpg
import { componentSnapshot } from '@kit.ArkUI';
import { image } from '@kit.ImageKit';
import { webview } from '@kit.ArkWeb'; // 或 import webview from '@ohos.web.webview';
import { fileIo } from '@kit.CoreFileKit'; // 文件操作
@Entry
@Component
struct Index {
@State pixmap: image.PixelMap | undefined = undefined;
private webController: webview.WebviewController = new webview.WebviewController();
@State webLoaded: boolean = false;
// 离屏 Web 组件构建器
@Builder
offscreenWebBuilder() {
Column() {
Web({ src: $rawfile('index.html'), controller: this.webController })
.width('100%')
.height('100%')
.backgroundColor(Color.Green)
.onPageEnd(() => {
console.log('Web 页面加载完成');
this.webLoaded = true;
})
.onErrorReceive((error) => {
console.error('Web 加载失败:', error);
})
}
.width(500) // 截图宽度(可根据需要调整)
.height(800) // 截图高度
.backgroundColor(Color.Blue)
}
build() {
Column() {
Button('截取离屏 Web 页面')
.onClick(() => this.takeWebSnapshot())
.margin(10)
if (this.pixmap) {
Image(this.pixmap)
.width('100%')
.height('80%')
.objectFit(ImageFit.Contain)
.margin(10)
} else {
Text('点击按钮截取离屏 Web 页面')
.fontSize(16)
.fontColor(Color.Gray)
}
}
.width('100%')
.height('100%')
}
// 使用 Promise 版本截图,避免参数顺序错误
async takeWebSnapshot() {
try {
// 调用 Promise 版本的 createFromBuilder
const pixelMap = await componentSnapshot.createFromBuilder(
() => this.offscreenWebBuilder(), // builder
3000, // delay(可选,单位 ms,0 表示立即执行)
false, // checkImageStatus(是否检查图像状态,默认 false)
{ scale: 2, waitUntilRenderFinished: true } // options(截图选项)
);
console.log('截图成功');
this.pixmap = pixelMap;
// 可选:保存到文件
await this.savePixelMapToFile(pixelMap);
} catch (error) {
console.error('截图失败:', JSON.stringify(error));
}
}
// 将 PixelMap 保存为 JPEG 文件
async savePixelMapToFile(pixelMap: image.PixelMap) {
const context = getContext(this); // 获取应用上下文
const filePath = context.filesDir + '/web_snapshot1.jpg';
console.log('filePath:' + filePath)
try {
const file = await fileIo.open(filePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
const packer = image.createImagePacker();
const options: image.PackingOption = {
format: 'image/jpeg',
quality: 95
};
const data = await packer.packing(pixelMap, options);
await fileIo.write(file.fd, data);
await fileIo.close(file.fd);
console.log('图片已保存到:', filePath);
} catch (err) {
console.error('保存图片失败:', JSON.stringify(err));
}
}
}
更多关于HarmonyOS鸿蒙Next系统里面,有没有webview离屏渲染并获取帧数据的方案?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在鸿蒙(HarmonyOS)中可以通过 BuilderNode离屏渲染方案实现 WebView 的离屏渲染并导出帧数据(纹理数据),这是之前不知道在哪里看到的一种方案,楼主可以尝试下:
- 核心方案:BuilderNode + 纹理导出
BuilderNode 是鸿蒙提供的离屏渲染节点,可在后台构建组件树并生成纹理数据。关键步骤如下:
1)创建 BuilderNode
构建一个离屏渲染节点,并在其内部加载 Web 组件:
import { BuilderNode, FrameNode } from '@ohos.arkui.node';
import web_webview from '@ohos.web.webview';
const builderNode = new BuilderNode();
builderNode.build(() => {
return Web({
src: $rawfile('webpage.html'),
controller: new web_webview.WebviewController()
});
});
2)获取纹理数据
通过 getTexture()方法获取渲染后的纹理对象:
const texture: FrameNode.Texture = builderNode.getTexture();
3)纹理转图片
将纹理数据转换为 PixelMap,再编码为图片文件(PNG/JPEG):
import image from '@ohos.multimedia.image';
// 将纹理转为 PixelMap
const pixelMap: image.PixelMap = await texture.createPixelMap();
// 编码为 PNG 并保存
const imagePacker = image.createImagePacker();
const packOptions: image.PackingOption = { format: 'image/png', quality: 100 };
const arrayBuffer = await imagePacker.packing(pixelMap, packOptions);
// 保存到文件
import fileio from '@ohos.fileio';
const filePath = 'xxx.png';
fileio.write(filePath, arrayBuffer);
- 关键注意事项
1)页面加载完成监听
需确保 Web 内容完全加载后再获取纹理,可在 Web 组件的 onPageEnd事件中触发纹理导出:
Web({
src: '...',
controller: this.controller,
onPageEnd: () => {
// 触发纹理获取逻辑
}
})
2)离屏渲染尺寸设置
BuilderNode 默认继承父容器尺寸,若需渲染超屏内容(如长截图),需显式设置大尺寸:
builderNode.setSize({ width: 2000, height: 5000 }); // 自定义宽高
3)性能优化建议
离屏渲染消耗较大,建议在后台线程执行。
大尺寸纹理可能引起内存溢出,可分段渲染(如分页截图)。
- 替代方案:WebView 原生截图(API 限制)
当前官方文档未开放 WebView 直接截图接口。若需简化流程,可考虑:
前端页面自渲染:通过 HTML5 Canvas 在网页内生成图像,再通过消息端口(MessagePort)传回应用侧。
系统级截图:仅适用于可视区域,无法实现离屏大图。
- 官方参考资料
在HarmonyOS Next中,可以通过BuilderNode结合Web组件实现WebView的离屏渲染,并获取其纹理数据用于截图等操作。
核心方案:BuilderNode + Web组件
- 创建离屏的BuilderNode:使用
BuilderNode.create接口创建一个离屏节点。关键是在其surfaceOptions中指定isTransparent: false(确保背景不透明)和正确的pixelFormat(如PixelFormat.RGBA_8888)。 - 构建Web内容:在BuilderNode的
build函数中,使用Web组件加载目标网页或本地HTML。这与在常规UI中使用的Web组件一致。 - 渲染与获取纹理:BuilderNode在离屏渲染后,其内容会生成到关联的纹理上。可以通过
BuilderNode的getTextureId()方法直接获取到其OpenGL纹理ID。 - 纹理处理与导出:获得纹理ID后,你可以使用OpenGL ES或图形库(如
PixelMap相关API)来读取纹理的像素数据。核心步骤是:- 将纹理绑定到帧缓冲区(FBO)。
- 使用
glReadPixels读取像素数据到内存缓冲区。 - 将缓冲区数据转换为
PixelMap。 - 最后,通过
image.Packer将PixelMap编码并保存为图片文件(如PNG、JPEG)。
关于纹理数据导出的关键接口与思路:
- 获取纹理:
builderNode.getTextureId(): number - 创建PixelMap:通常需要先创建
image.PixelMap对象来接收像素数据。你可以使用image.createPixelMap方法,并传入一个InitializationOptions来指定尺寸和格式。 - 读取数据到PixelMap:一种常见做法是,利用
Graphics模块的texture和render能力,或者直接通过Native层(C++)的OpenGL ES调用glReadPixels,将纹理数据读入ArrayBuffer,然后填充到PixelMap中。 - 保存图片:使用
image.Packer(例如image.createImagePacker())将PixelMap打包为图片二进制数据,然后通过fs文件系统API写入文件。
与您参考文档的区别:
您提供的OpenGL离屏渲染文档是针对视频解码器输出到NativeImage的方案,其数据流是:解码器 -> NativeWindow (Surface) -> OpenGL纹理。而BuilderNode的方案是:ArkUI组件树(含Web) -> 离屏渲染管线 -> OpenGL纹理。两者源头不同,因此直接将BuilderNode关联到为视频解码设计的NativeWindow可能无法工作。
直接使用BuilderNode获取纹理是更标准的ArkUI离屏渲染路径。目前公开的示例代码可能较少,但按照上述架构,在获得textureId后,结合OpenGL ES像素读取与PixelMap的创建、编码流程,即可实现您的“截大图”需求。请重点查阅@kit.ArkGraphics2D、@kit.ArkGraphics3D及@kit.Image等相关Kit的API文档,以获取纹理操作和图片处理的具体接口参数。


