HarmonyOS鸿蒙Next中选择相册图片后,怎么获取图片的尺寸信息呢?
HarmonyOS鸿蒙Next中选择相册图片后,怎么获取图片的尺寸信息呢? PhotoViewPicker和PhotoPickerComponent返回的uri;
image.createImageSource(uri).getImageInfo
后者返回的uri直接报错:
前者没有任何日志
import { photoAccessHelper } from '@kit.MediaLibraryKit';
let photoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;
photoSelectOptions.maxSelectNumber = 1;
let photoPicker = new photoAccessHelper.PhotoViewPicker();
photoPicker.select(photoSelectOptions, async (
err: BusinessError, photoSelectResult: photoAccessHelper.PhotoSelectResult) => {
if (err) {
Logger.error('PhotoViewPicker.select failed with err: ' + JSON.stringify(err));
return;
}
Logger.info('PhotoViewPicker.select successfully, ' +
'photoSelectResult uri: ' + JSON.stringify(photoSelectResult));
this.uris = photoSelectResult.photoUris;
Logger.info('uri: ' + this.uris);
try {
let file = fileIo.openSync(this.uris[0], fileIo.OpenMode.READ_ONLY);
Logger.info('file fd: ' + file.fd);
let inputBuffer = new ArrayBuffer(CommonConstants.ARRAY_BUFFER_SIZE);
let readLen = fileIo.readSync(file.fd, inputBuffer);
Logger.info('readSync data to file succeed and inputBuffer size is:' + readLen);
let imageSource = image.createImageSource(file.fd);
let pixelMap = await imageSource.createPixelMap();
let info = await pixelMap.getImageInfo();
Logger.info('info.width = ' + info.size.width);
Logger.info('info.height = ' + info.size.height);
...
}
}
更多关于HarmonyOS鸿蒙Next中选择相册图片后,怎么获取图片的尺寸信息呢?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
使用 PhotoPickerComponent 返回的 BaseItemInfo(直接获取尺寸)
// 假设 item 是 PhotoPickerComponent 返回的 BaseItemInfo 对象
let width = item.width; // 单位:像素
let height = item.height;
console.info(`图片尺寸:宽 ${width}像素, 高 ${height}像素`);
当使用PhotoViewPicker获取datashare://格式URI时,需先通过PhotoAccessHelper获取媒体资源对象:
let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
let predicates = new dataSharePredicates.DataSharePredicates();
predicates.equalTo('uri', fileUri); // 使用返回的URI作为查询条件
let fetchOption: photoAccessHelper.FetchOptions = {
fetchColumns: ['size'], // 明确查询尺寸字段
predicates: predicates
};
let fetchResult = await phAccessHelper.getAssets(fetchOption);
let asset = await fetchResult.getFirstObject();
console.info('图片尺寸:', asset.get(photoAccessHelper.PhotoKeys.SIZE));
获取图片的Asset,可以读取更多的元数据。包括图片宽高、大小、修改时间、更多信息。
async getUriAsset(uri: string): Promise<photoAccessHelper.PhotoAsset | null> {
const predicates: dataSharePredicates.DataSharePredicates = new dataSharePredicates.DataSharePredicates();
predicates.equalTo(photoAccessHelper.PhotoKeys.URI, uri.toString());
const fetchOptions: photoAccessHelper.FetchOptions = {
fetchColumns: [
photoAccessHelper.PhotoKeys.WIDTH,
photoAccessHelper.PhotoKeys.HEIGHT,
photoAccessHelper.PhotoKeys.SIZE
],
predicates: predicates
}
try {
const context = this.getUIContext().getHostContext();
const phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
const fetchResult: photoAccessHelper.FetchResult<photoAccessHelper.PhotoAsset> =
await phAccessHelper.getAssets(fetchOptions);
const photoAsset: photoAccessHelper.PhotoAsset = await fetchResult.getFirstObject();
fetchResult.close();
return photoAsset
} catch (err) {
return null
}
}
// 使用
const asset = await this.getUriAsset(fileUri)
if (asset) {
const width = asset.get(photoAccessHelper.PhotoKeys.WIDTH) as number
const height = asset.get(photoAccessHelper.PhotoKeys.HEIGHT) as number
}
问题分析与解决方案
你遇到的问题是:使用 PhotoViewPicker 或 PhotoPickerComponent 返回的 URI 无法直接用于 image.createImageSource(uri),这会导致报错。
核心问题
PhotoViewPicker 返回的 URI 格式是 file://media/Photo/…,这是媒体文件 URI,不能直接传递给 createImageSource(uri),因为:
- createImageSource(uri) 期望的 uri 参数是沙箱路径,如 /data/storage/el2/base/files/test.jpg
- PhotoPicker 返回的是媒体库 URI,需要先转换为文件描述符(fd)
正确的解决方案(基于最新 API)
方案 1: 使用 fd 方式(推荐)
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { fileIo } from '@kit.CoreFileKit';
import { image } from '@kit.ImageKit';
import { BusinessError } from '@kit.BasicServicesKit';
async function getImageSizeFromPicker() {
try {
// 1. 使用 PhotoViewPicker 选择图片
const photoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;
photoSelectOptions.maxSelectNumber = 1;
const photoPicker = new photoAccessHelper.PhotoViewPicker();
const photoSelectResult = await photoPicker.select(photoSelectOptions);
const uri = photoSelectResult.photoUris[0];
console.info('Selected photo uri: ' + uri);
// 2. 通过 fileIo.openSync 打开 URI 获取文件描述符(fd)
const file = fileIo.openSync(uri, fileIo.OpenMode.READ_ONLY);
console.info('File fd: ' + file.fd);
// 3. 使用 fd 创建 ImageSource
const imageSource: image.ImageSource = image.createImageSource(file.fd);
// 4. 获取图片信息(包含尺寸)
const imageInfo: image.ImageInfo = await imageSource.getImageInfo();
console.info('Image width: ' + imageInfo.size.width);
console.info('Image height: ' + imageInfo.size.height);
console.info('Image density: ' + imageInfo.density);
console.info('Image mimeType: ' + imageInfo.mimeType);
// 5. 释放资源
await imageSource.release();
fileIo.closeSync(file);
return imageInfo.size; // 返回 { width: number, height: number }
} catch (err) {
const error = err as BusinessError;
console.error(`Error: ${error.code}, ${error.message}`);
}
}
方案 2: 使用 getImageInfoSync 同步方式(API 12+)
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { fileIo } from '@kit.CoreFileKit';
import { image } from '@kit.ImageKit';
function getImageSizeSync(uri: string): image.Size | undefined {
try {
// 1. 通过 URI 获取 fd
const file = fileIo.openSync(uri, fileIo.OpenMode.READ_ONLY);
// 2. 创建 ImageSource
const imageSource: image.ImageSource = image.createImageSource(file.fd);
// 3. 同步获取图片信息
const imageInfo: image.ImageInfo = imageSource.getImageInfoSync(0);
console.info('Image width: ' + imageInfo.size.width);
console.info('Image height: ' + imageInfo.size.height);
// 4. 释放资源
imageSource.release();
fileIo.closeSync(file);
return imageInfo.size;
} catch (error) {
console.error('Failed to get image size: ' + error);
return undefined;
}
}
方案 3: 使用 PhotoAccessHelper 获取详细信息
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { dataSharePredicates } from '@kit.ArkData';
async function getImageInfoFromUri(uri: string, phAccessHelper: photoAccessHelper.PhotoAccessHelper) {
try {
// 1. 通过 URI 查询 PhotoAsset
let predicates = new dataSharePredicates.DataSharePredicates();
predicates.equalTo(photoAccessHelper.PhotoKeys.URI, uri);
let fetchOptions: photoAccessHelper.FetchOptions = {
fetchColumns: [
photoAccessHelper.PhotoKeys.WIDTH,
photoAccessHelper.PhotoKeys.HEIGHT,
photoAccessHelper.PhotoKeys.SIZE,
photoAccessHelper.PhotoKeys.TITLE
],
predicates: predicates
};
// 2. 获取资产
const fetchResult = await phAccessHelper.getAssets(fetchOptions);
const photoAsset = await fetchResult.getFirstObject();
// 3. 获取图片宽高
const width = photoAsset.get(photoAccessHelper.PhotoKeys.WIDTH);
const height = photoAsset.get(photoAccessHelper.PhotoKeys.HEIGHT);
const fileSize = photoAsset.get(photoAccessHelper.PhotoKeys.SIZE);
const title = photoAsset.get(photoAccessHelper.PhotoKeys.TITLE);
console.info(`Width: ${width}, Height: ${height}`);
console.info(`File size: ${fileSize}, Title: ${title}`);
fetchResult.close();
return { width, height, fileSize, title };
} catch (err) {
console.error('Failed to get image info: ' + err);
}
}
完整示例(组合方案)
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { fileIo } from '@kit.CoreFileKit';
import { image } from '@kit.ImageKit';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct ImagePickerDemo {
@State imageWidth: number = 0;
@State imageHeight: number = 0;
@State imageUri: string = '';
async selectAndGetImageSize() {
try {
// 1. 选择图片
const photoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;
photoSelectOptions.maxSelectNumber = 1;
const photoPicker = new photoAccessHelper.PhotoViewPicker();
const result = await photoPicker.select(photoSelectOptions);
if (result.photoUris.length > 0) {
this.imageUri = result.photoUris[0];
// 2. 打开文件获取 fd
const file = fileIo.openSync(this.imageUri, fileIo.OpenMode.READ_ONLY);
// 3. 创建 ImageSource
const imageSource = image.createImageSource(file.fd);
// 4. 获取图片信息
const imageInfo = await imageSource.getImageInfo();
this.imageWidth = imageInfo.size.width;
this.imageHeight = imageInfo.size.height;
console.info(`Image size: ${this.imageWidth} x ${this.imageHeight}`);
// 5. 清理资源
await imageSource.release();
fileIo.closeSync(file);
}
} catch (err) {
const error = err as BusinessError;
console.error(`Error: ${error.code}, ${error.message}`);
}
}
build() {
Column({ space: 20 }) {
Button('选择图片并获取尺寸')
.onClick(() => {
this.selectAndGetImageSize();
})
if (this.imageUri) {
Image(this.imageUri)
.width(300)
.height(300)
.objectFit(ImageFit.Contain)
Text(`宽度: ${this.imageWidth}px`)
Text(`高度: ${this.imageHeight}px`)
}
}
.width('100%')
.height('100%')
.padding(20)
}
}
关键要点总结
- 不能直接使用 URI: PhotoPicker 返回的 URI 不能直接传给 createImageSource(uri)
- 必须使用 fd: 需要通过 fileIo.openSync(uri, fileIo.OpenMode.READ_ONLY) 获取 fd
- 使用 fd 创建 ImageSource: image.createImageSource(file.fd)
- 获取图片信息: imageInfo.size.width 和 imageInfo.size.height
- 记得释放资源: 调用 imageSource.release() 和 fileIo.closeSync(file)
在HarmonyOS Next中,获取相册图片尺寸信息,可通过PhotoViewPicker选择图片后,使用image模块的getImageInfo方法。选择图片返回的URI,调用getImageInfo可异步获取包含size(width、height)的ImageInfo对象。
在HarmonyOS Next中,通过PhotoViewPicker或PhotoPickerComponent获取到图片URI后,直接使用image.createImageSource(uri).getImageInfo()来获取尺寸信息(如width和height)是正确的方法。
从你提供的错误信息来看,问题很可能出在URI的格式或权限上。PhotoPickerComponent返回的URI可能是一个需要特殊处理的临时或虚拟路径,直接用于createImageSource可能导致失败。
解决方案:
-
使用
PhotoViewPicker(推荐) 这是更稳定、官方推荐的方式。确保你已经正确声明了所需的权限(ohos.permission.READ_IMAGEVIDEO),并且在使用前用户已授权。获取URI的代码通常是正确的,getImageInfo()方法也应该能正常工作。如果无日志,请检查:- 权限是否已授予。
- 代码是否被正确执行(可添加基础日志排查)。
getImageInfo()是一个异步操作,确保你正确处理了Promise或使用了async/await。
示例代码片段:
import picker from '@ohos.file.picker'; import image from '@ohos.multimedia.image'; // 1. 创建并启动PhotoViewPicker(假设已获得权限) let photoPicker = new picker.PhotoViewPicker(); // ... 配置photoPicker ... let uris = await photoPicker.select(); if (uris && uris.length > 0) { let selectedUri = uris[0]; // 2. 创建ImageSource并获取信息 let imageSource = image.createImageSource(selectedUri); let imageInfo = await imageSource.getImageInfo(); console.log(`图片尺寸: width=${imageInfo.size.width}, height=${imageInfo.size.height}`); // 使用完毕后释放资源 imageSource.release(); } -
处理
PhotoPickerComponent的URIPhotoPickerComponent返回的URI可能需要通过FilePicker的getPhotoAccessHelper()或getPhotoPicker()方法转换为可用的绝对路径,或者它本身是一个需要ohos.permission.READ_IMAGEVIDEO权限才能访问的URI。直接使用该URI调用createImageSource可能会因权限或路径格式问题而失败。- 检查权限:确保应用已申请并获得了
ohos.permission.READ_IMAGEVIDEO权限。 - 尝试转换URI:如果可能,查阅
PhotoPickerComponent的API文档,看是否有方法将其返回的URI转换为标准的file://路径或通过ohos.file.fsAPI可访问的URI。
- 检查权限:确保应用已申请并获得了
核心要点:
- 权限是前提:无论使用哪种选择器,
ohos.permission.READ_IMAGEVIDEO权限是读取媒体文件所必需的。 PhotoViewPicker更可靠:对于直接从相册选择图片并获取元信息的场景,PhotoViewPickerAPI是更直接和稳定的选择。- 异步操作:
getImageInfo()返回Promise,需使用await或.then()获取结果。 - 资源释放:使用完
ImageSource后,调用其release()方法释放资源。
根据你描述的情况,建议优先采用PhotoViewPicker方案,并仔细检查权限管理代码。

