mirror of
https://github.com/zxing/zxing.git
synced 2024-11-09 20:44:03 -08:00
Adding the actionscript3/Flex conversion of the zxing library plus a demo app.
See the readme.txt file and the comments in the zxing client project for more details, hints and remarks. git-svn-id: https://zxing.googlecode.com/svn/trunk@1116 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
f337db0b35
commit
2893fb3804
15
actionscript/core/.actionScriptProperties
Normal file
15
actionscript/core/.actionScriptProperties
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<actionScriptProperties mainApplicationPath="zxing.as" version="3">
|
||||
<compiler additionalCompilerArguments="" copyDependentFiles="false" enableModuleDebug="true" generateAccessible="false" htmlExpressInstall="true" htmlGenerate="false" htmlHistoryManagement="false" htmlPlayerVersion="9.0.28" htmlPlayerVersionCheck="true" outputFolderPath="bin" strict="true" useApolloConfig="false" verifyDigests="true" warn="true">
|
||||
<compilerSourcePath/>
|
||||
<libraryPath defaultLinkType="1">
|
||||
<libraryPathEntry kind="4" path=""/>
|
||||
</libraryPath>
|
||||
<sourceAttachmentPath/>
|
||||
</compiler>
|
||||
<applications>
|
||||
<application path="zxing.as"/>
|
||||
</applications>
|
||||
<modules/>
|
||||
<buildCSSFiles/>
|
||||
</actionScriptProperties>
|
6
actionscript/core/.flexLibProperties
Normal file
6
actionscript/core/.flexLibProperties
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flexLibProperties version="1">
|
||||
<includeClasses/>
|
||||
<includeResources/>
|
||||
<namespaceManifests/>
|
||||
</flexLibProperties>
|
18
actionscript/core/.project
Normal file
18
actionscript/core/.project
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>zxing</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>com.adobe.flexbuilder.project.flexbuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.adobe.flexbuilder.project.flexlibnature</nature>
|
||||
<nature>com.adobe.flexbuilder.project.actionscriptnature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -0,0 +1,3 @@
|
|||
#Thu Nov 05 11:41:58 CET 2009
|
||||
eclipse.preferences.version=1
|
||||
encoding/<project>=utf-8
|
81
actionscript/core/src/com/google/zxing/BarcodeFormat.as
Normal file
81
actionscript/core/src/com/google/zxing/BarcodeFormat.as
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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
|
||||
{
|
||||
/**
|
||||
* Enumerates barcode formats known to this package.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
public class BarcodeFormat
|
||||
{
|
||||
// No, we can't use an enum here. J2ME doesn't support it.
|
||||
/** QR Code 2D barcode format. */
|
||||
public static var QR_CODE:BarcodeFormat = new BarcodeFormat("QR_CODE");
|
||||
/** DataMatrix 2D barcode format. */
|
||||
public static var DATAMATRIX:BarcodeFormat = new BarcodeFormat("DATAMATRIX");
|
||||
/** UPC-E 1D format. */
|
||||
public static var UPC_E:BarcodeFormat = new BarcodeFormat("UPC_E");
|
||||
/** UPC-A 1D format. */
|
||||
public static var UPC_A:BarcodeFormat = new BarcodeFormat("UPC_A");
|
||||
/** 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 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");
|
||||
|
||||
private var _name:String;
|
||||
|
||||
public function BarcodeFormat(name:String)
|
||||
{
|
||||
this._name = name;
|
||||
}
|
||||
|
||||
public function toString():String
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
82
actionscript/core/src/com/google/zxing/Binarizer.as
Normal file
82
actionscript/core/src/com/google/zxing/Binarizer.as
Normal file
|
@ -0,0 +1,82 @@
|
|||
package com.google.zxing
|
||||
{
|
||||
/**
|
||||
* This class hierarchy provides a set of methods to convert luminance data to 1 bit data.
|
||||
* It allows the algorithm to vary polymorphically, for example allowing a very expensive
|
||||
* thresholding technique for servers and a fast one for mobile. It also permits the implementation
|
||||
* to vary, e.g. a JNI version for Android and a Java fallback version for other platforms.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
|
||||
public class Binarizer
|
||||
{
|
||||
|
||||
import com.google.zxing.common.BitArray;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
|
||||
private var source:LuminanceSource;
|
||||
|
||||
public function Binarizer(source:LuminanceSource)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Source must be non-null.");
|
||||
}
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public function getLuminanceSource():LuminanceSource
|
||||
{
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts one row of luminance data to 1 bit data. May actually do the conversion, or return
|
||||
* cached data. Callers should assume this method is expensive and call it as seldom as possible.
|
||||
* This method is intended for decoding 1D barcodes and may choose to apply sharpening.
|
||||
* For callers which only examine one row of pixels at a time, the same BitArray should be reused
|
||||
* and passed in with each call for performance. However it is legal to keep more than one row
|
||||
* at a time if needed.
|
||||
*
|
||||
* @param y The row to fetch, 0 <= y < bitmap height.
|
||||
* @param row An optional preallocated array. If null or too small, it will be ignored.
|
||||
* If used, the Binarizer will call BitArray.clear(). Always use the returned object.
|
||||
* @return The array of bits for this row (true means black).
|
||||
*/
|
||||
public function getBlackRow(y:int, row:BitArray):BitArray
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a 2D array of luminance data to 1 bit data. As above, assume this method is expensive
|
||||
* and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or
|
||||
* may not apply sharpening. Therefore, a row from this matrix may not be identical to one
|
||||
* fetched using getBlackRow(), so don't mix and match between them.
|
||||
*
|
||||
* @return The 2D array of bits for the image (true means black).
|
||||
*/
|
||||
public function getBlackMatrix():BitMatrix
|
||||
{
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new object with the same type as this Binarizer implementation, but with pristine
|
||||
* state. This is needed because Binarizer implementations may be stateful, e.g. keeping a cache
|
||||
* of 1 bit data. See Effective Java for why we can't use Java's clone() method.
|
||||
*
|
||||
* @param source The LuminanceSource this Binarizer will operate on.
|
||||
* @return A new concrete Binarizer implementation object.
|
||||
*/
|
||||
public function createBinarizer(source:LuminanceSource ):Binarizer
|
||||
{
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
141
actionscript/core/src/com/google/zxing/BinaryBitmap.as
Normal file
141
actionscript/core/src/com/google/zxing/BinaryBitmap.as
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* 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
|
||||
{
|
||||
/**
|
||||
* This class is the core bitmap class used by ZXing to represent 1 bit data. Reader objects
|
||||
* accept a BinaryBitmap and attempt to decode it.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
|
||||
import com.google.zxing.common.BitArray;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
|
||||
public final class BinaryBitmap
|
||||
{
|
||||
private var binarizer:Binarizer;
|
||||
private var matrix:BitMatrix;
|
||||
|
||||
public function BinaryBitmap( binarizer:Binarizer)
|
||||
{
|
||||
if (binarizer == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Binarizer must be non-null.");
|
||||
}
|
||||
this.binarizer = binarizer;
|
||||
matrix = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The width of the bitmap.
|
||||
*/
|
||||
public function getWidth():int
|
||||
{
|
||||
return binarizer.getLuminanceSource().getWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The height of the bitmap.
|
||||
*/
|
||||
public function getHeight():int
|
||||
{
|
||||
return binarizer.getLuminanceSource().getHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts one row of luminance data to 1 bit data. May actually do the conversion, or return
|
||||
* cached data. Callers should assume this method is expensive and call it as seldom as possible.
|
||||
* This method is intended for decoding 1D barcodes and may choose to apply sharpening.
|
||||
*
|
||||
* @param y The row to fetch, 0 <= y < bitmap height.
|
||||
* @param row An optional preallocated array. If null or too small, it will be ignored.
|
||||
* If used, the Binarizer will call BitArray.clear(). Always use the returned object.
|
||||
* @return The array of bits for this row (true means black).
|
||||
*/
|
||||
public function getBlackRow(y:int, row:BitArray) :BitArray
|
||||
{
|
||||
return binarizer.getBlackRow(y, row);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a 2D array of luminance data to 1 bit. As above, assume this method is expensive
|
||||
* and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or
|
||||
* may not apply sharpening. Therefore, a row from this matrix may not be identical to one
|
||||
* fetched using getBlackRow(), so don't mix and match between them.
|
||||
*
|
||||
* @return The 2D array of bits for the image (true means black).
|
||||
*/
|
||||
public function getBlackMatrix():BitMatrix
|
||||
{
|
||||
// The matrix is created on demand the first time it is requested, then cached. There are two
|
||||
// reasons for this:
|
||||
// 1. This work will never be done if the caller only installs 1D Reader objects, or if a
|
||||
// 1D Reader finds a barcode before the 2D Readers run.
|
||||
// 2. This work will only be done once even if the caller installs multiple 2D Readers.
|
||||
if (matrix == null)
|
||||
{
|
||||
matrix = binarizer.getBlackMatrix();
|
||||
}
|
||||
return matrix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether this bitmap can be cropped.
|
||||
*/
|
||||
public function isCropSupported():Boolean
|
||||
{
|
||||
return binarizer.getLuminanceSource().isCropSupported();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new object with cropped image data. Implementations may keep a reference to the
|
||||
* original data rather than a copy. Only callable if isCropSupported() is true.
|
||||
*
|
||||
* @param left The left coordinate, 0 <= left < getWidth().
|
||||
* @param top The top coordinate, 0 <= top <= getHeight().
|
||||
* @param width The width of the rectangle to crop.
|
||||
* @param height The height of the rectangle to crop.
|
||||
* @return A cropped version of this object.
|
||||
*/
|
||||
public function crop(left:int, top:int, width:int, height:int ):BinaryBitmap {
|
||||
var newSource:LuminanceSource = binarizer.getLuminanceSource().crop(left, top, width, height);
|
||||
return new BinaryBitmap(binarizer.createBinarizer(newSource));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether this bitmap supports counter-clockwise rotation.
|
||||
*/
|
||||
public function isRotateSupported():Boolean
|
||||
{
|
||||
return binarizer.getLuminanceSource().isRotateSupported();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new object with rotated image data. Only callable if isRotateSupported() is true.
|
||||
*
|
||||
* @return A rotated version of this object.
|
||||
*/
|
||||
public function rotateCounterClockwise():BinaryBitmap
|
||||
{
|
||||
var newSource:LuminanceSource = binarizer.getLuminanceSource().rotateCounterClockwise();
|
||||
return new BinaryBitmap(binarizer.createBinarizer(newSource));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* 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
|
||||
{
|
||||
|
||||
import com.google.zxing.LuminanceSource;
|
||||
import mx.controls.Image;
|
||||
import flash.display.BitmapData;
|
||||
|
||||
/**
|
||||
* This LuminanceSource implementation is meant for J2SE clients and our blackbox unit tests.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class BufferedImageLuminanceSource extends LuminanceSource
|
||||
{
|
||||
|
||||
private var image:BitmapData ;
|
||||
private var left:int;
|
||||
private var top:int;
|
||||
private var rgbData:Array;
|
||||
|
||||
|
||||
public function getRGB(left:int, top:int, width:int, height:int, rgb:Array, value:int, numPixels:int):void
|
||||
{
|
||||
var cntr:int = 0;
|
||||
for (var i:int=top;i<(top+height);i++)
|
||||
{
|
||||
for (var j:int=left;j<(left+width);j++)
|
||||
{
|
||||
rgb[cntr] = image.getPixel(j,i);
|
||||
cntr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function BufferedImageLuminanceSource(image:BitmapData, left:int=0, top:int=0, width:int=0, height:int=0)
|
||||
{
|
||||
if ((width==0) && (height==0))
|
||||
{
|
||||
width = image.width;
|
||||
height = image.height;
|
||||
}
|
||||
super(width,height);
|
||||
|
||||
var sourceWidth:int = image.width;
|
||||
var sourceHeight:int = image.height;
|
||||
if (left + width > sourceWidth || top + height > sourceHeight) {
|
||||
throw new Error("Crop rectangle does not fit within image data.");
|
||||
}
|
||||
|
||||
this.image = image;
|
||||
this.left = left;
|
||||
this.top = top;
|
||||
}
|
||||
|
||||
// These methods use an integer calculation for luminance derived from:
|
||||
// <code>Y = 0.299R + 0.587G + 0.114B</code>
|
||||
public override function getRow(y:int, row:Array):Array {
|
||||
if (y < 0 || y >= image.height) {
|
||||
throw new Error("Requested row is outside the image: " + y);
|
||||
}
|
||||
var width:int = image.width;
|
||||
if (row == null || row.length < width) {
|
||||
row = new Array(width);
|
||||
}
|
||||
|
||||
if (rgbData == null || rgbData.length < width)
|
||||
{
|
||||
rgbData = new Array(width);
|
||||
}
|
||||
this.getRGB(left, top + y, width, 1, rgbData, 0, image.width);
|
||||
for (var x:int = 0; x < width; x++) {
|
||||
var pixel:int = rgbData[x];
|
||||
var luminance:int = (306 * ((pixel >> 16) & 0xFF) +
|
||||
601 * ((pixel >> 8) & 0xFF) +
|
||||
117 * (pixel & 0xFF)) >> 10;
|
||||
row[x] = luminance;
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
public override function getMatrix():Array {
|
||||
var width:int = image.width;
|
||||
var height:int = image.height;
|
||||
var area:int = width * height;
|
||||
var matrix:Array = new Array(area);
|
||||
|
||||
var rgb:Array = new Array(area);
|
||||
this.getRGB(left, top, width, height, rgb, 0, image.width);
|
||||
for (var y:int = 0; y < height; y++) {
|
||||
var offset:int = y * width;
|
||||
for (var x:int = 0; x < width; x++) {
|
||||
var pixel:int = rgb[offset + x];
|
||||
var luminance:int = (306 * ((pixel >> 16) & 0xFF) +
|
||||
601 * ((pixel >> 8) & 0xFF) +
|
||||
117 * (pixel & 0xFF)) >> 10;
|
||||
matrix[offset + x] = luminance;
|
||||
}
|
||||
}
|
||||
return matrix;
|
||||
}
|
||||
|
||||
public override function isCropSupported():Boolean
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override function crop(left:int, top:int, width:int, height:int):LuminanceSource
|
||||
{
|
||||
// BAS : todo
|
||||
return new BufferedImageLuminanceSource(image, left, top, width, height);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Can't run AffineTransforms on images of unknown format.
|
||||
public override function isRotateSupported():Boolean
|
||||
{
|
||||
return false;
|
||||
//Bas : TOO
|
||||
//return image.getType() != BufferedImage.TYPE_CUSTOM;
|
||||
}
|
||||
|
||||
|
||||
public override function rotateCounterClockwise():LuminanceSource
|
||||
{
|
||||
if (!isRotateSupported())
|
||||
{
|
||||
throw new Error("Rotate not supported");
|
||||
}
|
||||
// Bas : todo
|
||||
return null;
|
||||
/*
|
||||
var sourceWidth:int = image.getWidth();
|
||||
var sourceHeight:int = image.getHeight();
|
||||
|
||||
// Rotate 90 degrees counterclockwise.
|
||||
var transform:AffineTransform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, sourceWidth);
|
||||
var op:BufferedImageOp = new AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
|
||||
|
||||
// Note width/height are flipped since we are rotating 90 degrees.
|
||||
var rotatedImage:BufferedImage = new BufferedImage(sourceHeight, sourceWidth, image.getType());
|
||||
op.filter(image, rotatedImage);
|
||||
|
||||
// Maintain the cropped region, but rotate it too.
|
||||
var width:int = getWidth();
|
||||
return new BufferedImageLuminanceSource(rotatedImage, top, sourceWidth - (left + width),
|
||||
getHeight(), width);
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
}
|
65
actionscript/core/src/com/google/zxing/DecodeHintType.as
Normal file
65
actionscript/core/src/com/google/zxing/DecodeHintType.as
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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
|
||||
{
|
||||
/**
|
||||
* Encapsulates a type of hint that a caller may pass to a barcode reader to help it
|
||||
* more quickly or accurately decode it. It is up to implementations to decide what,
|
||||
* if anything, to do with the information that is supplied.
|
||||
*
|
||||
* @author Sean Owen
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
* @see Reader#decode(BinaryBitmap,java.util.Hashtable)
|
||||
*/
|
||||
|
||||
public class DecodeHintType
|
||||
{
|
||||
/**
|
||||
* Unspecified, application-specific hint. Maps to an unspecified {@link Object}.
|
||||
*/
|
||||
public static var OTHER:DecodeHintType = new DecodeHintType();
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
/**
|
||||
*
|
||||
* 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();
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
/**
|
||||
* Allowed lengths of encoded data -- reject anything else. Maps to an int[].
|
||||
*/
|
||||
public static var ALLOWED_LENGTHS:DecodeHintType = new DecodeHintType();
|
||||
|
||||
|
||||
public function DecodeHintType() {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
44
actionscript/core/src/com/google/zxing/EncodeHintType.as
Normal file
44
actionscript/core/src/com/google/zxing/EncodeHintType.as
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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
|
||||
{
|
||||
/**
|
||||
* These are a set of hints that you may pass to Writers to specify their behavior.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
|
||||
public class EncodeHintType
|
||||
{
|
||||
/**
|
||||
* Specifies what degree of error correction to use, for example in QR Codes (type Integer).
|
||||
*/
|
||||
public static var ERROR_CORRECTION:EncodeHintType = new EncodeHintType();
|
||||
|
||||
/**
|
||||
* Specifies what character encoding to use where applicable (type String)
|
||||
*/
|
||||
public static var CHARACTER_SET:EncodeHintType = new EncodeHintType();
|
||||
|
||||
|
||||
public function EncodeHintType()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
115
actionscript/core/src/com/google/zxing/LuminanceSource.as
Normal file
115
actionscript/core/src/com/google/zxing/LuminanceSource.as
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* 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
|
||||
{
|
||||
public class LuminanceSource
|
||||
{
|
||||
/**
|
||||
* The purpose of this class hierarchy is to abstract different bitmap implementations across
|
||||
* platforms into a standard interface for requesting greyscale luminance values. The interface
|
||||
* only provides immutable methods; therefore crop and rotation create copies. This is to ensure
|
||||
* that one Reader does not modify the original luminance source and leave it in an unknown state
|
||||
* for other Readers in the chain.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
private var width:int;
|
||||
private var height:int;
|
||||
|
||||
public function LuminanceSource(width:int, height:int)
|
||||
{
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches one row of luminance data from the underlying platform's bitmap. Values range from
|
||||
* 0 (black) to 255 (white). Because Java does not have an unsigned byte type, callers will have
|
||||
* to bitwise and with 0xff for each value. It is preferrable for implementations of this method
|
||||
* to only fetch this row rather than the whole image, since no 2D Readers may be installed and
|
||||
* getMatrix() may never be called.
|
||||
*
|
||||
* @param y The row to fetch, 0 <= y < getHeight().
|
||||
* @param row An optional preallocated array. If null or too small, it will be ignored.
|
||||
* Always use the returned object, and ignore the .length of the array.
|
||||
* @return An array containing the luminance data.
|
||||
*/
|
||||
public function getRow(y:int, row:Array):Array{ return null};
|
||||
|
||||
/**
|
||||
* Fetches luminance data for the underlying bitmap. Values should be fetched using:
|
||||
* int luminance = array[y * width + x] & 0xff;
|
||||
*
|
||||
* @return A row-major 2D array of luminance values. Do not use result.length as it may be
|
||||
* larger than width * height bytes on some platforms. Do not modify the contents
|
||||
* of the result.
|
||||
*/
|
||||
public function getMatrix():Array{ return null};
|
||||
|
||||
/**
|
||||
* @return The width of the bitmap.
|
||||
*/
|
||||
public final function getWidth():int {
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The height of the bitmap.
|
||||
*/
|
||||
public final function getHeight():int {
|
||||
return height;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether this subclass supports cropping.
|
||||
*/
|
||||
public function isCropSupported():Boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new object with cropped image data. Implementations may keep a reference to the
|
||||
* original data rather than a copy. Only callable if isCropSupported() is true.
|
||||
*
|
||||
* @param left The left coordinate, 0 <= left < getWidth().
|
||||
* @param top The top coordinate, 0 <= top <= getHeight().
|
||||
* @param width The width of the rectangle to crop.
|
||||
* @param height The height of the rectangle to crop.
|
||||
* @return A cropped version of this object.
|
||||
*/
|
||||
public function crop(left:int , top:int , width:int , height:int ):LuminanceSource {
|
||||
throw new Error("This luminance source does not support cropping.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether this subclass supports counter-clockwise rotation.
|
||||
*/
|
||||
public function isRotateSupported():Boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new object with rotated image data. Only callable if isRotateSupported() is true.
|
||||
*
|
||||
* @return A rotated version of this object.
|
||||
*/
|
||||
public function rotateCounterClockwise():LuminanceSource {
|
||||
throw new Error("This luminance source does not support rotation.");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
168
actionscript/core/src/com/google/zxing/MultiFormatReader.as
Normal file
168
actionscript/core/src/com/google/zxing/MultiFormatReader.as
Normal file
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* 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
|
||||
{
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.flexdatatypes.ArrayList;
|
||||
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;
|
||||
/**
|
||||
* 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
|
||||
* can provide a hints object to request different behavior, for example only decoding QR codes.
|
||||
*
|
||||
* @author Sean Owen
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
public class MultiFormatReader implements Reader
|
||||
{
|
||||
|
||||
protected var hints:HashTable;
|
||||
protected var readers:ArrayList;
|
||||
|
||||
|
||||
/**
|
||||
* Decode an image using the hints provided. Does not honor existing state.
|
||||
*
|
||||
* @param image The pixel data to decode
|
||||
* @param hints The hints to use, clearing the previous state.
|
||||
* @return The contents of the image
|
||||
* @throws ReaderException Any errors which occurred
|
||||
*/
|
||||
public function decode( image:BinaryBitmap, hints:HashTable=null):Result
|
||||
{
|
||||
setHints(hints);
|
||||
return decodeInternal(image);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode an image using the state set up by calling setHints() previously. Continuous scan
|
||||
* clients will get a <b>large</b> speed increase by using this instead of decode().
|
||||
*
|
||||
* @param image The pixel data to decode
|
||||
* @return The contents of the image
|
||||
* @throws ReaderException Any errors which occurred
|
||||
*/
|
||||
public function decodeWithState(image:BinaryBitmap):Result{
|
||||
// Make sure to set up the default state so we don't crash
|
||||
if (readers == null) {
|
||||
setHints(null);
|
||||
}
|
||||
return decodeInternal(image);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method adds state to the MultiFormatReader. By setting the hints once, subsequent calls
|
||||
* to decodeWithState(image) can reuse the same set of readers without reallocating memory. This
|
||||
* is important for performance in continuous scan clients.
|
||||
*
|
||||
* @param hints The set of hints to use for subsequent calls to decode(image)
|
||||
*/
|
||||
public function setHints(hints:HashTable):void
|
||||
{
|
||||
this.hints = hints;
|
||||
|
||||
var tryHarder:Boolean = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER);
|
||||
var formats:ArrayList = ((hints == null) ? null : hints.getValuesByKey(DecodeHintType.POSSIBLE_FORMATS));
|
||||
readers = new ArrayList();
|
||||
if (formats != null)
|
||||
{
|
||||
var addOneDReader:Boolean =
|
||||
(formats.indexOf(BarcodeFormat.UPC_A) != -1)||
|
||||
(formats.indexOf(BarcodeFormat.UPC_E) != -1)||
|
||||
(formats.indexOf(BarcodeFormat.ITF) != -1)||
|
||||
(formats.indexOf(BarcodeFormat.EAN_13) != -1)||
|
||||
(formats.indexOf(BarcodeFormat.EAN_8) != -1)||
|
||||
(formats.indexOf(BarcodeFormat.CODE_39) != -1)||
|
||||
(formats.indexOf(BarcodeFormat.CODE_128) != -1);
|
||||
// Put 1D readers upfront in "normal" mode
|
||||
|
||||
if (addOneDReader && !tryHarder)
|
||||
{
|
||||
readers.Add(new MultiFormatOneDReader(hints));
|
||||
}
|
||||
|
||||
if (formats.indexOf(BarcodeFormat.QR_CODE) != -1)
|
||||
{
|
||||
readers.Add(new QRCodeReader());
|
||||
}
|
||||
if (formats.indexOf(BarcodeFormat.PDF417) != -1) {
|
||||
readers.addElement(new PDF417Reader());
|
||||
}
|
||||
|
||||
// TODO re-enable once Data Matrix is ready
|
||||
if (formats.indexOf(BarcodeFormat.DATAMATRIX) != -1) {
|
||||
readers.Add(new DataMatrixReader());
|
||||
}
|
||||
// At end in "try harder" mode
|
||||
if (addOneDReader && tryHarder)
|
||||
{
|
||||
readers.Add(new MultiFormatOneDReader(hints));
|
||||
}
|
||||
}
|
||||
|
||||
if (readers.Count == 0)
|
||||
{
|
||||
if (!tryHarder)
|
||||
{
|
||||
var reader:MultiFormatOneDReader = new MultiFormatOneDReader(hints);
|
||||
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());
|
||||
|
||||
if (tryHarder)
|
||||
{
|
||||
readers.Add(new MultiFormatOneDReader(hints));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function decodeInternal( image:BinaryBitmap):Result
|
||||
{
|
||||
var size:int = readers.Count;
|
||||
for (var i:int = 0; i < size; i++)
|
||||
{
|
||||
var reader:Reader = (readers.getObjectByIndex(i)) as Reader;
|
||||
try
|
||||
{
|
||||
var res:Result = reader.decode(image, hints);
|
||||
return res;
|
||||
}
|
||||
catch ( re:ReaderException)
|
||||
{
|
||||
// continue
|
||||
var a:int=0;
|
||||
}
|
||||
}
|
||||
|
||||
// no decoder could decode the barcode
|
||||
return null;
|
||||
//throw new ReaderException("MultiFormatReader : decodeInternal :could not decode");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
41
actionscript/core/src/com/google/zxing/MultiFormatWriter.as
Normal file
41
actionscript/core/src/com/google/zxing/MultiFormatWriter.as
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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
|
||||
{
|
||||
public class MultiFormatWriter implements Writer
|
||||
{
|
||||
import com.google.zxing.common.ByteMatrix;
|
||||
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.EAN13Writer;
|
||||
import com.google.zxing.oned.EAN8Writer;
|
||||
|
||||
public function encode(contents:String, format:BarcodeFormat=null,width:int=0,height:int=0, hints:HashTable=null):Object{
|
||||
|
||||
if (format == BarcodeFormat.EAN_8) {
|
||||
return (new EAN8Writer()).encode(contents, format, width, height, hints);
|
||||
} else if (format == BarcodeFormat.EAN_13) {
|
||||
return (new EAN13Writer()).encode(contents, format, width, height, hints);
|
||||
} else if (format == BarcodeFormat.QR_CODE) {
|
||||
return (new QRCodeWriter()).encode(contents, format, width, height, hints);
|
||||
} else {
|
||||
throw new IllegalArgumentException("No encoder available for format " + format);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
49
actionscript/core/src/com/google/zxing/Reader.as
Normal file
49
actionscript/core/src/com/google/zxing/Reader.as
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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
|
||||
{
|
||||
/**
|
||||
* Implementations of this interface can decode an image of a barcode in some format into
|
||||
* the String it encodes. For example, {@link com.google.zxing.qrcode.QRCodeReader} can
|
||||
* decode a QR code. The decoder may optionally receive hints from the caller which may help
|
||||
* it decode more quickly or accurately.
|
||||
*
|
||||
* See {@link com.google.zxing.MultiFormatReader}, which attempts to determine what barcode
|
||||
* format is present within the image as well, and then decodes it accordingly.
|
||||
*
|
||||
* @author Sean Owen
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
|
||||
public interface Reader
|
||||
{
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
|
||||
|
||||
/**
|
||||
* Locates and decodes a barcode in some format within an image. This method also accepts
|
||||
* hints, each possibly associated to some data, which may help the implementation decode.
|
||||
*
|
||||
* @param image image of barcode to decode
|
||||
* @param hints passed as a {@link java.util.Hashtable} from {@link com.google.zxing.DecodeHintType} to aribtrary data. The
|
||||
* meaning of the data depends upon the hint type. The implementation may or may not do
|
||||
* anything with these hints.
|
||||
* @return String which the barcode encodes
|
||||
* @throws ReaderException if the barcode cannot be located or decoded for any reason
|
||||
*/
|
||||
function decode(image:BinaryBitmap, hints:HashTable=null):Result;
|
||||
}
|
||||
}
|
57
actionscript/core/src/com/google/zxing/ReaderException.as
Normal file
57
actionscript/core/src/com/google/zxing/ReaderException.as
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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
|
||||
{
|
||||
/**
|
||||
* The general exception class throw when something goes wrong during decoding of a barcode.
|
||||
* This includes, but is not limited to, failing checksums / error correction algorithms, being
|
||||
* unable to locate finder timing patterns, and so on.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
public class ReaderException extends Error
|
||||
{
|
||||
// TODO: Currently we throw up to 400 ReaderExceptions while scanning a single 240x240 image before
|
||||
// rejecting it. This involves a lot of overhead and memory allocation, and affects both performance
|
||||
// and latency on continuous scan clients. In the future, we should change all the decoders not to
|
||||
// throw exceptions for routine events, like not finding a barcode on a given row. Instead, we
|
||||
// should return error codes back to the callers, and simply delete this class. In the mean time, I
|
||||
// have altered this class to be as lightweight as possible, by ignoring the exception string, and
|
||||
// by disabling the generation of stack traces, which is especially time consuming. These are just
|
||||
// temporary measures, pending the big cleanup.
|
||||
|
||||
private static var instance:ReaderException = new ReaderException();
|
||||
|
||||
public function ReaderException(message:String=""):void {
|
||||
super(message);
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public static function getInstance():ReaderException {
|
||||
return instance;
|
||||
}
|
||||
|
||||
// Prevent stack traces from being taken
|
||||
// srowen says: huh, my IDE is saying this is not an override. native methods can't be overridden?
|
||||
// This, at least, does not hurt. Because we use a singleton pattern here, it doesn't matter anyhow.
|
||||
/*public function fillInStackTrace():Throwable {
|
||||
return null;
|
||||
}*/
|
||||
|
||||
}
|
||||
}
|
105
actionscript/core/src/com/google/zxing/Result.as
Normal file
105
actionscript/core/src/com/google/zxing/Result.as
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* 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
|
||||
{
|
||||
/**
|
||||
* <p>Encapsulates the result of decoding a barcode within an image.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public class Result
|
||||
{
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
|
||||
//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;
|
||||
|
||||
public function Result( text:String,
|
||||
rawBytes:Array,
|
||||
resultPoints:Array,
|
||||
format:BarcodeFormat)
|
||||
{
|
||||
if (text == null && rawBytes == null) {
|
||||
throw new IllegalArgumentException("Result : Text and bytes are both null");
|
||||
}
|
||||
this.text = text;
|
||||
this.rawBytes = rawBytes;
|
||||
this.resultPoints = resultPoints;
|
||||
this.format = format;
|
||||
this.resultMetadata = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return raw text encoded by the barcode, if applicable, otherwise <code>null</code>
|
||||
*/
|
||||
public function getText():String {
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return raw bytes encoded by the barcode, if applicable, otherwise <code>null</code>
|
||||
*/
|
||||
public function getRawBytes():Array {
|
||||
return rawBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return points related to the barcode in the image. These are typically points
|
||||
* identifying finder patterns or the corners of the barcode. The exact meaning is
|
||||
* specific to the type of barcode that was decoded.
|
||||
*/
|
||||
public function getResultPoints():Array {
|
||||
return resultPoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link BarcodeFormat} representing the format of the barcode that was recognized and decoded
|
||||
*/
|
||||
public function getBarcodeFormat():BarcodeFormat {
|
||||
return format;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link HashTable} mapping {@link ResultMetadataType} keys to values. May be <code>null</code>.
|
||||
* This contains optional metadata about what was detected about the barcode, like orientation.
|
||||
*/
|
||||
public function getResultMetadata():HashTable {
|
||||
return resultMetadata;
|
||||
}
|
||||
|
||||
public function putMetadata(type:ResultMetadataType, value:Object ):void {
|
||||
if (resultMetadata == null) {
|
||||
resultMetadata = new HashTable(3);
|
||||
}
|
||||
resultMetadata.Add(type, value);
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
if (text == null) {
|
||||
return "[" + rawBytes.length + " bytes]";
|
||||
} else {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
45
actionscript/core/src/com/google/zxing/ResultMetadataType.as
Normal file
45
actionscript/core/src/com/google/zxing/ResultMetadataType.as
Normal file
|
@ -0,0 +1,45 @@
|
|||
package com.google.zxing
|
||||
{
|
||||
public class ResultMetadataType
|
||||
{
|
||||
// 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();
|
||||
|
||||
/**
|
||||
* Denotes the likely approximate orientation of the barcode in the image. This value
|
||||
* is given as degrees rotated clockwise from the normal, upright orientation.
|
||||
* For example a 1D barcode which was found by reading top-to-bottom would be
|
||||
* 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();
|
||||
|
||||
/**
|
||||
* <p>2D barcode formats typically encode text, but allow for a sort of 'byte mode'
|
||||
* which is sometimes used to encode binary data. While {@link Result} makes available
|
||||
* the complete raw bytes in the barcode for these formats, it does not offer the bytes
|
||||
* from the byte segments alone.</p>
|
||||
*
|
||||
* <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();
|
||||
|
||||
/**
|
||||
* 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 function ResultMetadataType() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
150
actionscript/core/src/com/google/zxing/ResultPoint.as
Normal file
150
actionscript/core/src/com/google/zxing/ResultPoint.as
Normal file
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* 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
|
||||
{
|
||||
/**
|
||||
* <p>Encapsulates a point of interest in an image containing a barcode. Typically, this
|
||||
* would be the location of a finder pattern or the corner of the barcode, for example.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
|
||||
public class ResultPoint
|
||||
{
|
||||
|
||||
private var x:Number;
|
||||
private var y:Number;
|
||||
|
||||
public function ResultPoint(x:Number, y:Number)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public final function getX():Number
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
public final function getY():Number
|
||||
{
|
||||
return y;
|
||||
}
|
||||
|
||||
public function equals(other:Object ):Boolean
|
||||
{
|
||||
if (other is ResultPoint)
|
||||
{
|
||||
var otherPoint:ResultPoint = other as ResultPoint;
|
||||
return x == otherPoint.x && y == otherPoint.y;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* no default method to determine a hashcode for Number in Actionscript
|
||||
|
||||
public function hashCode():int
|
||||
{
|
||||
return 31 * identityHashCode(x) + identityHashCode(y);
|
||||
}
|
||||
*/
|
||||
public function toString():String
|
||||
{
|
||||
var result:StringBuilder = new StringBuilder(25);
|
||||
result.Append('(');
|
||||
result.Append(x);
|
||||
result.Append(',');
|
||||
result.Append(y);
|
||||
result.Append(')');
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Orders an array of three ResultPoints in an order [A,B,C] such that AB < AC and
|
||||
* BC < AC and the angle between BC and BA is less than 180 degrees.
|
||||
*/
|
||||
public static function orderBestPatterns(patterns:Array):void
|
||||
{
|
||||
|
||||
// Find distances between pattern centers
|
||||
var zeroOneDistance:Number = distance(patterns[0], patterns[1]);
|
||||
var oneTwoDistance:Number = distance(patterns[1], patterns[2]);
|
||||
var zeroTwoDistance:Number = distance(patterns[0], patterns[2]);
|
||||
|
||||
var pointA:ResultPoint;
|
||||
var pointB:ResultPoint;
|
||||
var pointC:ResultPoint;
|
||||
// Assume one closest to other two is B; A and C will just be guesses at first
|
||||
if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance)
|
||||
{
|
||||
pointB = patterns[0];
|
||||
pointA = patterns[1];
|
||||
pointC = patterns[2];
|
||||
}
|
||||
else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance)
|
||||
{
|
||||
pointB = patterns[1];
|
||||
pointA = patterns[0];
|
||||
pointC = patterns[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
pointB = patterns[2];
|
||||
pointA = patterns[0];
|
||||
pointC = patterns[1];
|
||||
}
|
||||
|
||||
// Use cross product to figure out whether A and C are correct or flipped.
|
||||
// This asks whether BC x BA has a positive z component, which is the arrangement
|
||||
// we want for A, B, C. If it's negative, then we've got it flipped around and
|
||||
// should swap A and C.
|
||||
if (crossProductZ(pointA, pointB, pointC) < 0.0) {
|
||||
var temp:ResultPoint = pointA;
|
||||
pointA = pointC;
|
||||
pointC = temp;
|
||||
}
|
||||
|
||||
patterns[0] = pointA;
|
||||
patterns[1] = pointB;
|
||||
patterns[2] = pointC;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return distance between two points
|
||||
*/
|
||||
public static function distance(pattern1:ResultPoint, pattern2:ResultPoint):Number
|
||||
{
|
||||
var xDiff:Number = pattern1.getX() - pattern2.getX();
|
||||
var yDiff:Number = pattern1.getY() - pattern2.getY();
|
||||
return Math.sqrt(xDiff * xDiff + yDiff * yDiff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the z component of the cross product between vectors BC and BA.
|
||||
*/
|
||||
public static function crossProductZ(pointA:ResultPoint, pointB:ResultPoint, pointC:ResultPoint):Number
|
||||
{
|
||||
var bX:Number = pointB.x;
|
||||
var bY:Number = pointB.y;
|
||||
return ((pointC.x - bX) * (pointA.y - bY)) - ((pointC.y - bY) * (pointA.x - bX));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
40
actionscript/core/src/com/google/zxing/Writer.as
Normal file
40
actionscript/core/src/com/google/zxing/Writer.as
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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
|
||||
{
|
||||
/**
|
||||
* The base class for all objects which encode/generate a barcode image.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
public interface Writer
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
34
actionscript/core/src/com/google/zxing/WriterException.as
Normal file
34
actionscript/core/src/com/google/zxing/WriterException.as
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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
|
||||
{
|
||||
/**
|
||||
* A base class which covers the range of exceptions which may occur when encoding a barcode using
|
||||
* the Writer framework.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
|
||||
public class WriterException extends Error
|
||||
{
|
||||
public function WriterException(message:String=undefined)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* <p>See
|
||||
* <a href="http://www.nttdocomo.co.jp/english/service/imode/make/content/barcode/about/s2.html">
|
||||
* DoCoMo's documentation</a> about the result types represented by subclasses of this class.</p>
|
||||
*
|
||||
* <p>Thanks to Jeff Griffin for proposing rewrite of these classes that relies less
|
||||
* on exception-based mechanisms during parsing.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public class AbstractDoCoMoResultParser extends ResultParser
|
||||
{
|
||||
|
||||
public static function matchDoCoMoPrefixedField(prefix:String , rawText:String, trim:Boolean):Array {
|
||||
return matchPrefixedField(prefix, rawText, ';', trim);
|
||||
}
|
||||
|
||||
public static function matchSingleDoCoMoPrefixedField(prefix:String, rawText:String, trim:Boolean):String {
|
||||
return matchSinglePrefixedField(prefix, rawText, ';', trim);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import com.google.zxing.common.flexdatatypes.ArrayList;
|
||||
import com.google.zxing.Result;
|
||||
|
||||
/**
|
||||
* Implements KDDI AU's address book format. See
|
||||
* <a href="http://www.au.kddi.com/ezfactory/tec/two_dimensions/index.html">
|
||||
* http://www.au.kddi.com/ezfactory/tec/two_dimensions/index.html</a>.
|
||||
* (Thanks to Yuzo for translating!)
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class AddressBookDocomoResultParser extends ResultParser {
|
||||
|
||||
public static function parse(result:Result ):AddressBookParsedResult {
|
||||
var rawText:String = result.getText();
|
||||
// MEMORY is mandatory; seems like a decent indicator, as does end-of-record separator CR/LF
|
||||
if (rawText == null || rawText.indexOf("MEMORY") < 0 || rawText.indexOf("\r\n") < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// NAME1 and NAME2 have specific uses, namely written name and pronunciation, respectively.
|
||||
// Therefore we treat them specially instead of as an array of names.
|
||||
var name:String = matchSinglePrefixedField("NAME1:", rawText, '\r', true);
|
||||
var pronunciation:String = matchSinglePrefixedField("NAME2:", rawText, '\r', true);
|
||||
|
||||
var phoneNumbers:Array = matchMultipleValuePrefix("TEL", 3, rawText, true);
|
||||
var emails:Array = matchMultipleValuePrefix("MAIL", 3, rawText, true);
|
||||
var note:String = matchSinglePrefixedField("MEMORY:", rawText, '\r', false);
|
||||
var address:String = matchSinglePrefixedField("ADD:", rawText, '\r', true);
|
||||
return new AddressBookParsedResult(maybeWrap(name), pronunciation, phoneNumbers, emails, note,
|
||||
address, null, null, null, null);
|
||||
}
|
||||
|
||||
public static function matchMultipleValuePrefix(prefix:String , max:int , rawText:String , trim:Boolean ):Array
|
||||
{
|
||||
var values:ArrayList = null;
|
||||
for (var i:int = 1; i <= max; i++)
|
||||
{
|
||||
var value:String = matchSinglePrefixedField(prefix + i + ':', rawText, '\r', trim);
|
||||
if (value == null) {
|
||||
break;
|
||||
}
|
||||
if (values == null) {
|
||||
values = new ArrayList(max); // lazy init
|
||||
}
|
||||
values.addElement(value);
|
||||
}
|
||||
if (values == null) {
|
||||
return null;
|
||||
}
|
||||
return toStringArray(values);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
|
||||
/**
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class AddressBookParsedResult extends ParsedResult
|
||||
{
|
||||
|
||||
private var names:Array;
|
||||
private var pronunciation:String;
|
||||
private var phoneNumbers:Array;
|
||||
private var emails:Array;
|
||||
private var note:String;
|
||||
private var address:String;
|
||||
private var org:String;
|
||||
private var birthday:String;
|
||||
private var title:String;
|
||||
private var url:String;
|
||||
|
||||
public function AddressBookParsedResult(names:Array,
|
||||
pronunciation:String,
|
||||
phoneNumbers:Array,
|
||||
emails:Array,
|
||||
note:String,
|
||||
address:String,
|
||||
org:String,
|
||||
birthday:String,
|
||||
title:String,
|
||||
url:String) {
|
||||
super(ParsedResultType.ADDRESSBOOK);
|
||||
this.names = names;
|
||||
this.pronunciation = pronunciation;
|
||||
this.phoneNumbers = phoneNumbers;
|
||||
this.emails = emails;
|
||||
this.note = note;
|
||||
this.address = address;
|
||||
this.org = org;
|
||||
this.birthday = birthday;
|
||||
this.title = title;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public function getNames():Array {
|
||||
return names;
|
||||
}
|
||||
|
||||
/**
|
||||
* In Japanese, the name is written in kanji, which can have multiple readings. Therefore a hint
|
||||
* is often provided, called furigana, which spells the name phonetically.
|
||||
*
|
||||
* @return The pronunciation of the getNames() field, often in hiragana or katakana.
|
||||
*/
|
||||
public function getPronunciation():String {
|
||||
return pronunciation;
|
||||
}
|
||||
|
||||
public function getPhoneNumbers():Array {
|
||||
return phoneNumbers;
|
||||
}
|
||||
|
||||
public function getEmails():Array {
|
||||
return emails;
|
||||
}
|
||||
|
||||
public function getNote():String {
|
||||
return note;
|
||||
}
|
||||
|
||||
public function getAddress():String {
|
||||
return address;
|
||||
}
|
||||
|
||||
public function getTitle():String {
|
||||
return title;
|
||||
}
|
||||
|
||||
public function getOrg():String {
|
||||
return org;
|
||||
}
|
||||
|
||||
public function getURL():String {
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return birthday formatted as yyyyMMdd (e.g. 19780917)
|
||||
*/
|
||||
public function getBirthday():String {
|
||||
return birthday;
|
||||
}
|
||||
|
||||
public override function getDisplayResult():String {
|
||||
var result:StringBuilder = new StringBuilder();
|
||||
maybeAppend(names, result);
|
||||
maybeAppend(pronunciation, result);
|
||||
maybeAppend(title, result);
|
||||
maybeAppend(org, result);
|
||||
maybeAppend(address, result);
|
||||
maybeAppend(phoneNumbers, result);
|
||||
maybeAppend(emails, result);
|
||||
maybeAppend(url, result);
|
||||
maybeAppend(birthday, result);
|
||||
maybeAppend(note, result);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
import com.google.zxing.common.flexdatatypes.ArrayList;
|
||||
import com.google.zxing.Result;
|
||||
|
||||
/**
|
||||
* Implements the "BIZCARD" address book entry format, though this has been
|
||||
* largely reverse-engineered from examples observed in the wild -- still
|
||||
* looking for a definitive reference.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class BizcardResultParser extends AbstractDoCoMoResultParser
|
||||
{
|
||||
|
||||
// Yes, we extend AbstractDoCoMoResultParser since the format is very much
|
||||
// like the DoCoMo MECARD format, but this is not technically one of
|
||||
// DoCoMo's proposed formats
|
||||
|
||||
public static function parse(result:Result):AddressBookParsedResult {
|
||||
var rawText:String = result.getText();
|
||||
if (rawText == null || !(rawText.substr(0,8) == "BIZCARD:")) {
|
||||
return null;
|
||||
}
|
||||
var firstName:String = matchSingleDoCoMoPrefixedField("N:", rawText, true);
|
||||
var lastName:String = matchSingleDoCoMoPrefixedField("X:", rawText, true);
|
||||
var fullName:String = buildName(firstName, lastName);
|
||||
var title:String = matchSingleDoCoMoPrefixedField("T:", rawText, true);
|
||||
var org:String = matchSingleDoCoMoPrefixedField("C:", rawText, true);
|
||||
var address:String = matchSingleDoCoMoPrefixedField("A:", rawText, true);
|
||||
var phoneNumber1:String = matchSingleDoCoMoPrefixedField("B:", rawText, true);
|
||||
var phoneNumber2:String = matchSingleDoCoMoPrefixedField("M:", rawText, true);
|
||||
var phoneNumber3:String = matchSingleDoCoMoPrefixedField("F:", rawText, true);
|
||||
var email:String = matchSingleDoCoMoPrefixedField("E:", rawText, true);
|
||||
|
||||
return new AddressBookParsedResult(maybeWrap(fullName),
|
||||
null,
|
||||
buildPhoneNumbers(phoneNumber1, phoneNumber2, phoneNumber3),
|
||||
maybeWrap(email),
|
||||
null,
|
||||
address,
|
||||
org,
|
||||
null,
|
||||
title,
|
||||
null);
|
||||
}
|
||||
|
||||
private static function buildPhoneNumbers(number1:String, number2:String, number3:String ):Array {
|
||||
var numbers:ArrayList = new ArrayList(3);
|
||||
if (number1 != null) {
|
||||
numbers.addElement(number1);
|
||||
}
|
||||
if (number2 != null) {
|
||||
numbers.addElement(number2);
|
||||
}
|
||||
if (number3 != null) {
|
||||
numbers.addElement(number3);
|
||||
}
|
||||
var size:int = numbers.size();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
var result:Array = new Array(size);
|
||||
for (var i:int = 0; i < size; i++) {
|
||||
result[i] = String(numbers.elementAt(i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static function buildName(firstName:String, lastName:String):String
|
||||
{
|
||||
if (firstName == null) {
|
||||
return lastName;
|
||||
} else {
|
||||
return lastName == null ? firstName : firstName + ' ' + lastName;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import com.google.zxing.Result;
|
||||
|
||||
/**
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class BookmarkDoCoMoResultParser extends AbstractDoCoMoResultParser
|
||||
{
|
||||
|
||||
public function BookmarkDoCoMoResultParser()
|
||||
{
|
||||
}
|
||||
|
||||
public static function parse(result:Result):URIParsedResult {
|
||||
var rawText:String = result.getText();
|
||||
if (rawText == null || (rawText.substr(0,6) != "MEBKM:")) {
|
||||
return null;
|
||||
}
|
||||
var title:String = matchSingleDoCoMoPrefixedField("TITLE:", rawText, true);
|
||||
var rawUri:Array = matchDoCoMoPrefixedField("URL:", rawText, true);
|
||||
if (rawUri == null) {
|
||||
return null;
|
||||
}
|
||||
var uri:String = rawUri[0];
|
||||
if (!URIResultParser.isBasicallyValidURI(uri)) {
|
||||
return null;
|
||||
}
|
||||
return new URIParsedResult(uri, title);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
import com.google.zxing.common.flexdatatypes.Utils;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class CalendarParsedResult extends ParsedResult
|
||||
{
|
||||
|
||||
private var summary:String;
|
||||
private var start:String;
|
||||
private var end:String;
|
||||
private var location:String;
|
||||
private var attendee:String;
|
||||
private var title:String;
|
||||
|
||||
public function CalendarParsedResult(summary:String,
|
||||
start:String,
|
||||
end:String,
|
||||
location:String,
|
||||
attendee:String,
|
||||
title:String)
|
||||
{
|
||||
super(ParsedResultType.CALENDAR);
|
||||
// Start is required, end is not
|
||||
if (start == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
validateDate(start);
|
||||
validateDate(end);
|
||||
this.summary = summary;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.location = location;
|
||||
this.attendee = attendee;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public function getSummary():String
|
||||
{
|
||||
return summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>We would return the start and end date as a {@link java.util.Date} except that this code
|
||||
* needs to work under JavaME / MIDP and there is no date parsing library available there, such
|
||||
* as <code>java.text.SimpleDateFormat</code>.</p> See validateDate() for the return format.
|
||||
*
|
||||
* @return start time formatted as a RFC 2445 DATE or DATE-TIME.</p>
|
||||
*/
|
||||
public function getStart():String
|
||||
{
|
||||
return start;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getStart(). May return null if the event has no duration.
|
||||
*/
|
||||
public function getEnd():String
|
||||
{
|
||||
return end;
|
||||
}
|
||||
|
||||
public function getLocation():String
|
||||
{
|
||||
return location;
|
||||
}
|
||||
|
||||
public function getAttendee():String {
|
||||
return attendee;
|
||||
}
|
||||
|
||||
public function getTitle():String {
|
||||
return title;
|
||||
}
|
||||
|
||||
public override function getDisplayResult():String {
|
||||
var result:StringBuilder = new StringBuilder();
|
||||
maybeAppend(summary, result);
|
||||
maybeAppend(start, result);
|
||||
maybeAppend(end, result);
|
||||
maybeAppend(location, result);
|
||||
maybeAppend(attendee, result);
|
||||
maybeAppend(title, result);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* RFC 2445 allows the start and end fields to be of type DATE (e.g. 20081021) or DATE-TIME
|
||||
* (e.g. 20081021T123000 for local time, or 20081021T123000Z for UTC).
|
||||
*
|
||||
* @param date The string to validate
|
||||
*/
|
||||
private static function validateDate( date:String):void {
|
||||
if (date != null) {
|
||||
var length:int = date.length;
|
||||
if (length != 8 && length != 15 && length != 16) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
for (var i:int = 0; i < 8; i++) {
|
||||
if (!Utils.isDigit(date.charAt(i))) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
if (length > 8) {
|
||||
if (date.charAt(8) != 'T') {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
for (var ii:int = 9; ii < 15; i++) {
|
||||
if (!Utils.isDigit(date.charAt(ii))) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
if (length == 16 && date.charAt(15) != 'Z') {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class EmailAddressParsedResult extends ParsedResult
|
||||
{
|
||||
|
||||
private var emailAddress:String;
|
||||
private var subject:String;
|
||||
private var body:String;
|
||||
private var mailtoURI:String;
|
||||
|
||||
public function EmailAddressParsedResult(emailAddress:String, subject:String, body:String , mailtoURI:String )
|
||||
{
|
||||
super(ParsedResultType.EMAIL_ADDRESS);
|
||||
this.emailAddress = emailAddress;
|
||||
this.subject = subject;
|
||||
this.body = body;
|
||||
this.mailtoURI = mailtoURI;
|
||||
}
|
||||
|
||||
public function getEmailAddress():String
|
||||
{
|
||||
return emailAddress;
|
||||
}
|
||||
|
||||
public function getSubject():String
|
||||
{
|
||||
return subject;
|
||||
}
|
||||
|
||||
public function getBody():String
|
||||
{
|
||||
return body;
|
||||
}
|
||||
|
||||
public function getMailtoURI():String
|
||||
{
|
||||
return mailtoURI;
|
||||
}
|
||||
|
||||
public override function getDisplayResult():String
|
||||
{
|
||||
var result:StringBuilder = new StringBuilder();
|
||||
maybeAppend(emailAddress, result);
|
||||
maybeAppend(subject, result);
|
||||
maybeAppend(body, result);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
}}
|
|
@ -0,0 +1,62 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
|
||||
/**
|
||||
* Represents a result that encodes an e-mail address, either as a plain address
|
||||
* like "joe@example.org" or a mailto: URL like "mailto:joe@example.org".
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class EmailAddressResultParser extends ResultParser {
|
||||
|
||||
public static function parse(result:Result):EmailAddressParsedResult {
|
||||
var rawText:String = result.getText();
|
||||
if (rawText == null) {
|
||||
return null;
|
||||
}
|
||||
var emailAddress:String;
|
||||
if ((rawText.substr(0,7) == "mailto:") || (rawText.substr(0,7) == "MAILTO:")) {
|
||||
// If it starts with mailto:, assume it is definitely trying to be an email address
|
||||
emailAddress = rawText.substring(7);
|
||||
var queryStart:int = emailAddress.indexOf('?');
|
||||
if (queryStart >= 0) {
|
||||
emailAddress = emailAddress.substring(0, queryStart);
|
||||
}
|
||||
var nameValues:HashTable = parseNameValuePairs(rawText);
|
||||
var subject:String = null;
|
||||
var body:String = null;
|
||||
if (nameValues != null) {
|
||||
if (emailAddress.length == 0) {
|
||||
emailAddress = String( nameValues._get("to"));
|
||||
}
|
||||
subject = String(nameValues._get("subject"));
|
||||
body = String(nameValues._get("body"));
|
||||
}
|
||||
return new EmailAddressParsedResult(emailAddress, subject, body, rawText);
|
||||
} else {
|
||||
if (!EmailDoCoMoResultParser.isBasicallyValidEmailAddress(rawText)) {
|
||||
return null;
|
||||
}
|
||||
emailAddress = rawText;
|
||||
return new EmailAddressParsedResult(emailAddress, null, null, "mailto:" + emailAddress);
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
|
@ -0,0 +1,88 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.common.flexdatatypes.Utils;
|
||||
|
||||
/**
|
||||
* Implements the "MATMSG" email message entry format.
|
||||
*
|
||||
* Supported keys: TO, SUB, BODY
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class EmailDoCoMoResultParser extends AbstractDoCoMoResultParser {
|
||||
|
||||
private static var ATEXT_SYMBOLS:Array = ['@','.','!','#','$','%','&','\'','*','+','-','/','=','?','^','_','`','{','|','}','~'];
|
||||
|
||||
public static function parse(result:Result):EmailAddressParsedResult {
|
||||
var rawText:String = result.getText();
|
||||
if (rawText == null || !Utils.startsWith(rawText,"MATMSG:")) {
|
||||
return null;
|
||||
}
|
||||
var rawTo:Array = matchDoCoMoPrefixedField("TO:", rawText, true);
|
||||
if (rawTo == null) {
|
||||
return null;
|
||||
}
|
||||
var _to:String = rawTo[0];
|
||||
if (!isBasicallyValidEmailAddress(_to)) {
|
||||
return null;
|
||||
}
|
||||
var subject:String = matchSingleDoCoMoPrefixedField("SUB:", rawText, false);
|
||||
var body:String = matchSingleDoCoMoPrefixedField("BODY:", rawText, false);
|
||||
return new EmailAddressParsedResult(_to, subject, body, "mailto:" + _to);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implements only the most basic checking for an email address's validity -- that it contains
|
||||
* an '@' contains no characters disallowed by RFC 2822. This is an overly lenient definition of
|
||||
* validity. We want to generally be lenient here since this class is only intended to encapsulate what's
|
||||
* in a barcode, not "judge" it.
|
||||
*/
|
||||
public static function isBasicallyValidEmailAddress(email:String):Boolean {
|
||||
if (email == null) {
|
||||
return false;
|
||||
}
|
||||
var atFound:Boolean = false;
|
||||
for (var i:int = 0; i < email.length; i++) {
|
||||
var c:String = email.charAt(i);
|
||||
if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && (c < '0' || c > '9') &&
|
||||
!isAtextSymbol(c)) {
|
||||
return false;
|
||||
}
|
||||
if (c == '@') {
|
||||
if (atFound) {
|
||||
return false;
|
||||
}
|
||||
atFound = true;
|
||||
}
|
||||
}
|
||||
return atFound;
|
||||
}
|
||||
|
||||
private static function isAtextSymbol(c:String):Boolean {
|
||||
for (var i:int = 0; i < ATEXT_SYMBOLS.length; i++) {
|
||||
if (c == ATEXT_SYMBOLS[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class GeoParsedResult extends ParsedResult {
|
||||
|
||||
private var geoURI:String;
|
||||
private var latitude:Number;
|
||||
private var longitude:Number;
|
||||
private var altitude:Number;
|
||||
|
||||
public function GeoParsedResult(geoURI:String, latitude:Number, longitude:Number, altitude:Number ) {
|
||||
super(ParsedResultType.GEO);
|
||||
this.geoURI = geoURI;
|
||||
this.latitude = latitude;
|
||||
this.longitude = longitude;
|
||||
this.altitude = altitude;
|
||||
}
|
||||
|
||||
public function getGeoURI():String {
|
||||
return geoURI;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return latitude in degrees
|
||||
*/
|
||||
public function getLatitude():Number {
|
||||
return latitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return longitude in degrees
|
||||
*/
|
||||
public function getLongitude():Number {
|
||||
return longitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return altitude in meters. If not specified, in the geo URI, returns 0.0
|
||||
*/
|
||||
public function getAltitude():Number {
|
||||
return altitude;
|
||||
}
|
||||
|
||||
public override function getDisplayResult():String {
|
||||
var result:StringBuilder = new StringBuilder(50);
|
||||
result.Append(latitude);
|
||||
result.Append(", ");
|
||||
result.Append(longitude);
|
||||
if (altitude > 0.0) {
|
||||
result.Append(", ");
|
||||
result.Append(altitude);
|
||||
result.Append('m');
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a URI link to Google Maps which display the point on the Earth described
|
||||
* by this instance, and sets the zoom level in a way that roughly reflects the
|
||||
* altitude, if specified
|
||||
*/
|
||||
/*
|
||||
public String getGoogleMapsURI() {
|
||||
StringBuffer result = new StringBuffer(50);
|
||||
result.append("http://maps.google.com/?ll=");
|
||||
result.append(latitude);
|
||||
result.append(',');
|
||||
result.append(longitude);
|
||||
if (altitude > 0.0f) {
|
||||
// Map altitude to zoom level, cleverly. Roughly, zoom level 19 is like a
|
||||
// view from 1000ft, 18 is like 2000ft, 17 like 4000ft, and so on.
|
||||
double altitudeInFeet = altitude * 3.28;
|
||||
int altitudeInKFeet = (int) (altitudeInFeet / 1000.0);
|
||||
// No Math.log() available here, so compute log base 2 the old fashioned way
|
||||
// Here logBaseTwo will take on a value between 0 and 18 actually
|
||||
int logBaseTwo = 0;
|
||||
while (altitudeInKFeet > 1 && logBaseTwo < 18) {
|
||||
altitudeInKFeet >>= 1;
|
||||
logBaseTwo++;
|
||||
}
|
||||
int zoom = 19 - logBaseTwo;
|
||||
result.append("&z=");
|
||||
result.append(zoom);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
*/
|
||||
|
||||
}}
|
|
@ -0,0 +1,65 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import com.google.zxing.Result;
|
||||
|
||||
/**
|
||||
* Parses a "geo:" URI result, which specifices a location on the surface of
|
||||
* the Earth as well as an optional altitude above the surface. See
|
||||
* <a href="http://tools.ietf.org/html/draft-mayrhofer-geo-uri-00">
|
||||
* http://tools.ietf.org/html/draft-mayrhofer-geo-uri-00</a>.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class GeoResultParser extends ResultParser {
|
||||
|
||||
public function GeoResultParser() {
|
||||
}
|
||||
|
||||
public static function parse(result:Result ):GeoParsedResult {
|
||||
var rawText:String = result.getText();
|
||||
if (rawText == null || (!(rawText.substr(0,4) == "geo:") && !(rawText.substr(0,4) == "GEO:"))) {
|
||||
return null;
|
||||
}
|
||||
// Drop geo, query portion
|
||||
var queryStart:int = rawText.indexOf('?', 4);
|
||||
var geoURIWithoutQuery:String = queryStart < 0 ? rawText.substring(4) : rawText.substring(4, queryStart);
|
||||
var latitudeEnd:int = geoURIWithoutQuery.indexOf(',');
|
||||
if (latitudeEnd < 0) {
|
||||
return null;
|
||||
}
|
||||
var longitudeEnd:int = geoURIWithoutQuery.indexOf(',', latitudeEnd + 1);
|
||||
var latitude:Number, longitude:Number, altitude:Number;
|
||||
try {
|
||||
latitude = Number(geoURIWithoutQuery.substring(0, latitudeEnd));
|
||||
if (longitudeEnd < 0) {
|
||||
longitude = Number(geoURIWithoutQuery.substring(latitudeEnd + 1));
|
||||
altitude = 0.0;
|
||||
} else {
|
||||
longitude = Number(geoURIWithoutQuery.substring(latitudeEnd + 1, longitudeEnd));
|
||||
altitude = Number(geoURIWithoutQuery.substring(longitudeEnd + 1));
|
||||
}
|
||||
} catch (nfe:Error) {
|
||||
return null;
|
||||
}
|
||||
return new GeoParsedResult((rawText.substr(0,4) == "GEO:") ? "geo:" + rawText.substring(4) : rawText,
|
||||
latitude, longitude, altitude);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @author jbreiden@google.com (Jeff Breidenbach)
|
||||
*/
|
||||
public final class ISBNParsedResult extends ParsedResult {
|
||||
|
||||
private var isbn:String;
|
||||
|
||||
public function ISBNParsedResult(isbn:String) {
|
||||
super(ParsedResultType.ISBN);
|
||||
this.isbn = isbn;
|
||||
}
|
||||
|
||||
public function getISBN():String {
|
||||
return isbn;
|
||||
}
|
||||
|
||||
public override function getDisplayResult():String {
|
||||
return isbn;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.common.flexdatatypes.Utils;
|
||||
|
||||
/**
|
||||
* Parses strings of digits that represent a ISBN.
|
||||
*
|
||||
* @author jbreiden@google.com (Jeff Breidenbach)
|
||||
*/
|
||||
public class ISBNResultParser extends ResultParser {
|
||||
|
||||
public function ISBNResultParser() {
|
||||
}
|
||||
|
||||
// ISBN-13 For Dummies
|
||||
// http://www.bisg.org/isbn-13/for.dummies.html
|
||||
public static function parse(result:Result):ISBNParsedResult
|
||||
{
|
||||
var format:BarcodeFormat = result.getBarcodeFormat();
|
||||
if (BarcodeFormat.EAN_13 != format) {
|
||||
return null;
|
||||
}
|
||||
var rawText:String = result.getText();
|
||||
if (rawText == null) {
|
||||
return null;
|
||||
}
|
||||
var length:int = rawText.length;
|
||||
if (length != 13) {
|
||||
return null;
|
||||
}
|
||||
if (!Utils.startsWith(rawText,"978") && !Utils.startsWith(rawText,"979")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ISBNParsedResult(rawText);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package com.google.zxing.client.result
|
||||
{/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
|
||||
/**
|
||||
* <p>Abstract class representing the result of decoding a barcode, as more than
|
||||
* a String -- as some type of structured data. This might be a subclass which represents
|
||||
* a URL, or an e-mail address. {@link ResultParser#parseResult(Result)} will turn a raw
|
||||
* decoded string into the most appropriate type of structured representation.</p>
|
||||
*
|
||||
* <p>Thanks to Jeff Griffin for proposing rewrite of these classes that relies less
|
||||
* on exception-based mechanisms during parsing.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public class ParsedResult {
|
||||
|
||||
private var type:ParsedResultType;
|
||||
|
||||
public function ParsedResult(type:ParsedResultType ) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public function getType():ParsedResultType {
|
||||
return type;
|
||||
}
|
||||
|
||||
public function getDisplayResult():String{return '';}
|
||||
|
||||
public function toString():String
|
||||
{
|
||||
return getDisplayResult();
|
||||
}
|
||||
|
||||
public static function maybeAppend(value1:Object, result:StringBuilder ):void
|
||||
{
|
||||
var value:Array;
|
||||
if (value1 is Array) { value = value1 as Array; }
|
||||
else if (value1 is String) { value = [value1]; }
|
||||
if (value != null) {
|
||||
for (var i:int = 0; i < value.length; i++) {
|
||||
if (value[i] != null && value[i].length > 0) {
|
||||
if (result.length > 0) {
|
||||
result.Append('\n');
|
||||
}
|
||||
result.Append(value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents the type of data encoded by a barcode -- from plain text, to a
|
||||
* URI, to an e-mail address, etc.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class ParsedResultType {
|
||||
|
||||
public static var ADDRESSBOOK:ParsedResultType = new ParsedResultType("ADDRESSBOOK");
|
||||
public static var EMAIL_ADDRESS:ParsedResultType = new ParsedResultType("EMAIL_ADDRESS");
|
||||
public static var PRODUCT:ParsedResultType = new ParsedResultType("PRODUCT");
|
||||
public static var URI:ParsedResultType = new ParsedResultType("URI");
|
||||
public static var TEXT:ParsedResultType = new ParsedResultType("TEXT");
|
||||
public static var ANDROID_INTENT:ParsedResultType = new ParsedResultType("ANDROID_INTENT");
|
||||
public static var GEO:ParsedResultType = new ParsedResultType("GEO");
|
||||
public static var TEL:ParsedResultType = new ParsedResultType("TEL");
|
||||
public static var SMS:ParsedResultType = new ParsedResultType("SMS");
|
||||
public static var CALENDAR:ParsedResultType = new ParsedResultType("CALENDAR");
|
||||
// "optional" types
|
||||
public static var NDEF_SMART_POSTER:ParsedResultType = new ParsedResultType("NDEF_SMART_POSTER");
|
||||
public static var MOBILETAG_RICH_WEB:ParsedResultType = new ParsedResultType("MOBILETAG_RICH_WEB");
|
||||
public static var ISBN:ParsedResultType = new ParsedResultType("ISBN");
|
||||
|
||||
private var name:String;
|
||||
|
||||
public function ParsedResultType(name:String) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
public final class ProductParsedResult extends ParsedResult {
|
||||
|
||||
public var productID:String;
|
||||
public var normalizedProductID:String;
|
||||
|
||||
/*
|
||||
public function ProductParsedResult(productID:String)
|
||||
{
|
||||
this(productID, productID);
|
||||
}
|
||||
*/
|
||||
public function ProductParsedResult(productID:String, normalizedProductID:String='')
|
||||
{
|
||||
if (normalizedProductID == '')
|
||||
{
|
||||
normalizedProductID = productID
|
||||
}
|
||||
super(ParsedResultType.PRODUCT);
|
||||
this.productID = productID;
|
||||
this.normalizedProductID = normalizedProductID;
|
||||
}
|
||||
|
||||
public function getProductID():String {
|
||||
return productID;
|
||||
}
|
||||
|
||||
public function getNormalizedProductID():String {
|
||||
return normalizedProductID;
|
||||
}
|
||||
|
||||
public override function getDisplayResult():String {
|
||||
return productID;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.oned.UPCEReader;
|
||||
|
||||
/**
|
||||
* Parses strings of digits that repesent a UPC code.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
public final class ProductResultParser extends ResultParser {
|
||||
|
||||
public function ProductResultParser() {
|
||||
}
|
||||
|
||||
// Treat all UPC and EAN variants as UPCs, in the sense that they are all product barcodes.
|
||||
public static function parse(result:Result):ProductParsedResult {
|
||||
var format:BarcodeFormat = result.getBarcodeFormat();
|
||||
if (!((BarcodeFormat.UPC_A == format) || (BarcodeFormat.UPC_E == format) ||
|
||||
(BarcodeFormat.EAN_8 == format) || (BarcodeFormat.EAN_13 == format))) {
|
||||
return null;
|
||||
}
|
||||
// Really neither of these should happen:
|
||||
var rawText:String = result.getText();
|
||||
if (rawText == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var length:int = rawText.length;
|
||||
for (var x:int = 0; x < length; x++) {
|
||||
var c:int = rawText.charCodeAt(x);//.charAt(x);
|
||||
if (c < ('0').charCodeAt(0) || c > ('9').charCodeAt(0)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// Not actually checking the checksum again here
|
||||
|
||||
var normalizedProductID:String;
|
||||
// Expand UPC-E for purposes of searching
|
||||
if (BarcodeFormat.UPC_E == format) {
|
||||
normalizedProductID = UPCEReader.convertUPCEtoUPCA(rawText);
|
||||
} else {
|
||||
normalizedProductID = rawText;
|
||||
}
|
||||
|
||||
return new ProductParsedResult(rawText, normalizedProductID);
|
||||
}
|
||||
|
||||
}}
|
|
@ -0,0 +1,292 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.flexdatatypes.ArrayList;
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
import com.google.zxing.common.flexdatatypes.Utils;
|
||||
import mx.utils.StringUtil;
|
||||
|
||||
/**
|
||||
* <p>Abstract class representing the result of decoding a barcode, as more than
|
||||
* a String -- as some type of structured data. This might be a subclass which represents
|
||||
* a URL, or an e-mail address. {@link #parseResult(com.google.zxing.Result)} will turn a raw
|
||||
* decoded string into the most appropriate type of structured representation.</p>
|
||||
*
|
||||
* <p>Thanks to Jeff Griffin for proposing rewrite of these classes that relies less
|
||||
* on exception-based mechanisms during parsing.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public class ResultParser {
|
||||
|
||||
public static function parseResult(theResult:Result):ParsedResult {
|
||||
// This is a bit messy, but given limited options in MIDP / CLDC, this may well be the simplest
|
||||
// way to go about this. For example, we have no reflection available, really.
|
||||
// Order is important here.
|
||||
var result:ParsedResult;
|
||||
if ((result = BookmarkDoCoMoResultParser.parse(theResult)) != null) {
|
||||
return result;
|
||||
} else if ((result = AddressBookDocomoResultParser.parse(theResult)) != null) {
|
||||
return result;
|
||||
} else if ((result = EmailDoCoMoResultParser.parse(theResult)) != null) {
|
||||
return result;
|
||||
} else if ((result = AddressBookDocomoResultParser.parse(theResult)) != null) {
|
||||
return result;
|
||||
} else if ((result = VCardResultParser.parse(theResult)) != null) {
|
||||
return result;
|
||||
} else if ((result = BizcardResultParser.parse(theResult)) != null) {
|
||||
return result;
|
||||
} else if ((result = VEventResultParser.parse(theResult)) != null) {
|
||||
return result;
|
||||
} else if ((result = EmailAddressResultParser.parse(theResult)) != null) {
|
||||
return result;
|
||||
} else if ((result = TelResultParser.parse(theResult)) != null) {
|
||||
return result;
|
||||
} else if ((result = SMSMMSResultParser.parse(theResult)) != null) {
|
||||
return result;
|
||||
} else if ((result = GeoResultParser.parse(theResult)) != null) {
|
||||
return result;
|
||||
} else if ((result = URLTOResultParser.parse(theResult)) != null) {
|
||||
return result;
|
||||
} else if ((result = URIResultParser.parse(theResult)) != null) {
|
||||
return result;
|
||||
} else if ((result = ISBNResultParser.parse(theResult)) != null) {
|
||||
// We depend on ISBN parsing coming before UPC, as it is a subset.
|
||||
return result;
|
||||
} else if ((result = ProductResultParser.parse(theResult)) != null) {
|
||||
return result;
|
||||
}
|
||||
return new TextParsedResult(theResult.getText(), null);
|
||||
}
|
||||
|
||||
protected static function maybeAppend(value:String, result:StringBuilder):void {
|
||||
if (value != null) {
|
||||
result.Append('\n');
|
||||
result.Append(value);
|
||||
}
|
||||
}
|
||||
|
||||
protected static function maybeWrap(value:String ):Array {
|
||||
return value == null ? null : [ value ];
|
||||
}
|
||||
|
||||
protected static function unescapeBackslash(escaped:String):String {
|
||||
if (escaped != null) {
|
||||
var backslash:int = escaped.indexOf('\\');
|
||||
if (backslash >= 0) {
|
||||
var max:int = escaped.length;
|
||||
var unescaped:StringBuilder = new StringBuilder(max - 1);
|
||||
unescaped.Append(escaped.split(""), 0, backslash);
|
||||
var nextIsEscaped:Boolean = false;
|
||||
for (var i:int = backslash; i < max; i++) {
|
||||
var c:String = escaped.charAt(i);
|
||||
if (nextIsEscaped || c != '\\') {
|
||||
unescaped.Append(c);
|
||||
nextIsEscaped = false;
|
||||
} else {
|
||||
nextIsEscaped = true;
|
||||
}
|
||||
}
|
||||
return unescaped.toString();
|
||||
}
|
||||
}
|
||||
return escaped;
|
||||
}
|
||||
|
||||
public static function urlDecode(escaped:String):String {
|
||||
|
||||
// No we can't use java.net.URLDecoder here. JavaME doesn't have it.
|
||||
if (escaped == null) {
|
||||
return null;
|
||||
}
|
||||
var escapedArray:Array = escaped.split("");
|
||||
|
||||
var first:int = findFirstEscape(escapedArray);
|
||||
if (first < 0) {
|
||||
return escaped;
|
||||
}
|
||||
|
||||
var max:int = escapedArray.length;
|
||||
// final length is at most 2 less than original due to at least 1 unescaping
|
||||
var unescaped:StringBuilder = new StringBuilder(max - 2);
|
||||
// Can append everything up to first escape character
|
||||
unescaped.Append(escapedArray, 0, first);
|
||||
|
||||
for (var i:int = first; i < max; i++) {
|
||||
var c:String = escapedArray[i];
|
||||
if (c == '+') {
|
||||
// + is translated directly into a space
|
||||
unescaped.Append(' ');
|
||||
} else if (c == '%') {
|
||||
// Are there even two more chars? if not we will just copy the escaped sequence and be done
|
||||
if (i >= max - 2) {
|
||||
unescaped.Append('%'); // append that % and move on
|
||||
} else {
|
||||
var firstDigitValue:int = parseHexDigit(escapedArray[++i]);
|
||||
var secondDigitValue:int = parseHexDigit(escapedArray[++i]);
|
||||
if (firstDigitValue < 0 || secondDigitValue < 0) {
|
||||
// bad digit, just move on
|
||||
unescaped.Append('%');
|
||||
unescaped.Append(escapedArray[i-1]);
|
||||
unescaped.Append(escapedArray[i]);
|
||||
}
|
||||
unescaped.Append(String.fromCharCode((firstDigitValue << 4) + secondDigitValue));
|
||||
}
|
||||
} else {
|
||||
unescaped.Append(c);
|
||||
}
|
||||
}
|
||||
return unescaped.toString();
|
||||
}
|
||||
|
||||
private static function findFirstEscape(escapedArray:Array):int {
|
||||
var max:int = escapedArray.length;
|
||||
for (var i:int = 0; i < max; i++) {
|
||||
var c:String = escapedArray[i];
|
||||
if (c == '+' || c == '%') {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static function parseHexDigit(c:String):int {
|
||||
if (c.charCodeAt(0) >= ('a').charCodeAt(0)) {
|
||||
if (c.charCodeAt(0) <= ('f').charCodeAt(0)) {
|
||||
return 10 + (c.charCodeAt(0) - ('a').charCodeAt(0));
|
||||
}
|
||||
} else if (c.charCodeAt(0) >= ('A').charCodeAt(0)) {
|
||||
if (c.charCodeAt(0) <= ('F').charCodeAt(0)) {
|
||||
return 10 + (c.charCodeAt(0) - ('A').charCodeAt(0));
|
||||
}
|
||||
} else if (c.charCodeAt(0) >= ('0').charCodeAt(0)) {
|
||||
if (c.charCodeAt(0) <= ('9').charCodeAt(0)) {
|
||||
return c.charCodeAt(0) - ('0').charCodeAt(0);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected static function isStringOfDigits(value:String,length:int):Boolean {
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
var stringLength:int = value.length;
|
||||
if (length != stringLength) {
|
||||
return false;
|
||||
}
|
||||
for (var i:int = 0; i < length; i++) {
|
||||
var c:String = value.charAt(i);
|
||||
if (c < '0' || c > '9') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function parseNameValuePairs(uri:String):HashTable {
|
||||
var paramStart:int = uri.indexOf('?');
|
||||
if (paramStart < 0) {
|
||||
return null;
|
||||
}
|
||||
var result:HashTable = new HashTable(3);
|
||||
paramStart++;
|
||||
var paramEnd:int;
|
||||
while ((paramEnd = uri.indexOf('&', paramStart)) >= 0) {
|
||||
appendKeyValue(uri, paramStart, paramEnd, result);
|
||||
paramStart = paramEnd + 1;
|
||||
}
|
||||
appendKeyValue(uri, paramStart, uri.length, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static function appendKeyValue(uri:String , paramStart:int , paramEnd:int, result:HashTable):void {
|
||||
var separator:int = uri.indexOf('=', paramStart);
|
||||
if (separator >= 0) {
|
||||
// key = value
|
||||
var key:String = uri.substring(paramStart, separator);
|
||||
var value:String = uri.substring(separator + 1, paramEnd);
|
||||
value = urlDecode(value);
|
||||
result._put(key, value);
|
||||
}
|
||||
// Can't put key, null into a hashtable
|
||||
}
|
||||
|
||||
public static function matchPrefixedField(prefix:String, rawText:String, endChar:String, trim:Boolean):Array {
|
||||
var matches:ArrayList = null;
|
||||
var i:int = 0;
|
||||
var max:int = rawText.length;
|
||||
while (i < max) {
|
||||
i = rawText.indexOf(prefix, i);
|
||||
if (i < 0) {
|
||||
break;
|
||||
}
|
||||
i += prefix.length; // Skip past this prefix we found to start
|
||||
var start:int = i; // Found the start of a match here
|
||||
var done:Boolean = false;
|
||||
while (!done) {
|
||||
i = rawText.indexOf( endChar, i);
|
||||
if (i < 0) {
|
||||
// No terminating end character? uh, done. Set i such that loop terminates and break
|
||||
i = rawText.length;
|
||||
done = true;
|
||||
} else if (rawText.charAt(i - 1) == '\\') {
|
||||
// semicolon was escaped so continue
|
||||
i++;
|
||||
} else {
|
||||
// found a match
|
||||
if (matches == null) {
|
||||
matches = new ArrayList(3); // lazy init
|
||||
}
|
||||
var element:String = unescapeBackslash(rawText.substring(start, i));
|
||||
if (trim) {
|
||||
element = StringUtil.trim(element);
|
||||
}
|
||||
matches.addElement(element);
|
||||
i++;
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (matches == null || matches.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return toStringArray(matches);
|
||||
}
|
||||
|
||||
public static function matchSinglePrefixedField(prefix:String, rawText:String, endChar:String, trim:Boolean ):String
|
||||
{
|
||||
var matches:Array = matchPrefixedField(prefix, rawText, endChar, trim);
|
||||
return matches == null ? null : matches[0];
|
||||
}
|
||||
|
||||
public static function toStringArray(strings:ArrayList):Array {
|
||||
var size:int = strings.size();
|
||||
var result:Array = new Array(size);
|
||||
for (var j:int = 0; j < size; j++) {
|
||||
result[j] = String(strings.elementAt(j));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.flexdatatypes.Utils;
|
||||
|
||||
/**
|
||||
* <p>Parses an "sms:" URI result, which specifies a number to SMS and optional
|
||||
* "via" number. See <a href="http://gbiv.com/protocols/uri/drafts/draft-antti-gsm-sms-url-04.txt">
|
||||
* the IETF draft</a> on this.</p>
|
||||
*
|
||||
* <p>This actually also parses URIs starting with "mms:", "smsto:", "mmsto:", "SMSTO:", and
|
||||
* "MMSTO:", and treats them all the same way, and effectively converts them to an "sms:" URI
|
||||
* for purposes of forwarding to the platform.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class SMSMMSResultParser extends ResultParser {
|
||||
|
||||
public function SMSMMSResultParser() {
|
||||
}
|
||||
|
||||
public static function parse(result:Result):SMSParsedResult {
|
||||
var rawText:String = result.getText();
|
||||
if (rawText == null) {
|
||||
return null;
|
||||
}
|
||||
var prefixLength:int;
|
||||
if (Utils.startsWith(rawText,"sms:") || Utils.startsWith(rawText,"SMS:") ||
|
||||
Utils.startsWith(rawText,"mms:") || Utils.startsWith(rawText,"MMS:")) {
|
||||
prefixLength = 4;
|
||||
} else if (Utils.startsWith(rawText,"smsto:") || Utils.startsWith(rawText,"SMSTO:") ||
|
||||
Utils.startsWith(rawText,"mmsto:") || Utils.startsWith(rawText,"MMSTO:")) {
|
||||
prefixLength = 6;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check up front if this is a URI syntax string with query arguments
|
||||
var nameValuePairs:HashTable = parseNameValuePairs(rawText);
|
||||
var subject:String = null;
|
||||
var body:String = null;
|
||||
var querySyntax:Boolean = false;
|
||||
if (nameValuePairs != null && !nameValuePairs.isEmpty()) {
|
||||
subject = String(nameValuePairs._get("subject"));
|
||||
body = String( nameValuePairs._get("body"));
|
||||
querySyntax = true;
|
||||
}
|
||||
|
||||
// Drop sms, query portion
|
||||
var queryStart:int = rawText.indexOf('?', prefixLength);
|
||||
var smsURIWithoutQuery:String;
|
||||
// If it's not query syntax, the question mark is part of the subject or message
|
||||
if (queryStart < 0 || !querySyntax) {
|
||||
smsURIWithoutQuery = rawText.substring(prefixLength);
|
||||
} else {
|
||||
smsURIWithoutQuery = rawText.substring(prefixLength, queryStart);
|
||||
}
|
||||
var numberEnd:int = smsURIWithoutQuery.indexOf(';');
|
||||
var number:String;
|
||||
var via:String;
|
||||
if (numberEnd < 0) {
|
||||
number = smsURIWithoutQuery;
|
||||
via = null;
|
||||
} else {
|
||||
number = smsURIWithoutQuery.substring(0, numberEnd);
|
||||
var maybeVia:String = smsURIWithoutQuery.substring(numberEnd + 1);
|
||||
if (Utils.startsWith(maybeVia,"via=")) {
|
||||
via = maybeVia.substring(4);
|
||||
} else {
|
||||
via = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Thanks to dominik.wild for suggesting this enhancement to support
|
||||
// smsto:number:body URIs
|
||||
if (body == null) {
|
||||
var bodyStart:int = number.indexOf(':');
|
||||
if (bodyStart >= 0) {
|
||||
body = number.substring(bodyStart + 1);
|
||||
number = number.substring(0, bodyStart);
|
||||
}
|
||||
}
|
||||
return new SMSParsedResult("sms:" + number, number, via, subject, body, null);
|
||||
}
|
||||
|
||||
}}
|
|
@ -0,0 +1,77 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
/**
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class SMSParsedResult extends ParsedResult {
|
||||
|
||||
private var smsURI:String;
|
||||
private var number:String;
|
||||
private var via:String;
|
||||
private var subject:String;
|
||||
private var body:String;
|
||||
private var title:String;
|
||||
|
||||
public function SMSParsedResult(smsURI:String ,number:String ,via:String,subject:String, body:String, title:String) {
|
||||
super(ParsedResultType.SMS);
|
||||
this.smsURI = smsURI;
|
||||
this.number = number;
|
||||
this.via = via;
|
||||
this.subject = subject;
|
||||
this.body = body;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public function getSMSURI():String {
|
||||
return smsURI;
|
||||
}
|
||||
|
||||
public function getNumber():String {
|
||||
return number;
|
||||
}
|
||||
|
||||
public function getVia():String {
|
||||
return via;
|
||||
}
|
||||
|
||||
public function getSubject():String {
|
||||
return subject;
|
||||
}
|
||||
|
||||
public function getBody():String {
|
||||
return body;
|
||||
}
|
||||
|
||||
public function getTitle():String {
|
||||
return title;
|
||||
}
|
||||
|
||||
public override function getDisplayResult():String {
|
||||
var result:StringBuilder = new StringBuilder();
|
||||
maybeAppend(number, result);
|
||||
maybeAppend(via, result);
|
||||
maybeAppend(subject, result);
|
||||
maybeAppend(body, result);
|
||||
maybeAppend(title, result);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
/**
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class TelParsedResult extends ParsedResult {
|
||||
|
||||
private var number:String;
|
||||
private var telURI:String;
|
||||
private var title:String;
|
||||
|
||||
public function TelParsedResult(number:String, telURI:String,title:String) {
|
||||
super(ParsedResultType.TEL);
|
||||
this.number = number;
|
||||
this.telURI = telURI;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public function getNumber():String {
|
||||
return number;
|
||||
}
|
||||
|
||||
public function getTelURI():String {
|
||||
return telURI;
|
||||
}
|
||||
|
||||
public function getTitle():String {
|
||||
return title;
|
||||
}
|
||||
|
||||
public override function getDisplayResult():String {
|
||||
var result:StringBuilder = new StringBuilder();
|
||||
maybeAppend(number, result);
|
||||
maybeAppend(title, result);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
}}
|
|
@ -0,0 +1,46 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.common.flexdatatypes.Utils;
|
||||
|
||||
/**
|
||||
* Parses a "tel:" URI result, which specifies a phone number.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class TelResultParser extends ResultParser {
|
||||
|
||||
public function TelResultParser() {
|
||||
}
|
||||
|
||||
public static function parse(result:Result):TelParsedResult {
|
||||
var rawText:String = result.getText();
|
||||
if (rawText == null || (!Utils.startsWith(rawText,"tel:") && !Utils.startsWith(rawText,"TEL:"))) {
|
||||
return null;
|
||||
}
|
||||
// Normalize "TEL:" to "tel:"
|
||||
var telURI:String = Utils.startsWith(rawText,"TEL:") ? "tel:" + rawText.substring(4) : rawText;
|
||||
// Drop tel, query portion
|
||||
var queryStart:int = rawText.indexOf('?', 4);
|
||||
var number:String = queryStart < 0 ? rawText.substring(4) : rawText.substring(4, queryStart);
|
||||
return new TelParsedResult(number, telURI, null);
|
||||
}
|
||||
|
||||
}}
|
|
@ -0,0 +1,51 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* A simple result type encapsulating a string that has no further
|
||||
* interpretation.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class TextParsedResult extends ParsedResult {
|
||||
|
||||
private var text:String;
|
||||
private var language:String;
|
||||
|
||||
public function TextParsedResult(text:String, language:String) {
|
||||
super(ParsedResultType.TEXT);
|
||||
this.text = text;
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
public function getText():String {
|
||||
return text;
|
||||
}
|
||||
|
||||
public function getLanguage():String {
|
||||
return language;
|
||||
}
|
||||
|
||||
public override function getDisplayResult():String {
|
||||
return text;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
/**
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class URIParsedResult extends ParsedResult {
|
||||
|
||||
private var uri:String;
|
||||
private var title:String;
|
||||
|
||||
public function URIParsedResult(uri:String,title:String) {
|
||||
super(ParsedResultType.URI);
|
||||
this.uri = massageURI(uri);
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public function getURI():String {
|
||||
return uri;
|
||||
}
|
||||
|
||||
public function getTitle():String {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the URI contains suspicious patterns that may suggest it intends to
|
||||
* mislead the user about its true nature. At the moment this looks for the presence
|
||||
* of user/password syntax in the host/authority portion of a URI which may be used
|
||||
* in attempts to make the URI's host appear to be other than it is. Example:
|
||||
* http://yourbank.com@phisher.com This URI connects to phisher.com but may appear
|
||||
* to connect to yourbank.com at first glance.
|
||||
*/
|
||||
public function isPossiblyMaliciousURI():Boolean {
|
||||
return containsUser();
|
||||
}
|
||||
|
||||
private function containsUser():Boolean {
|
||||
// This method is likely not 100% RFC compliant yet
|
||||
var hostStart:int = uri.indexOf(':'); // we should always have scheme at this point
|
||||
hostStart++;
|
||||
// Skip slashes preceding host
|
||||
var uriLength:int = uri.length;
|
||||
while (hostStart < uriLength && uri.charAt(hostStart) == '/') {
|
||||
hostStart++;
|
||||
}
|
||||
var hostEnd:int = uri.indexOf('/', hostStart);
|
||||
if (hostEnd < 0) {
|
||||
hostEnd = uriLength;
|
||||
}
|
||||
var at:int = uri.indexOf('@', hostStart);
|
||||
return at >= hostStart && at < hostEnd;
|
||||
}
|
||||
|
||||
public override function getDisplayResult():String {
|
||||
var result:StringBuilder = new StringBuilder();
|
||||
maybeAppend(title, result);
|
||||
maybeAppend(uri, result);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a string that represents a URI into something more proper, by adding or canonicalizing
|
||||
* the protocol.
|
||||
*/
|
||||
private static function massageURI(uri:String):String {
|
||||
var protocolEnd:int = uri.indexOf(':');
|
||||
if (protocolEnd < 0) {
|
||||
// No protocol, assume http
|
||||
uri = "http://" + uri;
|
||||
} else if (isColonFollowedByPortNumber(uri, protocolEnd)) {
|
||||
// Found a colon, but it looks like it is after the host, so the protocol is still missing
|
||||
uri = "http://" + uri;
|
||||
} else {
|
||||
// Lowercase protocol to avoid problems
|
||||
uri = uri.substring(0, protocolEnd).toLowerCase() + uri.substring(protocolEnd);
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
||||
private static function isColonFollowedByPortNumber(uri:String, protocolEnd:int):Boolean {
|
||||
var nextSlash:int = uri.indexOf('/', protocolEnd + 1);
|
||||
if (nextSlash < 0) {
|
||||
nextSlash = uri.length;
|
||||
}
|
||||
if (nextSlash <= protocolEnd + 1) {
|
||||
return false;
|
||||
}
|
||||
for (var x:int = protocolEnd + 1; x < nextSlash; x++) {
|
||||
if (uri.charAt(x) < '0' || uri.charAt(x) > '9') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.common.flexdatatypes.Utils;
|
||||
|
||||
/**
|
||||
* Tries to parse results that are a URI of some kind.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class URIResultParser extends ResultParser {
|
||||
|
||||
public function URIResultParser() {
|
||||
}
|
||||
|
||||
public static function parse(result:Result):URIParsedResult {
|
||||
var rawText:String = result.getText();
|
||||
// We specifically handle the odd "URL" scheme here for simplicity
|
||||
if (rawText != null && Utils.startsWith(rawText,"URL:")) {
|
||||
rawText = rawText.substring(4);
|
||||
}
|
||||
if (!isBasicallyValidURI(rawText)) {
|
||||
return null;
|
||||
}
|
||||
return new URIParsedResult(rawText, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a string is not obviously not a URI. This implements crude checks; this class does not
|
||||
* intend to strictly check URIs as its only function is to represent what is in a barcode, but, it does
|
||||
* need to know when a string is obviously not a URI.
|
||||
*/
|
||||
public static function isBasicallyValidURI(uri:String):Boolean {
|
||||
|
||||
if (uri == null || uri.indexOf(' ') >= 0 || uri.indexOf('\n') >= 0) {
|
||||
return false;
|
||||
}
|
||||
var period:int = uri.indexOf('.');
|
||||
// Look for period in a domain but followed by at least a two-char TLD
|
||||
return period < uri.length - 2 && (period >= 0 || uri.indexOf(':') >= 0);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.common.flexdatatypes.Utils;
|
||||
|
||||
/**
|
||||
* Parses the "URLTO" result format, which is of the form "URLTO:[title]:[url]".
|
||||
* This seems to be used sometimes, but I am not able to find documentation
|
||||
* on its origin or official format?
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class URLTOResultParser {
|
||||
|
||||
public function URLTOResultParser() {
|
||||
}
|
||||
|
||||
public static function parse(result:Result):URIParsedResult {
|
||||
var rawText:String = result.getText();
|
||||
if (rawText == null || (!Utils.startsWith(rawText,"urlto:") && !Utils.startsWith(rawText,"URLTO:"))) {
|
||||
return null;
|
||||
}
|
||||
var titleEnd:int = rawText.indexOf(':', 6);
|
||||
if (titleEnd < 0) {
|
||||
return null;
|
||||
}
|
||||
var title:String = titleEnd <= 6 ? null : rawText.substring(6, titleEnd);
|
||||
var uri:String = rawText.substring(titleEnd + 1);
|
||||
return new URIParsedResult(uri, title);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.common.flexdatatypes.ArrayList;
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
import com.google.zxing.common.flexdatatypes.Utils;
|
||||
import mx.utils.StringUtil;
|
||||
|
||||
/**
|
||||
* Parses contact information formatted according to the VCard (2.1) format. This is not a complete
|
||||
* implementation but should parse information as commonly encoded in 2D barcodes.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class VCardResultParser extends ResultParser {
|
||||
|
||||
public function VCardResultParser() {
|
||||
}
|
||||
|
||||
public static function parse(result:Result):AddressBookParsedResult {
|
||||
var rawText:String = result.getText();
|
||||
if (rawText == null || (Utils.startsWith(rawText,"BEGIN:VCARD")) || !Utils.endsWith(rawText,"END:VCARD")) {
|
||||
return null;
|
||||
}
|
||||
var names:Array = matchVCardPrefixedField("FN", rawText, true);
|
||||
if (names == null) {
|
||||
// If no display names found, look for regular name fields and format them
|
||||
names = matchVCardPrefixedField("N", rawText, true);
|
||||
formatNames(names);
|
||||
}
|
||||
var phoneNumbers:Array = matchVCardPrefixedField("TEL", rawText, true);
|
||||
var emails:Array = matchVCardPrefixedField("EMAIL", rawText, true);
|
||||
var note:String = matchSingleVCardPrefixedField("NOTE", rawText, false);
|
||||
var address:String = matchSingleVCardPrefixedField("ADR", rawText, true);
|
||||
address = formatAddress(address);
|
||||
var org:String = matchSingleVCardPrefixedField("ORG", rawText, true);
|
||||
var birthday:String = matchSingleVCardPrefixedField("BDAY", rawText, true);
|
||||
if (birthday != null && !isStringOfDigits(birthday, 8)) {
|
||||
return null;
|
||||
}
|
||||
var title:String = matchSingleVCardPrefixedField("TITLE", rawText, true);
|
||||
var url:String = matchSingleVCardPrefixedField("URL", rawText, true);
|
||||
return new AddressBookParsedResult(names, null, phoneNumbers, emails, note, address, org,
|
||||
birthday, title, url);
|
||||
}
|
||||
|
||||
private static function matchVCardPrefixedField(prefix:String, rawText:String, trim:Boolean):Array {
|
||||
var matches:ArrayList = null;
|
||||
var i:int = 0;
|
||||
var max:int = rawText.length;
|
||||
while (i < max) {
|
||||
i = rawText.indexOf(prefix, i);
|
||||
if (i < 0) {
|
||||
break;
|
||||
}
|
||||
if (i > 0 && rawText.charAt(i - 1) != '\n') {
|
||||
// then this didn't start a new token, we matched in the middle of something
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
i += prefix.length; // Skip past this prefix we found to start
|
||||
if (rawText.charAt(i) != ':' && rawText.charAt(i) != ';') {
|
||||
continue;
|
||||
}
|
||||
while (rawText.charAt(i) != ':') { // Skip until a colon
|
||||
i++;
|
||||
}
|
||||
i++; // skip colon
|
||||
var start:int = i; // Found the start of a match here
|
||||
i = rawText.indexOf('\n', i); // Really, ends in \r\n
|
||||
if (i < 0) {
|
||||
// No terminating end character? uh, done. Set i such that loop terminates and break
|
||||
i = max;
|
||||
} else if (i > start) {
|
||||
// found a match
|
||||
if (matches == null) {
|
||||
matches = new ArrayList(3); // lazy init
|
||||
}
|
||||
var element:String = rawText.substring(start, i);
|
||||
if (trim) {
|
||||
element = StringUtil.trim(element);
|
||||
}
|
||||
matches.addElement(element);
|
||||
i++;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (matches == null || matches.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return toStringArray(matches);
|
||||
}
|
||||
|
||||
public static function matchSingleVCardPrefixedField(prefix:String , rawText:String , trim:Boolean):String {
|
||||
var values:Array = matchVCardPrefixedField(prefix, rawText, trim);
|
||||
return values == null ? null : values[0];
|
||||
}
|
||||
|
||||
private static function formatAddress(address:String):String {
|
||||
if (address == null) {
|
||||
return null;
|
||||
}
|
||||
var length:int = address.length;
|
||||
var newAddress:StringBuilder = new StringBuilder(length);
|
||||
for (var j:int = 0; j < length; j++) {
|
||||
var c:String = address.charAt(j);
|
||||
if (c == ';') {
|
||||
newAddress.Append(' ');
|
||||
} else {
|
||||
newAddress.Append(c);
|
||||
}
|
||||
}
|
||||
return StringUtil.trim(newAddress.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats name fields of the form "Public;John;Q.;Reverend;III" into a form like
|
||||
* "Reverend John Q. Public III".
|
||||
*
|
||||
* @param names name values to format, in place
|
||||
*/
|
||||
private static function formatNames(names:Array):void {
|
||||
if (names != null) {
|
||||
for (var i:int = 0; i < names.length; i++) {
|
||||
var name:String = names[i];
|
||||
var components:Array = new Array(5);
|
||||
var start:int = 0;
|
||||
var end:int;
|
||||
var componentIndex:int = 0;
|
||||
while ((end = name.indexOf(';', start)) > 0) {
|
||||
components[componentIndex] = name.substring(start, end);
|
||||
componentIndex++;
|
||||
start = end + 1;
|
||||
}
|
||||
components[componentIndex] = name.substring(start);
|
||||
var newName:StringBuilder = new StringBuilder();
|
||||
maybeAppendComponent(components, 3, newName);
|
||||
maybeAppendComponent(components, 1, newName);
|
||||
maybeAppendComponent(components, 2, newName);
|
||||
maybeAppendComponent(components, 0, newName);
|
||||
maybeAppendComponent(components, 4, newName);
|
||||
names[i] = StringUtil.trim(newName.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function maybeAppendComponent(components:Array,i:int, newName:StringBuilder):void {
|
||||
if (components[i] != null) {
|
||||
newName.Append(' ');
|
||||
newName.Append(components[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package com.google.zxing.client.result
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Partially implements the iCalendar format's "VEVENT" format for specifying a
|
||||
* calendar event. See RFC 2445. This supports SUMMARY, DTSTART and DTEND fields.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class VEventResultParser extends ResultParser {
|
||||
|
||||
public function VEventResultParser() {
|
||||
}
|
||||
|
||||
public static function parse(result:Result):CalendarParsedResult {
|
||||
var rawText:String = result.getText();
|
||||
if (rawText == null) {
|
||||
return null;
|
||||
}
|
||||
var vEventStart:int = rawText.indexOf("BEGIN:VEVENT");
|
||||
if (vEventStart < 0) {
|
||||
return null;
|
||||
}
|
||||
var vEventEnd:int = rawText.indexOf("END:VEVENT");
|
||||
if (vEventEnd < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var summary:String = VCardResultParser.matchSingleVCardPrefixedField("SUMMARY", rawText, true);
|
||||
var start:String = VCardResultParser.matchSingleVCardPrefixedField("DTSTART", rawText, true);
|
||||
var end:String = VCardResultParser.matchSingleVCardPrefixedField("DTEND", rawText, true);
|
||||
try {
|
||||
return new CalendarParsedResult(summary, start, end, null, null, null);
|
||||
} catch (iae:IllegalArgumentException) {
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package com.google.zxing.client.result.optional
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import com.google.zxing.client.result.ResultParser;
|
||||
import com.google.zxing.common.flexdatatypes.Utils;
|
||||
/**
|
||||
* <p>Superclass for classes encapsulating reader results encoded according
|
||||
* to the MobileTag Reader International Specification.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public class AbstractMobileTagResultParser extends ResultParser {
|
||||
|
||||
public static var ACTION_DO:int = 1;
|
||||
public static var ACTION_EDIT:int = 2;
|
||||
public static var ACTION_SAVE:int = 4;
|
||||
|
||||
public static function matchDelimitedFields(rawText:String, maxItems:int):Array {
|
||||
var result:Array = new Array(maxItems);
|
||||
var item:int = 0;
|
||||
var i:int = 0;
|
||||
var max:int = rawText.length;
|
||||
while (item < maxItems && i < max) {
|
||||
var start:int = i; // Found the start of a match here
|
||||
var done:Boolean = false;
|
||||
while (!done) {
|
||||
i = rawText.indexOf('|', i);
|
||||
if (i < 0) {
|
||||
// No terminating end character? done. Set i such that loop terminates and break
|
||||
i = rawText.length;
|
||||
done = true;
|
||||
} else if (rawText.charAt(i - 1) == '\\') {
|
||||
// semicolon was escaped so continue
|
||||
i++;
|
||||
} else {
|
||||
// found a match
|
||||
if (start != i) {
|
||||
result[item] = unescapeBackslash(rawText.substring(start, i));
|
||||
}
|
||||
item++;
|
||||
i++;
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (item < maxItems) {
|
||||
return null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static function isDigits(s:String, expectedLength:int):Boolean
|
||||
{
|
||||
if (s == null) {
|
||||
return true;
|
||||
}
|
||||
if (s.length != expectedLength) {
|
||||
return false;
|
||||
}
|
||||
for (var i:int = 0; i < expectedLength; i++) {
|
||||
if (!Utils.isDigit(s.charAt(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}}
|
|
@ -0,0 +1,47 @@
|
|||
package com.google.zxing.client.result.optional
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
import com.google.zxing.client.result.ResultParser;
|
||||
|
||||
/**
|
||||
* <p>Superclass for classes encapsulating results in the NDEF format.
|
||||
* See <a href="http://www.nfc-forum.org/specs/">http://www.nfc-forum.org/specs/</a>.</p>
|
||||
*
|
||||
* <p>This code supports a limited subset of NDEF messages, ones that are plausibly
|
||||
* useful in 2D barcode formats. This generally includes 1-record messages, no chunking,
|
||||
* "short record" syntax, no ID field.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public class AbstractNDEFResultParser extends ResultParser {
|
||||
|
||||
public static function bytesToString(bytes:Array, offset:int, length:int, encoding:String):String {
|
||||
try {
|
||||
// can't do this in Actionscript
|
||||
//return new String(bytes, offset, length, encoding);
|
||||
throw new Error("Platform does not support encoding");
|
||||
} catch (uee:Error) {
|
||||
// This should only be used when 'encoding' is an encoding that must necessarily
|
||||
// be supported by the JVM, like UTF-8
|
||||
throw new Error("Platform does not support required encoding: " + uee);
|
||||
}
|
||||
throw new Error("Platform does not support encoding");
|
||||
}
|
||||
|
||||
}}
|
|
@ -0,0 +1,74 @@
|
|||
package com.google.zxing.client.result.optional
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.common.flexdatatypes.ArrayList;
|
||||
import com.google.zxing.client.result.ParsedResult;
|
||||
import com.google.zxing.client.result.ResultParser;
|
||||
import com.google.zxing.client.result.AddressBookParsedResult;
|
||||
|
||||
/**
|
||||
* Implements KDDI AU's address book format. See
|
||||
* <a href="http://www.au.kddi.com/ezfactory/tec/two_dimensions/index.html">
|
||||
* http://www.au.kddi.com/ezfactory/tec/two_dimensions/index.html</a>.
|
||||
* (Thanks to Yuzo for translating!)
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class AddressBookAUResultParser extends ResultParser {
|
||||
|
||||
public static function parse(result:Result):AddressBookParsedResult {
|
||||
var rawText:String = result.getText();
|
||||
// MEMORY is mandatory; seems like a decent indicator, as does end-of-record separator CR/LF
|
||||
if (rawText == null || rawText.indexOf("MEMORY") < 0 || rawText.indexOf("\r\n") < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// NAME1 and NAME2 have specific uses, namely written name and pronunciation, respectively.
|
||||
// Therefore we treat them specially instead of as an array of names.
|
||||
var name:String = matchSinglePrefixedField("NAME1:", rawText, '\r', true);
|
||||
var pronunciation:String = matchSinglePrefixedField("NAME2:", rawText, '\r', true);
|
||||
|
||||
var phoneNumbers:Array = matchMultipleValuePrefix("TEL", 3, rawText, true);
|
||||
var emails:Array = matchMultipleValuePrefix("MAIL", 3, rawText, true);
|
||||
var note:String = matchSinglePrefixedField("MEMORY:", rawText, '\r', false);
|
||||
var address:String = matchSinglePrefixedField("ADD:", rawText, '\r', true);
|
||||
return new AddressBookParsedResult(maybeWrap(name), pronunciation, phoneNumbers, emails, note,
|
||||
address, null, null, null, null);
|
||||
}
|
||||
|
||||
private static function matchMultipleValuePrefix(prefix:String, max:int, rawText:String, trim:Boolean):Array {
|
||||
var values:ArrayList = null;
|
||||
for (var i:int = 1; i <= max; i++) {
|
||||
var value:String = matchSinglePrefixedField(prefix + i + ':', rawText, '\r', trim);
|
||||
if (value == null) {
|
||||
break;
|
||||
}
|
||||
if (values == null) {
|
||||
values = new ArrayList(max); // lazy init
|
||||
}
|
||||
values.addElement(value);
|
||||
}
|
||||
if (values == null) {
|
||||
return null;
|
||||
}
|
||||
return toStringArray(values);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package com.google.zxing.client.result.optional
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.client.result.SMSParsedResult;
|
||||
|
||||
/**
|
||||
* <p>Represents a "MMS" result encoded according to section 4.7 of the
|
||||
* MobileTag Reader International Specification.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class MobileTagMMSResultParser extends AbstractMobileTagResultParser {
|
||||
|
||||
public static var SERVICE_TYPE:String = "05";
|
||||
|
||||
public static function parse(result:Result):SMSParsedResult {
|
||||
if (result.getBarcodeFormat() != BarcodeFormat.DATAMATRIX) {
|
||||
return null;
|
||||
}
|
||||
var rawText:String = result.getText();
|
||||
if (rawText.substr(0,(SERVICE_TYPE).length) != SERVICE_TYPE) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var matches:Array = matchDelimitedFields(rawText.substring(2), 4);
|
||||
if (matches == null) {
|
||||
return null;
|
||||
}
|
||||
var _to:String = matches[0];
|
||||
var subject:String = matches[1];
|
||||
var body:String = matches[2];
|
||||
var title:String = matches[3];
|
||||
|
||||
return new SMSParsedResult("sms:" + _to, _to, null, subject, body, title);
|
||||
}
|
||||
|
||||
}}
|
|
@ -0,0 +1,63 @@
|
|||
package com.google.zxing.client.result.optional
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
import com.google.zxing.client.result.ParsedResult;
|
||||
import com.google.zxing.client.result.ParsedResultType;
|
||||
|
||||
/**
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class MobileTagRichWebParsedResult extends ParsedResult {
|
||||
|
||||
// Example: "http://www.tagserver.com/script.asp?id="
|
||||
public static var TAGSERVER_URI_PREFIX:String;// = System.getProperty("zxing.mobiletag.tagserver");
|
||||
|
||||
private var id:String;
|
||||
private var action:int;
|
||||
|
||||
public function MobileTagRichWebParsedResult(id:String, action:int, tagserver:String)
|
||||
{
|
||||
super(ParsedResultType.MOBILETAG_RICH_WEB);
|
||||
this.id = id;
|
||||
this.action = action;
|
||||
MobileTagRichWebParsedResult.TAGSERVER_URI_PREFIX = tagserver;
|
||||
}
|
||||
|
||||
public static function getTagserverURIPrefix():String {
|
||||
return MobileTagRichWebParsedResult.TAGSERVER_URI_PREFIX;
|
||||
}
|
||||
|
||||
public function getId():String {
|
||||
return id;
|
||||
}
|
||||
|
||||
public function getAction():int {
|
||||
return action;
|
||||
}
|
||||
|
||||
public function getTagserverURI():String {
|
||||
return TAGSERVER_URI_PREFIX + id;
|
||||
}
|
||||
|
||||
public override function getDisplayResult():String {
|
||||
return id;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package com.google.zxing.client.result.optional
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
import com.google.zxing.common.flexdatatypes.Utils;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
|
||||
/**
|
||||
* <p>Represents a "rich web" result encoded according to section 5 of the
|
||||
* MobileTag Reader International Specification.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class MobileTagRichWebResultParser extends AbstractMobileTagResultParser {
|
||||
|
||||
public static var SERVICE_TYPE:String = "54";
|
||||
private static var DEFAULT_ACTION:int = AbstractMobileTagResultParser.ACTION_DO;
|
||||
|
||||
public static function parse(result:Result,tagserver:String):MobileTagRichWebParsedResult {
|
||||
if (MobileTagRichWebParsedResult.TAGSERVER_URI_PREFIX == null) {
|
||||
return null;
|
||||
}
|
||||
if (result.getBarcodeFormat() != BarcodeFormat.DATAMATRIX) {
|
||||
return null;
|
||||
}
|
||||
var rawText:String = result.getText();
|
||||
if (!Utils.startsWith(rawText,SERVICE_TYPE)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var length:int = rawText.length;
|
||||
if (!isDigits(rawText, length)) {
|
||||
return null;
|
||||
}
|
||||
var action:int;
|
||||
var id:String;
|
||||
if (length == 15) {
|
||||
action = DEFAULT_ACTION;
|
||||
id = rawText.substring(0, 2) + action + rawText.substring(2);
|
||||
} else if (length == 16) {
|
||||
action = rawText.charCodeAt(2) - ('0').charCodeAt(0);
|
||||
id = rawText;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new MobileTagRichWebParsedResult(id, action,tagserver);
|
||||
}
|
||||
|
||||
}}
|
|
@ -0,0 +1,55 @@
|
|||
package com.google.zxing.client.result.optional
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.client.result.SMSParsedResult;
|
||||
import com.google.zxing.common.flexdatatypes.Utils;
|
||||
|
||||
/**
|
||||
* <p>Represents a "SMS" result encoded according to section 4.6 of the
|
||||
* MobileTag Reader International Specification.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class MobileTagSMSResultParser extends AbstractMobileTagResultParser {
|
||||
|
||||
public static var SERVICE_TYPE:String = "03";
|
||||
|
||||
public static function parse(result:Result):SMSParsedResult {
|
||||
if (result.getBarcodeFormat() != BarcodeFormat.DATAMATRIX) {
|
||||
return null;
|
||||
}
|
||||
var rawText:String = result.getText();
|
||||
if (!Utils.startsWith(rawText,SERVICE_TYPE)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var matches:Array = matchDelimitedFields(rawText.substring(2), 3);
|
||||
if (matches == null) {
|
||||
return null;
|
||||
}
|
||||
var _to:String = matches[0];
|
||||
var body:String = matches[1];
|
||||
var title:String = matches[2];
|
||||
|
||||
return new SMSParsedResult("sms:" + _to, _to, null, null, body, title);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package com.google.zxing.client.result.optional
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.client.result.CalendarParsedResult;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
import com.google.zxing.common.flexdatatypes.Utils;
|
||||
|
||||
/**
|
||||
* <p>Represents a "simple calendar" result encoded according to section 4.9 of the
|
||||
* MobileTag Reader International Specification.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class MobileTagSimpleCalendarResultParser extends AbstractMobileTagResultParser {
|
||||
|
||||
public static var SERVICE_TYPE:String = "07";
|
||||
|
||||
public static function parse(result:Result):CalendarParsedResult {
|
||||
if (result.getBarcodeFormat() != BarcodeFormat.DATAMATRIX) {
|
||||
return null;
|
||||
}
|
||||
var rawText:String = result.getText();
|
||||
if (!Utils.startsWith(rawText,SERVICE_TYPE)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var matches:Array = matchDelimitedFields(rawText.substring(2), 6);
|
||||
if (matches == null || !isDigits(matches[1], 10) || !isDigits(matches[2], 10)) {
|
||||
return null;
|
||||
}
|
||||
var summary:String = matches[0];
|
||||
var start:String = expandDateString(matches[1]);
|
||||
var end:String = expandDateString(matches[2]);
|
||||
var location:String = matches[3];
|
||||
var attendee:String = matches[4];
|
||||
var title:String = matches[5];
|
||||
|
||||
try {
|
||||
return new CalendarParsedResult(summary, start, end, location, attendee, title);
|
||||
} catch ( iae:IllegalArgumentException) {
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static function expandDateString(date:String):String {
|
||||
if (date == null) {
|
||||
return null;
|
||||
}
|
||||
// Input is of form YYMMddHHmmss, and needs to be YYYYMMdd'T'HHmmss'Z'
|
||||
return "20" + date.substring(0, 6) + 'T' + date.substring(6) + "00Z";
|
||||
}
|
||||
|
||||
}}
|
|
@ -0,0 +1,71 @@
|
|||
package com.google.zxing.client.result.optional
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.client.result.AddressBookParsedResult;
|
||||
import com.google.zxing.common.flexdatatypes.Utils;
|
||||
/**
|
||||
* <p>Represents a "simple contact" result encoded according to section 4.8 of the
|
||||
* MobileTag Reader International Specification.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class MobileTagSimpleContactResultParser extends AbstractMobileTagResultParser {
|
||||
|
||||
public static var SERVICE_TYPE:String = "02";
|
||||
|
||||
public static function parse(result:Result):AddressBookParsedResult {
|
||||
if (result.getBarcodeFormat() != BarcodeFormat.DATAMATRIX) {
|
||||
return null;
|
||||
}
|
||||
var rawText:String = result.getText();
|
||||
if (!Utils.startsWith(rawText,SERVICE_TYPE)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var matches:Array = matchDelimitedFields(rawText.substring(2), 9);
|
||||
if (matches == null || !isDigits(matches[7], 8)) {
|
||||
return null;
|
||||
}
|
||||
var fullName:String = matches[0];
|
||||
var telephoneCell:String = matches[1];
|
||||
var telephone:String = matches[2];
|
||||
var email1:String = matches[3];
|
||||
var email2:String = matches[4];
|
||||
var address:String = matches[5];
|
||||
var org:String = matches[6];
|
||||
var birthday:String = matches[7];
|
||||
if (!isStringOfDigits(birthday, 8)) {
|
||||
return null;
|
||||
}
|
||||
var title:String = matches[8];
|
||||
|
||||
return new AddressBookParsedResult([fullName],
|
||||
null,
|
||||
[telephoneCell, telephone],
|
||||
[email1, email2],
|
||||
null,
|
||||
address,
|
||||
org,
|
||||
birthday,
|
||||
title,
|
||||
null);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package com.google.zxing.client.result.optional
|
||||
{
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
import com.google.zxing.client.result.URIParsedResult;
|
||||
import com.google.zxing.common.flexdatatypes.Utils;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
|
||||
/**
|
||||
* <p>Represents a "simple web" result encoded according to section 4.11 of the
|
||||
* MobileTag Reader International Specification.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class MobileTagSimpleWebResultParser extends AbstractMobileTagResultParser {
|
||||
|
||||
public static var SERVICE_TYPE:String = "04";
|
||||
private static var URI_PREFIXES:Array = [
|
||||
null,
|
||||
"http://",
|
||||
"http://www.",
|
||||
"https://",
|
||||
"https://www.",
|
||||
"rtsp://",
|
||||
];
|
||||
|
||||
public static function parse(result:Result):URIParsedResult {
|
||||
if (result.getBarcodeFormat() != BarcodeFormat.DATAMATRIX) {
|
||||
return null;
|
||||
}
|
||||
var rawText:String = result.getText();
|
||||
if (!Utils.startsWith(rawText,SERVICE_TYPE)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var matches:Array = matchDelimitedFields(rawText.substring(2), 2);
|
||||
if (matches == null) {
|
||||
return null;
|
||||
}
|
||||
var uri:String = matches[0];
|
||||
var title:String = matches[1];
|
||||
|
||||
var maybePrefixChar:String = uri.charAt(2);
|
||||
if (maybePrefixChar >= '0' && maybePrefixChar <= '9') {
|
||||
var prefixIndex:int = (maybePrefixChar).charCodeAt(0) - ('0').charCodeAt(0);
|
||||
// Note that '0' is reserved
|
||||
if (prefixIndex >= 1 && prefixIndex < URI_PREFIXES.length) {
|
||||
uri = URI_PREFIXES[prefixIndex] + uri.substring(1);
|
||||
} else {
|
||||
uri = uri.substring(1);
|
||||
}
|
||||
}
|
||||
|
||||
return new URIParsedResult(uri, title);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package com.google.zxing.client.result.optional
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.client.result.TelParsedResult;
|
||||
import com.google.zxing.common.flexdatatypes.Utils;
|
||||
|
||||
/**
|
||||
* <p>Represents a "TEL" result encoded according to section 4.4 of the
|
||||
* MobileTag Reader International Specification.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class MobileTagTelResultParser extends AbstractMobileTagResultParser {
|
||||
|
||||
public static var SERVICE_TYPE:String = "01";
|
||||
|
||||
public static function parse(result:Result):TelParsedResult {
|
||||
if (result.getBarcodeFormat() != BarcodeFormat.DATAMATRIX) {
|
||||
return null;
|
||||
}
|
||||
var rawText:String = result.getText();
|
||||
if (!Utils.startsWith(rawText,SERVICE_TYPE)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var matches:Array = matchDelimitedFields(rawText.substring(2), 2);
|
||||
if (matches == null) {
|
||||
return null;
|
||||
}
|
||||
var number:String = matches[0];
|
||||
var title:String = matches[1];
|
||||
|
||||
return new TelParsedResult(number, "tel:" + number, title);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package com.google.zxing.client.result.optional
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* <p>Represents a record in an NDEF message. This class only supports certain types
|
||||
* of records -- namely, non-chunked records, where ID length is omitted, and only
|
||||
* "short records".</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
import com.google.zxing.common.flexdatatypes.Utils;
|
||||
public final class NDEFRecord {
|
||||
|
||||
private static var SUPPORTED_HEADER_MASK:int = 0x3F; // 0 0 1 1 1 111 (the bottom 6 bits matter)
|
||||
private static var SUPPORTED_HEADER:int = 0x11; // 0 0 0 1 0 001
|
||||
|
||||
public static var TEXT_WELL_KNOWN_TYPE:String = "T";
|
||||
public static var URI_WELL_KNOWN_TYPE:String = "U";
|
||||
public static var SMART_POSTER_WELL_KNOWN_TYPE:String = "Sp";
|
||||
public static var ACTION_WELL_KNOWN_TYPE:String = "act";
|
||||
|
||||
private var header:int;
|
||||
private var type:String;
|
||||
private var payload:Array;
|
||||
private var totalRecordLength:int;
|
||||
|
||||
public function NDEFRecord(header:int, type:String, payload:Array, totalRecordLength:int) {
|
||||
this.header = header;
|
||||
this.type = type;
|
||||
this.payload = payload;
|
||||
this.totalRecordLength = totalRecordLength;
|
||||
}
|
||||
|
||||
public static function readRecord(bytes:Array, offset:int):NDEFRecord {
|
||||
var header:int = bytes[offset] & 0xFF;
|
||||
// Does header match what we support in the bits we care about?
|
||||
// XOR figures out where we differ, and if any of those are in the mask, fail
|
||||
if (((header ^ SUPPORTED_HEADER) & SUPPORTED_HEADER_MASK) != 0) {
|
||||
return null;
|
||||
}
|
||||
var typeLength:int = bytes[offset + 1] & 0xFF;
|
||||
|
||||
var payloadLength:int = bytes[offset + 2] & 0xFF;
|
||||
|
||||
var type:String = AbstractNDEFResultParser.bytesToString(bytes, offset + 3, typeLength, "US-ASCII");
|
||||
|
||||
var payload:Array = new Array(payloadLength);
|
||||
Utils.arraycopy(bytes, offset + 3 + typeLength, payload, 0, payloadLength);
|
||||
|
||||
return new NDEFRecord(header, type, payload, 3 + typeLength + payloadLength);
|
||||
}
|
||||
|
||||
public function isMessageBegin():Boolean {
|
||||
return (header & 0x80) != 0;
|
||||
}
|
||||
|
||||
public function isMessageEnd():Boolean {
|
||||
return (header & 0x40) != 0;
|
||||
}
|
||||
|
||||
public function getType():String {
|
||||
return type;
|
||||
}
|
||||
|
||||
public function getPayload():Array {
|
||||
return payload;
|
||||
}
|
||||
|
||||
public function getTotalRecordLength():int {
|
||||
return totalRecordLength;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package com.google.zxing.client.result.optional
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import com.google.zxing.client.result.ParsedResultType;
|
||||
import com.google.zxing.client.result.ParsedResult;
|
||||
|
||||
/**
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class NDEFSmartPosterParsedResult extends ParsedResult
|
||||
{
|
||||
|
||||
public static var ACTION_UNSPECIFIED:int = -1;
|
||||
public static var ACTION_DO:int = 0;
|
||||
public static var ACTION_SAVE:int = 1;
|
||||
public static var ACTION_OPEN:int = 2;
|
||||
|
||||
private var title:String;
|
||||
private var uri:String;
|
||||
private var action:int;
|
||||
|
||||
public function NDEFSmartPosterParsedResult(action:int, uri:String, title:String) {
|
||||
super(ParsedResultType.NDEF_SMART_POSTER);
|
||||
this.action = action;
|
||||
this.uri = uri;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public function getTitle():String {
|
||||
return title;
|
||||
}
|
||||
|
||||
public function getURI():String {
|
||||
return uri;
|
||||
}
|
||||
|
||||
public function getAction():int {
|
||||
return action;
|
||||
}
|
||||
|
||||
public override function getDisplayResult():String {
|
||||
if (title == null) {
|
||||
return uri;
|
||||
} else {
|
||||
return title + '\n' + uri;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package com.google.zxing.client.result.optional
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import com.google.zxing.Result;
|
||||
|
||||
/**
|
||||
* <p>Recognizes an NDEF message that encodes information according to the
|
||||
* "Smart Poster Record Type Definition" specification.</p>
|
||||
*
|
||||
* <p>This actually only supports some parts of the Smart Poster format: title,
|
||||
* URI, and action records. Icon records are not supported because the size
|
||||
* of these records are infeasibly large for barcodes. Size and type records
|
||||
* are not supported. Multiple titles are not supported.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class NDEFSmartPosterResultParser extends AbstractNDEFResultParser {
|
||||
|
||||
public static function parse(result:Result):NDEFSmartPosterParsedResult {
|
||||
var bytes:Array = result.getRawBytes();
|
||||
if (bytes == null) {
|
||||
return null;
|
||||
}
|
||||
var headerRecord:NDEFRecord = NDEFRecord.readRecord(bytes, 0);
|
||||
// Yes, header record starts and ends a message
|
||||
if (headerRecord == null || !headerRecord.isMessageBegin() || !headerRecord.isMessageEnd()) {
|
||||
return null;
|
||||
}
|
||||
if (headerRecord.getType() != NDEFRecord.SMART_POSTER_WELL_KNOWN_TYPE) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var offset:int = 0;
|
||||
var recordNumber:int = 0;
|
||||
var ndefRecord:NDEFRecord = null;
|
||||
var payload:Array = headerRecord.getPayload();
|
||||
var action:int = NDEFSmartPosterParsedResult.ACTION_UNSPECIFIED;
|
||||
var title:String = null;
|
||||
var uri:String = null;
|
||||
|
||||
while (offset < payload.length && (ndefRecord = NDEFRecord.readRecord(payload, offset)) != null) {
|
||||
if (recordNumber == 0 && !ndefRecord.isMessageBegin()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var type:String = ndefRecord.getType();
|
||||
if (NDEFRecord.TEXT_WELL_KNOWN_TYPE == type) {
|
||||
var languageText:Array = NDEFTextResultParser.decodeTextPayload(ndefRecord.getPayload());
|
||||
title = languageText[1];
|
||||
} else if (NDEFRecord.URI_WELL_KNOWN_TYPE == type) {
|
||||
uri = NDEFURIResultParser.decodeURIPayload(ndefRecord.getPayload());
|
||||
} else if (NDEFRecord.ACTION_WELL_KNOWN_TYPE == type) {
|
||||
action = ndefRecord.getPayload()[0];
|
||||
}
|
||||
recordNumber++;
|
||||
offset += ndefRecord.getTotalRecordLength();
|
||||
}
|
||||
|
||||
if (recordNumber == 0 || (ndefRecord != null && !ndefRecord.isMessageEnd())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new NDEFSmartPosterParsedResult(action, uri, title);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package com.google.zxing.client.result.optional
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
import com.google.zxing.client.result.TextParsedResult;
|
||||
import com.google.zxing.Result;
|
||||
|
||||
/**
|
||||
* Recognizes an NDEF message that encodes text according to the
|
||||
* "Text Record Type Definition" specification.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class NDEFTextResultParser extends AbstractNDEFResultParser {
|
||||
|
||||
public static function parse(result:Result ):TextParsedResult {
|
||||
var bytes:Array = result.getRawBytes();
|
||||
if (bytes == null) {
|
||||
return null;
|
||||
}
|
||||
var ndefRecord:NDEFRecord = NDEFRecord.readRecord(bytes, 0);
|
||||
if (ndefRecord == null || !ndefRecord.isMessageBegin() || !ndefRecord.isMessageEnd()) {
|
||||
return null;
|
||||
}
|
||||
if (ndefRecord.getType() != NDEFRecord.TEXT_WELL_KNOWN_TYPE) {
|
||||
return null;
|
||||
}
|
||||
var languageText:Array = decodeTextPayload(ndefRecord.getPayload());
|
||||
return new TextParsedResult(languageText[0], languageText[1]);
|
||||
}
|
||||
|
||||
public static function decodeTextPayload(payload:Array):Array {
|
||||
var statusByte:int = payload[0];
|
||||
var isUTF16:Boolean = (statusByte & 0x80) != 0;
|
||||
var languageLength:int = statusByte & 0x1F;
|
||||
// language is always ASCII-encoded:
|
||||
var language:String = bytesToString(payload, 1, languageLength, "US-ASCII");
|
||||
var encoding:String = isUTF16 ? "UTF-16" : "UTF8";
|
||||
var text:String = bytesToString(payload, 1 + languageLength, payload.length - languageLength - 1, encoding);
|
||||
return new [language, text ];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
package com.google.zxing.client.result.optional
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.client.result.URIParsedResult;
|
||||
|
||||
/**
|
||||
* Recognizes an NDEF message that encodes a URI according to the
|
||||
* "URI Record Type Definition" specification.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class NDEFURIResultParser extends AbstractNDEFResultParser {
|
||||
|
||||
private static var URI_PREFIXES:Array = [
|
||||
null,
|
||||
"http://www.",
|
||||
"https://www.",
|
||||
"http://",
|
||||
"https://",
|
||||
"tel:",
|
||||
"mailto:",
|
||||
"ftp://anonymous:anonymous@",
|
||||
"ftp://ftp.",
|
||||
"ftps://",
|
||||
"sftp://",
|
||||
"smb://",
|
||||
"nfs://",
|
||||
"ftp://",
|
||||
"dav://",
|
||||
"news:",
|
||||
"telnet://",
|
||||
"imap:",
|
||||
"rtsp://",
|
||||
"urn:",
|
||||
"pop:",
|
||||
"sip:",
|
||||
"sips:",
|
||||
"tftp:",
|
||||
"btspp://",
|
||||
"btl2cap://",
|
||||
"btgoep://",
|
||||
"tcpobex://",
|
||||
"irdaobex://",
|
||||
"file://",
|
||||
"urn:epc:id:",
|
||||
"urn:epc:tag:",
|
||||
"urn:epc:pat:",
|
||||
"urn:epc:raw:",
|
||||
"urn:epc:",
|
||||
"urn:nfc:",
|
||||
];
|
||||
|
||||
public static function parse(result:Result ):URIParsedResult {
|
||||
var bytes:Array = result.getRawBytes();
|
||||
if (bytes == null) {
|
||||
return null;
|
||||
}
|
||||
var ndefRecord:NDEFRecord = NDEFRecord.readRecord(bytes, 0);
|
||||
if (ndefRecord == null || !ndefRecord.isMessageBegin() || !ndefRecord.isMessageEnd()) {
|
||||
return null;
|
||||
}
|
||||
if (ndefRecord.getType() != NDEFRecord.URI_WELL_KNOWN_TYPE) {
|
||||
return null;
|
||||
}
|
||||
var fullURI:String = decodeURIPayload(ndefRecord.getPayload());
|
||||
return new URIParsedResult(fullURI, null);
|
||||
}
|
||||
|
||||
public static function decodeURIPayload(payload:Array):String {
|
||||
var identifierCode:int = payload[0] & 0xFF;
|
||||
var prefix:String = null;
|
||||
if (identifierCode < URI_PREFIXES.length) {
|
||||
prefix = URI_PREFIXES[identifierCode];
|
||||
}
|
||||
var restOfURI:String = bytesToString(payload, 1, payload.length - 1, "UTF8");
|
||||
return prefix == null ? restOfURI : prefix + restOfURI;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
188
actionscript/core/src/com/google/zxing/common/BitArray.as
Normal file
188
actionscript/core/src/com/google/zxing/common/BitArray.as
Normal file
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* 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
|
||||
{
|
||||
/**
|
||||
* <p>A simple, fast array of bits, represented compactly by an array of ints internally.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public class BitArray
|
||||
{
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
|
||||
// TODO: I have changed these members to be public so ProGuard can inline get() and set(). Ideally
|
||||
// they'd be private and we'd use the -allowaccessmodification flag, but Dalvik rejects the
|
||||
// resulting binary at runtime on Android. If we find a solution to this, these should be changed
|
||||
// back to private.
|
||||
public var bits:Array;
|
||||
public var Size:int;
|
||||
|
||||
public function BitArray(size:int) {
|
||||
if (size < 1) {
|
||||
throw new IllegalArgumentException("common : BitArray : size must be at least 1");
|
||||
}
|
||||
this.Size = size;
|
||||
this.bits = makeArray(size);
|
||||
}
|
||||
|
||||
public function getSize():int {
|
||||
return Size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param i bit to get
|
||||
* @return true iff bit i is set
|
||||
*/
|
||||
public function _get(i:int):Boolean {
|
||||
return (bits[i >> 5] & (1 << (i & 0x1F))) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets bit i.
|
||||
*
|
||||
* @param i bit to set
|
||||
*/
|
||||
public function _set(i:int):void {
|
||||
bits[i >> 5] |= 1 << (i & 0x1F);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flips bit i.
|
||||
*
|
||||
* @param i bit to set
|
||||
*/
|
||||
public function flip(i:int):void {
|
||||
bits[i >> 5] ^= 1 << (i & 0x1F);
|
||||
}
|
||||
/**
|
||||
* Sets a block of 32 bits, starting at bit i.
|
||||
*
|
||||
* @param i first bit to set
|
||||
* @param newBits the new value of the next 32 bits. Note again that the least-significant bit
|
||||
* corresponds to bit i, the next-least-significant to i+1, and so on.
|
||||
*/
|
||||
public function setBulk(i:int, newBits:int):void {
|
||||
bits[i >> 5] = newBits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all bits (sets to false).
|
||||
*/
|
||||
public function clear():void {
|
||||
var max:int = bits.length;
|
||||
for (var i:int = 0; i < max; i++) {
|
||||
bits[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Efficient method to check if a range of bits is set, or not set.
|
||||
*
|
||||
* @param start start of range, inclusive.
|
||||
* @param end end of range, exclusive
|
||||
* @param value if true, checks that bits in range are set, otherwise checks that they are not set
|
||||
* @return true iff all bits are set or not set in range, according to value argument
|
||||
* @throws IllegalArgumentException if end is less than or equal to start
|
||||
*/
|
||||
public function isRange(start:int, end:int, value:Boolean):Boolean {
|
||||
if (end < start) {
|
||||
throw new IllegalArgumentException("common : BitArray isRange : end before start");
|
||||
}
|
||||
if (end == start) {
|
||||
return true; // empty range matches
|
||||
}
|
||||
end--; // will be easier to treat this as the last actually set bit -- inclusive
|
||||
var firstInt:int = start >> 5;
|
||||
var lastInt:int = end >> 5;
|
||||
for (var i:int = firstInt; i <= lastInt; i++) {
|
||||
var firstBit:int = i > firstInt ? 0 : start & 0x1F;
|
||||
var lastBit:int = i < lastInt ? 31 : end & 0x1F;
|
||||
var mask:int;
|
||||
if (firstBit == 0 && lastBit == 31) {
|
||||
mask = -1;
|
||||
} else {
|
||||
mask = 0;
|
||||
for (var j:int = firstBit; j <= lastBit; j++) {
|
||||
mask |= 1 << j;
|
||||
}
|
||||
}
|
||||
|
||||
// Return false if we're looking for 1s and the masked bits[i] isn't all 1s (that is,
|
||||
// equals the mask, or we're looking for 0s and the masked portion is not all 0s
|
||||
if ((bits[i] & mask) != (value ? mask : 0)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return underlying array of ints. The first element holds the first 32 bits, and the least
|
||||
* significant bit is bit 0.
|
||||
*/
|
||||
public function getBitArray():Array {
|
||||
return bits;
|
||||
}
|
||||
|
||||
// bas : for debugging purposes
|
||||
public function setBitArray(a:Array):void {
|
||||
bits = a;
|
||||
}
|
||||
public function setSize(siz:int):void {
|
||||
Size = siz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverses all bits in the array.
|
||||
*/
|
||||
public function reverse():void {
|
||||
var newBits:Array = makeArray(Size);
|
||||
var max:int = Size;
|
||||
for (var i:int = 0; i < max; i++) { newBits[i] = 0; }//Flex : makew
|
||||
var size:int = this.Size;
|
||||
for (var ii:int = 0; ii < size; ii++) {
|
||||
if (this._get(size - ii - 1)) {
|
||||
newBits[ii >> 5] |= 1 << (ii & 0x1F);
|
||||
}
|
||||
}
|
||||
bits = newBits;
|
||||
}
|
||||
|
||||
private static function makeArray(size:int):Array {
|
||||
var arraySize:int = size >> 5;
|
||||
if ((size & 0x1F) != 0) {
|
||||
arraySize++;
|
||||
}
|
||||
return new Array(arraySize);
|
||||
}
|
||||
public function toString():String
|
||||
{
|
||||
var result:StringBuilder = new StringBuilder(this.Size);
|
||||
for (var i:int = 0; i < this.Size; i++)
|
||||
{
|
||||
if ((i & 0x07) == 0)
|
||||
{
|
||||
result.Append(' ');
|
||||
}
|
||||
result.Append(_get(i) ? 'X' : '.');
|
||||
}
|
||||
return result.ToString();
|
||||
}
|
||||
}
|
||||
}
|
202
actionscript/core/src/com/google/zxing/common/BitMatrix.as
Normal file
202
actionscript/core/src/com/google/zxing/common/BitMatrix.as
Normal file
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* 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
|
||||
{
|
||||
/**
|
||||
* <p>Represents a 2D matrix of bits. In function arguments below, and throughout the common
|
||||
* module, x is the column position, and y is the row position. The ordering is always x, y.
|
||||
* The origin is at the top-left.</p>
|
||||
*
|
||||
* <p>Internally the bits are represented in a 1-D array of 32-bit ints. However, each row begins
|
||||
* with a new int. This is done intentionally so that we can copy out a row into a BitArray very
|
||||
* efficiently.</p>
|
||||
*
|
||||
* <p>The ordering of bits is row-major. Within each int, the least significant bits are used first,
|
||||
* meaning they represent lower x values. This is compatible with BitArray's implementation.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
public class BitMatrix
|
||||
{
|
||||
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 bits:Array;
|
||||
|
||||
|
||||
public function BitMatrix(width:int, o:Object= null)
|
||||
{
|
||||
var height:int;
|
||||
if (o == null)
|
||||
{
|
||||
height = width;
|
||||
}
|
||||
else if (o is int)
|
||||
{
|
||||
height = (o as int);
|
||||
}
|
||||
|
||||
if (width < 1 || height < 1)
|
||||
{
|
||||
throw new IllegalArgumentException("common : BitMatrix : Both dimensions must be greater than 0");
|
||||
}
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
var rowSize:int = width >> 5;
|
||||
if ((width & 0x1f) != 0)
|
||||
{
|
||||
rowSize++;
|
||||
}
|
||||
this.rowSize = rowSize;
|
||||
bits = new Array(rowSize * height);
|
||||
// BAS : initialize the array
|
||||
for (var i:int=0;i<bits.length;i++) { bits[i] = 0; }
|
||||
|
||||
}
|
||||
/**
|
||||
* <p>Gets the requested bit, where true means black.</p>
|
||||
*
|
||||
* @param x The horizontal component (i.e. which column)
|
||||
* @param y The vertical component (i.e. which row)
|
||||
* @return value of given bit in matrix
|
||||
*/
|
||||
public function _get(x:int, y:int):Boolean {
|
||||
var offset:int = y * rowSize + (x >> 5);
|
||||
return ((bits[offset] >>> (x & 0x1f)) & 1) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Sets the given bit to true.</p>
|
||||
*
|
||||
* @param x The horizontal component (i.e. which column)
|
||||
* @param y The vertical component (i.e. which row)
|
||||
*/
|
||||
public function _set(x:int, y:int):void {
|
||||
var offset:int = y * rowSize + (x >> 5);
|
||||
bits[offset] |= 1 << (x & 0x1f);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Flips the given bit.</p>
|
||||
*
|
||||
* @param x The horizontal component (i.e. which column)
|
||||
* @param y The vertical component (i.e. which row)
|
||||
*/
|
||||
public function flip(x:int, y:int):void {
|
||||
var offset:int = y * rowSize + (x >> 5);
|
||||
bits[offset] ^= 1 << (x & 0x1f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all bits (sets to false).
|
||||
*/
|
||||
public function clear():void {
|
||||
var max:int = bits.length;
|
||||
for (var i:int = 0; i < max; i++) {
|
||||
bits[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Sets a square region of the bit matrix to true.</p>
|
||||
*
|
||||
* @param left The horizontal position to begin at (inclusive)
|
||||
* @param top The vertical position to begin at (inclusive)
|
||||
* @param width The width of the region
|
||||
* @param height The height of the region
|
||||
*/
|
||||
public function setRegion(left:int,top:int, width:int, height:int):void {
|
||||
if (top < 0 || left < 0) {
|
||||
throw new IllegalArgumentException("Common : BitMatrix : setRegion : Left and top must be nonnegative");
|
||||
}
|
||||
if (height < 1 || width < 1) {
|
||||
throw new IllegalArgumentException("Common : BitMatrix : setRegion : Height and width must be at least 1");
|
||||
}
|
||||
var right:int = left + width;
|
||||
var bottom:int = top + height;
|
||||
if (bottom > this.height || right > this.width) {
|
||||
throw new IllegalArgumentException("Common : BitMatrix : setRegion : The region must fit inside the matrix");
|
||||
}
|
||||
for (var y:int = top; y < bottom; y++) {
|
||||
var offset:int = y * rowSize;
|
||||
for (var x:int = left; x < right; x++) {
|
||||
bits[offset + (x >> 5)] |= 1 << (x & 0x1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A fast method to retrieve one row of data from the matrix as a BitArray.
|
||||
*
|
||||
* @param y The row to retrieve
|
||||
* @param row An optional caller-allocated BitArray, will be allocated if null or too small
|
||||
* @return The resulting BitArray - this reference should always be used even when passing
|
||||
* your own row
|
||||
*/
|
||||
public function getRow(y:int, row:BitArray ):BitArray {
|
||||
if (row == null || row.getSize() < width) {
|
||||
row = new BitArray(width);
|
||||
}
|
||||
var offset:int = y * rowSize;
|
||||
for (var x:int = 0; x < rowSize; x++) {
|
||||
row.setBulk(x << 5, bits[offset + x]);
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The width of the matrix
|
||||
*/
|
||||
public function getWidth():int {
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The height of the matrix
|
||||
*/
|
||||
public function getHeight():int {
|
||||
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");
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
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) ? "X " : " ");
|
||||
}
|
||||
result.Append('\n');
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
}
|
90
actionscript/core/src/com/google/zxing/common/BitSource.as
Normal file
90
actionscript/core/src/com/google/zxing/common/BitSource.as
Normal file
|
@ -0,0 +1,90 @@
|
|||
package com.google.zxing.common
|
||||
{
|
||||
/// <summary> A class which wraps a 2D array of bytes. The default usage is signed. If you want to use it as a
|
||||
/// unsigned container, it's up to you to do byteValue & 0xff at each location.
|
||||
/// *
|
||||
/// JAVAPORT: I'm not happy about the argument ordering throughout the file, as I always like to have
|
||||
/// the horizontal component first, but this is for compatibility with the C++ code. The original
|
||||
/// code was a 2D array of ints, but since it only ever gets assigned -1, 0, and 1, I'm going to use
|
||||
/// less memory and go with bytes.
|
||||
/// *
|
||||
/// </summary>
|
||||
/// <author> dswitkin@google.com (Daniel Switkin)
|
||||
///
|
||||
/// </author>
|
||||
public class BitSource
|
||||
{
|
||||
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
|
||||
private var bytes:Array;
|
||||
private var byteOffset:int;
|
||||
private var bitOffset:int;
|
||||
|
||||
/**
|
||||
* @param bytes bytes from which this will read bits. Bits will be read from the first byte first.
|
||||
* Bits are read within a byte from most-significant to least-significant bit.
|
||||
*/
|
||||
public function BitSource( bytes:Array) {
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param numBits number of bits to read
|
||||
* @return int representing the bits read. The bits will appear as the least-significant
|
||||
* bits of the int
|
||||
* @throws IllegalArgumentException if numBits isn't in [1,32]
|
||||
*/
|
||||
public function readBits(numBits:int):int
|
||||
{
|
||||
if (numBits < 1 || numBits > 32)
|
||||
{
|
||||
throw new IllegalArgumentException("BitSource : numBits out of range");
|
||||
}
|
||||
|
||||
var result:int = 0;
|
||||
|
||||
// First, read remainder from current byte
|
||||
if (bitOffset > 0) {
|
||||
var bitsLeft:int = 8 - bitOffset;
|
||||
var toRead:int = numBits < bitsLeft ? numBits : bitsLeft;
|
||||
var bitsToNotRead:int = bitsLeft - toRead;
|
||||
var mask:int = (0xFF >> (8 - toRead)) << bitsToNotRead;
|
||||
result = (bytes[byteOffset] & mask) >> bitsToNotRead;
|
||||
numBits -= toRead;
|
||||
bitOffset += toRead;
|
||||
if (bitOffset == 8) {
|
||||
bitOffset = 0;
|
||||
byteOffset++;
|
||||
}
|
||||
}
|
||||
|
||||
// Next read whole bytes
|
||||
if (numBits > 0) {
|
||||
while (numBits >= 8) {
|
||||
result = (result << 8) | (bytes[byteOffset] & 0xFF);
|
||||
byteOffset++;
|
||||
numBits -= 8;
|
||||
}
|
||||
|
||||
// Finally read a partial byte
|
||||
if (numBits > 0) {
|
||||
var bitsToNotRead2:int = 8 - numBits;
|
||||
var mask2:int = (0xFF >> bitsToNotRead2) << bitsToNotRead2;
|
||||
result = (result << numBits) | ((bytes[byteOffset] & mask2) >> bitsToNotRead2);
|
||||
bitOffset += numBits;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return number of bits that can be read successfully
|
||||
*/
|
||||
public function available():int {
|
||||
var bits:int = 8 * (bytes.length - byteOffset) - bitOffset;
|
||||
return bits;
|
||||
}
|
||||
}
|
||||
}
|
133
actionscript/core/src/com/google/zxing/common/ByteMatrix.as
Normal file
133
actionscript/core/src/com/google/zxing/common/ByteMatrix.as
Normal file
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* 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.common
|
||||
{
|
||||
/**
|
||||
* A class which wraps a 2D array of bytes. The default usage is signed. If you want to use it as a
|
||||
* unsigned container, it's up to you to do byteValue & 0xff at each location.
|
||||
*
|
||||
* JAVAPORT: The original code was a 2D array of ints, but since it only ever gets assigned
|
||||
* -1, 0, and 1, I'm going to use less memory and go with bytes.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
public class ByteMatrix
|
||||
{
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
|
||||
private var bytes:Array;
|
||||
private var Height:int;
|
||||
private var Width:int;
|
||||
|
||||
|
||||
public function ByteMatrix(height:int, width:int ) {
|
||||
bytes = new Array(height);
|
||||
for (var i:int = 0; i < height; i++) {
|
||||
bytes[i] = new Array(width);
|
||||
}
|
||||
this.Height = height;
|
||||
this.Width = width;
|
||||
}
|
||||
|
||||
public function height():int
|
||||
{
|
||||
return Height;
|
||||
}
|
||||
|
||||
public function width():int
|
||||
{
|
||||
return Width;
|
||||
}
|
||||
|
||||
public function _get(x:int, y:int):int
|
||||
{
|
||||
return bytes[y][x];
|
||||
}
|
||||
|
||||
public function getArray():Array
|
||||
{
|
||||
return bytes;
|
||||
}
|
||||
|
||||
//public function _set(y:int,x:int, value:int)
|
||||
//{
|
||||
// bytes[y][x] = value;
|
||||
//}
|
||||
|
||||
public function _set(x:int, y:int, value:Object ):void
|
||||
{
|
||||
if (value is int)
|
||||
{
|
||||
bytes[y][x] = value as int;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Error('ByteMatrix : _set : unknown type of value');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function clear(value:int):void
|
||||
{
|
||||
for (var y:int = 0; y < Height; ++y)
|
||||
{
|
||||
for (var x:int = 0; x < Width; ++x)
|
||||
{
|
||||
bytes[y][x] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function sum():int
|
||||
{
|
||||
var result:int = 0;
|
||||
for (var y:int = 0; y < Height; ++y)
|
||||
{
|
||||
for (var x:int = 0; x < Width; ++x)
|
||||
{
|
||||
result += bytes[y][x];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public function toString():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;
|
||||
}
|
||||
}
|
||||
result.Append('\n');
|
||||
}
|
||||
return result.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
115
actionscript/core/src/com/google/zxing/common/CharacterSetECI.as
Normal file
115
actionscript/core/src/com/google/zxing/common/CharacterSetECI.as
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* 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.common
|
||||
{
|
||||
/**
|
||||
* Encapsulates a Character Set ECI, according to "Extended Channel Interpretations" 5.3.1.1
|
||||
* of ISO 18004.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public class CharacterSetECI extends ECI
|
||||
{
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
|
||||
private static var VALUE_TO_ECI:HashTable = new HashTable(29);
|
||||
private static var NAME_TO_ECI:HashTable = new HashTable(29);
|
||||
|
||||
private static function initialize():void {
|
||||
VALUE_TO_ECI = new HashTable(29);
|
||||
NAME_TO_ECI = new HashTable(29);
|
||||
// TODO figure out if these values are even right!
|
||||
addCharacterSet(0, "Cp437");
|
||||
addCharacterSet(1, ["ISO8859_1", "ISO-8859-1"]);
|
||||
addCharacterSet(2, "Cp437");
|
||||
addCharacterSet(3, ["ISO8859_1", "ISO-8859-1"]);
|
||||
addCharacterSet(4, "ISO8859_2");
|
||||
addCharacterSet(5, "ISO8859_3");
|
||||
addCharacterSet(6, "ISO8859_4");
|
||||
addCharacterSet(7, "ISO8859_5");
|
||||
addCharacterSet(8, "ISO8859_6");
|
||||
addCharacterSet(9, "ISO8859_7");
|
||||
addCharacterSet(10, "ISO8859_8");
|
||||
addCharacterSet(11, "ISO8859_9");
|
||||
addCharacterSet(12, "ISO8859_10");
|
||||
addCharacterSet(13, "ISO8859_11");
|
||||
addCharacterSet(15, "ISO8859_13");
|
||||
addCharacterSet(16, "ISO8859_14");
|
||||
addCharacterSet(17, "ISO8859_15");
|
||||
addCharacterSet(18, "ISO8859_16");
|
||||
addCharacterSet(20, ["SJIS", "Shift_JIS"]);
|
||||
}
|
||||
|
||||
private var encodingName:String;
|
||||
|
||||
public function CharacterSetECI(value:int, encodingName:String) {
|
||||
super(value);
|
||||
this.encodingName = encodingName;
|
||||
}
|
||||
|
||||
public function getEncodingName():String {
|
||||
return encodingName;
|
||||
}
|
||||
|
||||
private static function addCharacterSet(value:int, encodingNames:Object):void
|
||||
{
|
||||
var eci:CharacterSetECI;
|
||||
if (encodingNames is String)
|
||||
{
|
||||
eci = new CharacterSetECI(value, encodingNames as String);
|
||||
VALUE_TO_ECI._put(value, eci);
|
||||
NAME_TO_ECI._put(encodingNames as String, eci);
|
||||
}
|
||||
else if (encodingNames is Array)
|
||||
{
|
||||
eci = new CharacterSetECI(value, encodingNames[0]);
|
||||
VALUE_TO_ECI._put(value, eci);
|
||||
for (var i:int = 0; i < encodingNames.length; i++) { NAME_TO_ECI._put(encodingNames[i], eci);}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value character set ECI value
|
||||
* @return {@link CharacterSetECI} representing ECI of given value, or null if it is legal but
|
||||
* unsupported
|
||||
* @throws IllegalArgumentException if ECI value is invalid
|
||||
*/
|
||||
public static function getCharacterSetECIByValue(value:int):CharacterSetECI {
|
||||
if (VALUE_TO_ECI == null)
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
if (value < 0 || value >= 900) {
|
||||
throw new IllegalArgumentException("COMMON : CharacterSetECI : getCharacterSetECIByValue : Bad ECI value: " + value);
|
||||
}
|
||||
return VALUE_TO_ECI.getValueByKey(value) as CharacterSetECI;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name character set ECI encoding name
|
||||
* @return {@link CharacterSetECI} representing ECI for character encoding, or null if it is legal
|
||||
* but unsupported
|
||||
*/
|
||||
public static function getCharacterSetECIByName(name:String ):CharacterSetECI {
|
||||
if (NAME_TO_ECI == null) {
|
||||
initialize();
|
||||
}
|
||||
return (NAME_TO_ECI.getValueByKey(name) as CharacterSetECI);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
59
actionscript/core/src/com/google/zxing/common/Collections.as
Normal file
59
actionscript/core/src/com/google/zxing/common/Collections.as
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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
|
||||
{
|
||||
/**
|
||||
* <p>This is basically a substitute for <code>java.util.Collections</code>, which is not
|
||||
* present in MIDP 2.0 / CLDC 1.1.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public class Collections
|
||||
{
|
||||
|
||||
import com.google.zxing.common.flexdatatypes.ArrayList;
|
||||
|
||||
public function Collections()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts its argument (destructively) using insert sort; in the context of this package
|
||||
* insertion sort is simple and efficient given its relatively small inputs.
|
||||
*
|
||||
* @param vector vector to sort
|
||||
* @param comparator comparator to define sort ordering
|
||||
*/
|
||||
public static function insertionSort( vector:ArrayList, comparator:Comparator ):void
|
||||
{
|
||||
var max:int = vector.Count;
|
||||
for (var i:int = 1; i < max; i++)
|
||||
{
|
||||
var valueA:Object = vector[i];
|
||||
var j:int = i - 1;
|
||||
var valueB:Object;
|
||||
while (j >= 0 && comparator.compare((valueB = vector[j]), valueA) > 0)
|
||||
{
|
||||
vector[j + 1] = valueB;
|
||||
j--;
|
||||
}
|
||||
vector[j + 1] = valueA;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
29
actionscript/core/src/com/google/zxing/common/Comparator.as
Normal file
29
actionscript/core/src/com/google/zxing/common/Comparator.as
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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
|
||||
{
|
||||
/**
|
||||
* This is merely a clone of <code>Comparator</code> since it is not available in
|
||||
* CLDC 1.1 / MIDP 2.0.
|
||||
*/
|
||||
public interface Comparator
|
||||
{
|
||||
|
||||
function compare(o1:Object, o2:Object):int;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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.qrcode.decoder.ErrorCorrectionLevel;
|
||||
import mx.controls.List;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
import com.google.zxing.common.flexdatatypes.ArrayList;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Encapsulates the result of decoding a matrix of bits. This typically
|
||||
* applies to 2D barcode formats. For now it contains the raw bytes obtained,
|
||||
* as well as a String interpretation of those bytes, if applicable.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/ public class DecoderResult
|
||||
{
|
||||
|
||||
private var rawBytes:Array;
|
||||
private var text:String ;
|
||||
private var byteSegments:ArrayList;
|
||||
private var ecLevel:ErrorCorrectionLevel;
|
||||
|
||||
public function DecoderResult(rawBytes:Array, text:String, byteSegments:ArrayList, ecLevel:ErrorCorrectionLevel)
|
||||
{
|
||||
if (rawBytes == null && text == null)
|
||||
{
|
||||
throw new IllegalArgumentException("common : DecoderResult : Constructor : rawBytes array contains no data and text == null");
|
||||
}
|
||||
this.rawBytes = rawBytes;
|
||||
this.text = text;
|
||||
this.byteSegments = byteSegments;
|
||||
this.ecLevel = ecLevel
|
||||
}
|
||||
|
||||
public function getRawBytes():Array {
|
||||
return this.rawBytes;
|
||||
}
|
||||
|
||||
public function getText():String {
|
||||
return text;
|
||||
}
|
||||
|
||||
public function getByteSegments():ArrayList
|
||||
{
|
||||
return byteSegments;
|
||||
}
|
||||
|
||||
public function getECLevel():ErrorCorrectionLevel
|
||||
{
|
||||
return ecLevel;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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.ResultPoint;
|
||||
|
||||
/**
|
||||
* <p>Encapsulates the result of detecting a barcode in an image. This includes the raw
|
||||
* matrix of black/white pixels corresponding to the barcode, and possibly points of interest
|
||||
* in the image, like the location of finder patterns or corners of the barcode in the image.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public class DetectorResult
|
||||
{
|
||||
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 {
|
||||
return bits;
|
||||
}
|
||||
|
||||
public function getPoints():Array {
|
||||
return points;
|
||||
}
|
||||
}
|
||||
}
|
56
actionscript/core/src/com/google/zxing/common/ECI.as
Normal file
56
actionscript/core/src/com/google/zxing/common/ECI.as
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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.common
|
||||
{
|
||||
/**
|
||||
* Superclass of classes encapsulating types ECIs, according to "Extended Channel Interpretations"
|
||||
* 5.3 of ISO 18004.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public class ECI
|
||||
{
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
|
||||
private var value:int;
|
||||
|
||||
public function ECI( value:int) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public function getValue():int {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value ECI value
|
||||
* @return {@link ECI} representing ECI of given value, or null if it is legal but unsupported
|
||||
* @throws IllegalArgumentException if ECI value is invalid
|
||||
*/
|
||||
|
||||
public static function getECIByValue(value:int ):ECI {
|
||||
if (value < 0 || value > 999999) {
|
||||
throw new IllegalArgumentException("Bad ECI value: " + value);
|
||||
}
|
||||
if (value < 900) { // Character set ECIs use 000000 - 000899
|
||||
return CharacterSetECI.getCharacterSetECIByValue(value);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* 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
|
||||
{
|
||||
|
||||
import com.google.zxing.Binarizer;
|
||||
import com.google.zxing.LuminanceSource;
|
||||
import com.google.zxing.ReaderException;
|
||||
|
||||
/**
|
||||
* This Binarizer implementation uses the old ZXing global histogram approach. It is suitable
|
||||
* for low-end mobile devices which don't have enough CPU or memory to use a local thresholding
|
||||
* algorithm. However, because it picks a global black point, it cannot handle difficult shadows
|
||||
* and gradients.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class GlobalHistogramBinarizer extends Binarizer {
|
||||
|
||||
|
||||
private static var LUMINANCE_BITS:int = 5;
|
||||
private static var LUMINANCE_SHIFT:int = 8 - LUMINANCE_BITS;
|
||||
private static var LUMINANCE_BUCKETS:int = 1 << LUMINANCE_BITS;
|
||||
|
||||
private var luminances:Array = null;
|
||||
private var buckets:Array = null;
|
||||
|
||||
public function GlobalHistogramBinarizer(source:LuminanceSource ) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
row = new BitArray(width);
|
||||
} else {
|
||||
row.clear();
|
||||
}
|
||||
|
||||
initArrays(width);
|
||||
var _localLuminances:Array = source.getRow(y, luminances);
|
||||
var localBuckets:Array = buckets;
|
||||
for (var x2:int = 0; x2 < width; x2++)
|
||||
{
|
||||
var pixel:int = _localLuminances[x2] & 0xff;
|
||||
localBuckets[pixel >> LUMINANCE_SHIFT]++;
|
||||
}
|
||||
|
||||
var blackPoint:int = estimateBlackPoint(localBuckets);
|
||||
|
||||
var left:int = _localLuminances[0] & 0xff;
|
||||
var center:int = _localLuminances[1] & 0xff;
|
||||
for (var x:int = 1; x < width - 1; x++)
|
||||
{
|
||||
var right:int = _localLuminances[x + 1] & 0xff;
|
||||
// A simple -1 4 -1 box filter with a weight of 2.
|
||||
var luminance:int = ((center << 2) - left - right) >> 1;
|
||||
if (luminance < blackPoint) {
|
||||
row._set(x);
|
||||
}
|
||||
left = center;
|
||||
center = right;
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
// Does not sharpen the data, as this call is intended to only be used by 2D Readers.
|
||||
public override function getBlackMatrix():BitMatrix {
|
||||
var source:LuminanceSource = getLuminanceSource();
|
||||
var width:int = source.getWidth();
|
||||
var height:int = source.getHeight();
|
||||
var matrix:BitMatrix = new BitMatrix(width, height);
|
||||
|
||||
// Quickly calculates the histogram by sampling four rows from the image. This proved to be
|
||||
// more robust on the blackbox tests than sampling a diagonal as we used to do.
|
||||
initArrays(width);
|
||||
var _localLuminances:Array;
|
||||
var localBuckets:Array = buckets;//assign empty array
|
||||
for (var y2:int = 1; y2 < 5; y2++)
|
||||
{
|
||||
var row: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 pixel:int = _localLuminances[x] & 0xff;
|
||||
var index:int = Math.floor(pixel >> LUMINANCE_SHIFT);
|
||||
localBuckets[index]++;
|
||||
}
|
||||
}
|
||||
|
||||
var blackPoint:int = estimateBlackPoint(localBuckets);
|
||||
|
||||
// We delay reading the entire image luminance until the black point estimation succeeds.
|
||||
// Although we end up reading four rows twice, it is consistent with our motto of
|
||||
// "fail quickly" which is necessary for continuous scanning.
|
||||
_localLuminances = source.getMatrix();
|
||||
for (var y:int = 0; y < height; y++)
|
||||
{
|
||||
var offset:int = y * width;
|
||||
for (var x2:int = 0; x2< width; x2++)
|
||||
{
|
||||
var pixel2:int = _localLuminances[offset + x2] & 0xff;
|
||||
if (pixel2 < blackPoint)
|
||||
{
|
||||
matrix._set(x2, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
public override function createBinarizer(source:LuminanceSource):Binarizer {
|
||||
return new GlobalHistogramBinarizer(source);
|
||||
}
|
||||
|
||||
private function initArrays(luminanceSize:int):void {
|
||||
if (luminances == null || luminances.length < luminanceSize)
|
||||
{
|
||||
luminances = new Array(luminanceSize);
|
||||
}
|
||||
for (var i:int=0;i<luminances.length;i++) { luminances[i]=0;}
|
||||
|
||||
if (buckets == null)
|
||||
{
|
||||
buckets = new Array(LUMINANCE_BUCKETS);
|
||||
}
|
||||
for (var j:int=0;j<buckets.length;j++) { buckets[j]=0;}
|
||||
}
|
||||
|
||||
private static function estimateBlackPoint(buckets:Array):int {
|
||||
// Find the tallest peak in the histogram.
|
||||
var numBuckets:int = buckets.length;
|
||||
var maxBucketCount:int = 0;
|
||||
var firstPeak:int = 0;
|
||||
var firstPeakSize:int = 0;
|
||||
for (var x:int = 0; x < numBuckets; x++) {
|
||||
if (buckets[x] > firstPeakSize) {
|
||||
firstPeak = x;
|
||||
firstPeakSize = buckets[x];
|
||||
}
|
||||
if (buckets[x] > maxBucketCount) {
|
||||
maxBucketCount = buckets[x];
|
||||
}
|
||||
}
|
||||
|
||||
// Find the second-tallest peak which is somewhat far from the tallest peak.
|
||||
var secondPeak:int = 0;
|
||||
var secondPeakScore:int = 0;
|
||||
for (var x2:int = 0; x2 < numBuckets; x2++) {
|
||||
var distanceToBiggest:int = x2 - firstPeak;
|
||||
// Encourage more distant second peaks by multiplying by square of distance.
|
||||
var score:int = buckets[x2] * distanceToBiggest * distanceToBiggest;
|
||||
if (score > secondPeakScore) {
|
||||
secondPeak = x2;
|
||||
secondPeakScore = score;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure firstPeak corresponds to the black peak.
|
||||
if (firstPeak > secondPeak) {
|
||||
var temp:int = firstPeak;
|
||||
firstPeak = secondPeak;
|
||||
secondPeak = temp;
|
||||
}
|
||||
|
||||
// If there is too little contrast in the image to pick a meaningful black point, throw rather
|
||||
// than waste time trying to decode the image, and risk false positives.
|
||||
// TODO: It might be worth comparing the brightest and darkest pixels seen, rather than the
|
||||
// two peaks, to determine the contrast.
|
||||
if (secondPeak - firstPeak <= numBuckets >> 4) {
|
||||
throw new ReaderException("GlobalHistogramBinarizer : estimateBlackPoint");
|
||||
}
|
||||
|
||||
// Find a valley between them that is low and closer to the white peak.
|
||||
var bestValley:int = secondPeak - 1;
|
||||
var bestValleyScore:int = -1;
|
||||
for (var x3:int = secondPeak - 1; x3 > firstPeak; x3--) {
|
||||
var fromFirst:int = x3 - firstPeak;
|
||||
var score2:int = fromFirst * fromFirst * (secondPeak - x3) * (maxBucketCount - buckets[x3]);
|
||||
if (score2 > bestValleyScore) {
|
||||
bestValley = x3;
|
||||
bestValleyScore = score2;
|
||||
}
|
||||
}
|
||||
|
||||
return bestValley << LUMINANCE_SHIFT;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
242
actionscript/core/src/com/google/zxing/common/GridSampler.as
Normal file
242
actionscript/core/src/com/google/zxing/common/GridSampler.as
Normal file
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
* 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
|
||||
{
|
||||
/**
|
||||
* Implementations of this class can, given locations of finder patterns for a QR code in an
|
||||
* image, sample the right points in the image to reconstruct the QR code, accounting for
|
||||
* perspective distortion. It is abstracted since it is relatively expensive and should be allowed
|
||||
* to take advantage of platform-specific optimized implementations, like Sun's Java Advanced
|
||||
* Imaging library, but which may not be available in other environments such as J2ME, and vice
|
||||
* versa.
|
||||
*
|
||||
* The implementation used can be controlled by calling {@link #setGridSampler(GridSampler)}
|
||||
* with an instance of a class which implements this interface.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*
|
||||
*/
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
import com.google.zxing.ReaderException;
|
||||
|
||||
public class GridSampler
|
||||
{
|
||||
|
||||
private static var gridSampler:GridSampler = new GridSampler();
|
||||
|
||||
/**
|
||||
* Sets the implementation of {@link GridSampler} used by the library. One global
|
||||
* instance is stored, which may sound problematic. But, the implementation provided
|
||||
* ought to be appropriate for the entire platform, and all uses of this library
|
||||
* in the whole lifetime of the JVM. For instance, an Android activity can swap in
|
||||
* an implementation that takes advantage of native platform libraries.
|
||||
*
|
||||
* @param newGridSampler The platform-specific object to install.
|
||||
*/
|
||||
public static function setGridSampler(newGridSampler:GridSampler):void {
|
||||
if (newGridSampler == null) {
|
||||
throw new IllegalArgumentException("common : GridSampler : setGridSampler");;
|
||||
}
|
||||
gridSampler = newGridSampler;
|
||||
}
|
||||
/**
|
||||
* @return the current implementation of {@link GridSampler}
|
||||
*/
|
||||
|
||||
|
||||
public static function getGridSamplerInstance():GridSampler
|
||||
{
|
||||
return gridSampler;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Samples an image for a square matrix of bits of the given dimension. This is used to extract
|
||||
* the black/white modules of a 2D barcode like a QR Code found in an image. Because this barcode
|
||||
* may be rotated or perspective-distorted, the caller supplies four points in the source image
|
||||
* that define known points in the barcode, so that the image may be sampled appropriately.</p>
|
||||
*
|
||||
* <p>The last eight "from" parameters are four X/Y coordinate pairs of locations of points in
|
||||
* the image that define some significant points in the image to be sample. For example,
|
||||
* these may be the location of finder pattern in a QR Code.</p>
|
||||
*
|
||||
* <p>The first eight "to" parameters are four X/Y coordinate pairs measured in the destination
|
||||
* {@link BitMatrix}, from the top left, where the known points in the image given by the "from"
|
||||
* parameters map to.</p>
|
||||
*
|
||||
* <p>These 16 parameters define the transformation needed to sample the image.</p>
|
||||
*
|
||||
* @param image image to sample
|
||||
* @param dimension width/height of {@link BitMatrix} to sample from iamge
|
||||
* @return {@link BitMatrix} representing a grid of points sampled from the image within a region
|
||||
* defined by the "from" parameters
|
||||
* @throws ReaderException if image can't be sampled, for example, if the transformation defined
|
||||
* 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;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* <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>
|
||||
*
|
||||
* <p>This method will actually "nudge" the endpoints back onto the image if they are found to be
|
||||
* barely (less than 1 pixel) off the image. This accounts for imperfect detection of finder
|
||||
* patterns in an image where the QR Code runs all the way to the image border.</p>
|
||||
*
|
||||
* <p>For efficiency, the method will check points from either end of the line until one is found
|
||||
* to be within the image. Because the set of points are assumed to be linear, this is valid.</p>
|
||||
*
|
||||
* @param image image into which the points should map
|
||||
* @param points actual points in x1,y1,...,xn,yn form
|
||||
* @throws ReaderException if an endpoint is lies outside the image boundaries
|
||||
*/
|
||||
public static function checkAndNudgePoints(image:BitMatrix, points:Array):void
|
||||
{
|
||||
var width:int = image.getWidth();
|
||||
var height:int = image.getHeight();
|
||||
// Check and nudge points from start until we see some that are OK:
|
||||
var nudged:Boolean = true;
|
||||
for (var offset:int = 0; offset < points.length && nudged; offset += 2)
|
||||
{
|
||||
var x:int = int(points[offset]);
|
||||
var y:int = int(points[offset + 1]);
|
||||
if (x < -1 || x > width || y < -1 || y > height)
|
||||
{
|
||||
throw new ReaderException("common : GridSampler : checkAndNudgePoints : point out of range ("+x+""+y+") max:"+width+" - "+height);
|
||||
}
|
||||
nudged = false;
|
||||
if (x == -1)
|
||||
{
|
||||
points[offset] = 0;
|
||||
nudged = true;
|
||||
}
|
||||
else if (x == width)
|
||||
{
|
||||
points[offset] = width - 1;
|
||||
nudged = true;
|
||||
}
|
||||
if (y == -1)
|
||||
{
|
||||
points[offset + 1] = 0;
|
||||
nudged = true;
|
||||
}
|
||||
else if (y == height)
|
||||
{
|
||||
points[offset + 1] = height - 1;
|
||||
nudged = true;
|
||||
}
|
||||
}
|
||||
// Check and nudge points from end:
|
||||
nudged = true;
|
||||
for (var offset1:int = points.length - 2; offset >= 0 && nudged; offset -= 2)
|
||||
{
|
||||
var x1:int = int(points[offset1]);
|
||||
var y1:int = int(points[offset1 + 1]);
|
||||
if (x1 < -1 || x1 > width || y1 < -1 || y1 > height)
|
||||
{
|
||||
throw new ReaderException("common : GridSampler : checkAndNudgePoints : out of bounds");
|
||||
}
|
||||
nudged = false;
|
||||
if (x1 == -1)
|
||||
{
|
||||
points[offset1] = 0;
|
||||
nudged = true;
|
||||
}
|
||||
else if (x1 == width)
|
||||
{
|
||||
points[offset1] = width - 1;
|
||||
nudged = true;
|
||||
}
|
||||
if (y1 == -1)
|
||||
{
|
||||
points[offset1 + 1] = 0;
|
||||
nudged = true;
|
||||
}
|
||||
else if (y1 == height)
|
||||
{
|
||||
points[offset1 + 1] = height - 1;
|
||||
nudged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* 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 final class LocalBlockBinarizer extends Binarizer {
|
||||
|
||||
|
||||
private var matrix:BitMatrix = null;
|
||||
|
||||
public function LocalBlockBinarizer(source:LuminanceSource) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
// TODO: Consider a different strategy for 1D Readers.
|
||||
public override function getBlackRow(y:int , row:BitArray ):BitArray {
|
||||
binarizeEntireImage();
|
||||
return matrix.getRow(y, row);
|
||||
}
|
||||
|
||||
// TODO: If getBlackRow() calculates its own values, removing sharpening here.
|
||||
public override function getBlackMatrix():BitMatrix {
|
||||
binarizeEntireImage();
|
||||
return matrix;
|
||||
}
|
||||
|
||||
public override function createBinarizer(source:LuminanceSource ):Binarizer {
|
||||
return new LocalBlockBinarizer(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();
|
||||
var luminances:Array = source.getMatrix();
|
||||
var width:int = source.getWidth();
|
||||
var height:int = source.getHeight();
|
||||
sharpenRow(luminances, width, height);
|
||||
|
||||
var subWidth:int = width >> 3;
|
||||
var subHeight:int = height >> 3;
|
||||
var blackPoints:Array = calculateBlackPoints(luminances, subWidth, subHeight, width);
|
||||
|
||||
matrix = new BitMatrix(width, height);
|
||||
calculateThresholdForBlock(luminances, subWidth, subHeight, width, blackPoints, matrix);
|
||||
}
|
||||
}
|
||||
|
||||
// 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 ,
|
||||
stride:int , blackPoints:Array , matrix:BitMatrix ):void {
|
||||
for (var y:int = 0; y < subHeight; y++) {
|
||||
for (var x:int = 0; x < subWidth; x++) {
|
||||
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++) {
|
||||
sum += blackPoints[top + z][left - 2];
|
||||
sum += blackPoints[top + z][left - 1];
|
||||
sum += blackPoints[top + z][left];
|
||||
sum += blackPoints[top + z][left + 1];
|
||||
sum += blackPoints[top + z][left + 2];
|
||||
}
|
||||
var average:int = sum / 25;
|
||||
threshold8x8Block(luminances, x << 3, y << 3, average, stride, 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,
|
||||
stride:int):Array {
|
||||
//int[][] blackPoints = new int[subHeight][subWidth];
|
||||
var blackPoints:Array = new Array();
|
||||
for (var y:int = 0; y < subHeight; y++) {
|
||||
for (var x:int = 0; x < subWidth; x++) {
|
||||
var sum:int = 0;
|
||||
var min:int = 255;
|
||||
var max:int = 0;
|
||||
for (var yy:int = 0; yy < 8; yy++) {
|
||||
var offset:int = ((y << 3) + yy) * stride + (x << 3);
|
||||
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 = (max - min > 24) ? (sum >> 6) : (min >> 1);
|
||||
blackPoints[y][x] = average;
|
||||
}
|
||||
}
|
||||
return blackPoints;
|
||||
}
|
||||
|
||||
// Applies a simple -1 4 -1 box filter with a weight of 2 to each row.
|
||||
private static function sharpenRow(luminances:Array, width:int, height:int):void {
|
||||
for (var y:int = 0; y < height; y++) {
|
||||
var offset:int = y * width;
|
||||
var left:int = luminances[offset] & 0xff;
|
||||
var center:int = luminances[offset + 1] & 0xff;
|
||||
for (var x:int = 1; x < width - 1; x++) {
|
||||
var right:int = luminances[offset + x + 1] & 0xff;
|
||||
var pixel:int = ((center << 2) - left - right) >> 1;
|
||||
// Must clamp values to 0..255 so they will fit in a byte.
|
||||
if (pixel > 255) {
|
||||
pixel = 255;
|
||||
} else if (pixel < 0) {
|
||||
pixel = 0;
|
||||
}
|
||||
luminances[offset + x] = pixel;
|
||||
left = center;
|
||||
center = right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* 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
|
||||
{
|
||||
/**
|
||||
* <p>This class implements a perspective transform in two dimensions. Given four source and four
|
||||
* destination points, it will compute the transformation implied between them. The code is based
|
||||
* directly upon section 3.4.2 of George Wolberg's "Digital Image Warping"; see pages 54-56.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public class PerspectiveTransform
|
||||
{
|
||||
|
||||
private var a11:Number;
|
||||
private var a12:Number;
|
||||
private var a13:Number;
|
||||
private var a21:Number;
|
||||
private var a22:Number;
|
||||
private var a23:Number;
|
||||
private var a31:Number;
|
||||
private var a32:Number;
|
||||
private var a33:Number;
|
||||
|
||||
public function PerspectiveTransform( a11:Number, a21:Number,a31:Number, a12:Number, a22:Number, a32:Number, a13:Number, a23:Number, a33:Number)
|
||||
{
|
||||
this.a11 = a11;
|
||||
this.a12 = a12;
|
||||
this.a13 = a13;
|
||||
this.a21 = a21;
|
||||
this.a22 = a22;
|
||||
this.a23 = a23;
|
||||
this.a31 = a31;
|
||||
this.a32 = a32;
|
||||
this.a33 = a33;
|
||||
}
|
||||
|
||||
public static function quadrilateralToQuadrilateral(x0:Number,y0:Number,x1:Number,y1:Number,x2:Number,y2:Number,x3:Number,y3:Number,x0p:Number,y0p:Number,x1p:Number,y1p:Number,x2p:Number, y2p:Number,x3p:Number,y3p:Number):PerspectiveTransform
|
||||
{
|
||||
|
||||
var qToS:PerspectiveTransform = quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3);
|
||||
var sToQ:PerspectiveTransform = squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p);
|
||||
return sToQ.times(qToS);
|
||||
}
|
||||
public function transformPoints(points:Array):Array
|
||||
{
|
||||
var max:int = points.length;
|
||||
var a11:Number = this.a11;
|
||||
var a12:Number = this.a12;
|
||||
var a13:Number = this.a13;
|
||||
var a21:Number = this.a21;
|
||||
var a22:Number = this.a22;
|
||||
var a23:Number = this.a23;
|
||||
var a31:Number = this.a31;
|
||||
var a32:Number = this.a32;
|
||||
var a33:Number = this.a33;
|
||||
for (var i:int = 0; i < max; i += 2)
|
||||
{
|
||||
var x:Number = points[i];
|
||||
var y:Number = points[i + 1];
|
||||
var denominator:Number = a13 * x + a23 * y + a33;
|
||||
points[i] = (a11 * x + a21 * y + a31) / denominator;
|
||||
points[i + 1] = (a12 * x + a22 * y + a32) / denominator;
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
public static function squareToQuadrilateral(x0:Number,y0:Number,x1:Number,y1:Number,x2:Number,y2:Number,x3:Number,y3:Number):PerspectiveTransform
|
||||
{
|
||||
var dy2:Number = y3 - y2;
|
||||
var dy3:Number = y0 - y1 + y2 - y3;
|
||||
if (dy2 == 0 && dy3 == 0)
|
||||
{
|
||||
return new PerspectiveTransform(x1 - x0, x2 - x1, x0, y1 - y0, y2 - y1, y0, 0, 0, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
var dx1:Number = x1 - x2;
|
||||
var dx2:Number = x3 - x2;
|
||||
var dx3:Number = x0 - x1 + x2 - x3;
|
||||
var dy1:Number = y1 - y2;
|
||||
var denominator:Number = dx1 * dy2 - dx2 * dy1;
|
||||
var a13:Number = (dx3 * dy2 - dx2 * dy3) / denominator;
|
||||
var a23:Number = (dx1 * dy3 - dx3 * dy1) / denominator;
|
||||
return new PerspectiveTransform(x1 - x0 + a13 * x1, x3 - x0 + a23 * x3, x0, y1 - y0 + a13 * y1, y3 - y0 + a23 * y3, y0, a13, a23, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public static function quadrilateralToSquare(x0:Number,y0:Number,x1:Number,y1:Number,x2:Number,y2:Number,x3:Number,y3:Number):PerspectiveTransform
|
||||
{
|
||||
// Here, the adjoint serves as the inverse:
|
||||
return squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3).buildAdjoint();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* 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.detector
|
||||
{
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.ResultPoint;
|
||||
import com.google.zxing.ReaderException;
|
||||
|
||||
/**
|
||||
* <p>A somewhat generic detector that looks for a barcode-like rectangular region within an image.
|
||||
* It looks within a mostly white region of an image for a region of black and white, but mostly
|
||||
* black. It returns the four corners of the region, as best it can determine.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class MonochromeRectangleDetector
|
||||
{
|
||||
|
||||
private static var MAX_MODULES:int = 32;
|
||||
|
||||
private var image:BitMatrix;
|
||||
|
||||
public function MonochromeRectangleDetector(image:BitMatrix)
|
||||
{
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Detects a rectangular region of black and white -- mostly black -- with a region of mostly
|
||||
* white, in an image.</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 ReaderException if no Data Matrix Code can be found
|
||||
*/
|
||||
public function detect():Array
|
||||
{
|
||||
var height:int = image.getHeight();
|
||||
var width:int = image.getWidth();
|
||||
var halfHeight:int = height >> 1;
|
||||
var halfWidth:int = width >> 1;
|
||||
var deltaY:int = Math.max(1, height / (MAX_MODULES << 3));
|
||||
var deltaX:int = Math.max(1, width / (MAX_MODULES << 3));
|
||||
|
||||
var top:int = 0;
|
||||
var bottom:int = height;
|
||||
var left:int = 0;
|
||||
var right:int = width;
|
||||
var pointA:ResultPoint = findCornerFromCenter(halfWidth, 0, left, right,
|
||||
halfHeight, -deltaY, top, bottom, halfWidth >> 1);
|
||||
top = int(pointA.getY() - 1);
|
||||
var pointB:ResultPoint = findCornerFromCenter(halfWidth, -deltaX, left, right,
|
||||
halfHeight, 0, top, bottom, halfHeight >> 1);
|
||||
left = int(pointB.getX() - 1);
|
||||
var pointC:ResultPoint = findCornerFromCenter(halfWidth, deltaX, left, right,
|
||||
halfHeight, 0, top, bottom, halfHeight >> 1);
|
||||
right = int(pointC.getX() + 1);
|
||||
var pointD:ResultPoint = findCornerFromCenter(halfWidth, 0, left, right,
|
||||
halfHeight, deltaY, top, bottom, halfWidth >> 1);
|
||||
bottom = int(pointD.getY() + 1);
|
||||
|
||||
// Go try to find point A again with better information -- might have been off at first.
|
||||
pointA = findCornerFromCenter(halfWidth, 0, left, right,
|
||||
halfHeight, -deltaY, top, bottom, halfWidth >> 2);
|
||||
|
||||
return [pointA, pointB, pointC, pointD ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to locate a corner of the barcode by scanning up, down, left or right from a center
|
||||
* point which should be within the barcode.
|
||||
*
|
||||
* @param centerX center's x component (horizontal)
|
||||
* @param deltaX same as deltaY but change in x per step instead
|
||||
* @param left minimum value of x
|
||||
* @param right maximum value of x
|
||||
* @param centerY center's y component (vertical)
|
||||
* @param deltaY change in y per step. If scanning up this is negative; down, positive;
|
||||
* left or right, 0
|
||||
* @param top minimum value of y to search through (meaningless when di == 0)
|
||||
* @param bottom maximum value of y
|
||||
* @param maxWhiteRun maximum run of white pixels that can still be considered to be within
|
||||
* the barcode
|
||||
* @return a {@link com.google.zxing.ResultPoint} encapsulating the corner that was found
|
||||
* @throws com.google.zxing.ReaderException if such a point cannot be found
|
||||
*/
|
||||
private function findCornerFromCenter(centerX:int, deltaX:int, left:int, right:int,
|
||||
centerY:int, deltaY:int, top:int, bottom:int, maxWhiteRun:int):ResultPoint
|
||||
{
|
||||
var lastRange:Array = null;
|
||||
for (var y:int = centerY, x:int = centerX;
|
||||
y < bottom && y >= top && x < right && x >= left;
|
||||
y += deltaY, x += deltaX) {
|
||||
var range:Array;
|
||||
if (deltaX == 0) {
|
||||
// horizontal slices, up and down
|
||||
range = blackWhiteRange(y, maxWhiteRun, left, right, true);
|
||||
} else {
|
||||
// vertical slices, left and right
|
||||
range = blackWhiteRange(x, maxWhiteRun, top, bottom, false);
|
||||
}
|
||||
if (range == null) {
|
||||
if (lastRange == null) {
|
||||
throw new ReaderException("MonochromeRectangleDetector : findCornerFromCenter : range and lastRange null");
|
||||
}
|
||||
// lastRange was found
|
||||
if (deltaX == 0) {
|
||||
var lastY:int = y - deltaY;
|
||||
if (lastRange[0] < centerX) {
|
||||
if (lastRange[1] > centerX) {
|
||||
// straddle, choose one or the other based on direction
|
||||
return new ResultPoint(deltaY > 0 ? lastRange[0] : lastRange[1], lastY);
|
||||
}
|
||||
return new ResultPoint(lastRange[0], lastY);
|
||||
} else {
|
||||
return new ResultPoint(lastRange[1], lastY);
|
||||
}
|
||||
} else {
|
||||
var lastX:int = x - deltaX;
|
||||
if (lastRange[0] < centerY) {
|
||||
if (lastRange[1] > centerY) {
|
||||
return new ResultPoint(lastX, deltaX < 0 ? lastRange[0] : lastRange[1]);
|
||||
}
|
||||
return new ResultPoint(lastX, lastRange[0]);
|
||||
} else {
|
||||
return new ResultPoint(lastX, lastRange[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
lastRange = range;
|
||||
}
|
||||
throw new ReaderException("MonochromeRectangleDetector : findCornerFromCenter :generic error");
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the start and end of a region of pixels, either horizontally or vertically, that could
|
||||
* be part of a Data Matrix barcode.
|
||||
*
|
||||
* @param fixedDimension if scanning horizontally, this is the row (the fixed vertical location)
|
||||
* where we are scanning. If scanning vertically it's the colummn, the fixed horizontal location
|
||||
* @param maxWhiteRun largest run of white pixels that can still be considered part of the
|
||||
* barcode region
|
||||
* @param minDim minimum pixel location, horizontally or vertically, to consider
|
||||
* @param maxDim maximum pixel location, horizontally or vertically, to consider
|
||||
* @param horizontal if true, we're scanning left-right, instead of up-down
|
||||
* @return int[] with start and end of found range, or null if no such range is found
|
||||
* (e.g. only white was found)
|
||||
*/
|
||||
private function blackWhiteRange(fixedDimension:int, maxWhiteRun:int, minDim:int, maxDim:int,
|
||||
horizontal:Boolean):Array
|
||||
{
|
||||
|
||||
var center:int = (minDim + maxDim) >> 1;
|
||||
|
||||
// Scan left/up first
|
||||
var start:int = center;
|
||||
var condition:Boolean;
|
||||
var whiteRunStart:int;
|
||||
while (start >= minDim) {
|
||||
if (horizontal ? image._get(start, fixedDimension) : image._get(fixedDimension, start)) {
|
||||
start--;
|
||||
} else {
|
||||
whiteRunStart = start;
|
||||
|
||||
do {
|
||||
start--;
|
||||
condition = (horizontal ? image._get(start, fixedDimension) : image._get(fixedDimension, start));
|
||||
} while ((start >= minDim )&& !condition);
|
||||
var whiteRunSize:int = whiteRunStart - start;
|
||||
if (start < minDim || whiteRunSize > maxWhiteRun) {
|
||||
start = whiteRunStart;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
start++;
|
||||
|
||||
// Then try right/down
|
||||
var end:int = center;
|
||||
while (end < maxDim) {
|
||||
if (horizontal ? image._get(end, fixedDimension) : image._get(fixedDimension, end)) {
|
||||
end++;
|
||||
} else {
|
||||
whiteRunStart = end;
|
||||
do {
|
||||
end++;
|
||||
condition = horizontal ? image._get(end, fixedDimension) : image._get(fixedDimension, end);
|
||||
} while (end < maxDim && !condition );
|
||||
var whiteRunSize2:int = end - whiteRunStart;
|
||||
if (end >= maxDim || whiteRunSize2 > maxWhiteRun) {
|
||||
end = whiteRunStart;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
end--;
|
||||
|
||||
return end > start ? [start, end] : null;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
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;
|
||||
|
||||
|
||||
public class ArrayList
|
||||
{
|
||||
//BAS : made public for debugging
|
||||
public var _array:Array;
|
||||
public function ArrayList(siz:int=0)
|
||||
{
|
||||
this._array = new Array(siz);
|
||||
}
|
||||
public function get Capacity():int
|
||||
{
|
||||
return this._array.length;
|
||||
}
|
||||
|
||||
public function getObjectByIndex(index:int):Object
|
||||
{
|
||||
var obj:Object = this._array[index];
|
||||
return obj;
|
||||
}
|
||||
|
||||
public function setObjectByIndex(index:int,obj:Object):void
|
||||
{
|
||||
this._array[index] = obj;
|
||||
}
|
||||
|
||||
|
||||
public function Contains(o:Object):Boolean
|
||||
{
|
||||
if (this._array.indexOf(o) != -1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function set Capacity(cap:int):void
|
||||
{
|
||||
// not needed;
|
||||
}
|
||||
|
||||
public function AddRange(itemsToAdd:Array):void
|
||||
{
|
||||
// add this number of items
|
||||
var len:int = this._array.length;
|
||||
for (var i:int=0;i<itemsToAdd.length;i++)
|
||||
{
|
||||
this._array.push(new Object());
|
||||
}
|
||||
}
|
||||
|
||||
public function indexOf(o:Object):int
|
||||
{
|
||||
return this._array.indexOf(o);
|
||||
}
|
||||
|
||||
public function RemoveRange(newSize:int,itemsToRemove:int):void
|
||||
{
|
||||
// remove the items
|
||||
var tmpAr:Object;
|
||||
for (var i:int=0;i<itemsToRemove;i++)
|
||||
{
|
||||
// remove the item with this index
|
||||
tmpAr = this._array.pop();
|
||||
}
|
||||
}
|
||||
|
||||
public function get Count():int
|
||||
{
|
||||
return this._array.length;
|
||||
}
|
||||
|
||||
public function Add(item:Object):void
|
||||
{
|
||||
|
||||
this._array.push(item);
|
||||
}
|
||||
|
||||
public function addElement(item:Object):void
|
||||
{
|
||||
this.Add(item);
|
||||
}
|
||||
|
||||
public function get length():int
|
||||
{
|
||||
return this._array.length;
|
||||
}
|
||||
|
||||
public function sort_ResultPointsAndTransitionsComparator():void
|
||||
{
|
||||
this._array.sort(ResultPointsAndTransitionsComparator.compare);
|
||||
//this._array.sort(args);
|
||||
}
|
||||
|
||||
public function sort_CenterComparator():void
|
||||
{
|
||||
this._array.sort(CenterComparator.compare);
|
||||
}
|
||||
|
||||
public function size():int
|
||||
{
|
||||
return this._array.length;
|
||||
}
|
||||
|
||||
public function elementAt(index:int):Object
|
||||
{
|
||||
return this._array[index];
|
||||
}
|
||||
|
||||
public function isEmpty():Boolean
|
||||
{
|
||||
if (this._array.length == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
package com.google.zxing.common.flexdatatypes
|
||||
{
|
||||
public class HashTable
|
||||
{
|
||||
// bas : made public for debugging
|
||||
public var _arr:Array;
|
||||
|
||||
public function isEmpty():Boolean
|
||||
{
|
||||
return this.getSize()==0?true:false;
|
||||
}
|
||||
|
||||
public function getSize():int
|
||||
{
|
||||
return this._arr.length;
|
||||
}
|
||||
|
||||
public function getIndexOf(key:Object):int
|
||||
{
|
||||
for (var i:int=0;i<this._arr.length;i++)
|
||||
{
|
||||
if (this._arr[i][0] == key)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public function getValueByIndex(index:int):Object
|
||||
{
|
||||
return this._arr[index][1];
|
||||
}
|
||||
|
||||
public function getKeyByIndex(index:int):Object
|
||||
{
|
||||
return this._arr[index][0];
|
||||
}
|
||||
|
||||
public function HashTable(siz:int=0)
|
||||
{
|
||||
this._arr = new Array(siz);
|
||||
}
|
||||
|
||||
public function Add(key:Object, value:Object):void
|
||||
{
|
||||
var ta:Array = new Array(2);
|
||||
ta[0] = key;
|
||||
ta[1] = value;
|
||||
this._arr[this._arr.length] = ta;
|
||||
}
|
||||
|
||||
public function _put(k:Object,v:Object):void
|
||||
{
|
||||
this.Add(k,v);
|
||||
}
|
||||
|
||||
public function ContainsKey(key:Object):Boolean
|
||||
{
|
||||
for (var i:int=0;i<this._arr.length;i++)
|
||||
{
|
||||
if (this._arr[i][0] == key) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getValuesByKey(key:Object):ArrayList
|
||||
{
|
||||
var al:ArrayList = new ArrayList();
|
||||
for (var i:int=0;i<this._arr.length;i++)
|
||||
{
|
||||
if (this._arr[i][0] == key)
|
||||
{
|
||||
al.Add(this._arr[i][1]);
|
||||
}
|
||||
}
|
||||
return al;
|
||||
}
|
||||
|
||||
public function _get(key:Object):Object
|
||||
{
|
||||
return this.getValueByKey(key);
|
||||
}
|
||||
|
||||
public function getValueByKey(key:Object):Object
|
||||
{
|
||||
var al:ArrayList = new ArrayList();
|
||||
for (var i:int=0;i<this._arr.length;i++)
|
||||
{
|
||||
if (this._arr[i][0] == key)
|
||||
{
|
||||
return this._arr[i][1];
|
||||
}
|
||||
}
|
||||
return al;
|
||||
}
|
||||
|
||||
public function setValue(key:Object,value:Object):void
|
||||
{
|
||||
for (var i:int=0;i<this._arr.length;i++)
|
||||
{
|
||||
if (this._arr[i][0] == key)
|
||||
{
|
||||
this._arr[i][1] = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getKeyByValue(value:Object):int
|
||||
{
|
||||
for (var i:int=0;i<this._arr.length;i++)
|
||||
{
|
||||
if (this._arr[i][1] == value)
|
||||
{
|
||||
return this._arr[i][0];
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public function containsKey(key:Object):Boolean
|
||||
{
|
||||
for (var i:int=0;i<this._arr.length;i++)
|
||||
{
|
||||
if (this._arr[i][0] == key)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.google.zxing.common.flexdatatypes
|
||||
{
|
||||
public class IllegalArgumentException extends Error
|
||||
{
|
||||
public function IllegalArgumentException(message:String="")
|
||||
{
|
||||
super("IllegalArgumentException"+message);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
package com.google.zxing.common.flexdatatypes
|
||||
{
|
||||
import com.google.zxing.ReaderException;
|
||||
|
||||
public class StringBuilder
|
||||
{
|
||||
public var _string:String = "";
|
||||
|
||||
public function StringBuilder(ignore:int=0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function charAt(index:int):String
|
||||
{
|
||||
return this._string.charAt(index);
|
||||
}
|
||||
|
||||
|
||||
public function setCharAt(index:int, char:String):void
|
||||
{
|
||||
var temp:Array = this._string.split("");
|
||||
temp[index] = char.charAt(0);
|
||||
this._string = temp.join("");
|
||||
}
|
||||
|
||||
public function setLength(l:int):void
|
||||
{
|
||||
if (l == 0)
|
||||
{
|
||||
this._string = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ReaderException("StringBuilder : setLength : only 0 supported");
|
||||
}
|
||||
}
|
||||
|
||||
public function Append(o:Object,startIndex:int=-1,count:int=-1):void
|
||||
{
|
||||
if (startIndex == -1)
|
||||
{
|
||||
if (o is Array)
|
||||
{
|
||||
this._string = this._string + (o as Array).join("");
|
||||
}
|
||||
else
|
||||
{
|
||||
this._string = this._string + o.toString();
|
||||
}
|
||||
}
|
||||
else if (count == -1)
|
||||
{
|
||||
this._string = this._string + (o.toString()).substr(startIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
this._string = this._string + (o.toString()).substr(startIndex,count);
|
||||
}
|
||||
}
|
||||
|
||||
public function ToString():String
|
||||
{
|
||||
return this._string;
|
||||
}
|
||||
|
||||
public function get length():int
|
||||
{
|
||||
return this._string.length;
|
||||
}
|
||||
|
||||
public function set length(size:int):void
|
||||
{
|
||||
if (size==0) { this._string = "";}
|
||||
else
|
||||
{
|
||||
throw new ReaderException("size can ony be set to 0");
|
||||
}
|
||||
}
|
||||
public function Insert (pos:int,o:Object):void
|
||||
{
|
||||
if (pos == 0)
|
||||
{
|
||||
this._string = o.toString() + this._string;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ReaderException('pos not supported yet');
|
||||
}
|
||||
}
|
||||
|
||||
public function Remove(startIndex:int,length:int):void
|
||||
{
|
||||
|
||||
var leftPart:String = "";
|
||||
var rightPart:String = "";
|
||||
if (startIndex > 0) { leftPart = this._string.substring(0,startIndex); }
|
||||
if ((startIndex+length) < this._string.length)
|
||||
{ rightPart = this._string.substr(startIndex+length); }
|
||||
this._string = leftPart + rightPart;
|
||||
}
|
||||
|
||||
public function toString():String
|
||||
{
|
||||
return this._string;
|
||||
}
|
||||
|
||||
public function deleteCharAt(index:int):void
|
||||
{
|
||||
var temp:Array = this._string.split("");
|
||||
var result:String = "";
|
||||
for(var i:int=0;i<temp.length;i++)
|
||||
{
|
||||
if (i!=index){result = result + (temp[i] as String); }
|
||||
}
|
||||
this._string = result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.google.zxing.common.flexdatatypes
|
||||
{
|
||||
public class Utils
|
||||
{
|
||||
public function Utils()
|
||||
{
|
||||
}
|
||||
|
||||
public static function startsWith(text:String, subtext:String):Boolean
|
||||
{
|
||||
if (text.substr(0,subtext.length) == subtext) { return true; }
|
||||
return false;
|
||||
}
|
||||
public static function endsWith(text:String, subtext:String):Boolean
|
||||
{
|
||||
if (text.substr(text.length-subtext.length) == subtext) { return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function isDigit(s:String):Boolean
|
||||
{
|
||||
return !isNaN(Number(s));
|
||||
}
|
||||
|
||||
public static function arraycopy(source:Array, sourceoffset:int, target:Array, targetoffset:int, length:int):void
|
||||
{
|
||||
for (var i:int=sourceoffset;i<(sourceoffset+length);i++)
|
||||
{
|
||||
target[targetoffset++] = source[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* 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.reedsolomon
|
||||
{
|
||||
/**
|
||||
* <p>This class contains utility methods for performing mathematical operations over
|
||||
* the Galois Field GF(256). Operations use a given primitive polynomial in calculations.</p>
|
||||
*
|
||||
* <p>Throughout this package, elements of GF(256) are represented as an <code>int</code>
|
||||
* for convenience and speed (but at the cost of memory).
|
||||
* Only the bottom 8 bits are really used.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public class GF256
|
||||
{
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
|
||||
public static var QR_CODE_FIELD:GF256 = new GF256(0x011D); // x^8 + x^4 + x^3 + x^2 + 1
|
||||
public static var DATA_MATRIX_FIELD:GF256 = new GF256(0x012D); // x^8 + x^5 + x^3 + x^2 + 1
|
||||
|
||||
public var expTable:Array;
|
||||
public var logTable:Array;
|
||||
private var zero:GF256Poly;
|
||||
private var one:GF256Poly;
|
||||
|
||||
/**
|
||||
* Create a representation of GF(256) using the given primitive polynomial.
|
||||
*
|
||||
* @param primitive irreducible polynomial whose coefficients are represented by
|
||||
* the bits of an int, where the least-significant bit represents the constant
|
||||
* coefficient
|
||||
*/
|
||||
public function GF256(primitive:int) {
|
||||
expTable = new Array(256);
|
||||
logTable = new Array(256);
|
||||
var x:int = 1;
|
||||
for (var i:int = 0; i < 256; i++) {
|
||||
expTable[i] = x;
|
||||
x <<= 1; // x = x * 2; we're assuming the generator alpha is 2
|
||||
if (x >= 0x100) {
|
||||
x ^= primitive;
|
||||
}
|
||||
}
|
||||
for (var i2:int = 0; i2 < 255; i2++) {
|
||||
logTable[expTable[i2]] = i2;
|
||||
}
|
||||
// logTable[0] == 0 but this should never be used
|
||||
zero = new GF256Poly(this, [0]);
|
||||
one = new GF256Poly(this, [1]);
|
||||
}
|
||||
|
||||
public function getZero():GF256Poly {
|
||||
return zero;
|
||||
}
|
||||
|
||||
public function getOne():GF256Poly
|
||||
{
|
||||
return one;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the monomial representing coefficient * x^degree
|
||||
*/
|
||||
public function buildMonomial(degree:int, coefficient:int):GF256Poly
|
||||
{
|
||||
if (degree < 0) {
|
||||
throw new IllegalArgumentException("common : reedsolomon : gf256 : buildnominal");
|
||||
}
|
||||
if (coefficient == 0) {
|
||||
return zero;
|
||||
}
|
||||
var coefficients:Array = new Array(degree + 1);
|
||||
coefficients[0] = coefficient;
|
||||
return new GF256Poly(this, coefficients);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements both addition and subtraction -- they are the same in GF(256).
|
||||
*
|
||||
* @return sum/difference of a and b
|
||||
*/
|
||||
public static function addOrSubtract(a:int, b:int):int {
|
||||
return a ^ b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 2 to the power of a in GF(256)
|
||||
*/
|
||||
public function exp(a:int):int
|
||||
{
|
||||
return expTable[a];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return base 2 log of a in GF(256)
|
||||
*/
|
||||
public function log(a:int):int
|
||||
{
|
||||
if (a == 0) {
|
||||
throw new IllegalArgumentException("common : reedsolomon : gf256 : log : a == 0");
|
||||
}
|
||||
return logTable[a];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return multiplicative inverse of a
|
||||
*/
|
||||
public function inverse(a:int):int
|
||||
{
|
||||
if (a == 0) {
|
||||
throw new IllegalArgumentException("GF256:inverse: a cannot be 0");
|
||||
}
|
||||
return expTable[255 - logTable[a]];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param a
|
||||
* @param b
|
||||
* @return product of a and b in GF(256)
|
||||
*/
|
||||
public function multiply(a:int, b:int):int
|
||||
{
|
||||
if (a == 0 || b == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (a == 1) {
|
||||
return b;
|
||||
}
|
||||
if (b == 1) {
|
||||
return a;
|
||||
}
|
||||
return expTable[(logTable[a] + logTable[b]) % 255];
|
||||
}
|
||||
|
||||
|
||||
public function Equals(other:GF256):Boolean
|
||||
{
|
||||
if (expTable != other.expTable) { return false; }
|
||||
if (logTable != other.logTable) { return false; }
|
||||
if (zero != other.getZero()) { return false; }
|
||||
if (one != other.getOne()) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,310 @@
|
|||
/*
|
||||
* 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.reedsolomon
|
||||
{
|
||||
/**
|
||||
* <p>Represents a polynomial whose coefficients are elements of GF(256).
|
||||
* Instances of this class are immutable.</p>
|
||||
*
|
||||
* <p>Much credit is due to William Rucklidge since portions of this code are an indirect
|
||||
* port of his C++ Reed-Solomon implementation.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
public class GF256Poly
|
||||
{
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
|
||||
private var field:GF256;
|
||||
private var coefficients:Array ;
|
||||
|
||||
/**
|
||||
* @param field the {@link GF256} instance representing the field to use
|
||||
* to perform computations
|
||||
* @param coefficients coefficients as ints representing elements of GF(256), arranged
|
||||
* from most significant (highest-power term) coefficient to least significant
|
||||
* @throws Error if argument is null or empty,
|
||||
* or if leading coefficient is 0 and this is not a
|
||||
* constant polynomial (that is, it is not the monomial "0")
|
||||
*/
|
||||
public function GF256Poly( field:GF256, coefficients:Array) {
|
||||
if (coefficients == null || coefficients.length == 0) {
|
||||
throw new IllegalArgumentException("common : reedsolomon : GFPoly : constructor input parameters invalid");
|
||||
}
|
||||
this.field = field;
|
||||
var coefficientsLength:int = coefficients.length;
|
||||
if (coefficientsLength > 1 && coefficients[0] == 0) {
|
||||
// Leading term must be non-zero for anything except the constant polynomial "0"
|
||||
var firstNonZero:int = 1;
|
||||
while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0) {
|
||||
firstNonZero++;
|
||||
}
|
||||
if (firstNonZero == coefficientsLength) {
|
||||
this.coefficients = field.getZero().coefficients;
|
||||
} else {
|
||||
this.coefficients = new Array(coefficientsLength - firstNonZero);
|
||||
|
||||
//System.Array.Copy(coefficients,firstNonZero,this.coefficients,0,this.coefficients.length);
|
||||
var ctr:int=0;
|
||||
for (var i:int = firstNonZero;i<coefficients.length;i++)
|
||||
{
|
||||
this.coefficients[ctr] = coefficients[i];
|
||||
ctr++;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} else {
|
||||
this.coefficients = coefficients;
|
||||
}
|
||||
}
|
||||
|
||||
public function getCoefficients():Array
|
||||
{
|
||||
return coefficients;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return degree of this polynomial
|
||||
*/
|
||||
public function getDegree():int
|
||||
{
|
||||
return coefficients.length - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true iff this polynomial is the monomial "0"
|
||||
*/
|
||||
public function isZero():Boolean
|
||||
{
|
||||
return coefficients[0] == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return coefficient of x^degree term in this polynomial
|
||||
*/
|
||||
public function getCoefficient(degree:int):int
|
||||
{
|
||||
return coefficients[coefficients.length - 1 - degree];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return evaluation of this polynomial at a given point
|
||||
*/
|
||||
public function evaluateAt(a:int):int
|
||||
{
|
||||
if (a == 0) {
|
||||
// Just return the x^0 coefficient
|
||||
return getCoefficient(0);
|
||||
}
|
||||
var size:int = coefficients.length;
|
||||
var result:int = 0;
|
||||
|
||||
if (a == 1) {
|
||||
// Just the sum of the coefficients
|
||||
result = 0;
|
||||
for (var i2:int = 0; i2 < size; i2++) {
|
||||
result = GF256.addOrSubtract(result, coefficients[i2]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
result = coefficients[0];
|
||||
for (var i:int = 1; i < size; i++) {
|
||||
result = GF256.addOrSubtract(field.multiply(a, result), coefficients[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public function addOrSubtract(other:GF256Poly):GF256Poly
|
||||
{
|
||||
if (field != other.field) {
|
||||
throw new IllegalArgumentException("common : reedsolomon : GFPoly : GF256Polys do not have same GF256 field");
|
||||
}
|
||||
if (isZero()) {
|
||||
return other;
|
||||
}
|
||||
if (other.isZero()) {
|
||||
return this;
|
||||
}
|
||||
|
||||
var smallerCoefficients:Array = this.coefficients;
|
||||
var largerCoefficients:Array = other.coefficients;
|
||||
if (smallerCoefficients.length > largerCoefficients.length) {
|
||||
var temp:Array = smallerCoefficients;
|
||||
smallerCoefficients = largerCoefficients;
|
||||
largerCoefficients = temp;
|
||||
}
|
||||
var sumDiff:Array = new Array(largerCoefficients.length);
|
||||
var lengthDiff:int = largerCoefficients.length - smallerCoefficients.length;
|
||||
// Copy high-order terms only found in higher-degree polynomial's coefficients
|
||||
//System.Array.Copy(largerCoefficients, 0, sumDiff, 0, lengthDiff);
|
||||
for (var ii:int=0;ii<lengthDiff;ii++)
|
||||
{
|
||||
sumDiff[ii] = largerCoefficients[ii];
|
||||
}
|
||||
|
||||
for (var i:int = lengthDiff; i < largerCoefficients.length; i++) {
|
||||
sumDiff[i] = GF256.addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]);
|
||||
}
|
||||
|
||||
return new GF256Poly(field, sumDiff);
|
||||
}
|
||||
|
||||
|
||||
public function multiply(other:Object):GF256Poly
|
||||
{
|
||||
if (other is GF256Poly) { return multiply_GF256Poly(other as GF256Poly);}
|
||||
else if (other is int) { return multiply_int(other as int);}
|
||||
else { new IllegalArgumentException('common : reedsolomon : GFPoly : GF256Poly : multiply : unknown type of other'); }
|
||||
return null;
|
||||
}
|
||||
|
||||
public function multiply_GF256Poly(other:GF256Poly ):GF256Poly
|
||||
{
|
||||
if (field != other.field) {
|
||||
throw new IllegalArgumentException("common : reedsolomon : GFPoly : GF256Polys do not have same GF256 field");
|
||||
}
|
||||
if (isZero() || other.isZero()) {
|
||||
return field.getZero();
|
||||
}
|
||||
var aCoefficients:Array = this.coefficients;
|
||||
var aLength:int = aCoefficients.length;
|
||||
var bCoefficients:Array = other.coefficients;
|
||||
var bLength:int = bCoefficients.length;
|
||||
var product:Array = new Array(aLength + bLength - 1);
|
||||
for (var i:int = 0; i < aLength; i++) {
|
||||
var aCoeff:int = aCoefficients[i];
|
||||
for (var j:int = 0; j < bLength; j++) {
|
||||
product[i + j] = GF256.addOrSubtract(product[i + j],
|
||||
field.multiply(aCoeff, bCoefficients[j]));
|
||||
}
|
||||
}
|
||||
return new GF256Poly(field, product);
|
||||
}
|
||||
|
||||
public function multiply_int(scalar:int):GF256Poly
|
||||
{
|
||||
if (scalar == 0) {
|
||||
return field.getZero();
|
||||
}
|
||||
if (scalar == 1) {
|
||||
return this;
|
||||
}
|
||||
var size:int = coefficients.length;
|
||||
var product:Array = new Array(size);
|
||||
for (var i:int = 0; i < size; i++) {
|
||||
product[i] = field.multiply(coefficients[i], scalar);
|
||||
}
|
||||
return new GF256Poly(field, product);
|
||||
}
|
||||
|
||||
public function multiplyByMonomial(degree:int, coefficient:int):GF256Poly
|
||||
{
|
||||
if (degree < 0) {
|
||||
throw new IllegalArgumentException("common : reedsolomon : GFPoly : degree less then 0");
|
||||
}
|
||||
if (coefficient == 0) {
|
||||
return field.getZero();
|
||||
}
|
||||
var size:int = coefficients.length;
|
||||
var product:Array = new Array(size + degree);
|
||||
for (var i:int = 0; i < size; i++) {
|
||||
product[i] = field.multiply(coefficients[i], coefficient);
|
||||
}
|
||||
return new GF256Poly(field, product);
|
||||
}
|
||||
|
||||
public function divide(other:GF256Poly):Array
|
||||
{
|
||||
if (field != other.field) {
|
||||
throw new IllegalArgumentException("common : reedsolomon : GFPoly : GF256Polys do not have same GF256 field");
|
||||
}
|
||||
if (other.isZero()) {
|
||||
throw new IllegalArgumentException("common : reedsolomon : GFPoly : Divide by 0");
|
||||
}
|
||||
|
||||
var quotient:GF256Poly = field.getZero();
|
||||
var remainder:GF256Poly = this;
|
||||
|
||||
var denominatorLeadingTerm:int = other.getCoefficient(other.getDegree());
|
||||
var inverseDenominatorLeadingTerm:int = field.inverse(denominatorLeadingTerm);
|
||||
|
||||
while (remainder.getDegree() >= other.getDegree() && !remainder.isZero()) {
|
||||
var degreeDifference:int = remainder.getDegree() - other.getDegree();
|
||||
var scale:int = field.multiply(remainder.getCoefficient(remainder.getDegree()), inverseDenominatorLeadingTerm);
|
||||
var term:GF256Poly = other.multiplyByMonomial(degreeDifference, scale);
|
||||
var iterationQuotient:GF256Poly = field.buildMonomial(degreeDifference, scale);
|
||||
quotient = quotient.addOrSubtract(iterationQuotient);
|
||||
remainder = remainder.addOrSubtract(term);
|
||||
}
|
||||
|
||||
return [quotient, remainder];
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
var result:StringBuilder = new StringBuilder(8 * getDegree());
|
||||
for (var degree:int = getDegree(); degree >= 0; degree--) {
|
||||
var coefficient:int = getCoefficient(degree);
|
||||
if (coefficient != 0) {
|
||||
if (coefficient < 0) {
|
||||
result.Append(" - ");
|
||||
coefficient = -coefficient;
|
||||
} else {
|
||||
if (result.length > 0) {
|
||||
result.Append(" + ");
|
||||
}
|
||||
}
|
||||
if (degree == 0 || coefficient != 1) {
|
||||
var alphaPower:int = field.log(coefficient);
|
||||
if (alphaPower == 0) {
|
||||
result.Append('1');
|
||||
} else if (alphaPower == 1) {
|
||||
result.Append('a');
|
||||
} else {
|
||||
result.Append("a^");
|
||||
result.Append(alphaPower);
|
||||
}
|
||||
}
|
||||
if (degree != 0) {
|
||||
if (degree == 1) {
|
||||
result.Append('x');
|
||||
} else {
|
||||
result.Append("x^");
|
||||
result.Append(degree);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.ToString();
|
||||
}
|
||||
public function Equals(other:GF256Poly):Boolean
|
||||
{
|
||||
var result:Boolean = false;
|
||||
if (this.field == other.field)
|
||||
{
|
||||
if (this.coefficients.Equals(other.coefficients))
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* 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.reedsolomon
|
||||
{
|
||||
/**
|
||||
* <p>Implements Reed-Solomon decoding, as the name implies.</p>
|
||||
*
|
||||
* <p>The algorithm will not be explained here, but the following references were helpful
|
||||
* in creating this implementation:</p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>Bruce Maggs.
|
||||
* <a href="http://www.cs.cmu.edu/afs/cs.cmu.edu/project/pscico-guyb/realworld/www/rs_decode.ps">
|
||||
* "Decoding Reed-Solomon Codes"</a> (see discussion of Forney's Formula)</li>
|
||||
* <li>J.I. Hall. <a href="www.mth.msu.edu/~jhall/classes/codenotes/GRS.pdf">
|
||||
* "Chapter 5. Generalized Reed-Solomon Codes"</a>
|
||||
* (see discussion of Euclidean algorithm)</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Much credit is due to William Rucklidge since portions of this code are an indirect
|
||||
* port of his C++ Reed-Solomon implementation.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
* @author William Rucklidge
|
||||
* @author sanfordsquires
|
||||
*/
|
||||
public class ReedSolomonDecoder
|
||||
{
|
||||
private var field:GF256;
|
||||
|
||||
public function ReedSolomonDecoder(field:GF256) {
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Decodes given set of received codewords, which include both data and error-correction
|
||||
* codewords. Really, this means it uses Reed-Solomon to detect and correct errors, in-place,
|
||||
* in the input.</p>
|
||||
*
|
||||
* @param received data and error-correction codewords
|
||||
* @param twoS number of error-correction codewords available
|
||||
* @throws ReedSolomonException if decoding fails for any reason
|
||||
*/
|
||||
public function decode(received:Array, twoS:int):void {
|
||||
var poly:GF256Poly = new GF256Poly(field, received);
|
||||
var syndromeCoefficients:Array = new Array(twoS);
|
||||
var dataMatrix:Boolean = (field == GF256.DATA_MATRIX_FIELD);
|
||||
var noError:Boolean = true;
|
||||
for (var i:int = 0; i < twoS; i++) {
|
||||
// Thanks to sanfordsquires for this fix:
|
||||
var eval:int = poly.evaluateAt(field.exp(dataMatrix ? i + 1 : i));
|
||||
syndromeCoefficients[syndromeCoefficients.length - 1 - i] = eval;
|
||||
if (eval != 0) {
|
||||
noError = false;
|
||||
}
|
||||
}
|
||||
if (noError) {
|
||||
return;
|
||||
}
|
||||
var syndrome:GF256Poly = new GF256Poly(field, syndromeCoefficients);
|
||||
var sigmaOmega:Array = runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS);
|
||||
var sigma:GF256Poly = sigmaOmega[0];
|
||||
var omega:GF256Poly = sigmaOmega[1];
|
||||
var errorLocations:Array = findErrorLocations(sigma);
|
||||
var errorMagnitudes:Array = findErrorMagnitudes(omega, errorLocations, dataMatrix);
|
||||
for (var j:int = 0; j < errorLocations.length; j++) {
|
||||
var position:int = received.length - 1 - field.log(errorLocations[j]);
|
||||
if (position < 0) {
|
||||
throw new ReedSolomonException("Bad error location");
|
||||
}
|
||||
received[position] = GF256.addOrSubtract(received[position], errorMagnitudes[j]);
|
||||
}
|
||||
}
|
||||
|
||||
private function runEuclideanAlgorithm(a:GF256Poly, b:GF256Poly, R:int ):Array
|
||||
{
|
||||
// Assume a's degree is >= b's
|
||||
if (a.getDegree() < b.getDegree()) {
|
||||
var temp:GF256Poly = a;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
||||
|
||||
var rLast:GF256Poly = a;
|
||||
var r:GF256Poly = b;
|
||||
var sLast:GF256Poly = field.getOne();
|
||||
var s:GF256Poly = field.getZero();
|
||||
var tLast:GF256Poly = field.getZero();
|
||||
var t:GF256Poly = field.getOne();
|
||||
|
||||
// Run Euclidean algorithm until r's degree is less than R/2
|
||||
while (r.getDegree() >= R / 2) {
|
||||
var rLastLast:GF256Poly = rLast;
|
||||
var sLastLast:GF256Poly = sLast;
|
||||
var tLastLast:GF256Poly = tLast;
|
||||
rLast = r;
|
||||
sLast = s;
|
||||
tLast = t;
|
||||
|
||||
// Divide rLastLast by rLast, with quotient in q and remainder in r
|
||||
if (rLast.isZero()) {
|
||||
// Oops, Euclidean algorithm already terminated?
|
||||
throw new ReedSolomonException("r_{i-1} was zero");
|
||||
}
|
||||
r = rLastLast;
|
||||
var q:GF256Poly = field.getZero();
|
||||
var denominatorLeadingTerm:int = rLast.getCoefficient(rLast.getDegree());
|
||||
var dltInverse:int = field.inverse(denominatorLeadingTerm);
|
||||
while (r.getDegree() >= rLast.getDegree() && !r.isZero()) {
|
||||
var degreeDiff:int = r.getDegree() - rLast.getDegree();
|
||||
var scale:int = field.multiply(r.getCoefficient(r.getDegree()), dltInverse);
|
||||
q = q.addOrSubtract(field.buildMonomial(degreeDiff, scale));
|
||||
r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale));
|
||||
}
|
||||
|
||||
s = q.multiply(sLast).addOrSubtract(sLastLast);
|
||||
t = q.multiply(tLast).addOrSubtract(tLastLast);
|
||||
}
|
||||
|
||||
var sigmaTildeAtZero:int = t.getCoefficient(0);
|
||||
if (sigmaTildeAtZero == 0) {
|
||||
throw new ReedSolomonException("sigmaTilde(0) was zero");
|
||||
}
|
||||
|
||||
var inverse:int = field.inverse(sigmaTildeAtZero);
|
||||
var sigma:GF256Poly = t.multiply(inverse);
|
||||
var omega:GF256Poly = r.multiply(inverse);
|
||||
return [sigma, omega];
|
||||
}
|
||||
|
||||
private function findErrorLocations(errorLocator:GF256Poly):Array{
|
||||
// This is a direct application of Chien's search
|
||||
var numErrors:int = errorLocator.getDegree();
|
||||
if (numErrors == 1) { // shortcut
|
||||
return [errorLocator.getCoefficient(1)];
|
||||
}
|
||||
var result:Array = new Array(numErrors);
|
||||
var e:int = 0;
|
||||
for (var i:int = 1; i < 256 && e < numErrors; i++) {
|
||||
if (errorLocator.evaluateAt(i) == 0) {
|
||||
result[e] = field.inverse(i);
|
||||
e++;
|
||||
}
|
||||
}
|
||||
if (e != numErrors) {
|
||||
throw new ReedSolomonException("Error locator degree does not match number of roots");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private function findErrorMagnitudes(errorEvaluator:GF256Poly , errorLocations:Array, dataMatrix:Boolean):Array {
|
||||
// This is directly applying Forney's Formula
|
||||
var s:int = errorLocations.length;
|
||||
var result:Array = new Array(s);
|
||||
for (var i:int = 0; i < s; i++) {
|
||||
var xiInverse:int = field.inverse(errorLocations[i]);
|
||||
var denominator:int = 1;
|
||||
for (var j:int = 0; j < s; j++) {
|
||||
if (i != j) {
|
||||
denominator = field.multiply(denominator,
|
||||
GF256.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse)));
|
||||
}
|
||||
}
|
||||
result[i] = field.multiply(errorEvaluator.evaluateAt(xiInverse),
|
||||
field.inverse(denominator));
|
||||
// Thanks to sanfordsquires for this fix:
|
||||
if (dataMatrix) {
|
||||
result[i] = field.multiply(result[i], xiInverse);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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.common.reedsolomon
|
||||
{
|
||||
public class ReedSolomonEncoder
|
||||
{
|
||||
import com.google.zxing.common.flexdatatypes.ArrayList;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
|
||||
private var Field:GF256 ;
|
||||
private var cachedGenerators:ArrayList;
|
||||
|
||||
public function ReedSolomonEncoder(field:GF256 ) {
|
||||
if (GF256.QR_CODE_FIELD != field) {
|
||||
throw new IllegalArgumentException("Only QR Code is supported at this time");
|
||||
}
|
||||
this.Field = field;
|
||||
this.cachedGenerators = new ArrayList();
|
||||
cachedGenerators.Add(new GF256Poly(field, [ 1 ]));
|
||||
}
|
||||
|
||||
private function buildGenerator(degree:int):GF256Poly {
|
||||
if (degree >= cachedGenerators.Count) {
|
||||
var lastGenerator:GF256Poly = cachedGenerators.getObjectByIndex(cachedGenerators.Count - 1) as GF256Poly;
|
||||
for (var d:int = cachedGenerators.Count; d <= degree; d++)
|
||||
{
|
||||
var nextGenerator:GF256Poly = lastGenerator.multiply(new GF256Poly(Field, [ 1, Field.exp(d - 1)]));
|
||||
cachedGenerators.Add(nextGenerator);
|
||||
lastGenerator = nextGenerator;
|
||||
}
|
||||
}
|
||||
return (cachedGenerators.getObjectByIndex(degree) as GF256Poly);
|
||||
}
|
||||
|
||||
public function encode( toEncode:Array, ecBytes:int) :void{
|
||||
if (ecBytes == 0) {
|
||||
throw new IllegalArgumentException("No error correction bytes");
|
||||
}
|
||||
var dataBytes:int = toEncode.length - ecBytes;
|
||||
if (dataBytes <= 0) {
|
||||
throw new IllegalArgumentException("No data bytes provided");
|
||||
}
|
||||
var generator:GF256Poly = buildGenerator(ecBytes);
|
||||
var infoCoefficients:Array = new Array(dataBytes);
|
||||
//System.Array.Copy(toEncode, 0, infoCoefficients, 0, dataBytes);
|
||||
for (var ii:int=0;ii<dataBytes;ii++)
|
||||
{
|
||||
infoCoefficients[ii] = toEncode[ii];
|
||||
}
|
||||
|
||||
var info:GF256Poly = new GF256Poly(this.Field, infoCoefficients);
|
||||
info = info.multiplyByMonomial(ecBytes, 1);
|
||||
var remainder:GF256Poly = info.divide(generator)[1];
|
||||
var coefficients:Array = remainder.getCoefficients();
|
||||
var numZeroCoefficients:int = ecBytes - coefficients.length;
|
||||
for (var i:int = 0; i < numZeroCoefficients; i++) {
|
||||
toEncode[dataBytes + i] = 0;
|
||||
}
|
||||
//System.Array.Copy(coefficients, 0, toEncode, dataBytes + numZeroCoefficients, coefficients.length);
|
||||
for(var jj:int=0;jj < coefficients.length;jj++)
|
||||
{
|
||||
toEncode[dataBytes + numZeroCoefficients + jj] = coefficients[jj];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.google.zxing.common.reedsolomon
|
||||
{
|
||||
public class ReedSolomonException extends Error
|
||||
{
|
||||
public function ReedSolomonException(message:String="")
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
155
actionscript/core/src/com/google/zxing/common/zxingByteArray.as
Normal file
155
actionscript/core/src/com/google/zxing/common/zxingByteArray.as
Normal file
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* 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.common
|
||||
{
|
||||
import mx.messaging.AbstractConsumer;
|
||||
/**
|
||||
* This class implements an array of unsigned bytes.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/ public class zxingByteArray
|
||||
{
|
||||
|
||||
private static var INITIAL_SIZE:int = 32;
|
||||
|
||||
// BAS : made public for debugging
|
||||
private var bytes:Array;
|
||||
private var Size:int;
|
||||
|
||||
public function zxingByteArray(size:Object=null)
|
||||
{
|
||||
if (size == null)
|
||||
{
|
||||
bytes = null;
|
||||
this.Size = 0;
|
||||
}
|
||||
else if (size is int)
|
||||
{
|
||||
bytes = new Array(int(size));
|
||||
this.Size = int(size);
|
||||
}
|
||||
else if (size is Array)
|
||||
{
|
||||
bytes = (size as Array);
|
||||
this.Size = size.length;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Error("unknown type of size");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Access an unsigned byte at location index.
|
||||
* @param index The index in the array to access.
|
||||
* @return The unsigned value of the byte as an int.
|
||||
*/
|
||||
public function at(index:int):int
|
||||
{
|
||||
return bytes[index] & 0xff;
|
||||
}
|
||||
|
||||
/*public function set(index:int, value:int):void
|
||||
{
|
||||
// Flex doesn't know bytes -> make it a byte
|
||||
if (value > 127) { value = 256 - value);
|
||||
bytes[index] = value;
|
||||
}*/
|
||||
|
||||
public function setByte(index:int, value:int):void
|
||||
{
|
||||
// Flex doesn't know bytes -> make it a byte
|
||||
if (value > 127) { value = (256 - value)*-1;}
|
||||
bytes[index] = value;
|
||||
}
|
||||
|
||||
|
||||
public function getByte(index:int):int
|
||||
{
|
||||
return bytes[index];
|
||||
}
|
||||
|
||||
public function size():int
|
||||
{
|
||||
return Size;
|
||||
}
|
||||
|
||||
public function empty():Boolean
|
||||
{
|
||||
return (Size == 0);
|
||||
}
|
||||
|
||||
public function appendByte(value:int):void
|
||||
{
|
||||
if (Size == 0 || Size >= bytes.length)
|
||||
{
|
||||
var newSize:int = Math.max(INITIAL_SIZE, Size << 1);
|
||||
reserve(newSize);
|
||||
}
|
||||
// Flex doesn't know bytes -> make it a byte
|
||||
if (value > 127) { value = (256 - value)*-1;}
|
||||
bytes[Size] = value;
|
||||
Size++;
|
||||
}
|
||||
|
||||
public function reserve(capacity:int):void
|
||||
{
|
||||
if (bytes == null || bytes.length < capacity)
|
||||
{
|
||||
var newArray:Array = new Array(capacity);
|
||||
if (bytes != null)
|
||||
{
|
||||
//System.Array.Copy(bytes, 0, newArray, 0, bytes.length);
|
||||
for (var i:int=0;i<bytes.length;i++)
|
||||
{
|
||||
newArray[i] = bytes[i];
|
||||
}
|
||||
}
|
||||
bytes = newArray;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy count bytes from array source starting at offset.
|
||||
public function _set(source:Array, offset:int, count:int):void
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
this.bytes[offset] = count;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes = new Array(count);
|
||||
Size = count;
|
||||
for (var x:int = 0; x < count; x++)
|
||||
{
|
||||
// Flex doesn't know bytes -> make it a byte
|
||||
if (source[offset + x] > 127)
|
||||
{
|
||||
bytes[x] = (256-source[offset + x])*-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes[x] = source[offset + x];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* 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.datamatrix
|
||||
{
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.DecodeHintType;
|
||||
import com.google.zxing.BinaryBitmap;
|
||||
import com.google.zxing.Reader;
|
||||
import com.google.zxing.ReaderException;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.ResultPoint;
|
||||
import com.google.zxing.ResultMetadataType;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.common.DecoderResult;
|
||||
import com.google.zxing.common.DetectorResult;
|
||||
import com.google.zxing.datamatrix.decoder.Decoder;
|
||||
import com.google.zxing.datamatrix.detector.Detector;
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
|
||||
public class DataMatrixReader implements Reader
|
||||
{
|
||||
|
||||
/**
|
||||
* This implementation can detect and decode Data Matrix codes in an image.
|
||||
*
|
||||
* @author bbrown@google.com (Brian Brown)
|
||||
*/
|
||||
|
||||
public function DataMatrixReader()
|
||||
{}
|
||||
|
||||
private static var NO_POINTS:Array = new Array();
|
||||
private var decoder:Decoder = new Decoder();
|
||||
|
||||
/**
|
||||
* Locates and decodes a Data Matrix code in an image.
|
||||
*
|
||||
* @return a String representing the content encoded by the Data Matrix code
|
||||
* @throws ReaderException if a Data Matrix code cannot be found, or cannot be decoded
|
||||
*/
|
||||
/* public function decode( image:MonochromeBitmapSource):Result {
|
||||
return decode(image, null);
|
||||
}
|
||||
*/
|
||||
|
||||
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.getBlackMatrix());
|
||||
decoderResult = decoder.decode(bits);
|
||||
points = NO_POINTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
var bm:BitMatrix = image.getBlackMatrix();
|
||||
var detectorResult:DetectorResult = new Detector(bm).detect();
|
||||
decoderResult = decoder.decode(detectorResult.getBits());
|
||||
points = detectorResult.getPoints();
|
||||
}
|
||||
var result:Result = new Result(decoderResult.getText(), decoderResult.getRawBytes(), points, BarcodeFormat.DATAMATRIX);
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method detects a Data Matrix code in a "pure" image -- that is, pure monochrome image
|
||||
* which contains only an unrotated, unskewed, image of a Data Matrix code, with some white border
|
||||
* 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
|
||||
|
||||
var height:int = image.getHeight();
|
||||
var width:int = image.getWidth();
|
||||
var minDimension:int = Math.min(height, width);
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
var moduleSize:int = moduleEnd - borderWidth;
|
||||
|
||||
// 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++;
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,458 @@
|
|||
/*
|
||||
* 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.datamatrix.decoder
|
||||
{
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
import com.google.zxing.ReaderException;
|
||||
/**
|
||||
* @author bbrown@google.com (Brian Brown)
|
||||
*/
|
||||
public class BitMatrixParser
|
||||
{
|
||||
|
||||
private var mappingBitMatrix:BitMatrix;
|
||||
private var readMappingMatrix:BitMatrix;
|
||||
private var version:Version;
|
||||
|
||||
/**
|
||||
* @param bitMatrix {@link BitMatrix} to parse
|
||||
* @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) {
|
||||
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());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Creates the version object based on the dimension of the original bit matrix from
|
||||
* the datamatrix code.</p>
|
||||
*
|
||||
* <p>See ISO 16022:2006 Table 7 - ECC 200 symbol attributes</p>
|
||||
*
|
||||
* @param bitMatrix Original {@link BitMatrix} including alignment patterns
|
||||
* @return {@link Version} encapsulating the Data Matrix Code's "version"
|
||||
* @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);;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Reads the bits in the {@link BitMatrix} representing the mapping matrix (No alignment patterns)
|
||||
* in the correct order in order to reconstitute the codewords bytes contained within the
|
||||
* Data Matrix Code.</p>
|
||||
*
|
||||
* @return bytes encoded within the Data Matrix Code
|
||||
* @throws ReaderException if the exact number of bytes expected is not read
|
||||
*/
|
||||
public function readCodewords():Array {
|
||||
|
||||
var result:Array = new Array(version.getTotalCodewords());
|
||||
var resultOffset:int = 0;
|
||||
|
||||
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 corner1Read:Boolean = false;
|
||||
var corner2Read:Boolean = false;
|
||||
var corner3Read:Boolean = false;
|
||||
var corner4Read:Boolean = false;
|
||||
|
||||
// Read all of the codewords
|
||||
do {
|
||||
// Check the four corner cases
|
||||
if ((row == numRows) && (column == 0) && !corner1Read) {
|
||||
result[resultOffset++] = int(readCorner1(numRows, numColumns));
|
||||
row -= 2;
|
||||
column +=2;
|
||||
corner1Read = true;
|
||||
} else if ((row == numRows-2) && (column == 0) && ((numColumns & 0x03) != 0) && !corner2Read) {
|
||||
result[resultOffset++] = int(readCorner2(numRows, numColumns));
|
||||
row -= 2;
|
||||
column +=2;
|
||||
corner2Read = true;
|
||||
} else if ((row == numRows+4) && (column == 2) && ((numColumns & 0x07) == 0) && !corner3Read) {
|
||||
result[resultOffset++] = int(readCorner3(numRows, numColumns));
|
||||
row -= 2;
|
||||
column +=2;
|
||||
corner3Read = true;
|
||||
} else if ((row == numRows-2) && (column == 0) && ((numColumns & 0x07) == 4) && !corner4Read) {
|
||||
result[resultOffset++] = int(readCorner4(numRows, numColumns));
|
||||
row -= 2;
|
||||
column +=2;
|
||||
corner4Read = true;
|
||||
} else {
|
||||
// Sweep upward diagonally to the right
|
||||
do {
|
||||
if ((row < numRows) && (column >= 0) && !readMappingMatrix._get(column,row)) {
|
||||
result[resultOffset++] = readUtah(row, column, numRows, numColumns);
|
||||
}
|
||||
row -= 2;
|
||||
column +=2;
|
||||
} while ((row >= 0) && (column < numColumns));
|
||||
row += 1;
|
||||
column +=3;
|
||||
|
||||
// Sweep downward diagonally to the left
|
||||
do {
|
||||
if ((row >= 0) && (column < numColumns) && !readMappingMatrix._get(column,row)) {
|
||||
result[resultOffset++] = readUtah(row, column, numRows, numColumns);
|
||||
}
|
||||
row += 2;
|
||||
column -=2;
|
||||
} while ((row < numRows) && (column >= 0));
|
||||
row += 3;
|
||||
column +=1;
|
||||
}
|
||||
} while ((row < numRows) || (column < numColumns));
|
||||
|
||||
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)
|
||||
for (var jj:int=0;jj<result.length;jj++)
|
||||
{
|
||||
if ((result[jj] & 128) > 0 )
|
||||
{
|
||||
result[jj] = (result[jj] & 127) - 128
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Reads a bit of the mapping matrix accounting for boundary wrapping.</p>
|
||||
*
|
||||
* @param row Row to read in the mapping matrix
|
||||
* @param column Column to read in the mapping matrix
|
||||
* @param numRows Number of rows in the mapping matrix
|
||||
* @param numColumns Number of columns in the mapping matrix
|
||||
* @return value of the given bit in the mapping matrix
|
||||
*/
|
||||
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) {
|
||||
row += numRows;
|
||||
column += 4 - ((numRows + 4) & 0x07);
|
||||
}
|
||||
if (column < 0) {
|
||||
column += numColumns;
|
||||
row += 4 - ((numColumns + 4) & 0x07);
|
||||
}
|
||||
readMappingMatrix._set(column,row);
|
||||
return mappingBitMatrix._get(column,row);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Reads the 8 bits of the standard utah shaped pattern.</p>
|
||||
*
|
||||
* <p>See ISO 16022:2006, 5.8.1 Figure 6</p>
|
||||
*
|
||||
* @param row Current row in the mapping matrix, anchored at the 8th bit (LSB) of the pattern
|
||||
* @param column Current column in the mapping matrix, anchored at the 8th bit (LSB) of the pattern
|
||||
* @param numRows Number of rows in the mapping matrix
|
||||
* @param numColumns Number of columns in the mapping matrix
|
||||
* @return byte from the utah shape
|
||||
*/
|
||||
public function readUtah(row:int , column:int , numRows:int , numColumns:int ):int
|
||||
{
|
||||
var currentByte:int = 0;
|
||||
if (readModule(row - 2, column - 2, numRows, numColumns))
|
||||
{
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row - 2, column - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row - 1, column - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row - 1, column - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row - 1, column, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row, column - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row, column - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(row, column, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
return currentByte;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Reads the 8 bits of the special corner condition 1.</p>
|
||||
*
|
||||
* <p>See ISO 16022:2006, Figure F.3</p>
|
||||
*
|
||||
* @param numRows Number of rows in the mapping matrix
|
||||
* @param numColumns Number of columns in the mapping matrix
|
||||
* @return byte from the Corner condition 1
|
||||
*/
|
||||
public function readCorner1(numRows:int, numColumns:int):int {
|
||||
var currentByte:int = 0;
|
||||
if (readModule(numRows - 1, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 1, 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 1, 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(2, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(3, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
return currentByte;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Reads the 8 bits of the special corner condition 2.</p>
|
||||
*
|
||||
* <p>See ISO 16022:2006, Figure F.4</p>
|
||||
*
|
||||
* @param numRows Number of rows in the mapping matrix
|
||||
* @param numColumns Number of columns in the mapping matrix
|
||||
* @return byte from the Corner condition 2
|
||||
*/
|
||||
public function readCorner2(numRows:int, numColumns:int):int {
|
||||
var currentByte:int = 0;
|
||||
if (readModule(numRows - 3, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 2, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 1, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 4, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 3, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
return currentByte;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Reads the 8 bits of the special corner condition 3.</p>
|
||||
*
|
||||
* <p>See ISO 16022:2006, Figure F.5</p>
|
||||
*
|
||||
* @param numRows Number of rows in the mapping matrix
|
||||
* @param numColumns Number of columns in the mapping matrix
|
||||
* @return byte from the Corner condition 3
|
||||
*/
|
||||
public function readCorner3(numRows:int, numColumns:int):int {
|
||||
var currentByte:int = 0;
|
||||
if (readModule(numRows - 1, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 1, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 3, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 3, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
return currentByte;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Reads the 8 bits of the special corner condition 4.</p>
|
||||
*
|
||||
* <p>See ISO 16022:2006, Figure F.6</p>
|
||||
*
|
||||
* @param numRows Number of rows in the mapping matrix
|
||||
* @param numColumns Number of columns in the mapping matrix
|
||||
* @return byte from the Corner condition 4
|
||||
*/
|
||||
public function readCorner4(numRows:int, numColumns:int):int {
|
||||
var currentByte:int = 0;
|
||||
if (readModule(numRows - 3, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 2, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(numRows - 1, 0, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 2, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(0, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(1, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(2, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
currentByte <<= 1;
|
||||
if (readModule(3, numColumns - 1, numRows, numColumns)) {
|
||||
currentByte |= 1;
|
||||
}
|
||||
return currentByte;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Extracts the data region from a {@link BitMatrix} that contains
|
||||
* alignment patterns.</p>
|
||||
*
|
||||
* @param bitMatrix Original {@link BitMatrix} with alignment patterns
|
||||
* @return BitMatrix that has the alignment patterns removed
|
||||
*/
|
||||
public function extractDataRegion( bitMatrix:BitMatrix):BitMatrix {
|
||||
var symbolSizeRows:int = version.getSymbolSizeRows();
|
||||
var symbolSizeColumns:int = version.getSymbolSizeColumns();
|
||||
|
||||
// TODO(bbrown): Make this work with rectangular codes
|
||||
if (bitMatrix.getDimension() != symbolSizeRows) {
|
||||
throw new IllegalArgumentException("Dimension of bitMarix must match the version size");
|
||||
}
|
||||
|
||||
var dataRegionSizeRows:int = version.getDataRegionSizeRows();
|
||||
var dataRegionSizeColumns:int = version.getDataRegionSizeColumns();
|
||||
|
||||
var numDataRegionsRow:int = symbolSizeRows / dataRegionSizeRows;
|
||||
var numDataRegionsColumn:int = symbolSizeColumns / dataRegionSizeColumns;
|
||||
|
||||
var sizeDataRegionRow:int = numDataRegionsRow * dataRegionSizeRows;
|
||||
//int sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns;
|
||||
|
||||
// TODO(bbrown): Make this work with rectangular codes
|
||||
var bitMatrixWithoutAlignment:BitMatrix = new BitMatrix(sizeDataRegionRow);
|
||||
for (var dataRegionRow:int = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow) {
|
||||
var dataRegionRowOffset:int = dataRegionRow * dataRegionSizeRows;
|
||||
for (var dataRegionColumn:int = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn) {
|
||||
var dataRegionColumnOffset:int = dataRegionColumn * dataRegionSizeColumns;
|
||||
for (var i:int = 0; i < dataRegionSizeRows; ++i) {
|
||||
var readRowOffset:int = dataRegionRow * (dataRegionSizeRows + 2) + 1 + i;
|
||||
var writeRowOffset:int = dataRegionRowOffset + i;
|
||||
for (var j:int = 0; j < dataRegionSizeColumns; ++j) {
|
||||
var readColumnOffset:int = dataRegionColumn * (dataRegionSizeColumns + 2) + 1 + j;
|
||||
if (bitMatrix._get(readColumnOffset, readRowOffset)) {
|
||||
var writeColumnOffset:int = dataRegionColumnOffset + j;
|
||||
bitMatrixWithoutAlignment._set(writeColumnOffset, writeRowOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bitMatrixWithoutAlignment;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* 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.datamatrix.decoder
|
||||
{
|
||||
/**
|
||||
* <p>Encapsulates a block of data within a Data Matrix Code. Data Matrix Codes may split their data into
|
||||
* multiple blocks, each of which is a unit of data and error-correction codewords. Each
|
||||
* is represented by an instance of this class.</p>
|
||||
*
|
||||
* @author bbrown@google.com (Brian Brown)
|
||||
*/
|
||||
public class DataBlock
|
||||
{
|
||||
import com.google.zxing.datamatrix.decoder.ECB;
|
||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||
|
||||
private var numDataCodewords:int;
|
||||
private var codewords:Array;
|
||||
|
||||
public function DataBlock(numDataCodewords:int, codewords:Array) {
|
||||
this.numDataCodewords = numDataCodewords;
|
||||
this.codewords = codewords;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>When Data Matrix Codes use multiple data blocks, they actually interleave the bytes of each of them.
|
||||
* That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This
|
||||
* method will separate the data into original blocks.</p>
|
||||
*
|
||||
* @param rawCodewords bytes as read directly from the Data Matrix Code
|
||||
* @param version version of the Data Matrix Code
|
||||
* @return {@link DataBlock}s containing original bytes, "de-interleaved" from representation in the
|
||||
* Data Matrix Code
|
||||
*/
|
||||
public static function getDataBlocks(rawCodewords:Array,
|
||||
version:Version):Array {
|
||||
// Figure out the number and size of data blocks used by this version
|
||||
var ecBlocks:ECBlocks = version.getECBlocks();
|
||||
|
||||
// First count the total number of data blocks
|
||||
var totalBlocks:int = 0;
|
||||
var ecBlockArray:Array = ecBlocks.getECBlocks();
|
||||
for (var i:int = 0; i < ecBlockArray.length; i++) {
|
||||
totalBlocks += ecBlockArray[i].getCount();
|
||||
}
|
||||
// Now establish DataBlocks of the appropriate size and number of data codewords
|
||||
var result:Array = new Array(totalBlocks);
|
||||
var numResultBlocks:int = 0;
|
||||
for (var j:int = 0; j < ecBlockArray.length; j++) {
|
||||
var ecBlock:ECB = ecBlockArray[j];
|
||||
for (var i3:int = 0; i3 < ecBlock.getCount(); i3++) {
|
||||
var numDataCodewords:int = ecBlock.getDataCodewords();
|
||||
var numBlockCodewords:int = ecBlocks.getECCodewords() + numDataCodewords;
|
||||
result[numResultBlocks++] = new DataBlock(numDataCodewords, new Array(numBlockCodewords));
|
||||
}
|
||||
}
|
||||
|
||||
// All blocks have the same amount of data, except that the last n
|
||||
// (where n may be 0) have 1 less byte. Figure out where these start.
|
||||
// TODO(bbrown): There is only one case where there is a difference for Data Matrix for size 144
|
||||
var longerBlocksTotalCodewords:int = result[0].codewords.length;
|
||||
//int shorterBlocksTotalCodewords = longerBlocksTotalCodewords - 1;
|
||||
|
||||
var longerBlocksNumDataCodewords:int = longerBlocksTotalCodewords - ecBlocks.getECCodewords();
|
||||
var shorterBlocksNumDataCodewords:int = longerBlocksNumDataCodewords - 1;
|
||||
// The last elements of result may be 1 element shorter for 144 matrix
|
||||
// first fill out as many elements as all of them have minus 1
|
||||
var rawCodewordsOffset:int = 0;
|
||||
for (var i2:int = 0; i2 < shorterBlocksNumDataCodewords; i2++) {
|
||||
for (var j2:int = 0; j2 < numResultBlocks; j2++)
|
||||
{
|
||||
result[j2].codewords[i2] = rawCodewords[rawCodewordsOffset];
|
||||
rawCodewordsOffset++;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill out the last data block in the longer ones
|
||||
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++;
|
||||
}
|
||||
|
||||
// Now add in error correction blocks
|
||||
var max:int = result[0].codewords.length;
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
if (rawCodewordsOffset != rawCodewords.length) {
|
||||
throw new IllegalArgumentException("DataBlock : getDataBlocks : rawCodewordsOffset != rawCodewords.length : "+rawCodewordsOffset +" - "+rawCodewords.length);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public function getNumDataCodewords():int {
|
||||
return numDataCodewords;
|
||||
}
|
||||
|
||||
public function getCodewords():Array {
|
||||
return codewords;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,464 @@
|
|||
/*
|
||||
* 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.datamatrix.decoder
|
||||
{
|
||||
/**
|
||||
* <p>Data Matrix Codes can encode text as bits in one of several modes, and can use multiple modes
|
||||
* in one Data Matrix Code. This class decodes the bits back into text.</p>
|
||||
*
|
||||
* <p>See ISO 16022:2006, 5.2.1 - 5.2.9.2</p>
|
||||
*
|
||||
* @author bbrown@google.com (Brian Brown)
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
public class DecodedBitStreamParser
|
||||
{
|
||||
import com.google.zxing.common.flexdatatypes.ArrayList;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.common.BitSource;
|
||||
import com.google.zxing.common.DecoderResult;
|
||||
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||
import com.google.zxing.common.zxingByteArray;
|
||||
import com.google.zxing.ReaderException;
|
||||
/**
|
||||
* See ISO 16022:2006, Annex C Table C.1
|
||||
* The C40 Basic Character Set (*'s used for placeholders for the shift values)
|
||||
*/
|
||||
private static var C40_BASIC_SET_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 var C40_SHIFT2_SET_CHARS:Array = [
|
||||
'!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.',
|
||||
'/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_'
|
||||
];
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006, Annex C Table C.2
|
||||
* The Text Basic Character Set (*'s used for placeholders for the shift values)
|
||||
*/
|
||||
private static var TEXT_BASIC_SET_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 var TEXT_SHIFT3_SET_CHARS:Array = [
|
||||
'\'', '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', '{', '|', '}', '~', String.fromCharCode(0x127)
|
||||
];
|
||||
|
||||
public static const PAD_ENCODE:int = 0; // Not really an encoding
|
||||
public static const ASCII_ENCODE:int = 1;
|
||||
public static const C40_ENCODE:int = 2;
|
||||
public static const TEXT_ENCODE:int = 3;
|
||||
public static const ANSIX12_ENCODE:int = 4;
|
||||
public static const EDIFACT_ENCODE:int = 5;
|
||||
public static const BASE256_ENCODE:int = 6;
|
||||
|
||||
public function DecodedBitStreamParser() {
|
||||
}
|
||||
|
||||
public static function decode(bytes:Array ):DecoderResult {
|
||||
var bits:BitSource = new BitSource(bytes);
|
||||
var result:StringBuilder = new StringBuilder();
|
||||
var resultTrailer:StringBuilder = new StringBuilder(0);
|
||||
var byteSegments:ArrayList = new ArrayList(1);
|
||||
var mode:int = DecodedBitStreamParser.ASCII_ENCODE;
|
||||
do {
|
||||
if (mode == ASCII_ENCODE) {
|
||||
mode = decodeAsciiSegment(bits, result, resultTrailer);
|
||||
} else {
|
||||
switch (mode) {
|
||||
case C40_ENCODE:
|
||||
decodeC40Segment(bits, result);
|
||||
break;
|
||||
case TEXT_ENCODE:
|
||||
decodeTextSegment(bits, result);
|
||||
break;
|
||||
case ANSIX12_ENCODE:
|
||||
decodeAnsiX12Segment(bits, result);
|
||||
break;
|
||||
case EDIFACT_ENCODE:
|
||||
decodeEdifactSegment(bits, result);
|
||||
break;
|
||||
case BASE256_ENCODE:
|
||||
decodeBase256Segment(bits, result, byteSegments);
|
||||
break;
|
||||
default:
|
||||
throw new ReaderException("DecodedBitStreamParser : decode : unknown mode : "+mode);
|
||||
}
|
||||
mode = ASCII_ENCODE;
|
||||
}
|
||||
} while (mode != PAD_ENCODE && bits.available() > 0);
|
||||
if (resultTrailer.length > 0) {
|
||||
result.Append(resultTrailer);
|
||||
}
|
||||
return new DecoderResult(bytes, result.ToString(), (byteSegments.Count === 0) ? null : byteSegments, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.3 and Annex C, Table C.2
|
||||
*/
|
||||
private static function decodeAsciiSegment(bits:BitSource, result:StringBuilder, resultTrailer:StringBuilder):int
|
||||
{
|
||||
var upperShift:Boolean = false;
|
||||
do {
|
||||
var oneByte:int = bits.readBits(8);
|
||||
if (oneByte == 0) {
|
||||
throw new ReaderException("DecodedBitStreamParser : decodeAsciiSegment : oneByte = 0");
|
||||
} else if (oneByte <= 128) { // ASCII data (ASCII value + 1)
|
||||
oneByte = upperShift ? (oneByte + 128) : oneByte;
|
||||
upperShift = false;
|
||||
result.Append(String.fromCharCode(oneByte - 1));
|
||||
return ASCII_ENCODE;
|
||||
} else if (oneByte == 129) { // Pad
|
||||
return PAD_ENCODE;
|
||||
} else if (oneByte <= 229) { // 2-digit data 00-99 (Numeric Value + 130)
|
||||
var value:int = oneByte - 130;
|
||||
if (value < 10) { // padd with '0' for single digit values
|
||||
result.Append('0');
|
||||
}
|
||||
result.Append(value);
|
||||
} else if (oneByte == 230) { // Latch to C40 encodation
|
||||
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 == 235) { // Upper Shift (shift to Extended ASCII)
|
||||
upperShift = true;
|
||||
} else if (oneByte == 236) { // 05 Macro
|
||||
result.Append("[)>\u001E05\u001D");
|
||||
resultTrailer.Insert(0, "\u001E\u0004");
|
||||
} else if (oneByte == 237) { // 06 Macro
|
||||
result.Append("[)>\u001E06\u001D");
|
||||
resultTrailer.Insert(0, "\u001E\u0004");
|
||||
} else if (oneByte == 238) { // Latch to ANSI X12 encodation
|
||||
return ANSIX12_ENCODE;
|
||||
} else if (oneByte == 239) { // Latch to Text encodation
|
||||
return TEXT_ENCODE;
|
||||
} 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");
|
||||
} else if (oneByte >= 242) { // Not to be used in ASCII encodation
|
||||
throw new ReaderException("DecodedBitStreamParser : decodeAsciiSegment : oneByte = 242");
|
||||
}
|
||||
} while (bits.available() > 0);
|
||||
return ASCII_ENCODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.5 and Annex C, Table C.1
|
||||
*/
|
||||
private static function decodeC40Segment(bits:BitSource , result:StringBuilder ):void {
|
||||
// Three C40 values are encoded in a 16-bit value as
|
||||
// (1600 * C1) + (40 * C2) + C3 + 1
|
||||
// TODO(bbrown): The Upper Shift with C40 doesn't work in the 4 value scenario all the time
|
||||
var upperShift:Boolean = false;
|
||||
|
||||
var cValues:Array = new Array(3);
|
||||
do {
|
||||
// If there is only one byte left then it will be encoded as ASCII
|
||||
if (bits.available() == 8) {
|
||||
return;
|
||||
}
|
||||
var firstByte:int = bits.readBits(8);
|
||||
if (firstByte == 254) { // Unlatch codeword
|
||||
return;
|
||||
}
|
||||
|
||||
parseTwoBytes(firstByte, bits.readBits(8), cValues);
|
||||
|
||||
var shift:int = 0;
|
||||
for (var i:int = 0; i < 3; i++) {
|
||||
var cValue:int = cValues[i];
|
||||
switch (shift) {
|
||||
case 0:
|
||||
if (cValue < 3) {
|
||||
shift = cValue + 1;
|
||||
} else {
|
||||
if (upperShift) {
|
||||
result.Append(C40_BASIC_SET_CHARS[cValue] + 128);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result.Append(C40_BASIC_SET_CHARS[cValue]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (upperShift) {
|
||||
result.Append(cValue + 128);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result.Append(cValue);
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
case 2:
|
||||
if (cValue < 27) {
|
||||
if (upperShift) {
|
||||
result.Append(C40_SHIFT2_SET_CHARS[cValue] + 128);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result.Append(C40_SHIFT2_SET_CHARS[cValue]);
|
||||
}
|
||||
} else if (cValue == 27) { // FNC1
|
||||
throw new ReaderException("DecodedBitStreamParser : decodeC40Segment : cValue = 27");
|
||||
} else if (cValue == 30) { // Upper Shift
|
||||
upperShift = true;
|
||||
} else {
|
||||
throw new ReaderException("DecodedBitStreamParser : decodeC40Segment : cValue = no match:"+cValue);
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
case 3:
|
||||
if (upperShift) {
|
||||
result.Append(cValue + 224);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result.Append(cValue + 96);
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
default:
|
||||
throw new ReaderException("DecodedBitStreamParser : decodeC40Segment : no match for shift:"+shift);
|
||||
}
|
||||
}
|
||||
} while (bits.available() > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.6 and Annex C, Table C.2
|
||||
*/
|
||||
private static function decodeTextSegment(bits:BitSource , result:StringBuilder ):void {
|
||||
// Three Text values are encoded in a 16-bit value as
|
||||
// (1600 * C1) + (40 * C2) + C3 + 1
|
||||
// TODO(bbrown): The Upper Shift with Text doesn't work in the 4 value scenario all the time
|
||||
var upperShift:Boolean = false;
|
||||
|
||||
var cValues:Array = new Array(3);
|
||||
do {
|
||||
// If there is only one byte left then it will be encoded as ASCII
|
||||
if (bits.available() == 8) {
|
||||
return;
|
||||
}
|
||||
var firstByte:int = bits.readBits(8);
|
||||
if (firstByte == 254) { // Unlatch codeword
|
||||
return;
|
||||
}
|
||||
|
||||
parseTwoBytes(firstByte, bits.readBits(8), cValues);
|
||||
|
||||
var shift:int = 0;
|
||||
for (var i:int = 0; i < 3; i++) {
|
||||
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;
|
||||
case 1:
|
||||
if (upperShift) {
|
||||
result.Append(cValue + 128);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result.Append(cValue);
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
case 2:
|
||||
// Shift 2 for Text is the same encoding as C40
|
||||
if (cValue < 27) {
|
||||
if (upperShift) {
|
||||
result.Append(C40_SHIFT2_SET_CHARS[cValue] + 128);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result.Append(C40_SHIFT2_SET_CHARS[cValue]);
|
||||
}
|
||||
} else if (cValue == 27) { // FNC1
|
||||
throw new ReaderException( "DecodedBitStreamParser : decodeTextSegment : cValue = 27");
|
||||
} else if (cValue == 30) { // Upper Shift
|
||||
upperShift = true;
|
||||
} else {
|
||||
throw new ReaderException("DecodedBitStreamParser : decodeTextSegment : no match for cValue:"+cValue);
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
case 3:
|
||||
if (upperShift) {
|
||||
result.Append(TEXT_SHIFT3_SET_CHARS[cValue] + 128);
|
||||
upperShift = false;
|
||||
} else {
|
||||
result.Append(TEXT_SHIFT3_SET_CHARS[cValue]);
|
||||
}
|
||||
shift = 0;
|
||||
break;
|
||||
default:
|
||||
throw new ReaderException("DecodedBitStreamParser : decodeTextSegment : no match for shift"+shift);
|
||||
}
|
||||
}
|
||||
} while (bits.available() > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.7
|
||||
*/
|
||||
private static function decodeAnsiX12Segment(bits:BitSource, result:StringBuilder):void {
|
||||
// Three ANSI X12 values are encoded in a 16-bit value as
|
||||
// (1600 * C1) + (40 * C2) + C3 + 1
|
||||
|
||||
var cValues:Array = new Array(3);
|
||||
do {
|
||||
// If there is only one byte left then it will be encoded as ASCII
|
||||
if (bits.available() == 8) {
|
||||
return;
|
||||
}
|
||||
var firstByte:int = bits.readBits(8);
|
||||
if (firstByte == 254) { // Unlatch codeword
|
||||
return;
|
||||
}
|
||||
|
||||
parseTwoBytes(firstByte, bits.readBits(8), cValues);
|
||||
|
||||
for (var i:int = 0; i < 3; i++) {
|
||||
var cValue:int = cValues[i];
|
||||
if (cValue == 0) { // X12 segment terminator <CR>
|
||||
result.Append('\r');
|
||||
} else if (cValue == 1) { // X12 segment separator *
|
||||
result.Append('*');
|
||||
} else if (cValue == 2) { // X12 sub-element separator >
|
||||
result.Append('>');
|
||||
} else if (cValue == 3) { // space
|
||||
result.Append(' ');
|
||||
} else if (cValue < 14) { // 0 - 9
|
||||
result.Append(cValue + 44);
|
||||
} else if (cValue < 40) { // A - Z
|
||||
result.Append(cValue + 51);
|
||||
} else {
|
||||
throw new ReaderException("DecodedBitStreamParser : decodeTextSegment : no match for cValue : "+ cValue);
|
||||
}
|
||||
}
|
||||
} while (bits.available() > 0);
|
||||
}
|
||||
|
||||
private static function parseTwoBytes(firstByte:int, secondByte:int, result:Array):void {
|
||||
var fullBitValue:int = (firstByte << 8) + secondByte - 1;
|
||||
var temp:int = fullBitValue / 1600;
|
||||
result[0] = temp;
|
||||
fullBitValue -= temp * 1600;
|
||||
temp = fullBitValue / 40;
|
||||
result[1] = temp;
|
||||
result[2] = fullBitValue - temp * 40;
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.8 and Annex C Table C.3
|
||||
*/
|
||||
private static function decodeEdifactSegment(bits:BitSource, result:StringBuilder):void {
|
||||
var unlatch:Boolean = false;
|
||||
do {
|
||||
// If there is only two or less bytes left then it will be encoded as ASCII
|
||||
if (bits.available() <= 16) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i:int = 0; i < 4; i++) {
|
||||
var edifactValue:int = bits.readBits(6);
|
||||
|
||||
// Check for the unlatch character
|
||||
if (edifactValue == 0x2B67) { // 011111
|
||||
unlatch = true;
|
||||
// If we encounter the unlatch code then continue reading because the Codeword triple
|
||||
// is padded with 0's
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
result.Append(edifactValue);
|
||||
}
|
||||
}
|
||||
} while (!unlatch && bits.available() > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006, 5.2.9 and Annex B, B.2
|
||||
*/
|
||||
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);
|
||||
|
||||
|
||||
} catch (uee:Error ) {
|
||||
throw new Error("Platform does not support required encoding: " + uee);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006, Annex B, B.2
|
||||
*/
|
||||
private static function unrandomize255State(randomizedBase256Codeword:int,
|
||||
base256CodewordPosition:int ):int {
|
||||
var pseudoRandomNumber:int = ((149 * base256CodewordPosition) % 255) + 1;
|
||||
var tempVariable:int = randomizedBase256Codeword - pseudoRandomNumber;
|
||||
var result:int = (tempVariable >= 0 ? tempVariable : (tempVariable + 256));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* 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.datamatrix.decoder
|
||||
{
|
||||
|
||||
/**
|
||||
* <p>The main class which implements Data Matrix Code decoding -- as opposed to locating and extracting
|
||||
* the Data Matrix Code from an image.</p>
|
||||
*
|
||||
* @author bbrown@google.com (Brian Brown)
|
||||
*/
|
||||
public class Decoder
|
||||
{
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
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.ReaderException;
|
||||
|
||||
|
||||
private var rsDecoder:ReedSolomonDecoder;
|
||||
public function Decoder() {
|
||||
rsDecoder = new ReedSolomonDecoder(GF256.DATA_MATRIX_FIELD);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Convenience method that can decode a Data Matrix Code represented as a 2D array of booleans.
|
||||
* "true" is taken to mean a black module.</p>
|
||||
*
|
||||
* @param image booleans representing white/black Data Matrix Code modules
|
||||
* @return text and bytes encoded within the Data Matrix Code
|
||||
* @throws ReaderException if the Data Matrix Code cannot be decoded
|
||||
*/
|
||||
public function decode (image:Object):DecoderResult
|
||||
{
|
||||
if (image is Array) { return decode_Array(image as Array); }
|
||||
else if (image is BitMatrix) { return decode_BitMatrix(image as BitMatrix); }
|
||||
else { throw new Error('Decoder : decode : unknown type of image'); }
|
||||
}
|
||||
|
||||
public function decode_Array(image:Array):DecoderResult {
|
||||
var dimension:int = image.length;
|
||||
var bits:BitMatrix = new BitMatrix(dimension);
|
||||
for (var i:int = 0; i < dimension; i++) {
|
||||
for (var j:int = 0; j < dimension; j++) {
|
||||
if (image[i][j]) {
|
||||
bits._set(j, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return decode(bits);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Decodes a Data Matrix Code represented as a {@link BitMatrix}. A 1 or "true" is taken
|
||||
* to mean a black module.</p>
|
||||
*
|
||||
* @param bits booleans representing white/black Data Matrix Code modules
|
||||
* @return text and bytes encoded within the Data Matrix Code
|
||||
* @throws ReaderException if the Data Matrix Code cannot be decoded
|
||||
*/
|
||||
public function decode_BitMatrix(bits:BitMatrix ):DecoderResult {
|
||||
|
||||
// Construct a parser and read version, error-correction level
|
||||
var parser:BitMatrixParser = new BitMatrixParser(bits);
|
||||
var version:Version = parser.readVersion(bits);
|
||||
|
||||
// Read codewords
|
||||
var codewords:Array = parser.readCodewords();
|
||||
// Separate into data blocks
|
||||
var dataBlocks:Array = DataBlock.getDataBlocks(codewords, version);
|
||||
|
||||
// Count total number of data bytes
|
||||
var totalBytes:int = 0;
|
||||
for (var i:int = 0; i < dataBlocks.length; i++) {
|
||||
totalBytes += dataBlocks[i].getNumDataCodewords();
|
||||
}
|
||||
var resultBytes:Array = new Array(totalBytes);
|
||||
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++) {
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
// Decode the contents of that stream of bytes
|
||||
return DecodedBitStreamParser.decode(resultBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Given data and error-correction codewords received, possibly corrupted by errors, attempts to
|
||||
* correct the errors in-place using Reed-Solomon error correction.</p>
|
||||
*
|
||||
* @param codewordBytes data and error correction codewords
|
||||
* @param numDataCodewords number of codewords that are data bytes
|
||||
* @throws ReaderException if error correction fails
|
||||
*/
|
||||
private function correctErrors( codewordBytes:Array, numDataCodewords:int ):void {
|
||||
var numCodewords:int = codewordBytes.length;
|
||||
// First read into an array of ints
|
||||
var codewordsInts:Array = new Array(numCodewords);
|
||||
for (var i:int = 0; i < numCodewords; i++) {
|
||||
codewordsInts[i] = codewordBytes[i] & 0xFF;
|
||||
}
|
||||
var numECCodewords:int = codewordBytes.length - numDataCodewords;
|
||||
try {
|
||||
rsDecoder.decode(codewordsInts, numECCodewords);
|
||||
} catch (rse:ReedSolomonException) {
|
||||
throw new ReaderException("Decoder : correctErrors : could not decode codewords");
|
||||
}
|
||||
// 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]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.google.zxing.datamatrix.decoder
|
||||
{
|
||||
/**
|
||||
* <p>Encapsualtes the parameters for one error-correction block in one symbol version.
|
||||
* This includes the number of data codewords, and the number of times a block with these
|
||||
* parameters is used consecutively in the Data Matrix code version's format.</p>
|
||||
*/
|
||||
public class ECB {
|
||||
private var count:int;
|
||||
private var dataCodewords:int;
|
||||
|
||||
public function ECB(count:int, dataCodewords:int) {
|
||||
this.count = count;
|
||||
this.dataCodewords = dataCodewords;
|
||||
}
|
||||
|
||||
public function getCount():int {
|
||||
return count;
|
||||
}
|
||||
|
||||
public function getDataCodewords():int {
|
||||
return dataCodewords;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.google.zxing.datamatrix.decoder
|
||||
{
|
||||
/**
|
||||
* <p>Encapsulates a set of error-correction blocks in one symbol version. Most versions will
|
||||
* use blocks of differing sizes within one version, so, this encapsulates the parameters for
|
||||
* each set of blocks. It also holds the number of error-correction codewords per block since it
|
||||
* will be the same across all blocks within one version.</p>
|
||||
*/
|
||||
public class ECBlocks
|
||||
{
|
||||
|
||||
private var ecCodewords:int;
|
||||
private var ecBlocks:Array;
|
||||
|
||||
public function ECBlocks(ecCodewords:int, ecBlocks:ECB, ecBlocks2:ECB=null)
|
||||
{
|
||||
this.ecCodewords = ecCodewords;
|
||||
|
||||
if (ecBlocks2 == null)
|
||||
{
|
||||
this.ecBlocks = [ecBlocks];
|
||||
}
|
||||
else
|
||||
{
|
||||
this.ecBlocks = [ecBlocks, ecBlocks2];
|
||||
}
|
||||
}
|
||||
|
||||
public function getECCodewords():int {
|
||||
return ecCodewords;
|
||||
}
|
||||
|
||||
public function getECBlocks():Array {
|
||||
return ecBlocks;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* 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.datamatrix.decoder
|
||||
{
|
||||
import com.google.zxing.ReaderException;
|
||||
/**
|
||||
* The Version object encapsulates attributes about a particular
|
||||
* size Data Matrix Code.
|
||||
*
|
||||
* @author bbrown@google.com (Brian Brown)
|
||||
*/
|
||||
|
||||
public class Version
|
||||
{
|
||||
|
||||
private static var VERSIONS:Array = buildVersions();
|
||||
private var versionNumber:int;
|
||||
private var symbolSizeRows:int;
|
||||
private var symbolSizeColumns:int;
|
||||
private var dataRegionSizeRows:int;
|
||||
private var dataRegionSizeColumns:int;
|
||||
private var ecBlocks:ECBlocks;
|
||||
private var totalCodewords:int;
|
||||
|
||||
public function Version(versionNumber:int,
|
||||
symbolSizeRows:int,
|
||||
symbolSizeColumns:int,
|
||||
dataRegionSizeRows:int,
|
||||
dataRegionSizeColumns:int,
|
||||
ecBlocks:ECBlocks) {
|
||||
this.versionNumber = versionNumber;
|
||||
this.symbolSizeRows = symbolSizeRows;
|
||||
this.symbolSizeColumns = symbolSizeColumns;
|
||||
this.dataRegionSizeRows = dataRegionSizeRows;
|
||||
this.dataRegionSizeColumns = dataRegionSizeColumns;
|
||||
this.ecBlocks = ecBlocks;
|
||||
|
||||
// Calculate the total number of codewords
|
||||
var total:int = 0;
|
||||
var ecCodewords:int = ecBlocks.getECCodewords();
|
||||
var ecbArray:Array = ecBlocks.getECBlocks();
|
||||
|
||||
for (var i:int = 0; i < ecbArray.length; i++)
|
||||
{
|
||||
var ecBlock:ECB = ecbArray[i];
|
||||
total += ecBlock.getCount() * (ecBlock.getDataCodewords() + ecCodewords);
|
||||
}
|
||||
|
||||
this.totalCodewords = total;
|
||||
}
|
||||
|
||||
public function getVersionNumber():int {
|
||||
return versionNumber;
|
||||
}
|
||||
|
||||
public function getSymbolSizeRows():int {
|
||||
return symbolSizeRows;
|
||||
}
|
||||
|
||||
public function getSymbolSizeColumns():int {
|
||||
return symbolSizeColumns;
|
||||
}
|
||||
|
||||
public function getDataRegionSizeRows():int {
|
||||
return dataRegionSizeRows;
|
||||
}
|
||||
|
||||
public function getDataRegionSizeColumns():int {
|
||||
return dataRegionSizeColumns;
|
||||
}
|
||||
|
||||
public function getTotalCodewords():int {
|
||||
return totalCodewords;
|
||||
}
|
||||
|
||||
public function getECBlocks():ECBlocks {
|
||||
return ecBlocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Deduces version information from Data Matrix dimensions.</p>
|
||||
*
|
||||
* @param numRows Number of rows in modules
|
||||
* @param numColumns Number of columns in modules
|
||||
* @return {@link Version} for a Data Matrix Code of those dimensions
|
||||
* @throws ReaderException if dimensions do correspond to a valid Data Matrix size
|
||||
*/
|
||||
public static function getVersionForDimensions(numRows:int,numColumns:int):Version {
|
||||
if ((numRows & 0x01) != 0 || (numColumns & 0x01) != 0) {
|
||||
throw new ReaderException("Version : getVersionForDimensions : numColumns ("+numRows+") or numRows ("+numColumns+") uneven ");
|
||||
}
|
||||
|
||||
// TODO(bbrown): This is doing a linear search through the array of versions.
|
||||
// If we interleave the rectangular versions with the square versions we could
|
||||
// do a binary search.
|
||||
var numVersions:int = VERSIONS.length;
|
||||
for (var i:int = 0; i < numVersions; ++i){
|
||||
var version:Version = VERSIONS[i];
|
||||
if (version.symbolSizeRows == numRows && version.symbolSizeColumns == numColumns) {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ReaderException("Version : getVersionForDimensions : version could not be determined");
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
return versionNumber.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006 5.5.1 Table 7
|
||||
*/
|
||||
private static function buildVersions():Array {
|
||||
return [
|
||||
new Version(1, 10, 10, 8, 8,
|
||||
new ECBlocks(5, new ECB(1, 3))),
|
||||
new Version(2, 12, 12, 10, 10,
|
||||
new ECBlocks(7, new ECB(1, 5))),
|
||||
new Version(3, 14, 14, 12, 12,
|
||||
new ECBlocks(10, new ECB(1, 8))),
|
||||
new Version(4, 16, 16, 14, 14,
|
||||
new ECBlocks(12, new ECB(1, 12))),
|
||||
new Version(5, 18, 18, 16, 16,
|
||||
new ECBlocks(14, new ECB(1, 18))),
|
||||
new Version(6, 20, 20, 18, 18,
|
||||
new ECBlocks(18, new ECB(1, 22))),
|
||||
new Version(7, 22, 22, 20, 20,
|
||||
new ECBlocks(20, new ECB(1, 30))),
|
||||
new Version(8, 24, 24, 22, 22,
|
||||
new ECBlocks(24, new ECB(1, 36))),
|
||||
new Version(9, 26, 26, 24, 24,
|
||||
new ECBlocks(28, new ECB(1, 44))),
|
||||
new Version(10, 32, 32, 14, 14,
|
||||
new ECBlocks(36, new ECB(1, 62))),
|
||||
new Version(11, 36, 36, 16, 16,
|
||||
new ECBlocks(42, new ECB(1, 86))),
|
||||
new Version(12, 40, 40, 18, 18,
|
||||
new ECBlocks(48, new ECB(1, 114))),
|
||||
new Version(13, 44, 44, 20, 20,
|
||||
new ECBlocks(56, new ECB(1, 144))),
|
||||
new Version(14, 48, 48, 22, 22,
|
||||
new ECBlocks(68, new ECB(1, 174))),
|
||||
new Version(15, 52, 52, 24, 24,
|
||||
new ECBlocks(42, new ECB(2, 102))),
|
||||
new Version(16, 64, 64, 14, 14,
|
||||
new ECBlocks(56, new ECB(2, 140))),
|
||||
new Version(17, 72, 72, 16, 16,
|
||||
new ECBlocks(36, new ECB(4, 92))),
|
||||
new Version(18, 80, 80, 18, 18,
|
||||
new ECBlocks(48, new ECB(4, 114))),
|
||||
new Version(19, 88, 88, 20, 20,
|
||||
new ECBlocks(56, new ECB(4, 144))),
|
||||
new Version(20, 96, 96, 22, 22,
|
||||
new ECBlocks(68, new ECB(4, 174))),
|
||||
new Version(21, 104, 104, 24, 24,
|
||||
new ECBlocks(56, new ECB(6, 136))),
|
||||
new Version(22, 120, 120, 18, 18,
|
||||
new ECBlocks(68, new ECB(6, 175))),
|
||||
new Version(23, 132, 132, 20, 20,
|
||||
new ECBlocks(62, new ECB(8, 163))),
|
||||
new Version(24, 144, 144, 22, 22,
|
||||
new ECBlocks(62, new ECB(8, 156), new ECB(2, 155))),
|
||||
new Version(25, 8, 18, 6, 16,
|
||||
new ECBlocks(7, new ECB(1, 5))),
|
||||
new Version(26, 8, 32, 6, 14,
|
||||
new ECBlocks(11, new ECB(1, 10))),
|
||||
new Version(27, 12, 26, 10, 24,
|
||||
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 ECBlocks(24, new ECB(1, 32))),
|
||||
new Version(30, 16, 48, 14, 22,
|
||||
new ECBlocks(28, new ECB(1, 49)))];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,289 @@
|
|||
/*
|
||||
* 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.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.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;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Encapsulates logic that can detect a Data Matrix Code in an image, even if the Data Matrix Code
|
||||
* is rotated or skewed, or partially obscured.</p>
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public class Detector
|
||||
{
|
||||
import com.google.zxing.common.flexdatatypes.HashTable;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.common.DecoderResult;
|
||||
import com.google.zxing.common.DetectorResult;
|
||||
import com.google.zxing.common.flexdatatypes.ArrayList;
|
||||
import com.google.zxing.common.BitArray;
|
||||
import com.google.zxing.common.GridSampler;
|
||||
import com.google.zxing.ResultPoint;
|
||||
import com.google.zxing.datamatrix.detector.ResultPointsAndTransitionsComparator;
|
||||
import com.google.zxing.common.detector.MonochromeRectangleDetector;
|
||||
|
||||
|
||||
//private static var MAX_MODULES:int = 32;
|
||||
|
||||
// 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 var image:BitMatrix ;
|
||||
private var rectangleDetector:MonochromeRectangleDetector
|
||||
|
||||
public function Detector(image:BitMatrix)
|
||||
{
|
||||
this.image = image;
|
||||
rectangleDetector = new MonochromeRectangleDetector(image);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Detects a Data Matrix Code in an image.</p>
|
||||
*
|
||||
* @return {@link DetectorResult} encapsulating results of detecting a QR Code
|
||||
* @throws ReaderException if no Data Matrix Code can be found
|
||||
*/
|
||||
public function detect():DetectorResult {
|
||||
|
||||
|
||||
var cornerPoints:Array = rectangleDetector.detect();
|
||||
var pointA:ResultPoint = cornerPoints[0]
|
||||
var pointB:ResultPoint = cornerPoints[1]
|
||||
var pointC:ResultPoint = cornerPoints[2]
|
||||
var pointD:ResultPoint = cornerPoints[3]
|
||||
|
||||
|
||||
// Point A and D are across the diagonal from one another,
|
||||
// as are B and C. Figure out which are the solid black lines
|
||||
// by counting transitions
|
||||
var transitions:ArrayList = new ArrayList(4);
|
||||
transitions.Add(transitionsBetween(pointA, pointB));
|
||||
transitions.Add(transitionsBetween(pointA, pointC));
|
||||
transitions.Add(transitionsBetween(pointB, pointD));
|
||||
transitions.Add(transitionsBetween(pointC, pointD));
|
||||
transitions.sort_ResultPointsAndTransitionsComparator();
|
||||
//Collections.insertionSort(transitions, new ResultPointsAndTransitionsComparator());
|
||||
|
||||
// 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));
|
||||
|
||||
// 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.
|
||||
var pointCount:HashTable = new HashTable();
|
||||
increment(pointCount, lSideOne.getFrom());
|
||||
increment(pointCount, lSideOne.getTo());
|
||||
increment(pointCount, lSideTwo.getFrom());
|
||||
increment(pointCount, lSideTwo.getTo());
|
||||
|
||||
var maybeTopLeft:ResultPoint = null;
|
||||
var bottomLeft:ResultPoint = null;
|
||||
var maybeBottomRight:ResultPoint = null;
|
||||
var size:int = pointCount.getSize();
|
||||
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;
|
||||
if (value == 2)
|
||||
{
|
||||
bottomLeft = point; // this is definitely the bottom left, then -- end of two L sides
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise it's either top left or bottom right -- just assign the two arbitrarily now
|
||||
if (maybeTopLeft == null)
|
||||
{
|
||||
maybeTopLeft = point;
|
||||
}
|
||||
else
|
||||
{
|
||||
maybeBottomRight = point;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (maybeTopLeft == null || bottomLeft == null || maybeBottomRight == null)
|
||||
{
|
||||
throw new ReaderException("Detector : detect : maybeTopLeft or bottomLeft or maybeBottomRight == null");
|
||||
}
|
||||
|
||||
// Bottom left is correct but top left and bottom right might be switched
|
||||
var corners:Array = [maybeTopLeft, bottomLeft, maybeBottomRight];
|
||||
// Use the dot product trick to sort them out
|
||||
ResultPoint.orderBestPatterns(corners);
|
||||
|
||||
// Now we know which is which:
|
||||
var bottomRight:ResultPoint = corners[0];
|
||||
bottomLeft = corners[1];
|
||||
var topLeft:ResultPoint = corners[2];
|
||||
|
||||
// Which point didn't we find in relation to the "L" sides? that's the top right corner
|
||||
var topRight:ResultPoint;
|
||||
if (!pointCount.ContainsKey(pointA))
|
||||
{
|
||||
topRight = pointA;
|
||||
}
|
||||
else if (!pointCount.ContainsKey(pointB))
|
||||
{
|
||||
topRight = pointB;
|
||||
}
|
||||
else if (!pointCount.ContainsKey(pointC))
|
||||
{
|
||||
topRight = pointC;
|
||||
}
|
||||
else
|
||||
{
|
||||
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:
|
||||
|
||||
// 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;
|
||||
|
||||
|
||||
|
||||
var bits:BitMatrix = sampleGrid(image, topLeft, bottomLeft, bottomRight, dimension);
|
||||
return new DetectorResult(bits, [pointA, pointB, pointC, pointD]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static function sampleGrid(image:BitMatrix ,
|
||||
topLeft:ResultPoint,
|
||||
bottomLeft:ResultPoint,
|
||||
bottomRight:ResultPoint,
|
||||
dimension:int):BitMatrix {
|
||||
|
||||
// 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();
|
||||
|
||||
// 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());
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of black/white transitions between two points, using something like Bresenham's algorithm.
|
||||
*/
|
||||
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 steep:Boolean = Math.abs(toY - fromY) > Math.abs(toX - fromX);
|
||||
if (steep) {
|
||||
var temp:int = fromX;
|
||||
fromX = fromY;
|
||||
fromY = temp;
|
||||
temp = toX;
|
||||
toX = toY;
|
||||
toY = temp;
|
||||
}
|
||||
|
||||
var dx:int = Math.abs(toX - fromX);
|
||||
var dy:int = Math.abs(toY - fromY);
|
||||
var error:int = -dx >> 1;
|
||||
var ystep:int = fromY < toY ? 1 : -1;
|
||||
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) {
|
||||
var isBlack:Boolean = image._get(steep ? y : x, steep ? x : y);
|
||||
if (isBlack == !inBlack) {
|
||||
transitions++;
|
||||
inBlack = isBlack;
|
||||
}
|
||||
error += dy;
|
||||
if (error > 0) {
|
||||
y += ystep;
|
||||
error -= dx;
|
||||
}
|
||||
}
|
||||
return new ResultPointsAndTransitions(from, _to, transitions);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package com.google.zxing.datamatrix.detector
|
||||
{
|
||||
import com.google.zxing.ResultPoint;
|
||||
/**
|
||||
* Simply encapsulates two points and a number of transitions between them.
|
||||
*/
|
||||
public class ResultPointsAndTransitions
|
||||
{
|
||||
private var from:ResultPoint;
|
||||
private var to:ResultPoint;
|
||||
private var transitions:int;
|
||||
|
||||
public function ResultPointsAndTransitions(from:ResultPoint, to:ResultPoint, transitions:int) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.transitions = transitions;
|
||||
}
|
||||
|
||||
public function getFrom():ResultPoint {
|
||||
return from;
|
||||
}
|
||||
public function getTo():ResultPoint {
|
||||
return to;
|
||||
}
|
||||
public function getTransitions():int {
|
||||
return transitions;
|
||||
}
|
||||
public function toString():String {
|
||||
return from + "/" + to + '/' + transitions;
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue