4***@qq.com
4***@qq.com
  • 发布:2026-07-12 01:04
  • 更新:2026-07-12 01:06
  • 阅读:64

uniapp x nvue vue3 拍照并截取指定区域

分类:uni-app x

API用哪个?

2026-07-12 01:04 负责人:无 分享
已邀请:
Ask小助手

Ask小助手 - Ask社区AI助手

欢迎到专业群( uni-app x技术交流群 ) 咨询,群中有相关专业的管理员和群友。

在 uni-app x 中实现“拍照并截取指定区域”,通常有两种方案。结合你的问题,核心 api 是 takeSnapshot,但需要注意 camera 组件本身的特殊性。

方案一:使用 uni.chooseImage 拍照后,用 canvas 裁剪

这是最通用的方案,适用于所有平台,但不是在拍照预览界面实时截取,而是拍照完成后对生成的图片进行裁剪。

适用平台:android、ios、鸿蒙 next、web、微信小程序

实现步骤

  1. 调用 uni.chooseImage,设置 sourceType: ['camera'] 调起相机拍照,获取图片临时路径。
  2. 将图片绘制到离屏 canvas 上,根据你指定的区域坐标和尺寸进行裁剪。
  3. 通过 canvas.toTempFilePath 导出裁剪后的图片。

示例代码pages/camera-crop/camera-crop.uvue):

<template>  
  <view class="page">  
    <button @click="takePhotoAndCrop">拍照并裁剪</button>  
    <image v-if="croppedImagePath" :src="croppedImagePath" style="width: 200rpx; height: 200rpx;" />  
  </view>  
</template>  

<script setup lang="uts">  
import { ref } from 'vue'  

const croppedImagePath = ref<string | null>(null)  

const takePhotoAndCrop = () => {  
  uni.chooseImage({  
    count: 1,  
    sourceType: ['camera'],  
    success: (res) => {  
      const tempFilePath = res.tempFilePaths[0]  
      // 获取图片信息,以便按比例计算裁剪区域  
      uni.getImageInfo({  
        src: tempFilePath,  
        success: (imageInfo) => {  
          cropImage(tempFilePath, imageInfo.width, imageInfo.height)  
        }  
      })  
    },  
    fail: (err) => {  
      console.error('拍照失败', err)  
    }  
  })  
}  

const cropImage = (src: string, originalWidth: number, originalHeight: number) => {  
  // 定义裁剪区域(相对于原始图片尺寸)  
  // 例如:从左上角 (50, 50) 开始,裁剪 200x200 的区域  
  const cropX = 50  
  const cropY = 50  
  const cropWidth = 200  
  const cropHeight = 200  

  // 创建离屏 canvas  
  const canvas = uni.createOffscreenCanvas({  
    type: '2d',  
    width: cropWidth,  
    height: cropHeight  
  })  
  const ctx = canvas.getContext('2d')  

  const image = new Image()  
  image.src = src  
  image.onload = () => {  
    // 将图片的指定区域绘制到 canvas 上  
    ctx.drawImage(image, cropX, cropY, cropWidth, cropHeight, 0, 0, cropWidth, cropHeight)  
    // 导出裁剪后的图片  
    canvas.toTempFilePath({  
      success: (res) => {  
        croppedImagePath.value = res.tempFilePath  
        console.log('裁剪后的图片路径:', res.tempFilePath)  
      },  
      fail: (err) => {  
        console.error('导出图片失败', err)  
      }  
    })  
  }  
}  
</script>  

<style>  
.page {  
  display: flex;  
  flex-direction: column;  
  align-items: center;  
  justify-content: center;  
  padding-top: 100rpx;  
}  
</style>

本助手使用国产模型,生成代码准确率较低。强烈建议使用uni-agent生成代码

方案二:在 camera 组件预览界面上实时截取指定区域

如果你需要在拍照预览界面,叠加一个取景框(如身份证拍摄框),并直接截取框内画面,可以使用 camera 组件配合 takeSnapshot api。

核心 apitakeSnapshot

注意:根据社区反馈,takeSnapshotcamera 组件的截图结果可能为黑屏,这是由系统底层相机预览层与 ui 渲染层不在同一图层导致的,属于平台限制。你可以通过插件市场寻找已经解决了此问题的原生相机插件。

适用平台:app-android、app-ios (vdom 和蒸汽模式均支持,但蒸汽模式需注意版本兼容)

实现步骤

  1. 使用 camera 组件全屏展示相机预览。
  2. camera 组件上方,使用 view 覆盖一个取景框(半透明遮罩,中间镂空)。
  3. 调用 uni.createSelectorQuery() 获取 camera 组件或根视图的 element
  4. 调用 element.takeSnapshot 方法截取整个视图。
  5. 将截图结果绘制到 canvas 上,根据取景框坐标和尺寸进行裁剪。

示例代码pages/camera-snapshot/camera-snapshot.uvue):

<template>  
  <view class="page">  
    <camera id="camera" class="camera" device-position="back" flash="off" />  
    <!-- 取景框 -->  
    <view class="crop-overlay">  
      <view class="crop-box" />  
    </view>  
    <button class="capture-btn" @click="captureAndCrop">截取框内画面</button>  
  </view>  
</template>  

<script setup lang="uts">  
import { ref } from 'vue'  

const captureAndCrop = () => {  
  // 1. 获取 camera 组件的元素节点  
  const query = uni.createSelectorQuery()  
  query.select('#camera').fields({  
    node: true,  
    size: true  
  }).exec((res) => {  
    const cameraNode = res[0]?.node  
    if (!cameraNode) {  
      console.error('未获取到 camera 节点')  
      return  
    }  
    // 2. 对 camera 组件进行截图  
    cameraNode.takeSnapshot({  
      success: (snapshotRes) => {  
        const snapshotPath = snapshotRes.tempFilePath  
        console.log('截图成功,路径:', snapshotPath)  
        // 3. 裁剪指定区域  
        cropSnapshot(snapshotPath, cameraNode)  
      },  
      fail: (err) => {  
        console.error('截图失败,可能为黑屏', err)  
        uni.showToast({ title: '截图失败,请重试', icon: 'none' })  
      }  
    })  
  })  
}  

const cropSnapshot = (snapshotPath: string, cameraNode: UniElement) => {  
  // 获取相机组件和取景框的尺寸与位置  
  const cameraRect = cameraNode.getBoundingClientRect()  
  // 定义取景框相对于相机组件的区域(这里假设取景框在相机中央,宽高 200rpx)  
  // 注意:rpx 需要根据屏幕宽度转换为 px  
  const systemInfo = uni.getSystemInfoSync()  
  const rpxRatio = systemInfo.screenWidth / 750  
  const boxWidth = 200 * rpxRatio  
  const boxHeight = 200 * rpxRatio  
  const boxX = (cameraRect.width - boxWidth) / 2  
  const boxY = (cameraRect.height - boxHeight) / 2  

  // 创建离屏 canvas 进行裁剪  
  const canvas = uni.createOffscreenCanvas({  
    type: '2d',  
    width: boxWidth,  
    height: boxHeight  
  })  
  const ctx = canvas.getContext('2d')  

  const image = new Image()  
  image.src = snapshotPath  
  image.onload = () => {  
    ctx.drawImage(image, boxX, boxY, boxWidth, boxHeight, 0, 0, boxWidth, boxHeight)  
    canvas.toTempFilePath({  
      success: (res) => {  
        console.log('裁剪后图片路径:', res.tempFilePath)  
        // 这里可以预览裁剪结果或上传  
      },  
      fail: (err) => {  
        console.error('裁剪失败', err)  
      }  
    })  
  }  
}  
</script>  

<style>  
.page {  
  flex: 1;  
  position: relative;  
}  
.camera {  
  width: 100%;  
  height: 100%;  
}  
.crop-overlay {  
  position: absolute;  
  top: 0;  
  left: 0;  
  right: 0;  
  bottom: 0;  
  background-color: rgba(0, 0, 0, 0.5);  
  display: flex;  
  align-items: center;  
  justify-content: center;  
}  
.crop-box {  
  width: 200rpx;  
  height: 200rpx;  
  border: 2px solid white;  
  background-color: transparent;  
}  
.capture-btn {  
  position: absolute;  
  bottom: 50px;  
  align-self: center;  
}  
</style>

本助手使用国产模型,生成代码准确率较低。强烈建议使用uni-agent生成代码

验证与排查

  • 截图黑屏:如果 takeSnapshotcamera 组件截图得到黑屏,说明系统相机预览层无法被应用层截图捕获。这是部分 android/ios 系统的已知限制。此时可考虑使用插件市场提供的原生相机插件,它们可能通过底层 api 解决了此问题。
  • 性能takeSnapshot 是异步操作,在蒸汽模式下性能表现会更好。务必在 release 包下测试性能,避免 debug 模式下的性能损耗。
  • 权限:确保在 manifest.json 中已配置相机权限。

插件市场推荐

如果上述方案不能满足需求,可以前往插件市场搜索原生相机组件,它们通常提供了更强大的自定义界面和截图能力:

内容为 AI 生成,仅供参考

要回复问题请先登录注册