国庆头像生成小程序

2,105 阅读3分钟

国庆来临,你们的节日头像换好了吗?最近“渐变国旗头像”火了,今天就为大家分享一下自己写的一个生成国庆头像的小程序。

不废话,先上图。

功能分出两个部分,第一个是渐变国旗,可以通过下面的参数调整生成的小程序。第二种就是常用的使用背景图和头像贴图。

下面小程序码直接预览效果。

gh_8f66e5930868_344.jpg

渐变国旗

网上很多案例都是使用已经处理的国旗背景图贴在头像上方,来是现实生成。但我想有没有方法可以调整渐变大小、五角星大小来生成背景图呢,而不是使用固定的背景图。开始我想的是使用完善的国旗背景,canvas能不能像ps那样加个蒙版,再拉个渐变实现(这个肯定是能显示的,canvas是可以操作像素级),但是网上搜索了半天也没有找到类似的案例。

后来是GitHub上找到一个另一种方法是现实的,就是这个项目查看这里,这个项目的实现方式是,先把国旗五角星部分剪成单独图片,而国旗的背景色通过canvas绘制,通过这样就可以显示调整生成渐变效果。

直接贴上渐变国旗代码,params为滑块的值,先把用户头像绘制到canvas上,大小覆盖这个canvas。然后这里list是多种渐变模式,0是圆形渐变,1是从左到右的线性渐变,2是从左上角到右下角的线性渐变。

这里大家可以自己根据想法扩展。然后绘制一个矩形,矩形的填充颜色使用上面生成的渐变。最后把五角星贴到最上面,效果就出来啦。

    async generate1() {
      const {
        ctx,
        params: { starSize, gradientPostion, gradientSzie, gradientSection }
      } = this;
      if (this.avatar) {
        const avatar = await this.loadImage(this.avatar);
        ctx.drawImage(avatar, 0, 0, size, size);
      }

      const list = {
        0: () => {
          return ctx.createRadialGradient(
            0,
            gradientPostion.value,
            0,
            0,
            gradientPostion.value + 20,
            gradientSzie.value * (1.414 / 1.5)
          );
        },
        1: () => {
          return ctx.createLinearGradient(
            0,
            size / 2,
            gradientSzie.value,
            size / 2
          );
        },
        2: () => {
          return ctx.createLinearGradient(
            0,
            0,
            gradientSzie.value,
            gradientSzie.value
          );
        }
      };
      let Gradient = list[this.imageIndex]();
      Gradient.addColorStop(0, "#d80203");
      Gradient.addColorStop(gradientSection.value / 10, "rgba(216,2,3,0.8)");
      Gradient.addColorStop(1, "rgba(255, 255, 255, 0)");
      ctx.fillStyle = Gradient;
      ctx.fillRect(0, 0, size, size);
      const image = this.startImage;
      ctx.drawImage(
        image,
        0,
        0,
        image.width,
        image.height,
        size * 0.04,
        size * 0.04,
        starSize.value * (image.width / image.height),
        starSize.value
      );
    },
    loadImage(url) {
      return new Promise((resolve, reject) => {
        const image = this.canvas.createImage();
        image.onload = () => resolve(image);
        image.onerror = reject;
        image.src = url;
      });
    }

因为参数变动就重新生成,如果每次清空画布在小程序中会有闪的一瞬间不好看,然而因为每次绘制都会覆盖这个画布,所以直接在保存的时候清空画布重新绘制一边,就可以提升参数变动预览的效果。

   async onSaveImage() {
      const { canvas, ctx } = this;
      ctx.clearRect(0, 0, size, size);
      await this.generate();
      uni.canvasToTempFilePath({
        canvas,
        success: res => {
          const tempFilePath = res.tempFilePath;
          uni.saveImageToPhotosAlbum({
            filePath: tempFilePath,
            success: () => {
              uni.showToast({
                title: "保存相册成功",
                icon: "success"
              });
            },
            fail: e => {
              if (e.errMsg !== "saveImageToPhotosAlbum:fail auth deny") return;
              uni.showModal({
                title: "温馨提示",
                content: "请选开启添加到相册权限",
                success: uni.openSetting
              });
            }
          });
        }
      });
    },

背景图与头像贴图

一样先上代码。这种就很简单了,就是把背景图先绘制在画布上,背景图是中间与部分是透明的,再把头像绘制在画布上,这样就完成了贴图,这种主要需要的是背景图素材。

当然大家也可以扩展,例如在某个位置加文字,例如显示很火的显示姓氏的头像,或者小挂坠修饰等等。这里就看大家的想法啦。

   async generate2() {
      const { ctx } = this;
      const avatar = await this.loadImage(this.avatar);
      ctx.drawImage(avatar, 0, 0, size, size);
      const image = await this.loadImage(this.image);
      ctx.drawImage(image, 0, 0, size, size);
    },

其他

项目代码已上传gitee,项目地址:avatar: 头像生成微信小程序 (gitee.com)

最后就大家国庆吃好,玩好,加班好!!!哈哈