前言
随着生态扩展,许多开发者都有对图片进行各种数据处理、转换、编码的需求。下文会为大家介绍如何去进行Base64编码以及在调研过程中遇到的一些重要问题。
开发环境
系统版本: 4.0-Release
DevEco Studio版本: 4.0 Release (build:4.0.0.600)
SDK版本: 4.0.10.13(及以上)
流程
通过图片选择器选择图片,拿到图片pixelMap
import picker from '@ohos.file.picker';
import image from '@ohos.multimedia.image';
import dataSharePredicates from '@ohos.data.dataSharePredicates';
import photoAccessHelper from '@ohos.file.photoAccessHelper';
let PhotoSelectOptions = new picker.PhotoSelectOptions();
PhotoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_VIDEO_TYPE;
PhotoSelectOptions.maxSelectNumber = 1;
let photoPicker = new picker.PhotoViewPicker();
photoPicker.select(PhotoSelectOptions).then(async (PhotoSelectResult: picker.PhotoSelectResult) => {
WinsleiLogManager.hilogIWithTag(TAG, `selectPhoto select, PhotoSelectResult: ${JSON.stringify(PhotoSelectResult)}`)
let uris = PhotoSelectResult.photoUris;
try {
for (let index = 0; index < uris.length; index++) {
let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(getContext(this));
let predicates: dataSharePredicates.DataSharePredicates = new dataSharePredicates.DataSharePredicates();
// 配置查询条件,使用PhotoViewPicker选择图片返回的uri进行查询
predicates.equalTo('uri', uris[index]);
let fetchOption: photoAccessHelper.FetchOptions = {
fetchColumns: [],
predicates: predicates
};
WinsleiLogManager.hilogIWithTag(TAG, `selectPhoto select, getAssets start`)
let fetchResult: photoAccessHelper.FetchResult<photoAccessHelper.PhotoAsset> = await phAccessHelper.getAssets(fetchOption);
// 得到uri对应的PhotoAsset对象,读取文件的部分信息
WinsleiLogManager.hilogIWithTag(TAG, `selectPhoto select, getFirstObject start`)
let asset: photoAccessHelper.PhotoAsset = await fetchResult.getFirstObject();
WinsleiLogManager.hilogIWithTag(TAG, 'selectPhoto asset displayName: ' + asset.displayName);
WinsleiLogManager.hilogIWithTag(TAG, 'selectPhoto asset uri: ' + asset.uri);
WinsleiLogManager.hilogIWithTag(TAG, 'selectPhoto asset photoType: ' + asset.photoType);
// 获取缩略图
let pixelMap = await asset.getThumbnail();
WinsleiLogManager.hilogIWithTag(TAG, 'selectPhoto getThumbnail, pixelMap: ' + JSON.stringify(pixelMap));
}).catch((err: base.BusinessError) => {
WinsleiLogManager.hilogIWithTag(TAG, `selectPhoto select, err: ${JSON.stringify(err)}`)
});
将pixelMap打包(重要步骤!!!)
const imagePackageApi: image.ImagePacker = image.createImagePacker()
let packOpts: image.PackingOption = {
format: 'image/jpeg',
quality: 100,
}
const readBuffer = await imagePackageApi.packing(pixelMap, packOpts)
将打包后的ArrayBuffer进行Base64编码
在OpenHarmony中,Base64编码有3种方式:
系统Api
https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-arkts/js-apis-util.md#base64helper9
三方库
https://ohpm.openharmony.cn/#/cn/detail/@ohos%2Fbase64
手动转换
arrayBufferToBase64(array: Uint8Array): string {
let length = array.byteLength;
let table = ['A','B','C','D','E','F','G','H',
'I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X',
'Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n',
'o','p','q','r','s','t','u','v',
'w','x','y','z','0','1','2','3',
'4','5','6','7','8','9','+','/'];
let base64Str = '';
for(let i = 0; length - i >= 3; i += 3) {
let num1 = array[i];
let num2 = array[i + 1];
let num3 = array[i + 2];
base64Str += table[num1 >>> 2]
+ table[((num1 & 0b11) << 4) | (num2 >>> 4)]
+ table[((num2 & 0b1111) << 2) | (num3 >>> 6)]
+ table[num3 & 0b111111];
let lastByte = length - i;
if(lastByte === 1) {
let lastNum1 = array[i];
base64Str += table[lastNum1 >>> 2] + table[((lastNum1 & 0b11) << 4)] + '==';
} else if(lastByte === 2){
let lastNum1 = array[i];
let lastNum2 = array[i + 1];
base64Str += table[lastNum1 >>> 2]
+ table[((lastNum1 & 0b11) << 4) | (lastNum2 >>> 4)]
+ table[(lastNum2 & 0b1111) << 2]
+ '=';
}
}
return base64Str;
}
这里以系统Api为例
import util from '@ohos.util';
// base64
let base64Helper = new util.Base64Helper()
let uint8Arr = new Uint8Array(readBuffer)
WinsleiLogManager.hilogIWithTag(TAG, 'selectPhoto Uint8Array, uint8Arr: ' + JSON.stringify(uint8Arr));
let pixelStr = base64Helper.encodeToStringSync(uint8Arr)
// let pixelStr = this.arrayBufferToBase64(uint8Arr)
this.base64Str = 'data:image/jpg;base64,' + pixelStr
WinsleiLogManager.hilogIWithTag(TAG, 'selectPhoto base64, base64Str: ' + this.base64Str);
即可正常加载Base64编码后的图片了。
注意事项
在上述流程中,可以看到其中一步操作将pixelMap打包。为什么说这一步是重要步骤,因为很多开发者(包括作者)在研究Base64编码过程中,会直接将PixelMap
直接转换为Uint8Array
再转换为base64
。反面示例:
// 获取pixelMap总字节数
let pixelBytesNumber: number = pixelMap.getPixelBytesNumber();
WinsleiLogManager.hilogIWithTag(TAG, 'selectPhoto getPixelBytesNumber, pixelBytesNumber: ' + JSON.stringify(pixelBytesNumber));
// 将读取的整张图像像素数据结果写入ArrayBuffer中
const readBuffer = new ArrayBuffer(pixelBytesNumber);
await pixelMap.readPixelsToBuffer(readBuffer)
WinsleiLogManager.hilogIWithTag(TAG, 'selectPhoto ArrayBuffer, readBuffer: ' + JSON.stringify(readBuffer));
这么处理无法得到正确的Uint8Array
。
参考文献
Base64Helper: https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-arkts/js-apis-util.md#base64helper9
DataSharePredicates: https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-arkdata/js-apis-data-dataSharePredicates.md
PhotoAccessHelper: https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-media-library-kit/js-apis-photoAccessHelper.md#photoviewpicker
示例Demo
https://gitee.com/winslei/open-harmony_-winsleikit/commit/7b0a1e49ad2c6193ad9605683160cc097c9a3b1b