摘要:背景最近接觸到的需求,前端生成一個帶企業(yè)的二維碼,并支持點擊下載它。
背景
最近接觸到的需求,前端生成一個帶企業(yè)logo的二維碼,并支持點擊下載它。
實現(xiàn)在前面的文章有講到如何用 canvas 畫二維碼,在此基礎(chǔ)上再畫一個公司logo,并提供下載的方法供調(diào)用,再封裝成 npm 插件
模塊名稱: qrcode-with-logos
github地址:https://github.com/zxpsuper/qrcode-with-logos
npm地址:https://www.npmjs.com/package/qrcode-with-logos
核心代碼將整個封裝成一個 QrCodeWithLogo類,并提供三個方法:
interface IQrCodeWithLogo { toCanvas(): Promise1. toCanvas(); toImage(): Promise ; downloadImage(name: string): void; } class QrCodeWithLogo implements IQrCodeWithLogo { option: BaseOptions; constructor(option: BaseOptions) { this.option = option; return this; } toCanvas = () => { return toCanvas.call(this, this.option); }; toImage = () => { return toImage.call(this, this.option); }; downloadImage = (name: string) => { saveImage(this.option.image, name); }; }
此方法用到了庫qrcode的toCanvas方法
export const toCanvas = (options: BaseOptions) => { return renderQrCode(options) .then(() => options) .then(drawLogo); };
這里先用qrcode庫畫出二維碼的canvas
import QRCode = require("qrcode"); const toCanvas = promisify(QRCode.toCanvas); export const renderQrCode = ({ canvas, content, width = 0, nodeQrCodeOptions = {} }: BaseOptions) => { // 容錯率,默認對內(nèi)容少的二維碼采用高容錯率,內(nèi)容多的二維碼采用低容錯率 // according to the content length to choose different errorCorrectionLevel nodeQrCodeOptions.errorCorrectionLevel = nodeQrCodeOptions.errorCorrectionLevel || getErrorCorrectionLevel(content); return getOriginWidth(content, nodeQrCodeOptions).then((_width: number) => { // 得到原始比例后還原至設(shè)定值,再放大4倍以獲取高清圖 // Restore to the set value according to the original ratio, and then zoom in 4 times to get the HD image. nodeQrCodeOptions.scale = width === 0 ? undefined : (width / _width) * 4; // @ts-ignore return toCanvas(canvas, content, nodeQrCodeOptions); }); };
promisify()是封裝的一個方法,用于減少return promise時的代碼,方便書寫
export const promisify = (f: Function): Function => { return function() { const args = Array.prototype.slice.call(arguments); return new Promise(function(resolve, reject) { args.push(function(err: object, result: object) { if (err) reject(err); else resolve(result); }); f.apply(null, args); }); }; };
畫出canvas,緊接著判斷是否有l(wèi)ogo, 如果有就畫logo,這里有兩種模式:
一種是直接畫圖 ctx.drawImage(image, logoXY, logoXY, logoWidth, logoWidth);,可拓展性不強。
一種是canvas疊加,使用 ctx.createPattern(canvasImage, "no-repeat"); 可以實現(xiàn)更多復(fù)雜的效果
export const drawLogo = ({ canvas, content, logo }: BaseOptions) => { if (!logo) { return; } // @ts-ignore const canvasWidth = canvas.width; const { logoSize = 0.15, borderColor = "#ffffff", bgColor = borderColor || "#ffffff", borderSize = 0.05, crossOrigin, borderRadius = 8, logoRadius = 0 } = logo; let logoSrc = typeof logo === "string" ? logo : logo.src; let logoWidth = canvasWidth * logoSize; let logoXY = (canvasWidth * (1 - logoSize)) / 2; let logoBgWidth = canvasWidth * (logoSize + borderSize); let logoBgXY = (canvasWidth * (1 - logoSize - borderSize)) / 2; // @ts-ignore const ctx = canvas.getContext("2d"); // logo 底色, draw logo background color canvasRoundRect(ctx)( logoBgXY, logoBgXY, logoBgWidth, logoBgWidth, borderRadius ); ctx.fillStyle = bgColor; ctx.fill(); // logo const image = new Image(); if (crossOrigin || logoRadius) { image.setAttribute("crossOrigin", crossOrigin || "anonymous"); } image.src = logoSrc; // 使用image繪制可以避免某些跨域情況 // Use image drawing to avoid some cross-domain situations const drawLogoWithImage = (image: any) => { ctx.drawImage(image, logoXY, logoXY, logoWidth, logoWidth); }; // 使用canvas繪制以獲得更多的功能 // Use canvas to draw more features, such as borderRadius const drawLogoWithCanvas = (image: any) => { const canvasImage = document.createElement("canvas"); canvasImage.width = logoXY + logoWidth; canvasImage.height = logoXY + logoWidth; canvasImage .getContext("2d") .drawImage(image, logoXY, logoXY, logoWidth, logoWidth); canvasRoundRect(ctx)(logoXY, logoXY, logoWidth, logoWidth, logoRadius); ctx.fillStyle = ctx.createPattern(canvasImage, "no-repeat"); ctx.fill(); }; // 將 logo繪制到 canvas上 // Draw the logo on the canvas return new Promise((resolve, reject) => { image.onload = () => { logoRadius ? drawLogoWithCanvas(image) : drawLogoWithImage(image); resolve(); }; }); };2. toImage()
此方法利用之前的toCanvas()方法,生成canvas后拿到 canvas.toDataURL() 的值,賦給
npm 模塊導(dǎo)入:
import QrCodeWithLogo from "qrcode-with-logos"; let qrcode = new QrCodeWithLogo({ canvas: document.getElementById("canvas"), content: "https://github.com/zxpsuper", width: 380, // download: true, image: document.getElementById("image"), logo: { src: "https://avatars1.githubusercontent.com/u/28730619?s=460&v=4" } }); qrcode.toCanvas().then(() => { qrcode.toImage().then(() => { setTimeout(() => { qrcode.downloadImage("hello world"); }, 2000); }); });
當然你也可以引入使用
That is all.
更多推薦前端進階小書(advanced_front_end)
前端每日一題(daily-question)
webpack4 搭建 Vue 應(yīng)用(createVue)
Canvas 進階(一)二維碼的生成與掃碼識別
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/105208.html
摘要:話不多說,先上和項目源碼有趣的是,在我寫完這篇文章之后,發(fā)現(xiàn)愛編程的李先森也寫了一篇手寫辨色力小游戲?qū)崿F(xiàn)方式有所不同,可以對比下。 1. 背景 之前寫過一篇文章 ES6 手寫一個辨色小游戲, 感覺好玩挺不錯。豈料評論區(qū)大神頻出,其中有人指出,打開控制臺,輸入以下代碼: setInterval( ()=>document.querySelector(#special-block).cli...
摘要:無需任何第三方依賴,輕型工具庫。繪制海報,生成帶的二維碼。默認重新編輯最終圖片壓縮比,默認基礎(chǔ)類型參數(shù)表示一個圖片部分。之間表示一個二維碼部分參數(shù)類型描述指定為二維碼類型要繪制的內(nèi)容。通過控制邊框顏色,默認為默認為容錯等級。 canvas_x 無需任何第三方依賴,輕型工具庫。canvas繪制海報,生成帶logo的二維碼。也可生成編輯界面,用戶自定義輸入,一鍵生成等等 默認開啟圖片跨域,...
摘要:前言月份開始出沒社區(qū),現(xiàn)在差不多月了,按照工作的說法,就是差不多過了三個月的試用期,準備轉(zhuǎn)正了一般來說,差不多到了轉(zhuǎn)正的時候,會進行總結(jié)或者分享會議那么今天我就把看過的一些學(xué)習(xí)資源主要是博客,博文推薦分享給大家。 1.前言 6月份開始出沒社區(qū),現(xiàn)在差不多9月了,按照工作的說法,就是差不多過了三個月的試用期,準備轉(zhuǎn)正了!一般來說,差不多到了轉(zhuǎn)正的時候,會進行總結(jié)或者分享會議!那么今天我就...
閱讀 3553·2021-11-25 09:43
閱讀 3134·2021-10-08 10:04
閱讀 1624·2019-08-26 12:20
閱讀 2052·2019-08-26 12:09
閱讀 595·2019-08-23 18:25
閱讀 3572·2019-08-23 17:54
閱讀 2321·2019-08-23 17:50
閱讀 802·2019-08-23 14:33