uniapp使用canvas实现app端海报绘制并保存图片?

uniapp项目的结构

    <canvas style="width: 750rpx; height: 1100rpx;" canvas-id="firstCanvas" id="firstCanvas"></canvas>
        <view>
            <u-button class="custom-style" @click="saveImg">保存</u-button>
        </view>
uniap项目js部分
    onLoad(params) {
            this.classData.class_id = params.classId
            this.classData.school_id = params.schoolId
            
            if (params.classId && params.schoolId) {
                let classId = {
                    class_id: params.classId,
                    school_id: params.schoolId,
                    type: 1
                }
                getClassQRcodeApi(classId).then(res => {
                    if (res.status == 200) {
                        this.codeImg = res.data.qr_url
                        this.school_name = res.data.school_name;
                        this.classes_name = res.data.classes_name
                        const dialogRect = {
                            width: 750,
                            height: 750
                        }
                        let canvasCtx = uni.createCanvasContext('firstCanvas', this);
                        canvasCtx.clearRect(0, 0, dialogRect.width, dialogRect.height)
                        canvasCtx.setFillStyle('#f3af1e')
                        canvasCtx.fillRect(0, 0, dialogRect.width, dialogRect.height)
                        canvasCtx.setFillStyle('#fff')
                        canvasCtx.setFontSize(18)
                        canvasCtx.setTextAlign('center')
                        canvasCtx.fillText(this.school_name, 180, 40)
                        canvasCtx.fillText(this.classes_name, 180, 80)
                        canvasCtx.drawImage(this.codeImg, 60, 120, 264, 270)
                        canvasCtx.drawImage('/static/img/codeImg.jpg', 0, 420, 375, 120)
                        canvasCtx.draw(true);
                        uni.canvasToTempFilePath({  
                            canvasId: 'firstCanvas',  
                            success: (res) => {  
                                const tempFilePath = res.tempFilePath;  
                                if (uni.getSystemInfoSync().platform === 'ios' || uni.getSystemInfoSync().platform === 'android') {  
                                    uni.saveImageToPhotosAlbum({  
                                                    filePath: tempFilePath,  
                                                    success: () => {  
                                                        uni.showToast({  
                                                            title: '图片已保存',  
                                                            icon: 'success'  
                                                        });  
                                                    },  
                                                    fail: (err) => {  
                                                        uni.showToast({  
                                                            title: '保存图片失败',  
                                                            icon: 'none'  
                                                        });  
                                                    }  
                                  });  
                                } else if (uni.getSystemInfoSync().platform === 'h5') {  
                                            const a = document.createElement('a');  
                                            a.href = tempFilePath;  
                                            a.download = 'poster.png';  
                                            document.body.appendChild(a);  
                                            a.click();  
                                            document.body.removeChild(a);  
                                            uni.showToast({  
                                                title: '图片已下载',  
                                                icon: 'success'  
                                            });  
                                }  
                            },  
                            fail: (err) => {  
                                    uni.showToast({  
                                        title: '生成图片失败',  
                                        icon: 'none'  
                                    });  
                            }  
                        });
                    }
                })
            }
        },

进来就加载 canvas ,回显到页面,然后点击保存按钮到手机相册上,现在遇到的问题浏览器切换h5页面,在切换 IOS 手机屏幕,或者到其他屏幕,canvasCtx.drawImage('/static/img/codeImg.jpg', 0, 420, 375, 120)跟canvasCtx.setFillStyle('#f3af1e') 没有铺满,请问大佬们,如何修改这段代码,还有点击保存海报图片,用了 canvasCtx.draw(true); 在真机调试环境下切换到这个页面会自动保存海报图片,用户点击保存才存到手机相册里面,而不是自动保存

阅读 1k
avatarAI BotBETA

回答

首先,针对canvasCtx.drawImagecanvasCtx.setFillStyle没有铺满的问题,这通常是由于canvas元素的尺寸与绘制内容的尺寸不一致或者绘制代码本身的问题。由于你的canvas元素设置了rpx单位,但绘制代码使用的是px单位,这可能导致在不同屏幕尺寸下显示不一致。

为了解决这个问题,你应该:

  1. 使用相同的单位:在绘制内容时,确保使用与canvas相同的单位(rpxpx)。由于uni-app主要使用rpx作为单位,你可能需要根据屏幕尺寸将px单位转换为rpx
  2. 动态计算尺寸:基于设备的屏幕尺寸或canvas的实际尺寸来动态计算绘制内容的位置和大小。

其次,关于点击保存海报图片时自动保存的问题,这是因为你调用了canvasCtx.draw(true);后直接调用了uni.canvasToTempFilePath。你应该将保存逻辑与绘制逻辑分离,并在用户点击保存按钮时触发保存逻辑。

修改后的代码示例

模板部分(保持不变)

<canvas style="width: 750rpx; height: 1100rpx;" canvas-id="firstCanvas" id="firstCanvas"></canvas>
<view>
    <u-button class="custom-style" @click="saveImg">保存</u-button>
</view>

JS部分

// ... 省略其他代码 ...

onLoad(params) {
    // ... 省略其他代码 ...

    if (params.classId && params.schoolId) {
        // ... 省略其他代码 ...

        // 假设你已经有了绘制函数
        this.drawCanvas();
    }
},

methods: {
    drawCanvas() {
        // ... 省略绘制代码 ...

        // 注意:这里不调用 canvasCtx.draw(true);
    },

    saveImg() {
        uni.canvasToTempFilePath({
            canvasId: 'firstCanvas',
            success: (res) => {
                // ... 省略保存图片到相册或下载的代码 ...
            },
            fail: (err) => {
                uni.showToast({
                    title: '生成图片失败',
                    icon: 'none'
                });
            }
        });
    }
}

在上面的代码中,我移除了canvasCtx.draw(true);的调用,并将绘制逻辑和保存逻辑分离。现在,当你点击保存按钮时,saveImg方法会被调用,然后保存canvas的内容到临时文件路径,并根据平台的不同保存到相册或下载。

对于绘制内容的尺寸问题,你需要根据canvas的实际尺寸(可能是通过uni.getSystemInfoSync().windowWidthuni.getSystemInfoSync().windowHeight获取的)来动态计算每个元素的位置和大小。这将确保在不同屏幕尺寸下,绘制的内容都能正确显示。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏