HarmonyOS鸿蒙Next中ArkUI如何将Component直接离屏渲染成图像用于保存相册?

HarmonyOS鸿蒙Next中ArkUI如何将Component直接离屏渲染成图像用于保存相册? 怎样才能实现以下Swift中等价的能力?

// 生成离屏 UIView 的截图

func captureOffscreenView(_ view: UIView) -> UIImage? { view.layoutIfNeeded() let renderer = UIGraphicsImageRenderer(size: view.bounds.size) let image = renderer.image { context in view.drawHierarchy(in: view.bounds, afterScreenUpdates: true) } return image }


更多关于HarmonyOS鸿蒙Next中ArkUI如何将Component直接离屏渲染成图像用于保存相册?的实战教程也可以访问 https://www.itying.com/category-93-b0.html

5 回复

【解决方案】

[@ohos.arkui.componentSnapshot](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-arkui-componentsnapshot)模块提供了获取组件截图的能力,组件截图只能够截取组件大小的区域。对于截取的图片,可以使用媒体文件管理服务保存至相册。组件截图的示例代码如下:点击SaveButton后将组件截图保存至相册,在实际开发中需要获取创建媒体资源的权限。

import { componentSnapshot } from '@kit.ArkUI';
import { image } from '@kit.ImageKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import fs from '[@ohos](/user/ohos).file.fs';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct ComponentSnapshotPage {
  @State pixmap: image.PixelMap | null = null

  build() {
    Column({ space: FlexAlign.SpaceBetween }) {
      SaveButton({ icon: SaveIconStyle.LINES, buttonType: ButtonType.Circle })
        .backgroundColor(Color.Gray)
        .onClick(async (event: ClickEvent, result: SaveButtonOnClickResult) => {
          if (result == SaveButtonOnClickResult.SUCCESS) {
            // 获取名为"hello"组件的截图快照
            componentSnapshot.get("hello", async (error: Error, pixmap: image.PixelMap) => {
              this.pixmap = pixmap
              // 配置图片编码参数
              let packOpts: image.PackingOption = { format: "image/png", quality: 100 };
              const imagePackerApi: image.ImagePacker = image.createImagePacker();
              // 将PixelMap编码为PNG格式的二进制数据
              imagePackerApi.packToData(pixmap, packOpts).then(async (buffer: ArrayBuffer) => {
                try {
                  // 保存至相册中
                  const context: Context = this.getUIContext().getHostContext() as Context;
                  let helper = photoAccessHelper.getPhotoAccessHelper(context)
                  let uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'png')
                  let file = await fs.open(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
                  await fs.write(file.fd, buffer);
                  await fs.close(file.fd);
                } catch (error) {
                  console.error(`error is ${error}`)
                }
              }).catch((error: BusinessError) => {
                console.error(`Failed to pack the image. ${error.code} ${error.name} ${error.message}`);
              })
            })
          }
        })
      Row() {
        Text('这是截图内容')
          .height(100)
          .fontSize(16)
          .fontColor(Color.Blue)
      }
      .width('100%')
      .height('100%')
      .justifyContent(FlexAlign.Center)
      .id('hello')
      .backgroundColor("#00000000") 
    }
  }
}

更多关于HarmonyOS鸿蒙Next中ArkUI如何将Component直接离屏渲染成图像用于保存相册?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


如何解决“无法连接到打印机0x0000011b”错误

错误原因

此错误通常由Windows更新引起,特别是2021年9月及之后发布的更新。这些更新改变了Windows与打印服务器之间的认证方式,导致部分打印机连接失败。

解决方案

方法一:卸载最近的Windows更新(推荐)

  1. 打开“设置” > “更新和安全” > “查看更新历史记录”
  2. 点击“卸载更新”
  3. 查找并卸载以下更新之一:
    • KB5005569
    • KB5005573
    • KB5005568
    • KB5005566
    • KB5005565
  4. 重启计算机

方法二:修改注册表(临时解决方案)

警告:修改注册表有风险,请先备份注册表。

  1. Win + R,输入 regedit,打开注册表编辑器
  2. 导航到:HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Print
  3. 右键点击“Print”键,选择“新建” > “DWORD (32位)值”
  4. 命名为:RpcAuthnLevelPrivacyEnabled
  5. 双击新建的值,将数值数据设置为 0
  6. 重启计算机

方法三:通过组策略禁用打印后台处理程序

  1. Win + R,输入 gpedit.msc
  2. 导航到:计算机配置 > 管理模板 > 打印机
  3. 找到“配置RPC连接设置”
  4. 选择“已启用”,将“RPC身份验证协议”设置为“无”
  5. 应用并重启

方法四:重新安装打印机驱动

  1. 打开“控制面板” > “设备和打印机”
  2. 右键点击有问题的打印机,选择“删除设备”
  3. 重新添加打印机:
    • 点击“添加打印机”
    • 选择“我需要的打印机不在列表中”
    • 使用TCP/IP地址或主机名添加
    • 安装最新的驱动程序

预防措施

  1. 暂停Windows更新,直到微软发布永久修复
  2. 定期备份注册表
  3. 考虑使用打印机的USB连接替代网络连接

注意事项

  • 如果使用域环境,建议在域控制器上应用注册表修改
  • 企业用户应与IT部门协调解决方案
  • 关注微软官方公告,获取最新修复信息

如果以上方法均无效,建议联系打印机厂商技术支持或微软客服获取进一步帮助。

在HarmonyOS Next中,使用ArkUI的PixelMapOffscreenCanvas进行离屏渲染。通过CanvasRenderingContext2D绘制Component,然后调用getPixelMap获取图像数据。最后使用@ohos.multimedia.image@ohos.file.photoAccessHelper将PixelMap保存至相册。

在HarmonyOS Next的ArkUI中,可以通过@Componentdraw方法结合CanvasRenderingContext2D实现离屏渲染,并将生成的PixelMap保存至相册。

核心步骤如下:

  1. 获取组件尺寸与创建离屏Canvas:使用组件的onAreaChange回调获取其布局完成后的尺寸。创建一个与组件同尺寸的离屏CanvasRenderingContext2D上下文。
  2. 自定义绘制命令:在CanvasRenderingContext2D上,通过调用其API(如fillRectdrawImage等)或更关键地,执行目标Component自身的draw方法,将组件的视觉内容绘制到离屏画布上。
  3. 生成PixelMap:通过CanvasRenderingContext2DtransferToImageBitmap方法获取ImageBitmap,再转换为PixelMap对象。
  4. 保存至相册:使用@ohos.file.photoAccessHelper接口将PixelMap保存为图片文件。

关键代码示例:

import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { image } from '@kit.ImageKit';

// 1. 在自定义Component的aboutToAppear或按钮事件中,获取组件尺寸后
private offscreenContext: CanvasRenderingContext2D | null = null;
private myComponentSize: Size = { width: 0, height: 0 };

// 假设通过onAreaChange获得尺寸
onAreaChange(oldArea: Area, newArea: Area) {
  this.myComponentSize = { width: newArea.width, height: newArea.height };
  this.initOffscreenCanvas();
}

private initOffscreenCanvas() {
  // 创建离屏Canvas上下文
  this.offscreenContext = new CanvasRenderingContext2D(this.myComponentSize);
}

// 2. 执行离屏渲染
private async captureComponent() {
  if (!this.offscreenContext) {
    return;
  }
  // 清空画布
  this.offscreenContext.clearRect(0, 0, this.myComponentSize.width, this.myComponentSize.height);

  // **关键:调用你需要截图的那个Component的draw方法,将其绘制到离屏上下文**
  // 例如,假设你的组件有一个自定义的draw逻辑,或者你可以直接绘制UI描述
  // 这里需要你根据实际组件的绘制命令来调用。如果是简单图形,可直接使用offscreenContext的API。
  // 如果是复杂组件,可能需要递归或调用其render方法。
  // 示例:绘制一个矩形(替代你的组件内容)
  this.offscreenContext.fillStyle = '#FF0000';
  this.offscreenContext.fillRect(0, 0, this.myComponentSize.width, this.myComponentSize.height);

  // 3. 生成PixelMap
  const imageBitmap: image.ImageBitmap = this.offscreenContext.transferToImageBitmap();
  const pixelMap: image.PixelMap = await image.createPixelMapFromImageBitmap(imageBitmap);

  // 4. 保存到相册
  await this.savePixelMapToAlbum(pixelMap);
}

// 保存PixelMap到相册的辅助方法
private async savePixelMapToAlbum(pixelMap: image.PixelMap) {
  try {
    const photoAccessHelper = photoAccessHelper.getPhotoAccessHelper(this.context);
    const testFileName = `ArkUI_Capture_${Date.now()}.jpg`;
    const photoUri = await photoAccessHelper.createAsset(testFileName);

    const imagePacker = image.createImagePacker();
    const packOptions: image.PackingOption = {
      format: 'image/jpeg', // 或 'image/png'
      quality: 100 // 质量参数
    };
    const arrayBuffer: ArrayBuffer = await imagePacker.packing(pixelMap, packOptions);

    // 将ArrayBuffer写入文件
    const fs = require('@ohos.file.fs');
    const file = await fs.open(photoUri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
    await fs.write(file.fd, arrayBuffer);
    await fs.close(file.fd);

    console.info('Image saved to album successfully.');
  } catch (err) {
    console.error(`Failed to save image: ${err.message}`);
  }
}

重要说明:

  • 直接绘制Component:上述示例中,this.offscreenContext.fillRect(...)部分需要替换为你目标Component的实际绘制命令。如果组件是自定义的,且其draw方法接收一个CanvasRenderingContext2D参数,你可以直接调用yourComponent.draw(this.offscreenContext)。对于系统内置组件或复杂组合组件,可能需要更复杂的遍历或渲染树截图方案。
  • 权限:保存到相册需要申请相应的媒体存储权限(ohos.permission.READ_IMAGEVIDEOohos.permission.WRITE_IMAGEVIDEO),并在module.json5中配置。
  • 性能:离屏渲染和PixelMap操作可能涉及较大内存开销,建议对图像尺寸进行合理控制,并在操作完成后及时释放资源(如pixelMap.release())。

这种方法提供了将ArkUI组件渲染为图像并保存的基础能力,具体实现需根据组件类型和复杂度进行调整。

回到顶部