如何使用canvas完成圖片合成下載

最近在群里面看到一個很有意思的提問:
用戶希望上傳一張海報與另外一個小圖片,最后可以下載下來,圖片,小圖片位于大圖片的右下角

這種功能其實(shí)還挺常見的,比如生成一個帶二維碼的海報之類的,就抽時間做了一下

首先分析一下思路

  1. 要做圖片合成,那么必定會使用到canvas
  2. 怎么進(jìn)行合成?這個就很簡單了?將canvas設(shè)置成大圖的寬高,繪制大圖,再在對應(yīng)位置繪制小圖,那么就得到我們所需要的圖案
  3. 最后需要做的是如何下載,可以使用a標(biāo)簽來完成

具體代碼

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <script src="https://cdn.bootcss.com/rxjs/6.5.2/rxjs.umd.js"></script>
</head>

<body>
  <canvas id="combination"></canvas>
  <a download id="download">下載</a>
  <script>
    const src0 = 'http://img5.imgtn.bdimg.com/it/u=3108685336,1951350863&fm=26&gp=0.jpg'
    const src1 = 'http://img5.imgtn.bdimg.com/it/u=2221756694,2517784243&fm=26&gp=0.jpg'
    const img0 = new Image()
    const img1 = new Image()
    img0.src = src0
    img1.src = src1
    // 當(dāng)兩張圖都加載好了的時候進(jìn)行canvas設(shè)置
    const img0Load$ = rxjs.fromEvent(img0, 'load')
    const img1Load$ = rxjs.fromEvent(img1, 'load')
    rxjs.zip(img0Load$, img1Load$).subscribe(([e0, e1]) => {
      console.log(e0);
      const img0 = e0.path[0]
      const img1 = e1.path[0]
      const imgSrc0 = img0.currentSrc
      const imgSrc1 = img1.currentSrc
      const img0Width = img0.naturalWidth
      const img1Width = img1.naturalWidth
      const img0Height = img0.naturalHeight
      const img1Height = img1.naturalHeight
      const minWidth = Math.min(img0Width, img1Width)
      const maxWidth = Math.max(img0Width, img1Width)
      const minHeight = Math.min(img0Height, img1Height)
      const maxHeight = Math.max(img0Height, img1Height)
      const canvas = document.getElementById('combination')
      canvas.width = maxWidth
      canvas.height = maxHeight
      const ctx = canvas.getContext('2d')
      let background = new Image()
      let minImage = new Image()
      // 如果不設(shè)置會導(dǎo)致報錯
      // Tainted canvases may not be exported
      // https://stackoverflow.com/questions/22710627/tainted-canvases-may-not-be-exported
      background.setAttribute('crossOrigin', 'anonymous')
      minImage.setAttribute('crossOrigin', 'anonymous')
      if (maxHeight === img0Height) {
        background.src = imgSrc0
        minImage.src = imgSrc1
      } else {
        background.src = imgSrc1
        minImage.src = imgSrc0
      }
      rxjs.zip(rxjs.fromEvent(background, 'load'), rxjs.fromEvent(minImage, 'load')).subscribe(() => {
        // 繪制背景
        ctx.drawImage(background, 0, 0, maxWidth, maxHeight)
        // 繪制小圖
        ctx.drawImage(minImage, maxWidth - minWidth, maxHeight - minHeight, minWidth, minHeight);
        const downloadImageSrc = canvas.toDataURL("image/png")
        document.getElementById('download').href = downloadImageSrc
      })
    })
  </script>
</body>

</html>

下面對代碼進(jìn)行解析

  1. 請無視rxjs的代碼,只要知道他們的作用是:當(dāng)兩張圖片都加載完成的時候,執(zhí)行里面的內(nèi)容,類似Promise.all
  2. 使用drawImage來繪制圖片,注意第一個參數(shù)不是src而是一個image對象
  3. 注意minImage.setAttribute('crossOrigin', 'anonymous') 這句代碼,如果沒有這段代碼會導(dǎo)致跨域加載圖片的問題出現(xiàn)導(dǎo)致 canvas.toDataURL("image/png") 無法執(zhí)行

可見還是相對比較簡單的,在實(shí)際開發(fā)中并不需要去識別那個是大圖那個是小圖,一般在上傳的時候就決定了,而且一般圖片大小都是固定的,所以并不需要使用這么麻煩的rxjs代碼

項目地址

圖片合成

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容