mirror of
https://github.com/zxing/zxing.git
synced 2024-11-10 04:54:04 -08:00
updated all actionscript files in accordance with the core library revision 1901
git-svn-id: https://zxing.googlecode.com/svn/trunk@2109 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
01c274cfd1
commit
9ee56c0b61
|
@ -20,10 +20,19 @@ package com.google.zxing
|
|||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
|
||||
public class BarcodeFormat
|
||||
{
|
||||
// No, we can't use an enum here. J2ME doesn't support it.
|
||||
|
||||
private static var VALUES:HashTable = new HashTable();
|
||||
|
||||
/** Aztec 2D barcode format. */
|
||||
public static var AZTEC:BarcodeFormat = new BarcodeFormat("AZTEC");
|
||||
/** CODABAR 1D format. */
|
||||
public static var CODABAR:BarcodeFormat = new BarcodeFormat("CODABAR");
|
||||
/** QR Code 2D barcode format. */
|
||||
public static var QR_CODE:BarcodeFormat = new BarcodeFormat("QR_CODE");
|
||||
/** DataMatrix 2D barcode format. */
|
||||
|
@ -32,24 +41,35 @@ public class BarcodeFormat
|
|||
public static var UPC_E:BarcodeFormat = new BarcodeFormat("UPC_E");
|
||||
/** UPC-A 1D format. */
|
||||
public static var UPC_A:BarcodeFormat = new BarcodeFormat("UPC_A");
|
||||
/** UPC/EAN extension format. Not a stand-alone format. */
|
||||
public static var UPC_EAN_EXTENSION:BarcodeFormat = new BarcodeFormat("UPC_EAN_EXTENSION");
|
||||
/** EAN-8 1D format. */
|
||||
public static var EAN_8:BarcodeFormat = new BarcodeFormat("EAN_8");
|
||||
/** EAN-13 1D format. */
|
||||
public static var EAN_13:BarcodeFormat = new BarcodeFormat("EAN_13");
|
||||
/** Code 128 1D format. */
|
||||
public static var CODE_128:BarcodeFormat = new BarcodeFormat("CODE_128");
|
||||
/** Code 93 1D format. */
|
||||
public static var CODE_93:BarcodeFormat = new BarcodeFormat("CODE_93");
|
||||
/** Code 39 1D format. */
|
||||
public static var CODE_39:BarcodeFormat = new BarcodeFormat("CODE_39");
|
||||
/** ITF (Interleaved Two of Five) 1D format. */
|
||||
public static var ITF:BarcodeFormat = new BarcodeFormat("ITF");
|
||||
/** PDF417 format. */
|
||||
public static var PDF417:BarcodeFormat = new BarcodeFormat("PDF417");
|
||||
|
||||
/** RSS 14 */
|
||||
public static var RSS_14:BarcodeFormat = new BarcodeFormat("RSS_14");
|
||||
/** RSS EXPANDED */
|
||||
public static var RSS_EXPANDED:BarcodeFormat = new BarcodeFormat("RSS_EXPANDED");
|
||||
/** MAXICODE */
|
||||
public static var MAXICODE:BarcodeFormat = new BarcodeFormat("MAXICODE");
|
||||
|
||||
private var _name:String;
|
||||
|
||||
public function BarcodeFormat(name:String)
|
||||
{
|
||||
this._name = name;
|
||||
VALUES._put(name, this);
|
||||
}
|
||||
|
||||
public function toString():String
|
||||
|
@ -57,25 +77,24 @@ public class BarcodeFormat
|
|||
return this._name;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
public function get name():String
|
||||
{
|
||||
return this._name;
|
||||
}
|
||||
|
||||
/*
|
||||
public function Equals(other:BarcodeFormat):Boolean
|
||||
{
|
||||
if (this._name == other.name)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*/
|
||||
public static function valueOf(name:String):BarcodeFormat
|
||||
{
|
||||
if (name == null || name.length == 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
var format:BarcodeFormat = (VALUES._get(name) as BarcodeFormat);
|
||||
if (format == null)
|
||||
{
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return format;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -123,7 +123,6 @@ public final class BufferedImageLuminanceSource extends LuminanceSource
|
|||
|
||||
public override function crop(left:int, top:int, width:int, height:int):LuminanceSource
|
||||
{
|
||||
// BAS : todo
|
||||
return new BufferedImageLuminanceSource(image, left, top, width, height);
|
||||
}
|
||||
|
||||
|
@ -133,7 +132,6 @@ public final class BufferedImageLuminanceSource extends LuminanceSource
|
|||
public override function isRotateSupported():Boolean
|
||||
{
|
||||
return false;
|
||||
//Bas : TOO
|
||||
//return image.getType() != BufferedImage.TYPE_CUSTOM;
|
||||
}
|
||||
|
||||
|
@ -144,7 +142,7 @@ public final class BufferedImageLuminanceSource extends LuminanceSource
|
|||
{
|
||||
throw new Error("Rotate not supported");
|
||||
}
|
||||
// Bas : todo
|
||||
// todo
|
||||
return null;
|
||||
/*
|
||||
var sourceWidth:int = image.getWidth();
|
||||
|
|
39
actionscript/core/src/com/google/zxing/ChecksumException.as
Normal file
39
actionscript/core/src/com/google/zxing/ChecksumException.as
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing
|
||||
{
|
||||
|
||||
/**
|
||||
* Thrown when a barcode was successfully detected and decoded, but
|
||||
* was not returned because its checksum feature failed.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public class ChecksumException extends ReaderException {
|
||||
|
||||
private static var instance:ChecksumException = new ChecksumException();
|
||||
|
||||
public function ChecksumException() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public static function getChecksumInstance():ChecksumException {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -31,35 +31,53 @@ package com.google.zxing
|
|||
/**
|
||||
* Unspecified, application-specific hint. Maps to an unspecified {@link Object}.
|
||||
*/
|
||||
public static var OTHER:DecodeHintType = new DecodeHintType();
|
||||
public static var OTHER:DecodeHintType = new DecodeHintType("OTHER");
|
||||
|
||||
/**
|
||||
* Image is a pure monochrome image of a barcode. Doesn't matter what it maps to;
|
||||
* use {@link Boolean#TRUE}.
|
||||
*/
|
||||
public static var PURE_BARCODE:DecodeHintType = new DecodeHintType();
|
||||
public static var PURE_BARCODE:DecodeHintType = new DecodeHintType("PURE_BARCODE");
|
||||
|
||||
/**
|
||||
*
|
||||
* Image is known to be of one of a few possible formats.
|
||||
* Maps to a {@link java.util.Vector} of {@link BarcodeFormat}s.
|
||||
*/
|
||||
public static var POSSIBLE_FORMATS:DecodeHintType = new DecodeHintType();
|
||||
public static var POSSIBLE_FORMATS:DecodeHintType = new DecodeHintType("POSSIBLE_FORMATS");
|
||||
|
||||
/**
|
||||
* Spend more time to try to find a barcode; optimize for accuracy, not speed.
|
||||
* Doesn't matter what it maps to; use {@link Boolean#TRUE}.
|
||||
*/
|
||||
public static var TRY_HARDER:DecodeHintType = new DecodeHintType();
|
||||
public static var TRY_HARDER:DecodeHintType = new DecodeHintType("TRY_HARDER");
|
||||
|
||||
/**
|
||||
* Specifies what character encoding to use when decoding, where applicable (type String)
|
||||
*/
|
||||
public static var CHARACTER_SET:DecodeHintType = new DecodeHintType("CHARACTER_SET");
|
||||
|
||||
/**
|
||||
* Allowed lengths of encoded data -- reject anything else. Maps to an int[].
|
||||
*/
|
||||
public static var ALLOWED_LENGTHS:DecodeHintType = new DecodeHintType();
|
||||
public static var ALLOWED_LENGTHS:DecodeHintType = new DecodeHintType("ALLOWED_LENGTHS");
|
||||
|
||||
/**
|
||||
* Assume Code 39 codes employ a check digit. Maps to {@link Boolean}.
|
||||
*/
|
||||
public static var ASSUME_CODE_39_CHECK_DIGIT:DecodeHintType = new DecodeHintType("ASSUME_CODE_39_CHECK_DIGIT");
|
||||
|
||||
/**
|
||||
* The caller needs to be notified via callback when a possible {@link ResultPoint}
|
||||
* is found. Maps to a {@link ResultPointCallback}.
|
||||
*/
|
||||
public static var NEED_RESULT_POINT_CALLBACK:DecodeHintType = new DecodeHintType("NEED_RESULT_POINT_CALLBACK");
|
||||
|
||||
public function DecodeHintType() {
|
||||
}
|
||||
|
||||
public var DHtype:String;
|
||||
|
||||
public function DecodeHintType(aType:String)
|
||||
{
|
||||
DHtype = aType;
|
||||
}
|
||||
}
|
||||
}
|
40
actionscript/core/src/com/google/zxing/FormatException.as
Normal file
40
actionscript/core/src/com/google/zxing/FormatException.as
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing
|
||||
{
|
||||
|
||||
/**
|
||||
* Thrown when a barcode was successfully detected, but some aspect of
|
||||
* the content did not conform to the barcode's format rules. This could have
|
||||
* been due to a mis-detection.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public class FormatException extends ReaderException {
|
||||
|
||||
private static var instance:FormatException = new FormatException();
|
||||
|
||||
public function FormatException() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public static function getFormatInstance():FormatException {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -13,8 +13,13 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package com.google.zxing
|
||||
{
|
||||
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
|
||||
public class LuminanceSource
|
||||
{
|
||||
/**
|
||||
|
@ -109,6 +114,32 @@ package com.google.zxing
|
|||
public function rotateCounterClockwise():LuminanceSource {
|
||||
throw new Error("This luminance source does not support rotation.");
|
||||
}
|
||||
|
||||
public function toString():String
|
||||
{
|
||||
var row:Array = new Array(width);
|
||||
var result:StringBuilder = new StringBuilder(height * (width + 1));
|
||||
for (var y:int = 0; y < height; y++) {
|
||||
row = getRow(y, row);
|
||||
for (var x:int = 0; x < width; x++) {
|
||||
var luminance:int = row[x] & 0xFF;
|
||||
var c:String;
|
||||
if (luminance < 0x40) {
|
||||
c = '#';
|
||||
} else if (luminance < 0x80) {
|
||||
c = '+';
|
||||
} else if (luminance < 0xC0) {
|
||||
c = '.';
|
||||
} else {
|
||||
c = ' ';
|
||||
}
|
||||
result.Append(c);
|
||||
}
|
||||
result.Append('\n');
|
||||
}
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -15,13 +15,16 @@
|
|||
*/
|
||||
package com.google.zxing
|
||||
{
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.aztec.AztecReader;
|
||||
import com.google.zxing.common.flexdatatypes.ArrayList;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.datamatrix.DataMatrixReader;
|
||||
import com.google.zxing.oned.MultiFormatOneDReader;
|
||||
import com.google.zxing.pdf417.PDF417Reader;
|
||||
import com.google.zxing.qrcode.QRCodeReader;
|
||||
import com.google.zxing.datamatrix.DataMatrixReader;
|
||||
import com.google.zxing.Reader;
|
||||
import com.google.zxing.maxicode.MaxiCodeReader;
|
||||
import com.google.zxing.common.flexdatatypes.ArrayList;
|
||||
|
||||
/**
|
||||
* MultiFormatReader is a convenience class and the main entry point into the library for most uses.
|
||||
* By default it attempts to decode all barcode formats that the library supports. Optionally, you
|
||||
|
@ -86,10 +89,14 @@ package com.google.zxing
|
|||
var addOneDReader:Boolean =
|
||||
(formats.indexOf(BarcodeFormat.UPC_A) != -1)||
|
||||
(formats.indexOf(BarcodeFormat.UPC_E) != -1)||
|
||||
(formats.indexOf(BarcodeFormat.CODABAR) != -1)||
|
||||
(formats.indexOf(BarcodeFormat.ITF) != -1)||
|
||||
(formats.indexOf(BarcodeFormat.EAN_13) != -1)||
|
||||
(formats.indexOf(BarcodeFormat.EAN_8) != -1)||
|
||||
(formats.indexOf(BarcodeFormat.RSS_14) != -1)||
|
||||
(formats.indexOf(BarcodeFormat.RSS_EXPANDED) != -1)||
|
||||
(formats.indexOf(BarcodeFormat.CODE_39) != -1)||
|
||||
(formats.indexOf(BarcodeFormat.CODE_93) != -1)||
|
||||
(formats.indexOf(BarcodeFormat.CODE_128) != -1);
|
||||
// Put 1D readers upfront in "normal" mode
|
||||
|
||||
|
@ -105,11 +112,17 @@ package com.google.zxing
|
|||
if (formats.indexOf(BarcodeFormat.PDF417) != -1) {
|
||||
readers.addElement(new PDF417Reader());
|
||||
}
|
||||
|
||||
if (formats.indexOf(BarcodeFormat.AZTEC) != -1) {
|
||||
readers.addElement(new AztecReader());
|
||||
}
|
||||
// TODO re-enable once Data Matrix is ready
|
||||
if (formats.indexOf(BarcodeFormat.DATAMATRIX) != -1) {
|
||||
readers.Add(new DataMatrixReader());
|
||||
}
|
||||
if (formats.Contains(BarcodeFormat.MAXICODE)) {
|
||||
readers.addElement(new MaxiCodeReader());
|
||||
}
|
||||
|
||||
// At end in "try harder" mode
|
||||
if (addOneDReader && tryHarder)
|
||||
{
|
||||
|
@ -125,11 +138,10 @@ package com.google.zxing
|
|||
readers.Add(reader);
|
||||
}
|
||||
readers.Add(new QRCodeReader());
|
||||
// TODO re-enable once Data Matrix is ready
|
||||
readers.Add(new DataMatrixReader());
|
||||
|
||||
// TODO: Enable once PDF417 has passed QA
|
||||
readers.addElement(new PDF417Reader());
|
||||
readers.Add(new AztecReader());
|
||||
readers.Add(new PDF417Reader());
|
||||
readers.Add(new MaxiCodeReader());
|
||||
|
||||
if (tryHarder)
|
||||
{
|
||||
|
@ -138,6 +150,15 @@ package com.google.zxing
|
|||
}
|
||||
|
||||
}
|
||||
public function reset():void
|
||||
{
|
||||
var size:int = readers.size();
|
||||
for (var i:int = 0; i < size; i++)
|
||||
{
|
||||
var reader:Reader = Reader(readers.elementAt(i));
|
||||
reader.reset();
|
||||
}
|
||||
}
|
||||
|
||||
private function decodeInternal( image:BinaryBitmap):Result
|
||||
{
|
||||
|
@ -145,6 +166,7 @@ package com.google.zxing
|
|||
for (var i:int = 0; i < size; i++)
|
||||
{
|
||||
var reader:Reader = (readers.getObjectByIndex(i)) as Reader;
|
||||
try{
|
||||
try
|
||||
{
|
||||
var res:Result = reader.decode(image, hints);
|
||||
|
@ -153,8 +175,15 @@ package com.google.zxing
|
|||
catch ( re:ReaderException)
|
||||
{
|
||||
// continue
|
||||
var a:int=0;
|
||||
var a:int =3;
|
||||
}
|
||||
}
|
||||
catch (e:Error)
|
||||
{
|
||||
var b:int = 4;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// no decoder could decode the barcode
|
||||
|
|
|
@ -21,20 +21,37 @@ package com.google.zxing
|
|||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
import com.google.zxing.qrcode.QRCodeWriter
|
||||
import com.google.zxing.oned.Code128Writer;
|
||||
import com.google.zxing.oned.Code39Writer;
|
||||
import com.google.zxing.oned.EAN13Writer;
|
||||
import com.google.zxing.oned.EAN8Writer;
|
||||
import com.google.zxing.oned.ITFWriter;
|
||||
import com.google.zxing.oned.UPCAWriter;
|
||||
import com.google.zxing.pdf417.encoder.PDF417Writer;
|
||||
|
||||
public function encode(contents:String, format:BarcodeFormat=null,width:int=0,height:int=0, hints:HashTable=null):Object{
|
||||
|
||||
var writer:Writer;
|
||||
if (format == BarcodeFormat.EAN_8) {
|
||||
return (new EAN8Writer()).encode(contents, format, width, height, hints);
|
||||
writer = new EAN8Writer();
|
||||
} else if (format == BarcodeFormat.EAN_13) {
|
||||
return (new EAN13Writer()).encode(contents, format, width, height, hints);
|
||||
writer = new EAN13Writer();
|
||||
} else if (format == BarcodeFormat.UPC_A) {
|
||||
writer = new UPCAWriter();
|
||||
} else if (format == BarcodeFormat.CODE_39) {
|
||||
writer = new Code39Writer();
|
||||
} else if (format == BarcodeFormat.CODE_128) {
|
||||
writer = new Code128Writer();
|
||||
} else if (format == BarcodeFormat.ITF) {
|
||||
writer = new ITFWriter();
|
||||
} else if (format == BarcodeFormat.PDF417) {
|
||||
writer = new PDF417Writer();
|
||||
} else if (format == BarcodeFormat.QR_CODE) {
|
||||
return (new QRCodeWriter()).encode(contents, format, width, height, hints);
|
||||
writer = new QRCodeWriter();
|
||||
} else {
|
||||
throw new IllegalArgumentException("No encoder available for format " + format);
|
||||
}
|
||||
return writer.encode(contents, format, width, height, hints);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
39
actionscript/core/src/com/google/zxing/NotFoundException.as
Normal file
39
actionscript/core/src/com/google/zxing/NotFoundException.as
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing
|
||||
{
|
||||
|
||||
/**
|
||||
* Thrown when a barcode was not found in the image. It might have been
|
||||
* partially detected but could not be confirmed.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public class NotFoundException extends ReaderException {
|
||||
|
||||
private static var instance:NotFoundException = new NotFoundException();
|
||||
|
||||
public function NotFoundException() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public static function getNotFoundInstance():NotFoundException {
|
||||
return instance;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -45,5 +45,6 @@ package com.google.zxing
|
|||
* @throws ReaderException if the barcode cannot be located or decoded for any reason
|
||||
*/
|
||||
function decode(image:BinaryBitmap, hints:HashTable=null):Result;
|
||||
function reset():void;
|
||||
}
|
||||
}
|
|
@ -24,27 +24,33 @@ package com.google.zxing
|
|||
{
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
import com.google.zxing.common.flexdatatypes.Enumeration;
|
||||
|
||||
//BAS : made public for debugging
|
||||
private var text:String;
|
||||
private var rawBytes:Array;
|
||||
private var resultPoints:Array;
|
||||
private var format:BarcodeFormat;
|
||||
private var resultMetadata:HashTable;
|
||||
protected var text:String;
|
||||
protected var rawBytes:Array;
|
||||
protected var resultPoints:Array;
|
||||
protected var format:BarcodeFormat;
|
||||
protected var resultMetadata:HashTable;
|
||||
protected var timestamp:Number;
|
||||
|
||||
public function Result( text:String,
|
||||
rawBytes:Array,
|
||||
resultPoints:Array,
|
||||
format:BarcodeFormat)
|
||||
format:BarcodeFormat,
|
||||
timestamp:Number = 0)
|
||||
{
|
||||
if (text == null && rawBytes == null) {
|
||||
throw new IllegalArgumentException("Result : Text and bytes are both null");
|
||||
}
|
||||
|
||||
|
||||
if (timestamp == 0) { timestamp = Math.round((new Date()).getTime()/1000); }
|
||||
this.text = text;
|
||||
this.rawBytes = rawBytes;
|
||||
this.resultPoints = resultPoints;
|
||||
this.format = format;
|
||||
this.resultMetadata = null;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,7 +105,51 @@ package com.google.zxing
|
|||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function putAllMetadata(metadata:HashTable ):void
|
||||
{
|
||||
if (metadata != null) {
|
||||
if (resultMetadata == null) {
|
||||
resultMetadata = metadata;
|
||||
} else {
|
||||
var e:Enumeration = new Enumeration(metadata.keys());
|
||||
while (e.hasMoreElement()) {
|
||||
var key:ResultMetadataType = (e.nextElement() as ResultMetadataType);
|
||||
var value:Object = metadata._get(key);
|
||||
resultMetadata._put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function addResultPoints(newPoints:Array):void
|
||||
{
|
||||
if (resultPoints == null) {
|
||||
resultPoints = newPoints;
|
||||
} else if (newPoints != null && newPoints.length > 0) {
|
||||
var allPoints:Array = new Array(resultPoints.length + newPoints.length);
|
||||
//System.arraycopy(resultPoints, 0, allPoints, 0, resultPoints.length);
|
||||
for (var i:int=0;i<resultPoints.length;i++)
|
||||
{
|
||||
allPoints[i] = resultPoints[i];
|
||||
}
|
||||
for (var j:int=0;j<newPoints.length;j++)
|
||||
{
|
||||
allPoints[i + resultPoints.length] = newPoints[i];
|
||||
}
|
||||
|
||||
//System.arraycopy(newPoints, 0, allPoints, resultPoints.length, newPoints.length);
|
||||
resultPoints = allPoints;
|
||||
}
|
||||
}
|
||||
|
||||
public function getTimestamp():Number
|
||||
{
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,13 +1,16 @@
|
|||
package com.google.zxing
|
||||
{
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
|
||||
public class ResultMetadataType
|
||||
{
|
||||
// No, we can't use an enum here. J2ME doesn't support it.
|
||||
// No, we can't use an enum here. J2ME doesn't support it.
|
||||
|
||||
/**
|
||||
* Unspecified, application-specific metadata. Maps to an unspecified {@link Object}.
|
||||
*/
|
||||
public static var OTHER:ResultMetadataType = new ResultMetadataType();
|
||||
public static var OTHER:ResultMetadataType = new ResultMetadataType("OTHER");
|
||||
|
||||
/**
|
||||
* Denotes the likely approximate orientation of the barcode in the image. This value
|
||||
|
@ -16,7 +19,7 @@ package com.google.zxing
|
|||
* said to have orientation "90". This key maps to an {@link Integer} whose
|
||||
* value is in the range [0,360).
|
||||
*/
|
||||
public static var ORIENTATION:ResultMetadataType = new ResultMetadataType();
|
||||
public static var ORIENTATION:ResultMetadataType = new ResultMetadataType("ORIENTATION");
|
||||
|
||||
/**
|
||||
* <p>2D barcode formats typically encode text, but allow for a sort of 'byte mode'
|
||||
|
@ -27,19 +30,63 @@ package com.google.zxing
|
|||
* <p>This maps to a {@link java.util.Vector} of byte arrays corresponding to the
|
||||
* raw bytes in the byte segments in the barcode, in order.</p>
|
||||
*/
|
||||
public static var BYTE_SEGMENTS:ResultMetadataType = new ResultMetadataType();
|
||||
public static var BYTE_SEGMENTS:ResultMetadataType = new ResultMetadataType("BYTE SEGMENTS");
|
||||
|
||||
/**
|
||||
* Error correction level used, if applicable. The value type depends on the
|
||||
* format, but is typically a String.
|
||||
*/
|
||||
public static var ERROR_CORRECTION_LEVEL:ResultMetadataType = new ResultMetadataType();
|
||||
public static var ERROR_CORRECTION_LEVEL:ResultMetadataType = new ResultMetadataType("ORIENTATION");
|
||||
|
||||
|
||||
public function ResultMetadataType() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* For some periodicals, indicates the issue number as an {@link Integer}.
|
||||
*/
|
||||
public static var ISSUE_NUMBER:ResultMetadataType = new ResultMetadataType("ISSUE_NUMBER");
|
||||
|
||||
/**
|
||||
* For some products, indicates the suggested retail price in the barcode as a
|
||||
* formatted {@link String}.
|
||||
*/
|
||||
public static var SUGGESTED_PRICE:ResultMetadataType = new ResultMetadataType("SUGGESTED_PRICE");
|
||||
|
||||
/**
|
||||
* For some products, the possible country of manufacture as a {@link String} denoting the
|
||||
* ISO country code. Some map to multiple possible countries, like "US/CA".
|
||||
*/
|
||||
public static var POSSIBLE_COUNTRY:ResultMetadataType = new ResultMetadataType("POSSIBLE_COUNTRY");
|
||||
|
||||
private var name:String ;
|
||||
|
||||
private static var VALUES:HashTable = new HashTable();
|
||||
|
||||
public function ResultMetadataType(name:String = "") {
|
||||
this.name = name;
|
||||
//VALUES.put(name, this);
|
||||
}
|
||||
|
||||
public function getName():String {
|
||||
return name;
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
return name;
|
||||
}
|
||||
|
||||
public static function valueOf(name:String):ResultMetadataType
|
||||
{
|
||||
if (name == null || name.length == 0)
|
||||
{
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
var format:ResultMetadataType = ResultMetadataType(VALUES._get(name));
|
||||
if (format == null)
|
||||
{
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return format;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -26,9 +26,8 @@ package com.google.zxing
|
|||
|
||||
public class ResultPoint
|
||||
{
|
||||
|
||||
private var x:Number;
|
||||
private var y:Number;
|
||||
protected var x:Number;
|
||||
protected var y:Number;
|
||||
|
||||
public function ResultPoint(x:Number, y:Number)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright 2009 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing
|
||||
{
|
||||
|
||||
/**
|
||||
* Callback which is invoked when a possible result point (significant
|
||||
* point in the barcode image such as a corner) is found.
|
||||
*
|
||||
* @see DecodeHintType#NEED_RESULT_POINT_CALLBACK
|
||||
*/
|
||||
public interface ResultPointCallback {
|
||||
|
||||
function foundPossibleResultPoint(point:ResultPoint ):void;
|
||||
|
||||
}
|
||||
}
|
|
@ -26,15 +26,16 @@ package com.google.zxing
|
|||
import com.google.zxing.common.ByteMatrix;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param contents The contents to encode in the barcode
|
||||
* @param format The barcode format to generate
|
||||
* @param width The preferred width in pixels
|
||||
* @param height The preferred height in pixels
|
||||
* @param hints Additional parameters to supply to the encoder
|
||||
* @return The generated barcode as a Matrix of unsigned bytes (0 == black, 255 == white)
|
||||
*/
|
||||
function encode(contents:String, format:BarcodeFormat=null, width:int=0, height:int=0, hints:HashTable=null):Object
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param contents The contents to encode in the barcode
|
||||
* @param format The barcode format to generate
|
||||
* @param width The preferred width in pixels
|
||||
* @param height The preferred height in pixels
|
||||
* @param hints Additional parameters to supply to the encoder
|
||||
* @return The generated barcode as a Matrix of unsigned bytes (0 == black, 255 == white)
|
||||
*/
|
||||
function encode(contents:String, format:BarcodeFormat=null, width:int=0, height:int=0, hints:HashTable=null):Object;
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright 2010 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.aztec
|
||||
{
|
||||
import com.google.zxing.common.DetectorResult;
|
||||
|
||||
public final class AztecDetectorResult extends DetectorResult
|
||||
{
|
||||
|
||||
import com.google.zxing.ResultPoint;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.common.DetectorResult;
|
||||
|
||||
|
||||
private var compact:Boolean;
|
||||
private var nbDatablocks:int;
|
||||
private var nbLayers:int;
|
||||
|
||||
public function AztecDetectorResult(bits:BitMatrix , points:Array, compact:Boolean, nbDatablocks:int, nbLayers:int)
|
||||
{
|
||||
super(bits, points);
|
||||
this.compact = compact;
|
||||
this.nbDatablocks = nbDatablocks;
|
||||
this.nbLayers = nbLayers;
|
||||
}
|
||||
|
||||
public function getNbLayers():int
|
||||
{
|
||||
return nbLayers;
|
||||
}
|
||||
|
||||
public function getNbDatablocks():int
|
||||
{
|
||||
return nbDatablocks;
|
||||
}
|
||||
|
||||
public function isCompact():Boolean
|
||||
{
|
||||
return compact;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
101
actionscript/core/src/com/google/zxing/aztec/AztecReader.as
Normal file
101
actionscript/core/src/com/google/zxing/aztec/AztecReader.as
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright 2010 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.aztec
|
||||
{
|
||||
import com.google.zxing.Reader;
|
||||
|
||||
public final class AztecReader implements Reader
|
||||
{
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.BinaryBitmap;
|
||||
import com.google.zxing.ChecksumException;
|
||||
import com.google.zxing.DecodeHintType;
|
||||
import com.google.zxing.FormatException;
|
||||
import com.google.zxing.NotFoundException;
|
||||
import com.google.zxing.Reader;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.ResultMetadataType;
|
||||
import com.google.zxing.ResultPoint;
|
||||
import com.google.zxing.ResultPointCallback;
|
||||
import com.google.zxing.common.DecoderResult;
|
||||
import com.google.zxing.aztec.decoder.Decoder;
|
||||
import com.google.zxing.aztec.detector.Detector;
|
||||
|
||||
import com.google.zxing.common.BitArray;
|
||||
import com.google.zxing.ResultPoint;
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
|
||||
/**
|
||||
* This implementation can detect and decode Aztec codes in an image.
|
||||
*
|
||||
* @author David Olivier
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Locates and decodes a Data Matrix code in an image.
|
||||
*
|
||||
* @return a String representing the content encoded by the Data Matrix code
|
||||
* @throws NotFoundException if a Data Matrix code cannot be found
|
||||
* @throws FormatException if a Data Matrix code cannot be decoded
|
||||
* @throws ChecksumException if error correction fails
|
||||
*/
|
||||
public function decode(image:BinaryBitmap, hints:HashTable=null ):Result
|
||||
{
|
||||
if (hints == null) {return decode(image, null);}
|
||||
|
||||
var detectorResult:AztecDetectorResult = new Detector(image.getBlackMatrix()).detect();
|
||||
var points:Array = detectorResult.getPoints();
|
||||
|
||||
if ((hints != null) && (detectorResult.getPoints() != null))
|
||||
{
|
||||
var rpcb:ResultPointCallback = hints._get(DecodeHintType.NEED_RESULT_POINT_CALLBACK) as ResultPointCallback;
|
||||
if (rpcb != null)
|
||||
{
|
||||
for (var i:int = 0; i < detectorResult.getPoints().length; i++)
|
||||
{
|
||||
rpcb.foundPossibleResultPoint(detectorResult.getPoints()[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var decoderResult:DecoderResult = new Decoder().decode(detectorResult);
|
||||
|
||||
var result:Result = new Result(decoderResult.getText(), decoderResult.getRawBytes(), points, BarcodeFormat.AZTEC);
|
||||
|
||||
if (decoderResult.getByteSegments() != null)
|
||||
{
|
||||
result.putMetadata(ResultMetadataType.BYTE_SEGMENTS, decoderResult.getByteSegments());
|
||||
}
|
||||
|
||||
if (decoderResult.getECLevel() != null)
|
||||
{
|
||||
result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, decoderResult.getECLevel().toString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public function reset():void
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
}
|
||||
}
|
19
actionscript/core/src/com/google/zxing/aztec/Point.as
Normal file
19
actionscript/core/src/com/google/zxing/aztec/Point.as
Normal file
|
@ -0,0 +1,19 @@
|
|||
// ActionScript file
|
||||
package com.google.zxing.aztec
|
||||
{
|
||||
import com.google.zxing.ResultPoint;
|
||||
|
||||
public class Point {
|
||||
public var x:int;
|
||||
public var y:int;
|
||||
|
||||
public function toResultPoint():ResultPoint {
|
||||
return new ResultPoint(x, y);
|
||||
}
|
||||
|
||||
public function Point( x:int, y:int) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
}
|
1054
actionscript/core/src/com/google/zxing/client/testClass.as
Normal file
1054
actionscript/core/src/com/google/zxing/client/testClass.as
Normal file
File diff suppressed because it is too large
Load diff
|
@ -44,7 +44,31 @@ package com.google.zxing.common
|
|||
public function getSize():int {
|
||||
return Size;
|
||||
}
|
||||
|
||||
|
||||
public function getSizeInBytes():int
|
||||
{
|
||||
return (this.Size + 7) >> 3;
|
||||
}
|
||||
|
||||
|
||||
private function ensureCapacity(size:int):void
|
||||
{
|
||||
if (size > bits.length << 5)
|
||||
{
|
||||
var newArray:Array = new Array(size);
|
||||
if (bits != null)
|
||||
{
|
||||
//System.Array.Copy(bytes, 0, newArray, 0, bytes.length);
|
||||
for (var i:int=0;i<bits.length;i++)
|
||||
{
|
||||
newArray[i] = bits[i];
|
||||
}
|
||||
}
|
||||
|
||||
this.bits = newArray;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param i bit to get
|
||||
* @return true iff bit i is set
|
||||
|
@ -132,6 +156,7 @@ package com.google.zxing.common
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return underlying array of ints. The first element holds the first 32 bits, and the least
|
||||
* significant bit is bit 0.
|
||||
|
@ -140,8 +165,7 @@ package com.google.zxing.common
|
|||
return bits;
|
||||
}
|
||||
|
||||
// bas : for debugging purposes
|
||||
public function setBitArray(a:Array):void {
|
||||
private function setBitArray(a:Array):void {
|
||||
bits = a;
|
||||
}
|
||||
public function setSize(siz:int):void {
|
||||
|
@ -171,6 +195,7 @@ package com.google.zxing.common
|
|||
}
|
||||
return new Array(arraySize);
|
||||
}
|
||||
|
||||
public function toString():String
|
||||
{
|
||||
var result:StringBuilder = new StringBuilder(this.Size);
|
||||
|
@ -184,5 +209,88 @@ package com.google.zxing.common
|
|||
}
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
public function appendBit(bit:Boolean):void
|
||||
{
|
||||
this.ensureCapacity(this.Size + 1);
|
||||
if (bit)
|
||||
{
|
||||
this.bits[this.Size >> 5] |= (1 << (this.Size & 0x1F));
|
||||
}
|
||||
this.Size++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the least-significant bits, from value, in order from most-significant to
|
||||
* least-significant. For example, appending 6 bits from 0x000001E will append the bits
|
||||
* 0, 1, 1, 1, 1, 0 in that order.
|
||||
*/
|
||||
public function appendBits(value:int, numBits:int):void {
|
||||
if (numBits < 0 || numBits > 32) {
|
||||
throw new IllegalArgumentException("Num bits must be between 0 and 32");
|
||||
}
|
||||
this.ensureCapacity(this.Size + numBits);
|
||||
for (var numBitsLeft:int = numBits; numBitsLeft > 0; numBitsLeft--) {
|
||||
appendBit(((value >> (numBitsLeft - 1)) & 0x01) == 1);
|
||||
}
|
||||
}
|
||||
|
||||
public function appendBitArray(other:BitArray):void {
|
||||
var otherSize:int = other.getSize();
|
||||
this.ensureCapacity(this.Size + otherSize);
|
||||
for (var i:int = 0; i < otherSize; i++) {
|
||||
appendBit(other._get(i));
|
||||
}
|
||||
}
|
||||
|
||||
public function xor(other:BitArray):void {
|
||||
if (bits.length != other.bits.length) {
|
||||
throw new IllegalArgumentException("Sizes don't match");
|
||||
}
|
||||
for (var i:int = 0; i < bits.length; i++) {
|
||||
// The last byte could be incomplete (i.e. not have 8 bits in
|
||||
// it) but there is no problem since 0 XOR 0 == 0.
|
||||
bits[i] ^= other.bits[i];
|
||||
}
|
||||
}
|
||||
/*
|
||||
private static function makeArray(size:int):Array {
|
||||
return new Array((size + 31) >> 5);
|
||||
}
|
||||
*
|
||||
/*
|
||||
public function toString():String {
|
||||
var result:StringBuffer = new StringBuffer(size);
|
||||
for (var i:int = 0; i < size; i++) {
|
||||
if ((i & 0x07) == 0) {
|
||||
result.append(' ');
|
||||
}
|
||||
result.append(get(i) ? 'X' : '.');
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
*/
|
||||
/**
|
||||
*
|
||||
* @param bitOffset first bit to start writing
|
||||
* @param array array to write into. Bytes are written most-significant byte first. This is the opposite
|
||||
* of the internal representation, which is exposed by {@link #getBitArray()}
|
||||
* @param offset position in array to start writing
|
||||
* @param numBytes how many bytes to write
|
||||
*/
|
||||
public function toBytes(bitOffset:int, array:Array, offset:int, numBytes:int):void
|
||||
{
|
||||
for (var i:int = 0; i < numBytes; i++) {
|
||||
var theByte:int = 0;
|
||||
for (var j:int = 0; j < 8; j++) {
|
||||
if (_get(bitOffset)) {
|
||||
theByte |= 1 << (7 - j);
|
||||
}
|
||||
bitOffset++;
|
||||
}
|
||||
array[offset + i] = theByte;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -35,9 +35,9 @@ package com.google.zxing.common
|
|||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
|
||||
private var width:int;
|
||||
private var height:int;
|
||||
private var rowSize:int;
|
||||
public var width:int;
|
||||
public var height:int;
|
||||
public var rowSize:int;
|
||||
public var bits:Array;
|
||||
|
||||
|
||||
|
@ -59,14 +59,9 @@ package com.google.zxing.common
|
|||
}
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
var rowSize:int = width >> 5;
|
||||
if ((width & 0x1f) != 0)
|
||||
{
|
||||
rowSize++;
|
||||
}
|
||||
this.rowSize = rowSize;
|
||||
this.rowSize = (width+31) >> 5;
|
||||
bits = new Array(rowSize * height);
|
||||
// BAS : initialize the array
|
||||
// initialize the array
|
||||
for (var i:int=0;i<bits.length;i++) { bits[i] = 0; }
|
||||
|
||||
}
|
||||
|
@ -92,6 +87,7 @@ package com.google.zxing.common
|
|||
var offset:int = y * rowSize + (x >> 5);
|
||||
bits[offset] |= 1 << (x & 0x1f);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>Flips the given bit.</p>
|
||||
|
@ -160,14 +156,58 @@ package com.google.zxing.common
|
|||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
public function getTopLeftOnBit():Array {
|
||||
var bitsOffset:int = 0;
|
||||
while (bitsOffset < bits.length && bits[bitsOffset] == 0) {
|
||||
bitsOffset++;
|
||||
}
|
||||
if (bitsOffset == bits.length) {
|
||||
return null;
|
||||
}
|
||||
var y:int = bitsOffset / rowSize;
|
||||
var x:int = (bitsOffset % rowSize) << 5;
|
||||
|
||||
/**
|
||||
var theBits:int = bits[bitsOffset];
|
||||
var bit:int = 0;
|
||||
while ((theBits << (31-bit)) == 0) {
|
||||
bit++;
|
||||
}
|
||||
x += bit;
|
||||
return [x, y];
|
||||
}
|
||||
/**
|
||||
* @return The width of the matrix
|
||||
*/
|
||||
public function getWidth():int {
|
||||
return width;
|
||||
}
|
||||
|
||||
public function getBottomRightOnBit():Array {
|
||||
var bitsOffset:int = bits.length - 1;
|
||||
while (bitsOffset >= 0 && bits[bitsOffset] == 0) {
|
||||
bitsOffset--;
|
||||
}
|
||||
if (bitsOffset < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var y:int = bitsOffset / rowSize;
|
||||
var x:int = (bitsOffset % rowSize) << 5;
|
||||
|
||||
var theBits:int = bits[bitsOffset];
|
||||
var bit:int = 31;
|
||||
while ((theBits >>> bit) == 0) {
|
||||
bit--;
|
||||
}
|
||||
x += bit;
|
||||
|
||||
return [x, y];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return The height of the matrix
|
||||
*/
|
||||
|
@ -175,17 +215,88 @@ package com.google.zxing.common
|
|||
return height;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is for compatibility with older code. It's only logical to call if the matrix
|
||||
* is square, so I'm throwing if that's not the case.
|
||||
*
|
||||
* @return row/column dimension of this matrix
|
||||
*/
|
||||
public function getDimension():int {
|
||||
if (width != height) {
|
||||
throw new Error("Common : BitMatrix : getDimension :Can't call getDimension() on a non-square matrix");
|
||||
|
||||
public function equals(o:Object):Boolean {
|
||||
if (!(o is BitMatrix)) {
|
||||
return false;
|
||||
}
|
||||
return width;
|
||||
var other:BitMatrix = BitMatrix(o);
|
||||
if (width != other.width || height != other.height ||
|
||||
rowSize != other.rowSize || bits.length != other.bits.length) {
|
||||
return false;
|
||||
}
|
||||
for (var i:int = 0; i < bits.length; i++) {
|
||||
if (bits[i] != other.bits[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function hashCode():int {
|
||||
var hash:int = width;
|
||||
hash = 31 * hash + width;
|
||||
hash = 31 * hash + height;
|
||||
hash = 31 * hash + rowSize;
|
||||
for (var i:int = 0; i < bits.length; i++) {
|
||||
hash = 31 * hash + bits[i];
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is useful in detecting the enclosing rectangle of a 'pure' barcode.
|
||||
*
|
||||
* @return {left,top,width,height} enclosing rectangle of all 1 bits, or null if it is all white
|
||||
*/
|
||||
public function getEnclosingRectangle():Array
|
||||
{
|
||||
var left:int = this.width;
|
||||
var top:int = this.height;
|
||||
var right:int = -1;
|
||||
var bottom:int = -1;
|
||||
var bit:int;
|
||||
|
||||
for (var y:int = 0; y < this.height; y++) {
|
||||
for (var x32:int = 0; x32 < rowSize; x32++) {
|
||||
var theBits:int = bits[y * rowSize + x32];
|
||||
if (theBits != 0) {
|
||||
if (y < top) {
|
||||
top = y;
|
||||
}
|
||||
if (y > bottom) {
|
||||
bottom = y;
|
||||
}
|
||||
if (x32 * 32 < left) {
|
||||
bit = 0;
|
||||
while ((theBits << (31 - bit)) == 0) {
|
||||
bit++;
|
||||
}
|
||||
if ((x32 * 32 + bit) < left) {
|
||||
left = x32 * 32 + bit;
|
||||
}
|
||||
}
|
||||
if (x32 * 32 + 31 > right) {
|
||||
bit = 31;
|
||||
while ((theBits >>> bit) == 0) {
|
||||
bit--;
|
||||
}
|
||||
if ((x32 * 32 + bit) > right) {
|
||||
right = x32 * 32 + bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var width:int = right - left;
|
||||
var height:int = bottom - top;
|
||||
|
||||
if (width < 0 || height < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [left, top, width, height];
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
|
@ -198,5 +309,29 @@ package com.google.zxing.common
|
|||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
|
||||
public function toString2():String {
|
||||
var totalbits:int = 0;
|
||||
var result:StringBuilder = new StringBuilder(height * (width + 1));
|
||||
for (var y:int = 0; y < height; y++) {
|
||||
for (var x:int = 0; x < width; x++) {
|
||||
result.Append(_get(x, y) ? "1" : "0");
|
||||
if (_get(x, y)) { totalbits++;}
|
||||
}
|
||||
}
|
||||
result.Append("\nsize:"+(this.width*this.height));
|
||||
result.Append("\ntotalbits:"+totalbits);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public function fromByteArray(width:int,height:int,arr:Array):void
|
||||
{
|
||||
this.bits = arr;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.rowSize = (width+31) >> 5;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -28,6 +28,13 @@ package com.google.zxing.common
|
|||
public function BitSource( bytes:Array) {
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return index of next byte in input byte array which would be read by the next call to {@link #readBits(int)}.
|
||||
*/
|
||||
public function getByteOffset():int {
|
||||
return byteOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param numBits number of bits to read
|
||||
|
|
|
@ -27,7 +27,6 @@ package com.google.zxing.common
|
|||
public class ByteMatrix
|
||||
{
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
|
||||
private var bytes:Array;
|
||||
private var Height:int;
|
||||
private var Width:int;
|
||||
|
@ -127,7 +126,31 @@ package com.google.zxing.common
|
|||
result.Append('\n');
|
||||
}
|
||||
return result.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public function toString2():String
|
||||
{
|
||||
var result:StringBuilder = new StringBuilder();
|
||||
for (var y:int = 0; y < Height; ++y)
|
||||
{
|
||||
for (var x:int = 0; x < Width; ++x)
|
||||
{
|
||||
switch (bytes[y][x])
|
||||
{
|
||||
case 0:
|
||||
result.Append("0");
|
||||
break;
|
||||
case 1:
|
||||
result.Append("1");
|
||||
break;
|
||||
default:
|
||||
result.Append("_");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -34,9 +34,9 @@ package com.google.zxing.common
|
|||
private var rawBytes:Array;
|
||||
private var text:String ;
|
||||
private var byteSegments:ArrayList;
|
||||
private var ecLevel:ErrorCorrectionLevel;
|
||||
private var ecLevel:String;
|
||||
|
||||
public function DecoderResult(rawBytes:Array, text:String, byteSegments:ArrayList, ecLevel:ErrorCorrectionLevel)
|
||||
public function DecoderResult(rawBytes:Array, text:String, byteSegments:ArrayList, ecLevel:String)
|
||||
{
|
||||
if (rawBytes == null && text == null)
|
||||
{
|
||||
|
@ -61,7 +61,7 @@ package com.google.zxing.common
|
|||
return byteSegments;
|
||||
}
|
||||
|
||||
public function getECLevel():ErrorCorrectionLevel
|
||||
public function getECLevel():String
|
||||
{
|
||||
return ecLevel;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright 2007 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.common
|
||||
{
|
||||
|
||||
import com.google.zxing.NotFoundException;
|
||||
|
||||
/**
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public class DefaultGridSampler extends GridSampler
|
||||
{
|
||||
|
||||
|
||||
|
||||
public function sampleGrid2(image:BitMatrix,
|
||||
dimensionX:int,
|
||||
dimensionY:int,
|
||||
p1ToX:Number,
|
||||
p1ToY:Number,
|
||||
p2ToX:Number, p2ToY:Number,
|
||||
p3ToX:Number, p3ToY:Number,
|
||||
p4ToX:Number, p4ToY:Number,
|
||||
p1FromX:Number, p1FromY:Number,
|
||||
p2FromX:Number, p2FromY:Number,
|
||||
p3FromX:Number, p3FromY:Number,
|
||||
p4FromX:Number, p4FromY:Number):BitMatrix
|
||||
{
|
||||
var transform:PerspectiveTransform = PerspectiveTransform.quadrilateralToQuadrilateral(
|
||||
p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY,
|
||||
p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY);
|
||||
return sampleGrid(image, dimensionX, dimensionY, transform);
|
||||
}
|
||||
|
||||
public override function sampleGrid(image:BitMatrix ,
|
||||
dimensionX:int,
|
||||
dimensionY:int,
|
||||
transform:PerspectiveTransform):BitMatrix {
|
||||
if (dimensionX <= 0 || dimensionY <= 0) {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
var bits:BitMatrix = new BitMatrix(dimensionX, dimensionY);
|
||||
var points:Array = new Array(dimensionX << 1);
|
||||
for (var y:int = 0; y < dimensionY; y++) {
|
||||
var max:int = points.length;
|
||||
var iValue:Number = Number(y + 0.5);
|
||||
for (var x:int = 0; x < max; x += 2) {
|
||||
points[x] = Number(int(x >> 1) + 0.5);
|
||||
points[x + 1] = iValue;
|
||||
}
|
||||
transform.transformPoints(points);
|
||||
// Quick check to see if points transformed to something inside the image;
|
||||
// sufficient to check the endpoints
|
||||
checkAndNudgePoints(image, points);
|
||||
try {
|
||||
for (var x:int = 0; x < max; x += 2) {
|
||||
if (image._get(int(points[x]), int( points[x + 1]))) {
|
||||
// Black(-ish) pixel
|
||||
bits._set(x >> 1, y);
|
||||
}
|
||||
}
|
||||
} catch (aioobe:ArrayIndexOutOfBoundsException) {
|
||||
// This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting
|
||||
// transform gets "twisted" such that it maps a straight line of points to a set of points
|
||||
// whose endpoints are in bounds, but others are not. There is probably some mathematical
|
||||
// way to detect this about the transformation that I don't know yet.
|
||||
// This results in an ugly runtime exception despite our clever checks above -- can't have
|
||||
// that. We could check each point's coordinates but that feels duplicative. We settle for
|
||||
// catching and wrapping ArrayIndexOutOfBoundsException.
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,12 +28,13 @@ package com.google.zxing.common
|
|||
*/
|
||||
public class DetectorResult
|
||||
{
|
||||
private var bits:BitMatrix;
|
||||
private var bits:BitMatrix;
|
||||
private var points:Array;
|
||||
|
||||
public function DetectorResult( bits:BitMatrix, points:Array ) {
|
||||
this.bits = bits;
|
||||
this.points = points;
|
||||
|
||||
}
|
||||
|
||||
public function getBits():BitMatrix {
|
||||
|
|
|
@ -29,7 +29,7 @@ import com.google.zxing.ReaderException;
|
|||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class GlobalHistogramBinarizer extends Binarizer {
|
||||
public class GlobalHistogramBinarizer extends Binarizer {
|
||||
|
||||
|
||||
private static var LUMINANCE_BITS:int = 5;
|
||||
|
@ -45,6 +45,7 @@ public final class GlobalHistogramBinarizer extends Binarizer {
|
|||
|
||||
// Applies simple sharpening to the row data to improve performance of the 1D Readers.
|
||||
public override function getBlackRow(y:int , row:BitArray ):BitArray {
|
||||
|
||||
var source:LuminanceSource = getLuminanceSource();
|
||||
var width:int = source.getWidth();
|
||||
if (row == null || row.getSize() < width) {
|
||||
|
@ -81,7 +82,8 @@ public final class GlobalHistogramBinarizer extends Binarizer {
|
|||
}
|
||||
|
||||
// Does not sharpen the data, as this call is intended to only be used by 2D Readers.
|
||||
public override function getBlackMatrix():BitMatrix {
|
||||
public override function getBlackMatrix():BitMatrix
|
||||
{
|
||||
var source:LuminanceSource = getLuminanceSource();
|
||||
var width:int = source.getWidth();
|
||||
var height:int = source.getHeight();
|
||||
|
@ -94,10 +96,10 @@ public final class GlobalHistogramBinarizer extends Binarizer {
|
|||
var localBuckets:Array = buckets;//assign empty array
|
||||
for (var y2:int = 1; y2 < 5; y2++)
|
||||
{
|
||||
var row:int = height * y2 / 5;
|
||||
var row:int = int(height * y2 / 5);
|
||||
_localLuminances = source.getRow(row, luminances);
|
||||
var right:int = (width << 2) / 5;
|
||||
for (var x:int = width / 5; x < right; x++)
|
||||
var right:int = int((width << 2) / 5);
|
||||
for (var x:int = int(width / 5); x < right; x++)
|
||||
{
|
||||
var pixel:int = _localLuminances[x] & 0xff;
|
||||
var index:int = Math.floor(pixel >> LUMINANCE_SHIFT);
|
||||
|
|
|
@ -30,8 +30,9 @@ package com.google.zxing.common
|
|||
* @author Sean Owen
|
||||
*
|
||||
*/
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
import com.google.zxing.ReaderException;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
import com.google.zxing.NotFoundException;
|
||||
|
||||
public class GridSampler
|
||||
{
|
||||
|
@ -87,74 +88,68 @@ package com.google.zxing.common
|
|||
* by the given points is invalid or results in sampling outside the image boundaries
|
||||
*/
|
||||
|
||||
public function sampleGrid(image:BitMatrix,
|
||||
dimension:int,
|
||||
p1ToX:Number,
|
||||
p1ToY:Number,
|
||||
p2ToX:Number,
|
||||
p2ToY:Number,
|
||||
p3ToX:Number,
|
||||
p3ToY:Number,
|
||||
p4ToX:Number,
|
||||
p4ToY:Number,
|
||||
p1FromX:Number,
|
||||
p1FromY:Number,
|
||||
p2FromX:Number,
|
||||
p2FromY:Number,
|
||||
p3FromX:Number,
|
||||
p3FromY:Number,
|
||||
p4FromX:Number,
|
||||
p4FromY:Number):BitMatrix
|
||||
{
|
||||
// BAS : originally in DefaultGridSampler
|
||||
var transform:PerspectiveTransform = PerspectiveTransform.quadrilateralToQuadrilateral(p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY, p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY);
|
||||
|
||||
var bits:BitMatrix = new BitMatrix(dimension);
|
||||
var points:Array = new Array(dimension << 1);
|
||||
for (var y:int = 0; y < dimension; y++)
|
||||
{
|
||||
var max:int = points.length;
|
||||
var iValue:Number = Number(y + 0.5);
|
||||
for (var x:int = 0; x < max; x += 2)
|
||||
{
|
||||
points[x] = Number((x >> 1) + 0.5);
|
||||
points[x + 1] = iValue;
|
||||
}
|
||||
points = transform.transformPoints(points);
|
||||
|
||||
// Quick check to see if points transformed to something inside the image;
|
||||
// sufficent to check the endpoints
|
||||
checkAndNudgePoints(image, points);
|
||||
try
|
||||
{
|
||||
for (var x2:int = 0; x2 < max; x2 += 2)
|
||||
{
|
||||
//UPGRADE_WARNING: Narrowing conversions may produce unexpected results in C#. 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="jlca1042"'
|
||||
if (image._get( int(points[x2]), int(points[x2 + 1])))
|
||||
//if (image._get( Math.floor(points[x2]), Math.floor(points[x2 + 1])))
|
||||
{
|
||||
// Black(-ish) pixel
|
||||
bits._set(x2 >> 1,y );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (aioobe:RangeError )
|
||||
{
|
||||
// This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting
|
||||
// transform gets "twisted" such that it maps a straight line of points to a set of points
|
||||
// whose endpoints are in bounds, but others are not. There is probably some mathematical
|
||||
// way to detect this about the transformation that I don't know yet.
|
||||
// This results in an ugly runtime exception despite our clever checks above -- can't have that.
|
||||
// We could check each point's coordinates but that feels duplicative. We settle for
|
||||
// catching and wrapping ArrayIndexOutOfBoundsException.
|
||||
throw new ReaderException("DefautGridSampler : sampleGrid : "+aioobe.message);
|
||||
}
|
||||
}
|
||||
return bits;
|
||||
|
||||
public function sampleGrid(image:BitMatrix ,
|
||||
dimensionX:int,
|
||||
dimensionY:int,
|
||||
transform:PerspectiveTransform):BitMatrix
|
||||
{
|
||||
// originally in DefaultGridSampler
|
||||
if (dimensionX <= 0 || dimensionY <= 0) {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
var bits:BitMatrix = new BitMatrix(dimensionX, dimensionY);
|
||||
var points:Array = new Array(dimensionX << 1);
|
||||
for (var y:int = 0; y < dimensionY; y++) {
|
||||
var max:int = points.length;
|
||||
var iValue:Number = Number(y + 0.5);
|
||||
for (var x:int = 0; x < max; x += 2) {
|
||||
points[x] = Number((x >> 1) + 0.5);
|
||||
points[x + 1] = iValue;
|
||||
}
|
||||
|
||||
/**
|
||||
transform.transformPoints(points);
|
||||
// Quick check to see if points transformed to something inside the image;
|
||||
// sufficient to check the endpoints
|
||||
checkAndNudgePoints(image, points);
|
||||
try {
|
||||
for (x = 0; x < max; x += 2) {
|
||||
if (image._get(int(points[x]), int( points[x + 1]))) {
|
||||
// Black(-ish) pixel
|
||||
bits._set(x >> 1, y);
|
||||
}
|
||||
}
|
||||
} catch (aioobe:RangeError) {
|
||||
// This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting
|
||||
// transform gets "twisted" such that it maps a straight line of points to a set of points
|
||||
// whose endpoints are in bounds, but others are not. There is probably some mathematical
|
||||
// way to detect this about the transformation that I don't know yet.
|
||||
// This results in an ugly runtime exception despite our clever checks above -- can't have
|
||||
// that. We could check each point's coordinates but that feels duplicative. We settle for
|
||||
// catching and wrapping ArrayIndexOutOfBoundsException.
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
public function sampleGrid2(image:BitMatrix,
|
||||
dimensionX:int,
|
||||
dimensionY:int,
|
||||
p1ToX:Number,
|
||||
p1ToY:Number,
|
||||
p2ToX:Number, p2ToY:Number,
|
||||
p3ToX:Number, p3ToY:Number,
|
||||
p4ToX:Number, p4ToY:Number,
|
||||
p1FromX:Number, p1FromY:Number,
|
||||
p2FromX:Number, p2FromY:Number,
|
||||
p3FromX:Number, p3FromY:Number,
|
||||
p4FromX:Number, p4FromY:Number):BitMatrix
|
||||
{
|
||||
var transform:PerspectiveTransform = PerspectiveTransform.quadrilateralToQuadrilateral(
|
||||
p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY,
|
||||
p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY);
|
||||
return sampleGrid(image, dimensionX, dimensionY, transform);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Checks a set of points that have been transformed to sample points on an image against
|
||||
* the image's dimensions to see if the point are even within the image.</p>
|
||||
*
|
||||
|
|
190
actionscript/core/src/com/google/zxing/common/HybridBinarizer.as
Normal file
190
actionscript/core/src/com/google/zxing/common/HybridBinarizer.as
Normal file
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* Copyright 2009 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.zxing.common
|
||||
{
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This class implements a local thresholding algorithm, which while slower than the
|
||||
* GlobalHistogramBinarizer, is fairly efficient for what it does. It is designed for
|
||||
* high frequency images of barcodes with black data on white backgrounds. For this application,
|
||||
* it does a much better job than a global blackpoint with severe shadows and gradients.
|
||||
* However it tends to produce artifacts on lower frequency images and is therefore not
|
||||
* a good general purpose binarizer for uses outside ZXing.
|
||||
*
|
||||
* NOTE: This class is still experimental and may not be ready for prime time yet.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
import com.google.zxing.Binarizer;
|
||||
import com.google.zxing.LuminanceSource;
|
||||
|
||||
public class HybridBinarizer extends GlobalHistogramBinarizer {
|
||||
|
||||
// This class uses 5x5 blocks to compute local luminance, where each block is 8x8 pixels.
|
||||
// So this is the smallest dimension in each axis we can accept.
|
||||
private static var MINIMUM_DIMENSION:int = 40;
|
||||
private var matrix:BitMatrix = null;
|
||||
|
||||
public function HybridBinarizer(source:LuminanceSource) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
public override function getBlackMatrix():BitMatrix
|
||||
{
|
||||
binarizeEntireImage();
|
||||
return matrix;
|
||||
}
|
||||
|
||||
public override function createBinarizer(source:LuminanceSource):Binarizer
|
||||
{
|
||||
return new HybridBinarizer(source);
|
||||
}
|
||||
|
||||
|
||||
// Calculates the final BitMatrix once for all requests. This could be called once from the
|
||||
// constructor instead, but there are some advantages to doing it lazily, such as making
|
||||
// profiling easier, and not doing heavy lifting when callers don't expect it.
|
||||
private function binarizeEntireImage():void {
|
||||
if (matrix == null) {
|
||||
var source:LuminanceSource = getLuminanceSource();
|
||||
if (source.getWidth() >= MINIMUM_DIMENSION && source.getHeight() >= MINIMUM_DIMENSION)
|
||||
{
|
||||
var luminances:Array = source.getMatrix();
|
||||
var width:int = source.getWidth();
|
||||
var height:int = source.getHeight();
|
||||
var subWidth:int = width >> 3;
|
||||
if ((width & 0x07) != 0) {
|
||||
subWidth++;
|
||||
}
|
||||
var subHeight:int = height >> 3;
|
||||
if ((height & 0x07) != 0) {
|
||||
subHeight++;
|
||||
}
|
||||
var blackPoints:Array = calculateBlackPoints(luminances, subWidth, subHeight, width, height);
|
||||
|
||||
matrix = new BitMatrix(width, height);
|
||||
calculateThresholdForBlock(luminances, subWidth, subHeight, width, height, blackPoints, matrix);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the image is too small, fall back to the global histogram approach.
|
||||
matrix = super.getBlackMatrix();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For each 8x8 block in the image, calculate the average black point using a 5x5 grid
|
||||
// of the blocks around it. Also handles the corner cases, but will ignore up to 7 pixels
|
||||
// on the right edge and 7 pixels at the bottom of the image if the overall dimsions are not
|
||||
// multiples of eight. In practice, leaving those pixels white does not seem to be a problem.
|
||||
private static function calculateThresholdForBlock(luminances:Array , subWidth:int , subHeight:int ,
|
||||
width:int, height:int , blackPoints:Array , matrix:BitMatrix ):void {
|
||||
for (var y:int = 0; y < subHeight; y++) {
|
||||
var yoffset:int = y << 3;
|
||||
if ((yoffset + 8) >= height) {
|
||||
yoffset = height - 8;
|
||||
}
|
||||
for (var x:int = 0; x < subWidth; x++) {
|
||||
var xoffset:int = x << 3;
|
||||
if ((xoffset + 8) >= width) {
|
||||
xoffset = width - 8;
|
||||
}
|
||||
var left:int = x > 1 ? x : 2;
|
||||
left = left < subWidth - 2 ? left : subWidth - 3;
|
||||
var top:int = y > 1 ? y : 2;
|
||||
top = top < subHeight - 2 ? top : subHeight - 3;
|
||||
var sum:int = 0;
|
||||
for (var z:int = -2; z <= 2; z++) {
|
||||
var blackRow:Array = blackPoints[top + z];
|
||||
sum += blackRow[left - 2];
|
||||
sum += blackRow[left - 1];
|
||||
sum += blackRow[left];
|
||||
sum += blackRow[left + 1];
|
||||
sum += blackRow[left + 2];
|
||||
}
|
||||
var average:int = int(sum / 25);
|
||||
threshold8x8Block(luminances, xoffset, yoffset, average, width, matrix);
|
||||
}
|
||||
} }
|
||||
|
||||
// Applies a single threshold to an 8x8 block of pixels.
|
||||
private static function threshold8x8Block(luminances:Array , xoffset:int , yoffset:int , threshold:int ,
|
||||
stride:int , matrix:BitMatrix ):void {
|
||||
for (var y:int = 0; y < 8; y++) {
|
||||
var offset:int = (yoffset + y) * stride + xoffset;
|
||||
for (var x:int = 0; x < 8; x++) {
|
||||
var pixel:int = luminances[offset + x] & 0xff;
|
||||
if (pixel < threshold) {
|
||||
matrix._set(xoffset + x, yoffset + y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculates a single black point for each 8x8 block of pixels and saves it away.
|
||||
private static function calculateBlackPoints(luminances:Array, subWidth:int, subHeight:int,
|
||||
width:int, height:int):Array {
|
||||
var blackPoints:Array = new Array(subHeight);
|
||||
for(var i:int=0;i<blackPoints.length;i++) { blackPoints[i]=new Array(subWidth);for(var j:int=0;j<subWidth;j++){blackPoints[i][j]=0; }}
|
||||
for (var y:int = 0; y < subHeight; y++) {
|
||||
var yoffset:int = y << 3;
|
||||
if ((yoffset + 8) >= height) {
|
||||
yoffset = height - 8;
|
||||
}
|
||||
for (var x:int = 0; x < subWidth; x++) {
|
||||
var xoffset:int = x << 3;
|
||||
if ((xoffset + 8) >= width) {
|
||||
xoffset = width - 8;
|
||||
}
|
||||
var sum:int = 0;
|
||||
var min:int = 255;
|
||||
var max:int = 0;
|
||||
for (var yy:int = 0; yy < 8; yy++) {
|
||||
var offset:int = (yoffset + yy) * width + xoffset;
|
||||
for (var xx:int = 0; xx < 8; xx++) {
|
||||
var pixel:int = luminances[offset + xx] & 0xff;
|
||||
sum += pixel;
|
||||
if (pixel < min) {
|
||||
min = pixel;
|
||||
}
|
||||
if (pixel > max) {
|
||||
max = pixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the contrast is inadequate, use half the minimum, so that this block will be
|
||||
// treated as part of the white background, but won't drag down neighboring blocks
|
||||
// too much.
|
||||
var average:int;
|
||||
if (max - min > 24) {
|
||||
average = sum >> 6;
|
||||
} else {
|
||||
// When min == max == 0, let average be 1 so all is black
|
||||
average = max == 0 ? 1 : min >> 1;
|
||||
}
|
||||
blackPoints[y][x] = average;
|
||||
}
|
||||
}
|
||||
return blackPoints;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -24,8 +24,7 @@ package com.google.zxing.common
|
|||
*/
|
||||
public class PerspectiveTransform
|
||||
{
|
||||
|
||||
private var a11:Number;
|
||||
private var a11:Number;
|
||||
private var a12:Number;
|
||||
private var a13:Number;
|
||||
private var a21:Number;
|
||||
|
@ -108,12 +107,28 @@ package com.google.zxing.common
|
|||
public function buildAdjoint():PerspectiveTransform
|
||||
{
|
||||
// Adjoint is the transpose of the cofactor matrix:
|
||||
return new PerspectiveTransform(a22 * a33 - a23 * a32, a23 * a31 - a21 * a33, a21 * a32 - a22 * a31, a13 * a32 - a12 * a33, a11 * a33 - a13 * a31, a12 * a31 - a11 * a32, a12 * a23 - a13 * a22, a13 * a21 - a11 * a23, a11 * a22 - a12 * a21);
|
||||
return new PerspectiveTransform(a22 * a33 - a23 * a32,
|
||||
a23 * a31 - a21 * a33,
|
||||
a21 * a32 - a22 * a31,
|
||||
a13 * a32 - a12 * a33,
|
||||
a11 * a33 - a13 * a31,
|
||||
a12 * a31 - a11 * a32,
|
||||
a12 * a23 - a13 * a22,
|
||||
a13 * a21 - a11 * a23,
|
||||
a11 * a22 - a12 * a21);
|
||||
}
|
||||
|
||||
private function times(other:PerspectiveTransform ):PerspectiveTransform
|
||||
{
|
||||
return new PerspectiveTransform(a11 * other.a11 + a21 * other.a12 + a31 * other.a13, a11 * other.a21 + a21 * other.a22 + a31 * other.a23, a11 * other.a31 + a21 * other.a32 + a31 * other.a33, a12 * other.a11 + a22 * other.a12 + a32 * other.a13, a12 * other.a21 + a22 * other.a22 + a32 * other.a23, a12 * other.a31 + a22 * other.a32 + a32 * other.a33, a13 * other.a11 + a23 * other.a12 + a33 * other.a13, a13 * other.a21 + a23 * other.a22 + a33 * other.a23, a13 * other.a31 + a23 * other.a32 + a33 * other.a33);
|
||||
return new PerspectiveTransform(a11 * other.a11 + a21 * other.a12 + a31 * other.a13,
|
||||
a11 * other.a21 + a21 * other.a22 + a31 * other.a23,
|
||||
a11 * other.a31 + a21 * other.a32 + a31 * other.a33,
|
||||
a12 * other.a11 + a22 * other.a12 + a32 * other.a13,
|
||||
a12 * other.a21 + a22 * other.a22 + a32 * other.a23,
|
||||
a12 * other.a31 + a22 * other.a32 + a32 * other.a33,
|
||||
a13 * other.a11 + a23 * other.a12 + a33 * other.a13,
|
||||
a13 * other.a21 + a23 * other.a22 + a33 * other.a23,
|
||||
a13 * other.a31 + a23 * other.a32 + a33 * other.a33);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright 2009 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing
|
||||
{
|
||||
|
||||
/**
|
||||
* Callback which is invoked when a possible result point (significant
|
||||
* point in the barcode image such as a corner) is found.
|
||||
*
|
||||
* @see DecodeHintType#NEED_RESULT_POINT_CALLBACK
|
||||
*/
|
||||
public interface ResultPointCallback {
|
||||
|
||||
function foundPossibleResultPoint(point:ResultPoint ):void;
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,354 @@
|
|||
/*
|
||||
* Copyright 2010 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.common.detector
|
||||
{
|
||||
|
||||
import com.google.zxing.NotFoundException;
|
||||
import com.google.zxing.ResultPoint;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Detects a candidate barcode-like rectangular region within an image. It
|
||||
* starts around the center of the image, increases the size of the candidate
|
||||
* region until it finds a white rectangular region. By keeping track of the
|
||||
* last black points it encountered, it determines the corners of the barcode.
|
||||
* </p>
|
||||
*
|
||||
* @author David Olivier
|
||||
*/
|
||||
public final class WhiteRectangleDetector
|
||||
{
|
||||
|
||||
private static var INIT_SIZE:int = 30;
|
||||
private static var CORR:int = 1;
|
||||
|
||||
private var image:BitMatrix ;
|
||||
private var height:int;
|
||||
private var width:int;
|
||||
private var leftInit:int;
|
||||
private var rightInit:int;
|
||||
private var downInit:int;
|
||||
private var upInit:int;
|
||||
|
||||
/**
|
||||
* @throws NotFoundException if image is too small
|
||||
*/
|
||||
public function WhiteRectangleDetector(image:BitMatrix , initSize:int=-1, x:int=-1, y:int=-1)
|
||||
{
|
||||
if ((initSize==-1)&&( x==-1)&&( y==-1))
|
||||
{
|
||||
this.image = image;
|
||||
height = image.getHeight();
|
||||
width = image.getWidth();
|
||||
leftInit = (width - INIT_SIZE) >> 1;
|
||||
rightInit = (width + INIT_SIZE) >> 1;
|
||||
upInit = (height - INIT_SIZE) >> 1;
|
||||
downInit = (height + INIT_SIZE) >> 1;
|
||||
if (upInit < 0 || leftInit < 0 || downInit >= height || rightInit >= width) {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
this.image = image;
|
||||
height = image.getHeight();
|
||||
width = image.getWidth();
|
||||
var halfsize:int = initSize >> 1;
|
||||
leftInit = x - halfsize;
|
||||
rightInit = x + halfsize;
|
||||
upInit = y - halfsize;
|
||||
downInit = y + halfsize;
|
||||
if (upInit < 0 || leftInit < 0 || downInit >= height || rightInit >= width) {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Detects a candidate barcode-like rectangular region within an image. It
|
||||
* starts around the center of the image, increases the size of the candidate
|
||||
* region until it finds a white rectangular region.
|
||||
* </p>
|
||||
*
|
||||
* @return {@link ResultPoint}[] describing the corners of the rectangular
|
||||
* region. The first and last points are opposed on the diagonal, as
|
||||
* are the second and third. The first point will be the topmost
|
||||
* point and the last, the bottommost. The second point will be
|
||||
* leftmost and the third, the rightmost
|
||||
* @throws NotFoundException if no Data Matrix Code can be found
|
||||
*/
|
||||
public function detect():Array {
|
||||
|
||||
var left:int = leftInit;
|
||||
var right:int = rightInit;
|
||||
var up:int = upInit;
|
||||
var down:int = downInit;
|
||||
var sizeExceeded:Boolean = false;
|
||||
var aBlackPointFoundOnBorder:Boolean = true;
|
||||
var atLeastOneBlackPointFoundOnBorder:Boolean = false;
|
||||
|
||||
while (aBlackPointFoundOnBorder) {
|
||||
|
||||
aBlackPointFoundOnBorder = false;
|
||||
|
||||
// .....
|
||||
// . |
|
||||
// .....
|
||||
var rightBorderNotWhite:Boolean = true;
|
||||
while (rightBorderNotWhite && right < width) {
|
||||
rightBorderNotWhite = containsBlackPoint(up, down, right, false);
|
||||
if (rightBorderNotWhite) {
|
||||
right++;
|
||||
aBlackPointFoundOnBorder = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (right >= width) {
|
||||
sizeExceeded = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// .....
|
||||
// . .
|
||||
// .___.
|
||||
var bottomBorderNotWhite:Boolean = true;
|
||||
while (bottomBorderNotWhite && down < height) {
|
||||
bottomBorderNotWhite = containsBlackPoint(left, right, down, true);
|
||||
if (bottomBorderNotWhite) {
|
||||
down++;
|
||||
aBlackPointFoundOnBorder = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (down >= height) {
|
||||
sizeExceeded = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// .....
|
||||
// | .
|
||||
// .....
|
||||
var leftBorderNotWhite:Boolean = true;
|
||||
while (leftBorderNotWhite && left >= 0) {
|
||||
leftBorderNotWhite = containsBlackPoint(up, down, left, false);
|
||||
if (leftBorderNotWhite) {
|
||||
left--;
|
||||
aBlackPointFoundOnBorder = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (left < 0) {
|
||||
sizeExceeded = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// .___.
|
||||
// . .
|
||||
// .....
|
||||
var topBorderNotWhite:Boolean = true;
|
||||
while (topBorderNotWhite && up >= 0) {
|
||||
topBorderNotWhite = containsBlackPoint(left, right, up, true);
|
||||
if (topBorderNotWhite) {
|
||||
up--;
|
||||
aBlackPointFoundOnBorder = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (up < 0) {
|
||||
sizeExceeded = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (aBlackPointFoundOnBorder) {
|
||||
atLeastOneBlackPointFoundOnBorder = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!sizeExceeded && atLeastOneBlackPointFoundOnBorder) {
|
||||
|
||||
var maxSize:int = right - left;
|
||||
|
||||
var z:ResultPoint = null;
|
||||
for (var i:int = 1; i < maxSize; i++)
|
||||
{
|
||||
z = getBlackPointOnSegment(left, down - i, left + i, down);
|
||||
|
||||
if (z != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (z == null) {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
var t:ResultPoint = null;
|
||||
//go down right
|
||||
for (var i4:int = 1; i4 < maxSize; i4++) {
|
||||
t = getBlackPointOnSegment(left, up + i4, left + i4, up);
|
||||
if (t != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (t == null) {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
var x:ResultPoint = null;
|
||||
//go down left
|
||||
for (var i5:int = 1; i5 < maxSize; i5++) {
|
||||
x = getBlackPointOnSegment(right, up + i5, right - i5, up);
|
||||
if (x != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (x == null) {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
var y:ResultPoint = null;
|
||||
//go up left
|
||||
for (i = 1; i < maxSize; i++) {
|
||||
y = getBlackPointOnSegment(right, down - i, right - i, down);
|
||||
if (y != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (y == null) {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
return centerEdges(y, z, x, t);
|
||||
|
||||
} else {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends up being a bit faster than Math.round(). This merely rounds its
|
||||
* argument to the nearest int, where x.5 rounds up.
|
||||
*/
|
||||
private static function round(d:Number):int {
|
||||
return (int) (d + 0.5);
|
||||
}
|
||||
|
||||
private function getBlackPointOnSegment(aX:Number, aY:Number, bX:Number, bY:Number):ResultPoint {
|
||||
var dist:int = distanceL2(aX, aY, bX, bY);
|
||||
var xStep:Number = (bX - aX) / dist;
|
||||
var yStep:Number = (bY - aY) / dist;
|
||||
|
||||
for (var i:int = 0; i < dist; i++) {
|
||||
var x:int = round(aX + i * xStep);
|
||||
var y:int = round(aY + i * yStep);
|
||||
if (image._get(x, y)) {
|
||||
return new ResultPoint(x, y);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static function distanceL2(aX:Number, aY:Number, bX:Number, bY:Number):int {
|
||||
var xDiff:Number = aX - bX;
|
||||
var yDiff:Number = aY - bY;
|
||||
return round(Math.sqrt(xDiff * xDiff + yDiff * yDiff));
|
||||
}
|
||||
|
||||
/**
|
||||
* recenters the points of a constant distance towards the center
|
||||
*
|
||||
* @param y bottom most point
|
||||
* @param z left most point
|
||||
* @param x right most point
|
||||
* @param t top most point
|
||||
* @return {@link ResultPoint}[] describing the corners of the rectangular
|
||||
* region. The first and last points are opposed on the diagonal, as
|
||||
* are the second and third. The first point will be the topmost
|
||||
* point and the last, the bottommost. The second point will be
|
||||
* leftmost and the third, the rightmost
|
||||
*/
|
||||
private function centerEdges(y:ResultPoint , z:ResultPoint,
|
||||
x:ResultPoint, t:ResultPoint):Array {
|
||||
|
||||
//
|
||||
// t t
|
||||
// z x
|
||||
// x OR z
|
||||
// y y
|
||||
//
|
||||
|
||||
var yi:Number = y.getX();
|
||||
var yj:Number = y.getY();
|
||||
var zi:Number = z.getX();
|
||||
var zj:Number = z.getY();
|
||||
var xi:Number = x.getX();
|
||||
var xj:Number = x.getY();
|
||||
var ti:Number = t.getX();
|
||||
var tj:Number = t.getY();
|
||||
|
||||
if (yi < width / 2) {
|
||||
return [
|
||||
new ResultPoint(ti - CORR, tj + CORR),
|
||||
new ResultPoint(zi + CORR, zj + CORR),
|
||||
new ResultPoint(xi - CORR, xj - CORR),
|
||||
new ResultPoint(yi + CORR, yj - CORR)];
|
||||
} else {
|
||||
return [
|
||||
new ResultPoint(ti + CORR, tj + CORR),
|
||||
new ResultPoint(zi + CORR, zj - CORR),
|
||||
new ResultPoint(xi - CORR, xj + CORR),
|
||||
new ResultPoint(yi - CORR, yj - CORR)];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a segment contains a black point
|
||||
*
|
||||
* @param a min value of the scanned coordinate
|
||||
* @param b max value of the scanned coordinate
|
||||
* @param fixed value of fixed coordinate
|
||||
* @param horizontal set to true if scan must be horizontal, false if vertical
|
||||
* @return true if a black point has been found, else false.
|
||||
*/
|
||||
private function containsBlackPoint(a:int, b:int, fixed:int, horizontal:Boolean):Boolean {
|
||||
|
||||
if (horizontal) {
|
||||
for (var x:int = a; x <= b; x++) {
|
||||
if (image._get(x, fixed)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (var y:int = a; y <= b; y++) {
|
||||
if (image._get(fixed, y)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -3,12 +3,12 @@ package com.google.zxing.common.flexdatatypes
|
|||
// these comparators should reside in the classes but that didn's work for some reason.
|
||||
import com.google.zxing.datamatrix.detector.ResultPointsAndTransitionsComparator;
|
||||
import com.google.zxing.qrcode.detector.CenterComparator;
|
||||
import com.google.zxing.qrcode.detector.FurthestFromAverageComparator;
|
||||
|
||||
|
||||
public class ArrayList
|
||||
{
|
||||
//BAS : made public for debugging
|
||||
public var _array:Array;
|
||||
private var _array:Array;
|
||||
public function ArrayList(siz:int=0)
|
||||
{
|
||||
this._array = new Array(siz);
|
||||
|
@ -63,6 +63,35 @@ package com.google.zxing.common.flexdatatypes
|
|||
return this._array.indexOf(o);
|
||||
}
|
||||
|
||||
public function removeElementAt(index:int):void
|
||||
{
|
||||
var newArray:Array = new Array();
|
||||
for(var i:int=0;i<this._array.length;i++)
|
||||
{
|
||||
if (i != index) { newArray.push(this._array[i]); }
|
||||
}
|
||||
this._array = newArray;
|
||||
}
|
||||
|
||||
public function setElementAt(elem:Object, index:int):void
|
||||
{
|
||||
this._array[index] = elem;
|
||||
}
|
||||
|
||||
// limit size of array
|
||||
public function setSize(size:int):void
|
||||
{
|
||||
var newArray:Array = new Array();
|
||||
if (this._array.length > size)
|
||||
{
|
||||
for (var i:int=0;i<size;i++)
|
||||
{
|
||||
newArray[i] = this._array[i]; // bas : fixed .push
|
||||
}
|
||||
this._array = newArray;
|
||||
}
|
||||
}
|
||||
|
||||
public function RemoveRange(newSize:int,itemsToRemove:int):void
|
||||
{
|
||||
// remove the items
|
||||
|
@ -101,11 +130,18 @@ package com.google.zxing.common.flexdatatypes
|
|||
//this._array.sort(args);
|
||||
}
|
||||
|
||||
public function sort_CenterComparator():void
|
||||
public function sort_CenterComparator(average:Number):void
|
||||
{
|
||||
CenterComparator.setAverage(average);
|
||||
this._array.sort(CenterComparator.compare);
|
||||
}
|
||||
|
||||
public function sort_FurthestFromAverageComparator(average:Number):void
|
||||
{
|
||||
FurthestFromAverageComparator.setAverage(average);
|
||||
this._array.sort(FurthestFromAverageComparator.compare);
|
||||
}
|
||||
|
||||
public function size():int
|
||||
{
|
||||
return this._array.length;
|
||||
|
@ -127,6 +163,21 @@ package com.google.zxing.common.flexdatatypes
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function clearAll():void
|
||||
{
|
||||
this._array = new Array();
|
||||
}
|
||||
|
||||
public function elements():Array
|
||||
{
|
||||
return this._array;
|
||||
}
|
||||
|
||||
public function lastElement():Object
|
||||
{
|
||||
return this._array[this._array.length-1]; // bas : fixed this
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package com.google.zxing.common.flexdatatypes
|
||||
{
|
||||
public class Enumeration
|
||||
{
|
||||
private var _arr:Array;
|
||||
|
||||
public function isEmpty():Boolean
|
||||
{
|
||||
return this.getSize()==0?true:false;
|
||||
}
|
||||
|
||||
public function getSize():int
|
||||
{
|
||||
return this._arr.length;
|
||||
}
|
||||
|
||||
public function Enumeration(arr:Array)
|
||||
{
|
||||
this._arr = arr;
|
||||
}
|
||||
|
||||
public function hasMoreElement():Boolean
|
||||
{
|
||||
return (!this.isEmpty());
|
||||
}
|
||||
|
||||
public function nextElement():Object
|
||||
{
|
||||
return this._arr.shift();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -2,8 +2,7 @@ package com.google.zxing.common.flexdatatypes
|
|||
{
|
||||
public class HashTable
|
||||
{
|
||||
// bas : made public for debugging
|
||||
public var _arr:Array;
|
||||
private var _arr:Array;
|
||||
|
||||
public function isEmpty():Boolean
|
||||
{
|
||||
|
@ -57,6 +56,7 @@ package com.google.zxing.common.flexdatatypes
|
|||
|
||||
public function ContainsKey(key:Object):Boolean
|
||||
{
|
||||
//for (var i:int=0;i<this._arr.length;i++)
|
||||
for (var i:String in this._arr)
|
||||
{
|
||||
if (this._arr[i][0] == key) { return true; }
|
||||
|
@ -67,6 +67,7 @@ package com.google.zxing.common.flexdatatypes
|
|||
public function getValuesByKey(key:Object):ArrayList
|
||||
{
|
||||
var al:ArrayList = new ArrayList();
|
||||
//for (var i:int=0;i<this._arr.length;i++)
|
||||
for (var i:String in this._arr)
|
||||
{
|
||||
if (this._arr[i][0] == key)
|
||||
|
@ -85,18 +86,20 @@ package com.google.zxing.common.flexdatatypes
|
|||
public function getValueByKey(key:Object):Object
|
||||
{
|
||||
var al:ArrayList = new ArrayList();
|
||||
for (var i:String in this._arr)
|
||||
//for (var i:int=0;i<this._arr.length;i++)
|
||||
for (var i:String in this._arr)
|
||||
{
|
||||
if (this._arr[i][0] == key)
|
||||
{
|
||||
return this._arr[i][1];
|
||||
}
|
||||
}
|
||||
return al;
|
||||
return null;
|
||||
}
|
||||
|
||||
public function setValue(key:Object,value:Object):void
|
||||
{
|
||||
//for (var i:int=0;i<this._arr.length;i++)
|
||||
for (var i:String in this._arr)
|
||||
{
|
||||
if (this._arr[i][0] == key)
|
||||
|
@ -109,6 +112,7 @@ package com.google.zxing.common.flexdatatypes
|
|||
|
||||
public function getKeyByValue(value:Object):int
|
||||
{
|
||||
//for (var i:int=0;i<this._arr.length;i++)
|
||||
for (var i:String in this._arr)
|
||||
{
|
||||
if (this._arr[i][1] == value)
|
||||
|
@ -121,15 +125,28 @@ package com.google.zxing.common.flexdatatypes
|
|||
|
||||
public function containsKey(key:Object):Boolean
|
||||
{
|
||||
//for (var i:int=0;i<this._arr.length;i++)
|
||||
for (var i:String in this._arr)
|
||||
{
|
||||
if (this._arr[i][0] == key)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function keys():Array
|
||||
{
|
||||
var result:Array = new Array(this._arr.length);
|
||||
//for (var i:int=0;i<this._arr.length;i++)
|
||||
for (var i:String in this._arr)
|
||||
{
|
||||
result[i] = this._arr[i][0];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ package com.google.zxing.common.flexdatatypes
|
|||
}
|
||||
else
|
||||
{
|
||||
throw new ReaderException("StringBuilder : setLength : only 0 supported");
|
||||
this._string = this._string.substr(0,l);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,10 @@ package com.google.zxing.common.flexdatatypes
|
|||
{
|
||||
this._string = this._string + (o as Array).join("");
|
||||
}
|
||||
else if (o is String)
|
||||
{
|
||||
this._string = this._string + o;
|
||||
}
|
||||
else
|
||||
{
|
||||
this._string = this._string + o.toString();
|
||||
|
@ -104,6 +108,21 @@ package com.google.zxing.common.flexdatatypes
|
|||
{
|
||||
return this._string;
|
||||
}
|
||||
|
||||
public function toHexString():String
|
||||
{
|
||||
var r:String="";
|
||||
var e:int=this._string.length;
|
||||
var c:int=0;
|
||||
var h:String;
|
||||
while(c<e){
|
||||
h=this._string.charCodeAt(c++).toString(16);
|
||||
while(h.length<3) h="0"+h;
|
||||
r+=h;
|
||||
}
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
public function deleteCharAt(index:int):void
|
||||
{
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
|
||||
private static var INITIAL_SIZE:int = 32;
|
||||
|
||||
// BAS : made public for debugging
|
||||
private var bytes:Array;
|
||||
private var Size:int;
|
||||
|
||||
|
|
|
@ -29,10 +29,18 @@ package com.google.zxing.datamatrix
|
|||
import com.google.zxing.datamatrix.decoder.Decoder;
|
||||
import com.google.zxing.datamatrix.detector.Detector;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.NotFoundException;
|
||||
|
||||
|
||||
|
||||
|
||||
public class DataMatrixReader implements Reader
|
||||
{
|
||||
|
||||
|
||||
public function reset():void {
|
||||
// do nothing
|
||||
}
|
||||
/**
|
||||
* This implementation can detect and decode Data Matrix codes in an image.
|
||||
*
|
||||
|
@ -91,71 +99,74 @@ package com.google.zxing.datamatrix
|
|||
* around it. This is a specialized method that works exceptionally fast in this special
|
||||
* case.
|
||||
*/
|
||||
private static function extractPureBits(image:BitMatrix ):BitMatrix {
|
||||
// Now need to determine module size in pixels
|
||||
private static function extractPureBits(image:BitMatrix):BitMatrix
|
||||
{
|
||||
var leftTopBlack:Array = image.getTopLeftOnBit();
|
||||
var rightBottomBlack:Array = image.getBottomRightOnBit();
|
||||
if (leftTopBlack == null || rightBottomBlack == null)
|
||||
{
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
var moduleSize:int = moduleSize(leftTopBlack, image);
|
||||
|
||||
var height:int = image.getHeight();
|
||||
var width:int = image.getWidth();
|
||||
var minDimension:int = Math.min(height, width);
|
||||
var top:int = leftTopBlack[1];
|
||||
var bottom:int = rightBottomBlack[1];
|
||||
var left:int = leftTopBlack[0];
|
||||
var right:int = rightBottomBlack[0];
|
||||
|
||||
// First, skip white border by tracking diagonally from the top left down and to the right:
|
||||
var borderWidth:int = 0;
|
||||
while (borderWidth < minDimension && !image._get(borderWidth, borderWidth)) {
|
||||
borderWidth++;
|
||||
}
|
||||
if (borderWidth == minDimension) {
|
||||
throw new ReaderException("DataMatrixReader : extractPureBits : borderWidth == minDimension");
|
||||
}
|
||||
var matrixWidth:int = (right - left + 1) / moduleSize;
|
||||
var matrixHeight:int = (bottom - top + 1) / moduleSize;
|
||||
if (matrixWidth <= 0 || matrixHeight <= 0)
|
||||
{
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
// And then keep tracking across the top-left black module to determine module size
|
||||
var moduleEnd:int = borderWidth + 1;
|
||||
while (moduleEnd < width && image._get(moduleEnd, borderWidth)) {
|
||||
moduleEnd++;
|
||||
}
|
||||
if (moduleEnd == width) {
|
||||
throw new ReaderException("DataMatrixReader : extractPureBits : moduleEnd == width");
|
||||
}
|
||||
// Push in the "border" by half the module width so that we start
|
||||
// sampling in the middle of the module. Just in case the image is a
|
||||
// little off, this will help recover.
|
||||
var nudge:int = moduleSize >> 1;
|
||||
top += nudge;
|
||||
left += nudge;
|
||||
|
||||
var moduleSize:int = moduleEnd - borderWidth;
|
||||
// Now just read off the bits
|
||||
var bits:BitMatrix = new BitMatrix(matrixWidth, matrixHeight);
|
||||
for (var y:int = 0; y < matrixHeight; y++)
|
||||
{
|
||||
var iOffset:int = top + y * moduleSize;
|
||||
for (var x:int = 0; x < matrixWidth; x++)
|
||||
{
|
||||
if (image._get(left + x * moduleSize, iOffset))
|
||||
{
|
||||
bits._set(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
// And now find where the bottommost black module on the first column ends
|
||||
var columnEndOfSymbol:int = height - 1;
|
||||
while (columnEndOfSymbol >= 0 && !image._get(borderWidth, columnEndOfSymbol)) {
|
||||
columnEndOfSymbol--;
|
||||
}
|
||||
if (columnEndOfSymbol < 0) {
|
||||
throw new ReaderException("DataMatrixReader : extractPureBits : columnEndOfSymbol < 0");
|
||||
}
|
||||
columnEndOfSymbol++;
|
||||
private static function moduleSize(leftTopBlack:Array, image:BitMatrix):int
|
||||
{
|
||||
var width:int = image.getWidth();
|
||||
var x:int = leftTopBlack[0];
|
||||
var y:int = leftTopBlack[1];
|
||||
while (x < width && image._get(x, y))
|
||||
{
|
||||
x++;
|
||||
}
|
||||
if (x == width)
|
||||
{
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
// Make sure width of barcode is a multiple of module size
|
||||
if ((columnEndOfSymbol - borderWidth) % moduleSize != 0) {
|
||||
throw new ReaderException("DataMatrixReader : extractPureBits : barcode width is not a multiple of module size");
|
||||
}
|
||||
var dimension:int = (columnEndOfSymbol - borderWidth) / moduleSize;
|
||||
|
||||
// Push in the "border" by half the module width so that we start
|
||||
// sampling in the middle of the module. Just in case the image is a
|
||||
// little off, this will help recover.
|
||||
borderWidth += moduleSize >> 1;
|
||||
|
||||
var sampleDimension:int = borderWidth + (dimension - 1) * moduleSize;
|
||||
if (sampleDimension >= width || sampleDimension >= height) {
|
||||
throw new ReaderException("DataMatrixReader : extractPureBits : sampleDimension ("+sampleDimension+") is large than width ("+width+") or height ("+height+")");
|
||||
}
|
||||
|
||||
// Now just read off the bits
|
||||
var bits:BitMatrix = new BitMatrix(dimension);
|
||||
for (var i:int = 0; i < dimension; i++) {
|
||||
var iOffset:int = borderWidth + i * moduleSize;
|
||||
for (var j:int = 0; j < dimension; j++) {
|
||||
if (image._get(borderWidth + j * moduleSize, iOffset)) {
|
||||
bits._set(j, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
var moduleSize:int = x - leftTopBlack[0];
|
||||
if (moduleSize == 0)
|
||||
{
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
return moduleSize;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -33,15 +33,14 @@ package com.google.zxing.datamatrix.decoder
|
|||
* @throws ReaderException if dimension is < 10 or > 144 or not 0 mod 2
|
||||
*/
|
||||
public function BitMatrixParser(bitMatrix:BitMatrix) {
|
||||
var dimension:int = bitMatrix.getDimension();
|
||||
if (dimension < 10 || dimension > 144 || (dimension & 0x01) != 0) {
|
||||
var dimension:int = bitMatrix.getHeight();
|
||||
if (dimension < 8 || dimension > 144 || (dimension & 0x01) != 0) {
|
||||
throw new ReaderException("BitMatrixParser : Dimension out of range :"+dimension+" range 11~143 or uneven number");
|
||||
}
|
||||
|
||||
version = readVersion(bitMatrix);
|
||||
this.mappingBitMatrix = extractDataRegion(bitMatrix);
|
||||
// TODO(bbrown): Make this work for rectangular symbols
|
||||
this.readMappingMatrix = new BitMatrix(this.mappingBitMatrix.getDimension());
|
||||
this.readMappingMatrix = new BitMatrix(this.mappingBitMatrix.getWidth(), this.mappingBitMatrix.getHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -55,16 +54,11 @@ package com.google.zxing.datamatrix.decoder
|
|||
* @throws ReaderException if the dimensions of the mapping matrix are not valid
|
||||
* Data Matrix dimensions.
|
||||
*/
|
||||
public function readVersion(bitMatrix:BitMatrix ):Version {
|
||||
|
||||
if (version != null) {
|
||||
return version;
|
||||
}
|
||||
|
||||
// TODO(bbrown): make this work for rectangular dimensions as well.
|
||||
var numRows:int = bitMatrix.getDimension();
|
||||
var numColumns:int = numRows;
|
||||
return Version.getVersionForDimensions(numRows, numColumns);;
|
||||
public function readVersion(bitMatrix:BitMatrix ):Version
|
||||
{
|
||||
var numRows:int = bitMatrix.getHeight();
|
||||
var numColumns:int = bitMatrix.getWidth();
|
||||
return Version.getVersionForDimensions(numRows, numColumns);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -82,9 +76,9 @@ package com.google.zxing.datamatrix.decoder
|
|||
|
||||
var row:int = 4;
|
||||
var column:int = 0;
|
||||
// TODO(bbrown): Data Matrix can be rectangular, assuming square for now
|
||||
var numRows:int = mappingBitMatrix.getDimension();
|
||||
var numColumns:int = numRows;
|
||||
|
||||
var numRows:int = mappingBitMatrix.getHeight();
|
||||
var numColumns:int = mappingBitMatrix.getWidth();
|
||||
|
||||
var corner1Read:Boolean = false;
|
||||
var corner2Read:Boolean = false;
|
||||
|
@ -142,7 +136,8 @@ package com.google.zxing.datamatrix.decoder
|
|||
if (resultOffset != version.getTotalCodewords()) {
|
||||
throw new ReaderException("BitMatrixParser : readCodewords : resultOffset != version.getTotalCodewords() : "+resultOffset +" - "+ version.getTotalCodewords());
|
||||
}
|
||||
// BAS : extra code for Flex : result should be a signed byte array (bit 7 = sign)
|
||||
|
||||
// extra code for Flex : result should be a signed byte array (bit 7 = sign)
|
||||
for (var jj:int=0;jj<result.length;jj++)
|
||||
{
|
||||
if ((result[jj] & 128) > 0 )
|
||||
|
@ -164,11 +159,13 @@ package com.google.zxing.datamatrix.decoder
|
|||
*/
|
||||
public function readModule(row:int , column:int , numRows:int , numColumns:int ):Boolean {
|
||||
// Adjust the row and column indices based on boundary wrapping
|
||||
if (row < 0) {
|
||||
if (row < 0)
|
||||
{
|
||||
row += numRows;
|
||||
column += 4 - ((numRows + 4) & 0x07);
|
||||
}
|
||||
if (column < 0) {
|
||||
if (column < 0)
|
||||
{
|
||||
column += numColumns;
|
||||
row += 4 - ((numColumns + 4) & 0x07);
|
||||
}
|
||||
|
@ -191,7 +188,7 @@ package com.google.zxing.datamatrix.decoder
|
|||
{
|
||||
var currentByte:int = 0;
|
||||
if (readModule(row - 2, column - 2, numRows, numColumns))
|
||||
{
|
||||
{
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
|
@ -416,8 +413,7 @@ package com.google.zxing.datamatrix.decoder
|
|||
var symbolSizeRows:int = version.getSymbolSizeRows();
|
||||
var symbolSizeColumns:int = version.getSymbolSizeColumns();
|
||||
|
||||
// TODO(bbrown): Make this work with rectangular codes
|
||||
if (bitMatrix.getDimension() != symbolSizeRows) {
|
||||
if (bitMatrix.getHeight() != symbolSizeRows) {
|
||||
throw new IllegalArgumentException("Dimension of bitMarix must match the version size");
|
||||
}
|
||||
|
||||
|
@ -428,10 +424,10 @@ package com.google.zxing.datamatrix.decoder
|
|||
var numDataRegionsColumn:int = symbolSizeColumns / dataRegionSizeColumns;
|
||||
|
||||
var sizeDataRegionRow:int = numDataRegionsRow * dataRegionSizeRows;
|
||||
//int sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns;
|
||||
var sizeDataRegionColumn:int = numDataRegionsColumn * dataRegionSizeColumns;
|
||||
|
||||
// TODO(bbrown): Make this work with rectangular codes
|
||||
var bitMatrixWithoutAlignment:BitMatrix = new BitMatrix(sizeDataRegionRow);
|
||||
var bitMatrixWithoutAlignment:BitMatrix = new BitMatrix(sizeDataRegionColumn,sizeDataRegionRow);
|
||||
for (var dataRegionRow:int = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow) {
|
||||
var dataRegionRowOffset:int = dataRegionRow * dataRegionSizeRows;
|
||||
for (var dataRegionColumn:int = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn) {
|
||||
|
|
|
@ -82,8 +82,7 @@ package com.google.zxing.datamatrix.decoder
|
|||
for (var i2:int = 0; i2 < shorterBlocksNumDataCodewords; i2++) {
|
||||
for (var j2:int = 0; j2 < numResultBlocks; j2++)
|
||||
{
|
||||
result[j2].codewords[i2] = rawCodewords[rawCodewordsOffset];
|
||||
rawCodewordsOffset++;
|
||||
result[j2].codewords[i2] = rawCodewords[rawCodewordsOffset++];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,8 +90,7 @@ package com.google.zxing.datamatrix.decoder
|
|||
var specialVersion:Boolean = version.getVersionNumber() == 24;
|
||||
var numLongerBlocks:int = specialVersion ? 8 : numResultBlocks;
|
||||
for (var j3:int = 0; j3 < numLongerBlocks; j3++) {
|
||||
result[j3].codewords[longerBlocksNumDataCodewords - 1] = rawCodewords[rawCodewordsOffset];
|
||||
rawCodewordsOffset++;
|
||||
result[j3].codewords[longerBlocksNumDataCodewords - 1] = rawCodewords[rawCodewordsOffset++];
|
||||
}
|
||||
|
||||
// Now add in error correction blocks
|
||||
|
@ -100,8 +98,7 @@ package com.google.zxing.datamatrix.decoder
|
|||
for (var i4:int = longerBlocksNumDataCodewords; i4 < max; i4++) {
|
||||
for (var j4:int = 0; j4 < numResultBlocks; j4++) {
|
||||
var iOffset:int = (specialVersion && j4 > 7) ? i4 - 1 : i4;
|
||||
result[j4].codewords[iOffset] = rawCodewords[rawCodewordsOffset];
|
||||
rawCodewordsOffset++;
|
||||
result[j4].codewords[iOffset] = rawCodewords[rawCodewordsOffset++];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ package com.google.zxing.datamatrix.decoder
|
|||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
import com.google.zxing.common.zxingByteArray;
|
||||
import com.google.zxing.ReaderException;
|
||||
import com.google.zxing.FormatException;
|
||||
/**
|
||||
* See ISO 16022:2006, Annex C Table C.1
|
||||
* The C40 Basic Character Set (*'s used for placeholders for the shift values)
|
||||
|
@ -77,10 +78,10 @@ package com.google.zxing.datamatrix.decoder
|
|||
|
||||
public static function decode(bytes:Array ):DecoderResult {
|
||||
var bits:BitSource = new BitSource(bytes);
|
||||
var result:StringBuilder = new StringBuilder();
|
||||
var result:StringBuilder = new StringBuilder(100);
|
||||
var resultTrailer:StringBuilder = new StringBuilder(0);
|
||||
var byteSegments:ArrayList = new ArrayList(1);
|
||||
var mode:int = DecodedBitStreamParser.ASCII_ENCODE;
|
||||
var mode:int = ASCII_ENCODE;
|
||||
do {
|
||||
if (mode == ASCII_ENCODE) {
|
||||
mode = decodeAsciiSegment(bits, result, resultTrailer);
|
||||
|
@ -140,12 +141,13 @@ package com.google.zxing.datamatrix.decoder
|
|||
return C40_ENCODE;
|
||||
} else if (oneByte == 231) { // Latch to Base 256 encodation
|
||||
return BASE256_ENCODE;
|
||||
} else if (oneByte == 232) { // FNC1
|
||||
throw new ReaderException("DecodedBitStreamParser : decodeAsciiSegment : oneByte = 232 ");
|
||||
} else if (oneByte == 233) { // Structured Append
|
||||
throw new ReaderException("DecodedBitStreamParser : decodeAsciiSegment : oneByte = 233");
|
||||
} else if (oneByte == 234) { // Reader Programming
|
||||
throw new ReaderException("DecodedBitStreamParser : decodeAsciiSegment : oneByte = 234");
|
||||
} else if (oneByte == 232) {
|
||||
// FNC1
|
||||
String.fromCharCode(29);// translate as ASCII 29
|
||||
} else if ((oneByte == 233) || (oneByte == 234))
|
||||
{ // Structured Append, Reader Programming
|
||||
// Ignore these symbols for now
|
||||
// throw new ReaderException("DecodedBitStreamParser : decodeAsciiSegment : oneByte = 234");
|
||||
} else if (oneByte == 235) { // Upper Shift (shift to Extended ASCII)
|
||||
upperShift = true;
|
||||
} else if (oneByte == 236) { // 05 Macro
|
||||
|
@ -161,11 +163,17 @@ package com.google.zxing.datamatrix.decoder
|
|||
} else if (oneByte == 240) { // Latch to EDIFACT encodation
|
||||
return EDIFACT_ENCODE;
|
||||
} else if (oneByte == 241) { // ECI Character
|
||||
// TODO(bbrown): I think we need to support ECI
|
||||
throw new ReaderException("DecodedBitStreamParser : decodeAsciiSegment : oneByte = 241");
|
||||
// TODO(bbrown): I think we need to support ECI
|
||||
//throw ReaderException.getInstance();
|
||||
// Ignore this symbol for now
|
||||
} else if (oneByte >= 242) { // Not to be used in ASCII encodation
|
||||
throw new ReaderException("DecodedBitStreamParser : decodeAsciiSegment : oneByte = 242");
|
||||
}
|
||||
// ... but work around encoders that end with 254, latch back to ASCII
|
||||
if (oneByte == 254 && bits.available() == 0) {
|
||||
// Ignore
|
||||
} else {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
}
|
||||
} while (bits.available() > 0);
|
||||
return ASCII_ENCODE;
|
||||
}
|
||||
|
@ -226,7 +234,7 @@ package com.google.zxing.datamatrix.decoder
|
|||
result.Append(C40_SHIFT2_SET_CHARS[cValue]);
|
||||
}
|
||||
} else if (cValue == 27) { // FNC1
|
||||
throw new ReaderException("DecodedBitStreamParser : decodeC40Segment : cValue = 27");
|
||||
result.Append(String.fromCharCode(29)); // translate as ASCII 29
|
||||
} else if (cValue == 30) { // Upper Shift
|
||||
upperShift = true;
|
||||
} else {
|
||||
|
@ -277,17 +285,20 @@ package com.google.zxing.datamatrix.decoder
|
|||
var cValue:int = cValues[i];
|
||||
switch (shift) {
|
||||
case 0:
|
||||
if (cValue < 3) {
|
||||
shift = cValue + 1;
|
||||
} else {
|
||||
if (upperShift) {
|
||||
result.Append(TEXT_BASIC_SET_CHARS[cValue]);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result.Append(TEXT_BASIC_SET_CHARS[cValue]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
if (cValue < 3) {
|
||||
shift = cValue + 1;
|
||||
} else if (cValue < TEXT_BASIC_SET_CHARS.length) {
|
||||
var textChar:String = TEXT_BASIC_SET_CHARS[cValue];
|
||||
if (upperShift) {
|
||||
result.Append(String.fromCharCode(textChar.charCodeAt(0) + 128));
|
||||
upperShift = false;
|
||||
} else {
|
||||
result.Append(textChar);
|
||||
}
|
||||
} else {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (upperShift) {
|
||||
result.Append(cValue + 128);
|
||||
|
@ -299,15 +310,16 @@ package com.google.zxing.datamatrix.decoder
|
|||
break;
|
||||
case 2:
|
||||
// Shift 2 for Text is the same encoding as C40
|
||||
if (cValue < 27) {
|
||||
if (cValue < C40_SHIFT2_SET_CHARS.length) {
|
||||
var c40char:String =C40_SHIFT2_SET_CHARS[cValue];
|
||||
if (upperShift) {
|
||||
result.Append(C40_SHIFT2_SET_CHARS[cValue] + 128);
|
||||
result.Append(c40char + 128);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result.Append(C40_SHIFT2_SET_CHARS[cValue]);
|
||||
result.Append(c40char);
|
||||
}
|
||||
} else if (cValue == 27) { // FNC1
|
||||
throw new ReaderException( "DecodedBitStreamParser : decodeTextSegment : cValue = 27");
|
||||
result.Append(String.fromCharCode(29)); // translate as ASCII 29
|
||||
} else if (cValue == 30) { // Upper Shift
|
||||
upperShift = true;
|
||||
} else {
|
||||
|
@ -316,14 +328,23 @@ package com.google.zxing.datamatrix.decoder
|
|||
shift = 0;
|
||||
break;
|
||||
case 3:
|
||||
if (cValue < TEXT_SHIFT3_SET_CHARS.length)
|
||||
{
|
||||
var textChar2:String = TEXT_SHIFT3_SET_CHARS[cValue];
|
||||
if (upperShift) {
|
||||
result.Append(TEXT_SHIFT3_SET_CHARS[cValue] + 128);
|
||||
result.Append(textChar2 + 128);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result.Append(TEXT_SHIFT3_SET_CHARS[cValue]);
|
||||
result.Append(textChar2);
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ReaderException();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ReaderException("DecodedBitStreamParser : decodeTextSegment : no match for shift"+shift);
|
||||
}
|
||||
|
@ -404,8 +425,8 @@ package com.google.zxing.datamatrix.decoder
|
|||
}
|
||||
|
||||
if (!unlatch) {
|
||||
if ((edifactValue & 32) == 0) { // no 1 in the leading (6th) bit
|
||||
edifactValue |= 64; // Add a leading 01 to the 6 bit binary value
|
||||
if ((edifactValue & 0x20) == 0) { // no 1 in the leading (6th) bit
|
||||
edifactValue |= 0x40; // Add a leading 01 to the 6 bit binary value
|
||||
}
|
||||
result.Append(edifactValue);
|
||||
}
|
||||
|
@ -416,37 +437,55 @@ package com.google.zxing.datamatrix.decoder
|
|||
/**
|
||||
* See ISO 16022:2006, 5.2.9 and Annex B, B.2
|
||||
*/
|
||||
private static function decodeBase256Segment(bits:BitSource, result:StringBuilder , byteSegments:ArrayList ):void {
|
||||
private static function decodeBase256Segment(bits:BitSource, result:StringBuilder , byteSegments:ArrayList ):void
|
||||
{
|
||||
// Figure out how long the Base 256 Segment is.
|
||||
var d1:int = bits.readBits(8);
|
||||
var count:int;
|
||||
if (d1 == 0) { // Read the remainder of the symbol
|
||||
count = bits.available() / 8;
|
||||
} else if (d1 < 250) {
|
||||
count = d1;
|
||||
} else {
|
||||
count = 250 * (d1 - 249) + bits.readBits(8);
|
||||
}
|
||||
var bytes:Array = new Array(count);
|
||||
for (var i:int = 0; i < count; i++)
|
||||
{
|
||||
bytes[i] = unrandomize255State(bits.readBits(8), i);
|
||||
}
|
||||
byteSegments.Add(bytes);
|
||||
try
|
||||
{
|
||||
//result.Append(System.Text.Encoding.GetEncoding("iso-8859-1").GetString(bytes));
|
||||
var str:String = "";
|
||||
for(var i2:int=0;i2<bytes.length;i2++)
|
||||
{
|
||||
str = str + String.fromCharCode(bytes[i2]);
|
||||
}
|
||||
result.Append(str);
|
||||
// Figure out how long the Base 256 Segment is.
|
||||
var codewordPosition:int = 1 + bits.getByteOffset(); // position is 1-indexed
|
||||
var d1:int = unrandomize255State(bits.readBits(8), codewordPosition++);
|
||||
var count:int;
|
||||
if (d1 == 0)
|
||||
{ // Read the remainder of the symbol
|
||||
count = bits.available() / 8;
|
||||
}
|
||||
else if (d1 < 250)
|
||||
{
|
||||
count = d1;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = 250 * (d1 - 249) + unrandomize255State(bits.readBits(8), codewordPosition++);
|
||||
}
|
||||
|
||||
|
||||
} catch (uee:Error ) {
|
||||
throw new Error("Platform does not support required encoding: " + uee);
|
||||
}
|
||||
// We're seeing NegativeArraySizeException errors from users.
|
||||
if (count < 0)
|
||||
{
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
|
||||
var bytes:Array = new Array(count);
|
||||
for (var i:int = 0; i < count; i++)
|
||||
{
|
||||
// Have seen this particular error in the wild, such as at
|
||||
// http://www.bcgen.com/demo/IDAutomationStreamingDataMatrix.aspx?MODE=3&D=Fred&PFMT=3&PT=F&X=0.3&O=0&LM=0.2
|
||||
if (bits.available() < 8)
|
||||
{
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
bytes[i] = unrandomize255State(bits.readBits(8), codewordPosition++);
|
||||
}
|
||||
byteSegments.addElement(bytes);
|
||||
/*try
|
||||
{
|
||||
result.append(new String(bytes, "ISO8859_1"));
|
||||
} catch (UnsupportedEncodingException uee)
|
||||
{
|
||||
throw new RuntimeException("Platform does not support required encoding: " + uee);
|
||||
}*/
|
||||
for (var k:int=0;k<bytes.length;k++)
|
||||
{
|
||||
result.Append(String.fromCharCode(bytes[k])); // BAS :Flex does not support encodings
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -29,13 +29,13 @@ package com.google.zxing.datamatrix.decoder
|
|||
import com.google.zxing.common.DecoderResult;
|
||||
import com.google.zxing.common.reedsolomon.ReedSolomonDecoder;
|
||||
import com.google.zxing.common.reedsolomon.ReedSolomonException;
|
||||
import com.google.zxing.common.reedsolomon.GF256;
|
||||
import com.google.zxing.common.reedsolomon.GenericGF;
|
||||
import com.google.zxing.ReaderException;
|
||||
|
||||
|
||||
private var rsDecoder:ReedSolomonDecoder;
|
||||
public function Decoder() {
|
||||
rsDecoder = new ReedSolomonDecoder(GF256.DATA_MATRIX_FIELD);
|
||||
rsDecoder = new ReedSolomonDecoder(GenericGF.DATA_MATRIX_FIELD_256);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -94,16 +94,18 @@ package com.google.zxing.datamatrix.decoder
|
|||
var resultOffset:int = 0;
|
||||
|
||||
// Error-correct and copy data blocks together into a stream of bytes
|
||||
for (var j:int = 0; j < dataBlocks.length; j++) {
|
||||
for (var j:int = 0; j < dataBlocks.length; j++)
|
||||
{
|
||||
var dataBlock:DataBlock = dataBlocks[j];
|
||||
var codewordBytes:Array = dataBlock.getCodewords();
|
||||
var numDataCodewords:int = dataBlock.getNumDataCodewords();
|
||||
correctErrors(codewordBytes, numDataCodewords);
|
||||
for (var ii:int = 0; ii < numDataCodewords; ii++) {
|
||||
resultBytes[resultOffset++] = codewordBytes[ii];
|
||||
for (var i5:int = 0; i5 < numDataCodewords; i5++)
|
||||
{
|
||||
// De-interlace data blocks.
|
||||
resultBytes[i5 * dataBlocks.length + j] = codewordBytes[i5];
|
||||
}
|
||||
}
|
||||
|
||||
// Decode the contents of that stream of bytes
|
||||
return DecodedBitStreamParser.decode(resultBytes);
|
||||
}
|
||||
|
@ -131,8 +133,10 @@ package com.google.zxing.datamatrix.decoder
|
|||
}
|
||||
// Copy back into array of bytes -- only need to worry about the bytes that were data
|
||||
// We don't care about errors in the error-correction codewords
|
||||
for (var ii:int = 0; ii < numDataCodewords; ii++) {
|
||||
codewordBytes[ii] = int( codewordsInts[ii]);
|
||||
for (var ii:int = 0; ii < numDataCodewords; ii++)
|
||||
{
|
||||
|
||||
codewordBytes[ii] = (codewordsInts[ii]>127)?codewordsInts[ii]-256:codewordsInts[ii];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@ package com.google.zxing.datamatrix.decoder
|
|||
|
||||
public class Version
|
||||
{
|
||||
|
||||
private static var VERSIONS:Array = buildVersions();
|
||||
private var versionNumber:int;
|
||||
private var symbolSizeRows:int;
|
||||
|
@ -182,7 +181,7 @@ package com.google.zxing.datamatrix.decoder
|
|||
new ECBlocks(14, new ECB(1, 16))),
|
||||
new Version(28, 12, 36, 10, 16,
|
||||
new ECBlocks(18, new ECB(1, 22))),
|
||||
new Version(29, 16, 36, 10, 16,
|
||||
new Version(29, 16, 36, 14, 16,
|
||||
new ECBlocks(24, new ECB(1, 32))),
|
||||
new Version(30, 16, 48, 14, 22,
|
||||
new ECBlocks(28, new ECB(1, 49)))];
|
||||
|
|
|
@ -15,17 +15,16 @@
|
|||
*/
|
||||
package com.google.zxing.datamatrix.detector
|
||||
{
|
||||
import com.google.zxing.common.detector.MonochromeRectangleDetector;
|
||||
import com.google.zxing.common.GridSampler;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.ReaderException;
|
||||
import com.google.zxing.ResultPoint;
|
||||
import com.google.zxing.common.DetectorResult;
|
||||
import com.google.zxing.common.flexdatatypes.ArrayList;
|
||||
import com.google.zxing.common.BitArray;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.ReaderException;
|
||||
|
||||
import com.google.zxing.common.DetectorResult;
|
||||
import com.google.zxing.common.GridSampler;
|
||||
import com.google.zxing.common.detector.MonochromeRectangleDetector;
|
||||
import com.google.zxing.common.detector.WhiteRectangleDetector;
|
||||
import com.google.zxing.common.flexdatatypes.ArrayList;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
|
||||
/**
|
||||
* <p>Encapsulates logic that can detect a Data Matrix Code in an image, even if the Data Matrix Code
|
||||
|
@ -51,16 +50,16 @@ package com.google.zxing.datamatrix.detector
|
|||
|
||||
// Trick to avoid creating new int objects below -- a sort of crude copy of
|
||||
// the int.valueOf(int) optimization added in Java 5, not in J2ME
|
||||
//private static var INTEGERS:Array = [0, 1, 2, 3, 4];
|
||||
private static var INTEGERS:Array =[ 0,1,2,3,4 ];
|
||||
|
||||
|
||||
private var image:BitMatrix ;
|
||||
private var rectangleDetector:MonochromeRectangleDetector
|
||||
|
||||
private var rectangleDetector:WhiteRectangleDetector;
|
||||
|
||||
public function Detector(image:BitMatrix)
|
||||
{
|
||||
this.image = image;
|
||||
rectangleDetector = new MonochromeRectangleDetector(image);
|
||||
rectangleDetector = new WhiteRectangleDetector(image);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -69,7 +68,8 @@ package com.google.zxing.datamatrix.detector
|
|||
* @return {@link DetectorResult} encapsulating results of detecting a QR Code
|
||||
* @throws ReaderException if no Data Matrix Code can be found
|
||||
*/
|
||||
public function detect():DetectorResult {
|
||||
public function detect():DetectorResult
|
||||
{
|
||||
|
||||
|
||||
var cornerPoints:Array = rectangleDetector.detect();
|
||||
|
@ -92,8 +92,8 @@ package com.google.zxing.datamatrix.detector
|
|||
|
||||
// Sort by number of transitions. First two will be the two solid sides; last two
|
||||
// will be the two alternating black/white sides
|
||||
var lSideOne:ResultPointsAndTransitions = ResultPointsAndTransitions( transitions.getObjectByIndex(0));
|
||||
var lSideTwo:ResultPointsAndTransitions = ResultPointsAndTransitions( transitions.getObjectByIndex(1));
|
||||
var lSideOne:ResultPointsAndTransitions = ( transitions.getObjectByIndex(0) as ResultPointsAndTransitions);
|
||||
var lSideTwo:ResultPointsAndTransitions = ( transitions.getObjectByIndex(1) as ResultPointsAndTransitions);
|
||||
|
||||
// Figure out which point is their intersection by tallying up the number of times we see the
|
||||
// endpoints in the four endpoints. One will show up twice.
|
||||
|
@ -110,7 +110,7 @@ package com.google.zxing.datamatrix.detector
|
|||
for (var ii:int=0;ii<size;ii++)
|
||||
{
|
||||
var point:ResultPoint = pointCount.getKeyByIndex(ii) as ResultPoint;// resultpoints are used as keys
|
||||
var value:int = pointCount.getValueByIndex(ii) as int;
|
||||
var value:int = Math.floor(pointCount.getValueByIndex(ii) as Number);
|
||||
if (value == 2)
|
||||
{
|
||||
bottomLeft = point; // this is definitely the bottom left, then -- end of two L sides
|
||||
|
@ -163,94 +163,250 @@ package com.google.zxing.datamatrix.detector
|
|||
topRight = pointD;
|
||||
}
|
||||
|
||||
// Next determine the dimension by tracing along the top or right side and counting black/white
|
||||
// transitions. Since we start inside a black module, we should see a number of transitions
|
||||
// equal to 1 less than the code dimension. Well, actually 2 less, because we are going to
|
||||
// end on a black module:
|
||||
// Next determine the dimension by tracing along the top or right side and counting black/white
|
||||
// transitions. Since we start inside a black module, we should see a number of transitions
|
||||
// equal to 1 less than the code dimension. Well, actually 2 less, because we are going to
|
||||
// end on a black module:
|
||||
|
||||
// The top right point is actually the corner of a module, which is one of the two black modules
|
||||
// adjacent to the white module at the top right. Tracing to that corner from either the top left
|
||||
// or bottom right should work here, but, one will be more reliable since it's traced straight
|
||||
// up or across, rather than at a slight angle. We use dot products to figure out which is
|
||||
// better to use:
|
||||
var dimension:int = Math.min(transitionsBetween(topLeft, topRight).getTransitions(),
|
||||
transitionsBetween(bottomRight, topRight).getTransitions());
|
||||
if ((dimension & 0x01) == 1)
|
||||
{
|
||||
// it can't be odd, so, round... up?
|
||||
dimension++;
|
||||
}
|
||||
dimension += 2;
|
||||
// The top right point is actually the corner of a module, which is one of the two black modules
|
||||
// adjacent to the white module at the top right. Tracing to that corner from either the top left
|
||||
// or bottom right should work here.
|
||||
|
||||
var dimensionTop:int = transitionsBetween(topLeft, topRight).getTransitions();
|
||||
var dimensionRight:int = transitionsBetween(bottomRight, topRight).getTransitions();
|
||||
|
||||
if ((dimensionTop & 0x01) == 1) {
|
||||
// it can't be odd, so, round... up?
|
||||
dimensionTop++;
|
||||
}
|
||||
dimensionTop += 2;
|
||||
|
||||
if ((dimensionRight & 0x01) == 1) {
|
||||
// it can't be odd, so, round... up?
|
||||
dimensionRight++;
|
||||
}
|
||||
dimensionRight += 2;
|
||||
|
||||
var bits:BitMatrix ;
|
||||
var correctedTopRight:ResultPoint ;
|
||||
|
||||
// Rectanguar symbols are 6x16, 6x28, 10x24, 10x32, 14x32, or 14x44. If one dimension is more
|
||||
// than twice the other, it's certainly rectangular, but to cut a bit more slack we accept it as
|
||||
// rectangular if the bigger side is at least 7/4 times the other:
|
||||
if (4 * dimensionTop >= 7 * dimensionRight || 4 * dimensionRight >= 7 * dimensionTop) {
|
||||
// The matrix is rectangular
|
||||
|
||||
correctedTopRight =
|
||||
correctTopRightRectangular(bottomLeft, bottomRight, topLeft, topRight, dimensionTop, dimensionRight);
|
||||
if (correctedTopRight == null){
|
||||
correctedTopRight = topRight;
|
||||
}
|
||||
|
||||
dimensionTop = transitionsBetween(topLeft, correctedTopRight).getTransitions();
|
||||
dimensionRight = transitionsBetween(bottomRight, correctedTopRight).getTransitions();
|
||||
|
||||
if ((dimensionTop & 0x01) == 1) {
|
||||
// it can't be odd, so, round... up?
|
||||
dimensionTop++;
|
||||
}
|
||||
|
||||
if ((dimensionRight & 0x01) == 1) {
|
||||
// it can't be odd, so, round... up?
|
||||
dimensionRight++;
|
||||
}
|
||||
|
||||
bits = sampleGrid(image, topLeft, bottomLeft, bottomRight, correctedTopRight, dimensionTop, dimensionRight);
|
||||
|
||||
} else {
|
||||
// The matrix is square
|
||||
|
||||
var dimension:int = Math.min(dimensionRight, dimensionTop);
|
||||
// correct top right point to match the white module
|
||||
correctedTopRight = correctTopRight(bottomLeft, bottomRight, topLeft, topRight, dimension);
|
||||
if (correctedTopRight == null){
|
||||
correctedTopRight = topRight;
|
||||
}
|
||||
|
||||
// Redetermine the dimension using the corrected top right point
|
||||
var dimensionCorrected:int = Math.max(transitionsBetween(topLeft, correctedTopRight).getTransitions(),
|
||||
transitionsBetween(bottomRight, correctedTopRight).getTransitions());
|
||||
dimensionCorrected++;
|
||||
if ((dimensionCorrected & 0x01) == 1) {
|
||||
dimensionCorrected++;
|
||||
}
|
||||
|
||||
bits = sampleGrid(image,
|
||||
topLeft,
|
||||
bottomLeft,
|
||||
bottomRight,
|
||||
correctedTopRight,
|
||||
dimensionCorrected,
|
||||
dimensionCorrected);
|
||||
}
|
||||
return new DetectorResult(bits, [topLeft, bottomLeft, bottomRight, correctedTopRight]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var bits:BitMatrix = sampleGrid(image, topLeft, bottomLeft, bottomRight, dimension);
|
||||
return new DetectorResult(bits, [pointA, pointB, pointC, pointD]);
|
||||
}
|
||||
/**
|
||||
* Calculates the position of the white top right module using the output of the rectangle detector
|
||||
* for a rectangular matrix
|
||||
*/
|
||||
private function correctTopRightRectangular(bottomLeft:ResultPoint ,
|
||||
bottomRight:ResultPoint , topLeft:ResultPoint , topRight:ResultPoint ,
|
||||
dimensionTop:int , dimensionRight:int ):ResultPoint {
|
||||
|
||||
var corr:Number = distance(bottomLeft, bottomRight) / dimensionTop;
|
||||
var norm:int = distance(topLeft, topRight);
|
||||
var cos:Number = (topRight.getX() - topLeft.getX()) / norm;
|
||||
var sin:Number = (topRight.getY() - topLeft.getY()) / norm;
|
||||
|
||||
var c1:ResultPoint = new ResultPoint(topRight.getX()+corr*cos, topRight.getY()+corr*sin);
|
||||
|
||||
corr = distance(bottomLeft, topLeft) / dimensionRight;
|
||||
norm = distance(bottomRight, topRight);
|
||||
cos = (topRight.getX() - bottomRight.getX()) / norm;
|
||||
sin = (topRight.getY() - bottomRight.getY()) / norm;
|
||||
|
||||
var c2:ResultPoint = new ResultPoint(topRight.getX()+corr*cos, topRight.getY()+corr*sin);
|
||||
|
||||
/**
|
||||
* Increments the int associated with a key by one.
|
||||
*/
|
||||
private static function increment(table:HashTable, key:ResultPoint):void
|
||||
{
|
||||
if (!table.ContainsKey(key))
|
||||
{
|
||||
table.Add(key,1);
|
||||
}
|
||||
else
|
||||
{
|
||||
var value:int = int(table.getValueByKey(key));
|
||||
table.setValue(key,value+1);
|
||||
}
|
||||
}
|
||||
if (!isValid(c1)){
|
||||
if (isValid(c2)){
|
||||
return c2;
|
||||
}
|
||||
return null;
|
||||
} else if (!isValid(c2)){
|
||||
return c1;
|
||||
}
|
||||
|
||||
var l1:int = Math.abs(dimensionTop - transitionsBetween(topLeft, c1).getTransitions()) +
|
||||
Math.abs(dimensionRight - transitionsBetween(bottomRight, c1).getTransitions());
|
||||
var l2:int = Math.abs(dimensionTop - transitionsBetween(topLeft, c2).getTransitions()) +
|
||||
Math.abs(dimensionRight - transitionsBetween(bottomRight, c2).getTransitions());
|
||||
|
||||
if (l1 <= l2){
|
||||
return c1;
|
||||
}
|
||||
|
||||
return c2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the position of the white top right module using the output of the rectangle detector
|
||||
* for a square matrix
|
||||
*/
|
||||
private function correctTopRight(bottomLeft:ResultPoint ,
|
||||
bottomRight:ResultPoint,
|
||||
topLeft:ResultPoint ,
|
||||
topRight:ResultPoint ,
|
||||
dimension:int ):ResultPoint {
|
||||
|
||||
var corr:Number = distance(bottomLeft, bottomRight) / dimension;
|
||||
var norm:int = distance(topLeft, topRight);
|
||||
var cos:Number = (topRight.getX() - topLeft.getX()) / norm;
|
||||
var sin:Number = (topRight.getY() - topLeft.getY()) / norm;
|
||||
|
||||
var c1:ResultPoint = new ResultPoint(topRight.getX() + corr * cos, topRight.getY() + corr * sin);
|
||||
|
||||
corr = distance(bottomLeft, bottomRight) / dimension;
|
||||
norm = distance(bottomRight, topRight);
|
||||
cos = (topRight.getX() - bottomRight.getX()) / norm;
|
||||
sin = (topRight.getY() - bottomRight.getY()) / norm;
|
||||
|
||||
var c2:ResultPoint = new ResultPoint(topRight.getX() + corr * cos, topRight.getY() + corr * sin);
|
||||
|
||||
private static function sampleGrid(image:BitMatrix ,
|
||||
topLeft:ResultPoint,
|
||||
bottomLeft:ResultPoint,
|
||||
bottomRight:ResultPoint,
|
||||
dimension:int):BitMatrix {
|
||||
if (!isValid(c1)) {
|
||||
if (isValid(c2)) {
|
||||
return c2;
|
||||
}
|
||||
return null;
|
||||
} else if (!isValid(c2)) {
|
||||
return c1;
|
||||
}
|
||||
|
||||
var l1:int = Math.abs(transitionsBetween(topLeft, c1).getTransitions() -
|
||||
transitionsBetween(bottomRight, c1).getTransitions());
|
||||
var l2:int = Math.abs(transitionsBetween(topLeft, c2).getTransitions() -
|
||||
transitionsBetween(bottomRight, c2).getTransitions());
|
||||
|
||||
// We make up the top right point for now, based on the others.
|
||||
// TODO: we actually found a fourth corner above and figured out which of two modules
|
||||
// it was the corner of. We could use that here and adjust for perspective distortion.
|
||||
var topRightX:Number = (bottomRight.getX() - bottomLeft.getX()) + topLeft.getX();
|
||||
var topRightY:Number = (bottomRight.getY() - bottomLeft.getY()) + topLeft.getY();
|
||||
return l1 <= l2 ? c1 : c2;
|
||||
}
|
||||
|
||||
private function isValid(p:ResultPoint):Boolean {
|
||||
return p.getX() >= 0 && p.getX() < image.getWidth() && p.getY() > 0 && p.getY() < image.getHeight();
|
||||
}
|
||||
|
||||
// Note that unlike in the QR Code sampler, we didn't find the center of modules, but the
|
||||
// very corners. So there is no 0.5f here; 0.0f is right.
|
||||
var sampler:GridSampler;
|
||||
sampler = GridSampler.getGridSamplerInstance();
|
||||
return sampler.sampleGrid(
|
||||
image,
|
||||
dimension,
|
||||
0,
|
||||
0,
|
||||
dimension,
|
||||
0,
|
||||
dimension,
|
||||
dimension,
|
||||
0,
|
||||
dimension,
|
||||
topLeft.getX(),
|
||||
topLeft.getY(),
|
||||
topRightX,
|
||||
topRightY,
|
||||
bottomRight.getX(),
|
||||
bottomRight.getY(),
|
||||
bottomLeft.getX(),
|
||||
bottomLeft.getY());
|
||||
}
|
||||
private static function round(d:Number):int
|
||||
{
|
||||
return Math.ceil(d);
|
||||
}
|
||||
|
||||
// L2 distance
|
||||
private static function distance(a:ResultPoint, b:ResultPoint):int {
|
||||
return Detector.round( Math.sqrt((a.getX() - b.getX())
|
||||
* (a.getX() - b.getX()) + (a.getY() - b.getY())
|
||||
* (a.getY() - b.getY())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the int associated with a key by one.
|
||||
*/
|
||||
private static function increment(table:HashTable, key:ResultPoint):void
|
||||
{
|
||||
if (!table.ContainsKey(key))
|
||||
{
|
||||
table.Add(key,1);
|
||||
}
|
||||
else
|
||||
{
|
||||
table.setValue(key,Math.floor(table.getValueByKey(key) as Number)+1);
|
||||
}
|
||||
}
|
||||
|
||||
private static function sampleGrid(image:BitMatrix ,
|
||||
topLeft:ResultPoint ,
|
||||
bottomLeft:ResultPoint ,
|
||||
bottomRight:ResultPoint ,
|
||||
topRight:ResultPoint ,
|
||||
dimensionX:int ,
|
||||
dimensionY:int ):BitMatrix{
|
||||
|
||||
var sampler:GridSampler = GridSampler.getGridSamplerInstance();
|
||||
|
||||
return sampler.sampleGrid2(image,
|
||||
dimensionX,
|
||||
dimensionY,
|
||||
0.5,
|
||||
0.5,
|
||||
dimensionX - 0.5,
|
||||
0.5,
|
||||
dimensionX - 0.5,
|
||||
dimensionY - 0.5,
|
||||
0.5,
|
||||
dimensionY - 0.5,
|
||||
topLeft.getX(),
|
||||
topLeft.getY(),
|
||||
topRight.getX(),
|
||||
topRight.getY(),
|
||||
bottomRight.getX(),
|
||||
bottomRight.getY(),
|
||||
bottomLeft.getX(),
|
||||
bottomLeft.getY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of black/white transitions between two points, using something like Bresenham's algorithm.
|
||||
*/
|
||||
private function transitionsBetween( from:ResultPoint, _to:ResultPoint):ResultPointsAndTransitions {
|
||||
private function transitionsBetween( from:ResultPoint, _to:ResultPoint):ResultPointsAndTransitions
|
||||
{
|
||||
// See QR Code Detector, sizeOfBlackWhiteBlackRun()
|
||||
var fromX:int = int( from.getX());
|
||||
var fromY:int = int( from.getY());
|
||||
var toX:int = int( _to.getX());
|
||||
var toY:int = int( _to.getY());
|
||||
var fromX:int = Math.floor(from.getX());
|
||||
var fromY:int = Math.floor( from.getY());
|
||||
var toX:int = Math.floor( _to.getX());
|
||||
var toY:int = Math.floor( _to.getY());
|
||||
var steep:Boolean = Math.abs(toY - fromY) > Math.abs(toX - fromX);
|
||||
if (steep) {
|
||||
var temp:int = fromX;
|
||||
|
@ -268,22 +424,28 @@ package com.google.zxing.datamatrix.detector
|
|||
var xstep:int = fromX < toX ? 1 : -1;
|
||||
var transitions:int = 0;
|
||||
var inBlack:Boolean = image._get(steep ? fromY : fromX, steep ? fromX : fromY);
|
||||
for (var x:int = fromX, y:int = fromY; x != toX; x += xstep) {
|
||||
for (var x:int = fromX, y:int = fromY; x != toX; x += xstep)
|
||||
{
|
||||
var isBlack:Boolean = image._get(steep ? y : x, steep ? x : y);
|
||||
if (isBlack == !inBlack) {
|
||||
|
||||
if (isBlack == !inBlack)
|
||||
{
|
||||
transitions++;
|
||||
inBlack = isBlack;
|
||||
}
|
||||
error += dy;
|
||||
if (error > 0) {
|
||||
y += ystep;
|
||||
error -= dx;
|
||||
}
|
||||
if (error > 0)
|
||||
{
|
||||
if (y == toY)
|
||||
{
|
||||
break;
|
||||
}
|
||||
y += ystep;
|
||||
error -= dx;
|
||||
}
|
||||
}
|
||||
return new ResultPointsAndTransitions(from, _to, transitions);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -9,7 +9,7 @@ package com.google.zxing.datamatrix.detector
|
|||
|
||||
public static function compare(o1:Object, o2:Object):int
|
||||
{
|
||||
var result:int = (ResultPointsAndTransitions( o1)).getTransitions() - (ResultPointsAndTransitions( o2)).getTransitions();
|
||||
var result:int = ((o1 as ResultPointsAndTransitions)).getTransitions() - ((o2 as ResultPointsAndTransitions)).getTransitions();
|
||||
if (result > 0) { return 1; }
|
||||
else if (result < 0) { return -1; }
|
||||
else {return 0;}
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright 2011 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.maxicode
|
||||
{
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.BinaryBitmap;
|
||||
import com.google.zxing.ChecksumException;
|
||||
import com.google.zxing.DecodeHintType;
|
||||
import com.google.zxing.FormatException;
|
||||
import com.google.zxing.NotFoundException;
|
||||
import com.google.zxing.Reader;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.ResultMetadataType;
|
||||
import com.google.zxing.ResultPoint;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.common.DecoderResult;
|
||||
import com.google.zxing.maxicode.decoder.Decoder;
|
||||
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.NotFoundException;
|
||||
|
||||
/**
|
||||
* This implementation can detect and decode a MaxiCode in an image.
|
||||
*/
|
||||
public class MaxiCodeReader implements Reader
|
||||
{
|
||||
|
||||
private static var NO_POINTS:Array = new Array(0);
|
||||
private static var MATRIX_WIDTH:int = 30;
|
||||
private static var MATRIX_HEIGHT:int = 33;
|
||||
|
||||
private var decoder:Decoder = new Decoder();
|
||||
|
||||
public function getDecoder():Decoder
|
||||
{
|
||||
return decoder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates and decodes a MaxiCode in an image.
|
||||
*
|
||||
* @return a String representing the content encoded by the MaxiCode
|
||||
* @throws NotFoundException if a MaxiCode cannot be found
|
||||
* @throws FormatException if a MaxiCode cannot be decoded
|
||||
* @throws ChecksumException if error correction fails
|
||||
*/
|
||||
public function decode(image:BinaryBitmap, hints:HashTable=null):Result
|
||||
{
|
||||
var decoderResult:DecoderResult ;
|
||||
if (hints != null && hints.containsKey(DecodeHintType.PURE_BARCODE))
|
||||
{
|
||||
var bits:BitMatrix = extractPureBits(image.getBlackMatrix());
|
||||
decoderResult = decoder.decode(bits, hints);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
var points:Array = NO_POINTS;
|
||||
var result:Result = new Result(decoderResult.getText(), decoderResult.getRawBytes(), points, BarcodeFormat.MAXICODE);
|
||||
|
||||
if (decoderResult.getECLevel() != null)
|
||||
{
|
||||
result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, decoderResult.getECLevel());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public function reset():void
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* This method detects a code in a "pure" image -- that is, pure monochrome image
|
||||
* which contains only an unrotated, unskewed, image of a code, with some white border
|
||||
* around it. This is a specialized method that works exceptionally fast in this special
|
||||
* case.
|
||||
*
|
||||
* @see com.google.zxing.pdf417.PDF417Reader#extractPureBits(BitMatrix)
|
||||
* @see com.google.zxing.datamatrix.DataMatrixReader#extractPureBits(BitMatrix)
|
||||
* @see com.google.zxing.qrcode.QRCodeReader#extractPureBits(BitMatrix)
|
||||
*/
|
||||
private static function extractPureBits(image:BitMatrix):BitMatrix
|
||||
{
|
||||
|
||||
var enclosingRectangle:Array = image.getEnclosingRectangle();
|
||||
if (enclosingRectangle == null)
|
||||
{
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
var left:int = enclosingRectangle[0];
|
||||
var top:int = enclosingRectangle[1];
|
||||
var width:int = enclosingRectangle[2];
|
||||
var height:int = enclosingRectangle[3];
|
||||
|
||||
// Now just read off the bits
|
||||
var bits:BitMatrix = new BitMatrix(MATRIX_WIDTH, MATRIX_HEIGHT);
|
||||
for (var y:int = 0; y < MATRIX_HEIGHT; y++) {
|
||||
var iy:int = top + (y * height + height / 2) / MATRIX_HEIGHT;
|
||||
for (var x:int = 0; x < MATRIX_WIDTH; x++) {
|
||||
var ix:int = left + (x * width + width / 2 + (y & 0x01) * width / 2) / MATRIX_WIDTH;
|
||||
if (image._get(ix, iy)) {
|
||||
bits._set(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright 2011 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.maxicode.decoder
|
||||
{
|
||||
|
||||
import com.google.zxing.FormatException;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
|
||||
/**
|
||||
* @author mike32767
|
||||
* @author Manuel Kasten
|
||||
*/
|
||||
public class BitMatrixParser {
|
||||
|
||||
private static var BITNR:Array = [
|
||||
[121,120,127,126,133,132,139,138,145,144,151,150,157,156,163,162,169,168,175,174,181,180,187,186,193,192,199,198, -2, -2],
|
||||
[123,122,129,128,135,134,141,140,147,146,153,152,159,158,165,164,171,170,177,176,183,182,189,188,195,194,201,200,816, -3],
|
||||
[125,124,131,130,137,136,143,142,149,148,155,154,161,160,167,166,173,172,179,178,185,184,191,190,197,196,203,202,818,817],
|
||||
[283,282,277,276,271,270,265,264,259,258,253,252,247,246,241,240,235,234,229,228,223,222,217,216,211,210,205,204,819, -3],
|
||||
[285,284,279,278,273,272,267,266,261,260,255,254,249,248,243,242,237,236,231,230,225,224,219,218,213,212,207,206,821,820],
|
||||
[287,286,281,280,275,274,269,268,263,262,257,256,251,250,245,244,239,238,233,232,227,226,221,220,215,214,209,208,822, -3],
|
||||
[289,288,295,294,301,300,307,306,313,312,319,318,325,324,331,330,337,336,343,342,349,348,355,354,361,360,367,366,824,823],
|
||||
[291,290,297,296,303,302,309,308,315,314,321,320,327,326,333,332,339,338,345,344,351,350,357,356,363,362,369,368,825, -3],
|
||||
[293,292,299,298,305,304,311,310,317,316,323,322,329,328,335,334,341,340,347,346,353,352,359,358,365,364,371,370,827,826],
|
||||
[409,408,403,402,397,396,391,390, 79, 78, -2, -2, 13, 12, 37, 36, 2, -1, 44, 43,109,108,385,384,379,378,373,372,828, -3],
|
||||
[411,410,405,404,399,398,393,392, 81, 80, 40, -2, 15, 14, 39, 38, 3, -1, -1, 45,111,110,387,386,381,380,375,374,830,829],
|
||||
[413,412,407,406,401,400,395,394, 83, 82, 41, -3, -3, -3, -3, -3, 5, 4, 47, 46,113,112,389,388,383,382,377,376,831, -3],
|
||||
[415,414,421,420,427,426,103,102, 55, 54, 16, -3, -3, -3, -3, -3, -3, -3, 20, 19, 85, 84,433,432,439,438,445,444,833,832],
|
||||
[417,416,423,422,429,428,105,104, 57, 56, -3, -3, -3, -3, -3, -3, -3, -3, 22, 21, 87, 86,435,434,441,440,447,446,834, -3],
|
||||
[419,418,425,424,431,430,107,106, 59, 58, -3, -3, -3, -3, -3, -3, -3, -3, -3, 23, 89, 88,437,436,443,442,449,448,836,835],
|
||||
[481,480,475,474,469,468, 48, -2, 30, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, 0, 53, 52,463,462,457,456,451,450,837, -3],
|
||||
[483,482,477,476,471,470, 49, -1, -2, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -1,465,464,459,458,453,452,839,838],
|
||||
[485,484,479,478,473,472, 51, 50, 31, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, 1, -2, 42,467,466,461,460,455,454,840, -3],
|
||||
[487,486,493,492,499,498, 97, 96, 61, 60, -3, -3, -3, -3, -3, -3, -3, -3, -3, 26, 91, 90,505,504,511,510,517,516,842,841],
|
||||
[489,488,495,494,501,500, 99, 98, 63, 62, -3, -3, -3, -3, -3, -3, -3, -3, 28, 27, 93, 92,507,506,513,512,519,518,843, -3],
|
||||
[491,490,497,496,503,502,101,100, 65, 64, 17, -3, -3, -3, -3, -3, -3, -3, 18, 29, 95, 94,509,508,515,514,521,520,845,844],
|
||||
[559,558,553,552,547,546,541,540, 73, 72, 32, -3, -3, -3, -3, -3, -3, 10, 67, 66,115,114,535,534,529,528,523,522,846, -3],
|
||||
[561,560,555,554,549,548,543,542, 75, 74, -2, -1, 7, 6, 35, 34, 11, -2, 69, 68,117,116,537,536,531,530,525,524,848,847],
|
||||
[563,562,557,556,551,550,545,544, 77, 76, -2, 33, 9, 8, 25, 24, -1, -2, 71, 70,119,118,539,538,533,532,527,526,849, -3],
|
||||
[565,564,571,570,577,576,583,582,589,588,595,594,601,600,607,606,613,612,619,618,625,624,631,630,637,636,643,642,851,850],
|
||||
[567,566,573,572,579,578,585,584,591,590,597,596,603,602,609,608,615,614,621,620,627,626,633,632,639,638,645,644,852, -3],
|
||||
[569,568,575,574,581,580,587,586,593,592,599,598,605,604,611,610,617,616,623,622,629,628,635,634,641,640,647,646,854,853],
|
||||
[727,726,721,720,715,714,709,708,703,702,697,696,691,690,685,684,679,678,673,672,667,666,661,660,655,654,649,648,855, -3],
|
||||
[729,728,723,722,717,716,711,710,705,704,699,698,693,692,687,686,681,680,675,674,669,668,663,662,657,656,651,650,857,856],
|
||||
[731,730,725,724,719,718,713,712,707,706,701,700,695,694,689,688,683,682,677,676,671,670,665,664,659,658,653,652,858, -3],
|
||||
[733,732,739,738,745,744,751,750,757,756,763,762,769,768,775,774,781,780,787,786,793,792,799,798,805,804,811,810,860,859],
|
||||
[735,734,741,740,747,746,753,752,759,758,765,764,771,770,777,776,783,782,789,788,795,794,801,800,807,806,813,812,861, -3],
|
||||
[737,736,743,742,749,748,755,754,761,760,767,766,773,772,779,778,785,784,791,790,797,796,803,802,809,808,815,814,863,862]
|
||||
];
|
||||
|
||||
private var bitMatrix:BitMatrix;
|
||||
|
||||
/**
|
||||
* @param bitMatrix {@link BitMatrix} to parse
|
||||
* @throws FormatException if height is not 33 or width is not 30
|
||||
*/
|
||||
public function BitMatrixParser(bitMatrix:BitMatrix)
|
||||
{
|
||||
this.bitMatrix = bitMatrix;
|
||||
}
|
||||
|
||||
public function readCodewords():Array
|
||||
{
|
||||
var result:Array = new Array(144);
|
||||
var height:int = bitMatrix.getHeight();
|
||||
var width:int = bitMatrix.getWidth();
|
||||
for (var y:int = 0; y < height; y++) {
|
||||
var bitnrRow:Array = BITNR[y];
|
||||
for (var x:int = 0; x < width; x++) {
|
||||
var bit:int = bitnrRow[x];
|
||||
if (bit >= 0 && bitMatrix._get(x, y)) {
|
||||
result[bit / 6] |= int((1 << (5 - (bit % 6))) & 255) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* Copyright 2011 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.maxicode.decoder
|
||||
{
|
||||
|
||||
import com.google.zxing.common.DecoderResult;
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
|
||||
/**
|
||||
* <p>MaxiCodes can encode text or structured information as bits in one of several modes,
|
||||
* with multiple character sets in one code. This class decodes the bits back into text.</p>
|
||||
*
|
||||
* @author mike32767
|
||||
* @author Manuel Kasten
|
||||
*/
|
||||
public class DecodedBitStreamParser
|
||||
{
|
||||
|
||||
private static var SHIFTA:String = '\uFFF0';
|
||||
private static var SHIFTB:String = '\uFFF1';
|
||||
private static var SHIFTC:String = '\uFFF2';
|
||||
private static var SHIFTD:String = '\uFFF3';
|
||||
private static var SHIFTE:String = '\uFFF4';
|
||||
private static var TWOSHIFTA:String = '\uFFF5';
|
||||
private static var THREESHIFTA:String = '\uFFF6';
|
||||
private static var LATCHA:String = '\uFFF7';
|
||||
private static var LATCHB:String = '\uFFF8';
|
||||
private static var LOCK:String = '\uFFF9';
|
||||
private static var ECI:String = '\uFFFA';
|
||||
private static var NS:String = '\uFFFB';
|
||||
private static var PAD:String = '\uFFFC';
|
||||
private static var FS:String = '\u001C';
|
||||
private static var GS:String = '\u001D';
|
||||
private static var RS:String = '\u001E';
|
||||
private static var NINE_DIGITS:String = "000000000";
|
||||
private static var THREE_DIGITS:String = "000";
|
||||
|
||||
private static var SETS:Array = [
|
||||
"\nABCDEFGHIJKLMNOPQRSTUVWXYZ"+ECI+FS+GS+RS+NS+' '+PAD+"\"#$%&'()*+,-./0123456789:"+SHIFTB+SHIFTC+SHIFTD+SHIFTE+LATCHB,
|
||||
"`abcdefghijklmnopqrstuvwxyz"+ECI+FS+GS+RS+NS+'{'+PAD+"}~\u007F;<=>?[\\]^_ ,./:@!|"+PAD+TWOSHIFTA+THREESHIFTA+PAD+SHIFTA+SHIFTC+SHIFTD+SHIFTE+LATCHA,
|
||||
"\u00C0\u00C1\u00C2\u00C3\u00C4\u00C5\u00C6\u00C7\u00C8\u00C9\u00CA\u00CB\u00CC\u00CD\u00CE\u00CF\u00D0\u00D1\u00D2\u00D3\u00D4\u00D5\u00D6\u00D7\u00D8\u00D9\u00DA"+ECI+FS+GS+RS+"\u00DB\u00DC\u00DD\u00DE\u00DF\u00AA\u00AC\u00B1\u00B2\u00B3\u00B5\u00B9\u00BA\u00BC\u00BD\u00BE\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089"+LATCHA+' '+LOCK+SHIFTD+SHIFTE+LATCHB,
|
||||
"\u00E0\u00E1\u00E2\u00E3\u00E4\u00E5\u00E6\u00E7\u00E8\u00E9\u00EA\u00EB\u00EC\u00ED\u00EE\u00EF\u00F0\u00F1\u00F2\u00F3\u00F4\u00F5\u00F6\u00F7\u00F8\u00F9\u00FA"+ECI+FS+GS+RS+NS+"\u00FB\u00FC\u00FD\u00FE\u00FF\u00A1\u00A8\u00AB\u00AF\u00B0\u00B4\u00B7\u00B8\u00BB\u00BF\u008A\u008B\u008C\u008D\u008E\u008F\u0090\u0091\u0092\u0093\u0094"+LATCHA+' '+SHIFTC+LOCK+SHIFTE+LATCHB,
|
||||
"\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\n\u000B\u000C\r\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A"+ECI+PAD+PAD+'\u001B'+NS+FS+GS+RS+"\u001F\u009F\u00A0\u00A2\u00A3\u00A4\u00A5\u00A6\u00A7\u00A9\u00AD\u00AE\u00B6\u0095\u0096\u0097\u0098\u0099\u009A\u009B\u009C\u009D\u009E"+LATCHA+' '+SHIFTC+SHIFTD+LOCK+LATCHB,
|
||||
"\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\n\u000B\u000C\r\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F\u0020\u0021\"\u0023\u0024\u0025\u0026\u0027\u0028\u0029\u002A\u002B\u002C\u002D\u002E\u002F\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u003A\u003B\u003C\u003D\u003E\u003F"
|
||||
];
|
||||
|
||||
|
||||
|
||||
public static function decode(bytes:Array, mode:int):DecoderResult
|
||||
{
|
||||
var result:StringBuilder = new StringBuilder(144);
|
||||
switch (mode)
|
||||
{
|
||||
case 2:
|
||||
case 3:
|
||||
var postcode:String;
|
||||
if (mode == 2)
|
||||
{
|
||||
postcode = NINE_DIGITS.substring(0,(getPostCode2(bytes).toString()).length) + getPostCode2(bytes).toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
postcode = getPostCode3(bytes);
|
||||
}
|
||||
|
||||
var country:String = THREE_DIGITS.substring(0,(getCountry(bytes).toString()).length) + getCountry(bytes).toString();
|
||||
var service:String = THREE_DIGITS.substring(0,(getServiceClass(bytes).toString()).length) + getServiceClass(bytes).toString();
|
||||
|
||||
result.Append(getMessage(bytes, 10, 84));
|
||||
var matchstring:String = "[)>"+RS+"01"+GS;
|
||||
if (result.toString().substr(0,matchstring.length) == matchstring)
|
||||
{
|
||||
result.Insert(9, postcode + GS + country + GS + service + GS);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Insert(0, postcode + GS + country + GS + service + GS);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
result.Append(getMessage(bytes, 1, 93));
|
||||
break;
|
||||
case 5:
|
||||
result.Append(getMessage(bytes, 1, 77));
|
||||
break;
|
||||
}
|
||||
return new DecoderResult(bytes, result.toString(), null, mode.toString());
|
||||
}
|
||||
|
||||
private static function getBit(bit:int, bytes:Array):int
|
||||
{
|
||||
bit--;
|
||||
return (bytes[bit / 6] & (1 << (5 - (bit % 6)))) == 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
private static function getInt(bytes:Array, x:Array):int
|
||||
{
|
||||
var val:int = 0;
|
||||
for (var i:int = 0; i < x.length; i++)
|
||||
{
|
||||
val += getBit(x[i], bytes) << (x.length - i - 1);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
private static function getCountry(bytes:Array):int
|
||||
{
|
||||
return getInt(bytes, [53, 54, 43, 44, 45, 46, 47, 48, 37, 38]);
|
||||
}
|
||||
|
||||
private static function getServiceClass(bytes:Array):int
|
||||
{
|
||||
return getInt(bytes, [55, 56, 57, 58, 59, 60, 49, 50, 51, 52]);
|
||||
}
|
||||
|
||||
private static function getPostCode2Length(bytes:Array):int
|
||||
{
|
||||
return getInt(bytes, [39, 40, 41, 42, 31, 32]);
|
||||
}
|
||||
|
||||
private static function getPostCode2(bytes:Array):int
|
||||
{
|
||||
return getInt(bytes, [33, 34, 35, 36, 25, 26, 27, 28, 29, 30, 19,
|
||||
20, 21, 22, 23, 24, 13, 14, 15, 16, 17, 18, 7, 8, 9, 10, 11, 12, 1, 2]);
|
||||
}
|
||||
|
||||
private static function getPostCode3(bytes:Array):String {
|
||||
return (SETS[0] as String).charAt(getInt(bytes, [39, 40, 41, 42, 31, 32])) +
|
||||
(SETS[0] as String).charAt(getInt(bytes, [33, 34, 35, 36, 25, 26])) +
|
||||
(SETS[0] as String).charAt(getInt(bytes, [27, 28, 29, 30, 19, 20])) +
|
||||
(SETS[0] as String).charAt(getInt(bytes, [21, 22, 23, 24, 13, 14])) +
|
||||
(SETS[0] as String).charAt(getInt(bytes, [15, 16, 17, 18, 7, 8])) +
|
||||
(SETS[0] as String).charAt(getInt(bytes, [ 9, 10, 11, 12, 1, 2]));
|
||||
}
|
||||
|
||||
private static function getMessage(bytes:Array, start:int, len:int):String
|
||||
{
|
||||
var sb:StringBuilder = new StringBuilder();
|
||||
var shift:int = -1;
|
||||
var curset:int = 0;
|
||||
var lastset:int = 0;
|
||||
for (var i:int = start; i < start + len; i++) {
|
||||
var c:String = SETS[curset].charAt(bytes[i]);
|
||||
switch (c) {
|
||||
case LATCHA:
|
||||
curset = 0;
|
||||
shift = -1;
|
||||
break;
|
||||
case LATCHB:
|
||||
curset = 1;
|
||||
shift = -1;
|
||||
break;
|
||||
case SHIFTA:
|
||||
case SHIFTB:
|
||||
case SHIFTC:
|
||||
case SHIFTD:
|
||||
case SHIFTE:
|
||||
lastset = curset;
|
||||
curset = c.charCodeAt(0) - SHIFTA.charCodeAt(0);
|
||||
shift = 1;
|
||||
break;
|
||||
case TWOSHIFTA:
|
||||
lastset = curset;
|
||||
curset = 0;
|
||||
shift = 2;
|
||||
break;
|
||||
case THREESHIFTA:
|
||||
lastset = curset;
|
||||
curset = 0;
|
||||
shift = 3;
|
||||
break;
|
||||
case NS:
|
||||
var nsval:int = (bytes[++i] << 24) + (bytes[++i] << 18) + (bytes[++i] << 12) + (bytes[++i] << 6) + bytes[++i];
|
||||
sb.Append(NINE_DIGITS.substring(0,NINE_DIGITS.length - (nsval.toString()).length) + nsval.toString());
|
||||
break;
|
||||
case LOCK:
|
||||
shift = -1;
|
||||
break;
|
||||
default:
|
||||
sb.Append(c);
|
||||
}
|
||||
if (shift-- == 0) {
|
||||
curset = lastset;
|
||||
}
|
||||
}
|
||||
while (sb.length > 0 && sb.charAt(sb.length - 1) == PAD) {
|
||||
sb.setLength(sb.length - 1);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright 2011 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.maxicode.decoder
|
||||
{
|
||||
|
||||
import com.google.zxing.ChecksumException;
|
||||
import com.google.zxing.FormatException;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.common.DecoderResult;
|
||||
import com.google.zxing.common.reedsolomon.GenericGFPoly;
|
||||
import com.google.zxing.common.reedsolomon.ReedSolomonDecoder;
|
||||
import com.google.zxing.common.reedsolomon.ReedSolomonException;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
|
||||
/**
|
||||
* <p>The main class which implements MaxiCode decoding -- as opposed to locating and extracting
|
||||
* the MaxiCode from an image.</p>
|
||||
*
|
||||
* @author Manuel Kasten
|
||||
*/
|
||||
public class Decoder {
|
||||
|
||||
private static var ALL:int = 0;
|
||||
private static var EVEN:int = 1;
|
||||
private static var ODD:int = 2;
|
||||
|
||||
private var rsDecoder:ReedSolomonDecoder;
|
||||
|
||||
public function Decoder()
|
||||
{
|
||||
//rsDecoder = new ReedSolomonDecoder(GF256.MAXICODE_FIELD_64);
|
||||
}
|
||||
|
||||
public function decode(bits:BitMatrix, hints:HashTable=null):DecoderResult {
|
||||
var parser:BitMatrixParser = new BitMatrixParser(bits);
|
||||
var codewords:Array = parser.readCodewords();
|
||||
|
||||
correctErrors(codewords, 0, 10, 10, ALL);
|
||||
var mode:int = codewords[0] & 0x0F;
|
||||
var datawords:Array;
|
||||
switch (mode) {
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
correctErrors(codewords, 20, 84, 40, EVEN);
|
||||
correctErrors(codewords, 20, 84, 40, ODD);
|
||||
datawords = new Array(94);
|
||||
break;
|
||||
case 5:
|
||||
correctErrors(codewords, 20, 68, 56, EVEN);
|
||||
correctErrors(codewords, 20, 68, 56, ODD);
|
||||
datawords = new Array(78);
|
||||
break;
|
||||
default:
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
|
||||
for (var i:int = 0; i < 10; i++)
|
||||
{
|
||||
datawords[i] = codewords[i];
|
||||
}
|
||||
for (i = 20; i < datawords.length + 10; i++)
|
||||
{
|
||||
datawords[i - 10] = codewords[i];
|
||||
}
|
||||
|
||||
return DecodedBitStreamParser.decode(datawords, mode);
|
||||
}
|
||||
|
||||
private function correctErrors(codewordBytes:Array,
|
||||
start:int,
|
||||
dataCodewords:int,
|
||||
ecCodewords:int,
|
||||
mode:int):void
|
||||
{
|
||||
var codewords:int = dataCodewords + ecCodewords;
|
||||
|
||||
// in EVEN or ODD mode only half the codewords
|
||||
var divisor:int = mode == ALL ? 1 : 2;
|
||||
|
||||
// First read into an array of ints
|
||||
var codewordsInts:Array = new Array(codewords / divisor);
|
||||
for (var i:int = 0; i < codewords; i++)
|
||||
{
|
||||
if ((mode == ALL) || (i % 2 == (mode - 1))) {
|
||||
codewordsInts[i / divisor] = codewordBytes[i + start] & 0xFF;
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
rsDecoder.decode(codewordsInts, ecCodewords / divisor);
|
||||
}
|
||||
catch (rse:ReedSolomonException)
|
||||
{
|
||||
throw ChecksumException.getChecksumInstance();
|
||||
}
|
||||
// Copy back into array of bytes -- only need to worry about the bytes that were data
|
||||
// We don't care about errors in the error-correction codewords
|
||||
for (i = 0; i < dataCodewords; i++)
|
||||
{
|
||||
if ((mode == ALL) || (i % 2 == (mode - 1)))
|
||||
{
|
||||
codewordBytes[i + start] = (int(codewordsInts[i / divisor]) & 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -76,12 +76,15 @@ public final class ByQuadrantReader implements Reader {
|
|||
// continue
|
||||
}
|
||||
|
||||
var quarterWidth:int = halfWidth / 2;
|
||||
var quarterHeight:int = halfHeight / 2;
|
||||
var center:BinaryBitmap = image.crop(quarterWidth, quarterHeight, width - quarterWidth,
|
||||
height - quarterHeight);
|
||||
var quarterWidth:int = Math.floor(halfWidth / 2);
|
||||
var quarterHeight:int = Math.floor(halfHeight / 2);
|
||||
var center:BinaryBitmap = image.crop(quarterWidth, quarterHeight, halfWidth, halfHeight);
|
||||
return delegate.decode(center, hints);
|
||||
}
|
||||
|
||||
public function reset():void {
|
||||
delegate.reset();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,265 +0,0 @@
|
|||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.oned
|
||||
{
|
||||
|
||||
import com.google.zxing.common.BitArray;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.BinaryBitmap;
|
||||
import com.google.zxing.DecodeHintType;
|
||||
import com.google.zxing.ReaderException;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.ResultMetadataType;
|
||||
import com.google.zxing.ResultPoint;
|
||||
import com.google.zxing.Reader;
|
||||
|
||||
public class AbstractOneDReader implements Reader
|
||||
{
|
||||
|
||||
private static var INTEGER_MATH_SHIFT:int = 8;
|
||||
public static var PATTERN_MATCH_RESULT_SCALE_FACTOR:int = (1 << INTEGER_MATH_SHIFT);
|
||||
|
||||
//public function decode(image:MonochromeBitmapSource):Result
|
||||
//{
|
||||
// return decode(image, null);
|
||||
//}
|
||||
|
||||
public function decode(image:BinaryBitmap,hints:HashTable=null):Result
|
||||
{
|
||||
try
|
||||
{
|
||||
return doDecode(image, hints);
|
||||
}
|
||||
catch (re:ReaderException)
|
||||
{
|
||||
var tryHarder:Boolean = (hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER));
|
||||
if (tryHarder && image.isRotateSupported())
|
||||
{
|
||||
var rotatedImage:BinaryBitmap = image.rotateCounterClockwise();
|
||||
var result:Result = doDecode(rotatedImage, hints);
|
||||
// Record that we found it rotated 90 degrees CCW / 270 degrees CW
|
||||
var metadata:HashTable = result.getResultMetadata();
|
||||
var orientation:int = 270;
|
||||
if (metadata != null && metadata.ContainsKey(ResultMetadataType.ORIENTATION))
|
||||
{
|
||||
// But if we found it reversed in doDecode(), add in that result here:
|
||||
orientation = (orientation + (int(metadata[ResultMetadataType.ORIENTATION]) )) % 360;
|
||||
}
|
||||
result.putMetadata(ResultMetadataType.ORIENTATION, orientation);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* We're going to examine rows from the middle outward, searching alternately above and below the
|
||||
* middle, and farther out each time. rowStep is the number of rows between each successive
|
||||
* attempt above and below the middle. So we'd scan row middle, then middle - rowStep, then
|
||||
* middle + rowStep, then middle - (2 * rowStep), etc.
|
||||
* rowStep is bigger as the image is taller, but is always at least 1. We've somewhat arbitrarily
|
||||
* decided that moving up and down by about 1/16 of the image is pretty good; we try more of the
|
||||
* image if "trying harder".
|
||||
*
|
||||
* @param image The image to decode
|
||||
* @param hints Any hints that were requested
|
||||
* @return The contents of the decoded barcode
|
||||
* @throws ReaderException Any spontaneous errors which occur
|
||||
*/
|
||||
private function doDecode(image:BinaryBitmap, hints:HashTable):Result
|
||||
{
|
||||
var width:int = image.getWidth();
|
||||
var height:int = image.getHeight();
|
||||
var row:BitArray = new BitArray(width);
|
||||
|
||||
var middle:int = height >> 1;
|
||||
var tryHarder:Boolean = (hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER));
|
||||
var rowStep:int = Math.max(1, height >> (tryHarder ? 7 : 4));
|
||||
var MaxLines:int;
|
||||
if (tryHarder)
|
||||
{
|
||||
MaxLines = height; // Look at the whole image, not just the center
|
||||
} else {
|
||||
MaxLines = 9; // Nine rows spaced 1/16 apart is roughly the middle half of the image
|
||||
}
|
||||
|
||||
for (var x:int = 0; x < MaxLines; x++) {
|
||||
|
||||
// Scanning from the middle out. Determine which row we're looking at next:
|
||||
var rowStepsAboveOrBelow:int = (x + 1) >> 1;
|
||||
var isAbove:Boolean = (x & 0x01) == 0; // i.e. is x even?
|
||||
var rowNumber:int = middle + rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow);
|
||||
if (rowNumber < 0 || rowNumber >= height) {
|
||||
// Oops, if we run off the top or bottom, stop
|
||||
break;
|
||||
}
|
||||
|
||||
// Estimate black point for this row and load it:
|
||||
try {
|
||||
row = image.getBlackRow(rowNumber,row);
|
||||
}
|
||||
catch (re:ReaderException)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// While we have the image data in a BitArray, it's fairly cheap to reverse it in place to
|
||||
// handle decoding upside down barcodes.
|
||||
for (var attempt:int = 0; attempt < 2; attempt++) {
|
||||
if (attempt == 1) { // trying again?
|
||||
row.reverse(); // reverse the row and continue
|
||||
}
|
||||
try {
|
||||
// Look for a barcode
|
||||
var result:Result = decodeRow(rowNumber, row, hints);
|
||||
// We found our barcode (else exception thrown)
|
||||
if (attempt == 1)
|
||||
{
|
||||
// But it was upside down, so note that
|
||||
result.putMetadata(ResultMetadataType.ORIENTATION, 180);
|
||||
// And remember to flip the result points horizontally.
|
||||
var points:Array = result.getResultPoints();
|
||||
points[0] = ResultPoint(new ResultPoint(width - points[0].getX() - 1, points[0].getY()));
|
||||
points[1] = ResultPoint(new ResultPoint(width - points[1].getX() - 1, points[1].getY()));
|
||||
}
|
||||
return result;
|
||||
} catch (re:ReaderException) {
|
||||
// continue -- just couldn't decode this row
|
||||
var a:int=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new ReaderException("AbstractOneDReader : doDecode : could not decode image");
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the size of successive runs of white and black pixels in a row, starting at a given point.
|
||||
* The values are recorded in the given array, and the number of runs recorded is equal to the size
|
||||
* of the array. If the row starts on a white pixel at the given start point, then the first count
|
||||
* recorded is the run of white pixels starting from that point; likewise it is the count of a run
|
||||
* of black pixels if the row begin on a black pixels at that point.
|
||||
*
|
||||
* @param row row to count from
|
||||
* @param start offset into row to start at
|
||||
* @param counters array into which to record counts
|
||||
* @throws ReaderException if counters cannot be filled entirely from row before running out of pixels
|
||||
*/
|
||||
public static function recordPattern(row:BitArray, start:int, counters:Array):void
|
||||
{
|
||||
var numCounters:int = counters.length;
|
||||
for (var i:int=0;i<counters.length;i++) { counters[i] = 0;}
|
||||
|
||||
var end:int = row.getSize();
|
||||
if (start >= end) {
|
||||
throw new ReaderException("AbstractOneDReader : recordPattern : start after end ("+start+" > "+end);
|
||||
}
|
||||
var isWhite:Boolean = !row._get(start);
|
||||
var counterPosition:int = 0;
|
||||
|
||||
var k:int = start;
|
||||
while (k < end)
|
||||
{
|
||||
var pixel:Boolean = row._get(k);
|
||||
if (pixel != isWhite)
|
||||
{
|
||||
counters[counterPosition] = counters[counterPosition] + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
counterPosition++;
|
||||
if (counterPosition == numCounters)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
counters[counterPosition] = 1;
|
||||
isWhite = !isWhite;//isWhite = !isWhite; Is this too clever? shorter byte code, no conditional
|
||||
}
|
||||
}
|
||||
k++;
|
||||
}
|
||||
// If we read fully the last section of pixels and filled up our counters -- or filled
|
||||
// the last counter but ran off the side of the image, OK. Otherwise, a problem.
|
||||
if (!(counterPosition == numCounters || (counterPosition == numCounters - 1 && k == end)))
|
||||
{
|
||||
throw new ReaderException("AbstractOneDReader : recordPattern : barcode seems to extend outside of the image");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines how closely a set of observed counts of runs of black/white values matches a given
|
||||
* target pattern. This is reported as the ratio of the total variance from the expected pattern
|
||||
* proportions across all pattern elements, to the length of the pattern.
|
||||
*
|
||||
* @param counters observed counters
|
||||
* @param pattern expected pattern
|
||||
* @param MaxIndividualVariance The most any counter can differ before we give up
|
||||
* @return ratio of total variance between counters and pattern compared to total pattern size,
|
||||
* where the ratio has been multiplied by 256. So, 0 means no variance (perfect match); 256 means
|
||||
* the total variance between counters and patterns equals the pattern length, higher values mean
|
||||
* even more variance
|
||||
*/
|
||||
public static function patternMatchVariance(counters:Array,pattern:Array, MaxIndividualVariance:int):int
|
||||
{
|
||||
var numCounters:int = counters.length;
|
||||
var total:int = 0;
|
||||
var patternLength:int = 0;
|
||||
for (var i:int = 0; i < numCounters; i++)
|
||||
{
|
||||
total += counters[i];
|
||||
patternLength += pattern[i];
|
||||
}
|
||||
if (total < patternLength)
|
||||
{
|
||||
// If we don't even have one pixel per unit of bar width, assume this is too small
|
||||
// to reliably match, so fail:
|
||||
return int.MAX_VALUE;
|
||||
}
|
||||
// We're going to fake floating-point math in integers. We just need to use more bits.
|
||||
// Scale up patternLength so that intermediate values below like scaledCounter will have
|
||||
// more "significant digits"
|
||||
var unitBarWidth:int = (total << INTEGER_MATH_SHIFT) / patternLength;
|
||||
MaxIndividualVariance = (MaxIndividualVariance * unitBarWidth) >> INTEGER_MATH_SHIFT;
|
||||
|
||||
var totalVariance:int = 0;
|
||||
for (var x:int = 0; x < numCounters; x++) {
|
||||
var counter:int = (counters[x]) << INTEGER_MATH_SHIFT;
|
||||
var scaledPattern:int = pattern[x] * unitBarWidth;
|
||||
var variance:int = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter;
|
||||
if (variance > MaxIndividualVariance)
|
||||
{
|
||||
return int.MAX_VALUE
|
||||
}
|
||||
totalVariance += variance;
|
||||
}
|
||||
return totalVariance / total;
|
||||
}
|
||||
|
||||
// This declaration should not be necessary, since this class is
|
||||
// abstract and so does not have to provide an implementation for every
|
||||
// method of an interface it implements, but it is causing NoSuchMethodError
|
||||
// issues on some Nokia JVMs. So we add this superfluous declaration:
|
||||
|
||||
public function decodeRow(rowNumber:int, row:BitArray, hints:Object):Result{return null;};
|
||||
}
|
||||
}
|
|
@ -1,337 +0,0 @@
|
|||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.oned
|
||||
{
|
||||
|
||||
public class AbstractUPCEANReader extends AbstractOneDReader
|
||||
{
|
||||
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
import com.google.zxing.common.BitArray;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.ReaderException;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.ResultPoint;
|
||||
|
||||
|
||||
private static var MAX_AVG_VARIANCE:int = int(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42);
|
||||
private static var MAX_INDIVIDUAL_VARIANCE:int = int(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7);
|
||||
|
||||
/**
|
||||
* Start/end guard pattern.
|
||||
*/
|
||||
public static var START_END_PATTERN:Array = [1, 1, 1];
|
||||
|
||||
/**
|
||||
* Pattern marking the middle of a UPC/EAN pattern, separating the two halves.
|
||||
*/
|
||||
public static var MIDDLE_PATTERN:Array = [1, 1, 1, 1, 1];
|
||||
|
||||
/**
|
||||
* "Odd", or "L" patterns used to encode UPC/EAN digits.
|
||||
*/
|
||||
|
||||
public static var L_PATTERNS:Array = [
|
||||
[3, 2, 1, 1], // 0
|
||||
[2, 2, 2, 1], // 1
|
||||
[2, 1, 2, 2], // 2
|
||||
[1, 4, 1, 1], // 3
|
||||
[1, 1, 3, 2], // 4
|
||||
[1, 2, 3, 1], // 5
|
||||
[1, 1, 1, 4], // 6
|
||||
[1, 3, 1, 2], // 7
|
||||
[1, 2, 1, 3], // 8
|
||||
[3, 1, 1, 2]]; // 9
|
||||
|
||||
|
||||
/**
|
||||
* As above but also including the "even", or "G" patterns used to encode UPC/EAN digits.
|
||||
*/
|
||||
//public static var L_AND_G_PATTERNS:Array = new Array(20);
|
||||
public static var L_AND_G_PATTERNS:Array = [
|
||||
[3, 2, 1, 1], // 0
|
||||
[2, 2, 2, 1], // 1
|
||||
[2, 1, 2, 2], // 2
|
||||
[1, 4, 1, 1], // 3
|
||||
[1, 1, 3, 2], // 4
|
||||
[1, 2, 3, 1], // 5
|
||||
[1, 1, 1, 4], // 6
|
||||
[1, 3, 1, 2], // 7
|
||||
[1, 2, 1, 3], // 8
|
||||
[3, 1, 1, 2], // 9
|
||||
[1, 1, 2, 3], //R0
|
||||
[1, 2, 2, 2], //R1
|
||||
[2, 2, 1, 2], //R2
|
||||
[1, 1, 4, 1], //R3
|
||||
[2, 3, 1, 1], //R4
|
||||
[1, 3, 2, 1], //R5
|
||||
[4, 1, 1, 1], //R6
|
||||
[2, 1, 3, 1], //R7
|
||||
[3, 1, 2, 1], //R8
|
||||
[2, 1, 1, 3], //R9
|
||||
];
|
||||
// create the inverse of the L patterns
|
||||
/* static {
|
||||
L_AND_G_PATTERNS = new int[20][];
|
||||
for (var i:int = 0; i < 10; i++)
|
||||
{
|
||||
L_AND_G_PATTERNS[i] = L_PATTERNS[i];
|
||||
}
|
||||
for (int i = 10; i < 20; i++)
|
||||
{
|
||||
var widths:Array = L_PATTERNS[i - 10];
|
||||
var reversedWidths:Array = new Array(widths.length);
|
||||
for (int j = 0; j < widths.length; j++)
|
||||
{
|
||||
reversedWidths[j] = widths[widths.length - j - 1];
|
||||
}
|
||||
L_AND_G_PATTERNS[i] = reversedWidths;
|
||||
}
|
||||
}
|
||||
*/
|
||||
private var decodeRowStringBuffer:StringBuilder;
|
||||
|
||||
public function AbstractUPCEANReader()
|
||||
{
|
||||
decodeRowStringBuffer = new StringBuilder(20);
|
||||
}
|
||||
|
||||
public static function findStartGuardPattern(row:BitArray):Array
|
||||
{
|
||||
var foundStart:Boolean = false;
|
||||
var startRange:Array = null;
|
||||
var nextStart:int = 0;
|
||||
while (!foundStart)
|
||||
{
|
||||
startRange = findGuardPattern(row, nextStart, false, START_END_PATTERN);
|
||||
var start:int = startRange[0];
|
||||
nextStart = startRange[1];
|
||||
// Make sure there is a quiet zone at least as big as the start pattern before the barcode. If
|
||||
// this check would run off the left edge of the image, do not accept this barcode, as it is
|
||||
// very likely to be a false positive.
|
||||
var quietStart:int = start - (nextStart - start);
|
||||
if (quietStart >= 0)
|
||||
{
|
||||
foundStart = row.isRange(quietStart, start, false);
|
||||
}
|
||||
}
|
||||
return startRange;
|
||||
}
|
||||
|
||||
public override function decodeRow(rowNumber:int, row:BitArray, o:Object):Result
|
||||
{
|
||||
if (o is HashTable){ return decodeRow_HashTable(rowNumber,row,o as HashTable); }
|
||||
else if (o is Array) { return decodeRow_Array(rowNumber,row,o as Array); }
|
||||
else {throw new Error('AbstractUPCEANReader : decodeRow : unknow type of object');}
|
||||
|
||||
}
|
||||
|
||||
public function decodeRow_HashTable(rowNumber:int, row:BitArray, hints:HashTable):Result
|
||||
{
|
||||
return decodeRow(rowNumber, row, findStartGuardPattern(row));
|
||||
}
|
||||
|
||||
public function decodeRow_Array(rowNumber:int, row:BitArray, startGuardRange:Array):Result
|
||||
{
|
||||
var result:StringBuilder = decodeRowStringBuffer;// empty stringbuilder
|
||||
result.length = 0;
|
||||
var endStart:int = decodeMiddle(row, startGuardRange, result);
|
||||
var endRange:Array = decodeEnd(row, endStart);
|
||||
|
||||
// Make sure there is a quiet zone at least as big as the end pattern after the barcode. The
|
||||
// spec might want more whitespace, but in practice this is the maximum we can count on.
|
||||
var end:int = endRange[1];
|
||||
var quietEnd:int = end + (end - endRange[0]);
|
||||
if (quietEnd >= row.getSize() || !row.isRange(end, quietEnd, false))
|
||||
{
|
||||
throw new ReaderException("AbstractUPCEANReader : decodeRow_Array : ending white space is missing");
|
||||
}
|
||||
|
||||
var resultString:String = result.toString();
|
||||
if (!checkChecksum(resultString)) {
|
||||
throw new ReaderException("AbstractUPCEANReader : decodeRow_Array : checkChecksum failed");
|
||||
}
|
||||
|
||||
var left:Number = (Number) (startGuardRange[1] + startGuardRange[0]) / 2;
|
||||
var right:Number = (Number) (endRange[1] + endRange[0]) / 2;
|
||||
return new Result(resultString,
|
||||
null, // no natural byte representation for these barcodes
|
||||
[new ResultPoint(left, Number(rowNumber)),new ResultPoint(right, Number(rowNumber))],
|
||||
getBarcodeFormat());
|
||||
}
|
||||
|
||||
public function getBarcodeFormat():BarcodeFormat
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link #checkStandardUPCEANChecksum(String)}
|
||||
*/
|
||||
public function checkChecksum(s:String):Boolean {
|
||||
return checkStandardUPCEANChecksum(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the UPC/EAN checksum on a string of digits, and reports
|
||||
* whether the checksum is correct or not.
|
||||
*
|
||||
* @param s string of digits to check
|
||||
* @return true iff string of digits passes the UPC/EAN checksum algorithm
|
||||
* @throws ReaderException if the string does not contain only digits
|
||||
*/
|
||||
public static function checkStandardUPCEANChecksum(s:String):Boolean {
|
||||
var length:int = s.length;
|
||||
if (length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var sum:int = 0;
|
||||
for (var i:int = length - 2; i >= 0; i -= 2) {
|
||||
var digit:int = s.charCodeAt(i) - ('0').charCodeAt(0);
|
||||
if (digit < 0 || digit > 9) {
|
||||
throw new ReaderException("AbstractUPCEANReader : checkStandardUPCEANChecksum : digit out of range ("+digit+")");
|
||||
}
|
||||
sum += digit;
|
||||
}
|
||||
sum *= 3;
|
||||
for (var i3:int = length - 1; i3 >= 0; i3 -= 2) {
|
||||
var digit2:int = s.charCodeAt(i3) - ('0').charCodeAt(0);
|
||||
if (digit2 < 0 || digit2 > 9) {
|
||||
throw new ReaderException("AbstractUPCEANReader : checkStandardUPCEANChecksum : digit2 out of range ("+digit2+")");
|
||||
}
|
||||
sum += digit2;
|
||||
}
|
||||
return sum % 10 == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses override this to decode the portion of a barcode between the start and end guard patterns.
|
||||
*
|
||||
* @param row row of black/white values to search
|
||||
* @param startRange start/end offset of start guard pattern
|
||||
* @param resultString {@link StringBuffer} to append decoded chars to
|
||||
* @return horizontal offset of first pixel after the "middle" that was decoded
|
||||
* @throws ReaderException if decoding could not complete successfully
|
||||
*/
|
||||
protected function decodeMiddle(row:BitArray, startRange:Array, resultString:StringBuilder):int{return -1;};
|
||||
|
||||
public function decodeEnd(row:BitArray, endStart:int):Array
|
||||
{
|
||||
return findGuardPattern(row, endStart, false, START_END_PATTERN);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param row row of black/white values to search
|
||||
* @param rowOffset position to start search
|
||||
* @param whiteFirst if true, indicates that the pattern specifies white/black/white/...
|
||||
* pixel counts, otherwise, it is interpreted as black/white/black/...
|
||||
* @param pattern pattern of counts of number of black and white pixels that are being
|
||||
* searched for as a pattern
|
||||
* @return start/end horizontal offset of guard pattern, as an array of two ints
|
||||
* @throws ReaderException if pattern is not found
|
||||
*/
|
||||
public static function findGuardPattern( row:BitArray, rowOffset:int, whiteFirst:Boolean, pattern:Array):Array
|
||||
{
|
||||
var patternLength:int = pattern.length;
|
||||
var counters:Array = new Array(patternLength);
|
||||
for (var i:int=0;i<patternLength;i++) { counters[i] = 0; }
|
||||
var width:int = row.getSize();
|
||||
var isWhite:Boolean = false;
|
||||
while (rowOffset < width) {
|
||||
isWhite = !row._get(rowOffset);
|
||||
if (whiteFirst == isWhite) {
|
||||
break;
|
||||
}
|
||||
rowOffset++;
|
||||
}
|
||||
|
||||
var counterPosition:int = 0;
|
||||
var patternStart:int = rowOffset;
|
||||
for (var x:int = rowOffset; x < width; x++)
|
||||
{
|
||||
var pixel:Boolean = row._get(x);
|
||||
if (pixel != isWhite)
|
||||
{
|
||||
counters[counterPosition] = counters[counterPosition] + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (counterPosition == patternLength - 1)
|
||||
{
|
||||
if (patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE)
|
||||
{
|
||||
return [patternStart, x];
|
||||
}
|
||||
patternStart = patternStart + counters[0] + counters[1];
|
||||
for (var y:int = 2; y < patternLength; y++)
|
||||
{
|
||||
counters[y - 2] = counters[y];
|
||||
}
|
||||
counters[patternLength - 2] = 0;
|
||||
counters[patternLength - 1] = 0;
|
||||
counterPosition--;
|
||||
}
|
||||
else
|
||||
{
|
||||
counterPosition++;
|
||||
}
|
||||
counters[counterPosition] = 1;
|
||||
isWhite = !isWhite;
|
||||
}
|
||||
}
|
||||
throw new ReaderException("AbstractUPCEANReader : findGuardPattern : pattern not found)");
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to decode a single UPC/EAN-encoded digit.
|
||||
*
|
||||
* @param row row of black/white values to decode
|
||||
* @param counters the counts of runs of observed black/white/black/... values
|
||||
* @param rowOffset horizontal offset to start decoding from
|
||||
* @param patterns the set of patterns to use to decode -- sometimes different encodings
|
||||
* for the digits 0-9 are used, and this indicates the encodings for 0 to 9 that should
|
||||
* be used
|
||||
* @return horizontal offset of first pixel beyond the decoded digit
|
||||
* @throws ReaderException if digit cannot be decoded
|
||||
*/
|
||||
public static function decodeDigit(row:BitArray,counters:Array, rowOffset:int, patterns:Array):int
|
||||
{
|
||||
|
||||
recordPattern(row, rowOffset, counters);
|
||||
var bestVariance:int = MAX_AVG_VARIANCE; // worst variance we'll accept
|
||||
var bestMatch:int = -1;
|
||||
var max:int = patterns.length;
|
||||
for (var i:int = 0; i < max; i++)
|
||||
{
|
||||
var pattern:Array = patterns[i];
|
||||
var variance:int = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
if (variance < bestVariance) {
|
||||
bestVariance = variance;
|
||||
bestMatch = i;
|
||||
}
|
||||
}
|
||||
if (bestMatch >= 0) {
|
||||
return bestMatch;
|
||||
} else {
|
||||
throw new ReaderException("AbstractUPCEANReader : decodeDigit : not bestMatch found");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,127 +0,0 @@
|
|||
/*
|
||||
* Copyright 2009 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.oned
|
||||
{
|
||||
import com.google.zxing.common.ByteMatrix;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
|
||||
/**
|
||||
* <p>Encapsulates functionality and implementation that is common to UPC and EAN families
|
||||
* of one-dimensional barcodes.</p>
|
||||
*
|
||||
* @author aripollak@gmail.com (Ari Pollak)
|
||||
*/
|
||||
public class AbstractUPCEANWriter implements UPCEANWriter
|
||||
{
|
||||
|
||||
public function encode(contents:String, format:BarcodeFormat=null, width:int=0, height:int=0, hints:HashTable=null):Object
|
||||
{
|
||||
if (contents == null || contents.length == 0) {
|
||||
throw new IllegalArgumentException("oned : AbstractUPCEANWriter : encode : Found empty contents");
|
||||
}
|
||||
|
||||
if (width < 0 || height < 0) {
|
||||
throw new IllegalArgumentException("oned : AbstractUPCEANWriter : encode : Requested dimensions are too small: "+ width + 'x' + height);
|
||||
}
|
||||
|
||||
var code:Array = encode(contents) as Array;
|
||||
return renderResult(code, width, height);
|
||||
}
|
||||
|
||||
/** @return a byte array of horizontal pixels (0 = white, 1 = black) */
|
||||
protected static function renderResult(code:Array, width:int, height:int):ByteMatrix {
|
||||
var inputWidth:int = code.length;
|
||||
// Add quiet zone on both sides
|
||||
var fullWidth:int = inputWidth + (AbstractUPCEANReader.START_END_PATTERN.length << 1);
|
||||
var outputWidth:int = Math.max(width, fullWidth);
|
||||
var outputHeight:int = Math.max(1, height);
|
||||
|
||||
var multiple:int = outputWidth / fullWidth;
|
||||
var leftPadding:int = (outputWidth - (inputWidth * multiple)) / 2;
|
||||
|
||||
var output:ByteMatrix = new ByteMatrix(outputWidth, outputHeight);
|
||||
var outputArray:Array = output.getArray();
|
||||
|
||||
var row:Array = new Array(outputWidth);
|
||||
|
||||
// a. Write the white pixels at the left of each row
|
||||
for (var x:int = 0; x < leftPadding; x++) {
|
||||
row[x] = 255;
|
||||
}
|
||||
|
||||
// b. Write the contents of this row of the barcode
|
||||
var offset:int = leftPadding;
|
||||
for (var x2:int = 0; x2 < inputWidth; x2++) {
|
||||
var value:int = (code[x2] == 1) ? 0 : 255;
|
||||
for (var z2:int = 0; z2 < multiple; z2++) {
|
||||
row[offset + z2] = value;
|
||||
}
|
||||
offset += multiple;
|
||||
}
|
||||
|
||||
// c. Write the white pixels at the right of each row
|
||||
offset = leftPadding + (inputWidth * multiple);
|
||||
for (var x3:int = offset; x3 < outputWidth; x3++) {
|
||||
row[x3] = 255;
|
||||
}
|
||||
|
||||
// d. Write the completed row multiple times
|
||||
for (var z:int = 0; z < outputHeight; z++)
|
||||
{
|
||||
//BAS : to convert
|
||||
//System.arraycopy(row, 0, outputArray[z], 0, outputWidth);
|
||||
var ctr:int=0;
|
||||
for (var i:int = 0;i<outputWidth;i++)
|
||||
{
|
||||
outputArray[z][ctr] = row[i];
|
||||
ctr++;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Appends the given pattern to the target array starting at pos.
|
||||
*
|
||||
* @param startColor
|
||||
* starting color - 0 for white, 1 for black
|
||||
* @return the number of elements added to target.
|
||||
*/
|
||||
protected static function appendPattern(target:Array, pos:int, pattern:Array, startColor:int):int {
|
||||
if (startColor != 0 && startColor != 1) {
|
||||
throw new Error("oned : AbstractUPCEANWriter : appendPattern : startColor must be either 0 or 1, but got: " + startColor);
|
||||
}
|
||||
|
||||
var color:int = startColor;
|
||||
var numAdded:int = 0;
|
||||
for (var i:int = 0; i < pattern.length; i++) {
|
||||
for (var j:int = 0; j < pattern[i]; j++) {
|
||||
target[pos] = color;
|
||||
pos += 1;
|
||||
numAdded += 1;
|
||||
}
|
||||
color ^= 1; // flip color after each segment
|
||||
}
|
||||
return numAdded;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
264
actionscript/core/src/com/google/zxing/oned/CodaBarReader.as
Normal file
264
actionscript/core/src/com/google/zxing/oned/CodaBarReader.as
Normal file
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.oned
|
||||
{
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.NotFoundException;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.ResultPoint;
|
||||
import com.google.zxing.common.BitArray;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
|
||||
/**
|
||||
* <p>Decodes Codabar barcodes.</p>
|
||||
*
|
||||
* @author Bas Vijfwinkel
|
||||
*/
|
||||
public final class CodaBarReader extends OneDReader {
|
||||
|
||||
public static var ALPHABET_STRING:String = "0123456789-$:/.+ABCDTN";
|
||||
public static var ALPHABET:Array = CodaBarReader.ALPHABET_STRING.split("");
|
||||
|
||||
/**
|
||||
* These represent the encodings of characters, as patterns of wide and narrow bars. The 7 least-significant bits of
|
||||
* each int correspond to the pattern of wide and narrow, with 1s representing "wide" and 0s representing narrow. NOTE
|
||||
* : c is equal to the * pattern NOTE : d is equal to the e pattern
|
||||
*/
|
||||
private static var CHARACTER_ENCODINGS:Array = [
|
||||
0x003, 0x006, 0x009, 0x060, 0x012, 0x042, 0x021, 0x024, 0x030, 0x048, // 0-9
|
||||
0x00c, 0x018, 0x045, 0x051, 0x054, 0x015, 0x01A, 0x029, 0x00B, 0x00E, // -$:/.+ABCD
|
||||
0x01A, 0x029 //TN
|
||||
];
|
||||
|
||||
// minimal number of characters that should be present (inclusing start and stop characters)
|
||||
// this check has been added to reduce the number of false positive on other formats
|
||||
// until the cause for this behaviour has been determined
|
||||
// under normal circumstances this should be set to 3
|
||||
private static var minCharacterLength:int = 6;
|
||||
|
||||
// multiple start/end patterns
|
||||
// official start and end patterns
|
||||
private static var STARTEND_ENCODING:Array = ['E', '*', 'A', 'B', 'C', 'D', 'T', 'N'];
|
||||
// some codabar generator allow the codabar string to be closed by every character
|
||||
//private static final char[] STARTEND_ENCODING = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '$', ':', '/', '.', '+', 'A', 'B', 'C', 'D', 'T', 'N'};
|
||||
|
||||
// some industries use a checksum standard but this is not part of the original codabar standard
|
||||
// for more information see : http://www.mecsw.com/specs/codabar.html
|
||||
|
||||
public override function decodeRow(rowNumber:Object, row:BitArray, o:Object):Result
|
||||
{
|
||||
var start:Array = findAsteriskPattern(row);
|
||||
start[1] = 0; // settings this to 0 improves the recognition rate somehow?
|
||||
var nextStart:int = start[1];
|
||||
var end:int = row.getSize();
|
||||
|
||||
// Read off white space
|
||||
while (nextStart < end && !row._get(nextStart)) {
|
||||
nextStart++;
|
||||
}
|
||||
|
||||
var result:StringBuilder = new StringBuilder();
|
||||
//int[] counters = new int[7];
|
||||
var counters:Array;
|
||||
var lastStart:int;
|
||||
|
||||
do {
|
||||
counters = [0, 0, 0, 0, 0, 0, 0]; // reset counters
|
||||
recordPattern(row, nextStart, counters);
|
||||
|
||||
var decodedChar:String = toNarrowWidePattern(counters);
|
||||
if (decodedChar == '!') {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
result.Append(decodedChar);
|
||||
lastStart = nextStart;
|
||||
for (i = 0; i < counters.length; i++) {
|
||||
nextStart += counters[i];
|
||||
}
|
||||
|
||||
// Read off white space
|
||||
while (nextStart < end && !row._get(nextStart)) {
|
||||
nextStart++;
|
||||
}
|
||||
} while (nextStart < end); // no fixed end pattern so keep on reading while data is available
|
||||
|
||||
// Look for whitespace after pattern:
|
||||
var lastPatternSize:int = 0;
|
||||
for (var i:int = 0; i < counters.length; i++) {
|
||||
lastPatternSize += counters[i];
|
||||
}
|
||||
|
||||
var whiteSpaceAfterEnd:int = nextStart - lastStart - lastPatternSize;
|
||||
// If 50% of last pattern size, following last pattern, is not whitespace, fail
|
||||
// (but if it's whitespace to the very end of the image, that's OK)
|
||||
if (nextStart != end && (whiteSpaceAfterEnd / 2 < lastPatternSize)) {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
// valid result?
|
||||
if (result.length < 2)
|
||||
{
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
var startchar:String = result.charAt(0);
|
||||
if (!arrayContains(STARTEND_ENCODING,startchar))
|
||||
{
|
||||
//invalid start character
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
// find stop character
|
||||
for (var k:int = 1;k < result.length ;k++)
|
||||
{
|
||||
if (result.charAt(k) == startchar)
|
||||
{
|
||||
// found stop character -> discard rest of the string
|
||||
if ((k+1) != result.length)
|
||||
{
|
||||
result.Remove(k+1,result.length-1);
|
||||
k = result.length;// break out of loop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove stop/start characters character and check if a string longer than 5 characters is contained
|
||||
if (result.length > minCharacterLength)
|
||||
{
|
||||
result.deleteCharAt(result.length-1);
|
||||
result.deleteCharAt(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Almost surely a false positive ( start + stop + at least 1 character)
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
var left:Number = (start[1] + start[0]) / 2.0;
|
||||
var right:Number = (nextStart + lastStart) / 2.0;
|
||||
return new Result(
|
||||
result.toString(),
|
||||
null,
|
||||
[new ResultPoint(left, Math.floor(rowNumber as Number)),new ResultPoint(right, Math.floor(rowNumber as Number))],
|
||||
BarcodeFormat.CODABAR);
|
||||
}
|
||||
|
||||
private static function findAsteriskPattern(row:BitArray):Array {
|
||||
var width:int = row.getSize();
|
||||
var rowOffset:int = 0;
|
||||
while (rowOffset < width) {
|
||||
if (row._get(rowOffset)) {
|
||||
break;
|
||||
}
|
||||
rowOffset++;
|
||||
}
|
||||
|
||||
var counterPosition:int = 0;
|
||||
var counters:Array = new Array(7);
|
||||
for (var k:int = 0;k<counters.length;k++){counters[k]=0;}
|
||||
var patternStart:int = rowOffset;
|
||||
var isWhite:Boolean = false;
|
||||
var patternLength:int = counters.length;
|
||||
|
||||
for (var i:int = rowOffset; i < width; i++) {
|
||||
var pixel:Boolean = row._get(i);
|
||||
if (pixel != isWhite) {
|
||||
counters[counterPosition]++;
|
||||
} else {
|
||||
if (counterPosition == patternLength - 1) {
|
||||
try {
|
||||
if (arrayContains(STARTEND_ENCODING, toNarrowWidePattern(counters))) {
|
||||
// Look for whitespace before start pattern, >= 50% of width of start pattern
|
||||
if (row.isRange(Math.max(0, patternStart - (i - patternStart) / 2), patternStart, false)) {
|
||||
return [patternStart, i];
|
||||
}
|
||||
}
|
||||
} catch (re:IllegalArgumentException ) {
|
||||
// no match, continue
|
||||
}
|
||||
patternStart += counters[0] + counters[1];
|
||||
for (var y:int = 2; y < patternLength; y++) {
|
||||
counters[y - 2] = counters[y];
|
||||
}
|
||||
counters[patternLength - 2] = 0;
|
||||
counters[patternLength - 1] = 0;
|
||||
counterPosition--;
|
||||
} else {
|
||||
counterPosition++;
|
||||
}
|
||||
counters[counterPosition] = 1;
|
||||
if (isWhite) {isWhite = false; } else { isWhite = true;} // isWhite = !isWhite;
|
||||
}
|
||||
}
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
private static function arrayContains(array:Array, key:String):Boolean {
|
||||
if (array != null) {
|
||||
for (var i:int = 0; i < array.length; i++) {
|
||||
if (array[i] == key) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static function toNarrowWidePattern(counters:Array):String {
|
||||
// BAS : I have changed the following part because some codabar images would fail with the original routine
|
||||
// I took from the Code39Reader.java file
|
||||
// ----------- change start
|
||||
var numCounters:int = counters.length;
|
||||
var maxNarrowCounter:int = 0;
|
||||
|
||||
var minCounter:int = int.MAX_VALUE;
|
||||
for (var i:int = 0; i < numCounters; i++) {
|
||||
if (counters[i] < minCounter) {
|
||||
minCounter = counters[i];
|
||||
}
|
||||
if (counters[i] > maxNarrowCounter) {
|
||||
maxNarrowCounter = counters[i];
|
||||
}
|
||||
}
|
||||
// ---------- change end
|
||||
|
||||
|
||||
do {
|
||||
var wideCounters:int = 0;
|
||||
var pattern:int = 0;
|
||||
for (i = 0; i < numCounters; i++) {
|
||||
if (counters[i] > maxNarrowCounter) {
|
||||
pattern |= 1 << (numCounters - 1 - i);
|
||||
wideCounters++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((wideCounters == 2) || (wideCounters == 3)) {
|
||||
for (i = 0; i < CHARACTER_ENCODINGS.length; i++) {
|
||||
if (CHARACTER_ENCODINGS[i] == pattern) {
|
||||
return ALPHABET[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
maxNarrowCounter--;
|
||||
} while (maxNarrowCounter > minCounter);
|
||||
return '!';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,8 +15,10 @@
|
|||
*/
|
||||
package com.google.zxing.oned
|
||||
{
|
||||
import com.google.zxing.ResultMetadataType;
|
||||
|
||||
public class Code128Reader extends AbstractOneDReader
|
||||
|
||||
public class Code128Reader extends OneDReader
|
||||
{
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
|
@ -25,9 +27,10 @@ package com.google.zxing.oned
|
|||
import com.google.zxing.Result;
|
||||
import com.google.zxing.ResultPoint;
|
||||
import com.google.zxing.common.BitArray;
|
||||
import com.google.zxing.BinaryBitmap;
|
||||
|
||||
|
||||
private static var CODE_PATTERNS:Array = [
|
||||
public static var CODE_PATTERNS:Array = [
|
||||
[2, 1, 2, 2, 2, 2], // 0
|
||||
[2, 2, 2, 1, 2, 2],
|
||||
[2, 2, 2, 2, 2, 1],
|
||||
|
@ -239,7 +242,7 @@ package com.google.zxing.oned
|
|||
}
|
||||
}
|
||||
|
||||
public override function decodeRow(rowNumber:int, row:BitArray, hints:Object):Result {
|
||||
public override function decodeRow(rowNumber:Object, row:BitArray, hints:Object):Result {
|
||||
|
||||
var startPatternInfo:Array = findStartPattern(row);
|
||||
var startCode:int = startPatternInfo[2];
|
||||
|
@ -405,14 +408,15 @@ package com.google.zxing.oned
|
|||
if (unshift) {
|
||||
switch (codeSet) {
|
||||
case CODE_CODE_A:
|
||||
codeSet = CODE_CODE_C;
|
||||
codeSet = CODE_CODE_B;
|
||||
// codeSet = CODE_CODE_C;
|
||||
break;
|
||||
case CODE_CODE_B:
|
||||
codeSet = CODE_CODE_A;
|
||||
break;
|
||||
case CODE_CODE_C:
|
||||
codeSet = CODE_CODE_B;
|
||||
break;
|
||||
// case CODE_CODE_C:
|
||||
// codeSet = CODE_CODE_B;
|
||||
// break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -463,6 +467,12 @@ package com.google.zxing.oned
|
|||
BarcodeFormat.CODE_128);
|
||||
|
||||
}
|
||||
|
||||
/* function decode(image:BinaryBitmap, hints:HashTable=null):Result
|
||||
{
|
||||
return super.decode(image,hints);
|
||||
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
|
|
203
actionscript/core/src/com/google/zxing/oned/Code128Writer.as
Normal file
203
actionscript/core/src/com/google/zxing/oned/Code128Writer.as
Normal file
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* Copyright 2010 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.oned
|
||||
{
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
import com.google.zxing.common.flexdatatypes.ArrayList;
|
||||
|
||||
/**
|
||||
* This object renders a CODE128 code as a {@link BitMatrix}.
|
||||
*
|
||||
* @author erik.barbara@gmail.com (Erik Barbara)
|
||||
*/
|
||||
public final class Code128Writer extends UPCEANWriter {
|
||||
|
||||
private static var CODE_START_B:int = 104;
|
||||
private static var CODE_START_C:int = 105;
|
||||
private static var CODE_CODE_B:int = 100;
|
||||
private static var CODE_CODE_C:int = 99;
|
||||
private static var CODE_STOP:int = 106;
|
||||
|
||||
// Dummy characters used to specify control characters in input
|
||||
private static var ESCAPE_FNC_1:String = '\u00f1';
|
||||
private static var ESCAPE_FNC_2:String = '\u00f2';
|
||||
private static var ESCAPE_FNC_3:String = '\u00f3';
|
||||
private static var ESCAPE_FNC_4:String = '\u00f4';
|
||||
|
||||
private static var CODE_FNC_1:int = 102; // Code A, Code B, Code C
|
||||
private static var CODE_FNC_2:int = 97; // Code A, Code B
|
||||
private static var CODE_FNC_3:int = 96; // Code A, Code B
|
||||
private static var CODE_FNC_4_B:int = 100; // Code B
|
||||
|
||||
public override function encode(contents:String ,
|
||||
format:BarcodeFormat = null,
|
||||
width:int = 0,
|
||||
height:int = 0,
|
||||
hints:HashTable = null):Object // either BitMatrix or String
|
||||
{
|
||||
if (format != null)
|
||||
{
|
||||
if (format != BarcodeFormat.CODE_128) {
|
||||
throw new IllegalArgumentException("Can only encode CODE_128, but got " + format);
|
||||
}
|
||||
//returns a BitMatrix
|
||||
return super.encode(contents, format, width, height, hints);
|
||||
}
|
||||
// this part will return a string
|
||||
var length:int = contents.length;
|
||||
// Check length
|
||||
if (length < 1 || length > 80) {throw new IllegalArgumentException("Contents length should be between 1 and 80 characters, but got " + length);
|
||||
}
|
||||
// Check content
|
||||
for (var i:int = 0; i < length; i++) {
|
||||
var c:String = contents.charAt(i);
|
||||
if (c < ' ' || c > '~') {
|
||||
switch (c) {
|
||||
case ESCAPE_FNC_1:
|
||||
case ESCAPE_FNC_2:
|
||||
case ESCAPE_FNC_3:
|
||||
case ESCAPE_FNC_4:
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Bad character in input: " + c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var patterns:ArrayList = new ArrayList(); // temporary storage for patterns
|
||||
var checkSum:int = 0;
|
||||
var checkWeight:int = 1;
|
||||
var codeSet:int = 0; // selected code (CODE_CODE_B or CODE_CODE_C)
|
||||
var position:int = 0; // position in contents
|
||||
|
||||
while (position < length) {
|
||||
//Select code to use
|
||||
var requiredDigitCount:int = codeSet == CODE_CODE_C ? 2 : 4;
|
||||
var newCodeSet:int;
|
||||
if (isDigits(contents, position, requiredDigitCount)) {
|
||||
newCodeSet = CODE_CODE_C;
|
||||
} else {
|
||||
newCodeSet = CODE_CODE_B;
|
||||
}
|
||||
|
||||
//Get the pattern index
|
||||
var patternIndex:int;
|
||||
if (newCodeSet == codeSet) {
|
||||
// Encode the current character
|
||||
if (codeSet == CODE_CODE_B) {
|
||||
patternIndex = contents.charCodeAt(position) - (' ').charCodeAt(0);
|
||||
position += 1;
|
||||
} else { // CODE_CODE_C
|
||||
switch (contents.charAt(position)) {
|
||||
case ESCAPE_FNC_1:
|
||||
patternIndex = CODE_FNC_1;
|
||||
position++;
|
||||
break;
|
||||
case ESCAPE_FNC_2:
|
||||
patternIndex = CODE_FNC_2;
|
||||
position++;
|
||||
break;
|
||||
case ESCAPE_FNC_3:
|
||||
patternIndex = CODE_FNC_3;
|
||||
position++;
|
||||
break;
|
||||
case ESCAPE_FNC_4:
|
||||
patternIndex = CODE_FNC_4_B; // FIXME if this ever outputs Code A
|
||||
position++;
|
||||
break;
|
||||
default:
|
||||
patternIndex = parseInt(contents.substring(position, position + 2));
|
||||
position += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Should we change the current code?
|
||||
// Do we have a code set?
|
||||
if (codeSet == 0) {
|
||||
// No, we don't have a code set
|
||||
if (newCodeSet == CODE_CODE_B) {
|
||||
patternIndex = CODE_START_B;
|
||||
} else {
|
||||
// CODE_CODE_C
|
||||
patternIndex = CODE_START_C;
|
||||
}
|
||||
} else {
|
||||
// Yes, we have a code set
|
||||
patternIndex = newCodeSet;
|
||||
}
|
||||
codeSet = newCodeSet;
|
||||
}
|
||||
|
||||
// Get the pattern
|
||||
patterns.addElement(Code128Reader.CODE_PATTERNS[patternIndex]);
|
||||
|
||||
// Compute checksum
|
||||
checkSum += patternIndex * checkWeight;
|
||||
if (position != 0) {
|
||||
checkWeight++;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute and append checksum
|
||||
checkSum %= 103;
|
||||
patterns.addElement(Code128Reader.CODE_PATTERNS[checkSum]);
|
||||
|
||||
// Append stop code
|
||||
patterns.addElement(Code128Reader.CODE_PATTERNS[CODE_STOP]);
|
||||
|
||||
// Compute code width
|
||||
var codeWidth:int = 0;
|
||||
for (var j:int=0;j<patterns.length;j++)
|
||||
{
|
||||
var pattern:Array = patterns.getObjectByIndex(j) as Array;
|
||||
for (i = 0; i < pattern.length; i++)
|
||||
{
|
||||
codeWidth += pattern[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Compute result
|
||||
var result:Array = new Array(codeWidth);
|
||||
var pos:int = 0;
|
||||
for (var jk:int=0;jk<patterns.length;jk++)
|
||||
{
|
||||
pos += appendPattern(result, pos, patterns.getObjectByIndex(jk) as Array, 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static function isDigits(value:String, start:int, length:int):Boolean {
|
||||
var end:int = start + length;
|
||||
var last:int = value.length;
|
||||
for (var i:int = start; i < end && i < last; i++) {
|
||||
var c:String = value.charAt(i);
|
||||
if (c < '0' || c > '9') {
|
||||
if (c != ESCAPE_FNC_1) {
|
||||
return false;
|
||||
}
|
||||
end++; // ignore FNC_1
|
||||
}
|
||||
}
|
||||
return end <= last; // end > last if we've run out of string
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package com.google.zxing.oned
|
||||
{
|
||||
public class Code39Reader extends AbstractOneDReader
|
||||
public class Code39Reader extends OneDReader
|
||||
{
|
||||
|
||||
import com.google.zxing.common.BitArray;
|
||||
|
@ -25,16 +25,17 @@ package com.google.zxing.oned
|
|||
import com.google.zxing.ResultPoint;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
import com.google.zxing.BinaryBitmap;
|
||||
|
||||
private static var ALPHABET_STRING:String = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%";
|
||||
private static var ALPHABET:Array = ALPHABET_STRING.split("");
|
||||
public static var ALPHABET_STRING:String = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%";
|
||||
public static var ALPHABET:Array = ALPHABET_STRING.split("");
|
||||
|
||||
/**
|
||||
* These represent the encodings of characters, as patterns of wide and narrow bars.
|
||||
* The 9 least-significant bits of each int correspond to the pattern of wide and narrow,
|
||||
* with 1s representing "wide" and 0s representing narrow.
|
||||
*/
|
||||
private static var CHARACTER_ENCODINGS:Array = [
|
||||
public static var CHARACTER_ENCODINGS:Array = [
|
||||
0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, 0x124, 0x064, // 0-9
|
||||
0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C, 0x04C, 0x01C, // A-J
|
||||
0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007, 0x106, 0x046, 0x016, // K-T
|
||||
|
@ -42,7 +43,7 @@ package com.google.zxing.oned
|
|||
0x0A8, 0x0A2, 0x08A, 0x02A // $-%
|
||||
];
|
||||
|
||||
private static var ASTERISK_ENCODING:int = CHARACTER_ENCODINGS[39];
|
||||
public static var ASTERISK_ENCODING:int = CHARACTER_ENCODINGS[39];
|
||||
|
||||
private var usingCheckDigit:Boolean;
|
||||
private var extendedMode:Boolean;
|
||||
|
@ -60,6 +61,9 @@ package com.google.zxing.oned
|
|||
* data, and verify that the checksum passes.
|
||||
*/
|
||||
|
||||
|
||||
// function decode(image:BinaryBitmap, hints:HashTable=null):Result { return null; }
|
||||
|
||||
/**
|
||||
* Creates a reader that can be configured to check the last character as a check digit,
|
||||
* or optionally attempt to decode "extended Code 39" sequences that are used to encode
|
||||
|
@ -91,7 +95,7 @@ package com.google.zxing.oned
|
|||
}
|
||||
}
|
||||
|
||||
public override function decodeRow(rowNumber:int, row:BitArray, hints:Object):Result {
|
||||
public override function decodeRow(rowNumber:Object, row:BitArray, hints:Object):Result {
|
||||
|
||||
var start:Array = findAsteriskPattern(row);
|
||||
var nextStart:int = start[1];
|
||||
|
@ -139,11 +143,11 @@ package com.google.zxing.oned
|
|||
var max:int = result.length - 1;
|
||||
var total:int = 0;
|
||||
for (var i3:int = 0; i3 < max; i3++) {
|
||||
total += ALPHABET_STRING.indexOf(result[i3]);
|
||||
total += ALPHABET_STRING.indexOf(result.charAt(i3));
|
||||
}
|
||||
if (total % 43 != ALPHABET_STRING.indexOf(result[max]))
|
||||
{
|
||||
throw new ReaderException("Code39Reader : decodeRow : total % 43 != ALPHABET_STRING.indexOf(result[max])");
|
||||
if (result.charAt(max) != ALPHABET[total % 43])
|
||||
{
|
||||
throw new ReaderException("Code39Reader : decodeRow : checkDigit incorrect)");
|
||||
}
|
||||
result.Remove(max,1);
|
||||
}
|
||||
|
|
85
actionscript/core/src/com/google/zxing/oned/Code39Writer.as
Normal file
85
actionscript/core/src/com/google/zxing/oned/Code39Writer.as
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright 2010 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.oned{
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
import com.google.zxing.oned.Code39Reader
|
||||
|
||||
/**
|
||||
* This object renders a CODE39 code as a {@link BitMatrix}.
|
||||
*
|
||||
* @author erik.barbara@gmail.com (Erik Barbara)
|
||||
*/
|
||||
public class Code39Writer extends UPCEANWriter {
|
||||
|
||||
public override function encode(contents:String ,
|
||||
format:BarcodeFormat = null,
|
||||
width:int = 0,
|
||||
height:int = 0,
|
||||
hints:HashTable = null):Object
|
||||
{
|
||||
if (format != null)
|
||||
{
|
||||
if (format != BarcodeFormat.CODE_39) {
|
||||
throw new IllegalArgumentException("Can only encode CODE_39, but got " + format);
|
||||
}
|
||||
// returns a bitmatrix
|
||||
return super.encode(contents, format, width, height, hints);
|
||||
}
|
||||
// this part returns an array
|
||||
var length:int = contents.length;
|
||||
if (length > 80) {
|
||||
throw new IllegalArgumentException(
|
||||
"Requested contents should be less than 80 digits long, but got " + length);
|
||||
}
|
||||
|
||||
var widths:Array = new Array(9);
|
||||
var codeWidth:int = 24 + 1 + length;
|
||||
for (var i:int = 0; i < length; i++) {
|
||||
var indexInString:int = Code39Reader.ALPHABET_STRING.indexOf(contents.charAt(i));
|
||||
toIntArray(Code39Reader.CHARACTER_ENCODINGS[indexInString], widths);
|
||||
for(var j:int = 0; j < widths.length; j++) {
|
||||
codeWidth += widths[j];
|
||||
}
|
||||
}
|
||||
var result:Array = new Array(codeWidth);
|
||||
toIntArray(Code39Reader.CHARACTER_ENCODINGS[39], widths);
|
||||
var pos:int = appendPattern(result, 0, widths, 1);
|
||||
var narrowWhite:Array = [1];
|
||||
pos += appendPattern(result, pos, narrowWhite, 0);
|
||||
//append next character to bytematrix
|
||||
for(i = length-1; i >= 0; i--) {
|
||||
indexInString = Code39Reader.ALPHABET_STRING.indexOf(contents.charAt(i));
|
||||
toIntArray(Code39Reader.CHARACTER_ENCODINGS[indexInString], widths);
|
||||
pos += appendPattern(result, pos, widths, 1);
|
||||
pos += appendPattern(result, pos, narrowWhite, 0);
|
||||
}
|
||||
toIntArray(Code39Reader.CHARACTER_ENCODINGS[39], widths);
|
||||
pos += appendPattern(result, pos, widths, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static function toIntArray(a:int, toReturn:Array):void {
|
||||
for (var i:int = 0; i < 9; i++) {
|
||||
var temp:int = a & (1 << i);
|
||||
toReturn[i] = temp == 0 ? 1 : 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
276
actionscript/core/src/com/google/zxing/oned/Code93Reader.as
Normal file
276
actionscript/core/src/com/google/zxing/oned/Code93Reader.as
Normal file
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
* Copyright 2010 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.oned
|
||||
{
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.ChecksumException;
|
||||
import com.google.zxing.FormatException;
|
||||
import com.google.zxing.NotFoundException;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.ResultPoint;
|
||||
import com.google.zxing.common.BitArray;
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
|
||||
/**
|
||||
* <p>Decodes Code 93 barcodes.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
* @see Code39Reader
|
||||
*/
|
||||
public final class Code93Reader extends OneDReader {
|
||||
|
||||
// Note that 'abcd' are dummy characters in place of control characters.
|
||||
private static var ALPHABET_STRING:String = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%abcd*";
|
||||
private static var ALPHABET:Array = ALPHABET_STRING.split("");
|
||||
|
||||
/**
|
||||
* These represent the encodings of characters, as patterns of wide and narrow bars.
|
||||
* The 9 least-significant bits of each int correspond to the pattern of wide and narrow.
|
||||
*/
|
||||
private static var CHARACTER_ENCODINGS:Array = [
|
||||
0x114, 0x148, 0x144, 0x142, 0x128, 0x124, 0x122, 0x150, 0x112, 0x10A, // 0-9
|
||||
0x1A8, 0x1A4, 0x1A2, 0x194, 0x192, 0x18A, 0x168, 0x164, 0x162, 0x134, // A-J
|
||||
0x11A, 0x158, 0x14C, 0x146, 0x12C, 0x116, 0x1B4, 0x1B2, 0x1AC, 0x1A6, // K-T
|
||||
0x196, 0x19A, 0x16C, 0x166, 0x136, 0x13A, // U-Z
|
||||
0x12E, 0x1D4, 0x1D2, 0x1CA, 0x16E, 0x176, 0x1AE, // - - %
|
||||
0x126, 0x1DA, 0x1D6, 0x132, 0x15E, // Control chars? $-*
|
||||
];
|
||||
private static var ASTERISK_ENCODING:int = CHARACTER_ENCODINGS[47];
|
||||
|
||||
public override function decodeRow(rowNumber:Object, row:BitArray, hints:Object):Result
|
||||
{
|
||||
|
||||
var start:Array = findAsteriskPattern(row);
|
||||
var nextStart:int = start[1];
|
||||
var end:int = row.getSize();
|
||||
|
||||
// Read off white space
|
||||
while (nextStart < end && !row._get(nextStart)) {
|
||||
nextStart++;
|
||||
}
|
||||
|
||||
var result:StringBuilder = new StringBuilder(20);
|
||||
var counters:Array = new Array(6);
|
||||
var decodedChar:String;
|
||||
var lastStart:int;
|
||||
do {
|
||||
recordPattern(row, nextStart, counters);
|
||||
var pattern:int = toPattern(counters);
|
||||
if (pattern < 0) {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
decodedChar = patternToChar(pattern);
|
||||
result.Append(decodedChar);
|
||||
lastStart = nextStart;
|
||||
for (var i:int = 0; i < counters.length; i++) {
|
||||
nextStart += counters[i];
|
||||
}
|
||||
// Read off white space
|
||||
while (nextStart < end && !row._get(nextStart)) {
|
||||
nextStart++;
|
||||
}
|
||||
} while (decodedChar != '*');
|
||||
result.deleteCharAt(result.length - 1); // remove asterisk
|
||||
|
||||
// Should be at least one more black module
|
||||
if (nextStart == end || !row._get(nextStart)) {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
if (result.length < 4) {
|
||||
// Almost surely a false positive
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
checkChecksums(result);
|
||||
// Remove checksum digits
|
||||
result.setLength(result.length - 2);
|
||||
|
||||
var resultString:String = decodeExtended(result);
|
||||
|
||||
var left:Number = (start[1] + start[0]) / 2.0;
|
||||
var right:Number = (nextStart + lastStart) / 2.0;
|
||||
return new Result(
|
||||
resultString,
|
||||
null,
|
||||
[
|
||||
new ResultPoint(left, Math.floor(rowNumber as Number)),
|
||||
new ResultPoint(right, Math.floor(rowNumber as Number))],
|
||||
BarcodeFormat.CODE_93);
|
||||
|
||||
}
|
||||
|
||||
private static function findAsteriskPattern(row:BitArray ):Array {
|
||||
var width:int = row.getSize();
|
||||
var rowOffset:int = 0;
|
||||
while (rowOffset < width) {
|
||||
if (row._get(rowOffset)) {
|
||||
break;
|
||||
}
|
||||
rowOffset++;
|
||||
}
|
||||
|
||||
var counterPosition:int = 0;
|
||||
var counters:Array= new Array(6);
|
||||
for(var k:int=0;k<counters.length;k++){ counters[k] = 0; }
|
||||
var patternStart:int = rowOffset;
|
||||
var isWhite:Boolean = false;
|
||||
var patternLength:int = counters.length;
|
||||
|
||||
for (var i:int = rowOffset; i < width; i++) {
|
||||
var pixel:Boolean = row._get(i);
|
||||
if (pixel != isWhite) {
|
||||
counters[counterPosition]++;
|
||||
} else {
|
||||
if (counterPosition == patternLength - 1) {
|
||||
if (toPattern(counters) == ASTERISK_ENCODING) {
|
||||
return [patternStart, i];
|
||||
}
|
||||
patternStart += counters[0] + counters[1];
|
||||
for (var y:int = 2; y < patternLength; y++) {
|
||||
counters[y - 2] = counters[y];
|
||||
}
|
||||
counters[patternLength - 2] = 0;
|
||||
counters[patternLength - 1] = 0;
|
||||
counterPosition--;
|
||||
} else {
|
||||
counterPosition++;
|
||||
}
|
||||
counters[counterPosition] = 1;
|
||||
if (isWhite) { isWhite = false; } else { isWhite = true;} //isWhite = !isWhite;
|
||||
}
|
||||
}
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
private static function toPattern(counters:Array):int {
|
||||
var max:int = counters.length;
|
||||
var sum:int = 0;
|
||||
for (var i:int = 0; i < max; i++) {
|
||||
sum += counters[i];
|
||||
}
|
||||
var pattern:int = 0;
|
||||
for (i = 0; i < max; i++) {
|
||||
var scaledShifted:int = (counters[i] << INTEGER_MATH_SHIFT) * 9 / sum;
|
||||
var scaledUnshifted:int = scaledShifted >> INTEGER_MATH_SHIFT;
|
||||
if ((scaledShifted & 0xFF) > 0x7F) {
|
||||
scaledUnshifted++;
|
||||
}
|
||||
if (scaledUnshifted < 1 || scaledUnshifted > 4) {
|
||||
return -1;
|
||||
}
|
||||
if ((i & 0x01) == 0) {
|
||||
for (var j:int = 0; j < scaledUnshifted; j++) {
|
||||
pattern = (pattern << 1) | 0x01;
|
||||
}
|
||||
} else {
|
||||
pattern <<= scaledUnshifted;
|
||||
}
|
||||
}
|
||||
return pattern;
|
||||
}
|
||||
|
||||
private static function patternToChar(pattern:int):String {
|
||||
for (var i:int = 0; i < CHARACTER_ENCODINGS.length; i++) {
|
||||
if (CHARACTER_ENCODINGS[i] == pattern) {
|
||||
return ALPHABET[i];
|
||||
}
|
||||
}
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
private static function decodeExtended(encoded:StringBuilder):String {
|
||||
var length:int = encoded.length;
|
||||
var decoded:StringBuilder = new StringBuilder(length);
|
||||
for (var i:int = 0; i < length; i++) {
|
||||
var c:String = encoded.charAt(i);
|
||||
if (c >= 'a' && c <= 'd') {
|
||||
var next:String = encoded.charAt(i + 1);
|
||||
var decodedChar:String = '\0';
|
||||
switch (c) {
|
||||
case 'd':
|
||||
// +A to +Z map to a to z
|
||||
if (next >= 'A' && next <= 'Z') {
|
||||
decodedChar = String.fromCharCode(next.charCodeAt(0) + 32);
|
||||
} else {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
break;
|
||||
case 'a':
|
||||
// $A to $Z map to control codes SH to SB
|
||||
if (next >= 'A' && next <= 'Z') {
|
||||
decodedChar = String.fromCharCode(next.charCodeAt(0) - 64);
|
||||
} else {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
// %A to %E map to control codes ESC to US
|
||||
if (next >= 'A' && next <= 'E') {
|
||||
decodedChar = String.fromCharCode(next.charCodeAt(0) - 38);
|
||||
} else if (next >= 'F' && next <= 'W') {
|
||||
decodedChar = String.fromCharCode(next.charCodeAt(0) - 11);
|
||||
} else {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
// /A to /O map to ! to , and /Z maps to :
|
||||
if (next >= 'A' && next <= 'O') {
|
||||
decodedChar = String.fromCharCode(next.charCodeAt(0) - 32);
|
||||
} else if (next == 'Z') {
|
||||
decodedChar = ':';
|
||||
} else {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
break;
|
||||
}
|
||||
decoded.Append(decodedChar);
|
||||
// bump up i again since we read two characters
|
||||
i++;
|
||||
} else {
|
||||
decoded.Append(c);
|
||||
}
|
||||
}
|
||||
return decoded.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static function checkChecksums(result:StringBuilder):void {
|
||||
var length:int = result.length;
|
||||
checkOneChecksum(result, length - 2, 20);
|
||||
checkOneChecksum(result, length - 1, 15);
|
||||
}
|
||||
|
||||
private static function checkOneChecksum(result:StringBuilder, checkPosition:int, weightMax:int):void
|
||||
{
|
||||
var weight:int = 1;
|
||||
var total:int = 0;
|
||||
for (var i:int = checkPosition - 1; i >= 0; i--) {
|
||||
total += weight * ALPHABET_STRING.indexOf(result.charAt(i));
|
||||
if (++weight > weightMax) {
|
||||
weight = 1;
|
||||
}
|
||||
}
|
||||
if (result.charAt(checkPosition) != ALPHABET[total % 47]) {
|
||||
throw ChecksumException.getChecksumInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@
|
|||
package com.google.zxing.oned
|
||||
{
|
||||
|
||||
public class EAN13Reader extends AbstractUPCEANReader
|
||||
public class EAN13Reader extends UPCEANReader
|
||||
{
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
import com.google.zxing.ReaderException;
|
||||
|
@ -101,7 +101,7 @@ package com.google.zxing.oned
|
|||
return rowOffset;
|
||||
}
|
||||
|
||||
public override function getBarcodeFormat():BarcodeFormat {
|
||||
public override function getBarcodeFormat():BarcodeFormat {
|
||||
return BarcodeFormat.EAN_13;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ package com.google.zxing.oned
|
|||
*
|
||||
* @author aripollak@gmail.com (Ari Pollak)
|
||||
*/
|
||||
public final class EAN13Writer extends AbstractUPCEANWriter {
|
||||
public final class EAN13Writer extends UPCEANWriter {
|
||||
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
|
@ -47,7 +47,7 @@ public final class EAN13Writer extends AbstractUPCEANWriter {
|
|||
}
|
||||
else
|
||||
{
|
||||
return (this.encode_extended(contents,format,width,height,hints) as ByteMatrix);
|
||||
return (this.encode_extended(contents,format,width,height,hints) as BitMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ public final class EAN13Writer extends AbstractUPCEANWriter {
|
|||
var result:Array = new Array(codeWidth);
|
||||
var pos:int = 0;
|
||||
|
||||
pos += appendPattern(result, pos, AbstractUPCEANReader.START_END_PATTERN, 1);
|
||||
pos += appendPattern(result, pos,UPCEANReader.START_END_PATTERN, 1);
|
||||
|
||||
// See {@link #EAN13Reader} for a description of how the first digit & left bars are encoded
|
||||
for (var i:int = 1; i <= 6; i++) {
|
||||
|
@ -79,16 +79,16 @@ public final class EAN13Writer extends AbstractUPCEANWriter {
|
|||
if ((parities >> (6 - i) & 1) == 1) {
|
||||
digit += 10;
|
||||
}
|
||||
pos += appendPattern(result, pos, AbstractUPCEANReader.L_AND_G_PATTERNS[digit], 0);
|
||||
pos += appendPattern(result, pos, UPCEANReader.L_AND_G_PATTERNS[digit], 0);
|
||||
}
|
||||
|
||||
pos += appendPattern(result, pos, AbstractUPCEANReader.MIDDLE_PATTERN, 0);
|
||||
pos += appendPattern(result, pos, UPCEANReader.MIDDLE_PATTERN, 0);
|
||||
|
||||
for (var i2:int = 7; i2 <= 12; i2++) {
|
||||
var digit2:int = parseInt(contents.substring(i2, i2 + 1));
|
||||
pos += appendPattern(result, pos, AbstractUPCEANReader.L_PATTERNS[digit2], 1);
|
||||
pos += appendPattern(result, pos, UPCEANReader.L_PATTERNS[digit2], 1);
|
||||
}
|
||||
pos += appendPattern(result, pos, AbstractUPCEANReader.START_END_PATTERN, 1);
|
||||
pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ package com.google.zxing.oned
|
|||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
|
||||
public class EAN8Reader extends AbstractUPCEANReader
|
||||
public class EAN8Reader extends UPCEANReader
|
||||
{
|
||||
|
||||
private var decodeMiddleCounters:Array;
|
||||
|
@ -28,7 +28,8 @@ package com.google.zxing.oned
|
|||
decodeMiddleCounters = new Array(4);
|
||||
}
|
||||
|
||||
protected override function decodeMiddle(row:BitArray, startRange:Array, result:StringBuilder):int {
|
||||
protected override function decodeMiddle(row:BitArray, startRange:Array, result:StringBuilder):int
|
||||
{
|
||||
var counters:Array = decodeMiddleCounters;
|
||||
counters[0] = 0;
|
||||
counters[1] = 0;
|
||||
|
@ -59,7 +60,7 @@ package com.google.zxing.oned
|
|||
return rowOffset;
|
||||
}
|
||||
|
||||
public override function getBarcodeFormat():BarcodeFormat {
|
||||
public override function getBarcodeFormat():BarcodeFormat {
|
||||
return BarcodeFormat.EAN_8;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,13 +21,15 @@ package com.google.zxing.oned
|
|||
*
|
||||
* @author aripollak@gmail.com (Ari Pollak)
|
||||
*/
|
||||
public final class EAN8Writer extends AbstractUPCEANWriter {
|
||||
public final class EAN8Writer extends UPCEANWriter {
|
||||
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.WriterException;
|
||||
import com.google.zxing.common.ByteMatrix;
|
||||
|
||||
|
||||
|
||||
private static var codeWidth:int = 3 + // start guard
|
||||
|
@ -44,19 +46,19 @@ import com.google.zxing.common.ByteMatrix;
|
|||
}
|
||||
else
|
||||
{
|
||||
return (this.encode_extended(contents,format,width,height,hints) as ByteMatrix);
|
||||
return (this.encode_extended(contents,format,width,height,hints) as BitMatrix);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function encode_extended(contents:String, format:BarcodeFormat, width:int , height:int, hints:HashTable):ByteMatrix
|
||||
public function encode_extended(contents:String, format:BarcodeFormat, width:int , height:int, hints:HashTable):BitMatrix
|
||||
{
|
||||
if (format != BarcodeFormat.EAN_8) {
|
||||
throw new IllegalArgumentException("Can only encode EAN_8, but got " + format);
|
||||
}
|
||||
|
||||
return (super.encode(contents, format, width, height, hints) as ByteMatrix);
|
||||
return (super.encode(contents, format, width, height, hints) as BitMatrix);
|
||||
}
|
||||
|
||||
/** @return a byte array of horizontal pixels (0 = white, 1 = black) */
|
||||
|
@ -69,20 +71,20 @@ import com.google.zxing.common.ByteMatrix;
|
|||
var result:Array = new Array(codeWidth);
|
||||
var pos:int = 0;
|
||||
|
||||
pos += appendPattern(result, pos, AbstractUPCEANReader.START_END_PATTERN, 1);
|
||||
pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, 1);
|
||||
|
||||
for (var i:int = 0; i <= 3; i++) {
|
||||
var digit:int = parseInt(contents.substring(i, i + 1));
|
||||
pos += appendPattern(result, pos, AbstractUPCEANReader.L_PATTERNS[digit], 0);
|
||||
pos += appendPattern(result, pos, UPCEANReader.L_PATTERNS[digit], 0);
|
||||
}
|
||||
|
||||
pos += appendPattern(result, pos, AbstractUPCEANReader.MIDDLE_PATTERN, 0);
|
||||
pos += appendPattern(result, pos, UPCEANReader.MIDDLE_PATTERN, 0);
|
||||
|
||||
for (var i2:int = 4; i2 <= 7; i2++) {
|
||||
var digit2:int = parseInt(contents.substring(i2, i2 + 1));
|
||||
pos += appendPattern(result, pos, AbstractUPCEANReader.L_PATTERNS[digit2], 1);
|
||||
pos += appendPattern(result, pos, UPCEANReader.L_PATTERNS[digit2], 1);
|
||||
}
|
||||
pos += appendPattern(result, pos, AbstractUPCEANReader.START_END_PATTERN, 1);
|
||||
pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* Copyright (C) 2010 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.oned
|
||||
{
|
||||
|
||||
import com.google.zxing.common.flexdatatypes.ArrayList;
|
||||
|
||||
/**
|
||||
* Records EAN prefix to GS1 Member Organization, where the member organization
|
||||
* correlates strongly with a country. This is an imperfect means of identifying
|
||||
* a country of origin by EAN-13 barcode value. See
|
||||
* <a href="http://en.wikipedia.org/wiki/List_of_GS1_country_codes">
|
||||
* http://en.wikipedia.org/wiki/List_of_GS1_country_codes</a>.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public class EANManufacturerOrgSupport {
|
||||
|
||||
private var ranges:ArrayList = new ArrayList();
|
||||
private var countryIdentifiers:ArrayList = new ArrayList();
|
||||
|
||||
public function lookupCountryIdentifier(productCode:String):String {
|
||||
initIfNeeded();
|
||||
var prefix:int = int(productCode.substring(0, 3));
|
||||
var max:int = ranges.size();
|
||||
for (var i:int = 0; i < max; i++) {
|
||||
var range:Array = ranges.elementAt(i) as Array;
|
||||
var start:int = range[0];
|
||||
if (prefix < start) {
|
||||
return null;
|
||||
}
|
||||
var end:int = range.length == 1 ? start : range[1];
|
||||
if (prefix <= end) {
|
||||
return (countryIdentifiers.elementAt(i) as String);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private function add(range:Array, id:String):void {
|
||||
ranges.addElement(range);
|
||||
countryIdentifiers.addElement(id);
|
||||
}
|
||||
|
||||
private function initIfNeeded():void {
|
||||
if (!ranges.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
add([0,19], "US/CA");
|
||||
add([30,39], "US");
|
||||
add([60,139], "US/CA");
|
||||
add([300,379],"FR");
|
||||
add([380],"BG");
|
||||
add([383],"SI");
|
||||
add([385],"HR");
|
||||
add([387],"BA");
|
||||
add([400,440],"DE");
|
||||
add([450,459],"JP");
|
||||
add([460,469],"RU");
|
||||
add([471],"TW");
|
||||
add([474],"EE");
|
||||
add([475],"LV");
|
||||
add([476],"AZ");
|
||||
add([477],"LT");
|
||||
add([478],"UZ");
|
||||
add([479],"LK");
|
||||
add([480],"PH");
|
||||
add([481],"BY");
|
||||
add([482],"UA");
|
||||
add([484],"MD");
|
||||
add([485],"AM");
|
||||
add([486],"GE");
|
||||
add([487],"KZ");
|
||||
add([489],"HK");
|
||||
add([490,499],"JP");
|
||||
add([500,509],"GB");
|
||||
add([520],"GR");
|
||||
add([528],"LB");
|
||||
add([529],"CY");
|
||||
add([531],"MK");
|
||||
add([535],"MT");
|
||||
add([539],"IE");
|
||||
add([540,549],"BE/LU");
|
||||
add([560],"PT");
|
||||
add([569],"IS");
|
||||
add([570,579],"DK");
|
||||
add([590],"PL");
|
||||
add([594],"RO");
|
||||
add([599],"HU");
|
||||
add([600,601],"ZA");
|
||||
add([603],"GH");
|
||||
add([608],"BH");
|
||||
add([609],"MU");
|
||||
add([611],"MA");
|
||||
add([613],"DZ");
|
||||
add([616],"KE");
|
||||
add([618],"CI");
|
||||
add([619],"TN");
|
||||
add([621],"SY");
|
||||
add([622],"EG");
|
||||
add([624],"LY");
|
||||
add([625],"JO");
|
||||
add([626],"IR");
|
||||
add([627],"KW");
|
||||
add([628],"SA");
|
||||
add([629],"AE");
|
||||
add([640,649],"FI");
|
||||
add([690,695],"CN");
|
||||
add([700,709],"NO");
|
||||
add([729],"IL");
|
||||
add([730,739],"SE");
|
||||
add([740],"GT");
|
||||
add([741],"SV");
|
||||
add([742],"HN");
|
||||
add([743],"NI");
|
||||
add([744],"CR");
|
||||
add([745],"PA");
|
||||
add([746],"DO");
|
||||
add([750],"MX");
|
||||
add([754,755],"CA");
|
||||
add([759],"VE");
|
||||
add([760,769],"CH");
|
||||
add([770],"CO");
|
||||
add([773],"UY");
|
||||
add([775],"PE");
|
||||
add([777],"BO");
|
||||
add([779],"AR");
|
||||
add([780],"CL");
|
||||
add([784],"PY");
|
||||
add([785],"PE");
|
||||
add([786],"EC");
|
||||
add([789,790],"BR");
|
||||
add([800,839],"IT");
|
||||
add([840,849],"ES");
|
||||
add([850],"CU");
|
||||
add([858],"SK");
|
||||
add([859],"CZ");
|
||||
add([860],"YU");
|
||||
add([865],"MN");
|
||||
add([867],"KP");
|
||||
add([868,869],"TR");
|
||||
add([870,879],"NL");
|
||||
add([880],"KR");
|
||||
add([885],"TH");
|
||||
add([888],"SG");
|
||||
add([890],"IN");
|
||||
add([893],"VN");
|
||||
add([896],"PK");
|
||||
add([899],"ID");
|
||||
add([900,919],"AT");
|
||||
add([930,939],"AU");
|
||||
add([940,949],"AZ");
|
||||
add([955],"MY");
|
||||
add([958],"MO");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -16,25 +16,27 @@
|
|||
package com.google.zxing.oned
|
||||
{
|
||||
|
||||
public class ITFReader extends AbstractOneDReader
|
||||
public class ITFReader extends OneDReader
|
||||
{
|
||||
import com.google.zxing.common.BitArray;
|
||||
import com.google.zxing.ResultPoint;
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.ReaderException;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.DecodeHintType;
|
||||
import com.google.zxing.BinaryBitmap;
|
||||
|
||||
private static var MAX_AVG_VARIANCE:int = int(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42);
|
||||
private static var MAX_INDIVIDUAL_VARIANCE:int = int(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.8);
|
||||
public static var MAX_AVG_VARIANCE:int = int(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42);
|
||||
public static var MAX_INDIVIDUAL_VARIANCE:int = int(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.8);
|
||||
|
||||
private static var W:int = 3; // Pixel width of a wide line
|
||||
private static var N:int = 1; // Pixed width of a narrow line
|
||||
public static var W:int = 3; // Pixel width of a wide line
|
||||
public static var N:int = 1; // Pixed width of a narrow line
|
||||
|
||||
// Stores the actual narrow line width of the image being decoded.
|
||||
private var narrowLineWidth:int = -1;
|
||||
public var narrowLineWidth:int = -1;
|
||||
|
||||
/**
|
||||
* Start/end guard pattern.
|
||||
|
@ -42,14 +44,14 @@ package com.google.zxing.oned
|
|||
* Note: The end pattern is reversed because the row is reversed before
|
||||
* searching for the END_PATTERN
|
||||
*/
|
||||
private static var START_PATTERN:Array = [N, N, N, N];
|
||||
private static var END_PATTERN_REVERSED:Array = [N, N, W];
|
||||
public static var START_PATTERN:Array = [N, N, N, N];
|
||||
public static var END_PATTERN_REVERSED:Array = [N, N, W];
|
||||
|
||||
private static var DEFAULT_ALLOWED_LENGTHS:Array = [ 6, 10, 14 ];
|
||||
public static var DEFAULT_ALLOWED_LENGTHS:Array = [ 6, 10, 14 ];
|
||||
/**
|
||||
* Patterns of Wide / Narrow lines to indicate each digit
|
||||
*/
|
||||
private static var PATTERNS:Array = [
|
||||
public static var PATTERNS:Array = [
|
||||
[N, N, W, W, N], // 0
|
||||
[W, N, N, N, W], // 1
|
||||
[N, W, N, N, W], // 2
|
||||
|
@ -62,7 +64,9 @@ package com.google.zxing.oned
|
|||
[N, W, N, W, N] // 9
|
||||
];
|
||||
|
||||
public override function decodeRow(rowNumber:int, row:BitArray, hints:Object):Result
|
||||
//function decode(image:BinaryBitmap, hints:HashTable=null):Result { return null; }
|
||||
|
||||
public override function decodeRow(rowNumber:Object, row:BitArray, hints:Object):Result
|
||||
{
|
||||
// Find out where the Middle section (payload) starts & ends
|
||||
var startRange:Array = decodeStart(row);
|
||||
|
|
74
actionscript/core/src/com/google/zxing/oned/ITFWriter.as
Normal file
74
actionscript/core/src/com/google/zxing/oned/ITFWriter.as
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright 2010 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.oned
|
||||
{
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.WriterException;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* This object renders a ITF code as a {@link BitMatrix}.
|
||||
*
|
||||
* @author erik.barbara@gmail.com (Erik Barbara)
|
||||
*/
|
||||
public class ITFWriter extends UPCEANWriter
|
||||
{
|
||||
|
||||
public override function encode(contents:String ,
|
||||
format:BarcodeFormat=null ,
|
||||
width:int=0,
|
||||
height:int=0,
|
||||
hints:HashTable=null ) : Object
|
||||
{
|
||||
|
||||
if (format != null)
|
||||
{
|
||||
if (format != BarcodeFormat.ITF) {
|
||||
throw new IllegalArgumentException("Can only encode ITF, but got " + format);
|
||||
}
|
||||
|
||||
return super.encode(contents, format, width, height, hints);
|
||||
}
|
||||
|
||||
//public byte[] encode(String contents) {
|
||||
var length:int = contents.length;
|
||||
if (length > 80) {
|
||||
throw new IllegalArgumentException(
|
||||
"Requested contents should be less than 80 digits long, but got " + length);
|
||||
}
|
||||
var result:Array = new Array(9 + 9 * length);
|
||||
var start:Array = [1, 1, 1, 1];
|
||||
var pos:int = appendPattern(result, 0, start, 1);
|
||||
for (var i:int = 0; i < length; i += 2) {
|
||||
var one:int = contents.charCodeAt(i) - 48 ;
|
||||
var two:int = contents.charCodeAt(i+1) - 48;
|
||||
var encoding:Array = new Array(18);
|
||||
for (var j:int = 0; j < 5; j++) {
|
||||
encoding[(j << 1)] = ITFReader.PATTERNS[one][j];
|
||||
encoding[(j << 1) + 1] = ITFReader.PATTERNS[two][j];
|
||||
}
|
||||
pos += appendPattern(result, pos, encoding, 1);
|
||||
}
|
||||
var end:Array = [3, 1, 1];
|
||||
pos += appendPattern(result, pos, end, 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package com.google.zxing.oned
|
||||
{
|
||||
public class MultiFormatOneDReader extends AbstractOneDReader
|
||||
public class MultiFormatOneDReader extends OneDReader
|
||||
{
|
||||
import com.google.zxing.common.BitArray;
|
||||
import com.google.zxing.common.flexdatatypes.ArrayList;
|
||||
|
@ -24,55 +24,79 @@ package com.google.zxing.oned
|
|||
import com.google.zxing.ReaderException;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.oned.rss.RSS14Reader;
|
||||
import com.google.zxing.oned.rss.expanded.RSSExpandedReader;
|
||||
|
||||
private var readers:ArrayList;
|
||||
|
||||
public function MultiFormatOneDReader(hints:HashTable)
|
||||
{
|
||||
var possibleFormats:ArrayList = (hints == null ? null : hints.getValuesByKey(DecodeHintType.POSSIBLE_FORMATS));
|
||||
|
||||
var useCode39CheckDigit:Boolean = hints != null && hints._get(DecodeHintType.ASSUME_CODE_39_CHECK_DIGIT) != null;
|
||||
readers = new ArrayList();
|
||||
if (possibleFormats != null) {
|
||||
if (possibleFormats.Contains(BarcodeFormat.EAN_13) ||
|
||||
possibleFormats.Contains(BarcodeFormat.UPC_A) ||
|
||||
possibleFormats.Contains(BarcodeFormat.EAN_8) ||
|
||||
possibleFormats.Contains(BarcodeFormat.UPC_E))
|
||||
{
|
||||
readers.Add(new MultiFormatUPCEANReader(hints));
|
||||
}
|
||||
if (possibleFormats.Contains(BarcodeFormat.CODE_39))
|
||||
{
|
||||
readers.Add(new Code39Reader());
|
||||
}
|
||||
if (possibleFormats.Contains(BarcodeFormat.CODE_128))
|
||||
{
|
||||
readers.Add(new Code128Reader());
|
||||
}
|
||||
if (possibleFormats.Contains(BarcodeFormat.ITF))
|
||||
{
|
||||
readers.Add(new ITFReader());
|
||||
}
|
||||
}
|
||||
if (readers.Count==0)
|
||||
|
||||
if (possibleFormats != null)
|
||||
{
|
||||
readers.Add(new MultiFormatUPCEANReader(hints));
|
||||
readers.Add(new Code39Reader());
|
||||
readers.Add(new Code128Reader());
|
||||
readers.Add(new ITFReader());
|
||||
|
||||
}
|
||||
if (possibleFormats.Contains(BarcodeFormat.EAN_13) ||
|
||||
possibleFormats.Contains(BarcodeFormat.UPC_A) ||
|
||||
possibleFormats.Contains(BarcodeFormat.EAN_8) ||
|
||||
possibleFormats.Contains(BarcodeFormat.UPC_E))
|
||||
{
|
||||
readers.addElement(new MultiFormatUPCEANReader(hints));
|
||||
}
|
||||
if (possibleFormats.Contains(BarcodeFormat.CODE_39))
|
||||
{
|
||||
readers.addElement(new Code39Reader(useCode39CheckDigit));
|
||||
}
|
||||
if (possibleFormats.Contains(BarcodeFormat.CODE_93))
|
||||
{
|
||||
readers.addElement(new Code93Reader());
|
||||
}
|
||||
if (possibleFormats.Contains(BarcodeFormat.CODE_128))
|
||||
{
|
||||
readers.addElement(new Code128Reader());
|
||||
}
|
||||
if (possibleFormats.Contains(BarcodeFormat.ITF))
|
||||
{
|
||||
readers.addElement(new ITFReader());
|
||||
}
|
||||
if (possibleFormats.Contains(BarcodeFormat.CODABAR))
|
||||
{
|
||||
readers.addElement(new CodaBarReader());
|
||||
}
|
||||
if (possibleFormats.Contains(BarcodeFormat.RSS_14))
|
||||
{
|
||||
readers.addElement(new RSS14Reader());
|
||||
}
|
||||
if (possibleFormats.Contains(BarcodeFormat.RSS_EXPANDED))
|
||||
{
|
||||
readers.addElement(new RSSExpandedReader());
|
||||
}
|
||||
}
|
||||
if (readers.isEmpty())
|
||||
{
|
||||
readers.addElement(new MultiFormatUPCEANReader(hints));
|
||||
readers.addElement(new Code39Reader());
|
||||
readers.addElement(new CodaBarReader());
|
||||
readers.addElement(new Code93Reader());
|
||||
readers.addElement(new Code128Reader());
|
||||
readers.addElement(new ITFReader());
|
||||
readers.addElement(new RSS14Reader());
|
||||
readers.addElement(new RSSExpandedReader());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public override function decodeRow(rowNumber:int, row:BitArray, hints:Object):Result
|
||||
public override function decodeRow(rowNumber:Object, row:BitArray, hints:Object):Result
|
||||
{
|
||||
var size:int = readers.Count;
|
||||
for (var i:int = 0; i < size; i++) {
|
||||
var reader:Object = readers.getObjectByIndex(i);
|
||||
try {
|
||||
var res:Result = reader.decodeRow(rowNumber, row, hints);
|
||||
var res:Result = reader.decodeRow(rowNumber as Number, row, hints);
|
||||
return res;
|
||||
} catch (re:ReaderException) {
|
||||
} catch (re:Error) {
|
||||
// continue
|
||||
var a:int=0;//BAS :needed for debugging
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package com.google.zxing.oned
|
||||
{
|
||||
public class MultiFormatUPCEANReader extends AbstractOneDReader
|
||||
public class MultiFormatUPCEANReader extends OneDReader
|
||||
{
|
||||
import com.google.zxing.common.BitArray;
|
||||
import com.google.zxing.common.flexdatatypes.ArrayList;
|
||||
|
@ -52,11 +52,11 @@ package com.google.zxing.oned
|
|||
}
|
||||
}
|
||||
|
||||
public override function decodeRow(rowNumber:int, row:BitArray,hints:Object):Result
|
||||
public override function decodeRow(rowNumber:Object, row:BitArray,hints:Object):Result
|
||||
{
|
||||
// Compute this location once and reuse it on multiple implementations
|
||||
|
||||
var startGuardPattern:Array = AbstractUPCEANReader.findStartGuardPattern(row);
|
||||
var startGuardPattern:Array = UPCEANReader.findStartGuardPattern(row);
|
||||
var size:int = readers.Count;
|
||||
for (var i:int = 0; i < size; i++) {
|
||||
|
||||
|
|
|
@ -13,32 +13,302 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.zxing.oned
|
||||
{
|
||||
import com.google.zxing.Reader;
|
||||
import com.google.zxing.common.BitArray;
|
||||
import com.google.zxing.Reader;
|
||||
import com.google.zxing.ReaderException;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
|
||||
public interface OneDReader extends Reader
|
||||
{
|
||||
/**
|
||||
* <p>Attempts to decode a one-dimensional barcode format given a single row of
|
||||
* an image.</p>
|
||||
*
|
||||
* @param rowNumber row number from top of the row
|
||||
* @param row the black/white pixel data of the row
|
||||
* @param hints decode hints
|
||||
* @return {@link Result} containing encoded string and start/end of barcode
|
||||
* @throws ReaderException if an error occurs or barcode cannot be found
|
||||
*/
|
||||
/* public function decodeRow_Hashtable(rowNumber:int, row:BitArray, hints:Object):Result
|
||||
{
|
||||
return null;
|
||||
};*/
|
||||
|
||||
package com.google.zxing.oned
|
||||
{
|
||||
import com.google.zxing.BinaryBitmap;
|
||||
import com.google.zxing.DecodeHintType;
|
||||
import com.google.zxing.NotFoundException;
|
||||
import com.google.zxing.Reader;
|
||||
import com.google.zxing.ReaderException;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.ResultMetadataType;
|
||||
import com.google.zxing.ResultPoint;
|
||||
import com.google.zxing.common.BitArray;
|
||||
import com.google.zxing.common.flexdatatypes.Enumeration;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
|
||||
|
||||
/**
|
||||
* Encapsulates functionality and implementation that is common to all families
|
||||
* of one-dimensional barcodes.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public class OneDReader implements Reader
|
||||
{
|
||||
|
||||
protected static var INTEGER_MATH_SHIFT:int = 8;
|
||||
protected static var PATTERN_MATCH_RESULT_SCALE_FACTOR:int = (1 << INTEGER_MATH_SHIFT);
|
||||
|
||||
// Note that we don't try rotation without the try harder flag, even if rotation was supported.
|
||||
|
||||
public function decode(image:BinaryBitmap , hints:HashTable=null):Result {
|
||||
try {
|
||||
return doDecode(image, hints);
|
||||
}
|
||||
catch (nfe:NotFoundException ) {
|
||||
var tryHarder:Boolean = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER);
|
||||
if (tryHarder && image.isRotateSupported()) {
|
||||
var rotatedImage:BinaryBitmap = image.rotateCounterClockwise();
|
||||
var result:Result = doDecode(rotatedImage, hints);
|
||||
// Record that we found it rotated 90 degrees CCW / 270 degrees CW
|
||||
var metadata:HashTable = result.getResultMetadata();
|
||||
var orientation:int = 270;
|
||||
if (metadata != null && metadata.containsKey(ResultMetadataType.ORIENTATION)) {
|
||||
// But if we found it reversed in doDecode(), add in that result here:
|
||||
orientation = (orientation +
|
||||
(metadata._get(ResultMetadataType.ORIENTATION) as int)) % 360;
|
||||
}
|
||||
result.putMetadata(ResultMetadataType.ORIENTATION, orientation);
|
||||
// Update result points
|
||||
var points:Array = result.getResultPoints();
|
||||
var height:int = rotatedImage.getHeight();
|
||||
for (var i:int = 0; i < points.length; i++) {
|
||||
points[i] = new ResultPoint(height - points[i].getY() - 1, points[i].getX());
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
throw nfe;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function reset():void {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* We're going to examine rows from the middle outward, searching alternately above and below the
|
||||
* middle, and farther out each time. rowStep is the number of rows between each successive
|
||||
* attempt above and below the middle. So we'd scan row middle, then middle - rowStep, then
|
||||
* middle + rowStep, then middle - (2 * rowStep), etc.
|
||||
* rowStep is bigger as the image is taller, but is always at least 1. We've somewhat arbitrarily
|
||||
* decided that moving up and down by about 1/16 of the image is pretty good; we try more of the
|
||||
* image if "trying harder".
|
||||
*
|
||||
* @param image The image to decode
|
||||
* @param hints Any hints that were requested
|
||||
* @return The contents of the decoded barcode
|
||||
* @throws NotFoundException Any spontaneous errors which occur
|
||||
*/
|
||||
private function doDecode(image:BinaryBitmap , hints:HashTable ):Result {
|
||||
try
|
||||
{
|
||||
var width:int = image.getWidth();
|
||||
var height:int = image.getHeight();
|
||||
var row:BitArray = new BitArray(width);
|
||||
|
||||
var middle:int = height >> 1;
|
||||
var tryHarder:Boolean = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER);
|
||||
var rowStep:int = Math.max(1, height >> (tryHarder ? 8 : 5));
|
||||
var maxLines:int;
|
||||
if (tryHarder) {
|
||||
maxLines = height; // Look at the whole image, not just the center
|
||||
} else {
|
||||
maxLines = 15; // 15 rows spaced 1/32 apart is roughly the middle half of the image
|
||||
}
|
||||
|
||||
}
|
||||
for (var x:int = 0; x < maxLines; x++)
|
||||
{
|
||||
|
||||
// Scanning from the middle out. Determine which row we're looking at next:
|
||||
var rowStepsAboveOrBelow:int = (x + 1) >> 1;
|
||||
var isAbove:Boolean = (x & 0x01) == 0; // i.e. is x even?
|
||||
var rowNumber:int = middle + rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow);
|
||||
if (rowNumber < 0 || rowNumber >= height) {
|
||||
// Oops, if we run off the top or bottom, stop
|
||||
break;
|
||||
}
|
||||
|
||||
// Estimate black point for this row and load it:
|
||||
try
|
||||
{
|
||||
row = image.getBlackRow(rowNumber, row);
|
||||
}
|
||||
catch (nfe:Error )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// While we have the image data in a BitArray, it's fairly cheap to reverse it in place to
|
||||
// handle decoding upside down barcodes.
|
||||
for (var attempt:int = 0; attempt < 2; attempt++)
|
||||
{
|
||||
if (attempt == 1)
|
||||
{ // trying again?
|
||||
row.reverse(); // reverse the row and continue
|
||||
// This means we will only ever draw result points *once* in the life of this method
|
||||
// since we want to avoid drawing the wrong points after flipping the row, and,
|
||||
// don't want to clutter with noise from every single row scan -- just the scans
|
||||
// that start on the center line.
|
||||
if (hints != null && hints.containsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK)) {
|
||||
var newHints:HashTable = new HashTable(); // Can't use clone() in J2ME
|
||||
var hintEnum:Enumeration = new Enumeration( hints.keys());
|
||||
while (hintEnum.hasMoreElement()) {
|
||||
var key:Object = hintEnum.nextElement();
|
||||
if (key != DecodeHintType.NEED_RESULT_POINT_CALLBACK)
|
||||
{
|
||||
newHints._put(key, hints._get(key));
|
||||
}
|
||||
}
|
||||
hints = newHints;
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
// Look for a barcode
|
||||
var result:Result = decodeRow(rowNumber, row, hints);
|
||||
// We found our barcode
|
||||
if (attempt == 1) {
|
||||
// But it was upside down, so note that
|
||||
//result.putMetadata(ResultMetadataType.ORIENTATION, new Array(180));
|
||||
result.putMetadata(ResultMetadataType.ORIENTATION,new Array(180));
|
||||
// And remember to flip the result points horizontally.
|
||||
var points:Array = result.getResultPoints();
|
||||
points[0] = new ResultPoint(width - points[0].getX() - 1, points[0].getY());
|
||||
points[1] = new ResultPoint(width - points[1].getX() - 1, points[1].getY());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (e:Error)
|
||||
{
|
||||
var g:int=5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch (e:Error)
|
||||
{
|
||||
var a:int=0;
|
||||
}
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the size of successive runs of white and black pixels in a row, starting at a given point.
|
||||
* The values are recorded in the given array, and the number of runs recorded is equal to the size
|
||||
* of the array. If the row starts on a white pixel at the given start point, then the first count
|
||||
* recorded is the run of white pixels starting from that point; likewise it is the count of a run
|
||||
* of black pixels if the row begin on a black pixels at that point.
|
||||
*
|
||||
* @param row row to count from
|
||||
* @param start offset into row to start at
|
||||
* @param counters array into which to record counts
|
||||
* @throws NotFoundException if counters cannot be filled entirely from row before running out
|
||||
* of pixels
|
||||
*/
|
||||
protected static function recordPattern(row:BitArray , start:int , counters:Array):void {
|
||||
var numCounters:int = counters.length;
|
||||
for (var i:int = 0; i < numCounters; i++) {
|
||||
counters[i] = 0;
|
||||
}
|
||||
var end:int = row.getSize();
|
||||
if (start >= end) {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
var isWhite:Boolean = !row._get(start);
|
||||
var counterPosition:int = 0;
|
||||
i= start;
|
||||
while (i < end) {
|
||||
var pixel:Boolean = row._get(i);
|
||||
if ((pixel && !isWhite) || (!pixel && isWhite))
|
||||
{ // that is, exactly one is true
|
||||
counters[counterPosition]++;
|
||||
} else {
|
||||
counterPosition++;
|
||||
if (counterPosition == numCounters) {
|
||||
break;
|
||||
} else {
|
||||
counters[counterPosition] = 1;
|
||||
isWhite = !isWhite;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
// If we read fully the last section of pixels and filled up our counters -- or filled
|
||||
// the last counter but ran off the side of the image, OK. Otherwise, a problem.
|
||||
if (!(counterPosition == numCounters || ((counterPosition == numCounters - 1) &&( i == end)))) {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
}
|
||||
|
||||
protected static function recordPatternInReverse(row:BitArray , start:int, counters:Array):void {
|
||||
// This could be more efficient I guess
|
||||
var numTransitionsLeft:int = counters.length;
|
||||
var last:Boolean = row._get(start);
|
||||
while (start > 0 && numTransitionsLeft >= 0) {
|
||||
if (row._get(--start) != last) {
|
||||
numTransitionsLeft--;
|
||||
last = !last;
|
||||
}
|
||||
}
|
||||
if (numTransitionsLeft >= 0) {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
recordPattern(row, start + 1, counters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines how closely a set of observed counts of runs of black/white values matches a given
|
||||
* target pattern. This is reported as the ratio of the total variance from the expected pattern
|
||||
* proportions across all pattern elements, to the length of the pattern.
|
||||
*
|
||||
* @param counters observed counters
|
||||
* @param pattern expected pattern
|
||||
* @param maxIndividualVariance The most any counter can differ before we give up
|
||||
* @return ratio of total variance between counters and pattern compared to total pattern size,
|
||||
* where the ratio has been multiplied by 256. So, 0 means no variance (perfect match); 256 means
|
||||
* the total variance between counters and patterns equals the pattern length, higher values mean
|
||||
* even more variance
|
||||
*/
|
||||
protected static function patternMatchVariance(counters:Array, pattern:Array, maxIndividualVariance:int ):int {
|
||||
var numCounters:int = counters.length;
|
||||
var total:int = 0;
|
||||
var patternLength:int = 0;
|
||||
for (var i:int = 0; i < numCounters; i++) {
|
||||
total += counters[i];
|
||||
patternLength += pattern[i];
|
||||
}
|
||||
if (total < patternLength) {
|
||||
// If we don't even have one pixel per unit of bar width, assume this is too small
|
||||
// to reliably match, so fail:
|
||||
return int.MAX_VALUE;
|
||||
}
|
||||
// We're going to fake floating-point math in integers. We just need to use more bits.
|
||||
// Scale up patternLength so that intermediate values below like scaledCounter will have
|
||||
// more "significant digits"
|
||||
var unitBarWidth:int = (total << INTEGER_MATH_SHIFT) / patternLength;
|
||||
maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> INTEGER_MATH_SHIFT;
|
||||
|
||||
var totalVariance:int = 0;
|
||||
for (var x:int = 0; x < numCounters; x++) {
|
||||
var counter:int = counters[x] << INTEGER_MATH_SHIFT;
|
||||
var scaledPattern:int = pattern[x] * unitBarWidth;
|
||||
var variance:int = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter;
|
||||
if (variance > maxIndividualVariance) {
|
||||
return int.MAX_VALUE;
|
||||
}
|
||||
totalVariance += variance;
|
||||
}
|
||||
return totalVariance / total;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Attempts to decode a one-dimensional barcode format given a single row of
|
||||
* an image.</p>
|
||||
*
|
||||
* @param rowNumber row number from top of the row
|
||||
* @param row the black/white pixel data of the row
|
||||
* @param hints decode hints
|
||||
* @return {@link Result} containing encoded string and start/end of barcode
|
||||
* @throws NotFoundException if an error occurs or barcode cannot be found
|
||||
*/;
|
||||
public function decodeRow(rowNumber:Object , row:BitArray , o:Object):Result { return null;}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ package com.google.zxing.oned
|
|||
|
||||
private var ean13Reader:EAN13Reader = new EAN13Reader();
|
||||
|
||||
public function decodeRow(rowNumber:Object, row:BitArray, o:Object):Result
|
||||
public override function decodeRow(rowNumber:Object, row:BitArray, o:Object):Result
|
||||
{
|
||||
if (rowNumber is int)
|
||||
{
|
||||
|
|
71
actionscript/core/src/com/google/zxing/oned/UPCAWriter.as
Normal file
71
actionscript/core/src/com/google/zxing/oned/UPCAWriter.as
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright 2010 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.oned
|
||||
{
|
||||
|
||||
import com.google.zxing.Writer;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
|
||||
/**
|
||||
* This object renders a UPC-A code as a {@link BitMatrix}.
|
||||
*
|
||||
* @author qwandor@google.com (Andrew Walbran)
|
||||
*/
|
||||
public class UPCAWriter implements Writer
|
||||
{
|
||||
|
||||
private var subWriter:EAN13Writer = new EAN13Writer();
|
||||
|
||||
|
||||
public function encode(contents:String, format:BarcodeFormat=null, width:int=0, height:int=0, hints:HashTable=null):Object
|
||||
{
|
||||
if (format != BarcodeFormat.UPC_A)
|
||||
{
|
||||
throw new IllegalArgumentException("Can only encode UPC-A, but got " + format);
|
||||
}
|
||||
return subWriter.encode(preencode(contents), BarcodeFormat.EAN_13, width, height, hints);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a UPC-A code into the equivalent EAN-13 code, and add a check digit if it is not
|
||||
* already present.
|
||||
*/
|
||||
private static function preencode(contents:String):String
|
||||
{
|
||||
var length:int = contents.length;
|
||||
if (length == 11)
|
||||
{
|
||||
// No check digit present, calculate it and add it
|
||||
var sum:int = 0;
|
||||
for (var i:int = 0; i < 11; ++i)
|
||||
{
|
||||
sum += (contents.charCodeAt(i) - ('0' as String).charCodeAt(0)) * (i % 2 == 0 ? 3 : 1);
|
||||
}
|
||||
contents += (1000 - sum) % 10;
|
||||
}
|
||||
else if (length != 12)
|
||||
{
|
||||
throw new IllegalArgumentException(
|
||||
"Requested contents should be 11 or 12 digits long, but got " + contents.length);
|
||||
}
|
||||
return '0' + contents;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* Copyright (C) 2010 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.oned
|
||||
{
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.NotFoundException;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.ResultMetadataType;
|
||||
import com.google.zxing.ResultPoint;
|
||||
import com.google.zxing.common.BitArray;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
|
||||
public class UPCEANExtensionSupport {
|
||||
|
||||
private var EXTENSION_START_PATTERN:Array = [1,1,2];
|
||||
private static var CHECK_DIGIT_ENCODINGS:Array = [
|
||||
0x18, 0x14, 0x12, 0x11, 0x0C, 0x06, 0x03, 0x0A, 0x09, 0x05
|
||||
];
|
||||
|
||||
private var decodeMiddleCounters:Array = new Array(4);
|
||||
private var decodeRowStringBuffer:StringBuilder = new StringBuilder();
|
||||
|
||||
public function decodeRow(rowNumber:int, row:BitArray, rowOffset:int):Result {
|
||||
|
||||
var extensionStartRange:Array = UPCEANReader.findGuardPattern(row, rowOffset, false, EXTENSION_START_PATTERN);
|
||||
|
||||
var result:StringBuilder = decodeRowStringBuffer;
|
||||
result.length = 0;
|
||||
var end:int = decodeMiddle(row, extensionStartRange, result);
|
||||
|
||||
var resultString:String = result.toString();
|
||||
var extensionData:HashTable = parseExtensionString(resultString);
|
||||
|
||||
var extensionResult:Result =
|
||||
new Result(resultString,
|
||||
null,
|
||||
[
|
||||
new ResultPoint((extensionStartRange[0] + extensionStartRange[1]) / 2.0, rowNumber),
|
||||
new ResultPoint( end, rowNumber),
|
||||
],
|
||||
BarcodeFormat.UPC_EAN_EXTENSION);
|
||||
if (extensionData != null) {
|
||||
extensionResult.putAllMetadata(extensionData);
|
||||
}
|
||||
return extensionResult;
|
||||
}
|
||||
|
||||
public function decodeMiddle(row:BitArray, startRange:Array, resultString:StringBuilder):int {
|
||||
var counters:Array = decodeMiddleCounters;
|
||||
counters[0] = 0;
|
||||
counters[1] = 0;
|
||||
counters[2] = 0;
|
||||
counters[3] = 0;
|
||||
var end:int = row.getSize();
|
||||
var rowOffset:int = startRange[1];
|
||||
|
||||
var lgPatternFound:int = 0;
|
||||
|
||||
for (var x:int = 0; x < 5 && rowOffset < end; x++) {
|
||||
var bestMatch:int = UPCEANReader.decodeDigit(row, counters, rowOffset, UPCEANReader.L_AND_G_PATTERNS);
|
||||
resultString.Append((('0' as String).charCodeAt(0) + bestMatch % 10));
|
||||
for (var i:int = 0; i < counters.length; i++) {
|
||||
rowOffset += counters[i];
|
||||
}
|
||||
if (bestMatch >= 10) {
|
||||
lgPatternFound |= 1 << (4 - x);
|
||||
}
|
||||
if (x != 4) {
|
||||
// Read off separator if not last
|
||||
while (rowOffset < end && !row._get(rowOffset)) {
|
||||
rowOffset++;
|
||||
}
|
||||
while (rowOffset < end && row._get(rowOffset)) {
|
||||
rowOffset++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (resultString.length != 5) {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
var checkDigit:int = determineCheckDigit(lgPatternFound);
|
||||
if (extensionChecksum(resultString.toString()) != checkDigit) {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
return rowOffset;
|
||||
}
|
||||
|
||||
private static function extensionChecksum(s:String):int {
|
||||
var length:int = s.length;
|
||||
var sum:int = 0;
|
||||
for (var i:int = length - 2; i >= 0; i -= 2) {
|
||||
sum += s.charAt(i).charCodeAt(0) - ('0' as String).charCodeAt(0);
|
||||
}
|
||||
sum *= 3;
|
||||
for (i = length - 1; i >= 0; i -= 2) {
|
||||
sum += s.charAt(i).charCodeAt(0) - ('0' as String).charCodeAt(0);
|
||||
}
|
||||
sum *= 3;
|
||||
return sum % 10;
|
||||
}
|
||||
|
||||
private static function determineCheckDigit(lgPatternFound:int):int {
|
||||
for (var d:int = 0; d < 10; d++) {
|
||||
if (lgPatternFound == UPCEANExtensionSupport.CHECK_DIGIT_ENCODINGS[d]) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param raw raw content of extension
|
||||
* @return formatted interpretation of raw content as a {@link Hashtable} mapping
|
||||
* one {@link ResultMetadataType} to appropriate value, or <code>null</code> if not known
|
||||
*/
|
||||
private static function parseExtensionString(raw:String):HashTable {
|
||||
var type:ResultMetadataType;
|
||||
var value:Object ;
|
||||
switch (raw.length) {
|
||||
case 2:
|
||||
type = ResultMetadataType.ISSUE_NUMBER;
|
||||
value = parseExtension2String(raw);
|
||||
break;
|
||||
case 5:
|
||||
type = ResultMetadataType.SUGGESTED_PRICE;
|
||||
value = parseExtension5String(raw);
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
var result:HashTable = new HashTable(1);
|
||||
result._put(type, value);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static function parseExtension2String(raw:String):int {
|
||||
return int(raw);
|
||||
}
|
||||
|
||||
private static function parseExtension5String(raw:String):String {
|
||||
var currency:String;
|
||||
switch (raw.charAt(0)) {
|
||||
case '0':
|
||||
currency = "£";
|
||||
break;
|
||||
case '5':
|
||||
currency = "$";
|
||||
break;
|
||||
case '9':
|
||||
// Reference: http://www.jollytech.com
|
||||
if (raw == "90000") {
|
||||
// No suggested retail price
|
||||
return null;
|
||||
} else if (raw == "99991") {
|
||||
// Complementary
|
||||
return "0.00";
|
||||
} else if (raw == "99990") {
|
||||
return "Used";
|
||||
}
|
||||
// Otherwise... unknown currency?
|
||||
currency = "";
|
||||
break;
|
||||
default:
|
||||
currency = "";
|
||||
break;
|
||||
}
|
||||
var rawAmount:int = int(raw.substring(1));
|
||||
var unitsString:String = (Number(rawAmount / 100)).toString();
|
||||
var hundredths:int = rawAmount % 100;
|
||||
var hundredthsString:String = hundredths < 10 ? String.fromCharCode(("0" as String).charCodeAt(0)+ hundredths) : String(hundredths);
|
||||
return currency + unitsString + '.' + hundredthsString;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,35 +1,363 @@
|
|||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.oned
|
||||
{
|
||||
import com.google.zxing.common.BitArray;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.BinaryBitmap;
|
||||
import com.google.zxing.Result;
|
||||
|
||||
public class UPCEANReader extends OneDReader
|
||||
{
|
||||
|
||||
/**
|
||||
* <p>This interfaces captures addtional functionality that readers of
|
||||
* UPC/EAN family of barcodes should expose.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
import com.google.zxing.common.BitArray;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.ReaderException;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.ResultPoint;
|
||||
import com.google.zxing.ResultMetadataType;
|
||||
|
||||
public class UPCEANReader implements OneDReader
|
||||
{
|
||||
|
||||
/**
|
||||
* <p>Like {@link #decodeRow(int, BitArray, java.util.Hashtable)}, but
|
||||
* allows caller to inform method about where the UPC/EAN start pattern is
|
||||
* found. This allows this to be computed once and reused across many implementations.</p>
|
||||
public static var MAX_AVG_VARIANCE:int = int(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42);
|
||||
public static var MAX_INDIVIDUAL_VARIANCE:int = int(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7);
|
||||
|
||||
/**
|
||||
* Start/end guard pattern.
|
||||
*/
|
||||
|
||||
public function decodeRow_Array(rowNumber:int, row:BitArray, startGuardRange:Array):Result
|
||||
{
|
||||
return null;
|
||||
};
|
||||
|
||||
public function decode(image:BinaryBitmap, hints:HashTable=null):Result
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static var START_END_PATTERN:Array = [1, 1, 1];
|
||||
|
||||
/**
|
||||
* Pattern marking the middle of a UPC/EAN pattern, separating the two halves.
|
||||
*/
|
||||
public static var MIDDLE_PATTERN:Array = [1, 1, 1, 1, 1];
|
||||
|
||||
/**
|
||||
* "Odd", or "L" patterns used to encode UPC/EAN digits.
|
||||
*/
|
||||
|
||||
public static var L_PATTERNS:Array = [
|
||||
[3, 2, 1, 1], // 0
|
||||
[2, 2, 2, 1], // 1
|
||||
[2, 1, 2, 2], // 2
|
||||
[1, 4, 1, 1], // 3
|
||||
[1, 1, 3, 2], // 4
|
||||
[1, 2, 3, 1], // 5
|
||||
[1, 1, 1, 4], // 6
|
||||
[1, 3, 1, 2], // 7
|
||||
[1, 2, 1, 3], // 8
|
||||
[3, 1, 1, 2]]; // 9
|
||||
|
||||
|
||||
/**
|
||||
* As above but also including the "even", or "G" patterns used to encode UPC/EAN digits.
|
||||
*/
|
||||
//public static var L_AND_G_PATTERNS:Array = new Array(20);
|
||||
public static var L_AND_G_PATTERNS:Array = [
|
||||
[3, 2, 1, 1], // 0
|
||||
[2, 2, 2, 1], // 1
|
||||
[2, 1, 2, 2], // 2
|
||||
[1, 4, 1, 1], // 3
|
||||
[1, 1, 3, 2], // 4
|
||||
[1, 2, 3, 1], // 5
|
||||
[1, 1, 1, 4], // 6
|
||||
[1, 3, 1, 2], // 7
|
||||
[1, 2, 1, 3], // 8
|
||||
[3, 1, 1, 2], // 9
|
||||
[1, 1, 2, 3], //R0
|
||||
[1, 2, 2, 2], //R1
|
||||
[2, 2, 1, 2], //R2
|
||||
[1, 1, 4, 1], //R3
|
||||
[2, 3, 1, 1], //R4
|
||||
[1, 3, 2, 1], //R5
|
||||
[4, 1, 1, 1], //R6
|
||||
[2, 1, 3, 1], //R7
|
||||
[3, 1, 2, 1], //R8
|
||||
[2, 1, 1, 3], //R9
|
||||
];
|
||||
// create the inverse of the L patterns
|
||||
/* static {
|
||||
L_AND_G_PATTERNS = new int[20][];
|
||||
for (var i:int = 0; i < 10; i++)
|
||||
{
|
||||
L_AND_G_PATTERNS[i] = L_PATTERNS[i];
|
||||
}
|
||||
for (int i = 10; i < 20; i++)
|
||||
{
|
||||
var widths:Array = L_PATTERNS[i - 10];
|
||||
var reversedWidths:Array = new Array(widths.length);
|
||||
for (int j = 0; j < widths.length; j++)
|
||||
{
|
||||
reversedWidths[j] = widths[widths.length - j - 1];
|
||||
}
|
||||
L_AND_G_PATTERNS[i] = reversedWidths;
|
||||
}
|
||||
}
|
||||
*/
|
||||
private var decodeRowStringBuffer:StringBuilder;
|
||||
private var extensionReader:UPCEANExtensionSupport;
|
||||
private var eanManSupport:EANManufacturerOrgSupport;
|
||||
|
||||
public function UPCEANReader():void
|
||||
{
|
||||
decodeRowStringBuffer = new StringBuilder(20);
|
||||
extensionReader = new UPCEANExtensionSupport();
|
||||
eanManSupport = new EANManufacturerOrgSupport();
|
||||
}
|
||||
|
||||
public static function findStartGuardPattern(row:BitArray):Array
|
||||
{
|
||||
var foundStart:Boolean = false;
|
||||
var startRange:Array = null;
|
||||
var nextStart:int = 0;
|
||||
while (!foundStart)
|
||||
{
|
||||
startRange = findGuardPattern(row, nextStart, false, START_END_PATTERN);
|
||||
var start:int = startRange[0];
|
||||
nextStart = startRange[1];
|
||||
// Make sure there is a quiet zone at least as big as the start pattern before the barcode. If
|
||||
// this check would run off the left edge of the image, do not accept this barcode, as it is
|
||||
// very likely to be a false positive.
|
||||
var quietStart:int = start - (nextStart - start);
|
||||
if (quietStart >= 0)
|
||||
{
|
||||
foundStart = row.isRange(quietStart, start, false);
|
||||
}
|
||||
}
|
||||
return startRange;
|
||||
}
|
||||
|
||||
public override function decodeRow(rowNumber:Object, row:BitArray, o:Object):Result
|
||||
{
|
||||
if (o is HashTable){ return decodeRow_HashTable(rowNumber as int,row,o as HashTable); }
|
||||
else if (o is Array) { return decodeRow_Array(rowNumber as int,row,o as Array); }
|
||||
else {throw new Error('AbstractUPCEANReader : decodeRow : unknow type of object');}
|
||||
|
||||
}
|
||||
|
||||
public function decodeRow_HashTable(rowNumber:int, row:BitArray, hints:HashTable):Result
|
||||
{
|
||||
return decodeRow(rowNumber, row, findStartGuardPattern(row));
|
||||
}
|
||||
|
||||
public function decodeRow_Array(rowNumber:int, row:BitArray, startGuardRange:Array):Result
|
||||
{
|
||||
var result:StringBuilder = decodeRowStringBuffer;// empty stringbuilder
|
||||
result.length = 0;
|
||||
var endStart:int = decodeMiddle(row, startGuardRange, result);
|
||||
var endRange:Array = decodeEnd(row, endStart);
|
||||
|
||||
// Make sure there is a quiet zone at least as big as the end pattern after the barcode. The
|
||||
// spec might want more whitespace, but in practice this is the maximum we can count on.
|
||||
var end:int = endRange[1];
|
||||
var quietEnd:int = end + (end - endRange[0]);
|
||||
if (quietEnd >= row.getSize() || !row.isRange(end, quietEnd, false))
|
||||
{
|
||||
throw new ReaderException("AbstractUPCEANReader : decodeRow_Array : ending white space is missing");
|
||||
}
|
||||
|
||||
var resultString:String = result.toString();
|
||||
if (!checkChecksum(resultString)) {
|
||||
throw new ReaderException("AbstractUPCEANReader : decodeRow_Array : checkChecksum failed");
|
||||
}
|
||||
|
||||
var left:Number = (Number) (startGuardRange[1] + startGuardRange[0]) / 2;
|
||||
var right:Number = (Number) (endRange[1] + endRange[0]) / 2;
|
||||
var format:BarcodeFormat = getBarcodeFormat();
|
||||
var decodeResult:Result = new Result(resultString,
|
||||
null, // no natural byte representation for these barcodes
|
||||
[
|
||||
new ResultPoint(left, rowNumber),
|
||||
new ResultPoint(right, rowNumber)],
|
||||
format);
|
||||
|
||||
try {
|
||||
var extensionResult:Result = extensionReader.decodeRow(rowNumber, row, endRange[1]);
|
||||
decodeResult.putAllMetadata(extensionResult.getResultMetadata());
|
||||
decodeResult.addResultPoints(extensionResult.getResultPoints());
|
||||
} catch (re:ReaderException) {
|
||||
// continue
|
||||
}
|
||||
|
||||
if ((format == BarcodeFormat.EAN_13) || (format == BarcodeFormat.UPC_A)) {
|
||||
var countryID:String = eanManSupport.lookupCountryIdentifier(resultString);
|
||||
if (countryID != null) {
|
||||
decodeResult.putMetadata(ResultMetadataType.POSSIBLE_COUNTRY, countryID);
|
||||
}
|
||||
}
|
||||
|
||||
return decodeResult;
|
||||
|
||||
}
|
||||
|
||||
public function getBarcodeFormat():BarcodeFormat
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link #checkStandardUPCEANChecksum(String)}
|
||||
*/
|
||||
public function checkChecksum(s:String):Boolean {
|
||||
return checkStandardUPCEANChecksum(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the UPC/EAN checksum on a string of digits, and reports
|
||||
* whether the checksum is correct or not.
|
||||
*
|
||||
* @param s string of digits to check
|
||||
* @return true iff string of digits passes the UPC/EAN checksum algorithm
|
||||
* @throws ReaderException if the string does not contain only digits
|
||||
*/
|
||||
public static function checkStandardUPCEANChecksum(s:String):Boolean {
|
||||
var length:int = s.length;
|
||||
if (length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var sum:int = 0;
|
||||
for (var i:int = length - 2; i >= 0; i -= 2) {
|
||||
var digit:int = s.charCodeAt(i) - ('0').charCodeAt(0);
|
||||
if (digit < 0 || digit > 9) {
|
||||
throw new ReaderException("AbstractUPCEANReader : checkStandardUPCEANChecksum : digit out of range ("+digit+")");
|
||||
}
|
||||
sum += digit;
|
||||
}
|
||||
sum *= 3;
|
||||
for (var i3:int = length - 1; i3 >= 0; i3 -= 2) {
|
||||
var digit2:int = s.charCodeAt(i3) - ('0').charCodeAt(0);
|
||||
if (digit2 < 0 || digit2 > 9) {
|
||||
throw new ReaderException("AbstractUPCEANReader : checkStandardUPCEANChecksum : digit2 out of range ("+digit2+")");
|
||||
}
|
||||
sum += digit2;
|
||||
}
|
||||
return sum % 10 == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses override this to decode the portion of a barcode between the start and end guard patterns.
|
||||
*
|
||||
* @param row row of black/white values to search
|
||||
* @param startRange start/end offset of start guard pattern
|
||||
* @param resultString {@link StringBuffer} to append decoded chars to
|
||||
* @return horizontal offset of first pixel after the "middle" that was decoded
|
||||
* @throws ReaderException if decoding could not complete successfully
|
||||
*/
|
||||
protected function decodeMiddle(row:BitArray, startRange:Array, resultString:StringBuilder):int{return -1;};
|
||||
|
||||
public function decodeEnd(row:BitArray, endStart:int):Array
|
||||
{
|
||||
return findGuardPattern(row, endStart, false, START_END_PATTERN);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param row row of black/white values to search
|
||||
* @param rowOffset position to start search
|
||||
* @param whiteFirst if true, indicates that the pattern specifies white/black/white/...
|
||||
* pixel counts, otherwise, it is interpreted as black/white/black/...
|
||||
* @param pattern pattern of counts of number of black and white pixels that are being
|
||||
* searched for as a pattern
|
||||
* @return start/end horizontal offset of guard pattern, as an array of two ints
|
||||
* @throws ReaderException if pattern is not found
|
||||
*/
|
||||
public static function findGuardPattern( row:BitArray, rowOffset:int, whiteFirst:Boolean, pattern:Array):Array
|
||||
{
|
||||
var patternLength:int = pattern.length;
|
||||
var counters:Array = new Array(patternLength);
|
||||
for (var i:int=0;i<patternLength;i++) { counters[i] = 0; }
|
||||
var width:int = row.getSize();
|
||||
var isWhite:Boolean = false;
|
||||
while (rowOffset < width) {
|
||||
isWhite = !row._get(rowOffset);
|
||||
if (whiteFirst == isWhite) {
|
||||
break;
|
||||
}
|
||||
rowOffset++;
|
||||
}
|
||||
|
||||
var counterPosition:int = 0;
|
||||
var patternStart:int = rowOffset;
|
||||
for (var x:int = rowOffset; x < width; x++)
|
||||
{
|
||||
var pixel:Boolean = row._get(x);
|
||||
if (pixel != isWhite)
|
||||
{
|
||||
counters[counterPosition] = counters[counterPosition] + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (counterPosition == patternLength - 1)
|
||||
{
|
||||
if (patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE)
|
||||
{
|
||||
return [patternStart, x];
|
||||
}
|
||||
patternStart = patternStart + counters[0] + counters[1];
|
||||
for (var y:int = 2; y < patternLength; y++)
|
||||
{
|
||||
counters[y - 2] = counters[y];
|
||||
}
|
||||
counters[patternLength - 2] = 0;
|
||||
counters[patternLength - 1] = 0;
|
||||
counterPosition--;
|
||||
}
|
||||
else
|
||||
{
|
||||
counterPosition++;
|
||||
}
|
||||
counters[counterPosition] = 1;
|
||||
isWhite = !isWhite;
|
||||
}
|
||||
}
|
||||
throw new ReaderException("AbstractUPCEANReader : findGuardPattern : pattern not found)");
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to decode a single UPC/EAN-encoded digit.
|
||||
*
|
||||
* @param row row of black/white values to decode
|
||||
* @param counters the counts of runs of observed black/white/black/... values
|
||||
* @param rowOffset horizontal offset to start decoding from
|
||||
* @param patterns the set of patterns to use to decode -- sometimes different encodings
|
||||
* for the digits 0-9 are used, and this indicates the encodings for 0 to 9 that should
|
||||
* be used
|
||||
* @return horizontal offset of first pixel beyond the decoded digit
|
||||
* @throws ReaderException if digit cannot be decoded
|
||||
*/
|
||||
public static function decodeDigit(row:BitArray,counters:Array, rowOffset:int, patterns:Array):int
|
||||
{
|
||||
|
||||
recordPattern(row, rowOffset, counters);
|
||||
var bestVariance:int = MAX_AVG_VARIANCE; // worst variance we'll accept
|
||||
var bestMatch:int = -1;
|
||||
var max:int = patterns.length;
|
||||
for (var i:int = 0; i < max; i++)
|
||||
{
|
||||
var pattern:Array = patterns[i];
|
||||
var variance:int = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
if (variance < bestVariance) {
|
||||
bestVariance = variance;
|
||||
bestMatch = i;
|
||||
}
|
||||
}
|
||||
if (bestMatch >= 0) {
|
||||
return bestMatch;
|
||||
} else {
|
||||
throw new ReaderException("AbstractUPCEANReader : decodeDigit : not bestMatch found");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,20 +14,90 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.oned
|
||||
{
|
||||
package com.google.zxing.oned{
|
||||
|
||||
import com.google.zxing.common.ByteMatrix;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.Writer;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.Writer;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* @author Ari Pollak
|
||||
* <p>Encapsulates functionality and implementation that is common to UPC and EAN families
|
||||
* of one-dimensional barcodes.</p>
|
||||
*
|
||||
* @author aripollak@gmail.com (Ari Pollak)
|
||||
*/
|
||||
public interface UPCEANWriter extends Writer
|
||||
public class UPCEANWriter implements Writer
|
||||
{
|
||||
|
||||
/** @return a byte array of horizontal pixels (0 = white, 1 = black) */
|
||||
//function encode(contents:String, format:BarcodeFormat, width:int, height:int, hints:HashTable=undefined):ByteMatrix;
|
||||
|
||||
public function encode(contents:String , format:BarcodeFormat=null, width:int=0, height:int=0, hints:HashTable = null):Object
|
||||
{
|
||||
if (contents == null || contents.length == 0) {
|
||||
throw new IllegalArgumentException("Found empty contents");
|
||||
}
|
||||
|
||||
if (width < 0 || height < 0) {
|
||||
throw new IllegalArgumentException("Requested dimensions are too small: "
|
||||
+ width + 'x' + height);
|
||||
}
|
||||
|
||||
var code:Array = encode(contents) as Array;
|
||||
return renderResult(code, width, height);
|
||||
}
|
||||
|
||||
/** @return a byte array of horizontal pixels (0 = white, 1 = black) */
|
||||
private static function renderResult(code:Array, width:int , height:int ):BitMatrix {
|
||||
var inputWidth:int = code.length;
|
||||
// Add quiet zone on both sides
|
||||
var fullWidth:int = inputWidth + (UPCEANReader.START_END_PATTERN.length << 1);
|
||||
var outputWidth:int = Math.max(width, fullWidth);
|
||||
var outputHeight:int = Math.max(1, height);
|
||||
|
||||
var multiple:int = int(outputWidth / fullWidth);
|
||||
var leftPadding:int = int((outputWidth - (inputWidth * multiple)) / 2);
|
||||
|
||||
var output:BitMatrix = new BitMatrix(outputWidth, outputHeight);
|
||||
var outputX:int = leftPadding;
|
||||
for (var inputX:int = 0; inputX < inputWidth; inputX++, outputX += multiple) {
|
||||
if (code[inputX] == 1)
|
||||
{
|
||||
output.setRegion(outputX, 0, multiple, outputHeight);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Appends the given pattern to the target array starting at pos.
|
||||
*
|
||||
* @param startColor
|
||||
* starting color - 0 for white, 1 for black
|
||||
* @return the number of elements added to target.
|
||||
*/
|
||||
protected static function appendPattern(target:Array, pos:int, pattern:Array, startColor:int):int
|
||||
{
|
||||
if (startColor != 0 && startColor != 1)
|
||||
{
|
||||
throw new IllegalArgumentException(
|
||||
"startColor must be either 0 or 1, but got: " + startColor);
|
||||
}
|
||||
|
||||
var color:int = startColor;
|
||||
var numAdded:int = 0;
|
||||
for (var i:int = 0; i < pattern.length; i++) {
|
||||
for (var j:int = 0; j < pattern[i]; j++) {
|
||||
target[pos] = color;
|
||||
pos += 1;
|
||||
numAdded += 1;
|
||||
}
|
||||
color ^= 1; // flip color after each segment
|
||||
}
|
||||
return numAdded;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,13 +26,17 @@ package com.google.zxing.oned
|
|||
*/
|
||||
|
||||
|
||||
public class UPCEReader extends AbstractUPCEANReader
|
||||
public class UPCEReader extends UPCEANReader
|
||||
{
|
||||
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.BitArray;
|
||||
import com.google.zxing.ReaderException;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.BinaryBitmap;
|
||||
import com.google.zxing.NotFoundException;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -53,6 +57,8 @@ package com.google.zxing.oned
|
|||
|
||||
private var decodeMiddleCounters:Array;
|
||||
|
||||
// function decode(image:BinaryBitmap, hints:HashTable=null):Result { return null; }
|
||||
|
||||
public function UPCEReader() {
|
||||
decodeMiddleCounters = new Array(4);
|
||||
}
|
||||
|
@ -107,7 +113,7 @@ package com.google.zxing.oned
|
|||
throw new ReaderException("UPCEReader : determineNumSysAndCheckDigit : could not determine numsys");
|
||||
}
|
||||
|
||||
public override function getBarcodeFormat():BarcodeFormat {
|
||||
public override function getBarcodeFormat():BarcodeFormat {
|
||||
return BarcodeFormat.UPC_E;
|
||||
}
|
||||
|
||||
|
@ -151,6 +157,40 @@ package com.google.zxing.oned
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Attempts to decode a single UPC/EAN-encoded digit.
|
||||
*
|
||||
* @param row row of black/white values to decode
|
||||
* @param counters the counts of runs of observed black/white/black/... values
|
||||
* @param rowOffset horizontal offset to start decoding from
|
||||
* @param patterns the set of patterns to use to decode -- sometimes different encodings
|
||||
* for the digits 0-9 are used, and this indicates the encodings for 0 to 9 that should
|
||||
* be used
|
||||
* @return horizontal offset of first pixel beyond the decoded digit
|
||||
* @throws NotFoundException if digit cannot be decoded
|
||||
*/
|
||||
public static function decodeDigit(row:BitArray , counters:Array, rowOffset:int,patterns:Array):int {
|
||||
recordPattern(row, rowOffset, counters);
|
||||
var bestVariance:int = MAX_AVG_VARIANCE; // worst variance we'll accept
|
||||
var bestMatch:int = -1;
|
||||
var max:int = patterns.length;
|
||||
for (var i:int = 0; i < max; i++) {
|
||||
var pattern:Array = patterns[i];
|
||||
var variance:int = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
|
||||
if (variance < bestVariance) {
|
||||
bestVariance = variance;
|
||||
bestMatch = i;
|
||||
}
|
||||
}
|
||||
if (bestMatch >= 0) {
|
||||
return bestMatch;
|
||||
} else {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ import com.google.zxing.common.DetectorResult;
|
|||
import com.google.zxing.pdf417.decoder.Decoder;
|
||||
import com.google.zxing.pdf417.detector.Detector;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.NotFoundException;
|
||||
|
||||
public final class PDF417Reader implements Reader {
|
||||
|
||||
|
@ -56,12 +57,16 @@ public final class PDF417Reader implements Reader {
|
|||
}
|
||||
*/
|
||||
|
||||
public function reset():void {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public function decode(image:BinaryBitmap , hints:HashTable=null):Result
|
||||
{
|
||||
var decoderResult:DecoderResult ;
|
||||
var points:Array ;
|
||||
if (hints != null && hints.ContainsKey(DecodeHintType.PURE_BARCODE)) {
|
||||
var bits:BitMatrix = extractPureBits(image);
|
||||
var bits:BitMatrix = extractPureBits(image.getBlackMatrix());
|
||||
decoderResult = decoder.decode(bits);
|
||||
points = NO_POINTS;
|
||||
} else {
|
||||
|
@ -69,9 +74,10 @@ public final class PDF417Reader implements Reader {
|
|||
decoderResult = decoder.decode(detectorResult.getBits());
|
||||
points = detectorResult.getPoints();
|
||||
}
|
||||
return new Result(decoderResult.getText(), decoderResult.getRawBytes(), points,
|
||||
BarcodeFormat.PDF417);
|
||||
return new Result(decoderResult.getText(), decoderResult.getRawBytes(), points,BarcodeFormat.PDF417,0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This method detects a barcode in a "pure" image -- that is, pure monochrome image
|
||||
|
@ -79,70 +85,112 @@ public final class PDF417Reader implements Reader {
|
|||
* around it. This is a specialized method that works exceptionally fast in this special
|
||||
* case.
|
||||
*/
|
||||
private static function extractPureBits(image:BinaryBitmap ):BitMatrix {
|
||||
// Now need to determine module size in pixels
|
||||
var matrix:BitMatrix = image.getBlackMatrix();
|
||||
var height:int = matrix.getHeight();
|
||||
var width:int = matrix.getWidth();
|
||||
var minDimension:int = Math.min(height, width);
|
||||
private static function extractPureBits(image:BitMatrix):BitMatrix {
|
||||
|
||||
// First, skip white border by tracking diagonally from the top left down and to the right:
|
||||
var borderWidth:int = 0;
|
||||
while (borderWidth < minDimension && !matrix._get(borderWidth, borderWidth)) {
|
||||
borderWidth++;
|
||||
}
|
||||
if (borderWidth == minDimension) {
|
||||
throw new ReaderException("PDF417Reader : extractPureBits");
|
||||
var leftTopBlack:Array = image.getTopLeftOnBit();
|
||||
var rightBottomBlack:Array = image.getBottomRightOnBit();
|
||||
if (leftTopBlack == null || rightBottomBlack == null) {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
// And then keep tracking across the top-left black module to determine module size
|
||||
var moduleEnd:int = borderWidth;
|
||||
while (moduleEnd < minDimension && matrix._get(moduleEnd, moduleEnd)) {
|
||||
moduleEnd++;
|
||||
}
|
||||
if (moduleEnd == minDimension) {
|
||||
throw new ReaderException("PDF417Reader : extractPureBits");
|
||||
}
|
||||
var moduleSize:int = moduleSize(leftTopBlack, image);
|
||||
|
||||
var moduleSize:int = moduleEnd - borderWidth;
|
||||
var top:int = leftTopBlack[1];
|
||||
var bottom:int = rightBottomBlack[1];
|
||||
var left:int = findPatternStart(leftTopBlack[0], top, image);
|
||||
var right:int = findPatternEnd(leftTopBlack[0], top, image);
|
||||
|
||||
// And now find where the rightmost black module on the first row ends
|
||||
var rowEndOfSymbol:int = width - 1;
|
||||
while (rowEndOfSymbol >= 0 && !matrix._get(rowEndOfSymbol, borderWidth)) {
|
||||
rowEndOfSymbol--;
|
||||
var matrixWidth:int = (right - left + 1) / moduleSize;
|
||||
var matrixHeight:int = (bottom - top + 1) / moduleSize;
|
||||
if (matrixWidth <= 0 || matrixHeight <= 0) {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
if (rowEndOfSymbol < 0) {
|
||||
throw new ReaderException("PDF417Reader : extractPureBits");
|
||||
}
|
||||
rowEndOfSymbol++;
|
||||
|
||||
// Make sure width of barcode is a multiple of module size
|
||||
if ((rowEndOfSymbol - borderWidth) % moduleSize != 0) {
|
||||
throw new ReaderException("PDF417Reader : extractPureBits");
|
||||
}
|
||||
var dimension:int = (rowEndOfSymbol - borderWidth) / moduleSize;
|
||||
|
||||
// Push in the "border" by half the module width so that we start
|
||||
// sampling in the middle of the module. Just in case the image is a
|
||||
// little off, this will help recover.
|
||||
borderWidth += moduleSize >> 1;
|
||||
|
||||
var sampleDimension:int = borderWidth + (dimension - 1) * moduleSize;
|
||||
if (sampleDimension >= width || sampleDimension >= height) {
|
||||
throw new ReaderException("PDF417Reader : extractPureBits");
|
||||
}
|
||||
var nudge:int = moduleSize >> 1;
|
||||
top += nudge;
|
||||
left += nudge;
|
||||
|
||||
// Now just read off the bits
|
||||
var bits:BitMatrix = new BitMatrix(dimension);
|
||||
for (var y:int = 0; y < dimension; y++) {
|
||||
var iOffset:int = borderWidth + y * moduleSize;
|
||||
for (var x:int = 0; x < dimension; x++) {
|
||||
if (matrix._get(borderWidth + x * moduleSize, iOffset)) {
|
||||
var bits:BitMatrix = new BitMatrix(matrixWidth, matrixHeight);
|
||||
for (var y:int = 0; y < matrixHeight; y++) {
|
||||
var iOffset:int = top + y * moduleSize;
|
||||
for (var x:int = 0; x < matrixWidth; x++) {
|
||||
if (image._get(left + x * moduleSize, iOffset)) {
|
||||
bits._set(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
private static function moduleSize(leftTopBlack:Array , image:BitMatrix ):int
|
||||
{
|
||||
var x:int = leftTopBlack[0];
|
||||
var y:int = leftTopBlack[1];
|
||||
var width:int = image.getWidth();
|
||||
while (x < width && image._get(x, y)) {
|
||||
x++;
|
||||
}
|
||||
if (x == width) {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
var moduleSize:int = (x - leftTopBlack[0]) >>> 3; // We've crossed left first bar, which is 8x
|
||||
if (moduleSize == 0) {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
return moduleSize;
|
||||
}
|
||||
|
||||
private static function findPatternStart(x:int, y:int, image:BitMatrix):int {
|
||||
var width:int = image.getWidth();
|
||||
var start:int = x;
|
||||
// start should be on black
|
||||
var transitions:int = 0;
|
||||
var black:Boolean = true;
|
||||
while (start < width - 1 && transitions < 8) {
|
||||
start++;
|
||||
var newBlack:Boolean = image._get(start, y);
|
||||
if (black != newBlack) {
|
||||
transitions++;
|
||||
}
|
||||
black = newBlack;
|
||||
}
|
||||
if (start == width - 1) {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
private static function findPatternEnd(x:int, y:int, image:BitMatrix):int {
|
||||
var width:int = image.getWidth();
|
||||
var end:int = width - 1;
|
||||
// end should be on black
|
||||
while (end > x && !image._get(end, y)) {
|
||||
end--;
|
||||
}
|
||||
var transitions:int = 0;
|
||||
var black:Boolean = true;
|
||||
while (end > x && transitions < 9) {
|
||||
end--;
|
||||
var newBlack:Boolean = image._get(end, y);
|
||||
if (black != newBlack) {
|
||||
transitions++;
|
||||
}
|
||||
black = newBlack;
|
||||
}
|
||||
if (end == x) {
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -62,28 +62,21 @@ import com.google.zxing.common.BitMatrix;
|
|||
*/
|
||||
public function readCodewords():Array
|
||||
{
|
||||
var width:int = bitMatrix.getDimension();
|
||||
// TODO should be a rectangular matrix
|
||||
var height:int = width;
|
||||
|
||||
erasures = new Array(MAX_CW_CAPACITY);
|
||||
for (var k:int=0;k<erasures.length;k++) { erasures[k]=0; }
|
||||
var width:int = bitMatrix.getWidth();
|
||||
var height:int = bitMatrix.getHeight();
|
||||
|
||||
erasures = new Array(MAX_CW_CAPACITY);for (var k:int=0;k<erasures.length;k++) { erasures[k]=0; }
|
||||
|
||||
// Get the number of pixels in a module across the X dimension
|
||||
//float moduleWidth = bitMatrix.getModuleWidth();
|
||||
var moduleWidth:Number = 1.0; // Image has been sampled and reduced
|
||||
|
||||
var rowCounters:Array = new Array(width);
|
||||
for (var n:int=0;n<rowCounters.length;n++) { rowCounters[n] = 0;}
|
||||
var codewords:Array = new Array(MAX_CW_CAPACITY);
|
||||
for(var m:int=0;m<codewords.length;m++){codewords[m]=0;}
|
||||
|
||||
var rowCounters:Array = new Array(width);for (var n:int=0;n<rowCounters.length;n++) { rowCounters[n] = 0;}
|
||||
var codewords:Array = new Array(MAX_CW_CAPACITY);for(var m:int=0;m<codewords.length;m++){codewords[m]=0;}
|
||||
var next:int = 0;
|
||||
var matchingConsecutiveScans:int = 0;
|
||||
var rowInProgress:Boolean = false;
|
||||
var rowNumber:int = 0;
|
||||
var rowHeight:int = 0;
|
||||
|
||||
var rowHeight:int = 0;
|
||||
for (var i:int = 1; i < height; i++) {
|
||||
if (rowNumber >= MAX_ROWS) {
|
||||
// Something is wrong, since we have exceeded
|
||||
|
@ -193,7 +186,7 @@ import com.google.zxing.common.BitMatrix;
|
|||
* this row.
|
||||
*/
|
||||
public function processRow(rowCounters:Array, rowNumber:int, rowHeight:int, codewords:Array, next:int):int {
|
||||
var width:int = bitMatrix.getDimension();
|
||||
var width:int = bitMatrix.getWidth();
|
||||
var columnNumber:int = 0;
|
||||
var symbol:Number = 0;
|
||||
for (var i:int = 0; i < width; i += MODULES_IN_SYMBOL)
|
||||
|
@ -263,7 +256,7 @@ import com.google.zxing.common.BitMatrix;
|
|||
if (rightColumnECData == leftColumnECData
|
||||
&& leftColumnECData != 0)
|
||||
{
|
||||
ecLevel = ((rightColumnECData % 30) - rows % 3) / 3;
|
||||
ecLevel = int(((rightColumnECData % 30) - rows % 3) / 3);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -386,158 +379,7 @@ import com.google.zxing.common.BitMatrix;
|
|||
return ecLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the symbols in the row to codewords.
|
||||
* Each PDF417 symbol character consists of four bar elements and four space
|
||||
* elements, each of which can be one to six modules wide. The four bar and
|
||||
* four space elements shall measure 17 modules in total.
|
||||
*
|
||||
* @param rowCounters an array containing the counts of black pixels for each column
|
||||
* in the row.
|
||||
* @param rowNumber the current row number of codewords.
|
||||
* @param rowHeight the height of this row in pixels.
|
||||
* @param moduleWidth the size of a module in pixels.
|
||||
* @param codewords the codeword array to save codewords into.
|
||||
* @param next the next available index into the codewords array.
|
||||
* @return the next available index into the codeword array after processing
|
||||
* this row.
|
||||
* @throws ReaderException
|
||||
*/
|
||||
/*
|
||||
int processRow1(int[] rowCounters, int rowNumber, int rowHeight,
|
||||
float moduleWidth, int[] codewords, int next) {
|
||||
int width = bitMatrix.getDimension();
|
||||
int firstBlack = 0;
|
||||
|
||||
for (firstBlack = 0; firstBlack < width; firstBlack++) {
|
||||
// Step forward until we find the first black pixels
|
||||
if (rowCounters[firstBlack] >= rowHeight >>> 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int[] counters = new int[8];
|
||||
int state = 0; // In black pixels, looking for white, first or second time
|
||||
long symbol = 0;
|
||||
int columnNumber = 0;
|
||||
for (int i = firstBlack; i < width; i++) {
|
||||
if (state == 1 || state == 3 || state == 5 || state == 7) { // In white
|
||||
// pixels,
|
||||
// looking
|
||||
// for
|
||||
// black
|
||||
// If more than half the column is black
|
||||
if (rowCounters[i] >= rowHeight >>> 1 || i == width - 1) {
|
||||
if (i == width - 1) {
|
||||
counters[state]++;
|
||||
}
|
||||
// In black pixels or the end of a row
|
||||
state++;
|
||||
if (state < 8) {
|
||||
// Don't count the last one
|
||||
counters[state]++;
|
||||
}
|
||||
} else {
|
||||
counters[state]++;
|
||||
}
|
||||
} else {
|
||||
if (rowCounters[i] < rowHeight >>> 1) {
|
||||
// Found white pixels
|
||||
state++;
|
||||
if (state == 7 && i == width - 1) {
|
||||
// Its found white pixels at the end of the row,
|
||||
// give it a chance to exit gracefully
|
||||
i--;
|
||||
} else {
|
||||
// Found white pixels
|
||||
counters[state]++;
|
||||
}
|
||||
} else {
|
||||
if (state < 8) {
|
||||
// Still in black pixels
|
||||
counters[state]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (state == 8) { // Found black, white, black, white, black, white,
|
||||
// black, white and stumbled back onto black; done
|
||||
if (columnNumber >= MAX_COLUMNS) {
|
||||
// Something is wrong, since we have exceeded
|
||||
// the maximum columns in the specification.
|
||||
// TODO Maybe return error code
|
||||
return -1;
|
||||
}
|
||||
if (columnNumber > 0) {
|
||||
symbol = getSymbol(counters, moduleWidth);
|
||||
int cw = getCodeword(symbol);
|
||||
// if (debug) System.out.println(" " +
|
||||
// Long.toBinaryString(symbol) + " cw=" +cw + " ColumnNumber="
|
||||
// +columnNumber + "i=" +i);
|
||||
if (cw < 0) {
|
||||
erasures[eraseCount] = next;
|
||||
next++;
|
||||
eraseCount++;
|
||||
} else {
|
||||
codewords[next++] = cw;
|
||||
}
|
||||
} else {
|
||||
// Left row indicator column
|
||||
symbol = getSymbol(counters, moduleWidth);
|
||||
int cw = getCodeword(symbol);
|
||||
if (ecLevel < 0) {
|
||||
switch (rowNumber % 3) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
leftColumnECData = cw;
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Step back so that this pixel can be examined during the next
|
||||
// pass.
|
||||
i--;
|
||||
counters = new int[8];
|
||||
columns = columnNumber;
|
||||
columnNumber++;
|
||||
// Introduce some errors if (rowNumber == 0 && columnNumber == 4)
|
||||
// { codewords[next-1] = 0; erasures[eraseCount] = next-1;
|
||||
// eraseCount++; } if (rowNumber == 0 && columnNumber == 6) {
|
||||
// codewords[next-1] = 10; erasures[eraseCount] = next-1;
|
||||
// eraseCount++; } if (rowNumber == 0 && columnNumber == 8) {
|
||||
// codewords[next-1] = 10; erasures[eraseCount] = next-1;
|
||||
// eraseCount++; }
|
||||
state = 0;
|
||||
symbol = 0;
|
||||
}
|
||||
}
|
||||
if (columnNumber > 1) {
|
||||
// Right row indicator column is in codeword[next]
|
||||
columns--;
|
||||
// Overwrite the last codeword i.e. Right Row Indicator
|
||||
--next;
|
||||
if (ecLevel < 0) {
|
||||
switch (rowNumber % 3) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
rightColumnECData = codewords[next];
|
||||
if (rightColumnECData == leftColumnECData
|
||||
&& leftColumnECData != 0) {
|
||||
ecLevel = ((rightColumnECData % 30) - rows % 3) / 3;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
codewords[next] = 0;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* The sorted table of all possible symbols. Extracted from the PDF417
|
||||
|
|
|
@ -23,7 +23,7 @@ package com.google.zxing.pdf417.decoder
|
|||
*
|
||||
* @author SITA Lab (kevin.osullivan@sita.aero)
|
||||
*/
|
||||
public final class DecodedBitStreamParser {
|
||||
public class DecodedBitStreamParser {
|
||||
|
||||
import com.google.zxing.ReaderException;
|
||||
import com.google.zxing.common.DecoderResult;
|
||||
|
@ -43,7 +43,9 @@ import com.google.zxing.common.flexdatatypes.StringBuilder;
|
|||
private static var LOWER:int = 1;
|
||||
private static var MIXED:int = 2;
|
||||
private static var PUNCT:int = 3;
|
||||
private static var PUNCT_SHIFT:int = 4;
|
||||
private static var ALPHA_SHIFT:int = 4;
|
||||
private static var PUNCT_SHIFT:int = 5;
|
||||
|
||||
|
||||
private static var PL:int = 25;
|
||||
private static var LL:int = 27;
|
||||
|
@ -55,7 +57,7 @@ import com.google.zxing.common.flexdatatypes.StringBuilder;
|
|||
|
||||
private static var PUNCT_CHARS:Array = [';', '<', '>', '@', '[', String.fromCharCode(92), '}', '_', String.fromCharCode(96), '~', '!',
|
||||
String.fromCharCode(13), String.fromCharCode(9), ',', ':', String.fromCharCode(10), '-', '.', '$', '/', String.fromCharCode(34), '|', '*',
|
||||
'(', ')', '?', '{', '}', 39];
|
||||
'(', ')', '?', '{', '}', String.fromCharCode(39)];
|
||||
|
||||
private static var MIXED_CHARS:Array = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '&',
|
||||
String.fromCharCode(13), String.fromCharCode(9), ',', ':', '#', '-', '.', '$', '/', '+', '%', '*',
|
||||
|
@ -150,14 +152,13 @@ import com.google.zxing.common.flexdatatypes.StringBuilder;
|
|||
for (var k:int=0;k<textCompactionData.length;k++) { textCompactionData[k]=0;byteCompactionData[k]=0;}
|
||||
|
||||
var index:int = 0;
|
||||
var code:int = 0;
|
||||
var end:Boolean = false;
|
||||
while ((codeIndex < codewords[0]) && !end)
|
||||
{
|
||||
code = codewords[codeIndex++];
|
||||
var code:int = codewords[codeIndex++];
|
||||
if (code < TEXT_COMPACTION_MODE_LATCH)
|
||||
{
|
||||
textCompactionData[index] = Math.floor(code / 30);
|
||||
textCompactionData[index] = int(code / 30);
|
||||
textCompactionData[index + 1] = code % 30;
|
||||
index += 2;
|
||||
}
|
||||
|
@ -188,6 +189,7 @@ import com.google.zxing.common.flexdatatypes.StringBuilder;
|
|||
// of the Text Compaction mode. Codeword 913 is only available
|
||||
// in Text Compaction mode; its use is described in 5.4.2.4.
|
||||
textCompactionData[index] = MODE_SHIFT_TO_BYTE_COMPACTION_MODE;
|
||||
code = codewords[codeIndex++];
|
||||
byteCompactionData[index] = code; //Integer.toHexString(code);
|
||||
index++;
|
||||
break;
|
||||
|
@ -264,8 +266,9 @@ import com.google.zxing.common.flexdatatypes.StringBuilder;
|
|||
} else {
|
||||
if (subModeCh == 26) {
|
||||
ch = ' ';
|
||||
} else if (subModeCh == AL) {
|
||||
subMode = ALPHA;
|
||||
} else if (subModeCh == AS) {
|
||||
priorToShiftMode = subMode;
|
||||
subMode = ALPHA_SHIFT;
|
||||
} else if (subModeCh == ML) {
|
||||
subMode = MIXED;
|
||||
} else if (subModeCh == PS) {
|
||||
|
@ -287,8 +290,8 @@ import com.google.zxing.common.flexdatatypes.StringBuilder;
|
|||
subMode = PUNCT;
|
||||
} else if (subModeCh == 26) {
|
||||
ch = ' ';
|
||||
} else if (subModeCh == AS) {
|
||||
//mode_change = true;
|
||||
} else if (subModeCh == LL) {
|
||||
subMode = LOWER;
|
||||
} else if (subModeCh == AL) {
|
||||
subMode = ALPHA;
|
||||
} else if (subModeCh == PS) {
|
||||
|
@ -303,7 +306,7 @@ import com.google.zxing.common.flexdatatypes.StringBuilder;
|
|||
|
||||
case PUNCT:
|
||||
// Punctuation
|
||||
if (subModeCh < PS) {
|
||||
if (subModeCh < PAL) {
|
||||
ch = PUNCT_CHARS[subModeCh];
|
||||
} else {
|
||||
if (subModeCh == PAL) {
|
||||
|
@ -314,10 +317,24 @@ import com.google.zxing.common.flexdatatypes.StringBuilder;
|
|||
}
|
||||
break;
|
||||
|
||||
case ALPHA_SHIFT:
|
||||
// Restore sub-mode
|
||||
subMode = priorToShiftMode;
|
||||
if (subModeCh < 26) {
|
||||
ch = String.fromCharCode(String('A').charCodeAt(0) + subModeCh);
|
||||
} else {
|
||||
if (subModeCh == 26) {
|
||||
ch = ' ';
|
||||
} else {
|
||||
// is this even possible?
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PUNCT_SHIFT:
|
||||
// Restore sub-mode
|
||||
subMode = priorToShiftMode;
|
||||
if (subModeCh < PS) {
|
||||
if (subModeCh < PAL) {
|
||||
ch = PUNCT_CHARS[subModeCh];
|
||||
} else {
|
||||
if (subModeCh == PAL) {
|
||||
|
@ -326,6 +343,7 @@ import com.google.zxing.common.flexdatatypes.StringBuilder;
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ((ch).charCodeAt(0) != 0) {
|
||||
// Append decoded character to result
|
||||
result.Append(ch);
|
||||
|
@ -349,7 +367,6 @@ import com.google.zxing.common.flexdatatypes.StringBuilder;
|
|||
{
|
||||
var count:int;
|
||||
var value:Number;
|
||||
var code:int;
|
||||
var end:Boolean;
|
||||
|
||||
if (mode == BYTE_COMPACTION_MODE_LATCH) {
|
||||
|
@ -358,20 +375,17 @@ import com.google.zxing.common.flexdatatypes.StringBuilder;
|
|||
count = 0;
|
||||
value = 0;
|
||||
var decodedData:Array = new Array(6);
|
||||
var byteCompactedCodewords:Array = new Array(6);
|
||||
for (var k:int=0;k<6;k++) { decodedData[k]=0;byteCompactedCodewords[k]=0;}
|
||||
code = 0;
|
||||
var byteCompactedCodewords:Array = new Array(6);for (var k:int=0;k<6;k++) { decodedData[k]=0;byteCompactedCodewords[k]=0;}
|
||||
end = false;
|
||||
while ((codeIndex < codewords[0]) && !end)
|
||||
{
|
||||
code = codewords[codeIndex++];
|
||||
var code:int = codewords[codeIndex++];
|
||||
if (code < TEXT_COMPACTION_MODE_LATCH)
|
||||
{
|
||||
byteCompactedCodewords[count] = String.fromCharCode(code);
|
||||
count++;
|
||||
// Base 900
|
||||
value = value * 900;
|
||||
value = value + code;
|
||||
value = value * 900 + code;
|
||||
} else {
|
||||
if ((code == TEXT_COMPACTION_MODE_LATCH) ||
|
||||
(code == BYTE_COMPACTION_MODE_LATCH) ||
|
||||
|
@ -401,7 +415,7 @@ import com.google.zxing.common.flexdatatypes.StringBuilder;
|
|||
// If Byte Compaction mode is invoked with codeword 901,
|
||||
// the group of codewords is interpreted directly
|
||||
// as one byte per codeword, without compaction.
|
||||
for (var i:int = (Math.floor(count / 5) * 5); i < count; i++)
|
||||
for (var i:int = (int(count / 5) * 5); i < count; i++)
|
||||
{
|
||||
result.Append( byteCompactedCodewords[i]);
|
||||
}
|
||||
|
@ -421,8 +435,7 @@ import com.google.zxing.common.flexdatatypes.StringBuilder;
|
|||
if (code < TEXT_COMPACTION_MODE_LATCH) {
|
||||
count += 1;
|
||||
// Base 900
|
||||
value *= 900;
|
||||
value += code;
|
||||
value = value * 900 + code;
|
||||
} else {
|
||||
if ((code == TEXT_COMPACTION_MODE_LATCH) ||
|
||||
(code == BYTE_COMPACTION_MODE_LATCH) ||
|
||||
|
@ -439,12 +452,11 @@ import com.google.zxing.common.flexdatatypes.StringBuilder;
|
|||
{
|
||||
// Decode every 5 codewords
|
||||
// Convert to Base 256
|
||||
var decodedData2:Array = new Array(6);
|
||||
for (var kk:int=0;kk<decodedData2.length;kk++) { decodedData2[kk] = 0; }
|
||||
var decodedData2:Array = new Array(6); for (var kk:int=0;kk<decodedData2.length;kk++) { decodedData2[kk] = 0; }
|
||||
for (var j2:int = 0; j2 < 6; ++j2) {
|
||||
var chcode2:int = value - Math.floor(value / 256) * 256; // BAS : Actionscript can't handle modulo for values > int.MAX_VALUE
|
||||
decodedData2[5 - j2] = String.fromCharCode(chcode2);// BAS : Actionscript can't handle modulo for values > int.MAX_VALUE
|
||||
value = Math.floor(value / 256);
|
||||
value >>= 8;
|
||||
}
|
||||
result.Append(decodedData2);
|
||||
}
|
||||
|
@ -465,8 +477,7 @@ import com.google.zxing.common.flexdatatypes.StringBuilder;
|
|||
var count:int = 0;
|
||||
var end:Boolean = false;
|
||||
|
||||
var numericCodewords:Array = new Array(MAX_NUMERIC_CODEWORDS);
|
||||
for (var kk:int=0;kk<numericCodewords.length;kk++) { numericCodewords[kk] = 0; }
|
||||
var numericCodewords:Array = new Array(MAX_NUMERIC_CODEWORDS);for (var kk:int=0;kk<numericCodewords.length;kk++) { numericCodewords[kk] = 0; }
|
||||
|
||||
while ((codeIndex < codewords.length) && !end) {
|
||||
var code:int = codewords[codeIndex++];
|
||||
|
@ -587,9 +598,9 @@ import com.google.zxing.common.flexdatatypes.StringBuilder;
|
|||
// Put zeros into the result.
|
||||
result.Append('0');
|
||||
}
|
||||
var hundreds:int = value2 / 100;
|
||||
var tens:int = (value2 / 10) % 10;
|
||||
var ones:int = value2 % 10;
|
||||
var hundreds:int = int(value2 / 100);
|
||||
var tens:int = int(int(value2 / 10) % 10);
|
||||
var ones:int = int(value2 % 10);
|
||||
// Multiply by ones
|
||||
for (var j:int = 0; j < ones; j++) {
|
||||
result = add(result.toString(), value1);
|
||||
|
@ -636,32 +647,17 @@ import com.google.zxing.common.flexdatatypes.StringBuilder;
|
|||
var intValue1:int = parseInt(temp1.toString());
|
||||
var intValue2:int = parseInt(temp2.toString());
|
||||
|
||||
var sumval:int = (intValue1 + intValue2 + carry) % 1000;
|
||||
carry = (intValue1 + intValue2 + carry) / 1000;
|
||||
var sumval:int = int((intValue1 + intValue2 + carry) % 1000);
|
||||
carry = int((intValue1 + intValue2 + carry) / 1000);
|
||||
|
||||
result.setCharAt(i + 2, String.fromCharCode( ((sumval % 10) + ('0').charCodeAt(0))));
|
||||
result.setCharAt(i + 1, String.fromCharCode( (((sumval / 10) % 10) + ('0').charCodeAt(0))));
|
||||
result.setCharAt(i, String.fromCharCode( ((sumval / 100) + ('0').charCodeAt(0))));
|
||||
result.setCharAt(i + 2, String.fromCharCode( (int(sumval % 10) + 0x30)));
|
||||
result.setCharAt(i + 1, String.fromCharCode( (int(int(sumval / 10) % 10) + 0x30)));
|
||||
result.setCharAt(i, String.fromCharCode( (int(sumval / 100) + 0x30)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
private static String decodeBase900toBase10(int codewords[], int count) {
|
||||
BigInteger accum = BigInteger.valueOf(0);
|
||||
BigInteger value = null;
|
||||
for (int i = 0; i < count; i++) {
|
||||
value = BigInteger.valueOf(900).pow(count - i - 1);
|
||||
value = value.multiply(BigInteger.valueOf(codewords[i]));
|
||||
accum = accum.add(value);
|
||||
}
|
||||
if (debug) System.out.println("Big Integer " + accum);
|
||||
String result = accum.toString().substring(1);
|
||||
return result;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -93,7 +93,11 @@ import com.google.zxing.common.flexdatatypes.HashTable;
|
|||
correctCodeWordVertices(vertices, false);
|
||||
}
|
||||
|
||||
if (vertices != null) {
|
||||
if (vertices == null)
|
||||
{
|
||||
throw new ReaderException("pdf417 : Detector : detect : no vertices");
|
||||
}
|
||||
|
||||
var moduleWidth:Number = computeModuleWidth(vertices);
|
||||
if (moduleWidth < 1) {
|
||||
throw new ReaderException("pdf417 : Detector : detect : module width < 1");
|
||||
|
@ -104,9 +108,7 @@ import com.google.zxing.common.flexdatatypes.HashTable;
|
|||
// Deskew and sample image.
|
||||
var bits:BitMatrix = sampleGrid(matrix, vertices[4], vertices[5],vertices[6], vertices[7], dimension);
|
||||
return new DetectorResult(bits, [vertices[4],vertices[5], vertices[6], vertices[7]]);
|
||||
} else {
|
||||
throw new ReaderException("pdf417 : Detector : detect : no vertices");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -132,13 +134,13 @@ import com.google.zxing.common.flexdatatypes.HashTable;
|
|||
var width:int = matrix.getWidth();
|
||||
var halfWidth:int = width >> 1;
|
||||
|
||||
var result:Array = new Array(8);
|
||||
var result:Array = new Array(8); for(var kk:int=0;kk<result.length;kk++){result[kk]=0;}
|
||||
var found:Boolean = false;
|
||||
|
||||
var loc:Array = null;
|
||||
// Top Left
|
||||
for (var i:int = 0; i < height; i++) {
|
||||
loc = findGuardPattern(matrix, 0, i, halfWidth, false, START_PATTERN);
|
||||
loc = findGuardPattern(matrix, 0, i, width, false, START_PATTERN);
|
||||
if (loc != null) {
|
||||
result[0] = new ResultPoint(loc[0], i);
|
||||
result[4] = new ResultPoint(loc[1], i);
|
||||
|
@ -150,7 +152,7 @@ import com.google.zxing.common.flexdatatypes.HashTable;
|
|||
if (found) { // Found the Top Left vertex
|
||||
found = false;
|
||||
for (var i2:int = height - 1; i2 > 0; i2--) {
|
||||
loc = findGuardPattern(matrix, 0, i2, halfWidth, false, START_PATTERN);
|
||||
loc = findGuardPattern(matrix, 0, i2, width, false, START_PATTERN);
|
||||
if (loc != null) {
|
||||
result[1] = new ResultPoint(loc[0], i2);
|
||||
result[5] = new ResultPoint(loc[1], i2);
|
||||
|
@ -163,7 +165,7 @@ import com.google.zxing.common.flexdatatypes.HashTable;
|
|||
if (found) { // Found the Bottom Left vertex
|
||||
found = false;
|
||||
for (var i3:int = 0; i3 < height; i3++) {
|
||||
loc = findGuardPattern(matrix, halfWidth, i3, halfWidth, false, STOP_PATTERN);
|
||||
loc = findGuardPattern(matrix, 0, i3, width, false, STOP_PATTERN);
|
||||
if (loc != null) {
|
||||
result[2] = new ResultPoint(loc[1], i3);
|
||||
result[6] = new ResultPoint(loc[0], i3);
|
||||
|
@ -176,7 +178,7 @@ import com.google.zxing.common.flexdatatypes.HashTable;
|
|||
if (found) { // Found the Top right vertex
|
||||
found = false;
|
||||
for (var i4:int = height - 1; i4 > 0; i4--) {
|
||||
loc = findGuardPattern(matrix, halfWidth, i4, halfWidth, false, STOP_PATTERN);
|
||||
loc = findGuardPattern(matrix, 0, i4, width, false, STOP_PATTERN);
|
||||
if (loc != null) {
|
||||
result[3] = new ResultPoint(loc[1], i4);
|
||||
result[7] = new ResultPoint(loc[0], i4);
|
||||
|
@ -212,7 +214,7 @@ import com.google.zxing.common.flexdatatypes.HashTable;
|
|||
var width:int = matrix.getWidth();
|
||||
var halfWidth:int = width >> 1;
|
||||
|
||||
var result:Array = new Array(8);
|
||||
var result:Array = new Array(8);for(var kk:int=0;kk<result.length;kk++){result[kk]=0;}
|
||||
var found:Boolean = false;
|
||||
|
||||
var loc:Array = null;
|
||||
|
@ -361,9 +363,9 @@ import com.google.zxing.common.flexdatatypes.HashTable;
|
|||
*/
|
||||
private static function computeDimension(topLeft:ResultPoint, topRight:ResultPoint,bottomLeft:ResultPoint, bottomRight:ResultPoint, moduleWidth:Number):int
|
||||
{
|
||||
var topRowDimension:int = Math.floor((ResultPoint.distance(topLeft, topRight) / moduleWidth));
|
||||
var bottomRowDimension:int = Math.floor(ResultPoint.distance(bottomLeft, bottomRight) / moduleWidth);
|
||||
return Math.floor((((topRowDimension + bottomRowDimension) >> 1) + 8) / 17) * 17;
|
||||
var topRowDimension:int = Math.round((ResultPoint.distance(topLeft, topRight) / moduleWidth));
|
||||
var bottomRowDimension:int = Math.round(ResultPoint.distance(bottomLeft, bottomRight) / moduleWidth);
|
||||
return int((((topRowDimension + bottomRowDimension) >> 1) + 8) / 17) * 17;
|
||||
/*
|
||||
* int topRowDimension = round(ResultPoint.distance(topLeft,
|
||||
* topRight)); //moduleWidth); int bottomRowDimension =
|
||||
|
@ -383,7 +385,11 @@ import com.google.zxing.common.flexdatatypes.HashTable;
|
|||
// very corners. So there is no 0.5f here; 0.0f is right.
|
||||
var sampler:GridSampler = GridSampler.getGridSamplerInstance();
|
||||
|
||||
return sampler.sampleGrid(matrix, dimension, 0, // p1ToX
|
||||
return sampler.sampleGrid2(
|
||||
matrix,
|
||||
dimension,
|
||||
dimension,
|
||||
0, // p1ToX
|
||||
0, // p1ToY
|
||||
dimension, // p2ToX
|
||||
0, // p2ToY
|
||||
|
@ -423,8 +429,7 @@ import com.google.zxing.common.flexdatatypes.HashTable;
|
|||
var patternLength:int = pattern.length;
|
||||
// TODO: Find a way to cache this array, as this method is called hundreds of times
|
||||
// per image, and we want to allocate as seldom as possible.
|
||||
var counters:Array = new Array(patternLength);
|
||||
for (var k:int=0;k<counters.length;k++){counters[k] = 0; }
|
||||
var counters:Array = new Array(patternLength);for (var k:int=0;k<counters.length;k++){counters[k] = 0; }
|
||||
var isWhite:Boolean = whiteFirst;
|
||||
|
||||
var counterPosition:int = 0;
|
||||
|
@ -488,7 +493,7 @@ import com.google.zxing.common.flexdatatypes.HashTable;
|
|||
// We're going to fake floating-point math in integers. We just need to use more bits.
|
||||
// Scale up patternLength so that intermediate values below like scaledCounter will have
|
||||
// more "significant digits".
|
||||
var unitBarWidth:int = (total << 8) / patternLength;
|
||||
var unitBarWidth:int = int((total << 8) / patternLength);
|
||||
maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> 8;
|
||||
|
||||
var totalVariance:int = 0;
|
||||
|
@ -501,7 +506,7 @@ import com.google.zxing.common.flexdatatypes.HashTable;
|
|||
}
|
||||
totalVariance += variance;
|
||||
}
|
||||
return totalVariance / total;
|
||||
return int(totalVariance / total);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -26,6 +26,7 @@ package com.google.zxing.qrcode
|
|||
import com.google.zxing.EncodeHintType;
|
||||
import com.google.zxing.Writer;
|
||||
import com.google.zxing.WriterException;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
|
||||
public class QRCodeWriter implements Writer
|
||||
{
|
||||
|
@ -65,7 +66,7 @@ package com.google.zxing.qrcode
|
|||
|
||||
// Note that the input matrix uses 0 == white, 1 == black, while the output matrix uses
|
||||
// 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap).
|
||||
private static function renderResult( code:QRCode, width:int, height:int):ByteMatrix {
|
||||
private static function renderResult( code:QRCode, width:int, height:int):BitMatrix {
|
||||
var input:ByteMatrix = code.getMatrix();
|
||||
var inputWidth:int = input.width();
|
||||
var inputHeight:int = input.height();
|
||||
|
@ -82,61 +83,16 @@ package com.google.zxing.qrcode
|
|||
var leftPadding:int = (outputWidth - (inputWidth * multiple)) / 2;
|
||||
var topPadding:int = (outputHeight - (inputHeight * multiple)) / 2;
|
||||
|
||||
var output:ByteMatrix = new ByteMatrix(outputHeight, outputWidth);
|
||||
var outputArray:Array = output.getArray(); //sbyte[][]
|
||||
var output:BitMatrix = new BitMatrix(outputHeight, outputWidth);
|
||||
|
||||
// We could be tricky and use the first row in each set of multiple as the temporary storage,
|
||||
// instead of allocating this separate array.
|
||||
var row:Array = new Array(outputWidth);
|
||||
|
||||
// 1. Write the white lines at the top
|
||||
for (var y:int = 0; y < topPadding; y++) {
|
||||
setRowColor(outputArray[y], 255);
|
||||
}
|
||||
|
||||
// 2. Expand the QR image to the multiple
|
||||
var inputArray:Array = input.getArray();
|
||||
for (var y2:int = 0; y2 < inputHeight; y2++) {
|
||||
// a. Write the white pixels at the left of each row
|
||||
for (var x2:int = 0; x2 < leftPadding; x2++) {
|
||||
row[x2] = 255;
|
||||
}
|
||||
|
||||
// b. Write the contents of this row of the barcode
|
||||
var offset:int = leftPadding;
|
||||
for (var x3:int = 0; x3 < inputWidth; x3++) {
|
||||
var value:int = (inputArray[y2][x3] == 1) ? 0 : 255;
|
||||
for (var z:int = 0; z < multiple; z++) {
|
||||
row[offset + z] = value;
|
||||
}
|
||||
offset += multiple;
|
||||
}
|
||||
|
||||
// c. Write the white pixels at the right of each row
|
||||
offset = leftPadding + (inputWidth * multiple);
|
||||
for (var x4:int = offset; x4 < outputWidth; x4++) {
|
||||
row[x4] = 255;
|
||||
}
|
||||
|
||||
// d. Write the completed row multiple times
|
||||
offset = topPadding + (y2 * multiple);
|
||||
for (var z2:int = 0; z2 < multiple; z2++)
|
||||
{
|
||||
//System.Array.Copy(row, 0, outputArray[offset + z], 0, outputWidth);
|
||||
for (var ii:int=0;ii<outputWidth;ii++)
|
||||
{
|
||||
outputArray[offset + z2][ii] = row[ii];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Write the white lines at the bottom
|
||||
var offset2:int = topPadding + (inputHeight * multiple);
|
||||
for (var y3:int = offset2; y3 < outputHeight; y3++)
|
||||
{
|
||||
setRowColor(outputArray[y3], 255);
|
||||
}
|
||||
for (var inputY:int = 0, outputY:int = topPadding; inputY < inputHeight; inputY++, outputY += multiple) {
|
||||
// Write the contents of this row of the barcode
|
||||
for (var inputX:int = 0, outputX:int = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) {
|
||||
if (input._get(inputX, inputY) == 1) {
|
||||
output.setRegion(outputX, outputY, multiple, multiple);
|
||||
}
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,10 +32,10 @@ package com.google.zxing.qrcode.decoder
|
|||
*/
|
||||
public function BitMatrixParser(bitMatrix:BitMatrix )
|
||||
{
|
||||
var dimension:int = bitMatrix.getDimension();
|
||||
var dimension:int = bitMatrix.getHeight();
|
||||
if ((dimension < 21) || ((dimension & 0x03) != 1))
|
||||
{
|
||||
throw new ReaderException("BitMatrixParser : BitMatrixParser : dimension ("+dimension+" less tahn 21 or not a power of 3)");
|
||||
throw new ReaderException("BitMatrixParser : BitMatrixParser : dimension ("+dimension+" less than 21 or not a power of 3)");
|
||||
}
|
||||
this.bitMatrix = bitMatrix;
|
||||
}
|
||||
|
@ -56,41 +56,34 @@ package com.google.zxing.qrcode.decoder
|
|||
}
|
||||
|
||||
// Read top-left format info bits
|
||||
var formatInfoBits:int = 0;
|
||||
var formatInfoBits1:int = 0;
|
||||
for (var j:int = 0; j < 6; j++)
|
||||
{
|
||||
formatInfoBits = copyBit(8, j, formatInfoBits);
|
||||
formatInfoBits1 = copyBit(j, 8, formatInfoBits1);
|
||||
}
|
||||
// .. and skip a bit in the timing pattern ...
|
||||
formatInfoBits = copyBit(8, 7, formatInfoBits);
|
||||
formatInfoBits = copyBit(8, 8, formatInfoBits);
|
||||
formatInfoBits = copyBit(7, 8, formatInfoBits);
|
||||
formatInfoBits1 = copyBit(7, 8, formatInfoBits1);
|
||||
formatInfoBits1 = copyBit(8, 8, formatInfoBits1);
|
||||
formatInfoBits1 = copyBit(8, 7, formatInfoBits1);
|
||||
// .. and skip a bit in the timing pattern ...
|
||||
for (var i:int = 5; i >= 0; i--)
|
||||
{
|
||||
formatInfoBits = copyBit(i, 8, formatInfoBits);
|
||||
formatInfoBits1 = copyBit(8, i, formatInfoBits1);
|
||||
}
|
||||
|
||||
parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits);
|
||||
if (parsedFormatInfo != null)
|
||||
{
|
||||
return parsedFormatInfo;
|
||||
}
|
||||
|
||||
// Hmm, failed. Try the top-right/bottom-left pattern
|
||||
var dimension:int = bitMatrix.getDimension();
|
||||
formatInfoBits = 0;
|
||||
var iMin:int = dimension - 8;
|
||||
for (i = dimension - 1; i >= iMin; i--)
|
||||
{
|
||||
formatInfoBits = copyBit(i, 8, formatInfoBits);
|
||||
}
|
||||
for (j = dimension - 7; j < dimension; j++)
|
||||
{
|
||||
formatInfoBits = copyBit(8, j, formatInfoBits);
|
||||
}
|
||||
|
||||
parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits);
|
||||
var dimension:int = bitMatrix.getHeight();
|
||||
var formatInfoBits2:int = 0;
|
||||
var jMin:int = dimension - 7;
|
||||
for (var j1:int= dimension - 1; j1 >= jMin; j1--)
|
||||
{
|
||||
formatInfoBits2 = copyBit(8, j1, formatInfoBits2);
|
||||
}
|
||||
for (var i1:int = dimension - 8; i1 < dimension; i1++)
|
||||
{
|
||||
formatInfoBits2 = copyBit(i1, 8, formatInfoBits2);
|
||||
}
|
||||
|
||||
parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits1,formatInfoBits2);
|
||||
if (parsedFormatInfo != null)
|
||||
{
|
||||
return parsedFormatInfo;
|
||||
|
@ -113,7 +106,7 @@ package com.google.zxing.qrcode.decoder
|
|||
return parsedVersion;
|
||||
}
|
||||
|
||||
var dimension:int = bitMatrix.getDimension();
|
||||
var dimension:int = bitMatrix.getHeight();
|
||||
|
||||
var provisionalVersion:int = (dimension - 17) >> 2;
|
||||
if (provisionalVersion <= 6)
|
||||
|
@ -123,34 +116,34 @@ package com.google.zxing.qrcode.decoder
|
|||
|
||||
// Read top-right version info: 3 wide by 6 tall
|
||||
var versionBits:int = 0;
|
||||
var jMin:int = dimension - 11;
|
||||
for (var i:int = 5; i >= 0; i--)
|
||||
{
|
||||
var jMin:int = dimension - 11;
|
||||
for (var j2:int = dimension - 9; j2 >= jMin; j2--)
|
||||
{
|
||||
versionBits = copyBit(i, j2, versionBits);
|
||||
versionBits = copyBit(j2, i, versionBits);
|
||||
}
|
||||
}
|
||||
|
||||
parsedVersion = Version.decodeVersionInformation(versionBits);
|
||||
if (parsedVersion != null)
|
||||
if (parsedVersion != null && parsedVersion.getDimensionForVersion() == dimension)
|
||||
{
|
||||
return parsedVersion;
|
||||
}
|
||||
|
||||
// Hmm, failed. Try bottom left: 6 wide by 3 tall
|
||||
versionBits = 0;
|
||||
var iMin:int = dimension - 11;
|
||||
for (var j:int = 5; j >= 0; j--)
|
||||
{
|
||||
var iMin:int = dimension - 11;
|
||||
for (var i2:int = dimension - 11; i2 >= iMin; i2--)
|
||||
for (var i2:int = dimension - 9; i2 >= iMin; i2--)
|
||||
{
|
||||
versionBits = copyBit(i2, j, versionBits);
|
||||
versionBits = copyBit(j, i2, versionBits);
|
||||
}
|
||||
}
|
||||
|
||||
parsedVersion = Version.decodeVersionInformation(versionBits);
|
||||
if (parsedVersion != null)
|
||||
if (parsedVersion != null && parsedVersion.getDimensionForVersion() == dimension)
|
||||
{
|
||||
return parsedVersion;
|
||||
}
|
||||
|
@ -159,7 +152,7 @@ package com.google.zxing.qrcode.decoder
|
|||
|
||||
private function copyBit(i:int, j:int, versionBits:int):int
|
||||
{
|
||||
return bitMatrix._get(j, i) ? (versionBits << 1) | 0x1 : versionBits << 1;
|
||||
return bitMatrix._get(i, j) ? (versionBits << 1) | 0x1 : versionBits << 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -181,7 +174,7 @@ package com.google.zxing.qrcode.decoder
|
|||
var dataMask:DataMaskBase;
|
||||
var ref:int = formatInfo.getDataMask();
|
||||
dataMask = DataMask.forReference(ref);
|
||||
var dimension:int = bitMatrix.getDimension();
|
||||
var dimension:int = bitMatrix.getHeight();
|
||||
dataMask.unmaskBitMatrix(bitMatrix, dimension);
|
||||
|
||||
var functionPattern:BitMatrix = version.buildFunctionPattern();
|
||||
|
|
|
@ -8,7 +8,7 @@ package com.google.zxing.qrcode.decoder
|
|||
public class DataMask011 extends DataMaskBase
|
||||
{
|
||||
public override function isMasked(i:int, j:int):Boolean {
|
||||
return (i + j) % 3 == 0;
|
||||
return int((i + j) % 3) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ package com.google.zxing.qrcode.decoder
|
|||
public class DataMask100 extends DataMaskBase {
|
||||
|
||||
public override function isMasked(i:int, j:int):Boolean {
|
||||
return (((i >>> 1) + (j /3)) & 0x01) == 0;
|
||||
return (((i >>> 1) + (int(j /3))) & 0x01) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ package com.google.zxing.qrcode.decoder
|
|||
public override function isMasked(i:int, j:int):Boolean
|
||||
{
|
||||
var temp:int = i * j;
|
||||
return (temp & 0x01) + (temp % 3) == 0;
|
||||
return (temp & 0x01) + (int(temp % 3)) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ package com.google.zxing.qrcode.decoder
|
|||
public override function isMasked(i:int, j:int):Boolean
|
||||
{
|
||||
var temp:int = i * j;
|
||||
return (((temp & 0x01) + (temp % 3)) & 0x01) == 0;
|
||||
return (((temp & 0x01) + (int(temp % 3))) & 0x01) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ package com.google.zxing.qrcode.decoder
|
|||
{
|
||||
|
||||
public override function isMasked(i:int, j:int):Boolean {
|
||||
return ((((i + j) & 0x01) + ((i * j) % 3)) & 0x01) == 0;
|
||||
return ((((i + j) & 0x01) + (int((i * j) % 3))) & 0x01) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,12 +15,12 @@
|
|||
*/
|
||||
package com.google.zxing.qrcode.decoder
|
||||
{
|
||||
import com.google.zxing.common.zxingByteArray;
|
||||
import flash.utils.ByteArray;
|
||||
import com.google.zxing.common.flexdatatypes.ArrayList;
|
||||
import com.google.zxing.FormatException;
|
||||
import com.google.zxing.common.BitSource;
|
||||
import com.google.zxing.common.CharacterSetECI;
|
||||
import com.google.zxing.common.DecoderResult;
|
||||
import com.google.zxing.common.flexdatatypes.ArrayList;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
|
||||
|
||||
|
@ -52,244 +52,222 @@ package com.google.zxing.qrcode.decoder
|
|||
* @author Sean Owen
|
||||
*/
|
||||
private static var ALPHANUMERIC_CHARS: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', ' ', '$', '%', '*', '+', '-', '.', '/', ':' ];
|
||||
private static const SHIFT_JIS:String = "Shift_JIS";
|
||||
private static var ASSUME_SHIFT_JIS:Boolean=true;
|
||||
private static const EUC_JP:String = "EUC_JP";
|
||||
private static const UTF8:String = "UTF8";
|
||||
private static const ISO88591:String = "ISO8859_1";
|
||||
private static const GB2312_SUBSET:int = 1;
|
||||
|
||||
|
||||
public function DecodedBitStreamParser()
|
||||
{
|
||||
// var platformDefault:String = System.getProperty("file.encoding");
|
||||
//ASSUME_SHIFT_JIS = SHIFT_JIS.EqualsIgnoreCase(platformDefault) || EUC_JP.EqualsIgnoreCase(platformDefault);
|
||||
ASSUME_SHIFT_JIS = true;// BAS : actionscript has no build in method to check the encoding
|
||||
}
|
||||
|
||||
|
||||
public static function decode(bytes:Array, version:Version, ecLevel:ErrorCorrectionLevel, hints:HashTable):DecoderResult
|
||||
{
|
||||
var bits:BitSource = new BitSource(bytes);
|
||||
var result:StringBuilder = new StringBuilder(50);
|
||||
var currentCharacterSetECI:CharacterSetECI = null;
|
||||
var fc1InEffect:Boolean = false;
|
||||
var byteSegments:ArrayList = new ArrayList(1);
|
||||
var mode:Mode;
|
||||
do {
|
||||
// While still another segment to read...
|
||||
if (bits.available() < 4) {
|
||||
// OK, assume we're done. Really, a TERMINATOR mode should have been recorded here
|
||||
mode = Mode.TERMINATOR;
|
||||
} else {
|
||||
try {
|
||||
mode = Mode.forBits(bits.readBits(4)); // mode is encoded by 4 bits
|
||||
} catch (iae:IllegalArgumentException) {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
}
|
||||
if (!mode.Equals(Mode.TERMINATOR)) {
|
||||
if (mode.Equals(Mode.FNC1_FIRST_POSITION) || mode.Equals(Mode.FNC1_SECOND_POSITION)) {
|
||||
// We do little with FNC1 except alter the parsed result a bit according to the spec
|
||||
fc1InEffect = true;
|
||||
} else if (mode.Equals(Mode.STRUCTURED_APPEND)) {
|
||||
// not really supported; all we do is ignore it
|
||||
// Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue
|
||||
bits.readBits(16);
|
||||
} else if (mode.Equals(Mode.ECI)) {
|
||||
// Count doesn't apply to ECI
|
||||
var value:int = parseECIValue(bits);
|
||||
currentCharacterSetECI = CharacterSetECI.getCharacterSetECIByValue(value);
|
||||
if (currentCharacterSetECI == null) {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
} else {
|
||||
// First handle Hanzi mode which does not start with character count
|
||||
if (mode.Equals(Mode.HANZI)) {
|
||||
//chinese mode contains a sub set indicator right after mode indicator
|
||||
var subset:int = bits.readBits(4);
|
||||
var countHanzi:int = bits.readBits(mode.getCharacterCountBits(version));
|
||||
if (subset == GB2312_SUBSET) {
|
||||
decodeHanziSegment(bits, result, countHanzi);
|
||||
}
|
||||
} else {
|
||||
// "Normal" QR code modes:
|
||||
// How many characters will follow, encoded in this mode?
|
||||
var count:int = bits.readBits(mode.getCharacterCountBits(version));
|
||||
if (mode.Equals(Mode.NUMERIC)) {
|
||||
decodeNumericSegment(bits, result, count);
|
||||
} else if (mode.Equals(Mode.ALPHANUMERIC)) {
|
||||
decodeAlphanumericSegment(bits, result, count, fc1InEffect);
|
||||
} else if (mode.Equals(Mode.BYTE)) {
|
||||
decodeByteSegment(bits, result, count, currentCharacterSetECI, byteSegments, hints);
|
||||
} else if (mode.Equals(Mode.KANJI)) {
|
||||
decodeKanjiSegment(bits, result, count);
|
||||
} else {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!mode.Equals(Mode.TERMINATOR));
|
||||
|
||||
return new DecoderResult(bytes,
|
||||
result.toString(),
|
||||
byteSegments.isEmpty() ? null : byteSegments,
|
||||
ecLevel == null ? null : ecLevel.toString());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See specification GBT 18284-2000
|
||||
*/
|
||||
private static function decodeHanziSegment(bits:BitSource,
|
||||
result:StringBuilder,
|
||||
count:int):void {
|
||||
// Don't crash trying to read more bits than we have available.
|
||||
if (count * 13 > bits.available()) {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
|
||||
// Each character will require 2 bytes. Read the characters as 2-byte pairs
|
||||
// and decode as GB2312 afterwards
|
||||
var buffer:Array = new Array(2 * count);
|
||||
var offset:int = 0;
|
||||
while (count > 0) {
|
||||
// Each 13 bits encodes a 2-byte character
|
||||
var twoBytes:int = bits.readBits(13);
|
||||
var assembledTwoBytes:int = (int(twoBytes / 0x060) << 8) | int(twoBytes % 0x060);
|
||||
if (assembledTwoBytes < 0x003BF) {
|
||||
// In the 0xA1A1 to 0xAAFE range
|
||||
assembledTwoBytes += 0x0A1A1;
|
||||
} else {
|
||||
// In the 0xB0A1 to 0xFAFE range
|
||||
assembledTwoBytes += 0x0A6A1;
|
||||
}
|
||||
buffer[offset] = int(((assembledTwoBytes >> 8) & 0xFF));
|
||||
buffer[offset + 1] = int(assembledTwoBytes & 0xFF);
|
||||
offset += 2;
|
||||
count--;
|
||||
}
|
||||
|
||||
//try {
|
||||
//result.Append(new String(buffer, StringUtils.GB2312));
|
||||
result.Append(buffer);
|
||||
//} catch (uee:UnsupportedEncodingException) {
|
||||
// throw FormatException.getFormatInstance();
|
||||
// }
|
||||
}
|
||||
|
||||
private static function decodeKanjiSegment(bits:BitSource,
|
||||
result:StringBuilder,
|
||||
count:int):void {
|
||||
// Don't crash trying to read more bits than we have available.
|
||||
if (count * 13 > bits.available()) {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
|
||||
// Each character will require 2 bytes. Read the characters as 2-byte pairs
|
||||
// and decode as Shift_JIS afterwards
|
||||
var buffer:Array = new Array(2 * count);
|
||||
var offset:int = 0;
|
||||
while (count > 0) {
|
||||
// Each 13 bits encodes a 2-byte character
|
||||
var twoBytes:int = bits.readBits(13);
|
||||
var assembledTwoBytes:int = (int(twoBytes / 0x0C0) << 8) | int(twoBytes % 0x0C0);
|
||||
if (assembledTwoBytes < 0x01F00) {
|
||||
// In the 0x8140 to 0x9FFC range
|
||||
assembledTwoBytes += 0x08140;
|
||||
} else {
|
||||
// In the 0xE040 to 0xEBBF range
|
||||
assembledTwoBytes += 0x0C140;
|
||||
}
|
||||
buffer[offset] = int(assembledTwoBytes >> 8);
|
||||
buffer[offset + 1] = int( assembledTwoBytes);
|
||||
offset += 2;
|
||||
count--;
|
||||
}
|
||||
// Shift_JIS may not be supported in some environments:
|
||||
//try {
|
||||
///result.Append(new String(buffer, StringUtils.SHIFT_JIS));
|
||||
result.Append(buffer);
|
||||
//} catch (uee:UnsupportedEncodingException) {
|
||||
// throw FormatException.getFormatInstance();
|
||||
//}
|
||||
}
|
||||
|
||||
private static function decodeByteSegment(bits:BitSource,
|
||||
result:StringBuilder,
|
||||
count:int,
|
||||
currentCharacterSetECI:CharacterSetECI,
|
||||
byteSegments:ArrayList,
|
||||
hints:HashTable):void {
|
||||
// Don't crash trying to read more bits than we have available.
|
||||
if (count << 3 > bits.available()) {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
|
||||
var readBytes:Array = new Array(count);
|
||||
for (var i:int = 0; i < count; i++) {
|
||||
readBytes[i] = String.fromCharCode(bits.readBits(8));
|
||||
}
|
||||
var encoding:String;
|
||||
//if (currentCharacterSetECI == null) {
|
||||
// The spec isn't clear on this mode; see
|
||||
// section 6.4.5: t does not say which encoding to assuming
|
||||
// upon decoding. I have seen ISO-8859-1 used as well as
|
||||
// Shift_JIS -- without anything like an ECI designator to
|
||||
// give a hint.
|
||||
//encoding = StringUtils.guessEncoding(readBytes, hints);
|
||||
//} else {
|
||||
// encoding = currentCharacterSetECI.getEncodingName();
|
||||
// }
|
||||
//try {
|
||||
//result.Append(new String(readBytes, encoding));
|
||||
|
||||
result.Append(readBytes);
|
||||
//} catch (uce:UnsupportedEncodingException) {
|
||||
// throw FormatException.getFormatInstance();
|
||||
//}
|
||||
byteSegments.addElement(readBytes);
|
||||
}
|
||||
|
||||
}
|
||||
private static function toAlphaNumericChar(value:int):String {
|
||||
if (value >= ALPHANUMERIC_CHARS.length) {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
return ALPHANUMERIC_CHARS[value];
|
||||
}
|
||||
|
||||
public static function decode(bytes:Array, version:Version, ecLevel:ErrorCorrectionLevel):DecoderResult
|
||||
{
|
||||
var bits:BitSource = new BitSource(bytes);
|
||||
var result:StringBuilder = new StringBuilder();
|
||||
var currentCharacterSetECI:CharacterSetECI = null;
|
||||
var fc1InEffect:Boolean = false;
|
||||
var byteSegments:ArrayList = new ArrayList(1);
|
||||
var mode:Mode;
|
||||
do
|
||||
{
|
||||
// While still another segment to read...
|
||||
if (bits.available() < 4)
|
||||
{
|
||||
// OK, assume we're done. Really, a TERMINATOR mode should have been recorded here
|
||||
mode = Mode.TERMINATOR;
|
||||
} else
|
||||
{
|
||||
try
|
||||
{
|
||||
mode = Mode.forBits(bits.readBits(4)); // mode is encoded by 4 bits
|
||||
}
|
||||
catch (e:IllegalArgumentException)
|
||||
{
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
if (!mode.Equals(Mode.TERMINATOR))
|
||||
{
|
||||
if (mode.Equals(Mode.FNC1_FIRST_POSITION) || mode.Equals(Mode.FNC1_SECOND_POSITION))
|
||||
{
|
||||
// We do little with FNC1 except alter the parsed result a bit according to the spec
|
||||
fc1InEffect = true;
|
||||
}
|
||||
else if (mode.Equals(Mode.STRUCTURED_APPEND))
|
||||
{
|
||||
// not really supported; all we do is ignore it
|
||||
// Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue
|
||||
bits.readBits(16);
|
||||
}
|
||||
else if (mode.Equals(Mode.ECI))
|
||||
{
|
||||
// Count doesn't apply to ECI
|
||||
var value:int = parseECIValue(bits);
|
||||
currentCharacterSetECI = CharacterSetECI.getCharacterSetECIByValue(value);
|
||||
if (currentCharacterSetECI == null)
|
||||
{
|
||||
throw new ReaderException();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// How many characters will follow, encoded in this mode?
|
||||
var count:int = bits.readBits(mode.getCharacterCountBits(version));
|
||||
if (mode.Equals(Mode.NUMERIC))
|
||||
{
|
||||
decodeNumericSegment(bits, result, count);
|
||||
}
|
||||
else if (mode.Equals(Mode.ALPHANUMERIC))
|
||||
{
|
||||
decodeAlphanumericSegment(bits, result, count, fc1InEffect);
|
||||
}
|
||||
else if (mode.Equals(Mode.BYTE))
|
||||
{
|
||||
decodeByteSegment(bits, result, count, currentCharacterSetECI, byteSegments);
|
||||
}
|
||||
else if (mode.Equals(Mode.KANJI))
|
||||
{
|
||||
decodeKanjiSegment(bits, result, count);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ReaderException();
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!mode.Equals(Mode.TERMINATOR));
|
||||
|
||||
return new DecoderResult(bytes, result.toString(), byteSegments.isEmpty() ? null : byteSegments, ecLevel);
|
||||
|
||||
}
|
||||
|
||||
private static function decodeKanjiSegment(bits:BitSource, result:StringBuilder, count:int):void
|
||||
{
|
||||
// Each character will require 2 bytes. Read the characters as 2-byte pairs
|
||||
// and decode as Shift_JIS afterwards
|
||||
var buffer:Array = new Array(2 * count);
|
||||
var offset:int = 0;
|
||||
while (count > 0)
|
||||
{
|
||||
// Each 13 bits encodes a 2-byte character
|
||||
var twoBytes:int = bits.readBits(13);
|
||||
var assembledTwoBytes:int = ((twoBytes / 0x0C0) << 8) | (twoBytes % 0x0C0);
|
||||
if (assembledTwoBytes < 0x01F00)
|
||||
{
|
||||
// In the 0x8140 to 0x9FFC range
|
||||
assembledTwoBytes += 0x08140;
|
||||
}
|
||||
else
|
||||
{
|
||||
// In the 0xE040 to 0xEBBF range
|
||||
assembledTwoBytes += 0x0C140;
|
||||
}
|
||||
buffer[offset] = assembledTwoBytes >> 8;
|
||||
buffer[offset + 1] = assembledTwoBytes;
|
||||
offset += 2;
|
||||
count--;
|
||||
}
|
||||
// Shift_JIS may not be supported in some environments:
|
||||
try
|
||||
{
|
||||
// var bytes:Array = SupportClass.ToByteArray(buffer);
|
||||
//var bytes:Array = new Array(buffer.length);
|
||||
//for (var i:int=0;i<buffer.length;i++) { bytes[i] = buffer[i]; }
|
||||
//UPGRADE_TODO: The differences in the Format of parameters for constructor 'java.lang.String.String' may cause compilation errors. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1092'"
|
||||
//result.Append(System.Text.Encoding.GetEncoding("Shift_JIS").GetString(bytes, 0, bytes.length));
|
||||
var ba:ByteArray = new ByteArray();
|
||||
for (var k:int=0;k<buffer.length;k++) { ba.writeByte(buffer[k]); }
|
||||
ba.position = 0;
|
||||
result.Append(ba.readMultiByte(ba.length,"shift-jis"));
|
||||
|
||||
}
|
||||
catch (uee:Error)
|
||||
{
|
||||
throw new ReaderException("SHIFT_JIS encoding is not supported on this device");
|
||||
}
|
||||
}
|
||||
|
||||
private static function decodeByteSegment(bits:BitSource ,
|
||||
result:StringBuilder ,
|
||||
count:int ,
|
||||
currentCharacterSetECI:CharacterSetECI ,
|
||||
byteSegments:ArrayList) :void
|
||||
{
|
||||
var readBytes:Array = new Array(count);
|
||||
if (count << 3 > bits.available())
|
||||
{
|
||||
throw new ReaderException("Count too large: " + count);
|
||||
}
|
||||
for (var i:int = 0; i < count; i++)
|
||||
{
|
||||
readBytes[i] = bits.readBits(8);
|
||||
}
|
||||
// The spec isn't clear on this mode; see
|
||||
// section 6.4.5: t does not say which encoding to assuming
|
||||
// upon decoding. I have seen ISO-8859-1 used as well as
|
||||
// Shift_JIS -- without anything like an ECI designator to
|
||||
// give a hint.
|
||||
var encoding:String;
|
||||
if (currentCharacterSetECI == null)
|
||||
{
|
||||
// The spec isn't clear on this mode; see
|
||||
// section 6.4.5: t does not say which encoding to assuming
|
||||
// upon decoding. I have seen ISO-8859-1 used as well as
|
||||
// Shift_JIS -- without anything like an ECI designator to
|
||||
// give a hint.
|
||||
encoding = guessEncoding(readBytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
encoding = currentCharacterSetECI.getEncodingName();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
//result.Append(new String(readBytes, encoding));
|
||||
// BAS : todo : encoding not supported in AS
|
||||
// convert bytes to string
|
||||
//private static const SHIFT_JIS:String = "Shift_JIS";
|
||||
//private static var ASSUME_SHIFT_JIS:Boolean=true;
|
||||
//private static const EUC_JP:String = "EUC_JP";
|
||||
//private static const UTF8:String = "UTF8";
|
||||
//private static const ISO88591:String = "ISO8859_1";
|
||||
|
||||
if ((encoding == DecodedBitStreamParser.SHIFT_JIS) ||
|
||||
(encoding == DecodedBitStreamParser.EUC_JP) ||
|
||||
(encoding == DecodedBitStreamParser.UTF8) ||
|
||||
(encoding == DecodedBitStreamParser.ISO88591))
|
||||
{
|
||||
var ba:ByteArray = new ByteArray();
|
||||
for (var k:int=0;k<readBytes.length;k++) { ba.writeByte(readBytes[k]); }
|
||||
ba.position = 0;
|
||||
if (encoding == DecodedBitStreamParser.SHIFT_JIS) { result.Append(ba.readMultiByte(ba.length,"shift-jis")); }
|
||||
else if (encoding == DecodedBitStreamParser.EUC_JP) { result.Append(ba.readMultiByte(ba.length," euc-jp")); }
|
||||
else if (encoding == DecodedBitStreamParser.UTF8) { result.Append(ba.readMultiByte(ba.length,"utf-8")); }
|
||||
else if (encoding == DecodedBitStreamParser.ISO88591) { result.Append(ba.readMultiByte(ba.length,"iso-8859-1")); }
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
var text:String ="";
|
||||
for (var i2:int=0;i2<readBytes.length;i2++)
|
||||
{
|
||||
text = text + String.fromCharCode(readBytes[i2]);
|
||||
}
|
||||
result.Append(text);
|
||||
}
|
||||
}
|
||||
catch (e:Error)
|
||||
{
|
||||
throw new ReaderException();
|
||||
}
|
||||
byteSegments.addElement(readBytes);
|
||||
}
|
||||
|
||||
private static function decodeAlphanumericSegment(bits:BitSource , result:StringBuilder, count:int, fc1InEffect:Boolean):void
|
||||
{
|
||||
var start:int = result.length;
|
||||
// Read two characters at a time
|
||||
while (count > 1)
|
||||
{
|
||||
var nextTwoCharsBits:int = bits.readBits(11);
|
||||
result.Append(ALPHANUMERIC_CHARS[int(nextTwoCharsBits / 45)]);
|
||||
result.Append(ALPHANUMERIC_CHARS[int(nextTwoCharsBits % 45)]);
|
||||
count -= 2;
|
||||
}
|
||||
if (count == 1)
|
||||
{
|
||||
// special case: one character left
|
||||
result.Append(ALPHANUMERIC_CHARS[bits.readBits(6)]);
|
||||
}
|
||||
// See section 6.4.8.1, 6.4.8.2
|
||||
private static function decodeAlphanumericSegment(bits:BitSource,
|
||||
result:StringBuilder,
|
||||
count:int,
|
||||
fc1InEffect:Boolean):void {
|
||||
// Read two characters at a time
|
||||
var start:int = result.length;
|
||||
while (count > 1) {
|
||||
var nextTwoCharsBits:int = bits.readBits(11);
|
||||
result.Append(toAlphaNumericChar(int(nextTwoCharsBits / 45)));
|
||||
result.Append(toAlphaNumericChar(int(nextTwoCharsBits % 45)));
|
||||
count -= 2;
|
||||
}
|
||||
if (count == 1) {
|
||||
// special case: one character left
|
||||
result.Append(toAlphaNumericChar(bits.readBits(6)));
|
||||
}
|
||||
// See section 6.4.8.1, 6.4.8.2
|
||||
if (fc1InEffect) {
|
||||
// We need to massage the result a bit if in an FNC1 mode:
|
||||
for (var i:int = start; i < result.length; i++) {
|
||||
|
@ -304,155 +282,67 @@ package com.google.zxing.qrcode.decoder
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function decodeNumericSegment(bits:BitSource , result:StringBuilder , count:int ):void
|
||||
{
|
||||
// Read three digits at a time
|
||||
while (count >= 3)
|
||||
{
|
||||
// Each 10 bits encodes three digits
|
||||
var threeDigitsBits:int = bits.readBits(10);
|
||||
if (threeDigitsBits >= 1000)
|
||||
{
|
||||
throw new ReaderException("Illegal value for 3-digit unit: " + threeDigitsBits);
|
||||
}
|
||||
result.Append(ALPHANUMERIC_CHARS[int(threeDigitsBits / 100)]);
|
||||
result.Append(ALPHANUMERIC_CHARS[int((threeDigitsBits / 10) % 10)]);
|
||||
result.Append(ALPHANUMERIC_CHARS[int(threeDigitsBits % 10)]);
|
||||
count -= 3;
|
||||
}
|
||||
if (count == 2)
|
||||
{
|
||||
// Two digits left over to read, encoded in 7 bits
|
||||
var twoDigitsBits:int = bits.readBits(7);
|
||||
if (twoDigitsBits >= 100)
|
||||
{
|
||||
throw new ReaderException("Illegal value for 2-digit unit: " + twoDigitsBits);
|
||||
}
|
||||
result.Append(ALPHANUMERIC_CHARS[int(twoDigitsBits / 10)]);
|
||||
result.Append(ALPHANUMERIC_CHARS[int(twoDigitsBits % 10)]);
|
||||
}
|
||||
else if (count == 1)
|
||||
{
|
||||
// One digit left over to read
|
||||
var digitBits:int = bits.readBits(4);
|
||||
if (digitBits >= 10)
|
||||
{
|
||||
throw new ReaderException("Illegal value for digit unit: " + digitBits);
|
||||
}
|
||||
result.Append(ALPHANUMERIC_CHARS[digitBits]);
|
||||
}
|
||||
}
|
||||
|
||||
private static function guessEncoding(bytes:Array):String
|
||||
{
|
||||
if (ASSUME_SHIFT_JIS) {
|
||||
return SHIFT_JIS;
|
||||
}
|
||||
|
||||
// Does it start with the UTF-8 byte order mark? then guess it's UTF-8
|
||||
if (bytes.length > 3 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) {
|
||||
return UTF8;
|
||||
}
|
||||
// For now, merely tries to distinguish ISO-8859-1, UTF-8 and Shift_JIS,
|
||||
// which should be by far the most common encodings. ISO-8859-1
|
||||
// should not have bytes in the 0x80 - 0x9F range, while Shift_JIS
|
||||
// uses this as a first byte of a two-byte character. If we see this
|
||||
// followed by a valid second byte in Shift_JIS, assume it is Shift_JIS.
|
||||
// If we see something else in that second byte, we'll make the risky guess
|
||||
// that it's UTF-8.
|
||||
var length:int = bytes.length;
|
||||
var canBeISO88591:Boolean = true;
|
||||
var canBeShiftJIS:Boolean = true;
|
||||
var maybeDoubleByteCount:int = 0;
|
||||
var maybeSingleByteKatakanaCount:int = 0;
|
||||
var sawLatin1Supplement:Boolean = false;
|
||||
var lastWasPossibleDoubleByteStart:Boolean = false;
|
||||
for (var i:int = 0; i < length && (canBeISO88591 || canBeShiftJIS); i++) {
|
||||
var value:int = bytes[i] & 0xFF;
|
||||
if ((value == 0xC2 || value == 0xC3) && i < length - 1) {
|
||||
// This is really a poor hack. The slightly more exotic characters people might want to put in
|
||||
// a QR Code, by which I mean the Latin-1 supplement characters (e.g. u-umlaut) have encodings
|
||||
// that start with 0xC2 followed by [0xA0,0xBF], or start with 0xC3 followed by [0x80,0xBF].
|
||||
var nextValue:int = bytes[i + 1] & 0xFF;
|
||||
if (nextValue <= 0xBF && ((value == 0xC2 && nextValue >= 0xA0) || (value == 0xC3 && nextValue >= 0x80))) {
|
||||
sawLatin1Supplement = true;
|
||||
}
|
||||
}
|
||||
if (value >= 0x7F && value <= 0x9F) {
|
||||
canBeISO88591 = false;
|
||||
}
|
||||
if (value >= 0xA1 && value <= 0xDF) {
|
||||
// count the number of characters that might be a Shift_JIS single-byte Katakana character
|
||||
if (!lastWasPossibleDoubleByteStart) {
|
||||
maybeSingleByteKatakanaCount++;
|
||||
}
|
||||
}
|
||||
if (!lastWasPossibleDoubleByteStart && ((value >= 0xF0 && value <= 0xFF) || value == 0x80 || value == 0xA0)) {
|
||||
canBeShiftJIS = false;
|
||||
}
|
||||
if (((value >= 0x81 && value <= 0x9F) || (value >= 0xE0 && value <= 0xEF))) {
|
||||
// These start double-byte characters in Shift_JIS. Let's see if it's followed by a valid
|
||||
// second byte.
|
||||
if (lastWasPossibleDoubleByteStart) {
|
||||
// If we just checked this and the last byte for being a valid double-byte
|
||||
// char, don't check starting on this byte. If this and the last byte
|
||||
// formed a valid pair, then this shouldn't be checked to see if it starts
|
||||
// a double byte pair of course.
|
||||
lastWasPossibleDoubleByteStart = false;
|
||||
} else {
|
||||
// ... otherwise do check to see if this plus the next byte form a valid
|
||||
// double byte pair encoding a character.
|
||||
lastWasPossibleDoubleByteStart = true;
|
||||
if (i >= bytes.length - 1) {
|
||||
canBeShiftJIS = false;
|
||||
} else {
|
||||
var nextValue2:int = bytes[i + 1] & 0xFF;
|
||||
if (nextValue2 < 0x40 || nextValue2 > 0xFC) {
|
||||
canBeShiftJIS = false;
|
||||
} else {
|
||||
maybeDoubleByteCount++;
|
||||
}
|
||||
// There is some conflicting information out there about which bytes can follow which in
|
||||
// double-byte Shift_JIS characters. The rule above seems to be the one that matches practice.
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lastWasPossibleDoubleByteStart = false;
|
||||
}
|
||||
}
|
||||
// Distinguishing Shift_JIS and ISO-8859-1 can be a little tough. The crude heuristic is:
|
||||
// - If we saw
|
||||
// - at least three byte that starts a double-byte value (bytes that are rare in ISO-8859-1), or
|
||||
// - over 5% of bytes that could be single-byte Katakana (also rare in ISO-8859-1),
|
||||
// - and, saw no sequences that are invalid in Shift_JIS, then we conclude Shift_JIS
|
||||
if (canBeShiftJIS && (maybeDoubleByteCount >= 3 || 20 * maybeSingleByteKatakanaCount > length)) {
|
||||
return SHIFT_JIS;
|
||||
}
|
||||
// Otherwise, we default to ISO-8859-1 unless we know it can't be
|
||||
if (!sawLatin1Supplement && canBeISO88591) {
|
||||
return ISO88591;
|
||||
}
|
||||
// Otherwise, we take a wild guess with UTF-8
|
||||
return UTF8;
|
||||
}
|
||||
|
||||
|
||||
private static function decodeNumericSegment(bits:BitSource,
|
||||
result:StringBuilder,
|
||||
count:int):void {
|
||||
// Read three digits at a time
|
||||
while (count >= 3) {
|
||||
// Each 10 bits encodes three digits
|
||||
if (bits.available() < 10) {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
var threeDigitsBits:int = bits.readBits(10);
|
||||
if (threeDigitsBits >= 1000) {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
result.Append(toAlphaNumericChar(int(threeDigitsBits / 100)));
|
||||
result.Append(toAlphaNumericChar(int(int(threeDigitsBits / 10) % 10)));
|
||||
result.Append(toAlphaNumericChar(int(threeDigitsBits % 10)));
|
||||
count -= 3;
|
||||
}
|
||||
if (count == 2) {
|
||||
// Two digits left over to read, encoded in 7 bits
|
||||
if (bits.available() < 7) {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
var twoDigitsBits:int = bits.readBits(7);
|
||||
if (twoDigitsBits >= 100) {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
result.Append(toAlphaNumericChar(int(twoDigitsBits / 10)));
|
||||
result.Append(toAlphaNumericChar(int(twoDigitsBits % 10)));
|
||||
} else if (count == 1) {
|
||||
// One digit left over to read
|
||||
if (bits.available() < 4) {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
var digitBits:int = bits.readBits(4);
|
||||
if (digitBits >= 10) {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
result.Append(toAlphaNumericChar(digitBits));
|
||||
}
|
||||
}
|
||||
|
||||
private static function parseECIValue(bits:BitSource):int {
|
||||
var firstByte:int = bits.readBits(8);
|
||||
if ((firstByte & 0x80) == 0) {
|
||||
// just one byte
|
||||
return firstByte & 0x7F;
|
||||
} else if ((firstByte & 0xC0) == 0x80) {
|
||||
}
|
||||
if ((firstByte & 0xC0) == 0x80) {
|
||||
// two bytes
|
||||
var secondByte:int = bits.readBits(8);
|
||||
return ((firstByte & 0x3F) << 8) | secondByte;
|
||||
} else if ((firstByte & 0xE0) == 0xC0) {
|
||||
}
|
||||
if ((firstByte & 0xE0) == 0xC0) {
|
||||
// three bytes
|
||||
var secondThirdBytes:int = bits.readBits(16);
|
||||
return ((firstByte & 0x1F) << 16) | secondThirdBytes;
|
||||
}
|
||||
throw new Error("Bad ECI bits starting with byte " + firstByte);
|
||||
throw new IllegalArgumentException("Bad ECI bits starting with byte " + firstByte);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package com.google.zxing.qrcode.decoder
|
||||
{
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
|
||||
|
||||
public class Decoder
|
||||
{
|
||||
|
@ -22,7 +24,7 @@ package com.google.zxing.qrcode.decoder
|
|||
import com.google.zxing.common.DecoderResult;
|
||||
import com.google.zxing.common.reedsolomon.ReedSolomonDecoder;
|
||||
import com.google.zxing.common.reedsolomon.ReedSolomonException;
|
||||
import com.google.zxing.common.reedsolomon.GF256;
|
||||
import com.google.zxing.common.reedsolomon.GenericGF;
|
||||
import com.google.zxing.common.zxingByteArray;
|
||||
import com.google.zxing.ReaderException;
|
||||
|
||||
|
@ -36,7 +38,7 @@ package com.google.zxing.qrcode.decoder
|
|||
private var rsDecoder:ReedSolomonDecoder;
|
||||
|
||||
public function Decoder() {
|
||||
rsDecoder = new ReedSolomonDecoder(GF256.QR_CODE_FIELD);
|
||||
rsDecoder = new ReedSolomonDecoder(GenericGF.QR_CODE_FIELD_256);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -48,14 +50,14 @@ package com.google.zxing.qrcode.decoder
|
|||
* @throws ReaderException if the QR Code cannot be decoded
|
||||
*/
|
||||
|
||||
public function decode(image:Object):DecoderResult
|
||||
public function decode(image:Object,hints:HashTable=null):DecoderResult
|
||||
{
|
||||
if (image is Array) { return decode_Array(image as Array);}
|
||||
else if (image is BitMatrix) { return decode_BitMatrix(image as BitMatrix);}
|
||||
if (image is Array) { return decode_Array(image as Array,hints);}
|
||||
else if (image is BitMatrix) { return decode_BitMatrix(image as BitMatrix,hints);}
|
||||
else { throw new Error('Decoder : decode : unknown type of image');}
|
||||
}
|
||||
|
||||
public function decode_Array(image:Array):DecoderResult {
|
||||
public function decode_Array(image:Array, hints:HashTable):DecoderResult {
|
||||
var dimension:int = image.length;
|
||||
var bits:BitMatrix = new BitMatrix(dimension);
|
||||
for (var i:int = 0; i < dimension; i++) {
|
||||
|
@ -65,7 +67,7 @@ package com.google.zxing.qrcode.decoder
|
|||
}
|
||||
}
|
||||
}
|
||||
return decode(bits);
|
||||
return decode(bits,hints);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -75,7 +77,7 @@ package com.google.zxing.qrcode.decoder
|
|||
* @return text and bytes encoded within the QR Code
|
||||
* @throws ReaderException if the QR Code cannot be decoded
|
||||
*/
|
||||
public function decode_BitMatrix(bits:BitMatrix ):DecoderResult{
|
||||
public function decode_BitMatrix(bits:BitMatrix, hints:HashTable ):DecoderResult{
|
||||
try{
|
||||
// Construct a parser and read version, error-correction level
|
||||
var parser:BitMatrixParser = new BitMatrixParser(bits);
|
||||
|
@ -109,7 +111,7 @@ package com.google.zxing.qrcode.decoder
|
|||
}
|
||||
|
||||
// Decode the contents of that stream of bytes
|
||||
return DecodedBitStreamParser.decode(resultBytes, version,ecLevel);
|
||||
return DecodedBitStreamParser.decode(resultBytes, version,ecLevel,hints);
|
||||
}catch(e:ReedSolomonException){
|
||||
throw new ReaderException(e.message);
|
||||
}
|
||||
|
@ -146,9 +148,9 @@ package com.google.zxing.qrcode.decoder
|
|||
// We don't care about errors in the error-correction codewords
|
||||
for (var i3:int = 0; i3 < numDataCodewords; i3++)
|
||||
{
|
||||
codewordBytes[i3] = int(codewordsInts[i3]);
|
||||
codewordBytes[i3] = Math.floor(codewordsInts[i3]);
|
||||
// Flex : make bytes
|
||||
if (codewordBytes[i3] > 127) { codewordBytes[i3] = (256-codewordBytes[i3])*-1; }
|
||||
if (codewordBytes[i3] > 127) { codewordBytes[i3] = (256-(Math.floor(codewordBytes[i3])))*-1; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,9 +7,8 @@ package com.google.zxing.qrcode.decoder
|
|||
*/
|
||||
public class ECB
|
||||
{
|
||||
// bas : made public for debugging
|
||||
public var count:int;
|
||||
public var dataCodewords:int;
|
||||
protected var count:int;
|
||||
protected var dataCodewords:int;
|
||||
|
||||
public function ECB(count:int, dataCodewords:int)
|
||||
{
|
||||
|
|
|
@ -3,9 +3,8 @@ package com.google.zxing.qrcode.decoder
|
|||
public class ECBlocks
|
||||
{
|
||||
|
||||
// bas : made public for debugging
|
||||
public var ecCodewordsPerBlock:int;
|
||||
public var ecBlocks:Array;
|
||||
protected var ecCodewordsPerBlock:int;
|
||||
protected var ecBlocks:Array;
|
||||
|
||||
//public function ECBlocks(ecCodewordsPerBlock, ECB ecBlocks)
|
||||
//{
|
||||
|
|
|
@ -38,10 +38,9 @@ package com.google.zxing.qrcode.decoder
|
|||
public static var H:ErrorCorrectionLevel = new ErrorCorrectionLevel(3, 0x02, "H");
|
||||
|
||||
private static var FOR_BITS:Array = [M, L, H, Q];
|
||||
|
||||
private var Ordinal:int;
|
||||
private var bits:int;
|
||||
private var name:String;
|
||||
protected var Ordinal:int;
|
||||
protected var bits:int;
|
||||
protected var name:String;
|
||||
|
||||
public function ErrorCorrectionLevel(ordinal:int, bits:int, name:String) {
|
||||
this.Ordinal = ordinal;
|
||||
|
|
|
@ -96,43 +96,52 @@ package com.google.zxing.qrcode.decoder
|
|||
* @param rawFormatInfo
|
||||
* @return
|
||||
*/
|
||||
public static function decodeFormatInformation(rawFormatInfo:int):FormatInformation
|
||||
public static function decodeFormatInformation(maskedFormatInfo1:int, maskedFormatInfo2:int):FormatInformation
|
||||
{
|
||||
var formatInfo:FormatInformation = doDecodeFormatInformation(rawFormatInfo);
|
||||
if (formatInfo != null)
|
||||
{
|
||||
return formatInfo;
|
||||
}
|
||||
// Should return null, but, some QR codes apparently
|
||||
// do not mask this info. Try again, first masking the raw bits so
|
||||
// the function will unmask
|
||||
return doDecodeFormatInformation(rawFormatInfo ^ FORMAT_INFO_MASK_QR);
|
||||
var formatInfo:FormatInformation = doDecodeFormatInformation(maskedFormatInfo1, maskedFormatInfo2);
|
||||
if (formatInfo != null) {
|
||||
return formatInfo;
|
||||
}
|
||||
// Should return null, but, some QR codes apparently
|
||||
// do not mask this info. Try again by actually masking the pattern
|
||||
// first
|
||||
return doDecodeFormatInformation(maskedFormatInfo1 ^ FORMAT_INFO_MASK_QR,
|
||||
maskedFormatInfo2 ^ FORMAT_INFO_MASK_QR);
|
||||
}
|
||||
|
||||
private static function doDecodeFormatInformation(rawFormatInfo:int):FormatInformation {
|
||||
// Unmask:
|
||||
var unmaskedFormatInfo:int = rawFormatInfo ^ FORMAT_INFO_MASK_QR;
|
||||
// Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing
|
||||
var bestDifference:int = int.MAX_VALUE;
|
||||
var bestFormatInfo:int = 0;
|
||||
for (var i:int = 0; i < FORMAT_INFO_DECODE_LOOKUP.length; i++) {
|
||||
var decodeInfo:Array = FORMAT_INFO_DECODE_LOOKUP[i];
|
||||
var targetInfo:int = decodeInfo[0];
|
||||
if (targetInfo == unmaskedFormatInfo) {
|
||||
// Found an exact match
|
||||
return new FormatInformation(decodeInfo[1]);
|
||||
}
|
||||
var bitsDifference:int = numBitsDiffering(unmaskedFormatInfo, targetInfo);
|
||||
if (bitsDifference < bestDifference) {
|
||||
bestFormatInfo = decodeInfo[1];
|
||||
bestDifference = bitsDifference;
|
||||
}
|
||||
}
|
||||
if (bestDifference <= 3) {
|
||||
return new FormatInformation(bestFormatInfo);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private static function doDecodeFormatInformation(maskedFormatInfo1:int, maskedFormatInfo2:int):FormatInformation
|
||||
{
|
||||
// Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing
|
||||
var bestDifference:int = int.MAX_VALUE;
|
||||
var bestFormatInfo:int = 0;
|
||||
for (var i:int = 0; i < FORMAT_INFO_DECODE_LOOKUP.length; i++) {
|
||||
var decodeInfo:Array = FORMAT_INFO_DECODE_LOOKUP[i];
|
||||
var targetInfo:int = decodeInfo[0];
|
||||
if (targetInfo == maskedFormatInfo1 || targetInfo == maskedFormatInfo2) {
|
||||
// Found an exact match
|
||||
return new FormatInformation(decodeInfo[1]);
|
||||
}
|
||||
var bitsDifference:int = numBitsDiffering(maskedFormatInfo1, targetInfo);
|
||||
if (bitsDifference < bestDifference) {
|
||||
bestFormatInfo = decodeInfo[1];
|
||||
bestDifference = bitsDifference;
|
||||
}
|
||||
if (maskedFormatInfo1 != maskedFormatInfo2) {
|
||||
// also try the other option
|
||||
bitsDifference = numBitsDiffering(maskedFormatInfo2, targetInfo);
|
||||
if (bitsDifference < bestDifference) {
|
||||
bestFormatInfo = decodeInfo[1];
|
||||
bestDifference = bitsDifference;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits
|
||||
// differing means we found a match
|
||||
if (bestDifference <= 3) {
|
||||
return new FormatInformation(bestFormatInfo);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getErrorCorrectionLevel():ErrorCorrectionLevel {
|
||||
return errorCorrectionLevel;
|
||||
|
|
|
@ -37,10 +37,12 @@ package com.google.zxing.qrcode.decoder
|
|||
public static var KANJI:Mode = new Mode([8, 10, 12], 0x08, "KANJI");
|
||||
public static var FNC1_FIRST_POSITION:Mode = new Mode(null, 0x05, "FNC1_FIRST_POSITION");
|
||||
public static var FNC1_SECOND_POSITION:Mode = new Mode(null, 0x09, "FNC1_SECOND_POSITION");
|
||||
/** See GBT 18284-2000; "Hanzi" is a transliteration of this mode name. */
|
||||
public static var HANZI:Mode = new Mode([8, 10, 12], 0x0D, "HANZI");
|
||||
|
||||
private var characterCountBitsForVersions:Array;
|
||||
private var bits:int;
|
||||
private var name:String;
|
||||
protected var characterCountBitsForVersions:Array;
|
||||
protected var bits:int;
|
||||
protected var name:String;
|
||||
|
||||
public function Mode(characterCountBitsForVersions:Array, bits:int, name:String)
|
||||
{
|
||||
|
@ -74,6 +76,9 @@ package com.google.zxing.qrcode.decoder
|
|||
return KANJI;
|
||||
case 0x9:
|
||||
return FNC1_SECOND_POSITION;
|
||||
case 0xD:
|
||||
// 0xD is defined in GBT 18284-2000, may not be supported in foreign country
|
||||
return HANZI;
|
||||
default:
|
||||
throw new IllegalArgumentException("Mode : forBits : bits does not match any format : "+bits);
|
||||
}
|
||||
|
|
|
@ -43,11 +43,10 @@ package com.google.zxing.qrcode.decoder
|
|||
];
|
||||
|
||||
private static var VERSIONS:Array = buildVersions();
|
||||
|
||||
private var versionNumber:int;
|
||||
private var alignmentPatternCenters:Array;
|
||||
private var ecBlocks:Array;
|
||||
private var totalCodewords:int;
|
||||
protected var versionNumber:int;
|
||||
protected var alignmentPatternCenters:Array;
|
||||
protected var ecBlocks:Array;
|
||||
protected var totalCodewords:int;
|
||||
|
||||
public function Version(versionNumber:int,
|
||||
alignmentPatternCenters:Array,
|
||||
|
@ -90,11 +89,9 @@ package com.google.zxing.qrcode.decoder
|
|||
return 17 + 4 * versionNumber;
|
||||
}
|
||||
|
||||
public function getECBlocksForLevel(ecLevel:ErrorCorrectionLevel):ECBlocks
|
||||
public function getECBlocksForLevel(ecLevel:ErrorCorrectionLevel):ECBlocks
|
||||
{
|
||||
var ordinal:int = ecLevel.ordinal();
|
||||
var result:ECBlocks = ecBlocks[ordinal]
|
||||
return result;
|
||||
return ecBlocks[ecLevel.ordinal()];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -163,9 +160,9 @@ package com.google.zxing.qrcode.decoder
|
|||
// Top left finder pattern + separator + format
|
||||
bitMatrix.setRegion(0, 0, 9, 9);
|
||||
// Top right finder pattern + separator + format
|
||||
bitMatrix.setRegion(0, dimension - 8, 9, 8);
|
||||
// Bottom left finder pattern + separator + format
|
||||
bitMatrix.setRegion(dimension - 8, 0, 8, 9);
|
||||
// Bottom left finder pattern + separator + format
|
||||
bitMatrix.setRegion(0, dimension - 8, 9, 8); // bas : hier zat een fout
|
||||
|
||||
// Alignment patterns
|
||||
var max:int = alignmentPatternCenters.length;
|
||||
|
@ -178,20 +175,20 @@ package com.google.zxing.qrcode.decoder
|
|||
// No alignment patterns near the three finder paterns
|
||||
continue;
|
||||
}
|
||||
bitMatrix.setRegion(i, alignmentPatternCenters[y] - 2, 5, 5);
|
||||
bitMatrix.setRegion(alignmentPatternCenters[y] - 2, i, 5, 5);
|
||||
}
|
||||
}
|
||||
|
||||
// Vertical timing pattern
|
||||
bitMatrix.setRegion(9, 6, dimension - 17, 1);
|
||||
bitMatrix.setRegion(6, 9, 1,dimension - 17);
|
||||
// Horizontal timing pattern
|
||||
bitMatrix.setRegion(6, 9, 1, dimension - 17);
|
||||
bitMatrix.setRegion(9, 6, dimension - 17,1);
|
||||
|
||||
if (versionNumber > 6) {
|
||||
// Version info, top right
|
||||
bitMatrix.setRegion(0, dimension - 11, 6, 3);
|
||||
bitMatrix.setRegion(dimension - 11, 0,3,6);
|
||||
// Version info, bottom left
|
||||
bitMatrix.setRegion(dimension - 11, 0, 3, 6);
|
||||
bitMatrix.setRegion(0, dimension - 11, 6,3);
|
||||
}
|
||||
|
||||
return bitMatrix;
|
||||
|
|
|
@ -17,12 +17,29 @@ package com.google.zxing.qrcode.detector
|
|||
* <p>Determines if this alignment pattern "about equals" an alignment pattern at the stated
|
||||
* position and size -- meaning, it is at nearly the same center with nearly the same size.</p>
|
||||
*/
|
||||
public function aboutEquals(moduleSize:Number, i:Number, j:Number):Boolean {
|
||||
return Math.abs(i - getY()) <= moduleSize &&
|
||||
Math.abs(j - getX()) <= moduleSize &&
|
||||
(Math.abs(moduleSize - estimatedModuleSize) <= 1 ||
|
||||
Math.abs(moduleSize - estimatedModuleSize) / estimatedModuleSize <= 0.1);
|
||||
public function aboutEquals(moduleSize:Number, i:Number, j:Number):Boolean
|
||||
{
|
||||
if (Math.abs(i - getY()) <= moduleSize && Math.abs(j - getX()) <= moduleSize)
|
||||
{
|
||||
var moduleSizeDiff:Number = Math.abs(moduleSize - estimatedModuleSize);
|
||||
return moduleSizeDiff <= 1 || moduleSizeDiff <= estimatedModuleSize;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Combines this object's current estimate of a finder pattern position and module size
|
||||
* with a new estimate. It returns a new {@code FinderPattern} containing an average of the two.
|
||||
*/
|
||||
public function combineEstimate(i:Number, j:Number, newModuleSize:Number ):AlignmentPattern {
|
||||
var combinedX:Number = (getX() + j) / 2;
|
||||
var combinedY:Number = (getY() + i) / 2;
|
||||
var combinedModuleSize:Number = (estimatedModuleSize + newModuleSize) / 2;
|
||||
return new AlignmentPattern(combinedX, combinedY, combinedModuleSize);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ package com.google.zxing.qrcode.detector
|
|||
import com.google.zxing.common.BitArray;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.ReaderException;
|
||||
import com.google.zxing.ResultPointCallback;
|
||||
import com.google.zxing.ResultPoint;
|
||||
|
||||
|
||||
private var image:BitMatrix;
|
||||
|
@ -17,6 +19,7 @@ package com.google.zxing.qrcode.detector
|
|||
private var height:int;
|
||||
private var moduleSize:Number;
|
||||
private var crossCheckStateCount:Array;
|
||||
private var resultPointCallback:ResultPointCallback;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -34,15 +37,17 @@ package com.google.zxing.qrcode.detector
|
|||
startY:int,
|
||||
width:int,
|
||||
height:int,
|
||||
moduleSize:Number) {
|
||||
moduleSize:Number,
|
||||
resultPointCallback:ResultPointCallback) {
|
||||
this.image = image;
|
||||
this.possibleCenters = new ArrayList(5);
|
||||
this.possibleCenters = new ArrayList(); // no fixed length : was 5
|
||||
this.startX = startX;
|
||||
this.startY = startY;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.moduleSize = moduleSize;
|
||||
this.crossCheckStateCount = new Array(3);
|
||||
this.resultPointCallback = resultPointCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -60,7 +65,9 @@ package com.google.zxing.qrcode.detector
|
|||
// We are looking for black/white/black modules in 1:1:1 ratio;
|
||||
// this tracks the number of black/white/black modules seen so far
|
||||
var stateCount:Array = new Array(3);
|
||||
for (var iGen:int = 0; iGen < height; iGen++) {
|
||||
for (var iGen:int = 0; iGen < height; iGen++)
|
||||
{
|
||||
|
||||
// Search from middle outwards
|
||||
var i:int = middleI + ((iGen & 0x01) == 0 ? ((iGen + 1) >> 1) : -((iGen + 1) >> 1));
|
||||
stateCount[0] = 0;
|
||||
|
@ -76,6 +83,12 @@ package com.google.zxing.qrcode.detector
|
|||
var currentState:int = 0;
|
||||
while (j < maxJ)
|
||||
{
|
||||
/*
|
||||
if (i==140 && j==210)
|
||||
{
|
||||
var wop:int=0;
|
||||
}
|
||||
*/
|
||||
if (image._get(j,i))
|
||||
{
|
||||
// Black pixel
|
||||
|
@ -103,8 +116,7 @@ package com.google.zxing.qrcode.detector
|
|||
}
|
||||
else
|
||||
{
|
||||
currentState++;
|
||||
stateCount[currentState] = stateCount[currentState] + 1;
|
||||
stateCount[++currentState]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -112,7 +124,7 @@ package com.google.zxing.qrcode.detector
|
|||
if (currentState == 1) { // Counting black pixels
|
||||
currentState++;
|
||||
}
|
||||
stateCount[currentState] = stateCount[currentState] + 1;
|
||||
stateCount[currentState]++;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
|
@ -138,8 +150,9 @@ package com.google.zxing.qrcode.detector
|
|||
* Given a count of black/white/black pixels just seen and an end position,
|
||||
* figures the location of the center of this black/white/black run.
|
||||
*/
|
||||
private static function centerFromEnd(stateCount:Array, end:int):Number {
|
||||
return Number( (end - stateCount[2]) - stateCount[1] / 2);
|
||||
private static function centerFromEnd(stateCount:Array, end:int):Number
|
||||
{
|
||||
return (end - stateCount[2]) - stateCount[1] / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -181,7 +194,7 @@ package com.google.zxing.qrcode.detector
|
|||
// Start counting up from center
|
||||
var i:int = startI;
|
||||
while (i >= 0 && image._get(centerJ, i) && stateCount[1] <= maxCount) {
|
||||
stateCount[1] = stateCount[1] + 1;
|
||||
stateCount[1]++;
|
||||
i--;
|
||||
}
|
||||
// If already too many modules in this state or ran off the edge:
|
||||
|
@ -199,14 +212,14 @@ package com.google.zxing.qrcode.detector
|
|||
// Now also count down from center
|
||||
i = startI + 1;
|
||||
while (i < maxI && image._get(centerJ, i) && stateCount[1] <= maxCount) {
|
||||
stateCount[1] = stateCount[1] + 1;
|
||||
stateCount[1]++;
|
||||
i++;
|
||||
}
|
||||
if (i == maxI || stateCount[1] > maxCount) {
|
||||
return Number.NaN;
|
||||
}
|
||||
while (i < maxI && !image._get(centerJ, i) && stateCount[2] <= maxCount) {
|
||||
stateCount[2] = stateCount[2] + 1;
|
||||
stateCount[2]++;
|
||||
i++;
|
||||
}
|
||||
if (stateCount[2] > maxCount) {
|
||||
|
@ -214,11 +227,11 @@ package com.google.zxing.qrcode.detector
|
|||
}
|
||||
|
||||
var stateCountTotal:int = stateCount[0] + stateCount[1] + stateCount[2];
|
||||
if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal) {
|
||||
if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= 2*originalStateCountTotal) {
|
||||
return Number.NaN;
|
||||
}
|
||||
|
||||
return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : NaN;
|
||||
return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : Number.NaN;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -232,7 +245,8 @@ package com.google.zxing.qrcode.detector
|
|||
* @param j end of possible alignment pattern in row
|
||||
* @return {@link AlignmentPattern} if we have found the same pattern twice, or null if not
|
||||
*/
|
||||
private function handlePossibleCenter(stateCount:Array, i:int, j:int):AlignmentPattern {
|
||||
private function handlePossibleCenter(stateCount:Array, i:int, j:int):AlignmentPattern
|
||||
{
|
||||
var stateCountTotal:int = stateCount[0] + stateCount[1] + stateCount[2];
|
||||
var centerJ:Number = centerFromEnd(stateCount, j);
|
||||
var centerI:Number = crossCheckVertical(i, int(centerJ), 2 * stateCount[1], stateCountTotal);
|
||||
|
@ -242,21 +256,23 @@ package com.google.zxing.qrcode.detector
|
|||
var max:int = possibleCenters.Count;
|
||||
for (var index:int = 0; index < max; index++)
|
||||
{
|
||||
var tmp:Object = possibleCenters.getObjectByIndex(index);
|
||||
if (tmp != null)
|
||||
{
|
||||
var center:AlignmentPattern = AlignmentPattern( tmp);
|
||||
var center:AlignmentPattern = (possibleCenters.getObjectByIndex(index) as AlignmentPattern);
|
||||
// Look for about the same center and module size:
|
||||
if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) {
|
||||
return new AlignmentPattern(centerJ, centerI, estimatedModuleSize);
|
||||
if ((center != null) && (center.aboutEquals(estimatedModuleSize, centerI, centerJ))) {
|
||||
return center.combineEstimate(centerI, centerJ, estimatedModuleSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Hadn't found this before; save it
|
||||
possibleCenters.Add(new AlignmentPattern(centerJ, centerI, estimatedModuleSize));
|
||||
}
|
||||
return null;s
|
||||
var point:ResultPoint = new AlignmentPattern(centerJ, centerI, estimatedModuleSize);
|
||||
possibleCenters.addElement(point);
|
||||
if (resultPointCallback != null)
|
||||
{
|
||||
resultPointCallback.foundPossibleResultPoint(point);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ package com.google.zxing.qrcode.detector
|
|||
*/
|
||||
public class CenterComparator
|
||||
{
|
||||
public static var average:Number = 0;
|
||||
/*
|
||||
public static function compare(center1:Object, center2:Object):int
|
||||
{
|
||||
var res:int = FinderPattern(center2).getCount() - (FinderPattern( center1)).getCount();
|
||||
|
@ -22,5 +24,40 @@ package com.google.zxing.qrcode.detector
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
*/
|
||||
public static function compare(center1:Object, center2:Object):int
|
||||
{
|
||||
if (((center2 as FinderPattern).getCount()) == ((center1 as FinderPattern).getCount()))
|
||||
{
|
||||
var dA:Number = Math.abs((center2 as FinderPattern).getEstimatedModuleSize() - CenterComparator.average);
|
||||
var dB:Number = Math.abs((center1 as FinderPattern).getEstimatedModuleSize() - CenterComparator.average);
|
||||
return dA < dB ? 1 : dA == dB ? 0 : -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ((center2 as FinderPattern).getCount()) - ((center1 as FinderPattern).getCount());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static function setAverage(average:Number):void
|
||||
{
|
||||
CenterComparator.average = average;
|
||||
}
|
||||
/**
|
||||
* <p>Orders by furthest from average</p>
|
||||
*/
|
||||
/*
|
||||
private static class FurthestFromAverageComparator implements Comparator {
|
||||
private final float average;
|
||||
private FurthestFromAverageComparator(float f) {
|
||||
average = f;
|
||||
}
|
||||
public int compare(Object center1, Object center2) {
|
||||
float dA = Math.abs(((FinderPattern) center2).getEstimatedModuleSize() - average);
|
||||
float dB = Math.abs(((FinderPattern) center1).getEstimatedModuleSize() - average);
|
||||
return dA < dB ? -1 : dA == dB ? 0 : 1;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
|
@ -6,13 +6,19 @@ package com.google.zxing.qrcode.detector
|
|||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.DetectorResult;
|
||||
import com.google.zxing.common.GridSampler;
|
||||
import com.google.zxing.common.PerspectiveTransform;
|
||||
import com.google.zxing.qrcode.decoder.Version;
|
||||
import com.google.zxing.ResultPoint;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.ReaderException;
|
||||
import com.google.zxing.ResultPointCallback;
|
||||
import com.google.zxing.DecodeHintType;
|
||||
import com.google.zxing.NotFoundException;
|
||||
import com.google.zxing.ResultPointCallback;
|
||||
|
||||
|
||||
private var image:BitMatrix ;
|
||||
private var resultPointCallback:ResultPointCallback ;
|
||||
|
||||
protected function getImage():BitMatrix
|
||||
{
|
||||
|
@ -25,7 +31,12 @@ package com.google.zxing.qrcode.detector
|
|||
this.image = image;
|
||||
}
|
||||
|
||||
/**
|
||||
public function getResultPointCallback():ResultPointCallback
|
||||
{
|
||||
return resultPointCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Detects a QR Code in an image, simply.</p>
|
||||
*
|
||||
* @return {@link DetectorResult} encapsulating results of detecting a QR Code
|
||||
|
@ -46,69 +57,18 @@ package com.google.zxing.qrcode.detector
|
|||
* @return {@link DetectorResult} encapsulating results of detecting a QR Code
|
||||
* @throws ReaderException if no QR Code can be found
|
||||
*/
|
||||
public function detect(hints:HashTable=null):DetectorResult {
|
||||
public function detect(hints:HashTable=null):DetectorResult
|
||||
{
|
||||
var resultPointCallback:ResultPointCallback = hints == null ? null : (hints._get(DecodeHintType.NEED_RESULT_POINT_CALLBACK) as ResultPointCallback);
|
||||
|
||||
|
||||
var finder:FinderPatternFinder = new FinderPatternFinder(image);
|
||||
var finder:FinderPatternFinder = new FinderPatternFinder(image,resultPointCallback);
|
||||
var info:FinderPatternInfo = finder.find(hints);
|
||||
|
||||
var result:DetectorResult = processFinderPatternInfo(info);
|
||||
return result;
|
||||
}
|
||||
|
||||
var topLeft:FinderPattern = info.getTopLeft();
|
||||
var topRight:FinderPattern = info.getTopRight();
|
||||
var bottomLeft:FinderPattern = info.getBottomLeft();
|
||||
|
||||
var moduleSize:Number = calculateModuleSize(topLeft, topRight, bottomLeft);
|
||||
if (moduleSize < 1) {
|
||||
throw new ReaderException("Detector : detect : moduleSize < 1");
|
||||
}
|
||||
var dimension:int = computeDimension(topLeft, topRight, bottomLeft, moduleSize);
|
||||
|
||||
var provisionalVersion:Version = Version.getProvisionalVersionForDimension(dimension);
|
||||
var modulesBetweenFPCenters:int = provisionalVersion.getDimensionForVersion() - 7;
|
||||
|
||||
var alignmentPattern:AlignmentPattern = null;
|
||||
// Anything above version 1 has an alignment pattern
|
||||
if (provisionalVersion.getAlignmentPatternCenters().length > 0) {
|
||||
|
||||
// Guess where a "bottom right" finder pattern would have been
|
||||
var bottomRightX:Number = topRight.getX() - topLeft.getX() + bottomLeft.getX();
|
||||
var bottomRightY:Number = topRight.getY() - topLeft.getY() + bottomLeft.getY();
|
||||
|
||||
// Estimate that alignment pattern is closer by 3 modules
|
||||
// from "bottom right" to known top left location
|
||||
var correctionToTopLeft:Number = 1 - 3 / Number( modulesBetweenFPCenters);
|
||||
var estAlignmentX:int = int( (topLeft.getX() + correctionToTopLeft * (bottomRightX - topLeft.getX())));
|
||||
var estAlignmentY:int = int( (topLeft.getY() + correctionToTopLeft * (bottomRightY - topLeft.getY())));
|
||||
|
||||
// Kind of arbitrary -- expand search radius before giving up
|
||||
for (var i:int = 4; i <= 16; i <<= 1) {
|
||||
try {
|
||||
alignmentPattern = findAlignmentInRegion(moduleSize,
|
||||
estAlignmentX,
|
||||
estAlignmentY,
|
||||
Number(i));
|
||||
break;
|
||||
} catch (re:ReaderException) {
|
||||
// try next round
|
||||
}
|
||||
}
|
||||
if (alignmentPattern == null) {
|
||||
throw new ReaderException("Detector : detect : alignmentPattern == null");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var bits:BitMatrix = sampleGrid(image, topLeft, topRight, bottomLeft, alignmentPattern, dimension);
|
||||
|
||||
var points:Array;
|
||||
if (alignmentPattern == null) {
|
||||
points = [bottomLeft, topLeft, topRight];
|
||||
} else {
|
||||
points = [bottomLeft, topLeft, topRight, alignmentPattern];
|
||||
}
|
||||
return new DetectorResult(bits, points);
|
||||
}
|
||||
|
||||
protected function processFinderPatternInfo(info:FinderPatternInfo ):DetectorResult
|
||||
public function processFinderPatternInfo(info:FinderPatternInfo ):DetectorResult
|
||||
{
|
||||
|
||||
var topLeft:FinderPattern = info.getTopLeft();
|
||||
|
@ -145,14 +105,19 @@ package com.google.zxing.qrcode.detector
|
|||
estAlignmentY,
|
||||
i);
|
||||
break;
|
||||
} catch (re:ReaderException) {
|
||||
}
|
||||
catch (re:ReaderException)
|
||||
{
|
||||
// try next round
|
||||
}
|
||||
}
|
||||
// If we didn't find alignment pattern... well try anyway without it
|
||||
}
|
||||
|
||||
var bits:BitMatrix = sampleGrid(image, topLeft, topRight, bottomLeft, alignmentPattern, dimension);
|
||||
var transform:PerspectiveTransform =
|
||||
createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension);
|
||||
|
||||
var bits:BitMatrix = sampleGrid(image, transform, dimension);
|
||||
|
||||
var points:Array;
|
||||
if (alignmentPattern == null) {
|
||||
|
@ -164,52 +129,15 @@ package com.google.zxing.qrcode.detector
|
|||
}
|
||||
|
||||
|
||||
private static function sampleGrid(image:BitMatrix ,
|
||||
transform:PerspectiveTransform ,
|
||||
dimension:int ):BitMatrix {
|
||||
|
||||
private static function sampleGrid(image:BitMatrix,
|
||||
topLeft:ResultPoint,
|
||||
topRight:ResultPoint,
|
||||
bottomLeft:ResultPoint,
|
||||
alignmentPattern:ResultPoint,
|
||||
dimension:int):BitMatrix {
|
||||
var dimMinusThree:Number = Number( dimension - 3.5);
|
||||
var bottomRightX:Number;
|
||||
var bottomRightY:Number;
|
||||
var sourceBottomRightX:Number;
|
||||
var sourceBottomRightY:Number;
|
||||
if (alignmentPattern != null) {
|
||||
bottomRightX = alignmentPattern.getX();
|
||||
bottomRightY = alignmentPattern.getY();
|
||||
sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3;
|
||||
} else {
|
||||
// Don't have an alignment pattern, just make up the bottom-right point
|
||||
bottomRightX = (topRight.getX() - topLeft.getX()) + bottomLeft.getX();
|
||||
bottomRightY = (topRight.getY() - topLeft.getY()) + bottomLeft.getY();
|
||||
sourceBottomRightX = sourceBottomRightY = dimMinusThree;
|
||||
}
|
||||
|
||||
var sampler:GridSampler = GridSampler.getGridSamplerInstance();
|
||||
return sampler.sampleGrid(
|
||||
image,
|
||||
dimension,
|
||||
3.5,
|
||||
3.5,
|
||||
dimMinusThree,
|
||||
3.5,
|
||||
sourceBottomRightX,
|
||||
sourceBottomRightY,
|
||||
3.5,
|
||||
dimMinusThree,
|
||||
topLeft.getX(),
|
||||
topLeft.getY(),
|
||||
topRight.getX(),
|
||||
topRight.getY(),
|
||||
bottomRightX,
|
||||
bottomRightY,
|
||||
bottomLeft.getX(),
|
||||
bottomLeft.getY());
|
||||
}
|
||||
|
||||
/**
|
||||
var sampler:GridSampler = GridSampler.getGridSamplerInstance();
|
||||
return sampler.sampleGrid(image, dimension, dimension, transform);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Computes the dimension (number of modules on a size) of the QR Code based on the position
|
||||
* of the finder patterns and estimated module size.</p>
|
||||
*/
|
||||
|
@ -241,8 +169,10 @@ package com.google.zxing.qrcode.detector
|
|||
*/
|
||||
private function calculateModuleSize(topLeft:ResultPoint , topRight:ResultPoint , bottomLeft:ResultPoint ):Number {
|
||||
// Take the average
|
||||
return (calculateModuleSizeOneWay(topLeft, topRight) +
|
||||
calculateModuleSizeOneWay(topLeft, bottomLeft)) / 2;
|
||||
var num1:Number = calculateModuleSizeOneWay(topLeft, topRight);
|
||||
var num2:Number = calculateModuleSizeOneWay(topLeft, bottomLeft);
|
||||
var res:Number = (num1+num2) / 2;
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -261,11 +191,11 @@ package com.google.zxing.qrcode.detector
|
|||
int( pattern.getY()));
|
||||
|
||||
if (isNaN(moduleSizeEst1)) {
|
||||
return moduleSizeEst2;
|
||||
return moduleSizeEst2 / 7;
|
||||
}
|
||||
if (isNaN(moduleSizeEst2))
|
||||
{
|
||||
return moduleSizeEst1;
|
||||
return moduleSizeEst1 / 7;
|
||||
}
|
||||
// Average them, and divide by 7 since we've counted the width of 3 black modules,
|
||||
// and 1 white and 1 black module on either side. Ergo, divide sum by 14.
|
||||
|
@ -282,20 +212,29 @@ package com.google.zxing.qrcode.detector
|
|||
var result:Number = sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY);
|
||||
|
||||
// Now count other way -- don't run off image though of course
|
||||
var scale:Number = 1;
|
||||
var otherToX:int = fromX - (toX - fromX);
|
||||
if (otherToX < 0) {
|
||||
// "to" should the be the first value not included, so, the first value off
|
||||
// the edge is -1
|
||||
otherToX = -1;
|
||||
scale = fromX / (fromX - otherToX);
|
||||
otherToX = 0;
|
||||
} else if (otherToX >= image.getWidth()) {
|
||||
otherToX = image.getWidth();
|
||||
scale = (image.getWidth() - 1 - fromX) / (otherToX - fromX);
|
||||
otherToX = image.getWidth() - 1;
|
||||
}
|
||||
var otherToY:int = fromY - (toY - fromY);
|
||||
var otherToY:int = int(fromY - (toY - fromY) * scale);
|
||||
|
||||
scale = 1;
|
||||
if (otherToY < 0) {
|
||||
otherToY = -1;
|
||||
scale = fromY / (fromY - otherToY);
|
||||
otherToY = 0;
|
||||
} else if (otherToY >= image.getHeight()) {
|
||||
otherToY = image.getHeight();
|
||||
scale = (image.getHeight() - 1 - fromY) / (otherToY - fromY);
|
||||
otherToY = image.getHeight() - 1;
|
||||
}
|
||||
otherToX = int(fromX + (otherToX - fromX) * scale);
|
||||
|
||||
result += sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY);
|
||||
return result - 1; // -1 because we counted the middle pixel twice
|
||||
}
|
||||
|
@ -326,40 +265,52 @@ package com.google.zxing.qrcode.detector
|
|||
var error:int = -dx >> 1;
|
||||
var ystep:int = fromY < toY ? 1 : -1;
|
||||
var xstep:int = fromX < toX ? 1 : -1;
|
||||
var state:int = 0; // In black pixels, looking for white, first or second time
|
||||
var diffX:int =0;
|
||||
var diffY:int =0;
|
||||
// In black pixels, looking for white, first or second time.
|
||||
var state:int = 0;
|
||||
// Loop up until x == toX, but not beyond
|
||||
var xLimit:int = toX + xstep;
|
||||
for (var x:int = fromX, y:int= fromY; x != xLimit; x += xstep)
|
||||
{
|
||||
var realX:int = steep ? y : x;
|
||||
var realY:int = steep ? x : y;
|
||||
|
||||
for (var x:int = fromX, y:int = fromY; x != toX; x += xstep) {
|
||||
|
||||
var realX:int = steep ? y : x;
|
||||
var realY:int = steep ? x : y;
|
||||
if (state == 1) { // In white pixels, looking for black
|
||||
if (image._get(realX, realY)) {
|
||||
state++;
|
||||
}
|
||||
} else {
|
||||
if (!image._get(realX, realY)) {
|
||||
state++;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == 3) { // Found black, white, black, and stumbled back onto white; done
|
||||
diffX = x - fromX;
|
||||
diffY = y - fromY;
|
||||
return Number( Math.sqrt(diffX * diffX + diffY * diffY));
|
||||
}
|
||||
error += dy;
|
||||
if (error > 0) {
|
||||
y += ystep;
|
||||
error -= dx;
|
||||
}
|
||||
}
|
||||
|
||||
diffX = toX - fromX;
|
||||
diffY = toY - fromY;
|
||||
return Number( Math.sqrt(diffX * diffX + diffY * diffY));
|
||||
}
|
||||
// Does current pixel mean we have moved white to black or vice versa?
|
||||
var pixl:Boolean = image._get(realX, realY);
|
||||
if (((state == 0) && !pixl) ||
|
||||
((state == 1) && pixl) ||
|
||||
((state == 2) && !pixl))
|
||||
{
|
||||
if (state == 2)
|
||||
{
|
||||
var diffX:int = x - fromX;
|
||||
var diffY:int = y - fromY;
|
||||
return Math.sqrt(diffX * diffX + diffY * diffY);
|
||||
}
|
||||
state++;
|
||||
}
|
||||
|
||||
error += dy;
|
||||
if (error > 0)
|
||||
{
|
||||
if (y == toY)
|
||||
{
|
||||
break;
|
||||
}
|
||||
y += ystep;
|
||||
error -= dx;
|
||||
}
|
||||
}
|
||||
// Found black-white-black; give the benefit of the doubt that the next pixel outside the image
|
||||
// is "white" so this last point at (toX+xStep,toY) is the right ending. This is really a
|
||||
// small approximation; (toX+xStep,toY+yStep) might be really correct. Ignore this.
|
||||
if (state == 2) {
|
||||
var diffX1:int = toX + xstep - fromX;
|
||||
var diffY1:int = toY - fromY;
|
||||
return Math.sqrt(diffX1 * diffX1 + diffY1 * diffY1);
|
||||
}
|
||||
// else we didn't find even black-white-black; no estimate is really possible
|
||||
return NaN;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Attempts to locate an alignment pattern in a limited region of the image, which is
|
||||
|
@ -378,7 +329,8 @@ package com.google.zxing.qrcode.detector
|
|||
allowanceFactor:Number):AlignmentPattern{
|
||||
// Look for an alignment pattern (3 modules in size) around where it
|
||||
// should be
|
||||
var allowance:int = int((allowanceFactor * overallEstModuleSize));
|
||||
|
||||
var allowance:int = int((allowanceFactor * overallEstModuleSize));
|
||||
var alignmentAreaLeftX:int = Math.max(0, estAlignmentX - allowance);
|
||||
var alignmentAreaRightX:int = Math.min(image.getWidth() - 1, estAlignmentX + allowance);
|
||||
if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3) {
|
||||
|
@ -387,6 +339,10 @@ package com.google.zxing.qrcode.detector
|
|||
|
||||
var alignmentAreaTopY:int = Math.max(0, estAlignmentY - allowance);
|
||||
var alignmentAreaBottomY:int = Math.min(image.getHeight() - 1, estAlignmentY + allowance);
|
||||
if (alignmentAreaBottomY - alignmentAreaTopY < overallEstModuleSize * 3)
|
||||
{
|
||||
throw NotFoundException.getNotFoundInstance();
|
||||
}
|
||||
|
||||
var alignmentFinder:AlignmentPatternFinder =
|
||||
new AlignmentPatternFinder(
|
||||
|
@ -395,7 +351,8 @@ package com.google.zxing.qrcode.detector
|
|||
alignmentAreaTopY,
|
||||
alignmentAreaRightX - alignmentAreaLeftX,
|
||||
alignmentAreaBottomY - alignmentAreaTopY,
|
||||
overallEstModuleSize);
|
||||
overallEstModuleSize,
|
||||
resultPointCallback);
|
||||
return alignmentFinder.find();
|
||||
}
|
||||
|
||||
|
@ -407,5 +364,45 @@ package com.google.zxing.qrcode.detector
|
|||
return int(d + 0.5);
|
||||
}
|
||||
|
||||
public static function createTransform(topLeft:ResultPoint ,
|
||||
topRight:ResultPoint ,
|
||||
bottomLeft:ResultPoint ,
|
||||
alignmentPattern:ResultPoint ,
|
||||
dimension:int):PerspectiveTransform {
|
||||
var dimMinusThree:Number = dimension - 3.5;
|
||||
var bottomRightX:Number;
|
||||
var bottomRightY:Number;
|
||||
var sourceBottomRightX:Number;
|
||||
var sourceBottomRightY:Number;
|
||||
if (alignmentPattern != null) {
|
||||
bottomRightX = alignmentPattern.getX();
|
||||
bottomRightY = alignmentPattern.getY();
|
||||
sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3.0;
|
||||
} else {
|
||||
// Don't have an alignment pattern, just make up the bottom-right point
|
||||
bottomRightX = (topRight.getX() - topLeft.getX()) + bottomLeft.getX();
|
||||
bottomRightY = (topRight.getY() - topLeft.getY()) + bottomLeft.getY();
|
||||
sourceBottomRightX = sourceBottomRightY = dimMinusThree;
|
||||
}
|
||||
|
||||
return PerspectiveTransform.quadrilateralToQuadrilateral(
|
||||
3.5,
|
||||
3.5,
|
||||
dimMinusThree,
|
||||
3.5,
|
||||
sourceBottomRightX,
|
||||
sourceBottomRightY,
|
||||
3.5,
|
||||
dimMinusThree,
|
||||
topLeft.getX(),
|
||||
topLeft.getY(),
|
||||
topRight.getX(),
|
||||
topRight.getY(),
|
||||
bottomRightX,
|
||||
bottomRightY,
|
||||
bottomLeft.getX(),
|
||||
bottomLeft.getY());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -4,13 +4,13 @@ package com.google.zxing.qrcode.detector
|
|||
|
||||
public class FinderPattern extends ResultPoint
|
||||
{
|
||||
private var estimatedModuleSize:Number;
|
||||
private var count:int;
|
||||
protected var estimatedModuleSize:Number;
|
||||
protected var count:int;
|
||||
|
||||
public function FinderPattern(posX:Number, posY:Number, estimatedModuleSize:Number) {
|
||||
public function FinderPattern(posX:Number, posY:Number, estimatedModuleSize:Number, count:int = 1) {
|
||||
super(posX,posY);
|
||||
this.estimatedModuleSize = estimatedModuleSize;
|
||||
this.count = 1;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public function getEstimatedModuleSize():Number
|
||||
|
@ -37,10 +37,26 @@ package com.google.zxing.qrcode.detector
|
|||
if (Math.abs(i - getY()) <= moduleSize && Math.abs(j - getX()) <= moduleSize)
|
||||
{
|
||||
var moduleSizeDiff:Number = Math.abs(moduleSize - estimatedModuleSize);
|
||||
return moduleSizeDiff <= 1 || moduleSizeDiff / estimatedModuleSize <= 1;
|
||||
var result:Boolean = moduleSizeDiff <= 1 || moduleSizeDiff / estimatedModuleSize <= 1;
|
||||
return result;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines this object's current estimate of a finder pattern position and module size
|
||||
* with a new estimate. It returns a new {@code FinderPattern} containing a weighted average
|
||||
* based on count.
|
||||
*/
|
||||
public function combineEstimate(i:Number,j:Number,newModuleSize:Number):FinderPattern
|
||||
{
|
||||
var combinedCount:int = count + 1;
|
||||
var combinedX:Number = (count * getX() + j) / combinedCount;
|
||||
var combinedY:Number = (count * getY() + i) / combinedCount;
|
||||
var combinedModuleSize:Number = (count * getEstimatedModuleSize() + newModuleSize) / combinedCount;
|
||||
return new FinderPattern(combinedX, combinedY, combinedModuleSize, combinedCount);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue