前端自动生成图片并下载(不到60行代码)

236 阅读3分钟

需求 由于一些简单的图片拼合需要处理(大概7~8000张),但是又没有找到合适的傻瓜软件能够很好地解决需求,同时也很令人头疼的是nodejs里面图片处理库,基本上没几个好用,且安装费时费劲 (当然我还是装了)。作为一个有追求的前端,如果能不依靠其他的东西,直接在前端页面上实现它不香么?于是就有了这个小尝试。其实非常简单,仅以此文记录一下,怕以后不用忘记。

前奏 1.由于canvas的安全限制,我们必须保证资源和网页在同一个域名下进行,否则画入是没问题的,但是导出就会报“画布被污染”的错误。所以我们一共有多个解决办法:

img.setAttribute('crossOrigin', 'anonymous') URL.revokeObjectURL 以上是我个人探索的五种解决办法,分别适合不同场景下的需求。

前两种例子不便于展示,直接下面是三种办法的对应代码例子:

let can = document.getElementById('canvas'); let ctx = can.getContext('2d'); fetch('img.alicdn.com/bao/uploade…!!0-item_pic.jpg_240x240.jpg').then( res => res.blob()) .then(res => { let fr = new FileReader(); fr.onload = function (e) { console.log(e) console.log(e.target.result) let img = new Image(); //第一种办法 // img.setAttribute('crossOrigin', 'anonymous'); // img.src = // 'img.alicdn.com/bao/uploade…!!0-item_pic.jpg_240x240.jpg' //第二种办法 // img.src = e.target.result; //转成base64 //第三种办法 // img.src = URL.createObjectURL(res);//转成Blob地址ObjectUrl

    img.onload = function () {
      ctx.drawImage(img, 0, 0)
      console.log(can.toDataURL())//导出成dataurl
      // canvas.toBlob(function (blob) {//导出成blob地址
      //   var url = URL.createObjectURL(blob);
      //   console.log(url)
      // });
    }
  }
  fr.onerror = function () {
    console.log('读取错误!')
  }
  fr.readAsDataURL(res)
})

复制代码 完善导出 有了之前的前奏流程,接下来我们可以开始实现下载,利用a标签的download即可。同时要注意,a标签download属性不支持跨域,不过在我们这里面,不会涉及到跨域(canvas数据就是从这页面里产生的)。

如何批量导出?

在这里要注意,由于我们存在一些异步环节,我们要使用Async await来实现对它们的顺序执行。这样的话,就会按照顺序执行,另外浏览器记得打开允许自动下载(本地环境可能会老有提示,但是如果拿一个localhost托管就不会有问题了)

例子:

(async () => { let result = [] let arr = [] for (let i = 0; i < arr.length; i++) { await new Promise((res, rej) => { setTimeout(() => { res() }, 10) }) try { await createImg(arr[i]).catch(err => { result.push(arr[i]) console.log(arr[i], '服务器端响应出错,无法获取图片') }) } catch (e) { result.push(arr[i]) console.log(arr[i], '程序处理时无法处理图片', '原因:', e) } }

document.body.innerText = result.join("")

})()

function createImg(article) { return new Promise((res, rej) => { let temp = new Image() temp.src = 'http://XXXXXX/getpic?type=touming&article=' + article; temp.onerror = function () { rej(article) } temp.onload = function () { ctx.drawImage(temp, 940, 90, 650, 650); var bloburl = canvas.toDataURL('image/jpeg'); var anchor = document.createElement('a'); anchor.href = bloburl; anchor.download = article; anchor.click() ctx.rect(0, 0, 2000, 800); ctx.fillStyle = "rgb(236,237,239)"; ctx.fill(); res() } }) } 复制代码 踩坑:

这里要注意,我定义了Image对象的onerror事件,因为async await等待的Promise不知道捕获到服务器错误的(如果服务器宕机了一下,脚本会直接停止报错),所以我们需要在onerror里面引入,然后reject掉,promise就可以拿到错误信息了,之后再catch就好了。同时为了防止出现复杂的报错停止,加入了try catch保证错误能被拿到。

www.jianshu.com/p/1fd15f383…