UNPKG

@jackybaby/react-custom-qrcode

Version:

React component to generate a QR Code customizable with logo and more properties

268 lines (267 loc) 11.6 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.QRCode = void 0; var isEqual = require("lodash.isequal"); var qrGenerator = require("qrcode-generator"); var React = require("react"); var ReactDOM = require("react-dom"); var QRCode = /** @class */ (function (_super) { __extends(QRCode, _super); function QRCode(props) { var _this = _super.call(this, props) || this; _this.canvas = React.createRef(); return _this; } QRCode.utf16to8 = function (str) { var out = '', i, c; var 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; }; /** * Draw a rounded square in the canvas */ QRCode.prototype.drawRoundedSquare = function (lineWidth, x, y, size, radii, fill, ctx) { ctx.lineWidth = lineWidth; // Adjust coordinates so that the outside of the stroke is aligned to the edges y += lineWidth / 2; x += lineWidth / 2; size -= lineWidth; if (!Array.isArray(radii)) { radii = [radii, radii, radii, radii]; } // Radius should not be greater than half the size or less than zero radii = radii.map(function (r) { r = Math.min(r, size / 2); return (r < 0) ? 0 : r; }); var rTopLeft = radii[0] || 0; var rTopRight = radii[1] || 0; var rBottomRight = radii[2] || 0; var rBottomLeft = radii[3] || 0; ctx.beginPath(); ctx.moveTo(x + rTopLeft, y); ctx.lineTo(x + size - rTopRight, y); if (rTopRight) ctx.quadraticCurveTo(x + size, y, x + size, y + rTopRight); ctx.lineTo(x + size, y + size - rBottomRight); if (rBottomRight) ctx.quadraticCurveTo(x + size, y + size, x + size - rBottomRight, y + size); ctx.lineTo(x + rBottomLeft, y + size); if (rBottomLeft) ctx.quadraticCurveTo(x, y + size, x, y + size - rBottomLeft); ctx.lineTo(x, y + rTopLeft); if (rTopLeft) ctx.quadraticCurveTo(x, y, x + rTopLeft, y); ctx.closePath(); ctx.stroke(); if (fill) { ctx.fill(); } }; /** * Draw a single positional pattern eye. */ QRCode.prototype.drawPositioningPattern = function (ctx, cellSize, offset, row, col, radii, colors) { if (radii === void 0) { radii = [0, 0, 0, 0]; } if (colors === void 0) { colors = ['#000000', '#000000']; } var lineWidth = Math.ceil(cellSize); var radiiOuter; var radiiInner; var fgColor = this.props.fgColor; if (typeof radii !== 'number' && !Array.isArray(radii)) { radiiOuter = radii.outer || 0; radiiInner = radii.inner || 0; } else { radiiOuter = radii; radiiInner = radiiOuter; } var y = (row * cellSize) + offset; var x = (col * cellSize) + offset; var size = cellSize * 7; ctx.strokeStyle = colors[0]; // Outer box this.drawRoundedSquare(lineWidth, x, y, size, radiiOuter, false, ctx); ctx.fillStyle = colors[1]; ctx.strokeStyle = colors[1]; // Inner box size = cellSize * 3; y += cellSize * 2; x += cellSize * 2; this.drawRoundedSquare(lineWidth, x, y, size, radiiInner, true, ctx); }; ; /** * Is this dot inside a positional pattern zone. */ QRCode.prototype.isInPositioninZone = function (col, row, zones) { return zones.some(function (zone) { return (row >= zone.row && row <= zone.row + 7 && col >= zone.col && col <= zone.col + 7); }); }; QRCode.prototype.transformPixelLengthIntoNumberOfCells = function (pixelLength, cellSize) { return pixelLength / cellSize; }; QRCode.prototype.isCoordinateInImage = function (col, row, dWidthLogo, dHeightLogo, dxLogo, dyLogo, cellSize, logoImage) { if (logoImage) { var numberOfCellsMargin = 2; var firstRowOfLogo = this.transformPixelLengthIntoNumberOfCells(dxLogo, cellSize); var firstColumnOfLogo = this.transformPixelLengthIntoNumberOfCells(dyLogo, cellSize); var logoWidthInCells = this.transformPixelLengthIntoNumberOfCells(dWidthLogo, cellSize) - 1; var logoHeightInCells = this.transformPixelLengthIntoNumberOfCells(dHeightLogo, cellSize) - 1; return row >= firstRowOfLogo - numberOfCellsMargin && row <= firstRowOfLogo + logoWidthInCells + numberOfCellsMargin // check rows && col >= firstColumnOfLogo - numberOfCellsMargin && col <= firstColumnOfLogo + logoHeightInCells + numberOfCellsMargin; // check cols } else { return false; } }; QRCode.prototype.shouldComponentUpdate = function (nextProps) { return !isEqual(this.props, nextProps); }; QRCode.prototype.componentDidMount = function () { this.update(); }; QRCode.prototype.componentDidUpdate = function () { this.update(); }; QRCode.prototype.update = function () { var _a = this.props, value = _a.value, ecLevel = _a.ecLevel, enableCORS = _a.enableCORS, size = _a.size, quietZone = _a.quietZone, bgColor = _a.bgColor, fgColor = _a.fgColor, logoImage = _a.logoImage, logoWidth = _a.logoWidth, logoHeight = _a.logoHeight, logoOpacity = _a.logoOpacity, removeQrCodeBehindLogo = _a.removeQrCodeBehindLogo, qrStyle = _a.qrStyle, eyeRadius = _a.eyeRadius, eyeColor = _a.eyeColor; var qrCode = qrGenerator(0, ecLevel); qrCode.addData(QRCode.utf16to8(value)); qrCode.make(); var canvas = ReactDOM.findDOMNode(this.canvas.current); var ctx = canvas.getContext('2d'); var canvasSize = +size + (2 * +quietZone); var length = qrCode.getModuleCount(); var cellSize = size / length; var scale = (window.devicePixelRatio || 1); canvas.height = canvas.width = canvasSize * scale; ctx.scale(scale, scale); ctx.fillStyle = bgColor; ctx.fillRect(0, 0, canvasSize, canvasSize); var offset = +quietZone; var dWidthLogo = logoWidth || size * 0.2; var dHeightLogo = logoHeight || dWidthLogo; var dxLogo = ((size - dWidthLogo) / 2); var dyLogo = ((size - dHeightLogo) / 2); var positioningZones = [ { row: 0, col: 0 }, { row: 0, col: length - 7 }, { row: length - 7, col: 0 }, ]; ctx.strokeStyle = fgColor; if (qrStyle === 'dots') { ctx.fillStyle = fgColor; var radius = cellSize / 2; for (var row = 0; row < length; row++) { for (var col = 0; col < length; col++) { if (qrCode.isDark(row, col) && !this.isInPositioninZone(row, col, positioningZones) && !(removeQrCodeBehindLogo && this.isCoordinateInImage(row, col, dWidthLogo, dHeightLogo, dxLogo, dyLogo, cellSize, logoImage))) { ctx.beginPath(); ctx.arc(Math.round(col * cellSize) + radius + offset, Math.round(row * cellSize) + radius + offset, (radius / 100) * 75, 0, 2 * Math.PI, false); ctx.closePath(); ctx.fill(); } } } } else { for (var row = 0; row < length; row++) { for (var col = 0; col < length; col++) { if (qrCode.isDark(row, col) && !this.isInPositioninZone(row, col, positioningZones) && !(removeQrCodeBehindLogo && this.isCoordinateInImage(row, col, dWidthLogo, dHeightLogo, dxLogo, dyLogo, cellSize, logoImage))) { ctx.fillStyle = fgColor; var w = (Math.ceil((col + 1) * cellSize) - Math.floor(col * cellSize)); var h = (Math.ceil((row + 1) * cellSize) - Math.floor(row * cellSize)); ctx.fillRect(Math.round(col * cellSize) + offset, Math.round(row * cellSize) + offset, w, h); } } } } // Draw positioning patterns for (var i = 0; i < 3; i++) { var _b = positioningZones[i], row = _b.row, col = _b.col; var radii = eyeRadius; var colors = eyeColor; if (Array.isArray(radii)) { radii = radii[i]; } if (typeof radii == 'number') { radii = [radii, radii, radii, radii]; } if (typeof colors == 'string') { colors = [eyeColor, eyeColor]; } this.drawPositioningPattern(ctx, cellSize, offset, row, col, radii, colors); } if (logoImage) { var image_1 = new Image(); if (enableCORS) { image_1.crossOrigin = 'Anonymous'; } image_1.onload = function () { ctx.save(); ctx.globalAlpha = logoOpacity; ctx.drawImage(image_1, dxLogo + offset, dyLogo + offset, dWidthLogo, dHeightLogo); ctx.restore(); }; image_1.src = logoImage; } }; QRCode.prototype.render = function () { var _a; var size = +this.props.size + (2 * +this.props.quietZone); return React.createElement('canvas', { id: (_a = this.props.id) !== null && _a !== void 0 ? _a : 'react-qrcode-logo', height: size, width: size, style: { height: size + 'px', width: size + 'px' }, ref: this.canvas }); }; QRCode.defaultProps = { value: 'https://reactjs.org/', ecLevel: 'M', enableCORS: false, size: 150, quietZone: 10, bgColor: '#FFFFFF', fgColor: '#000000', logoOpacity: 1, removeQrCodeBehindLogo: false, qrStyle: 'squares', eyeRadius: [], eyeColor: [ '#000000', '#000000', ] }; return QRCode; }(React.Component)); exports.QRCode = QRCode;