HarmonyOS 鸿蒙Next应用需要保存图片到相册

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

HarmonyOS 鸿蒙Next应用需要保存图片到相册

应用需要保存图片到相册,怎么保存?

3 回复

可以参考如下代码

import { webview } from '@kit.ArkWeb';

import { CommonConstant as Const } from '../common/Constant';

import { BusinessError, request } from '@kit.BasicServicesKit'

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

import { fileIo as fs, fileUri, ReadOptions, WriteOptions } from '@kit.CoreFileKit';

import { buffer } from '@kit.ArkTS'

const context = getContext(this);

class SaveImageResultVo {

  errorCode: number = 0

}

let writeBufferToFile = (dirPath: string, fileName: string, buf: ArrayBuffer) => {

  if (!fs.accessSync(dirPath)) {

    // 如果文件夹不存在,则先创建文件夹

    fs.mkdirSync(dirPath)

  }

  let file = fs.openSync(`${dirPath}/${fileName}`, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)

  fs.writeSync(file.fd, buf)

  fs.closeSync(file)

}

let saveImageToApplication = async (image: string, dirPath: string, fileName: string): Promise<SaveImageResultVo> => {

  return new Promise(async (resolve: Function, reject: Function) => {

    if (!fs.accessSync(dirPath)) {

      fs.mkdirSync(dirPath)

    }

    if (image.startsWith('http')) {

      // 如果是网络图片,则下载图片

      try {

        request

          .downloadFile(context, { url: image, filePath: `${dirPath}/${fileName}` })

          .then((downloadTask) => {

            console.debug(`image => 保存图片到应用沙盒`)

            downloadTask

              .on('complete', () => {

                // 图片下载完成

                console.log('图片下载完成')

                let vo = new SaveImageResultVo

                vo.errorCode = 0

                resolve(vo)

              })

            downloadTask

              .on('fail', (err: number) => {

                console.log('fail')

                let vo = new SaveImageResultVo

                vo.errorCode = err

                resolve(vo)

              })

          })

          .catch((error: BusinessError) => {

            reject(error)

          })

      } catch (err) {

        reject(err)

      }

    } else {

      // base64图片

      let content = image

      if (image.startsWith('data:')) {

        // 如果是data:,则截取,后的数据

        content = image.split(',')[1]

      }

      try {

        const decodeBuff = buffer.from(content, 'base64').buffer

        writeBufferToFile(dirPath, fileName, decodeBuff)

        let vo = new SaveImageResultVo

        vo.errorCode = 0

        resolve(vo)

      } catch (err) {

        reject(err)

      }

    }

  })

}

let 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);

}

let saveImageToAlbum = async (path: string, title?: string, extension?: string): Promise<boolean> => {

  return new Promise(async (resolve: Function, reject: Function) => {

    try {

      let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context)

      let srcFileUri: Array<string> = [fileUri.getUriFromPath(path)]

      console.debug(`图片 uri is : ${JSON.stringify(srcFileUri)}`)

      let photoCreationConfigs: Array<photoAccessHelper.PhotoCreationConfig> = [

        {

          title: '保存图片',

          fileNameExtension: extension ? extension : 'jpg',

          photoType: photoAccessHelper.PhotoType.IMAGE,

          subtype: photoAccessHelper.PhotoSubtype.DEFAULT

        }

      ]

      let desFileUris: Array<string> = await phAccessHelper.showAssetsCreationDialog(srcFileUri, photoCreationConfigs)

      console.debug(`目标图片 uri is : ${JSON.stringify(desFileUris)}`)

      if (desFileUris.length > 0) {

        for (let index = 0; index < desFileUris.length; index++) {

          copyFileContentTo(srcFileUri[index], desFileUris[index])

        }

        resolve(true)

      } else {

        resolve(false)

      }

    } catch (err) {

      reject(err)

    }

  })

}

class LinkClass {

  async messageFromHtml(value: string) {

    let dirPath = context.cacheDir

    let fileName = 'temp2.jpg'

    if (fs.accessSync(`${dirPath}/${fileName}`)) {

      fs.rmdirSync(`${dirPath}/${fileName}`)

    }

    try {

      let result: SaveImageResultVo = await saveImageToApplication(value, dirPath, fileName)

      if (0 == result.errorCode) {

        // 图片保存成功

        console.debug(`image => 保存图片到应用沙盒成功`)

        saveImageToAlbum(`${dirPath}/${fileName}`)

          .then((result) => {

            if (result) {

              console.debug(`image => 保存图片到相册成功`)

            } else {

              console.debug(`image => 用户拒绝授权`)

            }

          })

          .catch((error: BusinessError) => {

            console.error('image => 保存图片到相册异常:')

          })

      }

    } catch (err) {

      console.error(err, 'image => 保存图片到应用沙盒异常:')

    }

  }

}

@Entry

@Component

struct WebPage {

  webController: webview.WebviewController = new webview.WebviewController();

  @State linkObj: LinkClass = new LinkClass();

  build() {

    Stack({ alignContent: Alignment.TopStart }) {

      Row() {

        Column() {

          // Web component loading H5.

          Web({ src: $rawfile('local/index.html'), controller: this.webController })

            .zoomAccess(false)

            .width(Const.WEB_CONSTANT_WIDTH)

            .aspectRatio(1)

            .margin({

              left: Const.WEB_CONSTANT_MARGIN_LEFT, right: Const.WEB_CONSTANT_MARGIN_RIGHT,

              top: Const.WEB_CONSTANT_MARGIN_TOP

            })

            .javaScriptProxy({

              object: this.linkObj,

              name: 'linkObj',

              methodList: ['messageFromHtml'],

              controller: this.webController

            })

        }

        .width('100%')

        .width('100%')

      }

    }

    .backgroundColor('#F1F3F5')

  }

}

更多关于HarmonyOS 鸿蒙Next应用需要保存图片到相册的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


如何保存图片到相册

可以使用安全控件中的保存控件,免去权限申请和权限请求等环节,获得临时授权,保存对应图片。参考代码如下:

深色代码主题
复制
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { fileIo } from '@kit.CoreFileKit';
import { common } from '@kit.AbilityKit';
import { promptAction } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';

async function savePhotoToGallery(context: common.UIAbilityContext) { let helper = photoAccessHelper.getPhotoAccessHelper(context); try { // onClick触发后10秒内通过createAsset接口创建图片文件,10秒后createAsset权限收回。 let uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, ‘jpg’); // 使用uri打开文件,可以持续写入内容,写入过程不受时间限制 let file = await fileIo.open(uri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE); // $r(‘app.media.startIcon’)需要替换为开发者所需的图像资源文件 context.resourceManager.getMediaContent($r(‘app.media.startIcon’).id, 0) .then(async value => { let media = value.buffer; // 写到媒体库文件中 await fileIo.write(file.fd, media); await fileIo.close(file.fd); promptAction.showToast({ message: ‘已保存至相册!’ }); }); } catch (error) { const err: BusinessError = error as BusinessError; console.error(Failed to save photo. Code is <span class="hljs-subst">${err.code}</span>, message is <span class="hljs-subst">${err.message}</span>); } }

@Entry @Component struct Index { build() { Row() { Column({ space: 10 }) { // $r(‘app.media.startIcon’)需要替换为开发者所需的图像资源文件 Image($r(‘app.media.startIcon’)) .height(400) .width(‘100%’)

    <span class="hljs-title class_">SaveButton</span>().<span class="hljs-title function_">onClick</span>(<span class="hljs-keyword">async</span> (<span class="hljs-attr">event</span>: <span class="hljs-title class_">ClickEvent</span>, <span class="hljs-attr">result</span>: <span class="hljs-title class_">SaveButtonOnClickResult</span>) =&gt; {
      <span class="hljs-keyword">if</span> (result === <span class="hljs-title class_">SaveButtonOnClickResult</span>.<span class="hljs-property">SUCCESS</span>) {
        <span class="hljs-keyword">const</span> <span class="hljs-attr">context</span>: common.<span class="hljs-property">UIAbilityContext</span> = <span class="hljs-title function_">getContext</span>(<span class="hljs-variable language_">this</span>) <span class="hljs-keyword">as</span> common.<span class="hljs-property">UIAbilityContext</span>;
        <span class="hljs-comment">// 免去权限申请和权限请求等环节,获得临时授权,保存对应图片</span>
        <span class="hljs-title function_">savePhotoToGallery</span>(context);
      } <span class="hljs-keyword">else</span> {
        promptAction.<span class="hljs-title function_">showToast</span>({ <span class="hljs-attr">message</span>: <span class="hljs-string">'设置权限失败!'</span> })
      }
    })
  }
  .<span class="hljs-title function_">width</span>(<span class="hljs-string">'100%'</span>)
}
.<span class="hljs-title function_">height</span>(<span class="hljs-string">'100%'</span>)
.<span class="hljs-title function_">backgroundColor</span>(<span class="hljs-number">0xF1F3F5</span>)

} }

在HarmonyOS 鸿蒙Next应用中保存图片到相册,可以使用系统提供的MediaStore API。以下是实现这一功能的基本步骤:

  1. 获取图片文件:首先,确保你已经有了需要保存的图片文件,可以是Bitmap对象或图片路径。

  2. 构建MediaStore.Images.Media.ContentValues:为图片构建合适的ContentValues对象,包括标题、描述、MIME类型、日期等信息。例如,ContentValues values = new ContentValues(); values.put(MediaStore.Images.Media.DISPLAY_NAME, "image.jpg"); values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");

  3. 插入MediaStore:使用ContentResolver将ContentValues插入到MediaStore中,这将返回图片的URI。Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

  4. 写入图片数据:通过OutputStream将图片数据写入到上述URI指向的位置。try (OutputStream outputStream = getContentResolver().openOutputStream(uri)) { bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream); }

  5. 通知媒体存储:通常系统会自动通知,但在某些情况下,你可能需要手动通知媒体存储更新。

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

回到顶部