当前位置: 首页 > news >正文

鸿蒙自定义相机的拍照页面

1、权限申请

    "requestPermissions": [{"name": "ohos.permission.CAMERA","reason": "$string:reason_camera","usedScene": {"abilities": ["EntryAbility"]}},{"name": "ohos.permission.MEDIA_LOCATION","reason": "$string:reason_media_location","usedScene": {"abilities": ["EntryAbility"]}}]

2、ui实现

import { dataSharePredicates } from '@kit.ArkData';
import { abilityAccessCtrl, Permissions } from '@kit.AbilityKit';
import { camera } from '@kit.CameraKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { filePreview } from '@kit.PreviewKit';
import { cameraShooting, capture, getUriAsync, previewPhoto, setPhotoFlashMode } from '../utils/CameraShooter';
import display from '@ohos.display';
import { AppStorageV2, curves } from '@kit.ArkUI';
import { sensor } from '@kit.SensorServiceKit';
import { DegreeConstants } from '../constants/DegreeConstants'let cameraPosition = 0;
let surfaceId = '';
let context = getContext(this);@Entry
@ComponentV2
struct XComponentPage {mXComponentController: XComponentController = new XComponentController;permissions: Array<Permissions> = ['ohos.permission.CAMERA','ohos.permission.MEDIA_LOCATION',];@Local cameraMargin: number = 40@Local cameraHeight: number = 2560@Local isRatio: boolean = true; // true: 16 / 9@Local isFront: boolean = false;@Local photoUri: string | Resource | PixelMap = ''@Local isStabilization: boolean = false;@Local isMovingPhoto: boolean = false;@Local flashPic: ResourceStr = ''textTimerController: TextTimerController = new TextTimerController();@Local rotation: number = 0;@Local moreTools: ResourceStr[] = ['相册', '拍照', '拍视频']@BuilderbottomKeystrokeBuilder() {// 底部拍照翻转相机Row() {Image(this.photoUri).borderWidth(this.photoUri === '' ? 0 : 1).borderColor(Color.White).height(70).width(70).borderRadius(35).rotate({ angle: this.rotation }).animation({ curve: curves.springMotion() }).onClick(() => {if (this.photoUri !== '') {previewPhoto(context);}})// 拍照Column() {Column() {}.width(60).height(60).backgroundColor('#0FD7B8').borderRadius(30)}.width(72).height(72).border({ width: 3, color: Color.White }).borderRadius(36).justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center).onClick(() => {capture(this.isFront);getUriAsync().then(photoUri => {// photoUri 就是你要的图片uri// 可以赋值给 @State/@Local 变量,UI自动刷新this.photoUri = photoUri;console.log('hlasdlkas===' + this.photoUri)});})Column() {Text('翻转').width(28).onClick(async () => {cameraPosition = cameraPosition === 1 ? 0 : 1cameraShooting(cameraPosition, surfaceId, context, this.isRatio);this.Initialize();this.isFront = cameraPosition !== 0;})}.height(70).width(70).justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)}.margin({ top: 20 }).width('100%').justifyContent(FlexAlign.SpaceAround).margin({ bottom: 39 })}@BuilderproportionBuilder() {Row({ space: 20 }) {Text('1:1').height(30).onClick(() => {this.cameraMargin = 100this.cameraHeight = 1440this.isRatio = falsecameraShooting(cameraPosition, surfaceId, context, this.isRatio);this.Initialize();})Text('9:16').height(30).onClick(() => {this.cameraHeight = 2560this.cameraMargin = 40this.isRatio = truecameraShooting(cameraPosition, surfaceId, context, this.isRatio);this.Initialize();})}.margin({ top: 500 })}onPageShow(): void {filePreview.closePreview(context);}async aboutToAppear() {sensor.on(sensor.SensorId.GRAVITY, (data: sensor.GravityResponse) => {let degree: number = -1;degree = this.getCalDegree(data.x, data.y, data.z);if (degree >= 0 && (degree <= DegreeConstants.DEGREE_ONE || degree >= DegreeConstants.DEGREE_FOUR)) {this.rotation = camera.ImageRotation.ROTATION_0;} else if (degree >= DegreeConstants.DEGREE_ONE && degree <= DegreeConstants.DEGREE_TWO) {this.rotation = camera.ImageRotation.ROTATION_270;} else if (degree >= DegreeConstants.DEGREE_TWO && degree <= DegreeConstants.DEGREE_THREE) {this.rotation = camera.ImageRotation.ROTATION_180;} else if (degree >= DegreeConstants.DEGREE_THREE && degree <= DegreeConstants.DEGREE_FOUR) {this.rotation = camera.ImageRotation.ROTATION_90;}})abilityAccessCtrl.createAtManager().requestPermissionsFromUser(context, this.permissions).then(() => {setTimeout(async () => {await cameraShooting(cameraPosition, surfaceId, context, this.isRatio);}, 200);});}aboutToDisappear(): void {sensor.off(sensor.SensorId.GRAVITY);}getCalDegree(x: number, y: number, z: number): number {let degree: number = -1;if ((x * x + y * y) * 3 < z * z) {return degree;}degree = 90 - (Number)(Math.round(Math.atan2(y, -x) / Math.PI * 180));return degree >= 0 ? degree % 360 : degree % 360 + 360;}build() {Stack({ alignContent: Alignment.Top }) {XComponent({ type: XComponentType.SURFACE, controller: this.mXComponentController }).onLoad(async () => {// todo:切换比例,暂时用不到if (this.isRatio === true) {this.mXComponentController.setXComponentSurfaceRect({surfaceWidth: display.getDefaultDisplaySync().width,surfaceHeight: display.getDefaultDisplaySync().width * 16 / 9,offsetY: 0});surfaceId = this.mXComponentController.getXComponentSurfaceId();} else {this.mXComponentController.setXComponentSurfaceRect({surfaceWidth: display.getDefaultDisplaySync().width,surfaceHeight: display.getDefaultDisplaySync().width,});surfaceId = this.mXComponentController.getXComponentSurfaceId();}}).width(px2vp(1440)).height(px2vp(this.cameraHeight)).align(Alignment.Top)Column() {Column() {Row() {Text('x').width(24)Text('拍照').fontWeight(600)Text().width(24)}.width('100%').justifyContent(FlexAlign.SpaceBetween)//比例this.proportionBuilder()// 底部按键this.bottomKeystrokeBuilder()}.width('100%').height(px2vp(display.getDefaultDisplaySync().width * 16 / 9) - 10).justifyContent(FlexAlign.SpaceBetween)// 更多Row() {ForEach(this.moreTools, (item: ResourceStr, index: number) => {Text(item)})}.width('70%').layoutWeight(1).justifyContent(FlexAlign.SpaceBetween).alignItems(VerticalAlign.Center)}.height('100%').align(Alignment.Top).padding({ left: 14, right: 14, top: 10 })}.height('100%').width('100%').backgroundColor(Color.White).padding({ top: 50 }) //顶部安全区}Initialize(): void {this.isStabilization = false;this.isMovingPhoto = false;if (this.isRatio === true) {this.mXComponentController.setXComponentSurfaceRect({surfaceWidth: display.getDefaultDisplaySync().width,surfaceHeight: display.getDefaultDisplaySync().width * 16 / 9, offsetY: 0})} else {this.mXComponentController.setXComponentSurfaceRect({surfaceWidth: display.getDefaultDisplaySync().width,surfaceHeight: display.getDefaultDisplaySync().width})}}switchFlash(flashMode: number): void {setPhotoFlashMode(flashMode);}async getThumbnail(): Promise<void> {let predicates: dataSharePredicates.DataSharePredicates = new dataSharePredicates.DataSharePredicates();predicates.orderByDesc(photoAccessHelper.PhotoKeys.DATE_ADDED);let fetchOptions: photoAccessHelper.FetchOptions = {fetchColumns: [],predicates: predicates};let photoHelper = photoAccessHelper.getPhotoAccessHelper(context);let fetchResult: photoAccessHelper.FetchResult<photoAccessHelper.PhotoAsset> =await photoHelper.getAssets(fetchOptions);if (fetchResult !== undefined) {let photoAsset: photoAccessHelper.PhotoAsset = await fetchResult.getFirstObject();this.photoUri = await photoAsset.getThumbnail();}}
}

3、工具

import { camera } from '@kit.CameraKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { common } from '@kit.AbilityKit';
import { AppStorageV2, display } from '@kit.ArkUI';
import { colorSpaceManager } from '@kit.ArkGraphics2D';let previewOutput: camera.PreviewOutput;
let cameraInput: camera.CameraInput;
let photoSession: camera.PhotoSession;
let photoOutPut: camera.PhotoOutput;
let currentContext: Context;
let uri: string;
let uriWaiters: ((uri: string) => void)[] = [];export async function cameraShooting(cameraPosition: number, surfaceId: string, context: Context, ratio: boolean):Promise<number[]> {currentContext = context;releaseCamera();let cameraManager: camera.CameraManager = camera.getCameraManager(context);if (!cameraManager) {return [];}let cameraArray: camera.CameraDevice[] = cameraManager.getSupportedCameras();if (cameraArray.length <= 0) {return [];}cameraInput = cameraManager.createCameraInput(cameraArray[cameraPosition]);await cameraInput.open();let sceneModes: camera.SceneMode[] = cameraManager.getSupportedSceneModes(cameraArray[cameraPosition]);let cameraOutputCap: camera.CameraOutputCapability =cameraManager.getSupportedOutputCapability(cameraArray[cameraPosition], camera.SceneMode.NORMAL_PHOTO);let isSupportPhotoMode: boolean = sceneModes.indexOf(camera.SceneMode.NORMAL_PHOTO) >= 0;if (!isSupportPhotoMode) {return [];}if (!cameraOutputCap) {return [];}let previewProfilesArray: camera.Profile[] = cameraOutputCap.previewProfiles;let photoProfilesArray: camera.Profile[] = cameraOutputCap.photoProfiles;let previewProfile: undefined | camera.Profile = previewProfilesArray.find((profile: camera.Profile) => {let screen = display.getDefaultDisplaySync();if (screen.width <= 1080) {if (ratio === true) {return profile.size.height === 1080 && profile.size.width === 1920;} else {return profile.size.height === 1080 && profile.size.width === 1080;}} else {if (ratio === true) {return profile.size.height === 1440 && profile.size.width === 2560;} else {return profile.size.height === 1440 && profile.size.width === 1440;}}});let photoProfile: undefined | camera.Profile = photoProfilesArray.find((profile: camera.Profile) => {if (previewProfile) {return profile.size.width <= 4096 && profile.size.width >= 2448;}return undefined;});previewOutput = cameraManager.createPreviewOutput(previewProfile, surfaceId);if (previewOutput === undefined) {return [];}photoOutPut = cameraManager.createPhotoOutput(photoProfile);if (photoOutPut === undefined) {return [];}// Save PicturesetPhotoOutputCb(photoOutPut);photoSession = cameraManager.createSession(camera.SceneMode.NORMAL_PHOTO) as camera.PhotoSession;if (photoSession === undefined) {return [];}photoSession.beginConfig();photoSession.addInput(cameraInput);photoSession.addOutput(previewOutput);photoSession.addOutput(photoOutPut);photoSession.setColorSpace(colorSpaceManager.ColorSpace.DISPLAY_P3);await photoSession.commitConfig();await photoSession.start();let flashStatus: boolean = photoSession.hasFlash();if (flashStatus) {photoSession.setFlashMode(camera.FlashMode.FLASH_MODE_CLOSE);}let focusModeStatus: boolean = photoSession.isFocusModeSupported(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO);if (focusModeStatus) {photoSession.setFocusMode(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO);}let zoomRatioRange = photoSession.getZoomRatioRange();return zoomRatioRange;
}export function capture(isFront: boolean): void {let settings: camera.PhotoCaptureSetting = {quality: camera.QualityLevel.QUALITY_LEVEL_HIGH,rotation: camera.ImageRotation.ROTATION_0,mirror: isFront};photoOutPut.capture(settings);
}export async function setPhotoFlashMode(flashMode: number): Promise<void> {photoSession.setFlashMode(flashMode);
}export async function releaseCamera(): Promise<void> {if (photoSession) {photoSession.stop();}if (cameraInput) {cameraInput.close();}if (previewOutput) {previewOutput.release();}if (photoSession) {photoSession.release();}if (photoOutPut) {photoOutPut.release();}
}function setPhotoOutputCb(photoOutput: camera.PhotoOutput): void {photoOutput.on('photoAssetAvailable',async (_err: BusinessError, photoAsset: photoAccessHelper.PhotoAsset): Promise<void> => {let accessHelper: photoAccessHelper.PhotoAccessHelper =photoAccessHelper.getPhotoAccessHelper(currentContext);let assetChangeRequest: photoAccessHelper.MediaAssetChangeRequest =new photoAccessHelper.MediaAssetChangeRequest(photoAsset);assetChangeRequest.saveCameraPhoto();await accessHelper.applyChanges(assetChangeRequest);uri = photoAsset.uri;// AppStorage.setOrCreate('photoUri', await photoAsset.getThumbnail());uriWaiters.forEach(fn => fn(uri));uriWaiters = [];});
}export function getUriAsync(): Promise<string> {return new Promise(resolve => {uriWaiters.push(resolve);});
}export function previewPhoto(context: Context): void {let photoContext = context as common.UIAbilityContext;photoContext.startAbility({parameters: { uri: uri },action: 'ohos.want.action.viewData',bundleName: 'com.huawei.hmos.photos',abilityName: 'com.huawei.hmos.photos.MainAbility'})
}

http://www.lryc.cn/news/578968.html

相关文章:

  • 深入理解 LoRA:大语言模型微调的低秩魔法
  • 智能合约状态快照技术:实现 EVM 状态的快速同步与回滚
  • YOLOv8模型结构构件及问题汇总【持久更新】
  • HarmonyOS应用开发高级认证知识点梳理 (四)状态管理V2应用级状态
  • 商品中心—18.库存分桶的一致性改造文档
  • GIT基础命令和分支管理
  • Linux环境下使用 C++ 与 OpenCV 实现 ONNX 分类模型推理
  • ESP32与树莓派C++、Rust开发实战
  • 在米联客4EV上部署tinyriscv
  • 高速公路闲置土地资源化利用:广西浦北互通3MW分布式光伏监控实践
  • 基于大模型的急性重症胰腺炎全流程预测与诊疗方案研究
  • 从暴力穷举到智能导航,PC本地搜索被腾讯电脑管家“拯救”
  • 云原生环境下部署大语言模型服务:以 DeepSeek 为例的实战教程
  • Linux操作系统之文件(一):重识IO
  • 解决Linux下根目录磁盘空间不足的问题
  • 基于Cox风险比例模型的会员用户流失预测研究
  • [云上玩转Qwen3系列之四]PAI-LangStudio x AI搜索开放平台 x ElasticSearch: 构建AI Search RAG全栈应用
  • CLIP heat map generation
  • vue中的toRef
  • SpringBoot控制反转
  • 无人机AI制导模块运行方式概述
  • Docker Desktop导致存储空间不足时的解决方案
  • 阿里巴巴Java开发手册(1.3.0)
  • Python数据解析与图片下载工具:从JSON到本地文件的自动化流程
  • 买卖股票的最佳时机--js 算法
  • Nginx、Spring Cloud Gateway 与 Higress 的应用场景及核心区别
  • 从0到1:我的飞算JavaAI实战之旅,效率飙升10倍不是梦!
  • 【Rancher Server + Kubernets】- Nginx-ingress日志持久化至宿主机
  • uniapp项目中node_modules\sass\sass.dart.js的体积过大怎么处理
  • LeetCode[617]合并二叉树