12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034 |
- /*
- * 相机控制
- * */
- import router from '@ohos.router';
- import image from '@ohos.multimedia.image';
- import fs from "@ohos.file.fs"
- import CommonEventManager from '@ohos.commonEventManager'
- import promptAction from '@ohos.promptAction';
- import { ConfirmDialogParams } from '../viewmodel/ConfirmDialogParam';
- import { ConfirmDialog } from '../view/ConfirmDialog';
- import { PreviewManager } from '../common/util/PreviewManager';
- const TAG = "sony_camera info"
- @Entry
- @Component
- struct CameraControl {
- @StorageLink('CameraStatus') cameraStatus: boolean = false;
- commonDialogController: CustomDialogController | null = null;
- build() {
- Row() {
- Column() {
- Row() {
- }.width('100%')
- .height('3.4%')
- Row(){
- Row() {
- Image($r('app.media.general_return'))
- .height($r('app.float.virtualSize_56'))
- .width($r('app.float.virtualSize_56'))
- .fillColor($r('app.color.FFFFFF'))
- Text('图像采集')
- .fontColor($r('app.color.FFFFFF'))
- .fontSize($r('app.float.fontSize_30'))
- }
- .width('75%')
- .justifyContent(FlexAlign.Start)
- .margin({ left: '3%' })
- .onClick(() => {
- router.back()
- })
- } .height('4%').width('100%').justifyContent(FlexAlign.Start)
- Row(){
- Column(){
- Row(){
- Image($r('app.media.device_multimedia_acquisition'))
- .width('70%')
- .objectFit(ImageFit.Contain)
- .interpolation(ImageInterpolation.High)
- }
- .height('40%')
- .width('100%')
- //.margin({top:'5%'})
- .alignItems(VerticalAlign.Bottom)
- .justifyContent(FlexAlign.Center)
- Column({space:10}){
- InfoRow({
- label:"编号:",
- value:"DF441AS114F5555",
- })
- InfoRow({
- label:"状态:",
- value:this.cameraStatus?"在线":"离线",
- valueColor:$r('app.color.30D158')
- })
- InfoRow({
- label:"计量有效期:",
- value:"2024/11/11~2025/11/11",
- })
- InfoRow({
- label:"像素:",
- value:"2420万像素",
- })
- InfoRow({
- label:"数码变焦:",
- value:"8倍",
- })
- InfoRow({
- label:"对焦方式:",
- value:"自动对焦",
- })
- InfoRow({
- label:"闪光模式:",
- value:"自动,不闪光,强制闪光",
- })
- }.justifyContent(FlexAlign.Start).margin({left:'10%'})
- }.width('22%').justifyContent(FlexAlign.SpaceAround).height('100%')
- Divider()
- .vertical(true)
- .strokeWidth(1)
- .color($r('app.color.15FFFFFF'))
- .margin({top:'10%'})
- Column(){
- CameraDialog({})
- .height('90%')
- }.justifyContent(FlexAlign.SpaceAround).margin({top:'5%'})
- .height('100%')
- .width('70%')
- }.height('80%').width('100%').justifyContent(FlexAlign.SpaceAround)
- }
- .width('100%')
- .height('100%')
- .backgroundColor($r('app.color.000000'))
- }
- .height('100%')
- }
- }
- @Component
- struct InfoRow {
- label: string = ''
- @Prop value: string = ''
- valueColor?: Resource = $r('app.color.FFFFFF') // 默认白色,可覆盖
- build() {
- Row({ space: 5 }) {
- Circle()
- .width($r('app.float.virtualSize_5'))
- .height($r('app.float.virtualSize_5'))
- .fill($r('app.color.FFFFFF'))
- Text(this.label)
- .fontColor($r('app.color.FFFFFF'))
- .fontSize($r('app.float.fontSize_16'))
- Text(this.value)
- .fontColor(this.valueColor)
- .fontSize($r('app.float.fontSize_16'))
- }
- .width('100%')
- }
- }
- @Component
- export struct CameraDialog {
- private scrollerPhoto: Scroller = new Scroller()
- //
- @State isExpanded: boolean = false
- //闪光模式 0:自动 1:开启 2:关闭
- @State selectedFlashMode:number = 0
- //选择的照片索引
- @State selectedPhotoIndex:number = -1
- //拍照按键缩放
- @State shootButtonClick:number =1
- // 旋转角度
- @State rotateAngle: number = 0
- // 照片缩放比例
- @State scaleValue: number = 1
- // 照片X轴偏移
- @State offsetX: number = 0
- // 照片Y轴偏移
- @State offsetY: number = 0
- // 照片上次缩放值
- @State lastScale: number = 1
- // 照片上次X偏移
- @State lastOffsetX: number = 0
- // 照片上次Y偏移
- @State lastOffsetY: number = 0
- //双指缩放的中心点X
- @State pinchCenterX: number = 0;
- //双指缩放的中心点Y
- @State pinchCenterY: number = 0;
- // 照片列表
- //@State photoList:DrawingInfo[]=[]
- // 获取本地live照片
- @State commodityPixelMap: PixelMap | null = null;
- // 拍照动作是否完成
- @State isCapturing: boolean = false;
- // 是否停止预览
- @State isStopView: boolean = false;
- // 控制帧率
- @State readTimer:number = 0
- // 预览操作
- private previewManager: PreviewManager | null = null;
- @State photoPixelMaps: photoInfo[] = []; // 存储所有照片的 PixelMap
- // 加载照片并生成 PixelMap
- loadPhotos = async () => {
- const context = getContext(this);
- console.info(TAG, '开始加载照片', context.filesDir);
- try {
- const localImageDir = `${context.filesDir}/`;
- // 检查目录是否存在
- if (!fs.accessSync(localImageDir)) {
- console.warn(TAG, "目录不存在");
- return;
- }
- // 获取目录下所有文件
- const files = fs.listFileSync(localImageDir);
- const newPixelMaps: photoInfo[] = [];
- // 加载所有以image_开头的图片
- for (const file of files) {
- // 只处理以image_开头的文件
- if (!file.startsWith('image_') || !file.endsWith('.jpg')) {
- continue;
- }
- const filePath = `${localImageDir}${file}`;
- try {
- const imageSource = image.createImageSource(filePath);
- const imageInfo = await imageSource.getImageInfo();
- const scaleRatio = Math.min(600 / imageInfo.size.width, 800 / imageInfo.size.height);
- const thumbnailOpts: image.InitializationOptions = {
- size: {
- width: Math.floor(imageInfo.size.width * scaleRatio),
- height: Math.floor(imageInfo.size.height * scaleRatio)
- }
- }
- const pixelMap = await imageSource.createPixelMap(thumbnailOpts);
- const timestamp = this.parseTimestampFromFilename(file);
- newPixelMaps.push({
- pixelMap: pixelMap,
- timestamp: timestamp,
- filename: file
- });
- imageSource.release();
- } catch (err) {
- console.error(TAG, `加载图片 ${file} 失败:`, err);
- }
- }
- // 按时间戳降序排序
- newPixelMaps.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
- this.photoPixelMaps = newPixelMaps;
- } catch (err) {
- console.error(TAG, "加载照片失败:", err);
- }
- };
- private parseTimestampFromFilename(filename: string): string {
- if (!filename.startsWith("image_") || !filename.endsWith(".jpg")) {
- return "";
- }
- const dateTimePart = filename.substring(6, filename.length - 4);
- if (dateTimePart.length !== 15) {
- return "";
- }
- const datePart = dateTimePart.substring(0, 8);
- const timePart = dateTimePart.substring(9);
- const year = datePart.substring(0, 4);
- const month = datePart.substring(4, 6);
- const day = datePart.substring(6, 8);
- const hour = timePart.substring(0, 2);
- const minute = timePart.substring(2, 4);
- const second = timePart.substring(4);
- return `${year}/${month}/${day} ${hour}:${minute}:${second}`;
- }
- private releaseAllPixelMaps() {
- this.photoPixelMaps.forEach(item => item.pixelMap?.release());
- this.photoPixelMaps = [];
- }
- // 删除照片
- deletePhoto = async (index: number) => {
- try {
- const context = getContext(this);
- const photoToDelete = this.photoPixelMaps[index];
- const filePath = `${context.filesDir}/${photoToDelete.filename}`;
- console.info(TAG, `要删除文件: ${filePath}`);
- // 1. 删除物理文件
- fs.unlinkSync(filePath);
- console.info(TAG, `已删除文件: ${filePath}`);
- // 2. 释放PixelMap资源
- photoToDelete.pixelMap.release();
- // 3. 从数组中移除
- const newPhotoList = [...this.photoPixelMaps];
- newPhotoList.splice(index, 1);
- this.photoPixelMaps = newPhotoList;
- // 4. 处理选中的照片索引
- if (this.photoPixelMaps.length === 0) {
- // 如果所有照片都删完了
- this.selectedPhotoIndex = -1;
- this.startView();
- } else {
- // 还有照片剩余的情况
- if (this.selectedPhotoIndex === index) {
- // 当前删除的是正在显示的照片
- if (index > 0) {
- // 如果不是第一张,显示前一张
- this.selectedPhotoIndex = index - 1;
- } else {
- // 如果是第一张,显示下一张(现在index=0,所以下一张也是0)
- this.selectedPhotoIndex = 0;
- }
- } else if (this.selectedPhotoIndex > index) {
- // 删除的照片在当前显示照片之前,需要调整索引
- this.selectedPhotoIndex -= 1;
- }
- // 如果删除的照片在当前显示照片之后,不需要调整索引
- }
- promptAction.showToast({
- message: '照片删除成功',
- duration: 2000
- });
- } catch (err) {
- console.error(TAG, "删除照片失败:", err.code);
- promptAction.showToast({
- message: '删除照片失败',
- duration: 2000
- });
- }
- };
- //创建订阅者
- subscriber: CommonEventManager.CommonEventSubscriber | null = null;
- //订阅相机回调
- subscribeInfo: CommonEventManager.CommonEventSubscribeInfo = { events: ["sonycamera_callback"] };
- //提示确认弹窗
- commonDialogController: CustomDialogController | null = null;
- private showConfirmDialog(params: ConfirmDialogParams) {
- if (this.commonDialogController) {
- this.commonDialogController.close()
- }
- this.commonDialogController = new CustomDialogController({
- builder: ConfirmDialog({
- title: params.title || '提示',
- message: params.message,
- onConfirm: params.onConfirm
- }),
- cancel: () => console.log('用户取消操作'),
- customStyle: true,
- autoCancel:false,
- maskColor: 'rgba(0,0,0,0.6)'
- });
- this.commonDialogController.open();
- }
- //订阅回调(code=3代表连接成功,code=2代表拍照成功)
- createSubscriber = async () => {
- this.subscriber = await CommonEventManager.createSubscriber(this.subscribeInfo);
- if (this.subscriber) {
- console.info(TAG, "创建订阅回调成功");
- CommonEventManager.subscribe(this.subscriber, (err, data) => {
- if (err?.code) {
- console.error(TAG, "SubscribeCallBack err=" + JSON.stringify(err));
- return;
- }
- console.info(TAG, "SubscribeCallBack data=" + JSON.stringify(data));
- if (data?.code !== undefined) {
- switch (data.code) {
- case 2:
- this.loadPhotos()
- this.isCapturing =false
- this.startView(); // 拍照成功
- break;
- case 3:
- console.info(TAG, "开始预览");
- this.startView(); // 连接成功
- break;
- case -1:
- console.info(TAG,'连接故障')
- break;
- case 5:
- console.info(TAG,'暂停预览')
- break;
- }
- }
- //0001:自动闪光 0002:关闭闪光 0003:开启闪光
- if (data?.parameters?.flash_mode) {
- const flashMode:string = data.parameters.flash_mode
- console.info(TAG, `收到闪光模式: ${flashMode}`);
- switch (flashMode) {
- case '0001':
- this.selectedFlashMode = 0
- break;
- case '0002':
- this.selectedFlashMode = 2
- break;
- case '0003':
- this.selectedFlashMode = 1
- break;
- default:
- console.warn(TAG, `未知闪光模式: ${flashMode}`);
- }
- }
- });
- }
- };
- //旋转照片
- private rotateImage(angle: number) {
- this.offsetX = 0;
- this.offsetY = 0;
- this.rotateAngle += angle
- if (this.rotateAngle >= 360) {
- this.rotateAngle -= 360
- } else if (this.rotateAngle < 0) {
- this.rotateAngle += 360
- }
- if(this.rotateAngle==90||this.rotateAngle==270)
- {
- this.scaleValue=0.667
- }else {
- this.scaleValue=1
- }
- }
- // 重置图片变换
- private resetImageTransform() {
- this.rotateAngle = 0
- this.scaleValue = 1
- this.offsetX = 0
- this.offsetY = 0
- this.lastScale = 1
- this.lastOffsetX = 0
- this.lastOffsetY = 0
- }
- //连接相机
- connectCamera = async () => {
- CommonEventManager.publish("opensession", (err) => {
- if (err?.code) {
- console.info(TAG,"Publish openSession err=" + JSON.stringify(err))
- } else {
- console.info(TAG,"Publish openSession succeed ")
- this.queryFlashMode();
- }
- })
- }
- //查询闪光模式
- queryFlashMode = async () => {
- CommonEventManager.publish("queryflashmode", (err) => {
- if (err?.code) {
- console.info(TAG,"Publish queryflashmode err=" + JSON.stringify(err))
- } else {
- console.info(TAG,"Publish queryflashmode succeed ")
- }
- })
- }
- //开始预览
- startView=async()=>{
- CommonEventManager.publish("startview", (err) => {
- if (err?.code) {
- console.error(TAG, JSON.stringify(err));
- } else {
- console.info(TAG, 'publish startview succeed');
- this.isStopView =false;
- this.liveShow();
- }
- });
- }
- //停止预览
- stopView=async()=>{
- CommonEventManager.publish("stopview", (err) => {
- if (err?.code) {
- console.error(TAG, JSON.stringify(err));
- } else {
- this.isStopView =true;
- console.info(TAG, 'publish stopview succeed');
- if (this.readTimer) {
- clearInterval(this.readTimer);
- this.readTimer = 0 ;
- }
- }
- });
- }
- //重连相机
- reconnectCamera=async()=>{
- this.showConfirmDialog({
- title: '重连USB',
- message: `请重连USB后点击确定!`,
- onConfirm: async()=> {
- await new Promise<void>((resolve, reject) => {
- CommonEventManager.publish("stopview", (err) => {
- if (err) return reject(err);
- CommonEventManager.publish("closesession", (err) => {
- err ? reject(err) : resolve();
- });
- });
- });
- await new Promise<void>((resolve, reject) => {
- CommonEventManager.publish("reconnect", (err) => {
- if (err) return reject(err);
- resolve();
- });
- });
- promptAction.showToast({
- message: '相机正在重连中...',
- duration: 3000,
- bottom: 500
- });
- await sleep(3000);
- await this.connectCamera()
- //await this.liveShow()
- }
- });
- }
- liveShow = async () => {
- let index = 0;
- let retryCount = 0;
- const MAX_RETRIES = 10; // 最大重试次数
- const previewLoop = async () => {
- if (!this.isStopView && !this.isCapturing) {
- try {
- const success = await this.previewManager!.processFrame(index);
- if (success) {
- this.commodityPixelMap = await this.previewManager!.getActiveBuffer();
- retryCount = 0;
- } else {
- retryCount++;
- console.warn(TAG, "processFrame失败");
- }
- } catch (error) {
- retryCount++;
- console.warn(TAG, "预览更新失败:", error);
- }
- }
- if (retryCount === MAX_RETRIES) {
- clearInterval(this.readTimer)
- this.readTimer = 0;
- console.info(TAG,"GG")
- return;
- //this.reconnectCamera();
- }
- if (this.readTimer !== 0) { // 检查是否应该继续循环
- this.readTimer = setTimeout(previewLoop, 50);
- }
- };
- this.readTimer = setTimeout(previewLoop, 50);
- };
- //断开相机(停止预览->关闭连接)
- disconnectCamera = async () => {
- if(!this.isStopView)
- {
- await this.stopView()
- }
- CommonEventManager.publish("closesession", (err) => {
- if (err?.code) {
- console.info(TAG,"Publish closesession err=" + JSON.stringify(err))
- } else {
- console.info(TAG,"Publish closesession succeed ")
- }
- })
- }
- //拍照(停止预览->拍照->开始预览)
- takePhoto = async () => {
- this.isStopView = true;
- this.isCapturing = true;
- CommonEventManager.publish("stopview", (err) => {
- if (err?.code) {
- console.info(TAG,"Publish stopview err=" + JSON.stringify(err));
- } else {
- console.info(TAG,"Publish Publish stopview succeed");
- CommonEventManager.publish("shootandsave", (err) => {
- if (err?.code) {
- console.info(TAG,"Publish shootandsave error=" + JSON.stringify(err));
- } else {
- console.info(TAG,"Publish Publish shootandsave succeed");
- }
- });
- }
- });
- };
- //设置闪光模式
- setFlashMode = (mode: 'openflash' | 'closeflash' | 'autoflash') => {
- this.isStopView = true;
- CommonEventManager.publish("stopview", (err) => {
- if (err?.code) {
- console.info(TAG,"Publish stopview err=" + JSON.stringify(err));
- } else {
- console.info(TAG,"Publish Publish stopview succeed");
- CommonEventManager.publish(mode, (err) => {
- if (err?.code) {
- console.info(TAG,"Publish flashmode error=" + JSON.stringify(err));
- } else {
- console.info(TAG,"Publish Publish flashmode succeed");
- CommonEventManager.publish("startview", (err) => {
- this.isStopView = false;
- if (err?.code) {
- console.info(TAG,"Publish startview error=" + JSON.stringify(err));
- }else{
- console.info(TAG,"Publish Publish startview succeed");
- }
- })
- }
- });
- }
- });
- }
- private adjustOffsetWithAnimation() {
- const isRotated = (this.rotateAngle === 90 || this.rotateAngle === 270);
- //旋转90度或者70度 宽度0.667倍,长度超过1.5倍才拖动
- let moveScaleY = (this.scaleValue - (isRotated ? 0.667 : 1)) / 2;
- let moveScaleX = (this.scaleValue - (isRotated ? 1.50 : 1)) / 2;
- let maxOffsetX = (this.scaleValue<1.5&&isRotated) ?this.offsetX: (isRotated ? 506 : 760) * moveScaleX;
- let maxOffsetY = (isRotated ? 760 : 506) * moveScaleY; //rk3588
- // let maxOffsetX = (this.scaleValue<1.5&&isRotated) ?this.offsetX: (isRotated ? 1018 : 1524) * moveScaleX;
- // let maxOffsetY = (isRotated ? 1524 : 1018) * moveScaleY; //rk3568
- //console.info(TAG,"maxOffsetX",maxOffsetX,"scale",this.scaleValue,"offsetx",this.offsetX)
- const clampedX = Math.max(-maxOffsetX, Math.min(maxOffsetX, this.offsetX));
- const clampedY = Math.max(-maxOffsetY, Math.min(maxOffsetY, this.offsetY));
- if (this.offsetX !== clampedX || this.offsetY !== clampedY) {
- animateTo({
- duration: 100,
- curve: Curve.EaseOut
- }, () => {
- this.offsetX = clampedX;
- this.offsetY = clampedY;
- });
- }
- }
- //上传照片
- uploadPhoto=()=>{
- }
- async aboutToAppear() {
- this.previewManager = new PreviewManager(getContext(this));
- this.loadPhotos();
- await this.createSubscriber();
- await sleep(50)
- await this.connectCamera();
- }
- aboutToDisappear(): void {
- this.disconnectCamera()
- if (this.previewManager) {
- this.previewManager.release();
- this.previewManager = null
- }
- if (this.subscriber) {
- CommonEventManager.unsubscribe(this.subscriber);
- }
- this.releaseAllPixelMaps()
- if (this.commodityPixelMap) {
- this.commodityPixelMap.release();
- this.commodityPixelMap = null;
- }
- }
- build() {
- Row() {
- Stack(){
- if (this.commodityPixelMap) {
- if (this.selectedPhotoIndex === -1) {
- Image(this.commodityPixelMap)
- .width('100%')
- .height('100%')
- .objectFit(ImageFit.Fill)
- }
- }
- if(this.isCapturing){
- Column() {
- Text('正在拍照中...')
- .fontSize($r('app.float.fontSize_30'))
- .margin({bottom:'10%'})
- LoadingProgress()
- .color(Color.Blue)
- .width('25%')
- .width('25%')
- }
- .height('30%')
- .width('25%')
- .backgroundColor(Color.White)
- .borderRadius($r('app.float.virtualSize_16'))
- .justifyContent(FlexAlign.Center)
- }
- if(this.selectedPhotoIndex === -1){
- Row() {
- Image(
- this.selectedFlashMode === 0 ? $r('app.media.process_flash_auto') :
- this.selectedFlashMode === 1 ? $r('app.media.process_flash_open') :
- $r('app.media.process_flash_close')
- )
- .width($r('app.float.virtualSize_48'))
- .height($r('app.float.virtualSize_48'))
- .enabled(!this.isCapturing)
- .onClick(() => {
- this.isExpanded = !this.isExpanded
- })
- .margin({right:'5%'})
- if (this.isExpanded) {
- Row() {
- Row(){
- Text('自动')
- .fontSize($r('app.float.fontSize_24'))
- .fontColor(this.selectedFlashMode===0?$r('app.color.FFFFFF'):$r('app.color.60FFFFFF'))
- }
- .width('33.3%')
- .height('100%')
- .justifyContent(FlexAlign.Center)
- .borderRadius($r('app.float.virtualSize_16'))
- .backgroundColor(this.selectedFlashMode===0?$r('app.color.0A84FF'):$r('app.color.60000000'))
- .onClick(() => {
- this.setFlashMode('autoflash')
- this.isExpanded = false
- this.selectedFlashMode = 0
- })
- Row(){
- Text('开启')
- .fontSize($r('app.float.fontSize_24'))
- .fontColor(this.selectedFlashMode===1?$r('app.color.FFFFFF'):$r('app.color.60FFFFFF'))
- }
- .width('33.3%')
- .height('100%')
- .justifyContent(FlexAlign.Center)
- .borderRadius($r('app.float.virtualSize_16'))
- .backgroundColor(this.selectedFlashMode===1?$r('app.color.0A84FF'):$r('app.color.60000000'))
- .onClick(() => {
- this.setFlashMode('openflash')
- this.isExpanded = false
- this.selectedFlashMode = 1
- })
- Row(){
- Text('关闭')
- .fontSize($r('app.float.fontSize_24'))
- .fontColor(this.selectedFlashMode===2?$r('app.color.FFFFFF'):$r('app.color.60FFFFFF'))
- }
- .width('33.3%')
- .height('100%')
- .justifyContent(FlexAlign.Center)
- .borderRadius($r('app.float.virtualSize_16'))
- .backgroundColor(this.selectedFlashMode===2?$r('app.color.0A84FF'):$r('app.color.60000000'))
- .onClick(() => {
- this.setFlashMode('closeflash')
- this.isExpanded = false
- this.selectedFlashMode = 2
- })
- }
- .animation({ duration: 300, curve: Curve.EaseOut })
- .backgroundColor($r('app.color.60000000'))
- .borderRadius($r('app.float.virtualSize_16'))
- .width('85%')
- .height('100%')
- }
- }
- .justifyContent(FlexAlign.Start)
- .alignItems(VerticalAlign.Bottom)
- .position({ x: '2%', y: '92%' })
- .height('5%')
- .width('24%')
- Image(this.shootButtonClick===1?$r('app.media.process_no_shoot'):$r('app.media.process_shoot'))
- .width($r('app.float.virtualSize_88'))
- .height($r('app.float.virtualSize_88'))
- .scale({ x: this.shootButtonClick, y: this.shootButtonClick })
- .borderRadius($r('app.float.fontSize_16'))
- .enabled(!this.isCapturing)
- .animation({
- duration: 200,
- curve: Curve.Linear
- })
- .onClick(() => {
- this.shootButtonClick = 0.9;
- setTimeout(() => {
- this.shootButtonClick = 1;
- }, 200);
- this.takePhoto();
- })
- .position({ x: '48%', y: '90%' })
- Row(){
- Text("重连相机")
- .fontColor($r('app.color.FFFFFF'))
- .fontSize($r('app.float.fontSize_24'))
- }
- .width('10%')
- .height('6%')
- .backgroundColor($r('app.color.60000000'))
- .position({ x: '88%', y: '91%' })
- .borderRadius($r('app.float.virtualSize_16'))
- .enabled(!this.isCapturing)
- .justifyContent(FlexAlign.Center)
- .onClick(()=>{
- this.reconnectCamera()
- })
- }
- else{
- Stack() {
- Image(this.photoPixelMaps[this.selectedPhotoIndex].pixelMap)
- .width('100%')
- .height('100%')
- .autoResize(true)
- // .onComplete((event) => {
- // console.info(TAG,"width:"+event!.componentWidth +"height:"+ event!.componentHeight)
- // }) // 获取Image组件的长宽(除以1.5获取vp)
- .objectFit(ImageFit.Fill)
- .rotate({ angle: this.rotateAngle })
- .scale({ x: this.scaleValue, y: this.scaleValue })
- .borderRadius($r('app.float.virtualSize_16'))
- .translate({ x: this.offsetX, y: this.offsetY })
- .gesture(
- GestureGroup(GestureMode.Exclusive,
- PinchGesture()
- .onActionStart((event: GestureEvent) => {
- this.lastScale = this.scaleValue;
- this.lastOffsetX = this.offsetX;
- this.lastOffsetY = this.offsetY;
- // 记录双指中心点(相对于图片中心)
- this.pinchCenterX = event.pinchCenterX - 380 - 760 / 2;//rk3588
- this.pinchCenterY = event.pinchCenterY - 130 - 506 / 2;//rk3588
- // this.pinchCenterX = event.pinchCenterX - 1016 / 2; //rk3568
- // this.pinchCenterY = event.pinchCenterY - 678 / 2; //rk3568
- // console.info(TAG,this.pinchCenterX,TAG,this.pinchCenterY)
- })
- .onActionUpdate((event: GestureEvent) => {
- let newScale = this.lastScale * event.scale;
- //保持双指中心点不变
- const scaleRatio = newScale / this.lastScale;
- const newOffsetX = this.lastOffsetX + (1 - scaleRatio) * this.pinchCenterX;
- const newOffsetY = this.lastOffsetY + (1 - scaleRatio) * this.pinchCenterY;
- this.offsetX = newOffsetX;
- this.offsetY = newOffsetY;
- this.scaleValue = newScale;
- })
- .onActionEnd(() => {
- // 缩放最小比例为1
- if (this.scaleValue < 1) {
- // 旋转90°或者270°的最小缩小比例为0.667
- if(this.rotateAngle==90||this.rotateAngle==270) {
- if(this.scaleValue<0.667){
- this.scaleValue = 0.667
- }
- } else {
- this.scaleValue = 1
- }
- }
- // 缩放最大比例为3
- if (this.scaleValue > 3) this.scaleValue = 3
- this.adjustOffsetWithAnimation()
- }),
- // 单指滑动手势
- PanGesture()
- .onActionStart(() => {
- if(this.rotateAngle === 90 || this.rotateAngle === 270)
- {
- if (this.scaleValue <= 0.667)
- {
- return;
- }
- }else{
- if (this.scaleValue <= 1) return;
- }
- this.lastOffsetX = this.offsetX;
- this.lastOffsetY = this.offsetY;
- })
- .onActionUpdate((event: GestureEvent) => {
- if(this.rotateAngle === 90 || this.rotateAngle === 270)
- {
- if (this.scaleValue <= 0.667)
- {
- return;
- }
- }else{
- if (this.scaleValue <= 1) return;
- }
- let dx = event.offsetX;
- let dy = event.offsetY;
- const sensitivity = 0.5 * this.scaleValue;
- // 临时计算新位置
- let newOffsetX = this.lastOffsetX;
- let newOffsetY = this.lastOffsetY;
- newOffsetX += dx * sensitivity;
- newOffsetY += dy * sensitivity;
- this.offsetX = newOffsetX;
- this.offsetY = newOffsetY;
- //console.info(TAG,this.offsetX,TAG,this.offsetY)
- })
- .onActionEnd(() => {
- const isRotated = (this.rotateAngle === 90 || this.rotateAngle === 270);
- if(isRotated)
- {
- if(this.scaleValue<=1.5)
- {
- this.offsetX = 0
- }
- }else{
- if (this.scaleValue <= 1) {
- // 如果缩放比例<=1,直接重置位置
- this.offsetX = 0;
- this.offsetY = 0;
- return;
- }
- }
- this.adjustOffsetWithAnimation()
- })
- )
- )
- }
- .width('100%')
- .height('100%')
- .borderRadius($r('app.float.virtualSize_16'))
- .clip(true)
- Row()
- {
- Row(){
- Image($r('app.media.process_back_camera'))
- .width($r('app.float.virtualSize_80'))
- .height($r('app.float.virtualSize_80'))
- .onClick(()=>{
- this.selectedPhotoIndex=-1
- this.startView()
- })
- }
- .width('10%')
- .justifyContent(FlexAlign.Start)
- Row({space:20}){
- Image($r("app.media.process_photo_reset"))
- .width($r('app.float.virtualSize_80'))
- .height($r('app.float.virtualSize_80'))
- .onClick(()=>{
- this.resetImageTransform()
- })
- Image($r('app.media.process_photo_turn_left'))
- .width($r('app.float.virtualSize_80'))
- .height($r('app.float.virtualSize_80'))
- .onClick(()=>{
- this.rotateImage(-90)
- })
- Image($r('app.media.process_photo_turn_right'))
- .width($r('app.float.virtualSize_80'))
- .height($r('app.float.virtualSize_80'))
- .onClick(()=>{
- this.rotateImage(90)
- })
- Image($r('app.media.process_photo_delete'))
- .width($r('app.float.virtualSize_80'))
- .height($r('app.float.virtualSize_80'))
- .onClick(()=>{
- this.showConfirmDialog({
- title: '删除照片',
- message: `确定要删除照片吗?`,
- onConfirm: ()=> {
- this.deletePhoto(this.selectedPhotoIndex);
- }
- });
- })
- }.width('88%')
- .justifyContent(FlexAlign.End)
- .margin({right :'2%'})
- }.width('98%')
- .height('10%')
- .position({x:'2%',y:'90%'})
- }
- }
- .width('86%')
- .height('100%')
- .backgroundColor($r('app.color.000000'))
- .border({width:2})
- Column(){
- List({ space: 8,scroller:this.scrollerPhoto }) {
- ForEach(this.photoPixelMaps, (item:photoInfo, index) => {
- ListItem() {
- Column({space:4}){
- Column(){
- Image(item.pixelMap)
- .objectFit(ImageFit.Fill)
- .borderRadius($r('app.float.virtualSize_16'))
- .height('97%')
- .width('98%')
- .opacity(index === this.selectedPhotoIndex ? 0.8 : 1) // 20% 透明度
- Text(item.timestamp)
- .fontSize($r('app.float.fontSize_12'))
- .fontColor($r('app.color.FFFFFF'))
- .width('100%')
- .textAlign(TextAlign.Start)
- }
- .backgroundColor(index === this.selectedPhotoIndex ? $r('app.color.30D158') : '')
- .width('90%')
- .justifyContent(FlexAlign.Center)
- .alignItems(HorizontalAlign.Center)
- .borderRadius($r('app.float.virtualSize_16'))
- .height('85%')
- // Text(`${item.updated}`)
- // .fontSize($r('app.float.fontSize_12'))
- // .fontColor($r('app.color.FFFFFF'))
- // .width('90%')
- // .textAlign(TextAlign.Start)
- }
- .width('100%')
- .height('100%')
- .justifyContent(FlexAlign.Start)
- .alignItems(HorizontalAlign.Center)
- .enabled(!this.isCapturing)
- .onClick(()=>{
- this.selectedPhotoIndex = index;
- this.resetImageTransform()
- this.stopView();
- })
- }.height('19%')
- .margin({bottom:'2%'})
- })
- }
- .width('100%')
- .margin({top:'2%',bottom:'2%'})
- .height('96%')
- }
- .width('14%')
- .height('100%')
- }
- .width('100%')
- .height('100%')
- .backgroundColor($r('app.color.10FFFFFF'))
- .borderRadius($r('app.float.virtualSize_16'))
- .borderWidth(4)
- }
- }
- function sleep(ms: number): Promise<void> {
- return new Promise((resolve) => setTimeout(resolve, ms));
- }
- interface photoInfo {
- pixelMap: PixelMap;
- timestamp: string;
- filename: string;
- }
|