收藏
回答

微信xr相机如何保存照片?

本人这边项目里有个需求,就是人脸检测后,将指定的模型附加到使用者的脸上,随后有一个拍摄照片功能,将附加模型后的用户的画面截取出来,并存储到手机本地中,现在人脸识别,以及相关模型也附加到人脸上,但是在拍摄上出现问题,总是保存失败,wxml文件:

<xr-scene ar-system="modes:Face;camera:Front" bind:ready="handleReady" bind:tick="handleTick">
  <xr-assets bind:loaded="handleAssetsLoaded">
    <xr-asset-load type="gltf" asset-id="mask" src="{{ObjectPath}}" />
  </xr-assets>


  <xr-env env-data="xr-frame-team-workspace-day" />
  <xr-light type="ambient" color="1 1 1" intensity="1" />
  <xr-light type="directional" rotation="40 70 0" color="1 1 1" intensity="3" />


  <xr-ar-tracker mode="Face" auto-sync="43">
    <xr-gltf id="mask" model="mask" rotation="0 180 0" scale="0.5 0.5 0.5" />
  </xr-ar-tracker>


  <xr-camera id="camera" clear-color="0.4 0.8 0.6 1" background="ar" is-ar-camera />
</xr-scene>

ts 文件:

import { MarkerPath, SceneState } from "../../utils/data";


// components/user-xr-start/index.ts
Component({


  /**
   * 组件的属性列表
   */
  properties: {
    modelPath:{
      type:String,
      value:""
    }
  },


  /**
   * 组件的初始数据
   */
  data: {
    loaded:false,
    hasFrontCamerafalse,
    cameraPermissionGrantedfalse,
    ObjectPath:MarkerPath.object,
    tempImagePath:"",
    currentState:SceneState.Init,
  },


  // 添加生命周期函数
  lifetimes: {
    attachedfunction() {
      // 初始化实例属性
      this.scene = null;
      this.camera = null;
      this.mask = null;
      this.tmpV3 = null;
      
      // 组件加载时检查相机状态
      this.checkCameraStatus();
    },
    
    detachedfunction() {
      // 清理引用
      this.scene = null;
      this.camera = null;
      this.mask = null;
      this.tmpV3 = null;
    }
  },



    scenenull,
    masknull,



  /**
   * 组件的方法列表
   */
  methods: {


    // 检查相机状态
    checkCameraStatusfunction() {
      const that = this;
      
      // 1. 检查是否有前置相机
      wx.getSystemInfo({
        successfunction(res{
          // 大多数现代手机都有前置相机,但可以进一步确认
          that.setData({
            hasFrontCameratrue // 假设有前置相机
          });
          
          // 2. 检查相机权限
          that.checkCameraPermission();
        },
        failfunction(err{
          console.error('获取系统信息失败:', err);
          that.showCameraWarning('无法检测相机硬件状态');
        }
      });
    },  


    // 检查相机权限
    checkCameraPermissionfunction() {
      const that = this;
      
      wx.getSetting({
        success(res) => {
          if (res.authSetting['scope.camera']) {
            // 已授权相机权限
            that.setData({
              cameraPermissionGrantedtrue
            });
          } else {
            // 未授权相机权限
            that.setData({
              cameraPermissionGrantedfalse
            });
            that.requestCameraPermission();
          }
        },
        fail(err) => {
          console.error('获取设置失败:', err);
          that.showCameraWarning('无法检测相机权限状态');
        }
      });
    },


    // 请求相机权限
    requestCameraPermissionfunction() {
      const that = this;
      
      wx.authorize({
        scope'scope.camera',
        success() => {
          // 用户同意授权
          that.setData({
            cameraPermissionGrantedtrue
          });
        },
        fail(err) => {
          console.error('相机权限授权失败:', err);
          that.showCameraWarning('请允许使用相机以体验AR功能');
        }
      });
    },


    // 显示相机警告
    showCameraWarningfunction(message{
      wx.showModal({
        title'相机提示',
        content: message,
        showCancelfalse,
        confirmText'确定',
        success(res) => {
          if (res.confirm) {
            // 用户点击确定后的操作
            console.log('用户确认相机提示');
          }
        }
      });
    },      


    handleReadyfunction ({detail}{


      // if (!this.data.cameraPermissionGranted || !this.data.hasFrontCamera) {
      //   this.showCameraWarning('无法启动前置相机,请检查设备是否支持和权限设置');
      //   return;
      // }


      console.log("user-xr handleReady");
      console.log(detail.value);
      console.log("scene 对象方法:"Object.getOwnPropertyNames(detail.value));
      console.log("scene 对象原型方法:"Object.getOwnPropertyNames(Object.getPrototypeOf(detail.value)));


      if(this.data.ObjectPath === ""){
        this.setData({
          ObjectPath:MarkerPath.object,
        });
      }


      this.scene = detail.value;
      const xrFrameSystem = wx.getXrFrameSystem();
      this.camera = this.scene.getElementById('camera').getComponent(xrFrameSystem.Camera);


      // this.mask = {el: this.scene.getElementById('mask'), color: 'rgba(44, 44, 44, 0.5)'};
      const maskElement = this.scene.getElementById('mask');
      if (maskElement) {
        this.mask = {el: maskElement, color'rgba(44, 44, 44, 0.5)'};
        console.log('Mask element found:', maskElement);
      } else {
        this.mask = null;
        console.warn('Mask element not found in scene');
      }


      this.tmpV3 = new (xrFrameSystem.Vector3)();


      console.log("user-xr handleReady:", {
        scenethis.scene,
        maskElementExists: !!maskElement,
        sceneHasExportImagetypeof this.scene.exportImage === 'function',
        sceneHasGetContainertypeof this.scene.getContainer === 'function'
      });



      this.triggerEvent('ready', detail.value);


    },



    handleAssetsLoadedfunction (detail{


      console.log('资源加载完成', detail.value);


      if(!this.scene){
        this.scene = detail.value;
        const xrFrameSystem = wx.getXrFrameSystem();
        this.camera = this.scene.getElementById('camera').getComponent(xrFrameSystem.Camera);
      
        const maskElement = this.scene.getElementById('mask');
        if (maskElement) {
          this.mask = {el: maskElement, color'rgba(44, 44, 44, 0.5)'};
          console.log('Mask element found after asset load:', maskElement);
        }
      }


      console.log("user: "this.data.ObjectPath);


      this.triggerEvent('assetsLoaded', detail.value);
    },


    handleTickfunction({detail}{
      // this.mask && this.triggerEvent('syncPositions', [
      //   this.getScreenPosition(this.mask)
      // ]);
      if (this.mask && this.mask.el) {
        this.triggerEvent('syncPositions', [
          this.getScreenPosition(this.mask)
        ]);
      } else {
        // 可选:触发一个空的位置事件或者不触发
        console.log('Mask element not ready yet');
      }
    },



    handleTouchModelfunction ({detail}{
      const {target} = detail.value;
      this[target.id].color = `rgba(${Math.random()*255}${Math.random()*255}${Math.random()*255}, 0.5)`;
    },


    getScreenPositionfunction(value{
      const {el, color} = value;
      const xrFrameSystem = wx.getXrFrameSystem();


      // console.log("getScreenPosition" + xrFrameSystem);
      if (!el || typeof el.getComponent !== 'function') {
        console.error('Invalid element:', el);
        return [00, color, ''];
      }


      const transformComponent = el.getComponent(xrFrameSystem.Transform);
      if (!transformComponent) {
        console.error('Transform component not found on element:', el);
        return [00, color, ''];
      }


      this.tmpV3.set(transformComponent.worldPosition);


      // this.tmpV3.set(el.getComponent(xrFrameSystem.Transform).worldPosition);
      const clipPos = this.camera.convertWorldPositionToClip(this.tmpV3);
      const {frameWidth, frameHeight} = this.scene;
      return [((clipPos.x + 1) / 2) * frameWidth, (1 - (clipPos.y + 1) / 2) * frameHeight, color, el.id];
    },


    takephoto:function(){


      console.log("user-xr takephoto ");


      console.log("调试信息:", {
        scenethis.scene,
        sceneTypetypeof this.scene,
        sceneIsNullthis.scene === null,
        sceneIsUndefinedthis.scene === undefined,
      });


      if (!this.scene) {
        console.error('场景未初始化,请确保 handleReady 已被调用');
        wx.showToast({
          title'场景未准备好',
          icon'none'
        });
        return;
      }
 
      // 确保场景已经准备就绪
      if (!this.camera) {
        wx.showToast({
          title'相机未准备就绪',
          icon'none'
        });
        return;
      }


      console.log("user-xr takephoto 2");
      const that = this;


      try {
        // 方法1: 通过相机组件截图
        if (this.camera && this.camera.el) {
          console.log("使用相机组件截图");
          
          // 获取相机元素的渲染目标
          const cameraEl = this.camera.el;
          if (cameraEl && typeof cameraEl.exportImage === 'function') {
            cameraEl.exportImage({
              successfunction(res{
                console.log("相机截图成功:", res);
                that.handlePhotoSuccess(res.tempFilePath);
              },
              failfunction(err{
                console.error('相机截图失败:', err);
                that.tryAlternativeCapture();
              }
            });
          } else {
            // 方法2: 尝试通过场景的 canvas 截图
            console.log("尝试通过场景 canvas 截图");
            this.trySceneCanvasCapture();
          }
        } else {
          console.log("尝试通过场景 canvas 截图");
          this.trySceneCanvasCapture();
        }
      } catch (error) {
        console.error('截图过程出错:', error);
        this.tryAlternativeCapture();
      }   
    },


    tryAlternativeCapturefunction() {
      const that = this;
      
      // 尝试通过 xr-camera 组件截图
      if (this.camera && this.camera.el) {
        console.log("尝试通过 camera 元素截图");
        // 这里可以添加通过相机元素截图的逻辑
        
        wx.showToast({
          title'截图功能暂不可用',
          icon'none'
        });
        
        // 触发失败事件
        this.triggerEvent('phototaken', {
          successfalse,
          error'截图功能不可用'
        });
      }
    },


    handlePhotoSuccessfunction(filePath{
      const that = this;
      
      this.setData({
        tempImagePath: filePath
      });


      console.log("user-xr takephoto success: " + filePath);


      this.saveImage();


      // 触发事件将结果返回给父组件
      this.triggerEvent('phototaken', {
        successtrue,
        filePath: filePath
      });
    },


    takephotoFromPagefunction() {
      // 这个方法需要从页面调用,通过 selectComponent 获取 XR 组件
      // 然后调用组件的截图方法
      try {
        // 如果您的页面中有对组件的引用
        if (this.scene && typeof this.scene.exportImage === 'function') {
          this.scene.exportImage({
            success(res) => {
              this.handlePhotoSuccess(res.tempFilePath);
            },
            fail(err) => {
              console.error('截图失败:', err);
              this.triggerEvent('phototaken', {
                successfalse,
                error: err
              });
            }
          });
        }
      } catch (e) {
        console.error('截图异常:', e);
      }
    },


    saveImage:function(){
      const that = this;
      wx.getSetting({
        success(res) => {
          if (!res.authSetting['scope.writePhotosAlbum']) {
            // 没有权限,请求权限
            wx.authorize({
              scope'scope.writePhotosAlbum',
              success() => {
                // 授权成功,保存图片
                that.saveImageToPhotosAlbum();
              },
              fail(err) => {
                console.error('相册授权失败', err);
                // 引导用户打开授权设置
                that.showAuthGuide();
              }
            });
          } else {
            // 已有权限,直接保存
            that.saveImageToPhotosAlbum();
          }
        }
      });
    },
    
    saveImageToPhotosAlbum:function(){
      wx.saveImageToPhotosAlbum({
        filePaththis.data.tempImagePath,
        success() => {
          wx.showToast({
            title'保存成功',
            icon'success',
            duration2000
          });
        },
        fail(err) => {
          console.error('保存失败', err);
          // 处理保存失败的特定情况
          if (err.errMsg.includes('auth deny')) {
            this.showAuthGuide();
          } else {
            wx.showToast({
              title'保存失败',
              icon'none',
              duration2000
            });
          }
        }
      });
    },
    showAuthGuide:function(){
      wx.showModal({
        title:'提示',
        content:'需要您授权保存到相册权限',
        confirmText'去设置',
        success(res) => {
          if (res.confirm) {
            // 打开设置页面
            wx.openSetting({
              success(settingRes) => {
                if (settingRes.authSetting['scope.writePhotosAlbum']) {
                  wx.showToast({
                    title'授权成功',
                    icon'success'
                  });
                }
              }
            });
          }
        }
      })
    },


  },


  observers:{
    'cameraPosition'function(eve{
      console.log('用户:', eve);


    },
    "currentState":function(state){
      console.log('当前状态:', state);
      if(this.data.currentState !== state){
        this.setData({
          currentState:state,
        },()=>{
            console.log("user-xr currentState:" + this.data.currentState);
            if(state === SceneState.TakePhoto){
                this.takephoto();
            }
        });
      };
    }
  }



})请问哪里不对?
回答关注问题邀请回答
收藏

1 个回答

登录 后发表内容