HarmonyOS 鸿蒙Next开发 / ArkTS / 组件截图 / PixelMap / 长截图拼接 / UI截图

HarmonyOS 鸿蒙Next开发 / ArkTS / 组件截图 / PixelMap / 长截图拼接 / UI截图 在鸿蒙开发中,经常会遇到这样一个需求:

把多个不在同一个容器里的组件截图,按顺序拼接成一张长图

官方示例大多是「滚动列表长截图」,但多组件静态拼接几乎没有完整范例。

下面分享一个可直接复用的多组件拼接截图方案,核心思路专注在 PixelMap 的读取与合成。

一、整体思路说明

  1. 逐个组件截图
    • 使用 getComponentSnapshot().getSync
    • 拿到每个组件对应的 PixelMap
  2. 读取像素数据
    • 通过 readPixelsToBufferSync 将像素读入 ArrayBuffer
    • 封装为 image.PositionArea
  3. 统一创建目标 PixelMap
    • 高度 = 所有组件高度之和
    • 宽度 = 所有组件的最大宽度
  4. 按顺序写入像素
    • 使用 writePixelsSync
    • 通过 y 偏移量逐段往下写,实现“拼接”

整个过程不做 canvas 绘制、不做 bitmap 转换,完全是底层像素级拼接,性能和清晰度都很稳。

二、核心代码实现

export class SnapshotManager {

  /**
   * 拼接多个指定 ID 的组件为一张长图
   * @param uiContext UIContext
   * @param ids 组件 ID 数组(顺序即拼接顺序)
   */
  static concatComponentSnapshots(
    uiContext: UIContext,
    ids: string[]
  ): image.PixelMap {
    let areaArray: image.PositionArea[] = []
    let totalHeight = 0
    let maxWidth = 0
    // 1. 逐个组件截图并读取像素
    for (const id of ids) {
      const pm = uiContext
        .getComponentSnapshot()
        .getSync(id, { waitUntilRenderFinished: true })
      const info = pm.getImageInfoSync()
      const bytes = pm.getPixelBytesNumber()
      const buffer = new ArrayBuffer(bytes)
      // 读取像素
      pm.readPixelsToBufferSync(buffer)
      // 封装为 PositionArea
      const area: image.PositionArea = {
        pixels: buffer,
        offset: 0,
        stride: info.size.width * 4,
        region: {
          x: 0,
          y: 0,
          size: {
            width: info.size.width,
            height: info.size.height
          }
        }
      }
      areaArray.push(area)
      totalHeight += info.size.height
      maxWidth = Math.max(maxWidth, info.size.width)
      // 释放资源
      pm.release()
    }
    // 2. 创建目标长图 PixelMap
    const longPixelMap = image.createPixelMapSync({
      editable: true,
      pixelFormat: 4, // RGBA_8888
      size: {
        width: maxWidth,
        height: totalHeight
      }
    })
    // 3. 按顺序写入像素数据
    let currentY = 0
    for (const area of areaArray) {
      const writeArea: image.PositionArea = {
        pixels: area.pixels,
        offset: 0,
        stride: area.stride,
        region: {
          x: 0,
          y: currentY,
          size: area.region.size
        }
      }
      longPixelMap.writePixelsSync(writeArea)
      currentY += area.region.size.height
    }
    return longPixelMap
  }
}

三、最后

需要传入截图组件的必要ID即可获得长截图后的PixelMap


更多关于HarmonyOS 鸿蒙Next开发 / ArkTS / 组件截图 / PixelMap / 长截图拼接 / UI截图的实战教程也可以访问 https://www.itying.com/category-93-b0.html

3 回复

更多关于HarmonyOS 鸿蒙Next开发 / ArkTS / 组件截图 / PixelMap / 长截图拼接 / UI截图的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS中,使用ArkTS的@ohos.screenshot API可实现组件截图,获取PixelMap对象。长截图拼接需通过PixelMapreadPixelsToBuffer方法读取像素数据,再使用createPixelMap合并多个PixelMap。UI截图可通过WindowgetTopWindow获取窗口后调用screenshot方法完成。

这是一个非常专业且高效的解决方案,直接操作 PixelMap 进行像素级拼接,避免了不必要的渲染开销,确保了性能和图像质量。你的代码清晰地展示了 getComponentSnapshotreadPixelsToBufferSyncwritePixelsSync 这几个核心 API 的配合使用,为处理静态多组件截图拼接需求提供了最佳实践。

方案优势分析:

  1. 性能优异:全程在 Native 层处理像素数据,无需经过 Canvas 或多次位图转换,内存和计算效率高。
  2. 保真度高:直接读写原始 PixelMap 数据,避免了因格式转换可能带来的图像质量损失。
  3. 逻辑清晰PositionArea 的运用准确控制了每一段组件图像的写入位置,拼接顺序精准。

关键点说明:

  • pixelFormat: 4 对应 RGBA_8888,这是最常用的格式,确保了颜色的完整性和兼容性。
  • 在循环中及时调用 pm.release() 释放每个临时 PixelMap 是关键,能有效管理内存,防止泄漏。
  • stride 的计算(width * 4)是正确的,因为 RGBA_8888 格式每个像素占用 4 个字节。

一个潜在优化点(非必须): 如果待拼接的组件宽度不一致,当前方案是以最大宽度创建画布,宽度较小的组件区域在拼接后其右侧区域将是透明的(Alpha通道为0)。如果需求是“紧密拼接”或需要背景色,可以在创建目标 PixelMap 后,先调用 writePixelsSync 写入一个纯色(如白色)的 PositionArea 进行填充,然后再按顺序写入组件像素。

此方案完整、可用,是解决鸿蒙应用内非滚动组件长截图拼接的推荐实现方式。

回到顶部