SaveNetWorkPictures.ets 7.39 KB
/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import http from '@ohos.net.http';
import ResponseCode from '@ohos.net.http';
import { image } from '@kit.ImageKit';
import { BusinessError } from '@ohos.base';
import common from '@ohos.app.ability.common';
import photoAccessHelper from '@ohos.file.photoAccessHelper';
import fs from '@ohos.file.fs';
import promptAction from '@ohos.promptAction';
import picker from '@ohos.file.picker';
import { taskpool } from '@kit.ArkTS';
import { httpRequest } from '../utils/httpRequest';


/**
 * 实现步骤:
 * 点击上部“下载”按钮进入”下载网络图片到手机相册”场景示例;点击下部“下载到指定路径”按钮进入”下载文件到指定用户目录”场景示例,
 * 从而实现手机相册并进行网络图片的下载和保存。
 * photoAccessHelper参考文档:
 * https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-photoaccesshelper
 * saveButton参考文档
 * https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/savebutton-0000001820999677
 */
@Concurrent
async function getPicture(imageUrl: string): Promise<ArrayBuffer> {
  let ret: ArrayBuffer = await new Promise((resolve, reject) => {
    httpRequest.httpRequestInStream(imageUrl, (res: ArrayBuffer) => {
      resolve(res); // 成功时解析Promise
    }, () => {
      // 下载失败时弹窗提示检查网络
      promptAction.showToast({
        message: $r('app.string.image_request_fail'),
        duration: 2000
      });
      reject(new Error('Image download failed')); // 失败时拒绝Promise
    });
  });
  return ret
}

@Component
export struct SaveNetWorkPictures {
  @State image: PixelMap | undefined = undefined;
  @State photoAccessHelper: photoAccessHelper.PhotoAccessHelper | undefined = undefined; // 相册模块管理实例
  @State imageBuffer: ArrayBuffer | undefined = undefined; // 图片ArrayBuffer
  // @Prop @Watch('onChangeUrl') url: string = ''
  @Prop @Watch('onChangeUrl') url: string = ''

  /**
   * 通过http的request方法从网络下载图片资源
   */
  async getPicture() {
    http.createHttp()// 显示网络图片的地址
      // .request('https://gitee.com/harmonyos-cases/cases/raw/master/CommonAppDevelopment/feature/variablewatch/src/main/resources/base/media/variablewatch_grape.png',
      // .request('https://cdnjdphoto.aikan.pdnews.cn/zhbj-20240830/image/content/4d61839662044ac796ec7331a90da5d8.jpg',
      .request(this.url,
        (error: BusinessError, data: http.HttpResponse) => {
          if (error) {
            // 下载失败时弹窗提示检查网络,不执行后续逻辑
            promptAction.showToast({
              message: '下载失败',
              duration: 2000
            })
            return;
          }
          this.transcodePixelMap(data);
          // 判断网络获取到的资源是否为ArrayBuffer类型
          if (data.result instanceof ArrayBuffer) {
            this.imageBuffer = data.result as ArrayBuffer;
          }
        }
      )
  }

  /**
   * 使用createPixelMap将ArrayBuffer类型的图片装换为PixelMap类型
   * @param data:网络获取到的资源
   */
  transcodePixelMap(data: http.HttpResponse) {
    if (ResponseCode.ResponseCode.OK === data.responseCode) {
      const imageData: ArrayBuffer = data.result as ArrayBuffer;
      // 通过ArrayBuffer创建图片源实例。
      const imageSource: image.ImageSource = image.createImageSource(imageData);
      const options: image.InitializationOptions = {
        'alphaType': 0, // 透明度
        'editable': false, // 是否可编辑
        'pixelFormat': 3, // 像素格式
        'scaleMode': 1, // 缩略值
        'size': { height: 50, width: 50 }
      }; // 创建图片大小

      // 通过属性创建PixelMap
      imageSource.createPixelMap(options).then((pixelMap: PixelMap) => {
        this.image = pixelMap;
      });
    }
  }

  /**
   * 保存ArrayBuffer到图库
   * @param buffer:图片ArrayBuffer
   * @returns
   */
  async saveImage(buffer: ArrayBuffer | string): Promise<void> {
    const context = getContext(this) as common.UIAbilityContext; // 获取getPhotoAccessHelper需要的context
    const helper = photoAccessHelper.getPhotoAccessHelper(context); // 获取相册管理模块的实例
    const uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg'); // 指定待创建的文件类型、后缀和创建选项,创建图片或视频资源
    const file = await fs.open(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
    await fs.write(file.fd, buffer);
    await fs.close(file.fd);
  }

  /**
   * 保存ArrayBuffer到用户选择的路径
   * @param buffer:图片ArrayBuffer
   * @returns
   */
  async pickerSave(buffer: ArrayBuffer | string): Promise<void> {
    const photoSaveOptions = new picker.PhotoSaveOptions(); // 创建文件管理器保存选项实例
    photoSaveOptions.newFileNames = ['PhotoViewPicker ' + new Date().getTime() + '.jpg']; // 保存文件名(可选)
    const photoViewPicker = new picker.PhotoViewPicker;
    photoViewPicker.save(photoSaveOptions)
      .then(async (photoSvaeResult) => {
        const uri = photoSvaeResult[0];
        const file = await fs.open(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
        await fs.write(file.fd, buffer);
        await fs.close(file.fd);
        promptAction.showToast({
          message: '保存成功',
          duration: 2000
        })
      });
  }

  async aboutToAppear(): Promise<void> {
    // this.getPicture();
    this.onChangeUrl()
  }

  build() {
    Stack({ alignContent: Alignment.Center }) {
      // Column() {
      //   Text('下载')
      //     .fontWeight(FontWeight.Medium)
      // }

      Image(this.image)
        .objectFit(ImageFit.Contain)
        .width('50%')
        .height(28)

      SaveButton({ icon: SaveIconStyle.FULL_FILLED, buttonType: ButtonType.Capsule })
        .iconSize(24)
        .backgroundColor(Color.Transparent)
        .iconColor(Color.White)// .markAnchor({ x: '100%' })
        .position({ x: '25%' })
        .onClick(async () => {
          if (this.imageBuffer !== undefined) {
            await this.saveImage(this.imageBuffer);
            promptAction.showToast({
              message: '保存成功',
              duration: 2000
            })
          }
        })

    }

    // .alignSelf(ItemAlign.Center)
    // .align(Alignment.Center)
    // .backgroundColor(Color.Red)
  }

  async onChangeUrl(): Promise<void> {
    console.info(`cj2024 图片下载 ${this.url}`)
    // const context = getContext(this) as common.UIAbilityContext;
    // const atManager = abilityAccessCtrl.createAtManager();
    // await atManager.requestPermissionsFromUser(context, PERMISSIONS);
    // 通过任务池(taskpool)从网络下载图片资源
    taskpool.execute(getPicture, this.url).then((res) => {
      const imgBuffer = res as ArrayBuffer
      this.imageBuffer = imgBuffer;
    })
  }
}