Canvas生成并拼接图片上传至后端

生成jpg

不使用 png 是因为 背景透明,导出效果不太好,canvas 转换成 jpeg 之前会移除alpha通道,所以透明区域被填充成了黑色

toDataURL

canvas.toDataURL(type, encoderOptions);
type: 图片格式,默认为 image/png
encoderOptions: 在指定图片格式为 image/jpeg 或 image/webp的情况下,可以从 0 到 1 的区间内选择图片的质量。如果超出取值范围,将会使用默认值 0.92。其他参数会被忽略。

/**
 *  合并多张图片生成 一张 jpg 图片
 * @param {*} charts 一维数组
 * @param {*} outCanvasId 隐藏于视线之外 canvas的 id
 * @param {*} direction vertical | horizontal 按方向拼接图片
 */
export async function getChartImage(
  charts,
  outCanvasId,
  drawHorizontal = false
) {
  if (!Array.isArray(charts) || charts.length === 0 || !outCanvasId) return {};
  const arr = charts.map(item => {
    if ("toDataURL" in item) {
      return {
        base64Str: item.toDataURL("image/jpeg"),
        width: item.width,
        height: item.height,
      };
    }
    return item;
  });
  const offsetY = 30; // 每张图片的相互间隔距离
  const offsetX = 20; // 横向图片排布时的间隔距离

  const width = drawHorizontal
    ? arr.reduce((res, cur) => {
        return res + cur.width;
      }, (arr.length - 1) * offsetX)
    : Math.max(...arr.map(v => v.width));
  const height = drawHorizontal
    ? Math.max(...arr.map(v => v.height))
    : arr.reduce((res, cur) => {
        return res + cur.height;
      }, (arr.length - 1) * offsetY);

  // 异步代码这里要阻塞执行
  const imgs = await Promise.all(
    arr.map(v => {
      return new Promise(res => {
        const img = new Image();
        img.src = v.base64Str;
        img.addEventListener("load", () => {
          res(img);
        });
      });
    })
  );

  const canvas = document.getElementById(outCanvasId);
  const context = canvas.getContext("2d");

  // context.clearRect(0, 0, width, height); // 宽高被重设时会自动清空画布
  canvas.width = width;
  canvas.height = height;

  context.fillStyle = "#fff";
  context.fillRect(0, 0, width, height);
  imgs.forEach((img, index) => {
    const idx = index && index - 1;
    if (drawHorizontal) {
      context.drawImage(img, index * (imgs[idx].width + offsetX), 0);
    } else {
      context.drawImage(img, 0, index * (imgs[idx].height + offsetY));
    }
  });

  // toBlob(callback,"image/jpeg") 此方法时异步的
  const newBase64 = canvas.toDataURL("image/jpeg", 0.9);
  return {
    base64Str: newBase64,
    width,
    height,
  };
}

可以多次调用自己 以达到横向或竖向拼接图片的目的

注意:不考虑兼容性的情况下可直接使用toBlob转二进制数据传给后端,少写下面一部分代码

fetch上传

export function uploadImage(base64String, fileName) {
  return new Promise(resolve => {
    // 下面将要把 base64 转换成formdata
    // 这里对base64串进行操作,去掉url头,并转换为byte
    const bytes = window.atob(base64String.split(",")[1]);
    const arr = [];
    const bytesLength = bytes.length;
    for (let i = 0; i < bytesLength; i += 1) {
      arr.push(bytes.charCodeAt(i));
    }
    const blob = new Blob([new Uint8Array(arr)], { type: "image/jpeg" });

    const formData = new FormData();
    // 后端接收二进制数据
    formData.append("file", blob, `${fileName}.jpg`);
    fetch("http://localhost/xxxx",{
        method:"POST",
        body:formdata
    }).then(function(res){
        if (res.code === 0) {
        resolve(res.data.file_id);
    })
  });
}
image.png

可参考

推荐阅读更多精彩内容