forked from: QR Code sample from http://www.libspark.org/svn/as3/QRCodeReader/trunk/sample/ReadQrCodeSample.as
LOGOSWARE Class Library.
*
* Copyright 2009 (c) LOGOSWARE (http://www.logosware.com) All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*
/**
* Copyright snipsnipsnip ( http://wonderfl.net/user/snipsnipsnip )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/v0LN
*/
// forked from RobotHacker's QR Code sample from http://www.libspark.org/svn/as3/QRCodeReader/trunk/sample/ReadQrCodeSample.as
/**************************************************************************
* LOGOSWARE Class Library.
*
* Copyright 2009 (c) LOGOSWARE (http://www.logosware.com) All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*
**************************************************************************/
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.GradientType;
import flash.display.SimpleButton;
import flash.display.SpreadMethod;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.filters.BlurFilter;
import flash.filters.DropShadowFilter;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.media.Camera;
import flash.media.Video;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.utils.Timer;
/**
* QRコード解析クラスの使用例です
* @author Kenichi UENO
*/
public class ReadQrCodeSample extends Sprite
{
private const SRC_SIZE:int = 320;
private const STAGE_SIZE:int = 350;
private var getQRimage:GetQRimage;
private var qrDecode:QRdecode = new QRdecode();
private var errorView:Sprite;
private var errorText:TextField = new TextField();
private var startView:Sprite;
private var cameraView:Sprite;
private var camera:Camera;
private var video:Video = new Video(SRC_SIZE, SRC_SIZE);
private var freezeImage:Bitmap;
private var blue:Sprite = new Sprite();
private var red:Sprite = new Sprite();
private var blurFilter:BlurFilter = new BlurFilter();
private var resultView:Sprite;
private var textArea:TextField = new TextField();
private var cameraTimer:Timer = new Timer(2000);
private var textArray:Array = ["", "", ""];
/**
* コンストラクタ
*/
public function ReadQrCodeSample():void {
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
errorView = buildErrorView();
cameraTimer.addEventListener(TimerEvent.TIMER, getCamera);
cameraTimer.start();
getCamera();
}
/**
* カメラの接続をチェックします
*/
private function getCamera(e:TimerEvent = null):void{
camera = Camera.getCamera();
this.graphics.clear();
if ( camera == null ) {
this.addChild( errorView );
} else {
cameraTimer.stop();
if ( errorView.parent == this ) {
this.removeChild(errorView);
}
start();
}
}
/**
* スタートボタンを表示
*/
private function start():void {
startView = buildStartView();
this.addChild( startView );
startView.addEventListener(MouseEvent.CLICK, onStart);
}
/**
* 画像解析クラスにカメラ画像を渡し、解析完了イベントを監視します
*/
private function onStart(e:MouseEvent):void {
cameraView = buildCameraView();
resultView = buildResultView();
this.addChild( cameraView );
this.addChild( resultView );
this.removeChild( startView );
resultView.visible = false;
getQRimage = new GetQRimage(video);
getQRimage.addEventListener(QRreaderEvent.QR_IMAGE_READ_COMPLETE, onQrImageReadComplete);
qrDecode.addEventListener(QRdecoderEvent.QR_DECODE_COMPLETE, onQrDecodeComplete);
redTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onRedTimer );
this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
/**
* エラー画面を作成
*/
private function buildErrorView():Sprite {
var sprite:Sprite = new Sprite();
errorText.autoSize = TextFieldAutoSize.LEFT;
errorText.text = "no camera detected.";
errorText.x = 0.5 * (STAGE_SIZE - errorText.width);
errorText.y = 0.5 * (STAGE_SIZE - errorText.height);
errorText.border = true;
errorText.background = true;
sprite.graphics.lineStyle(0);
sprite.graphics.drawPath(Vector.<int>([1, 2, 2, 2, 2, 2, 1, 2]), Vector.<Number>([5, 5, STAGE_SIZE-5, 5, STAGE_SIZE-5, STAGE_SIZE-5, 5, STAGE_SIZE-5, 5, 5, STAGE_SIZE-5, STAGE_SIZE-5, 5, STAGE_SIZE-5, STAGE_SIZE-5, 5]));
sprite.addChild(errorText);
return sprite;
}
/**
* 開始ボタンを作成
*/
private function buildStartView():Sprite {
var sprite:Sprite = new Sprite();
sprite.graphics.beginGradientFill(GradientType.LINEAR, [0xCCCCCC, 0xAAAAAA], [1.0, 1.0], [0, 255], new Matrix(0, 0.03, -0.03, 0, 0, 15));
sprite.graphics.lineStyle(2);
sprite.graphics.drawRoundRect(0, 0, 200, 30, 5);
var btnText:TextField = new TextField();
btnText.autoSize = TextFieldAutoSize.LEFT;
btnText.text = "Click here to start!";
btnText.setTextFormat(new TextFormat(null, 16, null, true));
btnText.selectable = false;
btnText.x = 0.5 * (sprite.width - btnText.width);
btnText.y = 0.5 * (sprite.height - btnText.height);
sprite.addChild(btnText);
sprite.mouseChildren = false;
sprite.buttonMode = true;
sprite.x = 0.5 * (STAGE_SIZE - sprite.width);
sprite.y = 0.5 * (STAGE_SIZE - sprite.height);
return sprite;
}
/**
* カメラの表示部分を作成
*/
private function buildCameraView():Sprite {
camera.setQuality(0, 100);
camera.setMode(SRC_SIZE, SRC_SIZE, 24, true );
video.attachCamera( camera );
var sprite:Sprite = new Sprite();
sprite.graphics.beginGradientFill(GradientType.LINEAR, [0xCCCCCC, 0x999999], [1.0, 1.0], [0, 255], new Matrix(0, 0.1, -0.1, 0, 0, 150));
sprite.graphics.drawRoundRect(0, 0, SRC_SIZE+30, SRC_SIZE+30, 20);
var videoHolder:Sprite = new Sprite();
videoHolder.addChild( video );
videoHolder.x = videoHolder.y = 15;
freezeImage = new Bitmap(new BitmapData(SRC_SIZE, SRC_SIZE));
videoHolder.addChild( freezeImage );
freezeImage.visible = false;
red.graphics.lineStyle(2, 0xFF0000);
red.graphics.drawPath(Vector.<int>([1,2,2,1,2,2,1,2,2,1,2,2]), Vector.<Number>([30,60,30,30,60,30,290,60,290,30,260,30,30,260,30,290,60,290,290,260,290,290,260,290]));
blue.graphics.lineStyle(2, 0x0000FF);
blue.graphics.drawPath(Vector.<int>([1,2,2,1,2,2,1,2,2,1,2,2]), Vector.<Number>([30,60,30,30,60,30,290,60,290,30,260,30,30,260,30,290,60,290,290,260,290,290,260,290]));
sprite.addChild( videoHolder );
sprite.addChild( red );
sprite.addChild( blue );
blue.alpha = 0;
red.x = red.y = 15;
blue.x = blue.y = 15;
return sprite;
}
/**
* 結果表示用Sprite作成
*/
private function buildResultView():Sprite {
var sprite:Sprite = new Sprite();
sprite.graphics.beginGradientFill(GradientType.LINEAR, [0xDDDDEE, 0xBBBBCC], [0.9, 0.9], [0, 255], new Matrix(0, 0.1, -0.1, 0, 0, 150));
sprite.graphics.drawRoundRect(0, 0, 280, 280, 20);
sprite.addChild( textArea );
textArea.width = 250;
textArea.height = 200;
textArea.wordWrap = true;
textArea.multiline = true;
textArea.border = true;
textArea.background = true;
textArea.backgroundColor = 0xFFFFFF;
textArea.x = textArea.y = 15;
var btnText:TextField = new TextField();
btnText.autoSize = TextFieldAutoSize.LEFT;
btnText.text = "CLOSE";
btnText.selectable = false;
var btnSprite:Sprite = new Sprite();
btnSprite.addChild(btnText);
btnSprite.graphics.lineStyle(1);
btnSprite.graphics.beginGradientFill(GradientType.LINEAR, [0xEEEEEE, 0xCCCCCC], [0.9, 0.9], [0, 255], new Matrix(0, 0.01, -0.01, 0, 0, 10));
btnSprite.graphics.drawRoundRect(0, 0, 80, 20, 8);
btnText.x = 0.5 * (btnSprite.width - btnText.width);
btnText.y = 0.5 * (btnSprite.height - btnText.height);
btnSprite.x = 0.5 * ( 280 - 80 );
btnSprite.y = 240;
btnSprite.buttonMode = true;
btnSprite.mouseChildren = false;
btnSprite.addEventListener(MouseEvent.CLICK, onClose);
sprite.addChild( btnSprite );
sprite.addChild( textArea );
sprite.x = sprite.y = 35;
sprite.filters = [new DropShadowFilter(4.0,45,0,0.875)];
return sprite;
}
/**
* 解析を毎フレーム行う
*/
private function onEnterFrame(e: Event):void{
if( camera.currentFPS > 0 ){
getQRimage.process();
}
}
/**
* QRコードを発見したらデコーダーに渡す
*/
private function onQrImageReadComplete(e: QRreaderEvent):void{
qrDecode.setQR(e.data); // QRreaderEvent.data: QRコード配列
qrDecode.startDecode(); // デコード開始
}
/**
* デコードが完了したら結果テキストを表示する
*/
private function onQrDecodeComplete(e: QRdecoderEvent):void {
blue.alpha = 1.0;
redTimer.reset();
redTimer.start();
textArray.shift();
textArray.push( e.data ); // QRdecoderEvent.data: 解析文字列
if ( textArray[0] == textArray[1] && textArray[1] == textArray[2] ) {
textArea.htmlText = e.data;
cameraView.filters = [blurFilter];
redTimer.stop();
freezeImage.bitmapData.draw(video);
freezeImage.visible = true;
this.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
resultView.visible = true;
}
}
/**
* 結果を削除
*/
private function onClose(e: MouseEvent):void {
textArray = ["", "", ""];
freezeImage.visible = false;
redTimer.start();
this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
cameraView.filters = [];
resultView.visible = false;
}
private var redTimer:Timer = new Timer(400, 1);
/**
* ガイドの色を戻す
*/
private function onRedTimer(e:TimerEvent):void {
blue.alpha = 0;
}
}
}
//足りない定義をコピペした
// > svn co http://www.libspark.org/svn/as3/QRCodeReader/trunk/src/com/logosware/
// > cd logosware
// > ruby -ape "$_.gsub!(/^package.*$/, '/* \\0 */') or $_.gsub!(/^(\s*)public class/, '\\1/* public */ internal class') or $_.gsub!(/^(\s*)(import com.logosware.*)$/, '\\1/* \\2 */')" event\*.as utils\*.as utils\QRcode\*.as > hoge.txt
/**************************************************************************
* LOGOSWARE Class Library.
*
* Copyright 2009 (c) LOGOSWARE (http://www.logosware.com) All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*
**************************************************************************/
/* package com.logosware.event */
{
import flash.events.Event;
/**
* QRコードのデコード完了イベントを送出します
*/
/* public */ internal class QRdecoderEvent extends Event
{
// 定数( Class constants )
/**
* デコード完了を通知します。
* @eventType QR_DECODE_COMPLETE
**/
public static const QR_DECODE_COMPLETE:String = "QR_DECODE_COMPLETE";
// プロパティ( Proerties )
/**
* 解析した結果の文字列が格納されます
**/
public var data:String;
/**
* 解析に用いたコード配列が格納されます
**/
public var checkArray:Array;
// コンストラクタ( Constructor )
/**
* コンストラクタ
* @param type イベントタイプ
* @param data 抽出文字列
* @param check 入力したコード
**/
public function QRdecoderEvent(type:String, data:String, check:Array){
super(type);
// 新しいプロパティを設定する
this.data = data;
this.checkArray = check;
}
// Eventからオーバーライドしたメソッド( Overridden Method: Event )
/**
* @private
**/
override public function clone():Event {
return new QRdecoderEvent(type, data, checkArray);
}
}
}/**************************************************************************
* LOGOSWARE Class Library.
*
* Copyright 2009 (c) LOGOSWARE (http://www.logosware.com) All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*
**************************************************************************/
/* package com.logosware.event */
{
import flash.display.BitmapData;
import flash.events.Event;
/**
* QRコード画像の抽出完了イベントを送出します
*/
/* public */ internal class QRreaderEvent extends Event
{
// 定数( Class constants )
/**
* QRコードの抽出完了を通知します。
* @eventType QR_IMAGE_READ_COMPLETE
**/
public static const QR_IMAGE_READ_COMPLETE:String = "QR_IMAGE_READ_COMPLETE";
// プロパティ( Proerties )
/**
* 解析した結果のQRコード画像が格納されます
**/
public var imageData:BitmapData;
/**
* 解析した結果のQRコード画像のビットパターン配列が格納されます
**/
public var data:Array;
/**
* 入力した任意の配列が格納されます(デバッグ用)
**/
public var checkArray:Array;
// コンストラクタ( Constructor )
/**
* コンストラクタ
* @param type イベントタイプ
* @param imageData 抽出したQRコード画像
* @param data 抽出したQRコードのビット列
* @param check 入力した任意のコード
**/
public function QRreaderEvent(type:String, imageData:BitmapData, data:Array, checkArray:Array = null){
super(type);
// 新しいプロパティを設定する
this.imageData = imageData;
this.data = data;
this.checkArray = checkArray;
}
// Eventからオーバーライドしたメソッド( Overridden Method: Event )
/**
* @private
**/
override public function clone():Event {
return new QRreaderEvent(type, imageData, data, checkArray);
}
}
}/**************************************************************************
* LOGOSWARE Class Library.
*
* Copyright 2009 (c) LOGOSWARE (http://www.logosware.com) All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*
**************************************************************************/
/* package com.logosware.utils */
{
import flash.display.BitmapData;
import flash.geom.Point;
import flash.geom.Rectangle;
/**
* ラベリングを行うクラスです
*/
/* public */ internal class LabelingClass
{
private var _bmp:BitmapData;
private var _minSize:uint;
private var _startColor:uint;
private var _pickedRects:Array = [];
private var _pickedColor:Array = [];
/**
* コンストラクタ
* @param bmp 入力画像(0x0, 0xFFFFFFFFでニ値化されたもの)
* @param minSize 画素として認める最低サイズ(ノイズ対策)
* @param startColor 塗り開始色
* @param isChangeOriginal 入力画像を実際に塗るかどうか
**/
public function Labeling(bmp:BitmapData, minSize:uint = 10, startColor:uint = 0xFFFFFFFE, isChangeOriginal:Boolean = true):void{
_minSize = minSize;
_startColor = startColor;
if( isChangeOriginal ){
_bmp = bmp;
} else {
_bmp = bmp.clone();
}
_process();
}
/**
* ラベリングした結果得られた範囲の矩形情報を返します
* @return 矩形の配列
**/
public function getRects():Array{
return _pickedRects;
}
/**
* ラベリングした結果得られた範囲を塗った色情報を返します
* @return 色の配列
**/
public function getColors():Array{
return _pickedColor;
}
/**
* コア関数
**/
private function _process():void {
var _fillColor:uint = _startColor;
var _rect:Rectangle;
while (_paintNextLabel( _bmp, 0xFF000000, _fillColor ) ){
_rect = _bmp.getColorBoundsRect( 0xFFFFFFFF, _fillColor );
if ( ( _rect.width > _minSize) && ( _rect.height > _minSize ) ) {
var _tempRect:Rectangle = _rect.clone();
_pickedRects.push( _tempRect );
_pickedColor.push( _fillColor );
}
_fillColor --;
}
}
/**
* 次のpickcolor色の領域をfillcolor色に塗る。pickcolorが見つからなければfalseを返す
* @param bmp 画像
* @param pickcolor 次の色
* @param fillcolor 塗る色
* @return 目的の色があったかどうか
**/
private function _paintNextLabel( bmp:BitmapData, pickcolor:uint, fillcolor:uint ):Boolean {
var rect:Rectangle = bmp.getColorBoundsRect( 0xFFFFFFFF, pickcolor );
if( (rect.width > 0) && (rect.height> 0) ){
var tempBmp:BitmapData = new BitmapData( rect.width, 1 );
tempBmp.copyPixels( bmp, new Rectangle(rect.topLeft.x, rect.topLeft.y, rect.width, 1 ), new Point(0, 0) );
var rect2:Rectangle = tempBmp.getColorBoundsRect( 0xFFFFFFFF, pickcolor );
bmp.floodFill( rect2.topLeft.x + rect.topLeft.x, rect2.topLeft.y + rect.topLeft.y, fillcolor );
return true;
}
return false;
}
}
}/**************************************************************************
* LOGOSWARE Class Library.
*
* Copyright 2009 (c) LOGOSWARE (http://www.logosware.com) All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*
**************************************************************************/
/* package com.logosware.utils.QRcode */
{
/* import com.logosware.utils.QRcode.GFstatic; */
/**
* GF(2^4)を扱うためのクラス
**/
/* public */ internal class G4Num {
private var _vector:uint;
private var _power:int;
/**
* コンストラクタ
* @param power 指数
**/
public function G4Num(power:int) {
setPower( power );
}
/**
* 指数を指定する
* @param power 指数
**/
public function setPower( power:int ):void {
_power = power;
if ( _power < 0 ) {
_vector = 0;
} else {
_power %= 15;
_vector = GFstatic._power2vector_4[_power];
}
}
/**
* 整数値を指定する
* @param vector 整数値
**/
public function setVector( vector:uint ):void {
_vector = vector;
_power = GFstatic._vector2power_4[_vector];
}
/**
* 整数値を取得する
* @param 整数値
**/
public function getVector():uint {
return _vector;
}
/**
* 指数を取得する
* @param 指数
**/
public function getPower():int {
return _power;
}
/**
* 足し算を行う。整数値同士のxorを取る。
* @param other 足す対象となるG4Numインスタンス
* @param 計算結果
**/
public function plus( other:G4Num ):G4Num {
var newVector:uint = _vector ^ other.getVector();
return new G4Num( GFstatic._vector2power_4[ newVector ] );
}
/**
* 乗算を行う。指数同士の足し算を行う。
* @param other かける対象となるG4Numインスタンス
* @param 計算結果
**/
public function multiply( other:G4Num ):G4Num {
if ( (_power == -1) || (other.getPower() == -1 ) ) {
return new G4Num( -1 );
} else {
return new G4Num( _power + other.getPower() );
}
}
}
}/**************************************************************************
* LOGOSWARE Class Library.
*
* Copyright 2009 (c) LOGOSWARE (http://www.logosware.com) All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*
**************************************************************************/
/* package com.logosware.utils.QRcode */
{
/* import com.logosware.utils.QRcode.GFstatic; */
/**
* GF(2^8)を扱うためのクラス
**/
/* public */ internal class G8Num {
private var _vector:uint;
private var _power:int;
/**
* コンストラクタ
* @param power 指数
**/
public function G8Num(power:int) {
setPower( power );
}
/**
* 指数を指定する
* @param power 指数
**/
public function setPower( power:int ):void {
_power = power;
if ( _power < 0 ) {
_vector = 0;
} else {
_power %= 255;
_vector = GFstatic._power2vector_8[_power];
}
}
/**
* 整数値を指定する
* @param vector 整数値
**/
public function setVector( vector:uint ):void {
_vector = vector;
_power = GFstatic._vector2power_8[_vector];
}
/**
* 整数値を取得する
* @param 整数値
**/
public function getVector():uint {
return _vector;
}
/**
* 指数を取得する
* @param 指数
**/
public function getPower():int {
return _power;
}
/**
* 足し算を行う。整数値同士のxorを取る。
* @param other 足す対象となるG4Numインスタンス
* @param 計算結果
**/
public function plus( other:G8Num ):G8Num {
var newVector:uint = _vector ^ other.getVector();
return new G8Num( GFstatic._vector2power_8[ newVector ] );
}
/**
* 乗算を行う。指数同士の足し算を行う。
* @param other かける対象となるG4Numインスタンス
* @param 計算結果
**/
public function multiply( other:G8Num ):G8Num {
if ( (_power < 0) || (other.getPower() < 0 ) ) {
return new G8Num( -1 );
} else {
return new G8Num( _power + other.getPower() );
}
}
/**
* 逆数を計算して得る。元のインスタンスは変化しない。
* @param 計算結果
**/
public function inverse():G8Num {
return new G8Num( 255 - getPower() );
}
}
}/**************************************************************************
* LOGOSWARE Class Library.
*
* Copyright 2009 (c) LOGOSWARE (http://www.logosware.com) All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*
**************************************************************************/
/* package com.logosware.utils.QRcode */
{
/* import com.logosware.event.QRreaderEvent; */
/* import com.logosware.utils.LabelingClass; */
import flash.display.*;
import flash.events.EventDispatcher;
import flash.filters.ColorMatrixFilter;
import flash.filters.ConvolutionFilter;
import flash.geom.*;
import flash.utils.ByteArray;
/**
* 主にカメラ画像からQRコードを切り出すためのクラスです.
* 画像上にあるVersion 1~10のQRコードを0,1からなる2次元配列に整形して返します
* @author Kenichi UENO
**/
/* public */ internal class GetQRimage extends EventDispatcher
{
private var _wid:uint = 320;
private var _hgt:uint = 240;
private var _minVersion:uint = 1; // サポートする最低バージョン
private var _maxVersion:uint = 10; // サポートする最高バージョン
private var _imageSource:DisplayObject = new Sprite();
private var _resultImage:BitmapData = new BitmapData(1, 1);
private var _resultArray:Array = [];
private var _results:Array = [
_resultImage,
_resultArray
];
private const _origin:Point = new Point(0, 0);
private var detecter:QRCodeDetecter;
/**
* コンストラクタ.
* @param tempMC QRコード描画元のSpriteインスタンス
**/
public function GetQRimage(source:DisplayObject)
{
_imageSource = source;
detecter = new QRCodeDetecter(_imageSource);
}
/**
* 読み取りを実行します
* @eventType QRreaderEvent.QR_IMAGE_READ_COMPLETE
*/
public function process():void {
var QRCodes:Array = detecter.detect();
for ( var i:int = 0; i < QRCodes.length; i++ ) {
var bmpData:BitmapData = QRCodes[i].image;
var colors:Array = QRCodes[i].borderColors;
// バージョンの取得
var qrInfo:Object = _getVersion( bmpData, colors[0], colors[1], colors[2] );
if ( qrInfo.version > 0 ) {
// グリッドの結果を取得
_results = _getGrid( bmpData, qrInfo );
_resultImage = _results[0];
_resultArray = _results[1];
// グリッド中でもマーカー確認
var checkBmp:BitmapData = new BitmapData( _resultImage.width, _resultImage.height );
checkBmp.applyFilter(_resultImage,_resultImage.rect,_origin,new ConvolutionFilter(7, 7, [1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1],33));
if ( (checkBmp.getPixel(7, 7) == 0) && (checkBmp.getPixel(checkBmp.width - 8, 7) == 0) && (checkBmp.getPixel(7, checkBmp.height - 8) == 0) ) {
dispatchEvent( new QRreaderEvent( QRreaderEvent.QR_IMAGE_READ_COMPLETE, _resultImage, _resultArray ) );
} else {
}
}
}
// process終了
}
/**
* QRコードのビット情報を二次元配列化する
* @param bmpData 画像
* @param qrInfo QRコード情報オブジェクト
* @param ビットパターン配列
*/
private function _getGrid( bmpData:BitmapData, qrInfo:Object ):Array {
var __resultBmp:BitmapData = new BitmapData( 8 + qrInfo.version * 4 + 17, 8 + qrInfo.version * 4 + 17 );
var __resultArray:Array = new Array( qrInfo.version * 4 + 17 );
var __i:uint;
var __thisColor:uint;
var __tlCenter:Object = { x:qrInfo.topLeftRect.topLeft.x + 0.5 * ( qrInfo.topLeftRect.width ), y:qrInfo.topLeftRect.topLeft.y + 0.5 * ( qrInfo.topLeftRect.height ) };
var __trCenter:Object = { x:qrInfo.topRightRect.topLeft.x + 0.5 * ( qrInfo.topRightRect.width ), y:qrInfo.topRightRect.topLeft.y + 0.5 * ( qrInfo.topRightRect.height ) };
var __blCenter:Object = { x:qrInfo.bottomLeftRect.topLeft.x + 0.5 * ( qrInfo.bottomLeftRect.width ), y:qrInfo.bottomLeftRect.topLeft.y + 0.5 * ( qrInfo.bottomLeftRect.height ) };
for( __i = 0; __i < (qrInfo.version*4+17); __i++ ){
__resultArray[__i] = new Array( qrInfo.version * 4 + 17 );
}
__i = 0;
__thisColor = 0;
while ( __thisColor != 0xFFFFFF ) {
__i++;
__thisColor = bmpData.getPixel( qrInfo.topRightRect.topLeft.x + __i, qrInfo.bottomLeftRect.topLeft.y + __i );
}
bmpData.floodFill( qrInfo.topRightRect.topLeft.x + __i, qrInfo.bottomLeftRect.topLeft.y + __i, 0xFFCCFFFF );
var __bottomRightRect:Rectangle = bmpData.getColorBoundsRect( 0xFFFFFFFF, 0xFFCCFFFF );
bmpData.floodFill( qrInfo.topRightRect.topLeft.x + __i, qrInfo.bottomLeftRect.topLeft.y + __i, 0xFFFFFFFF );
var __brCenter:Object = { x:__bottomRightRect.topLeft.x + 0.5 * ( __bottomRightRect.width ), y:__bottomRightRect.topLeft.y + 0.5 * ( __bottomRightRect.height ) };
if( qrInfo.version == 1 ){
__brCenter.x = __blCenter.x + (__trCenter.x - __tlCenter.x) * 11.0 / 14.0;
__brCenter.y = __trCenter.y + (__blCenter.y - __tlCenter.y) * 11.0 / 14.0;
}
var __tempNum1:Number = ( qrInfo.version * 4.0 + 17 - 10 ); //QRコード上の、左上マーカー中心から右「下」マーカー中心までのx座標の差 (ver5なら27)
var __tempNum2:Number = ( qrInfo.version * 4.0 + 17 - 7 ); //QRコード上の、左上マーカー中心から右「上」マーカー中心までのx座標の差 (ver5なら30)
var __blTop:Object = { x: qrInfo.bottomLeftRect.topLeft.x + qrInfo.bottomLeftRect.width*0.5, y: qrInfo.bottomLeftRect.topLeft.y + qrInfo.bottomLeftRect.height/14.0 };
var __trLeft:Object = { x: qrInfo.topRightRect.topLeft.x + qrInfo.topRightRect.width / 14.0, y: qrInfo.topRightRect.topLeft.y + qrInfo.topRightRect.height * 0.5 };
var __sum:Number = 0.0;
var __num:Number = 0.0;
for ( __i = __blTop.y - qrInfo.cellSize; __i <= __blTop.y + qrInfo.cellSize; __i++ ) {
if ( bmpData.getPixel( __blTop.x, __i ) != 0xFFFFFF ) {
__sum += __i;
__num++;
}
}
__blTop.y = 0.5 * (__blTop.y + __sum / __num);
var __a3:Number = ( __tlCenter.y - __trLeft.y) / ( __tlCenter.x - __trLeft.x);
var __a30:Number = ( __blTop.y - __brCenter.y) / ( __blTop.x - __brCenter.x);
var __b3:Number = __trLeft.y - __a3 * __trLeft.x;
var __b30:Number = __brCenter.y - __a30 * __brCenter.x;
var __startX3:Number = __tlCenter.x + ( __trLeft.x - __tlCenter.x ) * ( -3.0 / __tempNum1 );
var __startX30:Number = __blTop.x + ( __brCenter.x - __blTop.x ) * ( -3.0 / __tempNum1 );
var __startY3:Number = __tlCenter.y + ( __trLeft.y - __tlCenter.y ) * ( -3.0 / __tempNum1 );
var __startY30:Number = __blTop.y + ( __brCenter.y - __blTop.y ) * ( -3.0 / __tempNum1 );
var __end3:Number = __trLeft.x + ( __trLeft.x - __tlCenter.x ) * ( 6.0 / __tempNum1 );
var __end30:Number = __brCenter.x + ( __brCenter.x - __blTop.x ) * ( 6.0 / __tempNum1 );
var __loopConst:uint = (__resultBmp.width - 8 );
var __loopConst2:uint = __loopConst - 1;
var __a:Array = new Array( __loopConst );
var __b:Array = new Array( __loopConst );
var __startX:Array = new Array( __loopConst );
var __startY:Array = new Array( __loopConst );
var __endX:Array = new Array( __loopConst );
for ( __i = 0; __i < __loopConst; __i++ ) {
__a[__i] = (( __a30 - __a3 ) / __tempNum1) * ( __i - 3 ) + __a3;
__startX[__i] = (( __startX30 - __startX3 ) / __tempNum1) * ( __i - 3 ) + __startX3;
__startY[__i] = (( __startY30 - __startY3 ) / __tempNum1) * ( __i - 3 ) + __startY3;
__endX[__i] = (( __end30 - __end3 ) / __tempNum1) * ( __i - 3 ) + __end3;
__b[__i] = __startY[__i] - __a[__i] * __startX[__i];
}
for ( var __y:Number = 0; __y < __loopConst; __y++ ) {
var __y2:Number = __y - 3;
for ( var __x:Number = 0; __x < __loopConst; __x++ ) {
var __x2:Number = __x - 3;
if ( (bmpData.getPixel( __startX[__y] + ( __endX[__y] - __startX[__y] ) * ( __x / __loopConst2 ), __a[__y] * (__startX[__y] + ( __endX[__y] - __startX[__y] ) * ( __x / __loopConst2 )) + __b[__y] ) & 0xFF0000) < 0xFF0000) {
__resultBmp.setPixel( 4 + __x, 4 + __y, 0 );
__resultArray[__y][__x] = 1;
}
}
}
return [__resultBmp, __resultArray];
}
/**
* QRコードのバージョンを判別する
* @param bmp 画像
* @param QRコード情報オブジェクト
*/
private function _getVersion( bmp:BitmapData, tlColor:uint, trColor:uint, blColor:uint ):Object {
var i:uint;
var thisColor:uint;
bmp.lock();
var topLeftRect:Rectangle = bmp.getColorBoundsRect( 0xFFFFFFFF, tlColor );
var topRightRect:Rectangle = bmp.getColorBoundsRect( 0xFFFFFFFF, trColor );
var bottomLeftRect:Rectangle = bmp.getColorBoundsRect( 0xFFFFFFFF, blColor );
var startTopLeft:Point = new Point( 26, topLeftRect.topLeft.y + topLeftRect.height );
var numX:uint = 0;
var tempX:uint;
var oldP:uint;
var whiteNum:uint = 0;
for ( var j:int = -8; j <= 0; j++ ) {
tempX = 0;
var whiteArray:Array = [];
var tempArray:ByteArray = bmp.getPixels( new Rectangle( startTopLeft.x, startTopLeft.y + j, bmp.width - 52, 1 ) );
var startColor:uint = tempArray[1];
var endColor:uint = tempArray[4*(bmp.width-26-1)+1];
if ( ( startColor != 0xFF ) && ( endColor != 0xFF ) ) {
oldP = startColor;
for ( i = 1; i < (bmp.width - 24); i++ ) {
var tempColor:uint = tempArray[4*i+1];
if ( tempColor != oldP ) {
tempX ++;
oldP = tempColor;
}
if ( tempColor == 0xFF ) {
whiteNum++;
} else {
if ( whiteNum > 0 ) {
whiteArray.push( [whiteNum] );
whiteNum = 0;
}
}
}
var sum:Number = 0;
// 妥当性のチェック 白いマスが全部同じくらいのサイズだったらOK
for ( var k:uint = 0; k < whiteArray.length; k++ ) {
sum += Number( whiteArray[k] );
}
var average:Number = sum / whiteArray.length;
var error:uint = 0;
for ( k = 0; k < whiteArray.length; k++ ) {
if ( ! ((whiteArray[k] > (average * 0.5)) && (whiteArray[k] < (average * 1.5)) ) ) {
error++;
}
}
if ( (numX < tempX) && (error == 0) ) {
numX = tempX;
}
}
}
numX = Math.floor( ( ( numX - 3 ) - 6 ) * 0.25 ) + 1;
startTopLeft = new Point( topLeftRect.topLeft.x + topLeftRect.width, 26 );
var numY:uint = 0;
whiteNum = 0;
for ( j = -8; j <= 0; j++ ) {
tempX = 0;
whiteArray = [];
tempArray = bmp.getPixels( new Rectangle( startTopLeft.x + j, startTopLeft.y, 1, bmp.height - 52 ) );
startColor = tempArray[1];
endColor = tempArray[4*(bmp.height-26-1)+1];
if ( ( startColor != 0xFF ) && ( endColor != 0xFF ) ) {
oldP = startColor;
for ( i = 1; i < (bmp.height - 24); i++ ) {
tempColor = tempArray[4*i+1];
if ( tempColor != oldP ) {
tempX ++;
oldP = tempColor;
}
if ( tempColor == 0xFF ) {
whiteNum++;
} else {
if ( whiteNum > 0 ) {
whiteArray.push( [whiteNum] );
whiteNum = 0;
}
}
}
sum = 0;
// 妥当性のチェック 白いマスが全部同じくらいのサイズだったらOK
for ( k = 0; k < whiteArray.length; k++ ) {
sum += Number( whiteArray[k] );
}
average = sum / whiteArray.length;
error = 0;
for ( k = 0; k < whiteArray.length; k++ ) {
if ( ! ((whiteArray[k] > (average * 0.5)) && (whiteArray[k] < (average * 1.5)) ) ) {
error++;
}
}
if ( (numY < tempX) && (error == 0) ) {
numY = tempX;
}
}
}
numY = Math.floor( ( ( numY - 3 ) - 6 ) * 0.25 ) + 1;
if ( (numX == numY) && (numX >= _minVersion) && (numX <= _maxVersion ) ) {
// trace("numX");
} else {
numX = 0;
}
bmp.unlock();
return {cellSize:(topRightRect.x + topRightRect.width - topLeftRect.x) / (numX * 4 + 17), version:numX, topLeftRect: topLeftRect, topRightRect:topRightRect, bottomLeftRect: bottomLeftRect};
}
/**
* 画像中央付近の明るさを使って白と黒の閾値を計算する
* @param bmp 画像
* @param 閾値
*/
private function _getThreshold( bmp:BitmapData ):uint {
var rect:Rectangle = new Rectangle( bmp.width * 0.5, 0, 1, bmp.height );
var bmp_check:BitmapData = new BitmapData( 1, bmp.height );
bmp_check.copyPixels(bmp, rect, new Point(0, 0));
bmp_check.lock();
var tempArray:ByteArray = bmp_check.getPixels( bmp_check.rect );
var sum:Number = 0.0;
for ( var i:uint = 0; i < bmp.height; i++ ) {
sum += tempArray[4*i+3]; // 緑成分で判定
}
sum /= bmp.height;
return uint(0xFF000000 + 0x00010101 * Math.round(sum));
}
/**
* 画像をグレースケール化する
* @param bmp_src 元の画像
* @param bmp_dst 結果格納先の画像
* @param rect 適用範囲指定
* @param point 適用原点指定
* @param constnum 明るさ補正
**/
private function _toGray( bmp_src:BitmapData, bmp_dst:BitmapData, rect:Rectangle, point:Point, constnum:Number = 2.5 ):void {
var conGray:Array = [constnum*0.3, constnum*0.59, constnum*0.11];
var cmfGray:ColorMatrixFilter = new ColorMatrixFilter(
[conGray[0], conGray[1], conGray[2], 0, 0,
conGray[0], conGray[1], conGray[2], 0, 0,
conGray[0], conGray[1],conGray[2], 0, 0,
0, 0, 0, 0, 255]
);
bmp_dst.applyFilter( bmp_src, rect, point, cmfGray );
}
/**
* 画像を2値化する
* @param bmp 2値化する画像
* @param threshold 閾値
**/
private function _binalization( bmp:BitmapData, threshold:uint = 0xFFFFFFFF ):void {
bmp.threshold(bmp, bmp.rect, new Point(0, 0), "<", threshold, 0xFF000000, 0xFFFFFFFF );
bmp.threshold(bmp, bmp.rect, new Point(0, 0), ">=", threshold, 0xFFFFFFFF, 0xFFFFFFFF );
}
/**
* 境界上の点をピックアップする
* @param bmp 元画像
* @param rect 対象画像位置
* @param color 対象色
* @param devide 分割個数
* @param 点情報
**/
private function _getBorderPoints(bmp:BitmapData, rect:Rectangle, color:uint, divide:uint):Array {
var tempX:uint;
var tempY:uint;
var tempBmpX:BitmapData = new BitmapData( rect.width, 1);
var tempBmpY:BitmapData = new BitmapData( 1, rect.height );
var tempRect2:Rectangle;
var tempPoint:Point;
var loopCount:uint = divide;
var borderPoints:Array = new Array();
for (var j:uint = 0; j <= loopCount; j++ ) {
tempX = ( (rect.width-1) * j ) / loopCount + rect.topLeft.x;
tempY = ( (rect.height-1) * j ) / loopCount + rect.topLeft.y;
tempBmpX.copyPixels( bmp, new Rectangle(rect.topLeft.x, tempY, rect.width, 1), new Point(0,0) );
tempBmpY.copyPixels( bmp, new Rectangle(tempX, rect.topLeft.y, 1, rect.height), new Point(0,0) );
// 横線スキャン
tempRect2 = tempBmpY.getColorBoundsRect( 0xFFFFFFFF, color );
tempPoint = new Point(
tempX + tempRect2.topLeft.x,
rect.topLeft.y + tempRect2.topLeft.y
);
borderPoints.push( tempPoint );
tempPoint = new Point(
tempX + tempRect2.topLeft.x + tempRect2.width,
rect.topLeft.y + tempRect2.topLeft.y + tempRect2.height );
borderPoints.push( tempPoint );
// 縦線スキャン
tempRect2 = tempBmpX.getColorBoundsRect( 0xFFFFFFFF, color );
tempPoint = new Point(
rect.topLeft.x + tempRect2.topLeft.x,
tempY + tempRect2.topLeft.y
);
borderPoints.push( tempPoint );
tempPoint = new Point(
rect.topLeft.x + tempRect2.topLeft.x + tempRect2.width,
tempY + tempRect2.topLeft.y + tempRect2.height
);
borderPoints.push( tempPoint );
}
return borderPoints;
}
}
}
import flash.geom.Point;
/**************************************************************************
* LOGOSWARE Class Library.
*
* Copyright 2009 (c) LOGOSWARE (http://www.logosware.com) All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*
**************************************************************************/
/* package com.logosware.utils.QRcode */
{
/**
* ガロア体GF(2^w) w=4, 8 の計算に用いる定数
*/
/* public */ internal class GFstatic
{
/**
* GF(2^4)計算用定数.
* _power2vector_4[指数] = 整数値 のように使います
*/
public static var _power2vector_4:Array = [
1, 2, 4, 8, 3, 6, 12, 11,
5, 10, 7, 14, 15, 13, 9, 1
];
/**
* GF(2^4)計算用定数.
* _power2vector_4[整数値] = 指数 のように使います
*/
public static var _vector2power_4:Array = [
-1, 0, 1, 4, 2, 8, 5, 10,
3, 14, 9, 7, 6, 13, 11, 12
];
/**
* GF(2^8)計算用定数.
* _power2vector_8[指数] = 整数値 のように使います
*/
public static var _power2vector_8:Array = [
1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38,
76, 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192,
157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193, 159, 35,
70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161,
95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240,
253, 231, 211, 187, 107, 214, 177, 127, 254, 225, 223, 163, 91, 182, 113, 226,
217, 175, 67, 134, 17, 34, 68, 136, 13, 26, 52, 104, 208, 189, 103, 206,
129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197, 151, 51, 102, 204,
133, 23, 46, 92, 184, 109, 218, 169, 79, 158, 33, 66, 132, 21, 42, 84,
168, 77, 154, 41, 82, 164, 85, 170, 73, 146, 57, 114, 228, 213, 183, 115,
230, 209, 191, 99, 198, 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255,
227, 219, 171, 75, 150, 49, 98, 196, 149, 55, 110, 220, 165, 87, 174, 65,
130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112, 224, 221, 167, 83, 166,
81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172, 69, 138, 9,
18, 36, 72, 144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22,
44, 88, 176, 125, 250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 142, 1
];
/**
* GF(2^8)計算用定数.
* _power2vector_8[整数] = 指数 のように使います
*/
public static var _vector2power_8:Array = [
-1, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75,
4, 100, 224, 14, 52, 141, 239, 129, 28, 193, 105, 248, 200, 8, 76, 113,
5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 218, 240, 18, 130, 69,
29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114, 166,
6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136,
54, 208, 148, 206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64,
30, 66, 182, 163, 195, 72, 126, 110, 107, 58, 40, 84, 250, 133, 186, 61,
202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172, 115, 243, 167, 87,
7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24,
227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217, 35, 32, 137, 46,
55, 63, 209, 91, 149, 188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97,
242, 86, 211, 171, 20, 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162,
31, 45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12, 111, 246,
108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204, 62, 90,
203, 89, 95, 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215,
79, 174, 213, 233, 230, 231, 173, 232, 116, 214, 244, 234, 168, 80, 88, 175
];
}
}/**************************************************************************
* LOGOSWARE Class Library.
*
* Copyright 2009 (c) LOGOSWARE (http://www.logosware.com) All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*
**************************************************************************/
/* package com.logosware.utils.QRcode */
{
/* import com.logosware.utils.LabelingClass; */
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BlendMode;
import flash.display.DisplayObject;
import flash.display.Loader;
import flash.display.Sprite;
import flash.filters.BlurFilter;
import flash.filters.ColorMatrixFilter;
import flash.filters.ConvolutionFilter;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.getTimer;
/**
* @author UENO Kenichi
*/
/* public */ internal class QRCodeDetecter extends Sprite
{
private var image:DisplayObject;
private var bd:BitmapData;
private var bd2:BitmapData;
private var threshold:uint = 0xFF888888;
private var grayConst:Array = [
0.3, 0.59, 0.11, 0, 0,
0.3, 0.59, 0.11, 0, 0,
0.3, 0.59, 0.11, 0, 0,
0, 0, 0, 0, 255
];
/**
* 画像からQRコードを見つけ出します
* @param imageSource
*/
public function QRCodeDetecter(imageSource:DisplayObject)
{
image = imageSource;
bd = new BitmapData(image.width, image.height, true, 0x0);
bd2 = new BitmapData(image.width, image.height, true, 0x0);
// debug code
/*
var bmp:Bitmap = new Bitmap( bd );
image.parent.addChild( bmp );
bmp.x = image.width;
*/
}
/**
* 見つかったQRコードの位置情報を返します
* @return マーカー配列
* [
* {
* image:BitmapData,
* borderColors:[
* 0: uint color of topleft marker
* 1: uint color of topright marker
* 2: uint color of bottomleft marker
* ],
* originalLocation:[
* 0: Rectangle of topleft marker
* 1: Rectangle of topright marker
* 2: Rectangle of bottomleft marker
* ]
* }
* ...
* ]
*/
public function detect():Array {
var ret:Array = [];
bd.lock();
bd.draw(image);
// グレー化
bd.applyFilter(bd, bd.rect, new Point(), new ColorMatrixFilter(grayConst));
bd.applyFilter(bd, bd.rect, new Point(), new ConvolutionFilter(5, 5, [
0, -1, -1, -1, 0,
-1, -1, -2, -1, -1,
-1, -2, 25, -2, -1,
-1, -1, -2, -1, -1,
0, -1, -1, -1, 0
]));
bd.applyFilter(bd, bd.rect, new Point(), new BlurFilter(3, 3));
// 二値化
bd.threshold(bd, bd.rect, new Point(), ">", threshold, 0xFFFFFFFF, 0x0000FF00);
bd.threshold(bd, bd.rect, new Point(), "!=", 0xFFFFFFFF, 0xFF000000);
// ラベリング
var LabelingObj:LabelingClass = new LabelingClass();
LabelingObj.Labeling( bd, 10, 0xFF88FFFE, true ); // ラベリング実行
var pickedRects:Array = LabelingObj.getRects();
var pickedColor:Array = LabelingObj.getColors();
LabelingObj = null;
// マーカー候補の矩形を取得
var borders:Array = _searchBorders( bd, pickedRects, pickedColor );
// 直角の位置にあるコードを検索
var codes:Array = _searchCode( borders );
// 適切な角度で切り抜き
var images:Array = _clipCodes( bd, codes );
for ( var i:int = 0; i < images.length; i++ ) {
ret.push( { image:images[i], borderColors:[codes[i][0].borderColor, codes[i][1].borderColor, codes[i][2].borderColor], originalLocation:[codes[i][0].borderRect, codes[i][1].borderRect, codes[i][2].borderRect] } );
}
bd.unlock();
return ret;
}
private function _clipCodes( bd:BitmapData, codes:Array):Array {
var ret:Array = [];
for ( var i:int = 0; i < codes.length; i++ ) {
var marker1:Rectangle = codes[i][0].borderRect; // top left
var marker2:Rectangle = codes[i][1].borderRect; // top right
var marker3:Rectangle = codes[i][2].borderRect; // bottom left
var vector12:Point = marker2.topLeft.subtract( marker1.topLeft ); // vector: top left -> top right
var vector13:Point = marker3.topLeft.subtract( marker1.topLeft ); // vector: top left -> bottom left
var theta:Number = -Math.atan2( vector12.y, vector12.x ); // 平面状の回転角
var matrix:Matrix = new Matrix();
var d:Number = (0.5 * marker1.width) / (Math.abs(Math.cos( theta )) + Math.abs(Math.sin( theta ) ) ); // マーカーの一辺の長さの半分
matrix.translate( -(marker1.topLeft.x + marker1.width * 0.5), -(marker1.topLeft.y + marker1.height * 0.5) );
matrix.rotate( theta );
matrix.translate( 20 + d, 20 + d );
var matrix2:Matrix = new Matrix();
matrix2.rotate( theta );
var vector13r:Point = matrix2.transformPoint( vector13 );
matrix2 = new Matrix(1.0, 0, -vector13r.x/vector13r.y, vector12.length / vector13r.y );
matrix.concat( matrix2 );
var len:Number = ( vector12.length + 2 * d ); // QRコードの一辺の長さ
var bd2:BitmapData = new BitmapData( 40 + len, 40 + len );
bd2.draw( bd, matrix );
ret.push( bd2 );
}
return ret;
}
/**
* マーカーの候補をピックアップする
* @param bmp ラベリング済みの画像
* @param rectArray 矩形情報
* @param colorArray 矩形の色情報
* @return 候補の配列
*/
private function _searchBorders(bmp:BitmapData, rectArray:Array, colorArray:Array):Array {
function isMarker( ary:Array ):Boolean {
var c:Number = 0.75;
var ave:Number = (ary[0] + ary[1] + ary[2] + ary[3] + ary[4]) / 7;
return(
ary[0] > ((1.0-c)*ave) && ary[0] < ((1.0+c)*ave) &&
ary[1] > ((1.0-c)*ave) && ary[1] < ((1.0+c)*ave) &&
ary[2] > ((3.0-c)*ave) && ary[2] < ((3.0+c)*ave) &&
ary[3] > ((1.0-c)*ave) && ary[3] < ((1.0+c)*ave) &&
ary[4] > ((1.0-c) * ave) && ary[4] < ((1.0+c) * ave)
);
}
var retArray:Array = [];
for ( var i:int = 0; i < rectArray.length; i++ ) {
var count:int = 0;
var target:Number = 0;
var tempRect:Rectangle = rectArray[i];// 外側
if( colorArray[i] != bmp.getPixel( rectArray[i].topLeft.x + rectArray[i].width*0.5, rectArray[i].topLeft.y + rectArray[i].height*0.5) ){
var oldFlg:uint = 0;
var tempFlg:uint = 0;
var index:int = -1;
var countArray:Array = [0.0, 0.0, 0.0, 0.0, 0.0];
var j:int;
var constNum:Number;
// 横方向
constNum = rectArray[i].topLeft.y + rectArray[i].height*0.5;
for ( j = 0; j < rectArray[i].width; j++ ){
tempFlg = (bmp.getPixel( rectArray[i].topLeft.x + j, constNum ) == 0xFFFFFF)?0:1;
if( (index == -1) && (tempFlg == 0) ){
//go next
} else {
if( tempFlg != oldFlg ){
index++;
oldFlg = tempFlg;
if( index >= 5 ){
break;
}
}
countArray[index]++;
}
}
if ( isMarker(countArray) ) {
// 縦方向
countArray = [0.0, 0.0, 0.0, 0.0, 0.0];
oldFlg = tempFlg = 0;
index = -1;
constNum = rectArray[i].topLeft.x + rectArray[i].width*0.5;
for ( j = 0; j < rectArray[i].width; j++ ) {
tempFlg = (bmp.getPixel( constNum, rectArray[i].topLeft.y + j ) == 0xFFFFFF)?0:1;
if( (index == -1) && (tempFlg == 0) ){
//go next
} else {
if( tempFlg != oldFlg ){
index++;
oldFlg = tempFlg;
if( index >= 5 ){
break;
}
}
countArray[index]++;
}
}
if ( isMarker(countArray) ) {
retArray.push( {borderColor:colorArray[i], borderRect:rectArray[i]} );
}
}
}
}
return retArray;
}
/**
* 直角関係にあるマーカーを探します
* @param borders 候補の配列
* @return
*/
private function _searchCode( borders:Array ):Array {
function isNear( p1:Point, p2:Point, d:Number ):Boolean {
return(
(p1.x + d) > p2.x &&
(p1.x - d) < p2.x &&
(p1.y + d) > p2.y &&
(p1.y - d) < p2.y
);
}
var ret:Array = [];
var loop:int = borders.length;
for ( var i:int = 0; i < (loop-2); i++ ) {
for ( var j:int = i + 1; j < (loop-1); j++ ) {
var vec:Point = borders[i].borderRect.topLeft.subtract( borders[j].borderRect.topLeft );
for ( var k:int = j + 1; k < loop; k++ ) {
if( isNear( borders[k].borderRect.topLeft, new Point( borders[i].borderRect.topLeft.x + vec.y, borders[i].borderRect.topLeft.y - vec.x ), 0.125 * vec.length ))
ret.push( [borders[i], borders[j], borders[k]] );
else if ( isNear( borders[k].borderRect.topLeft, new Point( borders[i].borderRect.topLeft.x - vec.y, borders[i].borderRect.topLeft.y + vec.x ), 0.125 * vec.length ))
ret.push( [borders[i], borders[k], borders[j]] );
else if ( isNear( borders[k].borderRect.topLeft, new Point( borders[j].borderRect.topLeft.x + vec.y, borders[j].borderRect.topLeft.y - vec.x ), 0.125 * vec.length ))
ret.push( [borders[j], borders[k], borders[i]] );
else if ( isNear( borders[k].borderRect.topLeft, new Point( borders[j].borderRect.topLeft.x - vec.y, borders[j].borderRect.topLeft.y + vec.x ), 0.125 * vec.length ))
ret.push( [borders[j], borders[i], borders[k]] );
}
}
}
return ret;
}
}
}/**************************************************************************
* LOGOSWARE Class Library.
*
* Copyright 2009 (c) LOGOSWARE (http://www.logosware.com) All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*
**************************************************************************/
/* package com.logosware.utils.QRcode */
{
/* import com.logosware.event.QRdecoderEvent; */
import flash.events.EventDispatcher;
import flash.system.System;
import flash.text.TextField;
import flash.utils.unescapeMultiByte;
/**
* QRコードをデコードして文字列を抽出するクラスです
* @author Kenichi UENO
**/
/* public */ internal class QRdecode extends EventDispatcher {
private var _xorPattern:Array = [1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0];
private var _fixed:Array;
private var _qr:Array;
// private var _textObj:TextField = new TextField();
private var _qrVersion:uint = 5;
public function QRdecode() {
}
/**
* 解析したいQRコードを格納する関数
* @param qr QRコードのビットパターン二次元配列
*/
public function setQR( qr:Array ):void {
_qr = qr;
_qrVersion = (qr.length - 17) * 0.25;
}
/**
* setQRで格納したQRコードのデコードを行う関数
* @param retObj 結果イベントに含ませたいオブジェクト
* @eventType QRdecoderEvent.QR_DECODE_COMPLETE
*/
public function startDecode(retObj:Object = null):void {
// 形式情報の読み出し
var dataArray:Array;
var unmaskedQR:Array;
var wordArray:Array;
var trueWordArray:Array;
var result:Array;
var resultFlg:uint;
var resultStr:String;
var qrSize:uint = _qrVersion * 4 + 17;
dataArray = _decode15_5();
// マスク処理の解除
unmaskedQR = _unmask( dataArray );
// 機能領域の計算
_makeFixed();
// データ読み出し
wordArray = _getWords( unmaskedQR );
// リードソロモン
trueWordArray = _ReedSolomon( wordArray, dataArray );
//データコード語復号
result = _readData( trueWordArray );
resultFlg = result[0];
if ( resultFlg ) {
resultStr = result[1];
// _textObj.appendText( "読み取り成功!\n" + resultStr );
dispatchEvent( new QRdecoderEvent( QRdecoderEvent.QR_DECODE_COMPLETE, resultStr, [retObj] ) );
}
}
/**
* リードソロモンで8bitずつ読み取る関数
*/
private function _RS8bit( __dataArray:Array, __codeNum:uint, __errorNum:uint, __snum:uint ):void {
var __i:uint;
var __j:uint;
var __index:uint;
var __dataLength:uint = __dataArray.length;
var __Snum:uint = __errorNum;
var __a:Array; // 誤り位置計算用変数
var __e:Array; // 誤り位置
var __S:Array = new Array(__Snum); // シンドローム
var __s:Array = new Array(__snum); // 誤り位置変数
var __tempNum1:G8Num;
var __tempNum2:G8Num;
// シンドローム配列初期化
for ( __j = 0; __j < __Snum; __j++ ) {
__S[__j] = new G8Num(-1);
}
for ( __i = 0; __i < __dataLength; __i++ ) {
__tempNum1 = new G8Num(0);
__tempNum1.setVector( __dataArray[__dataLength - 1 - __i] );
for ( __j = 0; __j < __Snum; __j++ ) {
__S[__j] = __S[__j].plus( __tempNum1.multiply(new G8Num( __i * __j )) );
}
}
__j = 0;
for ( __i = 0; __i < __Snum; __i++ ) {
if( __S[__i].getPower() != -1 ){
__j++;
}
}
if( __j == 0 ){ // 100%エラーなし
return;
}
// エラーあるかも
for ( __i = __snum; __i > 0; __i-- ){
if( _calcDet( __S, __i ) != 0 ){
break;
}
}
__snum = __i;
__a = new Array(__snum);
// 誤り訂正位置変数の計算
for (__i = 0; __i < __snum; __i++) {
__a[__i] = new Array(__snum+1);
for (__j = 0; __j <= __snum; __j++ ) {
__a[__i][__j] = new G8Num( __S[__i+__j].getPower() );
}
}
for ( __i = 0; __i < __snum; __i++ ){
_reduceToLU( __a, __i );
}
for (__i = 0; __i < __snum; __i++) {
for ( __j = 0; __j < __snum; __j++ ) {
if (__a[__i][__j].getPower() != -1) {
__s[__snum-1-__j] = __a[__i][__snum];
}
}
}
//__aは再利用
__e = new Array( __snum );
__index = 0;
for ( __i = 0; __i < __dataLength; __i++ ) {
__tempNum1 = new G8Num( __i * __snum );
for ( __j = __snum - 1; __j >= 1; __j-- ) {
__tempNum2 = new G8Num( __i * __j );
__tempNum1 = __tempNum1.plus( __tempNum2.multiply( __s[__snum-1-__j] ) );
}
__tempNum1 = __tempNum1.plus( __s[__snum-1] );
if ( __tempNum1.getPower() < 0 ) {
__e[__index] = __dataLength - 1 - __i;
for( __j = 0; __j < __snum; __j++ ){
__a[__j][__index] = new G8Num(__i * __j);
}
__a[__index][__snum] = new G8Num( __S[__index].getPower() );
__index++;
}
}
for ( __i = 0; __i < __snum; __i++ ){
_reduceToLU( __a, __i );
}
for ( __i = 0; __i < __snum; __i++ ){
for ( __j = 0; __j < __snum; __j++ ){
if( __a[__i][__j].getPower() == 0 ){
__dataArray[__e[__j]] = __dataArray[__e[__j]] ^ (__a[__i][__snum].getVector() );
}
}
}
}
/**
* 行列式を計算する
* @param 行列
* @param 行列サイズ
**/
private function _calcDet( __Dat:Array, __size:uint ):int {
var __i:uint;
var __j:uint;
var __k:uint;
var __doing:uint = 0;
var __result:G8Num = new G8Num(0);
var __tempNum:G8Num;
var __todo:Array = new Array( __size );
var __temp:Array = new Array( __size );
for( __j = 0; __j < __size; __j++ ){
__todo[__j] = 1;
__temp[__j] = new Array( __size );
for ( __i = 0; __i < __size; __i++ ){
__temp[__j][__i] = new G8Num( __Dat[__i+__j].getPower() );
}
}
//三角行列にする
while( __doing < __size ){ // 一列ずつ、つぶす
for( __i = 0; __i < __size; __i++ ){
if( __todo[__i] == 1 ){
if( __temp[__i][__doing].getPower() >= 0 ){
__result.multiply( __temp[__i][__doing] );
__tempNum = __temp[__i][__doing].inverse();
//自身の列の頭を1に
for( __j = __doing; __j < __size; __j++ ){
__temp[__i][__j] = __temp[__i][__j].multiply( __tempNum );
}
//その他の列を全部引き算
for( __k = 0; __k < __size; __k++ ){
if( (__k != __i) && (__todo[__k] == 1) && (__temp[__k][__doing].getPower() >= 0) ){
__tempNum = new G8Num(__temp[__k][__doing].getPower() );
for( __j = __doing; __j < __size; __j++ ){
__temp[__k][__j] = __temp[__k][__j].plus( __tempNum.multiply( __temp[__i][__j] ) );
}
}
}
__todo[__i] = 0;
break;
}
}
}
if( __i == __size ){
return 0;
}
__doing++;
}
return __result.getVector();
}
/**
* 下三角行列を作る
*/
private function _reduceToLU(__a:Array, __num:uint ):void {
var __i:uint;
var __j:uint;
var __it:uint;
var __flg:uint;
var __snum:uint = __a.length;
var __tempNum:G8Num;
for ( __i = 0; __i < __snum; __i++ ) {
__flg = 0;
if ( __a[__i][__num].getPower() != -1 ) {
__flg = 1;
for ( __j = 0; __j < __num; __j++ ) {
if ( __a[__i][__j].getPower() != -1 ) {
__flg = 0;
}
}
}
if ( __flg ) {
__it = __i;
__i = __snum;
}
}
__tempNum = __a[__it][__num].inverse();
for ( __j = __num; __j <= __snum; __j++ ) {
__a[__it][__j] = __a[__it][__j].multiply( __tempNum );
}
for ( __i = 0; __i < __snum; __i++ ) {
if ( (__i != __it) && (__a[__i][__num].getPower != -1 ) ) {
__tempNum = new G8Num( __a[__i][__num].getPower() );
for ( __j = __num; __j <= __snum; __j++ ) {
__a[__i][__j] = __a[__i][__j].plus( __a[__it][__j].multiply( __tempNum ) );
}
}
}
}
/**
* バイナリを文字列に変換する
* @param バイナリデータ
*/
private function _readData ( __dataCode:Array ):Array {
var __num2alphabet:Array = [
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
"K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
"U", "V", "W", "X", "Y", "Z", " ", "$", "%", "*",
"+", "-", ".", "/", ":"
];
var __verMode:uint;
var __stringBits:Array = [[10,9,8,8],[12,11,16,10],[14,13,16,12]];
var __result:String = "";
var __dataBin:Array;
var __i:uint;
var __mode:String;
var __num:uint;
var __tempNum:uint;
var __tempNum2:uint;
var __tempStr:String;
var __isSuccess:uint = 1;
if( _qrVersion < 10 ){
__verMode = 0;
} else if( _qrVersion < 27 ) {
__verMode = 1;
} else if( _qrVersion < 41 ) {
__verMode = 2;
}
__dataBin = _Hex2Bin( __dataCode );
//どんどん読み取り
while( __dataBin.length > 0 ){
__mode = _readNstr( __dataBin, 4 );
switch( __mode ) {
case "0001": // 数字
__num = _readNnumber( __dataBin, __stringBits[__verMode][0] ); // 10: バージョンに依存
for ( __i = 0; __i < __num; __i += 3 ) {
if ( (__num - __i) == 2 ) {
__tempNum = _readNnumber( __dataBin, 7 );
__result += String("00"+__tempNum).substr(-2,2);
} else if( (__num - __i) == 1 ) {
__tempNum = _readNnumber( __dataBin, 4 );
__result += String("0"+__tempNum).substr(-1,1);
} else {
__tempNum = _readNnumber( __dataBin, 10 );
__result += String("000"+__tempNum).substr(-3,3);
}
}
break;
case "0010": // 英数字
__num = _readNnumber( __dataBin, __stringBits[__verMode][1] ); // 9: バージョンに依存
for ( __i = 0; __i < __num; __i += 2 ) {
if ( (__num - __i) > 1 ) {
__tempNum = _readNnumber( __dataBin, 11 );
__result += __num2alphabet[ Math.floor(__tempNum / 45) ] + __num2alphabet[ __tempNum % 45 ];
} else {
__tempNum = _readNnumber( __dataBin, 6 );
__result += __num2alphabet[ __tempNum ];
}
}
break;
case "0100": // 8 bit Byte
__num = _readNnumber( __dataBin, __stringBits[__verMode][2] ); // 8: バージョンに依存
__tempStr = "";
for ( __i = 0; __i < __num; __i ++ ) {
__tempNum = _readNnumber( __dataBin, 8 );
// __result += String.fromCharCode(__tempNum);
__tempStr += "%"+_Hex2String(__tempNum);
}
System.useCodePage = true;
__result += unescapeMultiByte( __tempStr );
break;
case "1000": // 漢字
__num = _readNnumber( __dataBin, __stringBits[__verMode][3] ); // 8: バージョンに依存
for ( __i = 0; __i < __num; __i ++ ) {
__tempNum = _readNnumber( __dataBin, 13 );
__tempNum2 = Math.floor(__tempNum / 0xC0 );
__tempNum2 += ( __tempNum2 <= 0x1E )?0x81:0xC1;
__tempNum %= 0xC0;
__tempNum += 0x40;
System.useCodePage = true;
__result += unescapeMultiByte( "%"+_Hex2String(__tempNum2)+"%"+_Hex2String(__tempNum) );
// __result += "("+_Hex2String(__tempNum2)+_Hex2String(__tempNum)+")";
}
break;
case "0000":
case "000":
case "00":
case "0":
__tempNum = _readNnumber( __dataBin, __dataBin.length );
//正常終了
break;
default: //未対応
__isSuccess = 0;
__result += "***未対応の形式を検出しました。";
continue;
break;
}
}
return [__isSuccess, __result];
}
/**
* 32ビットのデータを文字に直す
* @param バイナリデータ
*/
private function _Hex2String( __hex:uint ):String {
var __tempNum:uint = __hex >> 4;
var __tempNum2:uint = __hex & 0xF;
return String.fromCharCode( __tempNum+48 + uint(__tempNum>9)*7 )+String.fromCharCode( __tempNum2+48 + uint(__tempNum2>9)*7 );
}
/**
* N文字分の文字列を読み込む
* @param バイナリデータ
* @param データ長
*/
private function _readNstr( __bin:Array, __length:uint ):String {
var __i:uint;
var __retStr:String = "";
if ( __bin.length < __length ) {
__length = __bin.length;
}
for ( __i = 0; __i < __length; __i++ ) {
__retStr += __bin[0]? "1":"0";
__bin.shift();
}
return __retStr;
}
/**
* N文字分の数字を読み込む
* @param バイナリデータ
* @param データ長
*/
private function _readNnumber( __bin:Array, __length:uint ):uint {
var __i:uint;
var __retNum:uint = 0;
for ( __i = 0; __i < __length; __i++ ) {
__retNum <<= 1;
__retNum += __bin[0];
__bin.shift();
}
return __retNum;
}
/**
* 16進数の配列を2進数の配列に直す
* @param 16進数パターン
*/
private function _Hex2Bin( __hex:Array ):Array {
var __i:uint;
var __index:uint;
var __loopCount:uint = __hex.length;
var __retArray:Array = new Array( __loopCount * 8 );
for ( __i = 0; __i < __loopCount; __i++ ) {
__retArray[__index++] = (__hex[__i]>>7) & 1;
__retArray[__index++] = (__hex[__i]>>6) & 1;
__retArray[__index++] = (__hex[__i]>>5) & 1;
__retArray[__index++] = (__hex[__i]>>4) & 1;
__retArray[__index++] = (__hex[__i]>>3) & 1;
__retArray[__index++] = (__hex[__i]>>2) & 1;
__retArray[__index++] = (__hex[__i]>>1) & 1;
__retArray[__index++] = (__hex[__i]>>0) & 1;
}
return __retArray;
}
/**
* リードソロモン解析
* @param 解析データ
* @param 形式情報
*/
private function _ReedSolomon( __data:Array, __type:Array ):Array {
var __RSblock:Array;
var __retArray:Array = [];
var __dataNum:Array;
var __errorNum:Array;
var __i:uint;
var __loopCount:uint;
var __j:uint;
var __loopCount2:uint;
var __index:uint = 0;
var __correctNum:uint = 0;
switch( _qrVersion ) {
case 1:
switch( (__type[0] << 1) + (__type[1] << 0) ) {
case 0: // M
__RSblock = new Array(1);
__dataNum = [16];
__errorNum = [10];
break;
case 1: // L
__RSblock = new Array(1);
__dataNum = [19];
__errorNum = [7];
break;
case 2: // H
__RSblock = new Array(1);
__dataNum = [9];
__errorNum = [17];
break;
case 3: // Q
__RSblock = new Array(1);
__dataNum = [13];
__errorNum = [13];
break;
}
break;
case 2:
switch( (__type[0] << 1) + (__type[1] << 0) ) {
case 0: // M
__RSblock = new Array(1);
__dataNum = [28];
__errorNum = [16];
break;
case 1: // L
__RSblock = new Array(1);
__dataNum = [34];
__errorNum = [10];
break;
case 2: // H
__RSblock = new Array(1);
__dataNum = [16];
__errorNum = [28];
break;
case 3: // Q
__RSblock = new Array(1);
__dataNum = [22];
__errorNum = [22];
break;
}
break;
case 3:
switch( (__type[0] << 1) + (__type[1] << 0) ) {
case 0: // M
__RSblock = new Array(1);
__dataNum = [44];
__errorNum = [26];
break;
case 1: // L
__RSblock = new Array(1);
__dataNum = [55];
__errorNum = [15];
break;
case 2: // H
__RSblock = new Array(2);
__dataNum = [13,13];
__errorNum = [22,22];
break;
case 3: // Q
__RSblock = new Array(2);
__dataNum = [17,17];
__errorNum = [18,18];
break;
}
break;
case 4:
switch( (__type[0] << 1) + (__type[1] << 0) ) {
case 0: // M
__RSblock = new Array(2);
__dataNum = [32,32];
__errorNum = [18,18];
break;
case 1: // L
__RSblock = new Array(1);
__dataNum = [80];
__errorNum = [20];
break;
case 2: // H
__RSblock = new Array(4);
__dataNum = [9,9,9,9];
__errorNum = [16,16,16,16];
break;
case 3: // Q
__RSblock = new Array(2);
__dataNum = [24,24];
__errorNum = [26,26];
break;
}
break;
case 5:
switch( (__type[0] << 1) + (__type[1] << 0) ) {
case 0: // M
__RSblock = new Array(2);
__dataNum = [43, 43];
__errorNum = [24, 24];
break;
case 1: // L
__RSblock = new Array(1);
__dataNum = [108];
__errorNum = [26];
break;
case 2: // H
__RSblock = new Array(4);
__dataNum = [11, 11, 12, 12];
__errorNum = [22, 22, 22, 22];
break;
case 3: // Q
__RSblock = new Array(4);
__dataNum = [15, 15, 16, 16];
__errorNum = [18, 18,18,18];
break;
}
break;
case 6:
switch( (__type[0] << 1) + (__type[1] << 0) ) {
case 0: // M
__RSblock = new Array(4);
__dataNum = [27, 27, 27, 27];
__errorNum = [16, 16, 16, 16];
break;
case 1: // L
__RSblock = new Array(2);
__dataNum = [68, 68];
__errorNum = [18, 18];
break;
case 2: // H
__RSblock = new Array(4);
__dataNum = [15, 15, 15, 15];
__errorNum = [28, 28, 28, 28];
break;
case 3: // Q
__RSblock = new Array(4);
__dataNum = [19, 19, 19, 19];
__errorNum = [24, 24, 24, 24];
break;
}
break;
case 7:
switch( (__type[0] << 1) + (__type[1] << 0) ) {
case 0: // M
__RSblock = new Array(4);
__dataNum = [31, 31, 31, 31];
__errorNum = [18, 18, 18, 18];
break;
case 1: // L
__RSblock = new Array(2);
__dataNum = [78, 78];
__errorNum = [20, 20];
break;
case 2: // H
__RSblock = new Array(5);
__dataNum = [13,13,13,13,14];
__errorNum = [26,26,26,26,26];
break;
case 3: // Q
__RSblock = new Array(6);
__dataNum = [14,14,15,15,15,15];
__errorNum = [18,18,18,18,18,18];
break;
}
break;
case 8:
switch( (__type[0] << 1) + (__type[1] << 0) ) {
case 0: // M
__RSblock = new Array(4);
__dataNum = [38, 38, 39, 39];
__errorNum = [22, 22, 22, 22];
break;
case 1: // L
__RSblock = new Array(2);
__dataNum = [97, 97];
__errorNum = [24, 24];
break;
case 2: // H
__RSblock = new Array(6);
__dataNum = [14, 14, 14, 14, 15, 15];
__errorNum = [26, 26, 26, 26, 26, 26];
break;
case 3: // Q
__RSblock = new Array(6);
__dataNum = [18, 18, 18, 18, 19, 19];
__errorNum = [22, 22, 22, 22, 22, 22];
break;
}
break;
case 9:
switch( (__type[0] << 1) + (__type[1] << 0) ) {
case 0: // M
__RSblock = new Array(5);
__dataNum = [36, 36, 36, 37, 37];
__errorNum = [22, 22, 22, 22, 22];
break;
case 1: // L
__RSblock = new Array(2);
__dataNum = [116, 116];
__errorNum = [30, 30];
break;
case 2: // H
__RSblock = new Array(8);
__dataNum = [12, 12, 12, 12, 13, 13, 13, 13];
__errorNum = [24, 24, 24, 24, 24, 24, 24, 24];
break;
case 3: // Q
__RSblock = new Array(8);
__dataNum = [16, 16, 16, 16, 17, 17, 17, 17];
__errorNum = [20, 20, 20, 20, 20, 20, 20, 20];
break;
}
break;
case 10:
switch( (__type[0] << 1) + (__type[1] << 0) ) {
case 0: // M
__RSblock = new Array(5);
__dataNum = [43, 43, 43, 43, 44];
__errorNum = [26, 26, 26, 26, 26];
break;
case 1: // L
__RSblock = new Array(4);
__dataNum = [68, 68, 69, 69];
__errorNum = [18, 18, 18, 18];
break;
case 2: // H
__RSblock = new Array(8);
__dataNum = [15, 15, 15, 15, 15, 15, 16, 16];
__errorNum = [28, 28, 28, 28, 28, 28, 28, 28];
break;
case 3: // Q
__RSblock = new Array(8);
__dataNum = [19, 19, 19, 19, 19, 19, 20, 20];
__errorNum = [24, 24, 24, 24, 24, 24, 24, 24];
break;
}
break;
default:
//trace( _qrVersion + ", " + (__type[0] << 1) + (__type[1] << 0) );
return [];
break
}
__loopCount = __RSblock.length;
for ( __i = 0; __i < __loopCount; __i++) {
__RSblock[__i] = new Array();
}
__loopCount2 = __dataNum[__loopCount-1];
for ( __j = 0; __j < __loopCount2; __j++) {
for ( __i = 0; __i < __loopCount; __i++) {
// ここに条件をいれないといけない気がする。 j < datanum とか
if( __j < __dataNum[__i] ){
__RSblock[__i].push( [ _readByteData(__data[__index++]) ] );
}
}
}
__correctNum = __errorNum[0] * 0.5;
if( _qrVersion == 1 ){
switch( (__type[0] << 1) + (__type[1] << 0) ){
case 0:
__correctNum = 4;
break;
case 1:
__correctNum = 2;
break;
case 2:
__correctNum = 8;
break;
case 3:
__correctNum = 6;
break;
}
}
if( (_qrVersion == 2) && ( ( (__type[0] << 1) + (__type[1] << 0) ) == 1 ) ){
__correctNum = 4;
}
if( (_qrVersion == 3) && ( ( (__type[0] << 1) + (__type[1] << 0) ) == 1 ) ){
__correctNum = 7;
}
__loopCount2 = __errorNum[0]; // 全部同じなので[0]
for ( __j = 0; __j < __loopCount2; __j++) {
for ( __i = 0; __i < __loopCount; __i++) {
__RSblock[__i].push( [ _readByteData(__data[__index++]) ] );
}
}
//誤り訂正
for ( __i = 0; __i < __loopCount; __i++ ) {
_RS8bit( __RSblock[__i], __dataNum[__i], __errorNum[__i], __correctNum );
}
//データ再配置
for ( __i = 0; __i < __loopCount; __i++) {
__loopCount2 = __dataNum[__i];
for ( __j = 0; __j < __loopCount2; __j++) {
__retArray.push(__RSblock[__i][__j]);
}
}
return __retArray;
}
/**
* 1バイト分の情報を読み込む
* @param 情報ビット列
*/
private function _readByteData( __byte:Array ):uint {
return (__byte[0] << 7) + (__byte[1] << 6) + (__byte[2] << 5) + (__byte[3] << 4) + (__byte[4] << 3) + (__byte[5] << 2) + (__byte[6] << 1) + (__byte[7] << 0) ;
}
/**
* 情報のバイト列を読み取る
* @param QRコードビットパターン
*/
private function _getWords( __qr:Array ):Array {
var __checkArray:Array = [];
var __cordNum:Array = [
26, 44, 70, 100, 134, 172, 196, 242, 292, 346,
404, 466, 532, 581, 655, 733, 815, 901, 991, 1085,
1156, 1258, 1364, 1474, 1588, 1706, 1828, 1921, 2051, 2185,
2323, 2465, 2611, 2761, 2876, 3034, 3196, 3362, 3532, 3706
]; // バージョン1~40までの総コード語数
var __retArray:Array = new Array( __cordNum[_qrVersion - 1] );
var __i:uint;
// var __j:uint;
var __loopCount:uint = __retArray.length;
var __x:uint = _qrVersion*4 + 16;
var __y:uint = _qrVersion*4 + 16;
var __len:uint;
var __toUp:uint = 1;
var __toLeft:uint = 1;
var __index:uint = 0;
for ( __i = 0; __i < __loopCount; __i++ ) {
__retArray[__i] = new Array(8);
__checkArray[__i] = new Array(8);
// for( __j = 0; __j < 8; __j++ ){
// __checkArray[__i][__j] = new Array(2);
// }
}
for ( __i = 0; __i < __loopCount; __i++ ) {
for ( __len = 0; __len < 8; __len++ ) {
while ( _isFixed(__x, __y) ) {
if ( __x == 6 ){
__x--;
}
if ( __toLeft ) {
__x--;
__toLeft = 0;
} else {
__toLeft = 1;
if ( __toUp ) {
if ( __y == 0 ) {
__x--;
__toUp = 0;
} else {
__x++;
__y--;
}
} else {
if ( __y == (_qrVersion*4+16) ) {
__x--;
__toUp = 1;
} else {
__x++;
__y++;
}
}
}
}
_fixed[__y][__x] = 1;
__retArray[__index][__len] = __qr[__y][__x];
__checkArray[__index][__len] = [__x, __y];
}
__index++;
}
return __retArray;
}
/**
* QRコードのマスクを解除する関数
* @param 形式情報
*/
private function _unmask( __typeData:Array ):Array {
var __qrSize:uint = _qrVersion * 4 + 17;
var __retArray:Array = new Array(__qrSize);
var __i:uint;
var __j:uint;
for ( __j = 0; __j < __qrSize; __j++ ) {
__retArray[__j] = new Array(__qrSize);
}
switch( (__typeData[2]<<2)+(__typeData[3]<<1)+(__typeData[4]) ) {
case 0: //(i+j)mod2==0
for ( __j = 0; __j < __qrSize; __j++ ) {
for ( __i = 0; __i < __qrSize; __i++ ) {
__retArray[__i][__j] = _getQR(__j, __i) ^ int( ( (__i + __j) % 2) == 0 );
}
}
break;
case 1: // i mod2==0
for ( __j = 0; __j < __qrSize; __j++ ) {
for ( __i = 0; __i < __qrSize; __i++ ) {
__retArray[__i][__j] = _getQR(__j, __i) ^ int( ( __i % 2) == 0 );
}
}
break;
case 2: //j mod3==0
for ( __j = 0; __j < __qrSize; __j++ ) {
for ( __i = 0; __i < __qrSize; __i++ ) {
__retArray[__i][__j] = _getQR(__j, __i) ^ int( ( __j % 3) == 0 );
}
}
break;
case 3: //(i+j)mod3==0
for ( __j = 0; __j < __qrSize; __j++ ) {
for ( __i = 0; __i < __qrSize; __i++ ) {
__retArray[__i][__j] = _getQR(__j, __i) ^ int( ( (__i + __j) % 3) == 0 );
}
}
break;
case 4: //((idiv2)+(jdiv3))mod2==0
for ( __j = 0; __j < __qrSize; __j++ ) {
for ( __i = 0; __i < __qrSize; __i++ ) {
__retArray[__i][__j] = _getQR(__j, __i) ^ int( ( (Math.floor(__i*0.5) + Math.floor(__j/3.0)) % 2) == 0 );
}
}
break;
case 5: //((ij)mod2+(ij)mod3)==0
for ( __j = 0; __j < __qrSize; __j++ ) {
for ( __i = 0; __i < __qrSize; __i++ ) {
__retArray[__i][__j] = _getQR(__j, __i) ^ int( ( ( (__i*__j) % 2 ) + ((__i*__j) % 3 ) ) == 0 );
}
}
break;
case 6: //((ij)mod2+(ij)mod3)mod2==0
for ( __j = 0; __j < __qrSize; __j++ ) {
for ( __i = 0; __i < __qrSize; __i++ ) {
__retArray[__i][__j] = _getQR(__j, __i) ^ int( ( ( ( (__i*__j) % 2 ) + ((__i*__j) % 3 ) ) % 2 ) == 0 );
}
}
break;
case 7: //((i+j)mod2+(ij)mod3)mod2==0
for ( __j = 0; __j < __qrSize; __j++ ) {
for ( __i = 0; __i < __qrSize; __i++ ) {
__retArray[__i][__j] = _getQR(__j, __i) ^ int( ( ( ( (__i+__j) % 2 ) + ((__i*__j) % 3 ) ) % 2 ) == 0 );
}
}
break;
}
return __retArray;
}
/**
* 機能パターンの範囲をバージョン別に指定する関数
*/
private function _makeFixed():void {
var __i:int;
var __j:int;
var __k:int;
var __l:int;
_fixed = new Array( _qrVersion * 4 + 17 );
for ( __i = 0; __i < (_qrVersion * 4 + 17); __i++) {
_fixed[__i] = new Array( _qrVersion * 4 + 17 );
}
switch( _qrVersion ) {
case 1:
for ( __i = 0; __i < 8; __i++) {
for ( __j = 0; __j < 8; __j++) {
_fixed[__j][__i] =
_fixed[__j][_qrVersion*4 + 9 + __i] =
_fixed[_qrVersion*4 + 9 + __j][__i] = 1;
}
}
for (__i = 0; __i < 8; __i++) {
_fixed[8][__i] =
_fixed[__i][8] =
_fixed[_qrVersion * 4 + 9+__i][8] =
_fixed[8][_qrVersion * 4 + 9+__i] = 1;
}
_fixed[8][8] = 1;
for ( __i = 9; __i < _qrVersion * 4 + 9; __i++ ) {
_fixed[6][__i] = _fixed[__i][6] = 1;
}
break;
case 2:
case 3:
case 4:
case 5:
case 6:
for ( __i = 0; __i < 8; __i++) {
for ( __j = 0; __j < 8; __j++) {
_fixed[__j][__i] =
_fixed[__j][_qrVersion*4 + 9 + __i] =
_fixed[_qrVersion*4 + 9 + __j][__i] = 1;
}
}
for (__i = 0; __i < 8; __i++) {
_fixed[8][__i] =
_fixed[__i][8] =
_fixed[_qrVersion * 4 + 9+__i][8] =
_fixed[8][_qrVersion * 4 + 9+__i] = 1;
}
_fixed[8][8] = 1;
for ( __i = -2; __i <= 2; __i++ ) {
for ( __j = -2; __j <= 2; __j++ ) {
_fixed[_qrVersion * 4 + 10 + __j][_qrVersion * 4 + 10 + __i] = 1;
}
}
for ( __i = 9; __i < _qrVersion * 4 + 9; __i++ ) {
_fixed[6][__i] = _fixed[__i][6] = 1;
}
break;
case 7:
case 8:
case 9:
case 10:
case 12:
case 13:
for ( __i = 0; __i < 3; __i++) {
for ( __j = 0; __j < 6; __j++) {
_fixed[__j][_qrVersion*4 + 6 + __i] =
_fixed[_qrVersion*4 + 6 + __i][__j] = 1;
}
}
for ( __i = 0; __i < 8; __i++) {
for ( __j = 0; __j < 8; __j++) {
_fixed[__j][__i] =
_fixed[__j][_qrVersion*4 + 9 + __i] =
_fixed[_qrVersion*4 + 9 + __j][__i] = 1;
}
}
for (__i = 0; __i < 8; __i++) {
_fixed[8][__i] =
_fixed[__i][8] =
_fixed[_qrVersion * 4 + 9+__i][8] =
_fixed[8][_qrVersion * 4 + 9+__i] = 1;
}
_fixed[8][8] = 1;
for( __k = 6; __k <= (_qrVersion*4 + 10); __k += (_qrVersion*2 + 2)){
for( __l = 6; __l <= (_qrVersion*4 + 10); __l += (_qrVersion*2 + 2)){
if(
!((__k == 6) && (__l == (_qrVersion*4 + 10))) &&
!((__l == 6) && (__k == (_qrVersion*4 + 10)))
){
for ( __i = -2; __i <= 2; __i++ ) {
for ( __j = -2; __j <= 2; __j++ ) {
_fixed[__k + __j][__l + __i] = 1;
}
}
}
}
}
for ( __i = 9; __i < _qrVersion * 4 + 9; __i++ ) {
_fixed[6][__i] = _fixed[__i][6] = 1;
}
break;
}
}
/**
* 座標(x,y)のビットパターンを返す関数
*/
private function _getQR(x:uint, y:uint):uint {
return _qr[y][x];
}
/**
* 機能パターン情報を返す関数
*/
private function _isFixed(x:uint, y:uint):uint {
return _fixed[y][x];
}
/**
* 形式情報をデコードする関数
*/
private function _decode15_5():Array {
var __str1:Array = new Array(15);
var __str2:Array = new Array(15);
var __i:uint;
var __j:uint;
var __S:Array = new Array(5); // シンドローム
var __s:Array = new Array(3); // 誤り位置変数
var __tempNum1:G4Num;
var __tempNum2:G4Num;
var __retArray:Array = new Array(5); // データ部
var __checkPattern:Array = new Array(15); //マスク解除後の形式情報
// シンドローム配列初期化
for ( __j = 0; __j < 5; __j++ ) {
__S[__j] = new G4Num(-1);
}
// 形式情報を取得
for ( __i = 0; __i <= 5; __i++ ) {
__str1[__i] = _getQR(8, __i);
}
__str1[6] = _getQR(8, 7);
__str1[7] = _getQR(8, 8);
__str1[8] = _getQR(7, 8);
for ( __i = 0; __i <= 5; __i++ ) {
__str1[__i + 9] = _getQR(5 - __i, 8);
}
for ( __i = 0; __i <= 7; __i++ ) {
__str2[__i] = _getQR(_qrVersion * 4 + 16 - __i, 8);
}
for ( __i = 0; __i <= 6; __i++ ) {
__str2[8+__i] = _getQR(8, _qrVersion * 4 + 10 + __i);
}
// マスク解除
for ( __i = 0; __i < 15; __i++ ) {
__checkPattern[__i] = __str1[14 - __i] ^ _xorPattern[__i];
}
for ( __i = 0; __i < 15; __i++ ) {
if ( __checkPattern[__i] ) {
for ( __j = 0; __j < 5; __j+=2 ) {
__S[__j] = __S[__j].plus( new G4Num( __i * (__j + 1) ) );
}
}
}
__S[1] = __S[0].multiply( __S[0] );
__S[3] = __S[1].multiply( __S[1] );
__s[0] = new G4Num( __S[0].getPower() );
__tempNum1 = __S[4].plus( __S[1].multiply( __S[2] ) );
__tempNum2 = __S[2].plus( __S[0].multiply( __S[1] ) );
if ( (__tempNum1.getPower() < 0) || (__tempNum2.getPower() < 0) ) {
__s[1] = new G4Num( -1 );
} else {
__s[1] = new G4Num( __tempNum1.getPower() - __tempNum2.getPower() + 15 );
}
__tempNum1 = __S[1].multiply( __s[0] );
__tempNum2 = __S[0].multiply( __s[1] );
__s[2] = __S[2].plus( __tempNum1.plus( __tempNum2 ) );
for ( __i = 0; __i < 5; __i++ ) {
__tempNum1 = new G4Num( (__i) * 3 );
__tempNum2 = new G4Num( (__i) * 2 );
__tempNum1 = __tempNum1.plus( __tempNum2.multiply( __s[0] ) );
__tempNum2 = new G4Num( (__i) );
__tempNum1 = __tempNum1.plus( __tempNum2.multiply( __s[1] ) );
__tempNum1 = __tempNum1.plus( __s[2] );
if ( __tempNum1.getPower() < 0 ) {
__retArray[__i] = __checkPattern[__i] ^ 1;
} else {
__retArray[__i] = __checkPattern[__i];
}
}
return __retArray;
}
}
}