Forráskód Böngészése

相机照片放大缩小

cjb 2 hete
szülő
commit
885d89c54f

+ 2 - 2
entry/src/main/ets/common/util/UsbDevice.ets

@@ -10,8 +10,8 @@ export const USBDeviceIds: Array<UsbDeviceInfo> = [
   },
   {
     DeviceName: "Scanning_Gun",
-    VendorId: 0x0c2e,
-    ProductId: 0x10a1
+    VendorId: 0x23d0,
+    ProductId: 0x0c80
   }
 ];
 

+ 105 - 78
entry/src/main/ets/pages/CameraView.ets

@@ -158,6 +158,10 @@ export struct CameraDialog {
   @State lastOffsetX: number = 0
   // 照片上次Y偏移
   @State lastOffsetY: number = 0
+  //双指缩放的中心点X
+  @State pinchCenterX: number = 0;
+  //双指缩放的中心点Y
+  @State pinchCenterY: number = 0;
   // 照片列表
   //@State photoList:DrawingInfo[]=[]
   // 获取本地live照片
@@ -177,38 +181,39 @@ export struct CameraDialog {
     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[] = [];
-
-      // 清空旧数据释放内存
-      this.releaseAllPixelMaps();
-
       // 加载所有以image_开头的图片
       for (const file of files) {
         // 只处理以image_开头的文件
-        if (!file.startsWith('image_')) {
+        if (!file.startsWith('image_') || !file.endsWith('.jpg')) {
           continue;
         }
         const filePath = `${localImageDir}${file}`;
         try {
           const imageSource = image.createImageSource(filePath);
-          const pixelMap = await imageSource.createPixelMap();
-          const timestamp = this.parseTimestampFromFilename(file);
+          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);
@@ -248,12 +253,13 @@ export struct CameraDialog {
 
   // 删除照片
   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}`);
@@ -264,15 +270,29 @@ export struct CameraDialog {
       // 3. 从数组中移除
       const newPhotoList = [...this.photoPixelMaps];
       newPhotoList.splice(index, 1);
-
-      // 4. 更新状态
       this.photoPixelMaps = newPhotoList;
 
-      if (this.selectedPhotoIndex === index) {
+      // 4. 处理选中的照片索引
+      if (this.photoPixelMaps.length === 0) {
+        // 如果所有照片都删完了
         this.selectedPhotoIndex = -1;
-        this.startView()
-      } else if (this.selectedPhotoIndex > index) {
-        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({
@@ -556,6 +576,28 @@ export struct CameraDialog {
     });
   }
 
+  private adjustOffsetWithAnimation() {
+    let moveScale = (this.scaleValue-1)/2
+    // const maxOffsetX =  760*moveScale  //rk3588
+    // const maxOffsetY =  500*moveScale  //rk3588
+    const maxOffsetX =  1524/1.5*moveScale //rk3568
+    const maxOffsetY =  1018/1.5*moveScale  //rk3568
+    // 钳制偏移量到合法范围内
+    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: 300,
+        curve: Curve.EaseOut
+      }, () => {
+        this.offsetX = clampedX;
+        this.offsetY = clampedY;
+      });
+    }
+  }
+
 
   //上传照片
   uploadPhoto=()=>{
@@ -570,7 +612,6 @@ export struct CameraDialog {
 
   aboutToDisappear(): void {
     this.isStopView = true;
-    sleep(100)
     this.disconnectCamera()
     if (this.subscriber) {
       CommonEventManager.unsubscribe(this.subscriber);
@@ -728,6 +769,10 @@ export struct CameraDialog {
             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 })
@@ -735,30 +780,53 @@ export struct CameraDialog {
               .translate({ x: this.offsetX, y: this.offsetY })
               .gesture(
                 GestureGroup(GestureMode.Exclusive,
-                  // 双指缩放手势
+                  // 替换原有的 PinchGesture 部分代码
                   PinchGesture()
-                    .onActionStart(() => {
-                      this.lastScale = this.scaleValue
-                      this.lastOffsetX = this.offsetX
-                      this.lastOffsetY = this.offsetY
+                    .onActionStart((event: GestureEvent) => {
+                      this.lastScale = this.scaleValue;
+                      this.lastOffsetX = this.offsetX;
+                      this.lastOffsetY = this.offsetY;
+                      // 记录双指中心点(相对于图片中心)
+                      //this.pinchCenterX = event.pinchCenterX - 1140 / 2;//rk3588
+                      //this.pinchCenterY = event.pinchCenterY - 750 / 2;//rk3588
+
+
+                      this.pinchCenterX = event.pinchCenterX - 1524 / 2; //rk3568
+                      this.pinchCenterY = event.pinchCenterY - 1018 / 2; //rk3568
                     })
                     .onActionUpdate((event: GestureEvent) => {
-                      this.scaleValue = this.lastScale * event.scale
+                      const newScale = this.lastScale * event.scale;
+                      // 计算缩放中心点相对于图片中心的位置
+                      // const currentCenterX = (event.pinchCenterX - 1140 / 2) - this.lastOffsetX; //rk3588
+                      // const currentCenterY = (event.pinchCenterY - 750 / 2) - this.lastOffsetY;  //rk3588
+
+                      const currentCenterX = (event.pinchCenterX - 1524 / 2) - this.lastOffsetX; //rk3568
+                      const currentCenterY = (event.pinchCenterY - 1018 / 2) - this.lastOffsetY; //rk3568
+
+                      // 计算缩放后的新位置
+                      const scaleRatio = newScale / this.lastScale;
+                      const newOffsetX = this.lastOffsetX + (currentCenterX * (1 - scaleRatio));
+                      const newOffsetY = this.lastOffsetY + (currentCenterY * (1 - scaleRatio));
+
+                      this.offsetX = newOffsetX;
+                      this.offsetY = newOffsetY;
+                      this.scaleValue = newScale;
                     })
                     .onActionEnd(() => {
-                      //缩放最小比例为1
+                      // 缩放最小比例为1
                       if (this.scaleValue < 1) {
-                        //旋转90°或者270°的最小缩小比例为0.63
+                        // 旋转90°或者270°的最小缩小比例为0.73
                         if(this.rotateAngle==90||this.rotateAngle==270) {
-                          if(this.scaleValue<0.63){
-                            this.scaleValue = 0.63
+                          if(this.scaleValue<0.73){
+                            this.scaleValue = 0.73
                           }
                         } else {
                           this.scaleValue = 1
                         }
                       }
-                      //缩放最大比例为4
-                      if (this.scaleValue > 4) this.scaleValue = 4
+                      // 缩放最大比例为3
+                      if (this.scaleValue > 3) this.scaleValue = 3
+                      this.adjustOffsetWithAnimation()
                     }),
 
                   // 单指滑动手势
@@ -778,25 +846,8 @@ export struct CameraDialog {
                       // 临时计算新位置
                       let newOffsetX = this.lastOffsetX;
                       let newOffsetY = this.lastOffsetY;
-
-                      switch(this.rotateAngle % 360) {
-                        case 0:
-                          newOffsetX += dx * sensitivity;
-                          newOffsetY += dy * sensitivity;
-                          break;
-                        case 90:
-                          newOffsetX -= dy * sensitivity;
-                          newOffsetY += dx * sensitivity;
-                          break;
-                        case 180:
-                          newOffsetX -= dx * sensitivity;
-                          newOffsetY -= dy * sensitivity;
-                          break;
-                        case 270:
-                          newOffsetX += dy * sensitivity;
-                          newOffsetY -= dx * sensitivity;
-                          break;
-                      }
+                      newOffsetX += dx * sensitivity;
+                      newOffsetY += dy * sensitivity;
                       this.offsetX = newOffsetX;
                       this.offsetY = newOffsetY;
                     })
@@ -807,31 +858,15 @@ export struct CameraDialog {
                         this.offsetY = 0;
                         return;
                       }
-                      // 计算最大允许偏移量(基于缩放比例)
-                      const maxOffsetX = (this.scaleValue - 1) * 500; //500是容器的半宽
-                      const maxOffsetY = (this.scaleValue - 1) * 345; //345是容器的半高
-                      // 检查X轴边界
-                      if (Math.abs(this.offsetX) > maxOffsetX) {
-                        this.offsetX = this.offsetX > 0 ? maxOffsetX : -maxOffsetX;
-                      }
-                      // 检查Y轴边界
-                      if (Math.abs(this.offsetY) > maxOffsetY) {
-                        this.offsetY = this.offsetY > 0 ? maxOffsetY : -maxOffsetY;
-                      }
-                      // 添加回弹动画
-                      animateTo({
-                        duration: 300,
-                        curve: Curve.EaseOut
-                      }, () => {
-                        this.offsetX = this.offsetX;
-                        this.offsetY = this.offsetY;
-                      });
+                      this.adjustOffsetWithAnimation()
+                      // 计算缩
+                      console.info(TAG,this.offsetX,TAG,this.offsetY,TAG,this.scaleValue)
                     })
                 )
               )
           }
-          .width('100%')
-          .height('100%')
+            .width('100%')
+            .height('100%')
           .borderRadius($r('app.float.virtualSize_16'))
           .clip(true)
           Row()
@@ -875,14 +910,6 @@ export struct CameraDialog {
                     message: `确定要删除照片吗?`,
                     onConfirm: ()=> {
                       this.deletePhoto(this.selectedPhotoIndex);
-                      // // const photosNum = this.photoList.length
-                      // // const photoId=this.photoList[this.selectedPhotoIndex].id
-                      // //如果是图册最后一张照片,显示前一张照片,没有照片则返回拍照页面
-                      // if(this.selectedPhotoIndex===photosNum-1)
-                      // {
-                      //   this.selectedPhotoIndex--
-                      // }
-                      // this.deletePhoto(photoId)
                     }
                   });
                 })

+ 86 - 64
entry/src/main/ets/view/process/MultiMediaCollect.ets

@@ -43,6 +43,10 @@ export struct MultiMediaCollect {
   @State isUploading: boolean = false
   // 照片列表
   @State photoList:DrawingInfo[]=[]
+  //双指缩放的中心点X
+  @State pinchCenterX: number = 0;
+  //双指缩放的中心点Y
+  @State pinchCenterY: number = 0;
   // 获取本地live照片
   @State commodityPixelMap: PixelMap | null = null;
   // 拍照动作是否完成
@@ -102,7 +106,7 @@ export struct MultiMediaCollect {
         if (data?.code !== undefined) {
           switch (data.code) {
             case 2:
-              this.isCapturing = true
+              this.isCapturing = false
               this.uploadPhoto(); // 拍照成功
               break;
             case 3:
@@ -111,6 +115,10 @@ export struct MultiMediaCollect {
               break;
             case -1:
               console.info(TAG,'连接故障')
+              promptAction.showToast({
+                message: '相机连接失败,请检查usb',
+                duration: 3000,
+              })
               break;
             case 5:
               console.info(TAG,'暂停预览')
@@ -203,9 +211,9 @@ export struct MultiMediaCollect {
   queryFlashMode = async () => {
     CommonEventManager.publish("queryflashmode", (err) => {
       if (err?.code) {
-        console.info(TAG,"Publish openSession err=" + JSON.stringify(err))
+        console.info(TAG,"Publish queryFlashMode err=" + JSON.stringify(err))
       } else {
-        console.info(TAG,"Publish openSession succeed ")
+        console.info(TAG,"Publish queryFlashMode succeed ")
       }
     })
   }
@@ -216,6 +224,7 @@ export struct MultiMediaCollect {
       if (err?.code) {
         console.error(TAG, JSON.stringify(err));
       } else {
+        console.info(TAG, "Publish startView succeed");
         this.isStopView =false;
         this.liveShow();
       }
@@ -256,7 +265,6 @@ export struct MultiMediaCollect {
         promptAction.showToast({
           message: '相机正在重连中...',
           duration: 3000,
-          bottom: 500
         });
         await sleep(3000);
         await this.connectCamera()
@@ -310,11 +318,11 @@ export struct MultiMediaCollect {
         console.info(TAG,"Publish stopview err=" + JSON.stringify(err));
       } else {
         console.info(TAG,"Publish Publish stopview succeed");
-        CommonEventManager.publish("shootonly", (err) => {
+        CommonEventManager.publish("shoot", (err) => {
           if (err?.code) {
-            console.info(TAG,"Publish  shootonly error=" + JSON.stringify(err));
+            console.info(TAG,"Publish  shoot error=" + JSON.stringify(err));
           } else {
-            console.info(TAG,"Publish Publish shootonly succeed");
+            console.info(TAG,"Publish Publish shoot succeed");
           }
         });
       }
@@ -331,15 +339,15 @@ export struct MultiMediaCollect {
         console.info(TAG,"Publish Publish stopview succeed");
         CommonEventManager.publish(mode, (err) => {
           if (err?.code) {
-            console.info(TAG,"Publish  shootonly error=" + JSON.stringify(err));
+            console.info(TAG,"Publish"+mode+" error=" + JSON.stringify(err));
           } else {
-            console.info(TAG,"Publish Publish shootonly succeed");
+            console.info(TAG,"Publish "+mode+" succeed");
             CommonEventManager.publish("startview", (err) => {
               this.isStopView = false;
               if (err?.code) {
-                console.info(TAG,"Publish  shootonly error=" + JSON.stringify(err));
+                console.info(TAG,"Publish  startview error=" + JSON.stringify(err));
               }else{
-                console.info(TAG,"Publish Publish shootonly succeed");
+                console.info(TAG,"Publish Publish startview succeed");
               }
             })
           }
@@ -351,12 +359,11 @@ export struct MultiMediaCollect {
 
   //上传照片
   uploadPhoto=()=>{
+    console.info(TAG,"start upload:");
     let imageUri: string = "/data/storage/el2/base/haps/entry/files/image_base64.txt"
     try {
       uploadInstance.startUploadBase64(imageUri, () => {
-        if (this.seqNo) {
-          this.loadPhotos()
-        }
+        this.loadPhotos()
         this.isUploading = false
         this.startView();//上传完恢复预览
       })
@@ -364,6 +371,29 @@ export struct MultiMediaCollect {
       console.error(TAG,"upload failed:", error.code);
     }
   }
+
+  private adjustOffsetWithAnimation() {
+    let moveScale = (this.scaleValue-1)/2
+    // const maxOffsetX =  760*moveScale  //rk3588
+    // const maxOffsetY =  520*moveScale  //rk3588
+    const maxOffsetX =  1635/1.5*moveScale  //rk3568
+    const maxOffsetY =  1038/1.5*moveScale  //rk3568
+    // 钳制偏移量到合法范围内
+    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: 300,
+        curve: Curve.EaseOut
+      }, () => {
+        this.offsetX = clampedX;
+        this.offsetY = clampedY;
+      });
+    }
+  }
+
   async aboutToAppear() {
     this.loadPhotos();
     await this.createSubscriber();
@@ -545,6 +575,9 @@ export struct MultiMediaCollect {
             Image(CommonConstants.PICTURE_URL_PREFIX + this.photoList[this.selectedPhotoIndex].filePath)
               .width('100%')
               .height('100%')
+              // .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 })
@@ -552,30 +585,52 @@ export struct MultiMediaCollect {
               .translate({ x: this.offsetX, y: this.offsetY })
               .gesture(
                 GestureGroup(GestureMode.Exclusive,
-                  // 双指缩放手势
+                  // 替换原有的 PinchGesture 部分代码
                   PinchGesture()
-                    .onActionStart(() => {
-                      this.lastScale = this.scaleValue
-                      this.lastOffsetX = this.offsetX
-                      this.lastOffsetY = this.offsetY
+                    .onActionStart((event: GestureEvent) => {
+                      this.lastScale = this.scaleValue;
+                      this.lastOffsetX = this.offsetX;
+                      this.lastOffsetY = this.offsetY;
+                      // 记录双指中心点(相对于图片中心)
+                      // this.pinchCenterX = event.pinchCenterX - 1230 / 2;  //rk3588
+                      // this.pinchCenterY = event.pinchCenterY - 780 / 2;   //rk3588
+
+                      this.pinchCenterX = event.pinchCenterX - 1635 / 2;     //rk3568
+                      this.pinchCenterY = event.pinchCenterY - 1038 / 2;     //rk3568
                     })
                     .onActionUpdate((event: GestureEvent) => {
-                      this.scaleValue = this.lastScale * event.scale
+                      const newScale = this.lastScale * event.scale;
+                      // 计算缩放中心点相对于图片中心的位置
+                      // const currentCenterX = (event.pinchCenterX - 1230 / 2) - this.lastOffsetX; //rk3588
+                      // const currentCenterY = (event.pinchCenterY - 780 / 2) - this.lastOffsetY;  //rk3588
+
+                      const currentCenterX = (event.pinchCenterX - 1635 / 2) - this.lastOffsetX;    //rk3568
+                      const currentCenterY = (event.pinchCenterY - 1038 / 2) - this.lastOffsetY;    //rk3568
+
+                      // 计算缩放后的新位置
+                      const scaleRatio = newScale / this.lastScale;
+                      const newOffsetX = this.lastOffsetX + (currentCenterX * (1 - scaleRatio));
+                      const newOffsetY = this.lastOffsetY + (currentCenterY * (1 - scaleRatio));
+
+                      this.offsetX = newOffsetX;
+                      this.offsetY = newOffsetY;
+                      this.scaleValue = newScale;
                     })
                     .onActionEnd(() => {
-                      //缩放最小比例为1
+                      // 缩放最小比例为1
                       if (this.scaleValue < 1) {
-                        //旋转90°或者270°的最小缩小比例为0.63
+                        // 旋转90°或者270°的最小缩小比例为0.73
                         if(this.rotateAngle==90||this.rotateAngle==270) {
-                          if(this.scaleValue<0.63){
-                            this.scaleValue = 0.63
+                          if(this.scaleValue<0.73){
+                            this.scaleValue = 0.73
                           }
                         } else {
                           this.scaleValue = 1
                         }
                       }
-                      //缩放最大比例为4
-                      if (this.scaleValue > 4) this.scaleValue = 4
+                      // 缩放最大比例为3
+                      if (this.scaleValue > 3) this.scaleValue = 3
+                      this.adjustOffsetWithAnimation()
                     }),
 
                   // 单指滑动手势
@@ -595,25 +650,8 @@ export struct MultiMediaCollect {
                       // 临时计算新位置
                       let newOffsetX = this.lastOffsetX;
                       let newOffsetY = this.lastOffsetY;
-
-                      switch(this.rotateAngle % 360) {
-                        case 0:
-                          newOffsetX += dx * sensitivity;
-                          newOffsetY += dy * sensitivity;
-                          break;
-                        case 90:
-                          newOffsetX -= dy * sensitivity;
-                          newOffsetY += dx * sensitivity;
-                          break;
-                        case 180:
-                          newOffsetX -= dx * sensitivity;
-                          newOffsetY -= dy * sensitivity;
-                          break;
-                        case 270:
-                          newOffsetX += dy * sensitivity;
-                          newOffsetY -= dx * sensitivity;
-                          break;
-                      }
+                      newOffsetX += dx * sensitivity;
+                      newOffsetY += dy * sensitivity;
                       this.offsetX = newOffsetX;
                       this.offsetY = newOffsetY;
                     })
@@ -624,25 +662,9 @@ export struct MultiMediaCollect {
                         this.offsetY = 0;
                         return;
                       }
-                      // 计算最大允许偏移量(基于缩放比例)
-                      const maxOffsetX = (this.scaleValue - 1) * 500; //500是容器的半宽
-                      const maxOffsetY = (this.scaleValue - 1) * 345; //345是容器的半高
-                      // 检查X轴边界
-                      if (Math.abs(this.offsetX) > maxOffsetX) {
-                        this.offsetX = this.offsetX > 0 ? maxOffsetX : -maxOffsetX;
-                      }
-                      // 检查Y轴边界
-                      if (Math.abs(this.offsetY) > maxOffsetY) {
-                        this.offsetY = this.offsetY > 0 ? maxOffsetY : -maxOffsetY;
-                      }
-                      // 添加回弹动画
-                      animateTo({
-                        duration: 300,
-                        curve: Curve.EaseOut
-                      }, () => {
-                        this.offsetX = this.offsetX;
-                        this.offsetY = this.offsetY;
-                      });
+                      this.adjustOffsetWithAnimation()
+                      // 计算缩
+                      console.info(TAG,this.offsetX,TAG,this.offsetY,TAG,this.scaleValue)
                     })
                 )
               )