HarmonyOS鸿蒙Next中拍照后对应的图片保存到本地后无法打开如何解决

HarmonyOS鸿蒙Next中拍照后对应的图片保存到本地后无法打开如何解决

【问题现象】

拍照后,获取到uri,存到本地后,再去读取该文件 ,无法打开。用Device file Browser导出保存的文件,提示已损坏 ,如下图所示:

点击放大

点击放大

相关部分核心代码如下:

// 此处省略导入模块相关代码, 具体参考解决方案部分相关代码
@Entry
@Component
struct ImagePickerPage { 
  // 此处省略部分代码,具体参考解决方案部分相关代码
  build() {
    Row() {
      Column() {
        Image(this.uri)
          .height($r('app.float.image_height'))
          .alt($r('app.media.startIcon'))

        Button($r('app.string.capture'))
          .width($r('app.float.button_width'))
          .margin({ top: $r('app.float.margin') })
          .onClick(async () => {
            try {
              // Configure to launch the rear camera
              let pickerProfile: cameraPicker.PickerProfile = { cameraPosition: this.cameraPosition[1] };
              // Configure to photo mode
              let pickerResult: cameraPicker.PickerResult = await cameraPicker.pick(getContext(this),
                [this.mediaType[0]], pickerProfile);
              // Get video URI
              let uri = pickerResult.resultUri
              let type = uri.split(".").pop()
              let fd = fs.openSync(uri , fs.OpenMode.READ_ONLY).fd
              let imgPixelMap = await image.createImageSource(fd).createPixelMap()
              let array = new ArrayBuffer(imgPixelMap.getPixelBytesNumber())
              imgPixelMap.readPixelsToBuffer(array)
              let res = this.saveImage(array,type??"jpg")
              this.uri = res
              hilog.info(0x0000, ' ', "the pick pickerResult is:" + JSON.stringify(pickerResult));
            } catch (error) {
              let err = error as BusinessError;
              hilog.error(0x0000, '', `the pick call failed. error code: ${err.code}`);
            }
          })
      }
      .width(Const.FULL_SIZE)
    }
    .height(Const.FULL_SIZE)
  }
}

【背景知识】

图像像素类PixelMap,用于读取或写入图像数据以及获取图像信息。在调用PixelMap的方法前,需要先通过createPixelMap创建一个PixelMap实例。目前pixelmap序列化大小最大128MB,超过会送显失败。大小计算方式为(宽每像素占用字节数)。

目前图片加载不支持直接用沙箱路径,需要进行转化。

【解决方案】

具体到该示例,首先图片大小为48M, 序列化后超过了128MB,因此需要调用packing方法压缩处理;其次saveImage函数返回的路径为沙箱路径, 需要通过getUriFromPath方法进行转换后才能加载显示。

修改后的代码如下:

import { cameraPicker } from '@kit.CameraKit';
import { camera } from '@kit.CameraKit';
import { BusinessError } from '@ohos.base';
import { hilog } from '@kit.PerformanceAnalysisKit'
import { CommonConstants as Const } from '../common/constants/CommonConstants';
import { image } from '@kit.ImageKit';

import fs from '@ohos.file.fs';
import { util } from '@kit.ArkTS';
import { fileUri } from '@kit.CoreFileKit';
@Entry
@Component
struct ImagePickerPage {
  @State uri: Resource | string | undefined = undefined;
  private cameraPosition: Array<camera.CameraPosition> = [
    camera.CameraPosition.CAMERA_POSITION_UNSPECIFIED, camera.CameraPosition.CAMERA_POSITION_BACK,
    camera.CameraPosition.CAMERA_POSITION_FRONT, camera.CameraPosition.CAMERA_POSITION_FOLD_INNER
  ];
  private mediaType: Array<cameraPicker.PickerMediaType> = [
    cameraPicker.PickerMediaType.PHOTO, cameraPicker.PickerMediaType.VIDEO
  ];
  baseDirStr: string = "/soon"
  imageDirStr: string = "/images"
  getBaseFileDir() {
    let path = getContext().filesDir + this.baseDirStr
    if (fs.accessSync(path) == false) {
      fs.mkdirSync(path)
    }
    return path
  }
  getImageFileDir() {
    let path = this.getBaseFileDir() + this.imageDirStr
    if (fs.accessSync(path) == false) {
      fs.mkdirSync(path)
    }
    return path
  }
  saveImage(buffer: ArrayBuffer,type:string , name?: string): string | undefined {
    if (!name) {
      name = util.generateRandomUUID(false)
    }
    let path = this.getImageFileDir() + "/" + name
    return this.saveFile(buffer , type , path)
  }
  saveFile(buffer: ArrayBuffer | string, type:string ,uri: string): string | undefined {
    let file: fs.File | undefined = undefined
    try {
      let path = uri + "." + type
      file = fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
      fs.writeSync(file.fd, buffer)
      fs.closeSync(file)
      return path
    } catch (e) {
      try {
        if (file) fs.close(file)
        console.log("whiteImage error" + e)
      } catch (e) {
      }
      return undefined
    }
  }
  build() {
    Row() {
      Column() {
        Image(this.uri)
          .height($r('app.float.image_height'))
          .alt($r('app.media.startIcon'))
        Button($r('app.string.capture'))
          .width($r('app.float.button_width'))
          .margin({ top: $r('app.float.margin') })
          .onClick(async () => {
            try {
              // Configure to launch the rear camera
              let pickerProfile: cameraPicker.PickerProfile = { cameraPosition: this.cameraPosition[1] };
              // Configure to photo mode
              let pickerResult: cameraPicker.PickerResult = await cameraPicker.pick(getContext(this),
                [this.mediaType[0]], pickerProfile);
              // Get URI
              let uri = pickerResult.resultUri
              let type = uri.split(".").pop()
              let fd = fs.openSync(uri , fs.OpenMode.READ_ONLY).fd
              const imagePackerApi: image.ImagePacker = image.createImagePacker();
              const imageSourceApi: image.ImageSource = image.createImageSource(fd);
              let packOpts: image.PackingOption = { format: "image/jpeg", quality: 98 };
              // Image compression processing
              imagePackerApi.packing(imageSourceApi, packOpts, (err: BusinessError, data: ArrayBuffer) => {
                if (err) {
                  console.error('packing failed.');
                } else {
                  let res = this.saveImage(data,type??"jpg")
                  // Obtain file URI using a synchronous method
                  this.uri = fileUri.getUriFromPath(res);
                  hilog.info(0x0000, ' ', "xxxxxx:" + this.uri);
                }
              })
              hilog.info(0x0000, ' ', "the pick pickerResult is:" + JSON.stringify(pickerResult));
            } catch (error) {
              let err = error as BusinessError;
              hilog.error(0x0000, '', `the pick call failed. error code: ${err.code}`);
            }
          })
      }
      .width(Const.FULL_SIZE)
    }
    .height(Const.FULL_SIZE)
  }
}

更多关于HarmonyOS鸿蒙Next中拍照后对应的图片保存到本地后无法打开如何解决的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于HarmonyOS鸿蒙Next中拍照后对应的图片保存到本地后无法打开如何解决的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,拍照后图片保存到本地无法打开,可能是由于以下原因:

  1. 文件损坏:图片在保存过程中可能因存储介质问题或系统错误导致文件损坏。
  2. 文件格式不兼容:保存的图片格式可能与系统或应用不兼容。
  3. 权限问题:应用可能没有足够的权限访问或读取保存的图片。
  4. 存储路径错误:图片可能被保存到了错误的路径,导致无法正确访问。
  5. 系统缓存问题:系统缓存可能导致图片无法正常显示。

解决方法:

  1. 检查图片文件是否完整,尝试在其他设备或应用中打开。
  2. 确认图片格式是否支持,必要时转换格式。
  3. 检查应用权限,确保有读取存储的权限。
  4. 确认图片保存路径是否正确,必要时手动查找。
  5. 清除系统缓存,重启设备后再次尝试打开图片。

如果问题依旧存在,建议检查系统更新或联系华为技术支持获取进一步帮助。

回到顶部