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:
bas5winkel@gmail.com 2012-01-11 16:50:26 +00:00
parent 01c274cfd1
commit 9ee56c0b61
115 changed files with 7832 additions and 2764 deletions

View file

@ -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;
}
}
}

View file

@ -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();

View 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;
}
}
}

View file

@ -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;
}
}
}

View 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;
}
}
}

View file

@ -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();
}
}

View file

@ -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

View file

@ -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);
}
}

View 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;
}
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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)
{

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}
}

View 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
}
}
}

View 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;
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -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;
}
}
}
}

View file

@ -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;
}
}
}

View file

@ -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

View file

@ -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();
}
}
}

View file

@ -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;
}

View file

@ -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;
}
}
}

View file

@ -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 {

View file

@ -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);

View file

@ -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>
*

View 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;
}
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}
}

View file

@ -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
}
}

View file

@ -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();
}
}
}

View file

@ -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;
}
}

View file

@ -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
{

View file

@ -25,7 +25,6 @@
private static var INITIAL_SIZE:int = 32;
// BAS : made public for debugging
private var bytes:Array;
private var Size:int;

View file

@ -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;
}
}
}

View file

@ -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) {

View file

@ -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++];
}
}

View file

@ -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
}
}
/**

View file

@ -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];
}
}

View file

@ -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)))];

View file

@ -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);
}
}
}

View file

@ -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;}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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();
}
}
}

View file

@ -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);
}
}
}
}
}

View file

@ -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();
}
}
}

View file

@ -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;};
}
}

View file

@ -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");
}
}
}
}

View file

@ -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;
}
}
}

View 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 '!';
}
}
}

View file

@ -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);
}*/
}

View 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
}
}
}

View file

@ -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);
}

View 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;
}
}
}
}

View 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();
}
}
}
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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");
}
}
}

View file

@ -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);

View 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;
}
}
}

View file

@ -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
}

View file

@ -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++) {

View file

@ -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;}
}
}

View file

@ -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)
{

View 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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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");
}
}
}
}

View file

@ -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;
}
}
}
}

View file

@ -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();
}
}
}

View file

@ -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;
}
}
}

View file

@ -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

View file

@ -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;
}
*/
}
}

View file

@ -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

View file

@ -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;
}

View file

@ -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();

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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; }
}
}
}

View file

@ -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)
{

View file

@ -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)
//{

View file

@ -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;

View file

@ -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;

View file

@ -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);
}

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}*/
}
}

View file

@ -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());
}
}
}

View file

@ -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