首页 > 其他分享 > 国庆微信头像DIY:轻松打造个性化头像

国庆微信头像DIY:轻松打造个性化头像

时间:2023-09-24 21:46:09浏览次数:40  
标签:const img getImg 微信 value 头像 DIY 模版

前言

国庆节马上要到了,今天就教你如何从0到1使用canvas生成国庆风微信头像。

本文包含以下内容:

  • vue3项目搭建,需求分析
  • canvas合成图片原理
  • github自动化部署
  • 开发过程遇到的问题及解决方案

文末附源码及在线体验地址~

搭建项目,分析需求

项目的话就直接使用脚手架生成一个 Vue3 + TS项目

npm create vue@latest

为了方便,使用了Element PlusUI库

npm install element-plus --save

配置的话,可以查看文档,全局导入、按需导入都可以看自己的需求

项目搭建完后,就可以来分析一下本次需求大概会涉及哪些功能了

  • 上传头像

这是一个合成微信头像的工具,那就必须得让用户上传自己的微信头像了

  • 合成模版

为了方便,我们当然还需要提供多种模版供用户自己选择

  • 用户自定义内容

为了让生成的头像更具独一无二性,我们还需要提供用户自定义内容的功能,比如:用户输入文字、选择文字颜色等

  • 合成头像

本次需求的重点当然是合成头像了

  • 下载合成后的头像

用户合成完当然还得支持让他下载

功能开发

上传头像

<script setup lang="ts">
// 用户头像
const user_img = ref("");
const change = (file: any, fileList: any) => {
  console.log(file, fileList);
  const fileReader = new FileReader();
  fileReader.readAsDataURL(file.raw);
  fileReader.onload = (e: any) => {
    user_img.value = e.target.result;
  };
};

// 删除用户头像
const remove = () => {
  user_img.value = "";
};
</script>

这部分比较简单,主要是用户上传自己的微信头像后再进行展示,UI部分就不贴了,后面有源码。

合成模版

合成模版部分,这里主要是需要考虑各个模版所需要的合成功能有哪些

<script>
const gqList = ref([
  {
    id: 1,
    name: "模版1",
    img: getImg("gq0", "jpg"),
    template: getImg("tem1"),
    has: ["text"],
    textLabel: "请输入你的姓",
    desc: "最多输入1个字",
    text: "宋",
    textLength: 1,
  },
  {
    id: 2,
    name: "模版2",
    img: getImg("gq1", "jpg"),
    template: getImg("tem2"),
  },
  {
    id: 3,
    name: "模版3",
    img: getImg("gq2", "jpg"),
    template: getImg("tem3"),
  },
  {
    id: 4,
    name: "模版4",
    img: getImg("gq3", "jpg"),
    template: getImg("tem4"),
    has: ["text"],
    textLabel: "请输入祝福语",
    textColor: "#FED800",
    text: "生在国旗下,长在春风里",
    desc: "最多输入12个字, 请用中文逗号隔开",
    textLength: 12,
  },
  { id: 5, name: "模版5", img: getImg("gq4"), template: getImg("tem5") },
  {
    id: 6,
    name: "模版6",
    img: getImg("gq5", "jpg"),
    template: getImg("tem6"),
    has: ["text"],
    textLabel: "请输入祝福语",
    textColor: "#FED800",
    desc: "最多输入12个字, 请用中文逗号隔开",
    text: "不负韶华,只争朝夕",
    textLength: 12,
  },
  { id: 7, name: "模版7", img: getImg("gq6"), template: getImg("tem7") },
]);
const template_id = ref(1);
// 选择模版
const gqChange = (val: any) => {
  console.log(val);
  template_id.value = val;
  generateImgRef.value.clear();
  generateImgRef.value.init();
};
</script>

合成图片

这里其实也不难,主要是使用canvas来绘制图片以及文字,由于各个模版的合成逻辑不一样,这里就不全部展示了,但整体上的合成流程是一样

// 模版4
const drawImg4 = (ctx: any) => {
  const img = new Image();
  img.src = user_img.value;
  const gqImg = new Image();
  gqImg.src = gqList.value[template_id.value - 1].img;
  img.onload = () => {
    ctx.drawImage(img, 0, 0, 300, 300); // 绘制头像
    gqImg.onload = () => {
      ctx.drawImage(gqImg, 0, 0, 300, 300); // 绘制国庆图
      ctx.fillStyle = textColor.value; // 设置文字颜色
      ctx.font = "20px kaiti"; // 设置文字大小及字体
      const textList = text.value?.split(",") ?? []; // 以中文逗号分割文字
      textList.forEach((item: string, i: number) => {
        drawVerticalText(ctx, item ?? "", 20 + i * 20, 186 + i * 20, {
          size: 20,
        }); // 绘制文字
      });
    };
    canDownload.value = true; // 合成完成
  };
};

这里主要的难点在于canvas默认不支持文字竖排绘制,所以这里需要特殊处理,原理其实就是遍历文字,计算文字高度,然后再一个一个去绘制

// 文字竖排
const drawVerticalText = (
  context: any,
  text: string,
  x: number,
  y: number,
  font: any
) => {
  context.save();
  context.font = font;
  for (var i = 0; i < text.length; i++) {
    context.fillText(text[i], x, y + i * font.size);
  }
  context.restore();
};

下载图片

这里主要是借助a标签的download属性,这里在手机上有点坑,后面会提到...

const downloadImg = () => {
  if (!canDownload.value) {
    ElMessage({
      message: "请先合成头像~",
      type: "warning",
    });
    return;
  }

  const url = canvas.value.toDataURL("image/png");
  const a = document.createElement("a");
  a.href = url;
  a.download = "国庆头像.png";
  a.click();
};

自动化部署

这里其实之前有写过文章,主要是使用github action来完成

搭建完就是这样的,我们写完代码只需要将代码提交上去就能够自动打包部署了

对这个不了解的可以去看我之前的文章:使用GitHub Actions实现自动化部署

体验

开发部署完就可以来体验一下了:体验地址

PC上体验下来,效果还可以。

问题及解决方案

开发过程中也遇到一些问题,来看看是如何解决的吧

保存图片不清晰

canvas绘制图片不清晰的原因主要是:

  • 图片被放大或缩小
  • 图片没处于完整像素的位置

因为canvas是点阵图,由一个个像素组成,当图像被放大时,一个像素会被强形拉伸至一个以上,多出来的像素均匀的分部在图像中,计算机为了使拉伸后的图像看起来平滑,会给这些多出来的像素计算出一个过渡色,缩小图像时,多个像素合成一个像素,计算机会用这多个像素的色彩值计算出一个过渡色来填充这个像素,不管是放大还是缩小,都会造成图像原有像素信息丢失。

所以只需要加上以下代码就能解决

const dpr = window.devicePixelRatio || 1; // 获取设备的devicePixelRatio
canvas.value.width = 300 * dpr; // 画布宽高放大dpr倍,绘制后再缩小dpr倍,解决模糊问题
canvas.value.height = 300 * dpr; // 画布宽高放大dpr倍,绘制后再缩小dpr倍,解决模糊问题
canvas.value.style.width = "300px"; // 显示高
canvas.value.style.height = "300px"; // 显示高
ctx.value.scale(dpr, dpr); // 按比例缩放画布,解决模糊问题

优化完,清晰度提升还是非常明显的

移动端体验问题

手机上下载图片会失败,这主要是因为blob格式在手机上不能下载,base64格式有点大,那就只能上传CDN再进行下载了?

不需要,我们可以利用手机上的长按图片保存来实现

const downloadImg = () => {
  if (!canDownload.value) {
    ElMessage({
      message: "请先合成头像~",
      type: "warning",
    });
    return;
  }

  const url = canvas.value.toDataURL("image/png");
  if (devices.some((item) => ua.includes(item))) {
    ElMessageBox.alert(
      `
    请长按图片保存
    <img src="${url}" style="width: 100%;height: 100%;object-fit: contain;" />
    `,
      "保存图片",
      {
        dangerouslyUseHTMLString: true,
      }
    );
    return;
  }
  const a = document.createElement("a");
  a.href = url;
  a.download = "国庆头像.png";
  a.click();
};

打包部署问题

打包生成的_plugin-vue_export-helper.cdc0426e.js文件访问404,刚开始我还以为是打包路径配置的有问题,但如果是打包路径的问题的话也不会只有这一个文件有问题。

最终,我在viteissues中找到了答案

简单点讲就是Github Pages 阻止了以下划线字符开头的文件,所以会导致这个文件访问返回404.

解决方法就是修改打包逻辑:

const INVALID_CHAR_REGEX = /[\u0000-\u001F"#$&*+,:;<=>?[\]^`{|}\u007F]/g;
const DRIVE_LETTER_REGEX = /^[a-z]:/i;

build: {
    outDir: "dist",
    assetsDir: "assets",
    chunkSizeWarningLimit: 2000, // 解决包大小超过500kb的警告
    rollupOptions: {
      output: {
        manualChunks: {
          // elementPlus: ["element-plus"],
          // highlightjs: ["highlight.js"],
        },
        chunkFileNames: "assets/[name]-[hash].js",
        entryFileNames: "assets/[name]-[hash].js",
        assetFileNames: "assets/[name]-[hash].[ext]",
        sanitizeFileName: (name) => {
          const match = DRIVE_LETTER_REGEX.exec(name);
          const driveLetter = match ? match[0] : "";
          return (
            driveLetter +
            name.slice(driveLetter.length).replace(INVALID_CHAR_REGEX, "") // 处理文件名中的非法字符
          );
        },
      },
    },
  },

vite.config.ts中加上以上代码,重新提交部署就可以了。

最后

整个内容到这里就结束了

标签:const,img,getImg,微信,value,头像,DIY,模版
From: https://www.cnblogs.com/songyao666/p/17726739.html

相关文章

  • 详谈怎样配置微信小程序的分包以解决体积过大问题(转载)
     一.文件结构和工具功能1.小程序编译的文件结构非常必要推荐了解小程序文件结构,对于稍大的项目,对于包的精简会起到柳暗花明又一村的效果。众所周知,微信小程序分为“主包”和“分包”模块,每个包不得超过2M最多分10个包共20M。而微信小程序的文件结构,只有主包和分包: 因此,我......
  • 微信小程序自定义tabbar遮挡scroll-view问题
    在使用小程序开发时,底部为自定义导航栏,在使用scroll-view滚动页面时,滚动到底部时最后一条或多条数据被导航栏遮挡,如下:解决方案:1.获取用户手机宽度和高度letdeviceWidth=wx.getSystemInfoSync().windowWidth;//获取屏幕宽度letdeviceHeight=wx.getSystemInfoSync().win......
  • 微信小程序 catch:tap bind:tap 的区别
    这二个都是点击事件,一个是阻止冒泡:catch:tap,bind:tap会向上冒泡。一般场景: 一个列表:1、点击行,会弹出相关详情信息,2、点击行中的按钮会执行相关的操作。 点按钮会出来二个窗口,按钮向上冒泡了,二个事件都被执行,所以会执行二次。......
  • 微信小程序开发手册(一)
    微信小程序中的this.setData()以前竟然都没注意这个:我们可能经常性的写出这样的data:data:{listt:[{text:"本周阻止辅导员职业技能大赛生情熟知和谈心谈话比赛",date:"2020.03.03-2020.03.20",mxc_gou:''},{text......
  • uniapp,微信小程序确认收货组件的使用
    直接上代码//拉起确认收货组件if(wx.openBusinessView){wx.openBusinessView({businessType:'weappOrderConfirm',extraData:{//merchant_id:'1230000109',//用户交易商户号//merchant_trade_no:"1234323JKHDFE1243252",//商户......
  • AES-256-ECB PKCS7Padding 解密 微信退款接口
    微信退款通知https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/pay/OfficialPayMent/chapter8_8.shtml需要的pom<!--https://mvnrepository.com/artifact/commons-codec/commons-codec--> <dependency> <groupId>commons-codec</groupId> <......
  • ubuntu上使用微信界面太小
    一开始:小小的也很可爱呢后来使用命令调整envWINEPREFIX="$HOME/.ukylin-wine/wechat"/usr/bin/ukylin-winewinecfg 进入wine设置界面将分辨率调高,设置虚拟桌面,就可以勉勉强强用了。 还是很难用!!!哭......
  • 微信获取用户信息
    微信有2个ACCESS_TOKEN,1,基础接口的token获取接口是 https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET 2,用户网页授权access_token获取接口地址是 https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&s......
  • 超越钉钉与企业微信:如何选择一款更适合企业的私有化即时通讯软件
    在现代企业中,高效的沟通与协作是成功的关键。钉钉与企业微信作为知名的即时通讯软件,为企业带来了许多便利。然而,在一些特定场景和对数据安全性要求更高的企业来说,选择一款更适合自身需求的私有化即时通讯软件才是最佳选择。WorkPlus作为领先的品牌,致力于提供满足企业需求的私有化即......
  • 微信小程序:获取不到表单数据
    今天碰到了一件让我怀疑人生的事情:获取不到表单的数据,但是productName能获取到数据,其他的都获取不到数据,而且他们的写法一模一样。<viewclass="contain"style="margin-bottom:200rpx;"><formbindsubmit="formSubmit"><viewclass="row2"sty......