鸿蒙NEXT开发组件截图和窗口截图工具类SnapshotUtil(ArkTs)

发布于:2025-05-01 ⋅ 阅读:(34) ⋅ 点赞:(0)
import { image } from '@kit.ImageKit';
import { componentSnapshot, window } from '@kit.ArkUI';
import { AppUtil } from './AppUtil';
import { ArrayUtil } from './ArrayUtil';

/**
 * 组件截图和窗口截图工具类
 * @author 鸿蒙布道师
 * @since 2025/04/28
 */
export class SnapshotUtil {
  private static callbacks: VoidCallback[] = []; // 缓存的截图回调列表。
  private static snapshotCallback: VoidCallback | undefined; // 全局的截图监听回调。

  /**
   * 获取已加载组件的截图(异步方式)。
   * @param id 目标组件的唯一标识。
   * @param options 截图相关的自定义参数。
   * @returns 返回 Promise<image.PixelMap> 截图结果。
   */
  static async get(id: string, options?: componentSnapshot.SnapshotOptions): Promise<image.PixelMap> {
    if (!id) {
      throw new Error('Component ID cannot be empty.');
    }
    return componentSnapshot.get(id, options);
  }

  /**
   * 获取已加载组件的截图(同步方式)。
   * @param id 目标组件的唯一标识。
   * @param options 截图相关的自定义参数。
   * @returns 返回 Promise<image.PixelMap> 截图结果。
   */
  static getSync(id: string, options?: componentSnapshot.SnapshotOptions): Promise<image.PixelMap> {
    if (!id) {
      throw new Error('Component ID cannot be empty.');
    }
    return componentSnapshot.get(id, options);
  }

  /**
   * 渲染 CustomBuilder 自定义组件并获取其截图。
   * @param builder 自定义组件构建函数。
   * @param delay 触发截图指令的延迟时间(默认值:300 毫秒)。
   * @param checkImageStatus 是否校验图片解码状态(默认值:false)。
   * @param options 截图相关的自定义参数。
   * @returns 返回 Promise<image.PixelMap> 截图结果。
   */
  static createFromBuilder(
    builder: CustomBuilder,
    delay: number = 300,
    checkImageStatus: boolean = false,
    options?: componentSnapshot.SnapshotOptions
  ): Promise<image.PixelMap> {
    if (!builder) {
      throw new Error('CustomBuilder cannot be undefined.');
    }
    return componentSnapshot.createFromBuilder(builder, delay, checkImageStatus, options);
  }

  /**
   * 获取窗口截图(异步方式)。
   * @param windowClass 窗口实例(默认为主窗口)。
   * @returns 返回 Promise<image.PixelMap> 截图结果。
   */
  static async snapshot(windowClass?: window.Window): Promise<image.PixelMap> {
    const targetWindow = windowClass ?? AppUtil.getMainWindow();
    if (!targetWindow) {
      throw new Error('Target window is not available.');
    }
    return targetWindow.snapshot();
  }

  /**
   * 开启系统截屏事件的监听。
   * @param callback 截图回调函数。
   */
  static onSnapshotListener(callback: VoidCallback): void {
    if (!callback) {
      throw new Error('Callback function cannot be undefined.');
    }

    if (!ArrayUtil.contains(SnapshotUtil.callbacks, callback)) {
      SnapshotUtil.callbacks.push(callback);
    }

    if (!SnapshotUtil.snapshotCallback) {
      SnapshotUtil.snapshotCallback = () => {
        SnapshotUtil.callbacks.forEach((cb) => cb?.());
      };
      AppUtil.getMainWindow()?.on('screenshot', SnapshotUtil.snapshotCallback);
    }
  }

  /**
   * 关闭系统截屏事件的监听。
   * @param callback 要移除的监听回调(如果为空,则移除所有监听)。
   */
  static removeSnapshotListener(callback?: VoidCallback): void {
    if (callback) {
      ArrayUtil.remove(SnapshotUtil.callbacks, callback);
    } else {
      SnapshotUtil.callbacks = [];
    }

    if (SnapshotUtil.callbacks.length === 0) {
      const mainWindow = AppUtil.getMainWindow();
      if (mainWindow) {
        if (SnapshotUtil.snapshotCallback) {
          mainWindow.off('screenshot', SnapshotUtil.snapshotCallback);
        } else {
          mainWindow.off('screenshot');
        }
        SnapshotUtil.snapshotCallback = undefined;
      }
    }
  }

  /**
   * 检查窗口是否可用。
   * @param windowClass 窗口实例。
   * @returns 如果窗口可用返回 true,否则返回 false。
   */
  private static isWindowAvailable(windowClass?: window.Window): boolean {
    return !!windowClass || !!AppUtil.getMainWindow();
  }
}
代码如下:

import { image } from '@kit.ImageKit';
import { componentSnapshot, window } from '@kit.ArkUI';
import { AppUtil } from './AppUtil';
import { ArrayUtil } from './ArrayUtil';

/**
 * 组件截图和窗口截图工具类
 * @author 鸿蒙布道师
 * @since 2025/04/28
 */
export class SnapshotUtil {
  private static callbacks: VoidCallback[] = []; // 缓存的截图回调列表。
  private static snapshotCallback: VoidCallback | undefined; // 全局的截图监听回调。

  /**
   * 获取已加载组件的截图(异步方式)。
   * @param id 目标组件的唯一标识。
   * @param options 截图相关的自定义参数。
   * @returns 返回 Promise<image.PixelMap> 截图结果。
   */
  static async get(id: string, options?: componentSnapshot.SnapshotOptions): Promise<image.PixelMap> {
    if (!id) {
      throw new Error('Component ID cannot be empty.');
    }
    return componentSnapshot.get(id, options);
  }

  /**
   * 获取已加载组件的截图(同步方式)。
   * @param id 目标组件的唯一标识。
   * @param options 截图相关的自定义参数。
   * @returns 返回 Promise<image.PixelMap> 截图结果。
   */
  static getSync(id: string, options?: componentSnapshot.SnapshotOptions): Promise<image.PixelMap> {
    if (!id) {
      throw new Error('Component ID cannot be empty.');
    }
    return componentSnapshot.get(id, options);
  }

  /**
   * 渲染 CustomBuilder 自定义组件并获取其截图。
   * @param builder 自定义组件构建函数。
   * @param delay 触发截图指令的延迟时间(默认值:300 毫秒)。
   * @param checkImageStatus 是否校验图片解码状态(默认值:false)。
   * @param options 截图相关的自定义参数。
   * @returns 返回 Promise<image.PixelMap> 截图结果。
   */
  static createFromBuilder(
    builder: CustomBuilder,
    delay: number = 300,
    checkImageStatus: boolean = false,
    options?: componentSnapshot.SnapshotOptions
  ): Promise<image.PixelMap> {
    if (!builder) {
      throw new Error('CustomBuilder cannot be undefined.');
    }
    return componentSnapshot.createFromBuilder(builder, delay, checkImageStatus, options);
  }

  /**
   * 获取窗口截图(异步方式)。
   * @param windowClass 窗口实例(默认为主窗口)。
   * @returns 返回 Promise<image.PixelMap> 截图结果。
   */
  static async snapshot(windowClass?: window.Window): Promise<image.PixelMap> {
    const targetWindow = windowClass ?? AppUtil.getMainWindow();
    if (!targetWindow) {
      throw new Error('Target window is not available.');
    }
    return targetWindow.snapshot();
  }

  /**
   * 开启系统截屏事件的监听。
   * @param callback 截图回调函数。
   */
  static onSnapshotListener(callback: VoidCallback): void {
    if (!callback) {
      throw new Error('Callback function cannot be undefined.');
    }

    if (!ArrayUtil.contains(SnapshotUtil.callbacks, callback)) {
      SnapshotUtil.callbacks.push(callback);
    }

    if (!SnapshotUtil.snapshotCallback) {
      SnapshotUtil.snapshotCallback = () => {
        SnapshotUtil.callbacks.forEach((cb) => cb?.());
      };
      AppUtil.getMainWindow()?.on('screenshot', SnapshotUtil.snapshotCallback);
    }
  }

  /**
   * 关闭系统截屏事件的监听。
   * @param callback 要移除的监听回调(如果为空,则移除所有监听)。
   */
  static removeSnapshotListener(callback?: VoidCallback): void {
    if (callback) {
      ArrayUtil.remove(SnapshotUtil.callbacks, callback);
    } else {
      SnapshotUtil.callbacks = [];
    }

    if (SnapshotUtil.callbacks.length === 0) {
      const mainWindow = AppUtil.getMainWindow();
      if (mainWindow) {
        if (SnapshotUtil.snapshotCallback) {
          mainWindow.off('screenshot', SnapshotUtil.snapshotCallback);
        } else {
          mainWindow.off('screenshot');
        }
        SnapshotUtil.snapshotCallback = undefined;
      }
    }
  }

  /**
   * 检查窗口是否可用。
   * @param windowClass 窗口实例。
   * @returns 如果窗口可用返回 true,否则返回 false。
   */
  private static isWindowAvailable(windowClass?: window.Window): boolean {
    return !!windowClass || !!AppUtil.getMainWindow();
  }
}