video / image上传操作-校验、截取首帧和正方形预览图等

常见video / image上传操作-校验、截取首帧和正方形预览图等。

上回搞了一个视频和图片上传和校验的需求,感觉学到很多,一些常见的函数记录如下:

1. 图片校验尺寸
const { maxCount = 30, maxWidth, maxHeight, minHeight = 200, minWidth = 200 } = props;
// 文件个数和内存大小、格式可以提前校验,不用请求图片信息。

const reader = new FileReader();
reader.readAsDataURL(file);
// eslint-disable-next-line no-loop-func
reader.onload = (e) => {
  const img = new Image();
  img.src = e.target.result;
  img.onload = () => {
    const width = img.width;
    const height = img.height;
    if (
      (maxWidth && width > maxWidth) ||
      (maxHeight && height > maxHeight) ||
      (minWidth && width < minWidth) ||
      (minHeight && height < minHeight)
    ) {
     resolve(false);
    } else {
      // 通过全部校验,处理图片
      resolve(true)
    }
  };
};
2. 视频校验尺寸

需要了解一下视频加载中的触发事件顺序。
参考:
https://guste.github.io/2018/07/24/video%E6%A0%87%E7%AD%BE%E4%BA%8B%E4%BB%B6%E6%8C%87%E5%8C%97/

  const { maxCount = 30, maxWidth, maxHeight, minHeight = 200, minWidth = 200 } = props;
  // 文件个数和内存大小、格式可以提前校验,不用请求图片信息。
  // 视频请求文件信息用createObjectURL
  
  let video = document.createElement('video');
  video.currentTime = 1; // 取封面首帧需要currentTime=1
  video.src = window.URL.createObjectURL(file);
  // 获取视频的元数据,但是文件不一定加载出来,此处可以进行校验
  video.addEventListener('loadedmetadata', (e) => {
    if (
      (maxWidth && video.videoWidth > maxWidth) ||
      (maxHeight && video.videoHeight > maxHeight) ||
      (minWidth && video.videoWidth < minWidth) ||
      (minHeight && video.videoHeight < minHeight) ||
      (maxDuration && video.duration > maxDuration)
    ) {
      resolve(false)
    } else {
      // 进行下一步 loadeddata 事件,取封面首帧
      // 此时视频画面信息不一定加载出来,取出来的画面是纯黑色。
    }
  });
  // 校验完毕,处理封面图和展示图
  video.addEventListener('loadeddata', (e) => {
	// 为了保险可以在这里再校验一次,不通过的resolve(false)
	// 取首帧,函数附下。
	const poster = getVideoPoster(video)
  });
  };
3. 视频截取第一帧

参考:https://juejin.cn/post/6844903933631004679
此处注意一个小坑:video视频设置currentTime不起作用?(我们要求视频出现需要跳转开头),但是设置currentTime=0不起作用,后面经过一番搜索,设置成currentTime=‘0’才能达到效果。要赋值字符串才行。

web前端处理图片首选当然是canvas。

// 注意传入的video是上文中已经赋值了src的DOM节点,并且设置currentTime=1。
// 存在有文章说即使在loadeddata事件中仍然截取为黑色,可以尝试将video属性赋值“muted” "autoplay" “preload”,因为在chrome中只有静音的视频才能自动播放,这样截取出的第一帧就会有值。

  getVideoPoster = (video) => {
    const canvas = document.createElement('canvas');
    canvas.width = video.videoWidth;
    canvas.height = video.videoHeight;
    const ctx = canvas.getContext('2d');
    ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
    return canvas.toDataURL('image/jpg', 1);
  };

完整截取的上传函数如下:
onChange = (e)=>{
  const uploadFiles = e.target.files?.[0] || {};
  let video = document.createElement('video');
  video.currentTime = '1'; // 取封面首帧需要currentTime=1
  video.src = window.URL.createObjectURL(file);
  video.addEventListener('loadeddata', (e) => {
	const poster = getVideoPoster(video)
  });
}

4. 截图方形预览图(视频 / 图片通用)

上文中已经截取到了base64格式的视频首帧,因此预览图从封面中截取,此处截取的规则如下:图片自适应在封面(设置为200*200)大小,短的那一条边和200px等宽,全部取用,而更长的那一条边取居中长度裁剪。(这么说不知道能不能形容清楚)
在裁剪之前简单介绍一下canvas裁剪的函数,其实还是靠最基本的drawImage。
ctx.drawImage(绘画对象, x, y, imageSizeX, imageSizeY, canvasX, canvasY, canvasSizeX, canvasSizeY);
使用这个函数的含义:
将绘画对象花在画布上,首先从绘画对象的(x,y)坐标开始,横着沿x轴画一条imageSizeX这么长的线,然后再纵向沿着y轴画一条imageSizeY这么长的线,我们就在【原图】上画了一个长方形。
然后把这个长方形放进canvas里
video / image上传操作-校验、截取首帧和正方形预览图等_第1张图片

  // 可以是imgDom或者videoDom,Dom节点就是上文中我们创建的节点对象。
  squareImage = (imgDom) => {
    const width = imgDom.videoWidth || imgDom.width;
    const height = imgDom.videoHeight || imgDom.height;
    const canvasSize = 200;
    var size = Math.min(width, height);

    const canvas = document.createElement('canvas');
    canvas.width = canvasSize;
    canvas.height = canvasSize;
    const ctx = canvas.getContext('2d');
    const offsetX = width >= height ? (width - size) / 2 : 0;
    const offsetY = width >= height ? 0 : (height - size) / 2;

    ctx.drawImage(imgDom, offsetX, offsetY, size, size, 0, 0, canvasSize, canvasSize);
    return canvas.toDataURL('image/jpg', 0.9);
  };
5. 图片压缩

参考之前的调研文章

  compressImage = (img) => {
    const canvas = document.createElement('canvas');
    canvas.width = img.width;
    canvas.height = img.height;
    const ctx = canvas.getContext('2d');
    ctx.drawImage(img, 0, 0, img.width, img.height);
    return canvas.toDataURL('image/jpg', 0.7);
  };
6. base64转二进制字节流上传
  dataURItoFile = (dataURI) => {
    var byteString = atob(dataURI.split(',')[1]);
    var ab = new ArrayBuffer(byteString.length);
    var ia = new Uint8Array(ab);
    for (let i = 0; i < byteString.length; i++) {
      ia[i] = byteString.charCodeAt(i);
    }
    return new Blob([ab], { type: 'image/png' });
  };

你可能感兴趣的:(视频图片媒体资源相关,html)