小程序 canvas 生成圖片

說明

  • canvas 舊版本生成圖片沒有長度限制
  • canvas 新版本(2d)生成圖片有長度限制:4096

工具: CanvasUtil.js

import { debug } from '../../../../utils/log'

class CanvasUtil {
    constructor(that, { canvasId, w, h }) {
        this.that = that

        this.w = w
        this.h = h
        this.canvasId = canvasId
        this.ctx = wx.createCanvasContext(canvasId, that)

        this.init()
    }

    init() {
        // 清空畫布
        this.ctx.clearRect(0, 0, this.w, this.h)
    }

    // 文本長度
    textWidth({ text, size, color, weight }) {
        this.ctx.font = `normal ${weight} ${Math.round(size)}px normal "PingFang SC-Regular", "PingFang SC"`
        this.ctx.setFillStyle(color)
        this.ctx.setFontSize(size)

        return this.ctx.measureText(text).width
    }

    // 單行文本
    drawTxt({ text, x, y, size, color, weight }) {
        this.ctx.save()
        this.ctx.font = `normal ${weight} ${Math.round(size)}px normal "PingFang SC-Regular", "PingFang SC"`
        this.ctx.setFillStyle(color)
        this.ctx.setFontSize(size)
        this.ctx.fillText(text, x, y)
        this.ctx.restore()

        return this.textWidth({ text, size, color, weight })
    }

    // 多行文本
    drawMulitLineTxt({ text, x, y, size, color, weight, lineWidth, lineHeight }) {
        this.ctx.save()

        this.ctx.font = `normal ${weight} ${Math.round(size)}px normal "PingFang SC-Regular", "PingFang SC"`
        this.ctx.setFillStyle(color)
        this.ctx.setFontSize(size)

        var temp = '', arr = []
        for (var i in text.split('')) {
            temp += text[i]

            // 如果大於行寬,輸出,重新初始化
            if (this.textWidth({ text: temp, size, color, weight }) >= lineWidth) {
                this.ctx.fillText(arr.join(''), x, y)

                temp = ''
                arr = []
                y += lineHeight

                continue
            }

            // 計算到末尾
            if ((parseInt(i) + 1) == text.length) {
                this.ctx.fillText(arr.join(''), x * this.r, y * this.r)
                break
            }

            arr.push(text[i])
        }

        this.ctx.restore()
    }

    // 畫圖
    drawImage({ src, x, y, w, h }) {
        return new Promise((resolve, reject) => {
            wx.getImageInfo({
                src,
                success: (res) => {
                    this.ctx.save()
                    this.ctx.drawImage(res.path, x, y, w, h)
                    this.ctx.restore()
                    resolve(this)
                }
            })
        })
    }

    // 圓角圖片
    drawCircleImage({ src, x, y, w, h }) {
        return new Promise((resolve, reject) => {
            wx.getImageInfo({
                src,
                success: (res) => {
                    debug(`[報告生成圖片] 生成圓角圖片成功 src=${src} res=${JSON.stringify(res)}`)
                    this.ctx.save()
                    this.ctx.beginPath()
                    this.ctx.arc(w / 2 + x, h / 2 + y, w / 2, 0, Math.PI * 2, false)
                    this.ctx.clip()
                    this.ctx.drawImage(res.path, x, y, w, h)
                    this.ctx.restore()
                    resolve(this)
                },
                fail: (err) => {
                    debug(`[報告生成圖片] 生成圓角圖片失敗 src=${src} err=${err}`)
                }
            })
        })
    }

    // 畫圓
    drawCircle({ w, h, x, y }) {
        this.ctx.save()
        this.ctx.beginPath()
        this.ctx.arc(w / 2 + x, h / 2 + y, w / 2, 0, Math.PI * 2, false)
        this.ctx.closePath()
        this.ctx.restore()
    }

    // 畫方塊
    drawBlock({ w, h, x = 0, y = 0, bg = '#ffffff', r = 0 }) {
        this.ctx.save()
        this.ctx.beginPath()
        this.ctx.moveTo(x + r, y)
        this.ctx.arcTo(x + w, y, x + w, y + h, r)
        this.ctx.arcTo(x + w, y + h, x, y + h, r)
        this.ctx.arcTo(x, y + h, x, y, r)
        this.ctx.arcTo(x, y, x + w, y, r)
        this.ctx.fillStyle = bg
        this.ctx.closePath()
        this.ctx.fill()
        this.ctx.restore()
    }

    saveImage() {
        return new Promise((resolve, reject) => {
            this.ctx.draw(false, () => {
                debug(`[報告生成圖片] 保存圖片 w=${this.w * 2} h=${this.h * 2} canvasId=${this.canvasId}`)
                wx.canvasToTempFilePath({
                    canvasId: this.canvasId,
                    destWidth: this.w * 2,
                    destHeight: this.h * 2,
                    success: (res) => {
                        debug(`[報告生成圖片] 生成臨時文件成功, path=${res.tempFilePath}`)
                        wx.saveImageToPhotosAlbum({
                            filePath: res.tempFilePath,
                            success: () => {
                                debug('[報告生成圖片] 保存圖片成功')
                                wx.showToast({
                                    title: '保存圖片成功',
                                    icon: 'none',
                                    duration: 2000
                                })
                                setTimeout(() => {
                                    wx.hideToast()
                                    resolve(this)
                                }, 2000)
                            },
                            fail: (err) => {
                                debug('[報告生成圖片] 保存圖片失敗!', err)
                                wx.showToast({
                                    title: '保存圖片失敗',
                                    icon: 'none',
                                    duration: 2000
                                })
                                setTimeout(() => {
                                    wx.hideToast()
                                    resolve(this)
                                }, 2000)
                            }
                        })
                    },
                    fail: (err) => {
                        debug('[報告生成圖片] 生成臨時文件失敗!', err)
                    }
                }, this.that)
            })
        })
    }
}

export default CanvasUtil

demo.wxml

<canvas class="my-canvas" canvas-id="diet-report-canvas" style="width:{{w}}px; height:{{h}}px"></canvas>

demo.js


            // canvas id
            const canvasId = 'diet-report-canvas'

            // 設備像素比
            const dpr = wx.getSystemInfoSync().pixelRatio

            // 寬
            const w = 343 * dpr
            // 高
            const h = getCanvasHeight() * dpr

            // 設置頁面canvas寬高
            this.setData({ w, h })

            // canvas 工具
            const cu = new CanvasUtil(this, { canvasId, w, h })

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章