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

4 回复

【解决方案】

开发者您好,可以参考以下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 的离屏渲染并导出帧数据(纹理数据),这是之前不知道在哪里看到的一种方案,楼主可以尝试下:

  1. 核心方案: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. 关键注意事项

1)页面加载完成监听

需确保 Web 内容完全加载后再获取纹理,可在 Web 组件的 onPageEnd事件中触发纹理导出:

Web({
  src: '...',
  controller: this.controller,
  onPageEnd: () => {
    // 触发纹理获取逻辑
  }
})

2)离屏渲染尺寸设置

BuilderNode 默认继承父容器尺寸,若需渲染超屏内容(如长截图),需显式设置大尺寸:

builderNode.setSize({ width: 2000, height: 5000 }); // 自定义宽高

3)性能优化建议

离屏渲染消耗较大,建议在后台线程执行。

大尺寸纹理可能引起内存溢出,可分段渲染(如分页截图)。

  1. 替代方案:WebView 原生截图(API 限制)

当前官方文档未开放 WebView 直接截图接口。若需简化流程,可考虑:

前端页面自渲染:通过 HTML5 Canvas 在网页内生成图像,再通过消息端口(MessagePort)传回应用侧。

系统级截图:仅适用于可视区域,无法实现离屏大图。

  1. 官方参考资料

自定义声明式节点 (BuilderNode)

HarmonyOS Next中,Web组件支持离屏渲染。通过OffscreenRenderingController可控制Web组件在后台渲染,结合PixelMap能获取渲染后的图像帧数据。具体使用createPixelMap方法捕获画面。

在HarmonyOS Next中,可以通过BuilderNode结合Web组件实现WebView的离屏渲染,并获取其纹理数据用于截图等操作。

核心方案:BuilderNode + Web组件

  1. 创建离屏的BuilderNode:使用BuilderNode.create接口创建一个离屏节点。关键是在其surfaceOptions中指定isTransparent: false(确保背景不透明)和正确的pixelFormat(如PixelFormat.RGBA_8888)。
  2. 构建Web内容:在BuilderNode的build函数中,使用Web组件加载目标网页或本地HTML。这与在常规UI中使用的Web组件一致。
  3. 渲染与获取纹理:BuilderNode在离屏渲染后,其内容会生成到关联的纹理上。可以通过BuilderNodegetTextureId()方法直接获取到其OpenGL纹理ID。
  4. 纹理处理与导出:获得纹理ID后,你可以使用OpenGL ES或图形库(如PixelMap相关API)来读取纹理的像素数据。核心步骤是:
    • 将纹理绑定到帧缓冲区(FBO)。
    • 使用glReadPixels读取像素数据到内存缓冲区。
    • 将缓冲区数据转换为PixelMap
    • 最后,通过image.PackerPixelMap编码并保存为图片文件(如PNG、JPEG)。

关于纹理数据导出的关键接口与思路

  • 获取纹理builderNode.getTextureId(): number
  • 创建PixelMap:通常需要先创建image.PixelMap对象来接收像素数据。你可以使用image.createPixelMap方法,并传入一个InitializationOptions来指定尺寸和格式。
  • 读取数据到PixelMap:一种常见做法是,利用Graphics模块的texturerender能力,或者直接通过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文档,以获取纹理操作和图片处理的具体接口参数。

回到顶部