npm package: @femate/web-camera
Description: 全网最强TS版人脸识别插件
Author: BlindMonk
Latest version: 0.2.5

<p align="center" style="margin:30px 0;">
  <a href="#">
    <!-- <img width="150" height="auto" src="./logo.svg"/> -->
    <img width="150" height="auto" src="https://cdn.jsdelivr.net/gh/MaleWeb/picture/images/techblog/face-logo.png"/>
    
  </a>
  <h1 align="center">WebCamera</h1>
  <p align="center">专注web端人脸、兼容多端、Client人脸识别、拓展美颜、基于TypeScript的插件</p>  
</p>

<p align="center">  
    <img src="https://img.shields.io/badge/-Rollup-34495e?logo=rollup" />
    <img src="https://img.shields.io/badge/-TypeScript-blue?logo=typescript&logoColor=white" />
    <img src="https://img.shields.io/badge/-ESLint-4b32c3?logo=eslint&logoColor=white" />
    <img src="https://img.shields.io/badge/-pnpm-F69220?logo=pnpm&logoColor=white" />
    <img src="https://img.shields.io/badge/-Prettier-ef9421?logo=Prettier&logoColor=white" alt="Prettier">
    <img src="https://img.shields.io/badge/-scss-1D365D?logo=scss&logoColor=white" alt="Less">  
    <img src="https://img.shields.io/badge/license-Apache-blue.svg" alt="Apache">   
    
<p>   
<p align="center"> 
<img width="460px" src="https://uufefile.uupt.com/eic/male/github/faceDemo-1.gif" />

  <!-- <img width="460px" src="./static/faceDemo-1.gif" /> -->
<p> 
<p align="center"> 
<img width="460px" src="https://uufefile.uupt.com/eic/male/github/faceDemo-2.gif" />
  <!-- <img width="460px" src="./static/faceDemo-2.gif" /> -->
<p> 
<p align="center"> 
<img width="460px" src="https://uufefile.uupt.com/eic/male/github/faceDemo-3.gif" />
  <!-- <img width="460px" src="./static/faceDemo-3.gif" /> -->
<p> 



# 简介

[使用文档介绍]()  |  [博文介绍]()  


# 特性

- ✅简单、易可拓展的API，零成本上手
- ✅三种相机模式：默认相机、美颜相机、本地人脸识别相机
- ✅支持镜像：可以水平翻转。PS：保存后的图片URL根据场景翻转
- ✅支持拍照功能：根据业务场景调用即可。
- ✅支持下载图片：插件自封装a标签，触发下载事件。PS：下载的图片为拍照时记录图片。
- ✅更多能力等你挖掘....

如果您觉得这个项目还不错, 可以在 [Github](https://github.com/tobe-fe-dalao/femate) 上面帮我点个`star`, 支持一下作者 ☜(ﾟヮﾟ☜)
# 如何使用

## 方式1：通过 script 标签引入  
### CDN源
CDN源：jsdelivr
```html

<script src="https://cdn.jsdelivr.net/npm/@femate/web-camera@latest"></script>


```
CDN源：unpkg
```html
<script src="https://unpkg.com/@femate/gweb-camera@latest"></script>

```
### HTML调用

```html
<h1 align="center">Hello 我是扫地盲僧!</h1>
<p align="center">这是一个兼容移动PC,实现客户端人脸识别,全网唯一TS版Web摄像头插件</p>
<div id="wrapper"></div>
<script type="text/javascript">
    window.onload = () => {
        const camera = new WebCamera('#wrapper', {
          // 任意参数大于0，则代表开启美颜插件
            beautyConfig: {
                beauty: 0,
                brightness: 0,
                ruddy: 0
            },
            // 本地人脸识别插件
            isClintFace: false,
            takePhoto(src) {
                console.log(src, '拍照的图片')
            },
            isHasFace(val) {
                console.log('检测到人脸')
            }
        });
        camera.start();
    }
</script>
```
## 方式2：通过 import 引入  

### 安装依赖
```shell
npm i @femate/web-camera
# or
pnpm add @femate/web-camera
# or
yarn add  @femate/web-camera 
```
### 使用

```html
<h1 align="center">Hello 我是扫地盲僧!</h1>
<p align="center">这是一个兼容移动PC,实现客户端人脸识别,全网唯一TS版Web摄像头插件</p>
<div id="wrapper"></div>
```

```javascript
  import WebCamera from '@femate/web-camera'
  const WebCam = new WebCamera('#app', {
            // 任意参数大于0，则代表开启美颜插件
            beautyConfig: {
                beauty: 0,
                brightness: 0,
                ruddy: 0
            },
            // 本地人脸识别插件
            isClintFace: false,
            takePhoto(src) {
                console.log(src, '拍照的图片')
            },
            isHasFace(val) {
                console.log('检测到人脸')
            }
        })
  WebCam.start()
```
# 事件
## Options
```typescript
const defaultOptions = {
  // 相机参数
  cameraStyle: {
    width: 320,
    height: 320,
    radius: '48%',
    border: '2px solid #ccc',
    bg: 'black'
  },
  // 导出图片设置
  outImg: {
    // 导出图片类型,/png|jpeg|bmp|gif/
    type: 'png',
    // 导出图片质量0-1之间
    quality: 0
  },
  // 是否开启镜像,响应式参数
  isFlip: true,
  // 美颜相机参数
  beautyConfig: {
    beauty: 0,
    brightness: 0,
    ruddy: 0
  },
  // 是否开启clint人脸检测
  isClintFace: false,
} as const

```
## PublicEvent
对外暴露事件
```typescript
  //开始视频  自动检测相机模式
  public start(){...}
  //拍照   PS：返回base64URL
  public takePhoto(callback):string{...}
  //清除画布
  public clearCanvas() {...}
  //手动更新美颜参数
  public setBeautyParam(params:BeautyConfig){...}
   //保存图片
  public downloadImg(){...}
  //上传图片,处理为文件格式
  public uploadImg(callback){...}
  //重置相机
  public reset(){...}
  //销毁实例
  public destroy() {...}
```
## 核心code
如果你不需要过多的插件，只想要基础版设备调用事件，这里已帮你抽离出最核心的部分。
### 设备兼容

``` typescript
// 设备兼容处理兼容
const cameraPolyFill = ():Promise=>{
  const URL = window.URL || window.webkitURL
  this.userMedia = this.userMedia && !!navigator.mediaDevices.getUserMedia && !!this.URL
  if (typeof window === 'undefined') {
      return;
  }
  if (navigator.mediaDevices === undefined) {
      navigator.mediaDevices = {};
  }
  // 兼容火狐不工作的情况
  if (navigator.userAgent.match(/Firefox\D+(\d+)/)) {
    if (parseInt(RegExp.$1, 10) < 21) this.userMedia = false;
  }
  // 兼容离开页面时关闭媒体流
  if (this.userMedia||window.stream) {
    window.addEventListener('beforeunload', function (event) {
      window.stream.getTracks().forEach((track: any) => {
        track.stop();
      });
    });
  }
  // 如果缺少 getUserMedia 属性，我们将添加它
  if (navigator.mediaDevices.getUserMedia === undefined) {
    // https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
    navigator.mediaDevices.getUserMedia = function (constraints) {
      const getUserMedia =
        navigator.getUserMedia ||
        navigator.webkitGetUserMedia ||
        navigator.mozGetUserMedia ||
        navigator.msGetUserMedia;

      if (!getUserMedia) {
        return Promise.reject(
          new Error("getUserMedia is not implemented in this browser")
        );
      }
      // 打包一个旧的 getUserMedia 函数
      return new Promise(function (resolve, reject) {
        getUserMedia.call(navigator, constraints, resolve, reject);
      });
    };
  }
}
```
### 设备调用
```typescript
public getUserMedia(width: number, height: number): Promise<any> {
    let self = this
    const constraints: ContainTypes = {
      audio: false,
      video: {
        width: { ideal: width },
        height: { ideal: height },
      },
      facingMode: this.front ? 'user' : 'environment',
    }
    return new Promise((resolve, reject) => {
      navigator.mediaDevices.getUserMedia(constraints).
        then((stream) => {
          // 兼容异步加载问题
          if ("srcObject" in this.video) {
            self.video.srcObject = stream;
          } else {
            // 使用 URL.createObjectURL作为旧浏览器的兼容
            self.video.src = self.URL.createObjectURL(stream)
          }
          window.stream = stream;
          resolve(stream)
        }).catch((error: Error) => {
          reject(error);
          console.log(error);
        });
    })
  }
```
### Video转Canvas
常规方案是toDataURL，但其性能问题我们要废弃它，1同步堵塞，2占用更多内存，3获得字符体积大等问题
```typescript
public videoToCanBlob(canvas: HTMLCanvasElement, imgType: string, quality: number):Promise<any> {
    return new Promise((resolve, reject) => {
      //异步执行函数
      const ctx = canvas.getContext('2d');
      ctx?.drawImage(this.video, 0, 0, canvas.width, canvas.height)
      const reader = new FileReader()
      canvas.toBlob((blob: any) => {
        reader.readAsDataURL(blob as any)
        reader.onload = (e: any) => {
          resolve(e.target?.result)
        }
      }, `images/${imgType}`, quality)
    })
  }
```
# About Me  

<img width="460px" src="https://cdn.jsdelivr.net/gh/MaleWeb/picture/images/techblog/book-slogan.gif" />

 <img src="https://uufefile.uupt.com/eic/male/github/wechat.jpg" width="220" />  

 公众号：盲僧公众号，关注后回复「粉丝群」

# RoadMap
[Milestones](https://github.com/tobe-fe-dalao/femate/projects)  

# License
 [Apache-2.0](./LICENSE) © [MaleWeb](https://github.com/MaleWeb)