|
@@ -158,6 +158,10 @@ export struct CameraDialog {
|
|
@State lastOffsetX: number = 0
|
|
@State lastOffsetX: number = 0
|
|
// 照片上次Y偏移
|
|
// 照片上次Y偏移
|
|
@State lastOffsetY: number = 0
|
|
@State lastOffsetY: number = 0
|
|
|
|
+ //双指缩放的中心点X
|
|
|
|
+ @State pinchCenterX: number = 0;
|
|
|
|
+ //双指缩放的中心点Y
|
|
|
|
+ @State pinchCenterY: number = 0;
|
|
// 照片列表
|
|
// 照片列表
|
|
//@State photoList:DrawingInfo[]=[]
|
|
//@State photoList:DrawingInfo[]=[]
|
|
// 获取本地live照片
|
|
// 获取本地live照片
|
|
@@ -177,38 +181,39 @@ export struct CameraDialog {
|
|
console.info(TAG, '开始加载照片', context.filesDir);
|
|
console.info(TAG, '开始加载照片', context.filesDir);
|
|
try {
|
|
try {
|
|
const localImageDir = `${context.filesDir}/`;
|
|
const localImageDir = `${context.filesDir}/`;
|
|
-
|
|
|
|
// 检查目录是否存在
|
|
// 检查目录是否存在
|
|
if (!fs.accessSync(localImageDir)) {
|
|
if (!fs.accessSync(localImageDir)) {
|
|
console.warn(TAG, "目录不存在");
|
|
console.warn(TAG, "目录不存在");
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
-
|
|
|
|
// 获取目录下所有文件
|
|
// 获取目录下所有文件
|
|
const files = fs.listFileSync(localImageDir);
|
|
const files = fs.listFileSync(localImageDir);
|
|
const newPixelMaps: photoInfo[] = [];
|
|
const newPixelMaps: photoInfo[] = [];
|
|
-
|
|
|
|
- // 清空旧数据释放内存
|
|
|
|
- this.releaseAllPixelMaps();
|
|
|
|
-
|
|
|
|
// 加载所有以image_开头的图片
|
|
// 加载所有以image_开头的图片
|
|
for (const file of files) {
|
|
for (const file of files) {
|
|
// 只处理以image_开头的文件
|
|
// 只处理以image_开头的文件
|
|
- if (!file.startsWith('image_')) {
|
|
|
|
|
|
+ if (!file.startsWith('image_') || !file.endsWith('.jpg')) {
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
const filePath = `${localImageDir}${file}`;
|
|
const filePath = `${localImageDir}${file}`;
|
|
try {
|
|
try {
|
|
const imageSource = image.createImageSource(filePath);
|
|
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({
|
|
newPixelMaps.push({
|
|
pixelMap: pixelMap,
|
|
pixelMap: pixelMap,
|
|
timestamp: timestamp,
|
|
timestamp: timestamp,
|
|
filename: file
|
|
filename: file
|
|
});
|
|
});
|
|
-
|
|
|
|
imageSource.release();
|
|
imageSource.release();
|
|
} catch (err) {
|
|
} catch (err) {
|
|
console.error(TAG, `加载图片 ${file} 失败:`, err);
|
|
console.error(TAG, `加载图片 ${file} 失败:`, err);
|
|
@@ -248,12 +253,13 @@ export struct CameraDialog {
|
|
|
|
|
|
// 删除照片
|
|
// 删除照片
|
|
deletePhoto = async (index: number) => {
|
|
deletePhoto = async (index: number) => {
|
|
-
|
|
|
|
try {
|
|
try {
|
|
const context = getContext(this);
|
|
const context = getContext(this);
|
|
const photoToDelete = this.photoPixelMaps[index];
|
|
const photoToDelete = this.photoPixelMaps[index];
|
|
const filePath = `${context.filesDir}/${photoToDelete.filename}`;
|
|
const filePath = `${context.filesDir}/${photoToDelete.filename}`;
|
|
|
|
+
|
|
console.info(TAG, `要删除文件: ${filePath}`);
|
|
console.info(TAG, `要删除文件: ${filePath}`);
|
|
|
|
+
|
|
// 1. 删除物理文件
|
|
// 1. 删除物理文件
|
|
fs.unlinkSync(filePath);
|
|
fs.unlinkSync(filePath);
|
|
console.info(TAG, `已删除文件: ${filePath}`);
|
|
console.info(TAG, `已删除文件: ${filePath}`);
|
|
@@ -264,15 +270,29 @@ export struct CameraDialog {
|
|
// 3. 从数组中移除
|
|
// 3. 从数组中移除
|
|
const newPhotoList = [...this.photoPixelMaps];
|
|
const newPhotoList = [...this.photoPixelMaps];
|
|
newPhotoList.splice(index, 1);
|
|
newPhotoList.splice(index, 1);
|
|
-
|
|
|
|
- // 4. 更新状态
|
|
|
|
this.photoPixelMaps = newPhotoList;
|
|
this.photoPixelMaps = newPhotoList;
|
|
|
|
|
|
- if (this.selectedPhotoIndex === index) {
|
|
|
|
|
|
+ // 4. 处理选中的照片索引
|
|
|
|
+ if (this.photoPixelMaps.length === 0) {
|
|
|
|
+ // 如果所有照片都删完了
|
|
this.selectedPhotoIndex = -1;
|
|
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({
|
|
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=()=>{
|
|
uploadPhoto=()=>{
|
|
@@ -570,7 +612,6 @@ export struct CameraDialog {
|
|
|
|
|
|
aboutToDisappear(): void {
|
|
aboutToDisappear(): void {
|
|
this.isStopView = true;
|
|
this.isStopView = true;
|
|
- sleep(100)
|
|
|
|
this.disconnectCamera()
|
|
this.disconnectCamera()
|
|
if (this.subscriber) {
|
|
if (this.subscriber) {
|
|
CommonEventManager.unsubscribe(this.subscriber);
|
|
CommonEventManager.unsubscribe(this.subscriber);
|
|
@@ -728,6 +769,10 @@ export struct CameraDialog {
|
|
Image(this.photoPixelMaps[this.selectedPhotoIndex].pixelMap)
|
|
Image(this.photoPixelMaps[this.selectedPhotoIndex].pixelMap)
|
|
.width('100%')
|
|
.width('100%')
|
|
.height('100%')
|
|
.height('100%')
|
|
|
|
+ .autoResize(true)
|
|
|
|
+ // .onComplete((event) => {
|
|
|
|
+ // console.info(TAG,"width:"+event!.componentWidth +"height:"+ event!.componentHeight)
|
|
|
|
+ // }) // 获取Image组件的长宽(除以1.5获取vp)
|
|
.objectFit(ImageFit.Fill)
|
|
.objectFit(ImageFit.Fill)
|
|
.rotate({ angle: this.rotateAngle })
|
|
.rotate({ angle: this.rotateAngle })
|
|
.scale({ x: this.scaleValue, y: this.scaleValue })
|
|
.scale({ x: this.scaleValue, y: this.scaleValue })
|
|
@@ -735,30 +780,53 @@ export struct CameraDialog {
|
|
.translate({ x: this.offsetX, y: this.offsetY })
|
|
.translate({ x: this.offsetX, y: this.offsetY })
|
|
.gesture(
|
|
.gesture(
|
|
GestureGroup(GestureMode.Exclusive,
|
|
GestureGroup(GestureMode.Exclusive,
|
|
- // 双指缩放手势
|
|
|
|
|
|
+ // 替换原有的 PinchGesture 部分代码
|
|
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) => {
|
|
.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(() => {
|
|
.onActionEnd(() => {
|
|
- //缩放最小比例为1
|
|
|
|
|
|
+ // 缩放最小比例为1
|
|
if (this.scaleValue < 1) {
|
|
if (this.scaleValue < 1) {
|
|
- //旋转90°或者270°的最小缩小比例为0.63
|
|
|
|
|
|
+ // 旋转90°或者270°的最小缩小比例为0.73
|
|
if(this.rotateAngle==90||this.rotateAngle==270) {
|
|
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 {
|
|
} else {
|
|
this.scaleValue = 1
|
|
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 newOffsetX = this.lastOffsetX;
|
|
let newOffsetY = this.lastOffsetY;
|
|
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.offsetX = newOffsetX;
|
|
this.offsetY = newOffsetY;
|
|
this.offsetY = newOffsetY;
|
|
})
|
|
})
|
|
@@ -807,31 +858,15 @@ export struct CameraDialog {
|
|
this.offsetY = 0;
|
|
this.offsetY = 0;
|
|
return;
|
|
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'))
|
|
.borderRadius($r('app.float.virtualSize_16'))
|
|
.clip(true)
|
|
.clip(true)
|
|
Row()
|
|
Row()
|
|
@@ -875,14 +910,6 @@ export struct CameraDialog {
|
|
message: `确定要删除照片吗?`,
|
|
message: `确定要删除照片吗?`,
|
|
onConfirm: ()=> {
|
|
onConfirm: ()=> {
|
|
this.deletePhoto(this.selectedPhotoIndex);
|
|
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)
|
|
|
|
}
|
|
}
|
|
});
|
|
});
|
|
})
|
|
})
|