vue3 vant4 h5圖片上傳時壓縮

ZerlinM發表於2024-04-30

程式碼如下

upload元件的 afterRead 方法:

const afterRead = async file => {
  file.status = "uploading";
  file.message = "上傳中...";
  const { data } = await upLoaderImg(file.file); //使用上傳的方法。file.file
  if (data) {
    file.status = "done";
    // fileList.value.push(data);
  } else {
    file.status = "failed";
    file.message = "上傳失敗";
  }
};

共用檔案中的方法如下:

export const upLoaderImg = async (file) => {
  let _file = file;
  const maxSize = 200;
  // 先壓縮 再上傳
  if (file.size / 1024 > maxSize) {
    const img = await readImg(file);
    const base64Data = compress(img);
    _file = dataURLtoFile(base64Data, file.name);
  }

  // file為 你讀取成功的回撥檔案資訊
  // new 一個FormData格式的引數
  let params = new FormData();
  params.append("file", _file);

  const config = {
    headers: {
      token: getToken()
    }
  };

  return new Promise((resolve, reject) => {
    axios
      .post(`${baseURL}/upload`, params, config)
      .then(res => {
        if (res && res.data && res.status === 200) {
          //如果為真 resolve出去
          if (res.data.data) {
            resolve(res.data);
          } else {
            showFailToast(res.data.message);
            resolve(res.data);
          }
        } else {
          //否則 showFailToast 提示
          showFailToast("請求失敗");
          resolve({});
        }
      })
      .catch(err => {
        console.log("err", err);
        showFailToast("請求失敗");
        resolve({});
      });
  });
};

const compress = img => {
  let initSize = img.src.length;
  let width = img.width;
  let height = img.height;

  //如果圖片大於四百萬畫素,計算壓縮比並將大小壓至400萬以下
  let ratio;
  if ((ratio = (width * height) / 4000000) > 1) {
    ratio = Math.sqrt(ratio);
    width /= ratio;
    height /= ratio;
  } else {
    ratio = 1;
  }

  let canvas = document.createElement("canvas"),
    ctx = canvas.getContext("2d");

  let tCanvas = document.createElement("canvas"),
    tctx = tCanvas.getContext("2d");

  canvas.width = width;
  canvas.height = height;

  //  鋪底色
  ctx.fillStyle = "#fff";
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  //如果圖片畫素大於100萬則使用瓦片繪製
  let count;
  if ((count = (width * height) / 1000000) > 1) {
    count = ~~(Math.sqrt(count) + 1); //計算要分成多少塊瓦片

    //   計算每塊瓦片的寬和高
    let nw = ~~(width / count);
    let nh = ~~(height / count);

    tCanvas.width = nw;
    tCanvas.height = nh;

    for (let i = 0; i < count; i++) {
      for (let j = 0; j < count; j++) {
        tctx.drawImage(
          img,
          i * nw * ratio,
          j * nh * ratio,
          nw * ratio,
          nh * ratio,
          0,
          0,
          nw,
          nh
        );

        ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh);
      }
    }
  } else {
    ctx.drawImage(img, 0, 0, width, height);
  }

  //進行最小壓縮
  let ndata = canvas.toDataURL("image/jpeg", 0.1);

  console.log("壓縮前:" + initSize);
  console.log("壓縮後:" + ndata.length);
  // console.log(
  //   "壓縮率:" + ~~((100 * (initSize - ndata.length)) / initSize) + "%"
  // );

  tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0;

  return ndata;
};

// File檔案轉為base64
const readImg = file => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();

    reader.onload = e => {
      // 建立一個Image物件
      const img = new Image();
      img.src = e.target.result;
      img.onload = () => {
        // 獲取圖片寬度和高度
        console.log(`圖片寬度: ${img.width}, 圖片高度: ${img.height}`);
        // return img;
        resolve(img);
      };
    };

    // 以DataURL的形式讀取檔案內容
    reader.readAsDataURL(file);
  });
};

//將base64轉換為檔案
const dataURLtoFile = (dataurl, filename) => {
  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 File([u8arr], filename, { type: mime });
};

相關文章