HarmonyOS鸿蒙Next中Image组件加载含有特殊字符的图片失败如何解决

HarmonyOS鸿蒙Next中Image组件加载含有特殊字符的图片失败如何解决

【问题现象】

Image组件使用file://协议,加载沙箱路径中含有特殊字符的图片资源失败,图片无法显示。

点击放大

【背景知识】

Image组件图片的数据源,支持本地图片和网络图片,本文主要讲述本地图片的引用。两种引用方式可以参考Image组件显示图片指南

Image组件支持三种类型的图片数据源,分别为PixelMap、ResourceStr、DrawableDescriptor。

  1. PixelMap格式为像素图,常用于图片编辑的场景。
  2. ResourceStr包含Resource和string格式。
    • string格式可用于加载网络图片和本地图片,常用于加载网络图片。当使用相对路径引用本地图片时,例如Image("common/test.jpg"),不支持跨包/跨模块调用该Image组件,建议使用Resource格式来管理需全局使用的图片资源。
    • 支持Base64字符串。格式data:image/[png|jpeg|bmp|webp|heif];base64,[base64 data],其中[base64 data]为Base64字符串数据。
Image("data:image/[png|jpeg|bmp|webp|heif];base64,[base64 data]")
  • 支持file://路径前缀的字符串,应用沙箱URI:file://<bundleName>/<sandboxPath>。当访问的路径中包含特殊符号时,需要使用fileUri.getUriFromPath(path)去做转换。同时需要保证目录包路径下的文件有可读权限。
Image("file://<bundleName>/data/storage/el2/base/haps/entry/files/test.jpg")
  • Resource格式可以跨包/跨模块访问资源文件,是访问本地图片的推荐方式。
Image($rawfile("test.jpg"))
  1. 当传入资源id或name为普通图片时,生成DrawableDescriptor对象。传入AnimatedDrawableDescriptor类型可播放PixelMap数组动画。

注意

  • ArkTS卡片上支持gif图片格式动效,但仅在显示时播放一次。
  • ArkTS卡片上不支持http://等网络相关路径前缀和file://路径前缀的字符串。
  • ArkTS卡片上不支持 PixelMap类型。
  • 加载本地图片过程中,如果对图片进行修改或者替换,可能会引起应用崩溃。因此需要覆盖图片文件时,应该先删除该文件再重新创建一个同名文件。
  • 如果SVG图片没有原生大小,需要给Image组件设置宽高,否则不显示。
  • 如果SVG图片通过image标签引用本地其他图片,被引用的图片不支持svg格式和gif格式。
  • src由有效切换为无效时,图片保持不动。

【定位思路】

Image组件使用file://路径前缀的字符串的路径格式加载应用沙箱中图片资源,例如【@%^\_,.jpg】这种文件名中有特殊符号的图片,需要将路径转换为URI,再放入Image组件显示。

【解决方案】

从相册中选取一张图片保存到应用沙箱中,并使用特殊符号给图片命名【@%^_,.jpg】

// 从相册选择图片
let PhotoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
PhotoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;
PhotoSelectOptions.maxSelectNumber = 1;
let photoPicker = new photoAccessHelper.PhotoViewPicker();
photoPicker.select(PhotoSelectOptions).then(async (PhotoSelectResult) => {
  // 将图片保存到应用沙箱,并用特殊符号给图片命名
  if (PhotoSelectResult.photoUris.length) {
    let photouri: Array<string> = PhotoSelectResult.photoUris
    let pathDir = getContext().filesDir;
    let path = pathDir + '/@%^_,.jpg'
    console.info("取出的uri:" + photouri[0])
    let file = fs.openSync(photouri[0], fs.OpenMode.READ_ONLY)
    let file2 = fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
    fs.copyFileSync(file.fd, file2.fd)
    fs.closeSync(file);
    fs.closeSync(file2);
  }
})

然后获取沙箱路径中图片对应的URI:

// 将沙箱路径的path转换为URI
this.path = "file://" + this.context.abilityInfo.bundleName + path
this.uri = fileUri.getUriFromPath(path)
console.info('uri:', this.uri)
console.info('path:', this.path)

最后显示界面设置两个Image组件,一个的图片资源是沙箱路径path,另一个是沙箱路径对应的URI:

// 显示沙箱路径URI的值
Text("使用沙箱路径URI加载图片").margin({ top: 30, bottom: 10 });
Text("uri: " + this.uri);
// 使用沙箱路径URI显示图片
Image(this.uri)
  .width(100)
  .height(100)
  .borderColor("#000000001")
  .border({ width: 1 })
  .margin({ bottom: 75 });
// 显示沙箱路径path的值
Text("使用沙箱路径path加载图片").margin({ bottom: 10 });
Text("path: " + this.path);
// 使用沙箱路径path显示图片
Image(this.path)
  .width(100)
  .height(100)
  .borderColor("#000000001")
  .border({ width: 1 });

可以看到展示结果中,URI的图片可以正常显示,而path的无法显示。

点击放大

Demo完整代码展示:

import { fileIo as fs, fileUri } from '@kit.CoreFileKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import common from '@ohos.app.ability.common'

@Entry
@Component
struct specialNameImage {
  context = getContext(this) as common.UIAbilityContext
  @State uri: string = ''
  @State path: string = ''

  build() {
    Column() {
      // 显示沙箱路径URI的值
      Text("使用沙箱路径URI加载图片")
        .margin({ top: 30, bottom: 10 })
      Text("uri: " + this.uri)
      // 使用沙箱路径URI显示图片
      Image(this.uri)
        .width(100)
        .height(100)
        .borderColor('# 000000001')
        .border({ width: 1 })
        .margin({ bottom: 75 })
      // 显示沙箱路径path的值
      Text("使用沙箱路径path加载图片")
        .margin({ bottom: 10 })
      Text("path: " + this.path)
      // 使用沙箱路径path显示图片
      Image(this.path)
        .width(100)
        .height(100)
        .borderColor('# 000000001')
        .border({ width: 1 })
      Text('测试')
        .padding(50)
        .onClick(async () => {
          // 从相册选择图片
          let PhotoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
          PhotoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;
          PhotoSelectOptions.maxSelectNumber = 1;
          let photoPicker = new photoAccessHelper.PhotoViewPicker();
          photoPicker.select(PhotoSelectOptions).then(async (PhotoSelectResult) => {
            // 将图片保存到应用沙箱,并用特殊符号给图片命名
            if (PhotoSelectResult.photoUris.length) {
              let photouri: Array<string> = PhotoSelectResult.photoUris
              let pathDir = getContext().filesDir;
              let path = pathDir + '/@%^_,.jpg'
              console.info("取出的uri:" + photouri[0])
              let file = fs.openSync(photouri[0], fs.OpenMode.READ_ONLY)
              let file2 = fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
              fs.copyFileSync(file.fd, file2.fd)
              fs.closeSync(file);
              fs.closeSync(file2);
              // 将沙箱路径的path和URI显示到界面
              this.path = "file://" + this.context.abilityInfo.bundleName + path
              this.uri = fileUri.getUriFromPath(path)
              console.info('uri:', this.uri)
              console.info('path:', this.path)
            }
          })
        })
    }
  }
}

【总结】

当文件名或文件路径存在特殊字符时,可以将路径转换为URI,再将URI传入组件中使用。


更多关于HarmonyOS鸿蒙Next中Image组件加载含有特殊字符的图片失败如何解决的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于HarmonyOS鸿蒙Next中Image组件加载含有特殊字符的图片失败如何解决的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,Image组件加载含有特殊字符的图片失败,通常是由于URL编码问题导致的。特殊字符如空格、#&等在URL中具有特殊含义,直接使用会导致解析错误。

解决方法

解决方法是对图片URL进行编码处理,使用encodeURIComponentencodeURI函数对特殊字符进行转义。例如:

  • #转义为%23
  • &转义为%26

确保URL在加载前已正确编码,避免因特殊字符导致的加载失败。

回到顶部