HarmonyOS 鸿蒙Next图片保存问题

发布于 1周前 作者 itying888 来自 鸿蒙OS

HarmonyOS 鸿蒙Next图片保存问题

目前已经获取了一个PixelMap类型的图片数据,如何在不获取文件读写权限的情况下,使用showAssetsCreationDialog,api将图片保存到本地相册,可以给一个demo么

3 回复

可以参考下这篇博文:

HarmonyOS Next 屏幕截图 + 保存图片到系统相册 代码分享

https://developer.huawei.com/consumer/cn/blog/topic/03166979994620019

import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { common } from '@kit.AbilityKit';
import fileUri from '@ohos.file.fileuri';
import json from '@ohos.util.json';
import fs, { ReadOptions, WriteOptions } from '@ohos.file.fs';

@Entry @Component struct Test { filePath: string = ‘’;

build() { Column() { Button(“复制文件到沙箱”) .onClick(() => { console.log(‘开始复制文件到沙箱’) this.copyFile() console.log(‘复制文件到沙箱完成’) }) Button(‘沙箱文件保存到相册’) .onClick(() => { console.log(‘开始沙箱文件保存到相册’) this.syncToSysAlbum(photoAccessHelper.PhotoType.IMAGE, ‘png’, this.filePath) }) Button(‘沙箱文件保存到相册’) .onClick(() => { console.log(‘开始沙箱文件保存到相册’) this.example() }) } .height(‘100%’) .width(‘100%’) }

copyFile() { console.log(“开发复制文件”) let context = getContext(this) as common.UIAbilityContext; let srcFileDescriptor = context.resourceManager.getRawFdSync(‘background.png’); //这里填rawfile文件夹下的文件名(包括后缀) let stat = fs.statSync(srcFileDescriptor.fd) console.log(stat isFile:${stat.isFile()});

<span class="hljs-comment">// 通过UIAbilityContext获取沙箱地址filesDir,以Stage模型为例</span>
<span class="hljs-keyword">let</span> pathDir = context.filesDir;
console.log(<span class="hljs-string">"沙箱文件目录路径:"</span>, pathDir)
<span class="hljs-keyword">let</span> dstPath = pathDir + <span class="hljs-string">"/background.png"</span>;
<span class="hljs-keyword">this</span>.filePath = fileUri.getUriFromPath(dstPath)
console.log(<span class="hljs-string">"沙箱文件URI"</span> + <span class="hljs-keyword">this</span>.filePath);
<span class="hljs-keyword">let</span> dest = fs.openSync(dstPath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE)
<span class="hljs-keyword">let</span> bufsize = <span class="hljs-number">4096</span>
<span class="hljs-keyword">let</span> buf = <span class="hljs-keyword">new</span> <span class="hljs-built_in">ArrayBuffer</span>(bufsize)
<span class="hljs-keyword">let</span> off = <span class="hljs-number">0</span>, len = <span class="hljs-number">0</span>, readedLen = <span class="hljs-number">0</span>
<span class="hljs-keyword">while</span> (len = fs.readSync(srcFileDescriptor.fd, buf, { offset: srcFileDescriptor.offset + off, length: bufsize })) {
  readedLen += len
  fs.writeSync(dest.fd, buf, { offset: off, length: len })
  off = off + len
  <span class="hljs-keyword">if</span> ((srcFileDescriptor.length - readedLen) &lt; bufsize) {
    bufsize = srcFileDescriptor.length - readedLen
  }
}
fs.close(dest.fd)

}

async syncToSysAlbum(fileType: photoAccessHelper.PhotoType, extension: string, …filePath: string[]) { //此处获取的phAccessHelper实例为全局对象,后续使用到phAccessHelper的地方默认为使用此处获取的对象,如未添加此段代码报phAccessHelper未定义的错误请自行添加 let context = getContext(this); let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context); try { const srcFileUris: string[] = [] filePath.forEach((path) => { srcFileUris.push(path) }) const config: photoAccessHelper.PhotoCreationConfig[] = [] config.push({ title: ‘background’, // 可选 fileNameExtension: extension, photoType: fileType, subtype: photoAccessHelper.PhotoSubtype.DEFAULT, // 可选 }) console.log(“syncToSysAlarm fileUri:” + json.stringify(srcFileUris) + “,config:” + json.stringify(config))

  <span class="hljs-keyword">const</span> desFileUris = await phAccessHelper.showAssetsCreationDialog(srcFileUris, config)

  console.debug(`目标图片 uri is : ${<span class="hljs-built_in">JSON</span>.stringify(desFileUris)}`)

  <span class="hljs-keyword">if</span> (desFileUris.length &gt; <span class="hljs-number">0</span>) {
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> index = <span class="hljs-number">0</span>; index &lt; desFileUris.length; index++) {
      <span class="hljs-keyword">this</span>.copyFileContentTo(srcFileUris[index], desFileUris[index])
    }
  }
} <span class="hljs-keyword">catch</span> (err) {
  console.log(<span class="hljs-string">"syncToSysAlarm filePath:"</span> + filePath + <span class="hljs-string">",error:"</span> + json.stringify(err))
}

}

async example() { console.info(‘ShowAssetsCreationDialogDemo.’); let context = getContext(this) as common.UIAbilityContext let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context); try { // 获取需要保存到媒体库的位于应用沙箱的图片/视频uri // let srcFileUris: Array = [ // // 实际场景请使用真实的uri // // ‘file://com.example.test35/data/storage/el2/base/haps/entry/files/background.png’ // this.filePath // ]; let srcFileUri: string[] = [this.filePath] console.debug("图片 uri is : ", JSON.stringify(srcFileUri)) let photoCreationConfigs: Array<photoAccessHelper.PhotoCreationConfig> = [ { title: ‘background’, // 可选 fileNameExtension: ‘png’, photoType: photoAccessHelper.PhotoType.IMAGE, subtype: photoAccessHelper.PhotoSubtype.DEFAULT, // 可选 } ]; console.log(“syncToSysAlarm fileUri:” + JSON.stringify(srcFileUri) + “,config:” + JSON.stringify(photoCreationConfigs)) let desFileUris: Array<string> = await phAccessHelper.showAssetsCreationDialog(srcFileUri, photoCreationConfigs); console.debug(目标图片 uri is : ${<span class="hljs-built_in">JSON</span>.stringify(desFileUris)})

  <span class="hljs-keyword">if</span> (desFileUris.length &gt; <span class="hljs-number">0</span>) {
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> index = <span class="hljs-number">0</span>; index &lt; desFileUris.length; index++) {
      <span class="hljs-keyword">this</span>.copyFileContentTo(srcFileUri[index], desFileUris[index])
    }
  }
} <span class="hljs-keyword">catch</span> (err) {
  console.error(<span class="hljs-string">'showAssetsCreationDialog failed, errCode is '</span> + err.code + <span class="hljs-string">', errMsg is '</span> + err.message);
}

}

/* @param srcFilePath 源文件路径 @param destFilePath 目标文件路径 */ private copyFileContentTo(srcFilePath: string, destFilePath: string) { let srcFile = fs.openSync(srcFilePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE) let destFile = fs.openSync(destFilePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE) // 读取源文件内容并写入至目的文件 let bufSize = 4096; let readSize = 0; let buf = new ArrayBuffer(bufSize); let readOptions: ReadOptions = { offset: readSize, length: bufSize }; let readLen = fs.readSync(srcFile.fd, buf, readOptions); while (readLen > 0) { readSize += readLen; let writeOptions: WriteOptions = { length: readLen }; fs.writeSync(destFile.fd, buf, writeOptions); readOptions.offset = readSize; readLen = fs.readSync(srcFile.fd, buf, readOptions); } // 关闭文件 fs.closeSync(srcFile); fs.closeSync(destFile); } }

可以参考这个demo

针对HarmonyOS 鸿蒙Next图片保存问题,以下是一些专业的解决方案:

首先,确保你已有图片的PixelMap对象或图片数据(如ArrayBuffer)。然后,使用image.createImagePacker()将PixelMap对象压缩为JPEG格式的图像数据。

接下来,需要将压缩后的图像数据保存到设备的临时或缓存目录中。这可以通过文件I/O操作完成,具体步骤包括:

  1. 使用fs模块创建文件并写入数据。
  2. 利用photoAccessHelper.showAssetsCreationDialog() API将图片添加到系统相册,此API需要传入源文件的URI和图片创建配置(如文件名、类型等)。

请注意,HarmonyOS 鸿蒙Next对应用访问媒体库的权限进行了严格限制,以保护用户隐私。若应用需保存图片到相册,需申请ohos.permission.WRITE_IMAGEVIDEO权限,但该权限的申请场景受限。若应用不符合这些受限权限场景,则无法直接通过API保存图片到相册。此时,可考虑使用SaveButton安全控件作为替代方案。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部