范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

鸿蒙上成功调用相机!

  相机是一个系统的基础能力,能够通过调用相机进行拍照,在很多场景下都会使用到相机的调用,如人脸识别门禁,人脸解锁等操作。
  本文主要介绍在 OpenHarmony 应用开发中 ArkUI 开发框架下相机应用的开发。 开发模式:Stage 开发模式 SDK 版本:3.2.2.5 开发环境:DevEco Studio 3.0 Release 3.0.0.993
  相机调用成功如下图:
  实现步骤 ①声明权限在 module.json5 中配置权限:"reqPermissions": [   {         "name": "ohos.permission.LOCATION",       },       {         "name": "ohos.permission.CAMERA"       },       {         "name": "ohos.permission.MICROPHONE"       },       {         "name": "ohos.permission.MEDIA_LOCATION"       },       {         "name": "ohos.permission.WRITE_MEDIA"       },       {         "name": "ohos.permission.READ_MEDIA"       }]在 MainAbility.ts 中调用 requestPermissionsFromUser 方法申请权限:const PERMISSIONS: Array = [     "ohos.permission.CAMERA",     "ohos.permission.MICROPHONE",     "ohos.permission.MEDIA_LOCATION",     "ohos.permission.READ_MEDIA",     "ohos.permission.WRITE_MEDIA",     "ohos.permission.GET_WIFI_INFO ",     "ohos.permission.GET_WIFI_PEERS_MAC ", ]             globalThis.abilityWant = want;         globalThis.context = this.context         globalThis.abilityContext = this.context;  globalThis.context.requestPermissionsFromUser(PERMISSIONS).then((message)=>{             console.log(JSON.stringify(message))         })
  注意:权限需要在页面加载前提前申请,所以需要在调用相机的页面前添加一个过渡的页面。 ②准备工作导包:import camera from "@ohos.multimedia.camera"; import image from "@ohos.multimedia.image"; import fileio from "@ohos.fileio"; import mediaLibrary from "@ohos.multimedia.mediaLibrary" const CameraSize = {   WIDTH: 640,   HEIGHT: 480 }
  定义变量: private mXComponentController = new XComponentController()   private cameraManager: camera.CameraManager = undefined   private cameras: Array = undefined   private cameraId: string = undefined   private mReceiver: image.ImageReceiver = undefined   private cameraInput: camera.CameraInput = undefined   private previewOutput: camera.PreviewOutput = undefined   private mSurfaceId: string = undefined   private photoOutput: camera.PhotoOutput = undefined   private captureSession: camera.CaptureSession = undefined   private mediaUtil: MediaUtil = undefined   @State desStr: string = ""   private fileAsset: mediaLibrary.FileAsset   private surfaceId: number   @State photoUriMedia: string = ""   private photoFlag: boolean = true   @State  imgUrl: string = ""   @State isMediaUrl:boolean=true  //判断保存路径为是沙箱路径或者媒体路径,默认媒体路径   aboutToAppear(){     this.mediaTest = mediaLibrary.getMediaLibrary(globalThis.context)   }
  工具方法: async createAndGetUri(mediaType: number) {     let info = this.getInfoFromType(mediaType)     let dateTimeUtil = new DateTimeUtil()     let name = `${dateTimeUtil.getDate()}_${dateTimeUtil.getTime()}`     let displayName = `${info.prefix}${name}${info.suffix}`     let publicPath = await this.mediaTest.getPublicDirectory(info.directory)     let dataUri = await this.mediaTest.createAsset(mediaType, displayName, publicPath)     return dataUri   }   async getFdPath(fileAsset: any) {     let fd = await fileAsset.open("Rw")     return fd   }   getInfoFromType(mediaType: number) {     let result = {       prefix: "", suffix: "", directory: 0     }     switch (mediaType) {       case mediaLibrary.MediaType.FILE:         result.prefix = "FILE_"         result.suffix = ".txt"         result.directory = mediaLibrary.DirectoryType.DIR_DOCUMENTS         break       case mediaLibrary.MediaType.IMAGE:         result.prefix = "IMG_"         result.suffix = ".jpg"         result.directory = mediaLibrary.DirectoryType.DIR_IMAGE         break       case mediaLibrary.MediaType.VIDEO:         result.prefix = "VID_"         result.suffix = ".mp4"         result.directory = mediaLibrary.DirectoryType.DIR_VIDEO         break       case mediaLibrary.MediaType.AUDIO:         result.prefix = "AUD_"         result.suffix = ".wav"         result.directory = mediaLibrary.DirectoryType.DIR_AUDIO         break     }     return result   }
  工具类: /**  * @file 日期工具  */ export default class DateTimeUtil {      /**    * 时分秒    */     getTime() {         const DATETIME = new Date()         return this.concatTime(DATETIME.getHours(), DATETIME.getMinutes(), DATETIME.getSeconds())     }      /**    * 年月日    */     getDate() {         const DATETIME = new Date()         return this.concatDate(DATETIME.getFullYear(), DATETIME.getMonth() + 1, DATETIME.getDate())     }      /**    * 日期不足两位补充0    * @param value-数据值    */     fill(value: number) {         return (value > 9 ? "" : "0") + value     }      /**    * 年月日格式修饰    * @param year    * @param month    * @param date    */     concatDate(year: number, month: number, date: number) {         return `${year}${this.fill(month)}${this.fill(date)}`     }      /**    * 时分秒格式修饰    * @param hours    * @param minutes    * @param seconds    */     concatTime(hours: number, minutes: number, seconds: number) {         return `${this.fill(hours)}${this.fill(minutes)}${this.fill(seconds)}`     } }
  这个工具类主要是用来进行获取时间对相片进行命名的工具类。 ③构建 UI 组件
  页面主要分为 2 块,左边为相机的 XComponent 组件,右边为图片显示区域。拍完的照片能够显示在右边。
  XComponent 组件作用于 EGL/OpenGLES 和媒体数据写入,并显示在 XComponent 组件。
  相关资料: https://developer.harmonyos.com/cn/docs/documentation/doc-references/ts-basic-components-xcomponent-0000001333800561
  hml 代码如下: build() {     Flex() {       Flex() {         Stack() {           Flex() {             //相机显示的组件             XComponent({               id: "componentId",               type: "surface",               controller: this.mXComponentController             }).onLoad(() => {               this.mXComponentController.setXComponentSurfaceSize({ surfaceWidth: 640, surfaceHeight: 480 })               this.surfaceId = this.mXComponentController.getXComponentSurfaceId()               this.initCamera(this.surfaceId)             })           }.width(800).height(800)           //显示在相机上面的组件:拍照和摄像的图标,摄像的时间           Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.End, alignItems: ItemAlign.Center }) {             if (this.photoFlag) { //拍照               Image($r("app.media.take_photo_normal")).width(50).height(50).onClick(() => {                 this.desStr = "拍照完成"                 this.takePicture()               })             }             Text(this.desStr).fontColor("red").height(30).fontSize(20)           }.width(480).height(480)         }.border({ width: 1, style: BorderStyle.Solid, color: "#000000" })         //右边的控制button和图片显示区域         Flex({           direction: FlexDirection.Column,           justifyContent: FlexAlign.SpaceBetween,           alignItems: ItemAlign.Center,         }) {           Button("选择沙箱路径存储").onClick(()=>{               this.isMediaUrl=false           }) .stateStyles({             normal: { // 设置默认情况下的显示样式               .backgroundColor(Color.Blue)             },             pressed: { // 设置手指摁下时的显示样式               .backgroundColor(Color.Pink)             }           })           Image(decodeURI("file://"+this.imgUrl)).width(480).height(350)//显示沙箱图片           Button("选择媒体路径存储").onClick(()=>{             this.isMediaUrl=true           }) .stateStyles({             normal: { // 设置默认情况下的显示样式               .backgroundColor(Color.Blue)             },             pressed: { // 设置手指摁下时的显示样式               .backgroundColor(Color.Pink)             }           })           Image(decodeURI(this.imgUrl)).width(480).height(350)   //显示媒体图片         }.width(480).height("100%").border({ width: 1, style: BorderStyle.Solid, color: "#000000" })        }.border({ width: 1, style: BorderStyle.Solid, color: "red" })       .width("100%").height("100%")     }     .height("100%").width("100%")   }
  UI 实现了对存储路径的选择,需要存储到沙箱路径还是媒体路径。
  注意:沙箱路径需要加上"file://",查看对应的存储路径步骤: 打开 hdc 命令窗口 cd /data/app/el2/100/base/com.chinasoft.photo/haps/entry/files进入 ls 查看全部文件 ④拍照流程初始化相机:这一步需要在拍照前就进行,一般是在 XComponent 组件的 onLoad() 中进行的。//初始化相机和会话管理   async initCamera(surfaceId: number) {     this.cameraManager = await camera.getCameraManager(globalThis.context)//需要在Ability中定义globalThis.cnotallow=this.context     this.cameras = await this.cameraManager.getCameras()     this.cameraId = this.cameras[1].cameraId     await this.photoReceiver() //创建图片接收器并进行订阅     this.mSurfaceId = await this.mReceiver.getReceivingSurfaceId()     this.cameraInput = await this.cameraManager.createCameraInput(this.cameraId)     this.previewOutput = await camera.createPreviewOutput(surfaceId.toString())     this.photoOutput = await camera.createPhotoOutput(this.mSurfaceId)      this.captureSession = await camera.createCaptureSession(globalThis.context)     await this.captureSession.beginConfig()     await this.captureSession.addInput(this.cameraInput)     await this.captureSession.addOutput(this.previewOutput)     await this.captureSession.addOutput(this.photoOutput)     await this.captureSession.commitConfig()     await this.captureSession.start().then(() => {       console.log("zmw1--Promise returned to indicate the session start success.");     })   }   //创建图片接收器并进行订阅   async photoReceiver() {     this.mReceiver = image.createImageReceiver(CameraSize.WIDTH, CameraSize.HEIGHT, 4, 8)     let buffer = new ArrayBuffer(4096)     this.mReceiver.on("imageArrival", () => {       console.log("zmw -service-imageArrival")       this.mReceiver.readNextImage((err, image) => {         if (err || image === undefined) {           return         }         image.getComponent(4, (errMsg, img) => {           if (errMsg || img === undefined) {             return           }           if (img.byteBuffer) {             buffer = img.byteBuffer           }           if(this.isMediaUrl){             this.savePictureMedia(buffer, image)           }else{             this.savePictureSand(buffer, image)           }         })       })       return buffer     })   }
  如下: 根据 camera 的 getCameraManager 方法获取 CameraManager 通过 CameraManager 获取所有的相机数组,找到可用的相机,并获取相机的 cameraid 创建图片接收器并进行订阅,获取 receiver 的 surfaceId 通过 CameraManager 的 createCameraInput(cameraid) 创建相机输入流 通过 camera 的 createPreviewOutput(sufaceId) 创建相机预览输出流,这里 sufaceId 为 XComponent 的 id 通过 camera 的 createPhotoOutput(sufaceId) 创建相机拍照输出流,这里 sufaceId 为图片接收器的 surfaceId 会话管理:创建会话,并且配置会话的相机输入流,相机拍照输出流与相机预览流,提交配置,开始会话
  至此,相机就能正常的显示出图像了。 用拍照方法拍摄照片://拍摄照片   async takePicture() {     let photoSettings = {       rotation: camera.ImageRotation.ROTATION_0,       quality: camera.QualityLevel.QUALITY_LEVEL_LOW,       mirror: false     }     await this.photoOutput.capture(photoSettings)   }
  调用相机的输出流的 capture 方法进行拍照操作,会触发图片接收器的监听,进行对字节流的写入操作,保存到沙箱或者媒体。 保存图片:分为沙箱路径与媒体路径。//保存沙箱路径   async savePictureSand(buffer: ArrayBuffer, img: image.Image) {     let info = this.mediaUtil.getInfoFromType(mediaLibrary.MediaType.IMAGE)     let dateTimeUtil = new DateTimeUtil()     let name = `${dateTimeUtil.getDate()}_${dateTimeUtil.getTime()}`     let displayName = `${info.prefix}${name}${info.suffix}`     let sandboxDirPath = globalThis.context.filesDir;     let path = sandboxDirPath + "/" + displayName     this.imgUrl=path     let fdSand = await fileio.open(path, 0o2 | 0o100, 0o666);     await fileio.write(fdSand, buffer)     await fileio.close(fdSand).then(()=>{       this.desStr=""     });     await img.release()   } //保存媒体路径   async savePictureMedia(buffer: ArrayBuffer, img: image.Image) {     this.fileAsset = await this.mediaUtil.createAndGetUri(mediaLibrary.MediaType.IMAGE)     this.imgUrl = this.fileAsset.uri     let fd = await this.mediaUtil.getFdPath(this.fileAsset)     await fileio.write(fd, buffer)     await this.fileAsset.close(fd).then(()=>{       this.desStr=""     })     await img.release()   }
  释放相机: //结束释放相机资源   async releaseCamera() {     if (this.captureSession) {       await this.captureSession.stop().then(() => {       })     }     if (this.cameraInput) {       await this.cameraInput.release().then(() => {       })     }     if (this.previewOutput) {       await this.previewOutput.release().then(() => {       })     }     if (this.photoOutput) {       await this.photoOutput.release().then(() => {       })     }     // 释放会话     if (this.captureSession) {       await this.captureSession.release((err) => {         if (err) {           console.error("zmw  Failed to release the CaptureSession instance ${err.message}");           return;         }       });     }   }
  在完成了相机的调用后,需要对相机的资源进行释放,否则再次调用的时候会一直被占用而导致黑屏。
  总结
  OpenHarmony 对于相机的官方使用文档不太清晰,有许多的坑,需要去趟。
  在这个过程中我遇到的问题: 在相机的使用时,由于开发板上的相机获取到了两个,一个是外接 USB 的相机,一个应该是系统的,在获取相机的 id 的时候需要注意。 在保存相机拍照的图片的时候,保存到沙箱路径时显示不到页面上,需要在保存的路径前加上"file://"。
  需要扩展研究的是进行相机的摄像操作,以及相机拍照与摄像的切换操作。
  参考资料: https://gitee.com/openharmony/app_samples/tree/master/media/Scan https://gitee.com/openharmony/applications_camera https://gitee.com/openharmony/docs/blob/OpenHarmony-3.2-Beta3/zh-cn/application-dev/media/camera.md
  作者:张明伟

助听器还有什么售后服务?您好,购买助听器包含了后期的售后服务哦。比如助听器调试保养维修复查听力等。听力是会随着时间以及身体素质的改变而发生变化的,所以定期复测听力是十分重要的。复测听力发现听力改变的话也是在京东上买了台华为电视机,安装后发现屏幕有破损,该怎么维权?我也买了华为电视,送货人员送来后告诉我不要动,等安装人员来再开箱,否则出现问题自己承担。安装人员来开箱了一顿试好了人介让你签个字就走了,后面屏幕和外观要是再出问题就是你自己的事儿了想买一个1k2k的戒指有什么推荐?戒指的种类款式非常多,铂金黄金K金钻戒等等都有,一两千预算少了点,但是也有很多适合的材质和款式。比如排钻戒指AKOYA珍珠戒指等。黄金戒指目前黄金首饰零售价加工费基本是500元一克在乡镇当公务员,每个月4000多元,该不该辞职?对比一下本地乡镇公务员工资水平,你再考虑要不要辞职笑哭笑哭。科员工资,除去五险一金,一个月2500左右,把车补乡镇补贴等所有补贴都加上,也就3700块钱左右,跟你的4000多还差了想移居到黄山市,黄山市有什么优缺点?黄山的缺点就是穷,优点就是大家都穷。优点1,环境质量好。黄山风景秀丽,植被丰富,化工产业不发达,蓝天白云是标配,夏天的时候,一朵朵白云就像棉花糖一样,可漂亮了。2,交通便利。黄山北开车怎么样观察是最安全的?作为新手,昨天10月22日是我开车上路第20天,周末一个人从合肥去南京自驾游,昨天是返程,高速上遇到两个紧急情况,因为事先有观察,紧急时刻处置迅速而且合理,没有发生追尾剐蹭等危险。马自达cx5油耗如何?应该选2。0L还是2。5L?李老猫说车为你非专业解答各种选车用车问题马自达cx5算不上一款特别主流的suv,多少有点叫好不叫座,平均月销量差不多在5千台左右。这款车优缺点都比较分明,优点就是操控性极佳,公路性中秋节超4成酒商销售下跌,茅台酒价格下跌,惨淡中秋的背后暗藏了哪些趋势?应该是老百姓越来越理智,像白酒这种非生活必需品不值得囤积,喝多少买多少,酱酒涨价我喝浓香,再不然喝清香酒。大不了改喝便宜的洋酒,绝不当傻乎乎的韭菜呲牙呲牙今年中秋节是什么过节商品都大闸蟹成大闸泄,旺季遇冷卖不动,咋了?每年金秋之季,也是蟹肥之时。尤其在中秋国庆双节期间,各方面的消费都有提高。很多农副产品销量也迎来销售高峰。每年中秋国庆双节也是大闸蟹销售旺季。很多单位发中秋福利朋友之间的来往自己家王者荣耀是一个公平游戏吗?个人认为这个游戏并不公平,原因如下第一皮肤tm竟然能加额外属性!以前玩lol跟朋友开玩笑说皮肤能加攻击力,结果腾讯真的做到了,所以腾讯所谓的5V5公平对战手游就成了笑柄。第二王者荣什么样的游戏玩家才能够变成NPC?大家好,这里是正经游戏,我是正经小弟。不久前,正经小弟发布了一篇关于硬核玩家将自己玩成游戏NPC的趣味故事,不少玩家留言告诉正经小弟更多的趣味故事,有很多还让小弟很感动,现在小弟将
中式妆盛行婉约有韵味青黛点眉花靥梅妆额黄近年,随着一批优质古装影视作品的上映,具有中国古典风情的精致妆容,令人眼前一亮,唤醒了东方审美眼光。图片源于网络图文无关如今,问起中国的年轻人中正流行什么风格的体态问题导致的副乳怎么有效解决?前几天的宝格丽活动上,Lisa以一头黑色长直发登场。身穿一袭白色低胸礼裙,配上华丽的珠宝,上演了一出克利奥帕特拉复活。结果随着Lisa的活动照的发酵有眼尖的网友发现她的礼服与赵露思看完巴黎路人穿搭才懂,什么是教科书级别的反油腻搭配,快学不管是年轻人还是中年人,又或者老年人,在穿衣打扮上都要远离油腻感。搭配油腻不仅会影响视觉美感,拉低好感,还会让你的气质得不到展现,难看又显邋遢。而提到反油腻穿搭就不能不提巴黎路人了星链巨额补贴被取消,美国自己都看不上,4。2万颗卫星可能失败?马斯克星链计划大家了解多少呢?它诞生之初的目的在于造福全人类。答案真的是如此吗?马斯克星链计划并没有我们想象得那么简单。值得一提的是,近段时间马斯克SpaceX星链申请近60亿元补老坛酸菜团体标准来了,能重拾消费者信任吗?红星资本局注意到,近日,中国调味品协会公布了团体标准老坛酸菜征求意见稿。10月23日,广东省食品安全保障促进会副会长朱丹蓬认为,老坛酸菜团体标准的出台极具意义,对整个酸菜行业的发展阿里巴巴大跌12,再创新低,2年下跌80,市值蒸发5。4万亿港元阿里巴巴港股大跌12,股价创上市以来新低,截至下午2点,阿里巴巴股价最低跌至61。35港元股,跌破了3月份创下的低点,在这个位置股价还能再创新低是出乎意外的。阿里巴巴的这波下跌要追立冬养生秘法抓住半个月关键期吃冬枣,收获一年容颜不老立冬养生秘法抓住半个月关键期吃冬枣,收获一年容颜不老每年到了立冬时刻,很多长寿的老人都不会忘记做一件事吃冬枣。民间流传这样一句话,立冬吃冬枣,一年不变老。这不是虚言。从立冬到小雪这吃得越咸,活得就越长?吃盐也要牢记这3个点日常饮食跟健康关系密切,能掌握方法注重营养获取的人往往抵抗力强,器官功能正常发挥。但有的人饮食重口味,多选择有味道的食物,在煮菜的过程中加入各种调味料吸引味蕾。但长时间重口味饮食行王楚钦夺冠获25万奖金,马龙四个字谈王楚钦,刘国梁没看错人樊振东丢冠原因揭晓,马龙四个字谈王楚钦,刘国梁果然没看错人北京时间10月24日,2022WTT冠军赛正式落下了帷幕。在男单决赛中王楚钦以4比3击败樊振东,也夺得了个人男单冠军。很多签约上海男篮!太意外了,真没想到血布也被NBA给抛弃了签约上海男篮!太意外了,真没想到血布也被NBA给抛弃了!众所周知,想要在全球最顶级篮球联盟NBA打球是一件非常艰难的事情!这里汇集了最顶级的篮球运动员,他们几乎个个都天赋异禀拥有一超过詹姆斯,正负值影响25,湖人终于做了一笔好交易湖人近几个赛季为了补强做了不少交易,但悲剧的是这些交易几乎都失败了,其中以威少的这笔交易最让球迷失望。在今年休赛期,湖人再次对阵容进行了大调整,很多新面孔加入湖人,那么这些新人达到