小程序之生成海报

  • 小程序之生成海报

废话不说,直接上干货~

前端代码

  • xml代码
 //只需看生成商品图片内容 其他可忽略
 <action-sheet hidden="{{ actionSheetHidden }}" bindchange="listenerActionSheet">
     <action-sheet-item>
         <button open-type="share" hover-class='none'>发送给朋友</button>
     </action-sheet-item>
     <action-sheet-item>
        <button catchtap="createposter">生成商品图片</button>
     </action-sheet-item>
     <action-sheet-item wx:if="{{salesperson_product == 1}}">
        <button catchtap="earning">推荐赚佣金</button>
     </action-sheet-item>
    //自动隐藏action-sheet
    <action-sheet-cancel>取消</action-sheet-cancel>
 </action-sheet>
 
 // imagePath 是重点 海报的路径    canvas_show 为控制是否显示
 <view hidden="{{ canvas_show ? true : false }}" class='bm_show'  bindtap="closephoto" >
     <view class='pics'>
       <image  src="/images/closecsv.png" class="closex" catchtap="closecsv" mode="widthFix" />
       <image src="{{ imagePath }}" mode="widthFix"></image>  
       <button class='save_box' catchtap='savephoto'>保存图片</button>
    </view>
  </view>
  <canvas class='mycanvas' canvas-id="mycanvas"></canvas>
  
  • js代码
	
  /**
   * 页面的初始数据
  */
  data: {
    actionSheetHidden:true,  //底部按钮显示
    canvas_show:true  //生成海报
  },
  
  /**
   * 生命周期函数--监听页面加载
   * 接收参数方式
  */
  onLoad: function (options) {
  //需要用decodeURIComponent转换所接的参数   仅供参考
  if (options.scene) {
      var ps = decodeURIComponent(options.scene).split("&");
      productid = ps[0];
      if (ps.length == 2) {
        unique_code = ps[1];
      } else if (ps.length == 3) {
        coupon_code = ps[2];
      }
    }
  },
  
  //生成海报
  createposter: function () {
    let that = this;
    that.createNewImg(); // 执行绘图
  },
  
  //也可以直接为一个方法生成海报
  createNewImg: function () {
    let that = this;
    if (that.data.swiperImgs.length == 0) {
      return false;
    }
    let top_pics = that.data.swiperImgs[0].real_path;    //获取图片数据
    let product_name = that.data.product_name;  //获取商品名字
    var context = wx.createCanvasContext('mycanvas');    //创建 canvas 绘图上下文(指定 canvasId)
    let productid = that.data.productid;   //商品id
    //准备encodeURIComponent之后传参数  当前参数  1 product_id 2 unique_code 3 appid
    let Params_productid = encodeURIComponent(productid);   
    let is_recruit = that.data.is_recruit; //是否是销售员
    let unique_code = is_recruit == 1 ? "" : that.data.unique_code;   //生成的随机字符 根据当前需求决定参数
    let appid = app.globalData.sysParams.ext_app_id;   //根据appid去后台获取access_token 必须的参数
    //传参数之前需要 encodeURIComponent 一下 
    let Params_unique_code = encodeURIComponent(unique_code);
 	wx.showLoading({title: "图片生成中…"});
	//注:invokeServer 方法为app.js文件中的一个封装调用接口方法  不用抄袭,可以按自己的来写
	//此接口只是为了获取小程序的二维码(带参数的)
    app.invokeServer('mall.product.product.getqrcode', {"appid":appid,"product_id":Params_productid,"unique_code":Params_unique_code}).then(function(res) {
    	if (res.data.code != 0) {
          app.showToast(res.data.msg, 'none', 1000)
          return;
        }
        var qrcode = res.data.data.url;
        console.log("qrcode",qrcode);  //打印返回二维码图片的路径
        //获取商品的图片信息
        that.getImageInfo(top_pics).then(function(obj){
		  //获取小程序二维码的图片信息
          that.getImageInfo(qrcode).then(function(codeobj){          

            console.log("codeobj:",codeobj);

            context.setFillStyle("#fff")  //背景颜色
            context.fillRect(0, 0, 320, 450)  // 画布坐标/大小
            context.stroke();

            //商品图片
            context.beginPath();
            context.drawImage(obj.path, 20, 20, 280, 280);
            context.stroke();

            context.beginPath();
            context.font = '14px Microsoft Yahei'  //设置字体
            context.setTextAlign('left');
            context.setFillStyle('#333');
            that.drawText(context,product_name, 20, 330, 80, 280); 
            context.stroke();
            
            let price = "";
            let price_icon = "";
            //这块逻辑可以忽略,只是写显示商品的价格 start
            let productAll = that.data.productAll;
            if (productAll.pur_price.min_price == productAll.pur_price.max_price) {
              price = productAll.pur_price.min_price;
              price_icon = "¥";
            } else {
              price =  productAll.pur_price.min_price + "~ ¥" + productAll.pur_price.max_price;
            }
            //end
            
            context.beginPath();
            context.font = '14px Microsoft Yahei'  //设置字体
            context.setTextAlign('left');
            context.setFillStyle('#f00');
            context.fillText(price_icon, 20, 410);
            context.stroke();

            context.beginPath();
            context.font = '18px Microsoft Yahei'  //设置字体
            context.setTextAlign('left');
            context.setFillStyle('#f00');
            context.fillText(price, 35, 410);
            context.stroke();

            // 二维码信息
            context.beginPath();
            context.drawImage(codeobj.path, 210, 360, 80, 80);
            context.stroke();

            context.draw() //开始进行绘图

            //将生成好的图片保存到本地,需要延迟一会,绘制期间耗时
            setTimeout(function() {
              wx.canvasToTempFilePath({
                canvasId: 'mycanvas', //必须和wx.createCanvasContext 保持一致
                success: function (con) {
                  wx.hideLoading();
                  var tempFilePaths = con.tempFilePath;
                  that.setData({
                    imagePath: tempFilePaths,  //海报展示的路径(--很关键--)
                    canvas_show:false,
                  });
                },  
                fail: function (resere) {
                  console.log(resere);
                }
              });
            }, 2000);

            setTimeout(function () {
              that.setData({
                canvas_show: false
              })
            }, 1500);

          }).catch(function(msg) {
            app.tip(msg)
          });

        }).catch(function(msg) {
            app.tip(msg)
        });
    }).catch(function(msg) {
      wx.hideLoading();
    });
  }//文本换行 参数:1、canvas对象,2、文本 3、距离左侧的距离 4、距离顶部的距离 5、文本的宽度
  drawText: function (ctx, str, leftWidth, initHeight, titleHeight, canvasWidth) {
    let lineWidth = 0;
    let lastSubStrIndex = 0; //每次开始截取的字符串的索引

    for (let i = 0; i < str.length; i++) {
      lineWidth += ctx.measureText(str[i]).width;
      if (lineWidth > canvasWidth) {
        ctx.fillText(str.substring(lastSubStrIndex, i), leftWidth, initHeight); //绘制截取部分
        initHeight += 24; //26为字体的高度
        lineWidth = 0;
        lastSubStrIndex = i;
        titleHeight += 24;
      }
      if (i == str.length - 1) { //绘制剩余部分
        ctx.fillText(str.substring(lastSubStrIndex, i + 1), leftWidth, initHeight);
      }
     }
    // 标题border-bottom 线距顶部距离
    titleHeight = titleHeight + 10;
    return titleHeight
  },
  
  //获取商品图片信息
  getImageInfo: function (imagesrc) {
    return new Promise(function (resolve, reject) {
       wx.getImageInfo({
        src: imagesrc,
        success(res) {
          resolve(res);
        },
        fail(ere) {
          this.tip(ere)
        }
      })
    });
  },
  
  //保存海报图片
  savephoto: function () {
    var that = this;
    wx.showLoading({ title: '保存中...' });
    wx.saveImageToPhotosAlbum({
      filePath: that.data.imagePath,
      success(res) {
        console.log("*res*",res);
        wx.showModal({
          content: '图片已保存到相册,赶紧晒一下吧~',
          showCancel: false,
          confirmText: '好的',
          confirmColor: '#333',
          success: function (res) {
            if (res.confirm) {
              console.log('用户点击确定');
              /* 该隐藏的隐藏 */
              that.setData({
                canvas_show: true,
              })
            }
          },fail:function(res){
            console.log(11111)
          }
        })
      },fail:function(ere){
          //授权失败-保存失败 这边微信做过调整,必须要在按钮中触发,因此需要在弹框回调中进行调用
          wx.showModal({
             title: '提示',
             content: '您未授权,保存失败!',
             showCancel: false,
             success:modalSuccess=>{
               wx.openSetting({
                 success(settingdata) {
                   console.log("settingdata", settingdata)
                   if (settingdata.authSetting['scope.writePhotosAlbum']) {
                     wx.showModal({
                       title: '提示',
                       content: '获取权限成功,再次点击图片即可保存',
                       showCancel: false,
                     })
                   } else {
                     wx.showModal({
                       title: '提示',
                       content: '获取权限失败,将无法保存到相册哦~',
                       showCancel: false,
                     })
                   }
                 },
                 fail(failData) {
                   console.log("failData",failData)
                 },
                 complete(finishData) {
                   console.log("finishData", finishData)
                 }
               })
             }
          })
      },
      complete(res) {
        wx.hideLoading()
      }
    })
  },
  
  //关闭画布
  closecsv: function () {
    this.setData({ canvas_show: true })
  },
 

附:获取小程序二维码也可请参考官网接口 请点击 这里
       关于画布问题请参考 这里
       关于保存图片到系统相册里的请参考 这里
       关于获取图片信息的请参考 这里
       其他的请自行查询百度

后端代码

  • PHP代码

    /**
     * @return array
     * 获取商品详情页小程序二维码
    */
    public function getqrcode()
    {
        $appid = trim($this->input('appid'));
        $product_id = trim($this->input('product_id'));
        $unique_code = trim($this->input('unique_code'));
        //获取access_token
        $access_token = WxmAppService::getComponentAccessToken($this->supplier_id, $appid);
        if (!$access_token) {
            return alert_info(1, 'access_token 获取失败!');
        }
		if ($unique_code) {
			$scene = $product_id . '&' . $unique_code;
		} else {
			$scene = $product_id . "&";
		}
        $page = "pages/shop/shopdetail/shopdetail";
        //微信官方接口 根据access_token获取小程序二维码  参数必须是json_encode加工 然后通过curl请求
        $url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=". $access_token;
        try {
            $res = curl_post($url, json_encode([
                'scene' => $scene,
                'page' => $page,
                'width' => 280,
            ]));
        } catch (\Exception $ex) {
            return alert_info(1, '调用异常!' . $ex->getMessage());
        }
        $res_arr = json_decode($res, true);
        if (isset($res_arr['errcode'])) {
            return alert_info($res['errcode'], $res['errmsg']);
        }
        $ym = date('Ym');
        $filepath = attached_path('wechat/scene/'.$ym);
        if (!is_dir($filepath)) mkdir($filepath, 0777, true);
        $filename = uniqid(substr(md5($scene), 3, 10)).'.jpg';
        //写入文件
        file_put_contents($filepath.'/'.$filename, $res);
        //alert_info是返回接口的封装方法,也可以自行封装。
        return alert_info(0, 'ok!', [
            'url' => url('attached/wechat/scene/'.$ym.'/'.$filename),
        ]);
    }
    
	/**
	 * 信息返回
	 * @param int $code 错误码 0成功,其他失败
	 * @param string $msg 返回消息
	 * @param array $data 返回数据
	 * @return array
	 */
	function alert_info($code, $msg = '', $data = array())
	{
	    $code = (int)$code;
	    $msg = trim($msg);
	    return ['code' => $code, 'msg' => $msg, 'data' => $data];
	}
	

测试阶段

可以使用微信开发工具中的 《通过二维码编译》去进行调试
在这里插入图片描述

最后展示效果

将此图片保存到手机当中
在这里插入图片描述
注:此图片是本小程序二维码图片,中间二维码带有商品id、appid、unique_code随机字符参数

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值