SOURCE

function stretchAndRotateImage(img, stretchWidthBeforeRotate, stretchHeightBeforeRotate, rotationAngle, showProcess = true) {
    // 拉伸图片
    const stretchCanvas = document.createElement('canvas')
    const ctx = stretchCanvas.getContext('2d')
    stretchCanvas.width = stretchWidthBeforeRotate
    stretchCanvas.height = stretchHeightBeforeRotate
    ctx.drawImage(img, 0, 0, stretchWidthBeforeRotate, stretchHeightBeforeRotate)

    if (showProcess) {
        const div = document.createElement('div')
        div.appendChild(document.createTextNode('拉伸'))
        document.body.appendChild(div)
        document.body.appendChild(stretchCanvas)
    }

    // 计算包含旋转后图形的最小矩形宽高
    const radians = (rotationAngle * Math.PI) / 180
    const sin = Math.sin(radians)
    const cos = Math.cos(radians)
    const width = Math.abs(stretchWidthBeforeRotate * cos) + Math.abs(stretchHeightBeforeRotate * sin)
    const height = Math.abs(stretchWidthBeforeRotate * sin) + Math.abs(stretchHeightBeforeRotate * cos)

    // 将拉伸后的图片绘制到能包含它的最小 canvas 中(即旋转后的矩形图片顶点在 canvas 的四条边上)
    const rotatedCanvas = document.createElement('canvas')
    const rotatedCtx = rotatedCanvas.getContext('2d')
    rotatedCanvas.width = width
    rotatedCanvas.height = height
    rotatedCtx.translate(width / 2, height / 2)
    rotatedCtx.rotate((rotationAngle * Math.PI) / 180)
    rotatedCtx.drawImage(stretchCanvas, -stretchWidthBeforeRotate / 2, -stretchHeightBeforeRotate / 2)

    if (showProcess) {
        const div = document.createElement('div')
        div.appendChild(document.createTextNode('旋转'))
        document.body.appendChild(div)
        document.body.appendChild(rotatedCanvas)
    }

    return rotatedCanvas
}

function loadImage(uri) {
    return new Promise((resolve, reject) => {
        const img = new Image()
        img.crossOrigin = 'anonymous' // 解决跨域问题
        img.onload = () => resolve(img)
        img.onerror = reject
        img.src = uri
    })
}

(async function () {
    const img = await loadImage('https://static-yh.yonghui.cn/app/fe-store-job-mgnt/shelf-price-tag-image-process.png')
    const canvas = stretchAndRotateImage(img, 500, 500, 30)
})()
canvas {
    border: 1px solid red;
}
console 命令行工具 X clear

                    
>
console