diff --git a/README.md b/README.md index 5e2d2dc6..148876c6 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,9 @@ var qrcode = new QRCode(document.getElementById("qrcode"), { height: 128, colorDark : "#000000", colorLight : "#ffffff", - correctLevel : QRCode.CorrectLevel.H + correctLevel : QRCode.CorrectLevel.H, + borderWidth:2, + autoAlignment:false, }); ``` diff --git a/qrcode.js b/qrcode.js index 5507c154..7ccfbeab 100644 --- a/qrcode.js +++ b/qrcode.js @@ -3,15 +3,25 @@ * - Using the 'QRCode for Javascript library' * - Fixed dataset of 'QRCode for Javascript library' for support full-spec. * - this library has no dependencies. - * + * * @author davidshimjs * @see http://www.d-project.com/ * @see http://jeromeetienne.github.com/jquery-qrcode/ */ var QRCode; -(function () { - //--------------------------------------------------------------------- +(function (root, factory) { + + /* CommonJS */ + if (typeof exports == 'object') module.exports = factory() + + /* AMD module */ + else if (typeof define == 'function' && define.amd) define(factory) + + /* Global */ + else root.QRCode = factory() + +}(this, function () { //--------------------------------------------------------------------- // QRCode for JavaScript // // Copyright (c) 2009 Kazuhiko Arase @@ -21,7 +31,7 @@ var QRCode; // Licensed under the MIT license: // http://www.opensource.org/licenses/mit-license.php // - // The word "QR Code" is registered trademark of + // The word "QR Code" is registered trademark of // DENSO WAVE INCORPORATED // http://www.denso-wave.com/qrcode/faqpatent-e.html // @@ -150,28 +160,28 @@ var QRCode; QRBitBuffer.prototype={get:function(index){var bufIndex=Math.floor(index/8);return((this.buffer[bufIndex]>>>(7-index%8))&1)==1;},put:function(num,length){for(var i=0;i>>(length-i-1))&1)==1);}},getLengthInBits:function(){return this.length;},putBit:function(bit){var bufIndex=Math.floor(this.length/8);if(this.buffer.length<=bufIndex){this.buffer.push(0);} if(bit){this.buffer[bufIndex]|=(0x80>>>(this.length%8));} this.length++;}};var QRCodeLimitLength=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]]; - + function _isSupportCanvas() { return typeof CanvasRenderingContext2D != "undefined"; } - + // android 2.x doesn't support Data-URI spec function _getAndroid() { var android = false; var sAgent = navigator.userAgent; - + if (/android/i.test(sAgent)) { // android android = true; var aMat = sAgent.toString().match(/android ([0-9]\.[0-9])/i); - + if (aMat && aMat[1]) { android = parseFloat(aMat[1]); } } - + return android; } - + var svgDrawer = (function() { var Drawing = function (el, htOption) { @@ -227,10 +237,10 @@ var QRCode; this._el = el; this._htOption = htOption; }; - + /** * Draw the QRCode - * + * * @param {QRCode} oQRCode */ Drawing.prototype.draw = function (oQRCode) { @@ -240,50 +250,50 @@ var QRCode; var nWidth = Math.floor(_htOption.width / nCount); var nHeight = Math.floor(_htOption.height / nCount); var aHTML = ['']; - + for (var row = 0; row < nCount; row++) { aHTML.push(''); - + for (var col = 0; col < nCount; col++) { aHTML.push(''); } - + aHTML.push(''); } - + aHTML.push('
'); _el.innerHTML = aHTML.join(''); - + // Fix the margin values as real size. var elTable = _el.childNodes[0]; var nLeftMarginTable = (_htOption.width - elTable.offsetWidth) / 2; var nTopMarginTable = (_htOption.height - elTable.offsetHeight) / 2; - + if (nLeftMarginTable > 0 && nTopMarginTable > 0) { - elTable.style.margin = nTopMarginTable + "px " + nLeftMarginTable + "px"; + elTable.style.margin = nTopMarginTable + "px " + nLeftMarginTable + "px"; } }; - + /** * Clear the QRCode */ Drawing.prototype.clear = function () { this._el.innerHTML = ''; }; - + return Drawing; })() : (function () { // Drawing in Canvas function _onMakeImage() { this._elImage.src = this._elCanvas.toDataURL("image/png"); this._elImage.style.display = "block"; - this._elCanvas.style.display = "none"; + this._elCanvas.style.display = "none"; } - + // Android 2.1 bug workaround // http://code.google.com/p/android/issues/detail?id=5141 if (this._android && this._android <= 2.1) { var factor = 1 / window.devicePixelRatio; - var drawImage = CanvasRenderingContext2D.prototype.drawImage; + var drawImage = CanvasRenderingContext2D.prototype.drawImage; CanvasRenderingContext2D.prototype.drawImage = function (image, sx, sy, sw, sh, dx, dy, dw, dh) { if (("nodeName" in image) && /img/i.test(image.nodeName)) { for (var i = arguments.length - 1; i >= 1; i--) { @@ -295,14 +305,14 @@ var QRCode; arguments[3] *= factor; arguments[4] *= factor; } - - drawImage.apply(this, arguments); + + drawImage.apply(this, arguments); }; } - + /** * Check whether the user's browser supports Data URI or not - * + * * @private * @param {Function} fSuccess Occurs if it supports Data URI * @param {Function} fFail Occurs if it doesn't support Data URI @@ -341,22 +351,22 @@ var QRCode; self._fFail.call(self); } }; - + /** * Drawing QRCode by using canvas - * + * * @constructor * @param {HTMLElement} el - * @param {Object} htOption QRCode Options + * @param {Object} htOption QRCode Options */ var Drawing = function (el, htOption) { this._bIsPainted = false; this._android = _getAndroid(); - + this._htOption = htOption; this._elCanvas = document.createElement("canvas"); - this._elCanvas.width = htOption.width; - this._elCanvas.height = htOption.height; + this._elCanvas.width = htOption.width+htOption.borderWidth*2; + this._elCanvas.height = htOption.height+htOption.borderWidth*2; el.appendChild(this._elCanvas); this._el = el; this._oContext = this._elCanvas.getContext("2d"); @@ -367,56 +377,76 @@ var QRCode; this._el.appendChild(this._elImage); this._bSupportDataURI = null; }; - + /** * Draw the QRCode - * - * @param {QRCode} oQRCode + * + * @param {QRCode} oQRCode */ Drawing.prototype.draw = function (oQRCode) { var _elImage = this._elImage; var _oContext = this._oContext; var _htOption = this._htOption; - + var nCount = oQRCode.getModuleCount(); var nWidth = _htOption.width / nCount; var nHeight = _htOption.height / nCount; var nRoundedWidth = Math.round(nWidth); var nRoundedHeight = Math.round(nHeight); + /** + If the data block corresponds exactly to the pixel, there is no need to turn on anti aliasing + */ + var antialiasing=nWidth==nRoundedWidth?false:true; + + + var offset={x:_htOption.borderWidth,y:_htOption.borderWidth}; + + /** + * automatic alignment + */ + if (_htOption.autoAlignment){ + antialiasing=false; + nWidth= Math.floor(_htOption.width / nCount); + nHeight = Math.floor(_htOption.height / nCount); + offset.x=(_htOption.width- nCount*nWidth)/2+_htOption.borderWidth; + offset.y=(_htOption.height- nCount*nHeight)/2+_htOption.borderWidth; + } _elImage.style.display = "none"; this.clear(); - + for (var row = 0; row < nCount; row++) { for (var col = 0; col < nCount; col++) { var bIsDark = oQRCode.isDark(row, col); - var nLeft = col * nWidth; - var nTop = row * nHeight; + var nLeft =offset.x + col * nWidth; + var nTop =offset.y + row * nHeight; _oContext.strokeStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight; - _oContext.lineWidth = 1; - _oContext.fillStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight; + _oContext.lineWidth = 0; + _oContext.fillStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight; _oContext.fillRect(nLeft, nTop, nWidth, nHeight); - - // 안티 앨리어싱 방지 처리 - _oContext.strokeRect( - Math.floor(nLeft) + 0.5, - Math.floor(nTop) + 0.5, - nRoundedWidth, - nRoundedHeight - ); - - _oContext.strokeRect( - Math.ceil(nLeft) - 0.5, - Math.ceil(nTop) - 0.5, - nRoundedWidth, - nRoundedHeight - ); + + if (antialiasing){ + // 안티 앨리어싱 방지 처리 antialiasing + _oContext.strokeRect( + Math.floor(nLeft) + 0.5, + Math.floor(nTop) + 0.5, + nRoundedWidth, + nRoundedHeight + ); + + _oContext.strokeRect( + Math.ceil(nLeft) - 0.5, + Math.ceil(nTop) - 0.5, + nRoundedWidth, + nRoundedHeight + ); + } } } - + this._bIsPainted = true; }; - + /** * Make the image from Canvas if the browser supports Data URI. */ @@ -425,16 +455,16 @@ var QRCode; _safeSetDataURI.call(this, _onMakeImage); } }; - + /** * Return whether the QRCode is painted or not - * + * * @return {Boolean} */ Drawing.prototype.isPainted = function () { return this._bIsPainted; }; - + /** * Clear the QRCode */ @@ -442,7 +472,7 @@ var QRCode; this._oContext.clearRect(0, 0, this._elCanvas.width, this._elCanvas.height); this._bIsPainted = false; }; - + /** * @private * @param {Number} nNumber @@ -451,28 +481,28 @@ var QRCode; if (!nNumber) { return nNumber; } - + return Math.floor(nNumber * 1000) / 1000; }; - + return Drawing; })(); - + /** * Get the type by string length - * + * * @private * @param {String} sText * @param {Number} nCorrectLevel * @return {Number} type */ - function _getTypeNumber(sText, nCorrectLevel) { + function _getTypeNumber(sText, nCorrectLevel) { var nType = 1; var length = _getUTF8Length(sText); - + for (var i = 0, len = QRCodeLimitLength.length; i <= len; i++) { var nLimit = 0; - + switch (nCorrectLevel) { case QRErrorCorrectLevel.L : nLimit = QRCodeLimitLength[i][0]; @@ -487,18 +517,18 @@ var QRCode; nLimit = QRCodeLimitLength[i][3]; break; } - + if (length <= nLimit) { break; } else { nType++; } } - + if (nType > QRCodeLimitLength.length) { throw new Error("Too long data"); } - + return nType; } @@ -506,11 +536,11 @@ var QRCode; var replacedText = encodeURI(sText).toString().replace(/\%[0-9a-fA-F]{2}/g, 'a'); return replacedText.length + (replacedText.length != sText ? 3 : 0); } - + /** * @class QRCode * @constructor - * @example + * @example * new QRCode(document.getElementById("test"), "http://jindo.dev.naver.com/collie"); * * @example @@ -519,7 +549,7 @@ var QRCode; * width : 128, * height : 128 * }); - * + * * oQRCode.clear(); // Clear the QRCode. * oQRCode.makeCode("http://map.naver.com"); // Re-create the QRCode. * @@ -530,31 +560,35 @@ var QRCode; * @param {Number} [vOption.height=256] * @param {String} [vOption.colorDark="#000000"] * @param {String} [vOption.colorLight="#ffffff"] - * @param {QRCode.CorrectLevel} [vOption.correctLevel=QRCode.CorrectLevel.H] [L|M|Q|H] + * @param {QRCode.CorrectLevel} [vOption.correctLevel=QRCode.CorrectLevel.H] [L|M|Q|H] + * @param {Number} [vOption.borderWidth=0] border width of QRCode + * @param {Boolean} [vOption.autoAlignment=false] auto alignment of pixel */ QRCode = function (el, vOption) { this._htOption = { - width : 256, + width : 256, height : 256, typeNumber : 4, colorDark : "#000000", colorLight : "#ffffff", - correctLevel : QRErrorCorrectLevel.H + correctLevel : QRErrorCorrectLevel.M, + borderWidth : 0, + autoAlignment:false, }; - + if (typeof vOption === 'string') { vOption = { text : vOption }; } - + // Overwrites options if (vOption) { for (var i in vOption) { this._htOption[i] = vOption[i]; } } - + if (typeof el == "string") { el = document.getElementById(el); } @@ -562,20 +596,20 @@ var QRCode; if (this._htOption.useSVG) { Drawing = svgDrawer; } - + this._android = _getAndroid(); this._el = el; this._oQRCode = null; this._oDrawing = new Drawing(this._el, this._htOption); - + if (this._htOption.text) { - this.makeCode(this._htOption.text); + this.makeCode(this._htOption.text); } }; - + /** * Make the QRCode - * + * * @param {String} sText link data */ QRCode.prototype.makeCode = function (sText) { @@ -583,15 +617,15 @@ var QRCode; this._oQRCode.addData(sText); this._oQRCode.make(); this._el.title = sText; - this._oDrawing.draw(this._oQRCode); + this._oDrawing.draw(this._oQRCode); this.makeImage(); }; - + /** * Make the Image from Canvas element * - It occurs automatically * - Android below 3 doesn't support Data-URI spec. - * + * * @private */ QRCode.prototype.makeImage = function () { @@ -599,16 +633,19 @@ var QRCode; this._oDrawing.makeImage(); } }; - + /** * Clear the QRCode */ QRCode.prototype.clear = function () { this._oDrawing.clear(); }; - + /** * @name QRCode.CorrectLevel */ QRCode.CorrectLevel = QRErrorCorrectLevel; -})(); + + return QRCode; + +}));