|
@@ -0,0 +1,520 @@
|
|
|
+import image from '@ohos.multimedia.image';
|
|
|
+import fs from "@ohos.file.fs"
|
|
|
+import common from '@ohos.app.ability.common';
|
|
|
+import photoAccessHelper from '@ohos.file.photoAccessHelper';
|
|
|
+import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
|
|
|
+import commonEvent from "@ohos.commonEvent";
|
|
|
+import CommonEventManager from '@ohos.commonEventManager'
|
|
|
+import uploadInstance from '../../utils/UploadUtil';
|
|
|
+import router from '@ohos.router';
|
|
|
+import fileIo from '@ohos.file.fs';
|
|
|
+const TAG = "openHarmonyBridge upload"
|
|
|
+@Entry
|
|
|
+@Component
|
|
|
+struct Index {
|
|
|
+
|
|
|
+ @State isUploading: boolean = false
|
|
|
+ /*相机需要启动lib脚本
|
|
|
+ * hdc shell mount -o remount,rw /vendor
|
|
|
+ * */
|
|
|
+ @State commodityPixelMap: PixelMap | null = null;
|
|
|
+ @State isButtonPressed: boolean = false;
|
|
|
+ @State isCapturing: boolean = false;
|
|
|
+ @State isCloseView: boolean = false;// 新增状态控制拍摄状态
|
|
|
+ @State reminds:string = ''
|
|
|
+
|
|
|
+ remindController: CustomDialogController = new CustomDialogController({
|
|
|
+ builder: RemindDialog({
|
|
|
+ remind: this.reminds,}
|
|
|
+ ),
|
|
|
+ })
|
|
|
+ //
|
|
|
+ subscriber: CommonEventManager.CommonEventSubscriber | null = null; // Used to save the created subscriber object for subsequent subscription and unsubscription.
|
|
|
+ // Subscriber information.
|
|
|
+ subscribeInfo: CommonEventManager.CommonEventSubscribeInfo = { events: ["sonycamera_callback"] };
|
|
|
+ getPermission = async () => {
|
|
|
+ let context = getContext(this) as common.UIAbilityContext;
|
|
|
+ let atManager = abilityAccessCtrl.createAtManager();
|
|
|
+ try {
|
|
|
+ atManager.requestPermissionsFromUser(context, ['ohos.permission.WRITE_IMAGEVIDEO', 'ohos.permission.READ_IMAGEVIDEO'])
|
|
|
+ .then((data) => {
|
|
|
+ console.log('data: ' + JSON.stringify(data));
|
|
|
+ })
|
|
|
+ .catch((err: object) => {
|
|
|
+ console.log('err: ' + JSON.stringify(err));
|
|
|
+ })
|
|
|
+ } catch (err) {
|
|
|
+ console.log('catch err->' + JSON.stringify(err));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //订阅回调(拍照完接收到照片收到回调)
|
|
|
+ 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("[CommonEvent] SubscribeCallBack err=" + JSON.stringify(err));
|
|
|
+ } else {
|
|
|
+ console.info("[CommonEvent] SubscribeCallBack data=" + JSON.stringify(data));
|
|
|
+ if (data && data.code&&data.code === 2) {
|
|
|
+ console.info(TAG,"开始传输照片");
|
|
|
+ this.handleCaptureSuccess()
|
|
|
+ }else if (data && data.code&&data.code === 3) {
|
|
|
+ console.info(TAG,"开始预览" );
|
|
|
+ this.publishStartView();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ handleCaptureSuccess = () => {
|
|
|
+ this.savePhoto();
|
|
|
+ // commonEvent.publish("startview", (err) => {
|
|
|
+ // if (err?.code) {
|
|
|
+ // console.error("Restart preview error:", JSON.stringify(err));
|
|
|
+ // } else {
|
|
|
+ // this.isCapturing = false;
|
|
|
+ // this.isCloseView =false;
|
|
|
+ // this.liveShow();// 拍摄完成后恢复预览
|
|
|
+ // console.log("Restart success")
|
|
|
+ // }
|
|
|
+ // });
|
|
|
+ };
|
|
|
+ publishStartView=()=>{
|
|
|
+ commonEvent.publish("startview", (err) => {
|
|
|
+ if (err?.code) {
|
|
|
+ console.error("Restart preview error:", JSON.stringify(err));
|
|
|
+ } else {
|
|
|
+ this.isCapturing = false;
|
|
|
+ this.isCloseView =false;
|
|
|
+ this.liveShow();// 拍摄完成后恢复预览
|
|
|
+ console.log("Restart success")
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ connectCamera = async () => {
|
|
|
+ commonEvent.publish("opensession", (err) => {
|
|
|
+ if (err?.code) {
|
|
|
+ console.info("[CommonEvent] Publish CallBack err=" + JSON.stringify(err))
|
|
|
+ } else {
|
|
|
+ console.info("[CommonEvent] Publish opensession succeed ")
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ disconnectCamera = () => {
|
|
|
+ commonEvent.publish("stopview", (err) => {
|
|
|
+ if (err?.code) {
|
|
|
+ console.info("[CommonEvent] Publish CallBack err=" + JSON.stringify(err))
|
|
|
+ } else {
|
|
|
+ console.info("[CommonEvent] Publish stopview succeed ")
|
|
|
+ commonEvent.publish("closesession", (err) => {
|
|
|
+ if (err?.code) {
|
|
|
+ console.info("[CommonEvent] Publish CallBack err=" + JSON.stringify(err))
|
|
|
+ } else {
|
|
|
+ console.info("[CommonEvent] Publish closesession succeed ")
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ savePhoto=()=>{
|
|
|
+ let imageUri: string = "/data/storage/el2/base/haps/entry/files/image_base64.txt"
|
|
|
+ console.log(TAG, "进入了savephoto")
|
|
|
+ try {
|
|
|
+ const file = fileIo.openSync(imageUri, fileIo.OpenMode.READ_ONLY);
|
|
|
+ fileIo.closeSync(file.fd); // 关闭文件描述符
|
|
|
+ this.reminds= "照片传输到小黑盒成功"
|
|
|
+ this.remindController.open()
|
|
|
+ delayExecution(()=>{
|
|
|
+ this.remindController.close()
|
|
|
+ }, 1000)
|
|
|
+ } catch (error) {
|
|
|
+ console.error('文件不存在或无法访问:', error);
|
|
|
+ this.reminds= "照片传输到小黑盒失败"
|
|
|
+ this.remindController.open()
|
|
|
+ delayExecution(()=>{
|
|
|
+ this.remindController.close()
|
|
|
+ }, 1000)
|
|
|
+
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ // 获取相册访问的 helper 实例
|
|
|
+
|
|
|
+ console.log(TAG, "进入了savephoto1")
|
|
|
+ // 创建一个新的图片资产,并获取目标 URI
|
|
|
+ // const dest = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg');
|
|
|
+
|
|
|
+ // console.log(TAG, "进入了savephoto2")
|
|
|
+ // 打开源文件和目标文件 这个是写死的 app的名字不能改
|
|
|
+ // let imageUri: string = "/data/storage/el2/base/haps/entry/files/shoots.jpg"
|
|
|
+ // 开始上传
|
|
|
+ console.log(TAG, "开始上传", imageUri)
|
|
|
+ uploadInstance.startUploadBase64(imageUri, () => {
|
|
|
+
|
|
|
+ console.log(TAG, "上传完成后的callback")
|
|
|
+ this.isUploading = false
|
|
|
+ this.publishStartView();
|
|
|
+ })
|
|
|
+
|
|
|
+
|
|
|
+ // let res = fs.accessSync(imageUri);
|
|
|
+ // console.info("demo1"+ "file " + imageUri)
|
|
|
+ // if (res) {
|
|
|
+ // console.info("demo1"+"file exists");
|
|
|
+ // } else {
|
|
|
+ // console.info("demo1"+"file not exists");
|
|
|
+ // }
|
|
|
+ // const srcFile = fs.openSync(imageUri);
|
|
|
+ // const destFile = fs.openSync(dest, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
|
|
|
+ // fs.copyFileSync(srcFile.fd, destFile.fd);
|
|
|
+ // fs.closeSync(srcFile);
|
|
|
+ // fs.closeSync(destFile);
|
|
|
+ // console.log("demo1"+'Image saved to album successfully:', dest);
|
|
|
+ } catch (error) {
|
|
|
+ console.log(TAG, "进入了savephoto3")
|
|
|
+ console.error("demo1"+'Failed to save image to album:', error.code);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ takePhoto = async () => {
|
|
|
+ this.isCloseView = true;
|
|
|
+ this.isCapturing = true;
|
|
|
+ commonEvent.publish("stopview", (err) => {
|
|
|
+ if (err?.code) {
|
|
|
+ console.info("demo1"+"[CommonEvent] Publish CallBack err=" + JSON.stringify(err));
|
|
|
+ this.isCapturing = false;
|
|
|
+ } else {
|
|
|
+ console.info("demo1"+"[CommonEvent] Publish stopview succeed");
|
|
|
+ commonEvent.publish("shootonly", (err) => {
|
|
|
+ if (err?.code) {
|
|
|
+ console.info("demo1"+"[CommonEvent] Publish CallBack err=" + JSON.stringify(err));
|
|
|
+ this.isCapturing = false;
|
|
|
+ } else {
|
|
|
+ console.info("demo1"+"[CommonEvent] Publish shootonly succeed");
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ readTimer = 0
|
|
|
+
|
|
|
+ liveShow = async () => {
|
|
|
+
|
|
|
+ const previewManager = new PreviewManager(getContext(this));
|
|
|
+ let index = 0;
|
|
|
+
|
|
|
+ this.readTimer = setInterval(async () => {
|
|
|
+ if (!this.isCloseView && !this.isCapturing) {
|
|
|
+ try {
|
|
|
+ const success = await previewManager.processFrame(index);
|
|
|
+ if (success) {
|
|
|
+ this.commodityPixelMap = previewManager.getActiveBuffer();
|
|
|
+ //index = (index + 1) % 10;
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.warn(TAG, "预览更新失败:", error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, 50); // 30ms interval for ~30fps
|
|
|
+
|
|
|
+ // 清理资源
|
|
|
+ return () => {
|
|
|
+ previewManager.release();
|
|
|
+ if (this.commodityPixelMap) {
|
|
|
+ this.commodityPixelMap.release();
|
|
|
+ this.commodityPixelMap = null;
|
|
|
+ }
|
|
|
+ };
|
|
|
+ };
|
|
|
+
|
|
|
+ aboutToAppear(): void {
|
|
|
+ this.createSubscriber();
|
|
|
+ this.connectCamera();
|
|
|
+ this.getPermission();
|
|
|
+ this.liveShow();
|
|
|
+ }
|
|
|
+
|
|
|
+ aboutToDisappear(): void {
|
|
|
+ this.isCloseView = true;
|
|
|
+ this.disconnectCamera();
|
|
|
+ if (this.subscriber) {
|
|
|
+ CommonEventManager.unsubscribe(this.subscriber);
|
|
|
+ }
|
|
|
+ if (this.readTimer) {
|
|
|
+ clearInterval(this.readTimer);
|
|
|
+ }
|
|
|
+ if (this.commodityPixelMap) {
|
|
|
+ this.commodityPixelMap.release();
|
|
|
+ this.commodityPixelMap = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ build() {
|
|
|
+ Column() {
|
|
|
+ Row() {
|
|
|
+
|
|
|
+ }
|
|
|
+ .width('100%')
|
|
|
+ .height('5%')
|
|
|
+ .alignItems(VerticalAlign.Center)
|
|
|
+ Row() {
|
|
|
+ if (this.commodityPixelMap) {
|
|
|
+ Stack({ alignContent: Alignment.Center }) {
|
|
|
+ Image(this.commodityPixelMap)
|
|
|
+ .width('100%')
|
|
|
+ .height('100%')
|
|
|
+ .objectFit(ImageFit.Contain)
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (this.isUploading) {
|
|
|
+ Stack({ alignContent: Alignment.Center }) {
|
|
|
+ // 半透明黑色背景蒙层
|
|
|
+ Column() {
|
|
|
+ Text('正在上传中...')
|
|
|
+ .fontSize(22)
|
|
|
+ .margin({ top: 10, bottom: 10 })
|
|
|
+
|
|
|
+ LoadingProgress()
|
|
|
+ .color(Color.Blue)
|
|
|
+ .width(50)
|
|
|
+ .height(50)
|
|
|
+ }
|
|
|
+ .height(140)
|
|
|
+ .width(150)
|
|
|
+ .backgroundColor(Color.White)
|
|
|
+ .borderRadius(10)
|
|
|
+ .justifyContent(FlexAlign.Center)
|
|
|
+ }
|
|
|
+ .width('100%')
|
|
|
+ .height('100%')
|
|
|
+ .position({ x: 0, y: 0 })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .width('100%')
|
|
|
+ .height('80%')
|
|
|
+ .backgroundColor('#000000') // 背景为黑色
|
|
|
+
|
|
|
+ // 底部:拍照按钮区域
|
|
|
+ Row() {
|
|
|
+ Button('', { type: ButtonType.Circle})
|
|
|
+ .width(this.isButtonPressed ? 70 : 80) // 按下时缩小按钮
|
|
|
+ .height(this.isButtonPressed ? 70 : 80)
|
|
|
+ .backgroundColor(this.isButtonPressed ? '#CCCCCC' : '#FFFFFF') // 按下时按钮颜色变灰
|
|
|
+ .border({ width: 4, color: '#FFFFFF' })// 白色边框
|
|
|
+ .onClick(() => {
|
|
|
+ console.log(TAG, "点击了拍照按钮")
|
|
|
+ if(this.isUploading){
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.isUploading = true
|
|
|
+ this.takePhoto();
|
|
|
+
|
|
|
+ })
|
|
|
+ .onTouch((event: TouchEvent) => {
|
|
|
+ if(this.isUploading){
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (event.type === TouchType.Down) {
|
|
|
+ this.isButtonPressed = true; // 按下时设置为 true
|
|
|
+ } else if (event.type === TouchType.Up || event.type === TouchType.Cancel) {
|
|
|
+ this.isButtonPressed = false; // 松开时设置为 false
|
|
|
+ }
|
|
|
+ })
|
|
|
+ Button(){
|
|
|
+ Image($r('app.media.close'))
|
|
|
+ .width(40)
|
|
|
+ .height(40)
|
|
|
+ }
|
|
|
+ .width(70)
|
|
|
+ .height(70)
|
|
|
+ .backgroundColor('#1c1c1c')
|
|
|
+ .onClick(() => {
|
|
|
+ this.isCloseView = true;
|
|
|
+ sleep(100)
|
|
|
+ this.disconnectCamera()
|
|
|
+ router.back() })
|
|
|
+
|
|
|
+ }.width('100%')
|
|
|
+ .height('15%')
|
|
|
+ .justifyContent(FlexAlign.SpaceEvenly) // 按钮居中
|
|
|
+ .backgroundColor('#000000') // 底部背景为黑色
|
|
|
+ }
|
|
|
+ .width('100%')
|
|
|
+ .height('100%')
|
|
|
+ .backgroundColor('#000000')
|
|
|
+ }
|
|
|
+
|
|
|
+ // 整体背景为黑色
|
|
|
+ /* Text("sada")
|
|
|
+ .onClick(async () => {
|
|
|
+ console.info("sssss");
|
|
|
+ // 异步加载图片
|
|
|
+ const context: Context = getContext(this);
|
|
|
+ let index = 0; // 初始化索引
|
|
|
+ while (true) { // 无限循环
|
|
|
+ const filePath: string = `${context.filesDir}/live${index}.jpg`;
|
|
|
+ try {
|
|
|
+ fs.accessSync(filePath); // 检查文件是否存在
|
|
|
+ console.info("file " + filePath);
|
|
|
+ const imageSource = image.createImageSource(filePath);
|
|
|
+ if (imageSource) {
|
|
|
+ this.commodityPixelMap = await imageSource.createPixelMap();
|
|
|
+ }
|
|
|
+ console.info("file exists");
|
|
|
+ } catch (error) {
|
|
|
+ console.info("file not exists");
|
|
|
+ }
|
|
|
+ index = index % 10; // 更新索引,循环从0到9
|
|
|
+ await sleep(100);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }).width('20%')
|
|
|
+ .height('10%')
|
|
|
+ Text("nihao")
|
|
|
+ .onClick(async () => {
|
|
|
+ const context = getContext() as common.UIAbilityContext;
|
|
|
+ try {
|
|
|
+ // 获取相册访问的 helper 实例
|
|
|
+ const helper = photoAccessHelper.getPhotoAccessHelper(context);
|
|
|
+
|
|
|
+ // 创建一个新的图片资产,并获取目标 URI
|
|
|
+ const dest = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg');
|
|
|
+
|
|
|
+ // 打开源文件和目标文件
|
|
|
+ let imageUri: string = "/data/storage/el2/base/haps/entry/files/shoot.jpg"
|
|
|
+ let res = fs.accessSync(imageUri);
|
|
|
+ console.info("file " + imageUri)
|
|
|
+ if (res) {
|
|
|
+ console.info("file exists");
|
|
|
+ } else {
|
|
|
+ console.info("file not exists");
|
|
|
+ }
|
|
|
+ const srcFile = fs.openSync(imageUri);
|
|
|
+ console.info("file 1")
|
|
|
+ const destFile = fs.openSync(dest, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
|
|
|
+ console.info("file 2")
|
|
|
+ // 将源文件内容复制到目标文件
|
|
|
+ fs.copyFileSync(srcFile.fd, destFile.fd);
|
|
|
+ console.info("file 3")
|
|
|
+ // 关闭文件句柄
|
|
|
+ fs.closeSync(srcFile);
|
|
|
+ fs.closeSync(destFile);
|
|
|
+
|
|
|
+ console.log('Image saved to album successfully:', dest);
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ console.error('Failed to save image to album:', error.code);
|
|
|
+ throw new Error(`Failed to save image to album: ${error.message}`);
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ .width('100%')
|
|
|
+ .height('100%')
|
|
|
+ .backgroundColor('#F1F3F5')
|
|
|
+ }
|
|
|
+ }
|
|
|
+}*/
|
|
|
+}
|
|
|
+function sleep(ms: number): Promise<void> {
|
|
|
+ return new Promise((resolve) => setTimeout(resolve, ms));
|
|
|
+}
|
|
|
+@CustomDialog
|
|
|
+struct RemindDialog {
|
|
|
+ controller: CustomDialogController
|
|
|
+ @Link remind: string
|
|
|
+ build() {
|
|
|
+ Column() {
|
|
|
+ Text(this.remind)
|
|
|
+ .fontSize(20)
|
|
|
+ .margin({ top: 10, bottom: 10 })
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function delayExecution(callback: Function, delay: number) {
|
|
|
+ let timerId = setInterval(() => {
|
|
|
+ clearInterval(timerId);
|
|
|
+ callback();
|
|
|
+ }, delay);
|
|
|
+}
|
|
|
+
|
|
|
+class PreviewManager {
|
|
|
+ private context: Context;
|
|
|
+ private activeBuffer: PixelMap | null = null;
|
|
|
+ private nextBuffer: PixelMap | null = null;
|
|
|
+ private isProcessing: boolean = false;
|
|
|
+ private lastFrameTime: number = 0;
|
|
|
+ private frameInterval: number = 50;
|
|
|
+
|
|
|
+ constructor(context: Context) {
|
|
|
+ this.context = context;
|
|
|
+ }
|
|
|
+
|
|
|
+ async processFrame(index: number): Promise<boolean> {
|
|
|
+ if (this.isProcessing) return false;
|
|
|
+
|
|
|
+ const now = Date.now();
|
|
|
+ if (now - this.lastFrameTime < this.frameInterval) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.isProcessing = true;
|
|
|
+ try {
|
|
|
+ const filePath = `${this.context.filesDir}/live${index}.jpg`;
|
|
|
+
|
|
|
+ // 检查文件是否存在
|
|
|
+ try {
|
|
|
+ fs.accessSync(filePath);
|
|
|
+ } catch {
|
|
|
+ this.isProcessing = false;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ const imageSource = image.createImageSource(filePath);
|
|
|
+ if (!imageSource) {
|
|
|
+ this.isProcessing = false;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建较小尺寸的PixelMap以提高性能
|
|
|
+
|
|
|
+ this.nextBuffer = await imageSource.createPixelMap();
|
|
|
+ imageSource.release();
|
|
|
+
|
|
|
+ // 交换缓冲区
|
|
|
+ if (this.activeBuffer) {
|
|
|
+ this.activeBuffer.release();
|
|
|
+ }
|
|
|
+ this.activeBuffer = this.nextBuffer;
|
|
|
+ this.nextBuffer = null;
|
|
|
+ this.lastFrameTime = now;
|
|
|
+ return true;
|
|
|
+ } catch (error) {
|
|
|
+ console.warn(TAG, "处理预览帧失败:", error);
|
|
|
+ return false;
|
|
|
+ } finally {
|
|
|
+ this.isProcessing = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ getActiveBuffer(): PixelMap | null {
|
|
|
+ return this.activeBuffer;
|
|
|
+ }
|
|
|
+
|
|
|
+ release() {
|
|
|
+ if (this.activeBuffer) {
|
|
|
+ this.activeBuffer.release();
|
|
|
+ this.activeBuffer = null;
|
|
|
+ }
|
|
|
+ if (this.nextBuffer) {
|
|
|
+ this.nextBuffer.release();
|
|
|
+ this.nextBuffer = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|