From bd973de725838871c1ba4c23ef99d9e4e671e06a Mon Sep 17 00:00:00 2001 From: dzw Date: Sat, 16 May 2020 17:44:00 +0800 Subject: [PATCH] add RS_BLOCK_TABLE --- as3/src/as3/com/d_project/qrcode/QRCode.as | 961 ++++++++++---------- as3/src/as3/com/d_project/qrcode/QRUtil.as | 184 ++-- as3/src/as3/com/d_project/qrcode/RSBlock.as | 310 +++++-- 3 files changed, 834 insertions(+), 621 deletions(-) diff --git a/as3/src/as3/com/d_project/qrcode/QRCode.as b/as3/src/as3/com/d_project/qrcode/QRCode.as index a72e5d1..71b4baa 100644 --- a/as3/src/as3/com/d_project/qrcode/QRCode.as +++ b/as3/src/as3/com/d_project/qrcode/QRCode.as @@ -1,5 +1,7 @@ package com.d_project.qrcode { - + import flash.display.BitmapData; + import flash.geom.Rectangle; + /** * QRコード. *
@@ -9,66 +11,66 @@ package com.d_project.qrcode { *
  • make() を呼び出してQRコードを作成します。
  • *
  • getModuleCount() と isDark() で、QRコードのデータを取得します。
  • * - * @author Kazuhiko Arase + * @author Kazuhiko Arase */ public class QRCode { - - private static const PAD0 : int = 0xEC; - - private static const PAD1 : int = 0x11; - - private var typeNumber : int; - - private var modules : Array; - - private var moduleCount : int; - - private var errorCorrectLevel : int; - - private var qrDataList : Array; - - /** + + private static const PAD0:int = 0xEC; + + private static const PAD1:int = 0x11; + + private var typeNumber:int; + + private var modules:Array; + + private var moduleCount:int; + + private var errorCorrectLevel:int; + + private var qrDataList:Array; + + /** * コンストラクタ *
    型番1, 誤り訂正レベルH のQRコードのインスタンスを生成します。 * @see ErrorCorrectLevel */ - public function QRCode() { - this.typeNumber = 1; - this.errorCorrectLevel = ErrorCorrectLevel.H; - this.qrDataList = new Array(); - } - + public function QRCode() { + this.typeNumber = 1; + this.errorCorrectLevel = ErrorCorrectLevel.H; + this.qrDataList = new Array(); + } + /** * 型番を取得する。 * @return 型番 */ - public function getTypeNumber() : int { - return typeNumber; - } - + public function getTypeNumber():int { + return typeNumber; + } + /** * 型番を設定する。 * @param typeNumber 型番 */ - public function setTypeNumber(typeNumber : int) : void { - this.typeNumber = typeNumber; - } - + public function setTypeNumber(typeNumber:int):void { + this.typeNumber = typeNumber; + } + /** * 誤り訂正レベルを取得する。 * @return 誤り訂正レベル * @see ErrorCorrectLevel */ - public function getErrorCorrectLevel() : int { + public function getErrorCorrectLevel():int { return errorCorrectLevel; } - + /** * 誤り訂正レベルを設定する。 * @param errorCorrectLevel 誤り訂正レベル * @see ErrorCorrectLevel */ - public function setErrorCorrectLevel(errorCorrectLevel : int) : void { + public function setErrorCorrectLevel(errorCorrectLevel:int):void { this.errorCorrectLevel = errorCorrectLevel; } @@ -78,473 +80,474 @@ package com.d_project.qrcode { * @param mode モード * @see Mode */ - public function addData(data : String, mode : int = 0) : void { + public function addData(data:String, mode:int = 0):void { if (mode == Mode.MODE_AUTO) { mode = QRUtil.getMode(data); } - switch(mode) { - - case Mode.MODE_NUMBER : - addQRData(new QRNumber(data) ); - break; - - case Mode.MODE_ALPHA_NUM : - addQRData(new QRAlphaNum(data) ); - break; - - case Mode.MODE_8BIT_BYTE : - addQRData(new QR8BitByte(data) ); - break; - - case Mode.MODE_KANJI : - addQRData(new QRKanji(data) ); - break; - - default : - throw new Error("mode:" + mode); - } - } - + switch (mode) { + + case Mode.MODE_NUMBER : + addQRData(new QRNumber(data)); + break; + + case Mode.MODE_ALPHA_NUM : + addQRData(new QRAlphaNum(data)); + break; + + case Mode.MODE_8BIT_BYTE : + addQRData(new QR8BitByte(data)); + break; + + case Mode.MODE_KANJI : + addQRData(new QRKanji(data)); + break; + + default : + throw new Error("mode:" + mode); + } + } + /** * データをクリアする。 *
    addData で追加されたデータをクリアします。 */ - public function clearData() : void { - qrDataList = new Array(); - } - - private function addQRData(qrData : QRData) : void { - qrDataList.push(qrData); - } - - private function getQRDataCount() : int { - return qrDataList.length; - } - - private function getQRData(index : int) : QRData { - return qrDataList[index]; - } - - /** - * 暗モジュールかどうかを取得する。 + public function clearData():void { + qrDataList = new Array(); + } + + private function addQRData(qrData:QRData):void { + qrDataList.push(qrData); + } + + private function getQRDataCount():int { + return qrDataList.length; + } + + private function getQRData(index:int):QRData { + return qrDataList[index]; + } + + /** + * 暗モジュールかどうかを取得する。 * @param row 行 (0 ~ モジュール数 - 1) * @param col 列 (0 ~ モジュール数 - 1) - */ - public function isDark(row : int, col : int) : Boolean { - if (modules[row][col] != null) { - return modules[row][col]; - } else { - return false; - } - } - - /** - * モジュール数を取得する。 - */ - public function getModuleCount() : int { - return moduleCount; - } - - /** - * QRコードを作成する。 - */ - public function make() : void { - makeImpl(false, getBestMaskPattern() ); - } - - private function getBestMaskPattern() : int { - - var minLostPoint : int = 0; - var pattern : int = 0; - - for (var i : int = 0; i < 8; i++) { - - makeImpl(true, i); - - var lostPoint : int = QRUtil.getLostPoint(this); - - if (i == 0 || minLostPoint > lostPoint) { - minLostPoint = lostPoint; - pattern = i; - } - } - - return pattern; - } - - /** - * - */ - private function makeImpl(test : Boolean, maskPattern : int) : void { - - // モジュール初期化 - moduleCount = typeNumber * 4 + 17; - modules = new Array(moduleCount); - for (var i : int = 0; i < moduleCount; i++) { - modules[i] = new Array(moduleCount); - } - - // 位置検出パターン及び分離パターンを設定 - setupPositionProbePattern(0, 0); - setupPositionProbePattern(moduleCount - 7, 0); - setupPositionProbePattern(0, moduleCount - 7); - - setupPositionAdjustPattern(); - setupTimingPattern(); - - setupTypeInfo(test, maskPattern); - - if (typeNumber >= 7) { - setupTypeNumber(test); - } - - var dataArray : Array = qrDataList; - var data : Array = createData(typeNumber, errorCorrectLevel, dataArray); - - mapData(data, maskPattern); - } - - private function mapData(data : Array, maskPattern : int) : void { - - var inc : int = -1; - var row : int = moduleCount - 1; - var bitIndex : int = 7; - var byteIndex : int = 0; - - for (var col : int = moduleCount - 1; col > 0; col -= 2) { - - if (col == 6) col--; - - while (true) { - - for (var c : int = 0; c < 2; c++) { - - if (modules[row][col - c] == null) { - - var dark : Boolean = false; - - if (byteIndex < data.length) { - dark = ( ( (data[byteIndex] >>> bitIndex) & 1) == 1); - } - - var mask : Boolean = QRUtil.getMask(maskPattern, row, col - c); - - if (mask) { - dark = !dark; - } - - modules[row][col - c] = (dark); - bitIndex--; - - if (bitIndex == -1) { - byteIndex++; - bitIndex = 7; - } - } - } - - row += inc; - - if (row < 0 || moduleCount <= row) { - row -= inc; - inc = -inc; - break; - } - } - } - - } - - /** - * 位置合わせパターンを設定 - */ - private function setupPositionAdjustPattern() : void { - - var pos : Array = QRUtil.getPatternPosition(typeNumber); - - for (var i : int = 0; i < pos.length; i++) { - - for (var j : int = 0; j < pos.length; j++) { - - var row : int = pos[i]; - var col : int = pos[j]; - - if (modules[row][col] != null) { - continue; - } - - for (var r : int = -2; r <= 2; r++) { - - for (var c : int = -2; c <= 2; c++) { - - if (r == -2 || r == 2 || c == -2 || c == 2 - || (r == 0 && c == 0) ) { - modules[row + r][col + c] = (true); - } else { - modules[row + r][col + c] = (false); - } - } - } - - } - } - } - - /** - * 位置検出パターンを設定 - */ - private function setupPositionProbePattern(row : int, col : int) : void { - - for (var r : int = -1; r <= 7; r++) { - - for (var c : int = -1; c <= 7; c++) { - - if (row + r <= -1 || moduleCount <= row + r - || col + c <= -1 || moduleCount <= col + c) { - continue; - } - - if ( (0 <= r && r <= 6 && (c == 0 || c == 6) ) - || (0 <= c && c <= 6 && (r == 0 || r == 6) ) - || (2 <= r && r <= 4 && 2 <= c && c <= 4) ) { - modules[row + r][col + c] = (true); - } else { - modules[row + r][col + c] = (false); - } - } - } - } - - /** - * タイミングパターンを設定 - */ - private function setupTimingPattern() : void { - for (var r : int = 8; r < moduleCount - 8; r++) { - if (modules[r][6] != null) { - continue; - } - modules[r][6] = (r % 2 == 0); - } - for (var c : int = 8; c < moduleCount - 8; c++) { - if (modules[6][c] != null) { - continue; - } - modules[6][c] = (c % 2 == 0); - } - } - - /** - * 型番を設定 - */ - private function setupTypeNumber(test : Boolean) : void { - - var bits : int = QRUtil.getBCHTypeNumber(typeNumber); - var i : int; - var mod : Boolean; - - for (i = 0; i < 18; i++) { - mod = (!test && ( (bits >> i) & 1) == 1); - modules[Math.floor(i / 3)][i % 3 + moduleCount - 8 - 3] = mod; - } - - for (i = 0; i < 18; i++) { - mod = (!test && ( (bits >> i) & 1) == 1); - modules[i % 3 + moduleCount - 8 - 3][Math.floor(i / 3)] = mod; - } - } - - /** - * 形式情報を設定 - */ - private function setupTypeInfo(test : Boolean, maskPattern : int) : void { - - var data : int = (errorCorrectLevel << 3) | maskPattern; - var bits : int = QRUtil.getBCHTypeInfo(data); - var i : int; - var mod : Boolean; - - // 縦方向 - for (i = 0; i < 15; i++) { - - mod = (!test && ( (bits >> i) & 1) == 1); - - if (i < 6) { - modules[i][8] = mod; - } else if (i < 8) { - modules[i + 1][8] = mod; - } else { - modules[moduleCount - 15 + i][8] = mod; - } - } - - // 横方向 - for (i = 0; i < 15; i++) { - - mod = (!test && ( (bits >> i) & 1) == 1); - - if (i < 8) { - modules[8][moduleCount - i - 1] = mod; - } else if (i < 9) { - modules[8][15 - i - 1 + 1] = mod; - } else { - modules[8][15 - i - 1] = mod; - } - } - - // 固定 - modules[moduleCount - 8][8] = (!test); - - } - - private static function createData(typeNumber : int, errorCorrectLevel : int, dataArray : Array) : Array { - - var rsBlocks : Array = RSBlock.getRSBlocks(typeNumber, errorCorrectLevel); - var buffer : BitBuffer = new BitBuffer(); - var i : int; - - for (i = 0; i < dataArray.length; i++) { - var data : QRData = dataArray[i]; - buffer.put(data.getMode(), 4); - buffer.put(data.getLength(), data.getLengthInBits(typeNumber) ); - data.write(buffer); - } - - // 最大データ数を計算 - var totalDataCount : int = 0; - for (i = 0; i < rsBlocks.length; i++) { - totalDataCount += rsBlocks[i].getDataCount(); - } - - if (buffer.getLengthInBits() > totalDataCount * 8) { - throw new Error("code length overflow. (" - + buffer.getLengthInBits() - + ">" - + totalDataCount * 8 - + ")"); - } - - // 終端コード - if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) { - buffer.put(0, 4); - } - - // padding - while (buffer.getLengthInBits() % 8 != 0) { - buffer.putBit(false); - } - - // padding - while (true) { - - if (buffer.getLengthInBits() >= totalDataCount * 8) { - break; - } - buffer.put(PAD0, 8); - - if (buffer.getLengthInBits() >= totalDataCount * 8) { - break; - } - buffer.put(PAD1, 8); - } - - return createBytes(buffer, rsBlocks); - } - - private static function createBytes(buffer : BitBuffer, rsBlocks : Array) : Array { - - var offset : int = 0; - - var maxDcCount : int = 0; - var maxEcCount : int = 0; - - var dcdata : Array = new Array(rsBlocks.length); - var ecdata : Array = new Array(rsBlocks.length); - - var i : int; - var r : int; - - for (r = 0; r < rsBlocks.length; r++) { - - var dcCount : int = rsBlocks[r].getDataCount(); - var ecCount : int = rsBlocks[r].getTotalCount() - dcCount; - - maxDcCount = Math.max(maxDcCount, dcCount); - maxEcCount = Math.max(maxEcCount, ecCount); - - dcdata[r] = new Array(dcCount); - for (i = 0; i < dcdata[r].length; i++) { - dcdata[r][i] = 0xff & buffer.getBuffer()[i + offset]; - } - offset += dcCount; - - var rsPoly : Polynomial = QRUtil.getErrorCorrectPolynomial(ecCount); - var rawPoly : Polynomial = new Polynomial(dcdata[r], rsPoly.getLength() - 1); - - var modPoly : Polynomial = rawPoly.mod(rsPoly); - ecdata[r] = new Array(rsPoly.getLength() - 1); - for (i = 0; i < ecdata[r].length; i++) { - var modIndex : int = i + modPoly.getLength() - ecdata[r].length; - ecdata[r][i] = (modIndex >= 0)? modPoly.getAt(modIndex) : 0; - } - - } - - var totalCodeCount : int = 0; - for (i = 0; i < rsBlocks.length; i++) { - totalCodeCount += rsBlocks[i].getTotalCount(); - } - - var data : Array = new Array(totalCodeCount); - - var index : int = 0; - - for (i = 0; i < maxDcCount; i++) { - for (r = 0; r < rsBlocks.length; r++) { - if (i < dcdata[r].length) { - data[index++] = dcdata[r][i]; - } - } - } - - for (i = 0; i < maxEcCount; i++) { - for (r = 0; r < rsBlocks.length; r++) { - if (i < ecdata[r].length) { - data[index++] = ecdata[r][i]; - } - } - } - - return data; - - } - + */ + public function isDark(row:int, col:int):Boolean { + if (modules[row][col] != null) { + return modules[row][col]; + } else { + return false; + } + } + + /** + * モジュール数を取得する。 + */ + public function getModuleCount():int { + return moduleCount; + } + + /** + * QRコードを作成する。 + */ + public function make():void { + makeImpl(false, getBestMaskPattern()); + } + + private function getBestMaskPattern():int { + + var minLostPoint:int = 0; + var pattern:int = 0; + + for (var i:int = 0; i < 8; i++) { + + makeImpl(true, i); + + var lostPoint:int = QRUtil.getLostPoint(this); + + if (i == 0 || minLostPoint > lostPoint) { + minLostPoint = lostPoint; + pattern = i; + } + } + + return pattern; + } + + /** + * + */ + private function makeImpl(test:Boolean, maskPattern:int):void { + + // モジュール初期化 + moduleCount = typeNumber * 4 + 17; + modules = new Array(moduleCount); + for (var i:int = 0; i < moduleCount; i++) { + modules[i] = new Array(moduleCount); + } + + // 位置検出パターン及び分離パターンを設定 + setupPositionProbePattern(0, 0); + setupPositionProbePattern(moduleCount - 7, 0); + setupPositionProbePattern(0, moduleCount - 7); + + setupPositionAdjustPattern(); + setupTimingPattern(); + + setupTypeInfo(test, maskPattern); + + if (typeNumber >= 7) { + setupTypeNumber(test); + } + + var dataArray:Array = qrDataList; + var data:Array = createData(typeNumber, errorCorrectLevel, dataArray); + + mapData(data, maskPattern); + } + + private function mapData(data:Array, maskPattern:int):void { + + var inc:int = -1; + var row:int = moduleCount - 1; + var bitIndex:int = 7; + var byteIndex:int = 0; + + for (var col:int = moduleCount - 1; col > 0; col -= 2) { + + if (col == 6) col--; + + while (true) { + + for (var c:int = 0; c < 2; c++) { + + if (modules[row][col - c] == null) { + + var dark:Boolean = false; + + if (byteIndex < data.length) { + dark = ( ( (data[byteIndex] >>> bitIndex) & 1) == 1); + } + + var mask:Boolean = QRUtil.getMask(maskPattern, row, col - c); + + if (mask) { + dark = !dark; + } + + modules[row][col - c] = (dark); + bitIndex--; + + if (bitIndex == -1) { + byteIndex++; + bitIndex = 7; + } + } + } + + row += inc; + + if (row < 0 || moduleCount <= row) { + row -= inc; + inc = -inc; + break; + } + } + } + + } + + /** + * 位置合わせパターンを設定 + */ + private function setupPositionAdjustPattern():void { + + var pos:Array = QRUtil.getPatternPosition(typeNumber); + + for (var i:int = 0; i < pos.length; i++) { + + for (var j:int = 0; j < pos.length; j++) { + + var row:int = pos[i]; + var col:int = pos[j]; + + if (modules[row][col] != null) { + continue; + } + + for (var r:int = -2; r <= 2; r++) { + + for (var c:int = -2; c <= 2; c++) { + + if (r == -2 || r == 2 || c == -2 || c == 2 + || (r == 0 && c == 0)) { + modules[row + r][col + c] = (true); + } else { + modules[row + r][col + c] = (false); + } + } + } + + } + } + } + + /** + * 位置検出パターンを設定 + */ + private function setupPositionProbePattern(row:int, col:int):void { + + for (var r:int = -1; r <= 7; r++) { + + for (var c:int = -1; c <= 7; c++) { + + if (row + r <= -1 || moduleCount <= row + r + || col + c <= -1 || moduleCount <= col + c) { + continue; + } + + if ((0 <= r && r <= 6 && (c == 0 || c == 6) ) + || (0 <= c && c <= 6 && (r == 0 || r == 6) ) + || (2 <= r && r <= 4 && 2 <= c && c <= 4)) { + modules[row + r][col + c] = (true); + } else { + modules[row + r][col + c] = (false); + } + } + } + } + + /** + * タイミングパターンを設定 + */ + private function setupTimingPattern():void { + for (var r:int = 8; r < moduleCount - 8; r++) { + if (modules[r][6] != null) { + continue; + } + modules[r][6] = (r % 2 == 0); + } + for (var c:int = 8; c < moduleCount - 8; c++) { + if (modules[6][c] != null) { + continue; + } + modules[6][c] = (c % 2 == 0); + } + } + + /** + * 型番を設定 + */ + private function setupTypeNumber(test:Boolean):void { + + var bits:int = QRUtil.getBCHTypeNumber(typeNumber); + var i:int; + var mod:Boolean; + + for (i = 0; i < 18; i++) { + mod = (!test && ( (bits >> i) & 1) == 1); + modules[Math.floor(i / 3)][i % 3 + moduleCount - 8 - 3] = mod; + } + + for (i = 0; i < 18; i++) { + mod = (!test && ( (bits >> i) & 1) == 1); + modules[i % 3 + moduleCount - 8 - 3][Math.floor(i / 3)] = mod; + } + } + + /** + * 形式情報を設定 + */ + private function setupTypeInfo(test:Boolean, maskPattern:int):void { + + var data:int = (errorCorrectLevel << 3) | maskPattern; + var bits:int = QRUtil.getBCHTypeInfo(data); + var i:int; + var mod:Boolean; + + // 縦方向 + for (i = 0; i < 15; i++) { + + mod = (!test && ( (bits >> i) & 1) == 1); + + if (i < 6) { + modules[i][8] = mod; + } else if (i < 8) { + modules[i + 1][8] = mod; + } else { + modules[moduleCount - 15 + i][8] = mod; + } + } + + // 横方向 + for (i = 0; i < 15; i++) { + + mod = (!test && ( (bits >> i) & 1) == 1); + + if (i < 8) { + modules[8][moduleCount - i - 1] = mod; + } else if (i < 9) { + modules[8][15 - i - 1 + 1] = mod; + } else { + modules[8][15 - i - 1] = mod; + } + } + + // 固定 + modules[moduleCount - 8][8] = (!test); + + } + + private static function createData(typeNumber:int, errorCorrectLevel:int, dataArray:Array):Array { + + var rsBlocks:Array = RSBlock.getRSBlocks(typeNumber, errorCorrectLevel); + var buffer:BitBuffer = new BitBuffer(); + var i:int; + + for (i = 0; i < dataArray.length; i++) { + var data:QRData = dataArray[i]; + buffer.put(data.getMode(), 4); + buffer.put(data.getLength(), data.getLengthInBits(typeNumber)); + data.write(buffer); + } + + // 最大データ数を計算 + var totalDataCount:int = 0; + for (i = 0; i < rsBlocks.length; i++) { + totalDataCount += rsBlocks[i].getDataCount(); + } + + var lengthInBits:int = buffer.getLengthInBits(); + if (lengthInBits > totalDataCount * 8) { + throw new Error("code length overflow. (" + + buffer.getLengthInBits() + + ">" + + totalDataCount * 8 + + ")"); + } + + // 終端コード + if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) { + buffer.put(0, 4); + } + + // padding + while (buffer.getLengthInBits() % 8 != 0) { + buffer.putBit(false); + } + + // padding + while (true) { + + if (buffer.getLengthInBits() >= totalDataCount * 8) { + break; + } + buffer.put(PAD0, 8); + + if (buffer.getLengthInBits() >= totalDataCount * 8) { + break; + } + buffer.put(PAD1, 8); + } + + return createBytes(buffer, rsBlocks); + } + + private static function createBytes(buffer:BitBuffer, rsBlocks:Array):Array { + + var offset:int = 0; + + var maxDcCount:int = 0; + var maxEcCount:int = 0; + + var dcdata:Array = new Array(rsBlocks.length); + var ecdata:Array = new Array(rsBlocks.length); + + var i:int; + var r:int; + + for (r = 0; r < rsBlocks.length; r++) { + + var dcCount:int = rsBlocks[r].getDataCount(); + var ecCount:int = rsBlocks[r].getTotalCount() - dcCount; + + maxDcCount = Math.max(maxDcCount, dcCount); + maxEcCount = Math.max(maxEcCount, ecCount); + + dcdata[r] = new Array(dcCount); + for (i = 0; i < dcdata[r].length; i++) { + dcdata[r][i] = 0xff & buffer.getBuffer()[i + offset]; + } + offset += dcCount; + + var rsPoly:Polynomial = QRUtil.getErrorCorrectPolynomial(ecCount); + var rawPoly:Polynomial = new Polynomial(dcdata[r], rsPoly.getLength() - 1); + + var modPoly:Polynomial = rawPoly.mod(rsPoly); + ecdata[r] = new Array(rsPoly.getLength() - 1); + for (i = 0; i < ecdata[r].length; i++) { + var modIndex:int = i + modPoly.getLength() - ecdata[r].length; + ecdata[r][i] = (modIndex >= 0) ? modPoly.getAt(modIndex) : 0; + } + + } + + var totalCodeCount:int = 0; + for (i = 0; i < rsBlocks.length; i++) { + totalCodeCount += rsBlocks[i].getTotalCount(); + } + + var data:Array = new Array(totalCodeCount); + + var index:int = 0; + + for (i = 0; i < maxDcCount; i++) { + for (r = 0; r < rsBlocks.length; r++) { + if (i < dcdata[r].length) { + data[index++] = dcdata[r][i]; + } + } + } + + for (i = 0; i < maxEcCount; i++) { + for (r = 0; r < rsBlocks.length; r++) { + if (i < ecdata[r].length) { + data[index++] = ecdata[r][i]; + } + } + } + + return data; + + } + /** * 最小の型番となる QRCode を作成する。 * @param data データ * @param errorCorrectLevel 誤り訂正レベル */ - public static function getMinimumQRCode(data : String, errorCorrectLevel : int) : QRCode { - - var mode : int = QRUtil.getMode(data); - - var qr : QRCode = new QRCode(); + public static function getMinimumQRCode(data:String, errorCorrectLevel:int):QRCode { + + var mode:int = QRUtil.getMode(data); + + var qr:QRCode = new QRCode(); qr.setErrorCorrectLevel(errorCorrectLevel); qr.addData(data, mode); - - var length : int = qr.getQRData(0).getLength(); - - for (var typeNumber : int = 1; typeNumber <= 10; typeNumber++) { - if (length <= QRUtil.getMaxLength(typeNumber, mode, errorCorrectLevel) ) { + + var length:int = qr.getQRData(0).getLength(); + for (var typeNumber:int = 1; typeNumber <= 40; typeNumber++) { + if (length <= QRUtil.getMaxLength(typeNumber, mode, errorCorrectLevel)) { qr.setTypeNumber(typeNumber); break; } - } - + } + qr.make(); - + return qr; } + } } \ No newline at end of file diff --git a/as3/src/as3/com/d_project/qrcode/QRUtil.as b/as3/src/as3/com/d_project/qrcode/QRUtil.as index 99e7d52..176fd9f 100644 --- a/as3/src/as3/com/d_project/qrcode/QRUtil.as +++ b/as3/src/as3/com/d_project/qrcode/QRUtil.as @@ -1,17 +1,17 @@ package com.d_project.qrcode { import flash.utils.ByteArray; - + /** * QRUtil - * @author Kazuhiko Arase + * @author Kazuhiko Arase */ internal class QRUtil { - + public static function getJISEncoding() : String { return "shift_jis"; } - + public static function getPatternPosition(typeNumber : int) : Array { return PATTERN_POSITION_TABLE[typeNumber - 1]; } @@ -27,7 +27,7 @@ package com.d_project.qrcode { [6, 24, 42], [6, 26, 46], [6, 28, 50], - [6, 30, 54], + [6, 30, 54], [6, 32, 58], [6, 34, 62], [6, 26, 46, 66], @@ -58,26 +58,56 @@ package com.d_project.qrcode { [6, 26, 54, 82, 110, 138, 166], [6, 30, 58, 86, 114, 142, 170] ]; - + private static var MAX_LENGTH : Array = [ - [ [41, 25, 17, 10], [34, 20, 14, 8], [27, 16, 11, 7], [17, 10, 7, 4] ], - [ [77, 47, 32, 20], [63, 38, 26, 16], [48, 29, 20, 12], [34, 20, 14, 8] ], - [ [127, 77, 53, 32], [101, 61, 42, 26], [77, 47, 32, 20], [58, 35, 24, 15] ], - [ [187, 114, 78, 48], [149, 90, 62, 38], [111, 67, 46, 28], [82, 50, 34, 21] ], - [ [255, 154, 106, 65], [202, 122, 84, 52], [144, 87, 60, 37], [106, 64, 44, 27] ], - [ [322, 195, 134, 82], [255, 154, 106, 65], [178, 108, 74, 45], [139, 84, 58, 36] ], - [ [370, 224, 154, 95], [293, 178, 122, 75], [207, 125, 86, 53], [154, 93, 64, 39] ], - [ [461, 279, 192, 118], [365, 221, 152, 93], [259, 157, 108, 66], [202, 122, 84, 52] ], - [ [552, 335, 230, 141], [432, 262, 180, 111], [312, 189, 130, 80], [235, 143, 98, 60] ], - [ [652, 395, 271, 167], [513, 311, 213, 131], [364, 221, 151, 93], [288, 174, 119, 74] ] - ]; - + [[41, 25, 17, 10], [34, 20, 14, 8], [27, 16, 11, 7], [17, 10, 7, 4]],//1 + [[77, 47, 32, 20], [63, 38, 26, 16], [48, 29, 20, 12], [34, 20, 14, 8]],//2 + [[127, 77, 53, 32], [101, 61, 42, 26], [77, 47, 32, 20], [58, 35, 24, 15]],//3 + [[187, 114, 78, 48], [149, 90, 62, 38], [111, 67, 46, 28], [82, 50, 34, 21]],//4 + [[255, 154, 106, 65], [202, 122, 84, 52], [144, 87, 60, 37], [106, 64, 44, 27]],//5 + [[322, 195, 134, 82], [255, 154, 106, 65], [178, 108, 74, 45], [139, 84, 58, 36]],//6 + [[370, 224, 154, 95], [293, 178, 122, 75], [207, 125, 86, 53], [154, 93, 64, 39]],//7 + [[461, 279, 192, 118], [365, 221, 152, 93], [259, 157, 108, 66], [202, 122, 84, 52]],//8 + [[552, 335, 230, 141], [432, 262, 180, 111], [312, 189, 130, 80], [235, 143, 98, 60]],//9 + [[652, 395, 271, 167], [513, 311, 213, 131], [364, 221, 151, 93], [288, 174, 119, 74]],//10 + [[772, 468, 321, 198], [604, 366, 251, 155], [427, 259, 177, 109], [331, 200, 137, 85]],//11 + [[883, 535, 367, 226], [691, 419, 287, 177], [489, 296, 203, 125], [374, 227, 155, 96]],//12 + [[1022, 619, 425, 262], [796, 483, 331, 204], [580, 352, 241, 149], [427, 259, 177, 109]],//13 + [[1101, 667, 458, 282], [871, 528, 362, 223], [621, 376, 258, 159], [468, 283, 194, 120]],//14 + [[1250, 758, 520, 320], [991, 600, 412, 254], [703, 426, 292, 180], [530, 321, 220, 136]],//15 + [[1408, 854, 586, 361], [1082, 656, 450, 277], [775, 470, 322, 198], [602, 365, 250, 154]],//16 + [[1548, 938, 644, 397], [1212, 734, 504, 310], [876, 531, 364, 224], [674, 408, 280, 173]],//17 + [[1725, 1046, 718, 442], [1346, 816, 560, 345], [948, 574, 394, 243], [746, 452, 310, 191]],//18 + [[1903, 1153, 792, 488], [1500, 909, 624, 384], [1063, 644, 442, 272], [813, 493, 338, 208]],//19 + [[2061, 1249, 858, 528], [1600, 970, 666, 410], [1159, 702, 482, 297], [919, 557, 382, 235]],//20 + [[2232, 1352, 929, 572], [1708, 1035, 711, 438], [1224, 742, 509, 314], [969, 587, 403, 248]],//21 + [[2409, 1460, 1003, 618], [1872, 1134, 779, 480], [1358, 823, 565, 348], [1056, 640, 439, 270]],//22 + [[2620, 1588, 1091, 672], [2059, 1248, 857, 528], [1468, 890, 611, 376], [1108, 672, 461, 284]],//23 + [[2812, 1704, 1171, 721], [2188, 1326, 911, 561], [1588, 963, 661, 407], [1228, 744, 511, 315]],//24 + [[3057, 1853, 1273, 784], [2395, 1451, 997, 614], [1718, 1041, 715, 440], [1286, 779, 535, 330]],//25 + [[3283, 1990, 1367, 842], [2544, 1542, 1059, 652], [1804, 1094, 751, 462], [1425, 864, 593, 365]],//26 + [[3517, 2132, 1465, 902], [2701, 1637, 1125, 692], [1933, 1172, 805, 496], [1501, 910, 625, 385]],//27 + [[3669, 2223, 1528, 940], [2857, 1732, 1190, 732], [2085, 1263, 868, 534], [1581, 958, 658, 405]],//28 + [[3909, 2369, 1628, 1002], [3035, 1839, 1264, 778], [2181, 1322, 908, 559], [1677, 1016, 698, 430]],//29 + [[4158, 2520, 1732, 1066], [3289, 1994, 1370, 843], [2358, 1429, 982, 604], [1782, 1080, 742, 457]],//30 + [[4417, 2677, 1840, 1132], [3486, 2113, 1452, 894], [2473, 1499, 1030, 634], [1897, 1150, 790, 486]],//31 + [[4686, 2840, 1952, 1201], [3693, 2238, 1538, 947], [2670, 1618, 1112, 684], [2022, 1226, 842, 518]],//32 + [[4965, 3009, 2068, 1273], [3909, 2369, 1628, 1002], [2805, 1700, 1168, 719], [2157, 1307, 898, 553]],//33 + [[5253, 3183, 2188, 1347], [4134, 2506, 1722, 1060], [2949, 1787, 1228, 756], [2301, 1394, 958, 590]],//34 + [[5529, 3351, 2303, 1417], [4343, 2632, 1809, 1113], [3081, 1867, 1283, 790], [2361, 1431, 983, 605]],//35 + [[5836, 3537, 2431, 1496], [4588, 2780, 1911, 1176], [3244, 1966, 1351, 832], [2524, 1530, 1051, 647]],//36 + [[6153, 3729, 2563, 1577], [4775, 2894, 1989, 1224], [3417, 2071, 1423, 876], [2625, 1591, 1093, 673]],//37 + [[6479, 3927, 2699, 1661], [5039, 3054, 2099, 1292], [3599, 2181, 1499, 923], [2735, 1658, 1139, 701]],//38 + [[6743, 4087, 2809, 1729], [5313, 3220, 2213, 1362], [3791, 2298, 1579, 972], [2927, 1774, 1219, 750]],//39 + [[7089, 4296, 2953, 1817], [5596, 3391, 2331, 1435], [3993, 2420, 1663, 1024], [3057, 1852, 1273, 784]],//40 + ]; + public static function getMaxLength(typeNumber : int, mode : int, errorCorrectLevel : int) : int { - + var t : int = typeNumber - 1; var e : int = 0; var m : int = 0; - + switch(errorCorrectLevel) { case ErrorCorrectLevel.L : e = 0; break; case ErrorCorrectLevel.M : e = 1; break; @@ -86,7 +116,7 @@ package com.d_project.qrcode { default : throw new Error("e:" + errorCorrectLevel); } - + switch(mode) { case Mode.MODE_NUMBER : m = 0; break; case Mode.MODE_ALPHA_NUM : m = 1; break; @@ -95,32 +125,32 @@ package com.d_project.qrcode { default : throw new Error("m:" + mode); } - + return MAX_LENGTH[t][e][m]; } - - + + /** * エラー訂正多項式を取得する。 */ public static function getErrorCorrectPolynomial(errorCorrectLength : int) : Polynomial{ - + var a : Polynomial = new Polynomial([1]); - + for (var i : int = 0; i < errorCorrectLength; i++) { a = a.multiply(new Polynomial([1, QRMath.gexp(i)]) ); } - + return a; } - + /** * 指定されたパターンのマスクを取得する。 */ public static function getMask(maskPattern : int, i : int, j : int) : Boolean { - + switch (maskPattern) { - + case MaskPattern.PATTERN000 : return (i + j) % 2 == 0; case MaskPattern.PATTERN001 : return i % 2 == 0; case MaskPattern.PATTERN010 : return j % 3 == 0; @@ -129,63 +159,63 @@ package com.d_project.qrcode { case MaskPattern.PATTERN101 : return (i * j) % 2 + (i * j) % 3 == 0; case MaskPattern.PATTERN110 : return ( (i * j) % 2 + (i * j) % 3) % 2 == 0; case MaskPattern.PATTERN111 : return ( (i * j) % 3 + (i + j) % 2) % 2 == 0; - + default : throw new Error("mask:" + maskPattern); } - } - + } + /** * 失点を取得する */ public static function getLostPoint(qrCode : QRCode) : int { - + var moduleCount : int = qrCode.getModuleCount(); - + var lostPoint : int = 0; - + var row : int; var col : int; - + // LEVEL1 - + for (row = 0; row < moduleCount; row++) { - + for (col = 0; col < moduleCount; col++) { - + var sameCount : int = 0; var dark : Boolean = qrCode.isDark(row, col); - + for (var r : int = -1; r <= 1; r++) { - + if (row + r < 0 || moduleCount <= row + r) { continue; } - + for (var c : int = -1; c <= 1; c++) { - + if (col + c < 0 || moduleCount <= col + c) { continue; } - + if (r == 0 && c == 0) { continue; } - + if (dark == qrCode.isDark(row + r, col + c) ) { sameCount++; } } } - + if (sameCount > 5) { lostPoint += (3 + sameCount - 5); } } } - + // LEVEL2 - + for (row = 0; row < moduleCount - 1; row++) { for (col = 0; col < moduleCount - 1; col++) { var count : int = 0; @@ -198,9 +228,9 @@ package com.d_project.qrcode { } } } - + // LEVEL3 - + for (row = 0; row < moduleCount; row++) { for (col = 0; col < moduleCount - 6; col++) { if (qrCode.isDark(row, col) @@ -214,7 +244,7 @@ package com.d_project.qrcode { } } } - + for (col = 0; col < moduleCount; col++) { for (row = 0; row < moduleCount - 6; row++) { if (qrCode.isDark(row, col) @@ -228,11 +258,11 @@ package com.d_project.qrcode { } } } - + // LEVEL4 - + var darkCount : int = 0; - + for (col = 0; col < moduleCount; col++) { for (row = 0; row < moduleCount; row++) { if (qrCode.isDark(row, col) ) { @@ -240,13 +270,13 @@ package com.d_project.qrcode { } } } - + var ratio : int = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5; lostPoint += ratio * 10; - - return lostPoint; + + return lostPoint; } - + public static function getMode(s : String) : int { if (isAlphaNum(s) ) { if (isNumber(s) ) { @@ -259,7 +289,7 @@ package com.d_project.qrcode { return Mode.MODE_8BIT_BYTE; } } - + private static function isNumber(s : String) : Boolean { for (var i : int = 0; i < s.length; i++) { var c : String = s.charAt(i); @@ -269,7 +299,7 @@ package com.d_project.qrcode { } return true; } - + private static function isAlphaNum(s : String) : Boolean { for (var i : int = 0; i < s.length; i++) { var c : String = s.charAt(i); @@ -279,7 +309,7 @@ package com.d_project.qrcode { } return true; } - + private static function isKanji(s : String) : Boolean { var data : ByteArray = StringUtil.getBytes(s, QRUtil.getJISEncoding() ); @@ -287,59 +317,59 @@ package com.d_project.qrcode { var i : int = 0; while (i + 1 < data.length) { - + var c : int = ( (0xff & data[i]) << 8) | (0xff & data[i + 1]); if (!(0x8140 <= c && c <= 0x9FFC) && !(0xE040 <= c && c <= 0xEBBF) ) { return false; } - + i += 2; } if (i < data.length) { return false; } - + return true; } - + private static const G15 : int = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0); - + private static const G18 : int = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0); - + private static const G15_MASK : int = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1); - + public static function getBCHTypeInfo(data : int) : int { var d : int = data << 10; while (getBCHDigit(d) - getBCHDigit(G15) >= 0) { - d ^= (G15 << (getBCHDigit(d) - getBCHDigit(G15) ) ); + d ^= (G15 << (getBCHDigit(d) - getBCHDigit(G15) ) ); } return ( (data << 10) | d) ^ G15_MASK; } - + public static function getBCHTypeNumber(data : int) : int { var d : int = data << 12; while (getBCHDigit(d) - getBCHDigit(G18) >= 0) { - d ^= (G18 << (getBCHDigit(d) - getBCHDigit(G18) ) ); + d ^= (G18 << (getBCHDigit(d) - getBCHDigit(G18) ) ); } return (data << 12) | d; } - + private static function getBCHDigit(data : int) : int { - + var digit : int = 0; - + while (data != 0) { digit++; data >>>= 1; } - + return digit; - + } } } \ No newline at end of file diff --git a/as3/src/as3/com/d_project/qrcode/RSBlock.as b/as3/src/as3/com/d_project/qrcode/RSBlock.as index c53c5be..6bab4db 100644 --- a/as3/src/as3/com/d_project/qrcode/RSBlock.as +++ b/as3/src/as3/com/d_project/qrcode/RSBlock.as @@ -7,71 +7,251 @@ package com.d_project.qrcode { internal class RSBlock { private static var RS_BLOCK_TABLE : Array = [ - - // L - // M - // Q - // H - - // 1 - [1, 26, 19], - [1, 26, 16], - [1, 26, 13], - [1, 26, 9], - - // 2 - [1, 44, 34], - [1, 44, 28], - [1, 44, 22], - [1, 44, 16], - - // 3 - [1, 70, 55], - [1, 70, 44], - [2, 35, 17], - [2, 35, 13], - - // 4 - [1, 100, 80], - [2, 50, 32], - [2, 50, 24], - [4, 25, 9], - - // 5 - [1, 134, 108], - [2, 67, 43], - [2, 33, 15, 2, 34, 16], - [2, 33, 11, 2, 34, 12], - - // 6 - [2, 86, 68], - [4, 43, 27], - [4, 43, 19], - [4, 43, 15], - - // 7 - [2, 98, 78], - [4, 49, 31], - [2, 32, 14, 4, 33, 15], - [4, 39, 13, 1, 40, 14], - - // 8 - [2, 121, 97], - [2, 60, 38, 2, 61, 39], - [4, 40, 18, 2, 41, 19], - [4, 40, 14, 2, 41, 15], - - // 9 - [2, 146, 116], - [3, 58, 36, 2, 59, 37], - [4, 36, 16, 4, 37, 17], - [4, 36, 12, 4, 37, 13], - - // 10 - [2, 86, 68, 2, 87, 69], - [4, 69, 43, 1, 70, 44], - [6, 43, 19, 2, 44, 20], - [6, 43, 15, 2, 44, 16] + + // L + // M + // Q + // H + + // 1 + [1, 26, 19], + [1, 26, 16], + [1, 26, 13], + [1, 26, 9], + + // 2 + [1, 44, 34], + [1, 44, 28], + [1, 44, 22], + [1, 44, 16], + + // 3 + [1, 70, 55], + [1, 70, 44], + [2, 35, 17], + [2, 35, 13], + + // 4 + [1, 100, 80], + [2, 50, 32], + [2, 50, 24], + [4, 25, 9], + + // 5 + [1, 134, 108], + [2, 67, 43], + [2, 33, 15, 2, 34, 16], + [2, 33, 11, 2, 34, 12], + + // 6 + [2, 86, 68], + [4, 43, 27], + [4, 43, 19], + [4, 43, 15], + + // 7 + [2, 98, 78], + [4, 49, 31], + [2, 32, 14, 4, 33, 15], + [4, 39, 13, 1, 40, 14], + + // 8 + [2, 121, 97], + [2, 60, 38, 2, 61, 39], + [4, 40, 18, 2, 41, 19], + [4, 40, 14, 2, 41, 15], + + // 9 + [2, 146, 116], + [3, 58, 36, 2, 59, 37], + [4, 36, 16, 4, 37, 17], + [4, 36, 12, 4, 37, 13], + + // 10 + [2, 86, 68, 2, 87, 69], + [4, 69, 43, 1, 70, 44], + [6, 43, 19, 2, 44, 20], + [6, 43, 15, 2, 44, 16], + + // 11 + [4, 101, 81], + [1, 80, 50, 4, 81, 51], + [4, 50, 22, 4, 51, 23], + [3, 36, 12, 8, 37, 13], + + // 12 + [2, 116, 92, 2, 117, 93], + [6, 58, 36, 2, 59, 37], + [4, 46, 20, 6, 47, 21], + [7, 42, 14, 4, 43, 15], + + // 13 + [4, 133, 107], + [8, 59, 37, 1, 60, 38], + [8, 44, 20, 4, 45, 21], + [12, 33, 11, 4, 34, 12], + + // 14 + [3, 145, 115, 1, 146, 116], + [4, 64, 40, 5, 65, 41], + [11, 36, 16, 5, 37, 17], + [11, 36, 12, 5, 37, 13], + + // 15 + [5, 109, 87, 1, 110, 88], + [5, 65, 41, 5, 66, 42], + [5, 54, 24, 7, 55, 25], + [11, 36, 12, 7, 37, 13], + + // 16 + [5, 122, 98, 1, 123, 99], + [7, 73, 45, 3, 74, 46], + [15, 43, 19, 2, 44, 20], + [3, 45, 15, 13, 46, 16], + + // 17 + [1, 135, 107, 5, 136, 108], + [10, 74, 46, 1, 75, 47], + [1, 50, 22, 15, 51, 23], + [2, 42, 14, 17, 43, 15], + + // 18 + [5, 150, 120, 1, 151, 121], + [9, 69, 43, 4, 70, 44], + [17, 50, 22, 1, 51, 23], + [2, 42, 14, 19, 43, 15], + + // 19 + [3, 141, 113, 4, 142, 114], + [3, 70, 44, 11, 71, 45], + [17, 47, 21, 4, 48, 22], + [9, 39, 13, 16, 40, 14], + + // 20 + [3, 135, 107, 5, 136, 108], + [3, 67, 41, 13, 68, 42], + [15, 54, 24, 5, 55, 25], + [15, 43, 15, 10, 44, 16], + + // 21 + [4, 144, 116, 4, 145, 117], + [17, 68, 42], + [17, 50, 22, 6, 51, 23], + [19, 46, 16, 6, 47, 17], + + // 22 + [2, 139, 111, 7, 140, 112], + [17, 74, 46], + [7, 54, 24, 16, 55, 25], + [34, 37, 13], + + // 23 + [4, 151, 121, 5, 152, 122], + [4, 75, 47, 14, 76, 48], + [11, 54, 24, 14, 55, 25], + [16, 45, 15, 14, 46, 16], + + // 24 + [6, 147, 117, 4, 148, 118], + [6, 73, 45, 14, 74, 46], + [11, 54, 24, 16, 55, 25], + [30, 46, 16, 2, 47, 17], + + // 25 + [8, 132, 106, 4, 133, 107], + [8, 75, 47, 13, 76, 48], + [7, 54, 24, 22, 55, 25], + [22, 45, 15, 13, 46, 16], + + // 26 + [10, 142, 114, 2, 143, 115], + [19, 74, 46, 4, 75, 47], + [28, 50, 22, 6, 51, 23], + [33, 46, 16, 4, 47, 17], + + // 27 + [8, 152, 122, 4, 153, 123], + [22, 73, 45, 3, 74, 46], + [8, 53, 23, 26, 54, 24], + [12, 45, 15, 28, 46, 16], + + // 28 + [3, 147, 117, 10, 148, 118], + [3, 73, 45, 23, 74, 46], + [4, 54, 24, 31, 55, 25], + [11, 45, 15, 31, 46, 16], + + // 29 + [7, 146, 116, 7, 147, 117], + [21, 73, 45, 7, 74, 46], + [1, 53, 23, 37, 54, 24], + [19, 45, 15, 26, 46, 16], + + // 30 + [5, 145, 115, 10, 146, 116], + [19, 75, 47, 10, 76, 48], + [15, 54, 24, 25, 55, 25], + [23, 45, 15, 25, 46, 16], + + // 31 + [13, 145, 115, 3, 146, 116], + [2, 74, 46, 29, 75, 47], + [42, 54, 24, 1, 55, 25], + [23, 45, 15, 28, 46, 16], + + // 32 + [17, 145, 115], + [10, 74, 46, 23, 75, 47], + [10, 54, 24, 35, 55, 25], + [19, 45, 15, 35, 46, 16], + + // 33 + [17, 145, 115, 1, 146, 116], + [14, 74, 46, 21, 75, 47], + [29, 54, 24, 19, 55, 25], + [11, 45, 15, 46, 46, 16], + + // 34 + [13, 145, 115, 6, 146, 116], + [14, 74, 46, 23, 75, 47], + [44, 54, 24, 7, 55, 25], + [59, 46, 16, 1, 47, 17], + + // 35 + [12, 151, 121, 7, 152, 122], + [12, 75, 47, 26, 76, 48], + [39, 54, 24, 14, 55, 25], + [22, 45, 15, 41, 46, 16], + + // 36 + [6, 151, 121, 14, 152, 122], + [6, 75, 47, 34, 76, 48], + [46, 54, 24, 10, 55, 25], + [2, 45, 15, 64, 46, 16], + + // 37 + [17, 152, 122, 4, 153, 123], + [29, 74, 46, 14, 75, 47], + [49, 54, 24, 10, 55, 25], + [24, 45, 15, 46, 46, 16], + + // 38 + [4, 152, 122, 18, 153, 123], + [13, 74, 46, 32, 75, 47], + [48, 54, 24, 14, 55, 25], + [42, 45, 15, 32, 46, 16], + + // 39 + [20, 147, 117, 4, 148, 118], + [40, 75, 47, 7, 76, 48], + [43, 54, 24, 22, 55, 25], + [10, 45, 15, 67, 46, 16], + + // 40 + [19, 148, 118, 6, 149, 119], + [18, 75, 47, 31, 76, 48], + [34, 54, 24, 34, 55, 25], + [20, 45, 15, 61, 46, 16] ];