IT评测·应用市场-qidao123.com技术社区
标题:
【HarmonyOS NEXT】FAQ之媒体开发(图片处理)
[打印本页]
作者:
嚴華
时间:
2024-10-6 20:58
标题:
【HarmonyOS NEXT】FAQ之媒体开发(图片处理)
1、通过PixelMap_CreatePixelMap创建的对象,内存在ArkTS侧和Native侧是否共享
A:通过PixelMap_CreatePixelMap创建的对象在ArkTS侧和Native侧会共享同一份内存。
2、怎样设置图片的高斯模糊效果
A:使用图像效果模块的blur接口,详情请参考链接:图像效果。
3、调用imageSource.createPixelMap()报错“Create PixelMap error”
A:该问题是sampleSize取值错误导致的,sampleSize表示缩略图采样巨细,当前只能取1。可通过DecodingOptions.desiredSize指定输出巨细。
4、图片压缩API的质量参数quality与图片原始巨细、压缩后巨细的关系
A:对于有损压缩图片格式,如jpeg格式,质量参数会影响压缩后的图片巨细,对于无损压缩图片格式,如png格式,质量参数不会影响压缩后的图片巨细
对于有损压缩图片格式,压缩后的图片巨细不仅取决于图片原始巨细、图片压缩质量,还与图片中内容有较大关系,因此当前系统不支持设置压缩后的图片巨细,如果应用想要指定压缩后图片巨细,可以根据压缩效果调整质量参数,或者将pixelmap scale到更小的尺寸后再压缩。
5、图片编解码支持的格式有哪些
A:办理如下
图片解码
指将所支持格式的存档图片解码成统一的PixelMap,以便在应用或系统中举行图片显示或图片处理。当前支持的存档图片格式包括JPEG、PNG、GIF、RAW、WebP、BMP、SVG。
图片编码
指将PixelMap编码成不同格式的存档图片(当前仅支持编码为JPEG、WebP 和 PNG 格式),用于后续处理,如保存、传输等。
6、怎样将相册选择的图片天生PixelMap
A:如下两种方法
方法一:
创建图库选择器实例,调用select()接口拉起photoPicker界面举行图片选择。图片选择成功后,返回PhotoSelectResult效果集。
通过photoAccessHelper模块中的getAssets接口获取媒体文件对应文件的uri。
调用getThumbnail获取缩略图。
方法二:
创建图库选择器实例,调用select()接口拉起photoPicker界面举行图片选择。图片选择成功后,返回PhotoSelectResult效果集。
待界面从图库返回后,使用fs.openSync接口,通过uri打开这个文件得到fd。这里需要注意接口权限参数是fs.OpenMode.READ_ONLY。
通过image使用image.createImageSource接口创建图片源实例。
然后根据imageSource创建pixelMap。
7、怎样对相册图片举行编辑裁剪
A:可以通过图片处理模块的pixelMap方法对图片举行编辑裁剪。
其中包括但不限于:
pixelMap.crop方法,可以根据输入的尺寸对图片举行裁剪。
pixelMap.opacity方法,可以通过设置透明比率对图片设置透明效果。
pixelMap.scale方法,可以根据输入的宽高对图片举行缩放。
pixelMap.rotate方法,可以根据输入的角度对图片举行旋转。
pixelMap.flip方法,可以根据输入的条件对图片举行翻转。
8、怎样设置图片显示的分辨率
A:可以通过sourceSize属性设置图片分辨率,实例代码如下所示,原图尺寸为1280
960,该示例将图片解码为40
40。
9、怎样保存本舆图片到相册中
A:步调如下
在模块级module.json5中说明权限
"requestPermissions": [
{
"name":
"ohos.permission.CAMERA", "usedScene":
{
"abilities": [
"EntryAbility" ],
"when":
"inuse"
}
,
"reason":
"$string:CAMERA"
}
,
{
"name":
"ohos.permission.READ_IMAGEVIDEO", "usedScene":
{
"abilities": [
"EntryAbility" ],
"when":
"inuse"
}
,
"reason":
"$string:CAMERA"
}
,
{
"name":
"ohos.permission.WRITE_IMAGEVIDEO", "usedScene":
{
"abilities": [
"EntryAbility" ],
"when":
"inuse"
}
,
"reason":
"$string:CAMERA"
}
]
复制代码
获取权限
import { abilityAccessCtrl, PermissionRequestResult, Permissions, bundleManager, common } from '@kit.AbilityKit';
const TAG: string = '[Permission]';
const PERMISSIONS: Array<Permissions> =
['ohos.permission.CAMERA', "ohos.permission.READ_IMAGEVIDEO", "ohos.permission.WRITE_IMAGEVIDEO"];
const context = getContext(this) as common.UIAbilityContext;
export default async function grantPermission(): Promise<boolean> {
try {
let bundleInfo: bundleManager.BundleInfo =
await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;
let tokenId = appInfo.accessTokenId;
let atManager = abilityAccessCtrl.createAtManager();
let pems: Array<Permissions> = [];
for (let i = 0; i < PERMISSIONS.length; i++) {
let state = await atManager.checkAccessToken(tokenId, PERMISSIONS[i]);
if (state !== abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
pems.push(PERMISSIONS[i]);
}
}
if (pems.length > 0) {
let ctx = context
let result: PermissionRequestResult = await atManager.requestPermissionsFromUser(ctx, pems);
let grantStatus: Array<number> = result.authResults;
let length: number = grantStatus.length;
for (let i = 0; i < length; i++) {
if (grantStatus[i] !== 0) {
return false;
}
}
}
return true;
} catch (error) {
return false;
}
}
复制代码
将本舆图片的buffer传入如下存储函数中
async savePicture(buffer: ArrayBuffer): Promise<void> {
let photoAccessHelper: PhotoAccessHelper.PhotoAccessHelper = PhotoAccessHelper.getPhotoAccessHelper(getContext(this) as common.UIAbilityContext);
let options: PhotoAccessHelper.CreateOptions = {
title: Date.now().toString()
};
let photoUri: string = await photoAccessHelper.createAsset(PhotoAccessHelper.PhotoType.IMAGE, 'jpg', options);
console.info(photoUri)
//createAsset的调用需要ohos.permission.READ_IMAGEVIDEO和ohos.permission.WRITE_IMAGEVIDEO的权限
let file: fs.File = fs.openSync(photoUri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
await fs.write(file.fd, buffer);
fs.closeSync(file);
}
复制代码
10、怎样读取相册中的图片
A:使用photoAccessHelper.PhotoSelectOptions接口
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { image } from '@kit.ImageKit';
import { fileIo as fs } from '@kit.CoreFileKit';
@Entry
@Component
struct Index {
@State getAlbum: string = '显示相册中的图片';
@State pixel: image.PixelMap | undefined = undefined;
@State albumPath: string = '';
@State photoSize: number = 0;
async getPictureFromAlbum() {
// 拉起相册,选择图片
let PhotoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
PhotoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;
PhotoSelectOptions.maxSelectNumber = 1;
let photoPicker = new photoAccessHelper.PhotoViewPicker();
let photoSelectResult: photoAccessHelper.PhotoSelectResult = await photoPicker.select(PhotoSelectOptions);
this.albumPath = photoSelectResult.photoUris[0];
// 读取图片为buffer
const file = fs.openSync(this.albumPath, fs.OpenMode.READ_ONLY);
this.photoSize = fs.statSync(file.fd).size;
console.info('Photo Size: ' + this.photoSize);
let buffer = new ArrayBuffer(this.photoSize);
fs.readSync(file.fd, buffer);
fs.closeSync(file);
// 解码成PixelMap
const imageSource = image.createImageSource(buffer);
console.log('imageSource: ' + JSON.stringify(imageSource));
this.pixel = await imageSource.createPixelMap({});
}
build() {
Row() {
Column() {
Image(this.pixel)
.width('100%')
.aspectRatio(1)
Button('显示照片')
.onClick(() => {
this.getPictureFromAlbum();
})
}
.width('100%')
}
.height('100%')
}
}
复制代码
11、怎样把ImageReceiver收到的视频帧数据保存到本地
A:如实例代码所示,在示例代码中保存接收到的前三帧数据,也可以通过业务需要调整。
let size: image.Size = {
width: 640,
height: 480
}
let receiver: image.ImageReceiver = image.createImageReceiver(size, image.ImageFormat.JPEG, 8);
receiver.on('imageArrival', () => {
console.info("imageArrival callback");
receiver.readNextImage((err: BusinessError, nextImage: image.Image) => {
if (err || nextImage === undefined) {
console.error("receiveImage -error:" + err + " nextImage:" + nextImage);
return;
}
nextImage.getComponent(image.ComponentType.JPEG, (err: BusinessError, imgComponent: image.Component) => {
if (err || imgComponent === undefined) {
console.error("receiveImage--getComponent -error:" + err + " imgComponent:" + imgComponent);
return;
}
if (imgComponent.byteBuffer as ArrayBuffer) {
let sourceOptions: image.SourceOptions = {
sourceDensity: 120,
sourcePixelFormat: 8,
sourceSize: {
height: 1080,
width: 1920
},
}
let imageResource = image.createImageSource(imgComponent.byteBuffer, sourceOptions);
let imagePackerApi = image.createImagePacker();
let packOpts: image.PackingOption = { format: "image/jpeg", quality: 90 };
const filePath: string = getContext().cacheDir + "/image.jpg";
let file = fs.openSync(filePath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
imagePackerApi.packToFile(imageResource, file.fd, packOpts).then(() => {
console.error('pack success: ' + filePath);
}).catch((error: BusinessError) => {
console.error('Failed to pack the image. And the error is: ' + error);
})
imageResource.createPixelMap({}).then((res) => {
this.imgUrl = res;
});
} else {
return;
}
nextImage.release();
});
});
});
复制代码
12、为什么获取到的yuv数据量比宽 * 高 * 1.5多
A:这是正通例格,多出来的为YUV尾部数据,不影响YUV数据的解析。
13、怎样保存网络图片到相册
A:步调如下
在模块级module.json5中说明权限
"requestPermissions": [
{
"name":
'ohos.permission.INTERNET', "usedScene":
{
"abilities": [
"EntryAbility" ],
"when":
"inuse"
}
,
"reason":
"$string:reason"
}
,
{
"name":
"ohos.permission.WRITE_IMAGEVIDEO", "usedScene":
{
"abilities": [
"EntryAbility" ],
"when":
"inuse"
}
,
"reason":
"$string:reason"
}
,
]
复制代码
创建如下页面
import { http } from '@kit.NetworkKit'
import { BusinessError } from '@kit.BasicServicesKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { fileIo } from '@kit.CoreFileKit';
import { abilityAccessCtrl, PermissionRequestResult, Permissions, bundleManager, common } from '@kit.AbilityKit';
@Entry
@Component
struct Index {
private PERMISSIONS: Array<Permissions> = ['ohos.permission.INTERNET', "ohos.permission.WRITE_IMAGEVIDEO"];
@State str:string = ''
async grantPermission(): Promise<boolean> {
try {
let bundleInfo: bundleManager.BundleInfo =
await bundleManager.getBundleInfoForSelf(
bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION
);
let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;
let tokenId = appInfo.accessTokenId;
let atManager = abilityAccessCtrl.createAtManager();
let pems: Array<Permissions> = [];
for (let i = 0; i < this.PERMISSIONS.length; i++) {
let state = await atManager.checkAccessToken(tokenId, this.PERMISSIONS[i]);
if (state !== abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
pems.push(this.PERMISSIONS[i]);
}
}
if (pems.length > 0) {
let ctx = getContext(this) as common.UIAbilityContext
let result: PermissionRequestResult = await atManager.requestPermissionsFromUser(ctx, pems);
let grantStatus: Array<number> = result.authResults;
let length: number = grantStatus.length;
for (let i = 0; i < length; i++) {
if (grantStatus[i] !== 0) {
return false;
}
}
}
return true;
} catch (error) {
return false;
}
}
loadImageWithUrl(url: string) {
// 使用request下载图片并在回调函数中保存图片到相册
http.createHttp().request(url,
{
method: http.RequestMethod.GET,
connectTimeout: 60000,
readTimeout: 60000
},
async (error: BusinessError, data: http.HttpResponse) => {
if (error) {
console.error(`http reqeust failed with. Code: ${error.code}, message: ${error.message}`);
} else {
if (http.ResponseCode.OK === data.responseCode) {
let imageBuffer: ArrayBuffer = data.result as ArrayBuffer;
try {
// 获取相册路径
const context = getContext(this);
let helper = photoAccessHelper.getPhotoAccessHelper(context);
let uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg')
let file = await fileIo.open(uri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE)
// 写入文件
await fileIo.write(file.fd, imageBuffer);
// 关闭文件
await fileIo.close(file.fd);
} catch (error) {
console.error("error is " + JSON.stringify(error))
}
} else {
console.error("error occurred when image downloaded!")
}
}
})
}
async aboutToAppear() {
await this.grantPermission().then(async () => {
}).catch((err: BusinessError) => {
console.info(`grantPermission faild ${JSON.stringify(err.code)}`);
})
}
build() {
Row() {
Column() {
TextInput({text:this.str, placeholder: '输入图片地址'})
.onChange((value: string) => {
this.str = value
})
Button('保存图片')
.onClick(() => {
this.loadImageWithUrl(this.str)
})
}
.width('100%')
}
.height('100%')
}
}
复制代码
14、通过OH_Pixelmap_CreatePixelMap创建的对象,内存是怎样分配的
A:通过OH_Pixelmap_CreatePixelMap创建的对象在ArkTS侧和Native侧会共享同一份内存。
15、怎样实现PixelMap和base64的相互转换
A:步调如下
PixelMap转base64:PixelMap转换成base64必须先使用imagePacker将pixelMap压缩后再举行base64转换。若要实现无损压缩,将PixelMap压缩成PNG,即调用imagePacker时,let packOpts: image.PackingOption = { format: 'image/png', quality: 100 };
base64转PixelMap:先将base64字符串解析成arraybuffer,然后利用这个arraybuffer构建新PixelMap,需要注意的是,使用decodeSync对base64字符串解码时,传入的base64字符串不能有'data:image/jpeg;base64,'如许的前缀。
16、怎样将PixelMap压缩到指定巨细以下
A:目前没有直接的接口支持将PixelMap压缩到指定巨细以下,但可以通过循环压缩的方式实现,具体可参考如下方案实现压缩:
调用自界说compressedImage方法,传入要压缩图片的pixelMap和指定图片的压缩目的巨细。
先判定设置图片质量参数quality为0时,packing能压缩到的图片最小字节巨细是否满足指定的图片压缩巨细。如果满足,则使用packing方式二分查找最接近指定图片压缩目的巨细的quality来循环压缩图片。如果不满足,则使用scale对图片先举行缩放,采用while循环每次递减0.4倍缩放图片,再用packing(图片质量参数quality设置0)获取压缩图片巨细,终极查找到最接近指定图片压缩目的巨细的缩放倍数的图片压缩数据。
17、错误码62980096怎么处理
A:pixelFormat罗列目前是给ImageSource用的,所以NV21或者NV12格式的图片如果要创建PixelMap需要通过以下方式:
首先通过createImageSource创建ImageSource。
此处需要设置 createimagesource的sourceOption参数,其中sourcePixelFormat参数的值8对应NV21格式,9对应NV12格式;sourceSize参数需要设置宽高(原始yuv图片的宽高数据),且width值不能为奇数。
然后通过ImageSource的createPixelMap接口创建PixelMap。
18、怎样将C++侧接收的PixelMap转换成cv::mat格式
A:将ArkTS侧传到Native侧的PixelMap转换成cv::mat有两种方法:
将PixelMap的arraybuffer转换成cv::mat。
使用OH_PixelMap_AccessPixels获取PixelMap的内存地点,将这个内存地点中的数据转换为cv::mat。
上述两种方法都必须保证PixelMap的格式与opencv中mat的格式同等,否则会出现色彩的偏差。
19、image.createPixelMap中pixelFormat不见效
A:目前image.createPixelMap默认只能使用BGRA_8888格式处理数据,通过Promise返回效果。后续会提供新接口,可以支持指定输入流格式。
20、怎样将PixelMap保存到相册
A:PixelMap使用imagePacker.packToFile()的方法将ImageSource图片源编码后直接打包进文件。
更多详情及参考代码查察如下:文档中心
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/)
Powered by Discuz! X3.4