/** * cordova-plugin-camera-preview 插件工具函数 */ import CameraPreviewBase, { IVideoConf } from "./CameraPreviewBase"; import { scaleImageToCanvas, scaleImage, getCanvasByImg } from "../img-utils"; export interface ICameraPreviewPluginParams { /** 插件配置 */ videoConf?: IPluginConf; /** 背景 DOM,用于控制背景显示隐藏 */ bgDom?: HTMLElement; /** 是否将结果图片缩放至设置的宽高,width 必须设置 */ isScaleImg?: boolean; } export interface IPluginConf extends IVideoConf { /** 预览视频播放 x 轴位置 默认为 0 */ x?: number; /** 预览视频播放 y 轴位置 默认为 0 */ y?: number; /** 摄像头 默认为前置摄像头 front */ camera?: "back" | "front"; /** 是否使用前置摄像头 */ isFrontCamera?: boolean; /** html 位于预览视频前面,则设置为 true */ toBack?: boolean; /** 如果 toBack 设置为 false 则不起作用,在这种情况下您使用 takePicture 方法 默认为 true */ tapPhoto?: boolean; /** 当视图位于前景时允许用户点击以聚焦 默认为 false */ tapFocus?: boolean; /** 如果 toBack 设置为 false 则不起作用 默认为 false */ previewDrag?: boolean; /** 将图像捕获到文件并返回文件路径,而不是返回 base64 编码数据 默认为 false */ storeToFile?: boolean; /** -仅适用于 Android - 禁用图像的自动旋转,并让浏览器处理它(继续阅读如何实现它) 默认为 false */ disableExifHeaderStripping?: boolean; } /** * @ionic-native/camera-preview 插件视频流 * https://github.com/cordova-plugin-camera-preview/cordova-plugin-camera-preview */ export class CameraPreviewPlugin extends CameraPreviewBase { videoConf: IPluginConf = { toBack: true, x: 0, y: 0, width: window.screen.width, height: window.screen.height, }; tempDisplay = ""; tempBg = ""; bgDom = document.getElementById("root"); isPlaying = false; isScaleImg; constructor(params: ICameraPreviewPluginParams) { super(params); const { videoConf, bgDom, isScaleImg = true } = params; if (bgDom) { this.bgDom = bgDom; } this.isScaleImg = isScaleImg; this.videoConf = { ...this.videoConf, ...videoConf }; if (!this.videoConf.camera && this.videoConf.facingMode === "environment") { this.videoConf.camera = "back"; } else if (!this.videoConf.camera) { this.videoConf.camera = "front"; } } /** * 获取 CameraPreview 实例,解决异步问题 * @returns */ getPreviewer() { return new Promise((resolve) => { if (window.CameraPreview) { resolve(window.CameraPreview); return window.CameraPreview; } console.warn("window.CameraPreview is not defined"); document.addEventListener( "deviceready", async () => { if (window.CameraPreview) { resolve(window.CameraPreview); } else { throw new Error("window.CameraPreview is not defined"); } }, false, ); }); } /** * 开启 * @returns */ async start() { if (this.isPlaying) { return Promise.reject(new Error("video is playing!")); } return new Promise(async (resolve, reject) => { await this._startCamera(resolve, reject); this.isPlaying = true; // 隐藏 DOM this.bgDom && this._hideDom(this.bgDom); }); } /** * 开启摄像头 * @param resolve * @returns */ async _startCamera(resolve: Function, reject: Function) { const CameraPreview = await this.getPreviewer(); if (void 0 === this.videoConf.toBack) { this.videoConf.toBack = true; } return new Promise((_resolve, _reject) => { CameraPreview?.startCamera( this.videoConf, function () { _resolve(); resolve(); }, function (err: Error) { _reject(err); reject(err); }, ); }); } /** * 截图,返回 canvas * @returns HTMLCanvasElement */ getSnap(): Promise { return this.getSnapImg().then((img) => Promise.resolve(getCanvasByImg(img))); } /** * 截图 返回 img * @returns HTMLImageElement */ getSnapBase64(opt = {}): Promise { return new Promise(async (resolve, reject) => { const CameraPreview = await this.getPreviewer(); const options = { quality: 85, ...opt, }; CameraPreview.takeSnapshot( options, (base64PictureData: string) => { resolve("data:image/jpeg;base64," + base64PictureData); }, reject, ); }); } /** * 截图,返回 image * @returns HTMLImageElement */ getSnapImg(): Promise { return new Promise(async (resolve) => { this.getSnapBase64().then((base64PictureData: string) => { this.getImgEle(base64PictureData).then((img) => { if (!this.isScaleImg || !this.videoConf?.width) { resolve(img); return; } const _imgSize = this.getDomWH(img); this.getImgEle( // 缩放图片,保证图片大小与配置的一致 scaleImage(img, { scaleFactor: this.videoConf?.width / _imgSize.width, }), ).then(resolve); }); }); }); } /** * 关闭摄像头 */ close() { return new Promise(async (resolve, reject) => { const CameraPreview = await this.getPreviewer(); this.bgDom && this._resetDom(this.bgDom); if ("function" === typeof CameraPreview?.stopCamera) { CameraPreview?.stopCamera(resolve, reject); } else { const err = new Error( "CameraPreview?.stopCamera is not a function, is" + JSON.stringify(CameraPreview?.stopCamera), ); reject(err); throw err; } this.isPlaying = false; }); } _hideDom(dom: HTMLElement) { this.tempDisplay = dom.style.display; dom.style.display = "none"; this.tempBg = document.body.style.background; document.body.style.background = "transparent"; } _resetDom(dom: HTMLElement) { dom.style.display = this.tempDisplay; document.body.style.background = this.tempBg; } getVideoSize() { return { width: this.videoConf.width ?? document.body.clientWidth * 0.5, height: this.videoConf.height ?? document.body.clientHeight * 0.5, }; } } export default CameraPreviewPlugin;