qrcode生成二维码并下载【带logo图标】【带文字描述】

news2025/2/27 21:36:20

  qrcode官网地址:http://jeromeetienne.github.io/jquery-qrcode/

结果图:

不带文字

带文字

遇到问题:

1、中文乱码:需要先将中文字体转码。

2、qrcode.js生成的二维码是没有白边的,需要重新绘制边框+logo+文字

3、将生成的二维码图片下载到本地。

html 

<!--到官网去下载-->
<script src="js/jquery.js"></script>
<script src="js/qrcode.min.js"></script>
……
<a ng-click="saveImageQrcode(vm.companyName)" title="点击下载公司二维码">
  <div rwd-create-qrcode="{{vm.qrcodeUrl}}" qrcode-logo="{{vm.companyLogoUrl}}" qrcode-size="90"></div>
  <div class="small text-g text-center">[点击下载]</div>
</a>

 js

// 二维码-白色边框大小
var borderSize = 15; // 15px
// 二维码宽高 【项目中只使用正方形的二维码,只需要一个数值就OK】
var qrcodeWidth = parseInt(attrs.qrcodeSize) || 200;
var qrcodeHeight = parseInt(attrs.qrcodeSize) || 200;
var strText = toUtf8(attrs.rwdCreateQrcode);//中文格式转换
var logoURl = attrs.qrcodeLogo;//二维码中间的logo图片url

setTimeout(() => {
  //生成二维码
  element.qrcode({
    text: strText, // 生成二维码的-链接或者文字
    render: 'canvas', //设置渲染方式 table canvas
    width: qrcodeWidth,// 二维码的宽度
    height: qrcodeHeight,// 二维码的高度
  });
  var initialCanvas = element.find('canvas').get(0);
  // 在初始的二维码上,绘制边框+logo
  drawQrcode(initialCanvas, qrcodeWidth, qrcodeHeight, borderSize, logoURl);

  //调用保存二维码图片的函数
  scope.saveImageQrcode = (fileName) => {
    // 利用 a 标签的 download 属性去下载图片
    let a = document.createElement('a');
    a.download = `${fileName}-二维码.png`; // 设置下载文件的名称
    a.href = initialCanvas.toDataURL('image/png');
    // 创建一个点击事件
    const clickEvent = new MouseEvent('click');
    // 触发 a 标签的点击事件
    a.dispatchEvent(clickEvent);
  };

}, 100);

1、中文乱码:query-qrcode这个库是采用 charCodeAt() 这个方式进行编码转换的,这个方法默认会获取它的 Unicode 编码,一般的解码器都是采用UTF-8, ISO-8859-1等方式。英文是没有问题,如果是中文,一般情况下Unicode是UTF-16实现,长度2位,而UTF-8编码是3位,这样二维码的编解码就不匹配了。需要先将中文字体转码。

function toUtf8(str) { //二维码编码前把字符串转换成UTF-8
  var out, i, len, c;
  out = '';
  len = str.length;
  for (i = 0; i < len; i++) {
    c = str.charCodeAt(i);
    if ((c >= 0x0001) && (c <= 0x007F)) {
      out += str.charAt(i);
    } else if (c > 0x07FF) {
      out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));
      out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F));
      out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
    } else {
      out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F));
      out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
    }
  }
  return out;
}

2、qrcode.js生成的二维码是没有白边的,需要重新绘制边框+logo+文字

   /* 在初始的二维码上,绘制边框+logo+文字
    * canvas:qrcodejs生成的二维码canvas
    * qrcodeWidth:二维码的宽度
    * qrcodeHeight:二维码的高度
    * borderSize:二维码白边大小
    * logoUrl:logo的url【有些二维码没有logo】
    * callback:回调函数,返回生成的二维码图片的url
    * **/
    function drawQrcode(canvas, qrcodeWidth, qrcodeHeight, borderSize, logoUrl, callback) {
      // logo宽高:是二维码的大小的1/4
      let logoWidth = qrcodeWidth / 4;
      let logoHeight = qrcodeHeight / 4;
      //logo位置:位于二维码中间
      let logoLeft = (qrcodeWidth - logoWidth) / 2 + borderSize;//logo距离左边的数值 = (二维码宽度 - logo宽度) / 2 + 白边宽度
      let logoTop = (qrcodeHeight - logoHeight) / 2 + borderSize;//logo距离顶部的数值 = (二维码高度 - logo高度) / 2 + 白边宽度

      const image = new Image();//二维码图片对象
      const logoImage = new Image(logoWidth, logoHeight);//logo图片对象
      // 解决跨域问题
      image.setAttribute('crossOrigin', 'anonymous');
      logoImage.setAttribute('crossOrigin', 'anonymous');

      // 图片加载完成后,通过canvas处理
      const context = canvas.getContext('2d');
      // qrcodejs 生成的二维码加载完成后,开始 canvas 绘制
      image.onload = function () {
        // 通过canvas绘制,canvas的宽高设置为二维码图片宽高+白边宽度(上下borderSize)
        canvas.width = qrcodeWidth + borderSize * 2;
        canvas.height = qrcodeHeight + borderSize * 2;
        ///
        //设置画布背景
        context.fillStyle = '#ffffff';
        //带白色边框borderSize
        context.fillRect(0, 0, canvas.width, canvas.height);
        ///
        //添加文字的时候:需要设置 canvas.height = qrcodeHeight + borderSize * 2 + 10;(10px为文字的位置)
        //text位置:位于二维码中间
        // let textLeft = canvas.width / 2;//text距离左边的数值 = canvas的宽度 / 2
        // let textTop = canvas.height - 10;//text距离顶部的数值 = canvas的宽度 - 底部留白的高度
        // //设置文字样式
        // context.fillStyle = '#000000';
        // context.font = 'bold ' + 12 + 'px Arial';
        // context.textAlign = 'center';
        // //文字描述
        // context.fillText('我的博客', textLeft, textTop);
        ///
        //绘制二维码
        // padding:borderSize
        context.drawImage(image, borderSize, borderSize); // 目标图像-二维码
        ///
        // 有logoURl,绘制logo;没有的时候直接返回最终canvas
        if (logoUrl) {
          // 中间的logo加载完成后,绘制logo
          logoImage.onload = function () {
            // 绘制logo图像,context.drawImage(logoImage,logoX, logoY, logoImage.width, logoImage.height);
            context.drawImage(logoImage, logoLeft, logoTop, logoWidth, logoHeight);
            // 将最终canvas传到回调函数中
            callback && callback(canvas);
          };
          // 获取logoUrl,赋值给logoImage,触发logoImage的onload方法
          logoImage.src = logoUrl;
        } else {
          // 将最终canvas传到回调函数中
          callback && callback(canvas);
        }
      };
      // canvas转为图片数据,赋值给image,触发image的onload方法
      image.src = canvas.toDataURL('image/png');// 二维码图片
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1959716.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IoTDB 入门教程 实战篇④——C#示例(开源)

文章目录 一、前文二、新建C#项目三、NuGet安装四、示例源码五、查询数据六、参考 一、前文 IoTDB入门教程——导读 本文详细阐述了如何通过一个C#项目成功连接到IoTDB时序数据库&#xff0c;进而展示了如何向该数据库高效地写入数据以及执行精确的数据查询操作。 此示例旨在为…

ImportError: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.20‘ 报错解决办法

1.查找 libstdc.so.6* find / -name libstdc.so.6*2.copy一个libstdc.so.6.0.19到/usr/lib64/下 cp /usr/lib64/libstdc.so.6 /usr/lib64/3.创建软连接 ln -sf /usr/lib64/libstdc.so.6.0.31 /usr/lib64/libstdc.so.6完毕&#xff01;

RISC-V (四)内存管理

本章目的&#xff1a; 对内存进一步的管理&#xff0c;实现动态的分配和释放。 实现page级别的内存分配和释放。 内存管理分类 -自动管理内存-栈&#xff08;stack&#xff09; -静态内存-全局变量/静态变量。放在数据段里面。 -动态管理内存-堆&#xff08;heap&#xff09;…

【Docker】LXC 容器操作实战

一、实战目的 通过 lxc 来完成容器的创建&#xff0c;体会容器并了解 docker 并不是容器的唯一实现。 自 docker 0.9 版本起&#xff0c;docker 除了继续支持 LXC 外&#xff0c;还开始引入自家的 libcontainer&#xff0c;试图打造更通用的底层容器虚拟化库。如今的 docker…

【EI稳定检索】第二届能源与化学工程国际会议(EACE 2024)

第二届能源与化学工程国际会议 2024 International Conference on Energy and Chemical Engineering 【1】会议简介 第二届能源与化学工程国际会议是一个旨在促进能源科学与化学工程领域学术交流与合作的重要平台。会议汇集了全球范围内的专家学者、研究人员及行业代表&#xf…

77.SAP ME - 数据库架构

目录 1.SAP ME的数据库 2.SAPMEINT的数据库 3.SAPMII的数据库 4.基于MSSQLSERVER或ORACLE的架构 5.基于HANA的架构 - 无ODS 1.SAP ME的数据库 WIP&#xff1a;在实时事务期间&#xff0c;SAP ME 在“在制品” (WIP) 数据库表中存储数据。ODS&#xff1a;可操作数据存储 (…

树莓派笔记22_小车:小车电机开环运动与opencv摄像头巡线

今日继续学习树莓派4B 4G&#xff1a;&#xff08;Raspberry Pi&#xff0c;简称RPi或RasPi&#xff09; 本人所用树莓派4B 装载的系统与版本如下: 版本可用命令 (lsb_release -a) 查询: ​ Opencv 版本是4.5.1&#xff1a; ​ Python 版本3.7.3&#xff1a; 今日尝试搭建一台小…

车车科技合纵连横:股价今年以来跌超八成,公司看好未来市场份额

《港湾商业观察》黄懿 6月27日&#xff0c;Cheche Group Inc. (NASDAQ: CCG&#xff0c;下称“车车科技”)宣布&#xff0c;公司已与北京安鹏保险经纪有限公司&#xff08;“北京安鹏”&#xff09;建立战略合作伙伴关系。其中&#xff0c;北京安鹏是北京汽车集团有限公司&…

vllm部署的一些思考

vllm号称利用ray支持多机多卡的方式,链接如下 Distributed Inference and Serving — vLLMhttps://docs.vllm.ai/en/stable/serving/distributed_serving.html但是这种方式只是把非常大的模型如lamma 3.1 ,这个模型有405b,需要用多机多卡的方式进行分布式。 事实上,生产中…

C语言:扫雷游戏实现

一、扫雷游戏的分析和设计 扫雷游戏想必大家都玩过吧&#xff0c;初级的玩法是在一个9*9的棋盘上找到没有雷的格子&#xff0c;而今天我们就要做的就是9*9扫雷游戏的实现。 1、游戏功能和规则 使用控制台实现经典的扫雷游戏游戏可以通过菜单实现继续玩或者退出游戏扫雷的棋盘…

Git 安装教程

1、登录git 官方网站&#xff1a;https://git-scm.com/ 点击左边的 Downloads 或者 右边标识的下载标志&#xff0c;它根据电脑操作系统自动匹配版本 Downloads for Windows 2、以 windows 为例下载对应版本 网络有时可能不大好&#xff0c;阿里镜像下载超快。 下载好以后&a…

传统物流机械锁控的痛点与难点深度剖析

在当今全球化和高度竞争的商业环境中&#xff0c;物流行业作为经济发展的重要支撑&#xff0c;其高效、安全的运营至关重要。而物流锁控&#xff0c;作为保障货物在运输和存储过程中安全的关键环节&#xff0c;传统机械物流锁控方式却面临着诸多严峻的挑战&#xff0c;这些问题…

Linux系统服务——【web,http协议,apache服务和nginx服务】(sixteen day)

一、web基础以及http协议 1、web基本概念和常识 前端开发一般用uniapp. 1、Web:为用户提供的一种在互联网上浏览信息的服务&#xff0c;Web 服务是动态的、可交互的、跨平台的和图形化的。 2、Web 服务为用户提供各种互联网服务&#xff0c;这些服务包括信息浏览服务&#xf…

关于使用pagehelper分页插件 进行mybatis 一对多嵌套查询时 查询数量太多 无法达到你想展示的效果的问题 --已解决

1.问题 先来描述一下问题 我有一个商品表 里面嵌套 1.1如下是我的数据库 一个商品对应两个口味对应三个商品轮播图&#xff0b;两个商品描述图 那可不是1*2*2*3 12 就是分页里面的pageSize 为12 时才能显示完这个商品的完整数据 这是我的sql语句 resultMap映射 2.正确做…

【香橙派系列教程】(二)刷机和系统启动

&#xff08;二&#xff09;刷机和系统启动 文章目录 &#xff08;二&#xff09;刷机和系统启动1.刷机2.基于 Windows PC 将 Linux 镜像烧写到 TF 卡的方法3.Debian 和 Ubuntu 系统使用说明4.串口登录系统5.修改登陆密码6.修改网络配置7.SSH登录开发板8.修改开发板内核启动日志…

学习008-02-04-05 Make a List View Editable(使列表视图可编辑)

Make a List View Editable&#xff08;使列表视图可编辑&#xff09; This lesson explains how to make a List View editable. 本课介绍如何使列表视图可编辑。 The instructions below show how to create new objects of the DemoTask type directly in the Task List V…

MSPM0G3507之电赛小车

一、前言 本文没什么技术分享&#xff0c;纯聊天。以下内容均为笔者的浅薄理解&#xff0c;有不对的地方还请多多包涵。 二、相关配置 主控单元&#xff1a;MSPM0G3507SPTR&#xff08;48角&#xff09; 编译环境&#xff1a;Keil5.33、5.39&#xff08;推荐&#xff09;都可 …

一分钟小课堂!电脑怎么录屏?4款热门软件实操指南

在这个信息超多的时代里&#xff0c;学会电脑怎么录屏可真是一门挺有用的技能。不管是你想做教学视频、录下游戏里好玩的瞬间&#xff0c;还是展示一下工作上的步骤&#xff0c;掌握录屏的方法都能让你的分享更直观、更有效率。今天&#xff0c;咱们就来聊聊四款很火的录屏大师…

vue3-环境变量-JavaScript-axio-基础使用-lzstring-字符串压缩-python

文章目录 1.Vue3环境变量1.1.简介1.2.全局变量的引用1.3.package.json文件 2.axio2.1.promise2.2.安装2.3.配置2.3.1.全局 axios 默认值2.3.2.响应信息格式 2.4.Axios的拦截器2.4.1.请求拦截器2.4.2.响应拦截器2.4.3.移除拦截器2.4.4.自定义实例添加拦截器 3.lz-string3.1.java…

Tantivy使用Rust 开发的全文搜索引擎库

一、概述 Tantivy是一个全文搜索引擎库&#xff0c;灵感来自Apache Lucene&#xff0c;用Rust编写。 如果你正在寻找Elasticsearch或Apache Solr的替代品&#xff0c;请查看我们基于Tantivy构建的分布式搜索引擎Quiuckwit。 Tantivy更接近Apache Lucene&#xff0c;而不是E…