canvas 图片压缩

1,099 阅读2分钟

图片压缩有两种方式

第一种:canvas改变图片的尺寸, 重新生成图片即可

第二种:canvas.toDataURL("image/jpeg", quality); 控制quality的值

  • 在不改变图片的(尺寸)宽高前提下:
  • 默认值得到的图片往往比原图大
  • quality0.2~0.5之间,压缩图片可以最大化,同时图片质量造成影响不大
  • 此参数要想有效,图片的mimeType需要是image/jpeg或者image/webp,其他mimeType值无效。默认压缩质量是0.92

示例

<input type="file" id="upload">

上传格式尺寸限制

//可上传的图片格式
const ACCEPT = ["image/jpg", "image/png", "image/jpeg"];
// 可上传的最大图片容量
const MAXIZE = 8 * 1024 * 1024;
const MAXIZE_STR = "8MB";

选择图片

const upload = document.getElementById("upload");
upload.addEventListener("change", function (e) {
  const [file] = e.target.files;
  if (!file) {
    return;
  }
  const { type: fileType, size: fileSize } = file;
  console.log("压缩前大小:", fileSize)
  // 图片类型检查
  if (!ACCEPT.includes(fileType)) {
    alert("不支持[" + fileType + "]文件类型!");
    upload.value = "";
    return;
  }
  // 图片容量检查
  if (fileSize > MAXIZE) {
    alert(`文件超出${MAXIZE_STR}`);
    upload.value = "";
    return;
  }
  // 压缩图片
  convertImageToBase64(file, (base64Image) => {
    compress(base64Image, uploadToServer)
  }
  );
});

核心:压缩图片

function compress(base64Image, callback) {
  let maxW = 1024;
  let maxH = 1024;
  const image = new Image();
  image.addEventListener("load", function (e) {
    let ratio; //图片的压缩比
    let needCompress = false; //是否需要压缩
    // 比较图片的实际宽高是否超出
    if (maxW < image.naturalWidth) {
      needCompress = true;
      ratio = image.naturalWidth / maxW;
      //图片高度也需要等比压缩
      maxH = image.naturalHeight / ratio;
    } //经过处理后,实际图片的尺寸为 1024 * 576
    if (maxH < image.naturalHeight) {
      needCompress = true;
      ratio = image.naturalHeight / maxH;
      maxW = image.naturalWidth / ratio;
    } //经过处理后,实际图片的尺寸为 1024 * 576
    if (!needCompress) {
      maxW = image.naturalWidth;
      maxH = image.naturalHeight;
    } //如果不需要压缩,需要获取图片的实际尺寸
    const canvas = document.createElement("canvas");
    canvas.setAttribute("id", "__compress__");
    canvas.width = maxW;
    canvas.height = maxH;
    canvas.style.visibility = "hidden";
    document.body.appendChild(canvas);

    const ctx = canvas.getContext("2d");
    ctx.clearRect(0, 0, maxW, maxH);
    ctx.drawImage(image, 0, 0, maxW, maxH);
    const compressImage = canvas.toDataURL("image/jpeg", 0.85);
  
    callback && callback(compressImage);
    const _image = new Image();
    _image.src = compressImage;
    document.body.appendChild(_image);
    canvas.remove();
    console.log("压缩比:" + image.src.length / _image.src.length);
  });
  image.src = base64Image;
  document.body.appendChild(image);
}

上传图片

function uploadToServer(compressImage) {
    const file = blobToFile(dataURLtoBlob(compressImage))
    console.log("压缩后大小:", file.size)
    showInfo("压缩后大小:" + file.size / 1024 + "K")
  // console.log("upload to server...", compressImage);
}

文件转换方法

将base64转换为blob

function dataURLtoBlob(dataurl) {
  var arr = dataurl.split(','),
    mime = arr[0].match(/:(.*?);/)[1],
    bstr = atob(arr[1]),
    n = bstr.length,
    u8arr = new Uint8Array(n);
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  return new Blob([u8arr], { type: mime });
}

将blob转换为file

function blobToFile(theBlob, fileName){
   theBlob.lastModifiedDate = new Date();  // 文件最后的修改日期
   theBlob.name = fileName;                // 文件名
   return new File([theBlob], fileName, {type: theBlob.type, lastModified: Date.now()});
}

图片转为base64

function convertImageToBase64(file, callback) {
  let reader = new FileReader();
  reader.addEventListener("load", function (e) {
    const base64Image = e.target.result;
    callback && callback(base64Image);
    reader = null;
  });
  // 读取文件内容
  reader.readAsDataURL(file);
}