小程序Canvas图片自适应、文字自适应、canvas图片导出不模糊

自适应图片大小、位置
自定义文字大小、位置
自适应核心:获取屏幕像素,用该像素转换成和设计稿对等的rem,每次设置大小或者位置的时候,都用需要设置的值乘以该rem就能达到自适应效果
下面有代码,代码下面有效果图

<template>
    <view class="content">
        <canvas style="margin:0 auto;width:630upx; height:1014upx;" canvas-id="myCanvas" class="canvas" disable-scroll='true'></canvas>
    </view>
</template>
export default {
    data() {
        return{
            windowWidth: 0,
            windowHeight: 0,
            ratio: 0,
            canvasWidht: 0,
            canvasHeight: 0,
            resData: {
                img: '',
                logo: ''
            }
        }
    },
    methods: {
        imgCengten (url, maxWidht, top, Round) {
            // 头像居中
            // maxWidht: canvas宽度
            // top: 高度
            // Round: 头像大小
            let that = this
            this.ctx.save();
            this.ctx.beginPath();
            this.ctx.arc(maxWidht / 2, top, Round, 0, 2 * Math.PI);
            this.ctx.closePath();
            this.ctx.clip();
            this.ctx.drawImage(url, maxWidht / 2 - Round, top - Round, Round * 2, Round * 2);
            this.ctx.restore();
            that.ctx.draw(true)
        },
        // 把网络图片下载到本地
        downloadfileFn (url, Callback) {
            // url:网络图片
            // Callback:回调
            uni.getImageInfo({
                src: url,
                success (res) {
                    Callback(res.path)
                }
            })
        },
        // 初始化、把px转换成rem
        Reset (Callback) {
            var that = this;
            // 获取Canvas。    坑:如果是用自定义组件的话,是在自定义组件里面的话,需要在后面加多一个this参数!!!!!!!!!
            that.ctx = uni.createCanvasContext('myCanvas', that);
            const ctx = that.ctx
            // 坑:如果是用自定义组件的话,是在自定义组件里面的话,需要在后面加多一个this参数!!!!!!!!!
            const query = uni.createSelectorQuery().in(this);
            // 获取canvas宽度
            query.select('.canvas').boundingClientRect(function(data) {
                that.canvasWidht = data.width
                that.canvasHeight = data.height
                uni.getSystemInfo({
                    success: function (res) {
                        that.windowWidth = res.windowWidth
                        that.windowHeight = res.windowHeight
                        // 用手机屏幕除以375。至于为什么除以375,因为我的设计图是根据375这个宽度设计的。
                        // (重要)这步非常重要,所有的自适应都会用到这个参数
                        // 只要用你需要定位的值,或者大小乘以这个参数,就能达到与rem一样的效果
                        that.ratio = that.windowWidth / 375
                        // 初始化成功,进行回调
                        Callback()
                    }
                })
            }).exec()
        }
    },
    mounted (options) {
        let that = this
        // 初始化
        that.Reset(function () {
            // 这里提供一种思路。
            // 如果请求多张网络图片的时候,可以把请求图片放在初始之后进行统一请求
            // 由于多张,把控不了请求的快慢所以,可以定义一个object,然后把他们放进去
            // 用watch深度监控该对象,每次成功请求一张图片都监控,然后判断对象里面的图片参数 === '',如果全部都不为空,就证明全部都请求完毕了,进行绘画
            let img = 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1572004417595&di=7b72a4a18bdb3bd7f3a68daf4813e483&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201811%2F17%2F20181117112448_RPkiQ.thumb.700_0.jpeg'
            that.downloadfileFn(img, function (url) {
                that.resData.img = url
            })
            let logo = 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1572005120044&di=3d0caa0abdf47f1184a2c011f0ff4b53&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201709%2F18%2F20170918154609_MZz3U.jpeg'
            that.downloadfileFn(logo, function (url) {
                that.resData.logo = url
            })
        })
    },
    watch: {
        resData: {
            handler (newName) {
                let that = this
                if (newName.img !== '' && newName.logo !== '') {
                    that.imgCengten(newName.img, that.canvasWidht, 295 * that.ratio, 30 * that.ratio)
                    let txt = '一段自适应大小以及定位的文字'
                    // 坑:设置文字的时候,如果也要做自适应大小的话,会导致有小数点,所以toFixed(0)把小数点去掉,不然自适应会失效
                    that.ctx.font = `normal 400 ${(18 * that.ratio).toFixed(0)}px PingFangSC-Semibold`
                    that.ctx.fillText(txt, 20 * that.ratio, 435 * that.ratio)
                    // 把所有东西都渲染完毕之后,最坑的地方来了,draw是一个异步函数!
                    // 也就是说,有可能在图片没渲染完或者在一些低配机型下面会导致渲染的东西丢失。
                    // 但是微信官方提供了一种解决方法,他有2个参数,第二个参数是回调!
                    // 但!!如果不加延时的话,回调就失效了。原因:迷。
                    that.ctx.draw(true, setTimeout(function(){
                        // 延时完毕执行回调之后,把canvas图片导出来。
                        // 重要:如果是自定义组件,需要导出图片也要加this的。
                        uni.canvasToTempFilePath({
                            x: 0,
                            y: 0,
                            // 由于初始化的时候就已经获取宽高了直接填就好了
                            width: that.windowWidth,
                            height: that.windowHeight,
                            // destWidth、destHeight是导出图片的大小
                            // 如果直接填的话,会导致导出来的图片变得模糊!!
                            // 解决:用获取的宽高乘以设备的像素比在乘以2(乘以2要不要其实好像都没什么区别= =)
                            destWidth: that.windowWidth * uni.getSystemInfoSync().pixelRatio * 2,
                            destHeight: that.windowHeight * uni.getSystemInfoSync().pixelRatio * 2,
                            canvasId: 'myCanvas',
                            fileType: 'jpg',
                            success: function (res) {
                                // 最终这就是导出的图像了
                                console.log(res.tempFilePath);
                            },
                            fail: (res) => {
                                console.log(res);
                            }
                        }, that)
                    }, 300))
                }
            },
            deep:true
        }
    }
}

6p.png
i5.png
i6.png
x.png
xr.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345