美文网首页技术贴
uni 小程序 canvas截图保存到本地

uni 小程序 canvas截图保存到本地

作者: zhudying | 来源:发表于2021-11-30 19:18 被阅读0次

    canvas 生产图片,保存到本地功能。

    1. canvas 组件
     <view
        class="r-canvas-component"
        :style="{width:canvas_width/scale+'rpx',height:canvas_height/scale+'rpx'}"
        :class="{'hidden':hidden}"
    >
        <canvas
            class="r-canvas"
            v-if="canvas_id"
            :canvas-id="canvas_id"
            :id="canvas_id"
            :style="{width:canvas_width+'rpx',height:canvas_height+'rpx','transform':`scale(${r_canvas_scale})`}"
        ></canvas>
    </view>
    

    js

    export default {
        data() {
            return {
                system_info: {}, //system info
                canvas_width: 0, //canvas width px
                canvas_height: 0, //canvas height px
                ctx: null, //canvas object
                canvas_id: null, //canvas id
                hidden: false, //Whether to hide canvas
                scale: 1, //canvas scale
                r_canvas_scale: 1,
                if_ctx: true
            }
        },
        methods: {
            /**
             * save r-canvas.vue object
             * @param {Object} that
             */
            // saveThis(that){
            //  rCanvasThis = that
            // },
            /**
             * Draw round rect text
             * @param {Object} config
             * @param {Number} config.x x坐标
             * @param {Number} config.y y坐标
             * @param {Number} config.w 宽度
             * @param {Number} config.h 高度
             * @param {Number} config.radius 圆角弧度
             * @param {String} config.fill_color 矩形颜色
             */
            fillRoundRect(config) {
                return new Promise((resolve, reject) => {
                    let x = this.compatibilitySize(parseFloat(config.x) * this.scale)
                    let y = this.compatibilitySize(parseFloat(config.y) * this.scale)
                    let w = this.compatibilitySize(parseFloat(config.w) * this.scale)
                    let h = this.compatibilitySize(parseFloat(config.h) * this.scale)
                    let radius = config.radius ? parseFloat(config.radius) * this.scale : 10 * this.scale
    
                    let fill_color = config.fill_color || "black"
                        // The diameter of the circle must be less than the width and height of the rectangle
                    if (2 * radius > w || 2 * radius > h) {
                        reject("The diameter of the circle must be less than the width and height of the rectangle")
                        return false;
                    }
                    this.ctx.save();
                    this.ctx.translate(x, y);
                    //  
                    this.drawRoundRectPath({
                        w: w,
                        h: h,
                        radius: radius
                    });
                    this.ctx.fillStyle = fill_color
                    this.ctx.fill();
                    this.ctx.restore();
                    resolve()
                })
            },
            /**
             * Draws the sides of a rounded rectangle
             * @param {Object} config
             * @param {Number} config.w 宽度
             * @param {Number} config.h 高度
             * @param {Number} config.radius 圆角弧度
             */
            drawRoundRectPath(config) {
                this.ctx.beginPath(0);
                this.ctx.arc(config.w - config.radius, config.h - config.radius, config.radius, 0, Math.PI / 2);
                this.ctx.lineTo(config.radius, config.h);
                this.ctx.arc(config.radius, config.h - config.radius, config.radius, Math.PI / 2, Math.PI);
                this.ctx.lineTo(0, config.radius);
                this.ctx.arc(config.radius, config.radius, config.radius, Math.PI, Math.PI * 3 / 2);
                this.ctx.lineTo(config.w - config.radius, 0);
                this.ctx.arc(config.w - config.radius, config.radius, config.radius, Math.PI * 3 / 2, Math.PI * 2);
                this.ctx.lineTo(config.w, config.h - config.radius);
                this.ctx.closePath();
            },
            /**
             * Draw special Text,line wrapping is not supported
             * @param {Object} config
             * @param {String} config.text 文字
             * @param {Number} config.x x坐标
             * @param {Number} config.y y坐标
             * @param {String} config.font_color 文字颜色
             * @param {String} config.font_family 文字字体
             * @param {Number} config.font_size 文字大小(px)
             */
            drawSpecialText(params) {
                let general = params.general
                let list = params.list
                return new Promise(async(resolve, reject) => {
                    if (!general) {
                        reject("general cannot be empty:101")
                        return;
                    } else if (list && list.length > 0) {
                        for (let i in list) {
                            if (i != 0) {
                                let font_size = list[i - 1].font_size ? parseFloat(list[i - 1].font_size) : 20
                                this.ctx.setFontSize(font_size)
                                general.x = parseFloat(general.x) + this.ctx.measureText(list[i - 1].text).width
                            }
                            list[i].x = general.x
                            list[i].y = general.y + (list[i].margin_top ? parseFloat(list[i].margin_top) : 0)
                            await this.drawText(list[i])
                        }
                        resolve()
                    } else {
                        reject("The length of config arr is less than 0")
                        return;
                    }
    
                })
            },
            /**
             * array delete empty
             * @param {Object} arr
             */
            arrDeleteEmpty(arr) {
                let newArr = []
                for (let i in arr) {
                    if (arr[i]) {
                        newArr.push(arr[i])
                    }
                }
                return newArr
            },
            /**
             * Draw Text,support line
             * @param {Object} config
             * @param {String} config.text 文字
             * @param {Number} config.max_width 文字最大宽度(大于宽度自动换行)
             * @param {Number} config.line_height 文字上下行间距
             * @param {Number} config.x x坐标
             * @param {Number} config.y y坐标
             * @param {String} config.font_color 文字颜色
             * @param {String} config.font_family 文字字体 默认值:Arial
             * @param {String} config.text_align 文字对齐方式(left/center/right)
             * @param {Number} config.font_size 文字大小(px)
             * @param {Boolean} config.line_through_height 中划线大小
             * @param {Boolean} config.line_through_color 中划线颜色
             * @param {String} config.font_style 规定文字样式
             * @param {String} config.font_variant 规定字体变体
             * @param {String} config.font_weight 规定字体粗细
             * @param {String} config.line_through_cap 线末端类型
             * @param {String} config.line_clamp 最大行数
             * @param {String} config.line_clamp_hint 超过line_clamp后,尾部显示的自定义标识 如 ...
             * @param {String} config.is_line_break 是否开启换行符换行
             * 
             */
            drawText(config, configuration = {}) {
    
                configuration['line_num'] = configuration.line_num ? configuration.line_num : 0
                configuration['text_width'] = configuration.text_width ? configuration.text_width : 0
    
                return new Promise(async(resolve, reject) => {
    
                    if (config.text) {
    
                        let draw_width = 0,
                            draw_height = 0,
                            draw_x = config.x,
                            draw_y = config.y
                        let font_size = config.font_size ? (parseFloat(config.font_size) * this.scale) : (20 * this.scale)
                        let font_color = config.font_color || "#000"
                        let font_family = config.font_family || "Arial"
                        let line_height = config.line_height || config.font_size || 20
                        let text_align = config.text_align || "left"
                        let font_weight = config.font_weight || "normal"
                        let font_variant = config.font_variant || "normal"
                        let font_style = config.font_style || "normal"
                        let line_clamp_hint = config.line_clamp_hint || '...'
                        let lineBreakJoinText = ""
                        let max_width = config.max_width ? parseFloat(config.max_width) * this.scale : 0
                            // checkout is line break
                        if (config.is_line_break) {
                            let splitTextArr = config.text.split(/[\n]/g)
                            if (splitTextArr && splitTextArr.length > 0) {
                                let newSplitTextArr = this.arrDeleteEmpty(splitTextArr)
                                if (newSplitTextArr && newSplitTextArr.length > 0) {
                                    lineBreakJoinText = newSplitTextArr.slice(1).join("\n")
                                    config.text = newSplitTextArr[0]
                                } else {
                                    reject("Text cannot be empty:103")
                                    return
                                }
                            } else {
                                reject("Text cannot be empty:102")
                                return
                            }
                        }
    
                        this.ctx.setFillStyle(font_color) // color
                        this.ctx.textAlign = text_align;
                        this.ctx.font = `${font_style} ${font_variant} ${font_weight} ${parseInt(font_size)}px ${font_family}`
                        if (configuration.text_width >= this.ctx.measureText(config.text).width) {
                            draw_width = configuration.text_width
                        } else if (max_width > 0) {
                            draw_width = max_width < this.ctx.measureText(config.text).width ? this.resetCompatibilitySize(max_width) : this.resetCompatibilitySize(this.ctx.measureText(config.text).width)
                        } else {
                            draw_width = this.ctx.measureText(config.text).width
                        }
                        configuration.text_width = draw_width / this.scale
                        if (max_width && this.compatibilitySize(this.ctx.measureText(config.text).width) > this.compatibilitySize(max_width)) {
                            let current_text = ""
                            let text_arr = config.text.split("")
                            for (let i in text_arr) {
                                if (this.compatibilitySize(this.ctx.measureText(current_text + text_arr[i]).width) > this.compatibilitySize(max_width)) {
                                    // Hyphenation that is greater than the drawable width continues to draw
                                    if (config.line_clamp && parseInt(config.line_clamp) == 1) {
                                        // Subtracting the current_text tail width from the line_clamp_hint width
                                        let current_text_arr = current_text.split('')
                                        let json_current_text = ''
                                        while (true) {
                                            current_text_arr = current_text_arr.slice(1)
                                            json_current_text = current_text_arr.join('')
                                            if (this.compatibilitySize(this.ctx.measureText(json_current_text).width) <= this.compatibilitySize(this.ctx.measureText(line_clamp_hint).width)) {
                                                current_text = current_text.replace(json_current_text, '')
                                                break;
                                            }
                                        }
                                        configuration.line_num += 1
                                        this.ctx.setFontSize(parseInt(this.compatibilitySize(font_size))) // font size
                                        this.ctx.fillText(current_text + line_clamp_hint, this.compatibilitySize(parseFloat(config.x) * this.scale), this.compatibilitySize(parseFloat(config.y) * this.scale));
                                    } else {
                                        configuration.line_num += 1
                                        this.ctx.setFontSize(parseInt(this.compatibilitySize(font_size))) // font size
                                        this.ctx.fillText(current_text, this.compatibilitySize(parseFloat(config.x) * this.scale), this.compatibilitySize(parseFloat(config.y) * this.scale));
                                        config.text = text_arr.slice(i).join("")
                                        config.y = config.y + line_height
                                        if (config.line_clamp) {
                                            config.line_clamp = parseInt(config.line_clamp) - 1
                                        }
                                        await this.drawText(config, configuration)
                                    }
    
                                    break;
                                } else {
                                    current_text = current_text + text_arr[i]
                                }
                            }
                        } else {
                            if (config.line_through_height) {
                                let x = parseFloat(config.x) * this.scale
                                let w
                                let y = parseFloat(config.y) * this.scale - (font_size / 2.6)
                                if (text_align == "left") {
                                    w = this.ctx.measureText(config.text).width / 1.1 + parseFloat(config.x) * this.scale
                                } else if (text_align == "right") {
                                    w = parseFloat(config.x) * this.scale - this.ctx.measureText(config.text).width / 1.1
                                } else if (text_align == "center") {
                                    x = parseFloat(config.x) * this.scale - this.ctx.measureText(config.text).width / 1.1 / 2
                                    w = parseFloat(config.x) * this.scale + this.ctx.measureText(config.text).width / 1.1 / 2
                                }
                                this.drawLineTo({
                                    x: x,
                                    y: y,
                                    w: w,
                                    h: y,
                                    line_width: config.line_through_height,
                                    line_color: config.line_through_color,
                                    line_cap: config.line_through_cap
                                })
                            }
                            configuration.line_num += 1
                            this.ctx.setFontSize(parseInt(this.compatibilitySize(font_size))) // font size
                            this.ctx.fillText(config.text, this.compatibilitySize(parseFloat(config.x) * this.scale), this.compatibilitySize(parseFloat(config.y) * this.scale));
                            if (config.line_clamp) {
                                config.line_clamp = parseInt(config.line_clamp) - 1
                            }
                        }
                        if (lineBreakJoinText) {
                            await this.drawText({...config, text: lineBreakJoinText, y: config.y + line_height }, configuration)
                        }
                        draw_height = config.font_size * configuration.line_num
                        draw_width = configuration.text_width
                        resolve({ draw_width, draw_height, draw_x, draw_y })
                    } else {
                        reject("Text cannot be empty:101")
                    }
                })
            },
            /**
             * Draw Line
             * @param {Object} config
             * @param {Object} config.x x坐标
             * @param {Object} config.y y坐标
             * @param {Object} config.w 线的宽度
             * @param {Object} config.h 线的高度
             * @param {Object} config.line_width 线的宽度
             * @param {Object} config.line_color 线条颜色
             */
            drawLineTo(config) {
                let x = this.compatibilitySize(config.x)
                let y = this.compatibilitySize(config.y)
                let w = this.compatibilitySize(config.w)
                let h = this.compatibilitySize(config.h)
                let line_width = config.line_width ? parseFloat(config.line_width) * this.scale : 1 * this.scale
                let line_color = config.line_color || "black"
                let line_cap = config.line_cap || "butt"
                this.ctx.beginPath()
                this.ctx.lineCap = line_cap
                this.ctx.lineWidth = line_width
                this.ctx.strokeStyle = line_color
                this.ctx.moveTo(x, y)
                this.ctx.lineTo(w, h)
                this.ctx.stroke()
            },
            /** 
             * Compatibility px
             * @param {Object} size
             */
            compatibilitySize(size) {
                let canvasSize = (parseFloat(size) / 750) * this.system_info.windowWidth
                canvasSize = parseFloat(canvasSize * 2)
                return canvasSize
            },
            /**
             * Restore compatibility px
             * @param {Object} size
             */
            resetCompatibilitySize(size) {
                let canvasSize = (parseFloat(size / 2) / this.system_info.windowWidth) * 750
                return canvasSize
            },
            /**
             * Init canvas
             */
            init(config) {
                return new Promise(async(resolve, reject) => {
                    if (!config.canvas_id) {
                        reject("Canvas ID cannot be empty, please refer to the usage example")
                        return;
                    }
                    this.hidden = config.hidden
                    this.canvas_id = config.canvas_id
                    let system_info = await uni.getSystemInfoSync()
                    this.system_info = system_info
                    this.scale = config.scale && parseFloat(config.scale) > 0 ? parseInt(config.scale) : 1
                    this.canvas_width = (config.canvas_width ? this.compatibilitySize(config.canvas_width) : system_info.windowWidth) * this.scale
                    this.canvas_height = (config.canvas_height ? this.compatibilitySize(config.canvas_height) : system_info.windowHeight) * this.scale,
                        this.r_canvas_scale = 1 / this.scale
                    this.ctx = uni.createCanvasContext(this.canvas_id, this)
                    this.setCanvasConfig({
                        global_alpha: config.global_alpha ? parseFloat(config.global_alpha) : 1,
                        backgroundColor: config.background_color ? config.background_color : "#fff"
                    })
                    resolve()
                })
            },
            /**
             * clear canvas all path
             */
            clearCanvas() {
                return new Promise(async(resolve, reject) => {
                    if (!this.ctx) {
                        reject("canvas is not initialized:101")
                        return
                    } else {
                        this.ctx.clearRect(0, 0, parseFloat(this.canvas_width) * this.scale, parseFloat(this.canvas_height) * this.scale)
                        await this.draw()
                        resolve()
                    }
                })
            },
            /**
             * Set canvas config
             * @param {Object} config
             */
            setCanvasConfig(config) {
                this.ctx.globalAlpha = config.global_alpha
                this.ctx.fillStyle = config.backgroundColor
                this.ctx.fillRect(0, 0, parseFloat(this.canvas_width) * this.scale, parseFloat(this.canvas_height) * this.scale)
            },
            /**
             * set canvas width
             * @param {Object} width
             */
            setCanvasWidth(width) {
                if (!width) {
                    uni.showToast({
                        title: 'setCanvasWidth:width error',
                        icon: 'none'
                    })
                }
                this.canvas_width = this.compatibilitySize(parseFloat(width)) * this.scale
                this.ctx.width = this.canvas_width
            },
            /**
             * set canvas height
             * @param {Object} height
             */
            setCanvasHeight(height) {
                if (!height) {
                    uni.showToast({
                        title: 'setCanvasWidth:height error',
                        icon: 'none'
                    })
                }
                this.canvas_height = this.compatibilitySize(parseFloat(height)) * this.scale
                this.ctx.height = this.canvas_height
            },
            /**
             * Draw to filepath
             */
            draw(callback) {
                return new Promise((resolve, reject) => {
                    let stop = setTimeout(() => {
                        this.ctx.draw(false, setTimeout(() => {
                            uni.canvasToTempFilePath({
                                canvasId: this.canvas_id,
                                quality: 1,
                                success: (res) => {
                                    console.log('res', res)
                                    resolve(res)
                                    callback && callback(res)
                                },
                                fail: (err) => {
                                    reject(JSON.stringify(err) || "Failed to generate poster:101")
                                }
                            }, this)
                        }, 300))
                        clearTimeout(stop)
                    }, 300)
                })
            },
            /**
             * draw rect
             * @param {Number} config.x x坐标
             * @param {Number} config.y y坐标
             * @param {Number} config.w 图形宽度(px)
             * @param {Number} config.h 图形高度(px)
             * @param {Number} config.color 图形颜色
             * @param {Number} config.is_radius 是否开启圆图(1.1.6及以下版本废弃,请使用border_radius)
             * @param {Number} config.border_width 边框大小
             * @param {Number} config.border_color 边框颜色
             * 
             */
            drawRect(config) {
                return new Promise(async(resolve, reject) => {
                    if (!config.border_width || config.border_width <= 0) {
                        config.border_width = 0
                    } else {
                        config.border_width = parseFloat(config.border_width)
                    }
                    if (parseFloat(config.border_width) > 0) {
                        let sub_config = JSON.parse(JSON.stringify(config))
                        sub_config.border_width = 0
                        sub_config.w = config.w + config.border_width
                        sub_config.h = config.h + config.border_width
                        sub_config.color = config.border_color || 'black'
                        if (sub_config.border_radius) {
                            sub_config.border_radius = parseFloat(sub_config.border_radius) + parseFloat(config.border_width) / 2
                        }
                        await this.drawRect(sub_config)
                    }
    
                    let color = config.color || 'white'
                    config.x = (parseFloat(config.x) + config.border_width / 2)
                    config.y = (parseFloat(config.y) + config.border_width / 2)
                    config['color'] = color
                    this.ctx.fillStyle = color;
                    if (config.is_radius || config.border_radius) {
                        this.setNativeBorderRadius(config)
                        this.ctx.fill()
                    } else {
                        console.log('config.border_width', config.border_width)
                        this.ctx.fillRect(this.compatibilitySize(config.x * this.scale), this.compatibilitySize(config.y * this.scale), this.compatibilitySize(parseFloat(config.w) * this.scale), this.compatibilitySize(parseFloat(config.h) * this.scale))
                    }
                    resolve()
                })
            },
            /**
             * Draw image
             * @param {Object} config
             * @param {String} config.url 图片链接
             * @param {Number} config.x x坐标
             * @param {Number} config.y y坐标
             * @param {Number} config.w 图片宽度(px)
             * @param {Number} config.h 图片高度(px)
             * @param {Number} config.border_width 边大小
             * @param {Number} config.border_color 边颜色
             * @param {Number} config.is_radius 是否开启圆图(1.1.6及以下版本废弃,请使用border_radius)
             * @param {Number} config.border_radius 圆角弧度
             */
            drawImage(config) {
                return new Promise(async(resolve, reject) => {
                    if (config.url) {
                        let type = 0 // 1、network image  2、native image  3、base64 image
                        let image_url
                        let reg = /^https?/ig;
                        if (reg.test(config.url)) {
                            type = 1
                        } else {
                            if ((config.url.indexOf("data:image/png;base64")  !=  -1)  ||  config.url.indexOf("data:image/jpeg;base64")  !=  -1  ||  config.url.indexOf("data:image/gif;base64")  !=  -1) {
                                type = 3
                            } else {
                                type = 2
                            }
                        }
                        if (type == 1) {
                            // network image
                            await this.downLoadNetworkFile(config.url).then(res => { // two function
                                image_url = res
                            }).catch(err => {
                                reject(err)
                                return;
                            })
                        } else if (type == 2) {
                            // native image
                            const imageInfoResult = await uni.getImageInfo({
                                src: config.url
                            });
                            try {
                                if (imageInfoResult.length <= 1) {
                                    reject(imageInfoResult[0].errMsg + ':404')
                                    return
                                }
                            } catch (e) {
                                reject(e + ':500')
                                return
                            }
                            let base64 = await this.urlToBase64({ url: imageInfoResult[1].path })
                                // #ifdef MP-WEIXIN
                            await this.base64ToNative({ url: base64 }).then(res => {
                                    image_url = res
                                }).catch(err => {
                                    reject(JSON.stringify(err) + ":501")
                                    return;
                                })
                                // #endif
                                // #ifndef MP-WEIXIN
                            image_url = base64
                                // #endif
    
                        } else if (type == 3) {
                            // #ifdef MP-WEIXIN
                            await this.base64ToNative({ url: config.url }).then(res => {
                                    image_url = res
                                }).catch(err => {
                                    reject(JSON.stringify(err) + ":500")
                                    return;
                                })
                                // #endif
                                // #ifndef MP-WEIXIN
                            image_url = config.url
                                // #endif
                        } else {
                            reject("Other Type Errors:101")
                            return
                        }
                        if (config.border_width) {
                            let border_radius = 0
                            if (config.border_radius) {
                                let multiple = config.w / config.border_radius
                                border_radius = (parseFloat(config.w) + parseFloat(config.border_width)) / multiple
                            }
                            // drawRect
                            await this.drawRect({
                                x: parseFloat(config.x) - parseFloat(config.border_width) / 2,
                                y: parseFloat(config.y) - parseFloat(config.border_width) / 2,
                                w: parseFloat(config.w) + parseFloat(config.border_width),
                                h: parseFloat(config.h) + parseFloat(config.border_width),
                                color: config.border_color,
                                border_radius: border_radius,
                                border_width: config.border_width,
                                is_radius: config.is_radius
                            })
                        }
    
    
    
                        if (config.border_radius) {
                            config.color = config.color ? config.color : 'rgba(0,0,0,0)'
    
                            // 圆角有白边,+0.5的误差
                            config.w = config.w + 0.3
                            config.h = config.h + 0.3
    
                            this.setNativeBorderRadius(config)
                        } else if (config.is_radius) {
                            //已废弃 is_radius
                            this.ctx.setStrokeStyle("rgba(0,0,0,0)")
                            this.ctx.save()
                            this.ctx.beginPath()
                            this.ctx.arc(this.compatibilitySize(parseFloat(config.x) * this.scale + parseFloat(config.w) * this.scale / 2), this.compatibilitySize(parseFloat(config.y) * this.scale + parseFloat(config.h) * this.scale / 2), this.compatibilitySize(parseFloat(config.w) * this.scale / 2), 0, 2 * Math.PI, false)
                            this.ctx.stroke();
                            this.ctx.clip()
                        }
    
                        await this.ctx.drawImage(image_url, this.compatibilitySize(parseFloat(config.x) * this.scale), this.compatibilitySize(parseFloat(config.y) * this.scale), this.compatibilitySize(parseFloat(config.w) * this.scale), this.compatibilitySize(parseFloat(config.h) * this.scale))
                        this.ctx.restore() //Restore previously saved drawing context
                        resolve()
                    } else {
                        let err_msg = "Links cannot be empty:101"
                        reject(err_msg)
                    }
                })
            },
            /**
             * base64 to native available path
             * @param {Object} config
             */
            base64ToNative(config) {
                return new Promise((resolve, reject) => {
                    let fileName = new Date().getTime()
                    var filePath = `${wx.env.USER_DATA_PATH}/${fileName}_rCanvas.png`
                    wx.getFileSystemManager().writeFile({
                        filePath: filePath,
                        data: config.url.replace(/^data:\S+\/\S+;base64,/, ''),
                        encoding: 'base64',
                        success: function() {
                            resolve(filePath)
                        },
                        fail: function(error) {
                            reject(error)
                        }
                    })
                })
            },
            /**
             * native url to base64
             * @param {Object} config
             */
            urlToBase64(config) {
                return new Promise(async(resolve, reject) => {
                    if (typeof window != 'undefined') {
                        await this.downLoadNetworkFile(config.url).then(res => { // two function
                            resolve(res)
                        }).catch(err => {
                            reject(err)
                        })
                    } else if (typeof plus != 'undefined') {
                        plus.io.resolveLocalFileSystemURL(config.url, (obj) => {
                            obj.file((file) => {
                                let fileReader = new plus.io.FileReader()
                                fileReader.onload = (res) => {
                                    resolve(res.target.result)
                                }
                                fileReader.onerror = (err) => {
                                    reject(err)
                                }
                                fileReader.readAsDataURL(file)
                            }, (err) => {
                                reject(err)
                            })
                        }, (err) => {
                            reject(err)
                        })
                    } else if (typeof wx != 'undefined') {
                        wx.getFileSystemManager().readFile({
                            filePath: config.url,
                            encoding: 'base64',
                            success: function(res) {
                                resolve('data:image/png;base64,' + res.data)
                            },
                            fail: function(error) {
                                reject(error)
                            }
                        })
                    }
                })
            },
            setNativeBorderRadius(config) {
                let border_radius = config.border_radius ? (parseFloat(config.border_radius) * this.scale) : (20 * this.scale)
                if ((parseFloat(config.w) * this.scale) < 2 * border_radius) border_radius = (parseFloat(config.w) * this.scale) / 2;
                if ((parseFloat(config.h) * this.scale) < 2 * border_radius) border_radius = (parseFloat(config.h) * this.scale) / 2;
                this.ctx.beginPath();
                this.ctx.moveTo(this.compatibilitySize((parseFloat(config.x) * this.scale) + border_radius), this.compatibilitySize((parseFloat(config.y) * this.scale)));
                this.ctx.arcTo(this.compatibilitySize((parseFloat(config.x) * this.scale) + (parseFloat(config.w) * this.scale)), this.compatibilitySize((parseFloat(config.y) * this.scale)), this.compatibilitySize((parseFloat(config.x) * this.scale) + (parseFloat(config.w) * this.scale)), this.compatibilitySize((parseFloat(config.y) * this.scale) + (parseFloat(config.h) * this.scale)), this.compatibilitySize(border_radius));
                this.ctx.arcTo(this.compatibilitySize((parseFloat(config.x) * this.scale) + (parseFloat(config.w) * this.scale)), this.compatibilitySize((parseFloat(config.y) * this.scale) + (parseFloat(config.h) * this.scale)), this.compatibilitySize((parseFloat(config.x) * this.scale)), this.compatibilitySize((parseFloat(config.y) * this.scale) + (parseFloat(config.h) * this.scale)), this.compatibilitySize(border_radius));
                this.ctx.arcTo((this.compatibilitySize(parseFloat(config.x) * this.scale)), this.compatibilitySize((parseFloat(config.y) * this.scale) + (parseFloat(config.h) * this.scale)), this.compatibilitySize((parseFloat(config.x) * this.scale)), this.compatibilitySize((parseFloat(config.y) * this.scale)), this.compatibilitySize(border_radius));
                this.ctx.arcTo(this.compatibilitySize((parseFloat(config.x) * this.scale)), this.compatibilitySize((parseFloat(config.y) * this.scale)), this.compatibilitySize((parseFloat(config.x) * this.scale) + (parseFloat(config.w) * this.scale)), this.compatibilitySize((parseFloat(config.y) * this.scale)), this.compatibilitySize(border_radius));
                this.ctx.closePath();
                this.ctx.strokeStyle = config.color || config.border_color || 'rgba(0,0,0,0)'; // 设置绘制边框的颜色
                this.ctx.stroke();
                this.ctx.save()
                this.ctx.clip();
    
            },
            /**
             * Download network file
             * @param {Object} url : download url
             */
            downLoadNetworkFile(url) {
                return new Promise((resolve, reject) => {
                    uni.downloadFile({
                        url,
                        success: (res) => {
                            if (res.statusCode == 200) {
                                resolve(res.tempFilePath)
                            } else {
                                reject("Download Image Fail:102")
                            }
                        },
                        fail: (err) => {
                            reject("Download Image Fail:101")
                        }
                    })
                })
            },
            /**
             * Save image to natice
             * @param {Object} filePath : native imageUrl
             */
            saveImage(filePath) {
                return new Promise((resolve, reject) => {
                    if (!filePath) {
                        reject("FilePath cannot be null:101")
                        return;
                    }
    
                    // #ifdef H5
                    var createA = document.createElement("a");
                    createA.download = filePath;
                    createA.href = filePath;
                    document.body.appendChild(createA);
                    createA.click();
                    createA.remove();
                    resolve()
                        // #endif
    
                    // #ifndef H5
                    uni.saveImageToPhotosAlbum({
                            filePath: filePath,
                            success: (res) => {
                                resolve(res)
                            },
                            fail: (err) => {
                                reject(err)
                            }
                        })
                        // #endif
                })
            }
        }
    }
    

    画canvas

    <view>
        <uni-canvas-to-image ref="rCanvas" ></uni-canvas-to-image>
    </view>
    

    js

                // 宝贝信息分享页生成图片
                drawCanvas (){
                    this.$nextTick(async ()=>{
                        try{
                            uni.showLoading({
                                title: "生成中..."
                            });
                            // 初始化
                            await this.$refs.rCanvas.init({
                                canvas_id:"rCanvas",
                                canvas_width: this.canvasWidth,
                                canvas_height: this.canvasHeight
                            })
    
                            // 画图片,网络图
                            let imgAvaW = parseInt(235 / 2 * this.getAdapt())
                            let imgAvaH = parseInt(235 / 2 * this.getAdapt())
                            let imgAvaL = parseInt(205 / 2 * this.getAdapt())
                            let imgAvaT = parseInt(61 / 2 * this.getAdapt())
                            await this.$refs.rCanvas.drawImage({
                                url: 'https//:xxxx/image/avatar.png', // 注:图片格式不能为 svg
                                x: imgAvaL,
                                y: imgAvaT,
                                w: imgAvaW,
                                h: imgAvaH,
                                border_radius:'28rpx'
                            }).catch(err_msg=>{
                                uni.showToast({
                                    title:err_msg,
                                    icon:"none"
                                })
                            })
    
                            // 画文字
                            let fontSize = parseInt(48 / 2 * this.getAdapt())
                            let fontSizeL = parseInt(200 / 2 * this.getAdapt())
                            let fontSizeT = parseInt(368 / 2 * this.getAdapt())
                            let maxW = parseInt(240 / 2 * this.getAdapt())
                            await this.$refs.rCanvas.drawText({
                                text: this.userInfo.name,
                                max_width: maxW,
                                x:fontSizeL,
                                y:fontSizeT,
                                line_clamp: 2, // 超过两行,自动隐藏...
                                font_color:"#080808",
                                font_family:"JRound500",
                                font_size: fontSize
                            }).catch(err_msg=>{
                                uni.showToast({
                                    title:err_msg,
                                    icon:"none"
                                })
                            })
                        
                            // 画图片,本地图片
                            let imgSexT = parseInt(330 / 2 * this.getAdapt())
                            let imgSexaL = parseInt(460 / 2 * this.getAdapt())
                            let imgSexW = parseInt(40 / 2 * this.getAdapt())
                            let imgSexH = parseInt(40 / 2 * this.getAdapt())
                            let imgUrl = ’./images/xx.png‘
                            await this.$refs.rCanvas.drawImage({
                                url: imgUrl,
                                x: imgSexaL,
                                y: imgSexT,
                                w: imgSexW,
                                h: imgSexH,
                            }).catch(err_msg=>{
                                uni.showToast({
                                    title:err_msg,
                                    icon:"none"
                                })
                            })
                            // 画二维码
                            let imgQrT = parseInt(500 / 2 * this.getAdapt())
                            let imgQraL = parseInt(160 / 2 * this.getAdapt())
                            let imgQrW = parseInt(320 / 2 * this.getAdapt())
                            let imgQrH = parseInt(320 / 2 * this.getAdapt())
                            await this.$refs.rCanvas.drawImage({
                                url: this.shareQr,
                                x: imgQraL,
                                y: imgQrT,
                                w: imgQrW,
                                h: imgQrH,
                            }).catch(err_msg=>{
                                uni.showToast({
                                    title:err_msg,
                                    icon:"none"
                                })
                            })
                            // 生成图片
                            await this.$refs.rCanvas.draw((res)=>{
                                // res.tempFilePath:生成成功,返回base64图片
                                uni.hideLoading();
                            })
                        }catch(e){
                            this.$refs.qrPopup.close()
                            uni.showToast({
                                title: '生成失败',
                                icon: 'none'
                            })
                        }
                    })
                },
                 // 自适应尺寸
                 getAdapt() {
                    let w = 0;
                    wx.getSystemInfo({
                        success:  (res) => {
                            w = res.windowWidth / 375; //按照750的屏宽,设计稿宽 / 2 * w
                        },
                    })
                    return w // 返回比率
                },
    

    相关文章

      网友评论

        本文标题:uni 小程序 canvas截图保存到本地

        本文链接:https://www.haomeiwen.com/subject/kdiwtrtx.html